Skip to content

Commit

Permalink
Components at top level in Transactron (kuznia-rdzeni#708)
Browse files Browse the repository at this point in the history
  • Loading branch information
tilk authored May 24, 2024
1 parent cf09d6d commit b46fa21
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 181 deletions.
81 changes: 16 additions & 65 deletions constants/ecp5_platforms.py
Original file line number Diff line number Diff line change
@@ -1,51 +1,33 @@
from collections.abc import Callable, Iterable
from itertools import chain
from typing import TypeAlias
from amaranth import *
from amaranth.build.dsl import Subsignal
from amaranth.vendor import LatticeECP5Platform
from amaranth.build import Resource, Attrs, Pins, Clock, PinsN
from amaranth.lib.wiring import Signature, Flow

from constants.ecp5_pinout import ecp5_bg756_pins, ecp5_bg756_pclk

from coreblocks.peripherals.wishbone import WishboneParameters
from transactron.lib import AdapterBase

__all__ = ["make_ecp5_platform"]


def WishboneResource( # noqa: N802
*args, dat_r, dat_w, rst, ack, adr, cyc, stall, err, lock, rty, sel, stb, we, conn=None
):
io = []

io.append(Subsignal("dat_r", Pins(dat_r, dir="i", conn=conn)))
io.append(Subsignal("dat_w", Pins(dat_w, dir="o", conn=conn)))
io.append(Subsignal("rst", Pins(rst, dir="o", conn=conn, assert_width=1)))
io.append(Subsignal("ack", Pins(ack, dir="i", conn=conn, assert_width=1)))
io.append(Subsignal("adr", Pins(adr, dir="o", conn=conn)))
io.append(Subsignal("cyc", Pins(cyc, dir="o", conn=conn, assert_width=1)))
io.append(Subsignal("stall", Pins(stall, dir="i", conn=conn, assert_width=1)))
io.append(Subsignal("err", Pins(err, dir="i", conn=conn, assert_width=1)))
io.append(Subsignal("lock", Pins(lock, dir="o", conn=conn, assert_width=1)))
io.append(Subsignal("rty", Pins(rty, dir="i", conn=conn, assert_width=1)))
io.append(Subsignal("sel", Pins(sel, dir="o", conn=conn)))
io.append(Subsignal("stb", Pins(stb, dir="o", conn=conn, assert_width=1)))
io.append(Subsignal("we", Pins(we, dir="o", conn=conn, assert_width=1)))
def iterate_members(signature: Signature):
for hier_name, member in signature.members.flatten():
if not member.is_port:
continue
name = "__".join(str(x) for x in hier_name)
yield name, member

return Resource.family(*args, default_name="wishbone", ios=io)


def AdapterResource(*args, en, done, data_in, data_out, conn=None): # noqa: N802
def SignatureResource(*args, signature: Signature, default_name: str, conn=None, **pinargs: str): # noqa: N802
io = []

io.append(Subsignal("en", Pins(en, dir="i", conn=conn, assert_width=1)))
io.append(Subsignal("done", Pins(done, dir="o", conn=conn, assert_width=1)))
if data_in:
io.append(Subsignal("data_in", Pins(data_in, dir="i", conn=conn)))
if data_out:
io.append(Subsignal("data_out", Pins(data_out, dir="o", conn=conn)))
for name, member in iterate_members(signature):
dir = "i" if member.flow == Flow.In else "o"
io.append(Subsignal(name, Pins(pinargs[name], dir=dir, conn=conn)))

return Resource.family(*args, default_name="adapter", ios=io)
return Resource.family(*args, default_name=default_name, ios=io)


class PinManager:
Expand All @@ -66,41 +48,10 @@ def named_pin(self, names: Iterable[str]):
ResourceBuilder: TypeAlias = Callable[[PinManager], list[Resource]]


def wishbone_resources(wb_params: WishboneParameters):
def make_resources(pins: PinManager) -> list[Resource]:
return [
WishboneResource(
0,
dat_r=pins.p(wb_params.data_width),
dat_w=pins.p(wb_params.data_width),
rst=pins.p(),
ack=pins.p(),
adr=pins.p(wb_params.addr_width),
cyc=pins.p(),
stall=pins.p(),
err=pins.p(),
lock=pins.p(),
rty=pins.p(),
sel=pins.p(wb_params.data_width // wb_params.granularity),
stb=pins.p(),
we=pins.p(),
),
]

return make_resources


def adapter_resources(adapter: AdapterBase, number: int):
def signature_resources(signature: Signature, default_name: str, number: int):
def make_resources(pins: PinManager) -> list[Resource]:
return [
AdapterResource(
number,
en=pins.p(),
done=pins.p(),
data_in=pins.p(adapter.data_in.shape().size),
data_out=pins.p(adapter.data_out.shape().size),
)
]
pinargs = {name: pins.p(Shape.cast(member.shape).width) for name, member in iterate_members(signature)}
return [SignatureResource(number, signature=signature, default_name=default_name, **pinargs)]

return make_resources

Expand Down
25 changes: 16 additions & 9 deletions coreblocks/core.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from amaranth import *
from amaranth.lib.wiring import flipped, connect
from amaranth.lib.wiring import Component, flipped, connect, Out
from transactron.utils.amaranth_ext.elaboratables import ModuleConnector

from transactron.utils.dependencies import DependencyContext
Expand All @@ -25,24 +25,31 @@
from coreblocks.backend.annoucement import ResultAnnouncement
from coreblocks.backend.retirement import Retirement
from coreblocks.peripherals.bus_adapter import WishboneMasterAdapter
from coreblocks.peripherals.wishbone import WishboneMaster, WishboneInterface
from coreblocks.peripherals.wishbone import WishboneMaster, WishboneInterface, WishboneSignature
from transactron.lib import BasicFifo
from transactron.lib.metrics import HwMetricsEnabledKey

__all__ = ["Core"]


class Core(Elaboratable):
def __init__(self, *, gen_params: GenParams, wb_instr_bus: WishboneInterface, wb_data_bus: WishboneInterface):
class Core(Component):
wb_instr: WishboneInterface
wb_data: WishboneInterface

def __init__(self, *, gen_params: GenParams):
super().__init__(
{
"wb_instr": Out(WishboneSignature(gen_params.wb_params)),
"wb_data": Out(WishboneSignature(gen_params.wb_params)),
}
)

self.gen_params = gen_params

self.connections = DependencyContext.get()
if self.gen_params.debug_signals_enabled:
self.connections.add_dependency(HwMetricsEnabledKey(), True)

self.wb_instr_bus = wb_instr_bus
self.wb_data_bus = wb_data_bus

self.wb_master_instr = WishboneMaster(self.gen_params.wb_params, "instr")
self.wb_master_data = WishboneMaster(self.gen_params.wb_params, "data")

Expand Down Expand Up @@ -89,8 +96,8 @@ def __init__(self, *, gen_params: GenParams, wb_instr_bus: WishboneInterface, wb
def elaborate(self, platform):
m = TModule()

connect(m, flipped(self.wb_instr_bus), self.wb_master_instr.wb_master)
connect(m, flipped(self.wb_data_bus), self.wb_master_data.wb_master)
connect(m, flipped(self.wb_instr), self.wb_master_instr.wb_master)
connect(m, flipped(self.wb_data), self.wb_master_data.wb_master)

m.submodules.wb_master_instr = self.wb_master_instr
m.submodules.wb_master_data = self.wb_master_data
Expand Down
4 changes: 2 additions & 2 deletions coreblocks/peripherals/wishbone.py
Original file line number Diff line number Diff line change
Expand Up @@ -438,8 +438,8 @@ class WishboneArbiter(Component):
def __init__(self, wb_params: WishboneParameters, num_masters: int):
super().__init__(
{
"slave_wb": In(WishboneSignature(wb_params)),
"masters": Out(WishboneSignature(wb_params)).array(num_masters),
"slave_wb": Out(WishboneSignature(wb_params)),
"masters": In(WishboneSignature(wb_params)).array(num_masters),
}
)

Expand Down
33 changes: 4 additions & 29 deletions scripts/gen_verilog.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,15 @@
import argparse

from amaranth import *
from amaranth.build import Platform
from amaranth import Module, Elaboratable


if __name__ == "__main__":
parent = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, parent)

from coreblocks.params.genparams import GenParams
from coreblocks.peripherals.wishbone import WishboneSignature
from coreblocks.core import Core
from transactron import TransactionModule
from transactron import TransactionComponent
from transactron.utils import DependencyManager, DependencyContext
from transactron.utils.gen import generate_verilog

Expand All @@ -29,34 +26,12 @@
}


class Top(Elaboratable):
def __init__(self, gen_params):
self.gp: GenParams = gen_params

self.wb_instr = WishboneSignature(self.gp.wb_params).create()
self.wb_data = WishboneSignature(self.gp.wb_params).create()

def elaborate(self, platform: Platform):
m = Module()
tm = TransactionModule(m, dependency_manager=DependencyContext.get())

m.submodules.c = Core(gen_params=self.gp, wb_instr_bus=self.wb_instr, wb_data_bus=self.wb_data)

return tm


def gen_verilog(core_config: CoreConfiguration, output_path: str):
with DependencyContext(DependencyManager()):
gp = GenParams(core_config)
top = Top(gp)
instr_ports: list[Signal] = [getattr(top.wb_instr, name) for name in top.wb_instr.signature.members]
data_ports: list[Signal] = [getattr(top.wb_data, name) for name in top.wb_data.signature.members]
for sig in instr_ports:
sig.name = "wb_instr__" + sig.name
for sig in data_ports:
sig.name = "wb_data__" + sig.name

verilog_text, gen_info = generate_verilog(top, instr_ports + data_ports)
top = TransactionComponent(Core(gen_params=gp), dependency_manager=DependencyContext.get())

verilog_text, gen_info = generate_verilog(top)

gen_info.encode(f"{output_path}.json")
with open(output_path, "w") as f:
Expand Down
96 changes: 49 additions & 47 deletions scripts/synthesize.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from amaranth.build import Platform
from amaranth import *
from amaranth.lib.wiring import Flow
from amaranth.lib.wiring import Component, Flow, Out, connect, flipped

if __name__ == "__main__":
parent = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
Expand All @@ -16,6 +16,7 @@

from transactron.utils.dependencies import DependencyContext, DependencyManager
from transactron.utils import ModuleConnector
from transactron.utils._typing import AbstractInterface
from coreblocks.params.genparams import GenParams
from coreblocks.params.fu_params import FunctionalComponentParams
from coreblocks.core import Core
Expand All @@ -26,13 +27,12 @@
from coreblocks.func_blocks.fu.zbc import ZbcComponent
from coreblocks.func_blocks.fu.zbs import ZbsComponent
from transactron import TransactionModule
from transactron.lib import AdapterBase, AdapterTrans
from coreblocks.peripherals.wishbone import WishboneArbiter, WishboneInterface
from transactron.lib import AdapterTrans
from coreblocks.peripherals.wishbone import WishboneArbiter, WishboneInterface, WishboneSignature
from constants.ecp5_platforms import (
ResourceBuilder,
adapter_resources,
append_resources,
wishbone_resources,
signature_resources,
make_ecp5_platform,
)

Expand All @@ -45,83 +45,85 @@
}


