diff options
Diffstat (limited to 'techlibs')
41 files changed, 1631 insertions, 512 deletions
diff --git a/techlibs/cmos/cmos_cells.v b/techlibs/cmos/cmos_cells.v index da75270cb..27278facb 100644 --- a/techlibs/cmos/cmos_cells.v +++ b/techlibs/cmos/cmos_cells.v @@ -1,17 +1,26 @@ +module BUF(A, Y); +input A; +output Y; +assign Y = A; +endmodule + module NOT(A, Y); input A; -output Y = ~A; +output Y; +assign Y = ~A; endmodule module NAND(A, B, Y); input A, B; -output Y = ~(A & B); +output Y; +assign Y = ~(A & B); endmodule module NOR(A, B, Y); input A, B; -output Y = ~(A | B); +output Y; +assign Y = ~(A | B); endmodule module DFF(C, D, Q); diff --git a/techlibs/common/Makefile.inc b/techlibs/common/Makefile.inc index 7c8cc2f66..d2ce61cf6 100644 --- a/techlibs/common/Makefile.inc +++ b/techlibs/common/Makefile.inc @@ -1,5 +1,7 @@ +ifneq ($(SMALL),1) OBJS += techlibs/common/synth.o +endif EXTRA_TARGETS += techlibs/common/blackbox.v @@ -7,29 +9,11 @@ techlibs/common/blackbox.v: techlibs/common/blackbox.sed techlibs/common/simlib. $(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/techmap.v share/blackbox.v share/pmux2mux.v share/adff2dff.v - -share/simlib.v: techlibs/common/simlib.v - $(P) mkdir -p share - $(Q) cp techlibs/common/simlib.v share/simlib.v - -share/simcells.v: techlibs/common/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 - $(P) mkdir -p share - $(Q) cp techlibs/common/blackbox.v share/blackbox.v - -share/pmux2mux.v: techlibs/common/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 +$(eval $(call add_share_file,share,techlibs/common/simlib.v)) +$(eval $(call add_share_file,share,techlibs/common/simcells.v)) +$(eval $(call add_share_file,share,techlibs/common/techmap.v)) +$(eval $(call add_share_file,share,techlibs/common/blackbox.v)) +$(eval $(call add_share_file,share,techlibs/common/pmux2mux.v)) +$(eval $(call add_share_file,share,techlibs/common/adff2dff.v)) +$(eval $(call add_share_file,share,techlibs/common/cells.lib)) diff --git a/techlibs/common/cells.lib b/techlibs/common/cells.lib new file mode 100644 index 000000000..eb89036d7 --- /dev/null +++ b/techlibs/common/cells.lib @@ -0,0 +1,108 @@ +library(yosys_cells) { + cell(DFF_N) { + ff(IQ, IQN) { + clocked_on: "!C"; + next_state: "D"; + } + pin(D) { direction: input; } + pin(C) { direction: input; clock: true; } + pin(Q) { direction: output; function: "IQ"; } + } + cell(DFF_P) { + ff(IQ, IQN) { + clocked_on: "C"; + next_state: "D"; + } + pin(D) { direction: input; } + pin(C) { direction: input; clock: true; } + pin(Q) { direction: output; function: "IQ"; } + } + cell(DFF_NN0) { + ff(IQ, IQN) { + clocked_on: "!C"; + next_state: "D"; + clear: "!R"; + } + pin(D) { direction: input; } + pin(R) { direction: input; } + pin(C) { direction: input; clock: true; } + pin(Q) { direction: output; function: "IQ"; } + } + cell(DFF_NN1) { + ff(IQ, IQN) { + clocked_on: "!C"; + next_state: "D"; + preset: "!R"; + } + pin(D) { direction: input; } + pin(R) { direction: input; } + pin(C) { direction: input; clock: true; } + pin(Q) { direction: output; function: "IQ"; } + } + cell(DFF_NP0) { + ff(IQ, IQN) { + clocked_on: "!C"; + next_state: "D"; + clear: "R"; + } + pin(D) { direction: input; } + pin(R) { direction: input; } + pin(C) { direction: input; clock: true; } + pin(Q) { direction: output; function: "IQ"; } + } + cell(DFF_NP1) { + ff(IQ, IQN) { + clocked_on: "!C"; + next_state: "D"; + preset: "R"; + } + pin(D) { direction: input; } + pin(R) { direction: input; } + pin(C) { direction: input; clock: true; } + pin(Q) { direction: output; function: "IQ"; } + } + cell(DFF_PN0) { + ff(IQ, IQN) { + clocked_on: "C"; + next_state: "D"; + clear: "!R"; + } + pin(D) { direction: input; } + pin(R) { direction: input; } + pin(C) { direction: input; clock: true; } + pin(Q) { direction: output; function: "IQ"; } + } + cell(DFF_PN1) { + ff(IQ, IQN) { + clocked_on: "C"; + next_state: "D"; + preset: "!R"; + } + pin(D) { direction: input; } + pin(R) { direction: input; } + pin(C) { direction: input; clock: true; } + pin(Q) { direction: output; function: "IQ"; } + } + cell(DFF_PP0) { + ff(IQ, IQN) { + clocked_on: "C"; + next_state: "D"; + clear: "R"; + } + pin(D) { direction: input; } + pin(R) { direction: input; } + pin(C) { direction: input; clock: true; } + pin(Q) { direction: output; function: "IQ"; } + } + cell(DFF_PP1) { + ff(IQ, IQN) { + clocked_on: "C"; + next_state: "D"; + preset: "R"; + } + pin(D) { direction: input; } + pin(R) { direction: input; } + pin(C) { direction: input; clock: true; } + pin(Q) { direction: output; function: "IQ"; } + } +} diff --git a/techlibs/common/simcells.v b/techlibs/common/simcells.v index a2a377350..eb62d7830 100644 --- a/techlibs/common/simcells.v +++ b/techlibs/common/simcells.v @@ -25,6 +25,12 @@ * */ +module \$_BUF_ (A, Y); +input A; +output Y; +assign Y = A; +endmodule + module \$_NOT_ (A, Y); input A; output Y; @@ -157,6 +163,38 @@ always @(posedge C) begin end endmodule +module \$_DFFE_NN_ (D, Q, C, E); +input D, C, E; +output reg Q; +always @(negedge C) begin + if (!E) Q <= D; +end +endmodule + +module \$_DFFE_NP_ (D, Q, C, E); +input D, C, E; +output reg Q; +always @(negedge C) begin + if (E) Q <= D; +end +endmodule + +module \$_DFFE_PN_ (D, Q, C, E); +input D, C, E; +output reg Q; +always @(posedge C) begin + if (!E) Q <= D; +end +endmodule + +module \$_DFFE_PP_ (D, Q, C, E); +input D, C, E; +output reg Q; +always @(posedge C) begin + if (E) Q <= D; +end +endmodule + module \$_DFF_NN0_ (D, Q, C, R); input D, C, R; output reg Q; 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 diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc index 4ccacd30b..c3e7288db 100644 --- a/techlibs/common/synth.cc +++ b/techlibs/common/synth.cc @@ -22,7 +22,10 @@ #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) +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +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); @@ -49,6 +52,12 @@ struct SynthPass : public Pass { log(" -top <module>\n"); log(" use the specified module as top module (default='top')\n"); log("\n"); + log(" -encfile <file>\n"); + log(" passed to 'fsm_recode' via 'fsm'\n"); + log("\n"); + log(" -noabc\n"); + log(" do not run abc (as if yosys was compiled without ABC support)\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"); @@ -62,6 +71,8 @@ struct SynthPass : public Pass { log("\n"); log(" coarse:\n"); log(" proc\n"); + log(" opt_clean\n"); + log(" check\n"); log(" opt\n"); log(" wreduce\n"); log(" alumacc\n"); @@ -73,19 +84,27 @@ struct SynthPass : public Pass { log(" opt_clean\n"); log("\n"); log(" fine:\n"); + log(" opt -fast -full\n"); log(" memory_map\n"); + log(" opt -full\n"); log(" techmap\n"); log(" opt -fast\n"); #ifdef YOSYS_ENABLE_ABC log(" abc -fast\n"); - log(" opt_clean\n"); + log(" opt -fast\n"); #endif log("\n"); + log(" check:\n"); + log(" hierarchy -check\n"); + log(" stat\n"); + log(" check\n"); + log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - std::string top_module; + std::string top_module, fsm_opts; std::string run_from, run_to; + bool noabc = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -94,6 +113,10 @@ struct SynthPass : public Pass { top_module = args[++argidx]; continue; } + if (args[argidx] == "-encfile" && argidx+1 < args.size()) { + fsm_opts = " -encfile " + args[++argidx]; + continue; + } if (args[argidx] == "-run" && argidx+1 < args.size()) { size_t pos = args[argidx+1].find(':'); if (pos == std::string::npos) { @@ -105,6 +128,10 @@ struct SynthPass : public Pass { } continue; } + if (args[argidx] == "-noabc") { + noabc = true; + continue; + } break; } extra_args(args, argidx, design); @@ -128,12 +155,14 @@ struct SynthPass : public Pass { if (check_label(active, run_from, run_to, "coarse")) { Pass::call(design, "proc"); + Pass::call(design, "opt_clean"); + Pass::call(design, "check"); 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, "fsm" + fsm_opts); Pass::call(design, "opt -fast"); Pass::call(design, "memory -nomap"); Pass::call(design, "opt_clean"); @@ -141,16 +170,29 @@ struct SynthPass : public Pass { if (check_label(active, run_from, run_to, "fine")) { + Pass::call(design, "opt -fast -full"); Pass::call(design, "memory_map"); + Pass::call(design, "opt -full"); Pass::call(design, "techmap"); Pass::call(design, "opt -fast"); + + if (!noabc) { #ifdef YOSYS_ENABLE_ABC - Pass::call(design, "abc -fast"); - Pass::call(design, "opt_clean"); + Pass::call(design, "abc -fast"); + Pass::call(design, "opt -fast"); #endif + } + } + + if (check_label(active, run_from, run_to, "check")) + { + Pass::call(design, "hierarchy -check"); + Pass::call(design, "stat"); + Pass::call(design, "check"); } log_pop(); } } SynthPass; +PRIVATE_NAMESPACE_END diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v index b6c075b67..e0ecf0c48 100644 --- a/techlibs/common/techmap.v +++ b/techlibs/common/techmap.v @@ -54,12 +54,17 @@ module _90_simplemap_logic_ops; endmodule (* techmap_simplemap *) +(* techmap_celltype = "$eq $eqx $ne $nex" *) +module _90_simplemap_compare_ops; +endmodule + +(* techmap_simplemap *) (* techmap_celltype = "$pos $slice $concat $mux" *) module _90_simplemap_various; endmodule (* techmap_simplemap *) -(* techmap_celltype = "$sr $dff $adff $dffsr $dlatch" *) +(* techmap_celltype = "$sr $dff $dffe $adff $dffsr $dlatch" *) module _90_simplemap_registers; endmodule @@ -207,7 +212,7 @@ module _90_lcu (P, G, CI, CO); g[0] = g[0] | (p[0] & CI); // [[CITE]] Brent Kung Adder - // R. P. Brent and H. T. Kung, “A Regular Layout for Parallel Adders”, + // 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 @@ -407,55 +412,6 @@ 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 // -------------------------------------------------------- diff --git a/techlibs/ice40/Makefile.inc b/techlibs/ice40/Makefile.inc new file mode 100644 index 000000000..08a24d92f --- /dev/null +++ b/techlibs/ice40/Makefile.inc @@ -0,0 +1,6 @@ + +OBJS += techlibs/ice40/synth_ice40.o + +$(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_map.v)) +$(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_sim.v)) + diff --git a/techlibs/ice40/cells_map.v b/techlibs/ice40/cells_map.v new file mode 100644 index 000000000..f7008a571 --- /dev/null +++ b/techlibs/ice40/cells_map.v @@ -0,0 +1,32 @@ +module \$_DFF_P_ (input D, C, output Q); + SB_DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); +endmodule + +module \$lut (A, Y); + parameter WIDTH = 0; + parameter LUT = 0; + + input [WIDTH-1:0] A; + output Y; + + generate + if (WIDTH == 1) begin + SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0]), .I1(1'b0), .I2(1'b0), .I3(1'b0)); + end else + if (WIDTH == 2) begin + SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0]), .I1(A[1]), .I2(1'b0), .I3(1'b0)); + end else + if (WIDTH == 3) begin + SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(1'b0)); + end else + if (WIDTH == 4) begin + SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(A[3])); + end else begin + wire _TECHMAP_FAIL_ = 1; + end + endgenerate +endmodule diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v new file mode 100644 index 000000000..a1d9b0ca8 --- /dev/null +++ b/techlibs/ice40/cells_sim.v @@ -0,0 +1,12 @@ +module SB_LUT4(output O, input I0, I1, I2, I3); + parameter [15:0] INIT = 0; + wire [ 7: 0] s3 = I3 ? INIT[15: 8] : INIT[ 7: 0]; + wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0]; + wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0]; + assign O = I0 ? s1[1] : s1[0]; +endmodule + +module SB_DFF (output reg Q, input C, D); + always @(posedge C) + Q <= D; +endmodule diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc new file mode 100644 index 000000000..8c98c4b27 --- /dev/null +++ b/techlibs/ice40/synth_ice40.cc @@ -0,0 +1,161 @@ +/* + * 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" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +bool check_label(bool &active, std::string run_from, std::string run_to, std::string label) +{ + if (label == run_from) + active = true; + if (label == run_to) + active = false; + return active; +} + +struct SynthIce40Pass : public Pass { + SynthIce40Pass() : Pass("synth_ice40", "synthesis for iCE40 FPGAs") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" synth_ice40 [options]\n"); + log("\n"); + log("This command runs synthesis for iCE40 FPGAs. This work is experimental.\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(" read_verilog -lib +/ice40/cells_sim.v\n"); + log(" hierarchy -check -top <top>\n"); + log("\n"); + log(" coarse:\n"); + log(" synth -run coarse\n"); + log("\n"); + log(" fine:\n"); + log(" opt -fast -full\n"); + log(" memory_map\n"); + log(" opt -full\n"); + log(" techmap\n"); + log(" opt -fast\n"); + log("\n"); + log(" map_luts:\n"); + log(" abc -lut 4\n"); + log(" clean\n"); + log("\n"); + log(" map_cells:\n"); + log(" techmap -map +/ice40/cells_map.v\n"); + log(" clean\n"); + log("\n"); + log(" check:\n"); + log(" hierarchy -check\n"); + log(" stat\n"); + log(" check -noinit\n"); + log("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + { + std::string top_module = "top"; + 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) + break; + 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_ICE40 pass.\n"); + log_push(); + + if (check_label(active, run_from, run_to, "begin")) + { + Pass::call(design, "read_verilog -lib +/ice40/cells_sim.v"); + Pass::call(design, stringf("hierarchy -check -top %s", top_module.c_str())); + } + + if (check_label(active, run_from, run_to, "coarse")) + { + Pass::call(design, "synth -run coarse"); + } + + if (check_label(active, run_from, run_to, "fine")) + { + Pass::call(design, "opt -fast -full"); + Pass::call(design, "memory_map"); + Pass::call(design, "opt -full"); + Pass::call(design, "techmap"); + Pass::call(design, "opt -fast"); + } + + if (check_label(active, run_from, run_to, "map_luts")) + { + Pass::call(design, "abc -lut 4"); + Pass::call(design, "clean"); + } + + if (check_label(active, run_from, run_to, "map_cells")) + { + Pass::call(design, "techmap -map +/ice40/cells_map.v"); + Pass::call(design, "clean"); + } + + if (check_label(active, run_from, run_to, "check")) + { + Pass::call(design, "hierarchy -check"); + Pass::call(design, "stat"); + Pass::call(design, "check -noinit"); + } + + log_pop(); + } +} SynthIce40Pass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc index cd19f10e7..9af7b58f3 100644 --- a/techlibs/xilinx/Makefile.inc +++ b/techlibs/xilinx/Makefile.inc @@ -1,9 +1,9 @@ OBJS += techlibs/xilinx/synth_xilinx.o -EXTRA_TARGETS += share/xilinx/cells.v - -share/xilinx/cells.v: techlibs/xilinx/cells.v - $(P) mkdir -p share/xilinx - $(Q) cp techlibs/xilinx/cells.v share/xilinx/cells.v +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_map.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_sim.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams.txt)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_map.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v)) diff --git a/techlibs/xilinx/arith_map.v b/techlibs/xilinx/arith_map.v new file mode 100644 index 000000000..a154f7740 --- /dev/null +++ b/techlibs/xilinx/arith_map.v @@ -0,0 +1,91 @@ +/* + * 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. + * + */ + +(* techmap_celltype = "$lcu" *) +module _80_xilinx_lcu (P, G, CI, CO); + parameter WIDTH = 2; + + input [WIDTH-1:0] P, G; + input CI; + + output [WIDTH-1:0] CO; + + wire _TECHMAP_FAIL_ = WIDTH <= 2; + + wire [WIDTH-1:0] C = {CO, CI}; + wire [WIDTH-1:0] S = P & ~G; + + genvar i; + generate for (i = 0; i < WIDTH; i = i + 1) begin:slice + MUXCY muxcy ( + .CI(C[i]), + .DI(G[i]), + .S(S[i]), + .O(CO[i]) + ); + end endgenerate +endmodule + +(* techmap_celltype = "$alu" *) +module _80_xilinx_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 _TECHMAP_FAIL_ = Y_WIDTH <= 2; + + 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; + + wire [Y_WIDTH-1:0] P = AA ^ BB; + wire [Y_WIDTH-1:0] G = AA & BB; + wire [Y_WIDTH-1:0] C = {CO, CI}; + wire [Y_WIDTH-1:0] S = P & ~G; + + genvar i; + generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice + MUXCY muxcy ( + .CI(C[i]), + .DI(G[i]), + .S(S[i]), + .O(CO[i]) + ); + XORCY xorcy ( + .CI(C[i]), + .LI(S[i]), + .O(Y[i]) + ); + end endgenerate + + assign X = P; +endmodule + diff --git a/techlibs/xilinx/brams.txt b/techlibs/xilinx/brams.txt new file mode 100644 index 000000000..84c114578 --- /dev/null +++ b/techlibs/xilinx/brams.txt @@ -0,0 +1,101 @@ + +bram $__XILINX_RAMB36_SDP + abits 9 + dbits 72 + groups 2 + ports 1 1 + wrmode 0 1 + enable 0 8 + transp 0 0 + clocks 2 3 + clkpol 2 3 +endbram + +bram $__XILINX_RAMB18_SDP + abits 9 + dbits 36 + groups 2 + ports 1 1 + wrmode 0 1 + enable 0 4 + transp 0 0 + clocks 2 3 + clkpol 2 3 +endbram + +bram $__XILINX_RAMB36_TDP + abits 10 @a10d36 + dbits 36 @a10d36 + abits 11 @a11d18 + dbits 18 @a11d18 + abits 12 @a12d9 + dbits 9 @a12d9 + abits 13 @a13d4 + dbits 4 @a13d4 + abits 14 @a14d2 + dbits 2 @a14d2 + abits 15 @a15d1 + dbits 1 @a15d1 + groups 2 + ports 1 1 + wrmode 0 1 + enable 0 4 @a10d36 + enable 0 2 @a11d18 + enable 0 1 @a12d9 @a13d4 @a14d2 @a15d1 + transp 0 0 + clocks 2 3 + clkpol 2 3 +endbram + +bram $__XILINX_RAMB18_TDP + abits 10 @a10d18 + dbits 18 @a10d18 + abits 11 @a11d9 + dbits 9 @a11d9 + abits 12 @a12d4 + dbits 4 @a12d4 + abits 13 @a13d2 + dbits 2 @a13d2 + abits 14 @a14d1 + dbits 1 @a14d1 + groups 2 + ports 1 1 + wrmode 0 1 + enable 0 2 @a10d18 + enable 0 1 @a11d9 @a12d4 @a13d2 @a14d1 + transp 0 0 + clocks 2 3 + clkpol 2 3 +endbram + +match $__XILINX_RAMB36_SDP + min bits 4096 + min efficiency 5 + shuffle_enable B + make_transp + or_next_if_better +endmatch + +match $__XILINX_RAMB18_SDP + min bits 4096 + min efficiency 5 + shuffle_enable B + make_transp + or_next_if_better +endmatch + +match $__XILINX_RAMB36_TDP + min bits 4096 + min efficiency 5 + shuffle_enable B + make_transp + or_next_if_better +endmatch + +match $__XILINX_RAMB18_TDP + min bits 4096 + min efficiency 5 + shuffle_enable B + make_transp +endmatch + diff --git a/techlibs/xilinx/brams_map.v b/techlibs/xilinx/brams_map.v new file mode 100644 index 000000000..2e9bba9a9 --- /dev/null +++ b/techlibs/xilinx/brams_map.v @@ -0,0 +1,267 @@ +module \$__XILINX_RAMB36_SDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN); + parameter CLKPOL2 = 1; + parameter CLKPOL3 = 1; + + input CLK2; + input CLK3; + + input [8:0] A1ADDR; + output [71:0] A1DATA; + + input [8:0] B1ADDR; + input [71:0] B1DATA; + input [7:0] B1EN; + + wire [15:0] A1ADDR_16 = {A1ADDR, 6'b0}; + wire [15:0] B1ADDR_16 = {B1ADDR, 6'b0}; + + wire [7:0] DIP, DOP; + wire [63:0] DI, DO; + + assign A1DATA = { DOP[7], DO[63:56], DOP[6], DO[55:48], DOP[5], DO[47:40], DOP[4], DO[39:32], + DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] }; + + assign { DIP[7], DI[63:56], DIP[6], DI[55:48], DIP[5], DI[47:40], DIP[4], DI[39:32], + DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA; + + RAMB36E1 #( + .RAM_MODE("SDP"), + .READ_WIDTH_A(72), + .WRITE_WIDTH_B(72), + .WRITE_MODE_A("READ_FIRST"), + .WRITE_MODE_B("READ_FIRST"), + .IS_CLKARDCLK_INVERTED(!CLKPOL2), + .IS_CLKBWRCLK_INVERTED(!CLKPOL3), + .SIM_DEVICE("7SERIES") + ) _TECHMAP_REPLACE_ ( + .DOBDO(DO[63:32]), + .DOADO(DO[31:0]), + .DOPBDOP(DOP[7:4]), + .DOPADOP(DOP[3:0]), + .DIBDI(DI[63:32]), + .DIADI(DI[31:0]), + .DIPBDIP(DIP[7:4]), + .DIPADIP(DIP[3:0]), + + .ADDRARDADDR(A1ADDR_16), + .CLKARDCLK(CLK2), + .ENARDEN(|1), + .REGCEAREGCE(|1), + .RSTRAMARSTRAM(|0), + .RSTREGARSTREG(|0), + .WEA(4'b0), + + .ADDRBWRADDR(B1ADDR_16), + .CLKBWRCLK(CLK3), + .ENBWREN(|1), + .REGCEB(|0), + .RSTRAMB(|0), + .RSTREGB(|0), + .WEBWE(B1EN) + ); +endmodule + +// ------------------------------------------------------------------------ + +module \$__XILINX_RAMB18_SDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN); + parameter CLKPOL2 = 1; + parameter CLKPOL3 = 1; + + input CLK2; + input CLK3; + + input [8:0] A1ADDR; + output [35:0] A1DATA; + + input [8:0] B1ADDR; + input [35:0] B1DATA; + input [3:0] B1EN; + + wire [13:0] A1ADDR_14 = {A1ADDR, 5'b0}; + wire [13:0] B1ADDR_14 = {B1ADDR, 5'b0}; + + wire [3:0] DIP, DOP; + wire [31:0] DI, DO; + + assign A1DATA = { DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] }; + assign { DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA; + + RAMB18E1 #( + .RAM_MODE("SDP"), + .READ_WIDTH_A(36), + .WRITE_WIDTH_B(36), + .WRITE_MODE_A("READ_FIRST"), + .WRITE_MODE_B("READ_FIRST"), + .IS_CLKARDCLK_INVERTED(!CLKPOL2), + .IS_CLKBWRCLK_INVERTED(!CLKPOL3), + .SIM_DEVICE("7SERIES") + ) _TECHMAP_REPLACE_ ( + .DOBDO(DO[31:16]), + .DOADO(DO[15:0]), + .DOPBDOP(DOP[3:2]), + .DOPADOP(DOP[1:0]), + .DIBDI(DI[31:16]), + .DIADI(DI[15:0]), + .DIPBDIP(DIP[3:2]), + .DIPADIP(DIP[1:0]), + + .ADDRARDADDR(A1ADDR_14), + .CLKARDCLK(CLK2), + .ENARDEN(|1), + .REGCEAREGCE(|1), + .RSTRAMARSTRAM(|0), + .RSTREGARSTREG(|0), + .WEA(2'b0), + + .ADDRBWRADDR(B1ADDR_14), + .CLKBWRCLK(CLK3), + .ENBWREN(|1), + .REGCEB(|0), + .RSTRAMB(|0), + .RSTREGB(|0), + .WEBWE(B1EN) + ); +endmodule + +// ------------------------------------------------------------------------ + +module \$__XILINX_RAMB36_TDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN); + parameter CFG_ABITS = 10; + parameter CFG_DBITS = 36; + parameter CFG_ENABLE_B = 4; + + parameter CLKPOL2 = 1; + parameter CLKPOL3 = 1; + + input CLK2; + input CLK3; + + input [CFG_ABITS-1:0] A1ADDR; + output [CFG_DBITS-1:0] A1DATA; + + input [CFG_ABITS-1:0] B1ADDR; + input [CFG_DBITS-1:0] B1DATA; + input [CFG_ENABLE_B-1:0] B1EN; + + wire [15:0] A1ADDR_16 = A1ADDR << (15 - CFG_ABITS); + wire [15:0] B1ADDR_16 = B1ADDR << (15 - CFG_ABITS); + wire [7:0] B1EN_8 = B1EN; + + wire [3:0] DIP, DOP; + wire [31:0] DI, DO; + + wire [31:0] DOBDO; + wire [3:0] DOPBDOP; + + assign A1DATA = { DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] }; + assign { DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA; + + RAMB36E1 #( + .RAM_MODE("TDP"), + .READ_WIDTH_A(CFG_DBITS), + .READ_WIDTH_B(CFG_DBITS), + .WRITE_WIDTH_A(CFG_DBITS), + .WRITE_WIDTH_B(CFG_DBITS), + .WRITE_MODE_A("READ_FIRST"), + .WRITE_MODE_B("READ_FIRST"), + .IS_CLKARDCLK_INVERTED(!CLKPOL2), + .IS_CLKBWRCLK_INVERTED(!CLKPOL3), + .SIM_DEVICE("7SERIES") + ) _TECHMAP_REPLACE_ ( + .DIADI(32'd0), + .DIPADIP(4'd0), + .DOADO(DO[31:0]), + .DOPADOP(DOP[3:0]), + .ADDRARDADDR(A1ADDR_16), + .CLKARDCLK(CLK2), + .ENARDEN(|1), + .REGCEAREGCE(|1), + .RSTRAMARSTRAM(|0), + .RSTREGARSTREG(|0), + .WEA(4'b0), + + .DIBDI(DI), + .DIPBDIP(DIP), + .DOBDO(DOBDO), + .DOPBDOP(DOPBDOP), + .ADDRBWRADDR(B1ADDR_16), + .CLKBWRCLK(CLK3), + .ENBWREN(|1), + .REGCEB(|0), + .RSTRAMB(|0), + .RSTREGB(|0), + .WEBWE(B1EN_8) + ); +endmodule + +// ------------------------------------------------------------------------ + +module \$__XILINX_RAMB18_TDP (CLK2, CLK3, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN); + parameter CFG_ABITS = 10; + parameter CFG_DBITS = 18; + parameter CFG_ENABLE_B = 2; + + parameter CLKPOL2 = 1; + parameter CLKPOL3 = 1; + + input CLK2; + input CLK3; + + input [CFG_ABITS-1:0] A1ADDR; + output [CFG_DBITS-1:0] A1DATA; + + input [CFG_ABITS-1:0] B1ADDR; + input [CFG_DBITS-1:0] B1DATA; + input [CFG_ENABLE_B-1:0] B1EN; + + wire [13:0] A1ADDR_14 = A1ADDR << (14 - CFG_ABITS); + wire [13:0] B1ADDR_14 = B1ADDR << (14 - CFG_ABITS); + wire [3:0] B1EN_4 = B1EN; + + wire [1:0] DIP, DOP; + wire [15:0] DI, DO; + + wire [15:0] DOBDO; + wire [1:0] DOPBDOP; + + assign A1DATA = { DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] }; + assign { DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA; + + RAMB18E1 #( + .RAM_MODE("TDP"), + .READ_WIDTH_A(CFG_DBITS), + .READ_WIDTH_B(CFG_DBITS), + .WRITE_WIDTH_A(CFG_DBITS), + .WRITE_WIDTH_B(CFG_DBITS), + .WRITE_MODE_A("READ_FIRST"), + .WRITE_MODE_B("READ_FIRST"), + .IS_CLKARDCLK_INVERTED(!CLKPOL2), + .IS_CLKBWRCLK_INVERTED(!CLKPOL3), + .SIM_DEVICE("7SERIES") + ) _TECHMAP_REPLACE_ ( + .DIADI(16'b0), + .DIPADIP(2'b0), + .DOADO(DO), + .DOPADOP(DOP), + .ADDRARDADDR(A1ADDR_14), + .CLKARDCLK(CLK2), + .ENARDEN(|1), + .REGCEAREGCE(|1), + .RSTRAMARSTRAM(|0), + .RSTREGARSTREG(|0), + .WEA(2'b0), + + .DIBDI(DI), + .DIPBDIP(DIP), + .DOBDO(DOBDO), + .DOPBDOP(DOPBDOP), + .ADDRBWRADDR(B1ADDR_14), + .CLKBWRCLK(CLK3), + .ENBWREN(|1), + .REGCEB(|0), + .RSTRAMB(|0), + .RSTREGB(|0), + .WEBWE(B1EN_4) + ); +endmodule + diff --git a/techlibs/xilinx/cells.v b/techlibs/xilinx/cells.v deleted file mode 100644 index d19be0db7..000000000 --- a/techlibs/xilinx/cells.v +++ /dev/null @@ -1,53 +0,0 @@ -module \$_DFF_P_ (D, C, Q); - - input D, C; - output Q; - - FDRE fpga_dff ( - .D(D), .Q(Q), .C(C), - .CE(1'b1), .R(1'b0) - ); - -endmodule - -module \$lut (A, Y); - - parameter WIDTH = 0; - parameter LUT = 0; - - input [WIDTH-1:0] A; - output Y; - - generate - if (WIDTH == 1) begin:lut1 - LUT1 #(.INIT(LUT)) fpga_lut (.O(Y), - .I0(A[0])); - end else - if (WIDTH == 2) begin:lut2 - LUT2 #(.INIT(LUT)) fpga_lut (.O(Y), - .I0(A[0]), .I1(A[1])); - end else - if (WIDTH == 3) begin:lut3 - LUT3 #(.INIT(LUT)) fpga_lut (.O(Y), - .I0(A[0]), .I1(A[1]), .I2(A[2])); - end else - if (WIDTH == 4) begin:lut4 - LUT4 #(.INIT(LUT)) fpga_lut (.O(Y), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3])); - end else - if (WIDTH == 5) begin:lut5 - LUT5 #(.INIT(LUT)) fpga_lut (.O(Y), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4])); - end else - if (WIDTH == 6) begin:lut6 - LUT6 #(.INIT(LUT)) fpga_lut (.O(Y), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - end else begin:error - wire _TECHMAP_FAIL_ = 1; - end - endgenerate - -endmodule diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v new file mode 100644 index 000000000..8e5a83ce5 --- /dev/null +++ b/techlibs/xilinx/cells_map.v @@ -0,0 +1,84 @@ + +module \$_DFF_N_ (input D, C, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule +module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule + +module \$_DFFE_NP_ (input D, C, E, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule +module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule + +module \$_DFF_NN0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule +module \$_DFF_NP0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule +module \$_DFF_PN0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule +module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule + +module \$_DFF_NN1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule +module \$_DFF_NP1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule +module \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule +module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule + +module \$lut (A, Y); + parameter WIDTH = 0; + parameter LUT = 0; + + input [WIDTH-1:0] A; + output Y; + + generate + if (WIDTH == 1) begin + LUT1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0])); + end else + if (WIDTH == 2) begin + LUT2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0]), .I1(A[1])); + end else + if (WIDTH == 3) begin + LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0]), .I1(A[1]), .I2(A[2])); + end else + if (WIDTH == 4) begin + LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3])); + end else + if (WIDTH == 5) begin + LUT5 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4])); + end else + if (WIDTH == 6) begin + LUT6 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + end else + if (WIDTH == 7) begin + wire T0, T1; + LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[6])); + end else + if (WIDTH == 8) begin + wire T0, T1, T2, T3, T4, T5; + LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + LUT6 #(.INIT(LUT[191:128])) fpga_lut_2 (.O(T2), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + LUT6 #(.INIT(LUT[255:192])) fpga_lut_3 (.O(T3), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[6])); + MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[6])); + MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[7])); + end else begin + wire _TECHMAP_FAIL_ = 1; + end + endgenerate +endmodule diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v new file mode 100644 index 000000000..1f114a22c --- /dev/null +++ b/techlibs/xilinx/cells_sim.v @@ -0,0 +1,158 @@ + +// See Xilinx UG953 and UG474 for a description of the cell types below. +// http://www.xilinx.com/support/documentation/user_guides/ug474_7Series_CLB.pdf +// http://www.xilinx.com/support/documentation/sw_manuals/xilinx2014_4/ug953-vivado-7series-libraries.pdf + +module VCC(output P); + assign P = 1; +endmodule + +module GND(output G); + assign G = 0; +endmodule + +module IBUF(output O, input I); + assign O = I; +endmodule + +module OBUF(output O, input I); + assign O = I; +endmodule + +module BUFG(output O, input I); + assign O = I; +endmodule + +// module OBUFT(output O, input I, T); +// assign O = T ? 1'bz : I; +// endmodule + +// module IOBUF(inout IO, output O, input I, T); +// assign O = IO, IO = T ? 1'bz : I; +// endmodule + +module INV(output O, input I); + assign O = !I; +endmodule + +module LUT1(output O, input I0); + parameter [1:0] INIT = 0; + assign O = I0 ? INIT[1] : INIT[0]; +endmodule + +module LUT2(output O, input I0, I1); + parameter [3:0] INIT = 0; + wire [ 1: 0] s1 = I1 ? INIT[ 3: 2] : INIT[ 1: 0]; + assign O = I0 ? s1[1] : s1[0]; +endmodule + +module LUT3(output O, input I0, I1, I2); + parameter [7:0] INIT = 0; + wire [ 3: 0] s2 = I2 ? INIT[ 7: 4] : INIT[ 3: 0]; + wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0]; + assign O = I0 ? s1[1] : s1[0]; +endmodule + +module LUT4(output O, input I0, I1, I2, I3); + parameter [15:0] INIT = 0; + wire [ 7: 0] s3 = I3 ? INIT[15: 8] : INIT[ 7: 0]; + wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0]; + wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0]; + assign O = I0 ? s1[1] : s1[0]; +endmodule + +module LUT5(output O, input I0, I1, I2, I3, I4); + parameter [31:0] INIT = 0; + wire [15: 0] s4 = I4 ? INIT[31:16] : INIT[15: 0]; + wire [ 7: 0] s3 = I3 ? s4[15: 8] : s4[ 7: 0]; + wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0]; + wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0]; + assign O = I0 ? s1[1] : s1[0]; +endmodule + +module LUT6(output O, input I0, I1, I2, I3, I4, I5); + parameter [63:0] INIT = 0; + wire [31: 0] s5 = I5 ? INIT[63:32] : INIT[31: 0]; + wire [15: 0] s4 = I4 ? s5[31:16] : s5[15: 0]; + wire [ 7: 0] s3 = I3 ? s4[15: 8] : s4[ 7: 0]; + wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0]; + wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0]; + assign O = I0 ? s1[1] : s1[0]; +endmodule + +module MUXCY(output O, input CI, DI, S); + assign O = S ? CI : DI; +endmodule + +module MUXF7(output O, input I0, I1, S); + assign O = S ? I1 : I0; +endmodule + +module MUXF8(output O, input I0, I1, S); + assign O = S ? I1 : I0; +endmodule + +module XORCY(output O, input CI, LI); + assign O = CI ^ LI; +endmodule + +module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S); + assign O = S ^ {CO[2:0], CI | CYINIT}; + assign CO[0] = S[0] ? CI | CYINIT : DI[0]; + assign CO[1] = S[1] ? CO[0] : DI[1]; + assign CO[2] = S[2] ? CO[1] : DI[2]; + assign CO[3] = S[3] ? CO[2] : DI[3]; +endmodule + +module FDRE (output reg Q, input C, CE, D, R); + parameter [0:0] INIT = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter [0:0] IS_R_INVERTED = 1'b0; + initial Q <= INIT; + generate case (|IS_C_INVERTED) + 1'b0: always @(posedge C) if (R == !IS_R_INVERTED) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED; + 1'b1: always @(negedge C) if (R == !IS_R_INVERTED) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED; + endcase endgenerate +endmodule + +module FDSE (output reg Q, input C, CE, D, S); + parameter [0:0] INIT = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter [0:0] IS_S_INVERTED = 1'b0; + initial Q <= INIT; + generate case (|IS_C_INVERTED) + 1'b0: always @(posedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED; + 1'b1: always @(negedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED; + endcase endgenerate +endmodule + +module FDCE (output reg Q, input C, CE, D, CLR); + parameter [0:0] INIT = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter [0:0] IS_CLR_INVERTED = 1'b0; + initial Q <= INIT; + generate case ({|IS_C_INVERTED, |IS_CLR_INVERTED}) + 2'b00: always @(posedge C, posedge CLR) if ( CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED; + 2'b01: always @(posedge C, negedge CLR) if (!CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED; + 2'b10: always @(negedge C, posedge CLR) if ( CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED; + 2'b11: always @(negedge C, negedge CLR) if (!CLR) Q <= 1'b0; else if (CE) Q <= D ^ IS_D_INVERTED; + endcase endgenerate +endmodule + +module FDPE (output reg Q, input C, CE, D, PRE); + parameter [0:0] INIT = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter [0:0] IS_PRE_INVERTED = 1'b0; + initial Q <= INIT; + generate case ({|IS_C_INVERTED, |IS_PRE_INVERTED}) + 2'b00: always @(posedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED; + 2'b01: always @(posedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED; + 2'b10: always @(negedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED; + 2'b11: always @(negedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED; + endcase endgenerate +endmodule + diff --git a/techlibs/xilinx/example_basys3/README b/techlibs/xilinx/example_basys3/README new file mode 100644 index 000000000..85b6eab10 --- /dev/null +++ b/techlibs/xilinx/example_basys3/README @@ -0,0 +1,16 @@ + +A simple example design, based on the Digilent BASYS3 board +=========================================================== + +Running Yosys: + yosys run_yosys.ys + +Running Vivado: + vivado -nolog -nojournal -mode batch -source run_vivado.tcl + +Programming board: + vivado -nolog -nojournal -mode batch -source run_prog.tcl + +All of the above: + bash run.sh + diff --git a/techlibs/xilinx/example_basys3/example.v b/techlibs/xilinx/example_basys3/example.v new file mode 100644 index 000000000..2b01a22a8 --- /dev/null +++ b/techlibs/xilinx/example_basys3/example.v @@ -0,0 +1,21 @@ +module example(CLK, LD); + input CLK; + output [15:0] LD; + + wire clock; + reg [15:0] leds; + + BUFG CLK_BUF (.I(CLK), .O(clock)); + OBUF LD_BUF[15:0] (.I(leds), .O(LD)); + + parameter COUNTBITS = 26; + reg [COUNTBITS-1:0] counter; + + always @(posedge CLK) begin + counter <= counter + 1; + if (counter[COUNTBITS-1]) + leds <= 16'h8000 >> counter[COUNTBITS-2:COUNTBITS-5]; + else + leds <= 16'h0001 << counter[COUNTBITS-2:COUNTBITS-5]; + end +endmodule diff --git a/techlibs/xilinx/example_basys3/example.xdc b/techlibs/xilinx/example_basys3/example.xdc new file mode 100644 index 000000000..c1fd0e925 --- /dev/null +++ b/techlibs/xilinx/example_basys3/example.xdc @@ -0,0 +1,21 @@ + +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN W5 } [get_ports CLK] +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN U16 } [get_ports {LD[0]}] +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN E19 } [get_ports {LD[1]}] +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN U19 } [get_ports {LD[2]}] +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN V19 } [get_ports {LD[3]}] +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN W18 } [get_ports {LD[4]}] +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN U15 } [get_ports {LD[5]}] +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN U14 } [get_ports {LD[6]}] +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN V14 } [get_ports {LD[7]}] +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN V13 } [get_ports {LD[8]}] +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN V3 } [get_ports {LD[9]}] +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN W3 } [get_ports {LD[10]}] +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN U3 } [get_ports {LD[11]}] +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN P3 } [get_ports {LD[12]}] +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN N3 } [get_ports {LD[13]}] +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN P1 } [get_ports {LD[14]}] +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN L1 } [get_ports {LD[15]}] + +create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports CLK] + diff --git a/techlibs/xilinx/example_basys3/run.sh b/techlibs/xilinx/example_basys3/run.sh new file mode 100644 index 000000000..10f059103 --- /dev/null +++ b/techlibs/xilinx/example_basys3/run.sh @@ -0,0 +1,4 @@ +#!/bin/bash +yosys run_yosys.ys +vivado -nolog -nojournal -mode batch -source run_vivado.tcl +vivado -nolog -nojournal -mode batch -source run_prog.tcl diff --git a/techlibs/xilinx/example_basys3/run_prog.tcl b/techlibs/xilinx/example_basys3/run_prog.tcl new file mode 100644 index 000000000..d711af840 --- /dev/null +++ b/techlibs/xilinx/example_basys3/run_prog.tcl @@ -0,0 +1,4 @@ +connect_hw_server +open_hw_target [lindex [get_hw_targets] 0] +set_property PROGRAM.FILE example.bit [lindex [get_hw_devices] 0] +program_hw_devices [lindex [get_hw_devices] 0] diff --git a/techlibs/xilinx/example_basys3/run_vivado.tcl b/techlibs/xilinx/example_basys3/run_vivado.tcl new file mode 100644 index 000000000..c3b6a610e --- /dev/null +++ b/techlibs/xilinx/example_basys3/run_vivado.tcl @@ -0,0 +1,9 @@ +read_xdc example.xdc +read_edif example.edif +link_design -part xc7a35tcpg236-1 -top example +opt_design +place_design +route_design +report_utilization +report_timing +write_bitstream -force example.bit diff --git a/techlibs/xilinx/example_basys3/run_yosys.ys b/techlibs/xilinx/example_basys3/run_yosys.ys new file mode 100644 index 000000000..4541826d3 --- /dev/null +++ b/techlibs/xilinx/example_basys3/run_yosys.ys @@ -0,0 +1,2 @@ +read_verilog example.v +synth_xilinx -edif example.edif -top example diff --git a/techlibs/xilinx/example_mojo_counter/README b/techlibs/xilinx/example_mojo_counter/README deleted file mode 100644 index 690a9d843..000000000 --- a/techlibs/xilinx/example_mojo_counter/README +++ /dev/null @@ -1,10 +0,0 @@ - -This is a simple example for Yosys synthesis targeting the Mojo FPGA -development board [1, 2]. Simple script for xst-based synthesis (incl. -generation of reference edif files) and uploading to the board can be -found here [3]. - -[1] http://embeddedmicro.com/tutorials/mojo -[2] https://www.sparkfun.com/products/11953 -[3] http://svn.clifford.at/handicraft/2013/mojo/ - diff --git a/techlibs/xilinx/example_mojo_counter/example.sh b/techlibs/xilinx/example_mojo_counter/example.sh deleted file mode 100644 index 74a0c117f..000000000 --- a/techlibs/xilinx/example_mojo_counter/example.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -set -ex - -XILINX_DIR=/opt/Xilinx/14.5/ISE_DS/ISE -XILINX_PART=xc6slx9-2-tqg144 - -../../../yosys - <<- EOT - read_verilog example.v - synth_xilinx -edif synth.edif -EOT - -$XILINX_DIR/bin/lin64/edif2ngd -a synth.edif synth.ngo -$XILINX_DIR/bin/lin64/ngdbuild -p $XILINX_PART -uc example.ucf synth.ngo synth.ngd -$XILINX_DIR/bin/lin64/map -p $XILINX_PART -w -o mapped.ncd synth.ngd constraints.pcf -$XILINX_DIR/bin/lin64/par -w mapped.ncd placed.ncd constraints.pcf -$XILINX_DIR/bin/lin64/bitgen -w placed.ncd example.bit constraints.pcf - diff --git a/techlibs/xilinx/example_mojo_counter/example.ucf b/techlibs/xilinx/example_mojo_counter/example.ucf deleted file mode 100644 index 93d97b4dc..000000000 --- a/techlibs/xilinx/example_mojo_counter/example.ucf +++ /dev/null @@ -1,14 +0,0 @@ -NET "clk" TNM_NET = clk; -TIMESPEC TS_clk = PERIOD "clk" 50 MHz HIGH 50%; - -NET "clk" LOC = P56; -NET "ctrl" LOC = P1; - -NET "led_0" LOC = P134; -NET "led_1" LOC = P133; -NET "led_2" LOC = P132; -NET "led_3" LOC = P131; -NET "led_4" LOC = P127; -NET "led_5" LOC = P126; -NET "led_6" LOC = P124; -NET "led_7" LOC = P123; diff --git a/techlibs/xilinx/example_mojo_counter/example.v b/techlibs/xilinx/example_mojo_counter/example.v deleted file mode 100644 index cb98cc1b2..000000000 --- a/techlibs/xilinx/example_mojo_counter/example.v +++ /dev/null @@ -1,14 +0,0 @@ -module top(clk, ctrl, led_7, led_6, led_5, led_4, led_3, led_2, led_1, led_0); - -input clk, ctrl; -output led_7, led_6, led_5, led_4; -output led_3, led_2, led_1, led_0; - -reg [31:0] counter; - -always @(posedge clk) - counter <= counter + (ctrl ? 4 : 1); - -assign {led_7, led_6, led_5, led_4, led_3, led_2, led_1, led_0} = counter >> 24; - -endmodule diff --git a/techlibs/xilinx/example_sim_counter/counter.v b/techlibs/xilinx/example_sim_counter/counter.v deleted file mode 100644 index 72208bd80..000000000 --- a/techlibs/xilinx/example_sim_counter/counter.v +++ /dev/null @@ -1,12 +0,0 @@ -module counter (clk, rst, en, count); - - input clk, rst, en; - output reg [3:0] count; - - always @(posedge clk) - if (rst) - count <= 4'd0; - else if (en) - count <= count + 4'd1; - -endmodule diff --git a/techlibs/xilinx/example_sim_counter/counter_tb.v b/techlibs/xilinx/example_sim_counter/counter_tb.v deleted file mode 100644 index b6b64269e..000000000 --- a/techlibs/xilinx/example_sim_counter/counter_tb.v +++ /dev/null @@ -1,61 +0,0 @@ -`timescale 1 ns / 1 ps - -module testbench; - -reg clk, en, rst; -wire [3:0] count; - -counter uut_counter( - .clk(clk), - .count(count), - .en(en), - .rst(rst) -); - -initial begin - clk <= 0; - forever begin - #50; - clk <= ~clk; - end -end - -initial begin - @(posedge clk); - forever begin - @(posedge clk); - $display("%d", count); - end -end - -initial begin - rst <= 1; en <= 0; @(posedge clk); - rst <= 1; en <= 0; @(posedge clk); - rst <= 0; en <= 0; @(posedge clk); - rst <= 0; en <= 1; @(posedge clk); - rst <= 0; en <= 1; @(posedge clk); - rst <= 0; en <= 1; @(posedge clk); - rst <= 0; en <= 0; @(posedge clk); - rst <= 0; en <= 1; @(posedge clk); - rst <= 0; en <= 1; @(posedge clk); - rst <= 0; en <= 1; @(posedge clk); - rst <= 1; en <= 1; @(posedge clk); - rst <= 0; en <= 0; @(posedge clk); - rst <= 0; en <= 1; @(posedge clk); - rst <= 0; en <= 1; @(posedge clk); - rst <= 0; en <= 0; @(posedge clk); - rst <= 0; en <= 1; @(posedge clk); - rst <= 0; en <= 1; @(posedge clk); - rst <= 0; en <= 0; @(posedge clk); - rst <= 1; en <= 0; @(posedge clk); - rst <= 0; en <= 1; @(posedge clk); - rst <= 0; en <= 0; @(posedge clk); - rst <= 0; en <= 1; @(posedge clk); - rst <= 0; en <= 1; @(posedge clk); - rst <= 0; en <= 0; @(posedge clk); - rst <= 0; en <= 1; @(posedge clk); - rst <= 0; en <= 0; @(posedge clk); - $finish; -end - -endmodule diff --git a/techlibs/xilinx/example_sim_counter/run_sim.sh b/techlibs/xilinx/example_sim_counter/run_sim.sh deleted file mode 100644 index b8354c002..000000000 --- a/techlibs/xilinx/example_sim_counter/run_sim.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -set -ex - -XILINX_DIR=/opt/Xilinx/14.5/ISE_DS/ISE - -../../../yosys -p 'synth_xilinx -top counter; write_verilog -noattr testbench_synth.v' counter.v - -iverilog -o testbench_gold counter_tb.v counter.v -iverilog -o testbench_gate counter_tb.v testbench_synth.v \ - $XILINX_DIR/verilog/src/{glbl,unisims/{FDRE,LUT1,LUT2,LUT3,LUT4,LUT5,LUT6,BUFGP,IBUF}}.v - -./testbench_gold > testbench_gold.txt -./testbench_gate > testbench_gate.txt - -if diff -u testbench_gold.txt testbench_gate.txt; then - set +x; echo; echo; banner " PASS " -else - exit 1 -fi - -rm -f testbench_{synth,gold,gate,mapped}* - diff --git a/techlibs/xilinx/example_zed_counter/README b/techlibs/xilinx/example_zed_counter/README deleted file mode 100644 index 539f24e73..000000000 --- a/techlibs/xilinx/example_zed_counter/README +++ /dev/null @@ -1,10 +0,0 @@ - -This is a simple example for Yosys synthesis targeting the ZED FPGA -development board [1, 2]. Simple script for xst-based synthesis (incl. -generation of reference edif files) and uploading to the board can be -found here [3]. - -[1] http://www.zedboard.org/ -[2] https://www.xilinx.com/zynq/ -[3] http://verilog.james.walms.co.uk/ - diff --git a/techlibs/xilinx/example_zed_counter/example.sh b/techlibs/xilinx/example_zed_counter/example.sh deleted file mode 100644 index d0fcd8322..000000000 --- a/techlibs/xilinx/example_zed_counter/example.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -set -ex - -XILINX_DIR=/opt/Xilinx/14.7/ISE_DS/ISE -XILINX_PART=xc7z020clg484-1 - -yosys - <<- EOT - read_verilog example.v - synth_xilinx -edif synth.edif -EOT - -$XILINX_DIR/bin/lin64/edif2ngd -a synth.edif synth.ngo -$XILINX_DIR/bin/lin64/ngdbuild -p $XILINX_PART -uc example.ucf synth.ngo synth.ngd -$XILINX_DIR/bin/lin64/map -p $XILINX_PART -w -o mapped.ncd synth.ngd constraints.pcf -$XILINX_DIR/bin/lin64/par -w mapped.ncd placed.ncd constraints.pcf -$XILINX_DIR/bin/lin64/bitgen -w placed.ncd example.bit constraints.pcf -$XILINX_DIR/bin/lin64/promgen -w -b -p bin -o example.bin -u 0 example.bit -data_width 32 diff --git a/techlibs/xilinx/example_zed_counter/example.ucf b/techlibs/xilinx/example_zed_counter/example.ucf deleted file mode 100644 index dadc8373c..000000000 --- a/techlibs/xilinx/example_zed_counter/example.ucf +++ /dev/null @@ -1,14 +0,0 @@ -NET "clk" TNM_NET = clk; -TIMESPEC TS_clk = PERIOD "clk" 50 MHz HIGH 50%; - -NET "clk" LOC = Y9 | IOSTANDARD=LVCMOS33; # "GCLK" -NET "ctrl" LOC = P16 | IOSTANDARD=LVCMOS18; # "BTNC" - -NET "led_0" LOC = T22 | IOSTANDARD=LVCMOS33; # "LD0" -NET "led_1" LOC = T21 | IOSTANDARD=LVCMOS33; # "LD0" -NET "led_2" LOC = U22 | IOSTANDARD=LVCMOS33; # "LD0" -NET "led_3" LOC = U21 | IOSTANDARD=LVCMOS33; # "LD0" -NET "led_4" LOC = V22 | IOSTANDARD=LVCMOS33; # "LD0" -NET "led_5" LOC = W22 | IOSTANDARD=LVCMOS33; # "LD0" -NET "led_6" LOC = U19 | IOSTANDARD=LVCMOS33; # "LD0" -NET "led_7" LOC = U14 | IOSTANDARD=LVCMOS33; # "LD0" diff --git a/techlibs/xilinx/example_zed_counter/example.v b/techlibs/xilinx/example_zed_counter/example.v deleted file mode 100644 index cb98cc1b2..000000000 --- a/techlibs/xilinx/example_zed_counter/example.v +++ /dev/null @@ -1,14 +0,0 @@ -module top(clk, ctrl, led_7, led_6, led_5, led_4, led_3, led_2, led_1, led_0); - -input clk, ctrl; -output led_7, led_6, led_5, led_4; -output led_3, led_2, led_1, led_0; - -reg [31:0] counter; - -always @(posedge clk) - counter <= counter + (ctrl ? 4 : 1); - -assign {led_7, led_6, led_5, led_4, led_3, led_2, led_1, led_0} = counter >> 24; - -endmodule diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index ff906db8f..836ba9add 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -22,7 +22,10 @@ #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) +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +bool check_label(bool &active, std::string run_from, std::string run_to, std::string label) { if (label == run_from) active = true; @@ -40,16 +43,12 @@ struct SynthXilinxPass : public Pass { log(" synth_xilinx [options]\n"); log("\n"); log("This command runs synthesis for Xilinx FPGAs. This command does not operate on\n"); - log("partly selected designs.\n"); + log("partly selected designs. At the moment this command creates netlists that are\n"); + log("compatible with 7-Series Xilinx devices.\n"); log("\n"); log(" -top <module>\n"); log(" use the specified module as top module (default='top')\n"); log("\n"); - log(" -arch <arch>\n"); - log(" select architecture. the following architectures are supported:\n"); - log(" spartan6 (default), artix7, kintex7, virtex7, zynq7000\n"); - log(" (this parameter is not used by the command at the moment)\n"); - log("\n"); log(" -edif <file>\n"); log(" write the design to the specified edif file. writing of an output file\n"); log(" is omitted if this parameter is not specified.\n"); @@ -59,39 +58,50 @@ struct SynthXilinxPass : public Pass { 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(" -flatten\n"); + log(" flatten design before synthesis\n"); + log("\n"); + log(" -retime\n"); + log(" run 'abc' with -dff option\n"); + log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); log("\n"); log(" begin:\n"); + log(" read_verilog -lib +/xilinx/cells_sim.v\n"); log(" hierarchy -check -top <top>\n"); log("\n"); - log(" coarse:\n"); + log(" flatten: (only if -flatten)\n"); log(" proc\n"); - log(" opt\n"); - log(" memory\n"); - log(" clean\n"); - log(" fsm\n"); - log(" opt\n"); + log(" flatten\n"); + log("\n"); + log(" coarse:\n"); + log(" synth -run coarse\n"); + log(" dff2dffe\n"); + log("\n"); + log(" bram:\n"); + log(" memory_bram -rules +/xilinx/brams.txt\n"); + log(" techmap -map +/xilinx/brams_map.v\n"); log("\n"); log(" fine:\n"); - log(" techmap\n"); - log(" opt\n"); + log(" opt -fast -full\n"); + log(" memory_map\n"); + log(" opt -full\n"); + log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v\n"); + log(" opt -fast\n"); log("\n"); log(" map_luts:\n"); - log(" abc -lut 6\n"); + log(" abc -lut 5:8 [-dff]\n"); log(" clean\n"); log("\n"); log(" map_cells:\n"); - log(" techmap -share_map xilinx/cells.v\n"); + log(" techmap -map +/xilinx/cells_map.v\n"); log(" clean\n"); log("\n"); - log(" clkbuf:\n"); - log(" select -set xilinx_clocks <top>/t:FDRE %%x:+FDRE[C] <top>/t:FDRE %%d\n"); - log(" iopadmap -inpad BUFGP O:I @xilinx_clocks\n"); - log("\n"); - log(" iobuf:\n"); - log(" select -set xilinx_nonclocks <top>/w:* <top>/t:BUFGP %%x:+BUFGP[I] %%d\n"); - log(" iopadmap -outpad OBUF I:O -inpad IBUF O:I @xilinx_nonclocks\n"); + log(" check:\n"); + log(" hierarchy -check\n"); + log(" stat\n"); + log(" check -noinit\n"); log("\n"); log(" edif:\n"); log(" write_edif synth.edif\n"); @@ -103,6 +113,8 @@ struct SynthXilinxPass : public Pass { std::string arch_name = "spartan6"; std::string edif_file; std::string run_from, run_to; + bool flatten = false; + bool retime = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -111,10 +123,6 @@ struct SynthXilinxPass : public Pass { top_module = args[++argidx]; continue; } - if (args[argidx] == "-arch" && argidx+1 < args.size()) { - arch_name = args[++argidx]; - continue; - } if (args[argidx] == "-edif" && argidx+1 < args.size()) { edif_file = args[++argidx]; continue; @@ -127,6 +135,14 @@ struct SynthXilinxPass : public Pass { run_to = args[argidx].substr(pos+1); continue; } + if (args[argidx] == "-flatten") { + flatten = true; + continue; + } + if (args[argidx] == "-retime") { + retime = true; + continue; + } break; } extra_args(args, argidx, design); @@ -134,20 +150,6 @@ struct SynthXilinxPass : public Pass { if (!design->full_selection()) log_cmd_error("This comannd only operates on fully selected designs!\n"); - if (arch_name == "spartan6") { - /* set flags */ - } else - if (arch_name == "artix7") { - /* set flags */ - } else - if (arch_name == "kintex7") { - /* set flags */ - } else - if (arch_name == "zynq7000") { - /* set flags */ - } else - log_cmd_error("Architecture '%s' is not supported!\n", arch_name.c_str()); - bool active = run_from.empty(); log_header("Executing SYNTH_XILINX pass.\n"); @@ -155,47 +157,54 @@ struct SynthXilinxPass : public Pass { if (check_label(active, run_from, run_to, "begin")) { + Pass::call(design, "read_verilog -lib +/xilinx/cells_sim.v"); Pass::call(design, stringf("hierarchy -check -top %s", top_module.c_str())); } - if (check_label(active, run_from, run_to, "coarse")) + if (flatten && check_label(active, run_from, run_to, "flatten")) { Pass::call(design, "proc"); - Pass::call(design, "opt"); - Pass::call(design, "memory"); - Pass::call(design, "clean"); - Pass::call(design, "fsm"); - Pass::call(design, "opt"); + Pass::call(design, "flatten"); + } + + if (check_label(active, run_from, run_to, "coarse")) + { + Pass::call(design, "synth -run coarse"); + Pass::call(design, "dff2dffe"); + } + + if (check_label(active, run_from, run_to, "bram")) + { + Pass::call(design, "memory_bram -rules +/xilinx/brams.txt"); + Pass::call(design, "techmap -map +/xilinx/brams_map.v"); } if (check_label(active, run_from, run_to, "fine")) { - Pass::call(design, "techmap"); - Pass::call(design, "opt"); + Pass::call(design, "opt -fast -full"); + Pass::call(design, "memory_map"); + Pass::call(design, "opt -full"); + Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v"); + Pass::call(design, "opt -fast"); } if (check_label(active, run_from, run_to, "map_luts")) { - Pass::call(design, "abc -lut 6"); + Pass::call(design, "abc -lut 5:8" + string(retime ? " -dff" : "")); Pass::call(design, "clean"); } if (check_label(active, run_from, run_to, "map_cells")) { - Pass::call(design, "techmap -share_map xilinx/cells.v"); + Pass::call(design, "techmap -map +/xilinx/cells_map.v"); Pass::call(design, "clean"); } - if (check_label(active, run_from, run_to, "clkbuf")) - { - Pass::call(design, stringf("select -set xilinx_clocks %s/t:FDRE %%x:+FDRE[C] %s/t:FDRE %%d", top_module.c_str(), top_module.c_str())); - Pass::call(design, "iopadmap -inpad BUFGP O:I @xilinx_clocks"); - } - - if (check_label(active, run_from, run_to, "iobuf")) + if (check_label(active, run_from, run_to, "check")) { - Pass::call(design, stringf("select -set xilinx_nonclocks %s/w:* %s/t:BUFGP %%x:+BUFGP[I] %%d", top_module.c_str(), top_module.c_str())); - Pass::call(design, "iopadmap -outpad OBUF I:O -inpad IBUF O:I @xilinx_nonclocks"); + Pass::call(design, "hierarchy -check"); + Pass::call(design, "stat"); + Pass::call(design, "check -noinit"); } if (check_label(active, run_from, run_to, "edif")) @@ -208,3 +217,4 @@ struct SynthXilinxPass : public Pass { } } SynthXilinxPass; +PRIVATE_NAMESPACE_END diff --git a/techlibs/xilinx/tests/.gitignore b/techlibs/xilinx/tests/.gitignore new file mode 100644 index 000000000..bc2f8babf --- /dev/null +++ b/techlibs/xilinx/tests/.gitignore @@ -0,0 +1,3 @@ +bram1_cmp +bram1.mk +bram1_[0-9]*/ diff --git a/techlibs/xilinx/tests/bram1.sh b/techlibs/xilinx/tests/bram1.sh new file mode 100644 index 000000000..1f0359ac9 --- /dev/null +++ b/techlibs/xilinx/tests/bram1.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +set -e + +transp_list="0 1" +abits_list="1 2 4 8 10 16 20" +dbits_list="1 2 4 8 10 16 20 24 30 32 40 48 50 56 60 64 70 72 80" + +use_xsim=false +unisims=/opt/Xilinx/Vivado/2014.4/data/verilog/src/unisims + +echo "all: all_list" > bram1.mk +all_list="" + +for transp in $transp_list; do +for abits in $abits_list; do +for dbits in $dbits_list; do + if [ $(( (1 << $abits) * $dbits )) -gt 1000000 ]; then continue; fi + id=`printf "%d%02d%02d" $transp $abits $dbits` + echo "Creating bram1_$id.." + rm -rf bram1_$id + mkdir -p bram1_$id + cp bram1.v bram1_tb.v bram1_$id/ + sed -i "/parameter/ s,ABITS *= *[0-9]*,ABITS = $abits," bram1_$id/*.v + sed -i "/parameter/ s,DBITS *= *[0-9]*,DBITS = $dbits," bram1_$id/*.v + sed -i "/parameter/ s,TRANSP *= *[0-9]*,TRANSP = $transp," bram1_$id/*.v + { + echo "set -e" + echo "../../../../yosys -q -lsynth.log -p 'synth_xilinx -top bram1; write_verilog synth.v' bram1.v" + if $use_xsim; then + echo "xvlog --work gold bram1_tb.v bram1.v > gold.txt" + echo "xvlog --work gate bram1_tb.v synth.v > gate.txt" + echo "xelab -R gold.bram1_tb >> gold.txt" + echo "xelab -L unisim -R gate.bram1_tb >> gate.txt" + else + echo "iverilog -o bram1_tb_gold bram1_tb.v bram1.v > gold.txt 2>&1" + echo "iverilog -o bram1_tb_gate bram1_tb.v synth.v -y $unisims $unisims/../glbl.v > gate.txt 2>&1" + echo "./bram1_tb_gold >> gold.txt" + echo "./bram1_tb_gate >> gate.txt" + fi + echo "../bram1_cmp <( grep '#OUT#' gold.txt; ) <( grep '#OUT#' gate.txt; )" + } > bram1_$id/run.sh + { + echo "bram1_$id/ok:" + echo " @cd bram1_$id && bash run.sh" + echo " @echo -n '[$id]'" + echo " @touch \$@" + } >> bram1.mk + all_list="$all_list bram1_$id/ok" +done; done; done + +cc -o bram1_cmp ../../../tests/tools/cmp_tbdata.c +echo all_list: $(echo $all_list | tr ' ' '\n' | sort -R) >> bram1.mk + +echo "Testing..." +${MAKE:-make} -f bram1.mk +echo + +echo "Used rules:" $(grep -h 'Selected rule.*with efficiency' bram1_*/synth.log | gawk '{ print $3; }' | sort -u) + +echo "Cleaning up..." +rm -rf bram1_cmp bram1.mk bram1_[0-9]*/ + diff --git a/techlibs/xilinx/tests/bram1.v b/techlibs/xilinx/tests/bram1.v new file mode 100644 index 000000000..034cc18e9 --- /dev/null +++ b/techlibs/xilinx/tests/bram1.v @@ -0,0 +1,24 @@ +module bram1 #( + parameter ABITS = 8, DBITS = 8, TRANSP = 0 +) ( + input clk, + + input [ABITS-1:0] WR_ADDR, + input [DBITS-1:0] WR_DATA, + input WR_EN, + + input [ABITS-1:0] RD_ADDR, + output [DBITS-1:0] RD_DATA +); + reg [DBITS-1:0] memory [0:2**ABITS-1]; + reg [ABITS-1:0] RD_ADDR_BUF; + reg [DBITS-1:0] RD_DATA_BUF; + + always @(posedge clk) begin + if (WR_EN) memory[WR_ADDR] <= WR_DATA; + RD_ADDR_BUF <= RD_ADDR; + RD_DATA_BUF <= memory[RD_ADDR]; + end + + assign RD_DATA = TRANSP ? memory[RD_ADDR_BUF] : RD_DATA_BUF; +endmodule diff --git a/techlibs/xilinx/tests/bram1_tb.v b/techlibs/xilinx/tests/bram1_tb.v new file mode 100644 index 000000000..8f854b749 --- /dev/null +++ b/techlibs/xilinx/tests/bram1_tb.v @@ -0,0 +1,116 @@ +module bram1_tb #( + parameter ABITS = 8, DBITS = 8, TRANSP = 0 +); + reg clk; + reg [ABITS-1:0] WR_ADDR; + reg [DBITS-1:0] WR_DATA; + reg WR_EN; + reg [ABITS-1:0] RD_ADDR; + wire [DBITS-1:0] RD_DATA; + + bram1 #( + // .ABITS(ABITS), + // .DBITS(DBITS), + // .TRANSP(TRANSP) + ) uut ( + .clk (clk ), + .WR_ADDR(WR_ADDR), + .WR_DATA(WR_DATA), + .WR_EN (WR_EN ), + .RD_ADDR(RD_ADDR), + .RD_DATA(RD_DATA) + ); + + reg [63:0] xorshift64_state = 64'd88172645463325252 ^ (ABITS << 24) ^ (DBITS << 16) ^ (TRANSP << 8); + + task xorshift64_next; + begin + // see page 4 of Marsaglia, George (July 2003). "Xorshift RNGs". Journal of Statistical Software 8 (14). + xorshift64_state = xorshift64_state ^ (xorshift64_state << 13); + xorshift64_state = xorshift64_state ^ (xorshift64_state >> 7); + xorshift64_state = xorshift64_state ^ (xorshift64_state << 17); + end + endtask + + reg [ABITS-1:0] randaddr1; + reg [ABITS-1:0] randaddr2; + reg [ABITS-1:0] randaddr3; + + function [31:0] getaddr(input [3:0] n); + begin + case (n) + 0: getaddr = 0; + 1: getaddr = 2**ABITS-1; + 2: getaddr = 'b101 << (ABITS / 3); + 3: getaddr = 'b101 << (2*ABITS / 3); + 4: getaddr = 'b11011 << (ABITS / 4); + 5: getaddr = 'b11011 << (2*ABITS / 4); + 6: getaddr = 'b11011 << (3*ABITS / 4); + 7: getaddr = randaddr1; + 8: getaddr = randaddr2; + 9: getaddr = randaddr3; + default: begin + getaddr = 1 << (2*n-16); + if (!getaddr) getaddr = xorshift64_state; + end + endcase + end + endfunction + + reg [DBITS-1:0] memory [0:2**ABITS-1]; + reg [DBITS-1:0] expected_rd, expected_rd_masked; + + event error; + reg error_ind = 0; + + integer i, j; + initial begin + // $dumpfile("testbench.vcd"); + // $dumpvars(0, bram1_tb); + + xorshift64_next; + xorshift64_next; + xorshift64_next; + xorshift64_next; + + randaddr1 = xorshift64_state; + xorshift64_next; + + randaddr2 = xorshift64_state; + xorshift64_next; + + randaddr3 = xorshift64_state; + xorshift64_next; + + clk <= 0; + for (i = 0; i < 512; i = i+1) begin + if (DBITS > 64) + WR_DATA <= (xorshift64_state << (DBITS-64)) ^ xorshift64_state; + else + WR_DATA <= xorshift64_state; + xorshift64_next; + WR_ADDR <= getaddr(i < 256 ? i[7:4] : xorshift64_state[63:60]); + xorshift64_next; + RD_ADDR <= getaddr(i < 256 ? i[3:0] : xorshift64_state[59:56]); + WR_EN <= xorshift64_state[55]; + xorshift64_next; + + #1; clk <= 1; + #1; clk <= 0; + + if (TRANSP) begin + if (WR_EN) memory[WR_ADDR] = WR_DATA; + expected_rd = memory[RD_ADDR]; + end else begin + expected_rd = memory[RD_ADDR]; + if (WR_EN) memory[WR_ADDR] = WR_DATA; + end + + for (j = 0; j < DBITS; j = j+1) + expected_rd_masked[j] = expected_rd[j] !== 1'bx ? expected_rd[j] : RD_DATA[j]; + + $display("#OUT# %3d | WA=%x WD=%x WE=%x | RA=%x RD=%x (%x) | %s", i, WR_ADDR, WR_DATA, WR_EN, RD_ADDR, RD_DATA, expected_rd, expected_rd_masked === RD_DATA ? "ok" : "ERROR"); + if (expected_rd_masked !== RD_DATA) begin -> error; error_ind = ~error_ind; end + end + end +endmodule |