logicaffeine_compile/spatial/decode_engine/rtl/
array.rs1pub const CHAIN: usize = 4;
22pub const CHAIN_ELEMENTS: usize = 2 * CHAIN;
24pub const LANE: u32 = 15;
26pub const HIGH_OFFSET: i64 = 8;
28pub const PE8_P_LATENCY: usize = CHAIN + 1;
31
32pub fn pack(q1: u8, q2: u8) -> i64 {
34 q1 as i64 + ((q2 as i64 - HIGH_OFFSET) << LANE)
35}
36
37pub fn split(sum: i64, act_sum: i64) -> (i64, i64) {
39 let low = sum & ((1 << LANE) - 1);
40 (low, ((sum - low) >> LANE) + HIGH_OFFSET * act_sum)
41}
42
43pub fn array_verilog() -> &'static str {
45 ARRAY_VERILOG
46}
47
48const ARRAY_VERILOG: &str = r#"// The array's processing element: two rows' partial dots with one token-row, four multiply-adds a DSP block.
49
50// A DSP block in 18x19 multiplier-adder sum mode with chain-in: signed 19-bit x and 18-bit y operands, 64-bit chain.
51module logos_dsp_sum2(input signed [18:0] ax, input signed [17:0] ay, input signed [18:0] bx, input signed [17:0] by,
52 input signed [63:0] chainin, output signed [63:0] chainout);
53 assign chainout = ax * ay + bx * by + chainin;
54endmodule
55
56// Eight elements of one token-row against two rows: four chained blocks, the lanes split from the chain's sum.
57// a: eight 8-bit excess codes; q1, q2: eight 4-bit digits of rows one and two; lo = sum a'.q1; hi = sum a'.(q2 - 8).
58module logos_pe8(input [63:0] a, input [31:0] q1, input [31:0] q2, output [14:0] lo, output signed [16:0] hi);
59 wire signed [63:0] chain [0:4];
60 assign chain[0] = 64'sd0;
61 genvar k;
62 generate
63 for (k = 0; k < 4; k = k + 1) begin : blk
64 wire [7:0] a0 = a[16*k +: 8], a1 = a[16*k + 8 +: 8];
65 wire [3:0] p0 = q1[8*k +: 4], p1 = q1[8*k + 4 +: 4], r0 = q2[8*k +: 4], r1 = q2[8*k + 4 +: 4];
66 wire signed [18:0] w0 = $signed({15'd0, p0}) + (($signed({15'd0, r0}) - 19'sd8) <<< 15);
67 wire signed [18:0] w1 = $signed({15'd0, p1}) + (($signed({15'd0, r1}) - 19'sd8) <<< 15);
68 logos_dsp_sum2 d(.ax(w0), .ay($signed({10'd0, a0})), .bx(w1), .by($signed({10'd0, a1})),
69 .chainin(chain[k]), .chainout(chain[k + 1]));
70 end
71 endgenerate
72 assign lo = chain[4][14:0];
73 assign hi = chain[4][31:15];
74endmodule
75
76// logos_pe8 for the user clock, systolic: block k's sum registered on the chain, its operands taken into its input
77// registers k clocks after block 0's, so lo and hi are logos_pe8's of the operands five clocks before. Block k's two
78// activations come in k clocks after block 0's (a's block k delayed by logos_column_act_stagger, once for every core);
79// its four digits are delayed here.
80module logos_pe8_p(input clk, input [63:0] a, input [31:0] q1, input [31:0] q2, output [14:0] lo, output signed [16:0] hi);
81 wire signed [63:0] chain [0:4];
82 assign chain[0] = 64'sd0;
83 // Block k's digits of both rows, {q2 byte, q1 byte}, delayed k clocks.
84 reg [15:0] n1, n2a, n2, n3a, n3b, n3;
85 always @(posedge clk) begin
86 n1 <= {q2[15:8], q1[15:8]};
87 n2a <= {q2[23:16], q1[23:16]}; n2 <= n2a;
88 n3a <= {q2[31:24], q1[31:24]}; n3b <= n3a; n3 <= n3b;
89 end
90 wire [63:0] nibs = {n3, n2, n1, q2[7:0], q1[7:0]};
91 genvar k;
92 generate
93 for (k = 0; k < 4; k = k + 1) begin : blk
94 wire [3:0] p0 = nibs[16*k +: 4], p1 = nibs[16*k + 4 +: 4], r0 = nibs[16*k + 8 +: 4], r1 = nibs[16*k + 12 +: 4];
95 wire signed [18:0] w0 = $signed({15'd0, p0}) + (($signed({15'd0, r0}) - 19'sd8) <<< 15);
96 wire signed [18:0] w1 = $signed({15'd0, p1}) + (($signed({15'd0, r1}) - 19'sd8) <<< 15);
97 reg signed [18:0] x0, x1;
98 reg [7:0] y0, y1;
99 reg signed [63:0] sum;
100 always @(posedge clk) begin
101 x0 <= w0; x1 <= w1; y0 <= a[16*k +: 8]; y1 <= a[16*k + 8 +: 8];
102 sum <= x0 * $signed({10'd0, y0}) + x1 * $signed({10'd0, y1}) + chain[k];
103 end
104 assign chain[k + 1] = sum;
105 end
106 endgenerate
107 assign lo = chain[4][14:0];
108 assign hi = chain[4][31:15];
109endmodule
110
111// A 32-element sub-block: four elements' lanes summed. s is the sub-block's sum of excess codes, which restores row
112// two's offset: p2 = sum hi + 8.s.
113module logos_subdot32(input [255:0] a, input [127:0] q1, input [127:0] q2, input [12:0] s,
114 output [16:0] p1, output signed [18:0] p2);
115 wire [14:0] lo [0:3];
116 wire signed [16:0] hi [0:3];
117 genvar j;
118 generate
119 for (j = 0; j < 4; j = j + 1) begin : pe
120 logos_pe8 u(.a(a[64*j +: 64]), .q1(q1[32*j +: 32]), .q2(q2[32*j +: 32]), .lo(lo[j]), .hi(hi[j]));
121 end
122 endgenerate
123 assign p1 = {2'd0, lo[0]} + {2'd0, lo[1]} + {2'd0, lo[2]} + {2'd0, lo[3]};
124 assign p2 = hi[0] + hi[1] + hi[2] + hi[3] + $signed({3'd0, s, 3'd0});
125endmodule
126"#;