Example #1
0
    def __init__(self, dut, init_val):
        """
        Setup the testbench.

        *init_val* signifies the ``BinaryValue`` which must be captured by the
        output monitor with the first rising clock edge.
        This must match the initial state of the D flip-flop in RTL.
        """
        # Some internal state
        self.dut = dut
        self.stopped = False

        # Create input driver and output monitor
        self.input_drv = BitDriver(signal=dut.d,
                                   clk=dut.c,
                                   generator=input_gen())
        self.output_mon = BitMonitor(name="output", signal=dut.q, clk=dut.c)

        # Create a scoreboard on the outputs
        self.expected_output = [init_val
                                ]  # a list with init_val as the first element
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            self.scoreboard = Scoreboard(dut)
        self.scoreboard.add_interface(self.output_mon, self.expected_output)

        # Use the input monitor to reconstruct the transactions from the pins
        # and send them to our 'model' of the design.
        self.input_mon = BitMonitor(name="input",
                                    signal=dut.d,
                                    clk=dut.c,
                                    callback=self.model)
Example #2
0
    def __init__(self, dut, debug=False):
        self.dut = dut
        self.stream_in = AvalonSTDriver(dut, "stream_in", dut.clk)
        self.backpressure = BitDriver(self.dut.stream_out_ready, self.dut.clk)
        self.stream_out = AvalonSTMonitor(
            dut,
            "stream_out",
            dut.clk,
            config={'firstSymbolInHighOrderBits': True})

        self.csr = AvalonMaster(dut, "csr", dut.clk)

        cocotb.fork(
            stream_out_config_setter(dut, self.stream_out, self.stream_in))

        # Create a scoreboard on the stream_out bus
        self.pkts_sent = 0
        self.expected_output = []
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            self.scoreboard = Scoreboard(dut)
        self.scoreboard.add_interface(self.stream_out, self.expected_output)

        # Reconstruct the input transactions from the pins
        # and send them to our 'model'
        self.stream_in_recovered = AvalonSTMonitor(dut,
                                                   "stream_in",
                                                   dut.clk,
                                                   callback=self.model)

        # Set verbosity on our various interfaces
        level = logging.DEBUG if debug else logging.WARNING
        self.stream_in.log.setLevel(level)
        self.stream_in_recovered.log.setLevel(level)
Example #3
0
class DFF_TB(object):
    def __init__(self, dut, init_val):
        """
        Setup the testbench.

        *init_val* signifies the ``BinaryValue`` which must be captured by the
        output monitor with the first rising clock edge.
        This must match the initial state of the D flip-flop in RTL.
        """
        # Some internal state
        self.dut = dut
        self.stopped = False

        # Create input driver and output monitor
        self.input_drv = BitDriver(signal=dut.d,
                                   clk=dut.c,
                                   generator=input_gen())
        self.output_mon = BitMonitor(name="output", signal=dut.q, clk=dut.c)

        # Create a scoreboard on the outputs
        self.expected_output = [init_val
                                ]  # a list with init_val as the first element
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            self.scoreboard = Scoreboard(dut)
        self.scoreboard.add_interface(self.output_mon, self.expected_output)

        # Use the input monitor to reconstruct the transactions from the pins
        # and send them to our 'model' of the design.
        self.input_mon = BitMonitor(name="input",
                                    signal=dut.d,
                                    clk=dut.c,
                                    callback=self.model)

    def model(self, transaction):
        """Model the DUT based on the input *transaction*.

        For a D flip-flop, what goes in at ``d`` comes out on ``q``,
        so the value on ``d`` (put into *transaction* by our ``input_mon``)
        can be used as expected output without change.
        Thus we can directly append *transaction* to the ``expected_output`` list,
        except for the very last clock cycle of the simulation
        (that is, after ``stop()`` has been called).
        """
        if not self.stopped:
            self.expected_output.append(transaction)

    def start(self):
        """Start generating input data."""
        self.input_drv.start()

    def stop(self):
        """Stop generating input data.

        Also stop generation of expected output transactions.
        One more clock cycle must be executed afterwards so that the output of
        the D flip-flop can be checked.
        """
        self.input_drv.stop()
        self.stopped = True
