litex/verilog/lm32/lm32_multiplier_spartan6.v

194 lines
3.1 KiB
Verilog

/*
* Milkymist SoC
* Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
*
* This program 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, version 3 of the License.
*
* This program 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/>.
*/
module lm32_multiplier(
input clk_i,
input rst_i,
input stall_x,
input stall_m,
input [31:0] operand_0,
input [31:0] operand_1,
output [31:0] result
);
// See UG389, esp. p. 29 "Fully Pipelined, 35 x 35 Multiplier Use Model (Large Multiplier)"
wire [17:0] au = {3'd0, operand_0[31:17]};
wire [17:0] al = {1'b0, operand_0[16:0]};
wire [17:0] bu = {3'd0, operand_1[31:17]};
wire [17:0] bl = {1'b0, operand_1[16:0]};
wire [17:0] bl_forward;
wire [35:0] al_bl;
reg [16:0] result_low;
always @(posedge clk_i) begin
if(rst_i)
result_low <= 17'd0;
else
result_low <= al_bl[16:0];
end
assign result[16:0] = result_low;
DSP48A1 #(
.A0REG(1),
.A1REG(0),
.B0REG(1),
.B1REG(0),
.CARRYINREG(0),
.CARRYINSEL("OPMODE5"),
.CARRYOUTREG(0),
.CREG(0),
.DREG(0),
.MREG(1),
.OPMODEREG(0),
.PREG(0),
.RSTTYPE("SYNC")
) D1 (
.BCOUT(bl_forward),
.PCOUT(),
.CARRYOUT(),
.CARRYOUTF(),
.M(al_bl),
.P(),
.PCIN(),
.CLK(clk_i),
.OPMODE(8'd1),
.A(al),
.B(bl),
.C(),
.CARRYIN(),
.D(),
.CEA(~stall_x),
.CEB(~stall_x),
.CEC(),
.CECARRYIN(),
.CED(),
.CEM(~stall_m),
.CEOPMODE(),
.CEP(1'b1),
.RSTA(rst_i),
.RSTB(rst_i),
.RSTC(),
.RSTCARRYIN(),
.RSTD(),
.RSTM(rst_i),
.RSTOPMODE(),
.RSTP()
);
wire [47:0] au_bl_sum;
DSP48A1 #(
.A0REG(1),
.A1REG(0),
.B0REG(0),
.B1REG(0),
.CARRYINREG(0),
.CARRYINSEL("OPMODE5"),
.CARRYOUTREG(0),
.CREG(0),
.DREG(0),
.MREG(1),
.OPMODEREG(0),
.PREG(0),
.RSTTYPE("SYNC")
) D2 (
.BCOUT(),
.PCOUT(au_bl_sum),
.CARRYOUT(),
.CARRYOUTF(),
.M(),
.P(),
.PCIN(),
.CLK(clk_i),
.OPMODE(8'd13),
.A(au),
.B(bl_forward),
.C({31'd0, al_bl[33:17]}),
.CARRYIN(),
.D(),
.CEA(~stall_x),
.CEB(),
.CEC(),
.CECARRYIN(),
.CED(),
.CEM(~stall_m),
.CEOPMODE(),
.CEP(),
.RSTA(rst_i),
.RSTB(),
.RSTC(),
.RSTCARRYIN(),
.RSTD(),
.RSTM(rst_i),
.RSTOPMODE(),
.RSTP()
);
wire [47:0] r_full;
assign result[31:17] = r_full[16:0];
DSP48A1 #(
.A0REG(1),
.A1REG(0),
.B0REG(1),
.B1REG(0),
.CARRYINREG(0),
.CARRYINSEL("OPMODE5"),
.CARRYOUTREG(0),
.CREG(0),
.DREG(0),
.MREG(1),
.OPMODEREG(0),
.PREG(1),
.RSTTYPE("SYNC")
) D3 (
.BCOUT(),
.PCOUT(),
.CARRYOUT(),
.CARRYOUTF(),
.M(),
.P(r_full),
.PCIN(au_bl_sum),
.CLK(clk_i),
.OPMODE(8'd5),
.A(bu),
.B(al),
.C(),
.CARRYIN(),
.D(),
.CEA(~stall_x),
.CEB(~stall_x),
.CEC(),
.CECARRYIN(),
.CED(),
.CEM(~stall_m),
.CEOPMODE(),
.CEP(1'b1),
.RSTA(rst_i),
.RSTB(rst_i),
.RSTC(),
.RSTCARRYIN(),
.RSTD(),
.RSTM(rst_i),
.RSTOPMODE(),
.RSTP(rst_i)
);
endmodule