Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove TestCoreSimple and TestCoreRandomized #597

Merged
merged 1 commit into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions coreblocks/frontend/fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ def __init__(self, gen_params: GenParams, icache: CacheInterface, cont: Method)
# ExceptionCauseRegister uses separate Transaction for it, so performace is not affected.
self.stall_exception.add_conflict(self.resume, Priority.LEFT)

# PC of the last fetched instruction. For now only used in tests.
self.pc = Signal(self.gen_params.isa.xlen)

def elaborate(self, platform):
m = TModule()

Expand Down Expand Up @@ -91,7 +88,6 @@ def stall(exception=False):
with m.If(unsafe_instr):
stall()

m.d.sync += self.pc.eq(target.addr)
m.d.comb += instr.eq(res.instr)

self.cont(m, instr=instr, pc=target.addr, access_fault=fetch_error, rvc=0)
Expand Down Expand Up @@ -138,9 +134,6 @@ def __init__(self, gen_params: GenParams, icache: CacheInterface, cont: Method)

self.perf_rvc = HwCounter("frontend.ifu.rvc", "Number of decompressed RVC instructions")

# PC of the last fetched instruction. For now only used in tests.
self.pc = Signal(self.gen_params.isa.xlen)

def elaborate(self, platform) -> TModule:
m = TModule()

Expand Down Expand Up @@ -231,7 +224,6 @@ def elaborate(self, platform) -> TModule:
m.d.sync += stalled_unsafe.eq(1)
m.d.sync += flushing.eq(1)

m.d.sync += self.pc.eq(current_pc)
with m.If(~cache_resp.error):
m.d.sync += current_pc.eq(current_pc + Mux(is_rvc, C(2, 3), C(4, 3)))

Expand Down
167 changes: 1 addition & 166 deletions test/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,15 @@
from coreblocks.params.configurations import CoreConfiguration, basic_core_config, full_core_config
from coreblocks.peripherals.wishbone import WishboneBus, WishboneMemorySlave

from typing import Optional, cast
from typing import Optional
import random
import subprocess
import tempfile
from parameterized import parameterized_class
from riscvmodel.insn import (
InstructionADDI,
InstructionSLTI,
InstructionSLTIU,
InstructionXORI,
InstructionORI,
InstructionANDI,
InstructionSLLI,
InstructionSRLI,
InstructionSRAI,
InstructionLUI,
InstructionJAL,
)
from riscvmodel.model import Model
from riscvmodel.isa import Instruction, InstructionRType, get_insns
from riscvmodel.variant import RV32I


class CoreTestElaboratable(Elaboratable):
Expand Down Expand Up @@ -58,14 +46,12 @@ def elaborate(self, platform):
)
self.core = Core(gen_params=self.gen_params, wb_instr_bus=wb_instr_bus, wb_data_bus=wb_data_bus)
self.io_in = TestbenchIO(AdapterTrans(self.core.fetch_continue.method))
self.rf_write = TestbenchIO(AdapterTrans(self.core.RF.write))
self.interrupt = TestbenchIO(AdapterTrans(self.core.interrupt_controller.report_interrupt))

m.submodules.wb_mem_slave = self.wb_mem_slave
m.submodules.wb_mem_slave_data = self.wb_mem_slave_data
m.submodules.c = self.core
m.submodules.io_in = self.io_in
m.submodules.rf_write = self.rf_write
m.submodules.interrupt = self.interrupt

m.d.comb += wb_instr_bus.connect(self.wb_mem_slave.bus)
Expand All @@ -74,53 +60,19 @@ def elaborate(self, platform):
return m


def gen_riscv_add_instr(dst, src1, src2):
return 0b0110011 | dst << 7 | src1 << 15 | src2 << 20


def gen_riscv_lui_instr(dst, imm):
return 0b0110111 | dst << 7 | imm << 12


class TestCoreBase(TestCaseWithSimulator):
gen_params: GenParams
m: CoreTestElaboratable

def check_RAT_alloc(self, rat, expected_alloc_count=None): # noqa: N802
allocated = []
for i in range(self.m.gen_params.isa.reg_cnt):
allocated.append((yield rat.entries[i]))
filtered_zeros = list(filter(lambda x: x != 0, allocated))

# check if 0th register is set to 0
self.assertEqual(allocated[0], 0)
# check if there are no duplicate physical registers allocated for two different architectural registers
self.assertEqual(len(filtered_zeros), len(set(filtered_zeros)))
# check if the expected number of allocated registers matches reality
if expected_alloc_count:
self.assertEqual(len(filtered_zeros), expected_alloc_count)

def get_phys_reg_rrat(self, reg_id):
return (yield self.m.core.RRAT.entries[reg_id])

def get_phys_reg_frat(self, reg_id):
return (yield self.m.core.FRAT.entries[reg_id])

def get_arch_reg_val(self, reg_id):
return (yield self.m.core.RF.entries[(yield from self.get_phys_reg_rrat(reg_id))].reg_val)

def get_phys_reg_val(self, reg_id):
return (yield self.m.core.RF.entries[reg_id].reg_val)