Example #4
0
class AvalonSTTB(object):
    """Testbench for avalon basic stream"""

    def __init__(self, dut):
        self.dut = dut

        self.clkedge = RisingEdge(dut.clk)

        self.stream_in = AvalonSTDriver(self.dut, "asi", dut.clk)
        self.stream_out = AvalonSTMonitor(self.dut, "aso", dut.clk)
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            self.scoreboard = Scoreboard(self.dut, fail_immediately=True)

        self.expected_output = []
        self.scoreboard.add_interface(self.stream_out, self.expected_output)

        self.backpressure = BitDriver(self.dut.aso_ready, self.dut.clk)

    async def initialise(self):
        self.dut.reset.value = 0
        cocotb.fork(Clock(self.dut.clk, 10).start())
        for _ in range(3):
            await self.clkedge
        self.dut.reset.value = 1
        await self.clkedge

    async def send_data(self, data):
        exp_data = struct.pack("B",data)
        self.expected_output.append(exp_data)
        await self.stream_in.send(data)
Example #5
0
 def __init__(self, dut, clkperiod=6.4):
     self.dut = dut
     dut._discover_all()  # scan all signals on the design
     dut._log.setLevel(logging.INFO)
     fork(Clock(dut.clk, clkperiod, 'ns').start())
     self.payload_in = AXI4STPKts(dut, "payload_in", dut.clk)
     self.stream_out = AXI4STMonitor(dut, "packet_out", dut.clk,
                                     callback=self.print_trans)
     self.scoreboard = Scoreboard(dut, fail_immediately=False)
     self.expected_output = []
     self.scoreboard.add_interface(self.stream_out, self.expected_output)
     self.nb_frame = 0
     self.packet = BinaryValue()
Example #6
0
class EndianSwapperTB(object):
    def __init__(self, dut, debug=False):
        self.dut = dut
        self.stream_in = AvalonSTDriver(dut, "stream_in", dut.clk)
        self.backpressure = BitDriver(self.dut.stream_out_ready, self.dut.clk)
        self.stream_out = AvalonSTMonitor(
            dut,
            "stream_out",
            dut.clk,
            config={'firstSymbolInHighOrderBits': True})

        self.csr = AvalonMaster(dut, "csr", dut.clk)

        cocotb.fork(
            stream_out_config_setter(dut, self.stream_out, self.stream_in))

        # Create a scoreboard on the stream_out bus
        self.pkts_sent = 0
        self.expected_output = []
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            self.scoreboard = Scoreboard(dut)
        self.scoreboard.add_interface(self.stream_out, self.expected_output)

        # Reconstruct the input transactions from the pins
        # and send them to our 'model'
        self.stream_in_recovered = AvalonSTMonitor(dut,
                                                   "stream_in",
                                                   dut.clk,
                                                   callback=self.model)

        # Set verbosity on our various interfaces
        level = logging.DEBUG if debug else logging.WARNING
        self.stream_in.log.setLevel(level)
        self.stream_in_recovered.log.setLevel(level)

    def model(self, transaction):
        """Model the DUT based on the input transaction"""
        self.expected_output.append(transaction)
        self.pkts_sent += 1

    async def reset(self, duration=20):
        self.dut._log.debug("Resetting DUT")
        self.dut.reset_n <= 0
        self.stream_in.bus.valid <= 0
        await Timer(duration, units='ns')
        await RisingEdge(self.dut.clk)
        self.dut.reset_n <= 1
        self.dut._log.debug("Out of reset")
Example #7
0
    def __init__(self, dut):
        self.dut = dut

        self.clkedge = RisingEdge(dut.clk)

        self.stream_in = AvalonSTDriver(self.dut, "asi", dut.clk)
        self.stream_out = AvalonSTMonitor(self.dut, "aso", dut.clk)
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            self.scoreboard = Scoreboard(self.dut, fail_immediately=True)

        self.expected_output = []
        self.scoreboard.add_interface(self.stream_out, self.expected_output)

        self.backpressure = BitDriver(self.dut.aso_ready, self.dut.clk)
