Skip to content

Commit

Permalink
Merge branch 'master' into piotro/transaction-component-universal
Browse files Browse the repository at this point in the history
  • Loading branch information
tilk committed Sep 25, 2024
2 parents 677be31 + 123e69c commit 1d54bc1
Show file tree
Hide file tree
Showing 12 changed files with 256 additions and 152 deletions.
5 changes: 3 additions & 2 deletions coreblocks/priv/csr/csr_instances.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from typing import Optional
from coreblocks.arch import CSRAddress
from coreblocks.arch.isa import Extension
from coreblocks.params.genparams import GenParams
from coreblocks.priv.csr.csr_register import CSRRegister
from coreblocks.priv.csr.aliased import AliasedCSR
Expand Down Expand Up @@ -74,8 +75,8 @@ def __init__(self, gen_params: GenParams):
# set `MODE` as fixed to 0 - Direct mode "All exceptions set pc to BASE"
self.mtvec = CSRRegister(CSRAddress.MTVEC, gen_params, ro_bits=0b11)

# TODO: set low bits R/O based on gp align
self.mepc = CSRRegister(CSRAddress.MEPC, gen_params)
mepc_ro_bits = 0b1 if Extension.C in gen_params.isa.extensions else 0b11 # pc alignment (SPEC)
self.mepc = CSRRegister(CSRAddress.MEPC, gen_params, ro_bits=mepc_ro_bits)

def elaborate(self, platform):
m = Module()
Expand Down
2 changes: 2 additions & 0 deletions test/asm/exception_mem.asm
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ sw x2, 4(x0)
sw x1, 4(x0) /* TODO: actually check the side fx */
li x2, 9

.section .bss
.skip 0x8
3 changes: 3 additions & 0 deletions test/asm/fibonacci_mem.asm
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ loop:
bne x3, x4, loop
infloop:
j infloop

.section .bss
.skip 0xC
8 changes: 8 additions & 0 deletions test/asm/init_regs.s
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.macro INIT_REGS_LOAD
# load the initial states of registers
# the value of a register `n` is assumed to be stored under address `0x100 + n * 4`.
lw x1, 0x104(x0)
Expand Down Expand Up @@ -31,3 +32,10 @@
lw x29,0x174(x0)
lw x30,0x178(x0)
lw x31,0x17c(x0)
.endm

.macro INIT_REGS_ALLOCATION
.section .init_regs, "a", @nobits
.skip 0x80
.previous
.endm
10 changes: 7 additions & 3 deletions test/asm/interrupt.asm
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
_start:
.include "init_regs.s"
.include "init_regs.s"

# fibonacci spiced with interrupt handler (also with fibonacci)
_start:
INIT_REGS_LOAD

# fibonacci spiced with interrupt handler (also with fibonacci)
li x1, 0x200
csrw mtvec, x1
li x27, 0 # handler count
Expand Down Expand Up @@ -98,3 +100,5 @@ fail:
.org 0x200
j int_handler
li x31, 0xae # should never happen

INIT_REGS_ALLOCATION
12 changes: 9 additions & 3 deletions test/asm/link.ld
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ start = 0;
SECTIONS
{
.text : { *(.text) }
. = 0x100000000; /* start from 2**32 - trick to emulate Harvard architecture (.bss addresses will start from 0) */
.bss : { *(.bss) }
_end = .;
. = 0x100000000; /* start from 2**32 - trick to emulate Harvard architecture (memory addresses will start from 0) */
.data : {
*(.data)
*(.bss)

. = _end_init_regs > . ? 0x1000 : .; /* skip .init_regs origin allocation if not used */
*(.init_regs)
_end_init_regs = .;
}
}
6 changes: 5 additions & 1 deletion test/asm/wfi_int.asm
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
.include "init_regs.s"

_start:
.include "init_regs.s"
INIT_REGS_LOAD

li x1, 0x100 # set handler vector
csrw mtvec, x1
Expand All @@ -26,3 +28,5 @@ skip:

.org 0x100
j handler

INIT_REGS_ALLOCATION
55 changes: 32 additions & 23 deletions test/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,17 @@
from coreblocks.params.configurations import CoreConfiguration, basic_core_config, full_core_config
from coreblocks.peripherals.wishbone import WishboneMemorySlave

from typing import Optional
import random
import subprocess
import tempfile
from parameterized import parameterized_class


