主要参考
ug479.pdf。之前的文章:
FIR调用DSP48E_05。本文主要记录基本用法。
一、DSP48核
A-参数说明
目前没发现C勾选与否,有何影响。
如上图所示,结果3拍后输出:
其他参数:
B-IP调用
生成IP核,参数设置完毕直接调用即可
dsp48_ex dsp_inst(
.CLK(clk),
.A(a),
.B(b),
.C(c),
.P(p)
);
二、原语示例
主要参考
pg148-dsp48 macro.pdf用到再细化补充。
Ex1:
// m = b * (a + d)
// p = c+m or p+m
`timescale 1ns / 1ps
// m = b * (a + d)
// p = c+m or p+m
module dsp48_wrap_f
(
input clock,
input ce1,
input ce2,
input cem,
input cep,
input signed [24:0] a,
input signed [17:0] b,
input signed [47:0] c,
input signed [24:0] d, // this has two fewer pipe stages
// X+Y is usually the multiplier output (M)
// Z is either P, PCIN or C
// bit 1:0: 0: Z+X+Y 3:Z-(X+Y) 1: -Z + (X+Y) 2: -1*(Z+X+Y+1)
// bits 3:2, 0: Z=0, 1: Z=PCIN, 2: Z=P, 3: Z = C
// bit 4: sub in pre add
input [4:0] mode,
input signed [47:0] pcin,
output signed [47:0] pcout,
output signed [47-S:0] p);
parameter S = 0;
parameter USE_DPORT = "FALSE"; // enabling adds 1 reg to A path
parameter AREG = 1;
parameter BREG = 1; // 0 - 2
wire signed [47:0] dsp_p;
assign p = dsp_p[47:S];
DSP48E1
#(
.A_INPUT("DIRECT"), // "DIRECT" "CASCADE"
.B_INPUT("DIRECT"), // "DIRECT" "CASCADE"
.USE_DPORT(USE_DPORT),
.USE_MULT("MULTIPLY"),// "MULTIPLY" "DYNAMIC" "NONE"
.USE_SIMD("ONE48"), // "ONE48" "TWO24" "FOUR12"
// pattern detector - not used
.AUTORESET_PATDET("NO_RESET"), .MASK(48'h3fffffffffff),
.PATTERN(48'h000000000000), .SEL_MASK("MASK"),
.SEL_PATTERN("PATTERN"), .USE_PATTERN_DETECT("NO_PATDET"),
// register enables
.ACASCREG(1), // pipeline stages between A/ACIN and ACOUT (0, 1 or 2)
.ADREG(1), // pipeline stages for pre-adder (0 or 1)
.ALUMODEREG(1), // pipeline stages for ALUMODE (0 or 1)
.AREG(AREG), // pipeline stages for A (0, 1 or 2)
.BCASCREG(1), // pipeline stages between B/BCIN and BCOUT (0, 1 or 2)
.BREG(BREG), // pipeline stages for B (0, 1 or 2)
.CARRYINREG(1), // this and below are 0 or 1
.CARRYINSELREG(1),
.CREG(1),
.DREG(1),
.INMODEREG(1),
.MREG(1),
.OPMODEREG(1),
.PREG(1))
dsp48_i
(
// status
.OVERFLOW(),
.PATTERNDETECT(), .PATTERNBDETECT(),
.UNDERFLOW(),
// outs
.CARRYOUT(),
.P(dsp_p),
// control
.ALUMODE({2'd0, mode[1:0]}),
.CARRYINSEL(3'd0),
.CLK(clock),
.INMODE({1'b0,mode[4],3'b100}),
.OPMODE({1'b0,mode[3:2],4'b0101}),
// signal inputs
.A({5'd0,a}), // 30
.B(b), // 18
.C(c), // 48
.CARRYIN(1'b0),
.D(d), // 25
// cascade ports
.ACOUT(),
.BCOUT(),
.CARRYCASCOUT(),
.MULTSIGNOUT(),
.PCOUT(pcout),
.ACIN(30'h0),
.BCIN(18'h0),
.CARRYCASCIN(1'b0),
.MULTSIGNIN(1'b0),
.PCIN(pcin),
// clock enables
.CEA1(ce1), .CEA2(ce2),
.CEAD(1'b1),
.CEALUMODE(1'b1),
.CEB1(ce1), .CEB2(ce2),
.CEC(1'b1),
.CECARRYIN(1'b1),
.CECTRL(1'b1), // opmode
.CED(1'b1),
.CEINMODE(1'b1),
.CEM(cem), .CEP(cep),
.RSTA(1'b0),
.RSTALLCARRYIN(1'b0),
.RSTALUMODE(1'b0),
.RSTB(1'b0),
.RSTC(1'b0),
.RSTCTRL(1'b0),
.RSTD(1'b0),
.RSTINMODE(1'b0),
.RSTM(1'b0),
.RSTP(1'b0)
);
endmodule // dsp48_wrap_f
Ex2:
/ /p = c + b * a 3 cycles if r else p = p + b * a
// p = c + b * a 3 cycles if r else p = p + b * a
module macc
(
input clock,
input [2:0] ce, // bit 0 = a, 1 = b , 2 = c
input r, // reset accumulator to c + a*b
input signed [24:0] a,
input signed [17:0] b,
input signed [47:0] c,
output signed [47-S:0] p;
parameter S = 0;
parameter AREG = 1; // 0 - 2
parameter BREG = 1; // 0 - 2
wire signed [47:0] dsp_p;
assign p = dsp_p[47:S];
// X+Y is usually the multiplier output (M)
// Z is either P, PCIN or C
// bit 1:0: 0: Z+X+Y 3:Z-(X+Y) 1: -Z + (X+Y) 2: -1*(Z+X+Y+1)
// bits 3:2, 0: Z=0, 1: Z=PCIN, 2: Z=P, 3: Z = C
// bit 4: sub in pre add
wire [4:0] mode = {1'b0, r ? 2'b11 : 2'b10, 2'b00};
DSP48E1
#(
.A_INPUT("DIRECT"), // "DIRECT" "CASCADE"
.B_INPUT("DIRECT"), // "DIRECT" "CASCADE"
.USE_DPORT("FALSE"),
.USE_MULT("MULTIPLY"),// "MULTIPLY" "DYNAMIC" "NONE"
.USE_SIMD("ONE48"), // "ONE48" "TWO24" "FOUR12"
// pattern detector - not used
.AUTORESET_PATDET("NO_RESET"), .MASK(48'h3fffffffffff),
.PATTERN(48'h000000000000), .SEL_MASK("MASK"),
.SEL_PATTERN("PATTERN"), .USE_PATTERN_DETECT("NO_PATDET"),
// register enables
.ACASCREG(1), // pipeline stages between A/ACIN and ACOUT (0, 1 or 2)
.ADREG(1), // pipeline stages for pre-adder (0 or 1)
.ALUMODEREG(1), // pipeline stages for ALUMODE (0 or 1)
.AREG(AREG), // pipeline stages for A (0, 1 or 2)
.BCASCREG(1), // pipeline stages between B/BCIN and BCOUT (0, 1 or 2)
.BREG(BREG), // pipeline stages for B (0, 1 or 2)
.CARRYINREG(1), // this and below are 0 or 1
.CARRYINSELREG(1),
.CREG(1),
.DREG(1),
.INMODEREG(1),
.MREG(1),
.OPMODEREG(1),
.PREG(1))
dsp48_i
(
// status
.OVERFLOW(),
.PATTERNDETECT(), .PATTERNBDETECT(),
.UNDERFLOW(),
// outs
.CARRYOUT(),
.P(dsp_p),
// control
.ALUMODE({2'd0, mode[1:0]}),
.CARRYINSEL(3'd0),
.CLK(clock),
.INMODE({1'b0,mode[4],3'b100}),
.OPMODE({1'b0,mode[3:2],4'b0101}),
// signal inputs
.A({5'd0,a}), // 30
.B(b), // 18
.C(c), // 48
.CARRYIN(1'b0),
.D(25'd0), // 25
// cascade ports
.ACOUT(),
.BCOUT(),
.CARRYCASCOUT(),
.MULTSIGNOUT(),
.PCOUT(),
.ACIN(30'h0),
.BCIN(18'h0),
.CARRYCASCIN(1'b0),
.MULTSIGNIN(1'b0),
.PCIN(48'h0),
// clock enables
.CEA1(1'b1), .CEA2(ce[0]),
.CEAD(1'b1),
.CEALUMODE(1'b1),
.CEB1(1'b1), .CEB2(ce[1]),
.CEC(ce[2]),
.CECARRYIN(1'b1),
.CECTRL(1'b1), // opmode
.CED(1'b1),
.CEINMODE(1'b1),
.CEM(1'b1), .CEP(1'b1),
.RSTA(1'b0),
.RSTALLCARRYIN(1'b0),
.RSTALUMODE(1'b0),
.RSTB(1'b0),
.RSTC(1'b0),
.RSTCTRL(1'b0),
.RSTD(1'b0),
.RSTINMODE(1'b0),
.RSTM(1'b0),
.RSTP(1'b0)
);
endmodule
Ex3:(35bit * 25bit,级联)
// wide multiply using 2x DSP48E1
// p = ((a * b) + c), 4 clock pipe delay
`timescale 1ns / 1ps
// wide multiply using 2x DSP48E1
// p = ((a * b) + c), 4 clock pipe delay
module mult_35x25
(
input clock,
input signed [24:0] a,
input signed [34:0] b,
input signed [47:0] c,
output signed [64:0] p);
wire signed [29:0] low_acout;
wire signed [47:0] low_pcout;
wire [47:0] p_low3;
reg [16:0] p_low4;
DSP48E1 #(.A_INPUT("CASCADE"), .AREG(1), .BREG(2)) dsp48_high
(
// status
.OVERFLOW(), .PATTERNDETECT(), .PATTERNBDETECT(), .UNDERFLOW(),
// outs
.P(p[64:17]), .CARRYOUT(),
// control
.ALUMODE(4'b0), .CARRYINSEL(3'd0),
.CLK(clock),
.INMODE(5'b00000),
.OPMODE(7'b1010101), // a*b + pcin >> 17
// signal inputs
.A(30'b0), .B(b[34:17]), .C(48'b0), .CARRYIN(1'b0), .D(25'b0),
// cascade ports
.ACOUT(), .BCOUT(), .CARRYCASCOUT(), .MULTSIGNOUT(), .PCOUT(),
.ACIN(low_acout), .BCIN(18'h0), .CARRYCASCIN(1'b0), .MULTSIGNIN(1'b0),
.PCIN(low_pcout),
// clock enables, resets
.CEA1(1'b1), .CEA2(1'b1), .CEAD(1'b1), .CEALUMODE(1'b1),
.CEB1(1'b1), .CEB2(1'b1), .CEC(1'b1), .CECARRYIN(1'b1),
.CECTRL(1'b1), .CED(1'b1), .CEINMODE(1'b1), .CEM(1'b1), .CEP(1'b1),
.RSTA(1'b0), .RSTALLCARRYIN(1'b0), .RSTALUMODE(1'b0),
.RSTB(1'b0), .RSTC(1'b0), .RSTCTRL(1'b0), .RSTD(1'b0),
.RSTINMODE(1'b0), .RSTM(1'b0), .RSTP(1'b0)
);
DSP48E1 #(.ACASCREG(1), .AREG(1), .BREG(1)) dsp48_low
(
// status
.OVERFLOW(), .PATTERNDETECT(), .PATTERNBDETECT(), .UNDERFLOW(),
// outs
.P(p_low3), .CARRYOUT(),
// control
.ALUMODE(4'b0), .CARRYINSEL(3'd0),
.CLK(clock),
.INMODE(5'b00000), .OPMODE(7'b0110101),
// signal inputs
.A({{5{a[24]}},a}), .B({1'b0,b[16:0]}),
.C(c),
.CARRYIN(1'b0),
.D(25'b0),
// cascade ports
.ACOUT(low_acout), .BCOUT(), .CARRYCASCOUT(), .MULTSIGNOUT(), .PCOUT(low_pcout),
.ACIN(30'h0), .BCIN(18'h0), .CARRYCASCIN(1'b0), .MULTSIGNIN(1'b0), .PCIN(48'h0),
// clock enables, resets
.CEA1(1'b1), .CEA2(1'b1), .CEAD(1'b1), .CEALUMODE(1'b1),
.CEB1(1'b1), .CEB2(1'b1), .CEC(1'b1), .CECARRYIN(1'b1),
.CECTRL(1'b1), .CED(1'b1), .CEINMODE(1'b1), .CEM(1'b1), .CEP(1'b1),
.RSTA(1'b0), .RSTALLCARRYIN(1'b0), .RSTALUMODE(1'b0),
.RSTB(1'b0), .RSTC(1'b0), .RSTCTRL(1'b0), .RSTD(1'b0),
.RSTINMODE(1'b0), .RSTM(1'b0), .RSTP(1'b0)
);
always @ (posedge clock)
begin
p_low4 <= p_low3[16:0];
end
assign p[16:0] = p_low4;
initial
begin
$dumpfile("dump.vcd");
$dumpvars(0);
end
endmodule