Example #8
0
async def mean_randomised_test(dut):
    """Test mean of random numbers multiple times"""

    # dut_in = StreamBusMonitor(dut, "i", dut.clk)  # this doesn't work:
    # VPI Error vpi_get_value():
    # ERROR - Cannot get a value for an object of type vpiArrayVar.

    dut_out = StreamBusMonitor(dut, "o", dut.clk)

    exp_out = []
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        scoreboard = Scoreboard(dut)
    scoreboard.add_interface(dut_out, exp_out)

    DATA_WIDTH = int(dut.DATA_WIDTH.value)
    BUS_WIDTH = int(dut.BUS_WIDTH.value)
    dut._log.info('Detected DATA_WIDTH = %d, BUS_WIDTH = %d' %
                  (DATA_WIDTH, BUS_WIDTH))

    cocotb.fork(Clock(dut.clk, CLK_PERIOD_NS, units='ns').start())

    dut.rst <= 1
    for i in range(BUS_WIDTH):
        dut.i_data[i] <= 0
    dut.i_valid <= 0
    await RisingEdge(dut.clk)
    await RisingEdge(dut.clk)
    dut.rst <= 0

    for j in range(10):
        nums = []
        for i in range(BUS_WIDTH):
            x = random.randint(0, 2**DATA_WIDTH - 1)
            dut.i_data[i] <= x
            nums.append(x)
        dut.i_valid <= 1

        nums_mean = sum(nums) // BUS_WIDTH
        exp_out.append(nums_mean)
        await RisingEdge(dut.clk)
        dut.i_valid <= 0

    await RisingEdge(dut.clk)
    await RisingEdge(dut.clk)
