Example #1
0
async def test_regfile_concurrentrw(dut):
    """Test regfile concurrent read/write to same address"""

    clkedge = init_posedge_clk(dut.regfile_clk)

    # Reset
    dut.regfile_nreset <= 0
    await clkedge
    dut.regfile_nreset <= 1
    await clkedge

    test_addr = 4
    test_value = 0xbeefbeef

    dut.regfile_write_addr1.setimmediatevalue(0)
    dut.regfile_write_enable1.setimmediatevalue(0)
    dut.regfile_write_value1.setimmediatevalue(0)
    dut.regfile_read_addr1.setimmediatevalue(0)
    dut.regfile_read_addr2.setimmediatevalue(0)
    await clkedge
    await Timer(1, 'us')
    assert_neq(dut.regfile_read_value1, test_value)
    assert_neq(dut.regfile_read_value2, test_value)

    dut.regfile_write_addr1.setimmediatevalue(test_addr)
    dut.regfile_write_value1.setimmediatevalue(test_value)
    dut.regfile_write_enable1.setimmediatevalue(1)
    # Read out value as soon as we can
    dut.regfile_read_addr1.setimmediatevalue(test_addr)
    dut.regfile_read_addr2.setimmediatevalue(test_addr)
    await clkedge
    await Timer(1, 'us')
    assert_eq(dut.regfile_read_value1, test_value)
    assert_eq(dut.regfile_read_value2, test_value)
Example #2
0
 def _check_expected():
     for signal, value in expected_outputs.items():
         try:
             assert_eq(signal, value)
         except AssertionError as exc:
             raise AssertionError(
                 'Failed expected value on signal {} with error: {}'.format(
                     signal._name, str(exc)))
Example #3
0
    async def _test_write(test_addr):
        test_value = 0xdeadbeef
        # 1. Read orig values
        orig_value = read_data_memory_word(test_addr, data_memory)
        dut.data_memory_read_addr <= test_addr
        # 2. Write new value to same location
        dut.data_memory_write_enable <= 1
        dut.data_memory_write_addr <= test_addr
        dut.data_memory_write_value <= test_value
        await clkedge
        write_data_memory_word(test_addr, test_value, data_memory)
        # We need to wait a little since the values just became available
        # at the last clkedge
        await Timer(1, 'us')
        # 3. See if read picks up value on next clock cycle
        assert_eq(dut.data_memory_read_value, test_value)

        # 4. Disable write enable, see if read still picks up value (i.e. value actually committed)
        dut.data_memory_write_enable <= 0
        dut.data_memory_write_value <= 0xAABBCCDD
        await clkedge
        # We need to wait a little since the values just became available
        # at the last clkedge
        await Timer(1, 'us')
        assert_eq(dut.data_memory_read_value, test_value)

        # 5. Try changing offset of value within word, see if that reflects on reads
        async def _test_read(read_addr):
            dut.data_memory_read_addr <= read_addr
            await clkedge
            # We need to wait a little since the values just became available
            # at the last clkedge
            await Timer(1, 'us')
            assert dut.data_memory_read_value == read_data_memory_word(
                read_addr, data_memory)

        await _test_read(test_addr + 1)
        await _test_read(test_addr - 1)
        await _test_read(test_addr + 2)
        await _test_read(test_addr - 2)
        await _test_read(test_addr + 3)
        await _test_read(test_addr - 3)

        # Reset original value
        dut.data_memory_write_enable <= 1
        dut.data_memory_write_addr <= test_addr
        dut.data_memory_write_value <= orig_value
        await clkedge
        write_data_memory_word(test_addr, orig_value, data_memory)
Example #4
0
    async def _write_and_check(new_addr, new_value):
        """Do a quick check of the value written"""
        dut._log.info(
            f"Start write and check for r{new_addr} = {hex(new_value)}")
        assert expected_regfile[new_addr] != new_value
        expected_regfile[new_addr] = new_value
        dut.regfile_write_addr1.setimmediatevalue(new_addr)
        dut.regfile_write_value1.setimmediatevalue(new_value)
        dut.regfile_write_enable1.setimmediatevalue(1)
        # Read out value as soon as we can
        dut.regfile_read_addr1.setimmediatevalue(new_addr)

        await clkedge
        # Wait a little bit after clkedge to check immediate values
        await Timer(1, 'us')

        assert_eq(dut.regfile_read_value1, new_value)
