为了便于读者理解,首先用MATLAB实现计算sqrt(x2+y2)的Cordic算法,代码如下:
function Xout = mysqrt (x, y); K = 8; An = 1; for i =1: K
a(i) = 1/(2^(i));
An =An*sqrt(1+1/(4^i)); end
%anger = atan(a); %计算出的角度 theta = 0;
for i = 1:K
sigma = -sign(y);
x = x - sigma*y/(2^i); y = y + sigma*x/(2^i); % z = z - sigma*a(i); end
Xout= x/An;
经过测试,上述程序可利用Cordic算法来计算输入数据平方和的根。
② Verilog代码
module mysqrt(clk, x, y, fout, fy); input clk; input [15:0] x; input [15:0] y;
output [15:0] fout; output [15:0] fy; reg [15:0] fout; reg [15:0] fy;
//采用8级流水线来实现
wire [15:0] x1, y1 ,x2, y2, x3, y3, x4, y4, x5, y5; wire [15:0] x6, y6 ,x7, y7, x8, y8; //
reg [15:0] xtemp, ytemp;
reg addx1, addx2, addx3, addx4, addx5, addx6, addx7, addx8; reg addy1, addy2, addy3, addy4, addy5, addy6, addy7, addy8;
always @(posedge clk) begin xtemp <= x; ytemp <= y;
fout <= x8; fy <= y8;
if(ytemp[15] == 0) begin addx1 <= 1; addy1 <= 0; end
else begin
addx1 <= 0; addy1 <= 1; end
if(y1[15] == 0) begin addx2 <= 1; addy2 <= 0; end
else begin
addx2 <= 0; addy2 <= 1; end
if(y2[15] == 0) begin addx3 <= 1; addy3 <= 0; end
else begin
addx3 <= 0; addy3 <= 1; end
if(y3[15] == 0) begin addx4 <= 1; addy4 <= 0; end
else begin
addx4 <= 0; addy4 <= 1; end
if(y4[15] == 0) begin
addx5 <= 1; addy5 <= 0; end
else begin
addx5 <= 0; addy5 <= 1; end
if(y5[15] == 0) begin addx6 <= 1; addy6 <= 0; end
else begin
addx6 <= 0; addy6 <= 1; end
if(y6[15] == 0) begin addx7 <= 1; addy7 <= 0; end
else begin
addx7 <= 0; addy7 <= 1; end
if(y7[15] == 0) begin addx8 <= 1; addy8 <= 0; end
else begin
addx8 <= 0; addy8 <= 1; end end
//第1次迭代模块
addandsub addandsub1x( .A(xtemp),
.B({ytemp[15],ytemp[15:1]}), .ADD(addx1), .Q(x1), .CLK(clk));
addandsub addandsub1y( .A(ytemp),
.B({xtemp[15],xtemp[15:1]}),
.ADD(addy1), .Q(y1), .CLK(clk));
//第2次迭代模块
addandsub addandsub2x( .A(x1),
.B({{2{y1[15]}},y1[15:2]}), .ADD(addx2), .Q(x2), .CLK(clk));
addandsub addandsub2y( .A(y1),
.B({{2{x1[15]}},x1[15:2]}), .ADD(addy2), .Q(y2), .CLK(clk));
//第3次迭代模块
addandsub addandsub3x( .A(x2),
.B({{3{y2[15]}},y2[15:3]}), .ADD(addx3), .Q(x3), .CLK(clk));
addandsub addandsub3y( .A(y2),
.B({{3{x2[15]}},x2[15:3]}), .ADD(addy3), .Q(y3), .CLK(clk));
//第4次迭代模块
addandsub addandsub4x( .A(x3),
.B({{4{y3[15]}},y3[15:4]}), .ADD(addx4), .Q(x4), .CLK(clk));
addandsub addandsub4y( .A(y3),
.B({{4{x3[15]}},x3[15:4]}), .ADD(addy4), .Q(y4), .CLK(clk));
//第5次迭代模块
addandsub addandsub5x( .A(x4),
.B({{5{y4[15]}},y4[15:5]}), .ADD(addx5), .Q(x5), .CLK(clk));
addandsub addandsub5y( .A(y4),
.B({{5{x4[15]}},x4[15:5]}), .ADD(addy5), .Q(y5), .CLK(clk));
//第6次迭代模块
addandsub addandsub6x( .A(x5),
.B({{6{y5[15]}},y5[15:6]}), .ADD(addx6), .Q(x6), .CLK(clk));
addandsub addandsub6y( .A(y5),
.B({{6{x5[15]}},x5[15:6]}), .ADD(addy6), .Q(y6), .CLK(clk));
//第7次迭代模块
addandsub addandsub7x( .A(x6),
.B({{7{y6[15]}},y6[15:7]}), .ADD(addx7), .Q(x7), .CLK(clk));
addandsub addandsub7y(
.A(y6),
.B({{7{x6[15]}},x6[15:7]}), .ADD(addy7), .Q(y7), .CLK(clk));
//第8次迭代
addandsub addandsub8x( .A(x7),
.B({{8{y7[15]}},y7[15:8]}), .ADD(addx8), .Q(x8), .CLK(clk));
addandsub addandsub8y( .A(y7),
.B({{8{x7[15]}},x7[15:8]}), .ADD(addy8), .Q(y8), .CLK(clk));
endmodule
上述程序的RTL级结构如图比较复杂,这里就不再给出。在ModelSim 6.2b中完成仿真,其结果如图2-35所示,如竖线所标,输入为170、170时,经过8个时钟周期,输出248,近似等于 ,如果对输出计算精度有更高的要求,则可加大迭代次数。
图2-35 Cordic算法的仿真结果示意图 2.7 本章小结 本章简要介绍了Verilog硬件描述语言的发展历史和技术特点;然后介绍了相关的基本语法,这是进行FPGA设计所必须的基础知识。读者如果想要了解Verilog语言更多的细节,可参考关于Verilog语言的专著。最后给出了典型的Verilog实例,包括基本的触发器、译码器设计,常用的算术运算模块以及高级的Cordic算法模块,希望读者从中体会到Verilog的开发技巧,初步具备Verilog设计开发的基本能力。 <<上一节 下一节>> 相关链接
因篇幅问题不能全部显示,请点此查看更多更全内容