Example #9
0
 def __init__(
     self,
     dut,
     test_name,
     expected_regfile_read=None,
     expected_regfile_write=None,
     expected_data_read=None,
     expected_data_write=None,
     instruction_memory=None,
     data_memory=None,
     enable_self_checking=True,
     pass_fail_address=None,
     pass_fail_values=None,
     output_address=None,
     timer_address=None,
 ):
     self.log = SimLog('cocotb.' + __name__ + '.' + self.__class__.__name__)
     self.test_name = test_name
     self.dut = dut
     self.clock = self.dut.clk
     self.reset_n = self.dut.rst
     core = self.dut
     self.reset_n.setimmediatevalue(0)
     self.pass_fail_address = pass_fail_address
     self.pass_fail_values = pass_fail_values
     self.output_address = output_address
     self.fake_uart = []
     self.timer_counter = 0
     self.timer_address = timer_address
     if self.timer_address is not None:
         cocotb.fork(self.timer())
     self.end_test = Event()
     ## Process parameters
     self.memory = {**instruction_memory, **data_memory}
     if 'debug_test' in cocotb.plusargs:
         csv_path = Path(test_name + '_memory.csv')
         self.log.debug(
             f"Dumping initial memory content to {csv_path.resolve()}")
         memory = [(f'0x{k:X}', f'0x{v:X}') for k, v in self.memory.items()]
         csv_path.write_text(
             tabulate(memory, ['address', 'value'], tablefmt="plain"))
     self.end_i_address = None
     if enable_self_checking:
         self.end_i_address = max(instruction_memory.keys())
         self.expected_regfile_read = [
             RegFileReadTransaction.from_string(t)
             for t in expected_regfile_read
         ]
         self.expected_regfile_write = [
             RegFileWriteTransaction.from_string(t)
             for t in expected_regfile_write
         ]
         self.expected_data_read = [
             BusReadTransaction.from_string(t) for t in expected_data_read
         ]
         self.expected_data_write = [
             BusWriteTransaction.from_string(t) for t in expected_data_write
         ]
     #self.log.debug(f"Instruction memory: {instruction_memory}")
     #self.log.debug(f"Data memory: {data_memory}")
     #self.log.debug(f"Memory: {self.memory}")
     ## Bus functional models
     prefix = None
     if not cocotb.plusargs.get('dut_copperv1', False):
         prefix = "bus_"
     self.bus_bfm = CoppervBusBfm(clock=self.clock,
                                  reset_n=self.reset_n,
                                  entity=self.dut,
                                  prefix=prefix)
     regfile_bfm = RegFileBfm(clock=self.clock,
                              reset_n=self.reset_n,
                              entity=core.regfile,
                              signals=RegFileBfm.Signals(
                                  rd_en="rd_en",
                                  rd_addr="rd",
                                  rd_data="rd_din",
                                  rs1_en="rs1_en",
                                  rs1_addr="rs1",
                                  rs1_data="rs1_dout",
                                  rs2_en="rs2_en",
                                  rs2_addr="rs2",
                                  rs2_data="rs2_dout",
                              ))
     ## Instruction read
     self.bus_ir_driver = BusSourceDriver("bus_ir", BusReadTransaction,
                                          self.bus_bfm.ir_send_response,
                                          self.bus_bfm.ir_drive_ready)
     self.bus_ir_monitor = BusMonitor("bus_ir", BusReadTransaction,
                                      self.bus_bfm.ir_get_request,
                                      self.bus_bfm.ir_get_response)
     self.bus_ir_req_monitor = BusMonitor("bus_ir_req",
                                          BusReadTransaction,
                                          self.bus_bfm.ir_get_request,
                                          callback=self.memory_callback,
                                          bus_name="bus_ir")
     ## Data read
     self.bus_dr_driver = BusSourceDriver("bus_dr", BusReadTransaction,
                                          self.bus_bfm.dr_send_response,
                                          self.bus_bfm.dr_drive_ready)
     self.bus_dr_monitor = BusMonitor("bus_dr", BusReadTransaction,
                                      self.bus_bfm.dr_get_request,
                                      self.bus_bfm.dr_get_response)
     self.bus_dr_req_monitor = BusMonitor("bus_dr_req",
                                          BusReadTransaction,
                                          self.bus_bfm.dr_get_request,
                                          callback=self.memory_callback,
                                          bus_name="bus_dr")
     ## Data write
     self.bus_dw_driver = BusSourceDriver("bus_dw", BusWriteTransaction,
                                          self.bus_bfm.dw_send_response,
                                          self.bus_bfm.dw_drive_ready)
     self.bus_dw_monitor = BusMonitor("bus_dw", BusWriteTransaction,
                                      self.bus_bfm.dw_get_request,
                                      self.bus_bfm.dw_get_response)
     self.bus_dw_req_monitor = BusMonitor("bus_dw_req",
                                          BusWriteTransaction,
                                          self.bus_bfm.dw_get_request,
                                          callback=self.memory_callback,
                                          bus_name="bus_dw")
     ## Regfile
     self.regfile_write_monitor = RegFileWriteMonitor(
         "regfile_write", regfile_bfm)
     self.regfile_read_monitor = RegFileReadMonitor("regfile_read",
                                                    regfile_bfm)
     ## Stack Monitor
     #StackMonitor(self.regfile_write_monitor)
     if enable_self_checking:
         ## Self checking
         self.scoreboard = Scoreboard(dut)
         self.scoreboard.add_interface(self.regfile_write_monitor,
                                       self.expected_regfile_write)
         self.scoreboard.add_interface(self.regfile_read_monitor,
                                       self.expected_regfile_read)
         self.scoreboard.add_interface(self.bus_dr_monitor,
                                       self.expected_data_read)
         self.scoreboard.add_interface(self.bus_dw_monitor,
                                       self.expected_data_write)
