在设计中,经常出现除法运算,实现方法:
 1、移位操作
 2、取模取余
 3、调用除法器IP核
 4、查找表
简单学习除法器IP。
 网上很多IP翻译文档,不详细介绍,记录几个重要的点:
 1、三种算法模式(不同模式所消耗的资源类型不同)
 
 2、分清除数和被除数;余数模式的选择
 
 3、延迟输出的周期可配置
 
除法器IP的关键信号:
 可以看到仍然是axis接口,所以在给数据时候,仍遵循tready和tvaild握手则数据有效的原则
 
 给定输入的除数以及被除数有效信号和数据,由于握手,所以只有在输出的对应tready信号准备好,才能给定输入的相关信号
代码如下:
`timescale 1ns / 1psmodule DIVIDE_IP(input                CLK                         ,input                RST                         ,output      [15:0]   REMINDER                    ,output      [17:0]   QUOEITINR     );reg           r_axis_divisor_tvalid  = 'b0      ;  reg  [15:0]   r_axis_divisor_tdata   = 'b0      ;  reg           r_axis_dividend_tvalid = 'b0     ; reg  [23:0]   r_axis_dividend_tdata  = 'b0     ;wire [15:0]   s_axis_divisor_tdata             ;wire [23:0]   s_axis_dividend_tdata            ;    wire [39:0]   m_axis_dout_tdata                ;assign        s_axis_divisor_tvalid =  r_axis_divisor_tvalid ;assign        s_axis_divisor_tdata  =  r_axis_divisor_tdata  ;assign        s_axis_dividend_tvalid=  r_axis_dividend_tvalid;assign        s_axis_dividend_tdata =  r_axis_dividend_tdata ;assign        REMINDER              =  m_axis_dout_tdata[15:0]; //余数assign        QUOEITINR             =  m_axis_dout_tdata[39:16]; //商div_gen_0 u_div_gen_0 (.aclk                  (CLK                   ),    // input wire aclk.s_axis_divisor_tvalid (s_axis_divisor_tvalid ),    // input wire s_axis_divisor_tvalid.s_axis_divisor_tready (s_axis_divisor_tready ),    // output wire s_axis_divisor_tready.s_axis_divisor_tdata  (s_axis_divisor_tdata  ),    // input wire [15 : 0] s_axis_divisor_tdata.s_axis_dividend_tvalid(s_axis_dividend_tvalid),    // input wire s_axis_dividend_tvalid.s_axis_dividend_tready(s_axis_dividend_tready),    // output wire s_axis_dividend_tready.s_axis_dividend_tdata (s_axis_dividend_tdata ),    // input wire [23 : 0] s_axis_dividend_tdata.m_axis_dout_tvalid    (m_axis_dout_tvalid    ),    // output wire m_axis_dout_tvalid.m_axis_dout_tdata     (m_axis_dout_tdata     )     // output wire [39 : 0] m_axis_dout_tdata
);always @(posedge CLK)beginif(RST)beginr_axis_divisor_tvalid     <= 'b0;r_axis_divisor_tdata      <= 'd0; endelse if(s_axis_divisor_tready)beginr_axis_divisor_tvalid     <= 'b1;//r_axis_divisor_tdata      <= r_axis_divisor_tdata + 'd1; //除数r_axis_divisor_tdata      <= r_axis_divisor_tdata + 'd4; //除数endelsebeginr_axis_divisor_tvalid     <= 'b0;r_axis_divisor_tdata      <= 'd0; endendalways @(posedge CLK)beginif(RST)beginr_axis_dividend_tvalid     <= 'b0;r_axis_dividend_tdata      <= 'd0; //被除数endelse if(s_axis_dividend_tready)beginr_axis_dividend_tvalid     <= 'b1;r_axis_dividend_tdata      <= r_axis_dividend_tdata + 'd5; //被除数endelse beginr_axis_dividend_tvalid     <= 'b0;r_axis_dividend_tdata      <= 'd0; //被除数endend
endmodule
TB:
`timescale 1ns / 1nsmodule DIVIDE_IP_TB;reg         CLK        ;reg         RST        ;DIVIDE_IP u_DIVIDE_IP(.CLK   (CLK       ),.RST   (RST       ));initial                    CLK = 1'b1;always    #10              CLK = ~CLK;initial beginRST           = 'b1;#100;RST           = 'b0;end
endmodule仿真情况:
 无余数的情况,可以看到m_axis_dout_tvalid高时,对应的余数都是0
 
有余数的情况:
 
出现的问题:
 IP输入信号出现高阻态。
 如下图所示,给了正确的r_axis_divisor_tvalid、r_axis_divisor_tdata、r_axis_dividend_tvalid、r_axis_dividend_tdata信号,并将其赋值给除法器IP的输入s_axis_divisor_tvalid、s_axis_divisor_tdata、s_axis_dividend_tvalid、s_axis_dividend_tdata。
 可以看到tvalid信号正常赋值,tdata却出现高阻态。
 原因:赋值时,tvalid位宽1bit,可不定义直接赋值;但等于多bit位宽的tdata来说,赋值assign之前,需要先定义。
wire [15:0]   s_axis_divisor_tdata             
wire [23:0]   s_axis_dividend_tdata            

以上简单记录除法器IP的使用方法,后续可应用。比如A / B的操作,若有余数则在商的基础上加1.若没有余数就是商。
 这样我们就可以先调用除法器IP,得到商和余数。
 判断,当余数==0时,r_tmp = 商,否则r_tmp = 商 + 'b1