单片机的硬件串口,发送和接收完毕都有相应的标志位,例如TC(发送完成)和RXNE(接收完成)位。
FPGA则不同,FPGA采用的是AXI4-Stream协议,数据送入IP核后,经过固定数量的时钟周期后,就得到运算结果,没有任何标志位表明运算完成。
利用浮点数IP核(Floating-point),将32位有符号定点数(Int32)转换为单精度浮点数(float),只需要6个时钟周期,就能得到结果。如下图所示:
将两个单精度浮点数相加,需要11个时钟周期后,才能得到结果,如下图所示:
利用CORDIC库计算sin和cos三角函数的值,需要20个时钟周期才能得到结果,如图所示:
那么,连续进行多次运算,需要多少时钟周期呢?让我们来编写程序测试一下:
【测试程序】
测试工程下载地址:https://pan.baidu.com/s/1qGiy64RmYWvopXLUUDa3HQ(提取码:9red)
test.v:
module test();
reg clock = 0;
main main(clock);
always begin
#10 clock = ~clock;
end
endmodule
main.v:
module main(
input clock,
output reg [3:0] leds = 0
);
reg [31:0] fixed_in = 0;
wire [31:0] float_out;
wire float_out_valid;
floating_point_0 fixed_to_float(
.aclk(clock),
.s_axis_a_tdata(fixed_in),
.s_axis_a_tvalid(1),
.m_axis_result_tdata(float_out),
.m_axis_result_tvalid(float_out_valid)
);
wire [31:0] addition_out;
wire addition_out_valid;
floating_point_1 float_addition(
.aclk(clock),
.s_axis_a_tdata(float_out),
.s_axis_a_tvalid(float_out_valid),
.s_axis_b_tdata(32'h3f800000),
.s_axis_b_tvalid(1),
.m_axis_result_tdata(addition_out),
.m_axis_result_tvalid(addition_out_valid)
);
// 请注意: Phase Format选择Scaled Radians后
// 还要把Coarse Rotation勾上,才能计算-Pi至Pi(即-180至180°)的范围
// 否则只能计算-Pi/4至Pi/4 (即-45至45°)
reg signed [15:0] phase_in = 16'b111_0000000000000; // -1
wire [32:0] degree_in = (phase_in >>> 10) * 180; // 转换成角度, -1对应-180°
wire [15:0] cos_out;
wire [15:0] sin_out;
wire sincos_valid;
cordic_0 sincos(
.aclk(clock),
.s_axis_phase_tdata(phase_in),
.s_axis_phase_tvalid(1),
.m_axis_dout_tdata({sin_out, cos_out}), // Y_OUT, X_OUT
.m_axis_dout_tvalid(sincos_valid)
);
always @(posedge clock) begin
fixed_in <= fixed_in + 1;
if (phase_in == 16'b001_0000000000000) begin // +1
phase_in <= 16'b111_0000000000000; // -1
leds <= leds + 1;
end
else
phase_in <= phase_in + 16'b000_0010000000000; // +0.125
end
endmodule
添加IP核的方法是,在vivado软件中点击左边的IP catalog
然后在右边搜索出要添加的IP核的名称,双击即可开始配置:
两者都选择non-blocking(非阻塞)模式。
注意配置CORDIC的时候,Phase Format要选择Scaled Radians(不带π的弧度单位),还必须要把Coarse Rotation勾上。
把Coarse Rotation勾上才能计算-180°~180°,否则只能计算-45°~45°。
配置完成后,点击Generate,就可以在代码中引用了。
来看下程序运行结果:(可以在右键菜单中将数字配置为浮点或定点方式显示)
可以看到,IP核的输入端每个时钟周期都在送入数据,IP核的输出端从valid信号变为高电平后,也是每个时钟周期都输出一次计算结果。
定点数转浮点数的模块,第一个时钟周期送入第一个数据后(注意输入的valid信号一直为1),第六个周期得到第一个数据的转换结果。第二个周期送入第二个数据后,在第七个周期得到转换结果。输出的valid信号是在第六个周期变成高电平的,说明到第六个周期才把第一个数据转换出来。
两个浮点数相加的模块,从第六个时钟周期开始送入数据(因为输入的valid信号连的是上一个模块输出的valid信号),同样也是每个时钟周期都送入一个数据。到第6+11=17个时钟周期,就开始得到计算结果了,每个周期都出一个新结果。
sin、cos三角函数计算模块,花了20个时钟周期才得到第一个结果,之后是每一个时钟周期都出一个新结果。
这表明,AXI4-Stream协议是按时钟周期来运行的,并没有任何表明运算完成的标志位。
每个时钟周期都可以送入数据,第一个数据运算出来需要花一定的时间,之后每个时钟都算出来新数据。
可以放大了看三角函数的运算结果,完全正确:
误差还是有一点:sin(0)算出来是-6.1×10^-5,其实就是0