RISC-V项目(2)---RISC-V指令解析

1、NOP指令

2、JAL指令(无条件跳转)

核心点:将当前PC指针加4存入reg[rd],跳转到PC+imm继续执行

execute阶段:

1
2
3
4
5
6
7
8
`INST_JAL:begin
wr_reg_en = 1'b1 ;
wr_reg_addr = rd ;
wr_reg_data = instr_addr + 32'h4 ;
jump_en = 1'b1 ;
jump_addr = instr_addr + op2 ;
jump_hold = 1'b0 ;
end

译码阶段:

1
2
3
4
5
6
`INST_JAL:begin
rd_rs1_addr = 5'h0 ;
rd_rs2_addr = 5'h0 ;
op1_out = 32'h0 ;
op2_out = imm ;
end

3、JALR间接跳转指令

1
2
3
4
5
6
`INST_JALR:begin
rd_rs1_addr = rs1 ;
rd_rs2_addr = 5'h0 ;
op1_out = rd_rs1_data ;
op2_out = imm ;
end

执行阶段的跳转:

1
2
3
4
5
6
7
8
`INST_JAL:begin
wr_reg_en = 1'b1 ;
wr_reg_addr = rd ;
wr_reg_data = instr_addr + 32'h4 ;
jump_en = 1'b1 ;
jump_addr = instr_addr + op2 ;
jump_hold = 1'b0 ;
end

4、LUI指令

译码阶段:

1
2
3
4
5
`INST_LUI:begin
rd_rs1_addr = 5'h0 ;
rd_rs2_addr = 5'h0 ;
op1_out = 32'h0 ;
op2_out = imm ;

执行阶段:

1
2
3
4
5
6
7
`INST_LUI:begin
wr_reg_en = 1'b1 ;
wr_reg_addr = rd ;
wr_reg_data = op2 ;
jump_en = 1'b0 ;
jump_addr = 'h0 ;
jump_hold = 1'b0 ;

5、LUIPC

这里简单提一嘴,就是LUI跟LUIPC的立即数计算方式如下:

