def make_poke(self, i, action): 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}" elif isinstance(action.port, SelectPath): name = "" if len(action.port) > 2: # TODO: Find the version that they changed this, 3.874 is known # to use top->v instead of top->{circuit_name} name += f"{prefix}->" name += action.port.verilator_path elif isinstance(action.port, actions.Var): name = action.port.name else: name = verilator_name(action.port.name) # Special case poking internal registers is_reg_poke = isinstance(action.port, SelectPath) and \ isinstance(action.port[-1], fault.WrappedVerilogInternalPort) \ and action.port[-1].path == "outReg" if isinstance(action.value, BitVector) and \ action.value.num_bits > max_bits: pokes = [] # For some reason, verilator chunks it by 32 instead of max_bits slice_range = 32 for i in range(math.ceil(action.value.num_bits / slice_range)): value = action.value[i * slice_range:min( (i + 1) * slice_range, action.value.num_bits)] pokes += [f"top->{name}[{i}] = {value};"] if is_reg_poke: raise NotImplementedError() return pokes else: value = action.value value = self.process_value(action.port, value) value = self.process_bitwise_assign(action.port, name, value) if isinstance(action.port, actions.Var): result = [f"{name} = {value};"] else: result = [f"top->{name} = {value};"] # Hack to support verilator's semantics, need to set the register # mux values for expected behavior if is_reg_poke: action.port[-1].path = "out" result += self.make_poke(i, action) action.port[-1].path = "in" result += self.make_poke(i, action) if "enable_mux" in action.port[-3].instance_map: mux_inst = action.port[-3].instance_map["enable_mux"] action.port[-2] = InstanceWrapper(mux_inst, action.port[-3]) action.port[-1] = type(mux_inst).I0 result += self.make_poke(i, action) return result
def make_poke(self, i, action): 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}" elif isinstance(action.port, SelectPath): name = "" if len(action.port) > 2: # TODO: Find the version that they changed this, 3.874 is known # to use top->v instead of top->{circuit_name} name += f"{prefix}->" name += action.port.verilator_path if len(action.port) > 2: self.debug_includes.add(f"{action.port[0].circuit.name}") for item in action.port[1:-1]: circuit = type(item.instance) circuit_name = circuit.verilog_name # Verilator specializes each parametrization into a separate # mdoule, this is an attempt to reverse engineer the naming # scheme if circuit_name == "coreir_reg": circuit_name += "_" circuit_name += f"_I{circuit.coreir_configargs['init']}" circuit_name += f"_W{circuit.coreir_genargs['width']}" elif circuit_name == "coreir_reg_arst": circuit_name += "_" circuit_name += f"_I{circuit.coreir_configargs['init']}" if circuit.coreir_genargs['width'] != 1: circuit_name += f"_W{circuit.coreir_genargs['width']}" self.debug_includes.add(f"{circuit_name}") else: name = verilog_name(action.port.name) # Special case poking internal registers is_reg_poke = isinstance(action.port, SelectPath) and \ isinstance(action.port[-1], fault.WrappedVerilogInternalPort) \ and action.port[-1].path == "outReg" # max_bits = 64 if platform.architecture()[0] == "64bit" else 32 max_bits = 32 if isinstance(action.value, BitVector) and \ action.value.num_bits > max_bits: asserts = [] for i in range(math.ceil(action.value.num_bits / max_bits)): value = action.value[i * max_bits:min( (i + 1) * max_bits, action.value.num_bits)] asserts += [f"top->{name}[{i}] = {value};"] if is_reg_poke: raise NotImplementedError() return asserts else: value = action.value if isinstance(value, actions.FileRead): value = f"*{value.file.name_without_ext}_in" if 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() result = [f"top->{name} = {value};"] # Hack to support verilator's semantics, need to set the register # mux values for expected behavior if is_reg_poke: action.port[-1].path = "out" result += self.make_poke(i, action) action.port[-1].path = "in" result += self.make_poke(i, action) if "enable_mux" in action.port[-3].instance_map: mux_inst = action.port[-3].instance_map["enable_mux"] action.port[-2] = InstanceWrapper(mux_inst, action.port[-3]) action.port[-1] = type(mux_inst).I0 result += self.make_poke(i, action) return result
def make_poke(self, i, action): 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}" elif isinstance(action.port, SelectPath): name = "" if len(action.port) > 2: # TODO: Find the version that they changed this, 3.874 is known # to use top->v instead of top->{circuit_name} name += f"{prefix}->" name += action.port.verilator_path if len(action.port) > 2: self.debug_includes.add(f"{action.port[0].circuit.name}") for item in action.port[1:-1]: circuit = type(item.instance) circuit_name = circuit.verilog_name # Verilator specializes each parametrization into a separate # mdoule, this is an attempt to reverse engineer the naming # scheme if circuit_name == "coreir_reg": circuit_name += "_" circuit_name += f"_C1" # Posedge clock circuit_name += f"_I{circuit.coreir_configargs['init']}" circuit_name += f"_W{circuit.coreir_genargs['width']}" elif circuit_name == "coreir_reg_arst": circuit_name += "_" circuit_name += f"_I{circuit.coreir_configargs['init']}" if circuit.coreir_genargs['width'] != 1: circuit_name += f"_W{circuit.coreir_genargs['width']}" self.debug_includes.add(f"{circuit_name}") else: name = verilator_name(action.port.name) # Special case poking internal registers is_reg_poke = isinstance(action.port, SelectPath) and \ isinstance(action.port[-1], fault.WrappedVerilogInternalPort) \ and action.port[-1].path == "outReg" if isinstance(action.value, BitVector) and \ action.value.num_bits > max_bits: pokes = [] # For some reason, verilator chunks it by 32 instead of max_bits slice_range = 32 for i in range(math.ceil(action.value.num_bits / slice_range)): value = action.value[i * slice_range:min( (i + 1) * slice_range, action.value.num_bits)] pokes += [f"top->{name}[{i}] = {value};"] if is_reg_poke: raise NotImplementedError() return pokes else: value = action.value if isinstance(value, actions.FileRead): mask = "FF" * value.file.chunk_size value = " | ".join(f"{value.file.name_without_ext}_in[{i}]" for i in range(value.file.chunk_size)) value = f"({value}) & 0x{mask}" value = self.process_value(action.port, value) value = self.process_bitwise_assign(action.port, name, value) result = [f"top->{name} = {value};"] # Hack to support verilator's semantics, need to set the register # mux values for expected behavior if is_reg_poke: action.port[-1].path = "out" result += self.make_poke(i, action) action.port[-1].path = "in" result += self.make_poke(i, action) if "enable_mux" in action.port[-3].instance_map: mux_inst = action.port[-3].instance_map["enable_mux"] action.port[-2] = InstanceWrapper(mux_inst, action.port[-3]) action.port[-1] = type(mux_inst).I0 result += self.make_poke(i, action) return result