# Vivado使用乘法器、除法器IP核实现乘除取余仿真
### 环境
Vivado 20.2   
## 添加并配置IP核
1. 打开vivado，找到对应IP核，如下图   
![](./vivado_ip_img/IPCore01.png)  
2. 先双击除法器IP核进入配置页面，如下图   
![](./vivado_ip_img/IPCore02.png)  
![](./vivado_ip_img/IPCore03.png)  
除法器配置默认即可，点击OK；后弹出界面，点击Generate   
如下图即配置完成   
![](./vivado_ip_img/IPCore04.png)  
3. 配置乘法器IP核   
![](./vivado_ip_img/IPCore05.png)  
上图使用十六位有符号数与十六位无符号数进行运算    
![](./vivado_ip_img/IPCore06.png)  
上图输出32位，间隔一个周期得到结果（电脑性能不佳可适当增加）   
4. 如下图即配置完成   
![](./vivado_ip_img/IPCore07.png)  
## 添加并编写仿真代码文件
1. 选择一个文件夹，创建例如ipcore_test.v文件   
2. 添加文件到vivado   
![](./vivado_ip_img/IPCore08.png)  
![](./vivado_ip_img/IPCore09.png)  
找到自己创建的.v文件路径并添加   
3. 完成如下图   
![](./vivado_ip_img/IPCore10.png)  
4. 复制示例代码   
![](./vivado_ip_img/IPCore11.png)  
双击打开.veo 示例代码文件   
![](./vivado_ip_img/IPCore12.png)  
复制上图红框中的代码到自己的仿真文件,如下图（我这是外部编辑器，vivado自带编辑器同理）   
![](./vivado_ip_img/IPCore13.png)  
上图的module与endmodule需要自己添加     
如下图，可以看到，除法器IP核在你自己的代码文件之下，表示被正确调用   
![](./vivado_ip_img/IPCore14.png)  
乘法器同理，打开.veo文件复制代码   
![](./vivado_ip_img/IPCore15.png)  
![](./vivado_ip_img/IPCore16.png)  
示例代码复制完成后如下图，这里我更改了实例名称（u_ 开头，不改没影响）   
![](./vivado_ip_img/IPCore17.png)  
5. 最后自己补全仿真代码，我这里这样写   
```verilog
`timescale 1ns / 1ps

module tb_ipcore_test();
  reg clk;                              //时钟变量
  reg signed [15:0] A;                  //有符号因数数据
  reg unsigned [15:0] B;                //无符号因数数据
  wire signed [31:0] P;                 //乘法器结果

  reg dividend_tvalid;                  //被除数有效使能，高为有效，低为无效
  reg signed [15:0] dividend_tdata;     //被除数数据
  reg divisor_tvalid;                   //除数有效使能，高为有效，低为无效
  reg signed [15:0] divisor_tdata;      //除数数据
  wire dout_tvalid;                     //输出电平，高为正确输出，低为错误输出
  wire [31:0] dout_tdata;               //除法器结果
  wire signed [15:0] quotient;          //商
  wire signed [15:0] remainder;         //余数


mult_gen_0 u_mult_gen_0 (
  .CLK(clk),  // input wire CLK
  .A(A),      // input wire [15 : 0] A
  .B(B),      // input wire [15 : 0] B
  .P(P)      // output wire [31 : 0] P
);

div_gen_0 u_div_gen_0 (
  .aclk(clk),                                      // input wire aclk
  .s_axis_divisor_tvalid(divisor_tvalid),    // input wire s_axis_divisor_tvalid
  .s_axis_divisor_tdata(divisor_tdata),      // input wire [15 : 0] s_axis_divisor_tdata
  .s_axis_dividend_tvalid(dividend_tvalid),  // input wire s_axis_dividend_tvalid
  .s_axis_dividend_tdata(dividend_tdata),    // input wire [15 : 0] s_axis_dividend_tdata
  .m_axis_dout_tvalid(dout_tvalid),          // output wire m_axis_dout_tvalid
  .m_axis_dout_tdata(dout_tdata)            // output wire [31 : 0] m_axis_dout_tdata
);
assign quotient = dout_tdata[31:16];    //除法器16位余数模式，高16位是商，低十六位是余数
assign remainder = dout_tdata[15:0];
always #5 clk = ~clk;                   //10ns周期时钟

initial begin
  clk = 0;

  A = 16'h7FFF;
  B = 16'hFFFF;
  dividend_tvalid = 1;
  dividend_tdata = 16'h7FFF;
  divisor_tvalid = 1;
  divisor_tdata = 16'hFFFF;
  #300;

  A = 16'h8001;
  B = 16'h0001;
  dividend_tvalid = 1;
  dividend_tdata = 16'h8001;
  divisor_tvalid = 1;
  divisor_tdata = 16'hFFFF;
  #300;

  $finish;
end
endmodule
```

6. 结果分析   
选中除B之外的所有变量，调整为有符号的十进制，B调整为无符号的十进制数   
![](./vivado_ip_img/IPCore19.png)  
下图可以看到，乘法器得到数据（一开始），在第一个周期得到结果，除法器得到数据，在第二十个周期得到结果   
![](./vivado_ip_img/IPCore18.png)  