class WishboneConnector(Elaboratable):
def __init__(self, wb: WishboneInterface, number: int):
self.wb = wb
class InterfaceConnector(Elaboratable):
def __init__(self, interface: AbstractInterface, name: str, number: int):
self.interface = interface
self.name = name
self.number = number

@staticmethod
def with_resources(interface: AbstractInterface, name: str, number: int):
connector = InterfaceConnector(interface, name, number)
resources = signature_resources(interface.signature, name, number)
return connector, resources

def elaborate(self, platform: Platform):
m = Module()

pins = platform.request("wishbone", self.number)
pins = platform.request(self.name, self.number)
assert isinstance(pins, Record)

for name in self.wb.signature.members:
member = self.wb.signature.members[name]
if member.flow == Flow.In:
m.d.comb += getattr(pins, name).o.eq(getattr(self.wb, name))
for hier_name, member, v in self.interface.signature.flatten(self.interface):
name = "__".join(str(x) for x in hier_name)
if member.flow == Flow.Out:
m.d.comb += getattr(pins, name).o.eq(v)
else:
m.d.comb += getattr(self.wb, name).eq(getattr(pins, name).i)
m.d.comb += v.eq(getattr(pins, name).i)

return m


class AdapterConnector(Elaboratable):
def __init__(self, adapter: AdapterBase, number: int):
self.adapter = adapter
self.number = number
UnitCore = Callable[[GenParams], tuple[ResourceBuilder, Elaboratable]]

