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

Destroy all records #612

Merged
merged 4 commits into from
Mar 14, 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
28 changes: 15 additions & 13 deletions coreblocks/cache/icache.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import operator

from amaranth import *
from amaranth.lib.data import View
from amaranth.utils import exact_log2

from transactron.core import def_method, Priority, TModule
Expand All @@ -12,6 +13,7 @@
from coreblocks.peripherals.bus_adapter import BusMasterInterface

from coreblocks.cache.iface import CacheInterface, CacheRefillerInterface
from transactron.utils.transactron_helpers import make_layout

__all__ = [
"ICache",
Expand Down Expand Up @@ -109,11 +111,11 @@ def __init__(self, layouts: ICacheLayouts, params: ICacheParameters, refiller: C
self.flush = Method()
self.flush.add_conflict(self.issue_req, Priority.LEFT)

self.addr_layout = [
self.addr_layout = make_layout(
("offset", self.params.offset_bits),
("index", self.params.index_bits),
("tag", self.params.tag_bits),
]
)

self.perf_loads = HwCounter("frontend.icache.loads", "Number of requests to the L1 Instruction Cache")
self.perf_hits = HwCounter("frontend.icache.hits")
Expand All @@ -131,7 +133,7 @@ def deserialize_addr(self, raw_addr: Value) -> dict[str, Value]:
"tag": raw_addr[-self.params.tag_bits :],
}

def serialize_addr(self, addr: Record) -> Value:
def serialize_addr(self, addr: View) -> Value:
return Cat(addr.offset, addr.index, addr.tag)

def elaborate(self, platform):
Expand Down Expand Up @@ -186,7 +188,7 @@ def elaborate(self, platform):

# Fast path - read requests
request_valid = self.req_fifo.read.ready
request_addr = Record(self.addr_layout)
request_addr = Signal(self.addr_layout)

tag_hit = [tag_data.valid & (tag_data.tag == request_addr.tag) for tag_data in self.mem.tag_rd_data]
tag_hit_any = reduce(operator.or_, tag_hit)
Expand All @@ -195,7 +197,7 @@ def elaborate(self, platform):
for i in OneHotSwitchDynamic(m, Cat(tag_hit)):
m.d.comb += mem_out.eq(self.mem.data_rd_data[i])

instr_out = extract_instr_from_word(m, self.params, mem_out, request_addr[:])
instr_out = extract_instr_from_word(m, self.params, mem_out, Value.cast(request_addr))

refill_error_saved = Signal()
m.d.comb += needs_refill.eq(request_valid & ~tag_hit_any & ~refill_error_saved)
Expand All @@ -214,7 +216,7 @@ def _():
self.req_latency.stop(m)
return self.res_fwd.read(m)

mem_read_addr = Record(self.addr_layout)
mem_read_addr = Signal(self.addr_layout)
m.d.comb += assign(mem_read_addr, request_addr)

@def_method(m, self.issue_req, ready=accepting_requests)
Expand Down Expand Up @@ -304,21 +306,21 @@ class ICacheMemory(Elaboratable):
def __init__(self, params: ICacheParameters) -> None:
self.params = params

self.tag_data_layout = [("valid", 1), ("tag", self.params.tag_bits)]
self.tag_data_layout = make_layout(("valid", 1), ("tag", self.params.tag_bits))

self.way_wr_en = Signal(self.params.num_of_ways)

self.tag_rd_index = Signal(self.params.index_bits)
self.tag_rd_data = Array([Record(self.tag_data_layout) for _ in range(self.params.num_of_ways)])
self.tag_rd_data = Array([Signal(self.tag_data_layout) for _ in range(self.params.num_of_ways)])
self.tag_wr_index = Signal(self.params.index_bits)
self.tag_wr_en = Signal()
self.tag_wr_data = Record(self.tag_data_layout)
self.tag_wr_data = Signal(self.tag_data_layout)

self.data_addr_layout = [("index", self.params.index_bits), ("offset", self.params.offset_bits)]
self.data_addr_layout = make_layout(("index", self.params.index_bits), ("offset", self.params.offset_bits))

self.data_rd_addr = Record(self.data_addr_layout)
self.data_rd_addr = Signal(self.data_addr_layout)
self.data_rd_data = Array([Signal(self.params.word_width) for _ in range(self.params.num_of_ways)])
self.data_wr_addr = Record(self.data_addr_layout)
self.data_wr_addr = Signal(self.data_addr_layout)
self.data_wr_en = Signal()
self.data_wr_data = Signal(self.params.word_width)

Expand All @@ -328,7 +330,7 @@ def elaborate(self, platform):
for i in range(self.params.num_of_ways):
way_wr = self.way_wr_en[i]

tag_mem = Memory(width=len(self.tag_wr_data), depth=self.params.num_of_sets)
tag_mem = Memory(width=len(Value.cast(self.tag_wr_data)), depth=self.params.num_of_sets)
tag_mem_rp = tag_mem.read_port()
tag_mem_wp = tag_mem.write_port()
m.submodules[f"tag_mem_{i}_rp"] = tag_mem_rp
Expand Down
3 changes: 2 additions & 1 deletion coreblocks/fu/div_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from collections.abc import Sequence

from amaranth import *
from amaranth.lib import data

from coreblocks.params.fu_params import FunctionalComponentParams
from coreblocks.params import Funct3, GenParams, FuncUnitLayouts, OpType
Expand Down Expand Up @@ -33,7 +34,7 @@ def get_instructions(self) -> Sequence[tuple]:
]


