From 92d61dd7c87493327aa9add1cd3f40a8463375ea Mon Sep 17 00:00:00 2001 From: Dennis Date: Sun, 16 May 2021 12:49:17 +0200 Subject: [PATCH] Add onread/onwrite properties to field class This commit also created a seperate private method for access related RTL and for the always_ff header. Furthermore, a bug which caused the singlepulse property to always show up was resolved. Lastly, the summary method was made truely public. So, rather than writing to the RTL list, it now returns a list and the calling method/function can decide what to do with that list. --- srdl2sv/components/field.py | 311 ++++++++++++++--------- srdl2sv/components/templates/fields.yaml | 48 +++- 2 files changed, 233 insertions(+), 126 deletions(-) diff --git a/srdl2sv/components/field.py b/srdl2sv/components/field.py index c574e29..1b0c975 100644 --- a/srdl2sv/components/field.py +++ b/srdl2sv/components/field.py @@ -4,10 +4,9 @@ import yaml from systemrdl import RDLCompiler, RDLCompileError, RDLWalker, RDLListener, node from systemrdl.node import FieldNode -from systemrdl.rdltypes import PrecedenceType, AccessType +from systemrdl.rdltypes import PrecedenceType, AccessType, OnReadType, OnWriteType # Local modules -from log.log import create_logger from components.component import Component, Port from . import templates @@ -34,126 +33,11 @@ class Field(Component): # can be found here: https://github.com/SystemRDL/systemrdl-compiler/issues/51 ################################################################################## # Print a summary - self.summary() - - # Handle always_ff - sense_list = 'sense_list_rst' if self.rst['async'] else 'sense_list_no_rst' - - self.rtl_header.append( - Field.templ_dict[sense_list].format( - clk_name = "clk", - rst_edge = self.rst['edge'], - rst_name = self.rst['name'])) - - # Add actual reset line - if self.rst['name']: - self.rtl_header.append( - Field.templ_dict['rst_field_assign'].format( - path = self.path_underscored, - rst_name = self.rst['name'], - rst_negl = "!" if self.rst['active'] == "active_high" else "", - rst_value = self.rst['value'], - genvars = self.genvars_str)) - - self.rtl_header.append("begin") - - # Not all access types are required and the order might differ - # depending on what types are defined and what precedence is - # set. Therefore, first add all RTL into a dictionary and - # later place it in the right order. - # - # The following RTL blocks are defined: - # - hw_write --> write access for the hardware interface - # - sw_write --> write access for the software interface - # - access_rtl = dict([]) - - # Define hardware access (if applicable) - access_rtl['hw_write'] = [] - - if self.hw_access in (AccessType.rw, AccessType.w): - if self.we_or_wel: - access_rtl['hw_write'].append( - Field.templ_dict['hw_access_we_wel'].format( - negl = '!' if obj.get_property('wel') else '', - path = self.path_underscored, - genvars = self.genvars_str)) - else: - access_rtl['hw_write'].append( - Field.templ_dict['hw_access_no_we_wel']) - - access_rtl['hw_write'].append( - Field.templ_dict['hw_access_field'].format( - path = self.path_underscored, - genvars = self.genvars_str)) - - # Define software access (if applicable) - access_rtl['sw_write'] = [] - - if self.sw_access in (AccessType.rw, AccessType.w): - access_rtl['sw_write'].append( - Field.templ_dict['sw_access_field'].format( - path_wo_field = self.path_wo_field, - genvars = self.genvars_str)) - - # If field spans multiple bytes, every byte shall have a seperate enable! - for j, i in enumerate(range(self.lsbyte, self.msbyte+1)): - access_rtl['sw_write'].append( - Field.templ_dict['sw_access_byte'].format( - path = self.path_underscored, - genvars = self.genvars_str, - i = i, - msb_bus = str(8*(i+1)-1 if i != self.msbyte else self.obj.msb), - bus_w = str(8 if i != self.msbyte else self.obj.width-(8*j)), - msb_field = str(8*(j+1)-1 if i != self.msbyte else self.obj.width-1), - field_w = str(8 if i != self.msbyte else self.obj.width-(8*j)))) - - access_rtl['sw_write'].append("end") - - # Add singlepulse property - access_rtl['singlepulse'] = [ - Field.templ_dict['singlepulse'].format( - path = self.path_underscored, - genvars = self.genvars_str) - ] - - # Define else - access_rtl['else'] = ["else"] - - # Add empty string - access_rtl[''] = [''] - - # Check if hardware has precedence (default `precedence = sw`) - if self.precedence == 'PrecedenceType.sw': - order_list = ['sw_write', - 'hw_write', - 'singlepulse'] - else: - order_list = ['hw_write', - 'sw_write', - 'singlepulse'] - - # Add appropriate else - order_list_rtl = [] - - for i in order_list: - # Still a loop and not a list comprehension since this might - # get longer in the future and thus become unreadable - if len(access_rtl[i]) > 0: - order_list_rtl = [*order_list_rtl, *access_rtl[i]] - order_list_rtl.append("else") - - # Remove last pop - order_list_rtl.pop() - - # Chain access RTL to the rest of the RTL - self.rtl_header = [*self.rtl_header, *order_list_rtl] - - self.rtl_header.append( - Field.templ_dict['end_field_ff'].format( - path = self.path_underscored)) - + self.rtl_header.append(self.summary()) + # Generate RTL + self.__add_always_ff() + self.__add_access_rtl() self.__add_combo() self.__add_ports() @@ -217,7 +101,7 @@ class Field(Component): self.rst['name'] = rst_signal.inst_name self.rst['async'] = rst_signal.get_property("async") - self.rst['type'] = "asynchronous" if rst['async'] else "synchronous" + self.rst['type'] = "asynchronous" if self.rst['async'] else "synchronous" # Active low or active high? if rst_signal.get_property("activelow"): @@ -253,7 +137,7 @@ class Field(Component): misc_flags.discard('reset') # Add comment with summary on field's properties - self.rtl_header.append( + return \ Field.templ_dict['field_comment'].format( name = self.obj.inst_name, hw_access = str(self.hw_access)[11:], @@ -265,7 +149,179 @@ class Field(Component): misc_flags = misc_flags if misc_flags else '-', lsb = self.obj.lsb, msb = self.obj.msb, - path_wo_field = self.path_wo_field)) + path_wo_field = self.path_wo_field) + + def __add_always_ff(self): + # Handle always_ff + sense_list = 'sense_list_rst' if self.rst['async'] else 'sense_list_no_rst' + + self.rtl_header.append( + Field.templ_dict[sense_list].format( + clk_name = "clk", + rst_edge = self.rst['edge'], + rst_name = self.rst['name'])) + + # Add actual reset line + if self.rst['name']: + self.rtl_header.append( + Field.templ_dict['rst_field_assign'].format( + path = self.path_underscored, + rst_name = self.rst['name'], + rst_negl = "!" if self.rst['active'] == "active_high" else "", + rst_value = self.rst['value'], + genvars = self.genvars_str)) + + self.rtl_header.append("begin") + + def __add_access_rtl(self): + # Not all access types are required and the order might differ + # depending on what types are defined and what precedence is + # set. Therefore, first add all RTL into a dictionary and + # later place it in the right order. + # + # The following RTL blocks are defined: + # - hw_write --> write access for the hardware interface + # - sw_write --> write access for the software interface + # + access_rtl = dict([]) + + # Define hardware access (if applicable) + access_rtl['hw_write'] = [] + + if self.hw_access in (AccessType.rw, AccessType.w): + if self.we_or_wel: + access_rtl['hw_write'].append( + Field.templ_dict['hw_access_we_wel'].format( + negl = '!' if self.obj.get_property('wel') else '', + path = self.path_underscored, + genvars = self.genvars_str)) + else: + access_rtl['hw_write'].append( + Field.templ_dict['hw_access_no_we_wel']) + + access_rtl['hw_write'].append( + Field.templ_dict['hw_access_field'].format( + path = self.path_underscored, + genvars = self.genvars_str)) + + # Define software access (if applicable) + access_rtl['sw_write'] = [] + + if self.sw_access in (AccessType.rw, AccessType.w): + access_rtl['sw_write'].append( + Field.templ_dict['sw_access_field'].format( + path_wo_field = self.path_wo_field, + genvars = self.genvars_str)) + + # Check if an onwrite property is set + onwrite = self.obj.get_property('onwrite') + + if onwrite: + if onwrite == OnWriteType.wuser: + self.logger.warning("The OnReadType.wuser is not yet supported!") + elif onwrite in (OnWriteType.wclr, OnWriteType.wset): + access_rtl['sw_write'].append( + Field.templ_dict[str(onwrite)].format( + path = self.path_underscored, + genvars = self.genvars_str, + path_wo_field = self.path_wo_field + ) + ) + else: + # If field spans multiple bytes, every byte shall have a seperate enable! + for j, i in enumerate(range(self.lsbyte, self.msbyte+1)): + access_rtl['sw_write'].append( + Field.templ_dict[str(onwrite)].format( + path = self.path_underscored, + genvars = self.genvars_str, + i = i, + msb_bus = str(8*(i+1)-1 if i != self.msbyte else self.obj.msb), + bus_w = str(8 if i != self.msbyte else self.obj.width-(8*j)), + msb_field = str(8*(j+1)-1 if i != self.msbyte else self.obj.width-1), + field_w = str(8 if i != self.msbyte else self.obj.width-(8*j)))) + else: + # Normal write + # If field spans multiple bytes, every byte shall have a seperate enable! + for j, i in enumerate(range(self.lsbyte, self.msbyte+1)): + access_rtl['sw_write'].append( + Field.templ_dict['sw_access_byte'].format( + path = self.path_underscored, + genvars = self.genvars_str, + i = i, + msb_bus = str(8*(i+1)-1 if i != self.msbyte else self.obj.msb), + bus_w = str(8 if i != self.msbyte else self.obj.width-(8*j)), + msb_field = str(8*(j+1)-1 if i != self.msbyte else self.obj.width-1), + field_w = str(8 if i != self.msbyte else self.obj.width-(8*j)))) + + access_rtl['sw_write'].append("end") + + onread = self.obj.get_property('onread') + + access_rtl['sw_read'] = [] + if self.sw_access in (AccessType.rw, AccessType.r) and onread: + if onread == OnReadType.ruser: + self.logger.warning("The OnReadType.ruser is not yet supported!") + else: + access_rtl['sw_read'].append( + Field.templ_dict[str(onread)].format( + path = self.path_underscored, + genvars = self.genvars_str, + path_wo_field = self.path_wo_field + ) + ) + + # Add singlepulse property + if self.obj.get_property('singlepulse'): + access_rtl['singlepulse'] = [ + Field.templ_dict['singlepulse'].format( + path = self.path_underscored, + genvars = self.genvars_str) + ] + else: + access_rtl['singlepulse'] = [] + + # Define else + access_rtl['else'] = ["else"] + + # Add empty string + access_rtl[''] = [''] + + # Check if hardware has precedence (default `precedence = sw`) + if self.precedence == PrecedenceType.sw: + order_list = [ + 'sw_write', + 'sw_read', + 'hw_write', + 'singlepulse' + ] + else: + order_list = [ + 'hw_write', + 'sw_write', + 'sw_read', + 'singlepulse' + ] + + # Add appropriate else + order_list_rtl = [] + + for i in order_list: + # Still a loop and not a list comprehension since this might + # get longer in the future and thus become unreadable + if len(access_rtl[i]) > 0: + order_list_rtl = [*order_list_rtl, *access_rtl[i]] + order_list_rtl.append("else") + + # Remove last pop + order_list_rtl.pop() + + # Chain access RTL to the rest of the RTL + self.rtl_header = [*self.rtl_header, *order_list_rtl] + + self.rtl_header.append( + Field.templ_dict['end_field_ff'].format( + path = self.path_underscored)) + def __add_ports(self): # Port is writable by hardware --> Input port from hardware @@ -291,6 +347,13 @@ class Field(Component): self.dimensions )) + # Connect flops to output port + self.rtl_header.append( + Field.templ_dict['out_port_assign'].format( + genvars = self.genvars_str, + path = self.path_underscored)) + + def sanity_checks(self): # If hw=rw/sw=[r]w and hw has no we/wel, sw will never be able to write if not self.we_or_wel and\ diff --git a/srdl2sv/components/templates/fields.yaml b/srdl2sv/components/templates/fields.yaml index feda75a..32d1f4b 100644 --- a/srdl2sv/components/templates/fields.yaml +++ b/srdl2sv/components/templates/fields.yaml @@ -17,17 +17,57 @@ sw_access_byte: |- begin {path}_q{genvars}[{msb_field}-:{field_w}] <= sw_wr_bus[{msb_bus}-:{bus_w}]; end - + hw_access_we_wel: |- if ({negl}{path}_hw_wr{genvars}) hw_access_no_we_wel: |- - if (1) // we or wel property not set + // we or wel property not set hw_access_field: |- begin {path}_q{genvars} <= {path}_in{genvars}; end end_field_ff: |- end // of {path}'s always_ff +OnWriteType.woset: |- + if (byte_enable[{i}]) // woset property + begin + {path}_q{genvars}[{msb_field}-:{field_w}] <= {path}_q{genvars}[{msb_field}-:{field_w}] | sw_wr_bus[{msb_bus}-:{bus_w}]; + end +OnWriteType.woclr: |- + if (byte_enable[{i}]) // woclr property + begin + {path}_q{genvars}[{msb_field}-:{field_w}] <= {path}_q{genvars}[{msb_field}-:{field_w}] & ~sw_wr_bus[{msb_bus}-:{bus_w}]; + end +OnWriteType.wot: |- + if (byte_enable[{i}]) // wot property + begin + {path}_q{genvars}[{msb_field}-:{field_w}] <= {path}_q{genvars}[{msb_field}-:{field_w}] ^ sw_wr_bus[{msb_bus}-:{bus_w}]; + end +OnWriteType.wzs: |- + if (byte_enable[{i}]) // wzs property + begin + {path}_q{genvars}[{msb_field}-:{field_w}] <= {path}_q{genvars}[{msb_field}-:{field_w}] & sw_wr_bus[{msb_bus}-:{bus_w}]; + end +OnWriteType.wzt: |- + if (byte_enable[{i}]) // wzt property + begin + {path}_q{genvars}[{msb_field}-:{field_w}] <= {path}_q{genvars}[{msb_field}-:{field_w}] ~^ sw_wr_bus[{msb_bus}-:{bus_w}]; + end +OnWriteType.wclr: |- + {path}_q{genvars} <= {{width{{1'b0}}}}; +OnWriteType.wset: |- + {path}_q{genvars} <= {{width{{1'b1}}}}; +OnReadType.rclr: |- + if ({path_wo_field}_sw_rd{genvars}) // rclr property + begin + {path}_q{genvars} <= {{width{{1'b0}}}}; + end +OnReadType.rset: |- + if ({path_wo_field}_sw_rd{genvars}) // rset property + begin + {path}_q{genvars} <= {{width{{1'b1}}}}; + end + field_comment: |- //-----------------FIELD SUMMARY----------------- @@ -46,4 +86,8 @@ singlepulse: |- begin {path}{genvars} <= 0; end +out_port_assign: |- + + // Connect register to hardware output port + assign {path}_r{genvars} <= {path}_q{genvars};