def push_instr(self, opcode):
yield from self.m.io_in.call(instr=opcode)

def compare_core_states(self, sw_core):
for i in range(self.gen_params.isa.reg_cnt):
reg_val = sw_core.state.intreg.regs[i].value
unsigned_val = reg_val & 0xFFFFFFFF
self.assertEqual((yield from self.get_arch_reg_val(i)), unsigned_val)

def push_register_load_imm(self, reg_id, val):
addi_imm = signed_to_int(val & 0xFFF, 12)
lui_imm = (val & 0xFFFFF000) >> 12
Expand All @@ -132,123 +84,6 @@ def push_register_load_imm(self, reg_id, val):
yield from self.push_instr(InstructionADDI(reg_id, reg_id, addi_imm).encode())


class TestCoreSimple(TestCoreBase):
def simple_test(self):
# this test first provokes allocation of physical registers,
# then sets the values in those registers, and finally runs
# an actual computation.

# The test sets values in the reg file by hand

# provoking allocation of physical register
for i in range(self.m.gen_params.isa.reg_cnt - 1):
yield from self.push_instr(gen_riscv_add_instr(i + 1, 0, 0))

# waiting for the retirement rat to be set
for i in range(100):
yield

# checking if all registers have been allocated
yield from self.check_RAT_alloc(self.m.core.FRAT, 31)
yield from self.check_RAT_alloc(self.m.core.RRAT, 31)

# writing values to physical registers
yield from self.m.rf_write.call(reg_id=(yield from self.get_phys_reg_rrat(1)), reg_val=1)
yield from self.m.rf_write.call(reg_id=(yield from self.get_phys_reg_rrat(2)), reg_val=2)
yield from self.m.rf_write.call(reg_id=(yield from self.get_phys_reg_rrat(3)), reg_val=3)

# waiting for potential conflicts on rf_write
for i in range(10):
yield

self.assertEqual((yield from self.get_arch_reg_val(1)), 1)
self.assertEqual((yield from self.get_arch_reg_val(2)), 2)
self.assertEqual((yield from self.get_arch_reg_val(3)), 3)

# issuing actual instructions for the test
yield from self.push_instr(gen_riscv_add_instr(4, 1, 2))
yield from self.push_instr(gen_riscv_add_instr(4, 3, 4))
yield from self.push_instr(gen_riscv_lui_instr(5, 1))

# waiting for the instructions to be processed
for i in range(50):
yield

self.assertEqual((yield from self.get_arch_reg_val(1)), 1)
self.assertEqual((yield from self.get_arch_reg_val(2)), 2)
self.assertEqual((yield from self.get_arch_reg_val(3)), 3)
# 1 + 2 + 3 = 6
self.assertEqual((yield from self.get_arch_reg_val(4)), 6)
self.assertEqual((yield from self.get_arch_reg_val(5)), 1 << 12)

def test_simple(self):
self.gen_params = GenParams(basic_core_config)
m = CoreTestElaboratable(self.gen_params)
self.m = m

with self.run_simulation(m) as sim:
sim.add_sync_process(self.simple_test)


class TestCoreRandomized(TestCoreBase):
def randomized_input(self):
infloop_addr = (len(self.instr_mem) - 1) * 4
# wait for PC to go past all instruction
while (yield self.m.core.fetch.pc) != infloop_addr:
yield

# finish calculations
yield from self.tick(50)

yield from self.compare_core_states(self.software_core)

def test_randomized(self):
self.gen_params = GenParams(basic_core_config)
self.instr_count = 300
random.seed(42)

# cast is there to avoid stubbing riscvmodel
instructions = cast(list[type[Instruction]], get_insns(cls=InstructionRType, variant=RV32I))
instructions += [
InstructionADDI,
InstructionSLTI,
InstructionSLTIU,
InstructionXORI,
InstructionORI,
InstructionANDI,
InstructionSLLI,
InstructionSRLI,
InstructionSRAI,
InstructionLUI,
]

# allocate some random values for registers
init_instr_list = list(
InstructionADDI(rd=i, rs1=0, imm=random.randint(-(2**11), 2**11 - 1))
for i in range(self.gen_params.isa.reg_cnt)
)

# generate random instruction stream
instr_list = list(random.choice(instructions)() for _ in range(self.instr_count))
for instr in instr_list:
instr.randomize(RV32I)

self.software_core = Model(RV32I)
self.software_core.execute(init_instr_list)
self.software_core.execute(instr_list)

# We add JAL instruction at the end to effectively create a infinite loop at the end of the program.
all_instr = init_instr_list + instr_list + [InstructionJAL(rd=0, imm=0)]

self.instr_mem = list(map(lambda x: x.encode(), all_instr))

m = CoreTestElaboratable(self.gen_params, instr_mem=self.instr_mem)
self.m = m

with self.run_simulation(m) as sim:
sim.add_sync_process(self.randomized_input)


class TestCoreAsmSourceBase(TestCoreBase):
base_dir: str = "test/asm/"

Expand Down
Loading