Skip to main content

logicaffeine_compile/spatial/decode_engine/rtl/
ram.rs

1//! The engine's memories as the FPGA's block RAM holds them.
2//!
3//! `logos_ram_w<W> #(D, A)` is a simple dual-port memory of `D` words of `W` bits: its read port latches the address on
4//! the clock's falling edge and holds the word until the next falling edge; its write port writes on the rising edge
5//! under a byte mask. Between two rising edges a read sees the memory as the last rising edge left it, at an address
6//! the registers that edge set, which is what a combinational read of a register array sees within the cycle. So a
7//! unit's state machine keeps its reads where they are while the memory maps onto M20K blocks, the address given half a
8//! cycle and the data half a cycle.
9//!
10//! `logos_bram_w<W> #(D, A)` is the same memory with the block RAM's registered read: the address taken on a rising edge
11//! and its word out from that edge until the next, a read of the address the same edge writes returning the word before
12//! the write. The streaming engine, clocked at the memory interface's rate, gives each read address a clock ahead.
13//!
14//! `logos_bram_re_w<W> #(D, A)` takes its read address only on a rising edge where `re` is high and holds the word it
15//! read until the next such edge: the hybrid engine's token-row store, clocked by the fast clock, read at the engine
16//! clock's falling edges while the engine owns it.
17//!
18//! Each width is its own module whose write names every byte lane in its own statement, the form the synthesis tools
19//! map to a block RAM's byte enables. A registered or held memory (`logos_bram_w<W>`, `logos_bram_re_w<W>`) of 40 bits
20//! or wider, more than one layer of 512 words deep in a number of layers that is no power of two, is stacks of powers of
21//! two layers, its deepest its own and the rest `<name>_part`s beside it, so no stack is built past the memory's depth.
22//!
23//! Every memory asks for the block RAM its depth fills (`LOGOS_RAMSTYLE`, [`RAMSTYLE`]): MLABs to [`MLAB_WORDS`] words,
24//! M20K blocks beyond.
25
26use std::fmt::Write as _;
27
28/// The deepest memory kept in MLABs: an MLAB's depth. A memory this shallow asking for nothing is built by Quartus Prime
29/// Pro in an M20K block for every forty bits of its width, a sixteenth of the block's depth or less filled (hybrid9c2:
30/// 5,142 blocks, 44% of the device's, on 2.2 Mbit, and a fit that failed routing with each column core spread over its
31/// 214 blocks). From two words on an MLAB holds a wide memory in fewer ALMs than its flip-flops do (hybrid9d: a column
32/// core's ring of two 5,280-bit beats in registers, 169k across the array, left synthesis at 88% of the device's ALMs);
33/// Quartus keeps a memory too small for one in registers itself.
34pub const MLAB_WORDS: usize = 32;
35
36/// `LOGOS_RAMSTYLE(words)`: the `ramstyle` attribute of a memory of `words` words (a constant expression of the module's
37/// parameters) read into a register — MLABs to [`MLAB_WORDS`] words, M20K blocks beyond — and
38/// `LOGOS_RAMSTYLE_ASYNC(words)` the same for a memory read without a register after it (unregistered, or at a
39/// registered address, so seeing a word the clock it is written), its MLABs asking for no read-during-write check:
40/// Quartus Prime Pro builds an MLAB's read only through the MLAB's output register otherwise, and builds such a memory in
41/// flip-flops (a probe's 32 x 1,056-bit buffer: 33,797 registers). An engine's build times an MLAB's read of a word in
42/// the clock after its write (`logos_settings.tcl`, [`super::super::ofs`]), so the word read is the one written, as the
43/// RTL reads it. Defined once in whichever text names it first, so every unit's text carries it.
44pub const RAMSTYLE: &str = "`ifndef LOGOS_RAMSTYLE
45// The block RAM a memory of `words` words read into a register asks for: MLABs to thirty-two words (an MLAB's depth),
46// M20K blocks beyond.
47`define LOGOS_RAMSTYLE(words) (* ramstyle = (words) <= 32 ? \"MLAB\" : \"M20K\" *)
48// The same for a memory read without a register after it, its MLABs checking no read-during-write: the build times an
49// MLAB's read in the clock after its word's write.
50`define LOGOS_RAMSTYLE_ASYNC(words) (* ramstyle = (words) <= 32 ? \"MLAB, no_rw_check\" : \"M20K\" *)
51`endif
52";
53
54/// The module name of the memory `w` bits wide.
55pub fn ram_name(w: usize) -> String {
56    format!("logos_ram_w{w}")
57}
58
59/// The module name of the memory `w` bits wide whose read is registered on the rising edge.
60pub fn bram_name(w: usize) -> String {
61    format!("logos_bram_w{w}")
62}
63
64/// The memory modules for the widths `widths` (each a whole number of bytes), each asking for the block RAM its depth fills.
65pub fn ram_verilog(widths: &[usize]) -> String {
66    memories(widths, ram_name, "the read address latched on the falling edge", Read::Falling)
67}
68
69/// The registered-read memory modules for the widths `widths` (each a whole number of bytes).
70pub fn bram_verilog(widths: &[usize]) -> String {
71    memories(widths, bram_name, "the read registered on the rising edge", Read::Rising)
72}
73
74/// The module name of the memory `w` bits wide whose read is registered on the rising edges `re` is high on.
75pub fn bram_re_name(w: usize) -> String {
76    format!("logos_bram_re_w{w}")
77}
78
79/// The memory modules for the widths `widths` whose read is registered on the rising edges `re` is high on, the word
80/// held between them.
81pub fn bram_re_verilog(widths: &[usize]) -> String {
82    memories(widths, bram_re_name, "the read registered on the rising edges re is high on and held between them", Read::Held)
83}
84
85/// The module name of the memory `w` bits wide of an engine whose registers step on the rising edges `ce` is high on.
86pub fn ram_ce_name(w: usize) -> String {
87    format!("logos_ram_ce_w{w}")
88}
89
90/// `logos_ram_w<W>` for an engine whose registers step on the rising edges `ce` is high on: the read registered on the
91/// edges `cr` is high on, the word held between them, the write on the edges `ce` is high on. With `ce` high the user
92/// clock's cycle that ends with an engine step and `cr` high the cycle after the engine cycle's middle, a read sees
93/// the memory as the step before left it, at an address the registers that step set, as the falling-edge read does.
94pub fn ram_ce_verilog(widths: &[usize]) -> String {
95    memories(widths, ram_ce_name, "the read registered on the rising edges cr is high on and held between them", Read::Enabled)
96}
97
98/// Clocks the pipelined token-row store (`logos_store_w512`, [`store_verilog`]) takes from a read's address to its word:
99/// the ports registered, the layer read, the layers' words gathered a group at a time, and the groups' into the word.
100pub const STORE_READ_LATENCY: usize = 4;
101
102/// Layers of a pipelined store whose words one register of its first gathering takes.
103pub const STORE_GROUP: usize = 8;
104
105/// `logos_store_w512 #(D, A)`: the token-row store's bank as [`bram_re_verilog`]'s `logos_bram_re_w512` holds it — its read
106/// taken on the edges `re` is high on and held between them, a write under a byte mask — its word out
107/// [`STORE_READ_LATENCY`] clocks after its address instead of one. Its words are layers of 512, each a block RAM of its
108/// own read every clock (`logos_bram_w512_part`), so the block takes its read register whole and reads the word before a
109/// write of its address in the same clock, as its port does; a layer read under the read enable would hand the block the
110/// address register instead and need pass-through logic in the fabric for its read-during-write. Every port is taken into
111/// registers a clock before the layers see it, each layer's write enable decoded there, the read's address and the write's
112/// row, data and mask copied near the layers they reach (`maxfan`). Each layer's word is zero unless the read was of it,
113/// and the words are gathered by an OR, [`STORE_GROUP`] layers at a time into registers, then across the groups into the
114/// word read, which alone is held between the clocks `re` is high on (the read enable carried beside the read). A write
115/// lands a clock after it is asked, as a read does, so each read sees the writes it would if neither waited: a reader that
116/// takes its word [`STORE_READ_LATENCY`] clocks after its address reads what it read a clock after its address from the
117/// bank of one.
118pub fn store_verilog() -> String {
119    format!("{}\n{}\n{STORE_VERILOG}", bram_re_verilog(&[512]), bram_verilog(&[512]))
120}
121
122const STORE_VERILOG: &str = r#"// The token-row store's bank in layers of 512 words, its word out four clocks after its address: the ports registered
123// (q_*), each layer's write enable decoded there; every layer read every clock, each layer's word kept only if the read
124// was of it (mine, taken with the read); eight layers' words ORed into a register (gq); the groups' ORed into the word
125// (rd_q), taken only where re was high (r2, r3: re beside the read), so held between the edges re is high on, as
126// logos_bram_re_w512. A write lands a clock after it is asked, as a read does.
127module logos_store_w512 #(parameter D = 1024, A = 10)
128  (input clk, input re, input [A-1:0] ra, output [511:0] rd,
129   input we, input [A-1:0] wa, input [511:0] wd, input [63:0] wm);
130  localparam LAYERS = (D + 511) / 512, GROUPS = (LAYERS + 7) / 8;
131  localparam LA = A > 9 ? A - 9 : 1;
132  // Each address's row within its layer and its layer.
133  wire [8:0] r_row, w_row;
134  wire [LA-1:0] r_layer, w_layer;
135  generate
136    if (A > 9) begin : deep
137      assign r_row = ra[8:0];
138      assign w_row = wa[8:0];
139      assign r_layer = ra[A-1:9];
140      assign w_layer = wa[A-1:9];
141    end else if (A == 9) begin : one
142      assign r_row = ra;
143      assign w_row = wa;
144      assign r_layer = 1'b0;
145      assign w_layer = 1'b0;
146    end else begin : shallow
147      assign r_row = {{(9-A){1'b0}}, ra};
148      assign w_row = {{(9-A){1'b0}}, wa};
149      assign r_layer = 1'b0;
150      assign w_layer = 1'b0;
151    end
152  endgenerate
153  (* maxfan = 64 *) reg q_re;
154  (* maxfan = 64 *) reg [8:0] q_ra, q_wa;
155  (* maxfan = 64 *) reg [63:0] q_wm;
156  (* maxfan = 64 *) reg [511:0] q_wd;
157  reg [LA-1:0] q_rl;
158  reg [LAYERS-1:0] q_we;
159  integer k;
160  always @(posedge clk) begin
161    q_re <= re;
162    q_ra <= r_row;
163    q_rl <= r_layer;
164    q_wa <= w_row;
165    q_wd <= wd;
166    q_wm <= wm;
167    for (k = 0; k < LAYERS; k = k + 1) q_we[k] <= we && w_layer == k[LA-1:0];
168  end
169  wire [512*LAYERS-1:0] lq;
170  (* maxfan = 64 *) reg [LAYERS-1:0] mine;
171  genvar l;
172  generate
173    for (l = 0; l < LAYERS; l = l + 1) begin : layer
174      localparam [LA-1:0] AT = l;
175      logos_bram_w512_part #(.D(512), .A(9)) part(.clk(clk), .ra(q_ra), .rd(lq[512*l +: 512]),
176        .we(q_we[l]), .wa(q_wa), .wd(q_wd), .wm(q_wm));
177      always @(posedge clk) mine[l] <= q_rl == AT;
178    end
179  endgenerate
180  // Each group's word: its layers' words where the read was of them, ORed.
181  reg [512*GROUPS-1:0] gsum, gq;
182  integer g, j;
183  always @* begin
184    gsum = {(512*GROUPS){1'b0}};
185    for (g = 0; g < GROUPS; g = g + 1)
186      for (j = 0; j < 8; j = j + 1)
187        if (8 * g + j < LAYERS) gsum[512*g +: 512] = gsum[512*g +: 512] | (mine[8*g + j] ? lq[512*(8*g + j) +: 512] : 512'd0);
188  end
189  always @(posedge clk) gq <= gsum;
190  reg [511:0] word, rd_q;
191  integer h;
192  always @* begin
193    word = 512'd0;
194    for (h = 0; h < GROUPS; h = h + 1) word = word | gq[512*h +: 512];
195  end
196  reg r2, r3;
197  always @(posedge clk) begin
198    r2 <= q_re;
199    r3 <= r2;
200    if (r3) rd_q <= word;
201  end
202  assign rd = rd_q;
203endmodule
204"#;
205
206/// The depth from which `logos_delay` keeps its words in block RAM: a chain of one or two registers is cheaper than a
207/// block, and from three clocks on a chain is three or more flip-flops a bit, which Quartus Prime Pro builds as written.
208pub const DELAY_RING_LEAST: usize = 3;
209
210/// The width from which `logos_delay`'s ring deeper than an MLAB asks for M20K blocks, a block's widest word; a narrower
211/// ring asks for MLABs, a block holding it in a fortieth of its bits or less.
212pub const DELAY_M20K_LEAST: usize = 40;
213
214/// `logos_delay #(W, D)`, a word of `W` bits delayed `D` clocks (the word itself at depth 0). One or two clocks are a
215/// chain of registers. From [`DELAY_RING_LEAST`] clocks on the words go round a ring, a memory of the next power of two
216/// of `D` words written a word a clock and read `D - 1` words behind the write into its port's register, the chain's
217/// `D·W` flip-flops left as the ring's write address: `logos_delay_mlab` in MLABs to [`MLAB_WORDS`] words whatever its
218/// width, and beyond that `logos_delay_m20k` in M20K blocks from [`DELAY_M20K_LEAST`] bits wide and `logos_delay_mlab`
219/// below.
220pub fn delay_verilog() -> &'static str {
221    DELAY_VERILOG
222}
223
224const DELAY_VERILOG: &str = r#"
225// A read's marks carried D clocks to the clock its word lands: the valid in_v and the marks in_d themselves at depth 0,
226// else through D registers, the valid in registers the reset clears; flight is high while a valid is in any of them.
227module logos_landing #(parameter W = 1, D = 0)
228  (input clk, input rst, input in_v, input [W-1:0] in_d, output out_v, output [W-1:0] out_d, output flight);
229  generate
230    if (D == 0) begin : now
231      assign out_v = in_v;
232      assign out_d = in_d;
233      assign flight = 1'b0;
234    end else begin : later
235      (* maxfan = 64 *) reg [D-1:0] v;
236      reg [W*D-1:0] m;
237      integer k;
238      always @(posedge clk) begin
239        v[0] <= !rst && in_v;
240        m[W-1:0] <= in_d;
241        for (k = 1; k < D; k = k + 1) begin
242          v[k] <= !rst && v[k-1];
243          m[W*k +: W] <= m[W*(k-1) +: W];
244        end
245      end
246      assign out_v = v[D-1];
247      assign out_d = m[W*(D-1) +: W];
248      assign flight = |v;
249    end
250  endgenerate
251endmodule
252
253// d delayed D clocks: the word itself at depth 0, a chain of registers at one or two, a ring of block RAM from three, in
254// MLABs to 32 words (an MLAB's depth), and past that in M20K blocks from 40 bits wide and in MLABs below.
255module logos_delay #(parameter W = 32, D = 1) (input clk, input [W-1:0] d, output [W-1:0] q);
256  generate
257    if (D == 0) begin : now
258      assign q = d;
259    end else if (D < 3) begin : chain
260      reg [W-1:0] r1, r2;
261      always @(posedge clk) begin
262        r1 <= d;
263        r2 <= r1;
264      end
265      assign q = D == 1 ? r1 : r2;
266    end else if (W >= 40 && (1 << $clog2(D)) > 32) begin : wide
267      logos_delay_m20k #(.W(W), .D(D)) r(.clk(clk), .d(d), .q(q));
268    end else begin : narrow
269      logos_delay_mlab #(.W(W), .D(D)) r(.clk(clk), .d(d), .q(q));
270    end
271  endgenerate
272endmodule
273
274// d delayed D clocks (D of 2 or more) through a memory of 2^A >= D words in M20K blocks: each clock's word written at the write
275// address, and the word written D - 1 clocks before read into q. The read is never of the address being written.
276module logos_delay_m20k #(parameter W = 32, D = 3) (input clk, input [W-1:0] d, output reg [W-1:0] q);
277  localparam A = $clog2(D);
278  (* ramstyle = "M20K" *) reg [W-1:0] mem [0:(1 << A) - 1];
279  localparam [A-1:0] BACK = D - 1;
280  reg [A-1:0] wa = {A{1'b0}};
281  wire [A-1:0] ra = wa - BACK;
282  always @(posedge clk) begin
283    mem[wa] <= d;
284    q <= mem[ra];
285    wa <= wa + 1'b1;
286  end
287endmodule
288
289// d delayed D clocks (D of 2 or more) through a memory of 2^A >= D words in MLABs: each clock's word written at the write
290// address, and the word written D - 1 clocks before read into q. The read is never of the address being written.
291module logos_delay_mlab #(parameter W = 32, D = 3) (input clk, input [W-1:0] d, output reg [W-1:0] q);
292  localparam A = $clog2(D);
293  (* ramstyle = "MLAB" *) reg [W-1:0] mem [0:(1 << A) - 1];
294  localparam [A-1:0] BACK = D - 1;
295  reg [A-1:0] wa = {A{1'b0}};
296  wire [A-1:0] ra = wa - BACK;
297  always @(posedge clk) begin
298    mem[wa] <= d;
299    q <= mem[ra];
300    wa <= wa + 1'b1;
301  end
302endmodule
303"#;
304
305/// When a memory reads.
306#[derive(Clone, Copy, PartialEq, Eq)]
307enum Read {
308    Falling,
309    Rising,
310    Held,
311    Enabled,
312}
313
314/// The memories `name` names, their read `read`. A registered or held memory (the vector units' registers, the token-row
315/// store) is, each width, a memory of its own (`<name>_part`, the depth it is given) and the memory callers name: built as
316/// the part is, but for a word as wide as an M20K block's widest (40 bits) or wider more than one layer of 512 words deep
317/// in a number of layers that is no power of two. That one is stacks of powers of two layers, the deepest its own and
318/// each other a part beside it, each word in the stack the address's layers name (the deepest from address 0), and its
319/// read the stack the read address named: the fitter builds a memory's depth as a stack of a power of two layers (1,088
320/// words in 2,048 words' blocks, 57,344 in 65,536's). A falling-edge or enabled memory is one memory a width.
321fn memories(widths: &[usize], name: fn(usize) -> String, what: &str, read: Read) -> String {
322    let mut v = String::from(RAMSTYLE);
323    for &w in widths {
324        assert!(w > 0 && w % 8 == 0, "a memory {w} bits wide is not whole bytes");
325        let name = name(w);
326        let (ports, connect, edge, write) = match read {
327            Read::Falling => ("", "", "always @(negedge clk)", "we"),
328            Read::Rising => ("", "", "always @(posedge clk)", "we"),
329            Read::Held => ("input re, ", ".re(re), ", "always @(posedge clk) if (re)", "we"),
330            Read::Enabled => ("input ce, input cr, ", ".ce(ce), .cr(cr), ", "always @(posedge clk) if (cr)", "ce && we"),
331        };
332        let bytes = |mem: &str, at: &str| -> String {
333            (0..w / 8).map(|b| format!("      if (wm[{b}]) {mem}[{at}][{}:{}] <= wd[{}:{}];\n", 8 * b + 7, 8 * b, 8 * b + 7, 8 * b)).collect()
334        };
335        let edges = if read == Read::Enabled { "s ce is high on" } else { "" };
336        let stacked = matches!(read, Read::Rising | Read::Held);
337        writeln!(v, "// A block-RAM memory of {w}-bit words: {what}, writes on the rising").unwrap();
338        writeln!(v, "// edge{edges} under a byte mask.").unwrap();
339        writeln!(v, "module {name}{} #(parameter D = 1024, A = 10)", if stacked { "_part" } else { "" }).unwrap();
340        writeln!(v, "  (input clk,").unwrap();
341        writeln!(v, "   {ports}input [A-1:0] ra, output reg [{}:0] rd,", w - 1).unwrap();
342        writeln!(v, "   input we, input [A-1:0] wa, input [{}:0] wd, input [{}:0] wm);", w - 1, w / 8 - 1).unwrap();
343        writeln!(v, "  `LOGOS_RAMSTYLE(D) reg [{}:0] mem [0:D-1];", w - 1).unwrap();
344        writeln!(v, "  {edge} rd <= mem[ra];").unwrap();
345        writeln!(v, "  always @(posedge clk)").unwrap();
346        writeln!(v, "    if ({write}) begin").unwrap();
347        v.push_str(&bytes("mem", "wa"));
348        writeln!(v, "    end").unwrap();
349        writeln!(v, "endmodule").unwrap();
350        if !stacked {
351            continue;
352        }
353        writeln!(v).unwrap();
354        if w >= 40 {
355            writeln!(v, "// {name}_part, but a memory more than one layer of 512 words deep in a number of layers no power of two").unwrap();
356            writeln!(v, "// as stacks of powers of two layers: the deepest its own from address 0, each other a part.").unwrap();
357        } else {
358            writeln!(v, "// {name}_part, the memory callers name.").unwrap();
359        }
360        writeln!(v, "module {name} #(parameter D = 1024, A = 10)").unwrap();
361        writeln!(v, "  (input clk,").unwrap();
362        writeln!(v, "   {ports}input [A-1:0] ra, output [{}:0] rd,", w - 1).unwrap();
363        writeln!(v, "   input we, input [A-1:0] wa, input [{}:0] wd, input [{}:0] wm);", w - 1, w / 8 - 1).unwrap();
364        writeln!(v, "  localparam [31:0] LAYERS = (D + 511) / 512;").unwrap();
365        writeln!(v, "  localparam SPLIT = {} && (LAYERS & (LAYERS - 1)) != 0;", if w >= 40 { "1" } else { "0" }).unwrap();
366        writeln!(v, "  localparam TOP = $clog2(LAYERS + 1) - 1;").unwrap();
367        writeln!(v, "  localparam P0 = SPLIT ? 512 << TOP : D, A0 = SPLIT ? 9 + TOP : A;").unwrap();
368        writeln!(v, "  localparam [A:0] OWN = P0;").unwrap();
369        writeln!(v, "  `LOGOS_RAMSTYLE(P0) reg [{}:0] mem [0:P0-1];", w - 1).unwrap();
370        writeln!(v, "  reg [{}:0] rd0;", w - 1).unwrap();
371        writeln!(v, "  {edge} rd0 <= mem[ra[A0-1:0]];").unwrap();
372        writeln!(v, "  always @(posedge clk)").unwrap();
373        writeln!(v, "    if ({write} && (!SPLIT || {{1'b0, wa}} < OWN)) begin").unwrap();
374        v.push_str(&bytes("mem", "wa[A0-1:0]"));
375        writeln!(v, "    end").unwrap();
376        writeln!(v, "  generate").unwrap();
377        writeln!(v, "    if (SPLIT) begin : stacks").unwrap();
378        writeln!(v, "      // Each stack's word, zero unless the read was of it.").unwrap();
379        writeln!(v, "      wire [{}:0] got [0:23];", w - 1).unwrap();
380        writeln!(v, "      reg own;").unwrap();
381        writeln!(v, "      {edge} own <= {{1'b0, ra}} < OWN;").unwrap();
382        writeln!(v, "      genvar j;").unwrap();
383        writeln!(v, "      for (j = 0; j < 24; j = j + 1) begin : layer").unwrap();
384        writeln!(v, "        if (j < TOP && LAYERS[j]) begin : stack").unwrap();
385        writeln!(v, "          localparam [31:0] FROM = 512 * (LAYERS & ~((32'd2 << j) - 32'd1)), TO = FROM + (512 << j);").unwrap();
386        writeln!(v, "          localparam [A:0] BASE = FROM[A:0], LIMIT = TO[A:0];").unwrap();
387        writeln!(v, "          wire [{}:0] q;", w - 1).unwrap();
388        writeln!(v, "          reg mine;").unwrap();
389        writeln!(v, "          {edge} mine <= {{1'b0, ra}} >= BASE && {{1'b0, ra}} < LIMIT;").unwrap();
390        writeln!(v, "          {name}_part #(.D(512 << j), .A(9 + j)) part(.clk(clk), {connect}.ra(ra[8+j:0]), .rd(q),").unwrap();
391        writeln!(v, "            .we(we && {{1'b0, wa}} >= BASE && {{1'b0, wa}} < LIMIT), .wa(wa[8+j:0]), .wd(wd), .wm(wm));").unwrap();
392        writeln!(v, "          assign got[j] = mine ? q : {{{w}{{1'b0}}}};").unwrap();
393        writeln!(v, "        end else begin : none").unwrap();
394        writeln!(v, "          assign got[j] = {{{w}{{1'b0}}}};").unwrap();
395        writeln!(v, "        end").unwrap();
396        writeln!(v, "      end").unwrap();
397        writeln!(v, "      reg [{}:0] word;", w - 1).unwrap();
398        writeln!(v, "      integer k;").unwrap();
399        writeln!(v, "      always @* begin").unwrap();
400        writeln!(v, "        word = own ? rd0 : {{{w}{{1'b0}}}};").unwrap();
401        writeln!(v, "        for (k = 0; k < 24; k = k + 1) word = word | got[k];").unwrap();
402        writeln!(v, "      end").unwrap();
403        writeln!(v, "      assign rd = word;").unwrap();
404        writeln!(v, "    end else begin : whole").unwrap();
405        writeln!(v, "      assign rd = rd0;").unwrap();
406        writeln!(v, "    end").unwrap();
407        writeln!(v, "  endgenerate").unwrap();
408        writeln!(v, "endmodule").unwrap();
409    }
410    v
411}