Change way the order of RTL is determined

By using a dictionary, it will be easier to mix & match the RTL
order dependend on the properties of the field.

This commit also adds anded/ored/xored properties.
This commit is contained in:
Dennis Potter 2021-05-04 00:23:14 +02:00
parent 861a020aff
commit f1d9ba2656
Signed by: Dennis
GPG Key ID: 186A8AD440942BAF
2 changed files with 93 additions and 35 deletions

View File

@ -1,10 +1,10 @@
import yaml
import math import math
import yaml
from systemrdl import RDLCompiler, RDLCompileError, RDLWalker, RDLListener, node from systemrdl import RDLCompiler, RDLCompileError, RDLWalker, RDLListener, node
from systemrdl.node import FieldNode from systemrdl.node import FieldNode
from systemrdl.rdltypes import PrecedenceType, AccessType from systemrdl.rdltypes import PrecedenceType, AccessType
from itertools import chain
TAB = " " TAB = " "
@ -18,6 +18,10 @@ class Field:
self.rtl = [] self.rtl = []
self.bytes = math.ceil(obj.width / 8) self.bytes = math.ceil(obj.width / 8)
# Make a list of I/O that shall be added to the addrmap
self.input_ports = []
self.output_ports = []
################################################################################## ##################################################################################
# LIMITATION: # LIMITATION:
# v1.x of the systemrdl-compiler does not support non-homogeneous arrays. # v1.x of the systemrdl-compiler does not support non-homogeneous arrays.
@ -43,7 +47,6 @@ class Field:
rst_negl = "" rst_negl = ""
rst_active = "active_high" rst_active = "active_high"
print(obj.get_property('reset'))
# Value of reset? # Value of reset?
rst_value = '\'x' if obj.get_property("reset") == None else obj.get_property('reset') rst_value = '\'x' if obj.get_property("reset") == None else obj.get_property('reset')
except: except:
@ -104,12 +107,23 @@ class Field:
indent_lvl += 1 indent_lvl += 1
# Define hardware access (if applicable) # Not all access types are required and the order might differ
hw_access_rtl = [] # 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([])
if hw_access == AccessType.rw or hw_access == AccessType.w: # Define hardware access (if applicable)
access_rtl['hw_write'] = []
if hw_access in (AccessType.rw, AccessType.w):
if obj.get_property('we') or obj.get_property('wel'): if obj.get_property('we') or obj.get_property('wel'):
hw_access_rtl.append( access_rtl['hw_write'].append(
Field.templ_dict['hw_access_we_wel'].format( Field.templ_dict['hw_access_we_wel'].format(
negl = '!' if obj.get_property('wel') else '', negl = '!' if obj.get_property('wel') else '',
reg_name = obj.parent.inst_name, reg_name = obj.parent.inst_name,
@ -117,7 +131,7 @@ class Field:
genvars = genvars_str, genvars = genvars_str,
indent = self.indent(indent_lvl))) indent = self.indent(indent_lvl)))
hw_access_rtl.append( access_rtl['hw_write'].append(
Field.templ_dict['hw_access_field'].format( Field.templ_dict['hw_access_field'].format(
reg_name = obj.parent.inst_name, reg_name = obj.parent.inst_name,
field_name = obj.inst_name, field_name = obj.inst_name,
@ -125,45 +139,52 @@ class Field:
indent = self.indent(indent_lvl))) indent = self.indent(indent_lvl)))
# Define software access (if applicable) # Define software access (if applicable)
sw_access_rtl = [] access_rtl['sw_write'] = []
# TODO: if sw_access_enabled if sw_access in (AccessType.rw, AccessType.w):
sw_access_rtl.append( access_rtl['sw_write'].append(
Field.templ_dict['sw_access_field'].format( Field.templ_dict['sw_access_field'].format(
reg_name = obj.parent.inst_name,
field_name = obj.inst_name,
genvars = genvars_str,
indent = self.indent(indent_lvl)))
indent_lvl += 1
# If field spans multiple bytes, every byte shall have a seperate enable!
for i in range(self.bytes):
sw_access_rtl.append(
Field.templ_dict['sw_access_byte'].format(
reg_name = obj.parent.inst_name, reg_name = obj.parent.inst_name,
field_name = obj.inst_name, field_name = obj.inst_name,
genvars = genvars_str, genvars = genvars_str,
i = i,
indent = self.indent(indent_lvl))) indent = self.indent(indent_lvl)))
sw_access_rtl.append("") indent_lvl += 1
indent_lvl -= 1 # If field spans multiple bytes, every byte shall have a seperate enable!
for i in range(self.bytes):
access_rtl['sw_write'].append(
Field.templ_dict['sw_access_byte'].format(
reg_name = obj.parent.inst_name,
field_name = obj.inst_name,
genvars = genvars_str,
i = i,
indent = self.indent(indent_lvl)))
sw_access_rtl.append("{}end".format(self.indent(indent_lvl))) indent_lvl -= 1
access_rtl['sw_write'].append("{}end".format(self.indent(indent_lvl)))
# Define else with correct indentation and add to dictionary
access_rtl['else'] = ["{}else".format(self.indent(indent_lvl))]
# Add empty string
access_rtl[''] = ['']
# Check if hardware has precedence (default `precedence = sw`) # Check if hardware has precedence (default `precedence = sw`)
if precedence == 'PrecedenceType.sw': if precedence == 'PrecedenceType.sw':
self.rtl = [*self.rtl, rtl_order = ['sw_write',
*sw_access_rtl, 'else' if len(access_rtl['hw_write']) > 0 else '',
'{}else'.format(self.indent(indent_lvl)), 'hw_write']
*hw_access_rtl]
else: else:
self.rtl = [*self.rtl, rtl_order = ['hw_write',
*sw_access_rtl, 'else' if len(access_rtl['sw_write']) > 0 else '',
'{}else'.format(self.indent(indent_lvl)), 'sw_write']
*hw_access_rtl]
# Add dictionary to main RTL list in correct order
self.rtl = [
*self.rtl,
*chain.from_iterable([access_rtl[i] for i in rtl_order])]
indent_lvl -= 1 indent_lvl -= 1
@ -173,6 +194,36 @@ class Field:
field_name = obj.inst_name, field_name = obj.inst_name,
indent = self.indent(indent_lvl))) indent = self.indent(indent_lvl)))
#####################
# Add combo logic
#####################
operations = []
if obj.get_property('anded'):
operations.append(['anded', '&'])
if obj.get_property('ored'):
operations.append(['ored', '|'])
if obj.get_property('xored'):
operations.append(['xored', '^'])
if len(operations) > 0:
self.rtl.append(
Field.templ_dict['combo_operation_comment'].format(
reg_name = obj.parent.inst_name,
field_name = obj.inst_name,
indent = self.indent(indent_lvl)))
self.rtl = [
*self.rtl,
*[Field.templ_dict['assign_combo_operation'].format(
field_name = obj.inst_name,
reg_name = obj.parent.inst_name,
genvars = genvars_str,
op_name = i[0],
op_verilog = i[1],
indent = self.indent(indent_lvl)) for i in operations]]
# TODO: Set sanity checks. For example, having no we but precedence = hw
# will cause weird behavior.
@staticmethod @staticmethod

