-
Notifications
You must be signed in to change notification settings - Fork 1
/
ex.v
165 lines (134 loc) · 4.37 KB
/
ex.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
`include "defines.v"
module ex(input wire rst,
input wire [`AluOpBus] aluop_i,
input wire [`AluSelBus] alusel_i,
input wire [`RegBus] reg1_i,
input wire [`RegBus] reg2_i,
input wire [`RegAddrBus] wd_i,
input wire wreg_i,
input wire [`RegBus] inst_i,
input wire [`RegBus] link_address_i,
output reg [`RegAddrBus] wd_o,
output reg wreg_o,
output reg [`RegBus] wdata_o,
output wire [`AluOpBus] aluop_o,
output wire [`RegBus] reg2_o,
output wire [`RegBus] mem_addr_o);
reg [`RegBus] logicout;
reg [`RegBus] shiftres;
reg [`RegBus] arithmeticres;
wire [`RegBus] reg2_i_mux;//第二个数补码
wire [`RegBus] reg1_i_not;//反码
wire [`RegBus] result_sum;//加法结果
wire ov_sum;//保存溢出
wire reg1_eq_reg2;//相等
wire reg1_lt_reg2;//小于
assign aluop_o = aluop_i;
assign mem_addr_o = reg1_i+{{16{inst_i[15]}}, inst_i[15:0]};
assign reg2_o = reg2_i;
always @(*) begin
if (rst == `RstEnable) begin
logicout <= `ZeroWord;
end else begin
case (aluop_i)
`EXE_OR_OP: begin
logicout <= reg1_i | reg2_i;
end
`EXE_AND_OP: begin
logicout <= reg1_i & reg2_i;
end
`EXE_NOR_OP: begin
logicout <= ~(reg1_i | reg2_i);
end
`EXE_XOR_OP: begin
logicout <= reg1_i ^ reg2_i;
end
default: begin
logicout <= `ZeroWord;
end
endcase
end //if
end //always
always @(*) begin
if (rst == `RstEnable) begin
shiftres <= `ZeroWord;
end
else begin
case (aluop_i)//运算类型
`EXE_SLL_OP: begin
shiftres <= reg2_i << reg1_i[4:0];
end
`EXE_SRL_OP: begin
shiftres <= reg2_i >> reg1_i[4:0];
end
`EXE_SRA_OP: begin
shiftres <= ({32{reg2_i[31]}} << (6'd32-{1'b0, reg1_i[4:0]}))
| reg2_i >> reg1_i[4:0];
end
default: begin
shiftres <= `ZeroWord;
end
endcase
end //if
end //always
assign reg2_i_mux = ((aluop_i == `EXE_SUB_OP) || (aluop_i == `EXE_SUBU_OP) ||
(aluop_i == `EXE_SLT_OP))
? (~reg2_i)+1:reg2_i;
assign result_sum = reg1_i+reg2_i_mux;
assign ov_sum = ((!reg1_i[31] && !reg2_i_mux[31]) && result_sum[31]) ||
((reg1_i[31] && reg2_i_mux[31]) && (!result_sum[31]));
assign reg1_lt_reg2 = ((aluop_i == `EXE_SLT_OP)) ?
((reg1_i[31] && !reg2_i[31]) ||
(!reg1_i[31] && !reg2_i[31] && result_sum[31]) ||
(reg1_i[31] && reg2_i[31] && result_sum[31]))
:(reg1_i < reg2_i);
assign reg1_i_not = ~reg1_i;
always @(*) begin
if (rst == `RstEnable) begin
arithmeticres <= `ZeroWord;
end
else begin
case (aluop_i)
`EXE_SLT_OP, `EXE_SLTU_OP: begin
arithmeticres <= reg1_lt_reg2;
end
`EXE_ADD_OP, `EXE_ADDU_OP, `EXE_ADDI_OP, `EXE_ADDIU_OP: begin
arithmeticres <= result_sum;
end
`EXE_SUB_OP, `EXE_SUBU_OP: begin
arithmeticres <= result_sum;
end
default: begin
arithmeticres <= `ZeroWord;
end
endcase
end
end
always @(*) begin
wd_o <= wd_i;
if (((aluop_i == `EXE_ADD_OP) || (aluop_i == `EXE_ADDI_OP) ||
(aluop_i == `EXE_SUB_OP)) && (ov_sum == 1'b1)) begin
wreg_o <= `WriteDisable;
end
else begin
wreg_o <= wreg_i;
end
case (alusel_i)
`EXE_RES_LOGIC: begin
wdata_o <= logicout;
end
`EXE_RES_SHIFT: begin
wdata_o <= shiftres;
end
`EXE_RES_ARITHMETIC: begin
wdata_o <= arithmeticres;
end
`EXE_RES_JUMP_BRANCH: begin
wdata_o <= link_address_i;
end
default: begin
wdata_o <= `ZeroWord;
end
endcase
end
endmodule