Skip to content

Commit be7158c

Browse files
feat(river_hdl): add data port writers
1 parent cb48d69 commit be7158c

File tree

3 files changed

+554
-0
lines changed

3 files changed

+554
-0
lines changed

packages/river_hdl/lib/river_hdl.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export 'src/core/exec.dart';
88
export 'src/core/fetcher.dart';
99
export 'src/core/pipeline.dart';
1010
export 'src/core.dart';
11+
export 'src/memory/port.dart';
1112
export 'src/river_hdl_base.dart';
1213

1314
// TODO: Export any libraries intended for clients of this package.
Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
import 'package:rohd/rohd.dart';
2+
import 'package:rohd_hcl/rohd_hcl.dart';
3+
4+
/// A sized prefix data port writer to multiple output data ports.
5+
///
6+
/// Using multiple data ports for writing, this is capable of updating a memory
7+
/// model without reading first. This however does increase the circuit complexity
8+
/// due to having more duplicate lines. This is suitable when the memory model supports
9+
/// multiple data ports of different sizes.
10+
class SizedWriteMultiDataPort extends Module {
11+
SizedWriteMultiDataPort(
12+
Logic clk,
13+
Logic reset, {
14+
required DataPortInterface backingWriteByte,
15+
required DataPortInterface backingWriteHalf,
16+
required DataPortInterface backingWriteWord,
17+
DataPortInterface? backingWriteDword,
18+
required DataPortInterface source,
19+
}) {
20+
clk = addInput('clk', clk);
21+
reset = addInput('reset', reset);
22+
23+
backingWriteByte = backingWriteByte.clone()
24+
..connectIO(
25+
this,
26+
backingWriteByte,
27+
outputTags: {DataPortGroup.control, DataPortGroup.data},
28+
inputTags: {DataPortGroup.integrity},
29+
uniquify: (og) => 'backingWriteByte_$og',
30+
);
31+
32+
backingWriteHalf = backingWriteHalf.clone()
33+
..connectIO(
34+
this,
35+
backingWriteHalf,
36+
outputTags: {DataPortGroup.control, DataPortGroup.data},
37+
inputTags: {DataPortGroup.integrity},
38+
uniquify: (og) => 'backingWriteHalf_$og',
39+
);
40+
41+
backingWriteWord = backingWriteWord.clone()
42+
..connectIO(
43+
this,
44+
backingWriteWord,
45+
outputTags: {DataPortGroup.control, DataPortGroup.data},
46+
inputTags: {DataPortGroup.integrity},
47+
uniquify: (og) => 'backingWriteWord_$og',
48+
);
49+
50+
if (backingWriteDword != null) {
51+
backingWriteDword = backingWriteDword!.clone()
52+
..connectIO(
53+
this,
54+
backingWriteDword!,
55+
outputTags: {DataPortGroup.control, DataPortGroup.data},
56+
inputTags: {DataPortGroup.integrity},
57+
uniquify: (og) => 'backingWriteDword_$og',
58+
);
59+
}
60+
61+
source = source.clone()
62+
..connectIO(
63+
this,
64+
source,
65+
outputTags: {DataPortGroup.control, DataPortGroup.integrity},
66+
inputTags: {DataPortGroup.data},
67+
uniquify: (og) => 'source_$og',
68+
);
69+
70+
Sequential(clk, [
71+
If(
72+
reset,
73+
then: [
74+
source.done < 0,
75+
source.valid < 0,
76+
backingWriteByte.en < 0,
77+
backingWriteByte.addr < 0,
78+
backingWriteHalf.en < 0,
79+
backingWriteHalf.addr < 0,
80+
backingWriteWord.en < 0,
81+
backingWriteWord.addr < 0,
82+
83+
if (backingWriteDword != null) ...[
84+
backingWriteDword!.en < 0,
85+
backingWriteDword!.addr < 0,
86+
],
87+
],
88+
orElse: [
89+
If(
90+
source.en,
91+
then: [
92+
Case(
93+
source.data.slice(6, 0),
94+
[
95+
CaseItem(Const(8, width: 7), [
96+
backingWriteByte.en < 1,
97+
backingWriteByte.addr < source.addr,
98+
backingWriteByte.data < source.data.slice(14, 7),
99+
source.done < backingWriteByte.done,
100+
source.valid < backingWriteByte.valid,
101+
]),
102+
CaseItem(Const(16, width: 7), [
103+
backingWriteHalf.en < 1,
104+
backingWriteHalf.addr < source.addr,
105+
backingWriteHalf.data < source.data.slice(22, 7),
106+
source.done < backingWriteHalf.done,
107+
source.valid < backingWriteHalf.valid,
108+
]),
109+
CaseItem(Const(32, width: 7), [
110+
backingWriteWord.en < 1,
111+
backingWriteWord.addr < source.addr,
112+
backingWriteWord.data < source.data.slice(38, 7),
113+
source.done < backingWriteWord.done,
114+
source.valid < backingWriteWord.valid,
115+
]),
116+
if (backingWriteDword != null)
117+
CaseItem(Const(64, width: 7), [
118+
backingWriteDword!.en < 1,
119+
backingWriteDword!.addr < source.addr,
120+
backingWriteDword!.data < source.data.slice(70, 7),
121+
source.done < backingWriteDword!.done,
122+
source.valid < backingWriteDword!.valid,
123+
]),
124+
],
125+
defaultItem: [
126+
source.done < 0,
127+
source.valid < 0,
128+
backingWriteByte.en < 0,
129+
backingWriteByte.addr < 0,
130+
backingWriteHalf.en < 0,
131+
backingWriteHalf.addr < 0,
132+
backingWriteWord.en < 0,
133+
backingWriteWord.addr < 0,
134+
135+
if (backingWriteDword != null) ...[
136+
backingWriteDword!.en < 0,
137+
backingWriteDword!.addr < 0,
138+
],
139+
],
140+
),
141+
],
142+
orElse: [
143+
source.done < 0,
144+
source.valid < 0,
145+
backingWriteByte.en < 0,
146+
backingWriteByte.addr < 0,
147+
backingWriteHalf.en < 0,
148+
backingWriteHalf.addr < 0,
149+
backingWriteWord.en < 0,
150+
backingWriteWord.addr < 0,
151+
152+
if (backingWriteDword != null) ...[
153+
backingWriteDword!.en < 0,
154+
backingWriteDword!.addr < 0,
155+
],
156+
],
157+
),
158+
],
159+
),
160+
]);
161+
}
162+
}
163+
164+
/// A sized prefix data port writer to a single data port.
165+
///
166+
/// Using a single data port for reading & writing, this is capable of updating
167+
/// a memory model using the least amount of data ports. However, it performs a read
168+
/// before a write. This is suitable when the memory model does not suport multiple
169+
/// data ports of different sizes.
170+
class SizedWriteSingleDataPort extends Module {
171+
SizedWriteSingleDataPort(
172+
Logic clk,
173+
Logic reset, {
174+
required DataPortInterface backingRead,
175+
required DataPortInterface backingWrite,
176+
required DataPortInterface source,
177+
}) {
178+
clk = addInput('clk', clk);
179+
reset = addInput('reset', reset);
180+
181+
if (backingRead.addr.width != backingWrite.addr.width) {
182+
throw 'Backing read & backing write must have the same address width';
183+
}
184+
185+
if (backingRead.data.width != backingWrite.data.width) {
186+
throw 'Backing read & backing write must have the same data width';
187+
}
188+
189+
if (source.data.width < 7) {
190+
throw 'Source port must be at least 7 bits to fit the width prefix';
191+
}
192+
193+
if (backingRead.addr.width != source.addr.width) {
194+
throw 'Backing data ports and source port must have the same address width';
195+
}
196+
197+
if (backingRead.data.width != (source.data.width - 7)) {
198+
throw 'Backing data ports and source port must have the same data width';
199+
}
200+
201+
backingWrite = backingWrite.clone()
202+
..connectIO(
203+
this,
204+
backingWrite,
205+
outputTags: {DataPortGroup.control, DataPortGroup.data},
206+
inputTags: {DataPortGroup.integrity},
207+
uniquify: (og) => 'backingWrite_$og',
208+
);
209+
210+
backingRead = backingRead.clone()
211+
..connectIO(
212+
this,
213+
backingRead,
214+
outputTags: {DataPortGroup.control},
215+
inputTags: {DataPortGroup.data, DataPortGroup.integrity},
216+
uniquify: (og) => 'backingRead_$og',
217+
);
218+
219+
source = source.clone()
220+
..connectIO(
221+
this,
222+
source,
223+
outputTags: {DataPortGroup.control, DataPortGroup.integrity},
224+
inputTags: {DataPortGroup.data},
225+
uniquify: (og) => 'source_$og',
226+
);
227+
228+
final width = source.data.width - 7;
229+
final value = source.data.slice(source.data.width - 1, 7);
230+
231+
final dataSize = source.data.slice(6, 0).zeroExtend(width);
232+
233+
final writeMask = Logic(name: 'writeMask', width: width);
234+
writeMask <=
235+
((Const(1, width: width) << dataSize) - Const(1, width: width));
236+
237+
Sequential(clk, [
238+
If(
239+
reset,
240+
then: [
241+
source.done < 0,
242+
source.valid < 0,
243+
backingRead.en < 0,
244+
backingRead.addr < 0,
245+
backingWrite.en < 0,
246+
backingWrite.addr < 0,
247+
],
248+
orElse: [
249+
If(
250+
source.en,
251+
then: [
252+
backingRead.en < 1,
253+
backingRead.addr < source.addr,
254+
backingWrite.en < backingRead.done & backingRead.valid,
255+
backingWrite.addr < source.addr,
256+
backingWrite.data <
257+
((backingRead.data & ~writeMask) | (value & writeMask)),
258+
source.done < backingRead.done & backingWrite.done,
259+
source.valid < backingRead.valid & backingWrite.valid,
260+
],
261+
orElse: [
262+
source.done < 0,
263+
source.valid < 0,
264+
backingRead.en < 0,
265+
backingRead.addr < 0,
266+
backingWrite.en < 0,
267+
backingWrite.addr < 0,
268+
],
269+
),
270+
],
271+
),
272+
]);
273+
}
274+
}

0 commit comments

Comments
 (0)