);
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,
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 IRSTTOP) 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]}}, iA[15: 8]} : iA[15: 8];
+ assign Al = A_SIGNED ? {{8{iA[ 7]}}, iA[ 7: 0]} : iA[15: 8];
+ assign Bh = B_SIGNED ? {{8{iB[15]}}, iB[15: 8]} : iB[15: 8];
+ assign Bl = B_SIGNED ? {{8{iB[ 7]}}, iB[ 7: 0]} : iB[15: 8];
+ 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
+ reg [31:0] P;
+ always @* begin
+ P = iG[7:0];
+ P = P + (iG[15:8] + iK[7:0]) << 8;
+ P = P + (iK[15:8] + iJ[7:0]) << 16;
+ P = P + (iJ[15:8] + iF[7:0]) << 24;
+ end
+ assign iL = P;
+
+ // Reg H
+ reg [15: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[31:16];
+ 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 : iQ[15:0];
+ 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 (!OHOLDTOP) 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
--- /dev/null
+[*]
+[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI
+[*] Tue Feb 19 13:33:31 2019
+[*]
+[dumpfile] "/home/clifford/Work/yosys/techlibs/ice40/tests/test_dsp_model.vcd"
+[dumpfile_mtime] "Tue Feb 19 13:29:34 2019"
+[dumpfile_size] 119605
+[savefile] "/home/clifford/Work/yosys/techlibs/ice40/tests/test_dsp_model.gtkw"
+[timestart] 0
+[size] 1850 1362
+[pos] 1816 32
+*-16.399944 42300 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[sst_width] 223
+[signals_width] 142
+[sst_expanded] 1
+[sst_vpaned_height] 420
+@28
+testbench.CLK
+testbench.CE
+@200
+-
+@28
+testbench.REF_ACCUMCO
+testbench.UUT_ACCUMCO
+@200
+-
+@28
+testbench.REF_CO
+testbench.UUT_CO
+@200
+-
+@22
+testbench.REF_O[31:0]
+testbench.UUT_O[31:0]
+@200
+-
+@28
+testbench.REF_SIGNEXTOUT
+testbench.UUT_SIGNEXTOUT
+@200
+-
+@22
+testbench.A[15:0]
+testbench.B[15:0]
+testbench.C[15:0]
+testbench.D[15:0]
+@200
+-
+@28
+testbench.AHOLD
+testbench.BHOLD
+testbench.CHOLD
+testbench.DHOLD
+@200
+-
+@28
+testbench.SIGNEXTIN
+testbench.ACCUMCI
+testbench.CI
+@200
+-
+@28
+testbench.ADDSUBTOP
+testbench.ADDSUBBOT
+@200
+-
+@28
+testbench.IRSTTOP
+testbench.IRSTBOT
+@200
+-
+@29
+testbench.OHOLDTOP
+@28
+testbench.OHOLDBOT
+@200
+-
+@28
+testbench.OLOADTOP
+testbench.OLOADBOT
+@200
+-
+@28
+testbench.ORSTTOP
+testbench.ORSTBOT
+[pattern_trace] 1
+[pattern_trace] 0
--- /dev/null
+#!/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
+iverilog -s testbench -o test_dsp_model test_dsp_model.v test_dsp_model_uut.v test_dsp_model_ref.v
+./test_dsp_model
--- /dev/null
+`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 = 2;
+ parameter [0:0] TOPADDSUB_UPPERINPUT = 1;
+ parameter [1:0] TOPADDSUB_CARRYSELECT = 2;
+ parameter [1:0] BOTOUTPUT_SELECT = 0;
+ parameter [1:0] BOTADDSUB_LOWERINPUT = 2;
+ parameter [0:0] BOTADDSUB_UPPERINPUT = 1;
+ parameter [1:0] BOTADDSUB_CARRYSELECT = 2;
+ 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", $time, 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);
+
+ #5;
+ CLK = NEG_TRIGGER;
+ CE = 1;
+ {C, A, B, D} = 0;
+ {AHOLD, BHOLD, CHOLD, DHOLD} = 0;
+ {IRSTTOP, IRSTBOT} = 0;
+ {ORSTTOP, ORSTBOT} = 0;
+ {OLOADTOP, OLOADBOT} = 0;
+ {ADDSUBTOP, ADDSUBBOT} = 0;
+ {OHOLDTOP, OHOLDBOT} = 0;
+ {CI, ACCUMCI, SIGNEXTIN} = 0;
+
+ // C = 10;
+ // A = 15;
+ // B = 22;
+ // D = 27;
+
+ repeat (10) clkcycle;
+
+ if (errcount == 0) begin
+ $display("All tests passed.");
+ end else begin
+ $display("Caught %1d errors.", errcount);
+ 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