Example #5
0
async def test_executor_branch(dut):
    """Test executor on branch instructions"""

    clkedge = init_posedge_clk(dut.executor_clk)

    # Need to add PC offset when setting executor_pc due to pipelining
    executor_pc_offset = 8

    # Reset and enable
    dut.executor_nreset <= 0
    await clkedge
    dut.executor_nreset <= 1
    dut.executor_enable <= 1

    # Test regular branch
    dut.executor_decoder_inst <= int('eafffffa', 16) # b 0x68 (relative to 0x78)
    pc_init = 20
    dut.executor_pc <= pc_init + executor_pc_offset
    await clkedge
    # We need to wait a little since the values just became available
    # at the last clkedge
    await Timer(1, 'us')
    assert dut.executor_ready.value.integer
    assert not dut.executor_update_Rd.value.integer
    assert dut.executor_flush_for_pc.value.integer
    assert dut.executor_update_pc.value.integer
    assert_eq(dut.executor_new_pc, pc_init + (0x68 - 0x78))

    # Test branch with link
    dut.executor_decoder_inst <= int('ebfffffb', 16) # bl 0x68 (relative to 0x74)
    pc_init = 16
    dut.executor_pc <= pc_init + executor_pc_offset
    await clkedge
    # We need to wait a little since the values just became available
    # at the last clkedge
    await Timer(1, 'us')
    assert dut.executor_ready.value.integer
    assert dut.executor_update_Rd.value.integer
    assert dut.executor_flush_for_pc.value.integer
    assert dut.executor_databranch_Rd_value == pc_init + 4
    assert dut.executor_update_pc.value.integer
    assert_eq(dut.executor_new_pc, pc_init + (0x68 - 0x74))

    # Reset dut to initial state
    dut.executor_enable.setimmediatevalue(0)
Example #6
0
async def test_memaccessor_read(dut):
    """Test memaccessor reads"""

    clkedge = await _setup_memaccessor(dut)

    data_memory = read_data_memory_init()

    databranch_Rd_value = 0xbeefdead
    dut.memaccessor_databranch_Rd_value <= databranch_Rd_value
    dut.memaccessor_executor_update_pc <= 0
    dut.memaccessor_enable <= 1

    dut.memaccessor_executor_inst <= int('e5984000', 16)  # ldr r4, [r8]
    Rn_value = 6  # r8
    dut.memaccessor_read_addr <= Rn_value
    dut.memaccessor_executor_update_Rd <= 1
    await clkedge
    # We need to wait a little since the values just became available
    # at the last clkedge
    await Timer(1, 'us')
    assert dut.memaccessor_ready.value.integer
    assert dut.memaccessor_update_Rd.value.integer
    assert_eq(dut.memaccessor_Rd_value,
              read_data_memory_word(Rn_value, data_memory))
    # Check forwarding values
    assert dut.memaccessor_fwd_has_Rd.value.integer
    assert_eq(dut.memaccessor_fwd_Rd_addr, 4)  # r4
    assert_eq(dut.memaccessor_fwd_Rd_value,
              read_data_memory_word(Rn_value, data_memory))

    dut.memaccessor_enable <= 0
Example #7
0
async def test_decoder_stall_for_ldr(dut):
    """Test decoder's stalling for LDR"""

    clkedge = init_posedge_clk(dut.decoder_clk)

    # Need to add PC offset when setting decoder_pc due to pipelining
    decoder_pc_offset = 8

    # Reset and enable
    dut.decoder_nreset <= 0
    await clkedge
    dut.decoder_nreset <= 1
    dut.decoder_enable <= 1

    dut.decoder_fetcher_inst <= 0xe79842a9  # ldr r4, [r8, r9, lsr #5]
    await clkedge
    # We need to wait a little since the values just became available
    # at the last clkedge
    await Timer(1, 'us')
    assert dut.decoder_ready.value.integer
    assert_eq(dut.decoder_regfile_read_addr1, 8)
    assert_eq(dut.decoder_regfile_read_addr2, 9)

    dut.decoder_fetcher_inst <= 0xe1a05004  # mov r5, r4
    await clkedge
    # We need to wait a little since the values just became available
    # at the last clkedge
    await Timer(1, 'us')
    assert dut.decoder_ready.value.integer
    assert_eq(dut.decoder_regfile_read_addr2, 4)  # r4
    assert dut.decoder_stall_for_ldr.value.integer
