verilog实现:比流水线法更简单的cordic算法
2018-01-06 23:22
211 查看
cordic原理不再赘诉
传统的流水线法有两个缺点:
1.代码冗长,16段流水线意味着要写16段很相近的代码,我自己在写的过程中都觉得十分疲惫。各位博主的代码也基本都长达380+行。
2.多段流水会带来较长周期的时延。以16段流水为例,如果不考虑预处理,则时延长达16周期,若考虑第一个周期的预处理,则时延为17周期。
流水线的方式去实现有两种方法:
1.手动实现右移操作,例如: x2 <= x1 + {y1[16],y1[16:1]};
通过算术右移来实现,即: x2 <= x1 + (y1 >>> 1); 但是算术右移操作需要将寄存器定义为有符号型(即在reg或wire后增加signed)。
此外,如果将代码中的阻塞赋值变为非阻塞赋值 也能完成,但是会增加1个时钟周期时延。
本人新学verilog 欢迎讨论!
传统的流水线法有两个缺点:
1.代码冗长,16段流水线意味着要写16段很相近的代码,我自己在写的过程中都觉得十分疲惫。各位博主的代码也基本都长达380+行。
2.多段流水会带来较长周期的时延。以16段流水为例,如果不考虑预处理,则时延长达16周期,若考虑第一个周期的预处理,则时延为17周期。
流水线的方式去实现有两种方法:
1.手动实现右移操作,例如: x2 <= x1 + {y1[16],y1[16:1]};
通过算术右移来实现,即: x2 <= x1 + (y1 >>> 1); 但是算术右移操作需要将寄存器定义为有符号型(即在reg或wire后增加signed)。
`timescale 1 ns/1ns module try_cordic( sin,cos, phase_in,clk); output reg signed [16:0]sin,cos; // 17位输出,sin输出正弦信号,cos输出余弦信号 input [15:0]phase_in; // 16位输入 input clk; // 时钟信号 parameter K = 16'h9b74; // 0.60725*2^16 ,把小数扩大2^16来减小误差 reg signed [16:0] x0=0,y0=0; //因为使用算术移位,因此需要定义有符号型 reg signed [16:0] temp1=0,temp2=0; // 作临时变量使用 reg signed [16:0] z=0; reg [1:0] quadrant; //象限 reg [15:0]rot[15:0]; //存储每次旋转的角度 integer i; initial begin temp1=K; temp2=0; rot[0]=16'h2000 ; //45 rot[1]=16'h12e4; //26.5651 rot[2]=16'h09fb ; //14.0362 rot[3]=16'h0511 ; //7.1250 rot[4]=16'h028b ; //3.5763 rot[5]=16'h0145 ; //1.7899 rot[6]=16'h00a3 ; //0.8952 rot[7]=16'h0051 ; //0.4476 rot[8]=16'h0028 ; //0.2238 rot[9]=16'h0014 ; //0.1119 rot[10]=16'h000a ; //0.0560 rot[11]=16'h0005 ; //0.0280 rot[12]=16'h0003 ; //0.0140 rot[13]=16'h0001 ; //0.0070 rot[14]=16'h0001 ; //0.0035 rot[15]=16'h0000 ; //0.0018 end always @(posedge clk) begin quadrant=phase_in[15:14]; // 输入的前两位表示象限 z={3'b0,phase_in[13:0]}; // z用于存储变换到第一象限后的角度 for(i=0;i<16;i=i+1) //迭代更新16次 begin if(z[16]) // 如果角度小于0,即旋转角度过大 begin x0 = temp1+(temp2>>>i); //使用算术右移需要带括号,因为优先级低于+号 y0 = temp2-(temp1>>>i); z = z+rot[i]; end else //如果旋转角度不够 begin x0 = temp1-(temp2>>>i); y0 = temp2+(temp1>>>i); z = z-rot[i]; end temp1=x0; //每循环一次需要把当前值赋给temp temp2=y0; end temp1=K; //16次迭代完成,temp重新置位,方便下个角度的计算 temp2=0; // 根据角度的象限作相应变换 case(quadrant) 2'b00:begin //第一象限 cos <= x0; sin <= y0; end 2'b01:begin //第二象限 cos <= ~(y0) + 1'b1; //-sin sin <= x0; //cos end 2'b10:begin //第三象限 cos <= ~(x0) + 1'b1; //-cos sin <= ~(y0) + 1'b1; //-sin end 2'b11:begin //第四象限 cos <= y0; //sin sin <= ~(x0) + 1'b1; //-cos end endcase end endmodule分析网上一直使用流水线法的原因:简化版本用到了算术移位,而算术移位是2001年才增加进来的,有些博主写的时候可能早在2001年以前,在那时恐怕只有流水线的方式才能实现。而后来的博主可能只是简单的模仿,并没有深究其他的方法。
此外,如果将代码中的阻塞赋值变为非阻塞赋值 也能完成,但是会增加1个时钟周期时延。
本人新学verilog 欢迎讨论!
相关文章推荐
- cordic算法原理及verilog实现
- 基于FPGA的cordic算法的verilog初步实现
- Cordic算法——verilog实现
- cordic算法verilog实现(复杂版)
- verilog实现基于Cordic算法的双曲函数计算
- verilog实现基于Cordic算法的双曲函数计算
- cordic算法原理及verilog实现
- 基于FPGA的CORDIC算法实现——Verilog版
- 使用C语言实现二维,三维绘图算法(3)-简单的二维分形
- [ASP]无限级分类的简单算法实现及代码重点讲解
- 用SHA1或MD5 算法加密数据(示例:对用户身份验证的简单实现)
- 简单算法 - 两个队列实现一个栈
- 一个CORDIC算法在圆周系统下的向量模式下获取角度的Verilog 程序
- JAVA简单分组的算法实现
- [算法]简单的字符串近似匹配算法实现
- 一个简单的随机数生成算法实现(C++)
- 用Java实现小球碰壁反弹的简单实例(算法十分简单)
- 【数据结构与算法】(三) c 语言栈的简单实现
- C# int to BCD encode(最简单的实现办法)BCD编码编程实现算法
- CRC算法原理及其Verilog实现