summaryrefslogtreecommitdiff
path: root/techlibs/ice40
diff options
context:
space:
mode:
Diffstat (limited to 'techlibs/ice40')
-rw-r--r--techlibs/ice40/Makefile.inc2
-rw-r--r--techlibs/ice40/brams_map.v4
-rw-r--r--techlibs/ice40/cells_sim.v279
-rw-r--r--techlibs/ice40/ice40_braminit.cc159
-rw-r--r--techlibs/ice40/ice40_ffssr.cc3
-rw-r--r--techlibs/ice40/ice40_opt.cc15
-rw-r--r--techlibs/ice40/ice40_unlut.cc106
-rw-r--r--techlibs/ice40/synth_ice40.cc81
-rw-r--r--techlibs/ice40/tests/.gitignore13
-rw-r--r--techlibs/ice40/tests/test_dsp_map.sh107
-rw-r--r--techlibs/ice40/tests/test_dsp_model.sh11
-rw-r--r--techlibs/ice40/tests/test_dsp_model.v342
12 files changed, 1025 insertions, 97 deletions
diff --git a/techlibs/ice40/Makefile.inc b/techlibs/ice40/Makefile.inc
index 14761c6c..723b59d6 100644
--- a/techlibs/ice40/Makefile.inc
+++ b/techlibs/ice40/Makefile.inc
@@ -1,8 +1,10 @@
OBJS += techlibs/ice40/synth_ice40.o
+OBJS += techlibs/ice40/ice40_braminit.o
OBJS += techlibs/ice40/ice40_ffssr.o
OBJS += techlibs/ice40/ice40_ffinit.o
OBJS += techlibs/ice40/ice40_opt.o
+OBJS += techlibs/ice40/ice40_unlut.o
GENFILES += techlibs/ice40/brams_init1.vh
GENFILES += techlibs/ice40/brams_init2.vh
diff --git a/techlibs/ice40/brams_map.v b/techlibs/ice40/brams_map.v
index 19a61d73..ad3bccd2 100644
--- a/techlibs/ice40/brams_map.v
+++ b/techlibs/ice40/brams_map.v
@@ -7,8 +7,8 @@ module \$__ICE40_RAM4K (
input [10:0] WADDR,
input [15:0] MASK, WDATA
);
- parameter integer READ_MODE = 0;
- parameter integer WRITE_MODE = 0;
+ parameter [1:0] READ_MODE = 0;
+ parameter [1:0] WRITE_MODE = 0;
parameter [0:0] NEGCLK_R = 0;
parameter [0:0] NEGCLK_W = 0;
diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v
index e0a07af3..62a28364 100644
--- a/techlibs/ice40/cells_sim.v
+++ b/techlibs/ice40/cells_sim.v
@@ -326,6 +326,8 @@ module SB_RAM40_4K (
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_FILE = "";
+
`ifndef BLACKBOX
wire [15:0] WMASK_I;
wire [15:0] RMASK_I;
@@ -408,24 +410,27 @@ module SB_RAM40_4K (
reg [15:0] memory [0:255];
initial begin
- for (i=0; i<16; i=i+1) begin
- memory[ 0*16 + i] <= INIT_0[16*i +: 16];
- memory[ 1*16 + i] <= INIT_1[16*i +: 16];
- memory[ 2*16 + i] <= INIT_2[16*i +: 16];
- memory[ 3*16 + i] <= INIT_3[16*i +: 16];
- memory[ 4*16 + i] <= INIT_4[16*i +: 16];
- memory[ 5*16 + i] <= INIT_5[16*i +: 16];
- memory[ 6*16 + i] <= INIT_6[16*i +: 16];
- memory[ 7*16 + i] <= INIT_7[16*i +: 16];
- memory[ 8*16 + i] <= INIT_8[16*i +: 16];
- memory[ 9*16 + i] <= INIT_9[16*i +: 16];
- memory[10*16 + i] <= INIT_A[16*i +: 16];
- memory[11*16 + i] <= INIT_B[16*i +: 16];
- memory[12*16 + i] <= INIT_C[16*i +: 16];
- memory[13*16 + i] <= INIT_D[16*i +: 16];
- memory[14*16 + i] <= INIT_E[16*i +: 16];
- memory[15*16 + i] <= INIT_F[16*i +: 16];
- end
+ if (INIT_FILE != "")
+ $readmemh(INIT_FILE, memory);
+ else
+ for (i=0; i<16; i=i+1) begin
+ memory[ 0*16 + i] = INIT_0[16*i +: 16];
+ memory[ 1*16 + i] = INIT_1[16*i +: 16];
+ memory[ 2*16 + i] = INIT_2[16*i +: 16];
+ memory[ 3*16 + i] = INIT_3[16*i +: 16];
+ memory[ 4*16 + i] = INIT_4[16*i +: 16];
+ memory[ 5*16 + i] = INIT_5[16*i +: 16];
+ memory[ 6*16 + i] = INIT_6[16*i +: 16];
+ memory[ 7*16 + i] = INIT_7[16*i +: 16];
+ memory[ 8*16 + i] = INIT_8[16*i +: 16];
+ memory[ 9*16 + i] = INIT_9[16*i +: 16];
+ memory[10*16 + i] = INIT_A[16*i +: 16];
+ memory[11*16 + i] = INIT_B[16*i +: 16];
+ memory[12*16 + i] = INIT_C[16*i +: 16];
+ memory[13*16 + i] = INIT_D[16*i +: 16];
+ memory[14*16 + i] = INIT_E[16*i +: 16];
+ memory[15*16 + i] = INIT_F[16*i +: 16];
+ end
end
always @(posedge WCLK) begin
@@ -485,6 +490,8 @@ module SB_RAM40_4KNR (
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_FILE = "";
+
SB_RAM40_4K #(
.WRITE_MODE(WRITE_MODE),
.READ_MODE (READ_MODE ),
@@ -503,7 +510,8 @@ module SB_RAM40_4KNR (
.INIT_C (INIT_C ),
.INIT_D (INIT_D ),
.INIT_E (INIT_E ),
- .INIT_F (INIT_F )
+ .INIT_F (INIT_F ),
+ .INIT_FILE (INIT_FILE )
) RAM (
.RDATA(RDATA),
.RCLK (~RCLKN),
@@ -547,6 +555,8 @@ module SB_RAM40_4KNW (
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_FILE = "";
+
SB_RAM40_4K #(
.WRITE_MODE(WRITE_MODE),
.READ_MODE (READ_MODE ),
@@ -565,7 +575,8 @@ module SB_RAM40_4KNW (
.INIT_C (INIT_C ),
.INIT_D (INIT_D ),
.INIT_E (INIT_E ),
- .INIT_F (INIT_F )
+ .INIT_F (INIT_F ),
+ .INIT_FILE (INIT_FILE )
) RAM (
.RDATA(RDATA),
.RCLK (RCLK ),
@@ -609,6 +620,8 @@ module SB_RAM40_4KNRNW (
parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_FILE = "";
+
SB_RAM40_4K #(
.WRITE_MODE(WRITE_MODE),
.READ_MODE (READ_MODE ),
@@ -627,7 +640,8 @@ module SB_RAM40_4KNRNW (
.INIT_C (INIT_C ),
.INIT_D (INIT_D ),
.INIT_E (INIT_E ),
- .INIT_F (INIT_F )
+ .INIT_F (INIT_F ),
+ .INIT_FILE (INIT_FILE )
) RAM (
.RDATA(RDATA),
.RCLK (~RCLKN),
@@ -867,59 +881,6 @@ module SB_WARMBOOT (
);
endmodule
-// UltraPlus feature cells
-(* blackbox *)
-module SB_MAC16 (
- input CLK,
- input CE,
- input [15:0] C,
- input [15:0] A,
- input [15:0] B,
- input [15:0] D,
- input AHOLD,
- input BHOLD,
- input CHOLD,
- input DHOLD,
- input IRSTTOP,
- input IRSTBOT,
- input ORSTTOP,
- input ORSTBOT,
- input OLOADTOP,
- input OLOADBOT,
- input ADDSUBTOP,
- input ADDSUBBOT,
- input OHOLDTOP,
- input OHOLDBOT,
- input CI,
- input ACCUMCI,
- input SIGNEXTIN,
- output [31:0] O,
- output CO,
- output ACCUMCO,
- output SIGNEXTOUT
-);
-parameter NEG_TRIGGER = 1'b0;
-parameter C_REG = 1'b0;
-parameter A_REG = 1'b0;
-parameter B_REG = 1'b0;
-parameter D_REG = 1'b0;
-parameter TOP_8x8_MULT_REG = 1'b0;
-parameter BOT_8x8_MULT_REG = 1'b0;
-parameter PIPELINE_16x16_MULT_REG1 = 1'b0;
-parameter PIPELINE_16x16_MULT_REG2 = 1'b0;
-parameter TOPOUTPUT_SELECT = 2'b00;
-parameter TOPADDSUB_LOWERINPUT = 2'b00;
-parameter TOPADDSUB_UPPERINPUT = 1'b0;
-parameter TOPADDSUB_CARRYSELECT = 2'b00;
-parameter BOTOUTPUT_SELECT = 2'b00;
-parameter BOTADDSUB_LOWERINPUT = 2'b00;
-parameter BOTADDSUB_UPPERINPUT = 1'b0;
-parameter BOTADDSUB_CARRYSELECT = 2'b00;
-parameter MODE_8x8 = 1'b0;
-parameter A_SIGNED = 1'b0;
-parameter B_SIGNED = 1'b0;
-endmodule
-
module SB_SPRAM256KA (
input [13:0] ADDRESS,
input [15:0] DATAIN,
@@ -928,6 +889,7 @@ module SB_SPRAM256KA (
output reg [15:0] DATAOUT
);
`ifndef BLACKBOX
+`ifndef EQUIV
reg [15:0] mem [0:16383];
wire off = SLEEP || !POWEROFF;
integer i;
@@ -954,6 +916,7 @@ module SB_SPRAM256KA (
end
end
`endif
+`endif
endmodule
(* blackbox *)
@@ -1252,3 +1215,171 @@ module SB_IO_OD (
endgenerate
`endif
endmodule
+
+module SB_MAC16 (
+ input CLK, CE,
+ input [15:0] C, A, B, D,
+ input AHOLD, BHOLD, CHOLD, DHOLD,
+ input IRSTTOP, IRSTBOT,
+ input ORSTTOP, ORSTBOT,
+ input OLOADTOP, OLOADBOT,
+ input ADDSUBTOP, ADDSUBBOT,
+ input OHOLDTOP, OHOLDBOT,
+ input CI, ACCUMCI, SIGNEXTIN,
+ output [31:0] O,
+ output CO, ACCUMCO, SIGNEXTOUT
+);
+ parameter [0:0] NEG_TRIGGER = 0;
+ parameter [0:0] C_REG = 0;
+ parameter [0:0] A_REG = 0;
+ parameter [0:0] B_REG = 0;
+ parameter [0:0] D_REG = 0;
+ parameter [0:0] TOP_8x8_MULT_REG = 0;
+ parameter [0:0] BOT_8x8_MULT_REG = 0;
+ parameter [0:0] PIPELINE_16x16_MULT_REG1 = 0;
+ parameter [0:0] PIPELINE_16x16_MULT_REG2 = 0;
+ parameter [1:0] TOPOUTPUT_SELECT = 0;
+ parameter [1:0] TOPADDSUB_LOWERINPUT = 0;
+ parameter [0:0] TOPADDSUB_UPPERINPUT = 0;
+ parameter [1:0] TOPADDSUB_CARRYSELECT = 0;
+ parameter [1:0] BOTOUTPUT_SELECT = 0;
+ parameter [1:0] BOTADDSUB_LOWERINPUT = 0;
+ parameter [0:0] BOTADDSUB_UPPERINPUT = 0;
+ parameter [1:0] BOTADDSUB_CARRYSELECT = 0;
+ parameter [0:0] MODE_8x8 = 0;
+ parameter [0:0] A_SIGNED = 0;
+ parameter [0:0] B_SIGNED = 0;
+
+ wire clock = CLK ^ NEG_TRIGGER;
+
+ // internal wires, compare Figure on page 133 of ICE Technology Library 3.0 and Fig 2 on page 2 of Lattice TN1295-DSP
+ // http://www.latticesemi.com/~/media/LatticeSemi/Documents/TechnicalBriefs/SBTICETechnologyLibrary201608.pdf
+ // https://www.latticesemi.com/-/media/LatticeSemi/Documents/ApplicationNotes/AD/DSPFunctionUsageGuideforICE40Devices.ashx
+ wire [15:0] iA, iB, iC, iD;
+ wire [15:0] iF, iJ, iK, iG;
+ wire [31:0] iL, iH;
+ wire [15:0] iW, iX, iP, iQ;
+ wire [15:0] iY, iZ, iR, iS;
+ wire HCI, LCI, LCO;
+
+ // Regs C and A
+ reg [15:0] rC, rA;
+ always @(posedge clock, posedge IRSTTOP) begin
+ if (IRSTTOP) begin
+ rC <= 0;
+ rA <= 0;
+ end else if (CE) begin
+ if (!CHOLD) rC <= C;
+ if (!AHOLD) rA <= A;
+ end
+ end
+ assign iC = C_REG ? rC : C;
+ assign iA = A_REG ? rA : A;
+
+ // Regs B and D
+ reg [15:0] rB, rD;
+ always @(posedge clock, posedge IRSTBOT) begin
+ if (IRSTBOT) begin
+ rB <= 0;
+ rD <= 0;
+ end else if (CE) begin
+ if (!BHOLD) rB <= B;
+ if (!DHOLD) rD <= D;
+ end
+ end
+ assign iB = B_REG ? rB : B;
+ assign iD = D_REG ? rD : D;
+
+ // Multiplier Stage
+ wire [15:0] p_Ah_Bh, p_Al_Bh, p_Ah_Bl, p_Al_Bl;
+ wire [15:0] Ah, Al, Bh, Bl;
+ assign Ah = {A_SIGNED ? {8{iA[15]}} : 8'b0, iA[15: 8]};
+ assign Al = {A_SIGNED ? {8{iA[ 7]}} : 8'b0, iA[ 7: 0]};
+ assign Bh = {B_SIGNED ? {8{iB[15]}} : 8'b0, iB[15: 8]};
+ assign Bl = {B_SIGNED ? {8{iB[ 7]}} : 8'b0, iB[ 7: 0]};
+ assign p_Ah_Bh = Ah * Bh;
+ assign p_Al_Bh = Al * Bh;
+ assign p_Ah_Bl = Ah * Bl;
+ assign p_Al_Bl = Al * Bl;
+
+ // Regs F and J
+ reg [15:0] rF, rJ;
+ always @(posedge clock, posedge IRSTTOP) begin
+ if (IRSTTOP) begin
+ rF <= 0;
+ rJ <= 0;
+ end else if (CE) begin
+ rF <= p_Ah_Bh;
+ if (!MODE_8x8) rJ <= p_Al_Bh;
+ end
+ end
+ assign iF = TOP_8x8_MULT_REG ? rF : p_Ah_Bh;
+ assign iJ = PIPELINE_16x16_MULT_REG1 ? rJ : p_Al_Bh;
+
+ // Regs K and G
+ reg [15:0] rK, rG;
+ always @(posedge clock, posedge IRSTBOT) begin
+ if (IRSTBOT) begin
+ rK <= 0;
+ rG <= 0;
+ end else if (CE) begin
+ if (!MODE_8x8) rK <= p_Ah_Bl;
+ rG <= p_Al_Bl;
+ end
+ end
+ assign iK = PIPELINE_16x16_MULT_REG1 ? rK : p_Ah_Bl;
+ assign iG = BOT_8x8_MULT_REG ? rG : p_Al_Bl;
+
+ // Adder Stage
+ assign iL = iG + (iK << 8) + (iJ << 8) + (iF << 16);
+
+ // Reg H
+ reg [31:0] rH;
+ always @(posedge clock, posedge IRSTBOT) begin
+ if (IRSTBOT) begin
+ rH <= 0;
+ end else if (CE) begin
+ if (!MODE_8x8) rH <= iL;
+ end
+ end
+ assign iH = PIPELINE_16x16_MULT_REG2 ? rH : iL;
+
+ // Hi Output Stage
+ wire [15:0] XW, Oh;
+ reg [15:0] rQ;
+ assign iW = TOPADDSUB_UPPERINPUT ? iC : iQ;
+ assign iX = (TOPADDSUB_LOWERINPUT == 0) ? iA : (TOPADDSUB_LOWERINPUT == 1) ? iF : (TOPADDSUB_LOWERINPUT == 2) ? iH[31:16] : {16{iZ[15]}};
+ assign {ACCUMCO, XW} = iX + (iW ^ {16{ADDSUBTOP}}) + HCI;
+ assign CO = ACCUMCO ^ ADDSUBTOP;
+ assign iP = OLOADTOP ? iC : XW ^ {16{ADDSUBTOP}};
+ always @(posedge clock, posedge ORSTTOP) begin
+ if (ORSTTOP) begin
+ rQ <= 0;
+ end else if (CE) begin
+ if (!OHOLDTOP) rQ <= iP;
+ end
+ end
+ assign iQ = rQ;
+ assign Oh = (TOPOUTPUT_SELECT == 0) ? iP : (TOPOUTPUT_SELECT == 1) ? iQ : (TOPOUTPUT_SELECT == 2) ? iF : iH[31:16];
+ assign HCI = (TOPADDSUB_CARRYSELECT == 0) ? 1'b0 : (TOPADDSUB_CARRYSELECT == 1) ? 1'b1 : (TOPADDSUB_CARRYSELECT == 2) ? LCO : LCO ^ ADDSUBBOT;
+ assign SIGNEXTOUT = iX[15];
+
+ // Lo Output Stage
+ wire [15:0] YZ, Ol;
+ reg [15:0] rS;
+ assign iY = BOTADDSUB_UPPERINPUT ? iD : iS;
+ assign iZ = (BOTADDSUB_LOWERINPUT == 0) ? iB : (BOTADDSUB_LOWERINPUT == 1) ? iG : (BOTADDSUB_LOWERINPUT == 2) ? iH[15:0] : {16{SIGNEXTIN}};
+ assign {LCO, YZ} = iZ + (iY ^ {16{ADDSUBBOT}}) + LCI;
+ assign iR = OLOADBOT ? iD : YZ ^ {16{ADDSUBBOT}};
+ always @(posedge clock, posedge ORSTBOT) begin
+ if (ORSTBOT) begin
+ rS <= 0;
+ end else if (CE) begin
+ if (!OHOLDBOT) rS <= iR;
+ end
+ end
+ assign iS = rS;
+ assign Ol = (BOTOUTPUT_SELECT == 0) ? iR : (BOTOUTPUT_SELECT == 1) ? iS : (BOTOUTPUT_SELECT == 2) ? iG : iH[15:0];
+ assign LCI = (BOTADDSUB_CARRYSELECT == 0) ? 1'b0 : (BOTADDSUB_CARRYSELECT == 1) ? 1'b1 : (BOTADDSUB_CARRYSELECT == 2) ? ACCUMCI : CI;
+ assign O = {Oh, Ol};
+endmodule
diff --git a/techlibs/ice40/ice40_braminit.cc b/techlibs/ice40/ice40_braminit.cc
new file mode 100644
index 00000000..4fa6b079
--- /dev/null
+++ b/techlibs/ice40/ice40_braminit.cc
@@ -0,0 +1,159 @@
+/*
+ * 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/yosys.h"
+#include "kernel/sigtools.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <bitset>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+static void run_ice40_braminit(Module *module)
+{
+ for (auto cell : module->selected_cells())
+ {
+ uint16_t mem[256];
+
+ /* Only consider cells we're interested in */
+ if (cell->type != "\\SB_RAM40_4K" &&
+ cell->type != "\\SB_RAM40_4KNR" &&
+ cell->type != "\\SB_RAM40_4KNW" &&
+ cell->type != "\\SB_RAM40_4KNRNW")
+ continue;
+ if (!cell->hasParam("\\INIT_FILE"))
+ continue;
+ std::string init_file = cell->getParam("\\INIT_FILE").decode_string();
+ cell->unsetParam("\\INIT_FILE");
+ if (init_file == "")
+ continue;
+
+ /* Open file */
+ log("Processing %s : %s\n", RTLIL::id2cstr(cell->name), init_file.c_str());
+
+ std::ifstream f;
+ f.open(init_file.c_str());
+ if (f.fail()) {
+ log("Can not open file `%s`.\n", init_file.c_str());
+ continue;
+ }
+
+ /* Defaults to 0 */
+ memset(mem, 0x00, sizeof(mem));
+
+ /* Process each line */
+ bool in_comment = false;
+ int cursor = 0;
+
+ while (!f.eof())
+ {
+ std::string line, token;
+ std::getline(f, line);
+
+ for (int i = 0; i < GetSize(line); i++)
+ {
+ if (in_comment && line.substr(i, 2) == "*/") {
+ line[i] = ' ';
+ line[i+1] = ' ';
+ in_comment = false;
+ continue;
+ }
+ if (!in_comment && line.substr(i, 2) == "/*")
+ in_comment = true;
+ if (in_comment)
+ line[i] = ' ';
+ }
+
+ while (1)
+ {
+ bool set_cursor = false;
+ long value;
+
+ token = next_token(line, " \t\r\n");
+ if (token.empty() || token.substr(0, 2) == "//")
+ break;
+
+ if (token[0] == '@') {
+ token = token.substr(1);
+ set_cursor = true;
+ }
+
+ const char *nptr = token.c_str();
+ char *endptr;
+ value = strtol(nptr, &endptr, 16);
+ if (!*nptr || *endptr) {
+ log("Can not parse %s `%s` for %s.\n",
+ set_cursor ? "address" : "value",
+ nptr, token.c_str()
+ );
+ continue;
+ }
+
+ if (set_cursor)
+ cursor = value;
+ else if (cursor >= 0 && cursor < 256)
+ mem[cursor++] = value;
+ else
+ log("Attempt to initialize non existent address %d\n", cursor);
+ }
+ }
+
+ /* Set attributes */
+ const char *hex = "0123456789ABCDEF";
+ for (int i=0; i<16; i++) {
+ std::string val = "";
+ for (int j=15; j>=0; j--)
+ val += std::bitset<16>(mem[i*16+j]).to_string();
+ cell->setParam("\\INIT_" + std::string(1, hex[i]), RTLIL::Const::from_string(val));
+ }
+ }
+}
+
+struct Ice40BRAMInitPass : public Pass {
+ Ice40BRAMInitPass() : Pass("ice40_braminit", "iCE40: perform SB_RAM40_4K initialization from file") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" ice40_braminit\n");
+ log("\n");
+ log("This command processes all SB_RAM40_4K blocks with a non-empty INIT_FILE\n");
+ log("parameter and converts it into the required INIT_x attributes\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing ICE40_BRAMINIT pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ // if (args[argidx] == "-???") {
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ run_ice40_braminit(module);
+ }
+} Ice40BRAMInitPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/ice40/ice40_ffssr.cc b/techlibs/ice40/ice40_ffssr.cc
index 668df09d..a7649d7a 100644
--- a/techlibs/ice40/ice40_ffssr.cc
+++ b/techlibs/ice40/ice40_ffssr.cc
@@ -81,6 +81,9 @@ struct Ice40FfssrPass : public Pass {
for (auto cell : ff_cells)
{
+ if (cell->get_bool_attribute("\\dont_touch"))
+ continue;
+
SigSpec sig_d = cell->getPort("\\D");
if (GetSize(sig_d) < 1)
diff --git a/techlibs/ice40/ice40_opt.cc b/techlibs/ice40/ice40_opt.cc
index 16274005..f528607d 100644
--- a/techlibs/ice40/ice40_opt.cc
+++ b/techlibs/ice40/ice40_opt.cc
@@ -33,7 +33,7 @@ static SigBit get_bit_or_zero(const SigSpec &sig)
return sig[0];
}
-static void run_ice40_opts(Module *module, bool unlut_mode)
+static void run_ice40_opts(Module *module)
{
pool<SigBit> optimized_co;
vector<Cell*> sb_lut_cells;
@@ -95,9 +95,6 @@ static void run_ice40_opts(Module *module, bool unlut_mode)
inbits.append(get_bit_or_zero(cell->getPort("\\I3")));
sigmap.apply(inbits);
- if (unlut_mode)
- goto remap_lut;
-
if (optimized_co.count(inbits[0])) goto remap_lut;
if (optimized_co.count(inbits[1])) goto remap_lut;
if (optimized_co.count(inbits[2])) goto remap_lut;
@@ -152,14 +149,10 @@ struct Ice40OptPass : public Pass {
log(" opt_clean\n");
log(" while <changed design>\n");
log("\n");
- log("When called with the option -unlut, this command will transform all already\n");
- log("mapped SB_LUT4 cells back to logic.\n");
- log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
string opt_expr_args = "-mux_undef -undriven";
- bool unlut_mode = false;
log_header(design, "Executing ICE40_OPT pass (performing simple optimizations).\n");
log_push();
@@ -170,10 +163,6 @@ struct Ice40OptPass : public Pass {
opt_expr_args += " -full";
continue;
}
- if (args[argidx] == "-unlut") {
- unlut_mode = true;
- continue;
- }
break;
}
extra_args(args, argidx, design);
@@ -184,7 +173,7 @@ struct Ice40OptPass : public Pass {
log_header(design, "Running ICE40 specific optimizations.\n");
for (auto module : design->selected_modules())
- run_ice40_opts(module, unlut_mode);
+ run_ice40_opts(module);
Pass::call(design, "opt_expr " + opt_expr_args);
Pass::call(design, "opt_merge");
diff --git a/techlibs/ice40/ice40_unlut.cc b/techlibs/ice40/ice40_unlut.cc
new file mode 100644
index 00000000..2428a8e7
--- /dev/null
+++ b/techlibs/ice40/ice40_unlut.cc
@@ -0,0 +1,106 @@
+/*
+ * 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/yosys.h"
+#include "kernel/sigtools.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+static SigBit get_bit_or_zero(const SigSpec &sig)
+{
+ if (GetSize(sig) == 0)
+ return State::S0;
+ return sig[0];
+}
+
+static void run_ice40_unlut(Module *module)
+{
+ SigMap sigmap(module);
+
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type == "\\SB_LUT4")
+ {
+ SigSpec inbits;
+
+ inbits.append(get_bit_or_zero(cell->getPort("\\I0")));
+ inbits.append(get_bit_or_zero(cell->getPort("\\I1")));
+ inbits.append(get_bit_or_zero(cell->getPort("\\I2")));
+ inbits.append(get_bit_or_zero(cell->getPort("\\I3")));
+ sigmap.apply(inbits);
+
+ log("Mapping SB_LUT4 cell %s.%s to $lut.\n", log_id(module), log_id(cell));
+
+ cell->type ="$lut";
+ cell->setParam("\\WIDTH", 4);
+ cell->setParam("\\LUT", cell->getParam("\\LUT_INIT"));
+ cell->unsetParam("\\LUT_INIT");
+
+ cell->setPort("\\A", SigSpec({
+ get_bit_or_zero(cell->getPort("\\I3")),
+ get_bit_or_zero(cell->getPort("\\I2")),
+ get_bit_or_zero(cell->getPort("\\I1")),
+ get_bit_or_zero(cell->getPort("\\I0"))
+ }));
+ cell->setPort("\\Y", cell->getPort("\\O")[0]);
+ cell->unsetPort("\\I0");
+ cell->unsetPort("\\I1");
+ cell->unsetPort("\\I2");
+ cell->unsetPort("\\I3");
+ cell->unsetPort("\\O");
+
+ cell->check();
+ }
+ }
+}
+
+struct Ice40UnlutPass : public Pass {
+ Ice40UnlutPass() : Pass("ice40_unlut", "iCE40: perform simple optimizations") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" ice40_unlut [options] [selection]\n");
+ log("\n");
+ log("This command transforms all SB_LUT4 cells to generic $lut cells.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ log_header(design, "Executing ICE40_UNLUT pass (convert SB_LUT4 to $lut).\n");
+ log_push();
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ // if (args[argidx] == "-???") {
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ run_ice40_unlut(module);
+ }
+} Ice40UnlutPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc
index b0687e5e..8899bfcc 100644
--- a/techlibs/ice40/synth_ice40.cc
+++ b/techlibs/ice40/synth_ice40.cc
@@ -63,15 +63,28 @@ struct SynthIce40Pass : public ScriptPass
log(" -retime\n");
log(" run 'abc' with -dff option\n");
log("\n");
+ log(" -relut\n");
+ log(" combine LUTs after synthesis\n");
+ log("\n");
log(" -nocarry\n");
log(" do not use SB_CARRY cells in output netlist\n");
log("\n");
log(" -nodffe\n");
log(" do not use SB_DFFE* cells in output netlist\n");
log("\n");
+ log(" -dffe_min_ce_use <min_ce_use>\n");
+ log(" do not use SB_DFFE* cells if the resulting CE line would go to less\n");
+ log(" than min_ce_use SB_DFFE*in output netlist\n");
+ log("\n");
log(" -nobram\n");
log(" do not use SB_RAM40_4K* cells in output netlist\n");
log("\n");
+ log(" -dsp\n");
+ log(" use iCE40 UltraPlus DSP cells for large arithmetic\n");
+ log("\n");
+ log(" -noabc\n");
+ log(" use built-in Yosys LUT techmapping instead of abc\n");
+ log("\n");
log(" -abc2\n");
log(" run two passes of 'abc' for slightly improved logic density\n");
log("\n");
@@ -86,7 +99,8 @@ struct SynthIce40Pass : public ScriptPass
}
string top_opt, blif_file, edif_file, json_file;
- bool nocarry, nodffe, nobram, flatten, retime, abc2, vpr;
+ bool nocarry, nodffe, nobram, dsp, flatten, retime, relut, noabc, abc2, vpr;
+ int min_ce_use;
void clear_flags() YS_OVERRIDE
{
@@ -96,9 +110,13 @@ struct SynthIce40Pass : public ScriptPass
json_file = "";
nocarry = false;
nodffe = false;
+ min_ce_use = -1;
nobram = false;
+ dsp = false;
flatten = true;
retime = false;
+ relut = false;
+ noabc = false;
abc2 = false;
vpr = false;
}
@@ -147,6 +165,10 @@ struct SynthIce40Pass : public ScriptPass
retime = true;
continue;
}
+ if (args[argidx] == "-relut") {
+ relut = true;
+ continue;
+ }
if (args[argidx] == "-nocarry") {
nocarry = true;
continue;
@@ -155,10 +177,22 @@ struct SynthIce40Pass : public ScriptPass
nodffe = true;
continue;
}
+ if (args[argidx] == "-dffe_min_ce_use" && argidx+1 < args.size()) {
+ min_ce_use = std::stoi(args[++argidx]);
+ continue;
+ }
if (args[argidx] == "-nobram") {
nobram = true;
continue;
}
+ if (args[argidx] == "-dsp") {
+ dsp = true;
+ continue;
+ }
+ if (args[argidx] == "-noabc") {
+ noabc = true;
+ continue;
+ }
if (args[argidx] == "-abc2") {
abc2 = true;
continue;
@@ -172,7 +206,7 @@ struct SynthIce40Pass : public ScriptPass
extra_args(args, argidx, design);
if (!design->full_selection())
- log_cmd_error("This comannd only operates on fully selected designs!\n");
+ log_cmd_error("This command only operates on fully selected designs!\n");
log_header(design, "Executing SYNTH_ICE40 pass.\n");
log_push();
@@ -188,11 +222,11 @@ struct SynthIce40Pass : public ScriptPass
{
run("read_verilog -lib +/ice40/cells_sim.v");
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
+ run("proc");
}
if (flatten && check_label("flatten", "(unless -noflatten)"))
{
- run("proc");
run("flatten");
run("tribuf -logic");
run("deminout");
@@ -200,20 +234,41 @@ struct SynthIce40Pass : public ScriptPass
if (check_label("coarse"))
{
- run("synth -run coarse");
+ run("opt_expr");
+ run("opt_clean");
+ run("check");
+ run("opt");
+ run("wreduce");
+ run("share");
+ run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4");
+ run("opt_expr");
+ run("opt_clean");
+ if (help_mode || dsp)
+ run("ice40_dsp", "(if -dsp)");
+ run("alumacc");
+ run("opt");
+ run("fsm");
+ run("opt -fast");
+ run("memory -nomap");
+ run("opt_clean");
}
if (!nobram && check_label("bram", "(skip if -nobram)"))
{
run("memory_bram -rules +/ice40/brams.txt");
run("techmap -map +/ice40/brams_map.v");
+ run("ice40_braminit");
}
- if (check_label("fine"))
+ if (check_label("map"))
{
run("opt -fast -mux_undef -undriven -fine");
run("memory_map");
run("opt -undriven -fine");
+ }
+
+ if (check_label("map_gates"))
+ {
if (nocarry)
run("techmap");
else
@@ -228,6 +283,10 @@ struct SynthIce40Pass : public ScriptPass
run("dffsr2dff");
if (!nodffe)
run("dff2dffe -direct-match $_DFF_*");
+ if (min_ce_use >= 0) {
+ run("opt_merge");
+ run(stringf("dff2dffe -unmap-mince %d", min_ce_use));
+ }
run("techmap -D NO_LUT -map +/ice40/cells_map.v");
run("opt_expr -mux_undef");
run("simplemap");
@@ -243,8 +302,18 @@ struct SynthIce40Pass : public ScriptPass
run("ice40_opt", "(only if -abc2)");
}
run("techmap -map +/ice40/latches_map.v");
- run("abc -lut 4");
+ if (noabc || help_mode) {
+ run("simplemap", " (only if -noabc)");
+ run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)");
+ }
+ if (!noabc) {
+ run("abc -dress -lut 4", "(skip if -noabc)");
+ }
run("clean");
+ if (relut || help_mode) {
+ run("ice40_unlut", " (only if -relut)");
+ run("opt_lut -dlogic SB_CARRY:I0=1:I1=2:CI=3", "(only if -relut)");
+ }
}
if (check_label("map_cells"))
diff --git a/techlibs/ice40/tests/.gitignore b/techlibs/ice40/tests/.gitignore
index b58f9ad4..12028655 100644
--- a/techlibs/ice40/tests/.gitignore
+++ b/techlibs/ice40/tests/.gitignore
@@ -1,2 +1,11 @@
-test_ffs_[01][01][01][01][01]_*
-test_bram_[0-9]*
+/test_ffs_[01][01][01][01][01]_*
+/test_bram_[0-9]*
+/test_dsp_model
+/test_dsp_model.vcd
+/test_dsp_model_ref.v
+/test_dsp_model_uut.v
+/test_dsp_map
+/test_dsp_map.vcd
+/test_dsp_map_tb.v
+/test_dsp_map_top.v
+/test_dsp_map_syn.v
diff --git a/techlibs/ice40/tests/test_dsp_map.sh b/techlibs/ice40/tests/test_dsp_map.sh
new file mode 100644
index 00000000..3f7f134e
--- /dev/null
+++ b/techlibs/ice40/tests/test_dsp_map.sh
@@ -0,0 +1,107 @@
+#!/bin/bash
+set -ex
+
+for iter in {1..100}
+do
+ SZA=$(( 3 + $RANDOM % 13 ))
+ SZB=$(( 3 + $RANDOM % 13 ))
+ SZO=$(( 3 + $RANDOM % 29 ))
+
+ C0=clk$(( $RANDOM & 1))
+ C1=clk$(( $RANDOM & 1))
+ C2=clk$(( $RANDOM & 1))
+ C3=clk$(( $RANDOM & 1))
+
+ E0=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge )
+ E1=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge )
+ E2=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge )
+ E3=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge )
+
+ SP=$( test $(( $RANDOM & 1 )) -eq 0 && echo S || echo P )
+
+ RC=$( test $(( $RANDOM & 1 )) -eq 0 && echo "reset" || echo "!reset" )
+ RV="32'h$( echo $RANDOM | md5sum | cut -c1-8 )"
+
+ cat > test_dsp_map_top.v << EOT
+module top (
+ input clk0, clk1, reset,
+ input [$SZA:0] A,
+ input [$SZB:0] B,
+ output [$SZO:0] O
+);
+ reg [15:0] AA, BB;
+ reg [31:0] P, S;
+
+ always @($E0 $C0) AA <= A;
+ always @($E1 $C1) BB <= B;
+ always @($E2 $C2) P <= AA * BB;
+ always @($E3 $C3) S <= $RC ? $RV : S + P;
+ assign O = $SP;
+endmodule
+EOT
+
+ cat > test_dsp_map_tb.v << EOT
+\`timescale 1ns / 1ps
+module testbench;
+ reg clk1, clk0, reset;
+ reg [$SZA:0] A;
+ reg [$SZB:0] B;
+
+ wire [$SZO:0] O_top, O_syn;
+
+ top top_inst (.clk0(clk0), .clk1(clk1), .reset(reset), .A(A), .B(B), .O(O_top));
+ syn syn_inst (.clk0(clk0), .clk1(clk1), .reset(reset), .A(A), .B(B), .O(O_syn));
+
+ initial begin
+ // \$dumpfile("test_dsp_map.vcd");
+ // \$dumpvars(0, testbench);
+
+ #2;
+ clk0 = 0;
+ clk1 = 0;
+ reset = 1;
+ reset = $RC;
+ A = 0;
+ B = 0;
+
+ repeat (3) begin
+ #2; clk0 = ~clk0;
+ #2; clk0 = ~clk0;
+ #2; clk1 = ~clk1;
+ #2; clk1 = ~clk1;
+ end
+
+ repeat (100) begin
+ #2;
+ A = \$urandom;
+ B = \$urandom;
+ reset = \$urandom & \$urandom & \$urandom & \$urandom;
+ if (\$urandom & 1) begin
+ #2; clk0 = ~clk0;
+ #2; clk0 = ~clk0;
+ end else begin
+ #2; clk1 = ~clk1;
+ #2; clk1 = ~clk1;
+ end
+ #2;
+ if (O_top !== O_syn) begin
+ \$display("ERROR: O_top=%b O_syn=%b", O_top, O_syn);
+ \$stop;
+ end
+ // \$display("OK O_top=O_syn=%b", O_top);
+ end
+
+ \$display("Test passed.");
+ \$finish;
+ end
+endmodule
+EOT
+
+ ../../../yosys -p 'read_verilog test_dsp_map_top.v; synth_ice40 -dsp; rename top syn; write_verilog test_dsp_map_syn.v'
+ iverilog -o test_dsp_map -s testbench test_dsp_map_tb.v test_dsp_map_top.v test_dsp_map_syn.v ../cells_sim.v
+ vvp -N test_dsp_map
+done
+
+: ""
+: "#### All tests passed. ####"
+: ""
diff --git a/techlibs/ice40/tests/test_dsp_model.sh b/techlibs/ice40/tests/test_dsp_model.sh
new file mode 100644
index 00000000..1bc0cc68
--- /dev/null
+++ b/techlibs/ice40/tests/test_dsp_model.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+set -ex
+sed 's/SB_MAC16/SB_MAC16_UUT/; /SB_MAC16_UUT/,/endmodule/ p; d;' < ../cells_sim.v > test_dsp_model_uut.v
+cat /opt/lscc/iCEcube2.2017.01/verilog/sb_ice_syn.v > test_dsp_model_ref.v
+for tb in testbench \
+ testbench_comb_8x8_A testbench_comb_8x8_B testbench_comb_16x16 \
+ testbench_seq_16x16_A testbench_seq_16x16_B
+do
+ iverilog -s $tb -o test_dsp_model test_dsp_model.v test_dsp_model_uut.v test_dsp_model_ref.v
+ vvp -N ./test_dsp_model
+done
diff --git a/techlibs/ice40/tests/test_dsp_model.v b/techlibs/ice40/tests/test_dsp_model.v
new file mode 100644
index 00000000..594bd4ad
--- /dev/null
+++ b/techlibs/ice40/tests/test_dsp_model.v
@@ -0,0 +1,342 @@
+`timescale 1ns / 1ps
+
+module testbench;
+ parameter [0:0] NEG_TRIGGER = 0;
+ parameter [0:0] C_REG = 0;
+ parameter [0:0] A_REG = 0;
+ parameter [0:0] B_REG = 0;
+ parameter [0:0] D_REG = 0;
+ parameter [0:0] TOP_8x8_MULT_REG = 0;
+ parameter [0:0] BOT_8x8_MULT_REG = 0;
+ parameter [0:0] PIPELINE_16x16_MULT_REG1 = 0;
+ parameter [0:0] PIPELINE_16x16_MULT_REG2 = 0;
+ parameter [1:0] TOPOUTPUT_SELECT = 0;
+ parameter [1:0] TOPADDSUB_LOWERINPUT = 0;
+ parameter [0:0] TOPADDSUB_UPPERINPUT = 1;
+ parameter [1:0] TOPADDSUB_CARRYSELECT = 0;
+ parameter [1:0] BOTOUTPUT_SELECT = 0;
+ parameter [1:0] BOTADDSUB_LOWERINPUT = 0;
+ parameter [0:0] BOTADDSUB_UPPERINPUT = 1;
+ parameter [1:0] BOTADDSUB_CARRYSELECT = 0;
+ parameter [0:0] MODE_8x8 = 0;
+ parameter [0:0] A_SIGNED = 0;
+ parameter [0:0] B_SIGNED = 0;
+
+ reg CLK, CE;
+ reg [15:0] C, A, B, D;
+ reg AHOLD, BHOLD, CHOLD, DHOLD;
+ reg IRSTTOP, IRSTBOT;
+ reg ORSTTOP, ORSTBOT;
+ reg OLOADTOP, OLOADBOT;
+ reg ADDSUBTOP, ADDSUBBOT;
+ reg OHOLDTOP, OHOLDBOT;
+ reg CI, ACCUMCI, SIGNEXTIN;
+
+ output [31:0] REF_O, UUT_O;
+ output REF_CO, REF_ACCUMCO, REF_SIGNEXTOUT;
+ output UUT_CO, UUT_ACCUMCO, UUT_SIGNEXTOUT;
+
+ integer errcount = 0;
+
+ task clkcycle;
+ begin
+ #5;
+ CLK = ~CLK;
+ #10;
+ CLK = ~CLK;
+ #2;
+ if (REF_O !== UUT_O) begin
+ $display("ERROR at %1t: REF_O=%b UUT_O=%b DIFF=%b", $time, REF_O, UUT_O, REF_O ^ UUT_O);
+ errcount = errcount + 1;
+ end
+ if (REF_CO !== UUT_CO) begin
+ $display("ERROR at %1t: REF_CO=%b UUT_CO=%b", $time, REF_CO, UUT_CO);
+ errcount = errcount + 1;
+ end
+ if (REF_ACCUMCO !== UUT_ACCUMCO) begin
+ $display("ERROR at %1t: REF_ACCUMCO=%b UUT_ACCUMCO=%b", $time, REF_ACCUMCO, UUT_ACCUMCO);
+ errcount = errcount + 1;
+ end
+ if (REF_SIGNEXTOUT !== UUT_SIGNEXTOUT) begin
+ $display("ERROR at %1t: REF_SIGNEXTOUT=%b UUT_SIGNEXTOUT=%b", $time, REF_SIGNEXTOUT, UUT_SIGNEXTOUT);
+ errcount = errcount + 1;
+ end
+ #3;
+ end
+ endtask
+
+ initial begin
+ $dumpfile("test_dsp_model.vcd");
+ $dumpvars(0, testbench);
+
+ #2;
+ CLK = NEG_TRIGGER;
+ CE = 1;
+ {C, A, B, D} = 0;
+ {AHOLD, BHOLD, CHOLD, DHOLD} = 0;
+ {OLOADTOP, OLOADBOT} = 0;
+ {ADDSUBTOP, ADDSUBBOT} = 0;
+ {OHOLDTOP, OHOLDBOT} = 0;
+ {CI, ACCUMCI, SIGNEXTIN} = 0;
+
+ {IRSTTOP, IRSTBOT} = ~0;
+ {ORSTTOP, ORSTBOT} = ~0;
+
+ #3;
+ {IRSTTOP, IRSTBOT} = 0;
+ {ORSTTOP, ORSTBOT} = 0;
+
+ repeat (300) begin
+ clkcycle;
+
+ A = $urandom;
+ B = $urandom;
+ C = $urandom;
+ D = $urandom;
+
+ {AHOLD, BHOLD, CHOLD, DHOLD} = $urandom & $urandom & $urandom;
+ {OLOADTOP, OLOADBOT} = $urandom & $urandom & $urandom;
+ {ADDSUBTOP, ADDSUBBOT} = $urandom & $urandom & $urandom;
+ {OHOLDTOP, OHOLDBOT} = $urandom & $urandom & $urandom;
+ {CI, ACCUMCI, SIGNEXTIN} = $urandom & $urandom & $urandom;
+
+ {IRSTTOP, IRSTBOT} = $urandom & $urandom & $urandom;
+ {ORSTTOP, ORSTBOT} = $urandom & $urandom & $urandom;
+ end
+
+ if (errcount == 0) begin
+ $display("All tests passed.");
+ $finish;
+ end else begin
+ $display("Caught %1d errors.", errcount);
+ $stop;
+ end
+ end
+
+ SB_MAC16 #(
+ .NEG_TRIGGER (NEG_TRIGGER ),
+ .C_REG (C_REG ),
+ .A_REG (A_REG ),
+ .B_REG (B_REG ),
+ .D_REG (D_REG ),
+ .TOP_8x8_MULT_REG (TOP_8x8_MULT_REG ),
+ .BOT_8x8_MULT_REG (BOT_8x8_MULT_REG ),
+ .PIPELINE_16x16_MULT_REG1 (PIPELINE_16x16_MULT_REG1),
+ .PIPELINE_16x16_MULT_REG2 (PIPELINE_16x16_MULT_REG2),
+ .TOPOUTPUT_SELECT (TOPOUTPUT_SELECT ),
+ .TOPADDSUB_LOWERINPUT (TOPADDSUB_LOWERINPUT ),
+ .TOPADDSUB_UPPERINPUT (TOPADDSUB_UPPERINPUT ),
+ .TOPADDSUB_CARRYSELECT (TOPADDSUB_CARRYSELECT ),
+ .BOTOUTPUT_SELECT (BOTOUTPUT_SELECT ),
+ .BOTADDSUB_LOWERINPUT (BOTADDSUB_LOWERINPUT ),
+ .BOTADDSUB_UPPERINPUT (BOTADDSUB_UPPERINPUT ),
+ .BOTADDSUB_CARRYSELECT (BOTADDSUB_CARRYSELECT ),
+ .MODE_8x8 (MODE_8x8 ),
+ .A_SIGNED (A_SIGNED ),
+ .B_SIGNED (B_SIGNED )
+ ) ref (
+ .CLK (CLK ),
+ .CE (CE ),
+ .C (C ),
+ .A (A ),
+ .B (B ),
+ .D (D ),
+ .AHOLD (AHOLD ),
+ .BHOLD (BHOLD ),
+ .CHOLD (CHOLD ),
+ .DHOLD (DHOLD ),
+ .IRSTTOP (IRSTTOP ),
+ .IRSTBOT (IRSTBOT ),
+ .ORSTTOP (ORSTTOP ),
+ .ORSTBOT (ORSTBOT ),
+ .OLOADTOP (OLOADTOP ),
+ .OLOADBOT (OLOADBOT ),
+ .ADDSUBTOP (ADDSUBTOP ),
+ .ADDSUBBOT (ADDSUBBOT ),
+ .OHOLDTOP (OHOLDTOP ),
+ .OHOLDBOT (OHOLDBOT ),
+ .CI (CI ),
+ .ACCUMCI (ACCUMCI ),
+ .SIGNEXTIN (SIGNEXTIN ),
+ .O (REF_O ),
+ .CO (REF_CO ),
+ .ACCUMCO (REF_ACCUMCO ),
+ .SIGNEXTOUT (REF_SIGNEXTOUT)
+ );
+
+ SB_MAC16_UUT #(
+ .NEG_TRIGGER (NEG_TRIGGER ),
+ .C_REG (C_REG ),
+ .A_REG (A_REG ),
+ .B_REG (B_REG ),
+ .D_REG (D_REG ),
+ .TOP_8x8_MULT_REG (TOP_8x8_MULT_REG ),
+ .BOT_8x8_MULT_REG (BOT_8x8_MULT_REG ),
+ .PIPELINE_16x16_MULT_REG1 (PIPELINE_16x16_MULT_REG1),
+ .PIPELINE_16x16_MULT_REG2 (PIPELINE_16x16_MULT_REG2),
+ .TOPOUTPUT_SELECT (TOPOUTPUT_SELECT ),
+ .TOPADDSUB_LOWERINPUT (TOPADDSUB_LOWERINPUT ),
+ .TOPADDSUB_UPPERINPUT (TOPADDSUB_UPPERINPUT ),
+ .TOPADDSUB_CARRYSELECT (TOPADDSUB_CARRYSELECT ),
+ .BOTOUTPUT_SELECT (BOTOUTPUT_SELECT ),
+ .BOTADDSUB_LOWERINPUT (BOTADDSUB_LOWERINPUT ),
+ .BOTADDSUB_UPPERINPUT (BOTADDSUB_UPPERINPUT ),
+ .BOTADDSUB_CARRYSELECT (BOTADDSUB_CARRYSELECT ),
+ .MODE_8x8 (MODE_8x8 ),
+ .A_SIGNED (A_SIGNED ),
+ .B_SIGNED (B_SIGNED )
+ ) uut (
+ .CLK (CLK ),
+ .CE (CE ),
+ .C (C ),
+ .A (A ),
+ .B (B ),
+ .D (D ),
+ .AHOLD (AHOLD ),
+ .BHOLD (BHOLD ),
+ .CHOLD (CHOLD ),
+ .DHOLD (DHOLD ),
+ .IRSTTOP (IRSTTOP ),
+ .IRSTBOT (IRSTBOT ),
+ .ORSTTOP (ORSTTOP ),
+ .ORSTBOT (ORSTBOT ),
+ .OLOADTOP (OLOADTOP ),
+ .OLOADBOT (OLOADBOT ),
+ .ADDSUBTOP (ADDSUBTOP ),
+ .ADDSUBBOT (ADDSUBBOT ),
+ .OHOLDTOP (OHOLDTOP ),
+ .OHOLDBOT (OHOLDBOT ),
+ .CI (CI ),
+ .ACCUMCI (ACCUMCI ),
+ .SIGNEXTIN (SIGNEXTIN ),
+ .O (UUT_O ),
+ .CO (UUT_CO ),
+ .ACCUMCO (UUT_ACCUMCO ),
+ .SIGNEXTOUT (UUT_SIGNEXTOUT)
+ );
+endmodule
+
+module testbench_comb_8x8_A;
+ testbench #(
+ .NEG_TRIGGER (0),
+ .C_REG (0),
+ .A_REG (0),
+ .B_REG (0),
+ .D_REG (0),
+ .TOP_8x8_MULT_REG (0),
+ .BOT_8x8_MULT_REG (0),
+ .PIPELINE_16x16_MULT_REG1 (0),
+ .PIPELINE_16x16_MULT_REG2 (0),
+ .TOPOUTPUT_SELECT (2), // 0=P, 1=Q, 2=8x8, 3=16x16
+ .TOPADDSUB_LOWERINPUT (0), // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+ .TOPADDSUB_UPPERINPUT (0), // 0=Q, 1=C
+ .TOPADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI
+ .BOTOUTPUT_SELECT (2), // 0=R, 1=S, 2=8x8, 3=16x16
+ .BOTADDSUB_LOWERINPUT (0), // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+ .BOTADDSUB_UPPERINPUT (0), // 0=S, 1=D
+ .BOTADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI
+ .MODE_8x8 (0),
+ .A_SIGNED (0),
+ .B_SIGNED (0)
+ ) testbench ();
+endmodule
+
+module testbench_comb_8x8_B;
+ testbench #(
+ .NEG_TRIGGER (0),
+ .C_REG (0),
+ .A_REG (0),
+ .B_REG (0),
+ .D_REG (0),
+ .TOP_8x8_MULT_REG (0),
+ .BOT_8x8_MULT_REG (0),
+ .PIPELINE_16x16_MULT_REG1 (0),
+ .PIPELINE_16x16_MULT_REG2 (0),
+ .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16
+ .TOPADDSUB_LOWERINPUT (1), // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+ .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C
+ .TOPADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI
+ .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16
+ .BOTADDSUB_LOWERINPUT (1), // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+ .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D
+ .BOTADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI
+ .MODE_8x8 (0),
+ .A_SIGNED (0),
+ .B_SIGNED (0)
+ ) testbench ();
+endmodule
+
+module testbench_comb_16x16;
+ testbench #(
+ .NEG_TRIGGER (0),
+ .C_REG (0),
+ .A_REG (0),
+ .B_REG (0),
+ .D_REG (0),
+ .TOP_8x8_MULT_REG (0),
+ .BOT_8x8_MULT_REG (0),
+ .PIPELINE_16x16_MULT_REG1 (0),
+ .PIPELINE_16x16_MULT_REG2 (0),
+ .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16
+ .TOPADDSUB_LOWERINPUT (2), // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+ .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C
+ .TOPADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI
+ .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16
+ .BOTADDSUB_LOWERINPUT (2), // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+ .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D
+ .BOTADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI
+ .MODE_8x8 (0),
+ .A_SIGNED (0),
+ .B_SIGNED (0)
+ ) testbench ();
+endmodule
+
+module testbench_seq_16x16_A;
+ testbench #(
+ .NEG_TRIGGER (0),
+ .C_REG (1),
+ .A_REG (1),
+ .B_REG (1),
+ .D_REG (1),
+ .TOP_8x8_MULT_REG (1),
+ .BOT_8x8_MULT_REG (1),
+ .PIPELINE_16x16_MULT_REG1 (1),
+ .PIPELINE_16x16_MULT_REG2 (1),
+ .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16
+ .TOPADDSUB_LOWERINPUT (2), // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+ .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C
+ .TOPADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI
+ .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16
+ .BOTADDSUB_LOWERINPUT (2), // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+ .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D
+ .BOTADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI
+ .MODE_8x8 (0),
+ .A_SIGNED (0),
+ .B_SIGNED (0)
+ ) testbench ();
+endmodule
+
+module testbench_seq_16x16_B;
+ testbench #(
+ .NEG_TRIGGER (0),
+ .C_REG (1),
+ .A_REG (1),
+ .B_REG (1),
+ .D_REG (1),
+ .TOP_8x8_MULT_REG (1),
+ .BOT_8x8_MULT_REG (1),
+ .PIPELINE_16x16_MULT_REG1 (1),
+ .PIPELINE_16x16_MULT_REG2 (0),
+ .TOPOUTPUT_SELECT (1), // 0=P, 1=Q, 2=8x8, 3=16x16
+ .TOPADDSUB_LOWERINPUT (2), // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+ .TOPADDSUB_UPPERINPUT (0), // 0=Q, 1=C
+ .TOPADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI
+ .BOTOUTPUT_SELECT (1), // 0=R, 1=S, 2=8x8, 3=16x16
+ .BOTADDSUB_LOWERINPUT (2), // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+ .BOTADDSUB_UPPERINPUT (0), // 0=S, 1=D
+ .BOTADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI
+ .MODE_8x8 (0),
+ .A_SIGNED (0),
+ .B_SIGNED (0)
+ ) testbench ();
+endmodule