From 9f4d8a0aee4ccb060a0de9bac3e7d42fb0dc9871 Mon Sep 17 00:00:00 2001 From: Alex Mykyta Date: Thu, 12 Jul 2018 07:43:39 -0700 Subject: [PATCH] address/field collisison validation --- .coveragerc | 7 +- docs/implementation_notes/semantic_checks.ods | Bin 34085 -> 34086 bytes systemrdl/compiler.py | 2 +- systemrdl/component.py | 9 +- systemrdl/core/ComponentVisitor.py | 12 +- systemrdl/core/ExprVisitor.py | 4 +- systemrdl/core/expressions.py | 20 ++-- systemrdl/core/namespace.py | 2 +- systemrdl/core/validate.py | 113 ++++++++++++++---- systemrdl/node.py | 80 +++++++++++-- 10 files changed, 193 insertions(+), 56 deletions(-) diff --git a/.coveragerc b/.coveragerc index 0364c91..4d709f2 100644 --- a/.coveragerc +++ b/.coveragerc @@ -13,4 +13,9 @@ omit = ./examples/* # Omit Antlr-generated parser templates - ./systemrdl/parser/* \ No newline at end of file + ./systemrdl/parser/* + +[report] +exclude_lines = + raise RuntimeError + raise NotImplementedError diff --git a/docs/implementation_notes/semantic_checks.ods b/docs/implementation_notes/semantic_checks.ods index 0f63b86ec3179ef086b2b1ad60ffb2c153432b55..9b02c8be90f6a1e3226c9ddb07ca954a7f2646b6 100644 GIT binary patch delta 9690 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 U;slaZ0NfaVHQC1b26WI|O$R95lGQJ74ad`R1Lu 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 diff --git a/systemrdl/compiler.py b/systemrdl/compiler.py index 9a29f2a..9559774 100644 --- a/systemrdl/compiler.py +++ b/systemrdl/compiler.py @@ -191,7 +191,7 @@ def elaborate(self, top_def_name=None, inst_name=None, parameters=None): ) # Validate design - walker.RDLWalker().walk(root_node, ValidateListener(self)) + walker.RDLWalker(skip_not_present=False).walk(root_node, ValidateListener(self)) if self.msg.error_count: self.msg.fatal("Elaborate aborted due to previous errors") diff --git a/systemrdl/component.py b/systemrdl/component.py index 0c6eb05..d9e05a6 100644 --- a/systemrdl/component.py +++ b/systemrdl/component.py @@ -19,7 +19,14 @@ def __init__(self): #: instance's parameter values. self.type_name = None - # Child elements instantiated inside this component + #: Child elements instantiated inside this component + #: + #: Child components are sorted as follows: + #: + #: - Signals first + #: - All other components follow. + #: - AddressableComponents are sorted by ascending base_addr + #: - Fields are sorted by ascending low bit self.children = [] # Parameters of this component definition. diff --git a/systemrdl/core/ComponentVisitor.py b/systemrdl/core/ComponentVisitor.py index b4fc8e6..56cd740 100644 --- a/systemrdl/core/ComponentVisitor.py +++ b/systemrdl/core/ComponentVisitor.py @@ -82,7 +82,7 @@ def visitComponent_def(self, ctx:SystemRDLParser.Component_defContext): elif ctx.component_named_def() is not None: comp_def = self.visit(ctx.component_named_def()) else: - raise RuntimeError # pragma: no cover + raise RuntimeError if ctx.component_insts() is not None: # Component is instantiated one or more times @@ -149,7 +149,7 @@ def define_component(self, body, type_token, def_name, param_defs): if subclass.comp_type == self._CompType_Map[type_token.type]: visitor = subclass(self.compiler, def_name, param_defs) return visitor.visit(body) - raise RuntimeError # pragma: no cover + raise RuntimeError #--------------------------------------------------------------------------- # Component Instantiation @@ -403,7 +403,7 @@ def visitComponent_inst(self, ctx:SystemRDLParser.Component_instContext): comp_inst.array_dimensions = array_suffixes comp_inst.array_stride = inst_addr_stride else: - raise RuntimeError # pragma: no cover + raise RuntimeError if inst_type == SystemRDLParser.EXTERNAL_kw: comp_inst.external = True @@ -415,7 +415,7 @@ def visitComponent_inst(self, ctx:SystemRDLParser.Component_instContext): comp_inst.is_alias = True comp_inst.alias_primary_inst = alias_primary_inst else: - raise RuntimeError # pragma: no cover + raise RuntimeError self.component.children.append(comp_inst) @@ -533,7 +533,7 @@ def visitLocal_property_assignment(self, ctx:SystemRDLParser.Local_property_assi rhs = rdltypes.InterruptType[prop_mod] else: - raise RuntimeError # pragma: no cover + raise RuntimeError if default: self.compiler.namespace.register_default_property(prop_name, (prop_token, rhs), prop_token) @@ -559,7 +559,7 @@ def visitDynamic_property_assignment(self, ctx:SystemRDLParser.Dynamic_property_ elif ctx.encode_prop_assign() is not None: prop_token, prop_name, rhs = self.visit(ctx.encode_prop_assign()) else: - raise RuntimeError # pragma: no cover + raise RuntimeError # Lookup component instance being assigned target_inst = self.component diff --git a/systemrdl/core/ExprVisitor.py b/systemrdl/core/ExprVisitor.py index 2c5beb1..88d88a4 100644 --- a/systemrdl/core/ExprVisitor.py +++ b/systemrdl/core/ExprVisitor.py @@ -243,7 +243,7 @@ def visitCastType(self, ctx:SystemRDLParser.CastTypeContext): elif ctx.typ.type == SystemRDLParser.BOOLEAN_kw: return e.BoolCast(self.compiler, ctx.op, self.visit(ctx.expr())) else: - raise RuntimeError # pragma: no cover + raise RuntimeError # Visit a parse tree produced by SystemRDLParser#CastWidth. def visitCastWidth(self, ctx:SystemRDLParser.CastWidthContext): @@ -294,7 +294,7 @@ def visitInstance_ref(self, ctx:SystemRDLParser.Instance_refContext): ref_elements=ref_elements ) else: - raise RuntimeError # pragma: no cover + raise RuntimeError return ref_expr diff --git a/systemrdl/core/expressions.py b/systemrdl/core/expressions.py index 7c719b0..53a4b29 100644 --- a/systemrdl/core/expressions.py +++ b/systemrdl/core/expressions.py @@ -33,7 +33,7 @@ def predict_type(self): even if the child type is not relevant to the resulting type. Raises exception if input types are not compatible. """ - raise NotImplementedError # pragma: no cover + raise NotImplementedError def get_min_eval_width(self): """ @@ -41,7 +41,7 @@ def get_min_eval_width(self): self-determined expression bit-width rules (SystemVerilog LRM: IEEE Std 1800-2012, Table 11-21) """ - raise RuntimeError # pragma: no cover + raise RuntimeError def get_value(self, eval_width=None): """ @@ -61,7 +61,7 @@ def get_value(self, eval_width=None): - If eval_width is set to a value: Parent expression is propagating the eval_width """ - raise NotImplementedError # pragma: no cover + raise NotImplementedError #------------------------------------------------------------------------------- class IntLiteral(Expr): @@ -194,7 +194,7 @@ def get_min_eval_width(self): return width else: - raise RuntimeError # pragma: no cover + raise RuntimeError def get_value(self, eval_width=None): if self.type == int: @@ -212,7 +212,7 @@ def get_value(self, eval_width=None): return result else: - raise RuntimeError # pragma: no cover + raise RuntimeError #------------------------------------------------------------------------------- class Replicate(Expr): @@ -242,7 +242,7 @@ def predict_type(self): else: # All replications contain a nested concatenation # Type check for invalid type is already halded there - raise RuntimeError # pragma: no cover + raise RuntimeError def get_min_eval_width(self): # Evaluate number of repetitions @@ -255,7 +255,7 @@ def get_min_eval_width(self): width *= self.reps_value return width else: - raise RuntimeError # pragma: no cover + raise RuntimeError def get_value(self, eval_width=None): # Evaluate number of repetitions @@ -279,7 +279,7 @@ def get_value(self, eval_width=None): return result else: - raise RuntimeError # pragma: no cover + raise RuntimeError #------------------------------------------------------------------------------- # Integer binary operators: @@ -488,7 +488,7 @@ def get_ops(self): l = self.l.get_value() r = self.r.get_value() else: - raise RuntimeError # pragma: no cover + raise RuntimeError return l,r @@ -777,7 +777,7 @@ def get_value(self, eval_width=None): j = self.j.get_value() k = self.k.get_value() else: - raise RuntimeError # pragma: no cover + raise RuntimeError if i: return j diff --git a/systemrdl/core/namespace.py b/systemrdl/core/namespace.py index b5dfcc7..81082df 100644 --- a/systemrdl/core/namespace.py +++ b/systemrdl/core/namespace.py @@ -54,7 +54,7 @@ def lookup_element(self, name:str): return (el, parent_def) else: return (None, None) - return None + return (None, None) def get_default_properties(self, comp_type): """ diff --git a/systemrdl/core/validate.py b/systemrdl/core/validate.py index 85e491a..59b96c2 100644 --- a/systemrdl/core/validate.py +++ b/systemrdl/core/validate.py @@ -1,6 +1,7 @@ from .. import walker from .. import rdltypes +from ..node import RegNode #=============================================================================== # Validation Listeners @@ -12,8 +13,15 @@ def __init__(self, compiler): self.msg = compiler.msg # Used in field overlap checks - self.prev_field = None + # This is a rolling buffer of previous fields that still have a chance + # to possibly collide with a future field + self.field_check_buffer = [] + # Used in addrmap, regfile, and reg overlap checks + # Same concept as the field check buffer, but is also a stack + self.addr_check_buffer_stack = [[]] + + def enter_Component(self, node): # Validate all properties that were applied to the component @@ -21,18 +29,65 @@ def enter_Component(self, node): prop_value = node.get_property(prop_name) prop_rule = self.compiler.property_rules.lookup_property(prop_name) prop_rule.validate(node, prop_value) + + + def enter_AddressableComponent(self, node): + addr_check_buffer = self.addr_check_buffer_stack[-1] + self.addr_check_buffer_stack.append([]) - def enter_Reg(self, node): - self.prev_field = None + # Check for collision with previous addressable sibling + new_addr_check_buffer = [] + for prev_addressable in addr_check_buffer: + if (prev_addressable.inst.addr_offset + prev_addressable.total_size) > node.inst.addr_offset: + # Overlaps! + + # Only allowable overlaps are as follows: + # 10.1-h: Registers shall not overlap, unless one contains only + # read-only fields and the other contains only write-only or + # write-once-only fields. + overlap_allowed = False + if isinstance(prev_addressable, RegNode) and isinstance(node, RegNode): + if ((not prev_addressable.has_sw_writable) and (not node.has_sw_readable) + or (not prev_addressable.has_sw_readable) and (not node.has_sw_writable) + ): + overlap_allowed = True + + if not overlap_allowed: + self.msg.error( + "Instance '%s' at offset +0x%X:0x%X overlaps with '%s' at offset +0x%X:0x%X" + % ( + node.inst.inst_name, node.inst.addr_offset, node.inst.addr_offset + node.total_size - 1, + prev_addressable.inst.inst_name, prev_addressable.inst.addr_offset, prev_addressable.inst.addr_offset + prev_addressable.total_size - 1, + ), + node.inst.inst_err_ctx + ) + + # Keep it in the list since it could collide again + new_addr_check_buffer.append(prev_addressable) + self.addr_check_buffer_stack[-2] = new_addr_check_buffer + + def exit_AddressableComponent(self, node): + self.addr_check_buffer_stack.pop() + self.addr_check_buffer_stack[-1].append(node) + + + def enter_Reg(self, node): + self.field_check_buffer = [] + + def exit_Reg(self, node): # 10.1-c: At least one field shall be instantiated within a register - if self.prev_field is None: + # + # At the end of field overlap checking, at least one entry is guaranteed to + # be left over in the field_check_buffer + if not self.field_check_buffer: self.msg.error( "Register '%s' does not contain any fields" % node.inst.inst_name, node.inst.inst_err_ctx ) - + + def enter_Field(self, node): this_f_hw = node.get_property('hw') this_f_sw = node.get_property('sw') @@ -80,23 +135,35 @@ def enter_Field(self, node): # 10.1-d: Two field instances shall not occupy overlapping bit positions # within a register unless one field is read-only and the other field # is write-only. - if (self.prev_field is not None) and (self.prev_field.inst.high >= node.inst.low): - prev_f_sw = self.prev_field.get_property('sw') - - if((prev_f_sw == rdltypes.AccessType.r) - and ((this_f_sw == rdltypes.AccessType.w) or this_f_sw == rdltypes.AccessType.w1) - ): - pass - elif((this_f_sw == rdltypes.AccessType.r) - and ((prev_f_sw == rdltypes.AccessType.w) or prev_f_sw == rdltypes.AccessType.w1) - ): - pass - else: - self.msg.error( - "Field '%s' overlaps with field '%s'" - % (node.inst.inst_name, self.prev_field.inst.inst_name), - node.inst.inst_err_ctx - ) + # + # Scan through a copied list of the field_check_buffer for collisions + # If an entry no longer collides with the current node, it can be removed + # from the list since fields are sorted. + new_field_check_buffer = [] + for prev_field in self.field_check_buffer: + if prev_field.inst.high >= node.inst.low: + # Found overlap! + # Check if the overlap is allowed + prev_f_sw = prev_field.get_property('sw') + + if((prev_f_sw == rdltypes.AccessType.r) + and ((this_f_sw == rdltypes.AccessType.w) or this_f_sw == rdltypes.AccessType.w1) + ): + pass + elif((this_f_sw == rdltypes.AccessType.r) + and ((prev_f_sw == rdltypes.AccessType.w) or prev_f_sw == rdltypes.AccessType.w1) + ): + pass + else: + self.msg.error( + "Field '%s[%d:%d]' overlaps with field '%s[%d:%d]'" + % (node.inst.inst_name, node.inst.msb, node.inst.lsb, + prev_field.inst.inst_name, prev_field.inst.msb, prev_field.inst.lsb), + node.inst.inst_err_ctx + ) + # Keep it in the list since it could collide again + new_field_check_buffer.append(prev_field) + self.new_field_check_buffer = new_field_check_buffer # 10.1-e: Field instances shall not occupy a bit position exceeding the @@ -110,4 +177,4 @@ def enter_Field(self, node): def exit_Field(self, node): - self.prev_field = node + self.field_check_buffer.append(node) diff --git a/systemrdl/node.py b/systemrdl/node.py index e6ad35f..84e0028 100644 --- a/systemrdl/node.py +++ b/systemrdl/node.py @@ -104,6 +104,26 @@ def children(self, unroll=False, skip_not_present=True): yield Node._factory(child_inst, self.compiler, self) + def signals(self, skip_not_present=True): + """ + Returns an iterator that provides nodes for all immediate signals of + this component. + + Parameters + ---------- + skip_not_present : bool + If True, skips fields whose 'ispresent' property is set to False + + Yields + ------ + :class:`~FieldNode` + All signals in this component + """ + for child in self.children(skip_not_present=skip_not_present): + if isinstance(child, SignalNode): + yield child + + def get_child_by_name(self, inst_name): """ Returns an immediate child :class:`~Node` whose instance name matches ``inst_name`` @@ -396,8 +416,11 @@ def is_volatile(self): should be interpreted as volatile. (Any hardware-writable field is inherently volatile) """ - # TODO: Implement is_volatile getter - raise NotImplementedError + + # TODO: There are way more conditions that make a field volatile (counters, next, ...) + hw = self.get_property('hw') + return hw in (rdltypes.AccessType.rw, rdltypes.AccessType.rw1, + rdltypes.AccessType.w, rdltypes.AccessType.w1) @property def is_sw_writable(self): @@ -406,11 +429,8 @@ def is_sw_writable(self): """ sw = self.get_property('sw') - return (sw == rdltypes.AccessType.rw - or sw == rdltypes.AccessType.rw1 - or sw == rdltypes.AccessType.w - or sw == rdltypes.AccessType.w1 - ) + return sw in (rdltypes.AccessType.rw, rdltypes.AccessType.rw1, + rdltypes.AccessType.w, rdltypes.AccessType.w1) @property def is_sw_readable(self): @@ -419,10 +439,8 @@ def is_sw_readable(self): """ sw = self.get_property('sw') - return (sw == rdltypes.AccessType.rw - or sw == rdltypes.AccessType.rw1 - or sw == rdltypes.AccessType.r - ) + return sw in (rdltypes.AccessType.rw, rdltypes.AccessType.rw1, + rdltypes.AccessType.r) @property def implements_storage(self): @@ -446,6 +464,26 @@ def implements_storage(self): #=============================================================================== class RegNode(AddressableNode): + def fields(self, skip_not_present=True): + """ + Returns an iterator that provides nodes for all fields of + this register. + + Parameters + ---------- + skip_not_present : bool + If True, skips fields whose 'ispresent' property is set to False + + Yields + ------ + :class:`~FieldNode` + All fields in this register + """ + for child in self.children(skip_not_present=skip_not_present): + if isinstance(child, FieldNode): + yield child + + @property def size(self): return self.get_property('regwidth') // 8 @@ -459,6 +497,26 @@ def is_virtual(self): # since mem components can only contain reg instances, a reg can only be # virtual if its direct parent is of type mem return isinstance(self.parent, MemNode) + + @property + def has_sw_writable(self): + """ + Register contains one or more present fields writable by software + """ + for field in self.fields(): + if field.is_sw_writable: + return True + return False + + @property + def has_sw_readable(self): + """ + Register contains one or more present fields readable by software + """ + for field in self.fields(): + if field.is_sw_readable: + return True + return False #=============================================================================== class RegfileNode(AddressableNode):