def make_expect(self, i, action): if value_utils.is_any(action.value): return [] if isinstance(action.port, SelectPath): name = f"dut.{action.port.system_verilog_path}" debug_name = action.port[-1].name elif isinstance(action.port, fault.WrappedVerilogInternalPort): name = f"dut.{action.port.path}" debug_name = name else: name = verilog_name(action.port.name) debug_name = action.port.name value = action.value if isinstance(value, actions.Peek): if isinstance(value.port, fault.WrappedVerilogInternalPort): value = f"dut.{value.port.path}" else: value = f"{value.port.name}" elif isinstance(value, PortWrapper): value = f"dut.{value.select_path.system_verilog_path}" elif isinstance(action.port, m.SIntType) and value < 0: # Handle sign extension for verilator since it expects and # unsigned c type port_len = len(action.port) value = BitVector(value, port_len).as_uint() return [ f"if ({name} != {value}) $error(\"Failed on action={i}" f" checking port {debug_name}. Expected %x, got %x\"" f", {value}, {name});" ]
def make_expect(self, i, action): # For verilator, if an expect is "AnyValue" we don't need to # perform the expect. if value_utils.is_any(action.value): return [] prefix = self.get_verilator_prefix() if isinstance(action.port, fault.WrappedVerilogInternalPort): path = action.port.path.replace(".", "->") name = f"{prefix}->{path}" debug_name = name elif isinstance(action.port, SelectPath): name = action.port.verilator_path if len(action.port) > 2: name = f"{prefix}->" + name debug_name = action.port[-1].debug_name else: name = verilator_name(action.port.name) debug_name = action.port.debug_name value = action.value if isinstance(value, actions.Peek): value = self.process_peek(value) elif isinstance(value, PortWrapper): value = f"top->{prefix}->" + value.select_path.verilator_path if isinstance(action.value, BitVector) and \ action.value.num_bits > max_bits: asserts = [] # For some reason, verilator chunks it by 32 instead of max_bits slice_range = 32 for j in range(math.ceil(action.value.num_bits / slice_range)): value = action.value[j * slice_range:min( (j + 1) * slice_range, action.value.num_bits)] asserts += [ f"my_assert(top->{name}[{j}], {value}, " f"{i}, \"{debug_name}\");" ] return asserts else: value = self.process_value(action.port, value) port_value = f"top->{name}" port_value = self.process_bitwise_expect(action.port, port_value) port = action.port if isinstance(port, SelectPath): port = port[-1] elif isinstance(port, fault.WrappedVerilogInternalPort): port = port.type_ if isinstance(port, m.Digital): port_len = 1 else: port_len = len(port) mask = (1 << port_len) - 1 return [ f"my_assert({port_value}, {value} & {mask}, " f"{i}, \"{debug_name}\");" ]
def make_expect(self, i, action): # don't do anything if any value is OK if value_utils.is_any(action.value): return [] # determine the exact name of the signal name = self.make_name(action.port) # TODO: add something like "make_read_name" and "make_write_name" # so that reading inout signals has more uniform behavior across # expect, peek, etc. if actions.is_inout(action.port): name = self.input_wire(name) # determine the name of the signal for debugging purposes if isinstance(action.port, SelectPath): debug_name = action.port[-1].name elif isinstance(action.port, fault.WrappedVerilogInternalPort): debug_name = name else: debug_name = action.port.name # determine the value to be checked value = self.process_value(action.port, action.value) # determine the condition and error body err_body = f'"Failed on action={i} checking port {debug_name}.' if action.above is not None: if action.below is not None: # must be in range cond = f'({action.above} <= {name}) && ({name} <= {action.below})' # noqa err_body += f' Expected %0f to %0f, got %0f", {action.above}, {action.below}, {name}' # noqa else: # must be above cond = f'{action.above} <= {name}' err_body += f' Expected above %0f, got %0f", {action.above}, {name}' # noqa else: if action.below is not None: # must be below cond = f'{name} <= {action.below}' err_body += f' Expected below %0f, got %0f", {action.below}, {name}' # noqa else: # equality comparison if action.strict: cond = f'{name} === {value}' else: cond = f'{name} == {value}' err_body += f' Expected %x, got %x" , {value}, {name}' # return a snippet of verilog implementing the assertion retval = [] retval += [f'if (!({cond})) begin'] retval += [self.make_line(f'$error({err_body});', tabs=1)] retval += ['end'] return retval
def make_expect(self, i, action): # For verilator, if an expect is "AnyValue" we don't need to # perform the expect. if value_utils.is_any(action.value): return [] if self.verilator_version > 3.874: prefix = f"{self.circuit_name}" else: prefix = f"v" if isinstance(action.port, fault.WrappedVerilogInternalPort): path = action.port.path.replace(".", "->") name = f"{prefix}->{path}" debug_name = name elif isinstance(action.port, SelectPath): name = action.port.verilator_path if len(action.port) > 2: name = f"{prefix}->" + name if self.verilator_version >= 3.856: if len(action.port) > 2: self.debug_includes.add(f"{action.port[0].circuit.name}") for item in action.port[1:-1]: circuit_name = type(item.instance).name self.debug_includes.add(f"{circuit_name}") debug_name = action.port[-1].debug_name else: name = verilog_name(action.port.name) debug_name = action.port.debug_name value = action.value if isinstance(value, actions.Peek): if isinstance(value.port, fault.WrappedVerilogInternalPort): path = action.port.path.replace(".", "->") value = f"top->{prefix}->{path}" else: value = f"top->{verilog_name(value.port.name)}" elif isinstance(value, PortWrapper): if self.verilator_version >= 3.856: if len(action.port) > 2: self.debug_includes.add(f"{action.port[0].circuit.name}") for item in value.select_path[1:-1]: circuit_name = type(item.instance).name self.debug_includes.add(f"{circuit_name}") value = f"top->{prefix}->" + value.select_path.verilator_path elif isinstance(action.port, m.SIntType) and value < 0: # Handle sign extension for verilator since it expects and # unsigned c type port_len = len(action.port) value = BitVector(value, port_len).as_uint() return [f"my_assert(top->{name}, {value}, " f"{i}, \"{debug_name}\");"]
def make_expect(self, i, action): # For verilator, if an expect is "AnyValue" we don't need to # perform the expect. if value_utils.is_any(action.value): return [] prefix = self.get_verilator_prefix() if isinstance(action.port, fault.WrappedVerilogInternalPort): path = action.port.path.replace(".", "->") name = f"{prefix}->{path}" debug_name = name elif isinstance(action.port, SelectPath): name = action.port.verilator_path if len(action.port) > 2: name = f"{prefix}->" + name debug_name = action.port[-1].debug_name else: name = verilator_name(action.port.name) debug_name = action.port.debug_name value = action.value if isinstance(value, actions.Peek): value = self.process_peek(value) elif isinstance(value, PortWrapper): value = f"top->{prefix}->" + value.select_path.verilator_path user_msg = () if action.msg is not None: if isinstance(action.msg, str): user_msg += (action.msg, ) else: assert isinstance(action.msg, tuple) user_msg += (action.msg[0], ) user_msg += self._make_print_args(action.msg[1:]) if isinstance(action.value, BitVector) and \ action.value.num_bits > max_bits: asserts = [] # For some reason, verilator chunks it by 32 instead of max_bits slice_range = 32 for j in range(math.ceil(action.value.num_bits / slice_range)): value = action.value[j * slice_range:min( (j + 1) * slice_range, action.value.num_bits)] asserts.append( self._make_assert(f"((unsigned int) top->{name}[{j}])", f"((unsigned int) {value})", i, f"\"{debug_name}\"", user_msg)) return asserts else: value = self.process_value(action.port, value) port_value = f"top->{name}" port_value = self.process_bitwise_expect(action.port, port_value) port = action.port if isinstance(port, SelectPath): port = port[-1] elif isinstance(port, fault.WrappedVerilogInternalPort): port = port.type_ if isinstance(port, m.Digital): port_len = 1 else: port_len = len(port) # deal with real-valued expressions if isinstance(port, RealType): got = f"({port_value})" expected = f"({value})" style = 'scientific' else: mask = (1 << port_len) - 1 got = f"((unsigned int) {port_value})" expected = f"(unsigned int) ({value} & {mask})" style = 'hex' return [ self._make_assert(got=got, expected=expected, i=i, port=f'"{debug_name}"', user_msg=user_msg, below=action.below, above=action.above, style=style) ]
def make_expect(self, i, action): # don't do anything if any value is OK if value_utils.is_any(action.value): return [] # determine the exact name of the signal name = self.make_name(action.port) # TODO: add something like "make_read_name" and "make_write_name" # so that reading inout signals has more uniform behavior across # expect, peek, etc. if actions.is_inout(action.port): name = self.input_wire(name) # determine the name of the signal for debugging purposes if isinstance(action.port, SelectPath): debug_name = action.port[-1].name elif isinstance(action.port, fault.WrappedVerilogInternalPort): debug_name = name else: debug_name = action.port.name # determine the value to be checked value = self.process_value(action.port, action.value) # determine the condition and error body err_hdr = '' err_hdr += f'Failed on action={i} checking port {debug_name}' if action.traceback is not None: err_hdr += f' with traceback {action.traceback}' if action.above is not None: if action.below is not None: # must be in range cond = f'(({action.above} <= {name}) && ({name} <= {action.below}))' # noqa err_msg = 'Expected %0f to %0f, got %0f' err_args = [action.above, action.below, name] else: # must be above cond = f'({action.above} <= {name})' err_msg = 'Expected above %0f, got %0f' err_args = [action.above, name] else: if action.below is not None: # must be below cond = f'({name} <= {action.below})' err_msg = 'Expected below %0f, got %0f' err_args = [action.below, name] else: # equality comparison if action.strict: cond = f'({name} === {value})' else: cond = f'({name} == {value})' err_msg = 'Expected %x, got %x' err_args = [value, name] if action.msg is not None: if isinstance(action.msg, str): err_msg += "\\n" + action.msg else: assert isinstance(action.msg, tuple) err_msg += "\\n" + action.msg[0] err_args += self._make_print_args(action.msg[1:]) # construct the body of the $error call err_fmt_str = f'"{err_hdr}. {err_msg}."' err_body = [err_fmt_str] + err_args err_body = ', '.join([str(elem) for elem in err_body]) if self.use_sva: return [f'assert ({cond}) else $error({err_body});'] else: # return a snippet of verilog implementing the assertion return self.make_if(i, If(f'!{cond}', [f'$error({err_body});']))