关于p7中断测试分享

Carbon

构想的中断发生情况

  • 常规指令:阻塞一周期、阻塞两周期
  • sw
  • 跳转延迟槽:跳转、未跳转
  • eret后一条指令
  • 乘除指令
  • 乘除槽
  • 乘除槽内的延迟槽
  • 指令异常
  • 指令异常且处于延迟槽

对应.asm

注:以下测试代码仅针对本人结构编写,即乘除模块在E级,cp0在M级。例如为了测乘除指令刚到乘除模块时的情况,macroPC取乘除指令上一条。然而,如果你采用了其他的设计,还请自行调整。

此代码未测试中断发生在eret后的情况,然而强烈建议自行进行测试

由于水平有限,不保证对应测试代码真的起到测试的作用,还请各位大佬批评指正

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
no_jump:
ori $28, $28, 4
ori $29, $29, 1

ori $20, $0, 0x1001
mtc0 $20, $12

ori $1, $1, 246
ori $2, $2, 135
beq $2, $zero, no_jump
nop

sw $28, 0($zero)

lw $3, 0($zero)
beq $3, $zero, no_jump
nop

beq $zero, $zero, jump1
add $4, $4, $29
add $5, $5, $29
jump1:
beq $zero, $29, jump2
add $4, $4, $29
add $5, $5, $29
jump2:

mult $1, $2
add $6, $29, $10
mflo $7

mult $1, $2
add $6, $29, $10
add $6, $29, $10
mflo $7

mult $7, $1
beq $zero, $29, jump3
mflo $7
jump3:
add $6, $29, $10

lw $8, 1($0)

beq $zero, $29, no_jump
lw $8, 1($0)
add $6, $29, $10

.ktext 0x4180
mfc0 $26, $13
ori $21, $21, 0x7c
and $26, $21, $26
beq $26, $zero, interruption
nop
# 对于异常程序直接忽视(未考虑pc异常)
exception:
mfc0 $27, $14
add $27, $27, $28
mtc0 $27, $14
eret
# 对于中断让30号寄存器加一
interruption:
add $30, $30, $29
sw $30, 0x7F20($zero)
eret
add $30, $30, $28 #eret无延迟槽

数据导出方案

在Mars所在地址打开cmd输入

1
java -jar <mars> db nc mc CompactDataAtZero a dump 0x4180-0x6ffc HexText <xxx.txt> <xxx.asm>

修改后的tb

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

module mips_txt;

reg clk;
reg reset;
reg interrupt;

wire [31:0] macroscopic_pc;

wire [31:0] i_inst_addr;
wire [31:0] i_inst_rdata;

wire [31:0] m_data_addr;
wire [31:0] m_data_rdata;
wire [31:0] m_data_wdata;
wire [3 :0] m_data_byteen;

wire [31:0] m_int_addr;
wire [3 :0] m_int_byteen;

wire [31:0] m_inst_addr;

wire w_grf_we;
wire [4 :0] w_grf_addr;
wire [31:0] w_grf_wdata;

wire [31:0] w_inst_addr;

mips uut(
.clk(clk),
.reset(reset),
.interrupt(interrupt),
.macroscopic_pc(macroscopic_pc),

.i_inst_addr(i_inst_addr),
.i_inst_rdata(i_inst_rdata),

.m_data_addr(m_data_addr),
.m_data_rdata(m_data_rdata),
.m_data_wdata(m_data_wdata),
.m_data_byteen(m_data_byteen),

.m_int_addr(m_int_addr),
.m_int_byteen(m_int_byteen),

.m_inst_addr(m_inst_addr),

.w_grf_we(w_grf_we),
.w_grf_addr(w_grf_addr),
.w_grf_wdata(w_grf_wdata),

.w_inst_addr(w_inst_addr)
);

initial begin
clk <= 0;
reset <= 1;
interrupt <= 0;
#20 reset <= 0;
end

integer i;
reg [31:0] fixed_addr;
reg [31:0] fixed_wdata;
reg [31:0] data[0:4095];
reg [31:0] inst[0:5119];

// ----------- For Instructions -----------