Example #8
0
async def test_memaccessor_write(dut):
    """Test memaccessor writes"""

    clkedge = await _setup_memaccessor(dut)

    data_memory = read_data_memory_init()

    databranch_Rd_value = 0xbeefdead
    dut.memaccessor_databranch_Rd_value <= databranch_Rd_value
    dut.memaccessor_executor_update_pc <= 0
    dut.memaccessor_enable <= 1

    dut._log.info("Test STR")
    dut.memaccessor_executor_inst <= int('e5885000', 16)  # str r5, [r8]
    Rd_Rm_value = 0xdeadbeef  # r5
    Rn_value = 1  # r8
    dut.memaccessor_write_enable <= 1
    dut.memaccessor_write_addr <= Rn_value
    dut.memaccessor_write_value <= Rd_Rm_value
    dut.memaccessor_executor_update_Rd <= 0
    await clkedge
    write_data_memory_word(Rn_value, Rd_Rm_value, data_memory)
    # We need to wait a little since the values just became available
    # at the last clkedge
    await Timer(1, 'us')
    dut.memaccessor_write_enable <= 0
    # STR should not update Rd
    assert dut.memaccessor_ready.value.integer
    assert not dut.memaccessor_update_Rd.value.integer
    assert not dut.memaccessor_fwd_has_Rd.value.integer

    dut._log.info("Verify STR with LDR")
    dut.memaccessor_executor_inst <= int('e5984000', 16)  # ldr r4, [r8]
    Rn_value = 1  # r8
    dut.memaccessor_read_addr <= Rn_value
    dut.memaccessor_executor_update_Rd <= 1
    await clkedge
    # We need to wait a little since the values just became available
    # at the last clkedge
    await Timer(1, 'us')
    assert dut.memaccessor_ready.value.integer
    assert dut.memaccessor_update_Rd.value.integer
    assert_eq(dut.memaccessor_Rd_value, Rd_Rm_value)
    # Check forwarding values
    assert dut.memaccessor_fwd_has_Rd.value.integer
    assert_eq(dut.memaccessor_fwd_Rd_addr, 4)  # r4
    assert_eq(dut.memaccessor_fwd_Rd_value, Rd_Rm_value)

    dut.memaccessor_enable <= 0
Example #9
0
async def test_executor_memaccessor_forward(dut):
    """Test executor's data forwarding from memaccessor"""

    clkedge = init_posedge_clk(dut.executor_clk)

    # Need to add PC offset when setting executor_pc due to pipelining
    executor_pc_offset = 8

    # Reset and enable
    dut.executor_nreset <= 0
    await clkedge
    dut.executor_nreset <= 1
    dut.executor_enable <= 1

    # Steps:
    # 1. Override r4 value in "mov r5, r4"
    # 2. Use executor forwarding to move r5 value from "mov r5, r4" to "str r5, [r8]"

    Rd_Rm_value_unused = 0xdeadbeef # r4, should not be used in STR below
    Rd_Rm_value = 0xbabafafa # r4

    dut.executor_decoder_inst <= 0xe1a05004 # mov r5, r4
    dut.executor_decoder_Rn_value <= 42 # unused
    dut.executor_decoder_Rd_Rm_value <= Rd_Rm_value_unused
    dut.executor_memaccessor_fwd_has_Rd <= 1
    dut.executor_memaccessor_fwd_Rd_addr <= 4 # r4
    dut.executor_memaccessor_fwd_Rd_value <= Rd_Rm_value
    await clkedge
    # We need to wait a little since the values just became available
    # at the last clkedge
    await Timer(1, 'us')
    assert dut.executor_ready.value.integer
    assert dut.executor_update_Rd.value.integer
    assert not dut.executor_flush_for_pc.value.integer
    assert_eq(dut.executor_databranch_Rd_value, Rd_Rm_value)
    assert not dut.executor_update_pc.value.integer

    dut.executor_decoder_inst <= 0xe5885000 # str r5, [r8]
    Rn_value = 1 # r8
    dut.executor_decoder_Rn_value <= Rn_value
    dut.executor_decoder_Rd_Rm_value <= Rd_Rm_value_unused
    await clkedge
    await Timer(1, 'us')
    assert dut.executor_ready.value.integer
    assert not dut.executor_update_Rd.value.integer
    assert not dut.executor_flush_for_pc.value.integer
    assert not dut.executor_update_pc.value.integer
    assert dut.executor_mem_write_enable.value.integer
    assert_eq(dut.executor_mem_write_value, Rd_Rm_value)

    # Repeat same as above, but replace STR with "mov r4, r5"

    dut.executor_decoder_inst <= 0xe1a05004 # mov r5, r4
    dut.executor_decoder_Rn_value <= 42 # unused
    dut.executor_decoder_Rd_Rm_value <= Rd_Rm_value_unused
    dut.executor_memaccessor_fwd_has_Rd <= 1
    dut.executor_memaccessor_fwd_Rd_addr <= 4 # r4
    dut.executor_memaccessor_fwd_Rd_value <= Rd_Rm_value
    await clkedge
    # We need to wait a little since the values just became available
    # at the last clkedge
    await Timer(1, 'us')
    assert dut.executor_ready.value.integer
    assert dut.executor_update_Rd.value.integer
    assert not dut.executor_flush_for_pc.value.integer
    assert_eq(dut.executor_databranch_Rd_value, Rd_Rm_value)
    assert not dut.executor_update_pc.value.integer

    dut.executor_decoder_inst <= 0xe1a04005 # mov r4, r5
    dut.executor_decoder_Rn_value <= 42 # unused
    dut.executor_decoder_Rd_Rm_value <= Rd_Rm_value_unused
    await clkedge
    await Timer(1, 'us')
    assert dut.executor_ready.value.integer
    assert dut.executor_update_Rd.value.integer
    assert not dut.executor_flush_for_pc.value.integer
    assert not dut.executor_update_pc.value.integer
    assert not dut.executor_mem_write_enable.value.integer
    assert_eq(dut.executor_databranch_Rd_value, Rd_Rm_value)
