mirror of
https://github.com/Silicon1602/srdl2sv.git
synced 2024-12-22 06:58:41 +00:00
Closes #8: Certain fields shall be implemented as wires or constants
The software now detects whether a field shall be implemented with flops, with wires, or as a constant. Everything should now follow Table 12 and Section 9.5.1 of the SystemRDL 2.0 LRM.
This commit is contained in:
parent
5a00d48c34
commit
e46e51f3cf
@ -3,6 +3,7 @@ import math
|
||||
import importlib.resources as pkg_resources
|
||||
import sys
|
||||
from typing import Optional
|
||||
from enum import Enum
|
||||
import yaml
|
||||
|
||||
from systemrdl.node import FieldNode, SignalNode
|
||||
@ -13,6 +14,11 @@ from systemrdl.rdltypes import PrecedenceType, AccessType, OnReadType, OnWriteTy
|
||||
from srdl2sv.components.component import Component, TypeDef
|
||||
from srdl2sv.components import templates
|
||||
|
||||
class StorageType(Enum):
|
||||
FLOPS = 0
|
||||
WIRE = 1
|
||||
CONST = 2
|
||||
|
||||
class Field(Component):
|
||||
# Save YAML template as class variable
|
||||
templ_dict = yaml.load(
|
||||
@ -36,6 +42,9 @@ class Field(Component):
|
||||
# Save and/or process important variables
|
||||
self.__init_variables(obj)
|
||||
|
||||
# Determine whether it is a wire, flops, or a wire
|
||||
self.__init_storage_type()
|
||||
|
||||
# Determine field types
|
||||
self.__init_fieldtype()
|
||||
|
||||
@ -54,12 +63,19 @@ class Field(Component):
|
||||
# HW Access can be handled in __init__ function but SW access
|
||||
# must be handled in a seperate method that can be called
|
||||
# seperately in case of alias registers
|
||||
if not self.config['external']:
|
||||
if self.config['external']:
|
||||
pass
|
||||
elif self.storage_type is not StorageType.FLOPS:
|
||||
self.__add_wire_const()
|
||||
self.__add_hw_rd_access()
|
||||
self.add_sw_access(obj)
|
||||
else:
|
||||
self.__add_always_ff()
|
||||
|
||||
# Only add normal hardware access if field is not an interrupt field
|
||||
if not self.__add_interrupt():
|
||||
self.__add_hw_access()
|
||||
self.__add_hw_wr_access()
|
||||
self.__add_hw_rd_access()
|
||||
|
||||
self.__add_combo()
|
||||
self.__add_swmod_swacc()
|
||||
@ -871,7 +887,23 @@ class Field(Component):
|
||||
|
||||
return self.properties['intr']
|
||||
|
||||
def __add_hw_access(self):
|
||||
def __add_wire_const(self):
|
||||
field_templ = 'hw_wire' if self.storage_type is StorageType.WIRE else 'hw_const'
|
||||
|
||||
self.access_rtl['hw_write'] = ([
|
||||
self._process_yaml(
|
||||
Field.templ_dict[field_templ],
|
||||
{'path': self.path_underscored,
|
||||
'genvars': self.genvars_str,
|
||||
'field_type': self.field_type,
|
||||
'width': self.obj.width,
|
||||
'const': self.rst['value'],
|
||||
}
|
||||
)
|
||||
],
|
||||
True)
|
||||
|
||||
def __add_hw_wr_access(self):
|
||||
# Mutually exclusive. systemrdl-compiler performs check for this
|
||||
enable_mask_negl = ''
|
||||
enable_mask = False
|
||||
@ -1012,6 +1044,7 @@ class Field(Component):
|
||||
else:
|
||||
self.access_rtl['hw_setclr'] = ([], False)
|
||||
|
||||
def __add_hw_rd_access(self):
|
||||
# Hookup flop to output port in case register is readable by hardware
|
||||
if self.obj.get_property('hw') in (AccessType.rw, AccessType.r):
|
||||
# Connect flops to output port
|
||||
@ -1131,6 +1164,7 @@ class Field(Component):
|
||||
# Chain access RTL to the rest of the RTL
|
||||
self.rtl_header = [*self.rtl_header, *order_list_rtl]
|
||||
|
||||
if self.storage_type is StorageType.FLOPS:
|
||||
self.rtl_header.append(
|
||||
self._process_yaml(
|
||||
Field.templ_dict['end_field_ff'],
|
||||
@ -1267,17 +1301,12 @@ class Field(Component):
|
||||
|
||||
if self.rst['name']:
|
||||
self.resets.add(self.rst['name'])
|
||||
elif obj.get_property("reset") is not None:
|
||||
self.logger.warning("Field has a reset value, but no reset "\
|
||||
"signal was defined and connected to the "\
|
||||
"field. Note that explicit connecting this "\
|
||||
"is not required if a field_reset was defined.")
|
||||
|
||||
# Value of reset must always be determined on field level
|
||||
# Don't use 'not obj.get_property("reset"), since the value
|
||||
# could (and will often be) be '0'
|
||||
self.rst['value'] = \
|
||||
'\'x' if obj.get_property("reset") == None else\
|
||||
'x' if obj.get_property("reset") is None else\
|
||||
obj.get_property('reset')
|
||||
|
||||
# Define dict that holds all RTL
|
||||
@ -1285,6 +1314,30 @@ class Field(Component):
|
||||
self.access_rtl['else'] = (["else"], False)
|
||||
self.access_rtl[''] = ([''], False)
|
||||
|
||||
def __init_storage_type(self):
|
||||
# It is not required to check for illegal conditions because the
|
||||
# compiler will take care of this
|
||||
hw_prop = self.obj.get_property('hw')
|
||||
sw_prop = self.obj.get_property('sw')
|
||||
|
||||
# Check the storage type, according to Table 12 of the SystemRDL 2.0 LRM
|
||||
if hw_prop is AccessType.r and sw_prop is AccessType.r:
|
||||
# hw=r/sw=r --> Constant
|
||||
self.storage_type = StorageType.CONST
|
||||
elif hw_prop is AccessType.na and sw_prop is AccessType.r:
|
||||
# hw=na/sw=r --> Constant
|
||||
self.storage_type = StorageType.CONST
|
||||
elif hw_prop is AccessType.w and sw_prop is AccessType.r \
|
||||
and self.obj.get_property("reset") is None \
|
||||
and not self.we_or_wel:
|
||||
# If hw=w/sw=r AND no reset or we/wel is defined, a simple wire is implemented.
|
||||
# This isn't clear from Table 12, but '9.5.1 Semantics' describes this
|
||||
self.storage_type = StorageType.WIRE
|
||||
else:
|
||||
self.storage_type = StorageType.FLOPS
|
||||
|
||||
self.logger.debug("Storage type of field detected as '%s'", self.storage_type)
|
||||
|
||||
def __summary(self):
|
||||
# Additional flags that are set
|
||||
# Use list, rather than set, to ensure the order stays the same
|
||||
@ -1315,7 +1368,9 @@ class Field(Component):
|
||||
external = self.config['external'],
|
||||
lsb = self.obj.lsb,
|
||||
msb = self.obj.msb,
|
||||
path_wo_field = self.path_wo_field)
|
||||
path_wo_field = self.path_wo_field,
|
||||
storage_type = self.storage_type,
|
||||
)
|
||||
|
||||
def __add_always_ff(self):
|
||||
# Handle always_ff
|
||||
@ -1340,7 +1395,9 @@ class Field(Component):
|
||||
'rst_negl': "!" if self.rst['active'] == "active_low" else "",
|
||||
'rst_value': self.rst['value'],
|
||||
'genvars': self.genvars_str,
|
||||
'field_type': self.field_type}
|
||||
'field_type': self.field_type,
|
||||
'width': self.obj.width,
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@ -1374,6 +1431,17 @@ class Field(Component):
|
||||
"property with the counter property. The counter property "\
|
||||
"will be ignored.")
|
||||
|
||||
# If there a reset value is defined but no reset value, throw a warning
|
||||
# This is not true in case of a constant
|
||||
if not self.rst['name'] \
|
||||
and self.obj.get_property("reset") is not None \
|
||||
and self.storage_type is StorageType.FLOPS:
|
||||
self.logger.warning("Field has a reset value, but no reset "\
|
||||
"signal was defined and connected to the "\
|
||||
"field. Note that explicit connecting this "\
|
||||
"is not required if a field_reset was defined.")
|
||||
|
||||
|
||||
@staticmethod
|
||||
def __process_reset_signal(reset_signal):
|
||||
rst = {}
|
||||
@ -1395,7 +1463,7 @@ class Field(Component):
|
||||
rst['async'] = False
|
||||
rst['name'] = None
|
||||
rst['edge'] = None
|
||||
rst['value'] = "'x"
|
||||
rst['value'] = "x"
|
||||
rst['active'] = "-"
|
||||
rst['type'] = "-"
|
||||
|
||||
|
@ -9,7 +9,7 @@ rst_field_assign:
|
||||
rtl: |-
|
||||
if ({rst_negl}{rst_name})
|
||||
begin
|
||||
{path}_q{genvars} <= {rst_value};
|
||||
{path}_q{genvars} <= {width}'d{rst_value};
|
||||
end
|
||||
else
|
||||
signals:
|
||||
@ -108,6 +108,25 @@ hw_access_counter:
|
||||
signal_type: 'logic'
|
||||
- name: '{path}_next'
|
||||
signal_type: '{field_type}'
|
||||
hw_const:
|
||||
rtl: |-
|
||||
// Field is defined as a constant.
|
||||
assign {path}_q{genvars} = {width}'d{const};
|
||||
signals:
|
||||
- name: '{path}_q'
|
||||
signal_type: '{field_type}'
|
||||
hw_wire:
|
||||
rtl: |-
|
||||
// Field is a simple wire.
|
||||
// To generate a flop either add the we/wel property, add
|
||||
// a reset, or change the sw/hw access properties
|
||||
assign {path}_q{genvars} = {path}_in{genvars};
|
||||
signals:
|
||||
- name: '{path}_q'
|
||||
signal_type: '{field_type}'
|
||||
input_ports:
|
||||
- name: '{path}_in'
|
||||
signal_type: '{field_type}'
|
||||
end_field_ff:
|
||||
rtl: |-
|
||||
end // of {path}'s always_ff
|
||||
@ -170,6 +189,7 @@ field_comment:
|
||||
// reset : {rst_active} / {rst_type}
|
||||
// flags : {misc_flags}
|
||||
// external : {external}
|
||||
// storage type : {storage_type}
|
||||
//-----------------------------------------------
|
||||
field_desc:
|
||||
rtl: |-
|
||||
|
Loading…
Reference in New Issue
Block a user