Commit 4e94f6ca authored by Andrey Filippov's avatar Andrey Filippov

working on replacement for 8x8 DCT

parent 116c9ce2
This diff is collapsed.
/*******************************************************************************
* <b>Module:</b>dct1d_chen_reorder_in
* @file dct1d_chen_reorder_in.v
* @date:2016-06-08
* @author: Andrey Filippov
*
* @brief: Reorder scan-line pixel stream for dct1d_chen module
*
* @copyright Copyright (c) 2016 Elphel, Inc.
*
* <b>License:</b>
*
*dct1d_chen_reorder_in.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dct1d_chen_reorder_in.v is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
`timescale 1ns/1ps
module dct1d_chen_reorder_in#(
parameter WIDTH = 24
)(
input clk,
input rst,
input en, // to be sampled when start is expected (start time slot)
input [WIDTH -1:0] din,
input start, // with first pixel
output [2*WIDTH -1:0] dout_10_32_76_54, // Concatenated/reordered output data {x[1],x[0]}/{x[3],x[2]}/ {x[7],x[6]}/{x[5],x[4]}
output reg start_out,
output reg en_out // to be sampled when start_out is expected
);
reg last_r;
reg [2:0] cntr_in;
reg [1:0] raddr;
wire restart = !rst && en && (start || last_r);
wire [1:0] we = ((|cntr_in) || en)? {~cntr_in[0]^cntr_in[2],cntr_in[0]^cntr_in[2]}:2'b0;
wire [1:0] waddr = {cntr_in[2],cntr_in[2]^cntr_in[1]};
reg [WIDTH-1:0] bufl_ram[0:3];
reg [WIDTH-1:0] bufh_ram[0:3];
reg [2*WIDTH -1:0] dout_10_32_76_54_r;
assign dout_10_32_76_54 = dout_10_32_76_54_r;
always @(posedge clk) begin
if (rst) last_r <= 0;
else last_r <= &cntr_in;
if (rst) cntr_in <= 0;
else if (restart || (|cntr_in)) cntr_in <= cntr_in + 1;
if (we[0]) bufl_ram[waddr] <= din;
if (we[1]) bufh_ram[waddr] <= din;
if (rst ) raddr <= ~0;
else if (cntr_in == 5) raddr <= 0;
else if (!(&raddr)) raddr <= raddr + 1;
dout_10_32_76_54_r <= {bufh_ram[raddr],bufl_ram[raddr]};
start_out <= (cntr_in == 5);
en_out <= en || (|cntr_in) || last_r;
end
endmodule
/*******************************************************************************
* <b>Module:</b>dct1d_chen_reorder_out
* @file dct1d_chen_reorder_out.v
* @date:2016-06-08
* @author: Andrey Filippov
*
* @brief: Reorder data from dct1d_chen output to natural sequence
*
* @copyright Copyright (c) 2016 Elphel, Inc.
*
* <b>License:</b>
*
*dct1d_chen_reorder_out.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dct1d_chen_reorder_out.v is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
`timescale 1ns/1ps
module dct1d_chen_reorder_out#(
parameter WIDTH = 24
)(
input clk,
input rst,
input [WIDTH -1:0] din, // pre2_start-X-F4-X-F2-X-F6-F5-F0-F3-X-F1-X-F7
input pre2_start, // Two cycles ahead of F4
output [WIDTH -1:0] dout, // data in natural order: F0-F1-F2-F3-F4-F5-F6-F7
output start_out, // 1 ahead of F0
output reg en_out // to be sampled when start_out is expected
);
reg [WIDTH -1:0] reord_buf_ram[0:15];
reg [WIDTH -1:0] dout_r;
reg [3:0] cntr_in;
wire start_8;
wire start_11;
reg start_12;
wire stop_in;
reg we_r;
reg [3:0] ina_rom;
wire [3:0] waddr = {ina_rom[3] ^ cntr_in[3], ina_rom[2:0]};
reg [3:0] raddr;
assign dout = dout_r;
assign start_out = start_12;
always @(posedge clk) begin
if (rst) we_r <= 0;
else if (pre2_start) we_r <= 1;
else if (stop_in) we_r <= 0;
if (rst) cntr_in <= 0;
else if (pre2_start) cntr_in <= {~cntr_in[3],3'b0};
else if (we_r) cntr_in <= cntr_in + 1;
case (cntr_in[2:0])
3'h0: ina_rom <= {1'b0,3'h4};
3'h1: ina_rom <= {1'b1,3'h1};
3'h2: ina_rom <= {1'b0,3'h2};
3'h3: ina_rom <= {1'b1,3'h7};
3'h4: ina_rom <= {1'b0,3'h6};
3'h5: ina_rom <= {1'b0,3'h5};
3'h6: ina_rom <= {1'b0,3'h0};
3'h7: ina_rom <= {1'b0,3'h3};
endcase
if (we_r) reord_buf_ram[waddr] <= din;
if (start_11) raddr <= {~cntr_in[3], 3'b0};
else if ((raddr[2:0] != 0) || we_r) raddr <= raddr + 1;
dout_r <= reord_buf_ram[raddr];
start_12 <= start_11;
en_out <= start_12 || (raddr[2:0] != 0);
end
dly01_16 start_8__i (
.clk (clk), // input
.rst (rst), // input
.dly (4'h7), // input[3:0]
.din (pre2_start), // input
.dout (start_8) // output
);
dly01_16 start_11__i (
.clk (clk), // input
.rst (rst), // input
.dly (4'h1), // input[3:0]
.din (start_8), // input
.dout (start_11) // output
);
dly01_16 dly01_16_2_i (
.clk (clk), // input
.rst (rst), // input
.dly (4'h4), // input[3:0]
.din (start_8 && !pre2_start), // input
.dout (stop_in) // output
);
endmodule
/*******************************************************************************
* <b>Module:</b>dsp_addsub_reg2_simd
* @file dsp_addsub_reg2_simd.v
* @date:2016-06-05
* @author: Andrey Filippov
*
* @brief: SIMD adder/subtracter with dual registers on the A-inputa
*
* @copyright Copyright (c) 2016 Elphel, Inc.
*
* <b>License:</b>
*
*dsp_addsub_reg2_simd.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dsp_addsub_reg2_simd.v is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
`timescale 1ns/1ps
module dsp_addsub_reg2_simd#(
parameter NUM_DATA = 2,
parameter WIDTH = 24
)(
input clk,
input rst,
input [NUM_DATA * WIDTH -1:0] ain,
input [NUM_DATA * WIDTH -1:0] bin,
input cea1, // load first a registers
input cea2, // load second a registers
input ceb, // load first b registers
input subtract, // 0 - add, 1 - subtract
input cep, // load output registers
output [NUM_DATA * WIDTH -1:0] pout);
`ifdef INSTANTIATE_DSP48E1
wire [4:0] inmode = { 1'b1, // ~selb,
1'b0, // sub_d,
1'b0, // seld,
1'b0, // seld, // ~en_a,
1'b1}; // ~sela};
wire [3:0] alumode = {2'b0, // Z + X + Y + CIN / -Z +( X + Y + CIN) -1
1'b0,
subtract};
wire [6:0] opmode = {3'b011, // Z = C-input
2'b00, // Y = 0
2'b11}; // X = A:B
wire cryin = subtract;
DSP48E1 #(
.ACASCREG (2), // (1),
.ADREG (0), // (1),
.ALUMODEREG (1),
.AREG (2), // (1)
.AUTORESET_PATDET ("NO_RESET"),
.A_INPUT ("DIRECT"),
.BCASCREG (2), // (1),
.BREG (2), // (1)
.B_INPUT ("DIRECT"),
.CARRYINREG (1),
.CARRYINSELREG (1),
.CREG (1), //(1),
.DREG (0), //(1),
.INMODEREG (1),
.IS_ALUMODE_INVERTED (4'b0),
.IS_CARRYIN_INVERTED (1'b0),
.IS_CLK_INVERTED (1'b0),
.IS_INMODE_INVERTED (5'b0),
.IS_OPMODE_INVERTED (7'b0),
.MASK (48'hffffffffffff),
.MREG (0),
.OPMODEREG (1),
.PATTERN (48'h000000000000),
.PREG (1),
.SEL_MASK ("MASK"),
.SEL_PATTERN ("PATTERN"),
.USE_DPORT ("TRUE"), //("FALSE"),
.USE_MULT ("NONE"), //("MULTIPLY"),
.USE_PATTERN_DETECT ("NO_PATDET"),
.USE_SIMD ("TWO24") // ("ONE48")
) DSP48E1_i (
.ACOUT (), // output[29:0]
.BCOUT (), // output[17:0]
.CARRYCASCOUT (), // output
.CARRYOUT (), // output[3:0]
.MULTSIGNOUT (), // output
.OVERFLOW (), // output
.P (pout), // output[47:0]
.PATTERNBDETECT (), // output
.PATTERNDETECT (), // output
.PCOUT (), // output[47:0]
.UNDERFLOW (), // output
.A (ain[47:18]), // input[29:0]
.ACIN (30'b0), // input[29:0]
.ALUMODE (alumode), // input[3:0]
.B (ain[17:0]), // input[17:0]
.BCIN (18'b0), // input[17:0]
.C (bin), // input[47:0]
.CARRYCASCIN (1'b0), // input
.CARRYIN (cryin), // input
.CARRYINSEL (3'h0), // input[2:0] // later modify?
.CEA1 (cea1), // input
.CEA2 (cea2), // input
.CEAD (1'b0), // input
.CEALUMODE (1'b1), // input
.CEB1 (cea1), // input
.CEB2 (cea2), // input
.CEC (ceb), // input
.CECARRYIN (1'b0), // input
.CECTRL (1'b0), // input
.CED (1'b0), // input
.CEINMODE (1'b1), // input
.CEM (1'b1), // input
.CEP (cep), // input
.CLK (clk), // input
.D (25'h1ffffff),// input[24:0]
.INMODE (inmode), // input[4:0]
.MULTSIGNIN (1'b0), // input
.OPMODE (opmode), // input[6:0]
.PCIN (48'b0), // input[47:0]
.RSTA (rst), // input
.RSTALLCARRYIN (rst), // input
.RSTALUMODE (rst), // input
.RSTB (rst), // input
.RSTC (rst), // input
.RSTCTRL (rst), // input
.RSTD (rst), // input
.RSTINMODE (rst), // input
.RSTM (rst), // input
.RSTP (rst) // input
);
`else
reg [NUM_DATA * WIDTH -1:0] a1_reg;
reg [NUM_DATA * WIDTH -1:0] a2_reg;
reg [NUM_DATA * WIDTH -1:0] b_reg;
reg [NUM_DATA * WIDTH -1:0] p_reg;
reg sub_r;
wire [NUM_DATA * WIDTH -1:0] p_w;
assign pout = p_reg;
generate
genvar i;
for (i = 0; i < 4; i = i+1) begin: byte_fifo_block
assign p_w[WIDTH*i +: WIDTH] = a2_reg[WIDTH*i +: WIDTH] + sub_r ? -b_reg[WIDTH*i +: WIDTH] : b_reg[WIDTH*i +: WIDTH];
end
endgenerate
always @ (posedge clk) begin
if (rst) a1_reg <= 0;
else if (cea1) a1_reg <= ain;
if (rst) a2_reg <= 0;
else if (cea2) a2_reg <= a1_reg;
if (rst) b_reg <= 0;
else if (ceb) b_reg <= bin;
sub_r <= subtract;
if (rst) p_reg <= 0;
if (cep) p_reg <= p_w;
end
`endif
endmodule
/*******************************************************************************
* <b>Module:</b>dsp_addsub_simd
* @file dsp_addsub_simd.v
* @date:2016-06-05
* @author: Andrey Filippov
*
* @brief: SIMD adder/subtracter
*
* @copyright Copyright (c) 2016 Elphel, Inc.
*
* <b>License:</b>
*
*dsp_addsub_simd.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dsp_addsub_simd.v is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
`timescale 1ns/1ps
module dsp_addsub_simd#(
parameter NUM_DATA = 2, // Currently with INSTANTIATE_DSP48E1 should be 2
parameter WIDTH = 24 // Currently with INSTANTIATE_DSP48E1 should be 24
)(
input clk,
input rst,
input [NUM_DATA * WIDTH -1:0] ain,
input [NUM_DATA * WIDTH -1:0] bin,
input cea, // load a registers
input ceb, // load b registers
input subtract, // 0 - add, 1 - subtract
input cep, // load output registers
output [NUM_DATA * WIDTH -1:0] pout);
`ifdef INSTANTIATE_DSP48E1
wire [4:0] inmode = { 1'b1, // ~selb,
1'b0, // sub_d,
1'b0, // seld,
1'b0, // seld, // ~en_a,
1'b1}; // ~sela};
wire [3:0] alumode = {2'b0, // Z + X + Y + CIN / -Z +( X + Y + CIN) -1
1'b0,
subtract};
wire [6:0] opmode = {3'b011, // Z = C-input
2'b00, // Y = 0
2'b11}; // X = A:B
wire cryin = subtract;
DSP48E1 #(
.ACASCREG (1),
.ADREG (0), // (1),
.ALUMODEREG (1),
.AREG (1), // (1)
.AUTORESET_PATDET ("NO_RESET"),
.A_INPUT ("DIRECT"),
.BCASCREG (1),
.BREG (1), // (1)
.B_INPUT ("DIRECT"),
.CARRYINREG (1),
.CARRYINSELREG (1),
.CREG (1), //(1),
.DREG (0), //(1),
.INMODEREG (1),
.IS_ALUMODE_INVERTED (4'b0),
.IS_CARRYIN_INVERTED (1'b0),
.IS_CLK_INVERTED (1'b0),
.IS_INMODE_INVERTED (5'b0),
.IS_OPMODE_INVERTED (7'b0),
.MASK (48'hffffffffffff),
.MREG (0),
.OPMODEREG (1),
.PATTERN (48'h000000000000),
.PREG (1),
.SEL_MASK ("MASK"),
.SEL_PATTERN ("PATTERN"),
.USE_DPORT ("TRUE"), //("FALSE"),
.USE_MULT ("NONE"), //("MULTIPLY"),
.USE_PATTERN_DETECT ("NO_PATDET"),
.USE_SIMD ("TWO24") // ("ONE48")
) DSP48E1_i (
.ACOUT (), // output[29:0]
.BCOUT (), // output[17:0]
.CARRYCASCOUT (), // output
.CARRYOUT (), // output[3:0]
.MULTSIGNOUT (), // output
.OVERFLOW (), // output
.P (pout), // output[47:0]
.PATTERNBDETECT (), // output
.PATTERNDETECT (), // output
.PCOUT (), // output[47:0]
.UNDERFLOW (), // output
.A (ain[47:18]), // input[29:0]
.ACIN (30'b0), // input[29:0]
.ALUMODE (alumode), // input[3:0]
.B (ain[17:0]), // input[17:0]
.BCIN (18'b0), // input[17:0]
.C (bin), // input[47:0]
.CARRYCASCIN (1'b0), // input
.CARRYIN (cryin), // input
.CARRYINSEL (3'h0), // input[2:0] // later modify?
.CEA1 (cea), // input
.CEA2 (1'b0), // input
.CEAD (1'b0), // input
.CEALUMODE (1'b1), // input
.CEB1 (cea), // input
.CEB2 (1'b0), // input
.CEC (ceb), // input
.CECARRYIN (1'b0), // input
.CECTRL (1'b0), // input
.CED (1'b0), // input
.CEINMODE (1'b1), // input
.CEM (1'b1), // input
.CEP (cep), // input
.CLK (clk), // input
.D (25'h1ffffff),// input[24:0]
.INMODE (inmode), // input[4:0]
.MULTSIGNIN (1'b0), // input
.OPMODE (opmode), // input[6:0]
.PCIN (48'b0), // input[47:0]
.RSTA (rst), // input
.RSTALLCARRYIN (rst), // input
.RSTALUMODE (rst), // input
.RSTB (rst), // input
.RSTC (rst), // input
.RSTCTRL (rst), // input
.RSTD (rst), // input
.RSTINMODE (rst), // input
.RSTM (rst), // input
.RSTP (rst) // input
);
`else
reg [NUM_DATA * WIDTH -1:0] a_reg;
reg [NUM_DATA * WIDTH -1:0] b_reg;
reg [NUM_DATA * WIDTH -1:0] p_reg;
reg sub_r;
wire [NUM_DATA * WIDTH -1:0] p_w;
assign pout = p_reg;
generate
genvar i;
for (i = 0; i < 4; i = i+1) begin: byte_fifo_block
assign p_w[WIDTH*i +: WIDTH] = a_reg[WIDTH*i +: WIDTH] + sub_r ? -b_reg[WIDTH*i +: WIDTH] : b_reg[WIDTH*i +: WIDTH];
end
endgenerate
always @ (posedge clk) begin
if (rst) a_reg <= 0;
else if (cea) a_reg <= ain;
if (rst) b_reg <= 0;
else if (ceb) b_reg <= bin;
sub_r <= subtract;
if (rst) p_reg <= 0;
if (cep) p_reg <= p_w;
end
`endif
endmodule
/*******************************************************************************
* dsp_ma
* @file dsp_ma.v
* @date:2016-06-05
* @author: Andrey Filippov
*
* @brief: DSP with multi-input multiplier and accumulator
*
* @copyright Copyright (c) 2016 Elphel, Inc.
*
* <b>License:</b>
*
* dsp_ma.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dsp_ma.v is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
`timescale 1ns/1ps
module dsp_ma #(
parameter B_WIDTH = 18,
parameter A_WIDTH = 25,
parameter P_WIDTH = 48)
(
input clk,
input rst,
input signed [B_WIDTH-1:0] bin,
input ceb1, // load b1 register
input ceb2, // load b2 register
input selb, // 0 - select b1, 1 - select b2
input signed [A_WIDTH-1:0] ain,
input cea1,
input cea2,
input signed [A_WIDTH-1:0] din,
input ced,
input sela, // 0 - select a1, 1 - select a2
input seld, // 0 - select a1/a2, 1 - select d
input neg_m, // 1 - negate multiplier result
input accum, // 0 - use multiplier result, 1 add to accumulator
output signed [P_WIDTH-1:0] pout
);
`ifdef INSTANTIATE_DSP48E1
wire [4:0] inmode = {~selb,
1'b0, // sub_d,
seld,
seld, // ~en_a,
~sela};
wire [3:0] alumode = {2'b0,
neg_m,
neg_m};
wire [6:0] opmode = {1'b0,
accum,
1'b0,
2'b01,
2'b01};
DSP48E1 #(
.ACASCREG (1),
.ADREG (0), // (1),
.ALUMODEREG (1),
.AREG (2), // (1)
.AUTORESET_PATDET ("NO_RESET"),
.A_INPUT ("DIRECT"),
.BCASCREG (1),
.BREG (2), // (1)
.B_INPUT ("DIRECT"),
.CARRYINREG (1),
.CARRYINSELREG (1),
.CREG (0), //(1),
.DREG (1),
.INMODEREG (1),
.IS_ALUMODE_INVERTED (4'b0),
.IS_CARRYIN_INVERTED (1'b0),
.IS_CLK_INVERTED (1'b0),
.IS_INMODE_INVERTED (5'b0),
.IS_OPMODE_INVERTED (7'b0),
.MASK (48'hffffffffffff),
.MREG (1),
.OPMODEREG (1),
.PATTERN (48'h000000000000),
.PREG (1),
.SEL_MASK ("MASK"),
.SEL_PATTERN ("PATTERN"),
.USE_DPORT ("TRUE"), //("FALSE"),
.USE_MULT ("MULTIPLY"),
.USE_PATTERN_DETECT ("NO_PATDET"),
.USE_SIMD ("ONE48")
) DSP48E1_i (
.ACOUT (), // output[29:0]
.BCOUT (), // output[17:0]
.CARRYCASCOUT (), // output
.CARRYOUT (), // output[3:0]
.MULTSIGNOUT (), // output
.OVERFLOW (), // output
.P (pout), // output[47:0]
.PATTERNBDETECT (), // output
.PATTERNDETECT (), // output
.PCOUT (), // output[47:0]
.UNDERFLOW (), // output
.A ({{30-A_WIDTH{ain[A_WIDTH-1]}}, ain}), // input[29:0]
.ACIN (30'b0), // input[29:0]
.ALUMODE (alumode), // input[3:0]
.B (bin), // input[17:0]
.BCIN (18'b0), // input[17:0]
.C (48'hffffffffffff), // input[47:0]
.CARRYCASCIN (1'b0), // input
.CARRYIN (1'b0), // input
.CARRYINSEL (3'h0), // input[2:0] // later modify?
.CEA1 (cea1), // input
.CEA2 (cea2), // input
.CEAD (1'b0), // input
.CEALUMODE (1'b1), // input
.CEB1 (ceb1), // input
.CEB2 (ceb2), // input
.CEC (1'b0), // input
.CECARRYIN (1'b0), // input
.CECTRL (1'b0), // input
.CED (ced), // input
.CEINMODE (1'b1), // input
.CEM (1'b1), // input
.CEP (1'b1), // input
.CLK (clk), // input
.D (din), // input[24:0]
.INMODE (inmode), // input[4:0]
.MULTSIGNIN (1'b0), // input
.OPMODE (opmode), // input[6:0]
.PCIN (48'b0), // input[47:0]
.RSTA (rst), // input
.RSTALLCARRYIN (rst), // input
.RSTALUMODE (rst), // input
.RSTB (rst), // input
.RSTC (rst), // input
.RSTCTRL (rst), // input
.RSTD (rst), // input
.RSTINMODE (rst), // input
.RSTM (rst), // input
.RSTP (rst) // input
);
`else
// Will try to make it infer DSP48e1
reg signed [B_WIDTH-1:0] b1_reg;
reg signed [B_WIDTH-1:0] b2_reg;
reg signed [A_WIDTH-1:0] a1_reg;
reg signed [A_WIDTH-1:0] a2_reg;
reg signed [A_WIDTH-1:0] d_reg;
reg signed [P_WIDTH-1:0] m_reg;
reg signed [P_WIDTH-1:0] p_reg;
wire signed [A_WIDTH+B_WIDTH-1:0] m_wire;
wire signed [B_WIDTH-1:0] b_wire;
wire signed [A_WIDTH-1:0] a_wire;
reg selb_r;
reg sela_r;
reg seld_r;
reg neg_m_r;
reg accum_r;
wire signed [P_WIDTH-1:0] m_reg_pm;
wire signed [P_WIDTH-1:0] p_reg_cond;
assign pout = p_reg;
assign b_wire = selb_r ? b2_reg : b1_reg;
assign a_wire = seld_r ? d_reg : (sela_r ? a2_reg : a1_reg);
assign m_wire = a_wire * b_wire;
assign m_reg_pm = neg_m_r ? - m_reg : m_reg;
assign p_reg_cond = accum_r ? p_reg : 0;
always @ (posedge clk) begin
if (rst) b1_reg <= 0;
else if (ceb1) b1_reg <= bin;
if (rst) b2_reg <= 0;
else if (ceb2) b2_reg <= bin;
if (rst) a1_reg <= 0;
else if (cea1) a1_reg <= ain;
if (rst) a2_reg <= 0;
else if (cea2) a2_reg <= ain;
if (rst) d_reg <= 0;
else if (ced) d_reg <= din;
selb_r <= selb;
sela_r <= sela;
seld_r <= seld;
neg_m_r <= neg_m;
accum_r <= accum;
m_reg <= {{P_WIDTH - A_WIDTH - B_WIDTH{1'b0}}, m_wire};
p_reg <= p_reg_cond + m_reg_pm;
end
`endif
endmodule
/*******************************************************************************
* dsp_ma_preadd
* @file dsp_ma_preadd.v
* @date:2016-06-05
* @author: Andrey Filippov
*
* @brief: DSP with multi-input multiplier and accumulator with pre-adder
*
* @copyright Copyright (c) 2016 Elphel, Inc.
*
* <b>License:</b>
*
* dsp_ma_preadd.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dsp_ma_preadd.v is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify this Program, or any covered work, by linking or combining it
* with independent modules provided by the FPGA vendor only (this permission
* does not extend to any 3-rd party modules, "soft cores" or macros) under
* different license terms solely for the purpose of generating binary "bitstream"
* files and/or simulating the code, the copyright holders of this Program give
* you the right to distribute the covered work without those independent modules
* as long as the source code for them is available from the FPGA vendor free of
* charge, and there is no dependence on any encrypted modules for simulating of
* the combined code. This permission applies to you if the distributed code
* contains all the components and scripts required to completely simulate it
* with at least one of the Free Software programs.
*******************************************************************************/
`timescale 1ns/1ps
module dsp_ma_preadd #(
parameter B_WIDTH = 18,
parameter A_WIDTH = 25,
parameter P_WIDTH = 48)
(
input clk,
input rst,
input signed [B_WIDTH-1:0] bin,
input ceb1, // load b1 register
input ceb2, // load b2 register
input selb, // 0 - select b1, 1 - select b2
input signed [A_WIDTH-1:0] ain,
input cea1, // clock enable a1 reg
input cea2, // clock enable a2 reg
input signed [A_WIDTH-1:0] din,
input ced, // enable d-reg
input cead, // enable ad register (after pre-adder)
input sela, // 0 - select a1, 1 - select a2
input en_a, // 1 - enable a input (0 - zero) ~inmode[1]
input en_d, // 1 - enable d input (0 - zero) ~inmode[2]
input sub_d, // 0 - pre-add (A+D), 1 - pre-subtract (A-D)
input neg_m, // 1 - negate multiplier result
input accum, // 0 - use multiplier result, 1 add to accumulator
output signed [P_WIDTH-1:0] pout
);
`ifdef INSTANTIATE_DSP48E1
wire [4:0] inmode = {~selb,
sub_d,
en_d,
~en_a,
~sela};
wire [3:0] alumode = {2'b0,
neg_m,
neg_m};
wire [6:0] opmode = {1'b0,
accum,
1'b0,
2'b01,
2'b01};
DSP48E1 #(
.ACASCREG (1),
.ADREG (1),
.ALUMODEREG (1),
.AREG (2), // (1)
.AUTORESET_PATDET ("NO_RESET"),
.A_INPUT ("DIRECT"),
.BCASCREG (1),
.BREG (2), // (1)
.B_INPUT ("DIRECT"),
.CARRYINREG (1),
.CARRYINSELREG (1),
.CREG (0), //(1),
.DREG (1),
.INMODEREG (1),
.IS_ALUMODE_INVERTED (4'b0),
.IS_CARRYIN_INVERTED (1'b0),
.IS_CLK_INVERTED (1'b0),
.IS_INMODE_INVERTED (5'b0),
.IS_OPMODE_INVERTED (7'b0),
.MASK (48'hffffffffffff),
.MREG (1),
.OPMODEREG (1),
.PATTERN (48'h000000000000),
.PREG (1),
.SEL_MASK ("MASK"),
.SEL_PATTERN ("PATTERN"),
.USE_DPORT ("TRUE"), //("FALSE"),
.USE_MULT ("MULTIPLY"),
.USE_PATTERN_DETECT ("NO_PATDET"),
.USE_SIMD ("ONE48")
) DSP48E1_i (
.ACOUT (), // output[29:0]
.BCOUT (), // output[17:0]
.CARRYCASCOUT (), // output
.CARRYOUT (), // output[3:0]
.MULTSIGNOUT (), // output
.OVERFLOW (), // output
.P (pout), // output[47:0]
.PATTERNBDETECT (), // output
.PATTERNDETECT (), // output
.PCOUT (), // output[47:0]
.UNDERFLOW (), // output
.A ({{30-A_WIDTH{ain[A_WIDTH-1]}}, ain}), // input[29:0]
.ACIN (30'b0), // input[29:0]
.ALUMODE (alumode), // input[3:0]
.B (bin), // input[17:0]
.BCIN (18'b0), // input[17:0]
.C (48'hffffffffffff), // input[47:0]
.CARRYCASCIN (1'b0), // input
.CARRYIN (1'b0), // input
.CARRYINSEL (3'h0), // input[2:0] // later modify?
.CEA1 (cea1), // input
.CEA2 (cea2), // input
.CEAD (cead), // input
.CEALUMODE (1'b1), // input
.CEB1 (ceb1), // input
.CEB2 (ceb2), // input
.CEC (1'b0), // input
.CECARRYIN (1'b0), // input
.CECTRL (1'b0), // input
.CED (ced), // input
.CEINMODE (1'b1), // input
.CEM (1'b1), // input
.CEP (1'b1), // input
.CLK (clk), // input
.D (din), // input[24:0]
.INMODE (inmode), // input[4:0]
.MULTSIGNIN (1'b0), // input
.OPMODE (opmode), // input[6:0]
.PCIN (48'b0), // input[47:0]
.RSTA (rst), // input
.RSTALLCARRYIN (rst), // input
.RSTALUMODE (rst), // input
.RSTB (rst), // input
.RSTC (rst), // input
.RSTCTRL (rst), // input
.RSTD (rst), // input
.RSTINMODE (rst), // input
.RSTM (rst), // input
.RSTP (rst) // input
);
`else
// Will try to make it infer DSP48e1
reg signed [B_WIDTH-1:0] b1_reg;
reg signed [B_WIDTH-1:0] b2_reg;
reg signed [A_WIDTH-1:0] a1_reg;
reg signed [A_WIDTH-1:0] a2_reg;
reg signed [A_WIDTH-1:0] d_reg;
reg signed [A_WIDTH-1:0] ad_reg;
reg signed [P_WIDTH-1:0] m_reg;
reg signed [P_WIDTH-1:0] p_reg;
wire signed [A_WIDTH+B_WIDTH-1:0] m_wire;
wire signed [B_WIDTH-1:0] b_wire;
wire signed [A_WIDTH-1:0] a_wire;
wire signed [A_WIDTH-1:0] d_wire;
reg selb_r;
reg sela_r;
reg en_a_r;
reg en_d_r;
reg sub_d_r;
reg neg_m_r;
reg accum_r;
wire signed [P_WIDTH-1:0] m_reg_pm;
wire signed [P_WIDTH-1:0] p_reg_cond;
assign pout = p_reg;
assign b_wire = selb_r ? b2_reg : b1_reg;
assign a_wire = en_a_r ? (sela_r ? a2_reg : a1_reg) : {A_WIDTH{1'b0}};
assign d_wire = en_d_r ? (sub_d_r ? -d_reg : d_reg) : {A_WIDTH{1'b0}};
assign m_wire = ad_reg * b_wire;
assign m_reg_pm = neg_m_r ? - m_reg : m_reg;
assign p_reg_cond = accum_r ? p_reg : 0;
always @ (posedge clk) begin
if (rst) b1_reg <= 0;
else if (ceb1) b1_reg <= bin;
if (rst) b2_reg <= 0;
else if (ceb2) b2_reg <= bin;
if (rst) a1_reg <= 0;
else if (cea1) a1_reg <= ain;
if (rst) a2_reg <= 0;
else if (cea2) a2_reg <= ain;
if (rst) d_reg <= 0;
else if (ced) d_reg <= din;
if (rst) ad_reg <= 0;
else if (cead) ad_reg <= a_wire + d_wire;
neg_m_r <= neg_m;
accum_r <= accum;
selb_r <= selb;
sela_r <= sela;
en_a_r <= en_a;
en_d_r <= en_d;
sub_d_r <= sub_d;
m_reg <= {{P_WIDTH - A_WIDTH - B_WIDTH{1'b0}}, m_wire};
p_reg <= p_reg_cond + m_reg_pm;
end
`endif
endmodule
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment