diff options
Diffstat (limited to 'techlibs/common')
-rw-r--r-- | techlibs/common/Makefile.inc | 32 | ||||
-rw-r--r-- | techlibs/common/adff2dff.v | 27 | ||||
-rw-r--r-- | techlibs/common/blackbox.sed | 5 | ||||
-rw-r--r-- | techlibs/common/simcells.v | 152 | ||||
-rw-r--r-- | techlibs/common/simlib.v | 452 | ||||
-rw-r--r-- | techlibs/common/stdcells.v | 1080 | ||||
-rw-r--r-- | techlibs/common/synth.cc | 156 | ||||
-rw-r--r-- | techlibs/common/techmap.v | 509 |
8 files changed, 1219 insertions, 1194 deletions
diff --git a/techlibs/common/Makefile.inc b/techlibs/common/Makefile.inc index 6d94d5c9b..7c8cc2f66 100644 --- a/techlibs/common/Makefile.inc +++ b/techlibs/common/Makefile.inc @@ -1,25 +1,35 @@ +OBJS += techlibs/common/synth.o + EXTRA_TARGETS += techlibs/common/blackbox.v techlibs/common/blackbox.v: techlibs/common/blackbox.sed techlibs/common/simlib.v techlibs/common/simcells.v - cat techlibs/common/simlib.v techlibs/common/simcells.v | sed -rf techlibs/common/blackbox.sed > techlibs/common/blackbox.v.new - mv techlibs/common/blackbox.v.new techlibs/common/blackbox.v + $(P) cat techlibs/common/simlib.v techlibs/common/simcells.v | $(SED) -rf techlibs/common/blackbox.sed > techlibs/common/blackbox.v.new + $(Q) mv techlibs/common/blackbox.v.new techlibs/common/blackbox.v -EXTRA_TARGETS += share/simlib.v share/simcells.v share/blackbox.v share/pmux2mux.v +EXTRA_TARGETS += share/simlib.v share/simcells.v share/techmap.v share/blackbox.v share/pmux2mux.v share/adff2dff.v share/simlib.v: techlibs/common/simlib.v - mkdir -p share - cp techlibs/common/simlib.v share/simlib.v + $(P) mkdir -p share + $(Q) cp techlibs/common/simlib.v share/simlib.v share/simcells.v: techlibs/common/simcells.v - mkdir -p share - cp techlibs/common/simcells.v share/simcells.v + $(P) mkdir -p share + $(Q) cp techlibs/common/simcells.v share/simcells.v + +share/techmap.v: techlibs/common/techmap.v + $(P) mkdir -p share + $(Q) cp techlibs/common/techmap.v share/techmap.v share/blackbox.v: techlibs/common/blackbox.v - mkdir -p share - cp techlibs/common/blackbox.v share/blackbox.v + $(P) mkdir -p share + $(Q) cp techlibs/common/blackbox.v share/blackbox.v share/pmux2mux.v: techlibs/common/pmux2mux.v - mkdir -p share - cp techlibs/common/pmux2mux.v share/pmux2mux.v + $(P) mkdir -p share + $(Q) cp techlibs/common/pmux2mux.v share/pmux2mux.v + +share/adff2dff.v: techlibs/common/adff2dff.v + $(P) mkdir -p share + $(Q) cp techlibs/common/adff2dff.v share/adff2dff.v diff --git a/techlibs/common/adff2dff.v b/techlibs/common/adff2dff.v new file mode 100644 index 000000000..86744d415 --- /dev/null +++ b/techlibs/common/adff2dff.v @@ -0,0 +1,27 @@ +(* techmap_celltype = "$adff" *) +module adff2dff (CLK, ARST, D, Q); + parameter WIDTH = 1; + parameter CLK_POLARITY = 1; + parameter ARST_POLARITY = 1; + parameter ARST_VALUE = 0; + + input CLK, ARST; + input [WIDTH-1:0] D; + output reg [WIDTH-1:0] Q; + wire reg [WIDTH-1:0] NEXT_Q; + + wire [1023:0] _TECHMAP_DO_ = "proc;;"; + + always @* + if (ARST == ARST_POLARITY) + NEXT_Q <= ARST_VALUE; + else + NEXT_Q <= D; + + if (CLK_POLARITY) + always @(posedge CLK) + Q <= NEXT_Q; + else + always @(negedge CLK) + Q <= NEXT_Q; +endmodule diff --git a/techlibs/common/blackbox.sed b/techlibs/common/blackbox.sed index 21693ecdd..db8900344 100644 --- a/techlibs/common/blackbox.sed +++ b/techlibs/common/blackbox.sed @@ -1,4 +1,5 @@ #!/bin/sed -r -/^(wire|assign|reg|event)/ d; -/^(genvar|generate|always|initial)/,/^end/ d; +/^(wire|assign|reg|event|integer|localparam|\/\/|[\/ ]\*| *$|`)/ d; +/^(genvar|generate|always|initial|task|function)/,/^end/ d; +/^endmodule/ s/$/\n/; s/ reg / /; diff --git a/techlibs/common/simcells.v b/techlibs/common/simcells.v index 10a809db6..a2a377350 100644 --- a/techlibs/common/simcells.v +++ b/techlibs/common/simcells.v @@ -20,12 +20,12 @@ * The internal logic cell simulation library. * * This verilog library contains simple simulation models for the internal - * logic cells ($_INV_ , $_AND_ , ...) that are generated by the default technology - * mapper (see "stdcells.v" in this directory) and expected by the "abc" pass. + * logic cells ($_NOT_ , $_AND_ , ...) that are generated by the default technology + * mapper (see "techmap.v" in this directory) and expected by the "abc" pass. * */ -module \$_INV_ (A, Y); +module \$_NOT_ (A, Y); input A; output Y; assign Y = ~A; @@ -37,24 +37,66 @@ output Y; assign Y = A & B; endmodule +module \$_NAND_ (A, B, Y); +input A, B; +output Y; +assign Y = ~(A & B); +endmodule + module \$_OR_ (A, B, Y); input A, B; output Y; assign Y = A | B; endmodule +module \$_NOR_ (A, B, Y); +input A, B; +output Y; +assign Y = ~(A | B); +endmodule + module \$_XOR_ (A, B, Y); input A, B; output Y; assign Y = A ^ B; endmodule +module \$_XNOR_ (A, B, Y); +input A, B; +output Y; +assign Y = ~(A ^ B); +endmodule + module \$_MUX_ (A, B, S, Y); input A, B, S; output Y; assign Y = S ? B : A; endmodule +module \$_AOI3_ (A, B, C, Y); +input A, B, C; +output Y; +assign Y = ~((A & B) | C); +endmodule + +module \$_OAI3_ (A, B, C, Y); +input A, B, C; +output Y; +assign Y = ~((A | B) & C); +endmodule + +module \$_AOI4_ (A, B, C, D, Y); +input A, B, C, D; +output Y; +assign Y = ~((A & B) | (C & D)); +endmodule + +module \$_OAI4_ (A, B, C, D, Y); +input A, B, C, D; +output Y; +assign Y = ~((A | B) & (C | D)); +endmodule + module \$_SR_NN_ (S, R, Q); input S, R; output reg Q; @@ -325,3 +367,107 @@ always @* begin end endmodule +module \$_DLATCHSR_NNN_ (E, S, R, D, Q); +input E, S, R, D; +output reg Q; +always @* begin + if (R == 0) + Q <= 0; + else if (S == 0) + Q <= 1; + else if (E == 0) + Q <= D; +end +endmodule + +module \$_DLATCHSR_NNP_ (E, S, R, D, Q); +input E, S, R, D; +output reg Q; +always @* begin + if (R == 1) + Q <= 0; + else if (S == 0) + Q <= 1; + else if (E == 0) + Q <= D; +end +endmodule + +module \$_DLATCHSR_NPN_ (E, S, R, D, Q); +input E, S, R, D; +output reg Q; +always @* begin + if (R == 0) + Q <= 0; + else if (S == 1) + Q <= 1; + else if (E == 0) + Q <= D; +end +endmodule + +module \$_DLATCHSR_NPP_ (E, S, R, D, Q); +input E, S, R, D; +output reg Q; +always @* begin + if (R == 1) + Q <= 0; + else if (S == 1) + Q <= 1; + else if (E == 0) + Q <= D; +end +endmodule + +module \$_DLATCHSR_PNN_ (E, S, R, D, Q); +input E, S, R, D; +output reg Q; +always @* begin + if (R == 0) + Q <= 0; + else if (S == 0) + Q <= 1; + else if (E == 1) + Q <= D; +end +endmodule + +module \$_DLATCHSR_PNP_ (E, S, R, D, Q); +input E, S, R, D; +output reg Q; +always @* begin + if (R == 1) + Q <= 0; + else if (S == 0) + Q <= 1; + else if (E == 1) + Q <= D; +end +endmodule + +module \$_DLATCHSR_PPN_ (E, S, R, D, Q); +input E, S, R, D; +output reg Q; +always @* begin + if (R == 0) + Q <= 0; + else if (S == 1) + Q <= 1; + else if (E == 1) + Q <= D; +end +endmodule + +module \$_DLATCHSR_PPP_ (E, S, R, D, Q); +input E, S, R, D; +output reg Q; +always @* begin + if (R == 1) + Q <= 0; + else if (S == 1) + Q <= 1; + else if (E == 1) + Q <= D; +end +endmodule + diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 4436abfe7..2d8088adb 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -55,30 +55,6 @@ endmodule // -------------------------------------------------------- -module \$bu0 (A, Y); - -parameter A_SIGNED = 0; -parameter A_WIDTH = 0; -parameter Y_WIDTH = 0; - -input [A_WIDTH-1:0] A; -output [Y_WIDTH-1:0] Y; - -generate - if (!A_SIGNED && 0 < A_WIDTH && A_WIDTH < Y_WIDTH) begin:BLOCK1 - assign Y[A_WIDTH-1:0] = A; - assign Y[Y_WIDTH-1:A_WIDTH] = 0; - end else if (A_SIGNED) begin:BLOCK2 - assign Y = $signed(A); - end else begin:BLOCK3 - assign Y = A; - end -endgenerate - -endmodule - -// -------------------------------------------------------- - module \$pos (A, Y); parameter A_SIGNED = 0; @@ -418,6 +394,142 @@ endmodule // -------------------------------------------------------- +module \$shift (A, B, Y); + +parameter A_SIGNED = 0; +parameter B_SIGNED = 0; +parameter A_WIDTH = 0; +parameter B_WIDTH = 0; +parameter Y_WIDTH = 0; + +input [A_WIDTH-1:0] A; +input [B_WIDTH-1:0] B; +output [Y_WIDTH-1:0] Y; + +generate + if (B_SIGNED) begin:BLOCK1 + assign Y = $signed(B) < 0 ? A << -B : A >> B; + end else begin:BLOCK2 + assign Y = A >> B; + end +endgenerate + +endmodule + +// -------------------------------------------------------- + +module \$shiftx (A, B, Y); + +parameter A_SIGNED = 0; +parameter B_SIGNED = 0; +parameter A_WIDTH = 0; +parameter B_WIDTH = 0; +parameter Y_WIDTH = 0; + +input [A_WIDTH-1:0] A; +input [B_WIDTH-1:0] B; +output [Y_WIDTH-1:0] Y; + +generate + if (Y_WIDTH > 0) + if (B_SIGNED) begin:BLOCK1 + assign Y = A[$signed(B) +: Y_WIDTH]; + end else begin:BLOCK2 + assign Y = A[B +: Y_WIDTH]; + end +endgenerate + +endmodule + +// -------------------------------------------------------- + +module \$fa (A, B, C, X, Y); + +parameter WIDTH = 1; + +input [WIDTH-1:0] A, B, C; +output [WIDTH-1:0] X, Y; + +wire [WIDTH-1:0] t1, t2, t3; + +assign t1 = A ^ B, t2 = A & B, t3 = C & t1; +assign Y = t1 ^ C, X = (t2 | t3) ^ (Y ^ Y); + +endmodule + +// -------------------------------------------------------- + +module \$lcu (P, G, CI, CO); + +parameter WIDTH = 1; + +input [WIDTH-1:0] P, G; +input CI; + +output reg [WIDTH-1:0] CO; + +integer i; +always @* begin + CO = 'bx; + if (^{P, G, CI} !== 1'bx) begin + CO[0] = G[0] || (P[0] && CI); + for (i = 1; i < WIDTH; i = i+1) + CO[i] = G[i] || (P[i] && CO[i-1]); + end +end + +endmodule + +// -------------------------------------------------------- + +module \$alu (A, B, CI, BI, X, Y, CO); + +parameter A_SIGNED = 0; +parameter B_SIGNED = 0; +parameter A_WIDTH = 1; +parameter B_WIDTH = 1; +parameter Y_WIDTH = 1; + +input [A_WIDTH-1:0] A; +input [B_WIDTH-1:0] B; +output [Y_WIDTH-1:0] X, Y; + +input CI, BI; +output [Y_WIDTH-1:0] CO; + +wire [Y_WIDTH-1:0] AA, BB; + +generate + if (A_SIGNED && B_SIGNED) begin:BLOCK1 + assign AA = $signed(A), BB = BI ? ~$signed(B) : $signed(B); + end else begin:BLOCK2 + assign AA = $unsigned(A), BB = BI ? ~$unsigned(B) : $unsigned(B); + end +endgenerate + +// this is 'x' if Y and CO should be all 'x', and '0' otherwise +wire y_co_undef = ^{A, A, B, B, CI, CI, BI, BI}; + +assign X = AA ^ BB; +assign Y = (AA + BB + CI) ^ {Y_WIDTH{y_co_undef}}; + +function get_carry; + input a, b, c; + get_carry = (a&b) | (a&c) | (b&c); +endfunction + +genvar i; +generate + assign CO[0] = get_carry(AA[0], BB[0], CI) ^ y_co_undef; + for (i = 1; i < Y_WIDTH; i = i+1) begin:BLOCK3 + assign CO[i] = get_carry(AA[i], BB[i], CO[i-1]) ^ y_co_undef; + end +endgenerate + +endmodule + +// -------------------------------------------------------- + module \$lt (A, B, Y); parameter A_SIGNED = 0; @@ -682,6 +794,108 @@ endmodule // -------------------------------------------------------- +module \$macc (A, B, Y); + +parameter A_WIDTH = 0; +parameter B_WIDTH = 0; +parameter Y_WIDTH = 0; +parameter CONFIG = 4'b0000; +parameter CONFIG_WIDTH = 4; + +input [A_WIDTH-1:0] A; +input [B_WIDTH-1:0] B; +output reg [Y_WIDTH-1:0] Y; + +// Xilinx XSIM does not like $clog2() below.. +function integer my_clog2; + input integer v; + begin + if (v > 0) + v = v - 1; + my_clog2 = 0; + while (v) begin + v = v >> 1; + my_clog2 = my_clog2 + 1; + end + end +endfunction + +localparam integer num_bits = CONFIG[3:0] > 0 ? CONFIG[3:0] : 1; +localparam integer num_ports = (CONFIG_WIDTH-4) / (2 + 2*num_bits); +localparam integer num_abits = my_clog2(A_WIDTH) > 0 ? my_clog2(A_WIDTH) : 1; + +function [2*num_ports*num_abits-1:0] get_port_offsets; + input [CONFIG_WIDTH-1:0] cfg; + integer i, cursor; + begin + cursor = 0; + get_port_offsets = 0; + for (i = 0; i < num_ports; i = i+1) begin + get_port_offsets[(2*i + 0)*num_abits +: num_abits] = cursor; + cursor = cursor + cfg[4 + i*(2 + 2*num_bits) + 2 +: num_bits]; + get_port_offsets[(2*i + 1)*num_abits +: num_abits] = cursor; + cursor = cursor + cfg[4 + i*(2 + 2*num_bits) + 2 + num_bits +: num_bits]; + end + end +endfunction + +localparam [2*num_ports*num_abits-1:0] port_offsets = get_port_offsets(CONFIG); + +`define PORT_IS_SIGNED (0 + CONFIG[4 + i*(2 + 2*num_bits)]) +`define PORT_DO_SUBTRACT (0 + CONFIG[4 + i*(2 + 2*num_bits) + 1]) +`define PORT_SIZE_A (0 + CONFIG[4 + i*(2 + 2*num_bits) + 2 +: num_bits]) +`define PORT_SIZE_B (0 + CONFIG[4 + i*(2 + 2*num_bits) + 2 + num_bits +: num_bits]) +`define PORT_OFFSET_A (0 + port_offsets[2*i*num_abits +: num_abits]) +`define PORT_OFFSET_B (0 + port_offsets[2*i*num_abits + num_abits +: num_abits]) + +integer i, j; +reg [Y_WIDTH-1:0] tmp_a, tmp_b; + +always @* begin + Y = 0; + for (i = 0; i < num_ports; i = i+1) + begin + tmp_a = 0; + tmp_b = 0; + + for (j = 0; j < `PORT_SIZE_A; j = j+1) + tmp_a[j] = A[`PORT_OFFSET_A + j]; + + if (`PORT_IS_SIGNED && `PORT_SIZE_A > 0) + for (j = `PORT_SIZE_A; j < Y_WIDTH; j = j+1) + tmp_a[j] = tmp_a[`PORT_SIZE_A-1]; + + for (j = 0; j < `PORT_SIZE_B; j = j+1) + tmp_b[j] = A[`PORT_OFFSET_B + j]; + + if (`PORT_IS_SIGNED && `PORT_SIZE_B > 0) + for (j = `PORT_SIZE_B; j < Y_WIDTH; j = j+1) + tmp_b[j] = tmp_b[`PORT_SIZE_B-1]; + + if (`PORT_SIZE_B > 0) + tmp_a = tmp_a * tmp_b; + + if (`PORT_DO_SUBTRACT) + Y = Y - tmp_a; + else + Y = Y + tmp_a; + end + for (i = 0; i < B_WIDTH; i = i+1) begin + Y = Y + B[i]; + end +end + +`undef PORT_IS_SIGNED +`undef PORT_DO_SUBTRACT +`undef PORT_SIZE_A +`undef PORT_SIZE_B +`undef PORT_OFFSET_A +`undef PORT_OFFSET_B + +endmodule + +// -------------------------------------------------------- + module \$div (A, B, Y); parameter A_SIGNED = 0; @@ -889,52 +1103,30 @@ input [S_WIDTH-1:0] S; output reg [WIDTH-1:0] Y; integer i; +reg found_active_sel_bit; always @* begin Y = A; - for (i = 0; i < S_WIDTH; i = i+1) - if (S[i]) - Y = B >> (WIDTH*i); -end - -endmodule - -// -------------------------------------------------------- - -module \$safe_pmux (A, B, S, Y); - -parameter WIDTH = 0; -parameter S_WIDTH = 0; - -input [WIDTH-1:0] A; -input [WIDTH*S_WIDTH-1:0] B; -input [S_WIDTH-1:0] S; -output reg [WIDTH-1:0] Y; - -integer i, j; - -always @* begin - j = 0; + found_active_sel_bit = 0; for (i = 0; i < S_WIDTH; i = i+1) if (S[i]) begin - Y = B >> (WIDTH*i); - j = j + 1; + Y = found_active_sel_bit ? 'bx : B >> (WIDTH*i); + found_active_sel_bit = 1; end - if (j != 1) - Y = A; end endmodule // -------------------------------------------------------- +`ifndef SIMLIB_NOLUT -module \$lut (I, O); +module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; -input [WIDTH-1:0] I; -output reg O; +input [WIDTH-1:0] A; +output reg Y; wire lut0_out, lut1_out; @@ -942,18 +1134,18 @@ generate if (WIDTH <= 1) begin:simple assign {lut1_out, lut0_out} = LUT; end else begin:complex - \$lut #( .WIDTH(WIDTH-1), .LUT(LUT ) ) lut0 ( .I(I[WIDTH-2:0]), .O(lut0_out) ); - \$lut #( .WIDTH(WIDTH-1), .LUT(LUT >> (2**(WIDTH-1))) ) lut1 ( .I(I[WIDTH-2:0]), .O(lut1_out) ); + \$lut #( .WIDTH(WIDTH-1), .LUT(LUT ) ) lut0 ( .A(A[WIDTH-2:0]), .Y(lut0_out) ); + \$lut #( .WIDTH(WIDTH-1), .LUT(LUT >> (2**(WIDTH-1))) ) lut1 ( .A(A[WIDTH-2:0]), .Y(lut1_out) ); end if (WIDTH > 0) begin:lutlogic always @* begin - casez ({I[WIDTH-1], lut0_out, lut1_out}) - 3'b?11: O = 1'b1; - 3'b?00: O = 1'b0; - 3'b0??: O = lut0_out; - 3'b1??: O = lut1_out; - default: O = 1'bx; + casez ({A[WIDTH-1], lut0_out, lut1_out}) + 3'b?11: Y = 1'b1; + 3'b?00: Y = 1'b0; + 3'b0??: Y = lut0_out; + 3'b1??: Y = lut1_out; + default: Y = 1'bx; endcase end end @@ -961,6 +1153,7 @@ endgenerate endmodule +`endif // -------------------------------------------------------- module \$assert (A, EN); @@ -977,6 +1170,7 @@ end endmodule // -------------------------------------------------------- +`ifndef SIMLIB_NOSR module \$sr (SET, CLR, Q); @@ -1003,6 +1197,7 @@ endgenerate endmodule +`endif // -------------------------------------------------------- module \$dff (CLK, D, Q); @@ -1022,6 +1217,7 @@ end endmodule // -------------------------------------------------------- +`ifndef SIMLIB_NOSR module \$dffsr (CLK, SET, CLR, D, Q); @@ -1053,6 +1249,7 @@ endgenerate endmodule +`endif // -------------------------------------------------------- module \$adff (CLK, ARST, D, Q); @@ -1096,6 +1293,40 @@ end endmodule // -------------------------------------------------------- +`ifndef SIMLIB_NOSR + +module \$dlatchsr (EN, SET, CLR, D, Q); + +parameter WIDTH = 0; +parameter EN_POLARITY = 1'b1; +parameter SET_POLARITY = 1'b1; +parameter CLR_POLARITY = 1'b1; + +input EN; +input [WIDTH-1:0] SET, CLR, D; +output reg [WIDTH-1:0] Q; + +wire pos_en = EN == EN_POLARITY; +wire [WIDTH-1:0] pos_set = SET_POLARITY ? SET : ~SET; +wire [WIDTH-1:0] pos_clr = CLR_POLARITY ? CLR : ~CLR; + +genvar i; +generate + for (i = 0; i < WIDTH; i = i+1) begin:bit + always @* + if (pos_clr[i]) + Q[i] <= 0; + else if (pos_set[i]) + Q[i] <= 1; + else if (pos_en) + Q[i] <= D[i]; + end +endgenerate + +endmodule + +`endif +// -------------------------------------------------------- module \$fsm (CLK, ARST, CTRL_IN, CTRL_OUT); @@ -1224,7 +1455,8 @@ parameter WIDTH = 8; parameter CLK_ENABLE = 0; parameter CLK_POLARITY = 0; -input CLK, EN; +input CLK; +input [WIDTH-1:0] EN; input [ABITS-1:0] ADDR; input [WIDTH-1:0] DATA; @@ -1260,7 +1492,8 @@ input [RD_PORTS-1:0] RD_CLK; input [RD_PORTS*ABITS-1:0] RD_ADDR; output reg [RD_PORTS*WIDTH-1:0] RD_DATA; -input [WR_PORTS-1:0] WR_CLK, WR_EN; +input [WR_PORTS-1:0] WR_CLK; +input [WR_PORTS*WIDTH-1:0] WR_EN; input [WR_PORTS*ABITS-1:0] WR_ADDR; input [WR_PORTS*WIDTH-1:0] WR_DATA; @@ -1273,71 +1506,94 @@ generate for (i = 0; i < RD_PORTS; i = i+1) begin:rd if (RD_CLK_ENABLE[i] == 0) begin:rd_noclk always @(RD_ADDR or update_async_rd) - RD_DATA[ i*WIDTH +: WIDTH ] <= data[ RD_ADDR[ i*ABITS +: ABITS ] - OFFSET ]; + RD_DATA[i*WIDTH +: WIDTH] <= data[RD_ADDR[i*ABITS +: ABITS] - OFFSET]; end else if (RD_TRANSPARENT[i] == 1) begin:rd_transparent reg [ABITS-1:0] addr_buf; if (RD_CLK_POLARITY[i] == 1) begin:rd_trans_posclk always @(posedge RD_CLK[i]) - addr_buf <= RD_ADDR[ i*ABITS +: ABITS ]; + addr_buf <= RD_ADDR[i*ABITS +: ABITS]; end else begin:rd_trans_negclk always @(negedge RD_CLK[i]) - addr_buf <= RD_ADDR[ i*ABITS +: ABITS ]; + addr_buf <= RD_ADDR[i*ABITS +: ABITS]; end always @(addr_buf or update_async_rd) - RD_DATA[ i*WIDTH +: WIDTH ] <= data[ addr_buf - OFFSET ]; + RD_DATA[i*WIDTH +: WIDTH] <= data[addr_buf - OFFSET]; end else begin:rd_notransparent if (RD_CLK_POLARITY[i] == 1) begin:rd_notrans_posclk always @(posedge RD_CLK[i]) - RD_DATA[ i*WIDTH +: WIDTH ] <= data[ RD_ADDR[ i*ABITS +: ABITS ] - OFFSET ]; + RD_DATA[i*WIDTH +: WIDTH] <= data[RD_ADDR[i*ABITS +: ABITS] - OFFSET]; end else begin:rd_notrans_negclk always @(negedge RD_CLK[i]) - RD_DATA[ i*WIDTH +: WIDTH ] <= data[ RD_ADDR[ i*ABITS +: ABITS ] - OFFSET ]; + RD_DATA[i*WIDTH +: WIDTH] <= data[RD_ADDR[i*ABITS +: ABITS] - OFFSET]; end end end for (i = 0; i < WR_PORTS; i = i+1) begin:wr - integer k; - reg found_collision; + integer k, n; + reg found_collision, run_update; if (WR_CLK_ENABLE[i] == 0) begin:wr_noclk always @(WR_ADDR or WR_DATA or WR_EN) begin - if (WR_EN[i]) begin - found_collision = 0; - for (k = i+1; k < WR_PORTS; k = k+1) - if (WR_EN[k] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ]) - found_collision = 1; - if (!found_collision) begin - data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ] <= WR_DATA[ i*WIDTH +: WIDTH ]; - update_async_rd <= 1; update_async_rd <= 0; + run_update = 0; + for (n = 0; n < WIDTH; n = n+1) begin + if (WR_EN[i*WIDTH + n]) begin + found_collision = 0; + for (k = i+1; k < WR_PORTS; k = k+1) + if (WR_EN[k*WIDTH + n] && WR_ADDR[i*ABITS +: ABITS] == WR_ADDR[k*ABITS +: ABITS]) + found_collision = 1; + if (!found_collision) begin + data[WR_ADDR[i*ABITS +: ABITS] - OFFSET][n] <= WR_DATA[i*WIDTH + n]; + run_update = 1; + end end end + if (run_update) begin + update_async_rd <= 1; + update_async_rd <= 0; + end end end else if (WR_CLK_POLARITY[i] == 1) begin:rd_posclk - always @(posedge WR_CLK[i]) - if (WR_EN[i]) begin - found_collision = 0; - for (k = i+1; k < WR_PORTS; k = k+1) - if (WR_EN[k] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ]) - found_collision = 1; - if (!found_collision) begin - data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ] <= WR_DATA[ i*WIDTH +: WIDTH ]; - update_async_rd <= 1; update_async_rd <= 0; + always @(posedge WR_CLK[i]) begin + run_update = 0; + for (n = 0; n < WIDTH; n = n+1) begin + if (WR_EN[i*WIDTH + n]) begin + found_collision = 0; + for (k = i+1; k < WR_PORTS; k = k+1) + if (WR_EN[k*WIDTH + n] && WR_ADDR[i*ABITS +: ABITS] == WR_ADDR[k*ABITS +: ABITS]) + found_collision = 1; + if (!found_collision) begin + data[WR_ADDR[i*ABITS +: ABITS] - OFFSET][n] <= WR_DATA[i*WIDTH + n]; + run_update = 1; + end end end + if (run_update) begin + update_async_rd <= 1; + update_async_rd <= 0; + end + end end else begin:rd_negclk - always @(negedge WR_CLK[i]) - if (WR_EN[i]) begin - found_collision = 0; - for (k = i+1; k < WR_PORTS; k = k+1) - if (WR_EN[k] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ]) - found_collision = 1; - if (!found_collision) begin - data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ] <= WR_DATA[ i*WIDTH +: WIDTH ]; - update_async_rd <= 1; update_async_rd <= 0; + always @(negedge WR_CLK[i]) begin + run_update = 0; + for (n = 0; n < WIDTH; n = n+1) begin + if (WR_EN[i*WIDTH + n]) begin + found_collision = 0; + for (k = i+1; k < WR_PORTS; k = k+1) + if (WR_EN[k*WIDTH + n] && WR_ADDR[i*ABITS +: ABITS] == WR_ADDR[k*ABITS +: ABITS]) + found_collision = 1; + if (!found_collision) begin + data[WR_ADDR[i*ABITS +: ABITS] - OFFSET][n] <= WR_DATA[i*WIDTH + n]; + run_update = 1; + end end end + if (run_update) begin + update_async_rd <= 1; + update_async_rd <= 0; + end + end end end diff --git a/techlibs/common/stdcells.v b/techlibs/common/stdcells.v deleted file mode 100644 index fdee26b6f..000000000 --- a/techlibs/common/stdcells.v +++ /dev/null @@ -1,1080 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * --- - * - * The internal logic cell technology mapper. - * - * This verilog library contains the mapping of internal cells (e.g. $not with - * variable bit width) to the internal logic cells (such as the single bit $_INV_ - * gate). Usually this logic network is then mapped to the actual technology - * using e.g. the "abc" pass. - * - * Note that this library does not map $mem cells. They must be mapped to logic - * and $dff cells using the "memory_map" pass first. (Or map it to custom cells, - * which is of course highly recommended for larger memories.) - * - */ - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$not ; -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$pos ; -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$bu0 ; -endmodule - -// -------------------------------------------------------- - -module \$neg (A, Y); - -parameter A_SIGNED = 0; -parameter A_WIDTH = 1; -parameter Y_WIDTH = 1; - -input [A_WIDTH-1:0] A; -output [Y_WIDTH-1:0] Y; - -\$sub #( - .A_SIGNED(A_SIGNED), - .B_SIGNED(A_SIGNED), - .A_WIDTH(1), - .B_WIDTH(A_WIDTH), - .Y_WIDTH(Y_WIDTH) -) sub ( - .A(1'b0), - .B(A), - .Y(Y) -); - -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$and ; -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$or ; -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$xor ; -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$xnor ; -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$reduce_and ; -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$reduce_or ; -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$reduce_xor ; -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$reduce_xnor ; -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$reduce_bool ; -endmodule - -// -------------------------------------------------------- - -module \$__shift (X, A, Y); - -parameter WIDTH = 1; -parameter SHIFT = 0; - -input X; -input [WIDTH-1:0] A; -output [WIDTH-1:0] Y; - -genvar i; -generate - for (i = 0; i < WIDTH; i = i + 1) begin:V - if (i+SHIFT < 0) begin - assign Y[i] = 0; - end else - if (i+SHIFT < WIDTH) begin - assign Y[i] = A[i+SHIFT]; - end else begin - assign Y[i] = X; - end - end -endgenerate - -endmodule - -// -------------------------------------------------------- - -module \$shl (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -parameter WIDTH = Y_WIDTH; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -genvar i; -generate - wire [WIDTH*(B_WIDTH+1)-1:0] chain; - \$pos #( - .A_SIGNED(A_SIGNED), - .A_WIDTH(A_WIDTH), - .Y_WIDTH(WIDTH) - ) expand ( - .A(A), - .Y(chain[WIDTH-1:0]) - ); - assign Y = chain[WIDTH*(B_WIDTH+1)-1 : WIDTH*B_WIDTH]; - for (i = 0; i < B_WIDTH; i = i + 1) begin:V - wire [WIDTH-1:0] unshifted, shifted, result; - assign unshifted = chain[WIDTH*i + WIDTH-1 : WIDTH*i]; - assign chain[WIDTH*(i+1) + WIDTH-1 : WIDTH*(i+1)] = result; - \$__shift #( - .WIDTH(WIDTH), - .SHIFT(0 - (2 ** (i > 30 ? 30 : i))) - ) sh ( - .X(0), - .A(unshifted), - .Y(shifted) - ); - \$mux #( - .WIDTH(WIDTH) - ) mux ( - .A(unshifted), - .B(shifted), - .Y(result), - .S(B[i]) - ); - end -endgenerate - -endmodule - -// -------------------------------------------------------- - -module \$shr (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -localparam WIDTH = A_WIDTH > Y_WIDTH ? A_WIDTH : Y_WIDTH; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -genvar i; -generate - wire [WIDTH*(B_WIDTH+1)-1:0] chain; - \$pos #( - .A_SIGNED(A_SIGNED), - .A_WIDTH(A_WIDTH), - .Y_WIDTH(WIDTH) - ) expand ( - .A(A), - .Y(chain[WIDTH-1:0]) - ); - assign Y = chain[WIDTH*(B_WIDTH+1)-1 : WIDTH*B_WIDTH]; - for (i = 0; i < B_WIDTH; i = i + 1) begin:V - wire [WIDTH-1:0] unshifted, shifted, result; - assign unshifted = chain[WIDTH*i + WIDTH-1 : WIDTH*i]; - assign chain[WIDTH*(i+1) + WIDTH-1 : WIDTH*(i+1)] = result; - \$__shift #( - .WIDTH(WIDTH), - .SHIFT(2 ** (i > 30 ? 30 : i)) - ) sh ( - .X(0), - .A(unshifted), - .Y(shifted) - ); - \$mux #( - .WIDTH(WIDTH) - ) mux ( - .A(unshifted), - .B(shifted), - .Y(result), - .S(B[i]) - ); - end -endgenerate - -endmodule - -// -------------------------------------------------------- - -module \$sshl (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -localparam WIDTH = Y_WIDTH; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -genvar i; -generate - wire [WIDTH*(B_WIDTH+1)-1:0] chain; - \$pos #( - .A_SIGNED(A_SIGNED), - .A_WIDTH(A_WIDTH), - .Y_WIDTH(WIDTH) - ) expand ( - .A(A), - .Y(chain[WIDTH-1:0]) - ); - assign Y = chain[WIDTH*(B_WIDTH+1)-1 : WIDTH*B_WIDTH]; - for (i = 0; i < B_WIDTH; i = i + 1) begin:V - wire [WIDTH-1:0] unshifted, shifted, result; - assign unshifted = chain[WIDTH*i + WIDTH-1 : WIDTH*i]; - assign chain[WIDTH*(i+1) + WIDTH-1 : WIDTH*(i+1)] = result; - \$__shift #( - .WIDTH(WIDTH), - .SHIFT(0 - (2 ** (i > 30 ? 30 : i))) - ) sh ( - .X(0), - .A(unshifted), - .Y(shifted) - ); - \$mux #( - .WIDTH(WIDTH) - ) mux ( - .A(unshifted), - .B(shifted), - .Y(result), - .S(B[i]) - ); - end -endgenerate - -endmodule - -// -------------------------------------------------------- - -module \$sshr (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -localparam WIDTH = A_WIDTH > Y_WIDTH ? A_WIDTH : Y_WIDTH; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -genvar i; -generate - wire [WIDTH*(B_WIDTH+1)-1:0] chain; - \$pos #( - .A_SIGNED(A_SIGNED), - .A_WIDTH(A_WIDTH), - .Y_WIDTH(WIDTH) - ) expand ( - .A(A), - .Y(chain[WIDTH-1:0]) - ); - for (i = 0; i < Y_WIDTH; i = i + 1) begin:Y - if (i < WIDTH) begin - assign Y[i] = chain[WIDTH*B_WIDTH + i]; - end else - if (A_SIGNED) begin - assign Y[i] = chain[WIDTH*B_WIDTH + WIDTH-1]; - end else begin - assign Y[i] = 0; - end - end - for (i = 0; i < B_WIDTH; i = i + 1) begin:V - wire [WIDTH-1:0] unshifted, shifted, result; - assign unshifted = chain[WIDTH*i + WIDTH-1 : WIDTH*i]; - assign chain[WIDTH*(i+1) + WIDTH-1 : WIDTH*(i+1)] = result; - \$__shift #( - .WIDTH(WIDTH), - .SHIFT(2 ** (i > 30 ? 30 : i)) - ) sh ( - .X(A_SIGNED && A[A_WIDTH-1]), - .A(unshifted), - .Y(shifted) - ); - \$mux #( - .WIDTH(WIDTH) - ) mux ( - .A(unshifted), - .B(shifted), - .Y(result), - .S(B[i]) - ); - end -endgenerate - -endmodule - -// -------------------------------------------------------- - -module \$__fulladd (A, B, C, X, Y); - -// {X, Y} = A + B + C -input A, B, C; -output X, Y; - -// {t1, t2} = A + B -wire t1, t2, t3; - -\$_AND_ gate1 ( .A(A), .B(B), .Y(t1) ); -\$_XOR_ gate2 ( .A(A), .B(B), .Y(t2) ); -\$_AND_ gate3 ( .A(t2), .B(C), .Y(t3) ); -\$_XOR_ gate4 ( .A(t2), .B(C), .Y(Y) ); -\$_OR_ gate5 ( .A(t1), .B(t3), .Y(X) ); - -endmodule - - -// -------------------------------------------------------- - -module \$__alu (A, B, Cin, Y, Cout, Csign); - -parameter WIDTH = 1; - -input [WIDTH-1:0] A, B; -input Cin; - -output [WIDTH-1:0] Y; -output Cout, Csign; - -wire [WIDTH:0] carry; -assign carry[0] = Cin; -assign Cout = carry[WIDTH]; -assign Csign = carry[WIDTH-1]; - -genvar i; -generate - for (i = 0; i < WIDTH; i = i + 1) begin:V - \$__fulladd adder ( - .A(A[i]), - .B(B[i]), - .C(carry[i]), - .X(carry[i+1]), - .Y(Y[i]) - ); - end -endgenerate - -endmodule - -// -------------------------------------------------------- - -module \$lt (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -wire carry, carry_sign; -wire [WIDTH-1:0] A_buf, B_buf, Y_buf; -\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf)); -\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf)); - -\$__alu #( - .WIDTH(WIDTH) -) alu ( - .A(A_buf), - .B(~B_buf), - .Cin(1'b1), - .Y(Y_buf), - .Cout(carry), - .Csign(carry_sign) -); - -// ALU flags -wire cf, of, zf, sf; -assign cf = !carry; -assign of = carry ^ carry_sign; -assign zf = ~|Y_buf; -assign sf = Y_buf[WIDTH-1]; - -generate - if (A_SIGNED && B_SIGNED) begin - assign Y = of != sf; - end else begin - assign Y = cf; - end -endgenerate - -endmodule - -// -------------------------------------------------------- - -module \$le (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -wire carry, carry_sign; -wire [WIDTH-1:0] A_buf, B_buf, Y_buf; -\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf)); -\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf)); - -\$__alu #( - .WIDTH(WIDTH) -) alu ( - .A(A_buf), - .B(~B_buf), - .Cin(1'b1), - .Y(Y_buf), - .Cout(carry), - .Csign(carry_sign) -); - -// ALU flags -wire cf, of, zf, sf; -assign cf = !carry; -assign of = carry ^ carry_sign; -assign zf = ~|Y_buf; -assign sf = Y_buf[WIDTH-1]; - -generate - if (A_SIGNED && B_SIGNED) begin - assign Y = zf || (of != sf); - end else begin - assign Y = zf || cf; - end -endgenerate - -endmodule - -// -------------------------------------------------------- - -module \$eq (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -wire carry, carry_sign; -wire [WIDTH-1:0] A_buf, B_buf; -\$bu0 #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf)); -\$bu0 #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf)); - -assign Y = ~|(A_buf ^ B_buf); - -endmodule - -// -------------------------------------------------------- - -module \$ne (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -wire carry, carry_sign; -wire [WIDTH-1:0] A_buf, B_buf; -\$bu0 #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf)); -\$bu0 #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf)); - -assign Y = |(A_buf ^ B_buf); - -endmodule - -// -------------------------------------------------------- - -module \$eqx (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -wire carry, carry_sign; -wire [WIDTH-1:0] A_buf, B_buf; -\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf)); -\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf)); - -assign Y = ~|(A_buf ^ B_buf); - -endmodule - -// -------------------------------------------------------- - -module \$nex (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -wire carry, carry_sign; -wire [WIDTH-1:0] A_buf, B_buf; -\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf)); -\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf)); - -assign Y = |(A_buf ^ B_buf); - -endmodule - -// -------------------------------------------------------- - -module \$ge (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -\$le #( - .A_SIGNED(B_SIGNED), - .B_SIGNED(A_SIGNED), - .A_WIDTH(B_WIDTH), - .B_WIDTH(A_WIDTH), - .Y_WIDTH(Y_WIDTH) -) ge_via_le ( - .A(B), - .B(A), - .Y(Y) -); - -endmodule - -// -------------------------------------------------------- - -module \$gt (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -\$lt #( - .A_SIGNED(B_SIGNED), - .B_SIGNED(A_SIGNED), - .A_WIDTH(B_WIDTH), - .B_WIDTH(A_WIDTH), - .Y_WIDTH(Y_WIDTH) -) gt_via_lt ( - .A(B), - .B(A), - .Y(Y) -); - -endmodule - -// -------------------------------------------------------- - -module \$add (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -wire [Y_WIDTH-1:0] A_buf, B_buf; -\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); -\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); - -\$__alu #( - .WIDTH(Y_WIDTH) -) alu ( - .A(A_buf), - .B(B_buf), - .Cin(1'b0), - .Y(Y) -); - -endmodule - -// -------------------------------------------------------- - -module \$sub (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -wire [Y_WIDTH-1:0] A_buf, B_buf; -\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); -\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); - -\$__alu #( - .WIDTH(Y_WIDTH) -) alu ( - .A(A_buf), - .B(~B_buf), - .Cin(1'b1), - .Y(Y) -); - -endmodule - -// -------------------------------------------------------- - -module \$__arraymul (A, B, Y); - -parameter WIDTH = 8; -input [WIDTH-1:0] A, B; -output [WIDTH-1:0] Y; - -wire [WIDTH*WIDTH-1:0] partials; - -genvar i; -assign partials[WIDTH-1 : 0] = A[0] ? B : 0; -generate for (i = 1; i < WIDTH; i = i+1) begin:gen - assign partials[WIDTH*(i+1)-1 : WIDTH*i] = (A[i] ? B << i : 0) + partials[WIDTH*i-1 : WIDTH*(i-1)]; -end endgenerate - -assign Y = partials[WIDTH*WIDTH-1 : WIDTH*(WIDTH-1)]; - -endmodule - -// -------------------------------------------------------- - -module \$mul (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -wire [Y_WIDTH-1:0] A_buf, B_buf; -\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); -\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); - -\$__arraymul #( - .WIDTH(Y_WIDTH) -) arraymul ( - .A(A_buf), - .B(B_buf), - .Y(Y) -); - -endmodule - -// -------------------------------------------------------- - -module \$__div_mod_u (A, B, Y, R); - -parameter WIDTH = 1; - -input [WIDTH-1:0] A, B; -output [WIDTH-1:0] Y, R; - -wire [WIDTH*WIDTH-1:0] chaindata; -assign R = chaindata[WIDTH*WIDTH-1:WIDTH*(WIDTH-1)]; - -genvar i; -generate begin - for (i = 0; i < WIDTH; i=i+1) begin:stage - wire [WIDTH-1:0] stage_in; - - if (i == 0) begin:cp - assign stage_in = A; - end else begin:cp - assign stage_in = chaindata[i*WIDTH-1:(i-1)*WIDTH]; - end - - assign Y[WIDTH-(i+1)] = stage_in >= {B, {WIDTH-(i+1){1'b0}}}; - assign chaindata[(i+1)*WIDTH-1:i*WIDTH] = Y[WIDTH-(i+1)] ? stage_in - {B, {WIDTH-(i+1){1'b0}}} : stage_in; - end -end endgenerate - -endmodule - -// -------------------------------------------------------- - -module \$__div_mod (A, B, Y, R); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -localparam WIDTH = - A_WIDTH >= B_WIDTH && A_WIDTH >= Y_WIDTH ? A_WIDTH : - B_WIDTH >= A_WIDTH && B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y, R; - -wire [WIDTH-1:0] A_buf, B_buf; -\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf)); -\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf)); - -wire [WIDTH-1:0] A_buf_u, B_buf_u, Y_u, R_u; -assign A_buf_u = A_SIGNED && A_buf[WIDTH-1] ? -A_buf : A_buf; -assign B_buf_u = B_SIGNED && B_buf[WIDTH-1] ? -B_buf : B_buf; - -\$__div_mod_u #( - .WIDTH(WIDTH) -) div_mod_u ( - .A(A_buf_u), - .B(B_buf_u), - .Y(Y_u), - .R(R_u) -); - -assign Y = A_SIGNED && B_SIGNED && (A_buf[WIDTH-1] != B_buf[WIDTH-1]) ? -Y_u : Y_u; -assign R = A_SIGNED && B_SIGNED && A_buf[WIDTH-1] ? -R_u : R_u; - -endmodule - -// -------------------------------------------------------- - -module \$div (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -\$__div_mod #( - .A_SIGNED(A_SIGNED), - .B_SIGNED(B_SIGNED), - .A_WIDTH(A_WIDTH), - .B_WIDTH(B_WIDTH), - .Y_WIDTH(Y_WIDTH) -) div_mod ( - .A(A), - .B(B), - .Y(Y) -); - -endmodule - -// -------------------------------------------------------- - -module \$mod (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -\$__div_mod #( - .A_SIGNED(A_SIGNED), - .B_SIGNED(B_SIGNED), - .A_WIDTH(A_WIDTH), - .B_WIDTH(B_WIDTH), - .Y_WIDTH(Y_WIDTH) -) div_mod ( - .A(A), - .B(B), - .R(Y) -); - -endmodule - -/**** -// -------------------------------------------------------- - -module \$pow (A, B, Y); - -parameter A_SIGNED = 0; -parameter B_SIGNED = 0; -parameter A_WIDTH = 1; -parameter B_WIDTH = 1; -parameter Y_WIDTH = 1; - -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] Y; - -wire signed [A_WIDTH:0] buffer_a = A_SIGNED ? $signed(A) : A; -wire signed [B_WIDTH:0] buffer_b = B_SIGNED ? $signed(B) : B; - -assign Y = buffer_a ** buffer_b; - -endmodule - -// -------------------------------------------------------- -****/ - -(* techmap_simplemap *) -module \$logic_not ; -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$logic_and ; -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$logic_or ; -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$slice ; -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$concat ; -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$mux ; -endmodule - -// -------------------------------------------------------- - -module \$pmux (A, B, S, Y); - -parameter WIDTH = 1; -parameter S_WIDTH = 1; - -input [WIDTH-1:0] A; -input [WIDTH*S_WIDTH-1:0] B; -input [S_WIDTH-1:0] S; -output [WIDTH-1:0] Y; - -wire [WIDTH-1:0] Y_B; - -genvar i, j; -generate - wire [WIDTH*S_WIDTH-1:0] B_AND_S; - for (i = 0; i < S_WIDTH; i = i + 1) begin:B_AND - assign B_AND_S[WIDTH*(i+1)-1:WIDTH*i] = B[WIDTH*(i+1)-1:WIDTH*i] & {WIDTH{S[i]}}; - end:B_AND - for (i = 0; i < WIDTH; i = i + 1) begin:B_OR - wire [S_WIDTH-1:0] B_AND_BITS; - for (j = 0; j < S_WIDTH; j = j + 1) begin:B_AND_BITS_COLLECT - assign B_AND_BITS[j] = B_AND_S[WIDTH*j+i]; - end:B_AND_BITS_COLLECT - assign Y_B[i] = |B_AND_BITS; - end:B_OR -endgenerate - -assign Y = |S ? Y_B : A; - -endmodule - -// -------------------------------------------------------- - -module \$safe_pmux (A, B, S, Y); - -parameter WIDTH = 1; -parameter S_WIDTH = 1; - -input [WIDTH-1:0] A; -input [WIDTH*S_WIDTH-1:0] B; -input [S_WIDTH-1:0] S; -output [WIDTH-1:0] Y; - -wire [S_WIDTH-1:0] status_found_first; -wire [S_WIDTH-1:0] status_found_second; - -genvar i; -generate - for (i = 0; i < S_WIDTH; i = i + 1) begin:GEN1 - wire pre_first; - if (i > 0) begin:GEN2 - assign pre_first = status_found_first[i-1]; - end:GEN2 else begin:GEN3 - assign pre_first = 0; - end:GEN3 - assign status_found_first[i] = pre_first | S[i]; - assign status_found_second[i] = pre_first & S[i]; - end:GEN1 -endgenerate - -\$pmux #( - .WIDTH(WIDTH), - .S_WIDTH(S_WIDTH) -) pmux_cell ( - .A(A), - .B(B), - .S(S & {S_WIDTH{~|status_found_second}}), - .Y(Y) -); - -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$sr ; -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$dff ; -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$adff ; -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$dffsr ; -endmodule - -// -------------------------------------------------------- - -(* techmap_simplemap *) -module \$dlatch ; -endmodule - -// -------------------------------------------------------- - diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc new file mode 100644 index 000000000..4ccacd30b --- /dev/null +++ b/techlibs/common/synth.cc @@ -0,0 +1,156 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/register.h" +#include "kernel/celltypes.h" +#include "kernel/rtlil.h" +#include "kernel/log.h" + +static bool check_label(bool &active, std::string run_from, std::string run_to, std::string label) +{ + if (!run_from.empty() && run_from == run_to) { + active = (label == run_from); + } else { + if (label == run_from) + active = true; + if (label == run_to) + active = false; + } + return active; +} + +struct SynthPass : public Pass { + SynthPass() : Pass("synth", "generic synthesis script") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" synth [options]\n"); + log("\n"); + log("This command runs the default synthesis script. This command does not operate\n"); + log("on partly selected designs.\n"); + log("\n"); + log(" -top <module>\n"); + log(" use the specified module as top module (default='top')\n"); + log("\n"); + log(" -run <from_label>[:<to_label>]\n"); + log(" only run the commands between the labels (see below). an empty\n"); + log(" from label is synonymous to 'begin', and empty to label is\n"); + log(" synonymous to the end of the command list.\n"); + log("\n"); + log("\n"); + log("The following commands are executed by this synthesis command:\n"); + log("\n"); + log(" begin:\n"); + log(" hierarchy -check [-top <top>]\n"); + log("\n"); + log(" coarse:\n"); + log(" proc\n"); + log(" opt\n"); + log(" wreduce\n"); + log(" alumacc\n"); + log(" share\n"); + log(" opt\n"); + log(" fsm\n"); + log(" opt -fast\n"); + log(" memory -nomap\n"); + log(" opt_clean\n"); + log("\n"); + log(" fine:\n"); + log(" memory_map\n"); + log(" techmap\n"); + log(" opt -fast\n"); + #ifdef YOSYS_ENABLE_ABC + log(" abc -fast\n"); + log(" opt_clean\n"); + #endif + log("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + { + std::string top_module; + std::string run_from, run_to; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-top" && argidx+1 < args.size()) { + top_module = args[++argidx]; + continue; + } + if (args[argidx] == "-run" && argidx+1 < args.size()) { + size_t pos = args[argidx+1].find(':'); + if (pos == std::string::npos) { + run_from = args[++argidx]; + run_to = args[argidx]; + } else { + run_from = args[++argidx].substr(0, pos); + run_to = args[argidx].substr(pos+1); + } + continue; + } + break; + } + extra_args(args, argidx, design); + + if (!design->full_selection()) + log_cmd_error("This comannd only operates on fully selected designs!\n"); + + bool active = run_from.empty(); + + log_header("Executing SYNTH pass.\n"); + log_push(); + + if (check_label(active, run_from, run_to, "begin")) + { + if (top_module.empty()) + Pass::call(design, stringf("hierarchy -check")); + else + Pass::call(design, stringf("hierarchy -check -top %s", top_module.c_str())); + } + + if (check_label(active, run_from, run_to, "coarse")) + { + Pass::call(design, "proc"); + Pass::call(design, "opt"); + Pass::call(design, "wreduce"); + Pass::call(design, "alumacc"); + Pass::call(design, "share"); + Pass::call(design, "opt"); + Pass::call(design, "fsm"); + Pass::call(design, "opt -fast"); + Pass::call(design, "memory -nomap"); + Pass::call(design, "opt_clean"); + } + + if (check_label(active, run_from, run_to, "fine")) + { + Pass::call(design, "memory_map"); + Pass::call(design, "techmap"); + Pass::call(design, "opt -fast"); + #ifdef YOSYS_ENABLE_ABC + Pass::call(design, "abc -fast"); + Pass::call(design, "opt_clean"); + #endif + } + + log_pop(); + } +} SynthPass; + diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v new file mode 100644 index 000000000..b6c075b67 --- /dev/null +++ b/techlibs/common/techmap.v @@ -0,0 +1,509 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * --- + * + * The internal logic cell technology mapper. + * + * This verilog library contains the mapping of internal cells (e.g. $not with + * variable bit width) to the internal logic cells (such as the single bit $_NOT_ + * gate). Usually this logic network is then mapped to the actual technology + * using e.g. the "abc" pass. + * + * Note that this library does not map $mem cells. They must be mapped to logic + * and $dff cells using the "memory_map" pass first. (Or map it to custom cells, + * which is of course highly recommended for larger memories.) + * + */ + +`define MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b)) +`define MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b)) + + +// -------------------------------------------------------- +// Use simplemap for trivial cell types +// -------------------------------------------------------- + +(* techmap_simplemap *) +(* techmap_celltype = "$not $and $or $xor $xnor" *) +module _90_simplemap_bool_ops; +endmodule + +(* techmap_simplemap *) +(* techmap_celltype = "$reduce_and $reduce_or $reduce_xor $reduce_xnor $reduce_bool" *) +module _90_simplemap_reduce_ops; +endmodule + +(* techmap_simplemap *) +(* techmap_celltype = "$logic_not $logic_and $logic_or" *) +module _90_simplemap_logic_ops; +endmodule + +(* techmap_simplemap *) +(* techmap_celltype = "$pos $slice $concat $mux" *) +module _90_simplemap_various; +endmodule + +(* techmap_simplemap *) +(* techmap_celltype = "$sr $dff $adff $dffsr $dlatch" *) +module _90_simplemap_registers; +endmodule + + +// -------------------------------------------------------- +// Shift operators +// -------------------------------------------------------- + +(* techmap_celltype = "$shr $shl $sshl $sshr" *) +module _90_shift_ops_shr_shl_sshl_sshr (A, B, Y); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + parameter _TECHMAP_CELLTYPE_ = ""; + localparam shift_left = _TECHMAP_CELLTYPE_ == "$shl" || _TECHMAP_CELLTYPE_ == "$sshl"; + localparam sign_extend = A_SIGNED && _TECHMAP_CELLTYPE_ == "$sshr"; + + input [A_WIDTH-1:0] A; + input [B_WIDTH-1:0] B; + output [Y_WIDTH-1:0] Y; + + localparam WIDTH = `MAX(A_WIDTH, Y_WIDTH); + localparam BB_WIDTH = `MIN($clog2(shift_left ? Y_WIDTH : A_SIGNED ? WIDTH : A_WIDTH) + 1, B_WIDTH); + + wire [1023:0] _TECHMAP_DO_00_ = "proc;;"; + wire [1023:0] _TECHMAP_DO_01_ = "RECURSION; CONSTMAP; opt_muxtree; opt_const -mux_undef -mux_bool -fine;;;"; + + integer i; + reg [WIDTH-1:0] buffer; + reg overflow; + + always @* begin + overflow = B_WIDTH > BB_WIDTH ? |B[B_WIDTH-1:BB_WIDTH] : 1'b0; + buffer = overflow ? {WIDTH{sign_extend ? A[A_WIDTH-1] : 1'b0}} : {{WIDTH-A_WIDTH{A_SIGNED ? A[A_WIDTH-1] : 1'b0}}, A}; + + for (i = 0; i < BB_WIDTH; i = i+1) + if (B[i]) begin + if (shift_left) + buffer = {buffer, (2**i)'b0}; + else if (2**i < WIDTH) + buffer = {{2**i{sign_extend ? buffer[WIDTH-1] : 1'b0}}, buffer[WIDTH-1 : 2**i]}; + else + buffer = {WIDTH{sign_extend ? buffer[WIDTH-1] : 1'b0}}; + end + end + + assign Y = buffer; +endmodule + +(* techmap_celltype = "$shift $shiftx" *) +module _90_shift_shiftx (A, B, Y); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + input [A_WIDTH-1:0] A; + input [B_WIDTH-1:0] B; + output [Y_WIDTH-1:0] Y; + + localparam BB_WIDTH = `MIN($clog2(`MAX(A_WIDTH, Y_WIDTH)) + (B_SIGNED ? 2 : 1), B_WIDTH); + localparam WIDTH = `MAX(A_WIDTH, Y_WIDTH) + (B_SIGNED ? 2**(BB_WIDTH-1) : 0); + + parameter _TECHMAP_CELLTYPE_ = ""; + localparam extbit = _TECHMAP_CELLTYPE_ == "$shift" ? 1'b0 : 1'bx; + + wire [1023:0] _TECHMAP_DO_00_ = "proc;;"; + wire [1023:0] _TECHMAP_DO_01_ = "CONSTMAP; opt_muxtree; opt_const -mux_undef -mux_bool -fine;;;"; + + integer i; + reg [WIDTH-1:0] buffer; + reg overflow; + + always @* begin + overflow = 0; + buffer = {WIDTH{extbit}}; + buffer[`MAX(A_WIDTH, Y_WIDTH)-1:0] = A; + + if (B_WIDTH > BB_WIDTH) begin + if (B_SIGNED) begin + for (i = BB_WIDTH; i < B_WIDTH; i = i+1) + if (B[i] != B[BB_WIDTH-1]) + overflow = 1; + end else + overflow = |B[B_WIDTH-1:BB_WIDTH]; + if (overflow) + buffer = {WIDTH{extbit}}; + end + + for (i = BB_WIDTH-1; i >= 0; i = i-1) + if (B[i]) begin + if (B_SIGNED && i == BB_WIDTH-1) + buffer = {buffer, {2**i{extbit}}}; + else if (2**i < WIDTH) + buffer = {{2**i{extbit}}, buffer[WIDTH-1 : 2**i]}; + else + buffer = {WIDTH{extbit}}; + end + end + + assign Y = buffer; +endmodule + + +// -------------------------------------------------------- +// Arithmetic operators +// -------------------------------------------------------- + +(* techmap_celltype = "$fa" *) +module _90_fa (A, B, C, X, Y); + parameter WIDTH = 1; + + input [WIDTH-1:0] A, B, C; + output [WIDTH-1:0] X, Y; + + wire [WIDTH-1:0] t1, t2, t3; + + assign t1 = A ^ B, t2 = A & B, t3 = C & t1; + assign Y = t1 ^ C, X = t2 | t3; +endmodule + +(* techmap_celltype = "$lcu" *) +module _90_lcu (P, G, CI, CO); + parameter WIDTH = 2; + + input [WIDTH-1:0] P, G; + input CI; + + output [WIDTH-1:0] CO; + + integer i, j; + reg [WIDTH-1:0] p, g; + + wire [1023:0] _TECHMAP_DO_ = "proc; opt -fast"; + + always @* begin + p = P; + g = G; + + // in almost all cases CI will be constant zero + g[0] = g[0] | (p[0] & CI); + + // [[CITE]] Brent Kung Adder + // R. P. Brent and H. T. Kung, “A Regular Layout for Parallel Adders”, + // IEEE Transaction on Computers, Vol. C-31, No. 3, p. 260-264, March, 1982 + + // Main tree + for (i = 1; i <= $clog2(WIDTH); i = i+1) begin + for (j = 2**i - 1; j < WIDTH; j = j + 2**i) begin + g[j] = g[j] | p[j] & g[j - 2**(i-1)]; + p[j] = p[j] & p[j - 2**(i-1)]; + end + end + + // Inverse tree + for (i = $clog2(WIDTH); i > 0; i = i-1) begin + for (j = 2**i + 2**(i-1) - 1; j < WIDTH; j = j + 2**i) begin + g[j] = g[j] | p[j] & g[j - 2**(i-1)]; + p[j] = p[j] & p[j - 2**(i-1)]; + end + end + end + + assign CO = g; +endmodule + +(* techmap_celltype = "$alu" *) +module _90_alu (A, B, CI, BI, X, Y, CO); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + input [A_WIDTH-1:0] A; + input [B_WIDTH-1:0] B; + output [Y_WIDTH-1:0] X, Y; + + input CI, BI; + output [Y_WIDTH-1:0] CO; + + wire [Y_WIDTH-1:0] A_buf, B_buf; + \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); + \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + + wire [Y_WIDTH-1:0] AA = A_buf; + wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; + + \$lcu #(.WIDTH(Y_WIDTH)) lcu (.P(X), .G(AA & BB), .CI(CI), .CO(CO)); + + assign X = AA ^ BB; + assign Y = X ^ {CO, CI}; +endmodule + +(* techmap_maccmap *) +(* techmap_celltype = "$macc" *) +module _90_macc; +endmodule + +(* techmap_wrap = "alumacc" *) +(* techmap_celltype = "$lt $le $ge $gt $add $sub $neg $mul" *) +module _90_alumacc; +endmodule + + +// -------------------------------------------------------- +// Divide and Modulo +// -------------------------------------------------------- + +module \$__div_mod_u (A, B, Y, R); + parameter WIDTH = 1; + + input [WIDTH-1:0] A, B; + output [WIDTH-1:0] Y, R; + + wire [WIDTH*WIDTH-1:0] chaindata; + assign R = chaindata[WIDTH*WIDTH-1:WIDTH*(WIDTH-1)]; + + genvar i; + generate begin + for (i = 0; i < WIDTH; i=i+1) begin:stage + wire [WIDTH-1:0] stage_in; + + if (i == 0) begin:cp + assign stage_in = A; + end else begin:cp + assign stage_in = chaindata[i*WIDTH-1:(i-1)*WIDTH]; + end + + assign Y[WIDTH-(i+1)] = stage_in >= {B, {WIDTH-(i+1){1'b0}}}; + assign chaindata[(i+1)*WIDTH-1:i*WIDTH] = Y[WIDTH-(i+1)] ? stage_in - {B, {WIDTH-(i+1){1'b0}}} : stage_in; + end + end endgenerate +endmodule + +module \$__div_mod (A, B, Y, R); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + localparam WIDTH = + A_WIDTH >= B_WIDTH && A_WIDTH >= Y_WIDTH ? A_WIDTH : + B_WIDTH >= A_WIDTH && B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH; + + input [A_WIDTH-1:0] A; + input [B_WIDTH-1:0] B; + output [Y_WIDTH-1:0] Y, R; + + wire [WIDTH-1:0] A_buf, B_buf; + \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf)); + \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf)); + + wire [WIDTH-1:0] A_buf_u, B_buf_u, Y_u, R_u; + assign A_buf_u = A_SIGNED && A_buf[WIDTH-1] ? -A_buf : A_buf; + assign B_buf_u = B_SIGNED && B_buf[WIDTH-1] ? -B_buf : B_buf; + + \$__div_mod_u #( + .WIDTH(WIDTH) + ) div_mod_u ( + .A(A_buf_u), + .B(B_buf_u), + .Y(Y_u), + .R(R_u) + ); + + assign Y = A_SIGNED && B_SIGNED && (A_buf[WIDTH-1] != B_buf[WIDTH-1]) ? -Y_u : Y_u; + assign R = A_SIGNED && B_SIGNED && A_buf[WIDTH-1] ? -R_u : R_u; +endmodule + +(* techmap_celltype = "$div" *) +module _90_div (A, B, Y); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + input [A_WIDTH-1:0] A; + input [B_WIDTH-1:0] B; + output [Y_WIDTH-1:0] Y; + + \$__div_mod #( + .A_SIGNED(A_SIGNED), + .B_SIGNED(B_SIGNED), + .A_WIDTH(A_WIDTH), + .B_WIDTH(B_WIDTH), + .Y_WIDTH(Y_WIDTH) + ) div_mod ( + .A(A), + .B(B), + .Y(Y) + ); +endmodule + +(* techmap_celltype = "$mod" *) +module _90_mod (A, B, Y); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + input [A_WIDTH-1:0] A; + input [B_WIDTH-1:0] B; + output [Y_WIDTH-1:0] Y; + + \$__div_mod #( + .A_SIGNED(A_SIGNED), + .B_SIGNED(B_SIGNED), + .A_WIDTH(A_WIDTH), + .B_WIDTH(B_WIDTH), + .Y_WIDTH(Y_WIDTH) + ) div_mod ( + .A(A), + .B(B), + .R(Y) + ); +endmodule + + +// -------------------------------------------------------- +// Power +// -------------------------------------------------------- + +(* techmap_celltype = "$pow" *) +module _90_pow (A, B, Y); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + input [A_WIDTH-1:0] A; + input [B_WIDTH-1:0] B; + output [Y_WIDTH-1:0] Y; + + wire _TECHMAP_FAIL_ = 1; +endmodule + + +// -------------------------------------------------------- +// Equal and Not-Equal +// -------------------------------------------------------- + +(* techmap_celltype = "$eq $eqx" *) +module _90_eq_eqx (A, B, Y); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH; + + input [A_WIDTH-1:0] A; + input [B_WIDTH-1:0] B; + output [Y_WIDTH-1:0] Y; + + wire carry, carry_sign; + wire [WIDTH-1:0] A_buf, B_buf; + \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf)); + \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf)); + + assign Y = ~|(A_buf ^ B_buf); +endmodule + +(* techmap_celltype = "$ne $nex" *) +module _90_ne_nex (A, B, Y); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH; + + input [A_WIDTH-1:0] A; + input [B_WIDTH-1:0] B; + output [Y_WIDTH-1:0] Y; + + wire carry, carry_sign; + wire [WIDTH-1:0] A_buf, B_buf; + \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf)); + \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf)); + + assign Y = |(A_buf ^ B_buf); +endmodule + + +// -------------------------------------------------------- +// Parallel Multiplexers +// -------------------------------------------------------- + +(* techmap_celltype = "$pmux" *) +module _90_pmux (A, B, S, Y); + parameter WIDTH = 1; + parameter S_WIDTH = 1; + + input [WIDTH-1:0] A; + input [WIDTH*S_WIDTH-1:0] B; + input [S_WIDTH-1:0] S; + output [WIDTH-1:0] Y; + + wire [WIDTH-1:0] Y_B; + + genvar i, j; + generate + wire [WIDTH*S_WIDTH-1:0] B_AND_S; + for (i = 0; i < S_WIDTH; i = i + 1) begin:B_AND + assign B_AND_S[WIDTH*(i+1)-1:WIDTH*i] = B[WIDTH*(i+1)-1:WIDTH*i] & {WIDTH{S[i]}}; + end:B_AND + for (i = 0; i < WIDTH; i = i + 1) begin:B_OR + wire [S_WIDTH-1:0] B_AND_BITS; + for (j = 0; j < S_WIDTH; j = j + 1) begin:B_AND_BITS_COLLECT + assign B_AND_BITS[j] = B_AND_S[WIDTH*j+i]; + end:B_AND_BITS_COLLECT + assign Y_B[i] = |B_AND_BITS; + end:B_OR + endgenerate + + assign Y = |S ? Y_B : A; +endmodule + + +// -------------------------------------------------------- +// LUTs +// -------------------------------------------------------- + +`ifndef NOLUT +(* techmap_celltype = "$lut" *) +module _90_lut (A, Y); + parameter WIDTH = 1; + parameter LUT = 0; + + input [WIDTH-1:0] A; + output Y; + + assign Y = LUT[A]; +endmodule +`endif + |