[wip] DSP48E1 sim model improvements
authorDavid Shah <dave@ds0.me>
Tue, 6 Aug 2019 17:47:18 +0000 (18:47 +0100)
committerDavid Shah <dave@ds0.me>
Tue, 6 Aug 2019 17:47:18 +0000 (18:47 +0100)
Signed-off-by: David Shah <dave@ds0.me>
techlibs/xilinx/cells_sim.v

index 9437a057b966c8405f341215e37b23584e65e02f..bc8a2d8f093076c5efb058e25030b31e01087a6e 100644 (file)
@@ -494,19 +494,35 @@ module DSP48E1 (
 `endif
     end
 
+    wire signed [29:0] A_muxed;
+    wire signed [17:0] B_muxed;
+
+    generate
+        if (A_INPUT == "CASCADE") assign A_muxed = ACIN;
+        else assign A_muxed = A;
+
+        if (B_INPUT == "CASCADE") assign B_muxed = BCIN;
+        else assign B_muxed = B;
+    endgenerate
+
     reg signed [29:0] Ar1, Ar2;
     reg signed [24:0] Dr;
     reg signed [17:0] Br1, Br2;
-    reg signed [47:0] Pr;
+    reg signed [47:0] Cr;
     reg        [4:0]  INMODEr;
+    reg        [6:0]  OPMODEr;
+    reg        [3:0]  ALUMODEr;
+    reg        [2:0]  CARRYINSELr;
+
     generate
+        // Configurable A register
         if (AREG == 2) begin
             always @(posedge CLK)
                 if (RSTA) begin
                     Ar1 <= 30'b0;
                     Ar2 <= 30'b0;
                 end else begin
-                    if (CEA1) Ar1 <= A;
+                    if (CEA1) Ar1 <= A_muxed;
                     if (CEA2) Ar2 <= Ar1;
                 end
         end else if (AREG == 1) begin
@@ -515,21 +531,22 @@ module DSP48E1 (
                     Ar1 <= 30'b0;
                     Ar2 <= 30'b0;
                 end else begin
-                    if (CEA1) Ar1 <= A;
-                    if (CEA2) Ar2 <= A;
+                    if (CEA1) Ar1 <= A_muxed;
+                    if (CEA2) Ar2 <= A_muxed;
                 end
         end else begin
-            always @* Ar1 <= A;
-            always @* Ar2 <= A;
+            always @* Ar1 <= A_muxed;
+            always @* Ar2 <= A_muxed;
         end
 
+        // Configurable A register
         if (BREG == 2) begin
             always @(posedge CLK)
                 if (RSTB) begin
                     Br1 <= 18'b0;
                     Br2 <= 18'b0;
                 end else begin
-                    if (CEB1) Br1 <= B;
+                    if (CEB1) Br1 <= B_muxed;
                     if (CEB2) Br2 <= Br1;
                 end
         end else if (AREG == 1) begin
@@ -538,21 +555,41 @@ module DSP48E1 (
                     Br1 <= 18'b0;
                     Br2 <= 18'b0;
                 end else begin
-                    if (CEB1) Br1 <= B;
-                    if (CEB2) Br2 <= B;
+                    if (CEB1) Br1 <= B_muxed;
+                    if (CEB2) Br2 <= B_muxed;
                 end
         end else begin
-            always @* Br1 <= B;
-            always @* Br2 <= B;
+            always @* Br1 <= B_muxed;
+            always @* Br2 <= B_muxed;
         end
 
+        // C and D registers
+        if (CREG == 1) begin always @(posedge CLK) if (RSTC) Cr <= 48'b0; else if (CEC) Cr <= D; end
+        else           always @* Cr <= C;
+
         if (DREG == 1) begin always @(posedge CLK) if (RSTD) Dr <= 25'b0; else if (CED) Dr <= D; end
         else           always @* Dr <= D;
 
+        // Control registers
         if (INMODEREG == 1) begin always @(posedge CLK) if (RSTINMODE) INMODEr <= 5'b0; else if (CEINMODE) INMODEr <= INMODE; end
         else           always @* INMODEr <= INMODE;
+        if (OPMODEREG == 1) begin always @(posedge CLK) if (RSTCTRL) OPMODEr <= 7'b0; else if (CECTRL) OPMODEr <= OPMODE; end
+        else           always @* OPMODEr <= OPMODE;
+        if (ALUMODEREG == 1) begin always @(posedge CLK) if (RSTALUMODE) ALUMODEr <= 4'b0; else if (CEALUMODE) ALUMODEr <= ALUMODE; end
+        else           always @* ALUMODEr <= ALUMODE;
+        if (CARRYINSELREG == 1) begin always @(posedge CLK) if (RSTCTRL) CARRYINSELr <= 3'b0; else if (CECTRL) CARRYINSELr <= CARRYINSEL; end
+        else           always @* CARRYINSELr <= CARRYINSEL;
+    endgenerate
+
+    // A and B cascsde
+    generate
+        if (ACASCREG == 1 && AREG == 2) assign ACOUT = Ar1;
+        else assign ACOUT = Ar2;
+        if (BCASCREG == 1 && BREG == 2) assign BCOUT = Br1;
+        else assign BCOUT = Br2;
     endgenerate
 
+    // A/D input selection and pre-adder
     wire signed [29:0] Ar12_muxed = INMODEr[0] ? Ar1 : Ar2;
     wire signed [24:0] Ar12_gated = INMODEr[1] ? 25'b0 : Ar12_muxed;
     wire signed [24:0] Dr_gated   = INMODEr[2] ? Dr : 25'b0;
@@ -564,31 +601,91 @@ module DSP48E1 (
         else            always @* ADr <= AD_result;
     endgenerate
 
+    // 25x18 multiplier
     wire signed [24:0] A_MULT;
-    wire signed [24:0] B_MULT = INMODEr[4] ? Br1 : Br2;
+    wire signed [17:0] B_MULT = INMODEr[4] ? Br1 : Br2;
     generate
         if (USE_DPORT == "TRUE") assign A_MULT = ADr;
         else assign A_MULT = Ar12_gated;
     endgenerate
 
+    wire signed [42:0] M = A_MULT * B_MULT;
+    reg  signed [42:0] Mr;
+
+    // Multiplier result register
+    generate
+        if (MREG == 1) begin always @(posedge CLK) if (RSTM) Mr <= 43'b0; else if (CEM) Mr <= M; end
+        else           always @* Mr <= M;
+    endgenerate
+
+    // X, Y and Z ALU inputs
+    reg signed [47:0] X, Y, Z;
+
+    always @* begin
+        // X multiplexer
+        case (OPMODEr[1:0])
+            2'b00: X = 48'b0;
+            2'b01: X = $signed(M);
+`ifdef __ICARUS__
+                if (OPMODEr[3:2] != 2'b01) $fatal(1, "OPMODEr[3:2] must be 2'b01 when OPMODEr[1:0] is 2'b01");
+`endif
+            2'b10: X = P;
+`ifdef __ICARUS__
+                if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[1:0] is 2'b10");
+`endif
+            2'b11: X = $signed({Ar2, Br2});
+            default: X = 48'bx;
+        endcase
+
+        // Y multiplexer
+        case (OPMODEr[3:2])
+            2'b00: Y = 48'b0;
+            2'b01: Y = 48'b0; // FIXME: more accurate partial product modelling?
+`ifdef __ICARUS__
+                if (OPMODEr[1:0] != 2'b01) $fatal(1, "OPMODEr[1:0] must be 2'b01 when OPMODEr[3:2] is 2'b01");
+`endif
+            2'b10: Y = {48{1'b1}};
+            2'b11: Y = C;
+            default: Y = 48'bx;
+        endcase
+
+        // Z multiplexer
+        case (OPMODEr[6:4])
+            3'b000: Z = 48'b0;
+            3'b001: Z = PCIN;
+            3'b010: Z = P;
+`ifdef __ICARUS__
+                if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[6:4] i0s 3'b010");
+`endif
+            3'b011: Z = C;
+            3'b100: Z = P;
+`ifdef __ICARUS__
+                if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[6:4] is 3'b100");
+                if (OPMODEr[3:0] != 4'b1000) $fatal(1, "OPMODEr[3:0] must be 4'b1000 when OPMODEr[6:4] i0s 3'b100");
+`endif
+            3'b101: Z = $signed(PCIN[47:17]);
+            3'b110: Z = $signed(P[47:17]);
+            default: Z = 48'bx;
+        endcase
+    end
+
+    wire alu_cin = 1'b0; // FIXME*
+
+    wire [47:0] Z_muxinv = ALUMODEr[0] ? ~Z : Z;
+    wire [47:0] xor_xyz = X ^ Y ^ Z_muxinv;
+    wire [47:0] maj_xyz = (X & Y) | (X & Z) | (X & Y);
+
+    
+
     always @* begin
-        Pr <= {48{1'bx}};
 `ifdef __ICARUS__
-        if (INMODE != 4'b0000)      $fatal(1, "Unsupported INMODE value");
-        if (ALUMODE != 4'b0000)     $fatal(1, "Unsupported ALUMODE value");
-        if (OPMODE != 7'b000101)    $fatal(1, "Unsupported OPMODE value");
         if (CARRYINSEL != 3'b000)   $fatal(1, "Unsupported CARRYINSEL value");
-        if (ACIN != 30'b0)          $fatal(1, "Unsupported ACIN value");
-        if (BCIN != 18'b0)          $fatal(1, "Unsupported BCIN value");
-        if (PCIN != 48'b0)          $fatal(1, "Unsupported PCIN value");
-        if (CARRYIN != 1'b0)        $fatal(1, "Unsupported CARRYIN value");
 `endif
-        Pr[42:0] <= A_MULT * B_MULT;
     end
 
     generate
-        if (PREG == 1) begin always @(posedge CLK) if (RSTP) P <= 48'b0; else if (CEP) P <= Pr; end
-        else           always @* P <= Pr;
+        if (PREG == 1) begin always @(posedge CLK) if (RSTP) P <= 48'b0; else if (CEP) P <= Mr; end
+        else           always @* P <= Mr;
     endgenerate
 
 endmodule