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 yaml
from systemrdl import RDLCompiler, RDLCompileError, RDLWalker, RDLListener, node
from systemrdl.node import FieldNode
from systemrdl.rdltypes import PrecedenceType, AccessType
from itertools import chain
TAB = " "
@ -18,6 +18,10 @@ class Field:
self.rtl = []
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:
# v1.x of the systemrdl-compiler does not support non-homogeneous arrays.
@ -43,7 +47,6 @@ class Field:
rst_negl = ""
rst_active = "active_high"
print(obj.get_property('reset'))
# Value of reset?
rst_value = '\'x' if obj.get_property("reset") == None else obj.get_property('reset')
except:
@ -104,12 +107,23 @@ class Field:
indent_lvl += 1
# Define hardware access (if applicable)
hw_access_rtl = []
# 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([])
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'):
hw_access_rtl.append(
access_rtl['hw_write'].append(
Field.templ_dict['hw_access_we_wel'].format(
negl = '!' if obj.get_property('wel') else '',
reg_name = obj.parent.inst_name,
@ -117,7 +131,7 @@ class Field:
genvars = genvars_str,
indent = self.indent(indent_lvl)))
hw_access_rtl.append(
access_rtl['hw_write'].append(
Field.templ_dict['hw_access_field'].format(
reg_name = obj.parent.inst_name,
field_name = obj.inst_name,
@ -125,45 +139,52 @@ class Field:
indent = self.indent(indent_lvl)))
# Define software access (if applicable)
sw_access_rtl = []
access_rtl['sw_write'] = []
# TODO: if sw_access_enabled
sw_access_rtl.append(
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(
if sw_access in (AccessType.rw, AccessType.w):
access_rtl['sw_write'].append(
Field.templ_dict['sw_access_field'].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("")
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`)
if precedence == 'PrecedenceType.sw':
self.rtl = [*self.rtl,
*sw_access_rtl,
'{}else'.format(self.indent(indent_lvl)),
*hw_access_rtl]
rtl_order = ['sw_write',
'else' if len(access_rtl['hw_write']) > 0 else '',
'hw_write']
else:
self.rtl = [*self.rtl,
*sw_access_rtl,
'{}else'.format(self.indent(indent_lvl)),
*hw_access_rtl]
rtl_order = ['hw_write',
'else' if len(access_rtl['sw_write']) > 0 else '',
'sw_write']
# 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
@ -173,6 +194,36 @@ class Field:
field_name = obj.inst_name,
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

View File

@ -13,6 +13,7 @@ sw_access_field: |-
sw_access_byte: |-
{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];
hw_access_we_wel: |-
{indent}if ({negl}{reg_name}_{field_name}_hw_wr{genvars})
hw_access_field: |-
@ -29,3 +30,9 @@ field_comment: |-
{indent}// sw = {sw_access} {sw_precedence}
{indent}// reset : {rst_active} / {rst_type}
{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}