Example #10
0
class Testbench():
    def __init__(
        self,
        dut,
        test_name,
        expected_regfile_read=None,
        expected_regfile_write=None,
        expected_data_read=None,
        expected_data_write=None,
        instruction_memory=None,
        data_memory=None,
        enable_self_checking=True,
        pass_fail_address=None,
        pass_fail_values=None,
        output_address=None,
        timer_address=None,
    ):
        self.log = SimLog('cocotb.' + __name__ + '.' + self.__class__.__name__)
        self.test_name = test_name
        self.dut = dut
        self.clock = self.dut.clk
        self.reset_n = self.dut.rst
        core = self.dut
        self.reset_n.setimmediatevalue(0)
        self.pass_fail_address = pass_fail_address
        self.pass_fail_values = pass_fail_values
        self.output_address = output_address
        self.fake_uart = []
        self.timer_counter = 0
        self.timer_address = timer_address
        if self.timer_address is not None:
            cocotb.fork(self.timer())
        self.end_test = Event()
        ## Process parameters
        self.memory = {**instruction_memory, **data_memory}
        if 'debug_test' in cocotb.plusargs:
            csv_path = Path(test_name + '_memory.csv')
            self.log.debug(
                f"Dumping initial memory content to {csv_path.resolve()}")
            memory = [(f'0x{k:X}', f'0x{v:X}') for k, v in self.memory.items()]
            csv_path.write_text(
                tabulate(memory, ['address', 'value'], tablefmt="plain"))
        self.end_i_address = None
        if enable_self_checking:
            self.end_i_address = max(instruction_memory.keys())
            self.expected_regfile_read = [
                RegFileReadTransaction.from_string(t)
                for t in expected_regfile_read
            ]
            self.expected_regfile_write = [
                RegFileWriteTransaction.from_string(t)
                for t in expected_regfile_write
            ]
            self.expected_data_read = [
                BusReadTransaction.from_string(t) for t in expected_data_read
            ]
            self.expected_data_write = [
                BusWriteTransaction.from_string(t) for t in expected_data_write
            ]
        #self.log.debug(f"Instruction memory: {instruction_memory}")
        #self.log.debug(f"Data memory: {data_memory}")
        #self.log.debug(f"Memory: {self.memory}")
        ## Bus functional models
        prefix = None
        if not cocotb.plusargs.get('dut_copperv1', False):
            prefix = "bus_"
        self.bus_bfm = CoppervBusBfm(clock=self.clock,
                                     reset_n=self.reset_n,
                                     entity=self.dut,
                                     prefix=prefix)
        regfile_bfm = RegFileBfm(clock=self.clock,
                                 reset_n=self.reset_n,
                                 entity=core.regfile,
                                 signals=RegFileBfm.Signals(
                                     rd_en="rd_en",
                                     rd_addr="rd",
                                     rd_data="rd_din",
                                     rs1_en="rs1_en",
                                     rs1_addr="rs1",
                                     rs1_data="rs1_dout",
                                     rs2_en="rs2_en",
                                     rs2_addr="rs2",
                                     rs2_data="rs2_dout",
                                 ))
        ## Instruction read
        self.bus_ir_driver = BusSourceDriver("bus_ir", BusReadTransaction,
                                             self.bus_bfm.ir_send_response,
                                             self.bus_bfm.ir_drive_ready)
        self.bus_ir_monitor = BusMonitor("bus_ir", BusReadTransaction,
                                         self.bus_bfm.ir_get_request,
                                         self.bus_bfm.ir_get_response)
        self.bus_ir_req_monitor = BusMonitor("bus_ir_req",
                                             BusReadTransaction,
                                             self.bus_bfm.ir_get_request,
                                             callback=self.memory_callback,
                                             bus_name="bus_ir")
        ## Data read
        self.bus_dr_driver = BusSourceDriver("bus_dr", BusReadTransaction,
                                             self.bus_bfm.dr_send_response,
                                             self.bus_bfm.dr_drive_ready)
        self.bus_dr_monitor = BusMonitor("bus_dr", BusReadTransaction,
                                         self.bus_bfm.dr_get_request,
                                         self.bus_bfm.dr_get_response)
        self.bus_dr_req_monitor = BusMonitor("bus_dr_req",
                                             BusReadTransaction,
                                             self.bus_bfm.dr_get_request,
                                             callback=self.memory_callback,
                                             bus_name="bus_dr")
        ## Data write
        self.bus_dw_driver = BusSourceDriver("bus_dw", BusWriteTransaction,
                                             self.bus_bfm.dw_send_response,
                                             self.bus_bfm.dw_drive_ready)
        self.bus_dw_monitor = BusMonitor("bus_dw", BusWriteTransaction,
                                         self.bus_bfm.dw_get_request,
                                         self.bus_bfm.dw_get_response)
        self.bus_dw_req_monitor = BusMonitor("bus_dw_req",
                                             BusWriteTransaction,
                                             self.bus_bfm.dw_get_request,
                                             callback=self.memory_callback,
                                             bus_name="bus_dw")
        ## Regfile
        self.regfile_write_monitor = RegFileWriteMonitor(
            "regfile_write", regfile_bfm)
        self.regfile_read_monitor = RegFileReadMonitor("regfile_read",
                                                       regfile_bfm)
        ## Stack Monitor
        #StackMonitor(self.regfile_write_monitor)
        if enable_self_checking:
            ## Self checking
            self.scoreboard = Scoreboard(dut)
            self.scoreboard.add_interface(self.regfile_write_monitor,
                                          self.expected_regfile_write)
            self.scoreboard.add_interface(self.regfile_read_monitor,
                                          self.expected_regfile_read)
            self.scoreboard.add_interface(self.bus_dr_monitor,
                                          self.expected_data_read)
            self.scoreboard.add_interface(self.bus_dw_monitor,
                                          self.expected_data_write)

    async def timer(self):
        while True:
            await RisingEdge(self.clock)
            self.timer_counter += 1

    def memory_callback(self, transaction):
        self.log.debug(f"Memory callback {transaction}")
        if isinstance(transaction,
                      BusReadTransaction) and transaction.bus_name == 'bus_ir':
            driver_transaction = "deassert_ready"
            if self.end_i_address is None or (
                    self.end_i_address is not None
                    and transaction.addr < self.end_i_address):
                driver_transaction = BusReadTransaction(
                    bus_name=transaction.bus_name,
                    data=from_array(self.memory, transaction.addr),
                    addr=transaction.addr)
            self.bus_ir_driver.append(driver_transaction)
            #self.log.debug('instruction_read_callback transaction: %s driver_transaction %s',
            #    transaction,driver_transaction)
        elif isinstance(
                transaction,
                BusReadTransaction) and transaction.bus_name == 'bus_dr':
            driver_transaction = BusReadTransaction(
                bus_name=transaction.bus_name,
                data=self.handle_data_read(transaction),
                addr=transaction.addr,
            )
            self.bus_dr_driver.append(driver_transaction)
            #self.log.debug('data_read_callback transaction: %s driver_transaction %s',
            #    transaction,driver_transaction)
        elif isinstance(transaction, BusWriteTransaction):
            self.handle_data_write(transaction)
            driver_transaction = BusWriteTransaction(
                bus_name=transaction.bus_name,
                data=transaction.data,
                addr=transaction.addr,
                strobe=transaction.strobe,
                response=1,
            )
            self.bus_dw_driver.append(driver_transaction)
            #self.log.debug('data_write_callback transaction: %s driver_transaction %s',
            #    transaction,driver_transaction)
        else:
            raise ValueError(f"Unsupported transaction type: {transaction}")

    def handle_data_write(self, transaction):
        if self.pass_fail_address is not None and self.pass_fail_address == transaction.addr:
            if len(self.fake_uart) > 0:
                self.log.info("Fake UART output:\n%s", ''.join(self.fake_uart))
            assert self.pass_fail_values[
                transaction.data] == True, "Received test fail from bus"
            self.log.debug("Received test pass from bus")
            self.end_test.set()
        elif self.output_address is not None and self.output_address == transaction.addr:
            recv = chr(transaction.data)
            self.fake_uart.append(recv)
            self.log.info('Fake UART received: %s', repr(recv))
        else:
            mask = f"{transaction.strobe:04b}"
            #self.log.debug('write start: %X mask: %s',from_array(self.memory,transaction.addr),mask)
            for i in range(4):
                if int(mask[3 - i]):
                    #self.log.debug('writing %X -> %X',transaction.addr+i,to_bytes(transaction.data)[i])
                    self.memory[transaction.addr + i] = to_bytes(
                        transaction.data)[i]
            #self.log.debug('write finished: %X',from_array(self.memory,transaction.addr))
    def handle_data_read(self, transaction):
        value = None
        if self.timer_address is not None and self.timer_address == transaction.addr:
            value = self.timer_counter
        else:
            value = from_array(self.memory, transaction.addr)
        return value

    @cocotb.coroutine
    async def finish(self):
        last_pending = ""
        while True:
            if all([
                    len(expected) == 0
                    for expected in self.scoreboard.expected.values()
            ]):
                break
            pending = repr({
                k.name: [str(i) for i in v]
                for k, v in self.scoreboard.expected.items()
            })
            if last_pending != pending:
                self.log.debug(f"Pending transactions: {pending}")
            last_pending = pending
            await RisingEdge(self.clock)
        await ClockCycles(self.clock, 2)
