-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
csr.reg: implement amaranth-lang/rfcs#16.
- Loading branch information
Showing
5 changed files
with
1,891 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
from .bus import * | ||
from .event import * | ||
from .reg import * |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
from amaranth import * | ||
|
||
from .reg import Field | ||
|
||
|
||
__all__ = ["R", "W", "RW", "RW1C", "RW1S"] | ||
|
||
|
||
class R(Field): | ||
__doc__ = Field._doc_template.format( | ||
description=""" | ||
A read-only field. | ||
""".strip(), | ||
parameters="", | ||
attributes=""" | ||
r_data : Signal(shape) | ||
Read data. Drives the :attr:`~FieldPort.r_data` signal of ``port``. | ||
""".strip()) | ||
|
||
def __init__(self, shape): | ||
super().__init__(shape, access="r") | ||
self.r_data = Signal(shape) | ||
|
||
def elaborate(self, platform): | ||
m = Module() | ||
m.d.comb += self.port.r_data.eq(self.r_data) | ||
return m | ||
|
||
|
||
class W(Field): | ||
__doc__ = Field._doc_template.format( | ||
description=""" | ||
A write-only field. | ||
""".strip(), | ||
parameters="", | ||
attributes=""" | ||
w_data : Signal(shape) | ||
Write data. Driven by the :attr:`~FieldPort.w_data` signal of ``port``. | ||
""".strip()) | ||
|
||
def __init__(self, shape): | ||
super().__init__(shape, access="w") | ||
self.w_data = Signal(shape) | ||
|
||
def elaborate(self, platform): | ||
m = Module() | ||
m.d.comb += self.w_data.eq(self.port.w_data) | ||
return m | ||
|
||
|
||
class RW(Field): | ||
__doc__ = Field._doc_template.format( | ||
description=""" | ||
A read/write field with built-in storage. | ||
Storage is updated with the value of ``port.w_data`` one clock cycle after ``port.w_stb`` is | ||
asserted. | ||
""".strip(), | ||
parameters=""" | ||
reset : :class:`int` | ||
Storage reset value. | ||
""", | ||
attributes=""" | ||
data : Signal(shape) | ||
Storage output. | ||
""".strip()) | ||
|
||
def __init__(self, shape, *, reset=0): | ||
super().__init__(shape, access="rw") | ||
self.data = Signal(shape) | ||
self._storage = Signal(shape, reset=reset) | ||
self._reset = reset | ||
|
||
@property | ||
def reset(self): | ||
return self._reset | ||
|
||
def elaborate(self, platform): | ||
m = Module() | ||
|
||
with m.If(self.port.w_stb): | ||
m.d.sync += self._storage.eq(self.port.w_data) | ||
|
||
m.d.comb += [ | ||
self.port.r_data.eq(self._storage), | ||
self.data.eq(self._storage), | ||
] | ||
|
||
return m | ||
|
||
|
||
class RW1C(Field): | ||
__doc__ = Field._doc_template.format( | ||
description=""" | ||
A read/write-one-to-clear field with built-in storage. | ||
Storage bits are: | ||
* cleared by high bits in ``port.w_data``, one clock cycle after ``port.w_stb`` is asserted; | ||
* set by high bits in ``set``, one clock cycle after they are asserted. | ||
If a storage bit is set and cleared on the same clock cycle, setting it has precedence. | ||
""".strip(), | ||
parameters=""" | ||
reset : :class:`int` | ||
Storage reset value. | ||
""", | ||
attributes=""" | ||
data : Signal(shape) | ||
Storage output. | ||
set : Signal(shape) | ||
Mask to set storage bits. | ||
""".strip()) | ||
|
||
def __init__(self, shape, *, reset=0): | ||
super().__init__(shape, access="rw") | ||
self.data = Signal(shape) | ||
self.set = Signal(shape) | ||
self._storage = Signal(shape, reset=reset) | ||
self._reset = reset | ||
|
||
@property | ||
def reset(self): | ||
return self._reset | ||
|
||
def elaborate(self, platform): | ||
m = Module() | ||
|
||
for i, storage_bit in enumerate(self._storage): | ||
with m.If(self.port.w_stb & self.port.w_data[i]): | ||
m.d.sync += storage_bit.eq(0) | ||
with m.If(self.set[i]): | ||
m.d.sync += storage_bit.eq(1) | ||
|
||
m.d.comb += [ | ||
self.port.r_data.eq(self._storage), | ||
self.data.eq(self._storage), | ||
] | ||
|
||
return m | ||
|
||
|
||
class RW1S(Field): | ||
__doc__ = Field._doc_template.format( | ||
description=""" | ||
A read/write-one-to-set field with built-in storage. | ||
Storage bits are: | ||
* set by high bits in ``port.w_data``, one clock cycle after ``port.w_stb`` is asserted; | ||
* cleared by high bits in ``clear``, one clock cycle after they are asserted. | ||
If a storage bit is set and cleared on the same clock cycle, setting it has precedence. | ||
""".strip(), | ||
parameters=""" | ||
reset : :class:`int` | ||
Storage reset value. | ||
""", | ||
attributes=""" | ||
data : Signal(shape) | ||
Storage output. | ||
clear : Signal(shape) | ||
Mask to clear storage bits. | ||
""".strip()) | ||
def __init__(self, shape, *, reset=0): | ||
super().__init__(shape, access="rw") | ||
self.data = Signal(shape) | ||
self.clear = Signal(shape) | ||
self._storage = Signal(shape, reset=reset) | ||
self._reset = reset | ||
|
||
@property | ||
def reset(self): | ||
return self._reset | ||
|
||
def elaborate(self, platform): | ||
m = Module() | ||
|
||
for i, storage_bit in enumerate(self._storage): | ||
with m.If(self.clear[i]): | ||
m.d.sync += storage_bit.eq(0) | ||
with m.If(self.port.w_stb & self.port.w_data[i]): | ||
m.d.sync += storage_bit.eq(1) | ||
|
||
m.d.comb += [ | ||
self.port.r_data.eq(self._storage), | ||
self.data.eq(self._storage), | ||
] | ||
|
||
return m |
Oops, something went wrong.