调用Xilinx IP实现乘除法运算部件
-
调用Xilinx IP实现乘法运算部件
wire [31:0] src1,src2;
wire [63:0] unsigned_prod;
wire [63:0] signed_prod;assign unsigned_prod = src1*src2;
assign signed_prod = signed(src1)*signed(src2); -
调用 Xilinx IP 实现除法运算部件
在工程导航栏中点击"IP Catalog",然后在右侧出现的窗口中搜索div。在搜索结果中双击"Divider Generator" 项,打开除法器 IP 设置界面,依次设置参数,如图5-2所示。
对于除法器的名字,读者可以根据自己的喜好进行调整。在"Channel Settings" 选项卡中,我们首先要对除法器IP的算法进行选择,我们建议采用 Radix2 算法,采用Radix2这种算法实现的除法器的优点是资源消耗少,缺点是完成运算要求的迭代周期数多。
在"Channel Settings"选项卡中还可以选择除法运算是有符号除法还是无符号除法。与前面介绍的乘法器IP类似,这里也需要生成有符号和无符号两个除法器IP,才能分别用于实现DIV和DIVU指令。将Remainder Type选择为Remainder,以确保余数类型是整数型。在"Options"选项卡中,选择多少拍处理一个除法,这个拍数是连续处理多个除法的间隔拍数,不是一个除法处理完成的拍数。
c
u_unsigned_div u_unsigned_divider (
.aclk (clk),
.s_axis_dividend_tdata (divider_dividend),
.s_axis_dividend_tready (unsigned_dividend_tready),
.s_axis_dividend_tvalid (unsigned_dividend_tvalid),
.s_axis_divisor_tdata (divider_divisor),
.s_axis_divisor_tready (unsigned_divisor_tready),
.s_axis_divisor_tvalid (unsigned_divisor_tvalid),
.m_axis_dout_tdata (unsigned_divider_res),
.m_axis_dout_tvalid (unsigned_dout_tvalid)
);
u_signed_div u_signed_divider (
.aclk (clk),
.s_axis_dividend_tdata (divider_dividend),
.s_axis_dividend_tready (signed_dividend_tready),
.s_axis_dividend_tvalid (signed_dividend_tvalid),
.s_axis_divisor_tdata (divider_divisor),
.s_axis_divisor_tready (signed_divisor_tready),
.s_axis_divisor_tvalid (signed_divisor_tvalid),
.m_axis_dout_tdata (signed_divider_res),
.m_axis_dout_tvalid (signed_dout_tvalid)
);
- s_axis_dividend_tdata 对应计算时输入的被除数数据
- s_axis_divisor_tdata 对应计算时输入的除数数据
- 计算得到的商和余数结果统一从商和余数通道中的64位信号m_axis_dout_tdata中输出。其中前32位是商,后32位是余数
- tvalid、tready信号是一对"握手"控制信号,其工作原理类似于我们在CPU流水线之间使用的valid、allowin信号。tvalid是请求信号,tready是应答信号。当时钟上升沿到来时,如果采样得到tvalid和tready都等于1,则请求发起方和接收方之间完成一次成功的握手。
- 我们 假设在执行流水阶段调用所生成的除法器IP。在除法指令处于执行流水级且没有对除法器成功输入数据的时候,同时将s_axis_dividend_tvalid和s_axis_divisor_tvalid置为1.当发现s_axis_dividend_tready和s_axis_divisor_tready反馈为1后(此时在一个时钟上升沿同时看到tvalid和tready为1,表示握手成功),需要将s_axis_dividend_tvalid和s_axis_divisor_tready清0.也就是确保握手成功的那个时钟上升沿之后的s_axis_dividend_tvalid和s_axis_divisor_tvalid为0.只要我们确保握手成功的那个时钟上升沿之后的s_axis_dividend_tvalid和s_axis_divisor_tready为0.只要我们保证s_axis_dividend_tvalid和s_axis_divisor_tready一定同时置为1,那么这里生成的除法器IP反馈的s_axis_dividend_tready和s_axis_divisor_tready一定也同时置为1.握手成功后,tvalid一定要撤销,否则对于除法器IP来说,它会认为又有一个新的除法运算。完成输入数据的握手之后,除法指令就需要在执行流水级等待除法器IP最终输出结果。当m_axis_dout_tvalid置为1时,表示除法计算完成。此时除法指令就可以从m_axis_dout_tdata上取出计算结果,进入流水线的后续阶段。
c
assign unsigned_dividend_tvalid = es_valid && (es_inst_div_wu | es_inst_mod_wu) && !unsigned_dividend_sent;
assign unsigned_divisor_tvalid = es_valid && (es_inst_div_wu | es_inst_mod_wu) && !unsigned_divisor_sent;
always @ (posedge clk) begin
if (reset) begin
unsigned_dividend_sent <= 1'b0;
end else if (unsigned_dividend_tready && unsigned_dividend_tvalid) begin
unsigned_dividend_sent <= 1'b1;
end else if (es_ready_go && ms_allowin) begin
unsigned_dividend_sent <= 1'b0;
end
if (reset) begin
unsigned_divisor_sent <= 1'b0;
end else if (unsigned_divisor_tready && unsigned_divisor_tvalid) begin
unsigned_divisor_sent <= 1'b1;
end else if (es_ready_go && ms_allowin) begin
unsigned_divisor_sent <= 1'b0;
end
end
reg signed_dividend_sent;
reg signed_divisor_sent;
assign signed_dividend_tvalid = es_valid && (es_inst_div_w | es_inst_mod_w) && !signed_dividend_sent;
assign signed_divisor_tvalid = es_valid && (es_inst_div_w | es_inst_mod_w) && !signed_divisor_sent;
always @ (posedge clk) begin
if (reset) begin
signed_dividend_sent <= 1'b0;
end else if (signed_dividend_tready && signed_dividend_tvalid) begin
signed_dividend_sent <= 1'b1;
end else if (es_ready_go && ms_allowin) begin
signed_dividend_sent <= 1'b0;
end
if (reset) begin
signed_divisor_sent <= 1'b0;
end else if (signed_divisor_tready && signed_divisor_tvalid) begin
signed_divisor_sent <= 1'b1;
end else if (es_ready_go && ms_allowin) begin
signed_divisor_sent <= 1'b0;
end
end