Skip to content

Commit 1e07895

Browse files
committed
csr.reg: implement amaranth-lang/rfcs#16.
1 parent d377e68 commit 1e07895

File tree

5 files changed

+1891
-0
lines changed

5 files changed

+1891
-0
lines changed

amaranth_soc/csr/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
from .bus import *
22
from .event import *
3+
from .reg import *

amaranth_soc/csr/field.py

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
from amaranth import *
2+
3+
from .reg import Field
4+
5+
6+
__all__ = ["R", "W", "RW", "RW1C", "RW1S"]
7+
8+
9+
class R(Field):
10+
__doc__ = Field._doc_template.format(
11+
description="""
12+
A read-only field.
13+
""".strip(),
14+
parameters="",
15+
attributes="""
16+
r_data : Signal(shape)
17+
Read data. Drives the :attr:`~FieldPort.r_data` signal of ``port``.
18+
""".strip())
19+
20+
def __init__(self, shape):
21+
super().__init__(shape, access="r")
22+
self.r_data = Signal(shape)
23+
24+
def elaborate(self, platform):
25+
m = Module()
26+
m.d.comb += self.port.r_data.eq(self.r_data)
27+
return m
28+
29+
30+
class W(Field):
31+
__doc__ = Field._doc_template.format(
32+
description="""
33+
A write-only field.
34+
""".strip(),
35+
parameters="",
36+
attributes="""
37+
w_data : Signal(shape)
38+
Write data. Driven by the :attr:`~FieldPort.w_data` signal of ``port``.
39+
""".strip())
40+
41+
def __init__(self, shape):
42+
super().__init__(shape, access="w")
43+
self.w_data = Signal(shape)
44+
45+
def elaborate(self, platform):
46+
m = Module()
47+
m.d.comb += self.w_data.eq(self.port.w_data)
48+
return m
49+
50+
51+
class RW(Field):
52+
__doc__ = Field._doc_template.format(
53+
description="""
54+
A read/write field with built-in storage.
55+
56+
Storage is updated with the value of ``port.w_data`` one clock cycle after ``port.w_stb`` is
57+
asserted.
58+
""".strip(),
59+
parameters="""
60+
reset : :class:`int`
61+
Storage reset value.
62+
""",
63+
attributes="""
64+
data : Signal(shape)
65+
Storage output.
66+
""".strip())
67+
68+
def __init__(self, shape, *, reset=0):
69+
super().__init__(shape, access="rw")
70+
self.data = Signal(shape)
71+
self._storage = Signal(shape, reset=reset)
72+
self._reset = reset
73+
74+
@property
75+
def reset(self):
76+
return self._reset
77+
78+
def elaborate(self, platform):
79+
m = Module()
80+
81+
with m.If(self.port.w_stb):
82+
m.d.sync += self._storage.eq(self.port.w_data)
83+
84+
m.d.comb += [
85+
self.port.r_data.eq(self._storage),
86+
self.data.eq(self._storage),
87+
]
88+
89+
return m
90+
91+
92+
class RW1C(Field):
93+
__doc__ = Field._doc_template.format(
94+
description="""
95+
A read/write-one-to-clear field with built-in storage.
96+
97+
Storage bits are:
98+
* cleared by high bits in ``port.w_data``, one clock cycle after ``port.w_stb`` is asserted;
99+
* set by high bits in ``set``, one clock cycle after they are asserted.
100+
101+
If a storage bit is set and cleared on the same clock cycle, setting it has precedence.
102+
""".strip(),
103+
parameters="""
104+
reset : :class:`int`
105+
Storage reset value.
106+
""",
107+
attributes="""
108+
data : Signal(shape)
109+
Storage output.
110+
set : Signal(shape)
111+
Mask to set storage bits.
112+
""".strip())
113+
114+
def __init__(self, shape, *, reset=0):
115+
super().__init__(shape, access="rw")
116+
self.data = Signal(shape)
117+
self.set = Signal(shape)
118+
self._storage = Signal(shape, reset=reset)
119+
self._reset = reset
120+
121+
@property
122+
def reset(self):
123+
return self._reset
124+
125+
def elaborate(self, platform):
126+
m = Module()
127+
128+
for i, storage_bit in enumerate(self._storage):
129+
with m.If(self.port.w_stb & self.port.w_data[i]):
130+
m.d.sync += storage_bit.eq(0)
131+
with m.If(self.set[i]):
132+
m.d.sync += storage_bit.eq(1)
133+
134+
m.d.comb += [
135+
self.port.r_data.eq(self._storage),
136+
self.data.eq(self._storage),
137+
]
138+
139+
return m
140+
141+
142+
class RW1S(Field):
143+
__doc__ = Field._doc_template.format(
144+
description="""
145+
A read/write-one-to-set field with built-in storage.
146+
147+
Storage bits are:
148+
* set by high bits in ``port.w_data``, one clock cycle after ``port.w_stb`` is asserted;
149+
* cleared by high bits in ``clear``, one clock cycle after they are asserted.
150+
151+
If a storage bit is set and cleared on the same clock cycle, setting it has precedence.
152+
""".strip(),
153+
parameters="""
154+
reset : :class:`int`
155+
Storage reset value.
156+
""",
157+
attributes="""
158+
data : Signal(shape)
159+
Storage output.
160+
clear : Signal(shape)
161+
Mask to clear storage bits.
162+
""".strip())
163+
def __init__(self, shape, *, reset=0):
164+
super().__init__(shape, access="rw")
165+
self.data = Signal(shape)
166+
self.clear = Signal(shape)
167+
self._storage = Signal(shape, reset=reset)
168+
self._reset = reset
169+
170+
@property
171+
def reset(self):
172+
return self._reset
173+
174+
def elaborate(self, platform):
175+
m = Module()
176+
177+
for i, storage_bit in enumerate(self._storage):
178+
with m.If(self.clear[i]):
179+
m.d.sync += storage_bit.eq(0)
180+
with m.If(self.port.w_stb & self.port.w_data[i]):
181+
m.d.sync += storage_bit.eq(1)
182+
183+
m.d.comb += [
184+
self.port.r_data.eq(self._storage),
185+
self.data.eq(self._storage),
186+
]
187+
188+
return m

0 commit comments

Comments
 (0)