mirror of
https://github.com/Silicon1602/srdl2sv.git
synced 2024-12-22 15:08:39 +00:00
Add basic interrupt framework
Up to this point, interrupt outputs are generated and intr, enable, mask, haltenable, and haltmask are supported. stick, stikcybit and the different types of interrupts are not yet supported. This commit also removes the option to turn off santiy checking. This is a bad idea anyway...
This commit is contained in:
parent
8ea1ad97da
commit
c52e59abd0
@ -51,13 +51,6 @@ class CliArguments():
|
|||||||
help="If set, the dependency directories will be\
|
help="If set, the dependency directories will be\
|
||||||
searched recursively.")
|
searched recursively.")
|
||||||
|
|
||||||
self.parser.add_argument(
|
|
||||||
"-x",
|
|
||||||
"--disable_sanity",
|
|
||||||
action="store_true",
|
|
||||||
help="Disable sanity checks or components. This might speed\
|
|
||||||
up the compiler but is generally not recommended!")
|
|
||||||
|
|
||||||
self.parser.add_argument(
|
self.parser.add_argument(
|
||||||
"-e",
|
"-e",
|
||||||
"--disable_enums",
|
"--disable_enums",
|
||||||
@ -141,10 +134,6 @@ class CliArguments():
|
|||||||
config['list_args'].append('Use Real Tabs : {}'.format(config['real_tabs']))
|
config['list_args'].append('Use Real Tabs : {}'.format(config['real_tabs']))
|
||||||
config['list_args'].append('Tab Width : {}'.format(config['tab_width']))
|
config['list_args'].append('Tab Width : {}'.format(config['tab_width']))
|
||||||
|
|
||||||
# Sanity check related
|
|
||||||
config['disable_sanity'] = args.disable_sanity
|
|
||||||
config['list_args'].append('Sanity Disabled : {}'.format(config['disable_sanity']))
|
|
||||||
|
|
||||||
# Set enums
|
# Set enums
|
||||||
config['enums'] = not args.disable_enums
|
config['enums'] = not args.disable_enums
|
||||||
config['list_args'].append('Enums Enabled : {}'.format(config['enums']))
|
config['list_args'].append('Enums Enabled : {}'.format(config['enums']))
|
||||||
|
@ -39,6 +39,10 @@ class Component():
|
|||||||
# Save config
|
# Save config
|
||||||
self.config = config.copy()
|
self.config = config.copy()
|
||||||
|
|
||||||
|
# By default, registers and fields are not interrupt registers
|
||||||
|
self.intr = False
|
||||||
|
self.halt = False
|
||||||
|
|
||||||
# Create logger object
|
# Create logger object
|
||||||
self.create_logger("{}".format(self.full_path), config)
|
self.create_logger("{}".format(self.full_path), config)
|
||||||
self.logger.debug('Starting to process {} "{}"'.format(
|
self.logger.debug('Starting to process {} "{}"'.format(
|
||||||
@ -210,7 +214,9 @@ class Component():
|
|||||||
name.append(obj.name)
|
name.append(obj.name)
|
||||||
|
|
||||||
# This is a property. Check if the original field actually has this property
|
# This is a property. Check if the original field actually has this property
|
||||||
if not obj.node.get_property(obj.name):
|
if obj.name == "intr" or obj.name == "halt":
|
||||||
|
pass
|
||||||
|
elif not obj.node.get_property(obj.name):
|
||||||
self.logger.fatal("Reference to the property '{}' of instance '{}' found. "
|
self.logger.fatal("Reference to the property '{}' of instance '{}' found. "
|
||||||
"This instance does hold the reference property! Please "
|
"This instance does hold the reference property! Please "
|
||||||
"fix this if you want me to do my job properly."
|
"fix this if you want me to do my job properly."
|
||||||
|
@ -47,6 +47,7 @@ class Field(Component):
|
|||||||
if not self.config['external']:
|
if not self.config['external']:
|
||||||
self.__add_always_ff()
|
self.__add_always_ff()
|
||||||
self.__add_hw_access()
|
self.__add_hw_access()
|
||||||
|
self.__add_interrupt()
|
||||||
self.__add_combo()
|
self.__add_combo()
|
||||||
self.__add_swmod_swacc()
|
self.__add_swmod_swacc()
|
||||||
self.__add_counter()
|
self.__add_counter()
|
||||||
@ -685,6 +686,47 @@ class Field(Component):
|
|||||||
|
|
||||||
self.rtl_footer = [*self.rtl_footer, swmod_props, swacc_props]
|
self.rtl_footer = [*self.rtl_footer, swmod_props, swacc_props]
|
||||||
|
|
||||||
|
def __add_interrupt(self):
|
||||||
|
if self.obj.get_property('intr'):
|
||||||
|
self.intr = True
|
||||||
|
|
||||||
|
# Generate masked & enabled version of interrupt to be
|
||||||
|
# picked up by the register at the top level
|
||||||
|
if mask := self.obj.get_property('mask'):
|
||||||
|
self.itr_masked = ' && !'.join([
|
||||||
|
self.register_name,
|
||||||
|
self.get_signal_name(mask)
|
||||||
|
])
|
||||||
|
elif enable := self.obj.get_property('enable'):
|
||||||
|
self.itr_masked = ' && '.join([
|
||||||
|
self.register_name,
|
||||||
|
self.get_signal_name(enable)
|
||||||
|
])
|
||||||
|
else:
|
||||||
|
self.itr_masked = self.register_name
|
||||||
|
|
||||||
|
# Generate haltmasked & haltenabled version of interrupt to be
|
||||||
|
# picked up by the register at the top level
|
||||||
|
if haltmask := self.obj.get_property('haltmask'):
|
||||||
|
self.itr_haltmasked = ' && !'.join([
|
||||||
|
self.register_name,
|
||||||
|
self.get_signal_name(haltmask)
|
||||||
|
])
|
||||||
|
|
||||||
|
self.halt = True
|
||||||
|
elif haltenable := self.obj.get_property('haltenable'):
|
||||||
|
self.itr_haltmasked = ' && '.join([
|
||||||
|
self.register_name,
|
||||||
|
self.get_signal_name(haltenable)
|
||||||
|
])
|
||||||
|
|
||||||
|
self.halt = True
|
||||||
|
else:
|
||||||
|
self.itr_haltmasked = self.register_name
|
||||||
|
else:
|
||||||
|
self.itr_masked = False
|
||||||
|
self.itr_haltmasked = False
|
||||||
|
|
||||||
def __add_hw_access(self):
|
def __add_hw_access(self):
|
||||||
# Mutually exclusive. systemrdl-compiler performs check for this
|
# Mutually exclusive. systemrdl-compiler performs check for this
|
||||||
enable_mask_negl = ''
|
enable_mask_negl = ''
|
||||||
@ -1037,6 +1079,7 @@ class Field(Component):
|
|||||||
def __process_variables(self, obj: FieldNode, array_dimensions: list, glbl_settings: dict):
|
def __process_variables(self, obj: FieldNode, array_dimensions: list, glbl_settings: dict):
|
||||||
# Create full name
|
# Create full name
|
||||||
self.path_wo_field = '__'.join(self.path.split('.', -1)[0:-1])
|
self.path_wo_field = '__'.join(self.path.split('.', -1)[0:-1])
|
||||||
|
self.register_name = ''.join([self.path_underscored, '_q'])
|
||||||
|
|
||||||
self.path_underscored_vec = []
|
self.path_underscored_vec = []
|
||||||
self.path_wo_field_vec = []
|
self.path_wo_field_vec = []
|
||||||
@ -1153,3 +1196,11 @@ class Field(Component):
|
|||||||
|
|
||||||
|
|
||||||
# TODO: Counter & hw=r shouldn't work
|
# TODO: Counter & hw=r shouldn't work
|
||||||
|
|
||||||
|
# If hw=ro and the next property is set, throw a fatal
|
||||||
|
if self.obj.get_property('hw') == AccessType.r\
|
||||||
|
and self.obj.get_property('next'):
|
||||||
|
self.logger.error("Hardware property of field is set to read-only "\
|
||||||
|
"but simultanously, the next property is set. Since "\
|
||||||
|
"this would reflect wrong behavior in documentation, "\
|
||||||
|
"the next property is ignored.")
|
||||||
|
@ -42,7 +42,11 @@ class Register(Component):
|
|||||||
self.config,
|
self.config,
|
||||||
glbl_settings)
|
glbl_settings)
|
||||||
|
|
||||||
if not config['disable_sanity']:
|
# Get certain properties from field that apply to whole register
|
||||||
|
self.intr = self.intr or self.children[field_range].intr
|
||||||
|
self.halt = self.halt or self.children[field_range].halt
|
||||||
|
|
||||||
|
# Perform sanity check
|
||||||
self.children[field_range].sanity_checks()
|
self.children[field_range].sanity_checks()
|
||||||
|
|
||||||
def create_rtl(self):
|
def create_rtl(self):
|
||||||
@ -68,6 +72,9 @@ class Register(Component):
|
|||||||
|
|
||||||
# Fields will be added by get_rtl()
|
# Fields will be added by get_rtl()
|
||||||
|
|
||||||
|
# Add interrupt logic
|
||||||
|
self.__add_interrupts()
|
||||||
|
|
||||||
# Add assignment of read-wires
|
# Add assignment of read-wires
|
||||||
self.__add_sw_mux_assignments()
|
self.__add_sw_mux_assignments()
|
||||||
|
|
||||||
@ -95,6 +102,42 @@ class Register(Component):
|
|||||||
*self.rtl_header
|
*self.rtl_header
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def __add_interrupts(self):
|
||||||
|
|
||||||
|
# Semantics on the intr and halt property:
|
||||||
|
# a) The intr and halt register properties are outputs; they should only
|
||||||
|
# occur on the right-hand side of an assignment in SystemRDL.
|
||||||
|
# b) The intr property shall always be present on a intr register even if
|
||||||
|
# no mask or enables are specified.
|
||||||
|
# c) The halt property shall only be present if haltmask or haltenable is
|
||||||
|
# specified on at least one field in the register.
|
||||||
|
if self.intr:
|
||||||
|
self.rtl_footer.append(Register.templ_dict['interrupt_comment']['rtl'])
|
||||||
|
|
||||||
|
self.rtl_footer.append(
|
||||||
|
self.process_yaml(
|
||||||
|
Register.templ_dict['interrupt_intr'],
|
||||||
|
{'path': self.path_underscored,
|
||||||
|
'genvars': self.genvars_str,
|
||||||
|
'list': ') || ('.join([
|
||||||
|
x.itr_masked for x in self.children.values() if x.itr_masked])
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.halt:
|
||||||
|
self.rtl_footer.append(
|
||||||
|
self.process_yaml(
|
||||||
|
Register.templ_dict['interrupt_halt'],
|
||||||
|
{'path': self.path_underscored,
|
||||||
|
'genvars': self.genvars_str,
|
||||||
|
'list': ') || ('.join([
|
||||||
|
x.itr_haltmasked for x in self.children.values() if x.itr_haltmasked])
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def __add_sw_mux_assignments(self):
|
def __add_sw_mux_assignments(self):
|
||||||
accesswidth = self.obj.get_property('accesswidth') - 1
|
accesswidth = self.obj.get_property('accesswidth') - 1
|
||||||
self.rtl_footer.append("")
|
self.rtl_footer.append("")
|
||||||
@ -383,9 +426,6 @@ class Register(Component):
|
|||||||
(self.create_underscored_path_static(obj)[3], obj.absolute_address)
|
(self.create_underscored_path_static(obj)[3], obj.absolute_address)
|
||||||
]
|
]
|
||||||
|
|
||||||
# Create full name
|
|
||||||
self.create_underscored_path()
|
|
||||||
|
|
||||||
# Gnerate already started?
|
# Gnerate already started?
|
||||||
self.generate_active = glbl_settings['generate_active']
|
self.generate_active = glbl_settings['generate_active']
|
||||||
|
|
||||||
|
@ -54,7 +54,9 @@ hw_access_we_wel:
|
|||||||
signal_type: 'logic'
|
signal_type: 'logic'
|
||||||
hw_access_no_we_wel:
|
hw_access_no_we_wel:
|
||||||
rtl: |-
|
rtl: |-
|
||||||
|
<<INDENT>>
|
||||||
// we or wel property not set
|
// we or wel property not set
|
||||||
|
<<UNINDENT>>
|
||||||
hw_access_hwset:
|
hw_access_hwset:
|
||||||
rtl: |-
|
rtl: |-
|
||||||
if ({path}_hwset{genvars})
|
if ({path}_hwset{genvars})
|
||||||
|
@ -122,3 +122,23 @@ external_err_condition:
|
|||||||
signal_type: 'logic'
|
signal_type: 'logic'
|
||||||
- name: '{path}_ext_{rd_or_wr}_ack'
|
- name: '{path}_ext_{rd_or_wr}_ack'
|
||||||
signal_type: 'logic'
|
signal_type: 'logic'
|
||||||
|
interrupt_comment:
|
||||||
|
rtl: |-
|
||||||
|
/**************************************
|
||||||
|
* Register contains interrupts *
|
||||||
|
**************************************/
|
||||||
|
interrupt_intr:
|
||||||
|
rtl: |-
|
||||||
|
// Register has at least one interrupt field
|
||||||
|
assign {path}_intr{genvars} = ({list});
|
||||||
|
output_ports:
|
||||||
|
- name: '{path}_intr'
|
||||||
|
signal_type: 'logic'
|
||||||
|
interrupt_halt:
|
||||||
|
rtl: |-
|
||||||
|
|
||||||
|
// Register has at least one interrupt field with halt property set
|
||||||
|
assign {path}_halt{genvars} = {list};
|
||||||
|
output_ports:
|
||||||
|
- name: '{path}_halt'
|
||||||
|
signal_type: 'logic'
|
||||||
|
Loading…
Reference in New Issue
Block a user