diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml
index c515414c2..cbba538a7 100644
--- a/.github/workflows/benchmark.yml
+++ b/.github/workflows/benchmark.yml
@@ -14,7 +14,7 @@ jobs:
name: Synthesis benchmarks
runs-on: ubuntu-latest
timeout-minutes: 40
- container: ghcr.io/kuznia-rdzeni/amaranth-synth:ecp5-3.11
+ container: ghcr.io/kuznia-rdzeni/amaranth-synth:ecp5-2023.11.19_v
steps:
- uses: actions/checkout@v3
@@ -63,7 +63,7 @@ jobs:
build-perf-benchmarks:
name: Build performance benchmarks
runs-on: ubuntu-latest
- container: ghcr.io/kuznia-rdzeni/riscv-toolchain:2023.10.08_v
+ container: ghcr.io/kuznia-rdzeni/riscv-toolchain:2023.11.19_v
steps:
- name: Checkout
uses: actions/checkout@v3
@@ -83,7 +83,7 @@ jobs:
name: Run performance benchmarks
runs-on: ubuntu-latest
timeout-minutes: 60
- container: ghcr.io/kuznia-rdzeni/verilator:v5.008-3.11
+ container: ghcr.io/kuznia-rdzeni/verilator:v5.008-2023.11.19_v
needs: build-perf-benchmarks
steps:
- name: Checkout
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 41e20abc5..1bcdac433 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -15,7 +15,7 @@ jobs:
build-regression-tests:
name: Build regression tests
runs-on: ubuntu-latest
- container: ghcr.io/kuznia-rdzeni/riscv-toolchain:2023.10.08_v
+ container: ghcr.io/kuznia-rdzeni/riscv-toolchain:2023.11.19_v
outputs:
cache_hit: ${{ steps.cache-regression.outputs.cache-hit }}
steps:
@@ -54,7 +54,7 @@ jobs:
name: Run regression tests
runs-on: ubuntu-latest
timeout-minutes: 10
- container: ghcr.io/kuznia-rdzeni/verilator:v5.008-3.11
+ container: ghcr.io/kuznia-rdzeni/verilator:v5.008-2023.11.19_v
needs: build-regression-tests
steps:
- name: Checkout
@@ -97,12 +97,8 @@ jobs:
. venv/bin/activate
scripts/run_tests.py -a regression
- - name: Test Report
- uses: EnricoMi/publish-unit-test-result-action@v2
- with:
- files: test/regression/cocotb/results.xml
- check_name: cocotb test results
- comment_mode: off
+ - name: Check for test failure
+ run: ./scripts/check_test_results.py
unit-test:
name: Run unit tests
@@ -131,7 +127,7 @@ jobs:
run: ./scripts/run_tests.py --verbose
- name: Check traces
- run: ./scripts/run_tests.py -t -c 1 TestCore
+ run: ./scripts/run_tests.py -t -c 1 TestCore
lint:
name: Check code formatting and typing
diff --git a/docker/AmaranthSynthECP5.Dockerfile b/docker/AmaranthSynthECP5.Dockerfile
index 3b9326ccf..3ae726972 100644
--- a/docker/AmaranthSynthECP5.Dockerfile
+++ b/docker/AmaranthSynthECP5.Dockerfile
@@ -3,7 +3,7 @@ FROM ubuntu:23.04
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive \
apt-get install -y --no-install-recommends \
- python3.11 python3-pip git yosys lsb-release \
+ python3.11 python3-pip python3.11-venv git yosys lsb-release \
build-essential cmake python3-dev libboost-all-dev libeigen3-dev && \
rm -rf /var/lib/apt/lists/*
diff --git a/docker/Verilator.Dockerfile b/docker/Verilator.Dockerfile
index 64c60c5e4..785e76b26 100644
--- a/docker/Verilator.Dockerfile
+++ b/docker/Verilator.Dockerfile
@@ -3,12 +3,12 @@ FROM ubuntu:23.04
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive \
apt-get install -y --no-install-recommends \
- python3.11 libpython3.11 python3-pip git lsb-release \
+ python3.11 libpython3.11 python3-pip python3.11-venv git lsb-release \
perl perl-doc help2man make autoconf g++ flex bison ccache numactl \
libgoogle-perftools-dev libfl-dev zlib1g-dev && \
rm -rf /var/lib/apt/lists/*
-RUN git clone --recursive \
+RUN git clone --recursive --shallow-since=2023.03.01 \
https://github.com/verilator/verilator.git \
verilator && \
cd verilator && \
diff --git a/docker/riscv-toolchain.Dockerfile b/docker/riscv-toolchain.Dockerfile
index d35c604b9..957141eb0 100644
--- a/docker/riscv-toolchain.Dockerfile
+++ b/docker/riscv-toolchain.Dockerfile
@@ -3,15 +3,39 @@ FROM ubuntu:23.04
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive \
apt-get install -y --no-install-recommends \
- autoconf automake autotools-dev curl python3 bc lsb-release \
+ autoconf automake autotools-dev curl python3.11 python3.11-venv python3-pip bc lsb-release \
libmpc-dev libmpfr-dev libgmp-dev gawk build-essential \
- bison flex texinfo gperf libtool patchutils zlib1g-dev \
- libexpat-dev ninja-build git ca-certificates python-is-python3 && \
+ bison flex texinfo gperf libtool patchutils zlib1g-dev device-tree-compiler \
+ libexpat-dev ninja-build git ca-certificates python-is-python3 \
+ libssl-dev libbz2-dev libreadline-dev libsqlite3-dev libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev && \
rm -rf /var/lib/apt/lists/*
-RUN git clone https://github.com/riscv/riscv-gnu-toolchain && \
+RUN git clone --shallow-since=2023.05.01 https://github.com/riscv/riscv-gnu-toolchain && \
cd riscv-gnu-toolchain && \
git checkout 2023.05.14 && \
./configure --with-multilib-generator="rv32i-ilp32--a*zifence*zicsr;rv32im-ilp32--a*zifence*zicsr;rv32ic-ilp32--a*zifence*zicsr;rv32imc-ilp32--a*zifence*zicsr;rv32imfc-ilp32f--a*zifence;rv32i_zmmul-ilp32--a*zifence*zicsr;rv32ic_zmmul-ilp32--a*zifence*zicsr" && \
make -j$(nproc) && \
cd / && rm -rf riscv-gnu-toolchain
+
+RUN git clone --shallow-since=2023.10.01 https://github.com/riscv-software-src/riscv-isa-sim.git spike && \
+ cd spike && \
+ git checkout eeef09ebb894c3bb7e42b7b47aae98792b8eef79 && \
+ mkdir build/ install/ && \
+ cd build/ && \
+ ../configure --prefix=/spike/install/ && \
+ make -j$(nproc) && \
+ make install && \
+ cd .. && \
+ rm -rf build/
+
+RUN git clone --depth=1 https://github.com/pyenv/pyenv.git .pyenv && \
+ export PATH=/.pyenv/bin:$PATH && \
+ export PYENV_ROOT=/root/.pyenv && \
+ eval "$(pyenv init --path)" && \
+ pyenv install 3.6.15 && \
+ pyenv global 3.6.15 && \
+ python -m venv venv3.6 && \
+ . venv3.6/bin/activate && \
+ python -m pip install --upgrade pip && \
+ python -m pip install riscof && \
+ pyenv global system
diff --git a/docs/Current_graph.md b/docs/Current_graph.md
deleted file mode 100644
index 1d64977b4..000000000
--- a/docs/Current_graph.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# Full transaction-method graph
-
-```{eval-rst}
-.. include:: auto_graph.rst
-```
diff --git a/docs/Assumptions.md b/docs/assumptions.md
similarity index 100%
rename from docs/Assumptions.md
rename to docs/assumptions.md
diff --git a/docs/current-graph.md b/docs/current-graph.md
new file mode 100644
index 000000000..c176682f2
--- /dev/null
+++ b/docs/current-graph.md
@@ -0,0 +1,12 @@
+# Full transaction-method graph
+
+
+
+
+ ```{eval-rst}
+ .. include:: auto_graph.rst
+
+ ```
+
+
+
diff --git a/docs/Development_environment.md b/docs/development-environment.md
similarity index 100%
rename from docs/Development_environment.md
rename to docs/development-environment.md
diff --git a/docs/Home.md b/docs/home.md
similarity index 100%
rename from docs/Home.md
rename to docs/home.md
diff --git a/docs/index.md b/docs/index.md
index 85d7b3e2c..0e16a25ec 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -5,17 +5,17 @@
maxdepth: 3
---
-Home.md
-Assumptions.md
-Development_environment.md
-Transactions.md
-scheduler/Overview.md
-shared_structs/Implementation/RS_impl.md
-shared_structs/RS.md
-Current_graph.md
-Problem-checklist.md
-synthesis/Synthesis.md
+home.md
+assumptions.md
+development-environment.md
+transactions.md
+scheduler/overview.md
+shared-structs/implementation/rs-impl.md
+shared-structs/rs.md
+current-graph.md
+problem-checklist.md
+synthesis/synthesis.md
components/icache.md
-miscellany/exceptionsSummary.md
+miscellany/exceptions-summary.md
api.md
```
diff --git a/docs/miscellany/exceptionsSummary.md b/docs/miscellany/exceptions-summary.md
similarity index 100%
rename from docs/miscellany/exceptionsSummary.md
rename to docs/miscellany/exceptions-summary.md
diff --git a/docs/Problem-checklist.md b/docs/problem-checklist.md
similarity index 100%
rename from docs/Problem-checklist.md
rename to docs/problem-checklist.md
diff --git a/docs/scheduler/Overview.md b/docs/scheduler/overview.md
similarity index 100%
rename from docs/scheduler/Overview.md
rename to docs/scheduler/overview.md
diff --git a/docs/shared_structs/Implementation/RS_impl.md b/docs/shared-structs/implementation/rs-impl.md
similarity index 100%
rename from docs/shared_structs/Implementation/RS_impl.md
rename to docs/shared-structs/implementation/rs-impl.md
diff --git a/docs/shared_structs/RS.md b/docs/shared-structs/rs.md
similarity index 100%
rename from docs/shared_structs/RS.md
rename to docs/shared-structs/rs.md
diff --git a/docs/synthesis/Synthesis.md b/docs/synthesis/synthesis.md
similarity index 100%
rename from docs/synthesis/Synthesis.md
rename to docs/synthesis/synthesis.md
diff --git a/docs/Transactions.md b/docs/transactions.md
similarity index 100%
rename from docs/Transactions.md
rename to docs/transactions.md
diff --git a/scripts/check_test_results.py b/scripts/check_test_results.py
new file mode 100755
index 000000000..c10af9bc2
--- /dev/null
+++ b/scripts/check_test_results.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python3
+
+import sys
+import os
+import pathlib
+import xml.etree.ElementTree as eT
+
+FAILURE_TAG = "failure"
+TOP_DIR = pathlib.Path(__file__).parent.parent
+TEST_RESULTS_FILE = TOP_DIR.joinpath("test/regression/cocotb/results.xml")
+
+if not os.path.exists(TEST_RESULTS_FILE):
+ print("File not found: ", TEST_RESULTS_FILE)
+ sys.exit(1)
+
+tree = eT.parse(TEST_RESULTS_FILE)
+
+if len(list(tree.iter(FAILURE_TAG))) > 0:
+ print("Some regression tests failed")
+ sys.exit(1)
+
+print("All regression tests pass")
diff --git a/test/structs_common/test_rat.py b/test/structs_common/test_rat.py
new file mode 100644
index 000000000..2119a9ced
--- /dev/null
+++ b/test/structs_common/test_rat.py
@@ -0,0 +1,85 @@
+from ..common import TestCaseWithSimulator, SimpleTestCircuit
+
+from coreblocks.structs_common.rat import FRAT, RRAT
+from coreblocks.params import GenParams
+from coreblocks.params.configurations import test_core_config
+
+from collections import deque
+from random import Random
+
+
+class TestFrontendRegisterAliasTable(TestCaseWithSimulator):
+ def gen_input(self):
+ for _ in range(self.test_steps):
+ rl = self.rand.randrange(self.gen_params.isa.reg_cnt)
+ rp = self.rand.randrange(1, 2**self.gen_params.phys_regs_bits) if rl != 0 else 0
+ rl_s1 = self.rand.randrange(self.gen_params.isa.reg_cnt)
+ rl_s2 = self.rand.randrange(self.gen_params.isa.reg_cnt)
+
+ self.to_execute_list.append({"rl": rl, "rp": rp, "rl_s1": rl_s1, "rl_s2": rl_s2})
+
+ def do_rename(self):
+ for _ in range(self.test_steps):
+ to_execute = self.to_execute_list.pop()
+ res = yield from self.m.rename.call(
+ rl_dst=to_execute["rl"], rp_dst=to_execute["rp"], rl_s1=to_execute["rl_s1"], rl_s2=to_execute["rl_s2"]
+ )
+ self.assertEqual(res["rp_s1"], self.expected_entries[to_execute["rl_s1"]])
+ self.assertEqual(res["rp_s2"], self.expected_entries[to_execute["rl_s2"]])
+
+ self.expected_entries[to_execute["rl"]] = to_execute["rp"]
+
+ def test_single(self):
+ self.rand = Random(0)
+ self.test_steps = 2000
+ self.gen_params = GenParams(test_core_config.replace(phys_regs_bits=5, rob_entries_bits=6))
+ m = SimpleTestCircuit(FRAT(gen_params=self.gen_params))
+ self.m = m
+
+ self.log_regs = self.gen_params.isa.reg_cnt
+ self.phys_regs = 2**self.gen_params.phys_regs_bits
+
+ self.to_execute_list = deque()
+ self.expected_entries = [0 for _ in range(self.log_regs)]
+
+ self.gen_input()
+ with self.run_simulation(m) as sim:
+ sim.add_sync_process(self.do_rename)
+
+
+class TestRetirementRegisterAliasTable(TestCaseWithSimulator):
+ def gen_input(self):
+ for _ in range(self.test_steps):
+ rl = self.rand.randrange(self.gen_params.isa.reg_cnt)
+ rp = self.rand.randrange(1, 2**self.gen_params.phys_regs_bits) if rl != 0 else 0
+ side_fx = self.rand.randrange(0, 2)
+
+ self.to_execute_list.append({"rl": rl, "rp": rp, "side_fx": side_fx})
+
+ def do_commit(self):
+ for _ in range(self.test_steps):
+ to_execute = self.to_execute_list.pop()
+ res = yield from self.m.commit.call(
+ rl_dst=to_execute["rl"], rp_dst=to_execute["rp"], side_fx=to_execute["side_fx"]
+ )
+ self.assertEqual(res["old_rp_dst"], self.expected_entries[to_execute["rl"]])
+
+ if to_execute["side_fx"]:
+ self.expected_entries[to_execute["rl"]] = to_execute["rp"]
+
+ def test_single(self):
+ self.rand = Random(0)
+ self.test_steps = 2000
+ self.gen_params = GenParams(test_core_config.replace(phys_regs_bits=5, rob_entries_bits=6))
+ m = SimpleTestCircuit(RRAT(gen_params=self.gen_params))
+ self.m = m
+
+ self.log_regs = self.gen_params.isa.reg_cnt
+ self.phys_regs = 2**self.gen_params.phys_regs_bits
+
+ self.to_execute_list = deque()
+ self.expected_entries = [0 for _ in range(self.log_regs)]
+
+ self.gen_input()
+ with self.run_simulation(m) as sim:
+ sim.add_sync_process(self.do_commit)
diff --git a/test/transactions/test_transaction_lib.py b/test/transactions/test_transaction_lib.py
index d43540860..6daa6517c 100644
--- a/test/transactions/test_transaction_lib.py
+++ b/test/transactions/test_transaction_lib.py
@@ -351,7 +351,7 @@ def test_many_out(self):
sim.add_sync_process(self.generate_producer(i))
-class MethodTransformerTestCircuit(Elaboratable):
+class MethodMapTestCircuit(Elaboratable):
def __init__(self, iosize: int, use_methods: bool, use_dicts: bool):
self.iosize = iosize
self.use_methods = use_methods
@@ -399,25 +399,21 @@ def _(arg: Record):
def _(arg: Record):
return otransform(m, arg)
- trans = MethodTransformer(
- self.target.adapter.iface, i_transform=(layout, imeth), o_transform=(layout, ometh)
- )
+ trans = MethodMap(self.target.adapter.iface, i_transform=(layout, imeth), o_transform=(layout, ometh))
else:
- trans = MethodTransformer(
+ trans = MethodMap(
self.target.adapter.iface,
i_transform=(layout, itransform),
o_transform=(layout, otransform),
)
- m.submodules.trans = trans
-
- m.submodules.source = self.source = TestbenchIO(AdapterTrans(trans.method))
+ m.submodules.source = self.source = TestbenchIO(AdapterTrans(trans.use(m)))
return m
class TestMethodTransformer(TestCaseWithSimulator):
- m: MethodTransformerTestCircuit
+ m: MethodMapTestCircuit
def source(self):
for i in range(2**self.m.iosize):
@@ -430,19 +426,19 @@ def target(self, data):
return {"data": (data << 1) | (data >> (self.m.iosize - 1))}
def test_method_transformer(self):
- self.m = MethodTransformerTestCircuit(4, False, False)
+ self.m = MethodMapTestCircuit(4, False, False)
with self.run_simulation(self.m) as sim:
sim.add_sync_process(self.source)
sim.add_sync_process(self.target)
def test_method_transformer_dicts(self):
- self.m = MethodTransformerTestCircuit(4, False, True)
+ self.m = MethodMapTestCircuit(4, False, True)
with self.run_simulation(self.m) as sim:
sim.add_sync_process(self.source)
sim.add_sync_process(self.target)
def test_method_transformer_with_methods(self):
- self.m = MethodTransformerTestCircuit(4, True, True)
+ self.m = MethodMapTestCircuit(4, True, True)
with self.run_simulation(self.m) as sim:
sim.add_sync_process(self.source)
sim.add_sync_process(self.target)
@@ -517,9 +513,9 @@ def elaborate(self, platform):
if self.add_combiner:
combiner = (layout, lambda _, vs: {"data": sum(vs)})
- m.submodules.product = product = MethodProduct(methods, combiner)
+ product = MethodProduct(methods, combiner)
- m.submodules.method = self.method = TestbenchIO(AdapterTrans(product.method))
+ m.submodules.method = self.method = TestbenchIO(AdapterTrans(product.use(m)))
return m
@@ -704,9 +700,9 @@ def elaborate(self, platform):
if self.add_combiner:
combiner = (layout, lambda _, vs: {"data": sum(Mux(s, r, 0) for (s, r) in vs)})
- m.submodules.product = product = MethodTryProduct(methods, combiner)
+ product = MethodTryProduct(methods, combiner)
- m.submodules.method = self.method = TestbenchIO(AdapterTrans(product.method))
+ m.submodules.method = self.method = TestbenchIO(AdapterTrans(product.use(m)))
return m
diff --git a/transactron/lib/transformers.py b/transactron/lib/transformers.py
index b3d1e2470..18c3ac73a 100644
--- a/transactron/lib/transformers.py
+++ b/transactron/lib/transformers.py
@@ -1,28 +1,56 @@
+from abc import ABC
from amaranth import *
from ..core import *
from ..core import RecordDict
from typing import Optional
from collections.abc import Callable
-from transactron.utils import ValueLike, assign, AssignType
+from transactron.utils import ValueLike, assign, AssignType, ModuleLike
from .connectors import Forwarder, ManyToOneConnectTrans, ConnectTrans
__all__ = [
- "MethodTransformer",
+ "Transformer",
+ "MethodMap",
"MethodFilter",
"MethodProduct",
"MethodTryProduct",
"Collector",
"CatTrans",
- "ConnectAndTransformTrans",
+ "ConnectAndMapTrans",
]
-class MethodTransformer(Elaboratable):
- """Method transformer.
+class Transformer(ABC):
+ """Method transformer abstract class.
+
+ Method transformers construct a new method which utilizes other methods.
+
+ Attributes
+ ----------
+ method: Method
+ The method.
+ """
+
+ method: Method
+
+ def use(self, m: ModuleLike):
+ """
+ Returns the method and adds the transformer to a module.
+
+ Parameters
+ ----------
+ m: Module or TModule
+ The module to which this transformer is added as a submodule.
+ """
+ m.submodules += self
+ return self.method
+
+
+class MethodMap(Transformer, Elaboratable):
+ """Bidirectional map for methods.
Takes a target method and creates a transformed method which calls the
- original target method, transforming the input and output values.
- The transformation functions take two parameters, a `Module` and the
+ original target method, mapping the input and output values with
+ functions. The mapping functions take two parameters, a `Module` and the
`Record` being transformed. Alternatively, a `Method` can be
passed.
@@ -45,13 +73,13 @@ def __init__(
target: Method
The target method.
i_transform: (record layout, function or Method), optional
- Input transformation. If specified, it should be a pair of a
+ Input mapping function. If specified, it should be a pair of a
function and a input layout for the transformed method.
- If not present, input is not transformed.
+ If not present, input is passed unmodified.
o_transform: (record layout, function or Method), optional
- Output transformation. If specified, it should be a pair of a
+ Output mapping function. If specified, it should be a pair of a
function and a output layout for the transformed method.
- If not present, output is not transformed.
+ If not present, output is passed unmodified.
"""
if i_transform is None:
i_transform = (target.data_in.layout, lambda _, x: x)
@@ -73,7 +101,7 @@ def _(arg):
return m
-class MethodFilter(Elaboratable):
+class MethodFilter(Transformer, Elaboratable):
"""Method filter.
Takes a target method and creates a method which calls the target method
@@ -129,7 +157,7 @@ def _(arg):
return m
-class MethodProduct(Elaboratable):
+class MethodProduct(Transformer, Elaboratable):
def __init__(
self,
targets: list[Method],
@@ -177,7 +205,7 @@ def _(arg):
return m
-class MethodTryProduct(Elaboratable):
+class MethodTryProduct(Transformer, Elaboratable):
def __init__(
self,
targets: list[Method],
@@ -229,7 +257,7 @@ def _(arg):
return m
-class Collector(Elaboratable):
+class Collector(Transformer, Elaboratable):
"""Single result collector.
Creates method that collects results of many methods with identical
@@ -308,14 +336,13 @@ def elaborate(self, platform):
return m
-class ConnectAndTransformTrans(Elaboratable):
- """Connecting transaction with transformations.
+class ConnectAndMapTrans(Elaboratable):
+ """Connecting transaction with mapping functions.
Behaves like `ConnectTrans`, but modifies the transferred data using
- functions or `Method`s. Equivalent to a combination of
- `ConnectTrans` and `MethodTransformer`. The transformation
- functions take two parameters, a `Module` and the `Record` being
- transformed.
+ functions or `Method`s. Equivalent to a combination of `ConnectTrans`
+ and `MethodMap`. The mapping functions take two parameters, a `Module`
+ and the `Record` being transformed.
"""
def __init__(
@@ -346,7 +373,7 @@ def __init__(
def elaborate(self, platform):
m = TModule()
- m.submodules.transformer = transformer = MethodTransformer(
+ m.submodules.transformer = transformer = MethodMap(
self.method2,
i_transform=(self.method1.data_out.layout, self.i_fun),
o_transform=(self.method1.data_in.layout, self.o_fun),