assign m_data_rdata = data[(m_data_addr >> 2) % 5120];
assign i_inst_rdata = inst[((i_inst_addr - 32'h3000) >> 2) % 5120];

initial begin
$dumpfile("wave.vcd"); // 指定VCD文件的名字为wave.vcd,仿真信息将记录到此文件
$dumpvars(0, mips_txt); // 指定层次数为0,则tb_code 模块及其下面各层次的所有信号将被记录
#20000 $finish;
end

initial begin
$readmemh("code.txt", inst);
$readmemh("handlerCode.txt", inst, (32'h4180-32'h3000)>>2);
for (i = 0; i < 5120; i = i + 1) data[i] <= 0;
end

// ----------- For Data Memory -----------

always @(*) begin
fixed_wdata = data[(m_data_addr >> 2) & 4095];
fixed_addr = m_data_addr & 32'hfffffffc;
if (m_data_byteen[3]) fixed_wdata[31:24] = m_data_wdata[31:24];
if (m_data_byteen[2]) fixed_wdata[23:16] = m_data_wdata[23:16];
if (m_data_byteen[1]) fixed_wdata[15: 8] = m_data_wdata[15: 8];
if (m_data_byteen[0]) fixed_wdata[7 : 0] = m_data_wdata[7 : 0];
end

always @(posedge clk) begin
if (reset) for (i = 0; i < 4096; i = i + 1) data[i] <= 0;
else if (|m_data_byteen && fixed_addr >> 2 < 4096) begin
data[fixed_addr >> 2] <= fixed_wdata;
$display("%d@%h: *%h <= %h", $time, m_inst_addr, fixed_addr, fixed_wdata);
end
end

// ----------- For Registers -----------

always @(posedge clk) begin
if (~reset) begin
if (w_grf_we && (w_grf_addr != 0)) begin
$display("%d@%h: $%d <= %h", $time, w_inst_addr, w_grf_addr, w_grf_wdata);
end
end
end

// ----------- For Interrupt -----------

wire [31:0] fixed_macroscopic_pc;

assign fixed_macroscopic_pc = macroscopic_pc & 32'hfffffffc;

integer cnt;

always @(negedge clk) begin
if (reset) begin
interrupt = 0;
cnt = 0;
end
else begin
if (interrupt) begin
if (|m_int_byteen && (m_int_addr & 32'hfffffffc) == 32'h7f20) begin
interrupt = 0;
end
end
//阻塞一个周期
else if (fixed_macroscopic_pc == 32'h3014 && cnt == 0) begin
interrupt = 1;
cnt = cnt + 1;
end
//sw同时中断(需停止写入)
else if (fixed_macroscopic_pc == 32'h3020 && cnt == 1) begin
interrupt = 1;
cnt = cnt + 1;
end
//阻塞两个周期
else if (fixed_macroscopic_pc == 32'h3028 && cnt == 2) begin
interrupt = 1;
cnt = cnt + 1;
end
//延迟槽
else if (fixed_macroscopic_pc == 32'h3034 && cnt == 3) begin
interrupt = 1;
cnt = cnt + 1;
end
else if (fixed_macroscopic_pc == 32'h3040 && cnt == 4) begin
interrupt = 1;
cnt = cnt + 1;
end
//乘除指令
else if (fixed_macroscopic_pc == 32'h3044 && cnt == 5) begin
interrupt = 1;
cnt = cnt + 1;
end
else if (fixed_macroscopic_pc == 32'h3060 && cnt == 6) begin
interrupt = 1;
cnt = cnt + 1;
end
else if (fixed_macroscopic_pc == 32'h306c && cnt == 7) begin
interrupt = 1;
cnt = cnt + 1;
end
//指令异常
else if (fixed_macroscopic_pc == 32'h3074 && cnt == 8) begin
interrupt = 1;
cnt = cnt + 1;
end
else if (fixed_macroscopic_pc == 32'h307c && cnt == 9) begin
interrupt = 1;
cnt = cnt + 1;
end
end
end

always #2 clk <= ~clk;

endmodule

对应易错点

  • 跳转指令无论是否跳转,接下来一条指令都应视为延迟槽
  • cp0设计在w级则需要检查store类指令在w时被下中断写使能信号是否关闭
  • 如果设计eret后清空延迟槽则需要考虑优先级问题(阻塞>清空)
  • 更进一步,如果设计了清空延迟槽需要考虑eret后的nop下中断的情况
0%