|  | // Copyright 2020-2022 F4PGA Authors | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  | // | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  | (* abc9_box, lib_whitebox *) | 
|  | module adder( | 
|  | output sumout, | 
|  | output cout, | 
|  | input a, | 
|  | input b, | 
|  | input cin | 
|  | ); | 
|  | assign sumout = a ^ b ^ cin; | 
|  | assign cout = (a & b) | ((a | b) & cin); | 
|  |  | 
|  | endmodule | 
|  |  | 
|  |  | 
|  |  | 
|  | (* abc9_lut=1, lib_whitebox *) | 
|  | module frac_lut6( | 
|  | input [0:5] in, | 
|  | output [0:3] lut4_out, | 
|  | output [0:1] lut5_out, | 
|  | output lut6_out | 
|  | ); | 
|  | parameter [0:63] LUT = 0; | 
|  | // Effective LUT input | 
|  | wire [0:5] li = in; | 
|  |  | 
|  | // Output function | 
|  | wire [0:31] s1 = li[0] ? | 
|  | {LUT[0] , LUT[2] , LUT[4] , LUT[6] , LUT[8] , LUT[10], LUT[12], LUT[14], | 
|  | LUT[16], LUT[18], LUT[20], LUT[22], LUT[24], LUT[26], LUT[28], LUT[30], | 
|  | LUT[32], LUT[34], LUT[36], LUT[38], LUT[40], LUT[42], LUT[44], LUT[46], | 
|  | LUT[48], LUT[50], LUT[52], LUT[54], LUT[56], LUT[58], LUT[60], LUT[62]}: | 
|  | {LUT[1] , LUT[3] , LUT[5] , LUT[7] , LUT[9] , LUT[11], LUT[13], LUT[15], | 
|  | LUT[17], LUT[19], LUT[21], LUT[23], LUT[25], LUT[27], LUT[29], LUT[31], | 
|  | LUT[33], LUT[35], LUT[37], LUT[39], LUT[41], LUT[43], LUT[45], LUT[47], | 
|  | LUT[49], LUT[51], LUT[53], LUT[55], LUT[57], LUT[59], LUT[61], LUT[63]}; | 
|  |  | 
|  | wire [0:15] s2 = li[1] ? | 
|  | {s1[0] , s1[2] , s1[4] , s1[6] , s1[8] , s1[10], s1[12], s1[14], | 
|  | s1[16], s1[18], s1[20], s1[22], s1[24], s1[26], s1[28], s1[30]}: | 
|  | {s1[1] , s1[3] , s1[5] , s1[7] , s1[9] , s1[11], s1[13], s1[15], | 
|  | s1[17], s1[19], s1[21], s1[23], s1[25], s1[27], s1[29], s1[31]}; | 
|  |  | 
|  | wire [0:7] s3 = li[2] ? | 
|  | {s2[0], s2[2], s2[4], s2[6], s2[8], s2[10], s2[12], s2[14]}: | 
|  | {s2[1], s2[3], s2[5], s2[7], s2[9], s2[11], s2[13], s2[15]}; | 
|  |  | 
|  | wire [0:3] s4 = li[3] ? {s3[0], s3[2], s3[4], s3[6]}: | 
|  | {s3[1], s3[3], s3[5], s3[7]}; | 
|  |  | 
|  | wire [0:1] s5 = li[4] ? {s4[0], s4[2]} : {s4[1], s4[3]}; | 
|  |  | 
|  | assign lut4_out[0] = s4[0]; | 
|  | assign lut4_out[1] = s4[1]; | 
|  | assign lut4_out[2] = s4[2]; | 
|  | assign lut4_out[3] = s4[3]; | 
|  |  | 
|  | assign lut5_out[0] = s5[0]; | 
|  | assign lut5_out[1] = s5[1]; | 
|  |  | 
|  | assign lut6_out = li[5] ? s5[0] : s5[1]; | 
|  |  | 
|  | endmodule | 
|  |  | 
|  | (* abc9_flop, lib_whitebox *) | 
|  | module dff( | 
|  | output reg Q, | 
|  | input D, | 
|  | (* clkbuf_sink *) | 
|  | (* invertible_pin = "IS_C_INVERTED" *) | 
|  | input C | 
|  | ); | 
|  | parameter [0:0] INIT = 1'b0; | 
|  | parameter [0:0] IS_C_INVERTED = 1'b0; | 
|  | initial Q = INIT; | 
|  | case(|IS_C_INVERTED) | 
|  | 1'b0: | 
|  | always @(posedge C) | 
|  | Q <= D; | 
|  | 1'b1: | 
|  | always @(negedge C) | 
|  | Q <= D; | 
|  | endcase | 
|  | endmodule | 
|  |  | 
|  | (* abc9_flop, lib_whitebox *) | 
|  | module dffr( | 
|  | output reg Q, | 
|  | input D, | 
|  | input R, | 
|  | (* clkbuf_sink *) | 
|  | (* invertible_pin = "IS_C_INVERTED" *) | 
|  | input C | 
|  | ); | 
|  | parameter [0:0] INIT = 1'b0; | 
|  | parameter [0:0] IS_C_INVERTED = 1'b0; | 
|  | initial Q = INIT; | 
|  | case(|IS_C_INVERTED) | 
|  | 1'b0: | 
|  | always @(posedge C or posedge R) | 
|  | if (R) | 
|  | Q <= 1'b0; | 
|  | else | 
|  | Q <= D; | 
|  | 1'b1: | 
|  | always @(negedge C or posedge R) | 
|  | if (R) | 
|  | Q <= 1'b0; | 
|  | else | 
|  | Q <= D; | 
|  | endcase | 
|  | endmodule | 
|  |  | 
|  | (* abc9_flop, lib_whitebox *) | 
|  | module dffre( | 
|  | output reg Q, | 
|  | input D, | 
|  | input R, | 
|  | input E, | 
|  | (* clkbuf_sink *) | 
|  | (* invertible_pin = "IS_C_INVERTED" *) | 
|  | input C | 
|  | ); | 
|  | parameter [0:0] INIT = 1'b0; | 
|  | parameter [0:0] IS_C_INVERTED = 1'b0; | 
|  | initial Q = INIT; | 
|  | case(|IS_C_INVERTED) | 
|  | 1'b0: | 
|  | always @(posedge C or posedge R) | 
|  | if (R) | 
|  | Q <= 1'b0; | 
|  | else if(E) | 
|  | Q <= D; | 
|  | 1'b1: | 
|  | always @(negedge C or posedge R) | 
|  | if (R) | 
|  | Q <= 1'b0; | 
|  | else if(E) | 
|  | Q <= D; | 
|  | endcase | 
|  | endmodule | 
|  |  | 
|  | module dffs( | 
|  | output reg Q, | 
|  | input D, | 
|  | (* clkbuf_sink *) | 
|  | (* invertible_pin = "IS_C_INVERTED" *) | 
|  | input C, | 
|  | input S | 
|  | ); | 
|  | parameter [0:0] INIT = 1'b0; | 
|  | parameter [0:0] IS_C_INVERTED = 1'b0; | 
|  | initial Q = INIT; | 
|  | case(|IS_C_INVERTED) | 
|  | 1'b0: | 
|  | always @(posedge C or negedge S) | 
|  | if (S) | 
|  | Q <= 1'b1; | 
|  | else | 
|  | Q <= D; | 
|  | 1'b1: | 
|  | always @(negedge C or negedge S) | 
|  | if (S) | 
|  | Q <= 1'b1; | 
|  | else | 
|  | Q <= D; | 
|  | endcase | 
|  | endmodule | 
|  |  | 
|  | module dffse( | 
|  | output reg Q, | 
|  | input D, | 
|  | (* clkbuf_sink *) | 
|  | (* invertible_pin = "IS_C_INVERTED" *) | 
|  | input C, | 
|  | input S, | 
|  | input E | 
|  | ); | 
|  | parameter [0:0] INIT = 1'b0; | 
|  | parameter [0:0] IS_C_INVERTED = 1'b0; | 
|  | initial Q = INIT; | 
|  | case(|IS_C_INVERTED) | 
|  | 1'b0: | 
|  | always @(posedge C or negedge S) | 
|  | if (S) | 
|  | Q <= 1'b1; | 
|  | else if(E) | 
|  | Q <= D; | 
|  | 1'b1: | 
|  | always @(negedge C or negedge S) | 
|  | if (S) | 
|  | Q <= 1'b1; | 
|  | else if(E) | 
|  | Q <= D; | 
|  | endcase | 
|  | endmodule | 
|  |  | 
|  | module dffsr( | 
|  | output reg Q, | 
|  | input D, | 
|  | (* clkbuf_sink *) | 
|  | (* invertible_pin = "IS_C_INVERTED" *) | 
|  | input C, | 
|  | input R, | 
|  | input S | 
|  | ); | 
|  | parameter [0:0] INIT = 1'b0; | 
|  | parameter [0:0] IS_C_INVERTED = 1'b0; | 
|  | initial Q = INIT; | 
|  | case(|IS_C_INVERTED) | 
|  | 1'b0: | 
|  | always @(posedge C or negedge S or negedge R) | 
|  | if (S) | 
|  | Q <= 1'b1; | 
|  | else if (R) | 
|  | Q <= 1'b0; | 
|  | else | 
|  | Q <= D; | 
|  | 1'b1: | 
|  | always @(negedge C or negedge S or negedge R) | 
|  | if (S) | 
|  | Q <= 1'b1; | 
|  | else if (R) | 
|  | Q <= 1'b0; | 
|  | else | 
|  | Q <= D; | 
|  | endcase | 
|  | endmodule | 
|  |  | 
|  | module dffsre( | 
|  | output reg Q, | 
|  | input D, | 
|  | (* clkbuf_sink *) | 
|  | (* invertible_pin = "IS_C_INVERTED" *) | 
|  | input C, | 
|  | input E, | 
|  | input R, | 
|  | input S | 
|  | ); | 
|  | parameter [0:0] INIT = 1'b0; | 
|  | parameter [0:0] IS_C_INVERTED = 1'b0; | 
|  | initial Q = INIT; | 
|  | case(|IS_C_INVERTED) | 
|  | 1'b0: | 
|  | always @(posedge C or posedge S or posedge R) | 
|  | if (S) | 
|  | Q <= 1'b1; | 
|  | else if (R) | 
|  | Q <= 1'b0; | 
|  | else if (E) | 
|  | Q <= D; | 
|  | endcase | 
|  | endmodule | 
|  |  | 
|  | (* abc9_flop, lib_whitebox *) | 
|  | module latchsre ( | 
|  | output reg Q, | 
|  | input S, | 
|  | input R, | 
|  | input D, | 
|  | input G, | 
|  | input E | 
|  | ); | 
|  | parameter [0:0] INIT = 1'b0; | 
|  | parameter [0:0] IS_C_INVERTED = 1'b0; | 
|  | initial Q = INIT; | 
|  | always @* | 
|  | begin | 
|  | if (R) Q <= 1'b0; | 
|  | if (S) Q <= 1'b1; | 
|  | else if (E && G) Q <= D; | 
|  | end | 
|  | endmodule | 
|  |  | 
|  | (* abc9_flop, lib_whitebox *) | 
|  | module scff( | 
|  | output reg Q, | 
|  | input D, | 
|  | input clk | 
|  | ); | 
|  | parameter [0:0] INIT = 1'b0; | 
|  | initial Q = INIT; | 
|  |  | 
|  | always @(posedge clk) | 
|  | Q <= D; | 
|  | endmodule | 
|  |  | 
|  | module DP_RAM16K ( | 
|  | input rclk, | 
|  | input wclk, | 
|  | input wen, | 
|  | input ren, | 
|  | input[8:0] waddr, | 
|  | input[8:0] raddr, | 
|  | input[31:0] d_in, | 
|  | input[31:0] wenb, | 
|  | output[31:0] d_out ); | 
|  |  | 
|  | _dual_port_sram memory_0 ( | 
|  | .wclk           (wclk), | 
|  | .wen            (wen), | 
|  | .waddr          (waddr), | 
|  | .data_in        (d_in), | 
|  | .rclk           (rclk), | 
|  | .ren            (ren), | 
|  | .raddr          (raddr), | 
|  | .wenb		(wenb), | 
|  | .d_out          (d_out) ); | 
|  |  | 
|  | endmodule | 
|  |  | 
|  | module _dual_port_sram ( | 
|  | input wclk, | 
|  | input wen, | 
|  | input[8:0] waddr, | 
|  | input[31:0] data_in, | 
|  | input rclk, | 
|  | input ren, | 
|  | input[8:0] raddr, | 
|  | input[31:0] wenb, | 
|  | output[31:0] d_out ); | 
|  |  | 
|  | // MODE 0:  512 x 32 | 
|  | // MODE 1: 1024 x 16 | 
|  | // MODE 2: 1024 x 8 | 
|  | // MODE 3: 2048 x 4 | 
|  |  | 
|  | integer i; | 
|  | reg[31:0] ram[512:0]; | 
|  | reg[31:0] internal; | 
|  | // The memory is self initialised | 
|  |  | 
|  | initial begin | 
|  | for (i=0;i<=512;i=i+1) | 
|  | begin | 
|  | ram[i] = 0; | 
|  | end | 
|  | internal = 31'b0; | 
|  | end | 
|  |  | 
|  | wire [31:0] WMASK; | 
|  |  | 
|  | assign d_out = internal; | 
|  | assign WMASK = wenb; | 
|  |  | 
|  | always @(posedge wclk) begin | 
|  | if(!wen) begin | 
|  | if (WMASK[ 0]) ram[waddr][ 0] <= data_in[ 0]; | 
|  | if (WMASK[ 1]) ram[waddr][ 1] <= data_in[ 1]; | 
|  | if (WMASK[ 2]) ram[waddr][ 2] <= data_in[ 2]; | 
|  | if (WMASK[ 3]) ram[waddr][ 3] <= data_in[ 3]; | 
|  | if (WMASK[ 4]) ram[waddr][ 4] <= data_in[ 4]; | 
|  | if (WMASK[ 5]) ram[waddr][ 5] <= data_in[ 5]; | 
|  | if (WMASK[ 6]) ram[waddr][ 6] <= data_in[ 6]; | 
|  | if (WMASK[ 7]) ram[waddr][ 7] <= data_in[ 7]; | 
|  | if (WMASK[ 8]) ram[waddr][ 8] <= data_in[ 8]; | 
|  | if (WMASK[ 9]) ram[waddr][ 9] <= data_in[ 9]; | 
|  | if (WMASK[10]) ram[waddr][10] <= data_in[10]; | 
|  | if (WMASK[11]) ram[waddr][11] <= data_in[11]; | 
|  | if (WMASK[12]) ram[waddr][12] <= data_in[12]; | 
|  | if (WMASK[13]) ram[waddr][13] <= data_in[13]; | 
|  | if (WMASK[14]) ram[waddr][14] <= data_in[14]; | 
|  | if (WMASK[15]) ram[waddr][15] <= data_in[15]; | 
|  | if (WMASK[16]) ram[waddr][16] <= data_in[16]; | 
|  | if (WMASK[17]) ram[waddr][17] <= data_in[17]; | 
|  | if (WMASK[18]) ram[waddr][18] <= data_in[18]; | 
|  | if (WMASK[19]) ram[waddr][19] <= data_in[19]; | 
|  | if (WMASK[20]) ram[waddr][20] <= data_in[20]; | 
|  | if (WMASK[21]) ram[waddr][21] <= data_in[21]; | 
|  | if (WMASK[22]) ram[waddr][22] <= data_in[22]; | 
|  | if (WMASK[23]) ram[waddr][23] <= data_in[23]; | 
|  | if (WMASK[24]) ram[waddr][24] <= data_in[24]; | 
|  | if (WMASK[25]) ram[waddr][25] <= data_in[25]; | 
|  | if (WMASK[26]) ram[waddr][26] <= data_in[26]; | 
|  | if (WMASK[27]) ram[waddr][27] <= data_in[27]; | 
|  | if (WMASK[28]) ram[waddr][28] <= data_in[28]; | 
|  | if (WMASK[29]) ram[waddr][29] <= data_in[29]; | 
|  | if (WMASK[30]) ram[waddr][30] <= data_in[30]; | 
|  | if (WMASK[31]) ram[waddr][31] <= data_in[31]; | 
|  | end | 
|  | end | 
|  |  | 
|  | always @(posedge rclk) begin | 
|  | if(!ren) begin | 
|  | internal <= ram[raddr]; | 
|  | end | 
|  | end | 
|  | endmodule | 
|  |  | 
|  | module QL_DSP ( | 
|  | input CLK, | 
|  | input [15:0] A, B, C, D, | 
|  | output [31:0] O, | 
|  | output CO // Currently unused, left in case we want to support signed operations in the future. | 
|  | ); | 
|  | parameter [0:0] A_REG = 0; | 
|  | parameter [0:0] B_REG = 0; | 
|  | parameter [0:0] C_REG = 0; | 
|  | parameter [0:0] D_REG = 0; | 
|  | parameter [0:0] ENABLE_DSP = 0; | 
|  | parameter [0:0] A_SIGNED = 0; | 
|  | parameter [0:0] B_SIGNED = 0; | 
|  |  | 
|  | wire [15:0] iA, iB, iC, iD; | 
|  | wire [15:0] iF, iJ, iK, iG; | 
|  |  | 
|  | // Regs C and A, currently unused | 
|  | reg [15:0] rC, rA; | 
|  |  | 
|  | assign iC = C_REG ? rC : C; | 
|  | assign iA = A_REG ? rA : A; | 
|  |  | 
|  | // Regs B and D, currently unused | 
|  | reg [15:0] rB, rD; | 
|  |  | 
|  | 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 = {8'b0, iA[ 7: 0]}; | 
|  | assign Bh = {B_SIGNED ? {8{iB[15]}} : 8'b0, iB[15: 8]}; | 
|  | assign Bl = {8'b0, iB[ 7: 0]}; | 
|  | assign p_Ah_Bh = Ah * Bh; // F | 
|  | assign p_Al_Bh = {8'b0, Al[7:0]} * Bh; // J | 
|  | assign p_Ah_Bl = Ah * {8'b0, Bl[7:0]}; // K | 
|  | assign p_Al_Bl = Al * Bl; // G | 
|  |  | 
|  | assign iF = p_Ah_Bh; | 
|  | assign iJ = p_Al_Bh; | 
|  |  | 
|  | assign iK = p_Ah_Bl; | 
|  | assign iG = p_Al_Bl; | 
|  |  | 
|  | // Adder Stage | 
|  | wire [23:0] iK_e = {A_SIGNED ? {8{iK[15]}} : 8'b0, iK}; | 
|  | wire [23:0] iJ_e = {B_SIGNED ? {8{iJ[15]}} : 8'b0, iJ}; | 
|  | assign iL = iG + (iK_e << 8) + (iJ_e << 8) + (iF << 16); | 
|  |  | 
|  | // Output Stage | 
|  | assign O = iL; | 
|  |  | 
|  | endmodule |