logicaffeine_compile/spatial/decode_engine/rtl/
act_quant.rs1use crate::spatial::decode_engine::numerics::ActScale;
10
11pub fn closed_form_wide_scale(s: u32, e: i32) -> ActScale {
15 let m1 = ((s + 511) >> 9).div_ceil(127) as i64;
16 if m1 <= 255 {
17 ActScale { m: m1, e: e - 14 }
18 } else {
19 ActScale { m: ((s + 1023) >> 10).div_ceil(127) as i64, e: e - 13 }
20 }
21}
22
23pub const WIDE_SCALE_P_LATENCY: usize = 3;
25
26pub fn closed_form_scale(s: u32, e: i32) -> ActScale {
28 let m1 = ((s + 8191) >> 13).div_ceil(127) as i64;
29 if m1 <= 15 {
30 ActScale { m: m1, e: e - 10 }
31 } else {
32 ActScale { m: ((s + 16383) >> 14).div_ceil(127) as i64, e: e - 9 }
33 }
34}
35
36pub fn act_quant_verilog() -> String {
43 format!("{}\n{}", super::ram::ram_verilog(&[512]), ACT_QUANT_VERILOG)
44}
45
46const ACT_QUANT_VERILOG: &str = r#"// One activation block: its 4-bit-significand scale and its exact codes.
47module logos_act_code(input [31:0] x, input [7:0] m, input signed [11:0] e, input two, output reg signed [15:0] code);
48 wire neg = x[31];
49 wire [7:0] ex = x[30:23];
50 wire [23:0] sx = (ex == 8'd0) ? 24'd0 : {1'b1, x[22:0]};
51 // The value's place against the scale's: x / (m·2^e) = sx·2^k / m, k = (ex − 150) − e; carried 32 places finer.
52 wire signed [12:0] k = $signed({5'd0, ex}) - 13'sd150 - e;
53 wire signed [12:0] up32 = k + 13'sd32;
54 wire [63:0] num = (up32 < 13'sd0) ? 64'd0 : (up32 > 13'sd39) ? 64'hffff_ffff_ffff_ffff : ({40'd0, sx} << up32[5:0]);
55 wire [63:0] q = num / {56'd0, m};
56 wire [63:0] rem = num % {56'd0, m};
57 wire [31:0] whole = q[63:32];
58 wire [31:0] frac = q[31:0];
59 wire up = (frac > 32'h8000_0000) || (frac == 32'h8000_0000 && (rem != 64'd0 || whole[0]));
60 wire [31:0] n = whole + {31'd0, up};
61 wire [31:0] lim = two ? 32'd32767 : 32'd127;
62 wire [31:0] c = (n > lim) ? lim : n;
63 always @* code = neg ? -$signed({1'b0, c[14:0]}) : $signed({1'b0, c[14:0]});
64endmodule
65
66module logos_act_block(input [1023:0] x, input two, output reg [3:0] m, output reg signed [11:0] e, output [511:0] codes);
67 // The largest magnitude, a denormal read as zero.
68 reg [30:0] amax;
69 integer i;
70 always @* begin
71 amax = 31'd0;
72 for (i = 0; i < 32; i = i + 1)
73 if (x[32*i+30 -: 8] != 8'd0 && x[32*i+30 -: 31] > amax) amax = x[32*i+30 -: 31];
74 end
75 wire [23:0] s = {1'b1, amax[22:0]};
76 wire signed [11:0] eu = $signed({4'd0, amax[30:23]}) - 12'sd127;
77 wire [24:0] r13 = ({1'b0, s} + 25'd8191) >> 13;
78 wire [11:0] c13 = r13[11:0];
79 wire [11:0] m1 = (c13 + 12'd126) / 12'd127;
80 wire [24:0] r14 = ({1'b0, s} + 25'd16383) >> 14;
81 wire [11:0] c14 = r14[11:0];
82 wire [11:0] m2 = (c14 + 12'd126) / 12'd127;
83 always @* begin
84 if (amax == 31'd0) begin m = 4'd8; e = 12'sd0; end
85 else if (m1 <= 12'd15) begin m = m1[3:0]; e = eu - 12'sd10 - (two ? 12'sd8 : 12'sd0); end
86 else begin m = m2[3:0]; e = eu - 12'sd9 - (two ? 12'sd8 : 12'sd0); end
87 end
88 genvar g;
89 generate
90 for (g = 0; g < 32; g = g + 1) begin : lane
91 wire signed [15:0] c;
92 logos_act_code u(.x(x[32*g +: 32]), .m({4'd0, m}), .e(e), .two(two), .code(c));
93 assign codes[16*g +: 16] = (amax == 31'd0) ? 16'd0 : c;
94 end
95 endgenerate
96endmodule
97
98// The per-block scale of a block whose largest magnitude is `amax` (the bits below the sign, a denormal read as zero):
99// wide_scale's 8-bit significand, its exponent eight lower for two-word codes.
100module logos_wide_scale(input [30:0] amax, input two, output reg [7:0] m, output reg signed [11:0] e);
101 wire [23:0] s = {1'b1, amax[22:0]};
102 wire signed [11:0] eu = $signed({4'd0, amax[30:23]}) - 12'sd127;
103 wire [24:0] r9 = ({1'b0, s} + 25'd511) >> 9;
104 wire [15:0] c9 = r9[15:0];
105 wire [24:0] r10 = ({1'b0, s} + 25'd1023) >> 10;
106 wire [15:0] c10 = r10[15:0];
107 // Each ceiling over 127 as a product and a shift, no divider: (x·33027) >> 22 is ⌊x/127⌋ for every x = c + 126, c at
108 // most 2^15.
109 wire [31:0] p1 = ({16'd0, c9} + 32'd126) * 32'd33027;
110 wire [31:0] p2 = ({16'd0, c10} + 32'd126) * 32'd33027;
111 wire [15:0] m1 = {6'd0, p1[31:22]};
112 wire [15:0] m2 = {6'd0, p2[31:22]};
113 always @* begin
114 if (amax == 31'd0) begin m = 8'd128; e = 12'sd0; end
115 else if (m1 <= 16'd255) begin m = m1[7:0]; e = eu - 12'sd14 - (two ? 12'sd8 : 12'sd0); end
116 else begin m = m2[7:0]; e = eu - 12'sd13 - (two ? 12'sd8 : 12'sd0); end
117 end
118endmodule
119
120// logos_wide_scale for the user clock, an operand a clock: m and e are logos_wide_scale's of the amax and two three
121// clocks before. Each ceiling's operand ⌈S/2^k⌉ + 126 by one addition (126·2^k added before the shift); its product by
122// 33027, whose top ten bits are the quotient by 127; the choice between the two.
123module logos_wide_scale_p(input clk, input [30:0] amax, input two, output reg [7:0] m, output reg signed [11:0] e);
124 wire [24:0] s = {2'b01, amax[22:0]};
125 wire [24:0] r9 = (s + 25'd65023) >> 9;
126 wire [24:0] r10 = (s + 25'd130047) >> 10;
127 reg [15:0] x1, x2;
128 reg signed [11:0] eu1, eu2;
129 reg z1, z2;
130 always @(posedge clk) begin
131 x1 <= r9[15:0];
132 x2 <= r10[15:0];
133 eu1 <= $signed({4'd0, amax[30:23]}) - (two ? 12'sd135 : 12'sd127);
134 z1 <= amax == 31'd0;
135 end
136 reg [31:0] p1, p2;
137 always @(posedge clk) begin
138 p1 <= {16'd0, x1} * 32'd33027;
139 p2 <= {16'd0, x2} * 32'd33027;
140 eu2 <= eu1;
141 z2 <= z1;
142 end
143 always @(posedge clk) begin
144 if (z2) begin m <= 8'd128; e <= 12'sd0; end
145 else if (p1[31:30] == 2'd0) begin m <= p1[29:22]; e <= eu2 - 12'sd14; end
146 else begin m <= p2[29:22]; e <= eu2 - 12'sd13; end
147 end
148endmodule
149
150// One weight block's activations under one 8-bit-significand scale.
151module logos_act_wide #(parameter LANES = 32)
152 (input [32*LANES-1:0] x, input two, output [7:0] m, output signed [11:0] e, output [16*LANES-1:0] codes);
153 reg [30:0] amax;
154 integer i;
155 always @* begin
156 amax = 31'd0;
157 for (i = 0; i < LANES; i = i + 1)
158 if (x[32*i+30 -: 8] != 8'd0 && x[32*i+30 -: 31] > amax) amax = x[32*i+30 -: 31];
159 end
160 logos_wide_scale sc(.amax(amax), .two(two), .m(m), .e(e));
161 genvar g;
162 generate
163 for (g = 0; g < LANES; g = g + 1) begin : lane
164 wire signed [15:0] c;
165 logos_act_code u(.x(x[32*g +: 32]), .m(m), .e(e), .two(two), .code(c));
166 assign codes[16*g +: 16] = (amax == 31'd0) ? 16'd0 : c;
167 end
168 endgenerate
169endmodule
170
171// logos_act_wide over a block that arrives sixteen values a beat, LANES a multiple of sixteen. `in_v` comes with each
172// beat and `clear` with a block's first: the block's largest magnitude is kept as its beats arrive and the beats are
173// held in block RAM. `go`, a cycle after the last beat, latches the scale; the sixteen code units then make a beat's
174// codes a cycle into `codes`, `busy` until the last beat's. A block of fewer beats leaves the codes above its own as
175// they were; the next block's beats come once `busy` falls.
176module logos_act_stream #(parameter LANES = 256)
177 (input clk, input rst, input clear, input in_v, input [511:0] in_beat, input go, input two,
178 output reg busy, output reg [7:0] m, output reg signed [11:0] e, output [16*LANES-1:0] codes);
179 localparam BEATS = LANES / 16;
180 localparam BA = (BEATS > 1) ? $clog2(BEATS) : 1;
181 // The beat's largest magnitude, a denormal read as zero, by a balanced tree.
182 wire [30:0] mag [0:15];
183 wire [30:0] t1 [0:7];
184 wire [30:0] t2 [0:3];
185 wire [30:0] t3 [0:1];
186 genvar g;
187 generate
188 for (g = 0; g < 16; g = g + 1) begin : magnitude
189 assign mag[g] = (in_beat[32*g+30 -: 8] == 8'd0) ? 31'd0 : in_beat[32*g+30 -: 31];
190 end
191 for (g = 0; g < 8; g = g + 1) begin : max8
192 assign t1[g] = (mag[2*g] > mag[2*g+1]) ? mag[2*g] : mag[2*g+1];
193 end
194 for (g = 0; g < 4; g = g + 1) begin : max4
195 assign t2[g] = (t1[2*g] > t1[2*g+1]) ? t1[2*g] : t1[2*g+1];
196 end
197 for (g = 0; g < 2; g = g + 1) begin : max2
198 assign t3[g] = (t2[2*g] > t2[2*g+1]) ? t2[2*g] : t2[2*g+1];
199 end
200 endgenerate
201 wire [30:0] beat_max = (t3[0] > t3[1]) ? t3[0] : t3[1];
202 reg [30:0] amax;
203 wire [7:0] m_c;
204 wire signed [11:0] e_c;
205 logos_wide_scale sc(.amax(amax), .two(two), .m(m_c), .e(e_c));
206 reg [BA:0] n, c;
207 reg two_r;
208 wire [511:0] xb;
209 logos_ram_w512 #(.D(BEATS), .A(BA)) beats(.clk(clk), .ra(c[BA-1:0]), .rd(xb), .we(in_v),
210 .wa(clear ? {BA{1'b0}} : n[BA-1:0]), .wd(in_beat), .wm({64{1'b1}}));
211 reg [256*BEATS-1:0] cr;
212 assign codes = cr[16*LANES-1:0];
213 wire [255:0] cb;
214 generate
215 for (g = 0; g < 16; g = g + 1) begin : lane
216 wire signed [15:0] cg;
217 logos_act_code u(.x(xb[32*g +: 32]), .m(m), .e(e), .two(two_r), .code(cg));
218 assign cb[16*g +: 16] = cg;
219 end
220 endgenerate
221 always @(posedge clk) begin
222 if (rst) begin
223 busy <= 1'b0; n <= {(BA+1){1'b0}};
224 end else begin
225 if (in_v) begin
226 n <= (clear ? {(BA+1){1'b0}} : n) + 1'b1;
227 amax <= (clear || beat_max > amax) ? beat_max : amax;
228 end
229 if (go) begin
230 busy <= n != {(BA+1){1'b0}}; c <= {(BA+1){1'b0}}; m <= m_c; e <= e_c; two_r <= two;
231 end else if (busy) begin
232 cr[256*c +: 256] <= cb;
233 if (c + 1'b1 == n) busy <= 1'b0; else c <= c + 1'b1;
234 end
235 end
236 end
237endmodule
238"#;