3. CORDIC流水线结构设计
任务目标
在迭代式CORDIC中,每次旋转依赖上一次结果,需N个时钟周期才能完成一次向量旋转,吞吐率仅为1/N。本案例设计并实现一个8级流水线CORDIC,每个时钟周期可启动一次新的旋转计算,从而将吞吐率提升至1(即每个时钟周期输出一个结果),并给出与迭代结构的性能对比方法。
设计思路
流水线CORDIC将迭代运算中的每一级旋转固化为独立的组合逻辑级,级间用寄存器暂存中间结果(包括旋转角度余量z和旋转方向判定所需的y符号)。每一级只需执行一次移位加/减法,方向由上一级寄存的y符号决定。由于各级并行工作,不同输入向量处于不同流水级,因此每个时钟周期均可接收新输入并输出一个已完成8次旋转的结果。
关键完整代码
module cordic_pipeline #(
parameter DW = 16, // 数据位宽
parameter N = 8 // 流水级数(迭代次数)
)(
input wire clk,
input wire rst_n,
input wire [DW-1:0] x_in,
input wire [DW-1:0] y_in,
input wire [DW-1:0] z_in, // 目标角度(弧度×2^14,范围[-π/2, π/2])
output reg [DW-1:0] x_out,
output reg [DW-1:0] y_out,
output reg [DW-1:0] z_out
);
// 反正切常数表(弧度×2^14):atan(2^(-i)),i=0..7
localparam signed [DW-1:0] ATAN_TABLE [0:N-1] = '{
16'd51472, // atan(1) ≈ 0.7854
16'd30386, // atan(0.5) ≈ 0.4636
16'd16055, // atan(0.25)≈ 0.2450
16'd8150, // atan(0.125)≈0.1244
16'd4091, // atan(0.0625)≈0.0624
16'd2047, // atan(0.03125)≈0.0312
16'd1024, // atan(0.015625)≈0.0156
16'd512 // atan(0.0078125)≈0.0078
};
// 各级流水线寄存器
reg signed [DW-1:0] x_stage [0:N];
reg signed [DW-1:0] y_stage [0:N];
reg signed [DW-1:0] z_stage [0:N];
integer i;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
for (i = 0; i <= N; i = i + 1) begin
x_stage[i] <= 0;
y_stage[i] <= 0;
z_stage[i] <= 0;
end
end else begin
// 输入级
x_stage[0] <= x_in;
y_stage[0] <= y_in;
z_stage[0] <= z_in;
// 流水线各级:第i级执行第i次旋转(i=0..N-1)
for (i = 0; i < N; i = i + 1) begin
if (y_stage[i][DW-1] == 1'b0) begin // y≥0,顺时针旋转
x_stage[i+1] <= x_stage[i] + (y_stage[i] >>> i);
y_stage[i+1] <= y_stage[i] - (x_stage[i] >>> i);
z_stage[i+1] <= z_stage[i] - ATAN_TABLE[i];
end else begin // y<0,逆时针旋转
x_stage[i+1] <= x_stage[i] - (y_stage[i] >>> i);
y_stage[i+1] <= y_stage[i] + (x_stage[i] >>> i);
z_stage[i+1] <= z_stage[i] + ATAN_TABLE[i];
end
end
// 输出级
x_out <= x_stage[N];
y_out <= y_stage[N];
z_out <= z_stage[N];
end
end
endmodule
测试平台与性能对比
// 流水线CORDIC测试平台(节选)
module tb_cordic_pipeline;
reg clk = 0, rst_n = 0;
reg signed [15:0] x_in, y_in, z_in;
wire signed [15:0] x_out, y_out, z_out;
integer cycle_count;
real x_real, y_real, angle_real;
cordic_pipeline dut(.*);
always #5 clk = ~clk;
initial begin
// 复位
#20 rst_n = 1;
// 输入向量 (x,y) = (10000, 5000),旋转角度 0(仅做向量模式)
x_in = 16'sd10000; y_in = 16'sd5000; z_in = 0;
cycle_count = 0;
// 连续输入8个不同向量,观察输出间隔
repeat (8) begin
@(posedge clk);
x_in <= x_in + 16'sd100; // 改变输入以观察吞吐
y_in <= y_in - 16'sd50;
cycle_count = cycle_count + 1;
end
// 等待流水线排空
repeat (10) @(posedge clk);
$display("吞吐率验证:每周期输入1个向量,输出连续有效");
$finish;
end
// 计算输出模长与输入模长比值(应接近CORDIC增益1.6467)
always @(posedge clk) begin
if (rst_n) begin
x_real = $itor(x_out) / 16384.0;
y_real = $itor(y_out) / 16384.0;
angle_real = $itor(z_out) / 16384.0;
$display("t=%0t x_out=%0d y_out=%0d z_out=%0d 模长比=%0.4f",
$time, x_out, y_out, z_out,
$sqrt(x_real*x_real + y_real*y_real) /
($sqrt(10000.0*10000.0 + 5000.0*5000.0)/16384.0));
end
end
endmodule
运行与验证方法
- 仿真运行:使用Vivado/ModelSim/Verilator运行上述测试平台。输入向量为(10000, 5000),z_in=0(向量模式)。
- 功能正确性判定:观察输出模长与输入模长之比,应在1.6467±0.02范围内(8级迭代的理论增益为∏√(1+2^(-2i))≈1.6467)。z_out应趋近于0(表示旋转完成)。
- 吞吐率对比:将本模块与迭代式CORDIC(单次计算需N个时钟)对比——在测试平台中统计:从第一个输入有效到第一个输出有效的时钟周期数(流水线延迟=N=8),以及连续两个输出之间的间隔(应为1个时钟周期)。迭代结构连续输出间隔为N个时钟周期。
性能对比要点
| 指标 | 迭代结构 | 流水线结构 |
|---|---|---|
| 延迟(首输出) | N个周期 | N个周期 |
| 吞吐率(连续输出间隔) | N个周期/结果 | 1个周期/结果 |
| 资源消耗 | 1级迭代逻辑复用 | N级迭代逻辑并行 |
| 适用场景 | 资源受限、低速率 | 高速连续数据流 |
验证结论:当测试平台连续输入向量且每个时钟周期均有效时,流水线CORDIC每个时钟周期输出一个有效结果,而迭代结构需要等待N个周期才能完成当前向量才能接收下一个。本设计以N倍逻辑资源换取N倍吞吐率提升,适用于雷达信号处理、OFDM同步等连续高速旋转场景。