@staticmethod
def with_resources(adapter: AdapterBase, number: int):
return AdapterConnector(adapter, number), adapter_resources(adapter, number)

def elaborate(self, platform: Platform):
m = Module()
class SynthesisCore(Component):
wb: WishboneInterface

m.submodules.adapter = self.adapter
def __init__(self, gen_params: GenParams):
super().__init__({"wb": Out(WishboneSignature(gen_params.wb_params))})
self.gen_params = gen_params

pins = platform.request("adapter", self.number)
assert isinstance(pins, Record)

m.d.comb += self.adapter.en.eq(pins.en)
m.d.comb += pins.done.eq(self.adapter.done)
if "data_in" in pins.fields:
m.d.comb += self.adapter.data_in.eq(pins.data_in)
if "data_out" in pins.fields:
m.d.comb += pins.data_out.eq(self.adapter.data_out)
def elaborate(self, platform):
m = Module()

return m
m.submodules.core = core = Core(gen_params=self.gen_params)
m.submodules.wb_arbiter = wb_arbiter = WishboneArbiter(self.gen_params.wb_params, 2)

connect(m, wb_arbiter.masters[0], core.wb_instr)
connect(m, wb_arbiter.masters[1], core.wb_data)
connect(m, flipped(self.wb), wb_arbiter.slave_wb)

