ecp5: Adding basic cells_sim and mapper for LUTs up to LUT7
authorDavid Shah <davey1576@gmail.com>
Fri, 13 Jul 2018 11:27:24 +0000 (13:27 +0200)
committerDavid Shah <davey1576@gmail.com>
Fri, 13 Jul 2018 11:27:24 +0000 (13:27 +0200)
Signed-off-by: David Shah <davey1576@gmail.com>
techlibs/ecp5/cells_map.v [new file with mode: 0644]
techlibs/ecp5/cells_sim.v [new file with mode: 0644]

diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v
new file mode 100644 (file)
index 0000000..399697c
--- /dev/null
@@ -0,0 +1,86 @@
+`ifndef NO_LUT
+module \$lut (A, Y);
+    parameter WIDTH = 0;
+    parameter LUT = 0;
+
+    input [WIDTH-1:0] A;
+    output Y;
+
+    generate
+        if (WIDTH == 1) begin
+            LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y),
+                .A(A[0]), .B(1'b0), .C(1'b0), .D(1'b0));
+        end else
+        if (WIDTH == 2) begin
+            LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y),
+                .A(A[0]), .B(A[1]), .C(1'b0), .D(1'b0));
+        end else
+        if (WIDTH == 3) begin
+            LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y),
+                .A(A[0]), .B(A[1]), .C(A[2]), .D(1'b0));
+        end else
+        if (WIDTH == 4) begin
+            LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y),
+                .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+        `ifndef NO_PFUMUX
+        end else
+        if (WIDTH == 5) begin
+            wire f0, f1;
+            LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0),
+                .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+            LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1),
+                .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+            PFUMX mux5(.ALUT(f1), .BLUT(f0), .SD(A[4]), .Z(Y));
+        end else
+        if (WIDTH == 6) begin
+            wire f0, f1, f2, f3, g0, g1;
+            LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0),
+                .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+            LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1),
+                .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+            LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2),
+                .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+            LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3),
+                .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+            PFUMX mux50(.ALUT(f1), .BLUT(f0), .SD(A[4]), .Z(g0));
+            PFUMX mux51(.ALUT(f3), .BLUT(f2), .SD(A[4]), .Z(g1));
+            L6MUX21 mux6 (.D0(g0), .D1(g1), .SD(A[5]), .Z(Y));
+        end else
+        if (WIDTH == 7) begin
+            wire f0, f1, f2, f3, f4, f5, f6, f7, g0, g1, g2, g3, h0, h1;
+            LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0),
+                .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+            LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1),
+                .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+            LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2),
+                .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+            LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3),
+                .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+            LUT4 #(.INIT(LUT[79:64])) lut4 (.Z(f4),
+                .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+            LUT4 #(.INIT(LUT[95:80])) lut5 (.Z(f5),
+                .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+            LUT4 #(.INIT(LUT[111: 96])) lut6 (.Z(f6),
+                .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+            LUT4 #(.INIT(LUT[127:112])) lut7 (.Z(f7),
+                .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+            PFUMX mux50(.ALUT(f1), .BLUT(f0), .SD(A[4]), .Z(g0));
+            PFUMX mux51(.ALUT(f3), .BLUT(f2), .SD(A[4]), .Z(g1));
+            PFUMX mux52(.ALUT(f5), .BLUT(f4), .SD(A[4]), .Z(g2));
+            PFUMX mux53(.ALUT(f7), .BLUT(f6), .SD(A[4]), .Z(g3));
+            L6MUX21 mux60 (.D0(g0), .D1(g1), .SD(A[5]), .Z(h0));
+            L6MUX21 mux61 (.D0(g2), .D1(g3), .SD(A[5]), .Z(h1));
+            L6MUX21 mux7  (.D0(h0), .D1(h1), .SD(A[6]), .Z(Y));
+        `endif
+        end else begin
+            wire _TECHMAP_FAIL_ = 1;
+        end
+    endgenerate
+endmodule
+`endif
diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v
new file mode 100644 (file)
index 0000000..5400621
--- /dev/null
@@ -0,0 +1,387 @@
+// ---------------------------------------
+
+module LUT4(input A, B, C, D, output Z);
+       parameter [15:0] INIT = 16'h0000;
+       assign Z = INIT[{D, C, B, A}];
+endmodule
+
+// ---------------------------------------
+
+module L6MUX21 (input D0, D1, SD, output Z);
+       assign Z = SD ? D1 : D0;
+endmodule
+
+// ---------------------------------------
+
+module CCU2C(input CIN, A0, B0, C0, D0, A1, B1, C1, D1,
+                  output S0, S1, COUT);
+
+       parameter [15:0] INIT0 = 16'h0000;
+       parameter [15:0] INIT1 = 16'h0000;
+       parameter INJECT1_0 = "YES";
+       parameter INJECT1_1 = "YES";
+
+       // First half
+       wire LUT4_0 = INIT0[{D0, C0, B0, A0}];
+       wire LUT2_0 = INIT0[{2'b00, B0, A0}];
+
+       wire gated_cin_0 = (INJECT1_0 == "YES") ? 1'b0 : CIN;
+       assign S0 = LUT4_0 ^ gated_cin_0;
+
+       wire gated_lut2_0 = (INJECT1_0 == "YES") ? 1'b0 : LUT2_0;
+       wire cout_0 = (~LUT4_0 & gated_lut2_0) | (LUT4_0 & CIN);
+
+       // Second half
+       wire LUT4_1 = INIT1[{D1, C1, B1, A1}];
+       wire LUT2_1 = INIT1[{2'b00, B1, A1}];
+
+       wire gated_cin_1 = (INJECT1_1 == "YES") ? 1'b0 : cout_0;
+       assign S1 = LUT4_1 ^ gated_cin_1;
+
+       wire gated_lut2_1 = (INJECT1_1 == "YES") ? 1'b0 : LUT2_1;
+       assign COUT = (~LUT4_1 & gated_lut2_1) | (LUT4_1 & cout_0);
+
+endmodule
+
+// ---------------------------------------
+
+module TRELLIS_RAM16X2 (
+       input DI0, DI1,
+       input WAD0, WAD1, WAD2, WAD3,
+       input WRE, WCK,
+       input RAD0, RAD1, RAD2, RAD3,
+       output DO0, DO1
+);
+  parameter WCKMUX = "WCK";
+       parameter WREMUX = "WRE";
+       parameter INITVAL_0 = 16'h0000;
+       parameter INITVAL_1 = 16'h0000;
+
+       reg [1:0] mem[15:0];
+
+       integer i;
+       initial begin
+               for (i = 0; i < 16; i = i + 1)
+                       mem[i] <= {INITVAL_1[i], INITVAL_0[i]};
+       end
+
+       wire muxwck = (WCKMUX == "INV") ? ~WCK : WCK;
+
+       wire muxwre = (WREMUX == "1") ? 1'b1 :
+                                                         (WREMUX == "0") ? 1'b0 :
+                                                         (WREMUX == "INV") ? ~WRE :
+                                                         WRE;
+
+       always @(posedge muxwck)
+               if (muxwre)
+                       mem[{WAD3, WAD2, WAD1, WAD0}] <= {DI1, DI0};
+
+       assign {DO1, DO0} = mem[{RAD3, RAD2, RAD1, RAD0}];
+endmodule
+
+// ---------------------------------------
+
+module PFUMX (input ALUT, BLUT, C0, output Z);
+       assign Z = C0 ? ALUT : BLUT;
+endmodule
+
+// ---------------------------------------
+
+module DPR16X4C (
+               input [3:0] DI,
+               input WCK, WRE,
+               input [3:0] RAD,
+               input [3:0] WAD,
+               output [3:0] DO
+);
+       // For legacy Lattice compatibility, INITIVAL is a hex
+       // string rather than a numeric parameter
+       parameter INITVAL = "0x0000000000000000";
+
+       function [63:0] convert_initval;
+               input [143:0] hex_initval;
+               reg done;
+               reg [63:0] temp;
+               reg [7:0] char;
+               integer i;
+               begin
+                       done = 1'b0;
+                       temp = 0;
+                       for (i = 0; i < 16; i = i + 1) begin
+                               if (!done) begin
+                                       char = hex_initval[8*i +: 8];
+                                       if (char == "x") begin
+                                               done = 1'b1;
+                                       end else begin
+                                               if (char >= "0" && char <= "9")
+                                                       temp[4*i +: 4] = char - "0";
+                                               else if (char >= "A" && char <= "F")
+                                                       temp[4*i +: 4] = 10 + char - "A";
+                                               else if (char >= "a" && char <= "f")
+                                                       temp[4*i +: 4] = 10 + char - "a";
+                                       end
+                               end
+                       end
+                       convert_initval = temp;
+               end
+       endfunction
+
+       localparam conv_initval = convert_initval(INITVAL);
+
+       reg [3:0] ram[0:15];
+       integer i;
+       initial begin
+               for (i = 0; i < 15; i = i + 1) begin
+                       ram[i] = conv_initval[4*i +: 4];
+               end
+       end
+
+       always @(posedge WCK)
+               if (WRE)
+                       ram[WAD] <= DI;
+
+       assign DO = ram[RAD];
+
+endmodule
+
+// ---------------------------------------
+
+module TRELLIS_FF(input CLK, LSR, CE, DI, output reg Q);
+       parameter GSR = "ENABLED";
+       parameter [127:0] CEMUX = "1";
+       parameter CLKMUX = "CLK";
+       parameter LSRMUX = "LSR";
+       parameter SRMODE = "LSR_OVER_CE";
+       parameter REGSET = "RESET";
+
+       wire muxce = (CEMUX == "1") ? 1'b1 :
+                    (CEMUX == "0") ? 1'b0 :
+                                                        (CEMUX == "INV") ? ~CE :
+                                                        CE;
+
+       wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR;
+       wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK;
+
+       wire srval = (REGSET == "SET") ? 1'b1 : 1'b0;
+
+       initial Q = 1'b0;
+
+       generate
+               if (SRMODE == "ASYNC") begin
+                       always @(posedge muxclk, posedge muxlsr)
+                               if (muxlsr)
+                                       Q <= srval;
+                               else
+                                       Q <= DI;
+               end else begin
+                       always @(posedge muxclk)
+                               if (muxlsr)
+                                       Q <= srval;
+                               else
+                                       Q <= DI;
+               end
+       endgenerate
+endmodule
+
+// ---------------------------------------
+
+module OBZ(input I, T, output O);
+assign O = T ? 1'bz : I;
+endmodule
+
+// ---------------------------------------
+
+module IB(input I, output O);
+assign O = I;
+endmodule
+
+// ---------------------------------------
+
+module TRELLIS_IO(
+       inout B,
+       input I,
+       input T,
+       output O
+);
+       parameter DIR = "INPUT";
+
+       generate
+               if (DIR == "INPUT") begin
+                       assign B = 1'bz;
+                       assign O = B;
+               end else if (DIR == "OUTPUT") begin
+                       assign B = T ? 1'bz : I;
+                       assign O = 1'bx;
+               end else if (DIR == "INOUT") begin
+                       assign B = T ? 1'bz : I;
+                       assign O = B;
+               end else begin
+                       ERROR_UNKNOWN_IO_MODE error();
+               end
+       endgenerate
+
+endmodule
+
+// ---------------------------------------
+
+module OB(input I, output O);
+assign O = I;
+endmodule
+
+// ---------------------------------------
+
+module BB(input I, T, output O, inout B);
+assign B = T ? 1'bz : I;
+assign O = B;
+endmodule
+
+// ---------------------------------------
+
+module INV(input A, output Z);
+       assign Z = !A;
+endmodule
+
+// ---------------------------------------
+
+module TRELLIS_SLICE(
+       input A0, B0, C0, D0,
+       input A1, B1, C1, D1,
+       input M0, M1,
+       input FCI, FXA, FXB,
+
+       input CLK, LSR, CE,
+       input DI0, DI1,
+
+       input WD0, WD1,
+       input WAD0, WAD1, WAD2, WAD3,
+       input WRE, WCK,
+
+       output F0, Q0,
+       output F1, Q1,
+       output FCO, OFX0, OFX1,
+
+       output WDO0, WDO1, WDO2, WDO3,
+       output WADO0, WADO1, WADO2, WADO3
+);
+
+       parameter MODE = "LOGIC";
+       parameter GSR = "ENABLED";
+       parameter SRMODE = "LSR_OVER_CE";
+       parameter [127:0] CEMUX = "1";
+       parameter CLKMUX = "CLK";
+       parameter LSRMUX = "LSR";
+       parameter LUT0_INITVAL = 16'h0000;
+       parameter LUT1_INITVAL = 16'h0000;
+       parameter REG0_SD = "0";
+       parameter REG1_SD = "0";
+       parameter REG0_REGSET = "RESET";
+       parameter REG1_REGSET = "RESET";
+       parameter [127:0] CCU2_INJECT1_0 = "NO";
+       parameter [127:0] CCU2_INJECT1_1 = "NO";
+       parameter WREMUX = "WRE";
+
+       function [15:0] permute_initval;
+               input [15:0] initval;
+               integer i;
+               begin
+                       for (i = 0; i < 16; i = i + 1) begin
+                               permute_initval[{i[0], i[2], i[1], i[3]}] = initval[i];
+                       end
+               end
+       endfunction
+
+       generate
+               if (MODE == "LOGIC") begin
+                       // LUTs
+                       LUT4 #(
+                               .INIT(LUT0_INITVAL)
+                       ) lut4_0 (
+                               .A(A0), .B(B0), .C(C0), .D(D0),
+                               .Z(F0)
+                       );
+                       LUT4 #(
+                               .INIT(LUT1_INITVAL)
+                       ) lut4_1 (
+                               .A(A1), .B(B1), .C(C1), .D(D1),
+                               .Z(F1)
+                       );
+                       // LUT expansion muxes
+                       PFUMX lut5_mux (.ALUT(F1), .BLUT(F0), .C0(M0), .Z(OFX0));
+                       L6MUX21 lutx_mux (.D0(FXA), .D1(FXB), .SD(M1), .Z(OFX1));
+               end else if (MODE == "CCU2") begin
+                       CCU2C #(
+                               .INIT0(LUT0_INITVAL),
+                               .INIT1(LUT1_INITVAL),
+                               .INJECT1_0(CCU2_INJECT1_0),
+                               .INJECT1_1(CCU2_INJECT1_1)
+                 ) ccu2c_i (
+                               .CIN(FCI),
+                               .A0(A0), .B0(B0), .C0(C0), .D0(D0),
+                               .A1(A1), .B1(B1), .C1(C1), .D1(D1),
+                               .S0(F0), .S1(F1),
+                               .COUT(FCO)
+                       );
+               end else if (MODE == "RAMW") begin
+                       assign WDO0 = C1;
+                       assign WDO1 = A1;
+                       assign WDO2 = D1;
+                       assign WDO3 = B1;
+                       assign WADO0 = D0;
+                       assign WADO1 = B0;
+                       assign WADO2 = C0;
+                       assign WADO3 = A0;
+               end else if (MODE == "DPRAM") begin
+                       TRELLIS_RAM16X2 #(
+                               .INITVAL_0(permute_initval(LUT0_INITVAL)),
+                               .INITVAL_1(permute_initval(LUT1_INITVAL)),
+                               .WREMUX(WREMUX)
+                       ) ram_i (
+                               .DI0(WD0), .DI1(WD1),
+                               .WAD0(WAD0), .WAD1(WAD1), .WAD2(WAD2), .WAD3(WAD3),
+                               .WRE(WRE), .WCK(WCK),
+                               .RAD0(D0), .RAD1(B0), .RAD2(C0), .RAD3(A0),
+                               .DO0(F0), .DO1(F1)
+                       );
+                       // TODO: confirm RAD and INITVAL ordering
+                       // DPRAM mode contract?
+                       always @(*) begin
+                               assert(A0==A1);
+                               assert(B0==B1);
+                               assert(C0==C1);
+                               assert(D0==D1);
+                       end
+               end else begin
+                       ERROR_UNKNOWN_SLICE_MODE error();
+               end
+       endgenerate
+
+       // FF input selection muxes
+       wire muxdi0 = (REG0_SD == "1") ? DI0 : M0;
+       wire muxdi1 = (REG1_SD == "1") ? DI1 : M1;
+       // Flipflops
+       TRELLIS_FF #(
+               .GSR(GSR),
+               .CEMUX(CEMUX),
+               .CLKMUX(CLKMUX),
+               .LSRMUX(LSRMUX),
+               .SRMODE(SRMODE),
+               .REGSET(REG0_REGSET)
+       ) ff_0 (
+               .CLK(CLK), .LSR(LSR), .CE(CE),
+               .DI(muxdi0),
+               .Q(Q0)
+       );
+       TRELLIS_FF #(
+               .GSR(GSR),
+               .CEMUX(CEMUX),
+               .CLKMUX(CLKMUX),
+               .LSRMUX(LSRMUX),
+               .SRMODE(SRMODE),
+               .REGSET(REG1_REGSET)
+       ) ff_1 (
+               .CLK(CLK), .LSR(LSR), .CE(CE),
+               .DI(muxdi1),
+               .Q(Q1)
+       );
+endmodule
+