diff options
Diffstat (limited to 'techlibs/common/simlib.v')
-rw-r--r-- | techlibs/common/simlib.v | 452 |
1 files changed, 354 insertions, 98 deletions
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 |