1 |
/* |
/* |
2 |
* Copyright (C) 2005-2006 Anders Gavare. All rights reserved. |
* Copyright (C) 2005-2007 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_mips_instr.c,v 1.97 2006/07/20 03:20:03 debug Exp $ |
* $Id: cpu_mips_instr.c,v 1.133 2007/06/13 02:08:03 debug Exp $ |
29 |
* |
* |
30 |
* MIPS instructions. |
* MIPS instructions. |
31 |
* |
* |
37 |
|
|
38 |
|
|
39 |
/* |
/* |
40 |
|
* COPROC_AVAILABILITY_CHECK(n) checks for the coprocessor available bit for |
41 |
|
* coprocessor number n, and causes a CoProcessor Unusable exception if it |
42 |
|
* is not set. (Note: For coprocessor 0 checks, use cop0_availability_check!) |
43 |
|
*/ |
44 |
|
#ifndef COPROC_AVAILABILITY_CHECK |
45 |
|
#define COPROC_AVAILABILITY_CHECK(x) { \ |
46 |
|
const int cpnr = (x); \ |
47 |
|
int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) \ |
48 |
|
/ sizeof(struct mips_instr_call); \ |
49 |
|
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) \ |
50 |
|
<< MIPS_INSTR_ALIGNMENT_SHIFT); \ |
51 |
|
cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); \ |
52 |
|
if (!(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & \ |
53 |
|
((1 << cpnr) << STATUS_CU_SHIFT)) ) { \ |
54 |
|
mips_cpu_exception(cpu, EXCEPTION_CPU, \ |
55 |
|
0, 0, cpnr, 0, 0, 0); \ |
56 |
|
return; \ |
57 |
|
} \ |
58 |
|
} |
59 |
|
#endif |
60 |
|
|
61 |
|
|
62 |
|
#ifndef COP0_AVAILABILITY_CHECK_INCLUDED |
63 |
|
#define COP0_AVAILABILITY_CHECK_INCLUDED |
64 |
|
/* |
65 |
|
* cop0_availability_check() causes a CoProcessor Unusable exception if |
66 |
|
* we are currently running in usermode, and the coprocessor available bit |
67 |
|
* for coprocessor 0 is not set. |
68 |
|
* |
69 |
|
* Returns 1 if ok (i.e. if the coprocessor was usable), 0 on exceptions. |
70 |
|
*/ |
71 |
|
int cop0_availability_check(struct cpu *cpu, struct mips_instr_call *ic) |
72 |
|
{ |
73 |
|
int in_usermode = 0; |
74 |
|
struct mips_coproc *cp0 = cpu->cd.mips.coproc[0]; |
75 |
|
|
76 |
|
switch (cpu->cd.mips.cpu_type.exc_model) { |
77 |
|
case EXC3K: |
78 |
|
/* |
79 |
|
* NOTE: If the KU bit is checked, Linux crashes. |
80 |
|
* It is the PC that counts. |
81 |
|
* |
82 |
|
* TODO: Check whether this is true or not for R4000 as well. |
83 |
|
*/ |
84 |
|
/* TODO: if (cp0->reg[COP0_STATUS] & MIPS1_SR_KU_CUR) */ |
85 |
|
if (cpu->pc <= 0x7fffffff) |
86 |
|
in_usermode = 1; |
87 |
|
break; |
88 |
|
default: |
89 |
|
/* R4000 etc: (TODO: How about supervisor mode?) */ |
90 |
|
if (((cp0->reg[COP0_STATUS] & |
91 |
|
STATUS_KSU_MASK) >> STATUS_KSU_SHIFT) != KSU_KERNEL) |
92 |
|
in_usermode = 1; |
93 |
|
if (cp0->reg[COP0_STATUS] & (STATUS_ERL | STATUS_EXL)) |
94 |
|
in_usermode = 0; |
95 |
|
break; |
96 |
|
} |
97 |
|
|
98 |
|
if (in_usermode) { |
99 |
|
int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) |
100 |
|
/ sizeof(struct mips_instr_call); |
101 |
|
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) |
102 |
|
<< MIPS_INSTR_ALIGNMENT_SHIFT); |
103 |
|
cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); |
104 |
|
if (!(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & |
105 |
|
(1 << STATUS_CU_SHIFT)) ) { |
106 |
|
mips_cpu_exception(cpu, EXCEPTION_CPU, |
107 |
|
0, 0, /* cpnr */ 0, 0, 0, 0); |
108 |
|
return 0; |
109 |
|
} |
110 |
|
} |
111 |
|
|
112 |
|
return 1; |
113 |
|
} |
114 |
|
#endif |
115 |
|
|
116 |
|
|
117 |
|
/* |
118 |
* invalid: For catching bugs. |
* invalid: For catching bugs. |
119 |
*/ |
*/ |
120 |
X(invalid) |
X(invalid) |
1149 |
|
|
1150 |
|
|
1151 |
/* |
/* |
1152 |
|
* ins: Insert bitfield. |
1153 |
|
* |
1154 |
|
* arg[0] = pointer to rt |
1155 |
|
* arg[1] = pointer to rs |
1156 |
|
* arg[2] = (msb << 5) + lsb |
1157 |
|
*/ |
1158 |
|
X(ins) |
1159 |
|
{ |
1160 |
|
int msb = ic->arg[2] >> 5, pos = ic->arg[2] & 0x1f; |
1161 |
|
int size = msb + 1 - pos; |
1162 |
|
uint32_t rt = reg(ic->arg[0]); |
1163 |
|
uint32_t rs = reg(ic->arg[1]); |
1164 |
|
uint32_t mask = (-1) << pos; |
1165 |
|
|
1166 |
|
mask <<= (32 - pos - size); |
1167 |
|
mask >>= (32 - pos - size); |
1168 |
|
|
1169 |
|
reg(ic->arg[0]) = (int32_t) ((rt & ~mask) | ((rs << pos) & mask)); |
1170 |
|
} |
1171 |
|
|
1172 |
|
|
1173 |
|
/* |
1174 |
|
* ext: Extract bitfield. |
1175 |
|
* |
1176 |
|
* arg[0] = pointer to rt |
1177 |
|
* arg[1] = pointer to rs |
1178 |
|
* arg[2] = (msbd << 5) + lsb |
1179 |
|
*/ |
1180 |
|
X(ext) |
1181 |
|
{ |
1182 |
|
int msbd = ic->arg[2] >> 5, lsb = ic->arg[2] & 0x1f; |
1183 |
|
int size = msbd + 1; |
1184 |
|
uint32_t rs = reg(ic->arg[1]); |
1185 |
|
uint32_t x = (rs << (32-lsb-size)) >> (32-lsb-size); |
1186 |
|
reg(ic->arg[0]) = (int32_t) (x >> lsb); |
1187 |
|
} |
1188 |
|
|
1189 |
|
|
1190 |
|
/* |
1191 |
|
* dext: Extract bitfield (64-bit). |
1192 |
|
* |
1193 |
|
* arg[0] = pointer to rt |
1194 |
|
* arg[1] = pointer to rs |
1195 |
|
* arg[2] = (msbd << 6) + lsb |
1196 |
|
*/ |
1197 |
|
X(dext) |
1198 |
|
{ |
1199 |
|
int msbd = ic->arg[2] >> 6, lsb = ic->arg[2] & 0x3f; |
1200 |
|
int size = msbd + 1; |
1201 |
|
uint64_t rs = reg(ic->arg[1]); |
1202 |
|
uint64_t x = (rs << (uint64_t)(64-lsb-size)) >> (uint64_t)(64-lsb-size); |
1203 |
|
reg(ic->arg[0]) = x >> lsb; |
1204 |
|
} |
1205 |
|
|
1206 |
|
|
1207 |
|
/* |
1208 |
|
* dsbh: Doubleword swap bytes within half-word |
1209 |
|
* dshd: Doubleword swap half-words within double-word |
1210 |
|
* wsbh: Word swap bytes within half-word |
1211 |
|
* seb: Sign-extend byte |
1212 |
|
* seh: Sign-extend half-word |
1213 |
|
* |
1214 |
|
* arg[0] = pointer to rt |
1215 |
|
* arg[1] = pointer to rd |
1216 |
|
*/ |
1217 |
|
X(dsbh) |
1218 |
|
{ |
1219 |
|
uint64_t x = reg(ic->arg[0]); |
1220 |
|
x = ((x & 0x00ff00ff00ff00ffULL) << 8) |
1221 |
|
| ((x & 0xff00ff00ff00ff00ULL) >> 8); |
1222 |
|
reg(ic->arg[1]) = x; |
1223 |
|
} |
1224 |
|
X(dshd) |
1225 |
|
{ |
1226 |
|
uint64_t x = reg(ic->arg[0]); |
1227 |
|
x = ((x & 0x000000000000ffffULL) << 48) |
1228 |
|
| ((x & 0x00000000ffff0000ULL) << 16) |
1229 |
|
| ((x & 0x0000ffff00000000ULL) >> 16) |
1230 |
|
| ((x & 0xffff000000000000ULL) >> 48); |
1231 |
|
reg(ic->arg[1]) = x; |
1232 |
|
} |
1233 |
|
X(wsbh) |
1234 |
|
{ |
1235 |
|
uint32_t x = reg(ic->arg[0]); |
1236 |
|
x = ((x & 0x00ff00ff) << 8) | ((x & 0xff00ff00) >> 8); |
1237 |
|
reg(ic->arg[1]) = (int32_t) x; |
1238 |
|
} |
1239 |
|
X(seb) { reg(ic->arg[1]) = (int8_t)reg(ic->arg[0]); } |
1240 |
|
X(seh) { reg(ic->arg[1]) = (int16_t)reg(ic->arg[0]); } |
1241 |
|
|
1242 |
|
|
1243 |
|
/* |
1244 |
* 2-register + immediate: |
* 2-register + immediate: |
1245 |
* |
* |
1246 |
* arg[0] = pointer to rs |
* arg[0] = pointer to rs |
1266 |
res = 0, rem = a; |
res = 0, rem = a; |
1267 |
else |
else |
1268 |
res = a / b, rem = a - b*res; |
res = a / b, rem = a - b*res; |
1269 |
reg(&cpu->cd.mips.lo) = (int32_t)res; |
cpu->cd.mips.lo = (int32_t)res; |
1270 |
reg(&cpu->cd.mips.hi) = (int32_t)rem; |
cpu->cd.mips.hi = (int32_t)rem; |
1271 |
} |
} |
1272 |
X(divu) |
X(divu) |
1273 |
{ |
{ |
1277 |
res = 0, rem = a; |
res = 0, rem = a; |
1278 |
else |
else |
1279 |
res = a / b, rem = a - b*res; |
res = a / b, rem = a - b*res; |
1280 |
reg(&cpu->cd.mips.lo) = (int32_t)res; |
cpu->cd.mips.lo = (int32_t)res; |
1281 |
reg(&cpu->cd.mips.hi) = (int32_t)rem; |
cpu->cd.mips.hi = (int32_t)rem; |
1282 |
} |
} |
1283 |
X(ddiv) |
X(ddiv) |
1284 |
{ |
{ |
1289 |
else |
else |
1290 |
res = a / b; |
res = a / b; |
1291 |
rem = a - b*res; |
rem = a - b*res; |
1292 |
reg(&cpu->cd.mips.lo) = res; |
cpu->cd.mips.lo = res; |
1293 |
reg(&cpu->cd.mips.hi) = rem; |
cpu->cd.mips.hi = rem; |
1294 |
} |
} |
1295 |
X(ddivu) |
X(ddivu) |
1296 |
{ |
{ |
1301 |
else |
else |
1302 |
res = a / b; |
res = a / b; |
1303 |
rem = a - b*res; |
rem = a - b*res; |
1304 |
reg(&cpu->cd.mips.lo) = res; |
cpu->cd.mips.lo = res; |
1305 |
reg(&cpu->cd.mips.hi) = rem; |
cpu->cd.mips.hi = rem; |
1306 |
} |
} |
1307 |
X(mult) |
X(mult) |
1308 |
{ |
{ |
1309 |
int32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); |
int32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); |
1310 |
int64_t res = (int64_t)a * (int64_t)b; |
int64_t res = (int64_t)a * (int64_t)b; |
1311 |
reg(&cpu->cd.mips.lo) = (int32_t)res; |
cpu->cd.mips.lo = (int32_t)res; |
1312 |
reg(&cpu->cd.mips.hi) = (int32_t)(res >> 32); |
cpu->cd.mips.hi = (int32_t)(res >> 32); |
1313 |
} |
} |
1314 |
X(mult_r5900) |
X(mult_r5900) |
1315 |
{ |
{ |
1317 |
hi, lo, and a third register */ |
hi, lo, and a third register */ |
1318 |
int32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); |
int32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); |
1319 |
int64_t res = (int64_t)a * (int64_t)b; |
int64_t res = (int64_t)a * (int64_t)b; |
1320 |
reg(&cpu->cd.mips.lo) = (int32_t)res; |
cpu->cd.mips.lo = (int32_t)res; |
1321 |
reg(&cpu->cd.mips.hi) = (int32_t)(res >> 32); |
cpu->cd.mips.hi = (int32_t)(res >> 32); |
1322 |
reg(ic->arg[2]) = (int32_t)res; |
reg(ic->arg[2]) = (int32_t)res; |
1323 |
} |
} |
1324 |
X(multu) |
X(multu) |
1325 |
{ |
{ |
1326 |
uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); |
uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); |
1327 |
uint64_t res = (uint64_t)a * (uint64_t)b; |
uint64_t res = (uint64_t)a * (uint64_t)b; |
1328 |
reg(&cpu->cd.mips.lo) = (int32_t)res; |
cpu->cd.mips.lo = (int32_t)res; |
1329 |
reg(&cpu->cd.mips.hi) = (int32_t)(res >> 32); |
cpu->cd.mips.hi = (int32_t)(res >> 32); |
1330 |
} |
} |
1331 |
X(multu_r5900) |
X(multu_r5900) |
1332 |
{ |
{ |
1334 |
hi, lo, and a third register */ |
hi, lo, and a third register */ |
1335 |
uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); |
uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); |
1336 |
uint64_t res = (uint64_t)a * (uint64_t)b; |
uint64_t res = (uint64_t)a * (uint64_t)b; |
1337 |
reg(&cpu->cd.mips.lo) = (int32_t)res; |
cpu->cd.mips.lo = (int32_t)res; |
1338 |
reg(&cpu->cd.mips.hi) = (int32_t)(res >> 32); |
cpu->cd.mips.hi = (int32_t)(res >> 32); |
1339 |
reg(ic->arg[2]) = (int32_t)res; |
reg(ic->arg[2]) = (int32_t)res; |
1340 |
} |
} |
1341 |
X(dmult) |
X(dmult) |
1364 |
hi ^= (int64_t) -1; |
hi ^= (int64_t) -1; |
1365 |
lo ^= (int64_t) -1; |
lo ^= (int64_t) -1; |
1366 |
} |
} |
1367 |
reg(&cpu->cd.mips.lo) = lo; |
cpu->cd.mips.lo = lo; |
1368 |
reg(&cpu->cd.mips.hi) = hi; |
cpu->cd.mips.hi = hi; |
1369 |
} |
} |
1370 |
X(dmultu) |
X(dmultu) |
1371 |
{ |
{ |
1381 |
} |
} |
1382 |
c = (c << 1) | (b >> 63); b <<= 1; |
c = (c << 1) | (b >> 63); b <<= 1; |
1383 |
} |
} |
1384 |
reg(&cpu->cd.mips.lo) = lo; |
cpu->cd.mips.lo = lo; |
1385 |
reg(&cpu->cd.mips.hi) = hi; |
cpu->cd.mips.hi = hi; |
1386 |
} |
} |
1387 |
X(tge) |
X(tge) |
1388 |
{ |
{ |
1791 |
|
|
1792 |
/* |
/* |
1793 |
* set: Set a register to an immediate (signed) 32-bit value. |
* set: Set a register to an immediate (signed) 32-bit value. |
1794 |
|
* (This is the actual implementation of the lui instruction.) |
1795 |
* |
* |
1796 |
* arg[0] = pointer to the register |
* arg[0] = pointer to the register |
1797 |
* arg[1] = (int32_t) immediate value |
* arg[1] = (int32_t) immediate value |
1830 |
coproc_register_read(cpu, cpu->cd.mips.coproc[0], rd, &tmp, select); |
coproc_register_read(cpu, cpu->cd.mips.coproc[0], rd, &tmp, select); |
1831 |
reg(ic->arg[0]) = (int32_t)tmp; |
reg(ic->arg[0]) = (int32_t)tmp; |
1832 |
} |
} |
1833 |
|
X(mfc0_select0) |
1834 |
|
{ |
1835 |
|
/* Fast int32_t read, with no side effects: */ |
1836 |
|
int rd = ic->arg[1] & 31; |
1837 |
|
#if 0 |
1838 |
|
uint64_t tmp; |
1839 |
|
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT); |
1840 |
|
cpu->pc |= ic->arg[2]; |
1841 |
|
/* TODO: cause exception if necessary */ |
1842 |
|
#endif |
1843 |
|
reg(ic->arg[0]) = (int32_t)cpu->cd.mips.coproc[0]->reg[rd]; |
1844 |
|
} |
1845 |
X(mtc0) |
X(mtc0) |
1846 |
{ |
{ |
1847 |
int rd = ic->arg[1] & 31, select = ic->arg[1] >> 5; |
int rd = ic->arg[1] & 31, select = ic->arg[1] >> 5; |
1862 |
uint32_t cause = cpu->cd.mips.coproc[0]->reg[COP0_CAUSE]; |
uint32_t cause = cpu->cd.mips.coproc[0]->reg[COP0_CAUSE]; |
1863 |
/* NOTE: STATUS_IE happens to match the enable bit also |
/* NOTE: STATUS_IE happens to match the enable bit also |
1864 |
on R2000/R3000, so this is ok. */ |
on R2000/R3000, so this is ok. */ |
1865 |
if (status & (STATUS_EXL | STATUS_ERL)) |
if (cpu->cd.mips.cpu_type.exc_model != EXC3K) { |
1866 |
status &= ~STATUS_IE; |
if (status & (STATUS_EXL | STATUS_ERL)) |
1867 |
|
status &= ~STATUS_IE; |
1868 |
|
} |
1869 |
/* Ugly R5900 special case: (TODO: move this?) */ |
/* Ugly R5900 special case: (TODO: move this?) */ |
1870 |
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900 && |
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900 && |
1871 |
!(status & R5900_STATUS_EIE)) |
!(status & R5900_STATUS_EIE)) |
1885 |
coproc_register_read(cpu, cpu->cd.mips.coproc[0], rd, |
coproc_register_read(cpu, cpu->cd.mips.coproc[0], rd, |
1886 |
(uint64_t *)ic->arg[0], select); |
(uint64_t *)ic->arg[0], select); |
1887 |
} |
} |
1888 |
|
X(dmfc0_select0) |
1889 |
|
{ |
1890 |
|
/* Fast int64_t read, with no side effects: */ |
1891 |
|
int rd = ic->arg[1] & 31; |
1892 |
|
#if 0 |
1893 |
|
uint64_t tmp; |
1894 |
|
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT); |
1895 |
|
cpu->pc |= ic->arg[2]; |
1896 |
|
/* TODO: cause exception if necessary */ |
1897 |
|
#endif |
1898 |
|
reg(ic->arg[0]) = cpu->cd.mips.coproc[0]->reg[rd]; |
1899 |
|
} |
1900 |
X(dmtc0) |
X(dmtc0) |
1901 |
{ |
{ |
1902 |
int rd = ic->arg[1] & 31, select = ic->arg[1] >> 5; |
int rd = ic->arg[1] & 31, select = ic->arg[1] >> 5; |
1918 |
X(cop1_bc) |
X(cop1_bc) |
1919 |
{ |
{ |
1920 |
MODE_int_t old_pc = cpu->pc; |
MODE_int_t old_pc = cpu->pc; |
1921 |
const int cpnr = 1; |
int x, cc = ic->arg[0]; |
|
int x, low_pc, cc = ic->arg[0]; |
|
1922 |
|
|
1923 |
low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) |
COPROC_AVAILABILITY_CHECK(1); |
|
/ sizeof(struct mips_instr_call); |
|
|
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<< MIPS_INSTR_ALIGNMENT_SHIFT); |
|
|
cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); |
|
|
if (!(cpu->cd.mips.coproc[0]-> |
|
|
reg[COP0_STATUS] & ((1 << cpnr) << STATUS_CU_SHIFT)) ) { |
|
|
mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0); |
|
|
return; |
|
|
} |
|
1924 |
|
|
1925 |
/* Get the correct condition code bit: */ |
/* Get the correct condition code bit: */ |
1926 |
if (cc == 0) |
if (cc == 0) |
1960 |
*/ |
*/ |
1961 |
X(cop1_slow) |
X(cop1_slow) |
1962 |
{ |
{ |
1963 |
const int cpnr = 1; |
COPROC_AVAILABILITY_CHECK(1); |
|
int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) |
|
|
/ sizeof(struct mips_instr_call); |
|
|
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<< MIPS_INSTR_ALIGNMENT_SHIFT); |
|
|
cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); |
|
|
|
|
|
if (!(cpu->cd.mips.coproc[0]-> |
|
|
reg[COP0_STATUS] & ((1 << cpnr) << STATUS_CU_SHIFT)) ) { |
|
|
mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0); |
|
|
return; |
|
|
} |
|
1964 |
|
|
1965 |
coproc_function(cpu, cpu->cd.mips.coproc[1], 1, ic->arg[0], 0, 1); |
coproc_function(cpu, cpu->cd.mips.coproc[1], 1, ic->arg[0], 0, 1); |
1966 |
} |
} |
1985 |
cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); |
cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); |
1986 |
mips_cpu_exception(cpu, EXCEPTION_BP, 0, 0, 0, 0, 0, 0); |
mips_cpu_exception(cpu, EXCEPTION_BP, 0, 0, 0, 0, 0, 0); |
1987 |
} |
} |
1988 |
|
X(reboot) |
1989 |
|
{ |
1990 |
|
if (!cop0_availability_check(cpu, ic)) |
1991 |
|
return; |
1992 |
|
|
1993 |
|
cpu->running = 0; |
1994 |
|
debugger_n_steps_left_before_interaction = 0; |
1995 |
|
cpu->cd.mips.next_ic = ¬hing_call; |
1996 |
|
} |
1997 |
|
|
1998 |
|
|
1999 |
/* |
/* |
2052 |
*/ |
*/ |
2053 |
X(tlbw) |
X(tlbw) |
2054 |
{ |
{ |
2055 |
|
if (!cop0_availability_check(cpu, ic)) |
2056 |
|
return; |
2057 |
|
|
2058 |
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT); |
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT); |
2059 |
cpu->pc |= ic->arg[2]; |
cpu->pc |= ic->arg[2]; |
2060 |
coproc_tlbwri(cpu, ic->arg[0]); |
coproc_tlbwri(cpu, ic->arg[0]); |
2069 |
*/ |
*/ |
2070 |
X(tlbp) |
X(tlbp) |
2071 |
{ |
{ |
2072 |
|
if (!cop0_availability_check(cpu, ic)) |
2073 |
|
return; |
2074 |
|
|
2075 |
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT); |
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT); |
2076 |
cpu->pc |= ic->arg[2]; |
cpu->pc |= ic->arg[2]; |
2077 |
coproc_tlbpr(cpu, 0); |
coproc_tlbpr(cpu, 0); |
2078 |
} |
} |
2079 |
X(tlbr) |
X(tlbr) |
2080 |
{ |
{ |
2081 |
|
if (!cop0_availability_check(cpu, ic)) |
2082 |
|
return; |
2083 |
|
|
2084 |
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT); |
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT); |
2085 |
cpu->pc |= ic->arg[2]; |
cpu->pc |= ic->arg[2]; |
2086 |
coproc_tlbpr(cpu, 1); |
coproc_tlbpr(cpu, 1); |
2088 |
|
|
2089 |
|
|
2090 |
/* |
/* |
2091 |
|
* ei_or_di: MIPS32/64 rev 2, Enable or disable interrupts |
2092 |
|
* |
2093 |
|
* arg[0] = ptr to rt |
2094 |
|
* arg[1] = non-zero to enable interrupts |
2095 |
|
*/ |
2096 |
|
X(ei_or_di) |
2097 |
|
{ |
2098 |
|
reg(ic->arg[0]) = cpu->cd.mips.coproc[0]->reg[COP0_STATUS]; |
2099 |
|
if (ic->arg[1]) |
2100 |
|
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |= STATUS_IE; |
2101 |
|
else |
2102 |
|
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_IE; |
2103 |
|
} |
2104 |
|
|
2105 |
|
|
2106 |
|
/* |
2107 |
* rfe: Return from exception handler (R2000/R3000) |
* rfe: Return from exception handler (R2000/R3000) |
2108 |
*/ |
*/ |
2109 |
X(rfe) |
X(rfe) |
2110 |
{ |
{ |
2111 |
|
if (!cop0_availability_check(cpu, ic)) |
2112 |
|
return; |
2113 |
|
|
2114 |
/* Just rotate the interrupt/user bits: */ |
/* Just rotate the interrupt/user bits: */ |
2115 |
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] = |
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] = |
2116 |
(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) | |
(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) | |
2129 |
*/ |
*/ |
2130 |
X(eret) |
X(eret) |
2131 |
{ |
{ |
2132 |
|
if (!cop0_availability_check(cpu, ic)) |
2133 |
|
return; |
2134 |
|
|
2135 |
if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) { |
if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) { |
2136 |
cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_ERROREPC]; |
cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_ERROREPC]; |
2137 |
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL; |
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL; |
2152 |
*/ |
*/ |
2153 |
X(deret) |
X(deret) |
2154 |
{ |
{ |
2155 |
|
if (!cop0_availability_check(cpu, ic)) |
2156 |
|
return; |
2157 |
|
|
2158 |
/* |
/* |
2159 |
* According to the MIPS64 manual, deret loads PC from the DEPC cop0 |
* According to the MIPS64 manual, deret loads PC from the DEPC cop0 |
2160 |
* register, and jumps there immediately. No delay slot. |
* register, and jumps there immediately. No delay slot. |
2173 |
|
|
2174 |
|
|
2175 |
/* |
/* |
2176 |
|
* idle: Called from the implementation of wait, or netbsd_pmax_idle. |
2177 |
|
*/ |
2178 |
|
X(idle) |
2179 |
|
{ |
2180 |
|
/* |
2181 |
|
* If there is an interrupt, then just return. Otherwise |
2182 |
|
* re-run the wait instruction (after a delay). |
2183 |
|
*/ |
2184 |
|
uint32_t status = cpu->cd.mips.coproc[0]->reg[COP0_STATUS]; |
2185 |
|
uint32_t cause = cpu->cd.mips.coproc[0]->reg[COP0_CAUSE]; |
2186 |
|
|
2187 |
|
if (cpu->cd.mips.cpu_type.exc_model != EXC3K) { |
2188 |
|
if (status & (STATUS_EXL | STATUS_ERL)) |
2189 |
|
status &= ~STATUS_IE; |
2190 |
|
} |
2191 |
|
|
2192 |
|
/* Ugly R5900 special case: (TODO: move this?) */ |
2193 |
|
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900 && |
2194 |
|
!(status & R5900_STATUS_EIE)) |
2195 |
|
status &= ~STATUS_IE; |
2196 |
|
if (status & STATUS_IE && (status & cause & STATUS_IM_MASK)) |
2197 |
|
return; |
2198 |
|
|
2199 |
|
cpu->cd.mips.next_ic = ic; |
2200 |
|
cpu->is_halted = 1; |
2201 |
|
cpu->has_been_idling = 1; |
2202 |
|
|
2203 |
|
/* |
2204 |
|
* There was no interrupt. Go to sleep. |
2205 |
|
* |
2206 |
|
* TODO: |
2207 |
|
* |
2208 |
|
* Think about how to actually implement this usleep stuff, |
2209 |
|
* in an SMP and/or timing accurate environment. |
2210 |
|
*/ |
2211 |
|
|
2212 |
|
if (cpu->machine->ncpus == 1) { |
2213 |
|
static int x = 0; |
2214 |
|
if ((++x) == 600) { |
2215 |
|
usleep(10); |
2216 |
|
x = 0; |
2217 |
|
} |
2218 |
|
cpu->n_translated_instrs += N_SAFE_DYNTRANS_LIMIT / 6; |
2219 |
|
} |
2220 |
|
} |
2221 |
|
|
2222 |
|
|
2223 |
|
/* |
2224 |
|
* wait: Wait for external interrupt. |
2225 |
|
*/ |
2226 |
|
X(wait) |
2227 |
|
{ |
2228 |
|
if (!cop0_availability_check(cpu, ic)) |
2229 |
|
return; |
2230 |
|
|
2231 |
|
instr(idle)(cpu, ic); |
2232 |
|
} |
2233 |
|
|
2234 |
|
|
2235 |
|
/* |
2236 |
* rdhwr: Read hardware register into gpr (MIPS32/64 rev 2). |
* rdhwr: Read hardware register into gpr (MIPS32/64 rev 2). |
2237 |
* |
* |
2238 |
* arg[0] = ptr to rt (destination register) |
* arg[0] = ptr to rt (destination register) |
2469 |
*/ |
*/ |
2470 |
X(lwc1) |
X(lwc1) |
2471 |
{ |
{ |
2472 |
const int cpnr = 1; |
COPROC_AVAILABILITY_CHECK(1); |
|
|
|
|
/* Synch. PC and call the generic load/store function: */ |
|
|
int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) |
|
|
/ sizeof(struct mips_instr_call); |
|
|
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) |
|
|
<< MIPS_INSTR_ALIGNMENT_SHIFT); |
|
|
cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); |
|
|
|
|
|
/* ... but first, let's see if the coprocessor is available: */ |
|
|
if (!(cpu->cd.mips.coproc[0]-> |
|
|
reg[COP0_STATUS] & ((1 << cpnr) << STATUS_CU_SHIFT)) ) { |
|
|
mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0); |
|
|
return; |
|
|
} |
|
2473 |
|
|
2474 |
#ifdef MODE32 |
#ifdef MODE32 |
2475 |
mips32_loadstore |
mips32_loadstore |
2481 |
} |
} |
2482 |
X(swc1) |
X(swc1) |
2483 |
{ |
{ |
2484 |
const int cpnr = 1; |
COPROC_AVAILABILITY_CHECK(1); |
|
|
|
|
/* Synch. PC and call the generic load/store function: */ |
|
|
int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) |
|
|
/ sizeof(struct mips_instr_call); |
|
|
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) |
|
|
<< MIPS_INSTR_ALIGNMENT_SHIFT); |
|
|
cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); |
|
|
|
|
|
/* ... but first, let's see if the coprocessor is available: */ |
|
|
if (!(cpu->cd.mips.coproc[0]-> |
|
|
reg[COP0_STATUS] & ((1 << cpnr) << STATUS_CU_SHIFT)) ) { |
|
|
mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0); |
|
|
return; |
|
|
} |
|
2485 |
|
|
2486 |
#ifdef MODE32 |
#ifdef MODE32 |
2487 |
mips32_loadstore |
mips32_loadstore |
2493 |
} |
} |
2494 |
X(ldc1) |
X(ldc1) |
2495 |
{ |
{ |
|
const int cpnr = 1; |
|
2496 |
int use_fp_pairs = |
int use_fp_pairs = |
2497 |
!(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_FR); |
!(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_FR); |
2498 |
uint64_t fpr, *backup_ptr; |
uint64_t fpr, *backup_ptr; |
2499 |
|
|
2500 |
/* Synch. PC and call the generic load/store function: */ |
COPROC_AVAILABILITY_CHECK(1); |
|
int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) |
|
|
/ sizeof(struct mips_instr_call); |
|
|
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) |
|
|
<< MIPS_INSTR_ALIGNMENT_SHIFT); |
|
|
cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); |
|
|
|
|
|
/* ... but first, let's see if the coprocessor is available: */ |
|
|
if (!(cpu->cd.mips.coproc[0]-> |
|
|
reg[COP0_STATUS] & ((1 << cpnr) << STATUS_CU_SHIFT)) ) { |
|
|
mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0); |
|
|
return; |
|
|
} |
|
2501 |
|
|
2502 |
backup_ptr = (uint64_t *) ic->arg[0]; |
backup_ptr = (uint64_t *) ic->arg[0]; |
2503 |
ic->arg[0] = (size_t) &fpr; |
ic->arg[0] = (size_t) &fpr; |
2521 |
} |
} |
2522 |
X(sdc1) |
X(sdc1) |
2523 |
{ |
{ |
|
const int cpnr = 1; |
|
2524 |
int use_fp_pairs = |
int use_fp_pairs = |
2525 |
!(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_FR); |
!(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_FR); |
2526 |
uint64_t fpr, *backup_ptr; |
uint64_t fpr, *backup_ptr; |
2527 |
|
|
2528 |
/* Synch. PC and call the generic load/store function: */ |
COPROC_AVAILABILITY_CHECK(1); |
|
int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) |
|
|
/ sizeof(struct mips_instr_call); |
|
|
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) |
|
|
<< MIPS_INSTR_ALIGNMENT_SHIFT); |
|
|
cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); |
|
|
|
|
|
/* ... but first, let's see if the coprocessor is available: */ |
|
|
if (!(cpu->cd.mips.coproc[0]-> |
|
|
reg[COP0_STATUS] & ((1 << cpnr) << STATUS_CU_SHIFT)) ) { |
|
|
mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0); |
|
|
return; |
|
|
} |
|
2529 |
|
|
2530 |
backup_ptr = (uint64_t *) ic->arg[0]; |
backup_ptr = (uint64_t *) ic->arg[0]; |
2531 |
ic->arg[0] = (size_t) &fpr; |
ic->arg[0] = (size_t) &fpr; |
2576 |
*/ |
*/ |
2577 |
X(di_r5900) |
X(di_r5900) |
2578 |
{ |
{ |
2579 |
|
if (!cop0_availability_check(cpu, ic)) |
2580 |
|
return; |
2581 |
|
|
2582 |
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~R5900_STATUS_EIE; |
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~R5900_STATUS_EIE; |
2583 |
} |
} |
2584 |
X(ei_r5900) |
X(ei_r5900) |
2585 |
{ |
{ |
2586 |
|
if (!cop0_availability_check(cpu, ic)) |
2587 |
|
return; |
2588 |
|
|
2589 |
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |= R5900_STATUS_EIE; |
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |= R5900_STATUS_EIE; |
2590 |
} |
} |
2591 |
|
|
2614 |
if (cpu->delay_slot || page == NULL || (rX & 3) != 0 || rZ != 0) { |
if (cpu->delay_slot || page == NULL || (rX & 3) != 0 || rZ != 0) { |
2615 |
instr(addiu)(cpu, ic); |
instr(addiu)(cpu, ic); |
2616 |
return; |
return; |
2617 |
} |
} |
2618 |
|
|
2619 |
if (rYp == (uint64_t *) ic->arg[0]) |
if (rYp == (uint64_t *) ic->arg[0]) |
2620 |
rYp = (uint64_t *) ic[1].arg[1]; |
rYp = (uint64_t *) ic[1].arg[1]; |
2643 |
} |
} |
2644 |
|
|
2645 |
|
|
2646 |
/* |
#ifdef MODE32 |
2647 |
* multi_sw_3: |
/* multi_{l,s}w_2, _3, etc. */ |
2648 |
* |
#include "tmp_mips_loadstore_multi.c" |
2649 |
* sw r?,ofs(rX) r?=arg[0], rX=arg[1], ofs=arg[2] |
#endif |
|
* sw r?,ofs(rX) r?=arg[0], rX=arg[1], ofs=arg[2] |
|
|
* sw r?,ofs(rX) r?=arg[0], rX=arg[1], ofs=arg[2] |
|
|
*/ |
|
|
X(multi_sw_3_le) |
|
|
{ |
|
|
uint32_t *page; |
|
|
MODE_uint_t rX = reg(ic[0].arg[1]), r1, r2, r3; |
|
|
MODE_uint_t addr0 = rX + (int32_t)ic[0].arg[2]; |
|
|
MODE_uint_t addr1 = rX + (int32_t)ic[1].arg[2]; |
|
|
MODE_uint_t addr2 = rX + (int32_t)ic[2].arg[2]; |
|
|
uint32_t index0 = addr0 >> 12, index1 = addr1 >> 12, |
|
|
index2 = addr2 >> 12; |
|
|
|
|
|
page = (uint32_t *) cpu->cd.mips.host_store[index0]; |
|
|
|
|
|
/* Fallback: */ |
|
|
if (cpu->delay_slot || |
|
|
page == NULL || (addr0 & 3) != 0 || (addr1 & 3) != 0 || |
|
|
(addr2 & 3) != 0 || index0 != index1 || index0 != index2) { |
|
|
/* Normal safe sw: */ |
|
|
ic[1].f(cpu, ic); |
|
|
return; |
|
|
} |
|
2650 |
|
|
|
addr0 = (addr0 >> 2) & 0x3ff; |
|
|
addr1 = (addr1 >> 2) & 0x3ff; |
|
|
addr2 = (addr2 >> 2) & 0x3ff; |
|
|
|
|
|
/* printf("addr0=%x 1=%x 2=%x\n", |
|
|
(int)addr0, (int)addr1, (int)addr2); */ |
|
|
|
|
|
r1 = reg(ic[0].arg[0]); |
|
|
r2 = reg(ic[1].arg[0]); |
|
|
r3 = reg(ic[2].arg[0]); |
|
|
|
|
|
r1 = LE32_TO_HOST(r1); |
|
|
r2 = LE32_TO_HOST(r2); |
|
|
r3 = LE32_TO_HOST(r3); |
|
|
|
|
|
page[addr0] = r1; |
|
|
page[addr1] = r2; |
|
|
page[addr2] = r3; |
|
2651 |
|
|
2652 |
cpu->n_translated_instrs += 2; |
/* |
2653 |
cpu->cd.mips.next_ic = (struct mips_instr_call *) &ic[3]; |
* multi_addu_3: |
2654 |
} |
*/ |
2655 |
X(multi_sw_3_be) |
X(multi_addu_3) |
2656 |
{ |
{ |
|
uint32_t *page; |
|
|
MODE_uint_t rX = reg(ic[0].arg[1]), r1, r2, r3; |
|
|
MODE_uint_t addr0 = rX + (int32_t)ic[0].arg[2]; |
|
|
MODE_uint_t addr1 = rX + (int32_t)ic[1].arg[2]; |
|
|
MODE_uint_t addr2 = rX + (int32_t)ic[2].arg[2]; |
|
|
uint32_t index0 = addr0 >> 12, index1 = addr1 >> 12, |
|
|
index2 = addr2 >> 12; |
|
|
|
|
|
page = (uint32_t *) cpu->cd.mips.host_store[index0]; |
|
|
|
|
2657 |
/* Fallback: */ |
/* Fallback: */ |
2658 |
if (cpu->delay_slot || |
if (cpu->delay_slot) { |
2659 |
page == NULL || (addr0 & 3) != 0 || (addr1 & 3) != 0 || |
instr(addu)(cpu, ic); |
|
(addr2 & 3) != 0 || index0 != index1 || index0 != index2) { |
|
|
/* Normal safe sw: */ |
|
|
ic[1].f(cpu, ic); |
|
2660 |
return; |
return; |
2661 |
} |
} |
|
|
|
|
addr0 = (addr0 >> 2) & 0x3ff; |
|
|
addr1 = (addr1 >> 2) & 0x3ff; |
|
|
addr2 = (addr2 >> 2) & 0x3ff; |
|
|
|
|
|
/* printf("addr0=%x 1=%x 2=%x\n", |
|
|
(int)addr0, (int)addr1, (int)addr2); */ |
|
|
|
|
|
r1 = reg(ic[0].arg[0]); |
|
|
r2 = reg(ic[1].arg[0]); |
|
|
r3 = reg(ic[2].arg[0]); |
|
|
|
|
|
r1 = BE32_TO_HOST(r1); |
|
|
r2 = BE32_TO_HOST(r2); |
|
|
r3 = BE32_TO_HOST(r3); |
|
|
|
|
|
page[addr0] = r1; |
|
|
page[addr1] = r2; |
|
|
page[addr2] = r3; |
|
2662 |
|
|
2663 |
|
reg(ic[0].arg[2]) = (int32_t)(reg(ic[0].arg[0]) + reg(ic[0].arg[1])); |
2664 |
|
reg(ic[1].arg[2]) = (int32_t)(reg(ic[1].arg[0]) + reg(ic[1].arg[1])); |
2665 |
|
reg(ic[2].arg[2]) = (int32_t)(reg(ic[2].arg[0]) + reg(ic[2].arg[1])); |
2666 |
cpu->n_translated_instrs += 2; |
cpu->n_translated_instrs += 2; |
2667 |
cpu->cd.mips.next_ic = (struct mips_instr_call *) &ic[3]; |
cpu->cd.mips.next_ic += 2; |
2668 |
} |
} |
2669 |
|
|
2670 |
|
|
2702 |
|
|
2703 |
#ifdef MODE32 |
#ifdef MODE32 |
2704 |
/* |
/* |
2705 |
|
* netbsd_pmax_idle(): |
2706 |
|
* |
2707 |
|
* s: lui rX, hi |
2708 |
|
* lw rY, lo(rX) |
2709 |
|
* nop |
2710 |
|
* beq zr, rY, s |
2711 |
|
* nop |
2712 |
|
*/ |
2713 |
|
X(netbsd_pmax_idle) |
2714 |
|
{ |
2715 |
|
uint32_t addr, pageindex, i; |
2716 |
|
int32_t *page; |
2717 |
|
|
2718 |
|
reg(ic[0].arg[0]) = (int32_t)ic[0].arg[1]; |
2719 |
|
|
2720 |
|
addr = reg(ic[0].arg[0]) + (int32_t)ic[1].arg[2]; |
2721 |
|
pageindex = addr >> 12; |
2722 |
|
i = (addr & 0xfff) >> 2; |
2723 |
|
page = (int32_t *) cpu->cd.mips.host_load[pageindex]; |
2724 |
|
|
2725 |
|
/* Fallback: */ |
2726 |
|
if (cpu->delay_slot || page == NULL || page[i] != 0) |
2727 |
|
return; |
2728 |
|
|
2729 |
|
instr(idle)(cpu, ic); |
2730 |
|
} |
2731 |
|
|
2732 |
|
|
2733 |
|
/* |
2734 |
|
* linux_pmax_idle(): |
2735 |
|
* |
2736 |
|
* s: lui rX, hi |
2737 |
|
* lw rX, lo(rX) |
2738 |
|
* nop |
2739 |
|
* bne zr, rX, ... |
2740 |
|
* nop |
2741 |
|
* lw rX, ofs(gp) |
2742 |
|
* nop |
2743 |
|
* beq zr, rX, s |
2744 |
|
* nop |
2745 |
|
*/ |
2746 |
|
X(linux_pmax_idle) |
2747 |
|
{ |
2748 |
|
uint32_t addr, addr2, pageindex, pageindex2, i, i2; |
2749 |
|
int32_t *page, *page2; |
2750 |
|
|
2751 |
|
reg(ic[0].arg[0]) = (int32_t)ic[0].arg[1]; |
2752 |
|
|
2753 |
|
addr = reg(ic[0].arg[0]) + (int32_t)ic[1].arg[2]; |
2754 |
|
pageindex = addr >> 12; |
2755 |
|
i = (addr & 0xfff) >> 2; |
2756 |
|
page = (int32_t *) cpu->cd.mips.host_load[pageindex]; |
2757 |
|
|
2758 |
|
addr2 = reg(ic[5].arg[1]) + (int32_t)ic[5].arg[2]; |
2759 |
|
pageindex2 = addr2 >> 12; |
2760 |
|
i2 = (addr2 & 0xfff) >> 2; |
2761 |
|
page2 = (int32_t *) cpu->cd.mips.host_load[pageindex2]; |
2762 |
|
|
2763 |
|
/* Fallback: */ |
2764 |
|
if (cpu->delay_slot || page == NULL || page[i] != 0 || page2[i2] != 0) |
2765 |
|
return; |
2766 |
|
|
2767 |
|
instr(idle)(cpu, ic); |
2768 |
|
} |
2769 |
|
|
2770 |
|
|
2771 |
|
/* |
2772 |
* netbsd_strlen(): |
* netbsd_strlen(): |
2773 |
* |
* |
2774 |
* lb rV,0(rX) |
* lb rV,0(rX) |
2822 |
|
|
2823 |
|
|
2824 |
/* |
/* |
2825 |
* lui_32bit: |
* addiu_bne_samepage_addiu: |
2826 |
* |
*/ |
2827 |
* Combination of lui and addiu. |
X(addiu_bne_samepage_addiu) |
2828 |
* Note: All 32 bits of arg[2] of the lui instr_call are used. |
{ |
2829 |
|
MODE_uint_t rs, rt; |
2830 |
|
|
2831 |
|
if (cpu->delay_slot) { |
2832 |
|
instr(addiu)(cpu, ic); |
2833 |
|
return; |
2834 |
|
} |
2835 |
|
|
2836 |
|
cpu->n_translated_instrs += 2; |
2837 |
|
reg(ic[0].arg[1]) = (int32_t) |
2838 |
|
((int32_t)reg(ic[0].arg[0]) + (int32_t)ic[0].arg[2]); |
2839 |
|
rs = reg(ic[1].arg[0]); |
2840 |
|
rt = reg(ic[1].arg[1]); |
2841 |
|
reg(ic[2].arg[1]) = (int32_t) |
2842 |
|
((int32_t)reg(ic[2].arg[0]) + (int32_t)ic[2].arg[2]); |
2843 |
|
if (rs != rt) |
2844 |
|
cpu->cd.mips.next_ic = (struct mips_instr_call *) ic[1].arg[2]; |
2845 |
|
else |
2846 |
|
cpu->cd.mips.next_ic += 2; |
2847 |
|
} |
2848 |
|
|
2849 |
|
|
2850 |
|
/* |
2851 |
|
* xor_andi_sll: |
2852 |
|
*/ |
2853 |
|
X(xor_andi_sll) |
2854 |
|
{ |
2855 |
|
/* Fallback: */ |
2856 |
|
if (cpu->delay_slot) { |
2857 |
|
instr(xor)(cpu, ic); |
2858 |
|
return; |
2859 |
|
} |
2860 |
|
|
2861 |
|
reg(ic[0].arg[2]) = reg(ic[0].arg[0]) ^ reg(ic[0].arg[1]); |
2862 |
|
reg(ic[1].arg[1]) = reg(ic[1].arg[0]) & (uint32_t)ic[1].arg[2]; |
2863 |
|
reg(ic[2].arg[2]) = (int32_t)(reg(ic[2].arg[0])<<(int32_t)ic[2].arg[1]); |
2864 |
|
|
2865 |
|
cpu->n_translated_instrs += 2; |
2866 |
|
cpu->cd.mips.next_ic += 2; |
2867 |
|
} |
2868 |
|
|
2869 |
|
|
2870 |
|
/* |
2871 |
|
* andi_sll: |
2872 |
*/ |
*/ |
2873 |
X(lui_32bit) |
X(andi_sll) |
2874 |
{ |
{ |
2875 |
reg(ic[0].arg[0]) = (int32_t) ic[0].arg[2]; |
/* Fallback: */ |
2876 |
|
if (cpu->delay_slot) { |
2877 |
|
instr(andi)(cpu, ic); |
2878 |
|
return; |
2879 |
|
} |
2880 |
|
|
2881 |
|
reg(ic[0].arg[1]) = reg(ic[0].arg[0]) & (uint32_t)ic[0].arg[2]; |
2882 |
|
reg(ic[1].arg[2]) = (int32_t)(reg(ic[1].arg[0])<<(int32_t)ic[1].arg[1]); |
2883 |
|
|
2884 |
|
cpu->n_translated_instrs ++; |
2885 |
|
cpu->cd.mips.next_ic ++; |
2886 |
|
} |
2887 |
|
|
2888 |
|
|
2889 |
|
/* |
2890 |
|
* lui_ori: |
2891 |
|
*/ |
2892 |
|
X(lui_ori) |
2893 |
|
{ |
2894 |
|
/* Fallback: */ |
2895 |
|
if (cpu->delay_slot) { |
2896 |
|
instr(set)(cpu, ic); |
2897 |
|
return; |
2898 |
|
} |
2899 |
|
|
2900 |
|
reg(ic[0].arg[0]) = (int32_t)ic[0].arg[1]; |
2901 |
|
reg(ic[1].arg[1]) = reg(ic[1].arg[0]) | (uint32_t)ic[1].arg[2]; |
2902 |
|
|
2903 |
|
cpu->n_translated_instrs ++; |
2904 |
|
cpu->cd.mips.next_ic ++; |
2905 |
|
} |
2906 |
|
|
2907 |
|
|
2908 |
|
/* |
2909 |
|
* lui_addiu: |
2910 |
|
*/ |
2911 |
|
X(lui_addiu) |
2912 |
|
{ |
2913 |
|
/* Fallback: */ |
2914 |
|
if (cpu->delay_slot) { |
2915 |
|
instr(set)(cpu, ic); |
2916 |
|
return; |
2917 |
|
} |
2918 |
|
|
2919 |
|
reg(ic[0].arg[0]) = (int32_t)ic[0].arg[1]; |
2920 |
|
reg(ic[1].arg[1]) = (int32_t) |
2921 |
|
((int32_t)reg(ic[1].arg[0]) + (int32_t)ic[1].arg[2]); |
2922 |
|
|
2923 |
cpu->n_translated_instrs ++; |
cpu->n_translated_instrs ++; |
2924 |
cpu->cd.mips.next_ic ++; |
cpu->cd.mips.next_ic ++; |
2925 |
} |
} |
3059 |
ic[0].arg[0] != ic[0].arg[1] && |
ic[0].arg[0] != ic[0].arg[1] && |
3060 |
ic[0].arg[1] == ic[-2].arg[0] && (int32_t)ic[0].arg[2] == -4) { |
ic[0].arg[1] == ic[-2].arg[0] && (int32_t)ic[0].arg[2] == -4) { |
3061 |
ic[-2].f = instr(sw_loop); |
ic[-2].f = instr(sw_loop); |
|
combined; |
|
3062 |
} |
} |
3063 |
} |
} |
3064 |
|
|
3065 |
|
|
3066 |
|
/* Only for 32-bit virtual address translation so far. */ |
3067 |
|
#ifdef MODE32 |
3068 |
/* |
/* |
3069 |
* Combine: Multiple SW in a row using the same base register |
* Combine: Multiple SW in a row using the same base register |
3070 |
* |
* |
3079 |
int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) |
int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) |
3080 |
& (MIPS_IC_ENTRIES_PER_PAGE - 1); |
& (MIPS_IC_ENTRIES_PER_PAGE - 1); |
3081 |
|
|
3082 |
/* Only for 32-bit virtual address translation so far. */ |
if (n_back < 3) |
|
if (!cpu->is_32bit) |
|
3083 |
return; |
return; |
3084 |
|
|
3085 |
if (n_back < 4) |
/* Convert a multi_sw_3 to a multi_sw_4: */ |
3086 |
return; |
if ((ic[-3].f == instr(multi_sw_3_be) || |
3087 |
|
ic[-3].f == instr(multi_sw_3_le)) && |
3088 |
|
ic[-3].arg[1] == ic[0].arg[1]) { |
3089 |
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) |
3090 |
|
ic[-3].f = instr(multi_sw_4_le); |
3091 |
|
else |
3092 |
|
ic[-3].f = instr(multi_sw_4_be); |
3093 |
|
} |
3094 |
|
|
3095 |
/* Avoid "overlapping" instruction combinations: */ |
/* Convert a multi_sw_2 to a multi_sw_3: */ |
3096 |
if (ic[-4].f == instr(multi_sw_3_be)||ic[-3].f == instr(multi_sw_3_be)|| |
if ((ic[-2].f == instr(multi_sw_2_be) || |
3097 |
ic[-4].f == instr(multi_sw_3_le)||ic[-3].f == instr(multi_sw_3_le)) |
ic[-2].f == instr(multi_sw_2_le)) && |
3098 |
|
ic[-2].arg[1] == ic[0].arg[1]) { |
3099 |
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) |
3100 |
|
ic[-2].f = instr(multi_sw_3_le); |
3101 |
|
else |
3102 |
|
ic[-2].f = instr(multi_sw_3_be); |
3103 |
|
} |
3104 |
|
|
3105 |
|
if (ic[-1].f == ic[0].f && ic[-1].arg[1] == ic[0].arg[1]) { |
3106 |
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) |
3107 |
|
ic[-1].f = instr(multi_sw_2_le); |
3108 |
|
else |
3109 |
|
ic[-1].f = instr(multi_sw_2_be); |
3110 |
|
} |
3111 |
|
} |
3112 |
|
#endif |
3113 |
|
|
3114 |
|
|
3115 |
|
/* Only for 32-bit virtual address translation so far. */ |
3116 |
|
#ifdef MODE32 |
3117 |
|
/* |
3118 |
|
* Combine: Multiple LW in a row using the same base register |
3119 |
|
* |
3120 |
|
* lw r?,???(rX) |
3121 |
|
* lw r?,???(rX) |
3122 |
|
* lw r?,???(rX) |
3123 |
|
* ... |
3124 |
|
*/ |
3125 |
|
void COMBINE(multi_lw)(struct cpu *cpu, struct mips_instr_call *ic, |
3126 |
|
int low_addr) |
3127 |
|
{ |
3128 |
|
int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) |
3129 |
|
& (MIPS_IC_ENTRIES_PER_PAGE - 1); |
3130 |
|
|
3131 |
|
if (n_back < 3) |
3132 |
return; |
return; |
3133 |
|
|
3134 |
if (ic[-2].f == ic[0].f && ic[-1].f == ic[0].f && |
/* Convert a multi_lw_3 to a multi_lw_4: */ |
3135 |
|
if ((ic[-3].f == instr(multi_lw_3_be) || |
3136 |
|
ic[-3].f == instr(multi_lw_3_le)) && |
3137 |
|
ic[-3].arg[1] == ic[0].arg[1] && |
3138 |
|
ic[-1].arg[0] != ic[0].arg[1]) { |
3139 |
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) |
3140 |
|
ic[-3].f = instr(multi_lw_4_le); |
3141 |
|
else |
3142 |
|
ic[-3].f = instr(multi_lw_4_be); |
3143 |
|
} |
3144 |
|
|
3145 |
|
/* Convert a multi_lw_2 to a multi_lw_3: */ |
3146 |
|
if ((ic[-2].f == instr(multi_lw_2_be) || |
3147 |
|
ic[-2].f == instr(multi_lw_2_le)) && |
3148 |
ic[-2].arg[1] == ic[0].arg[1] && |
ic[-2].arg[1] == ic[0].arg[1] && |
3149 |
ic[-1].arg[1] == ic[0].arg[1]) { |
ic[-1].arg[0] != ic[0].arg[1]) { |
3150 |
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) |
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) |
3151 |
ic[-2].f = instr(multi_sw_3_le); |
ic[-2].f = instr(multi_lw_3_le); |
3152 |
else |
else |
3153 |
ic[-2].f = instr(multi_sw_3_be); |
ic[-2].f = instr(multi_lw_3_be); |
3154 |
combined; |
} |
3155 |
|
|
3156 |
|
/* Note: Loads to the base register are not allowed in slot -1. */ |
3157 |
|
if (ic[-1].f == ic[0].f && |
3158 |
|
ic[-1].arg[1] == ic[0].arg[1] && |
3159 |
|
ic[-1].arg[0] != ic[0].arg[1]) { |
3160 |
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) |
3161 |
|
ic[-1].f = instr(multi_lw_2_le); |
3162 |
|
else |
3163 |
|
ic[-1].f = instr(multi_lw_2_be); |
3164 |
} |
} |
3165 |
} |
} |
3166 |
|
#endif |
3167 |
|
|
3168 |
|
|
3169 |
/* |
/* |
3199 |
ic[-3].arg[1] == ic[-5].arg[0] && |
ic[-3].arg[1] == ic[-5].arg[0] && |
3200 |
ic[-2].f == instr(nop) && ic[-1].f == instr(nop)) { |
ic[-2].f == instr(nop) && ic[-1].f == instr(nop)) { |
3201 |
ic[-8].f = instr(netbsd_r3k_picache_do_inv); |
ic[-8].f = instr(netbsd_r3k_picache_do_inv); |
|
combined; |
|
3202 |
} |
} |
3203 |
} |
} |
3204 |
|
|
3208 |
* |
* |
3209 |
* NetBSD's strlen core. |
* NetBSD's strlen core. |
3210 |
* [Conditional] branch, followed by nop. |
* [Conditional] branch, followed by nop. |
3211 |
|
* NetBSD/pmax' idle loop (and possibly others as well). |
3212 |
|
* Linux/pmax' idle loop. |
3213 |
*/ |
*/ |
3214 |
void COMBINE(nop)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) |
void COMBINE(nop)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) |
3215 |
{ |
{ |
3216 |
int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) |
int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) |
3217 |
& (MIPS_IC_ENTRIES_PER_PAGE - 1); |
& (MIPS_IC_ENTRIES_PER_PAGE - 1); |
3218 |
|
|
3219 |
|
if (n_back < 8) |
3220 |
|
return; |
3221 |
|
|
3222 |
#ifdef MODE32 |
#ifdef MODE32 |
3223 |
if (n_back < 3) |
if (ic[-8].f == instr(set) && |
3224 |
|
ic[-7].f == mips32_loadstore[4 + 1] && |
3225 |
|
ic[-7].arg[0] == ic[-1].arg[0] && |
3226 |
|
ic[-7].arg[0] == ic[-3].arg[0] && |
3227 |
|
ic[-7].arg[0] == ic[-5].arg[0] && |
3228 |
|
ic[-7].arg[0] == ic[-7].arg[1] && |
3229 |
|
ic[-7].arg[0] == ic[-8].arg[0] && |
3230 |
|
ic[-6].f == instr(nop) && |
3231 |
|
ic[-5].arg[1] == (size_t) &cpu->cd.mips.gpr[MIPS_GPR_ZERO] && |
3232 |
|
ic[-5].f == instr(bne_samepage_nop) && |
3233 |
|
ic[-4].f == instr(nop) && |
3234 |
|
ic[-3].f == mips32_loadstore[4 + 1] && |
3235 |
|
ic[-2].f == instr(nop) && |
3236 |
|
ic[-1].arg[1] == (size_t) &cpu->cd.mips.gpr[MIPS_GPR_ZERO] && |
3237 |
|
ic[-1].arg[2] == (size_t) &ic[-8] && |
3238 |
|
ic[-1].f == instr(beq_samepage)) { |
3239 |
|
ic[-8].f = instr(linux_pmax_idle); |
3240 |
|
return; |
3241 |
|
} |
3242 |
|
|
3243 |
|
if (ic[-4].f == instr(set) && |
3244 |
|
ic[-3].f == mips32_loadstore[4 + 1] && |
3245 |
|
ic[-3].arg[0] == ic[-1].arg[0] && |
3246 |
|
ic[-3].arg[1] == ic[-4].arg[0] && |
3247 |
|
ic[-2].f == instr(nop) && |
3248 |
|
ic[-1].arg[1] == (size_t) &cpu->cd.mips.gpr[MIPS_GPR_ZERO] && |
3249 |
|
ic[-1].arg[2] == (size_t) &ic[-4] && |
3250 |
|
ic[-1].f == instr(beq_samepage)) { |
3251 |
|
ic[-4].f = instr(netbsd_pmax_idle); |
3252 |
return; |
return; |
3253 |
|
} |
3254 |
|
|
3255 |
if ((ic[-3].f == mips32_loadstore[1] || |
if ((ic[-3].f == mips32_loadstore[1] || |
3256 |
ic[-3].f == mips32_loadstore[16 + 1]) && |
ic[-3].f == mips32_loadstore[16 + 1]) && |
3261 |
ic[-1].arg[1] == (size_t) &cpu->cd.mips.gpr[MIPS_GPR_ZERO] && |
ic[-1].arg[1] == (size_t) &cpu->cd.mips.gpr[MIPS_GPR_ZERO] && |
3262 |
ic[-1].f == instr(bne_samepage)) { |
ic[-1].f == instr(bne_samepage)) { |
3263 |
ic[-3].f = instr(netbsd_strlen); |
ic[-3].f = instr(netbsd_strlen); |
|
combined; |
|
3264 |
return; |
return; |
3265 |
} |
} |
3266 |
#endif |
#endif |
3267 |
|
|
|
if (n_back < 1) |
|
|
return; |
|
|
|
|
3268 |
if (ic[-1].f == instr(bne_samepage)) { |
if (ic[-1].f == instr(bne_samepage)) { |
3269 |
ic[-1].f = instr(bne_samepage_nop); |
ic[-1].f = instr(bne_samepage_nop); |
|
combined; |
|
3270 |
return; |
return; |
3271 |
} |
} |
3272 |
|
|
3273 |
if (ic[-1].f == instr(beq_samepage)) { |
if (ic[-1].f == instr(beq_samepage)) { |
3274 |
ic[-1].f = instr(beq_samepage_nop); |
ic[-1].f = instr(beq_samepage_nop); |
|
combined; |
|
3275 |
return; |
return; |
3276 |
} |
} |
3277 |
|
|
3282 |
/* |
/* |
3283 |
* Combine: |
* Combine: |
3284 |
* |
* |
3285 |
|
* xor + andi + sll |
3286 |
|
* andi + sll |
3287 |
|
*/ |
3288 |
|
void COMBINE(sll)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) |
3289 |
|
{ |
3290 |
|
int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) |
3291 |
|
& (MIPS_IC_ENTRIES_PER_PAGE - 1); |
3292 |
|
|
3293 |
|
if (n_back < 2) |
3294 |
|
return; |
3295 |
|
|
3296 |
|
if (ic[-2].f == instr(xor) && ic[-1].f == instr(andi)) { |
3297 |
|
ic[-2].f = instr(xor_andi_sll); |
3298 |
|
return; |
3299 |
|
} |
3300 |
|
|
3301 |
|
if (ic[-1].f == instr(andi)) { |
3302 |
|
ic[-1].f = instr(andi_sll); |
3303 |
|
return; |
3304 |
|
} |
3305 |
|
} |
3306 |
|
|
3307 |
|
|
3308 |
|
/* |
3309 |
|
* lui + ori |
3310 |
|
*/ |
3311 |
|
void COMBINE(ori)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) |
3312 |
|
{ |
3313 |
|
int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) |
3314 |
|
& (MIPS_IC_ENTRIES_PER_PAGE - 1); |
3315 |
|
|
3316 |
|
if (n_back < 1) |
3317 |
|
return; |
3318 |
|
|
3319 |
|
if (ic[-1].f == instr(set)) { |
3320 |
|
ic[-1].f = instr(lui_ori); |
3321 |
|
return; |
3322 |
|
} |
3323 |
|
} |
3324 |
|
|
3325 |
|
|
3326 |
|
/* |
3327 |
|
* addu + addu + addu |
3328 |
|
*/ |
3329 |
|
void COMBINE(addu)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) |
3330 |
|
{ |
3331 |
|
int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) |
3332 |
|
& (MIPS_IC_ENTRIES_PER_PAGE - 1); |
3333 |
|
|
3334 |
|
if (n_back < 4) |
3335 |
|
return; |
3336 |
|
|
3337 |
|
/* Avoid "overlapping" instruction combinations: */ |
3338 |
|
if (ic[-4].f == instr(multi_addu_3) || |
3339 |
|
ic[-3].f == instr(multi_addu_3)) |
3340 |
|
return; |
3341 |
|
|
3342 |
|
if (ic[-2].f == instr(addu) && ic[-1].f == instr(addu)) { |
3343 |
|
ic[-2].f = instr(multi_addu_3); |
3344 |
|
return; |
3345 |
|
} |
3346 |
|
} |
3347 |
|
|
3348 |
|
|
3349 |
|
/* |
3350 |
|
* Combine: |
3351 |
|
* |
3352 |
* [Conditional] branch, followed by addiu. |
* [Conditional] branch, followed by addiu. |
|
* lui + addiu. |
|
3353 |
*/ |
*/ |
3354 |
void COMBINE(addiu)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) |
void COMBINE(addiu)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) |
3355 |
{ |
{ |
3356 |
int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) |
int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) |
3357 |
& (MIPS_IC_ENTRIES_PER_PAGE - 1); |
& (MIPS_IC_ENTRIES_PER_PAGE - 1); |
3358 |
|
|
3359 |
if (n_back < 1) |
if (n_back < 2) |
3360 |
|
return; |
3361 |
|
|
3362 |
|
if (ic[-2].f == instr(addiu) && |
3363 |
|
ic[-1].f == instr(bne_samepage)) { |
3364 |
|
ic[-2].f = instr(addiu_bne_samepage_addiu); |
3365 |
return; |
return; |
3366 |
|
} |
3367 |
|
|
3368 |
if (ic[-1].f == instr(set) && ic[-1].arg[0] == ic[0].arg[0] && |
if (ic[-1].f == instr(set)) { |
3369 |
ic[0].arg[0] == ic[0].arg[1]) { |
ic[-1].f = instr(lui_addiu); |
|
ic[-1].f = instr(lui_32bit); |
|
|
ic[-1].arg[2] = (int32_t) (ic[-1].arg[1] + ic[0].arg[2]); |
|
|
combined; |
|
3370 |
return; |
return; |
3371 |
} |
} |
3372 |
|
|
3373 |
if (ic[-1].f == instr(b_samepage)) { |
if (ic[-1].f == instr(b_samepage)) { |
3374 |
ic[-1].f = instr(b_samepage_addiu); |
ic[-1].f = instr(b_samepage_addiu); |
|
combined; |
|
3375 |
return; |
return; |
3376 |
} |
} |
3377 |
|
|
3378 |
if (ic[-1].f == instr(beq_samepage)) { |
if (ic[-1].f == instr(beq_samepage)) { |
3379 |
ic[-1].f = instr(beq_samepage_addiu); |
ic[-1].f = instr(beq_samepage_addiu); |
|
combined; |
|
3380 |
return; |
return; |
3381 |
} |
} |
3382 |
|
|
3383 |
if (ic[-1].f == instr(bne_samepage)) { |
if (ic[-1].f == instr(bne_samepage)) { |
3384 |
ic[-1].f = instr(bne_samepage_addiu); |
ic[-1].f = instr(bne_samepage_addiu); |
|
combined; |
|
3385 |
return; |
return; |
3386 |
} |
} |
3387 |
|
|
3388 |
if (ic[-1].f == instr(jr_ra)) { |
if (ic[-1].f == instr(jr_ra)) { |
3389 |
ic[-1].f = instr(jr_ra_addiu); |
ic[-1].f = instr(jr_ra_addiu); |
|
combined; |
|
3390 |
return; |
return; |
3391 |
} |
} |
3392 |
|
|
3408 |
|
|
3409 |
if (ic[-1].f == instr(b_samepage)) { |
if (ic[-1].f == instr(b_samepage)) { |
3410 |
ic[-1].f = instr(b_samepage_daddiu); |
ic[-1].f = instr(b_samepage_daddiu); |
|
combined; |
|
3411 |
} |
} |
3412 |
|
|
3413 |
/* TODO: other branches that are followed by daddiu should be here */ |
/* TODO: other branches that are followed by daddiu should be here */ |
3431 |
uint32_t iword, imm; |
uint32_t iword, imm; |
3432 |
unsigned char *page; |
unsigned char *page; |
3433 |
unsigned char ib[4]; |
unsigned char ib[4]; |
3434 |
int main_opcode, rt, rs, rd, sa, s6, x64 = 0; |
int main_opcode, rt, rs, rd, sa, s6, x64 = 0, s10; |
3435 |
int in_crosspage_delayslot = 0; |
int in_crosspage_delayslot = 0; |
3436 |
void (*samepage_function)(struct cpu *, struct mips_instr_call *); |
void (*samepage_function)(struct cpu *, struct mips_instr_call *); |
3437 |
int store, signedness, size; |
int store, signedness, size; |
3512 |
sa = (iword >> 6) & 31; |
sa = (iword >> 6) & 31; |
3513 |
imm = (int16_t)iword; |
imm = (int16_t)iword; |
3514 |
s6 = iword & 63; |
s6 = iword & 63; |
3515 |
|
s10 = (rs << 5) | sa; |
3516 |
|
|
3517 |
switch (main_opcode) { |
switch (main_opcode) { |
3518 |
|
|
3565 |
ic->arg[2] = (size_t)&cpu->cd.mips.gpr[rd]; |
ic->arg[2] = (size_t)&cpu->cd.mips.gpr[rd]; |
3566 |
if (rd == MIPS_GPR_ZERO) |
if (rd == MIPS_GPR_ZERO) |
3567 |
ic->f = instr(nop); |
ic->f = instr(nop); |
3568 |
|
if (ic->f == instr(sll)) |
3569 |
|
cpu->cd.mips.combination_check = COMBINE(sll); |
3570 |
|
if (ic->f == instr(nop)) |
3571 |
|
cpu->cd.mips.combination_check = COMBINE(nop); |
3572 |
|
|
3573 |
|
/* Special checks for MIPS32/64 revision 2 opcodes, |
3574 |
|
such as rotation instructions: */ |
3575 |
|
if (sa >= 0 && rs != 0x00) { |
3576 |
|
switch (rs) { |
3577 |
|
/* TODO: [d]ror, etc. */ |
3578 |
|
default:goto bad; |
3579 |
|
} |
3580 |
|
} |
3581 |
|
if (sa < 0 && (s10 & 0x1f) != 0) { |
3582 |
|
switch (s10 & 0x1f) { |
3583 |
|
/* TODO: [d]rorv, etc. */ |
3584 |
|
default:goto bad; |
3585 |
|
} |
3586 |
|
} |
3587 |
break; |
break; |
3588 |
|
|
3589 |
case SPECIAL_ADD: |
case SPECIAL_ADD: |
3707 |
} |
} |
3708 |
} |
} |
3709 |
if (rd != MIPS_GPR_ZERO) { |
if (rd != MIPS_GPR_ZERO) { |
3710 |
fatal("TODO: rd NON-zero\n"); |
if (!cpu->translation_readahead) |
3711 |
|
fatal("TODO: rd NON-zero\n"); |
3712 |
goto bad; |
goto bad; |
3713 |
} |
} |
3714 |
/* These instructions don't use rd. */ |
/* These instructions don't use rd. */ |
3716 |
default:if (rd == MIPS_GPR_ZERO) |
default:if (rd == MIPS_GPR_ZERO) |
3717 |
ic->f = instr(nop); |
ic->f = instr(nop); |
3718 |
} |
} |
3719 |
|
|
3720 |
|
if (ic->f == instr(addu)) |
3721 |
|
cpu->cd.mips.combination_check = COMBINE(addu); |
3722 |
|
|
3723 |
break; |
break; |
3724 |
|
|
3725 |
case SPECIAL_JR: |
case SPECIAL_JR: |
3739 |
} else { |
} else { |
3740 |
ic->f = instr(jr); |
ic->f = instr(jr); |
3741 |
} |
} |
3742 |
|
if (cpu->translation_readahead > 2) |
3743 |
|
cpu->translation_readahead = 2; |
3744 |
break; |
break; |
3745 |
case SPECIAL_JALR: |
case SPECIAL_JALR: |
3746 |
if (cpu->machine->show_trace_tree) |
if (cpu->machine->show_trace_tree) |
3750 |
break; |
break; |
3751 |
} |
} |
3752 |
if (cpu->delay_slot) { |
if (cpu->delay_slot) { |
3753 |
fatal("TODO: branch in delay slot? (1)\n"); |
if (!cpu->translation_readahead) |
3754 |
|
fatal("TODO: branch in delay " |
3755 |
|
"slot? (1)\n"); |
3756 |
goto bad; |
goto bad; |
3757 |
} |
} |
3758 |
break; |
break; |
3767 |
break; |
break; |
3768 |
|
|
3769 |
case SPECIAL_BREAK: |
case SPECIAL_BREAK: |
3770 |
ic->f = instr(break); |
if (((iword >> 6) & 0xfffff) == 0x30378) { |
3771 |
|
/* "Magic trap" for REBOOT: */ |
3772 |
|
ic->f = instr(reboot); |
3773 |
|
} else { |
3774 |
|
ic->f = instr(break); |
3775 |
|
} |
3776 |
break; |
break; |
3777 |
|
|
3778 |
case SPECIAL_SYNC: |
case SPECIAL_SYNC: |
3850 |
ic->f = samepage_function; |
ic->f = samepage_function; |
3851 |
} |
} |
3852 |
if (cpu->delay_slot) { |
if (cpu->delay_slot) { |
3853 |
fatal("TODO: branch in delay slot? (2)\n"); |
if (!cpu->translation_readahead) |
3854 |
|
fatal("TODO: branch in delay slot? (2)\n"); |
3855 |
goto bad; |
goto bad; |
3856 |
} |
} |
3857 |
break; |
break; |
3900 |
if (rt == MIPS_GPR_ZERO) |
if (rt == MIPS_GPR_ZERO) |
3901 |
ic->f = instr(nop); |
ic->f = instr(nop); |
3902 |
|
|
3903 |
|
if (ic->f == instr(ori)) |
3904 |
|
cpu->cd.mips.combination_check = COMBINE(ori); |
3905 |
if (ic->f == instr(addiu)) |
if (ic->f == instr(addiu)) |
3906 |
cpu->cd.mips.combination_check = COMBINE(addiu); |
cpu->cd.mips.combination_check = COMBINE(addiu); |
3907 |
if (ic->f == instr(daddiu)) |
if (ic->f == instr(daddiu)) |
3923 |
switch (main_opcode) { |
switch (main_opcode) { |
3924 |
case HI6_J: |
case HI6_J: |
3925 |
ic->f = instr(j); |
ic->f = instr(j); |
3926 |
|
if (cpu->translation_readahead > 2) |
3927 |
|
cpu->translation_readahead = 2; |
3928 |
break; |
break; |
3929 |
case HI6_JAL: |
case HI6_JAL: |
3930 |
if (cpu->machine->show_trace_tree) |
if (cpu->machine->show_trace_tree) |
3936 |
ic->arg[0] = (iword & 0x03ffffff) << 2; |
ic->arg[0] = (iword & 0x03ffffff) << 2; |
3937 |
ic->arg[1] = (addr & 0xffc) + 8; |
ic->arg[1] = (addr & 0xffc) + 8; |
3938 |
if (cpu->delay_slot) { |
if (cpu->delay_slot) { |
3939 |
fatal("TODO: branch in delay slot (=%i)? (3); addr=%016" |
if (!cpu->translation_readahead) |
3940 |
PRIx64" iword=%08"PRIx32"\n", cpu->delay_slot, |
fatal("TODO: branch in delay slot (=%i)? (3);" |
3941 |
(uint64_t)addr, iword); |
" addr=%016"PRIx64" iword=%08"PRIx32"\n", |
3942 |
|
cpu->delay_slot, (uint64_t)addr, iword); |
3943 |
goto bad; |
goto bad; |
3944 |
} |
} |
3945 |
break; |
break; |
3970 |
case COP0_DERET: |
case COP0_DERET: |
3971 |
ic->f = instr(deret); |
ic->f = instr(deret); |
3972 |
break; |
break; |
3973 |
case COP0_IDLE: |
case COP0_WAIT: |
3974 |
|
ic->f = instr(wait); |
3975 |
|
if (cpu->cd.mips.cpu_type.rev != MIPS_RM5200 && |
3976 |
|
cpu->cd.mips.cpu_type.isa_level < 32) { |
3977 |
|
static int warned = 0; |
3978 |
|
ic->f = instr(reserved); |
3979 |
|
if (!warned && |
3980 |
|
!cpu->translation_readahead) { |
3981 |
|
fatal("{ WARNING: Attempt to " |
3982 |
|
"execute the WAIT instruct" |
3983 |
|
"ion, but the emulated CPU " |
3984 |
|
"is neither RM52xx, nor " |
3985 |
|
"MIPS32/64! }\n"); |
3986 |
|
warned = 1; |
3987 |
|
} |
3988 |
|
} |
3989 |
|
break; |
3990 |
case COP0_STANDBY: |
case COP0_STANDBY: |
3991 |
case COP0_SUSPEND: |
/* NOTE: Reusing the 'wait' instruction: */ |
3992 |
|
ic->f = instr(wait); |
3993 |
|
if (cpu->cd.mips.cpu_type.rev != MIPS_R4100) { |
3994 |
|
static int warned = 0; |
3995 |
|
ic->f = instr(reserved); |
3996 |
|
if (!warned && |
3997 |
|
!cpu->translation_readahead) { |
3998 |
|
fatal("{ WARNING: Attempt to " |
3999 |
|
"execute a R41xx instruct" |
4000 |
|
"ion, but the emulated CPU " |
4001 |
|
"doesn't support it! }\n"); |
4002 |
|
warned = 1; |
4003 |
|
} |
4004 |
|
} |
4005 |
|
break; |
4006 |
case COP0_HIBERNATE: |
case COP0_HIBERNATE: |
4007 |
/* TODO */ |
/* TODO */ |
4008 |
ic->f = instr(nop); |
goto bad; |
4009 |
|
case COP0_SUSPEND: |
4010 |
|
/* Used by NetBSD on HPCmips (VR41xx) to |
4011 |
|
halt the machine. */ |
4012 |
|
ic->f = instr(reboot); |
4013 |
break; |
break; |
4014 |
case COP0_EI: |
case COP0_EI: |
4015 |
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { |
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { |
4023 |
} else |
} else |
4024 |
goto bad; |
goto bad; |
4025 |
break; |
break; |
4026 |
default:fatal("UNIMPLEMENTED cop0 (func 0x%02x)\n", |
default:if (!cpu->translation_readahead) |
4027 |
iword & 0xff); |
fatal("UNIMPLEMENTED cop0 (func " |
4028 |
|
"0x%02x)\n", iword & 0xff); |
4029 |
goto bad; |
goto bad; |
4030 |
} |
} |
4031 |
break; |
break; |
4047 |
ic->arg[1] = rd + ((iword & 7) << 5); |
ic->arg[1] = rd + ((iword & 7) << 5); |
4048 |
ic->arg[2] = addr & 0xffc; |
ic->arg[2] = addr & 0xffc; |
4049 |
ic->f = rs == COPz_MFCz? instr(mfc0) : instr(dmfc0); |
ic->f = rs == COPz_MFCz? instr(mfc0) : instr(dmfc0); |
4050 |
|
if (rs == COPz_MFCz && (iword & 7) == 0 && |
4051 |
|
rd != COP0_COUNT) |
4052 |
|
ic->f = instr(mfc0_select0); |
4053 |
|
if (rs == COPz_DMFCz && (iword & 7) == 0 && |
4054 |
|
rd != COP0_COUNT) |
4055 |
|
ic->f = instr(dmfc0_select0); |
4056 |
if (rt == MIPS_GPR_ZERO) |
if (rt == MIPS_GPR_ZERO) |
4057 |
ic->f = instr(nop); |
ic->f = instr(nop); |
4058 |
break; |
break; |
4069 |
COMBINE(netbsd_r3k_cache_inv); |
COMBINE(netbsd_r3k_cache_inv); |
4070 |
|
|
4071 |
break; |
break; |
4072 |
case 8: if (iword == 0x4100ffff) { |
case COPz_MFMCz: |
4073 |
|
if ((iword & 0xffdf) == 0x6000) { |
4074 |
|
/* MIPS32/64 rev 2 "ei" or "di": */ |
4075 |
|
if (cpu->cd.mips.cpu_type.isa_level < 32 || |
4076 |
|
cpu->cd.mips.cpu_type.isa_revision < 2) { |
4077 |
|
static int warning_ei_di = 0; |
4078 |
|
if (!warning_ei_di && |
4079 |
|
!cpu->translation_readahead) { |
4080 |
|
fatal("[ WARNING! MIPS32/64 " |
4081 |
|
"revision 2 di or ei opcode" |
4082 |
|
" used, but the %s process" |
4083 |
|
"or does not implement " |
4084 |
|
"such instructions. Only " |
4085 |
|
"printing this " |
4086 |
|
"warning once. ]\n", |
4087 |
|
cpu->cd.mips.cpu_type.name); |
4088 |
|
warning_ei_di = 1; |
4089 |
|
} |
4090 |
|
ic->f = instr(reserved); |
4091 |
|
break; |
4092 |
|
} |
4093 |
|
ic->f = instr(ei_or_di); |
4094 |
|
ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; |
4095 |
|
if (rt == MIPS_GPR_ZERO) |
4096 |
|
ic->arg[0] = |
4097 |
|
(size_t)&cpu->cd.mips.scratch; |
4098 |
|
ic->arg[1] = iword & 0x20; |
4099 |
|
} else { |
4100 |
|
if (!cpu->translation_readahead) |
4101 |
|
fatal("Unimplemented COP0_MFMCz\n"); |
4102 |
|
goto bad; |
4103 |
|
} |
4104 |
|
break; |
4105 |
|
case COPz_BCzc: |
4106 |
|
if (iword == 0x4100ffff) { |
4107 |
/* R2020 DECstation write-loop thingy. */ |
/* R2020 DECstation write-loop thingy. */ |
4108 |
ic->f = instr(nop); |
ic->f = instr(nop); |
4109 |
} else { |
} else { |
4110 |
fatal("Unimplemented blah blah zzzz...\n"); |
if (!cpu->translation_readahead) |
4111 |
|
fatal("Unimplemented COP0_BCzc\n"); |
4112 |
goto bad; |
goto bad; |
4113 |
} |
} |
4114 |
break; |
break; |
4115 |
|
|
4116 |
default:fatal("UNIMPLEMENTED cop0 (rs = %i)\n", rs); |
default:if (!cpu->translation_readahead) |
4117 |
|
fatal("UNIMPLEMENTED cop0 (rs = %i)\n", rs); |
4118 |
goto bad; |
goto bad; |
4119 |
} |
} |
4120 |
break; |
break; |
4141 |
ic->arg[2] = (int32_t) ((imm << |
ic->arg[2] = (int32_t) ((imm << |
4142 |
MIPS_INSTR_ALIGNMENT_SHIFT) + (addr & 0xffc) + 4); |
MIPS_INSTR_ALIGNMENT_SHIFT) + (addr & 0xffc) + 4); |
4143 |
if (cpu->delay_slot) { |
if (cpu->delay_slot) { |
4144 |
fatal("TODO: branch in delay slot? (4)\n"); |
if (!cpu->translation_readahead) |
4145 |
|
fatal("TODO: branch in delay slot 4\n"); |
4146 |
goto bad; |
goto bad; |
4147 |
} |
} |
4148 |
if (cpu->cd.mips.cpu_type.isa_level <= 3 && |
if (cpu->cd.mips.cpu_type.isa_level <= 3 && |
4149 |
ic->arg[0] != 0) { |
ic->arg[0] != 0) { |
4150 |
fatal("Attempt to execute a non-cc-0 BC*" |
if (!cpu->translation_readahead) |
4151 |
" instruction on an isa level %i cpu. " |
fatal("Attempt to execute a non-cc-0 " |
4152 |
"TODO: How should this be handled?\n", |
"BC* instruction on an isa level " |
4153 |
cpu->cd.mips.cpu_type.isa_level); |
"%i cpu. TODO: How should this be " |
4154 |
|
"handled?\n", |
4155 |
|
cpu->cd.mips.cpu_type.isa_level); |
4156 |
goto bad; |
goto bad; |
4157 |
} |
} |
4158 |
|
|
4177 |
ic->arg[0] = (uint32_t)iword & ((1 << 26) - 1); |
ic->arg[0] = (uint32_t)iword & ((1 << 26) - 1); |
4178 |
break; |
break; |
4179 |
|
|
4180 |
default:fatal("COP1 floating point opcode = 0x%02x\n", rs); |
default:if (!cpu->translation_readahead) |
4181 |
|
fatal("COP1 floating point opcode = 0x%02x\n", rs); |
4182 |
goto bad; |
goto bad; |
4183 |
} |
} |
4184 |
break; |
break; |
4191 |
ic->arg[0] = 2; |
ic->arg[0] = 2; |
4192 |
break; |
break; |
4193 |
} |
} |
4194 |
fatal("COP2 functionality not yet implemented\n"); |
if (!cpu->translation_readahead) |
4195 |
|
fatal("COP2 functionality not yet implemented\n"); |
4196 |
goto bad; |
goto bad; |
4197 |
break; |
break; |
4198 |
|
|
4199 |
|
case HI6_COP3: |
4200 |
|
/* Always cause a coprocessor unusable exception if |
4201 |
|
there is no coprocessor 3: */ |
4202 |
|
if (cpu->cd.mips.coproc[3] == NULL) { |
4203 |
|
ic->f = instr(cpu); |
4204 |
|
ic->arg[0] = 3; |
4205 |
|
break; |
4206 |
|
} |
4207 |
|
|
4208 |
|
if (iword == 0x4d00ffff) { |
4209 |
|
/* R2020 writeback thing, used by e.g. NetBSD/pmax |
4210 |
|
on MIPSMATE. */ |
4211 |
|
ic->f = instr(nop); |
4212 |
|
} else { |
4213 |
|
if (!cpu->translation_readahead) |
4214 |
|
fatal("COP3 iword=0x%08x\n", iword); |
4215 |
|
goto bad; |
4216 |
|
} |
4217 |
|
break; |
4218 |
|
|
4219 |
case HI6_SPECIAL2: |
case HI6_SPECIAL2: |
4220 |
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { |
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { |
4221 |
/* R5900, TX79/C790, have MMI instead of SPECIAL2: */ |
/* R5900, TX79/C790, have MMI instead of SPECIAL2: */ |
4395 |
ic->f = samepage_function; |
ic->f = samepage_function; |
4396 |
} |
} |
4397 |
if (cpu->delay_slot) { |
if (cpu->delay_slot) { |
4398 |
fatal("TODO: branch in delay slot? (5)\n"); |
if (!cpu->translation_readahead) |
4399 |
|
fatal("TODO: branch in delay slot:5\n"); |
4400 |
goto bad; |
goto bad; |
4401 |
} |
} |
4402 |
break; |
break; |
4403 |
default:fatal("UNIMPLEMENTED regimm rt=%i\n", rt); |
|
4404 |
|
default:if (!cpu->translation_readahead) |
4405 |
|
fatal("UNIMPLEMENTED regimm rt=%i\n", rt); |
4406 |
goto bad; |
goto bad; |
4407 |
} |
} |
4408 |
break; |
break; |
4450 |
if (!store && rt == MIPS_GPR_ZERO) |
if (!store && rt == MIPS_GPR_ZERO) |
4451 |
ic->arg[0] = (size_t)&cpu->cd.mips.scratch; |
ic->arg[0] = (size_t)&cpu->cd.mips.scratch; |
4452 |
|
|
4453 |
/* Check for multiple stores in a row using the same |
/* Check for multiple loads or stores in a row using the same |
4454 |
base register: */ |
base register: */ |
4455 |
if (main_opcode == HI6_SW && rs == MIPS_GPR_SP) |
#ifdef MODE32 |
4456 |
|
if (main_opcode == HI6_LW) |
4457 |
|
cpu->cd.mips.combination_check = COMBINE(multi_lw); |
4458 |
|
if (main_opcode == HI6_SW) |
4459 |
cpu->cd.mips.combination_check = COMBINE(multi_sw); |
cpu->cd.mips.combination_check = COMBINE(multi_sw); |
4460 |
|
#endif |
4461 |
break; |
break; |
4462 |
|
|
4463 |
case HI6_LL: |
case HI6_LL: |
4482 |
ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rs]; |
ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rs]; |
4483 |
ic->arg[2] = (int32_t)imm; |
ic->arg[2] = (int32_t)imm; |
4484 |
if (!store && rt == MIPS_GPR_ZERO) { |
if (!store && rt == MIPS_GPR_ZERO) { |
4485 |
fatal("HM... unusual load linked\n"); |
if (!cpu->translation_readahead) |
4486 |
|
fatal("HM... unusual load linked\n"); |
4487 |
goto bad; |
goto bad; |
4488 |
} |
} |
4489 |
break; |
break; |
4553 |
/* Treat as nop for now: */ |
/* Treat as nop for now: */ |
4554 |
ic->f = instr(nop); |
ic->f = instr(nop); |
4555 |
} else { |
} else { |
4556 |
fatal("TODO: lwc3 not implemented yet\n"); |
if (!cpu->translation_readahead) |
4557 |
|
fatal("TODO: lwc3 not implemented yet\n"); |
4558 |
goto bad; |
goto bad; |
4559 |
} |
} |
4560 |
break; |
break; |
4561 |
|
|
4562 |
case HI6_LQ_MDMX: |
case HI6_LQ_MDMX: |
4563 |
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { |
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { |
4564 |
fatal("TODO: R5900 128-bit loads\n"); |
if (!cpu->translation_readahead) |
4565 |
|
fatal("TODO: R5900 128-bit loads\n"); |
4566 |
goto bad; |
goto bad; |
4567 |
} |
} |
4568 |
|
|
4569 |
fatal("TODO: MDMX\n"); |
if (!cpu->translation_readahead) |
4570 |
|
fatal("TODO: MDMX\n"); |
4571 |
|
|
4572 |
goto bad; |
goto bad; |
4573 |
/* break */ |
/* break */ |
4574 |
|
|
4575 |
case HI6_SQ_SPECIAL3: |
case HI6_SQ_SPECIAL3: |
4576 |
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { |
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { |
4577 |
fatal("TODO: R5900 128-bit stores\n"); |
if (!cpu->translation_readahead) |
4578 |
|
fatal("TODO: R5900 128-bit stores\n"); |
4579 |
goto bad; |
goto bad; |
4580 |
} |
} |
4581 |
|
|
4582 |
if (cpu->cd.mips.cpu_type.isa_level < 32 || |
if (cpu->cd.mips.cpu_type.isa_level < 32 || |
4583 |
cpu->cd.mips.cpu_type.isa_revision < 2) { |
cpu->cd.mips.cpu_type.isa_revision < 2) { |
4584 |
static int warning = 0; |
static int warning = 0; |
4585 |
if (!warning) { |
if (!warning && !cpu->translation_readahead) { |
4586 |
fatal("[ WARNING! SPECIAL3 opcode used, but" |
fatal("[ WARNING! SPECIAL3 opcode used, but" |
4587 |
" the %s processor does not implement " |
" the %s processor does not implement " |
4588 |
"such instructions. Only printing this " |
"such instructions. Only printing this " |
4596 |
|
|
4597 |
switch (s6) { |
switch (s6) { |
4598 |
|
|
4599 |
|
case SPECIAL3_EXT: |
4600 |
|
{ |
4601 |
|
int msbd = rd, lsb = (iword >> 6) & 0x1f; |
4602 |
|
ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; |
4603 |
|
ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rs]; |
4604 |
|
ic->arg[2] = (msbd << 5) + lsb; |
4605 |
|
ic->f = instr(ext); |
4606 |
|
if (rt == MIPS_GPR_ZERO) |
4607 |
|
ic->f = instr(nop); |
4608 |
|
} |
4609 |
|
break; |
4610 |
|
|
4611 |
|
case SPECIAL3_DEXT: |
4612 |
|
case SPECIAL3_DEXTM: |
4613 |
|
case SPECIAL3_DEXTU: |
4614 |
|
{ |
4615 |
|
int msbd = rd, lsb = (iword >> 6) & 0x1f; |
4616 |
|
if (s6 == SPECIAL3_DEXTM) |
4617 |
|
msbd += 32; |
4618 |
|
if (s6 == SPECIAL3_DEXTU) |
4619 |
|
lsb += 32; |
4620 |
|
ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; |
4621 |
|
ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rs]; |
4622 |
|
ic->arg[2] = (msbd << 6) + lsb; |
4623 |
|
ic->f = instr(dext); |
4624 |
|
if (rt == MIPS_GPR_ZERO) |
4625 |
|
ic->f = instr(nop); |
4626 |
|
} |
4627 |
|
break; |
4628 |
|
|
4629 |
|
case SPECIAL3_INS: |
4630 |
|
{ |
4631 |
|
int msb = rd, lsb = (iword >> 6) & 0x1f; |
4632 |
|
ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; |
4633 |
|
ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rs]; |
4634 |
|
ic->arg[2] = (msb << 5) + lsb; |
4635 |
|
ic->f = instr(ins); |
4636 |
|
if (rt == MIPS_GPR_ZERO) |
4637 |
|
ic->f = instr(nop); |
4638 |
|
} |
4639 |
|
break; |
4640 |
|
|
4641 |
|
case SPECIAL3_BSHFL: |
4642 |
|
ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; |
4643 |
|
ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rd]; |
4644 |
|
switch (s10) { |
4645 |
|
case BSHFL_WSBH: |
4646 |
|
ic->f = instr(wsbh); |
4647 |
|
break; |
4648 |
|
case BSHFL_SEB: |
4649 |
|
ic->f = instr(seb); |
4650 |
|
break; |
4651 |
|
case BSHFL_SEH: |
4652 |
|
ic->f = instr(seh); |
4653 |
|
break; |
4654 |
|
default:goto bad; |
4655 |
|
} |
4656 |
|
break; |
4657 |
|
|
4658 |
|
case SPECIAL3_DBSHFL: |
4659 |
|
ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; |
4660 |
|
ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rd]; |
4661 |
|
switch (s10) { |
4662 |
|
case BSHFL_DSBH: |
4663 |
|
ic->f = instr(dsbh); |
4664 |
|
break; |
4665 |
|
case BSHFL_DSHD: |
4666 |
|
ic->f = instr(dshd); |
4667 |
|
break; |
4668 |
|
default:goto bad; |
4669 |
|
} |
4670 |
|
break; |
4671 |
|
|
4672 |
case SPECIAL3_RDHWR: |
case SPECIAL3_RDHWR: |
4673 |
ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; |
ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; |
4674 |
|
|
4679 |
ic->f = instr(nop); |
ic->f = instr(nop); |
4680 |
break; |
break; |
4681 |
|
|
4682 |
default:fatal("unimplemented rdhwr register rd=%i\n", |
default:if (!cpu->translation_readahead) |
4683 |
rd); |
fatal("unimplemented rdhwr " |
4684 |
|
"register rd=%i\n", rd); |
4685 |
goto bad; |
goto bad; |
4686 |
} |
} |
4687 |
break; |
break; |
4698 |
default:goto bad; |
default:goto bad; |
4699 |
} |
} |
4700 |
|
|
4701 |
|
|
4702 |
#ifdef MODE32 |
#ifdef MODE32 |
4703 |
if (x64) { |
if (x64) { |
4704 |
static int has_warned = 0; |
static int has_warned = 0; |
4705 |
if (!has_warned) |
if (!has_warned && !cpu->translation_readahead) { |
4706 |
fatal("[ WARNING/NOTE: attempt to execute a 64-bit" |
fatal("[ WARNING/NOTE: attempt to execute a 64-bit" |
4707 |
" instruction on an emulated 32-bit processor; " |
" instruction on an emulated 32-bit processor; " |
4708 |
"pc=0x%08"PRIx32" ]\n", (uint32_t)cpu->pc); |
"pc=0x%08"PRIx32" ]\n", (uint32_t)cpu->pc); |
4709 |
has_warned = 1; |
has_warned = 1; |
4710 |
ic->f = instr(reserved); |
} |
4711 |
|
if (cpu->translation_readahead) |
4712 |
|
goto bad; |
4713 |
|
else |
4714 |
|
ic->f = instr(reserved); |
4715 |
} |
} |
4716 |
#endif |
#endif |
4717 |
|
|
|
if (ic->f == instr(nop) && cpu->cd.mips.combination_check == NULL) |
|
|
cpu->cd.mips.combination_check = COMBINE(nop); |
|
|
|
|
4718 |
|
|
4719 |
#define DYNTRANS_TO_BE_TRANSLATED_TAIL |
#define DYNTRANS_TO_BE_TRANSLATED_TAIL |
4720 |
#include "cpu_dyntrans.c" |
#include "cpu_dyntrans.c" |