Skip to content

Commit 0d0e042

Browse files
committed
vr4300/cp0: @sp1187: Fix undefined CP0 register access.
simer/sp1187 pointed out that undefined CP0 registers all share a common value (that is, a write to any undefined CP0 register effectively acts as a write to *all* undefined CP0 registers). This commit implements the specified behaviour.
1 parent 6f6f769 commit 0d0e042

File tree

1 file changed

+40
-20
lines changed

1 file changed

+40
-20
lines changed

vr4300/cp0.c

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ static const uint64_t vr4300_cp0_reg_masks[32] = {
2121
0xFFFFFFFFFFFFFFF0ULL, // 4: VR4300_CP0_REGISTER_CONTEXT
2222
0x0000000001FFE000ULL, // 5: VR4300_CP0_REGISTER_PAGEMASK
2323
0xFFFFFFFFFFFFFFFFULL, // 6: VR4300_CP0_REGISTER_WIRED
24-
0x000000000000003FULL, // 7:
24+
0x0000000000000BADULL, // 7:
2525
0xFFFFFFFFFFFFFFFFULL, // 8: VR4300_CP0_REGISTER_BADVADDR
2626
0x00000000FFFFFFFFULL, // 9: VR4300_CP0_REGISTER_COUNT
2727
0xC00000FFFFFFE0FFULL, // 10: VR4300_CP0_REGISTER_ENTRYHI
@@ -35,17 +35,17 @@ static const uint64_t vr4300_cp0_reg_masks[32] = {
3535
0x00000000FFFFFFFBULL, // 18: VR4300_CP0_REGISTER_WATCHLO
3636
0x000000000000000FULL, // 19: VR4300_CP0_REGISTER_WATCHHI
3737
0xFFFFFFFFFFFFFFFFULL, // 20: VR4300_CP0_REGISTER_XCONTEXT
38-
0xFFFFFFFFFFFFFFFFULL, // 21:
39-
0xFFFFFFFFFFFFFFFFULL, // 22:
40-
0xFFFFFFFFFFFFFFFFULL, // 23:
41-
0xFFFFFFFFFFFFFFFFULL, // 24:
42-
0xFFFFFFFFFFFFFFFFULL, // 25:
38+
0x0000000000000BADULL, // 21:
39+
0x0000000000000BADULL, // 22:
40+
0x0000000000000BADULL, // 23:
41+
0x0000000000000BADULL, // 24:
42+
0x0000000000000BADULL, // 25:
4343
0x0000000000000000ULL, // 26: VR4300_CP0_REGISTER_PARITYERROR
4444
0x0000000000000000ULL, // 27: VR4300_CP0_REGISTER_CACHEERR
4545
0x000000000FFFFFC0ULL, // 28: VR4300_CP0_REGISTER_TAGLO
4646
0x0000000000000000ULL, // 29: VR4300_CP0_REGISTER_TAGHI
4747
0xFFFFFFFFFFFFFFFFULL, // 30: VR4300_CP0_REGISTER_ERROREPC
48-
0xFFFFFFFFFFFFFFFFULL, // 31
48+
0x0000000000000BADULL, // 31
4949
};
5050

5151
static inline uint64_t mask_reg(unsigned reg, uint64_t data) {
@@ -61,13 +61,18 @@ int VR4300_DMFC0(struct vr4300 *vr4300,
6161
unsigned dest = GET_RT(iw);
6262
unsigned src = GET_RD(iw);
6363

64-
if (src == (VR4300_CP0_REGISTER_COUNT - 32)) {
64+
if (src == (VR4300_CP0_REGISTER_COUNT - VR4300_REGISTER_CP0_0)) {
6565
exdc_latch->result = (uint32_t)
6666
(vr4300->regs[VR4300_CP0_REGISTER_COUNT] >> 1);
6767
}
6868

69-
else
70-
exdc_latch->result = mask_reg(src, vr4300->regs[32 + src]);
69+
else if (vr4300_cp0_reg_masks[src] == 0x0000000000000BADULL)
70+
exdc_latch->result = vr4300->regs[VR4300_REGISTER_CP0_0 + 7];
71+
72+
else {
73+
exdc_latch->result = mask_reg(src,
74+
vr4300->regs[VR4300_REGISTER_CP0_0 + src]);
75+
}
7176

7277
exdc_latch->dest = dest;
7378
return 0;
@@ -78,12 +83,17 @@ int VR4300_DMFC0(struct vr4300 *vr4300,
7883
//
7984
int VR4300_DMTC0(struct vr4300 *vr4300,
8085
uint32_t iw, uint64_t rs, uint64_t rt) {
81-
unsigned dest = 32 + GET_RD(iw);
86+
unsigned dest = GET_RD(iw);
8287

83-
if (dest == VR4300_CP0_REGISTER_COMPARE)
88+
if ((dest + VR4300_REGISTER_CP0_0) == VR4300_CP0_REGISTER_COMPARE)
8489
vr4300->regs[VR4300_CP0_REGISTER_CAUSE] &= ~0x8000;
8590

86-
vr4300->regs[dest] = rt;
91+
if (vr4300_cp0_reg_masks[dest] == 0x0000000000000BADULL)
92+
vr4300->regs[VR4300_REGISTER_CP0_0 + 7] = rt;
93+
94+
else
95+
vr4300->regs[VR4300_REGISTER_CP0_0 + dest] = rt;
96+
8797
return 0;
8898
}
8999

@@ -135,13 +145,18 @@ int VR4300_MFC0(struct vr4300 *vr4300,
135145
unsigned dest = GET_RT(iw);
136146
unsigned src = GET_RD(iw);
137147

138-
if (src == (VR4300_CP0_REGISTER_COUNT - 32)) {
148+
if (src == (VR4300_CP0_REGISTER_COUNT - VR4300_REGISTER_CP0_0)) {
139149
exdc_latch->result = (int32_t)
140150
(vr4300->regs[VR4300_CP0_REGISTER_COUNT] >> 1);
141151
}
142152

143-
else
144-
exdc_latch->result = (int32_t) mask_reg(src, vr4300->regs[32 + src]);
153+
else if (vr4300_cp0_reg_masks[src] == 0x0000000000000BADULL)
154+
exdc_latch->result = (int32_t) vr4300->regs[VR4300_REGISTER_CP0_0 + 7];
155+
156+
else {
157+
exdc_latch->result = (int32_t) mask_reg(src,
158+
vr4300->regs[VR4300_REGISTER_CP0_0 + src]);
159+
}
145160

146161
exdc_latch->dest = (int32_t) dest;
147162
return 0;
@@ -154,17 +169,22 @@ int VR4300_MTC0(struct vr4300 *vr4300,
154169
uint32_t iw, uint64_t rs, uint64_t rt) {
155170
struct vr4300_icrf_latch *icrf_latch = &vr4300->pipeline.icrf_latch;
156171
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
157-
unsigned dest = 32 + GET_RD(iw);
172+
unsigned dest = GET_RD(iw);
158173

159-
if (dest == VR4300_CP0_REGISTER_COMPARE)
174+
if ((dest + VR4300_REGISTER_CP0_0) == VR4300_CP0_REGISTER_COMPARE)
160175
vr4300->regs[VR4300_CP0_REGISTER_CAUSE] &= ~0x8000;
161176

162-
else if (dest == VR4300_CP0_REGISTER_STATUS) {
177+
else if ((dest + VR4300_REGISTER_CP0_0) == VR4300_CP0_REGISTER_STATUS) {
163178
icrf_latch->segment = get_segment(icrf_latch->common.pc, rt);
164179
exdc_latch->segment = get_default_segment();
165180
}
166181

167-
vr4300->regs[dest] = (int32_t) rt;
182+
if (vr4300_cp0_reg_masks[dest] == 0x0000000000000BADULL)
183+
vr4300->regs[VR4300_REGISTER_CP0_0 + 7] = (int32_t) rt;
184+
185+
else
186+
vr4300->regs[VR4300_REGISTER_CP0_0 + dest] = (int32_t) rt;
187+
168188
return 0;
169189
}
170190

0 commit comments

Comments
 (0)