Ejemplo n.º 1
0
 def make_print(self, i, action):
     port_names = []
     prefix = self.get_verilator_prefix()
     for port in action.ports:
         if isinstance(port, fault.WrappedVerilogInternalPort):
             path = port.path.replace(".", "->")
             name = f"{prefix}->{path}"
         elif isinstance(port, PortWrapper):
             port = port.select_path
             name = port.verilator_path
             if len(port) > 2:
                 name = f"{prefix}->" + name
             if self.verilator_version >= 3.856:
                 if len(port) > 2:
                     self.debug_includes.add(f"{port[0].circuit.name}")
             for item in port[1:-1]:
                 circuit_name = type(item.instance).name
                 self.debug_includes.add(f"{circuit_name}")
         else:
             name = verilator_name(port.name)
         port_names.append(name)
     ports = ", ".join(f"top->{name}" for name in port_names)
     if ports:
         ports = ", " + ports
     return [f'printf("{action.format_str}"{ports});']
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
    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}\");"
            ]
Ejemplo n.º 4
0
 def make_step(self, i, action):
     name = verilator_name(action.clock.name)
     code = []
     code.append("top->eval();")
     for step in range(action.steps):
         code.append("#if VM_TRACE")
         code.append("tracer->dump(main_time);")
         code.append("#endif")
         code.append(f"top->{name} ^= 1;")
         code.append("top->eval();")
         code.append("main_time += 5;")
     return code
Ejemplo n.º 5
0
 def _make_print_args(self, ports):
     port_names = []
     prefix = self.get_verilator_prefix()
     for port in ports:
         if isinstance(port, fault.WrappedVerilogInternalPort):
             path = port.path.replace(".", "->")
             name = f"{prefix}->{path}"
         elif isinstance(port, PortWrapper):
             port = port.select_path
             name = port.verilator_path
             if len(port) > 2:
                 name = f"{prefix}->" + name
         else:
             name = verilator_name(port.name)
         port_names.append(name)
     return tuple(f"top->{name}" for name in port_names)
Ejemplo n.º 6
0
 def make_print(self, i, action):
     port_names = []
     prefix = self.get_verilator_prefix()
     for port in action.ports:
         if isinstance(port, fault.WrappedVerilogInternalPort):
             path = port.path.replace(".", "->")
             name = f"{prefix}->{path}"
         elif isinstance(port, PortWrapper):
             port = port.select_path
             name = port.verilator_path
             if len(port) > 2:
                 name = f"{prefix}->" + name
         else:
             name = verilator_name(port.name)
         port_names.append(name)
     ports = ", ".join(f"top->{name}" for name in port_names)
     if ports:
         ports = ", " + ports
     return [f'printf("{action.format_str}"{ports});']
Ejemplo n.º 7
0
 def __init__(self, *args, clock=None, **kwargs):
     if clock is None:
         raise ValueError("Clock required")
     self.clock = verilator_name(clock.name)
Ejemplo n.º 8
0
    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)
            ]
Ejemplo n.º 9
0
    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