Example #10
0
async def test_executor_executor_forward(dut):
    """Test executor's data forwarding to itself"""

    clkedge = init_posedge_clk(dut.executor_clk)

    # Need to add PC offset when setting executor_pc due to pipelining
    executor_pc_offset = 8

    # Reset and enable
    dut.executor_nreset <= 0
    await clkedge
    dut.executor_nreset <= 1
    dut.executor_enable <= 1

    Rd_Rm_value = 0xdeadbeef # r4

    # Try mov, then str (memory forwarding)

    dut.executor_decoder_inst <= 0xe1a05004 # mov r5, r4
    dut.executor_decoder_Rn_value <= 42 # unused
    dut.executor_decoder_Rd_Rm_value <= Rd_Rm_value
    await clkedge
    # We need to wait a little since the values just became available
    # at the last clkedge
    await Timer(1, 'us')
    assert dut.executor_ready.value.integer
    assert dut.executor_update_Rd.value.integer
    assert not dut.executor_flush_for_pc.value.integer
    assert_eq(dut.executor_databranch_Rd_value, Rd_Rm_value)
    assert not dut.executor_update_pc.value.integer

    dut.executor_decoder_inst <= 0xe5885000 # str r5, [r8]
    Rd_Rm_value_unused = 0xbabafafa # r5, should not be used
    Rn_value = 1 # r8
    dut.executor_decoder_Rn_value <= Rn_value
    dut.executor_decoder_Rd_Rm_value <= Rd_Rm_value_unused
    await clkedge
    await Timer(1, 'us')
    assert dut.executor_ready.value.integer
    assert not dut.executor_update_Rd.value.integer
    assert not dut.executor_flush_for_pc.value.integer
    assert not dut.executor_update_pc.value.integer
    assert dut.executor_mem_write_enable.value.integer
    assert_eq(dut.executor_mem_write_value, Rd_Rm_value)

    # Try mov r5, r4, then mov r4, r5 (data forwarding)

    dut.executor_decoder_inst <= 0xe1a05004 # mov r5, r4
    dut.executor_decoder_Rn_value <= 42 # unused
    dut.executor_decoder_Rd_Rm_value <= Rd_Rm_value
    await clkedge
    # We need to wait a little since the values just became available
    # at the last clkedge
    await Timer(1, 'us')
    assert dut.executor_ready.value.integer
    assert dut.executor_update_Rd.value.integer
    assert not dut.executor_flush_for_pc.value.integer
    assert_eq(dut.executor_databranch_Rd_value, Rd_Rm_value)
    assert not dut.executor_update_pc.value.integer

    dut.executor_decoder_inst <= 0xe1a04005 # mov r4, r5
    Rd_Rm_value_unused = 0xbabafafa # r5, should not be used
    dut.executor_decoder_Rn_value <= 42 # unused
    dut.executor_decoder_Rd_Rm_value <= Rd_Rm_value_unused
    await clkedge
    await Timer(1, 'us')
    assert dut.executor_ready.value.integer
    assert dut.executor_update_Rd.value.integer
    assert not dut.executor_flush_for_pc.value.integer
    assert not dut.executor_update_pc.value.integer
    assert not dut.executor_mem_write_enable.value.integer
    assert_eq(dut.executor_databranch_Rd_value, Rd_Rm_value)