3. CORDIC流水线设计
任务目标
设计一个16级流水线结构的CORDIC处理器,在旋转模式下计算给定角度对应的正弦/余弦值。通过流水线寄存器将迭代运算在时间上展开,使每个时钟周期都能启动一次新的角度计算,从而提升系统吞吐率。最终与单次迭代(非流水)结构进行资源与延迟对比。
实现方案
采用16级流水线,每级执行一次CORDIC微旋转。输入角度为16位定点数(格式:1位符号 + 15位小数,表示范围[-π, π)),输出为16位正弦/余弦定点值(1位符号 + 14位整数 + 1位小数,实际输出范围[-1,1])。每级包含:角度累加器、X/Y坐标旋转、以及对应的反正切常数ROM。流水线寄存器在每级之间插入,确保数据同步推进。
关键完整代码
// 文件: cordic_pipeline.v
module cordic_pipeline #(
parameter DATA_WIDTH = 16,
parameter STAGES = 16
)(
input wire clk,
input wire rst_n,
input wire valid_in,
input wire [DATA_WIDTH-1:0] angle_in, // 定点角度输入
output reg valid_out,
output reg [DATA_WIDTH-1:0] sin_out,
output reg [DATA_WIDTH-1:0] cos_out
);
// 反正切常数表 (弧度 * 2^15 / π * 2^15 归一化)
// 实际存储值 = atan(2^-i) * 2^15 / (π/2) 的定点近似
localparam [DATA_WIDTH-1:0] ATAN_TABLE [0:STAGES-1] = '{
16'd8192, 16'd4836, 16'd2555, 16'd1297,
16'd651, 16'd326, 16'd163, 16'd81,
16'd41, 16'd20, 16'd10, 16'd5,
16'd3, 16'd1, 16'd1, 16'd0
};
// 流水线寄存器组
reg [DATA_WIDTH-1:0] x_reg [0:STAGES];
reg [DATA_WIDTH-1:0] y_reg [0:STAGES];
reg [DATA_WIDTH-1:0] z_reg [0:STAGES];
reg valid_reg [0:STAGES];
integer i;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
for (i = 0; i <= STAGES; i = i + 1) begin
x_reg[i] <= 0;
y_reg[i] <= 0;
z_reg[i] <= 0;
valid_reg[i] <= 0;
end
end else begin
// 输入级
x_reg[0] <= 16'd19898; // 增益补偿常数 K = 0.60725 * 2^15 ≈ 19898
y_reg[0] <= 0;
z_reg[0] <= angle_in;
valid_reg[0] <= valid_in;
// 16级流水线处理
for (i = 0; i < STAGES; i = i + 1) begin
// 根据z的符号决定旋转方向
wire [DATA_WIDTH-1:0] x_shift = x_reg[i] >>> i;
wire [DATA_WIDTH-1:0] y_shift = y_reg[i] >>> i;
wire [DATA_WIDTH-1:0] atan_val = ATAN_TABLE[i];
if (z_reg[i][DATA_WIDTH-1] == 1'b0) begin // z为正,顺时针旋转
x_reg[i+1] <= x_reg[i] - y_shift;
y_reg[i+1] <= y_reg[i] + x_shift;
z_reg[i+1] <= z_reg[i] - atan_val;
end else begin // z为负,逆时针旋转
x_reg[i+1] <= x_reg[i] + y_shift;
y_reg[i+1] <= y_reg[i] - x_shift;
z_reg[i+1] <= z_reg[i] + atan_val;
end
valid_reg[i+1] <= valid_reg[i];
end
// 输出级
valid_out <= valid_reg[STAGES];
cos_out <= x_reg[STAGES];
sin_out <= y_reg[STAGES];
end
end
endmodule
测试平台与验证
// 文件: tb_cordic_pipeline.v
`timescale 1ns/1ps
module tb_cordic_pipeline;
reg clk = 0, rst_n = 0, valid_in = 0;
reg [15:0] angle_in;
wire valid_out;
wire [15:0] sin_out, cos_out;
cordic_pipeline dut (
.clk(clk), .rst_n(rst_n), .valid_in(valid_in),
.angle_in(angle_in), .valid_out(valid_out),
.sin_out(sin_out), .cos_out(cos_out)
);
always #5 clk = ~clk;
// 测试角度:30° = π/6 ≈ 0.5236 rad
// 定点表示:0.5236 * 2^15 ≈ 17157
initial begin
#20 rst_n = 1;
#10 valid_in = 1; angle_in = 16'd17157;
#10 valid_in = 0;
// 等待流水线输出(16个周期 + 1个周期输出寄存器)
#340;
if (valid_out) begin
$display("sin(30°) = %d (期望约8192)", sin_out);
$display("cos(30°) = %d (期望约14199)", cos_out);
end
#50 $finish;
end
endmodule
运行与对比方法
- 仿真运行:使用Vivado/ModelSim运行上述测试平台,观察valid_out拉高时sin_out和cos_out的值。
- 判定标准:sin(30°)输出应在8192±50范围内(对应0.5±0.0015),cos(30°)输出应在14199±50范围内(对应0.866±0.0015)。
- 性能对比:与迭代结构(单次计算需16个周期)相比,流水线结构在连续输入时每个周期均可输出一次结果,吞吐率提升16倍;代价是寄存器资源增加约16倍(每级需3个16位寄存器+1个有效位)。
常见问题
- 增益补偿:CORDIC迭代后幅度会放大约1.647倍,因此输入X初始值需预乘1/K(K≈0.60725),代码中已用19898(=0.60725×2^15)补偿。
- 角度范围:本设计仅支持[-π/2, π/2]输入,超出范围需先进行象限转换(将角度映射到第一/四象限)。
- 流水线延迟:从输入到输出共需17个时钟周期(16级+1级输出寄存器),但吞吐率为每周期1个结果。