1
2
3
4
5
6
always_comb begin
case(opcode)
`INST_LUI,`INST_LUIPC:
imm = {instr_in[31:12],12'h0};
endcase
end

译码阶段:

1
2
3
4
5
6
`INST_LUIPC:begin
rd_rs1_addr = 5'h0 ;
rd_rs2_addr = 5'h0 ;
op1_out = instr_addr_in ;
op2_out = imm ;
end

执行阶段:

1
2
3
4
5
6
7
8
`INST_LUIPC:begin
wr_reg_en = 1'b1 ;
wr_reg_addr = rd ;
wr_reg_data = op1 + op2 ;
jump_en = 1'b0 ;
jump_addr = 'h0 ;
jump_hold = 1'b0 ;
end

6、B型指令

B型指令的立即数计算方式:

1
2
3
4
5
6
always_comb begin
case(opcode)
`INST_TYPE_B:
imm = {{20{instr_in[31]}},instr_in[7],instr_in[30:25],instr_in[11:8],1'b0};
endcase
end

B型指令的指令定义方式:

B型指令译码阶段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
`INST_TYPE_B:begin
case(func3)
`INST_BEQ,`INST_BNE,`INST_BLT,`INST_BGE,`INST_BLTU,`INST_BGEU:begin
rd_rs1_addr = rs1 ;
rd_rs2_addr = rs2 ;
op1_out = rd_rs1_data ;
op2_out = rd_rs2_data ;
end
default:begin
rd_rs1_addr = 'h0 ;
rd_rs2_addr = 'h0 ;
op1_out = 'h0 ;
op2_out = 'h0 ;
end
endcase
end

执行阶段:

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
assign	imm										= {{20{instr[31]}},instr[7],instr[30:25],instr[11:8],1'b0}; 
assign equal = (op1 == op2) ? 1'b1 : 1'b0;
assign less_signed = ($signed(op1) < $signed(op2)) ? 1'b1 : 1'b0;
assign less_unsigned = (op1 < op2) ? 1'b1 : 1'b0;
assign jump_imm = instr_addr + imm ;


`INST_TYPE_B: begin
case(func3)
`INST_BEQ: begin
wr_reg_en = 1'b0 ;
wr_reg_addr = 5'h0 ;
wr_reg_data = 'h0 ;
jump_en = equal ;
jump_addr = equal ? jump_imm : 'h0 ;
jump_hold = 1'b0 ;
end
`INST_BNE: begin
wr_reg_en = 1'b0 ;
wr_reg_addr = 5'h0 ;
wr_reg_data = 'h0 ;
jump_en = ~equal ;
jump_addr = ~equal ? jump_imm : 'h0 ;
jump_hold = 1'b0 ;
end
`INST_BLT: begin
wr_reg_en = 1'b0 ;
wr_reg_addr = 5'h0 ;
wr_reg_data = 'h0 ;
jump_en = less_signed ;
jump_addr = less_signed ? jump_imm : 'h0 ;
jump_hold = 1'b0 ;
end
`INST_BGE: begin
wr_reg_en = 1'b0 ;
wr_reg_addr = 5'h0 ;
wr_reg_data = 'h0 ;
jump_en = ~less_signed ;
jump_addr = ~less_signed ? jump_imm : 'h0 ;
jump_hold = 1'b0 ;
end
`INST_BLTU: begin
wr_reg_en = 1'b0 ;
wr_reg_addr = 5'h0 ;
wr_reg_data = 'h0 ;
jump_en = less_unsigned ;
jump_addr = less_unsigned ? jump_imm : 'h0 ;
jump_hold = 1'b0 ;
end
`INST_BGEU: begin
wr_reg_en = 1'b0 ;
wr_reg_addr = 5'h0 ;
wr_reg_data = 'h0 ;
jump_en = ~less_unsigned ;
jump_addr = ~less_unsigned ? jump_imm : 'h0 ;
jump_hold = 1'b0 ;
end
default:begin
wr_reg_en = 1'b0 ;
wr_reg_addr = 5'h0 ;
wr_reg_data = 'h0 ;
jump_en = 1'b0 ;
jump_addr = 'h0 ;
jump_hold = 1'b0 ;
end
endcase
end

7、I型指令

译码阶段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
`INST_TYPE_I:begin
case(func3)
`INST_ADDI,`INST_SLTI, `INST_SLTIU, `INST_XORI, `INST_ORI, `INST_ANDI, `INST_SLLI, `INST_SRI:begin
rd_rs1_addr = rs1 ;
rd_rs2_addr = 5'h0 ;
op1_out = rd_rs1_data ;
op2_out = imm ;
end
default:begin
rd_rs1_addr = 'h0 ;
rd_rs2_addr = 'h0 ;
op1_out = 'h0 ;
op2_out = 'h0 ;
end
endcase
end
1
2
3
4
5
always_comb begin
case(opcode)
`INST_TYPE_I:
imm = {{20{instr_in[31]}},instr_in[31:20]};
end

执行阶段:

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
`INST_TYPE_I:begin
case(func3)
`INST_ADDI:begin
wr_reg_en = 1'b1 ;
wr_reg_addr = rd ;
wr_reg_data = op1 + op2 ;
jump_en = 1'b0 ;
jump_addr = 'h0 ;
jump_hold = 1'b0 ;
end
`INST_SLTI:begin
wr_reg_en = 1'b1 ;
wr_reg_addr = rd ;
wr_reg_data = less_signed ? 32'h1 : 32'h0 ;
jump_en = 1'b0 ;
jump_addr = 'h0 ;
jump_hold = 1'b0 ;
end
`INST_SLTIU:begin
wr_reg_en = 1'b1 ;
wr_reg_addr = rd ;
wr_reg_data = less_unsigned ? 32'h1 : 32'h0 ;
jump_en = 1'b0 ;
jump_addr = 'h0 ;
jump_hold = 1'b0 ;
end
`INST_XORI:begin
wr_reg_en = 1'b1 ;
wr_reg_addr = rd ;
wr_reg_data = op1 ^ op2 ;
jump_en = 1'b0 ;
jump_addr = 'h0 ;
jump_hold = 1'b0 ;
end
`INST_ORI:begin
wr_reg_en = 1'b1 ;
wr_reg_addr = rd ;
wr_reg_data = op1 | op2 ;
jump_en = 1'b0 ;
jump_addr = 'h0 ;
jump_hold = 1'b0 ;
end
`INST_ANDI:begin
wr_reg_en = 1'b1 ;
wr_reg_addr = rd ;
wr_reg_data = op1 & op2 ;
jump_en = 1'b0 ;
jump_addr = 'h0 ;
jump_hold = 1'b0 ;
end
`INST_SLLI:begin
wr_reg_en = 1'b1 ;
wr_reg_addr = rd ;
wr_reg_data = op1 << op2[4:0] ;
jump_en = 1'b0 ;
jump_addr = 'h0 ;
jump_hold = 1'b0 ;
end
`INST_SRI:begin
if(instr[30])
wr_reg_data = (sr_shift & sr_shift_mask) |
({DW{op1[DW-1]}} & (~sr_shift_mask));
else
wr_reg_data = op1 >> op2[4:0] ;
wr_reg_en = 1'b1 ;
wr_reg_addr = rd ;
jump_en = 1'b0 ;
jump_addr = 'h0 ;
jump_hold = 1'b0 ;
end
default:begin
wr_reg_en = 1'b0 ;
wr_reg_addr = 5'h0 ;
wr_reg_data = 'h0 ;
jump_en = 1'b0 ;
jump_addr = 'h0 ;
jump_hold = 1'b0 ;
end
endcase
end

在这里我们重点说一下:
SRLI跟SRAI指令的区别

实现这几步的主要代码:

1
2
3
4
5
6
assign  sr_shift							=	op1 >> op2[4:0];//将reg[rs1]逻辑左移shamt位后写入到reg[rd],空位用0填补

assign sr_shift_mask = {DW{1'b1}} >> op2[4:0];

//DW{}

执行阶段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
`INST_SLLI:begin
wr_reg_en = 1'b1 ;
wr_reg_addr = rd ;
wr_reg_data = op1 << op2[4:0] ;
jump_en = 1'b0 ;
jump_addr = 'h0 ;
jump_hold = 1'b0 ;
end
`INST_SRI:begin
if(instr[30])
wr_reg_data = (sr_shift & sr_shift_mask) |
({DW{op1[DW-1]}} & (~sr_shift_mask));
else
wr_reg_data = op1 >> op2[4:0] ;
wr_reg_en = 1'b1 ;
wr_reg_addr = rd ;
jump_en = 1'b0 ;
jump_addr = 'h0 ;
jump_hold = 1'b0 ;
end
ESC 关闭 | 导航 | Enter 打开
输入关键词开始搜索