tastynoob
Articles58
Tags18
Categories7
FPGA-RISCV内核入门5

FPGA-RISCV内核入门5

译码段设计

译码段是纯组合逻辑

这部分比较简单

也就是将指令译码出详细信息

这里直接贴上代码

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
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375

`define decinfo_wigth (17)
/*译码出的具体指令内容
1'是否要进行运算[0]
1'alu b位是否选择立即数[1]
1'alu pc是否参与计算[2]
1'是否是条件分支指令[3]
1'是否是强制跳转[4]
1‘是否要读内存[5]
1’是否要写内存[6]
1’是否要读写csr寄存器[8]
3’func[11:9]
7‘func7[18:12]
*/

`define decinfo_alu 0
`define decinfo_b 1
`define decinfo_pc 2
`define decinfo_branch 3
`define decinfo_jal 4
`define decinfo_rdbus 5
`define decinfo_wdbus 6
`define decinfo_wcsr 7
`define decinfo_func3 10:8
`define decinfo_func7 17:11


//译码模块
module ID (
input wire i_clk,
input wire i_rst_n,

//解码出的具体指令
output wire[`decinfo_wigth:0] o_dec_data,
//csr地址
output wire[11:0] o_csr_addr,

//rd寄存器写地址
output wire[4:0] o_rd_addr1,
output wire[4:0] o_rd_addr2,
//rs1读地址
output wire[4:0] o_rs1_addr,

//rs2读地址
output wire[4:0] o_rs2_addr,

//立即数
output wire[31:0] o_imm_data,

//如果是opc_load指令,那么则暂停取指直到opc_load执行完毕
output wire o_opc_load,


/*分割线*/
//上级传递下来的指令地址
input wire[31:0] i_iaddr,
input wire[31:0] i_idata
);


// 取出指令中的每一个域
wire[6:0] opc = i_idata[6:0];
wire[2:0] func = i_idata[14:12];
wire[6:0] func7 = i_idata[31:25];
wire[4:0] rd = i_idata[11:7];
wire[4:0] rs1 = i_idata[19:15];
wire[4:0] rs2 = i_idata[24:20];
wire[11:0] type_i_imm_11_0 = i_idata[31:20];
wire[6:0] type_s_imm_11_5 = i_idata[31:25];
wire[4:0] type_s_imm_4_0 = i_idata[11:7];
wire[6:0] type_b_imm_12_10_5 = i_idata[31:25];
wire[4:0] type_b_imm_4_1_11 = i_idata[11:7];
wire[19:0] type_u_imm_31_12 = i_idata[31:12];
wire[19:0] type_j_imm_31_12 = i_idata[31:12];

`define opc_lui 7'b0110111 // rd = imm
`define opc_auipc 7'b0010111 // rd = pc + imm
`define opc_jal 7'b1101111
`define opc_jalr 7'b1100111
`define opc_branch 7'b1100011
`define opc_load 7'b0000011
`define opc_store 7'b0100011
`define opc_opimm 7'b0010011
`define opc_op 7'b0110011
`define opc_fence 7'b0001111
`define opc_system 7'b1110011

// 指令opc域的取值
wire opc_lui = (opc == `opc_lui);
wire opc_auipc = (opc == `opc_auipc);
wire opc_jal = (opc == `opc_jal);
wire opc_jalr = (opc == `opc_jalr);
wire opc_branch = (opc == `opc_branch);
wire opc_load = (opc == `opc_load);
wire opc_store = (opc == `opc_store);
wire opc_opimm = (opc == `opc_opimm);
wire opc_op = (opc == `opc_op);
wire opc_fence = (opc == `opc_fence);
wire opc_system = (opc == `opc_system);

