参考链接
问题描述
在使用Verilog编写模块时,有时会需要进行多个浮点数中取最大/最小值的操作,而Vivado中提供的floating-point IP核并未提供取极值的相关操作。这里实现了一个float_max模块用于获取两个输入浮点数中的最大值。
C实现
单精度浮点数比较大小的过程见float_max函数,这里在主函数中将float_max和max函数的输出结果进行了比较,用于保证float_max的正确性。
#include <stdio.h>
#include <math.h>
float float_max(float a, float b) {
unsigned int a_hex = *((unsigned int*)&a);
unsigned int b_hex = *((unsigned int*)&b);
unsigned int a_flag = a_hex & 0x80000000;
unsigned int a_floor = a_hex & 0x7f800000;
unsigned int a_tail = a_hex & 0x007fffff;
unsigned int b_flag = b_hex & 0x80000000;
unsigned int b_floor = b_hex & 0x7f800000;
unsigned int b_tail = b_hex & 0x007fffff;
if (a == b) {
return a;//or b
}
else if (a != b && a_flag > b_flag) {
return b;
}
else if (a != b && a_flag < b_flag) {
return a;
}
else if (a != b && a_flag == b_flag && a_flag == 0 && a_floor > b_floor) {
return a;
}
else if (a != b && a_flag == b_flag && a_flag == 0 && a_floor < b_floor) {
return b;
}
else if (a != b && a_flag == b_flag && a_flag == 0 && a_floor == b_floor && a_tail > b_tail) {
return a;
}
else if (a != b && a_flag == b_flag && a_flag == 0 && a_floor == b_floor && a_tail < b_tail) {
return b;
}
else if (a != b && a_flag == b_flag && a_flag > 0 && a_floor > b_floor) {
return b;
}
else if (a != b && a_flag == b_flag && a_flag > 0 && a_floor < b_floor) {
return a;
}
else if (a != b && a_flag == b_flag && a_flag > 0 && a_floor == b_floor && a_tail > b_tail) {
return b;
}
else if (a != b && a_flag == b_flag && a_flag > 0 && a_floor == b_floor && a_tail < b_tail) {
return a;
}
return 0;
}
float max(float a, float b) {
if (a > b)
return a;
else
return b;
}
int main()
{
float a = 0;
float b = 0;
for (a = -10; a < 10; a += 0.01) {
for (b = -10; b < 10; b += 0.01) {
if (fabs(float_max(a,b) - max(a,b)) > 1e-3) {
printf("%f %f %f %f\n", a, b, float_max(a,b), max(a,b));
return 0;
}
}
}
printf("done:)");
return 0;
}
Verilog实现
在Vivado中,float_max函数可改写为如下代码:
module float_max #(
localparam precision = 32
) (
input [31 : 0] a,
input [31 : 0] b,
output [31 : 0] c
);
wire a_flag = a[31];
wire [7 : 0] a_floor = a[30 : 23];
wire [22 : 0] a_tail = a[22 : 0];
wire b_flag = b[31];
wire [7 : 0] b_floor = b[30 : 23];
wire [22 : 0] b_tail = b[22 : 0];
wire a_e_b = ~(| (a[31 : 0] ^ b[31 : 0]));
//wire a_flag_g_b_flag = a_flag & (~b_flag);
wire a_flag_l_b_flag = (~a_flag) & b_flag;
wire a_flag_e_b_flag = ~(a_flag ^ b_flag);
wire a_floor_g_b_floor = a_floor > b_floor ? 1 : 0;
wire a_floor_l_b_floor = a_floor < b_floor ? 1 : 0;
wire a_floor_e_b_floor = ~(| (a_floor[7 : 0] ^ b_floor[7 : 0]));
wire a_tail_g_b_tail = a_tail > b_tail ? 1 : 0;
wire a_tail_l_b_tail = a_tail < b_tail ? 1 : 0;
//wire a_tail_e_b_tail = ~(| (a_tail[22 : 0] ^ b_tail[22 : 0]));
wire condition1 = a_e_b;
//wire condition2 = ~a_e_b & a_flag_g_b_flag;
wire condition3 = ~a_e_b & a_flag_l_b_flag;
wire condition4 = ~a_e_b & a_flag_e_b_flag & (~a_flag) & a_floor_g_b_floor;
//wire condition5 = ~a_e_b & a_flag_e_b_flag & (~a_flag) & a_floor_l_b_floor;
wire condition6 = ~a_e_b & a_flag_e_b_flag & (~a_flag) & a_floor_e_b_floor & a_tail_g_b_tail;
//wire condition7 = ~a_e_b & a_flag_e_b_flag & (~a_flag) & a_floor_e_b_floor & a_tail_l_b_tail;
//wire condition8 = ~a_e_b & a_flag_e_b_flag & (a_flag) & a_floor_g_b_floor;
wire condition9 = ~a_e_b & a_flag_e_b_flag & (a_flag) & a_floor_l_b_floor;
//wire condition10= ~a_e_b & a_flag_e_b_flag & (a_flag) & a_floor_e_b_floor & a_tail_g_b_tail;
wire condition11= ~a_e_b & a_flag_e_b_flag & (a_flag) & a_floor_e_b_floor & a_tail_l_b_tail;
assign c = (condition1 | condition3 | condition4 | condition6 | condition9 | condition11) ? a : b;
endmodule
本人刚刚接触Verilog开发,编写的代码可能存在错误,欢迎大佬批评指正。