http://blog.chinaaet.com/justlxy/p/5100053166大佬博客,講的非常有條理的
1,基礎知識
(1)定點數的基礎認知:
首先例如一個16位的數表示的定點數的范圍是:(MAX:16‘d32767 MIN: -32767#2^15-1#’)最高位符號位,三位整數位,其余的12位是小數位的話,那么
它的精度有小數部分決定:1/4096=0.0244140625
可表示數的范圍為:(0.0244140625*4095)=0.999755859375,然后加上整數的最大表示值7,即極限最大值為7.999755859375。
(2)浮點數的認知
浮點數就是指整數和小數位數不確定的數字的表達,實際上采用的就是咱們常用的科學計數法。如1.23*10^2采用的是基數(10),指數(2),尾數(1.23)以及一個符號位來表示。這里實際上是采用指數方法實現了小數點的浮動。
在 IEEE 標准中,浮點數是將特定長度的連續字節的所有二進制位分割為特定寬度的符號域,指數域和尾數域三個域,其中保存的值分別用於表示給定二進制浮點數中的符號,指數和尾數。這樣,通過尾數和可以調節的指數(所以稱為"浮點")就可以表達給定的數值了。具體的格式參見下面的圖例:
上圖中可以看出S表示符號位,EXponent表示指數位,也就是“浮動”的指數位,指數的范圍在32位的系統中(0-2^8 -1)/2 也就是0-127,在double型位2^11位浮動指數。
2.FPGA浮點數的定點化
首先明確輸入的浮點數是什么格式的:其次明白要輸出的定點數又是怎樣的,最后兩者之間的轉換也就明了了:
輸入的浮點數是::f[31:0]表示一個單精度32位浮點數,f[31]是符號位,其為‘0’表示正數、為‘1’表示負數;f[30:23]這8位為指數位,為了能表示負指數,將在實際指數的基礎上加上127得到的結果存入f[30:23];f[22:0]表示小數位(尾數),類似科學計數法,不過采用了省略整數位(2進制的科學計數法整數位必定是1)1。那么這個浮點數要轉換成定點數,就需要先判斷指數位與127的關系,小於127,則說明該指數位是正數,那么轉化成定點數的話就需要將{8'd1,float_in[22:0]}右移127-float_in[30:23]位,否則左移float_in[30:23]-127位。
代碼稍微貼一下
module float2fixed_pipeline ( input [31:0] float_in, input enable, input clk, input rst, output reg [31:0] fixed_out, output reg valid ); reg [30:0] M_copy; reg [4:0] shift_value; reg shift_direction; //0, shift left; 1, shift right reg sign; //符號位 reg valid_count; // Pipeline level 1 always @ (posedge clk or posedge rst) begin //synchronous enable and asynchronous reset if(rst) begin shift_value <= 5'd0; shift_direction <= 1'b0; sign <= 1'b0; M_copy <= 31'd0; end else if(enable) begin sign <= float_in[31]; M_copy <= {8'd1,float_in[22:0]}; if(float_in[30:23] <= 8'd127) begin //E <= 127,shfit {1'b1,M} right to get I(指數) and F(小數) shift_direction <= 1'b1; shift_value <= 8'd127 - float_in[30:23]; end else begin //E > 127,shfit {1'b1,M} left to get I and F shift_direction <= 1'b0; shift_value <= float_in[30:23] - 8'd127;//2^7-1 end end else begin //enable = 0, Maintain the previous value shift_value <= shift_value; shift_direction <= shift_direction; sign <= sign; M_copy <= M_copy; end end // Output logic always @ (posedge clk or posedge rst) begin //synchronous enable and asynchronous reset if(rst) begin fixed_out <= 32'd0; end else if(enable) begin if(shift_direction) begin //E <= 127,shfit {1'b1,M} right to get I and F fixed_out <= {sign,M_copy >> shift_value}; end else begin //E > 127,shfit {1'b1,M} left to get I and F fixed_out <= {sign,M_copy << shift_value}; end end else begin //enable = 0, Maintain the previous value fixed_out <= fixed_out; end end // The valid output logic always @ (posedge clk or posedge rst) begin //asynchronous reset if(rst) begin valid <= 1'b0; valid_count <= 1'd0; end else if(enable) begin if(valid_count == 1'd1) begin //Maintain valid as ture unless reset valid <= 1'b1; valid_count <= valid_count; end else begin valid_count <= 1'b1; valid <= 1'b0; end end else begin //enable = 0, Maintain the previous value valid <= valid; valid_count <= valid_count; end end endmodule
3.FPGA定點數的浮點化
也是想明白輸入的定點數格式為最高位是符號位,然后緊接着8位整數位,最后是23位小數位。我們需要注意的是轉換后的輸出的浮點數最高位符號位,然后是8位的指數位,最后是23位小數位,其表達的浮點數的大小為
,將小數位從高到低依次存入f[22:0]的從高到低的位數,不足23位則在末尾補0,例如小數位只有“10011001”則f[22:0]="10011001000000000000000",這樣就可以用23位存儲空間表示24位的數據,變相增加了精度。另外還有一些特殊編碼,如無窮大、0、NAN和非正規數,這里沒有考慮,待以后用到再細究吧。
手算整理思路:
首先是浮點數的指數位的確定:看定點數整數部分的最高非零位的位置N,那么exp=N-1,
然后是浮點數的小數位的確定:這里用到了127這個所謂的偏置數以及流水線的設計方法:
// Output logic always @ (posedge clk or posedge rst) begin //synchronous enable and asynchronous reset if(rst) begin float_out <= 32'd0; end else if(enable) begin if(fixed_shift_reg3[22] == 1'b1) begin float_out <= {fixed_shift_reg3[23],8'd127 - shift_count3 - 8'd1 + ((shift_direction3) ? 8'd8 : 8'd0),fixed_shift_reg3[21:0],1'd0}; end else if(fixed_shift_reg3[21] == 1'b1) begin float_out <= {fixed_shift_reg3[23],8'd127 - shift_count3 - 8'd2 + ((shift_direction3) ? 8'd8 : 8'd0),fixed_shift_reg3[20:0],2'd0}; end else if(fixed_shift_reg3[20] == 1'b1) begin float_out <= {fixed_shift_reg3[23],8'd127 - shift_count3 - 8'd3 + ((shift_direction3) ? 8'd8 : 8'd0),fixed_shift_reg3[19:0],3'd0}; end else begin //The fixed-point input is zero, -0 will be cast to 0 too. float_out <= {1'b0,8'd127,23'd0}; end end else begin //enable = 0, Maintain the previous value float_out <= float_out; end end
小數位的移動在三級流水線中分別根據的是fixed_in[22:11],fixed_shift_reg1[22:17],fixed_shift_reg1[22:20].不等於0的時候不移位,直接拼接,等於0的時候分別移位12,6,3位,將每級流水線中的移位次數記錄下來為shift_count3.。。。。。。
關於流水線的verilog基礎還是不扎實,所以下一篇接上流水線的解剖~