Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Inferring DSP48A1 on Spartan6

Status
Not open for further replies.

rudzz34

Newbie level 2
Joined
Mar 14, 2010
Messages
2
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,296
Will the following code infer two DSP48A1 slices? Will they if I use (*Use DSP48*) before the module declaration? If this won't infer DSP48A1 slices, what else would I need to add?
Code:
module tap(
		input clk,
		input [17:0] xn,
		input [35:0] addin,
		input [17:0] errmu,
		output reg [17:0] xn1,
		output reg [35:0] addout
    );


	always@(posedge clk) begin
		xn1 <= xn;
	end

	always@(posedge clk) begin
		addout <= addin + (wght * xn);
	end

	always@(posedge clk) begin
		wght <= wght + (errmu * xn);
	end
	
endmodule
 

Ok so I have restructured my code a bit. If you can't tell, I'm trying to implement an LMS Adaptive Filter using DSP48A1 slices on a Spartan6. Here I have a tap module and a coefficient update module. I would like each to use one DSP48A1 slice. I'm going to instantiate multiple of each(one coeff module for every tap module), and stitch them together as a Systolic FIR filter with the coeff modules feeding in the coefficients.

Am I correct in implementing these modules so that a DSP48A1 slice will be used for each?

Tap Module:
Code:
(* USE_DSP48="YES" *)
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: 		 John *****
// Create Date:    22:24:29 05/02/2011  
// Module Name:    tap 
// Project Name:   
// Target Devices:  Atlys Board - Spartan6(XC6SLX45)
// Description: Infer DSP48A1 Slice - Systolic FIR Tap w/ Coeff Input
//					 addout = (xin * win) + addin
//////////////////////////////////////////////////////////////////////////////////
module tap(
		input clk,
		input rst,
		input ce,
		input signed [17:0] xin,
		input signed [17:0] wn,
		input signed [47:0] addin,
		output signed [17:0] xout,
		output signed [47:0] addout
    );
	
	
	//Pipeline registers
	reg signed [35:0] M;
	reg signed [47:0] accum;
	reg signed [17:0] xin_r;
	reg signed [47:0] addin_r;

	//addout = (xin * win) + addin
	always@(posedge clk) begin
		if(rst) begin
			M <= 0;
			accum <= 0;
			xin_r <= 0;
			xin_r_r <= 0;
			wn_r <= 0;
			addin_r <= 0;
		end
		else if(ce == 1'b1) 
			begin
				xin_r <= xin;
				wn_r <= wn;
				
				M <= xin_r * wn_r;
				accum <= M + addin;
			end
	end
	assign addout = accum;
	assign xout = xin_r;
	
endmodule

Coefficient Module:
Code:
(* USE_DSP48="YES" *)
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: John *****
// Create Date:    20:31:48 05/04/2011 
// Module Name:    coeff 
// Project Name:  
// Target Devices:  Atlys Board - Spartan6(XC6SLX45)
// Description: Infer DSP48A1 Slice - New Coeff Generator - LMS Algorithm
//					 wout = wout + (xin * emu) - (truncated to 18 bits)
//////////////////////////////////////////////////////////////////////////////////
module coeff(
		input clk,
		input rst,
		input ce,
		input signed [17:0] xin,
		input signed [17:0] emu,
		output signed [17:0] wout,
    );

	//Pipeline registers
	reg signed [17:0] xin_r;
	reg signed [17:0] emu_r;
	reg signed [35:0] M;
	reg signed [47:0] wout_r;
	
	always@(posedge clk) begin
		if(rst) begin
			xin_r <= 0;
			emu_r <= 0;
			wout_r <= 0;
		end
		else if(ce == 1'b1)
			begin
				xin_r <= xin;
				emu_r <= emu;
				
				M <= xin_r * emu_r;
				wout_r <= wout_r + M;
			end
	end
	assign wout = wout_r[47:30];
endmodule

Error Signal Calculation:
Code:
(* USE_DSP48="YES" *)
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: 		John *****
// Create Date:    21:01:03 05/04/2011 
// Module Name:    errcalc 
// Project Name:    
// Target Devices:  Atlys Board - Spartan6(XC6SLX45)
// Description: Infer DSP48A1 Slice - Error Calculation
//					 
//////////////////////////////////////////////////////////////////////////////////
module errcalc(
		input clk,
		input rst,
		input ce,
		input signed [17:0] mu;
		input signed [17:0] xin,
		input signed [17:0] yin,
		output signed [17:0] err,
		output signed [17:0] emu
    );

	//Pipeline Registers
	reg signed [17:0] xin_r;
	reg signed [17:0] yin_r;
	reg signed [17:0] mu_r;
	reg signed [17:0] mu_r_r;
	
	reg signed [17:0] preadd;
	reg signed [47:0] emu_r;
	
	always@(posedge clk) begin
		if(rst) begin
			xin_r <= 0;
			yin_r <= 0;
			mu_r <= 0;
			mu_r_r <= 0;
			preadd <= 0;
			emu_r <= 0;
		end
		else if(ce == 1'b1)
			begin
				xin_r <= xin;
				yin_r <= yin;
				mu_r <= mu;
				mu_r_r <= mu_r;
				
				preadd <= xin_r - yin_r;
				emu_r <= mu_r_r * preadd;
			end
	end
	assign err = preadd;
	assign emu = emu_r;

endmodule
 

Am I correct in implementing these modules so that a DSP48A1 slice will be used for each?

AFAIK, you have to put verilog style attributes right before the "module" for it to take effect. So ...

Code:
`default_nettype none
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: 		 John *****
// Create Date:    22:24:29 05/02/2011  
// Module Name:    tap 
// Project Name:   
// Target Devices:  Atlys Board - Spartan6(XC6SLX45)
// Description: Infer DSP48A1 Slice - Systolic FIR Tap w/ Coeff Input
//					 addout = (xin * win) + addin
//////////////////////////////////////////////////////////////////////////////////
(* USE_DSP48="YES" *)
module tap(
		input  wire               clk,
		input  wire               rst,
		input  wire               ce,
		input  wire signed [17:0] xin,
		input  wire signed [17:0] wn,
		input  wire signed [47:0] addin,
		output wire signed [17:0] xout,
		output wire signed [47:0] addout
    );
	
	
	//Pipeline registers
	reg signed [35:0] M;
	reg signed [47:0] accum;
	reg signed [17:0] xin_r;
	reg signed [47:0] addin_r;

	//addout = (xin * win) + addin
	always@(posedge clk) begin
		if(rst) begin
			M <= 0;
			accum <= 0;
			xin_r <= 0;
			xin_r_r <= 0;
			wn_r <= 0;
			addin_r <= 0;
		end
		else if(ce == 1'b1) 
			begin
				xin_r <= xin;
				wn_r <= wn;
				
				M <= xin_r * wn_r;
				accum <= M + addin;
			end
	end
	assign addout = accum;
	assign xout = xin_r;
	
endmodule // tap
`default_nettype wire


Also note the "`default_nettype" + explicit "wire" declarations in the port list. That makes your code less vulnerable to the inevitable typo + verilog making up stuff (implicit net declarations, with the wrong typo'd name). Just remember to return it to the default of "`default_nettype wire" so you don't break other people's code that the project also might be using...

To be sure your design uses the "USE_DSP48" directive as intended, synthesize it. Then go over the synthesis log in the console and look for either the USE_DSP48 string, or for the name of the module "tap". There you will find details about how XST handles this module. And finally another way of knowing is to go the usage report in the design summary. That will also list the total number of DSP48 resources used in the design.

Hope that helps...
 

just synthesize the module -- XST will tell you what it does. also "addin_r" gets assigned, but not used. I've had pretty good luck with the basic DSP48 features being inferred from code. some of the advanced features still need manual instantiation. The big issue with inferred code is that you should explain it, otherwise someone will be tempted to take the output of one of the intermediate signals and use it.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top