diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 1fc7fac1d..859df8ef1 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -16,7 +16,7 @@ jobs: timeout-minutes: 40 container: ghcr.io/kuznia-rdzeni/amaranth-synth:ecp5-2023.11.19_v steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set ownership (Github Actions workaround) run: | @@ -24,7 +24,7 @@ jobs: chown -R $(id -u):$(id -g) $PWD - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.11' @@ -66,14 +66,14 @@ jobs: container: ghcr.io/kuznia-rdzeni/riscv-toolchain:2024.03.12 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: recursive - name: Build embench run: cd test/external/embench && make - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: "embench" path: | @@ -87,7 +87,7 @@ jobs: needs: build-perf-benchmarks steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set ownership (Github Actions workaround) run: | @@ -95,7 +95,7 @@ jobs: chown -R $(id -u):$(id -g) $PWD - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.11' @@ -111,7 +111,7 @@ jobs: . venv/bin/activate PYTHONHASHSEED=0 TRANSACTRON_VERBOSE=1 ./scripts/gen_verilog.py --verbose --config full - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: "embench" path: test/external/embench/build diff --git a/.github/workflows/deploy_gh_pages.yml b/.github/workflows/deploy_gh_pages.yml index 89fdeea7d..eaf35d90a 100644 --- a/.github/workflows/deploy_gh_pages.yml +++ b/.github/workflows/deploy_gh_pages.yml @@ -21,10 +21,10 @@ jobs: BUILD_DIR: "build" steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.11" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 06ceb129d..05200b7e4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,10 +18,10 @@ jobs: timeout-minutes: 5 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.11' @@ -37,7 +37,7 @@ jobs: . venv/bin/activate PYTHONHASHSEED=0 TRANSACTRON_VERBOSE=1 ./scripts/gen_verilog.py --verbose --config full - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: "verilog-full-core" path: | @@ -60,7 +60,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Get submodules HEAD hash working-directory: . @@ -72,7 +72,7 @@ jobs: - name: Cache compiled and reference riscv-arch-test id: cache-riscv-arch-test - uses: actions/cache@v3 + uses: actions/cache@v4 env: cache-name: cache-riscv-arch-test with: @@ -93,7 +93,7 @@ jobs: - if: ${{ steps.cache-riscv-arch-test.outputs.cache-hit != 'true' }} name: Checkout with submodules - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: recursive @@ -127,7 +127,7 @@ jobs: - if: ${{ steps.cache-riscv-arch-test.outputs.cache-hit != 'true' }} name: Upload compiled and reference tests artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: "riscof-tests" path: | @@ -143,10 +143,10 @@ jobs: timeout-minutes: 30 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.11' @@ -157,7 +157,7 @@ jobs: python3 -m pip install --upgrade pip python3 -m pip install -r requirements-dev.txt - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 name: Download full verilog core with: name: "verilog-full-core" @@ -168,7 +168,7 @@ jobs: git config --global --add safe.directory /__w/coreblocks/coreblocks git submodule > .gitmodules-hash - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Download tests from cache env: cache-name: cache-riscv-arch-test @@ -204,7 +204,7 @@ jobs: timeout-minutes: 10 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Get submodules HEAD hash run: | @@ -213,7 +213,7 @@ jobs: - name: Cache regression-tests id: cache-regression - uses: actions/cache@v3 + uses: actions/cache@v4 env: cache-name: cache-regression-tests with: @@ -229,7 +229,7 @@ jobs: - if: ${{ steps.cache-regression.outputs.cache-hit != 'true' }} name: Checkout with submodules - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: recursive @@ -238,7 +238,7 @@ jobs: - if: ${{ steps.cache-regression.outputs.cache-hit != 'true' }} name: Upload riscv-tests - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: test/external/riscv-tests @@ -250,10 +250,10 @@ jobs: needs: [ build-regression-tests, build-core ] steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.11' @@ -264,7 +264,7 @@ jobs: python3 -m pip install --upgrade pip python3 -m pip install -r requirements-dev.txt - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 name: Download full verilog core with: name: "verilog-full-core" @@ -275,7 +275,7 @@ jobs: git config --global --add safe.directory /__w/coreblocks/coreblocks git submodule > .gitmodules-hash - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Download tests from cache env: cache-name: cache-regression-tests @@ -307,10 +307,10 @@ jobs: timeout-minutes: 15 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.11' cache: 'pip' @@ -339,10 +339,10 @@ jobs: timeout-minutes: 5 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.11' cache: 'pip' diff --git a/coreblocks/params/instr.py b/coreblocks/params/instr.py index 8f14d6b11..370d25b84 100644 --- a/coreblocks/params/instr.py +++ b/coreblocks/params/instr.py @@ -3,7 +3,7 @@ from amaranth.hdl import ValueCastable from amaranth import * -from transactron.utils import ValueLike +from transactron.utils import ValueLike, int_to_signed from coreblocks.params.isa_params import * from coreblocks.frontend.decoder.isa import * @@ -53,6 +53,10 @@ def __init__( def pack(self) -> Value: return Cat(C(0b11, 2), self.opcode, self.rd, self.funct3, self.rs1, self.rs2, self.funct7) + @staticmethod + def encode(opcode: int, rd: int, funct3: int, rs1: int, rs2: int, funct7: int): + return int(f"{funct7:07b}{rs2:05b}{rs1:05b}{funct3:03b}{rd:05b}{opcode:05b}11", 2) + class ITypeInstr(RISCVInstr): def __init__(self, opcode: ValueLike, rd: ValueLike, funct3: ValueLike, rs1: ValueLike, imm: ValueLike): @@ -65,6 +69,11 @@ def __init__(self, opcode: ValueLike, rd: ValueLike, funct3: ValueLike, rs1: Val def pack(self) -> Value: return Cat(C(0b11, 2), self.opcode, self.rd, self.funct3, self.rs1, self.imm) + @staticmethod + def encode(opcode: int, rd: int, funct3: int, rs1: int, imm: int): + imm = int_to_signed(imm, 12) + return int(f"{imm:012b}{rs1:05b}{funct3:03b}{rd:05b}{opcode:05b}11", 2) + class STypeInstr(RISCVInstr): def __init__(self, opcode: ValueLike, imm: ValueLike, funct3: ValueLike, rs1: ValueLike, rs2: ValueLike): @@ -77,6 +86,12 @@ def __init__(self, opcode: ValueLike, imm: ValueLike, funct3: ValueLike, rs1: Va def pack(self) -> Value: return Cat(C(0b11, 2), self.opcode, self.imm[0:5], self.funct3, self.rs1, self.rs2, self.imm[5:12]) + @staticmethod + def encode(opcode: int, imm: int, funct3: int, rs1: int, rs2: int): + imm = int_to_signed(imm, 12) + imm_str = f"{imm:012b}" + return int(f"{imm_str[5:12]:07b}{rs2:05b}{rs1:05b}{funct3:03b}{imm_str[0:5]:05b}{opcode:05b}11", 2) + class BTypeInstr(RISCVInstr): def __init__(self, opcode: ValueLike, imm: ValueLike, funct3: ValueLike, rs1: ValueLike, rs2: ValueLike): @@ -99,6 +114,16 @@ def pack(self) -> Value: self.imm[12], ) + @staticmethod + def encode(opcode: int, imm: int, funct3: int, rs1: int, rs2: int): + imm = int_to_signed(imm, 13) + imm_str = f"{imm:013b}" + return int( + f"{imm_str[12]:01b}{imm_str[5:11]:06b}{rs2:05b}{rs1:05b}{funct3:03b}{imm_str[1:5]:04b}" + + f"{imm_str[11]:01b}{opcode:05b}11", + 2, + ) + class UTypeInstr(RISCVInstr): def __init__(self, opcode: ValueLike, rd: ValueLike, imm: ValueLike): @@ -109,6 +134,11 @@ def __init__(self, opcode: ValueLike, rd: ValueLike, imm: ValueLike): def pack(self) -> Value: return Cat(C(0b11, 2), self.opcode, self.rd, self.imm[12:]) + @staticmethod + def encode(opcode: int, rd: int, imm: int): + imm = int_to_signed(imm, 20) + return int(f"{imm:020b}{rd:05b}{opcode:05b}11", 2) + class JTypeInstr(RISCVInstr): def __init__(self, opcode: ValueLike, rd: ValueLike, imm: ValueLike): @@ -119,6 +149,14 @@ def __init__(self, opcode: ValueLike, rd: ValueLike, imm: ValueLike): def pack(self) -> Value: return Cat(C(0b11, 2), self.opcode, self.rd, self.imm[12:20], self.imm[11], self.imm[1:11], self.imm[20]) + @staticmethod + def encode(opcode: int, rd: int, imm: int): + imm = int_to_signed(imm, 21) + imm_str = f"{imm:021b}" + return int( + f"{imm_str[20]:01b}{imm_str[1:11]:010b}{imm_str[11]:01b}{imm_str[12:20]:08b}{rd:05b}{opcode:05b}11", 2 + ) + class IllegalInstr(RISCVInstr): def __init__(self): @@ -127,6 +165,10 @@ def __init__(self): def pack(self) -> Value: return C(1).replicate(32) # Instructions with all bits set to 1 are reserved to be illegal. + @staticmethod + def encode(opcode: int, rd: int, imm: int): + return int("1" * 32, 2) + class EBreakInstr(ITypeInstr): def __init__(self): diff --git a/requirements-dev.txt b/requirements-dev.txt index 1d9530305..fa39140f1 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,9 +1,8 @@ -r requirements.txt -black==23.3.0 +black==24.3.0 docutils==0.15.2 flake8==6.0.0 pep8-naming==0.13.3 -git+https://github.com/kristopher38/riscv-python-model@b5d0737#riscv-model markupsafe==2.0.1 myst-parser==0.18.0 numpydoc==1.5.0 diff --git a/test/lsu/test_dummylsu.py b/test/lsu/test_dummylsu.py index 4211720a6..776f0e2cd 100644 --- a/test/lsu/test_dummylsu.py +++ b/test/lsu/test_dummylsu.py @@ -173,9 +173,9 @@ def generate_instr(self, max_reg_val, max_imm_val): self.exception_queue.append( { "rob_id": rob_id, - "cause": ExceptionCause.LOAD_ADDRESS_MISALIGNED - if misaligned - else ExceptionCause.LOAD_ACCESS_FAULT, + "cause": ( + ExceptionCause.LOAD_ADDRESS_MISALIGNED if misaligned else ExceptionCause.LOAD_ACCESS_FAULT + ), "pc": 0, } ) diff --git a/test/regression/cocotb/benchmark.Makefile b/test/regression/cocotb/benchmark.Makefile index 5c89d3785..9962315fb 100644 --- a/test/regression/cocotb/benchmark.Makefile +++ b/test/regression/cocotb/benchmark.Makefile @@ -15,6 +15,7 @@ SIM_BUILD = build/benchmark # Yosys/Amaranth borkedness workaround ifeq ($(SIM),verilator) EXTRA_ARGS += -Wno-CASEINCOMPLETE -Wno-CASEOVERLAP -Wno-WIDTHEXPAND -Wno-WIDTHTRUNC + BUILD_ARGS += -j`nproc` endif ifeq ($(TRACES),1) diff --git a/test/regression/cocotb/signature.Makefile b/test/regression/cocotb/signature.Makefile index 74b803083..b4f690635 100644 --- a/test/regression/cocotb/signature.Makefile +++ b/test/regression/cocotb/signature.Makefile @@ -15,6 +15,7 @@ SIM_BUILD = build/signature # Yosys/Amaranth borkedness workaround ifeq ($(SIM),verilator) EXTRA_ARGS += -Wno-CASEINCOMPLETE -Wno-CASEOVERLAP -Wno-WIDTHEXPAND -Wno-WIDTHTRUNC + BUILD_ARGS += -j`nproc` endif ifeq ($(TRACES),1) diff --git a/test/regression/cocotb/test.Makefile b/test/regression/cocotb/test.Makefile index bda120bc1..210618067 100644 --- a/test/regression/cocotb/test.Makefile +++ b/test/regression/cocotb/test.Makefile @@ -15,6 +15,7 @@ SIM_BUILD = build/test # Yosys/Amaranth borkedness workaround ifeq ($(SIM),verilator) EXTRA_ARGS += -Wno-CASEINCOMPLETE -Wno-CASEOVERLAP -Wno-WIDTHEXPAND -Wno-WIDTHTRUNC + BUILD_ARGS += -j`nproc` endif ifeq ($(TRACES),1) diff --git a/test/test_core.py b/test/test_core.py index 21869184e..44c68fe4c 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -7,7 +7,9 @@ from transactron.testing import TestCaseWithSimulator, TestbenchIO from coreblocks.core import Core +from coreblocks.frontend.decoder import Opcode, Funct3 from coreblocks.params import GenParams +from coreblocks.params.instr import * from coreblocks.params.configurations import CoreConfiguration, basic_core_config, full_core_config from coreblocks.peripherals.wishbone import WishboneSignature, WishboneMemorySlave @@ -16,10 +18,6 @@ import subprocess import tempfile from parameterized import parameterized_class -from riscvmodel.insn import ( - InstructionADDI, - InstructionLUI, -) class CoreTestElaboratable(Elaboratable): @@ -81,8 +79,8 @@ def push_register_load_imm(self, reg_id, val): if val & 0x800: lui_imm = (lui_imm + 1) & (0xFFFFF) - yield from self.push_instr(InstructionLUI(reg_id, lui_imm).encode()) - yield from self.push_instr(InstructionADDI(reg_id, reg_id, addi_imm).encode()) + yield from self.push_instr(UTypeInstr.encode(Opcode.LUI, reg_id, lui_imm)) + yield from self.push_instr(ITypeInstr.encode(Opcode.OP_IMM, reg_id, Funct3.ADD, reg_id, addi_imm)) class TestCoreAsmSourceBase(TestCoreBase): diff --git a/transactron/lib/transformers.py b/transactron/lib/transformers.py index f874cea2c..5e9b1a6b0 100644 --- a/transactron/lib/transformers.py +++ b/transactron/lib/transformers.py @@ -60,8 +60,7 @@ def use(self, m: ModuleLike): class Unifier(Transformer, Protocol): method: Method - def __init__(self, targets: list[Method]): - ... + def __init__(self, targets: list[Method]): ... class MethodMap(Elaboratable, Transformer): diff --git a/transactron/utils/_typing.py b/transactron/utils/_typing.py index 32497c7d5..e8e3152b9 100644 --- a/transactron/utils/_typing.py +++ b/transactron/utils/_typing.py @@ -86,17 +86,13 @@ # Protocols for Amaranth classes class _ModuleBuilderDomainsLike(Protocol): - def __getattr__(self, name: str) -> "_ModuleBuilderDomain": - ... + def __getattr__(self, name: str) -> "_ModuleBuilderDomain": ... - def __getitem__(self, name: str) -> "_ModuleBuilderDomain": - ... + def __getitem__(self, name: str) -> "_ModuleBuilderDomain": ... - def __setattr__(self, name: str, value: "_ModuleBuilderDomain") -> None: - ... + def __setattr__(self, name: str, value: "_ModuleBuilderDomain") -> None: ... - def __setitem__(self, name: str, value: "_ModuleBuilderDomain") -> None: - ... + def __setitem__(self, name: str, value: "_ModuleBuilderDomain") -> None: ... _T_ModuleBuilderDomains = TypeVar("_T_ModuleBuilderDomains", bound=_ModuleBuilderDomainsLike) @@ -127,80 +123,59 @@ def Default(self) -> AbstractContextManager[None]: # noqa: N802 def FSM( # noqa: N802 self, reset: Optional[str] = ..., domain: str = ..., name: str = ... - ) -> AbstractContextManager["amaranth.hdl._dsl.FSM"]: - ... + ) -> AbstractContextManager["amaranth.hdl._dsl.FSM"]: ... def State(self, name: str) -> AbstractContextManager[None]: # noqa: N802 ... @property - def next(self) -> NoReturn: - ... + def next(self) -> NoReturn: ... @next.setter - def next(self, name: str) -> None: - ... + def next(self, name: str) -> None: ... class AbstractSignatureMembers(Protocol): - def flip(self) -> "AbstractSignatureMembers": - ... + def flip(self) -> "AbstractSignatureMembers": ... - def __eq__(self, other) -> bool: - ... + def __eq__(self, other) -> bool: ... - def __contains__(self, name: str) -> bool: - ... + def __contains__(self, name: str) -> bool: ... - def __getitem__(self, name: str) -> Member: - ... + def __getitem__(self, name: str) -> Member: ... - def __setitem__(self, name: str, member: Member) -> NoReturn: - ... + def __setitem__(self, name: str, member: Member) -> NoReturn: ... - def __delitem__(self, name: str) -> NoReturn: - ... + def __delitem__(self, name: str) -> NoReturn: ... - def __iter__(self) -> Iterator[str]: - ... + def __iter__(self) -> Iterator[str]: ... - def __len__(self) -> int: - ... + def __len__(self) -> int: ... - def flatten(self, *, path: tuple[str | int, ...] = ...) -> Iterator[tuple[tuple[str | int, ...], Member]]: - ... + def flatten(self, *, path: tuple[str | int, ...] = ...) -> Iterator[tuple[tuple[str | int, ...], Member]]: ... - def create(self, *, path: tuple[str | int, ...] = ..., src_loc_at: int = ...) -> dict[str, Any]: - ... + def create(self, *, path: tuple[str | int, ...] = ..., src_loc_at: int = ...) -> dict[str, Any]: ... - def __repr__(self) -> str: - ... + def __repr__(self) -> str: ... class AbstractSignature(Protocol): - def flip(self) -> "AbstractSignature": - ... + def flip(self) -> "AbstractSignature": ... @property - def members(self) -> AbstractSignatureMembers: - ... + def members(self) -> AbstractSignatureMembers: ... - def __eq__(self, other) -> bool: - ... + def __eq__(self, other) -> bool: ... - def flatten(self, obj) -> Iterator[tuple[tuple[str | int, ...], Flow, ValueLike]]: - ... + def flatten(self, obj) -> Iterator[tuple[tuple[str | int, ...], Flow, ValueLike]]: ... - def is_compliant(self, obj, *, reasons: Optional[list[str]] = ..., path: tuple[str, ...] = ...) -> bool: - ... + def is_compliant(self, obj, *, reasons: Optional[list[str]] = ..., path: tuple[str, ...] = ...) -> bool: ... def create( self, *, path: tuple[str | int, ...] = ..., src_loc_at: int = ... - ) -> "AbstractInterface[AbstractSignature]": - ... + ) -> "AbstractInterface[AbstractSignature]": ... - def __repr__(self) -> str: - ... + def __repr__(self) -> str: ... _T_AbstractSignature = TypeVar("_T_AbstractSignature", bound=AbstractSignature) @@ -211,14 +186,12 @@ class AbstractInterface(Protocol, Generic[_T_AbstractSignature]): class HasElaborate(Protocol): - def elaborate(self, platform) -> "HasElaborate": - ... + def elaborate(self, platform) -> "HasElaborate": ... @runtime_checkable class HasDebugSignals(Protocol): - def debug_signals(self) -> SignalBundle: - ... + def debug_signals(self) -> SignalBundle: ... def type_self_kwargs_as(as_func: Callable[Concatenate[Any, P], Any]): diff --git a/transactron/utils/amaranth_ext/elaboratables.py b/transactron/utils/amaranth_ext/elaboratables.py index 3af4ded98..b0ddbae35 100644 --- a/transactron/utils/amaranth_ext/elaboratables.py +++ b/transactron/utils/amaranth_ext/elaboratables.py @@ -59,13 +59,11 @@ def case(n: Optional[int] = None): @overload -def OneHotSwitchDynamic(m: ModuleLike, test: Value, *, default: Literal[True]) -> Iterable[Optional[int]]: - ... +def OneHotSwitchDynamic(m: ModuleLike, test: Value, *, default: Literal[True]) -> Iterable[Optional[int]]: ... @overload -def OneHotSwitchDynamic(m: ModuleLike, test: Value, *, default: Literal[False] = False) -> Iterable[int]: - ... +def OneHotSwitchDynamic(m: ModuleLike, test: Value, *, default: Literal[False] = False) -> Iterable[int]: ... def OneHotSwitchDynamic(m: ModuleLike, test: Value, *, default: bool = False) -> Iterable[Optional[int]]: