对于FPGA来说尽量不要做除法,因为比较消耗资源,可以用截位的方式实现对2的N次方的除法,比如N/2就等于N右移一位。
我们今天来讲使用移位减的方法实现一般的除法操作:
实现流程为:
1、将除数、被除数转换为正数,2、确定符号位;3、被除数从最高位开始取数,与除数比较: 被除数大于等于除数:商为1,余数为差值 被除数小于除数 :商为0,余数不变4、依次向下,直至结束输入数据I_data_ina为被除数,I_data_inb为除数:input wire I_data_en , // 输入数据有效标志input wire [C_DATA_WITH-1:0] I_data_ina , // 输入被除数input wire [C_DATA_WITH-1:0] I_data_inb , // 输入除数output reg O_data_en , // 输出数据有效标志
首先对符号位进行判断:
always @(posedge I_sys_clk) if(I_data_en) S_out_flag <= I_data_ina[C_DATA_WITH-1]^I_data_inb[C_DATA_WITH-1] ;
然后将被除数和除数进行取绝对值(这里为了方便做移位减法中的减法操作,将除数置为负数):
/// 被除数转换为正数always @(posedge I_sys_clk) if(I_data_en) if(I_data_ina[C_DATA_WITH-1]) S_data_ina_abs <= ~I_data_ina + 1; else S_data_ina_abs <= I_data_ina ; else S_data_ina_abs <= (S_data_ina_abs <<1); /// 除数取负值always @(posedge I_sys_clk) if(I_data_en) if(I_data_inb[C_DATA_WITH-1]) S_data_inb_abs <= I_data_inb ; else S_data_inb_abs <= ~I_data_inb + 1;
然后就是循环移位求差值的过程了:
/// 比较差值assign S_data_cut_temp = S_data_ina_temp + S_data_inb_abs ; /// 循环求差always @(posedge I_sys_clk) if(S_data_en[0]) begin S_data_ina_temp <= {{(C_DATA_WITH-1){1'b0}},S_data_ina_abs[C_DATA_WITH-2]}; S_data_out_temp <= {(C_DATA_WITH){1'b0}}; end else if(S_data_cut_temp[C_DATA_WITH-1]) begin S_data_ina_temp <= {S_data_ina_temp[C_DATA_WITH-2:0],S_data_ina_abs[C_DATA_WITH-2]}; S_data_out_temp <= {S_data_out_temp[C_DATA_WITH-2:0],1'b0}; end else begin S_data_ina_temp <= {S_data_cut_temp[C_DATA_WITH-2:0],S_data_ina_abs[C_DATA_WITH-2]}; S_data_out_temp <= {S_data_out_temp[C_DATA_WITH-2:0],1'b1}; end
代码在数据有效标志来了之后先将被除数的绝对值送入,将商置1,然后判断差值:差值大于等于0时,商为1,余数为差值,差值小于0时,商为0,余数不变。
最后仿真的结果为: