25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_mips_instr.c,v 1.104 2006/08/14 17:45:47 debug Exp $ |
* $Id: cpu_mips_instr.c,v 1.118 2006/10/29 05:10:27 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 |
|
* ext: Extract bitfield. |
1153 |
|
* |
1154 |
|
* arg[0] = pointer to rt |
1155 |
|
* arg[1] = pointer to rs |
1156 |
|
* arg[2] = (msbd << 5) + lsb |
1157 |
|
*/ |
1158 |
|
X(ext) |
1159 |
|
{ |
1160 |
|
fatal("ext: todo\n"); |
1161 |
|
exit(1); |
1162 |
|
} |
1163 |
|
|
1164 |
|
|
1165 |
|
/* |
1166 |
|
* dsbh: Doubleword swap bytes within half-word |
1167 |
|
* dshd: Doubleword swap half-words within double-word |
1168 |
|
* wsbh: Word swap bytes within half-word |
1169 |
|
* seb: Sign-extend byte |
1170 |
|
* seh: Sign-extend half-word |
1171 |
|
* |
1172 |
|
* arg[0] = pointer to rt |
1173 |
|
* arg[1] = pointer to rd |
1174 |
|
*/ |
1175 |
|
X(dsbh) |
1176 |
|
{ |
1177 |
|
uint64_t x = reg(ic->arg[0]); |
1178 |
|
x = ((x & 0x00ff00ff00ff00ffULL) << 8) |
1179 |
|
| ((x & 0xff00ff00ff00ff00ULL) >> 8); |
1180 |
|
reg(ic->arg[1]) = x; |
1181 |
|
} |
1182 |
|
X(dshd) |
1183 |
|
{ |
1184 |
|
uint64_t x = reg(ic->arg[0]); |
1185 |
|
x = ((x & 0x000000000000ffffULL) << 48) |
1186 |
|
| ((x & 0x00000000ffff0000ULL) << 16) |
1187 |
|
| ((x & 0x0000ffff00000000ULL) >> 16) |
1188 |
|
| ((x & 0xffff000000000000ULL) >> 48); |
1189 |
|
reg(ic->arg[1]) = x; |
1190 |
|
} |
1191 |
|
X(wsbh) |
1192 |
|
{ |
1193 |
|
uint32_t x = reg(ic->arg[0]); |
1194 |
|
x = ((x & 0x00ff00ff) << 8) | ((x & 0xff00ff00) >> 8); |
1195 |
|
reg(ic->arg[1]) = (int32_t) x; |
1196 |
|
} |
1197 |
|
X(seb) { reg(ic->arg[1]) = (int8_t)reg(ic->arg[0]); } |
1198 |
|
X(seh) { reg(ic->arg[1]) = (int16_t)reg(ic->arg[0]); } |
1199 |
|
|
1200 |
|
|
1201 |
|
/* |
1202 |
* 2-register + immediate: |
* 2-register + immediate: |
1203 |
* |
* |
1204 |
* arg[0] = pointer to rs |
* arg[0] = pointer to rs |
1224 |
res = 0, rem = a; |
res = 0, rem = a; |
1225 |
else |
else |
1226 |
res = a / b, rem = a - b*res; |
res = a / b, rem = a - b*res; |
1227 |
reg(&cpu->cd.mips.lo) = (int32_t)res; |
cpu->cd.mips.lo = (int32_t)res; |
1228 |
reg(&cpu->cd.mips.hi) = (int32_t)rem; |
cpu->cd.mips.hi = (int32_t)rem; |
1229 |
} |
} |
1230 |
X(divu) |
X(divu) |
1231 |
{ |
{ |
1235 |
res = 0, rem = a; |
res = 0, rem = a; |
1236 |
else |
else |
1237 |
res = a / b, rem = a - b*res; |
res = a / b, rem = a - b*res; |
1238 |
reg(&cpu->cd.mips.lo) = (int32_t)res; |
cpu->cd.mips.lo = (int32_t)res; |
1239 |
reg(&cpu->cd.mips.hi) = (int32_t)rem; |
cpu->cd.mips.hi = (int32_t)rem; |
1240 |
} |
} |
1241 |
X(ddiv) |
X(ddiv) |
1242 |
{ |
{ |
1247 |
else |
else |
1248 |
res = a / b; |
res = a / b; |
1249 |
rem = a - b*res; |
rem = a - b*res; |
1250 |
reg(&cpu->cd.mips.lo) = res; |
cpu->cd.mips.lo = res; |
1251 |
reg(&cpu->cd.mips.hi) = rem; |
cpu->cd.mips.hi = rem; |
1252 |
} |
} |
1253 |
X(ddivu) |
X(ddivu) |
1254 |
{ |
{ |
1259 |
else |
else |
1260 |
res = a / b; |
res = a / b; |
1261 |
rem = a - b*res; |
rem = a - b*res; |
1262 |
reg(&cpu->cd.mips.lo) = res; |
cpu->cd.mips.lo = res; |
1263 |
reg(&cpu->cd.mips.hi) = rem; |
cpu->cd.mips.hi = rem; |
1264 |
} |
} |
1265 |
X(mult) |
X(mult) |
1266 |
{ |
{ |
1267 |
int32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); |
int32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); |
1268 |
int64_t res = (int64_t)a * (int64_t)b; |
int64_t res = (int64_t)a * (int64_t)b; |
1269 |
reg(&cpu->cd.mips.lo) = (int32_t)res; |
cpu->cd.mips.lo = (int32_t)res; |
1270 |
reg(&cpu->cd.mips.hi) = (int32_t)(res >> 32); |
cpu->cd.mips.hi = (int32_t)(res >> 32); |
1271 |
} |
} |
1272 |
X(mult_r5900) |
X(mult_r5900) |
1273 |
{ |
{ |
1275 |
hi, lo, and a third register */ |
hi, lo, and a third register */ |
1276 |
int32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); |
int32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); |
1277 |
int64_t res = (int64_t)a * (int64_t)b; |
int64_t res = (int64_t)a * (int64_t)b; |
1278 |
reg(&cpu->cd.mips.lo) = (int32_t)res; |
cpu->cd.mips.lo = (int32_t)res; |
1279 |
reg(&cpu->cd.mips.hi) = (int32_t)(res >> 32); |
cpu->cd.mips.hi = (int32_t)(res >> 32); |
1280 |
reg(ic->arg[2]) = (int32_t)res; |
reg(ic->arg[2]) = (int32_t)res; |
1281 |
} |
} |
1282 |
X(multu) |
X(multu) |
1283 |
{ |
{ |
1284 |
uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); |
uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); |
1285 |
uint64_t res = (uint64_t)a * (uint64_t)b; |
uint64_t res = (uint64_t)a * (uint64_t)b; |
1286 |
reg(&cpu->cd.mips.lo) = (int32_t)res; |
cpu->cd.mips.lo = (int32_t)res; |
1287 |
reg(&cpu->cd.mips.hi) = (int32_t)(res >> 32); |
cpu->cd.mips.hi = (int32_t)(res >> 32); |
1288 |
} |
} |
1289 |
X(multu_r5900) |
X(multu_r5900) |
1290 |
{ |
{ |
1292 |
hi, lo, and a third register */ |
hi, lo, and a third register */ |
1293 |
uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); |
uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); |
1294 |
uint64_t res = (uint64_t)a * (uint64_t)b; |
uint64_t res = (uint64_t)a * (uint64_t)b; |
1295 |
reg(&cpu->cd.mips.lo) = (int32_t)res; |
cpu->cd.mips.lo = (int32_t)res; |
1296 |
reg(&cpu->cd.mips.hi) = (int32_t)(res >> 32); |
cpu->cd.mips.hi = (int32_t)(res >> 32); |
1297 |
reg(ic->arg[2]) = (int32_t)res; |
reg(ic->arg[2]) = (int32_t)res; |
1298 |
} |
} |
1299 |
X(dmult) |
X(dmult) |
1322 |
hi ^= (int64_t) -1; |
hi ^= (int64_t) -1; |
1323 |
lo ^= (int64_t) -1; |
lo ^= (int64_t) -1; |
1324 |
} |
} |
1325 |
reg(&cpu->cd.mips.lo) = lo; |
cpu->cd.mips.lo = lo; |
1326 |
reg(&cpu->cd.mips.hi) = hi; |
cpu->cd.mips.hi = hi; |
1327 |
} |
} |
1328 |
X(dmultu) |
X(dmultu) |
1329 |
{ |
{ |
1339 |
} |
} |
1340 |
c = (c << 1) | (b >> 63); b <<= 1; |
c = (c << 1) | (b >> 63); b <<= 1; |
1341 |
} |
} |
1342 |
reg(&cpu->cd.mips.lo) = lo; |
cpu->cd.mips.lo = lo; |
1343 |
reg(&cpu->cd.mips.hi) = hi; |
cpu->cd.mips.hi = hi; |
1344 |
} |
} |
1345 |
X(tge) |
X(tge) |
1346 |
{ |
{ |
1749 |
|
|
1750 |
/* |
/* |
1751 |
* set: Set a register to an immediate (signed) 32-bit value. |
* set: Set a register to an immediate (signed) 32-bit value. |
1752 |
|
* (This is the actual implementation of the lui instruction.) |
1753 |
* |
* |
1754 |
* arg[0] = pointer to the register |
* arg[0] = pointer to the register |
1755 |
* arg[1] = (int32_t) immediate value |
* arg[1] = (int32_t) immediate value |
1788 |
coproc_register_read(cpu, cpu->cd.mips.coproc[0], rd, &tmp, select); |
coproc_register_read(cpu, cpu->cd.mips.coproc[0], rd, &tmp, select); |
1789 |
reg(ic->arg[0]) = (int32_t)tmp; |
reg(ic->arg[0]) = (int32_t)tmp; |
1790 |
} |
} |
1791 |
|
X(mfc0_select0) |
1792 |
|
{ |
1793 |
|
/* Fast int32_t read, with no side effects: */ |
1794 |
|
int rd = ic->arg[1] & 31; |
1795 |
|
#if 0 |
1796 |
|
uint64_t tmp; |
1797 |
|
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT); |
1798 |
|
cpu->pc |= ic->arg[2]; |
1799 |
|
/* TODO: cause exception if necessary */ |
1800 |
|
#endif |
1801 |
|
reg(ic->arg[0]) = (int32_t)cpu->cd.mips.coproc[0]->reg[rd]; |
1802 |
|
} |
1803 |
X(mtc0) |
X(mtc0) |
1804 |
{ |
{ |
1805 |
int rd = ic->arg[1] & 31, select = ic->arg[1] >> 5; |
int rd = ic->arg[1] & 31, select = ic->arg[1] >> 5; |
1843 |
coproc_register_read(cpu, cpu->cd.mips.coproc[0], rd, |
coproc_register_read(cpu, cpu->cd.mips.coproc[0], rd, |
1844 |
(uint64_t *)ic->arg[0], select); |
(uint64_t *)ic->arg[0], select); |
1845 |
} |
} |
1846 |
|
X(dmfc0_select0) |
1847 |
|
{ |
1848 |
|
/* Fast int64_t read, with no side effects: */ |
1849 |
|
int rd = ic->arg[1] & 31; |
1850 |
|
#if 0 |
1851 |
|
uint64_t tmp; |
1852 |
|
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT); |
1853 |
|
cpu->pc |= ic->arg[2]; |
1854 |
|
/* TODO: cause exception if necessary */ |
1855 |
|
#endif |
1856 |
|
reg(ic->arg[0]) = cpu->cd.mips.coproc[0]->reg[rd]; |
1857 |
|
} |
1858 |
X(dmtc0) |
X(dmtc0) |
1859 |
{ |
{ |
1860 |
int rd = ic->arg[1] & 31, select = ic->arg[1] >> 5; |
int rd = ic->arg[1] & 31, select = ic->arg[1] >> 5; |
1876 |
X(cop1_bc) |
X(cop1_bc) |
1877 |
{ |
{ |
1878 |
MODE_int_t old_pc = cpu->pc; |
MODE_int_t old_pc = cpu->pc; |
1879 |
const int cpnr = 1; |
int x, cc = ic->arg[0]; |
|
int x, low_pc, cc = ic->arg[0]; |
|
1880 |
|
|
1881 |
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; |
|
|
} |
|
1882 |
|
|
1883 |
/* Get the correct condition code bit: */ |
/* Get the correct condition code bit: */ |
1884 |
if (cc == 0) |
if (cc == 0) |
1918 |
*/ |
*/ |
1919 |
X(cop1_slow) |
X(cop1_slow) |
1920 |
{ |
{ |
1921 |
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; |
|
|
} |
|
1922 |
|
|
1923 |
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); |
1924 |
} |
} |
1945 |
} |
} |
1946 |
X(reboot) |
X(reboot) |
1947 |
{ |
{ |
1948 |
|
if (!cop0_availability_check(cpu, ic)) |
1949 |
|
return; |
1950 |
|
|
1951 |
cpu->running = 0; |
cpu->running = 0; |
1952 |
debugger_n_steps_left_before_interaction = 0; |
debugger_n_steps_left_before_interaction = 0; |
1953 |
cpu->cd.mips.next_ic = ¬hing_call; |
cpu->cd.mips.next_ic = ¬hing_call; |
2010 |
*/ |
*/ |
2011 |
X(tlbw) |
X(tlbw) |
2012 |
{ |
{ |
2013 |
|
if (!cop0_availability_check(cpu, ic)) |
2014 |
|
return; |
2015 |
|
|
2016 |
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT); |
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT); |
2017 |
cpu->pc |= ic->arg[2]; |
cpu->pc |= ic->arg[2]; |
2018 |
coproc_tlbwri(cpu, ic->arg[0]); |
coproc_tlbwri(cpu, ic->arg[0]); |
2027 |
*/ |
*/ |
2028 |
X(tlbp) |
X(tlbp) |
2029 |
{ |
{ |
2030 |
|
if (!cop0_availability_check(cpu, ic)) |
2031 |
|
return; |
2032 |
|
|
2033 |
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT); |
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT); |
2034 |
cpu->pc |= ic->arg[2]; |
cpu->pc |= ic->arg[2]; |
2035 |
coproc_tlbpr(cpu, 0); |
coproc_tlbpr(cpu, 0); |
2036 |
} |
} |
2037 |
X(tlbr) |
X(tlbr) |
2038 |
{ |
{ |
2039 |
|
if (!cop0_availability_check(cpu, ic)) |
2040 |
|
return; |
2041 |
|
|
2042 |
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT); |
cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<<MIPS_INSTR_ALIGNMENT_SHIFT); |
2043 |
cpu->pc |= ic->arg[2]; |
cpu->pc |= ic->arg[2]; |
2044 |
coproc_tlbpr(cpu, 1); |
coproc_tlbpr(cpu, 1); |
2050 |
*/ |
*/ |
2051 |
X(rfe) |
X(rfe) |
2052 |
{ |
{ |
2053 |
|
if (!cop0_availability_check(cpu, ic)) |
2054 |
|
return; |
2055 |
|
|
2056 |
/* Just rotate the interrupt/user bits: */ |
/* Just rotate the interrupt/user bits: */ |
2057 |
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] = |
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] = |
2058 |
(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) | |
(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) | |
2071 |
*/ |
*/ |
2072 |
X(eret) |
X(eret) |
2073 |
{ |
{ |
2074 |
|
if (!cop0_availability_check(cpu, ic)) |
2075 |
|
return; |
2076 |
|
|
2077 |
if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) { |
if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) { |
2078 |
cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_ERROREPC]; |
cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_ERROREPC]; |
2079 |
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL; |
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL; |
2094 |
*/ |
*/ |
2095 |
X(deret) |
X(deret) |
2096 |
{ |
{ |
2097 |
|
if (!cop0_availability_check(cpu, ic)) |
2098 |
|
return; |
2099 |
|
|
2100 |
/* |
/* |
2101 |
* According to the MIPS64 manual, deret loads PC from the DEPC cop0 |
* According to the MIPS64 manual, deret loads PC from the DEPC cop0 |
2102 |
* register, and jumps there immediately. No delay slot. |
* register, and jumps there immediately. No delay slot. |
2115 |
|
|
2116 |
|
|
2117 |
/* |
/* |
2118 |
* wait: Wait for external interrupt. |
* idle: Called from the implementation of wait, or netbsd_pmax_idle. |
2119 |
*/ |
*/ |
2120 |
X(wait) |
X(idle) |
2121 |
{ |
{ |
2122 |
/* |
/* |
2123 |
* If there is an interrupt, then just return. Otherwise |
* If there is an interrupt, then just return. Otherwise |
2126 |
uint32_t status = cpu->cd.mips.coproc[0]->reg[COP0_STATUS]; |
uint32_t status = cpu->cd.mips.coproc[0]->reg[COP0_STATUS]; |
2127 |
uint32_t cause = cpu->cd.mips.coproc[0]->reg[COP0_CAUSE]; |
uint32_t cause = cpu->cd.mips.coproc[0]->reg[COP0_CAUSE]; |
2128 |
|
|
|
/* NOTE: STATUS_IE happens to match the enable bit also |
|
|
on R2000/R3000, so this is ok. */ |
|
2129 |
if (cpu->cd.mips.cpu_type.exc_model != EXC3K) { |
if (cpu->cd.mips.cpu_type.exc_model != EXC3K) { |
2130 |
if (status & (STATUS_EXL | STATUS_ERL)) |
if (status & (STATUS_EXL | STATUS_ERL)) |
2131 |
status &= ~STATUS_IE; |
status &= ~STATUS_IE; |
2132 |
} |
} |
2133 |
|
|
2134 |
/* Ugly R5900 special case: (TODO: move this?) */ |
/* Ugly R5900 special case: (TODO: move this?) */ |
2135 |
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900 && |
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900 && |
2136 |
!(status & R5900_STATUS_EIE)) |
!(status & R5900_STATUS_EIE)) |
2140 |
|
|
2141 |
cpu->cd.mips.next_ic = ic; |
cpu->cd.mips.next_ic = ic; |
2142 |
cpu->is_halted = 1; |
cpu->is_halted = 1; |
2143 |
|
cpu->has_been_idling = 1; |
2144 |
|
|
2145 |
/* |
/* |
2146 |
* There was no interrupt. Go to sleep. |
* There was no interrupt. Go to sleep. |
2154 |
if (cpu->machine->ncpus == 1) { |
if (cpu->machine->ncpus == 1) { |
2155 |
static int x = 0; |
static int x = 0; |
2156 |
if ((++x) == 600) { |
if ((++x) == 600) { |
2157 |
usleep(1); |
usleep(10); |
2158 |
x = 0; |
x = 0; |
2159 |
} |
} |
2160 |
cpu->n_translated_instrs += N_SAFE_DYNTRANS_LIMIT / 6; |
cpu->n_translated_instrs += N_SAFE_DYNTRANS_LIMIT / 6; |
2163 |
|
|
2164 |
|
|
2165 |
/* |
/* |
2166 |
|
* wait: Wait for external interrupt. |
2167 |
|
*/ |
2168 |
|
X(wait) |
2169 |
|
{ |
2170 |
|
if (!cop0_availability_check(cpu, ic)) |
2171 |
|
return; |
2172 |
|
|
2173 |
|
instr(idle)(cpu, ic); |
2174 |
|
} |
2175 |
|
|
2176 |
|
|
2177 |
|
/* |
2178 |
* rdhwr: Read hardware register into gpr (MIPS32/64 rev 2). |
* rdhwr: Read hardware register into gpr (MIPS32/64 rev 2). |
2179 |
* |
* |
2180 |
* arg[0] = ptr to rt (destination register) |
* arg[0] = ptr to rt (destination register) |
2411 |
*/ |
*/ |
2412 |
X(lwc1) |
X(lwc1) |
2413 |
{ |
{ |
2414 |
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; |
|
|
} |
|
2415 |
|
|
2416 |
#ifdef MODE32 |
#ifdef MODE32 |
2417 |
mips32_loadstore |
mips32_loadstore |
2423 |
} |
} |
2424 |
X(swc1) |
X(swc1) |
2425 |
{ |
{ |
2426 |
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; |
|
|
} |
|
2427 |
|
|
2428 |
#ifdef MODE32 |
#ifdef MODE32 |
2429 |
mips32_loadstore |
mips32_loadstore |
2435 |
} |
} |
2436 |
X(ldc1) |
X(ldc1) |
2437 |
{ |
{ |
|
const int cpnr = 1; |
|
2438 |
int use_fp_pairs = |
int use_fp_pairs = |
2439 |
!(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_FR); |
!(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_FR); |
2440 |
uint64_t fpr, *backup_ptr; |
uint64_t fpr, *backup_ptr; |
2441 |
|
|
2442 |
/* 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; |
|
|
} |
|
2443 |
|
|
2444 |
backup_ptr = (uint64_t *) ic->arg[0]; |
backup_ptr = (uint64_t *) ic->arg[0]; |
2445 |
ic->arg[0] = (size_t) &fpr; |
ic->arg[0] = (size_t) &fpr; |
2463 |
} |
} |
2464 |
X(sdc1) |
X(sdc1) |
2465 |
{ |
{ |
|
const int cpnr = 1; |
|
2466 |
int use_fp_pairs = |
int use_fp_pairs = |
2467 |
!(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_FR); |
!(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_FR); |
2468 |
uint64_t fpr, *backup_ptr; |
uint64_t fpr, *backup_ptr; |
2469 |
|
|
2470 |
/* 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; |
|
|
} |
|
2471 |
|
|
2472 |
backup_ptr = (uint64_t *) ic->arg[0]; |
backup_ptr = (uint64_t *) ic->arg[0]; |
2473 |
ic->arg[0] = (size_t) &fpr; |
ic->arg[0] = (size_t) &fpr; |
2518 |
*/ |
*/ |
2519 |
X(di_r5900) |
X(di_r5900) |
2520 |
{ |
{ |
2521 |
|
if (!cop0_availability_check(cpu, ic)) |
2522 |
|
return; |
2523 |
|
|
2524 |
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~R5900_STATUS_EIE; |
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~R5900_STATUS_EIE; |
2525 |
} |
} |
2526 |
X(ei_r5900) |
X(ei_r5900) |
2527 |
{ |
{ |
2528 |
|
if (!cop0_availability_check(cpu, ic)) |
2529 |
|
return; |
2530 |
|
|
2531 |
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |= R5900_STATUS_EIE; |
cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |= R5900_STATUS_EIE; |
2532 |
} |
} |
2533 |
|
|
3148 |
|
|
3149 |
#ifdef MODE32 |
#ifdef MODE32 |
3150 |
/* |
/* |
3151 |
|
* netbsd_pmax_idle(): |
3152 |
|
* |
3153 |
|
* s: lui rX, hi |
3154 |
|
* lw rY, lo(rX) |
3155 |
|
* nop |
3156 |
|
* beq zr, rY, s |
3157 |
|
* nop |
3158 |
|
*/ |
3159 |
|
X(netbsd_pmax_idle) |
3160 |
|
{ |
3161 |
|
uint32_t addr, pageindex, i; |
3162 |
|
int32_t *page; |
3163 |
|
|
3164 |
|
reg(ic[0].arg[0]) = (int32_t)ic[0].arg[1]; |
3165 |
|
|
3166 |
|
addr = reg(ic[0].arg[0]) + (int32_t)ic[1].arg[2]; |
3167 |
|
pageindex = addr >> 12; |
3168 |
|
i = (addr & 0xfff) >> 2; |
3169 |
|
page = (int32_t *) cpu->cd.mips.host_load[pageindex]; |
3170 |
|
|
3171 |
|
/* Fallback: */ |
3172 |
|
if (cpu->delay_slot || page == NULL || page[i] != 0) |
3173 |
|
return; |
3174 |
|
|
3175 |
|
instr(idle)(cpu, ic); |
3176 |
|
} |
3177 |
|
|
3178 |
|
|
3179 |
|
/* |
3180 |
|
* linux_pmax_idle(): |
3181 |
|
* |
3182 |
|
* s: lui rX, hi |
3183 |
|
* lw rX, lo(rX) |
3184 |
|
* nop |
3185 |
|
* bne zr, rX, ... |
3186 |
|
* nop |
3187 |
|
* lw rX, ofs(gp) |
3188 |
|
* nop |
3189 |
|
* beq zr, rX, s |
3190 |
|
* nop |
3191 |
|
*/ |
3192 |
|
X(linux_pmax_idle) |
3193 |
|
{ |
3194 |
|
uint32_t addr, addr2, pageindex, pageindex2, i, i2; |
3195 |
|
int32_t *page, *page2; |
3196 |
|
|
3197 |
|
reg(ic[0].arg[0]) = (int32_t)ic[0].arg[1]; |
3198 |
|
|
3199 |
|
addr = reg(ic[0].arg[0]) + (int32_t)ic[1].arg[2]; |
3200 |
|
pageindex = addr >> 12; |
3201 |
|
i = (addr & 0xfff) >> 2; |
3202 |
|
page = (int32_t *) cpu->cd.mips.host_load[pageindex]; |
3203 |
|
|
3204 |
|
addr2 = reg(ic[5].arg[1]) + (int32_t)ic[5].arg[2]; |
3205 |
|
pageindex2 = addr2 >> 12; |
3206 |
|
i2 = (addr2 & 0xfff) >> 2; |
3207 |
|
page2 = (int32_t *) cpu->cd.mips.host_load[pageindex2]; |
3208 |
|
|
3209 |
|
/* Fallback: */ |
3210 |
|
if (cpu->delay_slot || page == NULL || page[i] != 0 || page2[i2] != 0) |
3211 |
|
return; |
3212 |
|
|
3213 |
|
instr(idle)(cpu, ic); |
3214 |
|
} |
3215 |
|
|
3216 |
|
|
3217 |
|
/* |
3218 |
* netbsd_strlen(): |
* netbsd_strlen(): |
3219 |
* |
* |
3220 |
* lb rV,0(rX) |
* lb rV,0(rX) |
3654 |
* |
* |
3655 |
* NetBSD's strlen core. |
* NetBSD's strlen core. |
3656 |
* [Conditional] branch, followed by nop. |
* [Conditional] branch, followed by nop. |
3657 |
|
* NetBSD/pmax' idle loop (and possibly others as well). |
3658 |
|
* Linux/pmax' idle loop. |
3659 |
*/ |
*/ |
3660 |
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) |
3661 |
{ |
{ |
3662 |
int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) |
int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) |
3663 |
& (MIPS_IC_ENTRIES_PER_PAGE - 1); |
& (MIPS_IC_ENTRIES_PER_PAGE - 1); |
3664 |
|
|
3665 |
|
if (n_back < 8) |
3666 |
|
return; |
3667 |
|
|
3668 |
#ifdef MODE32 |
#ifdef MODE32 |
3669 |
if (n_back < 3) |
if (ic[-8].f == instr(set) && |
3670 |
|
ic[-7].f == mips32_loadstore[4 + 1] && |
3671 |
|
ic[-7].arg[0] == ic[-1].arg[0] && |
3672 |
|
ic[-7].arg[0] == ic[-3].arg[0] && |
3673 |
|
ic[-7].arg[0] == ic[-5].arg[0] && |
3674 |
|
ic[-7].arg[0] == ic[-7].arg[1] && |
3675 |
|
ic[-7].arg[0] == ic[-8].arg[0] && |
3676 |
|
ic[-6].f == instr(nop) && |
3677 |
|
ic[-5].arg[1] == (size_t) &cpu->cd.mips.gpr[MIPS_GPR_ZERO] && |
3678 |
|
ic[-5].f == instr(bne_samepage_nop) && |
3679 |
|
ic[-4].f == instr(nop) && |
3680 |
|
ic[-3].f == mips32_loadstore[4 + 1] && |
3681 |
|
ic[-2].f == instr(nop) && |
3682 |
|
ic[-1].arg[1] == (size_t) &cpu->cd.mips.gpr[MIPS_GPR_ZERO] && |
3683 |
|
ic[-1].arg[2] == (size_t) &ic[-8] && |
3684 |
|
ic[-1].f == instr(beq_samepage)) { |
3685 |
|
ic[-8].f = instr(linux_pmax_idle); |
3686 |
|
return; |
3687 |
|
} |
3688 |
|
|
3689 |
|
if (ic[-4].f == instr(set) && |
3690 |
|
ic[-3].f == mips32_loadstore[4 + 1] && |
3691 |
|
ic[-3].arg[0] == ic[-1].arg[0] && |
3692 |
|
ic[-3].arg[1] == ic[-4].arg[0] && |
3693 |
|
ic[-2].f == instr(nop) && |
3694 |
|
ic[-1].arg[1] == (size_t) &cpu->cd.mips.gpr[MIPS_GPR_ZERO] && |
3695 |
|
ic[-1].arg[2] == (size_t) &ic[-4] && |
3696 |
|
ic[-1].f == instr(beq_samepage)) { |
3697 |
|
ic[-4].f = instr(netbsd_pmax_idle); |
3698 |
return; |
return; |
3699 |
|
} |
3700 |
|
|
3701 |
if ((ic[-3].f == mips32_loadstore[1] || |
if ((ic[-3].f == mips32_loadstore[1] || |
3702 |
ic[-3].f == mips32_loadstore[16 + 1]) && |
ic[-3].f == mips32_loadstore[16 + 1]) && |
3711 |
} |
} |
3712 |
#endif |
#endif |
3713 |
|
|
|
if (n_back < 1) |
|
|
return; |
|
|
|
|
3714 |
if (ic[-1].f == instr(bne_samepage)) { |
if (ic[-1].f == instr(bne_samepage)) { |
3715 |
ic[-1].f = instr(bne_samepage_nop); |
ic[-1].f = instr(bne_samepage_nop); |
3716 |
return; |
return; |
3877 |
uint32_t iword, imm; |
uint32_t iword, imm; |
3878 |
unsigned char *page; |
unsigned char *page; |
3879 |
unsigned char ib[4]; |
unsigned char ib[4]; |
3880 |
int main_opcode, rt, rs, rd, sa, s6, x64 = 0; |
int main_opcode, rt, rs, rd, sa, s6, x64 = 0, s10; |
3881 |
int in_crosspage_delayslot = 0; |
int in_crosspage_delayslot = 0; |
3882 |
void (*samepage_function)(struct cpu *, struct mips_instr_call *); |
void (*samepage_function)(struct cpu *, struct mips_instr_call *); |
3883 |
int store, signedness, size; |
int store, signedness, size; |
3958 |
sa = (iword >> 6) & 31; |
sa = (iword >> 6) & 31; |
3959 |
imm = (int16_t)iword; |
imm = (int16_t)iword; |
3960 |
s6 = iword & 63; |
s6 = iword & 63; |
3961 |
|
s10 = (rs << 5) | sa; |
3962 |
|
|
3963 |
switch (main_opcode) { |
switch (main_opcode) { |
3964 |
|
|
4013 |
ic->f = instr(nop); |
ic->f = instr(nop); |
4014 |
if (ic->f == instr(sll)) |
if (ic->f == instr(sll)) |
4015 |
cpu->cd.mips.combination_check = COMBINE(sll); |
cpu->cd.mips.combination_check = COMBINE(sll); |
4016 |
|
if (ic->f == instr(nop)) |
4017 |
|
cpu->cd.mips.combination_check = COMBINE(nop); |
4018 |
|
|
4019 |
|
/* Special checks for MIPS32/64 revision 2 opcodes, |
4020 |
|
such as rotation instructions: */ |
4021 |
|
if (sa >= 0 && rs != 0x00) { |
4022 |
|
switch (rs) { |
4023 |
|
/* TODO: [d]ror, etc. */ |
4024 |
|
default:goto bad; |
4025 |
|
} |
4026 |
|
} |
4027 |
|
if (sa < 0 && (s10 & 0x1f) != 0) { |
4028 |
|
switch (s10 & 0x1f) { |
4029 |
|
/* TODO: [d]rorv, etc. */ |
4030 |
|
default:goto bad; |
4031 |
|
} |
4032 |
|
} |
4033 |
break; |
break; |
4034 |
|
|
4035 |
case SPECIAL_ADD: |
case SPECIAL_ADD: |
4423 |
} |
} |
4424 |
break; |
break; |
4425 |
case COP0_STANDBY: |
case COP0_STANDBY: |
4426 |
case COP0_SUSPEND: |
/* NOTE: Reusing the 'wait' instruction: */ |
4427 |
|
ic->f = instr(wait); |
4428 |
|
if (cpu->cd.mips.cpu_type.rev != MIPS_R4100) { |
4429 |
|
static int warned = 0; |
4430 |
|
ic->f = instr(reserved); |
4431 |
|
if (!warned) { |
4432 |
|
fatal("{ WARNING: Attempt to " |
4433 |
|
"execute a R41xx instruct" |
4434 |
|
"ion, but the emulated CPU " |
4435 |
|
"doesn't support it! }\n"); |
4436 |
|
warned = 1; |
4437 |
|
} |
4438 |
|
} |
4439 |
|
break; |
4440 |
case COP0_HIBERNATE: |
case COP0_HIBERNATE: |
4441 |
/* TODO */ |
/* TODO */ |
4442 |
ic->f = instr(nop); |
goto bad; |
4443 |
|
case COP0_SUSPEND: |
4444 |
|
/* Used by NetBSD on HPCmips (VR41xx) to |
4445 |
|
halt the machine. */ |
4446 |
|
ic->f = instr(reboot); |
4447 |
break; |
break; |
4448 |
case COP0_EI: |
case COP0_EI: |
4449 |
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { |
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { |
4480 |
ic->arg[1] = rd + ((iword & 7) << 5); |
ic->arg[1] = rd + ((iword & 7) << 5); |
4481 |
ic->arg[2] = addr & 0xffc; |
ic->arg[2] = addr & 0xffc; |
4482 |
ic->f = rs == COPz_MFCz? instr(mfc0) : instr(dmfc0); |
ic->f = rs == COPz_MFCz? instr(mfc0) : instr(dmfc0); |
4483 |
|
if (rs == COPz_MFCz && (iword & 7) == 0 && |
4484 |
|
rd != COP0_COUNT) |
4485 |
|
ic->f = instr(mfc0_select0); |
4486 |
|
if (rs == COPz_DMFCz && (iword & 7) == 0 && |
4487 |
|
rd != COP0_COUNT) |
4488 |
|
ic->f = instr(dmfc0_select0); |
4489 |
if (rt == MIPS_GPR_ZERO) |
if (rt == MIPS_GPR_ZERO) |
4490 |
ic->f = instr(nop); |
ic->f = instr(nop); |
4491 |
break; |
break; |
4959 |
|
|
4960 |
switch (s6) { |
switch (s6) { |
4961 |
|
|
4962 |
|
case SPECIAL3_EXT: |
4963 |
|
/* TODO: Cleanup and extend to DEXT... etc */ |
4964 |
|
{ |
4965 |
|
int msbd = rd, lsb = (iword >> 6) & 0x1f; |
4966 |
|
ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; |
4967 |
|
ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rs]; |
4968 |
|
ic->arg[2] = (msbd << 5) + lsb; |
4969 |
|
ic->f = instr(ext); |
4970 |
|
if (rt == MIPS_GPR_ZERO) |
4971 |
|
ic->f = instr(nop); |
4972 |
|
} |
4973 |
|
break; |
4974 |
|
|
4975 |
|
case SPECIAL3_BSHFL: |
4976 |
|
ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; |
4977 |
|
ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rd]; |
4978 |
|
switch (s10) { |
4979 |
|
case BSHFL_WSBH: |
4980 |
|
ic->f = instr(wsbh); |
4981 |
|
break; |
4982 |
|
case BSHFL_SEB: |
4983 |
|
ic->f = instr(seb); |
4984 |
|
break; |
4985 |
|
case BSHFL_SEH: |
4986 |
|
ic->f = instr(seh); |
4987 |
|
break; |
4988 |
|
default:goto bad; |
4989 |
|
} |
4990 |
|
break; |
4991 |
|
|
4992 |
|
case SPECIAL3_DBSHFL: |
4993 |
|
ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; |
4994 |
|
ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rd]; |
4995 |
|
switch (s10) { |
4996 |
|
case BSHFL_DSBH: |
4997 |
|
ic->f = instr(dsbh); |
4998 |
|
break; |
4999 |
|
case BSHFL_DSHD: |
5000 |
|
ic->f = instr(dshd); |
5001 |
|
break; |
5002 |
|
default:goto bad; |
5003 |
|
} |
5004 |
|
break; |
5005 |
|
|
5006 |
case SPECIAL3_RDHWR: |
case SPECIAL3_RDHWR: |
5007 |
ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; |
ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; |
5008 |
|
|
5043 |
} |
} |
5044 |
#endif |
#endif |
5045 |
|
|
|
if (ic->f == instr(nop) && cpu->cd.mips.combination_check == NULL) |
|
|
cpu->cd.mips.combination_check = COMBINE(nop); |
|
|
|
|
5046 |
|
|
5047 |
#define DYNTRANS_TO_BE_TRANSLATED_TAIL |
#define DYNTRANS_TO_BE_TRANSLATED_TAIL |
5048 |
#include "cpu_dyntrans.c" |
#include "cpu_dyntrans.c" |