Coarse arithmetics¶
The $macc cell type represents a generalized multiply and accumulate
operation. The cell is purely combinational. It outputs the result of summing up
a sequence of products and other injected summands.
Y = 0 +- a0factor1 * a0factor2 +- a1factor1 * a1factor2 +- ...
+ B[0] + B[1] + ...
The A port consists of concatenated pairs of multiplier inputs (“factors”). A zero length factor2 acts as a constant 1, turning factor1 into a simple summand.
In this pseudocode, u(foo) means an unsigned int that’s foo bits long.
struct A {
u(CONFIG.mul_info[0].factor1_len) a0factor1;
u(CONFIG.mul_info[0].factor2_len) a0factor2;
u(CONFIG.mul_info[1].factor1_len) a1factor1;
u(CONFIG.mul_info[1].factor2_len) a1factor2;
...
};
The cell’s CONFIG parameter determines the layout of cell port A. The
CONFIG parameter carries the following information:
struct CONFIG {
u4 num_bits;
struct mul_info {
bool is_signed;
bool is_subtract;
u(num_bits) factor1_len;
u(num_bits) factor2_len;
}[num_ports];
};
B is an array of concatenated 1-bit-wide unsigned integers to also be summed up.
- yosys> help $alu¶
Arithmetic logic unit
A building block supporting both binary addition/subtraction operations, and indirectly, comparison operations. Typically created by the
alumaccpass, which transforms:$add,$sub,$lt,$le,$ge,$gt,$eq,$eqx,$ne,$nexcells into this$alucell.- Properties:
- Simulation model (verilog)¶
688module \$alu (A, B, CI, BI, X, Y, CO); 689 690 parameter A_SIGNED = 0; 691 parameter B_SIGNED = 0; 692 parameter A_WIDTH = 1; 693 parameter B_WIDTH = 1; 694 parameter Y_WIDTH = 1; 695 696 input [A_WIDTH-1:0] A; // Input operand 697 input [B_WIDTH-1:0] B; // Input operand 698 output [Y_WIDTH-1:0] X; // A xor B (sign-extended, optional B inversion, 699 // used in combination with 700 // reduction-AND for $eq/$ne ops) 701 output [Y_WIDTH-1:0] Y; // Sum 702 703 input CI; // Carry-in (set for $sub) 704 input BI; // Invert-B (set for $sub) 705 output [Y_WIDTH-1:0] CO; // Carry-out 706 707 wire [Y_WIDTH-1:0] AA, BB; 708 709 generate 710 if (A_SIGNED && B_SIGNED) begin:BLOCK1 711 assign AA = $signed(A), BB = BI ? ~$signed(B) : $signed(B); 712 end else begin:BLOCK2 713 assign AA = $unsigned(A), BB = BI ? ~$unsigned(B) : $unsigned(B); 714 end 715 endgenerate 716 717 // this is 'x' if Y and CO should be all 'x', and '0' otherwise 718 wire y_co_undef = ^{A, A, B, B, CI, CI, BI, BI}; 719 720 assign X = AA ^ BB; 721 // Full adder 722 assign Y = (AA + BB + CI) ^ {Y_WIDTH{y_co_undef}}; 723 724 function get_carry; 725 input a, b, c; 726 get_carry = (a&b) | (a&c) | (b&c); 727 endfunction 728 729 genvar i; 730 generate 731 assign CO[0] = get_carry(AA[0], BB[0], CI) ^ y_co_undef; 732 for (i = 1; i < Y_WIDTH; i = i+1) begin:BLOCK3 733 assign CO[i] = get_carry(AA[i], BB[i], CO[i-1]) ^ y_co_undef; 734 end 735 endgenerate 736 737endmodule
- yosys> help $fa¶
- Properties:
- Simulation model (verilog)¶
628module \$fa (A, B, C, X, Y); 629 630 parameter WIDTH = 1; 631 632 input [WIDTH-1:0] A, B, C; 633 output [WIDTH-1:0] X, Y; 634 635 wire [WIDTH-1:0] t1, t2, t3; 636 637 assign t1 = A ^ B, t2 = A & B, t3 = C & t1; 638 assign Y = t1 ^ C, X = (t2 | t3) ^ (Y ^ Y); 639 640endmodule
- yosys> help $lcu¶
Lookahead carry unit A building block dedicated to fast computation of carry-bits used in binary arithmetic operations. By replacing the ripple carry structure used in full-adder blocks, the more significant bits of the sum can be expected to be computed more quickly. Typically created during
techmapof $alu cells (see the “_90_alu” rule in +/techmap.v).- Properties:
- Simulation model (verilog)¶
656module \$lcu (P, G, CI, CO); 657 658 parameter WIDTH = 1; 659 660 input [WIDTH-1:0] P; // Propagate 661 input [WIDTH-1:0] G; // Generate 662 input CI; // Carry-in 663 664 output reg [WIDTH-1:0] CO; // Carry-out 665 666 integer i; 667 always @* begin 668 CO = 'bx; 669 if (^{P, G, CI} !== 1'bx) begin 670 CO[0] = G[0] || (P[0] && CI); 671 for (i = 1; i < WIDTH; i = i+1) 672 CO[i] = G[i] || (P[i] && CO[i-1]); 673 end 674 end 675 676endmodule
- yosys> help $macc¶
Multiply and accumulate. A building block for summing any number of negated and unnegated signals and arithmetic products of pairs of signals. Cell port A concatenates pairs of signals to be multiplied together. When the second signal in a pair is zero length, a constant 1 is used instead as the second factor. Cell port B concatenates 1-bit-wide signals to also be summed, such as “carry in” in adders. Typically created by the
alumaccpass, which transforms $add and $mul into $macc cells.- Properties:
- Simulation model (verilog)¶
1104module \$macc (A, B, Y); 1105 1106 parameter A_WIDTH = 0; 1107 parameter B_WIDTH = 0; 1108 parameter Y_WIDTH = 0; 1109 // CONFIG determines the layout of A, as explained below 1110 parameter CONFIG = 4'b0000; 1111 parameter CONFIG_WIDTH = 4; 1112 1113 // In the terms used for this cell, there's mixed meanings for the term "port". To disambiguate: 1114 // A cell port is for example the A input (it is constructed in C++ as cell->setPort(ID::A, ...)) 1115 // Multiplier ports are pairs of multiplier inputs ("factors"). 1116 // If the second signal in such a pair is zero length, no multiplication is necessary, and the first signal is just added to the sum. 1117 input [A_WIDTH-1:0] A; // Cell port A is the concatenation of all arithmetic ports 1118 input [B_WIDTH-1:0] B; // Cell port B is the concatenation of single-bit unsigned signals to be also added to the sum 1119 output reg [Y_WIDTH-1:0] Y; // Output sum 1120 1121 // Xilinx XSIM does not like $clog2() below.. 1122 function integer my_clog2; 1123 input integer v; 1124 begin 1125 if (v > 0) 1126 v = v - 1; 1127 my_clog2 = 0; 1128 while (v) begin 1129 v = v >> 1; 1130 my_clog2 = my_clog2 + 1; 1131 end 1132 end 1133 endfunction 1134 1135 // Bits that a factor's length field in CONFIG per factor in cell port A 1136 localparam integer num_bits = CONFIG[3:0] > 0 ? CONFIG[3:0] : 1; 1137 // Number of multiplier ports 1138 localparam integer num_ports = (CONFIG_WIDTH-4) / (2 + 2*num_bits); 1139 // Minium bit width of an induction variable to iterate over all bits of cell port A 1140 localparam integer num_abits = my_clog2(A_WIDTH) > 0 ? my_clog2(A_WIDTH) : 1; 1141 1142 // In this pseudocode, u(foo) means an unsigned int that's foo bits long. 1143 // The CONFIG parameter carries the following information: 1144 // struct CONFIG { 1145 // u4 num_bits; 1146 // struct port_field { 1147 // bool is_signed; 1148 // bool is_subtract; 1149 // u(num_bits) factor1_len; 1150 // u(num_bits) factor2_len; 1151 // }[num_ports]; 1152 // }; 1153 1154 // The A cell port carries the following information: 1155 // struct A { 1156 // u(CONFIG.port_field[0].factor1_len) port0factor1; 1157 // u(CONFIG.port_field[0].factor2_len) port0factor2; 1158 // u(CONFIG.port_field[1].factor1_len) port1factor1; 1159 // u(CONFIG.port_field[1].factor2_len) port1factor2; 1160 // ... 1161 // }; 1162 // and log(sizeof(A)) is num_abits. 1163 // No factor1 may have a zero length. 1164 // A factor2 having a zero length implies factor2 is replaced with a constant 1. 1165 1166 // Additionally, B is an array of 1-bit-wide unsigned integers to also be summed up. 1167 // Finally, we have: 1168 // Y = port0factor1 * port0factor2 + port1factor1 * port1factor2 + ... 1169 // * B[0] + B[1] + ... 1170 1171 function [2*num_ports*num_abits-1:0] get_port_offsets; 1172 input [CONFIG_WIDTH-1:0] cfg; 1173 integer i, cursor; 1174 begin 1175 cursor = 0; 1176 get_port_offsets = 0; 1177 for (i = 0; i < num_ports; i = i+1) begin 1178 get_port_offsets[(2*i + 0)*num_abits +: num_abits] = cursor; 1179 cursor = cursor + cfg[4 + i*(2 + 2*num_bits) + 2 +: num_bits]; 1180 get_port_offsets[(2*i + 1)*num_abits +: num_abits] = cursor; 1181 cursor = cursor + cfg[4 + i*(2 + 2*num_bits) + 2 + num_bits +: num_bits]; 1182 end 1183 end 1184 endfunction 1185 1186 localparam [2*num_ports*num_abits-1:0] port_offsets = get_port_offsets(CONFIG); 1187 1188 `define PORT_IS_SIGNED (0 + CONFIG[4 + i*(2 + 2*num_bits)]) 1189 `define PORT_DO_SUBTRACT (0 + CONFIG[4 + i*(2 + 2*num_bits) + 1]) 1190 `define PORT_SIZE_A (0 + CONFIG[4 + i*(2 + 2*num_bits) + 2 +: num_bits]) 1191 `define PORT_SIZE_B (0 + CONFIG[4 + i*(2 + 2*num_bits) + 2 + num_bits +: num_bits]) 1192 `define PORT_OFFSET_A (0 + port_offsets[2*i*num_abits +: num_abits]) 1193 `define PORT_OFFSET_B (0 + port_offsets[2*i*num_abits + num_abits +: num_abits]) 1194 1195 integer i, j; 1196 reg [Y_WIDTH-1:0] tmp_a, tmp_b; 1197 1198 always @* begin 1199 Y = 0; 1200 for (i = 0; i < num_ports; i = i+1) 1201 begin 1202 tmp_a = 0; 1203 tmp_b = 0; 1204 1205 for (j = 0; j < `PORT_SIZE_A; j = j+1) 1206 tmp_a[j] = A[`PORT_OFFSET_A + j]; 1207 1208 if (`PORT_IS_SIGNED && `PORT_SIZE_A > 0) 1209 for (j = `PORT_SIZE_A; j < Y_WIDTH; j = j+1) 1210 tmp_a[j] = tmp_a[`PORT_SIZE_A-1]; 1211 1212 for (j = 0; j < `PORT_SIZE_B; j = j+1) 1213 tmp_b[j] = A[`PORT_OFFSET_B + j]; 1214 1215 if (`PORT_IS_SIGNED && `PORT_SIZE_B > 0) 1216 for (j = `PORT_SIZE_B; j < Y_WIDTH; j = j+1) 1217 tmp_b[j] = tmp_b[`PORT_SIZE_B-1]; 1218 1219 if (`PORT_SIZE_B > 0) 1220 tmp_a = tmp_a * tmp_b; 1221 1222 if (`PORT_DO_SUBTRACT) 1223 Y = Y - tmp_a; 1224 else 1225 Y = Y + tmp_a; 1226 end 1227 for (i = 0; i < B_WIDTH; i = i+1) begin 1228 Y = Y + B[i]; 1229 end 1230 end 1231 1232 `undef PORT_IS_SIGNED 1233 `undef PORT_DO_SUBTRACT 1234 `undef PORT_SIZE_A 1235 `undef PORT_SIZE_B 1236 `undef PORT_OFFSET_A 1237 `undef PORT_OFFSET_B 1238 1239endmodule
- yosys> help $macc_v2¶
Multiply and add. This cell represents a generic fused multiply-add operation, it supersedes the earlier $macc cell.
- Properties:
- Simulation model (verilog)¶
1251module \$macc_v2 (A, B, C, Y); 1252 1253 parameter NPRODUCTS = 0; 1254 parameter NADDENDS = 0; 1255 parameter A_WIDTHS = 16'h0000; 1256 parameter B_WIDTHS = 16'h0000; 1257 parameter C_WIDTHS = 16'h0000; 1258 parameter Y_WIDTH = 0; 1259 1260 parameter PRODUCT_NEGATED = 1'bx; 1261 parameter ADDEND_NEGATED = 1'bx; 1262 parameter A_SIGNED = 1'bx; 1263 parameter B_SIGNED = 1'bx; 1264 parameter C_SIGNED = 1'bx; 1265 1266 function integer sum_widths1; 1267 input [(16*NPRODUCTS)-1:0] widths; 1268 integer i; 1269 begin 1270 sum_widths1 = 0; 1271 for (i = 0; i < NPRODUCTS; i++) begin 1272 sum_widths1 = sum_widths1 + widths[16*i+:16]; 1273 end 1274 end 1275 endfunction 1276 1277 function integer sum_widths2; 1278 input [(16*NADDENDS)-1:0] widths; 1279 integer i; 1280 begin 1281 sum_widths2 = 0; 1282 for (i = 0; i < NADDENDS; i++) begin 1283 sum_widths2 = sum_widths2 + widths[16*i+:16]; 1284 end 1285 end 1286 endfunction 1287 1288 input [sum_widths1(A_WIDTHS)-1:0] A; // concatenation of LHS factors 1289 input [sum_widths1(B_WIDTHS)-1:0] B; // concatenation of RHS factors 1290 input [sum_widths2(C_WIDTHS)-1:0] C; // concatenation of summands 1291 output reg [Y_WIDTH-1:0] Y; // output sum 1292 1293 integer i, j, ai, bi, ci, aw, bw, cw; 1294 reg [Y_WIDTH-1:0] product; 1295 reg [Y_WIDTH-1:0] addend, oper_a, oper_b; 1296 1297 always @* begin 1298 Y = 0; 1299 ai = 0; 1300 bi = 0; 1301 for (i = 0; i < NPRODUCTS; i = i+1) 1302 begin 1303 aw = A_WIDTHS[16*i+:16]; 1304 bw = B_WIDTHS[16*i+:16]; 1305 1306 oper_a = 0; 1307 oper_b = 0; 1308 for (j = 0; j < Y_WIDTH && j < aw; j = j + 1) 1309 oper_a[j] = A[ai + j]; 1310 for (j = 0; j < Y_WIDTH && j < bw; j = j + 1) 1311 oper_b[j] = B[bi + j]; 1312 // A_SIGNED[i] == B_SIGNED[i] as RTLIL invariant 1313 if (A_SIGNED[i] && B_SIGNED[i]) begin 1314 for (j = aw; j > 0 && j < Y_WIDTH; j = j + 1) 1315 oper_a[j] = oper_a[j - 1]; 1316 for (j = bw; j > 0 && j < Y_WIDTH; j = j + 1) 1317 oper_b[j] = oper_b[j - 1]; 1318 end 1319 1320 product = oper_a * oper_b; 1321 1322 if (PRODUCT_NEGATED[i]) 1323 Y = Y - product; 1324 else 1325 Y = Y + product; 1326 1327 ai = ai + aw; 1328 bi = bi + bw; 1329 end 1330 1331 ci = 0; 1332 for (i = 0; i < NADDENDS; i = i+1) 1333 begin 1334 cw = C_WIDTHS[16*i+:16]; 1335 1336 addend = 0; 1337 for (j = 0; j < Y_WIDTH && j < cw; j = j + 1) 1338 addend[j] = C[ci + j]; 1339 if (C_SIGNED[i]) begin 1340 for (j = cw; j > 0 && j < Y_WIDTH; j = j + 1) 1341 addend[j] = addend[j - 1]; 1342 end 1343 1344 if (ADDEND_NEGATED[i]) 1345 Y = Y - addend; 1346 else 1347 Y = Y + addend; 1348 1349 ci = ci + cw; 1350 end 1351 end 1352 1353endmodule