Skip to content

Commit

Permalink
Autumn cleaning part 2 - split transactron/lib.py (kuznia-rdzeni/core…
Browse files Browse the repository at this point in the history
  • Loading branch information
lekcyjna123 authored Oct 7, 2023
1 parent 20b43d6 commit 2ea5084
Show file tree
Hide file tree
Showing 9 changed files with 1,208 additions and 1,187 deletions.
1,187 changes: 0 additions & 1,187 deletions transactron/lib.py

This file was deleted.

7 changes: 7 additions & 0 deletions transactron/lib/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from .connectors import * # noqa: F401
from .buttons import * # noqa: F401
from .adapters import * # noqa: F401
from .transformers import * # noqa: F401
from .reqres import * # noqa: F401
from .storage import * # noqa: F401
from .simultaneous import * # noqa: F401
115 changes: 115 additions & 0 deletions transactron/lib/adapters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
from amaranth import *
from ..core import *
from ..core import SignalBundle
from typing import Optional

__all__ = [
"AdapterBase",
"AdapterTrans",
"Adapter",
]


class AdapterBase(Elaboratable):
data_in: Record
data_out: Record

def __init__(self, iface: Method):
self.iface = iface
self.en = Signal()
self.done = Signal()

def debug_signals(self) -> SignalBundle:
return [self.en, self.done, self.data_in, self.data_out]


class AdapterTrans(AdapterBase):
"""Adapter transaction.
Creates a transaction controlled by plain Amaranth signals. Allows to
expose a method to plain Amaranth code, including testbenches.
Attributes
----------
en: Signal, in
Activates the transaction (sets the `request` signal).
done: Signal, out
Signals that the transaction is performed (returns the `grant`
signal).
data_in: Record, in
Data passed to the `iface` method.
data_out: Record, out
Data returned from the `iface` method.
"""

def __init__(self, iface: Method):
"""
Parameters
----------
iface: Method
The method to be called by the transaction.
"""
super().__init__(iface)
self.data_in = Record.like(iface.data_in)
self.data_out = Record.like(iface.data_out)

def elaborate(self, platform):
m = TModule()

# this forces data_in signal to appear in VCD dumps
data_in = Signal.like(self.data_in)
m.d.comb += data_in.eq(self.data_in)

with Transaction(name=f"AdapterTrans_{self.iface.name}").body(m, request=self.en):
data_out = self.iface(m, data_in)
m.d.top_comb += self.data_out.eq(data_out)
m.d.comb += self.done.eq(1)

return m


class Adapter(AdapterBase):
"""Adapter method.
Creates a method controlled by plain Amaranth signals. One of the
possible uses is to mock a method in a testbench.
Attributes
----------
en: Signal, in
Activates the method (sets the `ready` signal).
done: Signal, out
Signals that the method is called (returns the `run` signal).
data_in: Record, in
Data returned from the defined method.
data_out: Record, out
Data passed as argument to the defined method.
"""

def __init__(self, *, name: Optional[str] = None, i: MethodLayout = (), o: MethodLayout = ()):
"""
Parameters
----------
i: record layout
The input layout of the defined method.
o: record layout
The output layout of the defined method.
"""
super().__init__(Method(name=name, i=i, o=o))
self.data_in = Record.like(self.iface.data_out)
self.data_out = Record.like(self.iface.data_in)

def elaborate(self, platform):
m = TModule()

# this forces data_in signal to appear in VCD dumps
data_in = Signal.like(self.data_in)
m.d.comb += data_in.eq(self.data_in)

@def_method(m, self.iface, ready=self.en)
def _(arg):
m.d.top_comb += self.data_out.eq(arg)
m.d.comb += self.done.eq(1)
return data_in

return m
102 changes: 102 additions & 0 deletions transactron/lib/buttons.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
from amaranth import *
from ..core import *

__all__ = ["ClickIn", "ClickOut"]


class ClickIn(Elaboratable):
"""Clicked input.
Useful for interactive simulations or FPGA button/switch interfaces.
On a rising edge (tested synchronously) of `btn`, the `get` method
is enabled, which returns the data present on `dat` at the time.
Inputs are synchronized.
Attributes
----------
get: Method
The method for retrieving data from the input. Accepts an empty
argument, returns a `Record`.
btn: Signal, in
The button input.
dat: Record, in
The data input.
"""

def __init__(self, layout: MethodLayout):
"""
Parameters
----------
layout: record layout
The data format for the input.
"""
self.get = Method(o=layout)
self.btn = Signal()
self.dat = Record(layout)

def elaborate(self, platform):
m = TModule()

btn1 = Signal()
btn2 = Signal()
dat1 = Signal.like(self.dat)
m.d.sync += btn1.eq(self.btn)
m.d.sync += btn2.eq(btn1)
m.d.sync += dat1.eq(self.dat)
get_ready = Signal()
get_data = Signal.like(self.dat)

@def_method(m, self.get, ready=get_ready)
def _():
m.d.sync += get_ready.eq(0)
return get_data

with m.If(~btn2 & btn1):
m.d.sync += get_ready.eq(1)
m.d.sync += get_data.eq(dat1)

return m


class ClickOut(Elaboratable):
"""Clicked output.
Useful for interactive simulations or FPGA button/LED interfaces.
On a rising edge (tested synchronously) of `btn`, the `put` method
is enabled, which, when called, changes the value of the `dat` signal.
Attributes
----------
put: Method
The method for retrieving data from the input. Accepts a `Record`,
returns empty result.
btn: Signal, in
The button input.
dat: Record, out
The data output.
"""

def __init__(self, layout: MethodLayout):
"""
Parameters
----------
layout: record layout
The data format for the output.
"""
self.put = Method(i=layout)
self.btn = Signal()
self.dat = Record(layout)

def elaborate(self, platform):
m = TModule()

btn1 = Signal()
btn2 = Signal()
m.d.sync += btn1.eq(self.btn)
m.d.sync += btn2.eq(btn1)

@def_method(m, self.put, ready=~btn2 & btn1)
def _(arg):
m.d.sync += self.dat.eq(arg)

return m
Loading

0 comments on commit 2ea5084

Please sign in to comment.