def get_input(arg: Record) -> tuple[Value, Value]:
def get_input(arg: data.View) -> tuple[Value, Value]:
return arg.s1_val, Mux(arg.imm, arg.imm, arg.s2_val)


Expand Down
2 changes: 1 addition & 1 deletion coreblocks/fu/fu_decoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class Decoder(Elaboratable):
Attributes
----------
decode_fn: Signal
exec_fn: Record
exec_fn: View
"""

def __init__(self, gen_params: GenParams, decode_fn: Type[IntFlag], ops: Sequence[tuple], check_optype: bool):
Expand Down
15 changes: 10 additions & 5 deletions coreblocks/lsu/pma.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from functools import reduce
from operator import or_
from amaranth import *
from amaranth.lib import data

from coreblocks.params import *
from transactron.utils import HasElaborate
Expand Down Expand Up @@ -29,6 +30,11 @@ class PMARegion:
mmio: bool = False


class PMALayout(data.StructLayout):
def __init__(self):
super().__init__({"mmio": unsigned(1)})


class PMAChecker(Elaboratable):
"""
Implementation of physical memory attributes checker. It may or may not be a part of LSU.
Expand All @@ -38,21 +44,20 @@ class PMAChecker(Elaboratable):
----------
addr : Signal
Memory address, for which PMAs are requested.
result : Record
result : View
PMAs for given address.
"""

def __init__(self, gen_params: GenParams) -> None:
# poor man's interval list
self.segments = gen_params.pma
self.attr_layout = gen_params.get(PMALayouts).pma_attrs_layout
self.result = Record(self.attr_layout)
self.result = Signal(PMALayout())
self.addr = Signal(gen_params.isa.xlen)

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

outputs = [Record(self.attr_layout) for _ in self.segments]
outputs = [Signal(PMALayout()) for _ in self.segments]

# zero output if addr not in region, propagate value if addr in region
for i, segment in enumerate(self.segments):
Expand All @@ -64,6 +69,6 @@ def elaborate(self, platform) -> HasElaborate:
m.d.comb += outputs[i].eq(segment.mmio)

# OR all outputs
m.d.comb += self.result.eq(reduce(or_, outputs, 0))
m.d.comb += self.result.eq(reduce(or_, [Value.cast(o) for o in outputs], 0))

return m
6 changes: 0 additions & 6 deletions coreblocks/params/layouts.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
"UnsignedMulUnitLayouts",
"RATLayouts",
"LSULayouts",
"PMALayouts",
"CSRLayouts",
"ICacheLayouts",
"JumpBranchLayouts",
Expand Down Expand Up @@ -551,11 +550,6 @@ def __init__(self, gen_params: GenParams):
self.accept = make_layout(fields.data, fields.exception, fields.cause)


class PMALayouts:
def __init__(self, gen_params: GenParams):
self.pma_attrs_layout = [("mmio", 1)]


class CSRLayouts:
"""Layouts used in the control and status registers."""

Expand Down
5 changes: 3 additions & 2 deletions coreblocks/structs_common/rf.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from amaranth import *
from transactron import Method, def_method, TModule
from coreblocks.params import RFLayouts, GenParams
from transactron.utils.transactron_helpers import make_layout

__all__ = ["RegisterFile"]

Expand All @@ -9,9 +10,9 @@ class RegisterFile(Elaboratable):
def __init__(self, *, gen_params: GenParams):
self.gen_params = gen_params
layouts = gen_params.get(RFLayouts)
self.internal_layout = [("reg_val", gen_params.isa.xlen), ("valid", 1)]
self.internal_layout = make_layout(("reg_val", gen_params.isa.xlen), ("valid", 1))
self.read_layout = layouts.rf_read_out
self.entries = Array(Record(self.internal_layout) for _ in range(2**gen_params.phys_regs_bits))
self.entries = Array(Signal(self.internal_layout) for _ in range(2**gen_params.phys_regs_bits))

self.read1 = Method(i=layouts.rf_read_in, o=layouts.rf_read_out)
self.read2 = Method(i=layouts.rf_read_in, o=layouts.rf_read_out)
Expand Down
6 changes: 3 additions & 3 deletions stubs/amaranth/hdl/_ast.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -410,14 +410,14 @@ class Repl(Value):

class _SignalMeta(ABCMeta):
@overload
def __call__(cls, shape: ShapeCastable[T], src_loc_at = ..., **kwargs) -> T:
def __call__(cls, shape: ShapeCastable[T], src_loc_at: int = ..., **kwargs) -> T:
...

@overload
def __call__(cls, shape = ..., src_loc_at = ..., **kwargs) -> Signal:
def __call__(cls, shape: ShapeLike = ..., src_loc_at: int = ..., **kwargs) -> Signal:
...

def __call__(cls, shape = ..., src_loc_at = ..., **kwargs):
def __call__(cls, shape: ShapeLike = ..., src_loc_at: int = ..., **kwargs):
...


Expand Down
16 changes: 8 additions & 8 deletions test/transactions/test_assign.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from amaranth.lib import data
from amaranth.hdl._ast import ArrayProxy, Slice

from transactron.utils._typing import LayoutLike
from transactron.utils._typing import MethodLayout
from transactron.utils import AssignType, assign
from transactron.utils.assign import AssignArg, AssignFields

Expand Down Expand Up @@ -54,15 +54,15 @@ def mkstruct(layout):
],
)
class TestAssign(TestCase):
# constructs `assign` arguments (records, proxies, dicts) which have an "inner" and "outer" part
# parameterized with a Record-like constructor and a layout of the inner part
build: Callable[[Callable[[LayoutLike], AssignArg], LayoutLike], AssignArg]
# constructs `assign` arguments (views, proxies, dicts) which have an "inner" and "outer" part
# parameterized with a constructor and a layout of the inner part
build: Callable[[Callable[[MethodLayout], AssignArg], MethodLayout], AssignArg]
# constructs field specifications for `assign`, takes field specifications for the inner part
wrap: Callable[[AssignFields], AssignFields]
# extracts the inner part of the structure
extr: Callable[[AssignArg], Record | ArrayProxy]
# Record-like constructor, takes a record layout
mk: Callable[[LayoutLike], AssignArg]
extr: Callable[[AssignArg], ArrayProxy]
# constructor, takes a layout
mk: Callable[[MethodLayout], AssignArg]

def test_rhs_exception(self):
with self.assertRaises(KeyError):
Expand Down Expand Up @@ -99,7 +99,7 @@ def test_wrong_bits(self):
("list", layout_ab, layout_ab, ["a", "a"]),
]
)
def test_assign_a(self, name, layout1: LayoutLike, layout2: LayoutLike, atype: AssignType):
def test_assign_a(self, name, layout1: MethodLayout, layout2: MethodLayout, atype: AssignType):
lhs = self.build(self.mk, layout1)
rhs = self.build(self.mk, layout2)
alist = list(assign(lhs, rhs, fields=self.wrap(atype)))
Expand Down
17 changes: 9 additions & 8 deletions transactron/lib/storage.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from amaranth import *
from amaranth.utils import *

from transactron.utils.transactron_helpers import from_method_layout
from transactron.utils.transactron_helpers import from_method_layout, make_layout
from ..core import *
from ..utils import SrcLoc, get_src_loc
from typing import Optional
Expand All @@ -23,7 +23,7 @@ class MemoryBank(Elaboratable):
The read request method. Accepts an `addr` from which data should be read.
Only ready if there is there is a place to buffer response.
read_resp: Method
The read response method. Return `data_layout` Record which was saved on `addr` given by last
The read response method. Return `data_layout` View which was saved on `addr` given by last
`read_req` method call. Only ready after `read_req` call.
write: Method
The write method. Accepts `addr` where data should be saved, `data` in form of `data_layout`
Expand All @@ -33,7 +33,7 @@ class MemoryBank(Elaboratable):
def __init__(
self,
*,
data_layout: MethodLayout,
data_layout: LayoutList,
elem_count: int,
granularity: Optional[int] = None,
safe_writes: bool = True,
Expand All @@ -58,17 +58,18 @@ def __init__(
Alternatively, the source location to use instead of the default.
"""
self.src_loc = get_src_loc(src_loc)
self.data_layout = data_layout
self.data_layout = make_layout(*data_layout)
self.elem_count = elem_count
self.granularity = granularity
self.width = from_method_layout(self.data_layout).size
self.addr_width = bits_for(self.elem_count - 1)
self.safe_writes = safe_writes