def test_dut(dut):
    '''
    The testbench:
      * binds the interfaces
      * Loads the Key
      * Loads the IV in the ICB
      * Sends the AAD data through the pipeline
      * Sends the PT data through the pipeline
      * Checks the CT and the MAC match the model '''

    # Create the lists of transactions
    aad_tran = []
    pt_tran = []
    aad_model_tran = []
    pt_model_tran = []

    tb = gcm_gctr(dut)

    # Open config file
    with open('./tmp/' + str(cocotb.RANDOM_SEED) + '.json',
              'r') as config_file:
        tb.config = dict(json.load(config_file))

    # Generate configuration data
    tb.config_data()

    # Initialise GCM model
    dut_model = gcm_model.gcm(tb.data['key'], tb.data['iv'])

    # Create drivers
    pkt_drv = pkt_driver(dut.clk_i, dut.aes_gcm_ghash_pkt_val_i)
    aad_drv = aad_driver(dut.clk_i, dut.aes_gcm_ghash_aad_bval_i,
                         dut.aes_gcm_ghash_aad_i)
    pt_drv = pt_driver(dut.clk_i, dut.aes_gcm_plain_text_bval_i,
                       dut.aes_gcm_plain_text_i, dut.aes_gcm_cipher_ready_o)

    # Create delay function
    delay = wait_for(dut.clk_i, RisingEdge)

    # Get the AES mode
    dut._log.info('AES mode: ' + tb.config['aes_mode'])

    # Get AES key size
    dut._log.info('AES size: ' + tb.config['aes_size'])

    # Release the Reset
    cocotb.fork(tb.release_rst(RST_WINDOW))

    # Start the Clock
    cocotb.fork(Clock(dut.clk_i, CLK_PERIOD, 'ns').start())

    # Wait for the Reset falling edge event
    yield FallingEdge(dut.rst_i)

    # Wait few clocks
    yield ClockCycles(dut.clk_i, random.randint(10, 20))

    # Create the sequencer
    seq = sequencer(pkt_drv, aad_drv, pt_drv, delay.n_clk, tb.data,
                    str(tb.config['seed']), aad_tran, pt_tran)

    # Create monitors
    mon_aad = gcm_AAD_monitor("Get AAD", dut, dut_model.load_aad)
    mon_pt = gcm_PT_monitor("Get PT", dut, dut_model.load_plain_text)
    mon_ct = gcm_CT_monitor("Get CT", dut)
    mon_tag = gcm_TAG_monitor("Get TAG", dut, dut_model.get_tag)

    # Create scoreboard
    scoreboard = Scoreboard(dut)

    # Add scoreboard interfaces
    scoreboard.add_interface(mon_aad, aad_model_tran)
    scoreboard.add_interface(mon_pt, pt_model_tran)
    scoreboard.add_interface(mon_ct, dut_model.ct)
    scoreboard.add_interface(mon_tag, dut_model.tag)

    # Set AES key mode
    yield tb.aes_set_mode()

    # Load the KEY
    if (tb.config['key_pre_exp'] == True):
        yield tb.load_pre_exp_key(tb.data['key'])
    else:
        yield tb.load_key(tb.data['key'])

    # Load the ICB
    yield tb.load_iv(tb.data['iv'])

    # Start The ICB
    yield tb.start_icb()

    # Wait the AES to produce cipher data
    yield tb.cipher_is_ready()

    # Set the number of AAD transactions
    n_transaction = tb.data['aad_n_bytes'] >> 4
    if tb.data['aad_n_bytes'] & 0xF:
        n_transaction += 1
    dut._log.info('\n' + str(n_transaction) + " AAD transactions to read")

    # Set the number of PT transactions
    n_transaction = tb.data['pt_n_bytes'] >> 4
    if tb.data['pt_n_bytes'] & 0xF:
        n_transaction += 1
    dut._log.info(str(n_transaction) + " PT transactions to read\n")

    # Start the sequencer
    seq.start_sequencer()

    # Encrypt data
    yield tb.encrypt_data(tb.data['aad_n_bytes'], tb.data['pt_n_bytes'],
                          aad_tran, pt_tran, aad_model_tran, pt_model_tran)

    # Wait for the test to finish
    while dut.aes_gcm_ghash_tag_val_o.value == 0:
        yield RisingEdge(dut.clk_i)

    last_cycles = ClockCycles(dut.clk_i, 20)
    yield last_cycles
