CPU 速通系列 3-2:DIV 模块
代码
Path src/cpu/div.sv
1`include "defines.svh"
2
3module div (
4
5 input logic clk,
6 input logic rst,
7
8 input logic signed_div_i,
9 input logic [31:0] opdata1_i,
10 input logic [31:0] opdata2_i,
11 input logic start_i,
12 input logic annul_i,
13
14 output logic [63:0] result_o,
15 output logic ready_o
16);
17
18 logic [32:0] div_temp;
19 logic [ 5:0] cnt;
20 logic [64:0] dividend;
21 logic [ 1:0] state;
22 logic [31:0] divisor;
23 logic [31:0] temp_op1;
24 logic [31:0] temp_op2;
25
26 assign div_temp = {1'b0, dividend[63:32]} - {1'b0, divisor};
27
28 always_ff @(posedge clk) begin
29 if (rst == `RstEnable) begin
30 state <= `DivFree;
31 ready_o <= `DivResultNotReady;
32 result_o <= {`ZeroWord, `ZeroWord};
33 end else begin
34 case (state)
35 `DivFree: begin //DivFree状态
36 if (start_i == `DivStart && annul_i == 1'b0) begin
37 if (opdata2_i == `ZeroWord) begin
38 state <= `DivByZero;
39 end else begin
40 state <= `DivOn;
41 cnt <= 6'b000000;
42 if (signed_div_i == 1'b1 && opdata1_i[31] == 1'b1) begin
43 temp_op1 <= ~opdata1_i + 1;
44 end else begin
45 temp_op1 <= opdata1_i;
46 end
47 if (signed_div_i == 1'b1 && opdata2_i[31] == 1'b1) begin
48 temp_op2 <= ~opdata2_i + 1;
49 end else begin
50 temp_op2 <= opdata2_i;
51 end
52 dividend <= {`ZeroWord, `ZeroWord};
53 dividend[32:1] <= temp_op1;
54 divisor <= temp_op2;
55 end
56 end else begin
57 ready_o <= `DivResultNotReady;
58 result_o <= {`ZeroWord, `ZeroWord};
59 end
60 end
61 `DivByZero: begin //DivByZero状态
62 dividend <= {`ZeroWord, `ZeroWord};
63 state <= `DivEnd;
64 end
65 `DivOn: begin //DivOn状态
66 if (annul_i == 1'b0) begin
67 if (cnt != 6'b100000) begin
68 if (div_temp[32] == 1'b1) begin
69 dividend <= {dividend[63:0], 1'b0};
70 end else begin
71 dividend <= {div_temp[31:0], dividend[31:0], 1'b1};
72 end
73 cnt <= cnt + 1;
74 end else begin
75 if ((signed_div_i == 1'b1) && ((opdata1_i[31] ^ opdata2_i[31]) == 1'b1)) begin
76 dividend[31:0] <= (~dividend[31:0] + 1);
77 end
78 if ((signed_div_i == 1'b1) && ((opdata1_i[31] ^ dividend[64]) == 1'b1)) begin
79 dividend[64:33] <= (~dividend[64:33] + 1);
80 end
81 state <= `DivEnd;
82 cnt <= 6'b000000;
83 end
84 end else begin
85 state <= `DivFree;
86 end
87 end
88 `DivEnd: begin //DivEnd状态
89 result_o <= {dividend[64:33], dividend[31:0]};
90 ready_o <= `DivResultReady;
91 if (start_i == `DivStop) begin
92 state <= `DivFree;
93 ready_o <= `DivResultNotReady;
94 result_o <= {`ZeroWord, `ZeroWord};
95 end
96 end
97 endcase
98 end
99 end
100
101endmodule
解读
实现了一个除法模块。
设计意图
简要而言,该模块旨在实现一个有符号除法器,用于执行两个32位有符号操作数的除法运算。
具体而言,该模块需要完成以下任务:
-
接收时钟信号和复位信号
-
接收有关除法运算的输入信号,包括被除数、除数、有符号除法标志、启动信号和终止信号
-
根据输入信号的控制,执行除法运算
-
输出除法运算的结果和准备信号
端口
-
clk
:输入时钟信号 -
rst
:输入复位信号 -
signed_div_i
:输入有符号除法标志 -
opdata1_i
:输入操作数1(被除数) -
opdata2_i
:输入操作数2(除数) -
start_i
:输入启动信号 -
annul_i
:输入终止信号 -
result_o
:输出结果 -
ready_o
:输出准备信号
实现思路
这个除法模块使用了有限状态机(FSM)来执行除法运算。模块内部包含以下变量:
-
div_temp
:用于存储部分商的临时变量 -
cnt
:用于计数 -
dividend
:存储被除数 -
state
:表示当前状态 -
divisor
:存储除数 -
temp_op1
:临时存储操作数1 -
temp_op2
:临时存储操作数2
模块在时钟上升沿时进行状态转换和计算。当复位信号为有效时,将模块状态初始化为DivFree
,结果和准备信号初始化为未就绪状态,并将临时变量和寄存器清零。在其他情况下,根据当前状态进行相应的操作。
在DivFree
状态下,如果收到启动信号且终止信号未激活,执行以下操作:
-
检查除数是否为零,如果是,则进入
DivByZero
状态,表示除以零错误。 -
否则,进入
DivOn
状态,设置计数器为0,并根据有符号除法标志对操作数1和操作数2进行调整,将调整后的值存储到临时变量中,并将被除数和除数初始化为零,然后将调整后的操作数1存储到被除数中,将操作数2存储到除数中。
在DivByZero
状态下,将被除数设置为零,并将状态转换为DivEnd
。
在DivOn
状态下,如果终止信号未激活,执行以下操作:
- 如果计数器不等于最大计数值(6’b100
000),执行以下操作:
-
检查部分商的最高位是否为1,如果是,则将被除数左移一位并在最低位补零,否则,将临时变量的低32位存储到被除数的低32位,并将被除数的最高位置为1。
-
计数器加1。
-
否则,执行以下操作:
-
如果是有符号除法且操作数1的符号位与操作数2的符号位不同,将被除数的低32位取反加1。
-
如果是有符号除法且操作数1的符号位与被除数的最高位不同,将被除数的高32位取反加1。
-
将状态转换为
DivEnd
,计数器清零。
-
在DivEnd
状态下,输出除法运算的结果和准备信号。如果收到终止信号,则将状态转换为DivFree
,结果和准备信号重新初始化为未就绪状态。
这样,该除法模块能够根据输入的操作数和控制信号执行有符号除法运算,并输出运算结果和准备信号。
参考资料
本文与 AI 合作完成。