class CoreTestElaboratable(Elaboratable):
def __init__(self, gen_params: GenParams, instr_mem: list[int] = [0], data_mem: Optional[list[int]] = None):
def __init__(self, gen_params: GenParams, instr_mem: list[int] = [0], data_mem: list[int] = []):
self.gen_params = gen_params
self.instr_mem = instr_mem
if data_mem is None:
self.data_mem = [0] * (2**10)
else:
self.data_mem = data_mem
self.data_mem = data_mem

def elaborate(self, platform):
m = Module()
Expand Down Expand Up @@ -71,20 +67,18 @@ def get_arch_reg_val(self, reg_id):
class TestCoreAsmSourceBase(TestCoreBase):
base_dir: str = "test/asm/"

def prepare_source(self, filename):
bin_src = []
def prepare_source(self, filename, *, c_extension=False):
with (
tempfile.NamedTemporaryFile() as asm_tmp,
tempfile.NamedTemporaryFile() as ld_tmp,
tempfile.NamedTemporaryFile() as bin_tmp,
):
subprocess.check_call(
[
"riscv64-unknown-elf-as",
"-mabi=ilp32",
# Specified manually, because toolchains from most distributions don't support new extensioins
# and this test should be accessible locally.
"-march=rv32im_zicsr",
f"-march=rv32im{'c' if c_extension else ''}_zicsr",
"-I",
self.base_dir,
"-o",
Expand All @@ -104,16 +98,31 @@ def prepare_source(self, filename):
ld_tmp.name,
]
)
subprocess.check_call(
["riscv64-unknown-elf-objcopy", "-O", "binary", "-j", ".text", ld_tmp.name, bin_tmp.name]
)
code = bin_tmp.read()
for word_idx in range(0, len(code), 4):
word = code[word_idx : word_idx + 4]
bin_instr = int.from_bytes(word, "little")
bin_src.append(bin_instr)

return bin_src
def load_section(section: str):
with tempfile.NamedTemporaryFile() as bin_tmp:
bin = []

subprocess.check_call(
[
"riscv64-unknown-elf-objcopy",
"-O",
"binary",
"-j",
section,
ld_tmp.name,
bin_tmp.name,
]
)

data = bin_tmp.read()
for word_idx in range(0, len(data), 4):
word = data[word_idx : word_idx + 4]
bin.append(int.from_bytes(word, "little"))

return bin

return {"text": load_section(".text"), "data": load_section(".data")}