UnitCore = Callable[[GenParams], tuple[ResourceBuilder, Elaboratable]]
return m


def unit_core(gen_params: GenParams):
resources = wishbone_resources(gen_params.wb_params)

wb_arbiter = WishboneArbiter(gen_params.wb_params, 2)
wb_instr = wb_arbiter.masters[0]
wb_data = wb_arbiter.masters[1]

wb_connector = WishboneConnector(wb_arbiter.slave_wb, 0)
core = SynthesisCore(gen_params)

core = Core(gen_params=gen_params, wb_instr_bus=wb_instr, wb_data_bus=wb_data)
connector, resources = InterfaceConnector.with_resources(core, "wishbone", 0)

module = ModuleConnector(core=core, wb_arbiter=wb_arbiter, wb_connector=wb_connector)
module = ModuleConnector(core=core, connector=connector)

return resources, TransactionModule(module, dependency_manager=DependencyContext.get())


def unit_fu(unit_params: FunctionalComponentParams):
def unit(gen_params: GenParams):
fu = unit_params.get_module(gen_params)
issue_adapter = AdapterTrans(fu.issue)
accept_adapter = AdapterTrans(fu.accept)

issue_connector, issue_resources = AdapterConnector.with_resources(AdapterTrans(fu.issue), 0)
accept_connector, accept_resources = AdapterConnector.with_resources(AdapterTrans(fu.accept), 1)
issue_connector, issue_resources = InterfaceConnector.with_resources(issue_adapter, "adapter", 0)
accept_connector, accept_resources = InterfaceConnector.with_resources(accept_adapter, "adapter", 1)

resources = append_resources(issue_resources, accept_resources)

module = ModuleConnector(fu=fu, issue_connector=issue_connector, accept_connector=accept_connector)
module = ModuleConnector(
fu=fu,
issue_connector=issue_connector,
accept_connector=accept_connector,
issue_adapter=issue_adapter,
accept_adapter=accept_adapter,
)

return resources, TransactionModule(module, dependency_manager=DependencyContext.get())

Expand Down
Loading

0 comments on commit b46fa21

Please sign in to comment.