View File

@ -13,6 +13,7 @@ sw_access_field: |-
sw_access_byte: |- sw_access_byte: |-
{indent}if (byte_enable[{i}]) {indent}if (byte_enable[{i}])
{indent} {reg_name}_{field_name}_q{genvars}[8*({i}+1)-1 -: 8] <= sw_wr_bus[8*({i}+1)-1 -: 8]; {indent} {reg_name}_{field_name}_q{genvars}[8*({i}+1)-1 -: 8] <= sw_wr_bus[8*({i}+1)-1 -: 8];
hw_access_we_wel: |- hw_access_we_wel: |-
{indent}if ({negl}{reg_name}_{field_name}_hw_wr{genvars}) {indent}if ({negl}{reg_name}_{field_name}_hw_wr{genvars})
hw_access_field: |- hw_access_field: |-
@ -29,3 +30,9 @@ field_comment: |-
{indent}// sw = {sw_access} {sw_precedence} {indent}// sw = {sw_access} {sw_precedence}
{indent}// reset : {rst_active} / {rst_type} {indent}// reset : {rst_active} / {rst_type}
{indent}//----------------------------------------------- {indent}//-----------------------------------------------
combo_operation_comment: |-
{indent}// Combinational logic for {reg_name}_{field_name}
assign_combo_operation: |-
{indent}assign {reg_name}_{field_name}_{op_name}{genvars} = {op_verilog}{reg_name}_{field_name}_q{genvars}