// 指令func域的取值
wire func_000 = (func == 3'b000);
wire func_001 = (func == 3'b001);
wire func_010 = (func == 3'b010);
wire func_011 = (func == 3'b011);
wire func_100 = (func == 3'b100);
wire func_101 = (func == 3'b101);
wire func_110 = (func == 3'b110);
wire func_111 = (func == 3'b111);

// 指令func7域的取值
wire func7_0000000 = (func7 == 7'b0000000);
wire func7_0100000 = (func7 == 7'b0100000);
wire func7_0000001 = (func7 == 7'b0000001);

// I类型指令imm域的取值
wire type_i_imm_000000000000 = (type_i_imm_11_0 == 12'b000000000000);
wire type_i_imm_000000000001 = (type_i_imm_11_0 == 12'b000000000001);

/*********************************************************/
// 译码出具体指令
/*j*/
wire inst_lui = opc_lui;
wire inst_auipc = opc_auipc;
wire inst_jal = opc_jal;
wire inst_jalr = opc_jalr & func_000;
/*branch*/
wire inst_beq = opc_branch & func_000;
wire inst_bne = opc_branch & func_001;
wire inst_blt = opc_branch & func_100;
wire inst_bge = opc_branch & func_101;
wire inst_bltu = opc_branch & func_110;
wire inst_bgeu = opc_branch & func_111;
/*load*/
wire inst_lb = opc_load & func_000;
wire inst_lh = opc_load & func_001;
wire inst_lw = opc_load & func_010;
wire inst_lbu = opc_load & func_100;
wire inst_lhu = opc_load & func_101;
/*store*/
wire inst_sb = opc_store & func_000;
wire inst_sh = opc_store & func_001;
wire inst_sw = opc_store & func_010;
/*opimm*/
wire inst_addi = opc_opimm & func_000;
wire inst_slti = opc_opimm & func_010;
wire inst_sltiu = opc_opimm & func_011;
wire inst_xori = opc_opimm & func_100;
wire inst_ori = opc_opimm & func_110;
wire inst_andi = opc_opimm & func_111;
wire inst_slli = opc_opimm & func_001 & func7_0000000;
wire inst_srli = opc_opimm & func_101 & func7_0000000;
wire inst_srai = opc_opimm & func_101 & func7_0100000;
/*op*/
wire inst_add = opc_op & func_000 & func7_0000000;
wire inst_sub = opc_op & func_000 & func7_0100000;
wire inst_sll = opc_op & func_001 & func7_0000000;
wire inst_slt = opc_op & func_010 & func7_0000000;
wire inst_sltu = opc_op & func_011 & func7_0000000;
wire inst_xor = opc_op & func_100 & func7_0000000;
wire inst_srl = opc_op & func_101 & func7_0000000;
wire inst_sra = opc_op & func_101 & func7_0100000;
wire inst_or = opc_op & func_110 & func7_0000000;
wire inst_and = opc_op & func_111 & func7_0000000;
/*fence*/
wire inst_fence = opc_fence & func_000;
wire inst_fencei = opc_fence & func_001;
/*system*/
wire inst_ecall = opc_system & func_000 & type_i_imm_000000000000;
wire inst_ebreak = opc_system & func_000 & type_i_imm_000000000001;
wire inst_csrrw = opc_system & func_001;
wire inst_csrrs = opc_system & func_010;
wire inst_csrrc = opc_system & func_011;
wire inst_csrrwi = opc_system & func_101;
wire inst_csrrsi = opc_system & func_110;
wire inst_csrrci = opc_system & func_111;

/*M拓展*/
wire inst_mul = opc_op & func_000 & func7_0000001;
wire inst_mulh = opc_op & func_001 & func7_0000001;
wire inst_mulhsu = opc_op & func_010 & func7_0000001;
wire inst_mulhu = opc_op & func_011 & func7_0000001;
wire inst_div = opc_op & func_100 & func7_0000001;
wire inst_divu = opc_op & func_101 & func7_0000001;
wire inst_rem = opc_op & func_110 & func7_0000001;
wire inst_remu = opc_op & func_111 & func7_0000001;
/*********************************************************/

// 指令中的立即数
wire[31:0] inst_u_type_imm = {i_idata[31:12], 12'b0};
wire[31:0] inst_j_type_imm = {{12{i_idata[31]}}, i_idata[19:12], i_idata[20], i_idata[30:21], 1'b0};
wire[31:0] inst_b_type_imm = {{20{i_idata[31]}}, i_idata[7], i_idata[30:25], i_idata[11:8], 1'b0};
wire[31:0] inst_s_type_imm = {{20{i_idata[31]}}, i_idata[31:25], i_idata[11:7]};
wire[31:0] i_idata_type_imm = {{20{i_idata[31]}}, i_idata[31:20]};
//csr zimm
wire[31:0] inst_csr_type_imm = {27'h0, i_idata[19:15]};
wire[31:0] inst_shift_type_imm = {27'h0, i_idata[24:20]};



//立即数选择
assign o_imm_data = (opc_lui | opc_auipc) ? inst_u_type_imm :
(opc_jal) ? inst_j_type_imm :
(opc_jalr | opc_load) ? i_idata_type_imm :
(opc_branch) ? inst_b_type_imm :
(opc_store) ? inst_s_type_imm :
(opc_opimm) ?
((inst_slli | inst_srli | inst_srai) ? inst_shift_type_imm : i_idata_type_imm) :
(inst_ecall | inst_ebreak) ? i_idata_type_imm ://这里把ecall和ebreak的后12位当作立即数处理
0;

//csr寄存器地址
assign o_csr_addr = opc_system ? i_idata_type_imm : 0;



// 是否需要写rd寄存器
wire access_rd = opc_lui |
opc_auipc |
opc_jal |
opc_jalr |
opc_opimm |
opc_op |
opc_system;
assign o_rd_addr1 = access_rd ? rd: 5'h0;
assign o_rd_addr2 = opc_load ? rd:5'd0;

// 是否需要访问rs1寄存器
wire access_rs1 = opc_jalr |
opc_branch |
opc_load |
opc_store |
opc_opimm |
opc_op |
inst_csrrw |
inst_csrrs |
inst_csrrc;
assign o_rs1_addr = access_rs1 ? rs1: 5'h0;


// 是否需要访问rs2寄存器
wire access_rs2 = opc_branch |
opc_store |
opc_op;
assign o_rs2_addr = access_rs2? rs2: 5'h0;




//是否需要进行数学计算
//这个标志貌似可有可无
assign o_dec_data[`decinfo_alu] = opc_lui | opc_auipc | opc_jal | opc_jalr | opc_branch | opc_load | opc_store | opc_opimm | opc_op;

//alu b位是否选择立即数
assign o_dec_data[`decinfo_b] = opc_lui | opc_auipc | opc_jal | opc_jalr | opc_load | opc_store | opc_opimm;

//alu pc是否参与计算,是否是jal等跳转指令
assign o_dec_data[`decinfo_pc] = opc_auipc | opc_jal ;

//是否是条件分支指令
assign o_dec_data[`decinfo_branch] = opc_branch;

//是否需要强制跳转
assign o_dec_data[`decinfo_jal] = opc_jal | opc_jalr;

//是否需要读内存
assign o_dec_data[`decinfo_rdbus] = opc_load;
//是否需要写内存
assign o_dec_data[`decinfo_wdbus] = opc_store;


//是否要读写csr寄存器
assign o_dec_data[`decinfo_wcsr] = opc_system & (~(inst_ecall | inst_ebreak));



assign o_dec_data[`decinfo_func3] = (opc_lui | opc_auipc | opc_jal) ? 0 : func;
assign o_dec_data[`decinfo_func7] = (inst_slli | inst_srli | inst_srai | opc_op) ? func7 : 0;


assign o_opc_load = opc_load;

endmodule



module ID_EX (
input wire i_clk,
input wire i_rst_n,
//流水线暂停
input wire i_pipe_stop,
//流水线冲刷
input wire i_pipe_flush,

/**/
input wire[`decinfo_wigth:0] i_dec_data,
input wire[11:0] i_csr_addr,
input wire[4:0] i_rd_addr1,
input wire[4:0] i_rd_addr2,
input wire[4:0] i_rs1_addr,
input wire[4:0] i_rs2_addr,
input wire[31:0] i_imm_data,
input wire i_opc_load,
input wire[31:0] i_iaddr,

output reg[`decinfo_wigth:0] o_dec_data,
output reg[11:0] o_csr_addr,
output reg[4:0] o_rd_addr1,
output reg[4:0] o_rd_addr2,
output reg[4:0] o_rs1_addr,
output reg[4:0] o_rs2_addr,
output reg[31:0] o_imm_data,
output reg o_opc_load,
output reg[31:0] o_iaddr


);
wire en = (~i_pipe_stop) | i_pipe_flush;


wire[`decinfo_wigth:0] dec_data= i_pipe_flush ? 0 : i_dec_data;
wire[11:0] csr_addr= i_pipe_flush ? 0 : i_csr_addr;
wire[4:0] rd_addr1= i_pipe_flush ? 0 : i_rd_addr1;
wire[4:0] rd_addr2= i_pipe_flush ? 0 : i_rd_addr2;
wire[4:0] rs1_addr= i_pipe_flush ? 0 : i_rs1_addr;
wire[4:0] rs2_addr= i_pipe_flush ? 0 : i_rs2_addr;
wire[31:0] imm_data= i_pipe_flush ? 0 : i_imm_data;
wire opc_load= i_pipe_flush ? 0 : i_opc_load;
wire[31:0] iaddr = i_pipe_flush ? 0 : i_iaddr;




initial begin
o_dec_data <= 0 ;
o_csr_addr <=0;
o_rd_addr1<= 0;
o_rd_addr2<= 0;
o_rs1_addr <= 0 ;
o_rs2_addr <= 0 ;
o_imm_data <= 0 ;
o_opc_load <= 0;
o_iaddr <= 0 ;
end


always @(posedge i_clk or negedge i_rst_n) begin
if(i_rst_n == `rst)begin
o_dec_data <= 0 ;
o_csr_addr <=0;
o_rd_addr1 <= 0 ;
o_rs1_addr <= 0 ;
o_rs2_addr <= 0 ;
o_imm_data <= 0 ;
o_opc_load <= 0;
o_iaddr <= 0 ;
end
else if(en == `en)begin
o_dec_data <= dec_data;
o_csr_addr <= csr_addr;
o_rd_addr1 <= rd_addr1;
o_rd_addr2 <= rd_addr2;
o_rs1_addr <= rs1_addr;
o_rs2_addr <= rs2_addr;
o_imm_data <= imm_data;
o_opc_load <= opc_load;
o_iaddr <= iaddr;
end
end



endmodule


这里面没有什么特殊技术

但之前也说了,制作这个riscv内核单纯是为了学习

只要求能跑,不要求性能

译码段主要译码出的就是

1、读写寄存器地址(不读不写则设置为0)
2、执行段所需资源
3、是否读写csr寄存器
4、是否跳转
5、指令类型

然后由译码段到执行段的连接段传递

Author:tastynoob
Link:https://tastynoob.github.io/1970/01/01/RISCV/RITTER-CORE5/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可
×