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 importlib.resources as pkg_resources
|
||||||
import sys
|
import sys
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
from enum import Enum
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from systemrdl.node import FieldNode, SignalNode
|
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.component import Component, TypeDef
|
||||||
from srdl2sv.components import templates
|
from srdl2sv.components import templates
|
||||||
|
|
||||||
|
class StorageType(Enum):
|
||||||
|
FLOPS = 0
|
||||||
|
WIRE = 1
|
||||||
|
CONST = 2
|
||||||
|
|
||||||
class Field(Component):
|
class Field(Component):
|
||||||
# Save YAML template as class variable
|
# Save YAML template as class variable
|
||||||
templ_dict = yaml.load(
|
templ_dict = yaml.load(
|
||||||
@ -36,6 +42,9 @@ class Field(Component):
|
|||||||
# Save and/or process important variables
|
# Save and/or process important variables
|
||||||
self.__init_variables(obj)
|
self.__init_variables(obj)
|
||||||
|
|
||||||
|
# Determine whether it is a wire, flops, or a wire
|
||||||
|
self.__init_storage_type()
|
||||||
|
|
||||||
# Determine field types
|
# Determine field types
|
||||||
self.__init_fieldtype()
|
self.__init_fieldtype()
|
||||||
|
|
||||||
@ -54,18 +63,25 @@ class Field(Component):
|
|||||||
# HW Access can be handled in __init__ function but SW access
|
# HW Access can be handled in __init__ function but SW access
|
||||||
# must be handled in a seperate method that can be called
|
# must be handled in a seperate method that can be called
|
||||||
# seperately in case of alias registers
|
# 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()
|
self.__add_always_ff()
|
||||||
|
|
||||||
# Only add normal hardware access if field is not an interrupt field
|
# Only add normal hardware access if field is not an interrupt field
|
||||||
if not self.__add_interrupt():
|
if not self.__add_interrupt():
|
||||||
self.__add_hw_access()
|
self.__add_hw_wr_access()
|
||||||
|
self.__add_hw_rd_access()
|
||||||
|
|
||||||
self.__add_combo()
|
self.__add_combo()
|
||||||
self.__add_swmod_swacc()
|
self.__add_swmod_swacc()
|
||||||
self.__add_counter()
|
self.__add_counter()
|
||||||
|
|
||||||
self.add_sw_access(obj)
|
self.add_sw_access(obj)
|
||||||
|
|
||||||
def add_sw_access(self, obj, alias = False):
|
def add_sw_access(self, obj, alias = False):
|
||||||
access_rtl = {}
|
access_rtl = {}
|
||||||
@ -871,7 +887,23 @@ class Field(Component):
|
|||||||
|
|
||||||
return self.properties['intr']
|
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
|
# Mutually exclusive. systemrdl-compiler performs check for this
|
||||||
enable_mask_negl = ''
|
enable_mask_negl = ''
|
||||||
enable_mask = False
|
enable_mask = False
|
||||||
@ -1012,6 +1044,7 @@ class Field(Component):
|
|||||||
else:
|
else:
|
||||||
self.access_rtl['hw_setclr'] = ([], False)
|
self.access_rtl['hw_setclr'] = ([], False)
|
||||||
|
|
||||||
|
def __add_hw_rd_access(self):
|
||||||
# Hookup flop to output port in case register is readable by hardware
|
# Hookup flop to output port in case register is readable by hardware
|
||||||
if self.obj.get_property('hw') in (AccessType.rw, AccessType.r):
|
if self.obj.get_property('hw') in (AccessType.rw, AccessType.r):
|
||||||
# Connect flops to output port
|
# Connect flops to output port
|
||||||
@ -1131,12 +1164,13 @@ class Field(Component):
|
|||||||
# Chain access RTL to the rest of the RTL
|
# Chain access RTL to the rest of the RTL
|
||||||
self.rtl_header = [*self.rtl_header, *order_list_rtl]
|
self.rtl_header = [*self.rtl_header, *order_list_rtl]
|
||||||
|
|
||||||
self.rtl_header.append(
|
if self.storage_type is StorageType.FLOPS:
|
||||||
self._process_yaml(
|
self.rtl_header.append(
|
||||||
Field.templ_dict['end_field_ff'],
|
self._process_yaml(
|
||||||
{'path': self.path_underscored}
|
Field.templ_dict['end_field_ff'],
|
||||||
|
{'path': self.path_underscored}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
def __add_combo(self):
|
def __add_combo(self):
|
||||||
operations = []
|
operations = []
|
||||||
@ -1267,24 +1301,43 @@ class Field(Component):
|
|||||||
|
|
||||||
if self.rst['name']:
|
if self.rst['name']:
|
||||||
self.resets.add(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
|
# Value of reset must always be determined on field level
|
||||||
# Don't use 'not obj.get_property("reset"), since the value
|
# Don't use 'not obj.get_property("reset"), since the value
|
||||||
# could (and will often be) be '0'
|
# could (and will often be) be '0'
|
||||||
self.rst['value'] = \
|
self.rst['value'] = \
|
||||||
'\'x' if obj.get_property("reset") == None else\
|
'x' if obj.get_property("reset") is None else\
|
||||||
obj.get_property('reset')
|
obj.get_property('reset')
|
||||||
|
|
||||||
# Define dict that holds all RTL
|
# Define dict that holds all RTL
|
||||||
self.access_rtl = {}
|
self.access_rtl = {}
|
||||||
self.access_rtl['else'] = (["else"], False)
|
self.access_rtl['else'] = (["else"], False)
|
||||||
self.access_rtl[''] = ([''], 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):
|
def __summary(self):
|
||||||
# Additional flags that are set
|
# Additional flags that are set
|
||||||
# Use list, rather than set, to ensure the order stays the same
|
# Use list, rather than set, to ensure the order stays the same
|
||||||
@ -1315,7 +1368,9 @@ class Field(Component):
|
|||||||
external = self.config['external'],
|
external = self.config['external'],
|
||||||
lsb = self.obj.lsb,
|
lsb = self.obj.lsb,
|
||||||
msb = self.obj.msb,
|
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):
|
def __add_always_ff(self):
|
||||||
# Handle always_ff
|
# Handle always_ff
|
||||||
@ -1340,7 +1395,9 @@ class Field(Component):
|
|||||||
'rst_negl': "!" if self.rst['active'] == "active_low" else "",
|
'rst_negl': "!" if self.rst['active'] == "active_low" else "",
|
||||||
'rst_value': self.rst['value'],
|
'rst_value': self.rst['value'],
|
||||||
'genvars': self.genvars_str,
|
'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 "\
|
"property with the counter property. The counter property "\
|
||||||
"will be ignored.")
|
"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
|
@staticmethod
|
||||||
def __process_reset_signal(reset_signal):
|
def __process_reset_signal(reset_signal):
|
||||||
rst = {}
|
rst = {}
|
||||||
@ -1395,7 +1463,7 @@ class Field(Component):
|
|||||||
rst['async'] = False
|
rst['async'] = False
|
||||||
rst['name'] = None
|
rst['name'] = None
|
||||||
rst['edge'] = None
|
rst['edge'] = None
|
||||||
rst['value'] = "'x"
|
rst['value'] = "x"
|
||||||
rst['active'] = "-"
|
rst['active'] = "-"
|
||||||
rst['type'] = "-"
|
rst['type'] = "-"
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ rst_field_assign:
|
|||||||
rtl: |-
|
rtl: |-
|
||||||
if ({rst_negl}{rst_name})
|
if ({rst_negl}{rst_name})
|
||||||
begin
|
begin
|
||||||
{path}_q{genvars} <= {rst_value};
|
{path}_q{genvars} <= {width}'d{rst_value};
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
signals:
|
signals:
|
||||||
@ -108,6 +108,25 @@ hw_access_counter:
|
|||||||
signal_type: 'logic'
|
signal_type: 'logic'
|
||||||
- name: '{path}_next'
|
- name: '{path}_next'
|
||||||
signal_type: '{field_type}'
|
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:
|
end_field_ff:
|
||||||
rtl: |-
|
rtl: |-
|
||||||
end // of {path}'s always_ff
|
end // of {path}'s always_ff
|
||||||
@ -164,12 +183,13 @@ field_comment:
|
|||||||
rtl: |-
|
rtl: |-
|
||||||
|
|
||||||
//-----------------FIELD SUMMARY-----------------
|
//-----------------FIELD SUMMARY-----------------
|
||||||
// name : {name} ({path_wo_field}[{msb}:{lsb}])
|
// name : {name} ({path_wo_field}[{msb}:{lsb}])
|
||||||
// access : hw = {hw_access} {hw_precedence}
|
// access : hw = {hw_access} {hw_precedence}
|
||||||
// sw = {sw_access} {sw_precedence}
|
// sw = {sw_access} {sw_precedence}
|
||||||
// reset : {rst_active} / {rst_type}
|
// reset : {rst_active} / {rst_type}
|
||||||
// flags : {misc_flags}
|
// flags : {misc_flags}
|
||||||
// external : {external}
|
// external : {external}
|
||||||
|
// storage type : {storage_type}
|
||||||
//-----------------------------------------------
|
//-----------------------------------------------
|
||||||
field_desc:
|
field_desc:
|
||||||
rtl: |-
|
rtl: |-
|
||||||
|
Loading…
Reference in New Issue
Block a user