verilog五层流水线CPU(简化指令)

模块设计

整体视图:

1. GRF(寄存器堆)

端口名 输入\输出 位宽 功能
clk Input 1 时钟信号
reset Input 1 复位信号
WE Input 1 使能信号
PC Input 31:0 pc
A1 Input 4:0 输入寄存器地址端口1
A2 Input 4:0 输入寄存器地址端口2
A3 Input 4:0 输入寄存器地址端口3,写寄存器地址
EXTRA Input 4:0 输入寄存器地址端口EX,读寄存器地址
WD Input 31:0 数据输入端口,输入一个32位数据,存入编码为A3的寄存器中
RD1 Output 31:0 输出编码为A1中输入的寄存器中的值
RD2 Output 31:0 输出编码为A2中输入的寄存器中的值
RDEXTRA Output 31:0 输出编码为EXTRA中输入的寄存器中的值

初始化!!

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
module GRF (
input clk,
input reset,
input WE,
input [31:0] PC,
input [4:0] A1,
input [4:0] A2,
input [4:0] A3,
input [4:0] EXTRA,
input [31:0] WD,
output [31:0] RD1,
output [31:0] RD2,
output [31:0] RDEXTRA

);

reg [31:0] registers[31:0];
integer i;
assign RD1 = (A1 === 5'b0) ? 32'b0 : ((A1 === A3) && WE) ? WD : registers[A1];
assign RD2 = (A2 === 5'b0) ? 32'b0 : ((A2 === A3) && WE) ? WD : registers[A2];
assign RDEXTRA = (EXTRA === 5'b0) ? 32'b0 : ((EXTRA === A3) && WE) ? WD : registers[EXTRA];

initial begin
for (i = 0; i < 32; i = i + 1) begin
registers[i] = 32'b0;
end
end


always @(posedge clk) begin
if (reset) begin
for (i = 0; i < 32; i = i + 1) begin
registers[i] <= 32'b0;
end
end else begin
if (WE) begin
$display("%d@%h: $%d <= %h", $time, PC, A3, WD);
registers[A3] <= WD;
end
end
end

endmodule

2. DM

端口名 输入\输出 位宽 功能
clk Input 1 时钟信号
reset Input 1 复位信号
PC Input 31:0 pc
memwrite Input 1 内存写使能
memaddr Input 31:0 内存地址
memdata Input 31:0 写入的内存数据
outdata Output 31:0 输出的内存数据

使用寄存器数组实现。初始化!!

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
module DM (
input clk,
input reset,
input [31:0] PC,
input memwrite,
input [31:0] memaddr,
input [31:0] memdata,
output [31:0] outdata
);
reg [31:0] mem[0:4095];
integer i;

assign outdata = mem[memaddr[13:2]];

initial begin
for (i = 0; i < 4096; i = i + 1) begin
mem[i] = 32'b0;
end
end
always @(posedge clk) begin
if (reset) begin
for (i = 0; i < 4096; i = i + 1) begin
mem[i] <= 32'b0;
end
end else begin
if (memwrite) begin
mem[memaddr[13:2]] <= memdata;
$display("%d@%h: *%h <= %h", $time, PC, {18'b0,memaddr[13:0]}, memdata);
end
end
end
endmodule

DM中一个字是一个地址,按字节为14位(16K),按字为12位地址(32bit*4096),端口应该连接ALU输出端的2~13位。

3. NPC

端口名 输入\输出 位宽 功能
clk Input 1 时钟信号
reset Input 1 复位信号
beq_judge Input 1 beq指令pc选择
j_if Input 1 j指令pc选择
jr_if Input 1 jr指令pc选择
jal_if Input 1 jal指令pc选择
imm Input 31:0 位扩展后的立即数
j_addr Input 25:0 j指令跳转地址
jr_addr Input 31:0 jr指令跳转地址
NPC Output 31:0 输出的真实pc值
NPC_4 Output 31:0 pc+4(用于jal指令写入$ra)

外部引入两个对应位置的寄存器通过ALU的减法结果zero,通过与beq_if(判断指令是否为beq)连接,实现beq(if$[rs]==$[rt]): PC=PC+offest+4。

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
module NPC (
input clk,
input reset,
input beq_judge,
input block,
input j_if,
input jr_if,
input jal_if,
input [31:0] imm,
input [31:0] PC_D,
input [25:0] j_addr,
input [31:0] jr_addr,
output reg [31:0] NPC,
output [31:0] NPC_4 //pc+4
);

assign NPC_4 = (NPC + 4);

initial begin
NPC = 32'h0000_3000;
end

always @(posedge clk) begin
if (reset) begin
NPC <= 32'h00003000;
end
else if (block) begin
NPC <= NPC;
end
else if (j_if == 1'b1||jal_if == 1'b1) begin
NPC <= {PC_D[31 : 28], j_addr, 2'b00};
end
else if (jr_if == 1'b1) begin
NPC <= jr_addr;
end
else if (beq_judge) begin
NPC <= ((imm << 2) + PC_D);
end
else begin
NPC <= (NPC + 4);
end

end

endmodule

4.IM

通过ROM元件存储和读入指令代码,PC在内部为0x00000000起始,而外部为0x00003000,需要减去一个偏移量

ROM中一个字是一个地址,按字为12位地址端口应该连接ALU输出端的2~13位。

端口名 输入\输出 位宽 功能
pc Input 31:0 pc
inster Output 31:0 指令机器码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
module IM(
input [31:0] pc,
output [31:0] instr
);
reg [31:0] mem[0:4095];
wire [31:0] fakepc;
assign fakepc = pc-32'h0000_3000;
assign instr = mem[fakepc[13:2]];

initial begin
$readmemh("code.txt", mem);
end
endmodule

使用$readmemh(“code.txt”, mem)指令读取文件,初始化im。

5.ALU

端口名 输入\输出 位宽 功能
ALUOp Input 3:0 ALU功能选择
A Input 31:0 待处理数字1
B Input 31:0 待处理数字2
result Output 31:0 计算结果
overflow Output 1 溢出判断
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
`define ADD 4'b0000
`define SUB 4'b0001
`define MUL 4'b0010
`define DIV 4'b0011
`define AND 4'b0100
`define OR 4'b0101
module ALU (
input [ 3:0] aluop,
input [31:0] A,
input [31:0] B,

output [31:0] result,
output overflow
);
reg [32:0] bit_33;

assign overflow = (bit_33[32]!=bit_33[31]);
assign result = bit_33[31:0];

always @(*) begin
case (aluop)
`ADD: bit_33 = A + B;
`SUB: bit_33 = A - B;
`MUL: bit_33 = A * B;
`DIV: bit_33 = A / B;
`AND: bit_33 = A & B;
`OR: bit_33 = A | B;
default: begin
bit_33 = 33'b0;
end
endcase

end



endmodule

ALUOp:(留一位给剩下的)

0000 0001 0010 0011 0100 0101 0110 0111
add sub mul div and or sll srl

6.EXT

端口名 输入\输出 位宽 功能
imm Input 15:0 16位立即数
extp Input 1 位扩展选择功能
extresult Output 31:0 位扩展计算结果
1
2
3
4
5
6
7
8
9
10
module EXT (
input [1:0] extop,
input [15:0] imm,
output [31:0] extresult
);
assign extresult = (extop == 2'b00) ? {16'h0000, imm} :
(extop == 2'b01) ? {{16{imm[15]}}, imm} :
(extop == 2'b10) ? {imm, 16'h0000} : {16'h0000, imm};//²âÊÔ
endmodule

EXTOp: 00 01 10 11
功能 0扩展 符号扩展 高位加载 空余

7.CTRL

端口名 输入\输出 位宽 功能
opcode Input 5:0 高六位opcode
func Input 5:0 低六位opcode
instr Input 31:0 指令码
regwrite Output 1 reg写使能
regwritedst Output 1:0 寄存器写选择
alusrc Output 1 alu选择imm入B口
memwrite Output 1 mem写使能
memtoreg Output 1 mem写入reg选择
jr_if Output 1 jr判断
j_if Output 1 j判断
jal_if Output 1 jal判断
beq_if Output 1 beq判断
extop Output 1:0 ext功能选择
aluop Output 3:0 alu功能选择

通过输入的指令码各部分,进行操作状态输出。

执行指令
信号名 add sub andi lui ori j jal jr beq sw lw nop
opcode 000000 000000 001100 001111 001101 000010 000011 000000 000100 101011 100011 000000
func 100000 100010 001000 000000
regwrite 1 1 1 1 1 0 1 0 0 0 1 0
regwritedst(2) 01(rd) 01 00 00 00(rt) 00 10($ra) 00 00 00 00 01
alusrc(imm) 0 0 1 1 1 0 0 0 0 1 1 0
memwrite 0 0 0 0 0 0 0 0 0 1 0 0
memtoreg 0 0 0 0 0 0 0 0 0 0 1 0
extop(2) 00 00 00 10 00 00 00 00 01 01 01 00
beq_if 0 0 0 0 0 0 0 0 1 0 0 0
j_if 0 0 0 0 0 1 0 0 0 0 0 0
jal_if 0 0 0 0 0 0 1 0 0 0 0 0
jr_if 0 0 0 0 0 0 0 1 0 0 0 0
ALU_ctr3 0 0 1 0(add$0) 1 0 0 0 0 0 0 0
ALU_ctr2 0 0 0 0 0 0 0 0 0 0 0 0
ALU_ctr1 0 1 0 0 1 0 0 0 1(sub验证) 0 0 0
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
`define OPCODE0 6'b000000
`define ADD 6'b100000
`define SUB 6'b100010
`define ANDI 6'b001100
`define ORI 6'b001101
`define LUI 6'b001111
`define J 6'b000010
`define JAL 6'b000011
`define JR 6'b001000
`define SW 6'b101011
`define LW 6'b100011
`define BEQ 6'b000100
`define SLT 6'b101010
`define SLTU 6'b101011
`define FUNC0 6'b000000

`define NOP 6'b000000
module CTRL (
input [5:0] opcode,
input [5:0] func,
input [31:0] instr,
output reg regwrite,
output reg [1:0] regwritedst,
output reg alusrc,
output reg memwrite,
output reg memtoreg,
output reg [1:0] extop,
output reg [3:0] aluop,



output reg beq_if,
output reg j_if,
output reg jr_if,
output reg jal_if
);

always @(*) begin
if (instr == 32'b0) begin
{regwrite , regwritedst} = {1'b0,2'b00};//rt,rd,31
{memwrite , memtoreg} = {1'b0,1'b0};
{beq_if , j_if , jal_if , jr_if} = {1'b0,1'b0,1'b0,1'b0};
extop = 2'b00; //unsigned,signed,lui
alusrc = 1'b0; //grf,imm
aluop = 4'b0000;
end else begin
case (opcode)
`OPCODE0:
case (func)
`ADD: begin
{regwrite , regwritedst} = {1'b1,2'b01};//rt,rd,31
{memwrite , memtoreg} = {1'b0,1'b0};
{beq_if , j_if , jal_if , jr_if} = {1'b0,1'b0,1'b0,1'b0};
extop = 2'b00; //unsigned,signed,lui
alusrc = 1'b0; //grf,imm
aluop = 4'b0000;
end
`SUB: begin
{regwrite , regwritedst} = {1'b1,2'b01};//rt,rd,31
{memwrite , memtoreg} = {1'b0,1'b0};
{beq_if , j_if , jal_if , jr_if} = {1'b0,1'b0,1'b0,1'b0};
extop = 2'b00; //unsigned,signed,lui
alusrc = 1'b0; //grf,imm
aluop = 4'b0001;
end
`JR: begin
{regwrite , regwritedst} = {1'b0,2'b00};//rt,rd,31
{memwrite , memtoreg} = {1'b0,1'b0};
{beq_if , j_if , jal_if , jr_if} = {1'b0,1'b0,1'b0,1'b1};
extop = 2'b00; //unsigned,signed,lui
alusrc = 1'b0; //grf,imm
aluop = 4'b0000;
end

default: begin
{regwrite , regwritedst} = {1'b0,2'b00};//rt,rd,31
{memwrite , memtoreg} = {1'b0,1'b0};
{beq_if , j_if , jal_if , jr_if} = {1'b0,1'b0,1'b0,1'b0};
extop = 2'b00; //unsigned,signed,lui
alusrc = 1'b0; //grf,imm
aluop = 4'b0000;
end
endcase
`ANDI: begin
{regwrite , regwritedst} = {1'b1,2'b00};//rt,rd,31
{memwrite , memtoreg} = {1'b0,1'b0};
{beq_if , j_if , jal_if , jr_if} = {1'b0,1'b0,1'b0,1'b0};
extop = 2'b00; //unsigned,signed,lui
alusrc = 1'b1; //grf,imm
aluop = 4'b0100;
end
`LUI: begin
{regwrite , regwritedst} = {1'b1,2'b00};//rt,rd,31
{memwrite , memtoreg} = {1'b0,1'b0};
{beq_if , j_if , jal_if , jr_if} = {1'b0,1'b0,1'b0,1'b0};
extop = 2'b10; //unsigned,signed,lui
alusrc = 1'b1; //grf,imm
aluop = 4'b0000;
end
`ORI: begin
{regwrite , regwritedst} = {1'b1,2'b00};//rt,rd,31
{memwrite , memtoreg} = {1'b0,1'b0};
{beq_if , j_if , jal_if , jr_if} = {1'b0,1'b0,1'b0,1'b0};
extop = 2'b00; //unsigned,signed,lui
alusrc = 1'b1; //grf,imm
aluop = 4'b0101;
end
`J: begin
{regwrite , regwritedst} = {1'b0,2'b00};//rt,rd,31
{memwrite , memtoreg} = {1'b0,1'b0};
{beq_if , j_if , jal_if , jr_if} = {1'b0,1'b1,1'b0,1'b0};
extop = 2'b00; //unsigned,signed,lui
alusrc = 1'b0; //grf,imm
aluop = 4'b0000;
end
`JAL: begin
{regwrite , regwritedst} = {1'b1,2'b10};//rt,rd,31
{memwrite , memtoreg} = {1'b0,1'b0};
{beq_if , j_if , jal_if , jr_if} = {1'b0,1'b0,1'b1,1'b0};
extop = 2'b00; //unsigned,signed,lui
alusrc = 1'b0; //grf,imm
aluop = 4'b0000;
end
`BEQ: begin
{regwrite , regwritedst} = {1'b0,2'b00};//rt,rd,31
{memwrite , memtoreg} = {1'b0,1'b0};
{beq_if , j_if , jal_if , jr_if} = {1'b1,1'b0,1'b0,1'b0};
extop = 2'b01; //unsigned,signed,lui
alusrc = 1'b0; //grf,imm
aluop = 4'b0001;
end
`SW: begin
{regwrite , regwritedst} = {1'b0,2'b00};//rt,rd,31
{memwrite , memtoreg} = {1'b1,1'b0};
{beq_if , j_if , jal_if , jr_if} = {1'b0,1'b0,1'b0,1'b0};
extop = 2'b01; //unsigned,signed,lui
alusrc = 1'b1; //grf,imm
aluop = 4'b0000;
end
`LW: begin
{regwrite , regwritedst} = {1'b1,2'b00};//rt,rd,31
{memwrite , memtoreg} = {1'b0,1'b1};
{beq_if , j_if , jal_if , jr_if} = {1'b0,1'b0,1'b0,1'b0};
extop = 2'b01; //unsigned,signed,lui
alusrc = 1'b1; //grf,imm
aluop = 4'b0000;
end
default: begin
{regwrite , regwritedst} = {1'b0,2'b00};//rt,rd,31
{memwrite , memtoreg} = {1'b0,1'b0};
{beq_if , j_if , jal_if , jr_if} = {1'b0,1'b0,1'b0,1'b0};
extop = 2'b00; //unsigned,signed,lui
alusrc = 1'b0; //grf,imm
aluop = 4'b0000;
end
endcase
end

end
endmodule

各信号注意点:

  • add、sub、jr指令需要先判断opcode再判断func。

8.HCTRL

端口名 输入\输出 位宽 批注
IR_F Input 31:0 /
IR_D Input 31:0 /
RS_D Input 4:0 /
RT_D Input 4:0 /
RS_E Input 4:0 /
RT_E Input 4:0 /
WA_E Input 4:0 /
WA_M Input 4:0 /
WA_W Input 4:0 /
memtoreg_E Input 1 /
memtoreg_M Input 1 /
regwrite_E Input 1 /
regwrite_M Input 1 /
regwrite_W Input 1 /
memwrite_M Input 1 /
D_CLEAR Output 1 D流水寄存器清空
F_BLOCK Output 1 F流水寄存器保持
PC_BLOCK Output 1 PC保持
rd1_sel Output 1:0 R1_D_IN选择
rd2_sel Output 1:0 R2_D_IN选择
frd1_sel Output 1:0 aluA选择
frd1_sel Output 1:0 aluB选择
memdata_sel Output 1:0 mem写入WD选择
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
`timescale 1ns / 1ps
`define OPCODE0 6'b000000
`define ADD 6'b100000
`define SUB 6'b100010
`define ANDI 6'b001100
`define ORI 6'b001101
`define LUI 6'b001111
`define J 6'b000010
`define JAL 6'b000011
`define JR 6'b001000
`define SW 6'b101011
`define LW 6'b100011
`define BEQ 6'b000100
`define FUNC0 6'b000000
`define NOP 6'b000000
module HCTRL (
input clk,
input [31:0] IR_F,
input [31:0] IR_D,
input [4:0] RS_D,
input [4:0] RT_D,
input [4:0] RS_E,
input [4:0] RT_E,
input [4:0] WA_M,
input [4:0] WA_W,
input [4:0] WA_E,
input memtoreg_E,
input memtoreg_M,
input regwrite_E,
input regwrite_M,
input regwrite_W,
input memwrite_M,
output reg D_CLEAR,
output reg F_BLOCK,
output reg PC_BLOCK,
output reg [1:0] rd1_sel,
output reg [1:0] rd2_sel,
output reg [1:0] frd1_sel,
output reg [1:0] frd2_sel,
output reg [1:0] memdata_sel

);

reg [31:0] E_T_new;
reg [31:0] M_T_new;
reg [31:0] W_T_new;
reg [31:0] T_use;
wire [5:0] opcode_F;
wire [5:0] func_F;
wire use_less_E_new;
wire use_less_M_new;
wire use_less_W_new;
assign use_less_E_new=(((WA_E==RS_D&&RS_D!=0)||(WA_E==RT_D&&RT_D!=0))&&(regwrite_E)&&(T_use < E_T_new)===1);
assign use_less_M_new=(((WA_M==RS_D&&RS_D!=0)||(WA_M==RT_D&&RT_D!=0))&&(regwrite_M)&&(T_use < M_T_new)===1);
assign use_less_W_new=(((WA_W==RS_D&&RS_D!=0)||(WA_W==RT_D&&RT_D!=0))&&(regwrite_W)&&(T_use < W_T_new)===1);

assign opcode_F = IR_F[31:26];
assign func_F = IR_F[5:0];
always @(*) begin
if (memtoreg_E && regwrite_E) begin
E_T_new = 2;
end else if ((!memtoreg_E) && regwrite_E) begin
E_T_new = 1;
end else begin
E_T_new = 0;
end


if (memtoreg_M) begin
M_T_new = 1;
end else begin
M_T_new = 0;
end
W_T_new = 0;
if(((opcode_F==`OPCODE0)&&(func_F==`ADD||func_F==`SUB))||(opcode_F==`ORI)||(opcode_F==`LW)||(opcode_F==`SW)) begin
T_use = 1;
end else if (opcode_F == `LUI || opcode_F == `J || opcode_F == `JAL || IR_F == 32'b0) begin
T_use = 9;
end else begin
T_use = 0;
end
if (use_less_E_new || use_less_M_new || use_less_W_new) begin
PC_BLOCK = 1;
D_CLEAR = 1;
F_BLOCK = 1;
end else begin

PC_BLOCK = 0;
D_CLEAR = 0;
F_BLOCK = 0;
end



if ((M_T_new == 0) && (WA_M == RS_E) && (regwrite_M)) begin
frd1_sel = 1;
end else if ((W_T_new == 0) && (WA_W == RS_E) && (regwrite_W)) begin
frd1_sel = 2;
end else begin
frd1_sel = 0;
end

if ((M_T_new == 0) && (WA_M == RT_E) && (regwrite_M)) begin
frd2_sel = 1;
end else if ((W_T_new == 0) && (WA_W == RT_E) && (regwrite_W)) begin
frd2_sel = 2;
end else begin
frd2_sel = 0;
end




if (M_T_new == 0 && WA_M == RS_D && regwrite_M) begin
rd1_sel = 0;
end else begin
rd1_sel = 1;
end
if (M_T_new == 0 && WA_M == RT_D && regwrite_M) begin
rd2_sel = 0;
end else begin
rd2_sel = 1;
end

if (memwrite_M) begin
memdata_sel = 1;
end else begin
memdata_sel = 0;
end


end

endmodule

9.流水线REG

F:

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
`timescale 1ns / 1ps

module F_REG (
input clk,
input reset,
input BLOCK,
input [31:0] PC_F_IN,
input [31:0] IR_F_IN,
output [31:0] PC_F_OUT,
output [31:0] IR_F_OUT

);
reg [31:0] PC_F;
reg [31:0] IR_F;
assign PC_F_OUT = PC_F;
assign IR_F_OUT = IR_F;

always @(posedge clk) begin
if (reset) begin
PC_F <= 32'b0;
IR_F <= 32'b0;
end else begin
if (BLOCK) begin
PC_F <= PC_F;
IR_F <= IR_F;
end else begin
PC_F <= PC_F_IN;
IR_F <= IR_F_IN;
end
end
end
endmodule

D:

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
module D_REG (
input clk,
input reset,
input D_CLEAR,
input [31:0] PC_D_IN,
input [31:0] IR_D_IN,
input [31:0] R1_D_IN,
input [31:0] R2_D_IN,

output [31:0] PC_D_OUT,
output [31:0] R1_D_OUT,
output [31:0] R2_D_OUT,
output [31:0] IR_D_OUT,


input regwrite,
input [1:0] regwritedst,
input alusrc,
input memwrite,
input memtoreg,
input [3:0] aluop,
input jal_if,
input [31:0] IMM_D_IN,

output memtoreg_E,
output regwrite_E,
output [1:0] regwritedst_E,
output memwrite_E,
output alusrc_E,
output [3:0] aluop_E,
output jal_if_E,
output [31:0] IMM_D_OUT

);

reg [31:0] PC_D;
reg [31:0] R1_D;
reg [31:0] R2_D;
reg [31:0] IR_D;
reg [31:0] IMM_D;
reg regwritereg;
reg [1:0] regwritedstreg;
reg alusrcreg;
reg memwritereg;
reg memtoregreg;
reg [3:0] aluopreg;
reg jal_ifreg;

assign PC_D_OUT = PC_D;
assign R1_D_OUT = R1_D;
assign R2_D_OUT = R2_D;
assign IR_D_OUT = IR_D;
assign IMM_D_OUT = IMM_D;
assign regwrite_E = regwritereg;
assign regwritedst_E = regwritedstreg;
assign memtoreg_E = memtoregreg;
assign memwrite_E = memwritereg;
assign alusrc_E = alusrcreg;
assign aluop_E = aluopreg;
assign jal_if_E = jal_ifreg;
always @(posedge clk) begin
if (reset) begin
PC_D <= 32'b0;
R1_D <= 32'b0;
R2_D <= 32'b0;
IR_D <= 32'b0;
IMM_D <= 32'b0;
jal_ifreg <= 0;
regwritereg <= 0;
regwritedstreg <= 2'b0;
alusrcreg <= 0;
memwritereg <= 0;
memtoregreg <= 0;
aluopreg <= 4'b0;
end else begin
if (D_CLEAR) begin
PC_D <= 32'b0;
R1_D <= 32'b0;
R2_D <= 32'b0;
IR_D <= 32'b0;
IMM_D <= 32'b0;
jal_ifreg <= 0;
regwritereg <= 0;
regwritedstreg <= 2'b0;
alusrcreg <= 0;
memwritereg <= 0;
memtoregreg <= 0;
aluopreg <= 4'b0;
end else begin
PC_D <= PC_D_IN;
IR_D <= IR_D_IN;
R1_D <= R1_D_IN;
R2_D <= R2_D_IN;
IMM_D <= IMM_D_IN;
jal_ifreg <= jal_if;
regwritereg <= regwrite;
regwritedstreg <= regwritedst;
alusrcreg <= alusrc;
memwritereg <= memwrite;
memtoregreg <= memtoreg;
aluopreg <= aluop;
end
end
end
endmodule

E:

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
`timescale 1ns / 1ps

module E_REG(
input clk,
input reset,
input [31:0] PC_E_IN,
input [31:0] AO_E_IN,
input [31:0] WD_E_IN,
input [4:0] WA_E_IN,
input [31:0] IR_E_IN,
output [31:0] PC_E_OUT,
output [31:0] AO_E_OUT,
output [31:0] WD_E_OUT,
output [4:0] WA_E_OUT,
output [31:0] IR_E_OUT,

input regwrite,
input memwrite,
input memtoreg,

output memtoreg_M,
output regwrite_M,
output memwrite_M

);
reg [31:0] PC_E;
reg [31:0] AO_E;
reg [31:0] WD_E;
reg [4:0] WA_E;
reg [31:0] IR_E;
reg regwritereg;
reg memtoregreg;
reg memwritereg;
assign PC_E_OUT=PC_E;
assign AO_E_OUT=AO_E;
assign WD_E_OUT=WD_E;
assign WA_E_OUT=WA_E;
assign IR_E_OUT=IR_E;
assign memtoreg_M=memtoregreg;
assign memwrite_M=memwritereg;
assign regwrite_M=regwritereg;
always @(posedge clk) begin
if (reset) begin
PC_E<=32'b0;
AO_E<=32'b0;
WD_E<=32'b0;
WA_E<=5'b0;
IR_E<=31'b0;
memtoregreg<=0;
memwritereg<=0;
regwritereg<=0;
end
else begin

PC_E<=PC_E_IN;
AO_E<=AO_E_IN;
WD_E<=WD_E_IN;
WA_E<=WA_E_IN;
IR_E<=IR_E_IN;
memtoregreg<=memtoreg;
memwritereg<=memwrite;
regwritereg<=regwrite;;


end

end
endmodule

M:

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
module M_REG (
input clk,
input reset,
input [31:0] PC_M_IN,
input [31:0] AO_M_IN,
input [31:0] MD_M_IN,
input [4:0] WA_M_IN,
output [31:0] AO_M_OUT,
output [31:0] MD_M_OUT,
output [4:0] WA_M_OUT,
output [31:0] PC_M_OUT,

input regwrite,
input memtoreg,

output memtoreg_W,
output regwrite_W

);
reg [31:0] AO_M;
reg [31:0] MD_M;
reg [4:0] WA_M;
reg [31:0] PC_M;
reg regwritereg;
reg memtoregreg;
assign AO_M_OUT = AO_M;
assign MD_M_OUT = MD_M;
assign WA_M_OUT = WA_M;
assign PC_M_OUT = PC_M;
assign regwrite_W = regwritereg;
assign memtoreg_W = memtoregreg;
always @(posedge clk) begin
if (reset) begin
AO_M <= 32'b0;
MD_M <= 32'b0;
WA_M <= 5'b0;
PC_M <= 32'b0;
regwritereg <= 0;
memtoregreg <= 0;
end else begin

AO_M <= AO_M_IN;
MD_M <= MD_M_IN;
WA_M <= WA_M_IN;
PC_M <= PC_M_IN;
regwritereg <= regwrite;
memtoregreg <= memtoreg;

end
end
endmodule

注意一下特殊的清空或者阻塞信号即可。

10.mips(顶层模块)

注意流水寄存器中为pc+4,使用时需要减去4,而jal的pc+8需要加4

添加了31号和pc+8的选择。

x_D_IN表示一个名为x的信号,IN表示输入,D表示输入的流水线寄存器

x_E 表示一个名为x的信号,处于E时期,可能为D_OUT或者E_IN。

M_REG表示其前一阶段为M阶段。

转发表:

供给者序号\需求者 D级grf的输出 E级alu的输入 M级mem的内存写入数据WD
0 AO_E_OUT r1_D_OUT/r2_D_OUT WD_E_OUT
1 rd1/rd2 AO_E_OUT realgrfdata(真实值)
2 / grfwritedata(包括memout和AO_M_OUT) /

mux暂时不用,改为assign选择。

MUX选择信号表:

序号 \ 需求者/控制信号 aluB/alusrc AO_E_IN/jal_if WA_E_IN/regdst_E grfwritedata/memtoreg_W
0 转发后的rd2 aluresult rt AO_M_OUT(alu结果)
1 imm pc+8(jal使用0) rd MD_M_OUT(内存读取)
2 / / 31 /
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
module mips (
input clk,
input reset
);
///////////////////////////////////////////////WIRE
wire [31:0]pc_4;
wire d_clear;
wire f_block;
wire pc_block;
wire [1:0] rd1_sel;
wire [1:0] rd2_sel;
wire [1:0] frd1_sel;
wire [1:0] frd2_sel;
wire [31:0] pc_NPC_IM;//
wire [31:0] ir_IM_F;//
wire [31:0] pc_F_OUT;//
wire [31:0] ir_F_OUT;//
wire [31:0] r1_D_IN;
wire [31:0] r2_D_IN;
wire [31:0] rd1;
wire [31:0] rd2;
wire memwrite;
wire memtoreg;
wire regwrite;
wire [1:0] regwritedst;
wire alusrc;

wire beq_if;
wire j_if;
wire jr_if;
wire jal_if;

wire [1:0] extop;
wire [3:0] aluop;

wire [31:0] extresult;

wire [31:0] imm_D_OUT;
wire [31:0] pc_D_OUT;
wire [31:0] r1_D_OUT;
wire [31:0] r2_D_OUT;
wire [31:0] ir_D_OUT;
wire [3:0] aluop_E;
wire memwrite_E;
wire memtoreg_E;
wire regwrite_E;
wire [1:0] regwritedst_E;
wire alusrc_E;
wire beq_judge;
wire jal_if_E;

wire [31:0] aluA;
wire [31:0] aluB;
wire overflow;
wire [31:0] aluresult;

wire [31:0] ao_E_IN;
wire memwrite_M;
wire memtoreg_M;
wire regwrite_M;

wire [31:0] wd_E_IN;
wire [4:0] wa_E_IN;
wire [31:0] pc_E_OUT;
wire [31:0] ao_E_OUT;
wire [31:0] wd_E_OUT;
wire [4:0] wa_E_OUT;


wire [31:0] memoutdata;

wire memtoreg_W;
wire regwrite_W;

wire [31:0] md_M_OUT;
wire [31:0] ao_M_OUT;
wire [4:0] wa_M_OUT;

wire [31:0] pc_M_OUT;

wire [31:0] grfdata;

wire [31:0]memdata;
wire [1:0]memdata_sel;
wire [31:0]realgrfdata;
wire [31:0]ir_E_OUT;
////////////////////////////////////////////////////MUX_F

assign r1_D_IN=(rd1_sel===2'b00)?((wa_E_OUT===5'b0)?32'b0:ao_E_OUT):rd1;
assign r2_D_IN=(rd2_sel===2'b00)?((wa_E_OUT===5'b0)?32'b0:ao_E_OUT):rd2;

assign beq_judge=(beq_if&&(r1_D_IN==r2_D_IN))?1'b1:1'b0;

////////////////////////////////////////////////////MUX_D

assign aluA=(ir_D_OUT[25:21]===5'b0)?(32'b0):((frd1_sel===2'b00)?r1_D_OUT:
(frd1_sel===2'b01)?ao_E_OUT:grfdata);
assign aluB=(alusrc_E===1'b0)?((ir_D_OUT[20:16]===5'b0)?32'b0:(frd2_sel===2'b00)?r2_D_OUT:
(frd2_sel===2'b01)?ao_E_OUT:grfdata):(imm_D_OUT);

////////////////////////////////////////////////////MUX_E

assign ao_E_IN=(jal_if_E===1'b0)?aluresult:(pc_D_OUT+4);//pc+8
assign wd_E_IN=(ir_D_OUT[20:16]===5'b0)?32'b0:(frd2_sel===2'b00)?r2_D_OUT:
(frd2_sel===2'b01)?ao_E_OUT:grfdata;
assign wa_E_IN=(regwritedst_E===2'b00)?ir_D_OUT[20:16]:
(regwritedst_E===2'b01)?ir_D_OUT[15:11]:5'b11111;

////////////////////////////////////////////////////MUX_M

assign memdata=(memdata_sel===2'b00)?(wd_E_OUT):
realgrfdata;

////////////////////////////////////////////////////MUX_W
assign grfdata=(memtoreg_W===0)?ao_M_OUT:md_M_OUT;
HCTRL hctrl(
.clk(clk),//
.IR_F(ir_F_OUT),
.IR_D(ir_D_OUT),//
.D_CLEAR(d_clear),//
.F_BLOCK(f_block),//
.PC_BLOCK(pc_block),//
.RS_D(ir_F_OUT[25:21]),//
.RT_D(ir_F_OUT[20:16]),//
.RS_E(ir_D_OUT[25:21]),//
.RT_E(ir_D_OUT[20:16]),//
.WA_M(wa_E_OUT),//
.WA_W(wa_M_OUT),//
.WA_E(wa_E_IN),//
.memtoreg_E(memtoreg_E),//
.memtoreg_M(memtoreg_M),//
.regwrite_E(regwrite_E),//
.regwrite_M(regwrite_M),//
.regwrite_W(regwrite_W),//
.memwrite_M(memwrite_M),


.rd1_sel(rd1_sel),
.rd2_sel(rd2_sel),
.frd1_sel(frd1_sel),
.frd2_sel(frd2_sel),
.memdata_sel(memdata_sel)
);
///////////////////////////////////F_REG
NPC npc (
.clk(clk), //
.reset(reset), //
.NPC(pc_NPC_IM), //
.NPC_4(pc_4), //
.PC_D(pc_F_OUT),//
.block(pc_block),//
.beq_judge(beq_judge), //
.j_if(j_if), //
.jr_if(jr_if),//
.jal_if(jal_if), //
.imm(extresult), //
.j_addr(ir_F_OUT[25:0]), //
.jr_addr(r1_D_IN)//
);
IM im (
.pc(pc_NPC_IM), //
.instr(ir_IM_F) //
);
F_REG f_reg (
.clk(clk), //
.reset(reset), //
.BLOCK(f_block), //
.PC_F_IN(pc_4), //
.IR_F_IN(ir_IM_F), //
.PC_F_OUT(pc_F_OUT), //
.IR_F_OUT(ir_F_OUT)//
);
////////////////////////////////////D_REG
GRF grf (
.clk(clk), //
.reset(reset), //
.PC(pc_M_OUT-4), //

.WE(regwrite_W), //
.A1(ir_F_OUT[25:21]), //RS
.A2(ir_F_OUT[20:16]), //RT
.A3(wa_M_OUT),
.EXTRA(ir_E_OUT[20:16]), //
.WD(grfdata), //
.RD1(rd1), //
.RD2(rd2),
.RDEXTRA(realgrfdata) //
);

CTRL ctrl (
.instr(ir_F_OUT),//
.opcode(ir_F_OUT[31:26]),//
.func(ir_F_OUT[5:0]),//

.regwrite(regwrite),//
.regwritedst(regwritedst),//
.alusrc(alusrc),//
.memwrite(memwrite),//
.memtoreg(memtoreg),//
.beq_if(beq_if),//
.j_if(j_if),//
.jr_if(jr_if),//
.jal_if(jal_if),//
.extop(extop),//
.aluop(aluop)//
);
EXT ext (
.extop(extop), //
.imm(ir_F_OUT[15:0]), //
.extresult(extresult) //
);
D_REG d_reg (
.clk(clk), //
.reset(reset), //
.D_CLEAR(d_clear), //

.regwrite(regwrite),//
.regwritedst(regwritedst),//
.alusrc(alusrc),//
.memwrite(memwrite),//
.memtoreg(memtoreg),//
.aluop(aluop),//
.jal_if(jal_if),//

.regwritedst_E(regwritedst_E),//
.alusrc_E(alusrc_E),//
.memwrite_E(memwrite_E),//
.memtoreg_E(memtoreg_E),//
.regwrite_E(regwrite_E),//
.aluop_E(aluop_E),//
.jal_if_E(jal_if_E),

.PC_D_IN(pc_F_OUT), //
.IR_D_IN(ir_F_OUT), //
.IMM_D_IN(extresult),//
.R1_D_IN(r1_D_IN), //
.R2_D_IN(r2_D_IN), //

.IMM_D_OUT(imm_D_OUT),//
.PC_D_OUT(pc_D_OUT), //
.R1_D_OUT(r1_D_OUT), //
.R2_D_OUT(r2_D_OUT), //
.IR_D_OUT(ir_D_OUT)//
);
////////////////////////////////////E_REG
ALU alu (
.aluop(aluop_E), //
.A(aluA), //
.B(aluB), //
.result(aluresult), //
.overflow(overflow) //
);



E_REG e_reg (
.clk(clk), //
.reset(reset), //
.IR_E_IN(ir_D_OUT),
.IR_E_OUT(ir_E_OUT),

.memwrite(memwrite_E),//
.memtoreg(memtoreg_E),//
.regwrite(regwrite_E),//

.memwrite_M(memwrite_M),//
.memtoreg_M(memtoreg_M),//
.regwrite_M(regwrite_M),//

.PC_E_IN(pc_D_OUT), //
.AO_E_IN(ao_E_IN), //
.WD_E_IN(wd_E_IN), //
.WA_E_IN(wa_E_IN), //
.PC_E_OUT(pc_E_OUT), //
.AO_E_OUT(ao_E_OUT), //
.WD_E_OUT(wd_E_OUT), //
.WA_E_OUT(wa_E_OUT)//
);
/////////////////////////////////M_REG
DM dm (
.clk(clk), //
.reset(reset), //
.PC(pc_E_OUT-4), //
.memwrite(memwrite_M), //
.memaddr(ao_E_OUT), //
.memdata(memdata), //
.outdata(memoutdata) //
);
M_REG m_reg (
.clk(clk), //
.reset(reset), //

.memtoreg(memtoreg_M),//
.regwrite(regwrite_M),//

.memtoreg_W(memtoreg_W),//
.regwrite_W(regwrite_W),//

.AO_M_IN(ao_E_OUT), //
.MD_M_IN(memoutdata), //
.WA_M_IN(wa_E_OUT),//
.PC_M_IN(pc_E_OUT), //
.AO_M_OUT(ao_M_OUT), //
.MD_M_OUT(md_M_OUT), //
.WA_M_OUT(wa_M_OUT),//
.PC_M_OUT(pc_M_OUT)//
);

endmodule

AT法详表:

指令 T_use E_T_new M_T_new W_T_new
ADD/SUB/ORI 1 1 0 0
LW 1 2 1 0
SW 1(特殊) 0 0 0
LUI INF 1 0 0
BEQ 0 0 0 0
JR 0 0 0 0
J INF 0 0 0
JAL INF 1(用aluresult传入pc+8) 0 0
NOP INF 0 0 0

对于sw

如果sw处于E级,lw处于M级,会产生wd无法正确转发的错误。

其读取rt的值写入内存时所需的rt是有可能在后方的先前指令修改,用grf魔改端口实现实时输出真实值,通过对E级memwrite判断是否需要写入内存,来选择真实值,避免对sw进行错误的判断。

测试方案

通过mars编写汇编程序,编写相关测试代码,将mars生成的机器码通过文件导入到verilog,通过向输出中间数据,和mars进行对拍,以此验证各代码是否运行正确。

思考题

1.

例如:

1
2
3
add $t1,$t1,$t2
add $t1,$t1,$t2
beq $t1,$t3,label

提前分支判断会导致其阻塞一周期,但是如果在M级分支判断可以通过转发解决。

2.

延迟槽会导致跳转指令下一条指令也会被执行,但是如果使用pc+4会导致跳转回来时候重复执行,所以需要pc+8。

3.

这样可以保证时序的准确性,如果直接接到元器件上,可能会产生一些毛刺数据造成潜在的转发错误。

4.

因为要实现在D级跳转,如果此时W级有写入数据,那么需要在判断时转发数据保证正确性,而此时转发的接收者和发送者都是grf,因此可以内部转发。

实现:

1
2
assign RD1 = (A1 == 5'b0) ? 32'b0 : ((A1 == A3) && WE) ? WD : registers[A1];
assign RD2 = (A2 == 5'b0) ? 32'b0 : ((A2 == A3) && WE) ? WD : registers[A2];

值得注意的是需要对$0特判。

5.

供给者序号\需求者 D级grf的输出 E级alu的输入 M级mem的内存写入数据WD
0 AO_E_OUT r1_D_OUT/r2_D_OUT WD_E_OUT
1 rd1/rd2 AO_E_OUT realgrfdata(真实值)
2 / grfwritedata(包括memout和AO_M_OUT) /

6.

可能的修改:

alu内部计算逻辑、alu计算数选择、grf的读取写入寄存器选择、冒险控制元件判断逻辑、PC增加逻辑、imm预处理、

7.

通过对opcode和func的分层判断,以此来判断命令类型译码,采用命令控制的信号驱动,对每一条指令产生的所有信号进行判断,这种好处是如果产生的新的命令,可以方便地加入,缺点是如果同时加入大量指令,可能有大部分无效添加的低电平信号,而且不便于管理单个信号的命令控制。

附录:

题目测试代码翻译:

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
0x0000000000000000:  34 1C 00 00    ori $gp, $zero, 0
0x0000000000000004: 34 1D 00 00 ori $sp, $zero, 0
0x0000000000000008: 34 01 10 10 ori $at, $zero, 0x1010
0x000000000000000c: 3C 02 87 23 lui $v0, 0x8723
0x0000000000000010: 34 03 78 56 ori $v1, $zero, 0x7856
0x0000000000000014: 3C 04 85 FF lui $a0, 0x85ff
0x0000000000000018: 34 05 00 01 ori $a1, $zero, 1
0x000000000000001c: 3C 06 FF FF lui $a2, 0xffff
0x0000000000000020: 34 07 FF FF ori $a3, $zero, 0xffff
0x0000000000000024: 00 22 08 20 add $at, $at, $v0
0x0000000000000028: 00 23 48 20 add $t1, $at, $v1
0x000000000000002c: 00 22 40 22 sub $t0, $at, $v0
0x0000000000000030: 00 E0 00 22 sub $zero, $a3, $zero
0x0000000000000034: 13 91 00 03 beq $gp, $s1, 0x44
0x0000000000000038: 00 00 00 00 nop
0x000000000000003c: 10 00 00 15 b 0x94
0x0000000000000040: 00 00 00 00 nop
0x0000000000000044: 10 22 00 13 beq $at, $v0, 0x94
0x0000000000000048: 00 00 00 00 nop
0x000000000000004c: 34 02 00 0C ori $v0, $zero, 0xc
0x0000000000000050: 00 00 00 00 nop
0x0000000000000054: 00 00 00 00 nop
0x0000000000000058: 00 00 00 00 nop
0x000000000000005c: 0C 00 0C 1B jal 0x306c
0x0000000000000060: AC 41 00 00 sw $at, ($v0)
0x0000000000000064: 10 00 00 0B b 0x94
0x0000000000000068: 00 22 08 20 add $at, $at, $v0
0x000000000000006c: 00 22 08 20 add $at, $at, $v0
0x0000000000000070: 00 22 08 20 add $at, $at, $v0
0x0000000000000074: 00 22 08 20 add $at, $at, $v0
0x0000000000000078: AC 5F 00 00 sw $ra, ($v0)
0x000000000000007c: 8C 41 00 00 lw $at, ($v0)
0x0000000000000080: 00 00 00 00 nop
0x0000000000000084: 00 00 00 00 nop
0x0000000000000088: 00 00 00 00 nop
0x000000000000008c: 00 20 00 08 jr $at
0x0000000000000090: AC 5F 00 00 sw $ra, ($v0)
0x0000000000000094: 10 00 FF FF b 0x94
0x0000000000000098: 00 00 00 00 nop
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@00003000: $28 <= 00000000
@00003004: $29 <= 00000000
@00003008: $ 1 <= 00001010
@0000300c: $ 2 <= 87230000
@00003010: $ 3 <= 00007856
@00003014: $ 4 <= 85ff0000
@00003018: $ 5 <= 00000001
@0000301c: $ 6 <= ffff0000
@00003020: $ 7 <= 0000ffff
@00003024: $ 1 <= 87231010
@00003028: $ 9 <= 87238866
@0000302c: $ 8 <= 00001010
@00003030: $ 0 <= 0000ffff
@0000304c: $ 2 <= 0000000c
@0000305c: $31 <= 00003064
@00003060: *0000000c <= 87231010
@0000306c: $ 1 <= 8723101c
@00003070: $ 1 <= 87231028
@00003074: $ 1 <= 87231034
@00003078: *0000000c <= 00003064
@0000307c: $ 1 <= 00003064
@00003090: *0000000c <= 00003064
@00003068: $ 1 <= 00003070

所涉及的指令的手册解释