@parameterized_class(
Expand Down Expand Up @@ -146,7 +155,8 @@ def test_asm_source(self):
self.gen_params = GenParams(self.configuration)

bin_src = self.prepare_source(self.source_file)
self.m = CoreTestElaboratable(self.gen_params, instr_mem=bin_src)
self.m = CoreTestElaboratable(self.gen_params, instr_mem=bin_src["text"], data_mem=bin_src["data"])

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

Expand Down Expand Up @@ -269,10 +279,9 @@ def do_interrupt():

def test_interrupted_prog(self):
bin_src = self.prepare_source(self.source_file)
data_mem = [0] * (2**10)
for reg_id, val in self.start_regvals.items():
data_mem[self.reg_init_mem_offset // 4 + reg_id] = val
self.m = CoreTestElaboratable(self.gen_params, instr_mem=bin_src, data_mem=data_mem)
bin_src["data"][self.reg_init_mem_offset // 4 + reg_id] = val
self.m = CoreTestElaboratable(self.gen_params, instr_mem=bin_src["text"], data_mem=bin_src["data"])
with self.run_simulation(self.m) as sim:
sim.add_sync_process(self.run_with_interrupt_process)
sim.add_sync_process(self.clear_level_interrupt_procsess)
90 changes: 23 additions & 67 deletions test/transactron/lib/test_transaction_lib.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import pytest
from itertools import product
import random
import itertools
from operator import and_
from functools import reduce
from amaranth.sim import Settle, Passive
from amaranth.sim import Settle
from typing import Optional, TypeAlias
from parameterized import parameterized
from collections import deque
Expand Down Expand Up @@ -139,22 +138,22 @@ def test_pipelining(self):


class TestMemoryBank(TestCaseWithSimulator):
test_conf = [(9, 3, 3, 3, 14), (16, 1, 1, 3, 15), (16, 1, 1, 1, 16), (12, 3, 1, 1, 17)]
test_conf = [(9, 3, 3, 3, 14), (16, 1, 1, 3, 15), (16, 1, 1, 1, 16), (12, 3, 1, 1, 17), (9, 0, 0, 0, 18)]

parametrized_input = [tc + sf for tc, sf in itertools.product(test_conf, [(True,), (False,)])]

@parameterized.expand(parametrized_input)
def test_mem(self, max_addr, writer_rand, reader_req_rand, reader_resp_rand, seed, safe_writes):
@pytest.mark.parametrize("max_addr, writer_rand, reader_req_rand, reader_resp_rand, seed", test_conf)
@pytest.mark.parametrize("transparent", [False, True])
def test_mem(
self, max_addr: int, writer_rand: int, reader_req_rand: int, reader_resp_rand: int, seed: int, transparent: bool
):
test_count = 200

data_width = 6
m = SimpleTestCircuit(
MemoryBank(data_layout=[("data", data_width)], elem_count=max_addr, safe_writes=safe_writes)
MemoryBank(data_layout=[("data", data_width)], elem_count=max_addr, transparent=transparent)
)

data: list[int] = list(0 for _ in range(max_addr))
read_req_queue = deque()
addr_queue = deque()

random.seed(seed)

Expand All @@ -163,83 +162,40 @@ def writer():
d = random.randrange(2**data_width)
a = random.randrange(max_addr)
yield from m.write.call(data=d, addr=a)
for _ in range(2):
for _ in range(2 if not transparent else 0):
yield Settle()
data[a] = d
yield from self.random_wait(writer_rand, min_cycle_cnt=1)
yield from self.random_wait(writer_rand)

def reader_req():
for cycle in range(test_count):
a = random.randrange(max_addr)
yield from m.read_req.call(addr=a)
for _ in range(1):
yield Settle()
if safe_writes:
d = data[a]
read_req_queue.append(d)
else:
addr_queue.append((cycle, a))
yield from self.random_wait(reader_req_rand, min_cycle_cnt=1)
d = data[a]
read_req_queue.append(d)
yield from self.random_wait(reader_req_rand)

def reader_resp():
for cycle in range(test_count):
for _ in range(3):
yield Settle()
while not read_req_queue:
yield from self.random_wait(reader_resp_rand, min_cycle_cnt=1)
yield from self.random_wait(reader_resp_rand or 1, min_cycle_cnt=1)
for _ in range(3):
yield Settle()
d = read_req_queue.popleft()
assert (yield from m.read_resp.call()) == {"data": d}
yield from self.random_wait(reader_resp_rand, min_cycle_cnt=1)

def internal_reader_resp():
assert m._dut._internal_read_resp_trans is not None
yield Passive()
while True:
if addr_queue:
instr, a = addr_queue[0]
else:
yield
continue
d = data[a]
# check when internal method has been run to capture
# memory state for tests purposes
if (yield m._dut._internal_read_resp_trans.grant):
addr_queue.popleft()
read_req_queue.append(d)
yield
yield from self.random_wait(reader_resp_rand)

with self.run_simulation(m) as sim:
pipeline_test = writer_rand == 0 and reader_req_rand == 0 and reader_resp_rand == 0
max_cycles = test_count + 2 if pipeline_test else 100000

with self.run_simulation(m, max_cycles=max_cycles) as sim:
sim.add_sync_process(reader_req)
sim.add_sync_process(reader_resp)
sim.add_sync_process(writer)
if not safe_writes:
sim.add_sync_process(internal_reader_resp)

def test_pipelined(self):
data_width = 6
max_addr = 9
m = SimpleTestCircuit(MemoryBank(data_layout=[("data", data_width)], elem_count=max_addr, safe_writes=False))

random.seed(14)

def process():
a = 3
d1 = random.randrange(2**data_width)
yield from m.write.call_init(data=d1, addr=a)
yield from m.read_req.call_init(addr=a)
yield
d2 = random.randrange(2**data_width)
yield from m.write.call_init(data=d2, addr=a)
yield from m.read_resp.call_init()
yield
yield from m.write.disable()
yield from m.read_req.disable()
ret_d1 = (yield from m.read_resp.call_result())["data"]
assert d1 == ret_d1
yield
ret_d2 = (yield from m.read_resp.call_result())["data"]
assert d2 == ret_d2

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


class TestAsyncMemoryBank(TestCaseWithSimulator):
Expand Down
Loading

0 comments on commit 1d54bc1

Please sign in to comment.