diff options
Diffstat (limited to 'techlibs/common/simlib.v')
-rw-r--r-- | techlibs/common/simlib.v | 238 |
1 files changed, 138 insertions, 100 deletions
diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 2d8088adb..abd2af521 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -1160,12 +1160,51 @@ module \$assert (A, EN); input A, EN; +`ifndef SIMLIB_NOCHECKS always @* begin if (A !== 1'b1 && EN === 1'b1) begin - $display("Assertation failed!"); - $finish; + $display("Assertation %m failed!"); + $stop; + end +end +`endif + +endmodule + +// -------------------------------------------------------- + +module \$assume (A, EN); + +input A, EN; + +`ifndef SIMLIB_NOCHECKS +always @* begin + if (A !== 1'b1 && EN === 1'b1) begin + $display("Assumption %m failed!"); + $stop; + end +end +`endif + +endmodule + +// -------------------------------------------------------- + +module \$equiv (A, B, Y); + +input A, B; +output Y; + +assign Y = (A !== 1'bx && A !== B) ? 1'bx : A; + +`ifndef SIMLIB_NOCHECKS +always @* begin + if (A !== 1'bx && A !== B) begin + $display("Equivalence failed!"); + $stop; end end +`endif endmodule @@ -1217,6 +1256,25 @@ end endmodule // -------------------------------------------------------- + +module \$dffe (CLK, EN, D, Q); + +parameter WIDTH = 0; +parameter CLK_POLARITY = 1'b1; +parameter EN_POLARITY = 1'b1; + +input CLK, EN; +input [WIDTH-1:0] D; +output reg [WIDTH-1:0] Q; +wire pos_clk = CLK == CLK_POLARITY; + +always @(posedge pos_clk) begin + if (EN == EN_POLARITY) Q <= D; +end + +endmodule + +// -------------------------------------------------------- `ifndef SIMLIB_NOSR module \$dffsr (CLK, SET, CLR, D, Q); @@ -1287,7 +1345,7 @@ output reg [WIDTH-1:0] Q; always @* begin if (EN == EN_POLARITY) - Q <= D; + Q = D; end endmodule @@ -1315,11 +1373,11 @@ generate for (i = 0; i < WIDTH; i = i+1) begin:bit always @* if (pos_clr[i]) - Q[i] <= 0; + Q[i] = 0; else if (pos_set[i]) - Q[i] <= 1; + Q[i] = 1; else if (pos_en) - Q[i] <= D[i]; + Q[i] = D[i]; end endgenerate @@ -1430,6 +1488,7 @@ parameter WIDTH = 8; parameter CLK_ENABLE = 0; parameter CLK_POLARITY = 0; +parameter TRANSPARENT = 0; input CLK; input [ABITS-1:0] ADDR; @@ -1454,6 +1513,7 @@ parameter WIDTH = 8; parameter CLK_ENABLE = 0; parameter CLK_POLARITY = 0; +parameter PRIORITY = 0; input CLK; input [WIDTH-1:0] EN; @@ -1471,13 +1531,36 @@ endmodule // -------------------------------------------------------- +module \$meminit (ADDR, DATA); + +parameter MEMID = ""; +parameter ABITS = 8; +parameter WIDTH = 8; + +parameter PRIORITY = 0; + +input [ABITS-1:0] ADDR; +input [WIDTH-1:0] DATA; + +initial begin + if (MEMID != "") begin + $display("ERROR: Found non-simulatable instance of $meminit!"); + $finish; + end +end + +endmodule + +// -------------------------------------------------------- + module \$mem (RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA); parameter MEMID = ""; -parameter SIZE = 256; +parameter SIZE = 4; parameter OFFSET = 0; -parameter ABITS = 8; +parameter ABITS = 2; parameter WIDTH = 8; +parameter signed INIT = 1'bx; parameter RD_PORTS = 1; parameter RD_CLK_ENABLE = 1'b1; @@ -1497,107 +1580,62 @@ input [WR_PORTS*WIDTH-1:0] WR_EN; input [WR_PORTS*ABITS-1:0] WR_ADDR; input [WR_PORTS*WIDTH-1:0] WR_DATA; -reg [WIDTH-1:0] data [SIZE-1:0]; -reg update_async_rd; +reg [WIDTH-1:0] memory [SIZE-1:0]; -genvar i; -generate +integer i, j; +reg [WR_PORTS-1:0] LAST_WR_CLK; +reg [RD_PORTS-1:0] LAST_RD_CLK; + +function port_active; + input clk_enable; + input clk_polarity; + input last_clk; + input this_clk; + begin + casez ({clk_enable, clk_polarity, last_clk, this_clk}) + 4'b0???: port_active = 1; + 4'b1101: port_active = 1; + 4'b1010: port_active = 1; + default: port_active = 0; + endcase + end +endfunction - 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]; - 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]; - end else begin:rd_trans_negclk - always @(negedge RD_CLK[i]) - addr_buf <= RD_ADDR[i*ABITS +: ABITS]; - end - always @(addr_buf or update_async_rd) - 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]; - end else begin:rd_notrans_negclk - always @(negedge RD_CLK[i]) - RD_DATA[i*WIDTH +: WIDTH] <= data[RD_ADDR[i*ABITS +: ABITS] - OFFSET]; - end +initial begin + for (i = 0; i < SIZE; i = i+1) + memory[i] = INIT >>> (i*WIDTH); +end + +always @(RD_CLK, RD_ADDR, RD_DATA, WR_CLK, WR_EN, WR_ADDR, WR_DATA) begin +`ifdef SIMLIB_MEMDELAY + #`SIMLIB_MEMDELAY; +`endif + for (i = 0; i < RD_PORTS; i = i+1) begin + if ((!RD_TRANSPARENT[i] && RD_CLK_ENABLE[i]) && port_active(RD_CLK_ENABLE[i], RD_CLK_POLARITY[i], LAST_RD_CLK[i], RD_CLK[i])) begin + // $display("Read from %s: addr=%b data=%b", MEMID, RD_ADDR[i*ABITS +: ABITS], memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]); + RD_DATA[i*WIDTH +: WIDTH] <= memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]; end end - for (i = 0; i < WR_PORTS; i = i+1) begin:wr - 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 - 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; + for (i = 0; i < WR_PORTS; i = i+1) begin + if (port_active(WR_CLK_ENABLE[i], WR_CLK_POLARITY[i], LAST_WR_CLK[i], WR_CLK[i])) + for (j = 0; j < WIDTH; j = j+1) + if (WR_EN[i*WIDTH+j]) begin + // $display("Write to %s: addr=%b data=%b", MEMID, WR_ADDR[i*ABITS +: ABITS], WR_DATA[i*WIDTH+j]); + memory[WR_ADDR[i*ABITS +: ABITS] - OFFSET][j] = WR_DATA[i*WIDTH+j]; end - end - end else - if (WR_CLK_POLARITY[i] == 1) begin:rd_posclk - 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]) 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 + + for (i = 0; i < RD_PORTS; i = i+1) begin + if ((RD_TRANSPARENT[i] || !RD_CLK_ENABLE[i]) && port_active(RD_CLK_ENABLE[i], RD_CLK_POLARITY[i], LAST_RD_CLK[i], RD_CLK[i])) begin + // $display("Transparent read from %s: addr=%b data=%b", MEMID, RD_ADDR[i*ABITS +: ABITS], memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]); + RD_DATA[i*WIDTH +: WIDTH] <= memory[RD_ADDR[i*ABITS +: ABITS] - OFFSET]; end end -endgenerate + LAST_RD_CLK <= RD_CLK; + LAST_WR_CLK <= WR_CLK; +end endmodule |