-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdecoder.v
155 lines (140 loc) · 4.15 KB
/
decoder.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
module decoder
(
ip_inst,
write_en,
write_addr,
read_addr1,
read_addr2,
immediate,
mem_write_en,
mem_read_en,
funct3,
funct7,
alu_opcode,
alu_src2_from_imm,
branch_inst,
alu_src1_from_pc,
jump_inst
);
input wire [31:0] ip_inst;
output reg write_en;
output reg [4:0] write_addr;
output reg [4:0] read_addr1;
output reg [4:0] read_addr2;
output reg [31:0] immediate;
output reg mem_write_en;
output reg mem_read_en;
output reg [2:0] funct3;
output reg [6:0] funct7;
output reg [3:0] alu_opcode;
output reg alu_src2_from_imm;
output reg branch_inst;
output reg alu_src1_from_pc;
output reg jump_inst;
reg [6:0] opcode;
// Immediate values are calculated differently for different
// instruction variants.
reg [31:0] immediate_I;
reg [31:0] immediate_S;
reg [31:0] immediate_B;
reg [31:0] immediate_U;
reg [31:0] immediate_J;
always @(*)
begin
// Fixed values that do not change
opcode = ip_inst[6:0];
funct3 = ip_inst[14:12];
funct7 = ip_inst[31:25];
write_addr = ip_inst[11:7];
read_addr1 = ip_inst[19:15];
read_addr2 = ip_inst[24:20];
immediate_I = {{20{ip_inst[31]}}, ip_inst[31:20]};
immediate_S = {{20{ip_inst[31]}}, ip_inst[31:25], ip_inst[11:7]};
immediate_B = {{20{ip_inst[31]}}, ip_inst[7], ip_inst[30:25], ip_inst[11:8], 1'b0};
immediate_U = {ip_inst[31:12], 12'h0};
immediate_J = {{12{ip_inst[31]}}, ip_inst[19:12], ip_inst[20], ip_inst[30:21], 1'b0};
// Values that will be changed based on opcode
write_en = 1'b0;
immediate = 32'hx;
mem_write_en = 1'b0;
mem_read_en = 1'b0;
alu_src2_from_imm = 1'b0;
alu_opcode = 4'hx;
branch_inst = 1'b0;
alu_src1_from_pc = 1'b0;
jump_inst = 1'b0;
case (opcode)
7'b0010011: // I-Type
begin
write_en = 1'b1;
alu_opcode = (funct3 == 3'b101) ? {ip_inst[30], funct3} : {1'b0, funct3};
alu_src2_from_imm = 1'b1;
immediate = immediate_I;
end
7'b0110011: // R-Type
begin
write_en = 1'b1;
alu_opcode = {ip_inst[30], funct3};
end
7'b1100011: // B-Type
begin
branch_inst = 1'b1;
immediate = immediate_B;
end
7'b0100011: // S-Type
begin
mem_write_en = 1'b1;
alu_opcode = 4'h0;
alu_src2_from_imm = 1'b1;
immediate = immediate_S;
end
7'b0000011: // I-Load-Type
begin
write_en = 1'b1;
mem_read_en = 1'b1;
alu_opcode = 4'h0;
alu_src2_from_imm = 1'b1;
immediate = immediate_I;
end
7'b0110111: // U-LUI
begin
write_en = 1'b1;
alu_opcode = 4'h0;
alu_src2_from_imm = 1'b1;
immediate = immediate_U;
// Making the read_addr1 as 0 will
// let us reuse the RF->ALU->RF path
// for the LUI instruction.
read_addr1 = 5'h0;
end
7'b0010111: // U-AUIPC
begin
alu_src1_from_pc = 1'b1;
write_en = 1'b1;
alu_opcode = 4'h0;
alu_src2_from_imm = 1'b1;
immediate = immediate_U;
end
7'b1101111: // J-JAL
begin
jump_inst = 1'b1;
write_en = 1'b1;
alu_opcode = 4'h0;
alu_src2_from_imm = 1'b1;
immediate = immediate_J;
// This will make the result of ALU calculate
// PC + immediate_J which can then be fed back
// to PC
alu_src1_from_pc = 1'b1;
end
7'b1100111: // I-JALR
begin
jump_inst = 1'b1;
write_en = 1'b1;
alu_opcode = 4'h0;
alu_src2_from_imm = 1'b1;
immediate = immediate_I;
end
endcase
end
endmodule