Example #12
0
class deparser_TB(object):
    def __init__(self, dut, clkperiod=6.4):
        self.dut = dut
        dut._discover_all()  # scan all signals on the design
        dut._log.setLevel(logging.INFO)
        fork(Clock(dut.clk, clkperiod, 'ns').start())
        self.payload_in = AXI4STPKts(dut, "payload_in", dut.clk)
        self.stream_out = AXI4STMonitor(dut, "packet_out", dut.clk,
                                        callback=self.print_trans)
        self.scoreboard = Scoreboard(dut, fail_immediately=False)
        self.expected_output = []
        self.scoreboard.add_interface(self.stream_out, self.expected_output)
        self.nb_frame = 0
        self.packet = BinaryValue()

    """
    Dictionnary to convert scapy name to VHDL.
    structure : scapyName: [VHDLname, length in bits]
    """
    name_to_VHDL = {
        "Ether": ["ethernet", 112],
        "IP": ["ipv4", 160],
        "TCP": ["tcp", 160],
        "UDP": ["udp", 64],
        "IPv6": ["ipv6", 320]}

    @coroutine
    def async_rst(self):
        """ This function execute the reset_n for 40ns
        it also set all input signals to default value
        """
        self.dut._log.info("begin Rst")
        for n, t in self.dut._sub_handles.items():
            if isinstance(t, handle.ModifiableObject):
                t.value = 0
        yield Timer(40, 'ns')
        self.dut.reset_n.value = 1
        yield Timer(15, 'ns')
        self.dut._log.info("end Rst")

    def print_trans(self, transaction):
        self.dut._log.info("Frame : {}, {}B:{}".format(self.nb_frame,
                                                       len(transaction.buff),
                                                       transaction))
        self.packet.buff += transaction.buff
        self.nb_frame += 1
        if self.dut.packet_out_tlast == 1:
            print(self.packet.buff)
            if len(self.packet.binstr) < 6*8:
                self.dut._log.warning("received packet lesser than 6Bytes\n"
                                      "received :‌\n{}".format(self.packet.binstr))
            else:
                print("received :‌\n{}".format(raw(BinaryValue_to_scapy(self.packet))))
            self.packet = BinaryValue()
            # BinaryValue_to_scapy(self.packet).display()
            # self.dut._log.info("received {}B : {}".format(
            #    len(self.packet.buff),
            #    self.packet.binstr))

    def set_PHV(self, pkt, payload=None):
        """ set PHV for deparser
        """
        scap_to_PHV(self.dut, pkt, self.name_to_VHDL)
        full_hdr = scapy_to_BinaryValue(pkt)
        print("emitted {} bytes : \n {}".format(len(raw(pkt)), raw(pkt)))
        self.dut._log.info("send {}B : {}".format(len(full_hdr.buff),
                                                  full_hdr.binstr))
        new_output = PHVDeparser(len(self.dut.packet_out_tdata),
                                 full_hdr)
        self.expected_output.extend(new_output)