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};