-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathdecoder.v
More file actions
308 lines (299 loc) · 11.5 KB
/
decoder.v
File metadata and controls
308 lines (299 loc) · 11.5 KB
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
`ifndef __DECODER__
`define __DECODER__
/*
file: Decoder in ID Stage, used to decode all 32 bits instructions,
generate control signals for other components
// 32 bits Instruction OP code type
`define OPCODE_LOAD 7'b0000011
`define OPCODE_OP_IMM 7'b0010011
`define OPCODE_AUIPC 7'b0010111
`define OPCODE_STORE 7'b0100011
`define OPCODE_RTYPE 7'b0110011
`define OPCODE_LUI 7'b0110111
`define OPCODE_BRANCH 7'b1100011
`define OPCODE_JALR 7'b1100111
`define OPCODE_JAL 7'b1101111
author: fujie
time: 2023年 4月27日 星期四 09时09分22秒 CST
*/
`include "definitions.vh"
`ifdef DIFFTEST
import "DPI-C" function void ebreak();
`endif
module decoder(
input wire [31:0] instruction_i, // instruction from IF stage
// ========= alu related signals =========
output wire [20:0] alu_op_o,
output reg rs1_sel_o, // alu operand a selection, 0 for rd1, 1 for pc
output reg rs2_sel_o, // alu operand b selection, 0 for rd2, 1 for imm
// ========= immediate types =========
output reg [2:0] imm_type_o,
// ========= branch signals used by extending unit and pass to ALU =========
output reg branchBType_o, // to show the instruction is BType instruction
output reg branchJAL_o,
output reg branchJALR_o,
output reg is_load_o,
// ========= load store signals =========
output reg [3:0] dmem_type_o, // data memory type
// ========= =========
// output reg regWriteEnD,
output reg [3:0] wb_src_o, // write back select
output reg wb_en_o, // write back enable
// ========= illegal instruction =========
output reg instr_illegal_o
);
// =========================================================================
// ============================ signals defination =============================
// =========================================================================
wire [6:0] opcode;
wire [2:0] funct3;
wire funct7;
wire beq_wire, blt_wire, branch_type_wire;
reg [17:0] alu_calculation;
// addtional signals for branch control
reg beq; // used by `beq`
reg blt; // used by `blt`, `bge`
// =========================================================================
// ============================ implementation =============================
// =========================================================================
assign opcode = instruction_i[6:0];
assign funct3 = instruction_i[14:12];
assign funct7 = instruction_i[30];
assign beq_wire = beq;
assign blt_wire = blt;
assign branch_type_wire = branchBType_o;
assign alu_op_o = {branch_type_wire, blt_wire, beq_wire, alu_calculation};
always @(*) begin
// suppose branch instruction is not asserted by default
alu_calculation = `ALUOP_ADD; // suppose alu opcode = error by default
rs1_sel_o = `RS1SEL_RF;
rs2_sel_o = `RS2SEL_IMM;
imm_type_o = `IMM_NO; // suppose instruction imm_type_o is IMM_NO by default.
beq = 1'b0; // suppose branch instruction is not asserted by default
blt = 1'b0;
branchBType_o = 1'b0;
branchJAL_o = 1'b0;
branchJALR_o = 1'b0;
is_load_o = 1'b0;
instr_illegal_o = 1'b0; // suppose instruction is legal by default.
wb_src_o = `WBSRC_ALU; // suppose write back source is from ALU
wb_en_o = 1'b0; // suppose write back is not enable
dmem_type_o = `DMEM_NO;
case(opcode)
`OPCODE_LOAD : begin
imm_type_o = `IMM_I;
alu_calculation = `ALUOP_ADD;
wb_src_o = `WBSRC_MEM;
wb_en_o = 1'b1;
is_load_o = 1'b1;
case(funct3)
3'b000: begin
dmem_type_o = `DMEM_LB;
end
3'b001: begin
dmem_type_o = `DMEM_LH;
end
3'b010: begin
dmem_type_o = `DMEM_LW;
end
3'b100: begin
dmem_type_o = `DMEM_LBU;
end
3'b101: begin
dmem_type_o = `DMEM_LHU;
end
default: instr_illegal_o = 1'b1;
endcase
end
`OPCODE_OP_IMM: begin
imm_type_o = `IMM_I;
wb_src_o = `WBSRC_ALU;
wb_en_o = instruction_i != 32'h00000013;
case(funct3)
3'b000: begin
alu_calculation = `ALUOP_ADD; // addi
// alu_calculation = `ALUOP_SLL; // slli
end
3'b001: begin
alu_calculation = `ALUOP_SLL; // slli
end
3'b010: begin
alu_calculation = `ALUOP_SLT; // slti
end
3'b011: begin
alu_calculation = `ALUOP_SLTU; // sluti
end
3'b100: begin
alu_calculation = `ALUOP_XOR; // xori
end
3'b101: begin
case(funct7)
0: alu_calculation = `ALUOP_SRL; // srli
default: alu_calculation = `ALUOP_SRA; // srai
endcase
end
3'b110: begin
alu_calculation = `ALUOP_OR; // ori
end
3'b111: begin
alu_calculation = `ALUOP_AND; // andi
end
default: instr_illegal_o = 1'b1;
endcase
end
`OPCODE_AUIPC : begin
imm_type_o = `IMM_U;
alu_calculation = `ALUOP_ADD;
rs1_sel_o = `RS1SEL_PC;
wb_src_o = `WBSRC_ALU;
wb_en_o = 1'b1;
end
`OPCODE_STORE : begin
imm_type_o = `IMM_S;
alu_calculation = `ALUOP_ADD;
wb_en_o = 1'b0;
case(funct3)
3'b000: begin
dmem_type_o = `DMEM_SB;
end
3'b001: begin
dmem_type_o = `DMEM_SH;
end
3'b010: begin
dmem_type_o = `DMEM_SW;
end
default: instr_illegal_o = 1'b1;
endcase
end
`OPCODE_RTYPE : begin
imm_type_o = `IMM_NO; // rType instructions don't have imm
rs2_sel_o = `RS2SEL_RF;
wb_src_o = `WBSRC_ALU;
wb_en_o = 1'b1;
if(~instruction_i[25]) begin // R type instruction
case(funct3)
3'b000: begin
case(funct7)
0: alu_calculation = `ALUOP_ADD; // add
default: alu_calculation = `ALUOP_SUB; // sub
endcase
end
3'b001: begin
alu_calculation = `ALUOP_SLL; // sll
end
3'b010: begin
alu_calculation = `ALUOP_SLT; // slt
end
3'b011: begin
alu_calculation = `ALUOP_SLTU; // sltu
end
3'b100: begin
alu_calculation = `ALUOP_XOR; // xor
end
3'b101: begin
case(funct7)
0: alu_calculation = `ALUOP_SRL; // srl
default: alu_calculation = `ALUOP_SRA; // sra
endcase
end
3'b110: begin
alu_calculation = `ALUOP_OR; // or
end
3'b111: begin
alu_calculation = `ALUOP_AND; // and
end
default: instr_illegal_o = 1'b1;
endcase
end
else begin // RISC-V 32M instruction
case(funct3)
3'b000: begin
alu_calculation = `ALUOP_MUL; // mul
end
3'b001: begin
alu_calculation = `ALUOP_MULH; // mulh
end
3'b010: begin
alu_calculation = `ALUOP_MULHSU; // mulhsu
end
3'b011: begin
alu_calculation = `ALUOP_MULHU; // mulhu
end
3'b100: begin
alu_calculation = `ALUOP_DIV; // div
end
3'b101: begin
alu_calculation = `ALUOP_DIVU; // divu
end
3'b110: begin
alu_calculation = `ALUOP_REM; // rem
end
3'b111: begin
alu_calculation = `ALUOP_REMU; // remu
end
default: instr_illegal_o = 1'b1;
endcase
end
end
`OPCODE_LUI : begin
imm_type_o = `IMM_U;
alu_calculation = `ALUOP_ADD;
wb_src_o = `WBSRC_IMM;
wb_en_o = 1'b1;
end
`OPCODE_BRANCH: begin
imm_type_o = `IMM_B;
branchBType_o = 1'b1;
rs2_sel_o = `RS2SEL_RF;
wb_en_o = 1'b0;
case(funct3)
3'b000: begin
alu_calculation = `ALUOP_SUB; // beq
beq = 1'b1;
end
3'b001: begin
alu_calculation = `ALUOP_SUB; // bne
end
3'b100: begin
alu_calculation = `ALUOP_SLT; // blt
blt = 1'b1;
end
3'b101: begin
alu_calculation = `ALUOP_SLT; // bge
end
3'b110: begin
alu_calculation = `ALUOP_SLTU; // bltu
blt = 1'b1;
end
3'b111: begin
alu_calculation = `ALUOP_SLTU; // bgeu
end
default: instr_illegal_o = 1'b1;
endcase
end
`OPCODE_JALR : begin
imm_type_o = `IMM_I;
branchJALR_o = 1'b1;
alu_calculation = `ALUOP_ADD;
wb_src_o = `WBSRC_PC;
wb_en_o = 1'b1;
end
`OPCODE_JAL : begin
imm_type_o = `IMM_J;
branchJAL_o = 1'b1;
alu_calculation = `ALUOP_ADD;
wb_src_o = `WBSRC_PC;
wb_en_o = 1'b1;
end
default: instr_illegal_o = 1'b1;
endcase
end
`ifdef DIFFTEST
wire inst_ebreak;
assign inst_ebreak = instruction_i == 32'h00000073;
always @(*) begin
if (inst_ebreak) ebreak();
end
`endif
endmodule
`endif