blob: ab875f153f2b04b5e7576130ffcbd2238a15ffc6 [file] [log] [blame]
// 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