self.read_req_layout: LayoutList = [("addr", self.addr_width)]
self.write_layout = [("addr", self.addr_width), ("data", self.data_layout)]
write_layout = [("addr", self.addr_width), ("data", self.data_layout)]
if self.granularity is not None:
self.write_layout.append(("mask", self.width // self.granularity))
write_layout.append(("mask", self.width // self.granularity))
self.write_layout = make_layout(*write_layout)

self.read_req = Method(i=self.read_req_layout, src_loc=self.src_loc)
self.read_resp = Method(o=self.data_layout, src_loc=self.src_loc)
Expand All @@ -85,8 +86,8 @@ def elaborate(self, platform) -> TModule:
prev_read_addr = Signal(self.addr_width)
write_pending = Signal()
write_req = Signal()
write_args = Record(self.write_layout)
write_args_prev = Record(self.write_layout)
write_args = Signal(self.write_layout)
write_args_prev = Signal(self.write_layout)
m.d.comb += read_port.addr.eq(prev_read_addr)

zipper = ArgumentsToResultsZipper([("valid", 1)], self.data_layout)
Expand Down
7 changes: 1 addition & 6 deletions transactron/utils/_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,13 @@
Any,
TYPE_CHECKING,
)
from collections.abc import Iterable, Iterator, Mapping, Sequence
from collections.abc import Iterable, Iterator, Mapping
from contextlib import AbstractContextManager
from enum import Enum
from amaranth import *
from amaranth.lib.data import StructLayout, View
from amaranth.lib.wiring import Flow, Member
from amaranth.hdl import ShapeCastable, ValueCastable
from amaranth.hdl.rec import Direction, Layout

if TYPE_CHECKING:
from amaranth.hdl._ast import Statement
Expand All @@ -33,7 +32,6 @@
"ValueLike",
"ShapeLike",
"StatementLike",
"LayoutLike",
"SwitchKey",
"SrcLoc",
"MethodLayout",
Expand All @@ -60,9 +58,6 @@
ValueLike: TypeAlias = Value | int | Enum | ValueCastable
ShapeLike: TypeAlias = Shape | ShapeCastable | int | range | type[Enum]
StatementLike: TypeAlias = Union["Statement", Iterable["StatementLike"]]
LayoutLike: TypeAlias = (
Layout | Sequence[tuple[str, "ShapeLike | LayoutLike"] | tuple[str, "ShapeLike | LayoutLike", Direction]]
)
SwitchKey: TypeAlias = str | int | Enum
SrcLoc: TypeAlias = tuple[str, int]

Expand Down
Loading
Loading