Commit | Line | Data |
---|---|---|
cf76e892 JPM |
1 | /* |
2 | * UAE - The Un*x Amiga Emulator - CPU core | |
3 | * | |
4 | * Read 68000 CPU specs from file "table68k" | |
5 | * | |
6 | * Copyright 1995,1996 Bernd Schmidt | |
7 | * | |
8 | * Adaptation to Hatari by Thomas Huth | |
9 | * Adaptation to Virtual Jaguar by James Hammons | |
10 | * | |
11 | * This file is distributed under the GNU Public License, version 3 or at | |
12 | * your option any later version. Read the file GPLv3 for details. | |
13 | */ | |
14 | ||
15 | ||
16 | /* 2008/04/26 [NP] Handle sz_byte for Areg as a valid srcmode if current instruction is a MOVE */ | |
17 | /* (e.g. move.b a1,(a0) ($1089)) (fix Blood Money on Superior 65) */ | |
18 | ||
19 | ||
20 | //const char ReadCpu_fileid[] = "Hatari readcpu.c : " __DATE__ " " __TIME__; | |
21 | ||
22 | #include <ctype.h> | |
23 | #include <string.h> | |
24 | ||
25 | #include "readcpu.h" | |
26 | ||
27 | int nr_cpuop_funcs; | |
28 | ||
29 | const struct mnemolookup lookuptab[] = { | |
30 | { i_ILLG, "ILLEGAL" }, | |
31 | { i_OR, "OR" }, | |
32 | { i_CHK, "CHK" }, | |
33 | { i_CHK2, "CHK2" }, | |
34 | { i_AND, "AND" }, | |
35 | { i_EOR, "EOR" }, | |
36 | { i_ORSR, "ORSR" }, | |
37 | { i_ANDSR, "ANDSR" }, | |
38 | { i_EORSR, "EORSR" }, | |
39 | { i_SUB, "SUB" }, | |
40 | { i_SUBA, "SUBA" }, | |
41 | { i_SUBX, "SUBX" }, | |
42 | { i_SBCD, "SBCD" }, | |
43 | { i_ADD, "ADD" }, | |
44 | { i_ADDA, "ADDA" }, | |
45 | { i_ADDX, "ADDX" }, | |
46 | { i_ABCD, "ABCD" }, | |
47 | { i_NEG, "NEG" }, | |
48 | { i_NEGX, "NEGX" }, | |
49 | { i_NBCD, "NBCD" }, | |
50 | { i_CLR, "CLR" }, | |
51 | { i_NOT, "NOT" }, | |
52 | { i_TST, "TST" }, | |
53 | { i_BTST, "BTST" }, | |
54 | { i_BCHG, "BCHG" }, | |
55 | { i_BCLR, "BCLR" }, | |
56 | { i_BSET, "BSET" }, | |
57 | { i_CMP, "CMP" }, | |
58 | { i_CMPM, "CMPM" }, | |
59 | { i_CMPA, "CMPA" }, | |
60 | { i_MVPRM, "MVPRM" }, | |
61 | { i_MVPMR, "MVPMR" }, | |
62 | { i_MOVE, "MOVE" }, | |
63 | { i_MOVEA, "MOVEA" }, | |
64 | { i_MVSR2, "MVSR2" }, | |
65 | { i_MV2SR, "MV2SR" }, | |
66 | { i_SWAP, "SWAP" }, | |
67 | { i_EXG, "EXG" }, | |
68 | { i_EXT, "EXT" }, | |
69 | { i_MVMEL, "MVMEL" }, | |
70 | { i_MVMLE, "MVMLE" }, | |
71 | { i_TRAP, "TRAP" }, | |
72 | { i_MVR2USP, "MVR2USP" }, | |
73 | { i_MVUSP2R, "MVUSP2R" }, | |
74 | { i_NOP, "NOP" }, | |
75 | { i_RESET, "RESET" }, | |
76 | { i_RTE, "RTE" }, | |
77 | { i_RTD, "RTD" }, | |
78 | { i_LINK, "LINK" }, | |
79 | { i_UNLK, "UNLK" }, | |
80 | { i_RTS, "RTS" }, | |
81 | { i_STOP, "STOP" }, | |
82 | { i_TRAPV, "TRAPV" }, | |
83 | { i_RTR, "RTR" }, | |
84 | { i_JSR, "JSR" }, | |
85 | { i_JMP, "JMP" }, | |
86 | { i_BSR, "BSR" }, | |
87 | { i_Bcc, "Bcc" }, | |
88 | { i_LEA, "LEA" }, | |
89 | { i_PEA, "PEA" }, | |
90 | { i_DBcc, "DBcc" }, | |
91 | { i_Scc, "Scc" }, | |
92 | { i_DIVU, "DIVU" }, | |
93 | { i_DIVS, "DIVS" }, | |
94 | { i_MULU, "MULU" }, | |
95 | { i_MULS, "MULS" }, | |
96 | { i_ASR, "ASR" }, | |
97 | { i_ASL, "ASL" }, | |
98 | { i_LSR, "LSR" }, | |
99 | { i_LSL, "LSL" }, | |
100 | { i_ROL, "ROL" }, | |
101 | { i_ROR, "ROR" }, | |
102 | { i_ROXL, "ROXL" }, | |
103 | { i_ROXR, "ROXR" }, | |
104 | { i_ASRW, "ASRW" }, | |
105 | { i_ASLW, "ASLW" }, | |
106 | { i_LSRW, "LSRW" }, | |
107 | { i_LSLW, "LSLW" }, | |
108 | { i_ROLW, "ROLW" }, | |
109 | { i_RORW, "RORW" }, | |
110 | { i_ROXLW, "ROXLW" }, | |
111 | { i_ROXRW, "ROXRW" }, | |
112 | ||
113 | { i_MOVE2C, "MOVE2C" }, | |
114 | { i_MOVEC2, "MOVEC2" }, | |
115 | { i_CAS, "CAS" }, | |
116 | { i_CAS2, "CAS2" }, | |
117 | { i_MULL, "MULL" }, | |
118 | { i_DIVL, "DIVL" }, | |
119 | { i_BFTST, "BFTST" }, | |
120 | { i_BFEXTU, "BFEXTU" }, | |
121 | { i_BFCHG, "BFCHG" }, | |
122 | { i_BFEXTS, "BFEXTS" }, | |
123 | { i_BFCLR, "BFCLR" }, | |
124 | { i_BFFFO, "BFFFO" }, | |
125 | { i_BFSET, "BFSET" }, | |
126 | { i_BFINS, "BFINS" }, | |
127 | { i_PACK, "PACK" }, | |
128 | { i_UNPK, "UNPK" }, | |
129 | { i_TAS, "TAS" }, | |
130 | { i_BKPT, "BKPT" }, | |
131 | { i_CALLM, "CALLM" }, | |
132 | { i_RTM, "RTM" }, | |
133 | { i_TRAPcc, "TRAPcc" }, | |
134 | { i_MOVES, "MOVES" }, | |
135 | { i_FPP, "FPP" }, | |
136 | { i_FDBcc, "FDBcc" }, | |
137 | { i_FScc, "FScc" }, | |
138 | { i_FTRAPcc, "FTRAPcc" }, | |
139 | { i_FBcc, "FBcc" }, | |
140 | { i_FBcc, "FBcc" }, | |
141 | { i_FSAVE, "FSAVE" }, | |
142 | { i_FRESTORE, "FRESTORE" }, | |
143 | ||
144 | { i_CINVL, "CINVL" }, | |
145 | { i_CINVP, "CINVP" }, | |
146 | { i_CINVA, "CINVA" }, | |
147 | { i_CPUSHL, "CPUSHL" }, | |
148 | { i_CPUSHP, "CPUSHP" }, | |
149 | { i_CPUSHA, "CPUSHA" }, | |
150 | { i_MOVE16, "MOVE16" }, | |
151 | ||
152 | { i_MMUOP, "MMUOP" }, | |
153 | { i_ILLG, "" }, | |
154 | }; | |
155 | ||
156 | ||
157 | struct instr * table68k; | |
158 | ||
159 | ||
160 | STATIC_INLINE amodes mode_from_str(const char * str) | |
161 | { | |
162 | if (strncmp (str, "Dreg", 4) == 0) return Dreg; | |
163 | if (strncmp (str, "Areg", 4) == 0) return Areg; | |
164 | if (strncmp (str, "Aind", 4) == 0) return Aind; | |
165 | if (strncmp (str, "Apdi", 4) == 0) return Apdi; | |
166 | if (strncmp (str, "Aipi", 4) == 0) return Aipi; | |
167 | if (strncmp (str, "Ad16", 4) == 0) return Ad16; | |
168 | if (strncmp (str, "Ad8r", 4) == 0) return Ad8r; | |
169 | if (strncmp (str, "absw", 4) == 0) return absw; | |
170 | if (strncmp (str, "absl", 4) == 0) return absl; | |
171 | if (strncmp (str, "PC16", 4) == 0) return PC16; | |
172 | if (strncmp (str, "PC8r", 4) == 0) return PC8r; | |
173 | if (strncmp (str, "Immd", 4) == 0) return imm; | |
174 | ||
175 | abort(); | |
176 | return 0; | |
177 | } | |
178 | ||
179 | ||
180 | STATIC_INLINE amodes mode_from_mr(int mode, int reg) | |
181 | { | |
182 | switch (mode) | |
183 | { | |
184 | case 0: return Dreg; | |
185 | case 1: return Areg; | |
186 | case 2: return Aind; | |
187 | case 3: return Aipi; | |
188 | case 4: return Apdi; | |
189 | case 5: return Ad16; | |
190 | case 6: return Ad8r; | |
191 | case 7: | |
192 | switch (reg) | |
193 | { | |
194 | case 0: return absw; | |
195 | case 1: return absl; | |
196 | case 2: return PC16; | |
197 | case 3: return PC8r; | |
198 | case 4: return imm; | |
199 | case 5: | |
200 | case 6: | |
201 | case 7: return am_illg; | |
202 | } | |
203 | } | |
204 | ||
205 | abort(); | |
206 | return 0; | |
207 | } | |
208 | ||
209 | ||
210 | static void build_insn(int insn) | |
211 | { | |
212 | int find = -1; | |
213 | int variants; | |
214 | int isjmp = 0; | |
215 | struct instr_def id; | |
216 | const char * opcstr; | |
217 | int j; | |
218 | ||
219 | int flaglive = 0, flagdead = 0; | |
220 | id = defs68k[insn]; | |
221 | ||
222 | /* Note: We treat anything with unknown flags as a jump. That | |
223 | is overkill, but "the programmer" was lazy quite often, and | |
224 | *this* programmer can't be bothered to work out what can and | |
225 | can't trap. Usually, this will be overwritten with the gencomp | |
226 | based information, anyway. */ | |
227 | ||
228 | for(j=0; j<5; j++) | |
229 | { | |
230 | switch (id.flaginfo[j].flagset) | |
231 | { | |
232 | case fa_unset: break; | |
233 | case fa_isjmp: isjmp = 1; break; | |
234 | case fa_isbranch: isjmp = 1; break; | |
235 | case fa_zero: flagdead |= 1 << j; break; | |
236 | case fa_one: flagdead |= 1 << j; break; | |
237 | case fa_dontcare: flagdead |= 1 << j; break; | |
238 | case fa_unknown: isjmp = 1; flagdead = -1; goto out1; | |
239 | case fa_set: flagdead |= 1 << j; break; | |
240 | } | |
241 | } | |
242 | ||
243 | out1: | |
244 | for(j=0; j<5; j++) | |
245 | { | |
246 | switch (id.flaginfo[j].flaguse) | |
247 | { | |
248 | case fu_unused: break; | |
249 | case fu_isjmp: isjmp = 1; flaglive |= 1 << j; break; | |
250 | case fu_maybecc: isjmp = 1; flaglive |= 1 << j; break; | |
251 | case fu_unknown: isjmp = 1; flaglive |= 1 << j; break; | |
252 | case fu_used: flaglive |= 1 << j; break; | |
253 | } | |
254 | } | |
255 | ||
256 | opcstr = id.opcstr; | |
257 | ||
258 | for(variants=0; variants<(1 << id.n_variable); variants++) | |
259 | { | |
260 | int bitcnt[lastbit]; | |
261 | int bitval[lastbit]; | |
262 | int bitpos[lastbit]; | |
263 | int i; | |
264 | uint16_t opc = id.bits; | |
265 | uint16_t msk, vmsk; | |
266 | int pos = 0; | |
267 | int mnp = 0; | |
268 | int bitno = 0; | |
269 | char mnemonic[10]; | |
270 | ||
271 | wordsizes sz = sz_long; | |
272 | int srcgather = 0, dstgather = 0; | |
273 | int usesrc = 0, usedst = 0; | |
274 | int srctype = 0; | |
275 | int srcpos = -1, dstpos = -1; | |
276 | ||
277 | amodes srcmode = am_unknown, destmode = am_unknown; | |
278 | int srcreg = -1, destreg = -1; | |
279 | ||
280 | for(i=0; i<lastbit; i++) | |
281 | bitcnt[i] = bitval[i] = 0; | |
282 | ||
283 | vmsk = 1 << id.n_variable; | |
284 | ||
285 | for(i=0, msk=0x8000; i<16; i++, msk >>= 1) | |
286 | { | |
287 | if (!(msk & id.mask)) | |
288 | { | |
289 | int currbit = id.bitpos[bitno++]; | |
290 | int bit_set; | |
291 | vmsk >>= 1; | |
292 | bit_set = (variants & vmsk ? 1 : 0); | |
293 | ||
294 | if (bit_set) | |
295 | opc |= msk; | |
296 | ||
297 | bitpos[currbit] = 15 - i; | |
298 | bitcnt[currbit]++; | |
299 | bitval[currbit] <<= 1; | |
300 | bitval[currbit] |= bit_set; | |
301 | } | |
302 | } | |
303 | ||
304 | if (bitval[bitj] == 0) | |
305 | bitval[bitj] = 8; | |
306 | ||
307 | /* first check whether this one does not match after all */ | |
308 | if (bitval[bitz] == 3 || bitval[bitC] == 1) | |
309 | continue; | |
310 | ||
311 | if (bitcnt[bitI] && (bitval[bitI] == 0x00 || bitval[bitI] == 0xff)) | |
312 | continue; | |
313 | ||
314 | /* bitI and bitC get copied to biti and bitc */ | |
315 | if (bitcnt[bitI]) | |
316 | { | |
317 | bitval[biti] = bitval[bitI]; bitpos[biti] = bitpos[bitI]; | |
318 | } | |
319 | ||
320 | if (bitcnt[bitC]) | |
321 | bitval[bitc] = bitval[bitC]; | |
322 | ||
323 | pos = 0; | |
324 | while (opcstr[pos] && !isspace((unsigned)opcstr[pos])) | |
325 | { | |
326 | if (opcstr[pos] == '.') | |
327 | { | |
328 | pos++; | |
329 | ||
330 | switch (opcstr[pos]) | |
331 | { | |
332 | case 'B': sz = sz_byte; break; | |
333 | case 'W': sz = sz_word; break; | |
334 | case 'L': sz = sz_long; break; | |
335 | case 'z': | |
336 | switch (bitval[bitz]) | |
337 | { | |
338 | case 0: sz = sz_byte; break; | |
339 | case 1: sz = sz_word; break; | |
340 | case 2: sz = sz_long; break; | |
341 | default: abort(); | |
342 | } | |
343 | break; | |
344 | default: abort(); | |
345 | } | |
346 | } | |
347 | else | |
348 | { | |
349 | mnemonic[mnp] = opcstr[pos]; | |
350 | ||
351 | if (mnemonic[mnp] == 'f') | |
352 | { | |
353 | find = -1; | |
354 | switch (bitval[bitf]) | |
355 | { | |
356 | case 0: mnemonic[mnp] = 'R'; break; | |
357 | case 1: mnemonic[mnp] = 'L'; break; | |
358 | default: abort(); | |
359 | } | |
360 | } | |
361 | ||
362 | mnp++; | |
363 | } | |
364 | ||
365 | pos++; | |
366 | } | |
367 | ||
368 | mnemonic[mnp] = 0; | |
369 | ||
370 | /* now, we have read the mnemonic and the size */ | |
371 | while (opcstr[pos] && isspace((unsigned)opcstr[pos])) | |
372 | pos++; | |
373 | ||
374 | /* A goto a day keeps the D******a away. */ | |
375 | if (opcstr[pos] == 0) | |
376 | goto endofline; | |
377 | ||
378 | /* parse the source address */ | |
379 | usesrc = 1; | |
380 | switch (opcstr[pos++]) | |
381 | { | |
382 | case 'D': | |
383 | srcmode = Dreg; | |
384 | ||
385 | switch (opcstr[pos++]) | |
386 | { | |
387 | case 'r': srcreg = bitval[bitr]; srcgather = 1; srcpos = bitpos[bitr]; break; | |
388 | case 'R': srcreg = bitval[bitR]; srcgather = 1; srcpos = bitpos[bitR]; break; | |
389 | default: abort(); | |
390 | } | |
391 | ||
392 | break; | |
393 | case 'A': | |
394 | srcmode = Areg; | |
395 | ||
396 | switch (opcstr[pos++]) | |
397 | { | |
398 | case 'r': srcreg = bitval[bitr]; srcgather = 1; srcpos = bitpos[bitr]; break; | |
399 | case 'R': srcreg = bitval[bitR]; srcgather = 1; srcpos = bitpos[bitR]; break; | |
400 | default: abort(); | |
401 | } | |
402 | ||
403 | switch (opcstr[pos]) | |
404 | { | |
405 | case 'p': srcmode = Apdi; pos++; break; | |
406 | case 'P': srcmode = Aipi; pos++; break; | |
407 | } | |
408 | break; | |
409 | ||
410 | case 'L': | |
411 | srcmode = absl; | |
412 | break; | |
413 | case '#': | |
414 | switch (opcstr[pos++]) | |
415 | { | |
416 | case 'z': srcmode = imm; break; | |
417 | case '0': srcmode = imm0; break; | |
418 | case '1': srcmode = imm1; break; | |
419 | case '2': srcmode = imm2; break; | |
420 | case 'i': | |
421 | srcmode = immi; srcreg = (int32_t)(int8_t)bitval[biti]; | |
422 | ||
423 | if (CPU_EMU_SIZE < 4) | |
424 | { | |
425 | /* Used for branch instructions */ | |
426 | srctype = 1; | |
427 | srcgather = 1; | |
428 | srcpos = bitpos[biti]; | |
429 | } | |
430 | ||
431 | break; | |
432 | case 'j': | |
433 | srcmode = immi; srcreg = bitval[bitj]; | |
434 | ||
435 | if (CPU_EMU_SIZE < 3) | |
436 | { | |
437 | /* 1..8 for ADDQ/SUBQ and rotshi insns */ | |
438 | srcgather = 1; | |
439 | srctype = 3; | |
440 | srcpos = bitpos[bitj]; | |
441 | } | |
442 | ||
443 | break; | |
444 | case 'J': | |
445 | srcmode = immi; srcreg = bitval[bitJ]; | |
446 | ||
447 | if (CPU_EMU_SIZE < 5) | |
448 | { | |
449 | /* 0..15 */ | |
450 | srcgather = 1; | |
451 | srctype = 2; | |
452 | srcpos = bitpos[bitJ]; | |
453 | } | |
454 | ||
455 | break; | |
456 | case 'k': | |
457 | srcmode = immi; srcreg = bitval[bitk]; | |
458 | ||
459 | if (CPU_EMU_SIZE < 3) | |
460 | { | |
461 | srcgather = 1; | |
462 | srctype = 4; | |
463 | srcpos = bitpos[bitk]; | |
464 | } | |
465 | ||
466 | break; | |
467 | case 'K': | |
468 | srcmode = immi; srcreg = bitval[bitK]; | |
469 | ||
470 | if (CPU_EMU_SIZE < 5) | |
471 | { | |
472 | /* 0..15 */ | |
473 | srcgather = 1; | |
474 | srctype = 5; | |
475 | srcpos = bitpos[bitK]; | |
476 | } | |
477 | ||
478 | break; | |
479 | case 'p': | |
480 | srcmode = immi; srcreg = bitval[bitK]; | |
481 | ||
482 | if (CPU_EMU_SIZE < 5) | |
483 | { | |
484 | /* 0..3 */ | |
485 | srcgather = 1; | |
486 | srctype = 7; | |
487 | srcpos = bitpos[bitp]; | |
488 | } | |
489 | ||
490 | break; | |
491 | default: abort(); | |
492 | } | |
493 | ||
494 | break; | |
495 | case 'd': | |
496 | srcreg = bitval[bitD]; | |
497 | srcmode = mode_from_mr(bitval[bitd],bitval[bitD]); | |
498 | ||
499 | if (srcmode == am_illg) | |
500 | continue; | |
501 | ||
502 | if (CPU_EMU_SIZE < 2 | |
503 | && (srcmode == Areg || srcmode == Dreg || srcmode == Aind | |
504 | || srcmode == Ad16 || srcmode == Ad8r || srcmode == Aipi | |
505 | || srcmode == Apdi)) | |
506 | { | |
507 | srcgather = 1; | |
508 | srcpos = bitpos[bitD]; | |
509 | } | |
510 | ||
511 | if (opcstr[pos] == '[') | |
512 | { | |
513 | pos++; | |
514 | ||
515 | if (opcstr[pos] == '!') | |
516 | { | |
517 | /* exclusion */ | |
518 | do | |
519 | { | |
520 | pos++; | |
521 | ||
522 | if (mode_from_str(opcstr + pos) == srcmode) | |
523 | goto nomatch; | |
524 | ||
525 | pos += 4; | |
526 | } | |
527 | while (opcstr[pos] == ','); | |
528 | ||
529 | pos++; | |
530 | } | |
531 | else | |
532 | { | |
533 | if (opcstr[pos + 4] == '-') | |
534 | { | |
535 | /* replacement */ | |
536 | if (mode_from_str(opcstr + pos) == srcmode) | |
537 | srcmode = mode_from_str(opcstr + pos + 5); | |
538 | else | |
539 | goto nomatch; | |
540 | ||
541 | pos += 10; | |
542 | } | |
543 | else | |
544 | { | |
545 | /* normal */ | |
546 | while(mode_from_str(opcstr + pos) != srcmode) | |
547 | { | |
548 | pos += 4; | |
549 | ||
550 | if (opcstr[pos] == ']') | |
551 | goto nomatch; | |
552 | ||
553 | pos++; | |
554 | } | |
555 | ||
556 | while(opcstr[pos] != ']') | |
557 | pos++; | |
558 | ||
559 | pos++; | |
560 | break; | |
561 | } | |
562 | } | |
563 | } | |
564 | ||
565 | /* Some addressing modes are invalid as destination */ | |
566 | if (srcmode == imm || srcmode == PC16 || srcmode == PC8r) | |
567 | goto nomatch; | |
568 | ||
569 | break; | |
570 | case 's': | |
571 | srcreg = bitval[bitS]; | |
572 | srcmode = mode_from_mr(bitval[bits],bitval[bitS]); | |
573 | ||
574 | if (srcmode == am_illg) | |
575 | continue; | |
576 | ||
577 | if (CPU_EMU_SIZE < 2 | |
578 | && (srcmode == Areg || srcmode == Dreg || srcmode == Aind | |
579 | || srcmode == Ad16 || srcmode == Ad8r || srcmode == Aipi | |
580 | || srcmode == Apdi)) | |
581 | { | |
582 | srcgather = 1; | |
583 | srcpos = bitpos[bitS]; | |
584 | } | |
585 | ||
586 | if (opcstr[pos] == '[') | |
587 | { | |
588 | pos++; | |
589 | ||
590 | if (opcstr[pos] == '!') | |
591 | { | |
592 | /* exclusion */ | |
593 | do | |
594 | { | |
595 | pos++; | |
596 | ||
597 | if (mode_from_str(opcstr + pos) == srcmode) | |
598 | goto nomatch; | |
599 | ||
600 | pos += 4; | |
601 | } | |
602 | while (opcstr[pos] == ','); | |
603 | ||
604 | pos++; | |
605 | } | |
606 | else | |
607 | { | |
608 | if (opcstr[pos + 4] == '-') | |
609 | { | |
610 | /* replacement */ | |
611 | if (mode_from_str(opcstr + pos) == srcmode) | |
612 | srcmode = mode_from_str(opcstr + pos + 5); | |
613 | else | |
614 | goto nomatch; | |
615 | ||
616 | pos += 10; | |
617 | } | |
618 | else | |
619 | { | |
620 | /* normal */ | |
621 | while(mode_from_str(opcstr+pos) != srcmode) | |
622 | { | |
623 | pos += 4; | |
624 | ||
625 | if (opcstr[pos] == ']') | |
626 | goto nomatch; | |
627 | ||
628 | pos++; | |
629 | } | |
630 | ||
631 | while(opcstr[pos] != ']') | |
632 | pos++; | |
633 | ||
634 | pos++; | |
635 | } | |
636 | } | |
637 | } | |
638 | break; | |
639 | default: abort(); | |
640 | } | |
641 | ||
642 | /* safety check - might have changed */ | |
643 | if (srcmode != Areg && srcmode != Dreg && srcmode != Aind | |
644 | && srcmode != Ad16 && srcmode != Ad8r && srcmode != Aipi | |
645 | && srcmode != Apdi && srcmode != immi) | |
646 | { | |
647 | srcgather = 0; | |
648 | } | |
649 | ||
650 | // if (srcmode == Areg && sz == sz_byte) | |
651 | if (srcmode == Areg && sz == sz_byte && strcmp(mnemonic, "MOVE") != 0 ) // [NP] move.b is valid on 68000 | |
652 | goto nomatch; | |
653 | ||
654 | if (opcstr[pos] != ',') | |
655 | goto endofline; | |
656 | ||
657 | pos++; | |
658 | ||
659 | /* parse the destination address */ | |
660 | usedst = 1; | |
661 | ||
662 | switch (opcstr[pos++]) | |
663 | { | |
664 | case 'D': | |
665 | destmode = Dreg; | |
666 | ||
667 | switch (opcstr[pos++]) | |
668 | { | |
669 | case 'r': destreg = bitval[bitr]; dstgather = 1; dstpos = bitpos[bitr]; break; | |
670 | case 'R': destreg = bitval[bitR]; dstgather = 1; dstpos = bitpos[bitR]; break; | |
671 | default: abort(); | |
672 | } | |
673 | ||
674 | if (dstpos < 0 || dstpos >= 32) | |
675 | abort(); | |
676 | ||
677 | break; | |
678 | case 'A': | |
679 | destmode = Areg; | |
680 | ||
681 | switch (opcstr[pos++]) | |
682 | { | |
683 | case 'r': destreg = bitval[bitr]; dstgather = 1; dstpos = bitpos[bitr]; break; | |
684 | case 'R': destreg = bitval[bitR]; dstgather = 1; dstpos = bitpos[bitR]; break; | |
685 | case 'x': destreg = 0; dstgather = 0; dstpos = 0; break; | |
686 | default: abort(); | |
687 | } | |
688 | ||
689 | if (dstpos < 0 || dstpos >= 32) | |
690 | abort(); | |
691 | ||
692 | switch (opcstr[pos]) | |
693 | { | |
694 | case 'p': destmode = Apdi; pos++; break; | |
695 | case 'P': destmode = Aipi; pos++; break; | |
696 | } | |
697 | ||
698 | break; | |
699 | case 'L': | |
700 | destmode = absl; | |
701 | break; | |
702 | case '#': | |
703 | switch (opcstr[pos++]) | |
704 | { | |
705 | case 'z': destmode = imm; break; | |
706 | case '0': destmode = imm0; break; | |
707 | case '1': destmode = imm1; break; | |
708 | case '2': destmode = imm2; break; | |
709 | case 'i': destmode = immi; destreg = (int32_t)(int8_t)bitval[biti]; break; | |
710 | case 'j': destmode = immi; destreg = bitval[bitj]; break; | |
711 | case 'J': destmode = immi; destreg = bitval[bitJ]; break; | |
712 | case 'k': destmode = immi; destreg = bitval[bitk]; break; | |
713 | case 'K': destmode = immi; destreg = bitval[bitK]; break; | |
714 | default: abort(); | |
715 | } | |
716 | break; | |
717 | case 'd': | |
718 | destreg = bitval[bitD]; | |
719 | destmode = mode_from_mr(bitval[bitd],bitval[bitD]); | |
720 | ||
721 | if (destmode == am_illg) | |
722 | continue; | |
723 | ||
724 | if (CPU_EMU_SIZE < 1 | |
725 | && (destmode == Areg || destmode == Dreg || destmode == Aind | |
726 | || destmode == Ad16 || destmode == Ad8r || destmode == Aipi | |
727 | || destmode == Apdi)) | |
728 | { | |
729 | dstgather = 1; | |
730 | dstpos = bitpos[bitD]; | |
731 | } | |
732 | ||
733 | if (opcstr[pos] == '[') | |
734 | { | |
735 | pos++; | |
736 | ||
737 | if (opcstr[pos] == '!') | |
738 | { | |
739 | /* exclusion */ | |
740 | do | |
741 | { | |
742 | pos++; | |
743 | ||
744 | if (mode_from_str(opcstr + pos) == destmode) | |
745 | goto nomatch; | |
746 | ||
747 | pos += 4; | |
748 | } | |
749 | while (opcstr[pos] == ','); | |
750 | ||
751 | pos++; | |
752 | } | |
753 | else | |
754 | { | |
755 | if (opcstr[pos+4] == '-') | |
756 | { | |
757 | /* replacement */ | |
758 | if (mode_from_str(opcstr + pos) == destmode) | |
759 | destmode = mode_from_str(opcstr + pos + 5); | |
760 | else | |
761 | goto nomatch; | |
762 | ||
763 | pos += 10; | |
764 | } | |
765 | else | |
766 | { | |
767 | /* normal */ | |
768 | while(mode_from_str(opcstr + pos) != destmode) | |
769 | { | |
770 | pos += 4; | |
771 | ||
772 | if (opcstr[pos] == ']') | |
773 | goto nomatch; | |
774 | ||
775 | pos++; | |
776 | } | |
777 | ||
778 | while(opcstr[pos] != ']') | |
779 | pos++; | |
780 | ||
781 | pos++; | |
782 | break; | |
783 | } | |
784 | } | |
785 | } | |
786 | ||
787 | /* Some addressing modes are invalid as destination */ | |
788 | if (destmode == imm || destmode == PC16 || destmode == PC8r) | |
789 | goto nomatch; | |
790 | ||
791 | break; | |
792 | case 's': | |
793 | destreg = bitval[bitS]; | |
794 | destmode = mode_from_mr(bitval[bits], bitval[bitS]); | |
795 | ||
796 | if (destmode == am_illg) | |
797 | continue; | |
798 | if (CPU_EMU_SIZE < 1 | |
799 | && (destmode == Areg || destmode == Dreg || destmode == Aind | |
800 | || destmode == Ad16 || destmode == Ad8r || destmode == Aipi | |
801 | || destmode == Apdi)) | |
802 | { | |
803 | dstgather = 1; | |
804 | dstpos = bitpos[bitS]; | |
805 | } | |
806 | ||
807 | if (opcstr[pos] == '[') | |
808 | { | |
809 | pos++; | |
810 | ||
811 | if (opcstr[pos] == '!') | |
812 | { | |
813 | /* exclusion */ | |
814 | do | |
815 | { | |
816 | pos++; | |
817 | ||
818 | if (mode_from_str(opcstr + pos) == destmode) | |
819 | goto nomatch; | |
820 | ||
821 | pos += 4; | |
822 | } | |
823 | while (opcstr[pos] == ','); | |
824 | ||
825 | pos++; | |
826 | } | |
827 | else | |
828 | { | |
829 | if (opcstr[pos+4] == '-') | |
830 | { | |
831 | /* replacement */ | |
832 | if (mode_from_str(opcstr + pos) == destmode) | |
833 | destmode = mode_from_str(opcstr + pos + 5); | |
834 | else | |
835 | goto nomatch; | |
836 | ||
837 | pos += 10; | |
838 | } | |
839 | else | |
840 | { | |
841 | /* normal */ | |
842 | while (mode_from_str(opcstr + pos) != destmode) | |
843 | { | |
844 | pos += 4; | |
845 | ||
846 | if (opcstr[pos] == ']') | |
847 | goto nomatch; | |
848 | ||
849 | pos++; | |
850 | } | |
851 | ||
852 | while (opcstr[pos] != ']') | |
853 | pos++; | |
854 | ||
855 | pos++; | |
856 | } | |
857 | } | |
858 | } | |
859 | break; | |
860 | default: abort(); | |
861 | } | |
862 | ||
863 | /* safety check - might have changed */ | |
864 | if (destmode != Areg && destmode != Dreg && destmode != Aind | |
865 | && destmode != Ad16 && destmode != Ad8r && destmode != Aipi | |
866 | && destmode != Apdi) | |
867 | { | |
868 | dstgather = 0; | |
869 | } | |
870 | ||
871 | if (destmode == Areg && sz == sz_byte) | |
872 | goto nomatch; | |
873 | #if 0 | |
874 | if (sz == sz_byte && (destmode == Aipi || destmode == Apdi)) { | |
875 | dstgather = 0; | |
876 | } | |
877 | #endif | |
878 | endofline: | |
879 | /* now, we have a match */ | |
880 | if (table68k[opc].mnemo != i_ILLG) | |
881 | fprintf(stderr, "Double match: %x: %s\n", opc, opcstr); | |
882 | ||
883 | if (find == -1) | |
884 | { | |
885 | for(find=0; ; find++) | |
886 | { | |
887 | if (strcmp(mnemonic, lookuptab[find].name) == 0) | |
888 | { | |
889 | table68k[opc].mnemo = lookuptab[find].mnemo; | |
890 | break; | |
891 | } | |
892 | ||
893 | if (strlen(lookuptab[find].name) == 0) | |
894 | abort(); | |
895 | } | |
896 | } | |
897 | else | |
898 | { | |
899 | table68k[opc].mnemo = lookuptab[find].mnemo; | |
900 | } | |
901 | ||
902 | table68k[opc].cc = bitval[bitc]; | |
903 | ||
904 | if (table68k[opc].mnemo == i_BTST | |
905 | || table68k[opc].mnemo == i_BSET | |
906 | || table68k[opc].mnemo == i_BCLR | |
907 | || table68k[opc].mnemo == i_BCHG) | |
908 | { | |
909 | sz = (destmode == Dreg ? sz_long : sz_byte); | |
910 | } | |
911 | ||
912 | table68k[opc].size = sz; | |
913 | table68k[opc].sreg = srcreg; | |
914 | table68k[opc].dreg = destreg; | |
915 | table68k[opc].smode = srcmode; | |
916 | table68k[opc].dmode = destmode; | |
917 | table68k[opc].spos = (srcgather ? srcpos : -1); | |
918 | table68k[opc].dpos = (dstgather ? dstpos : -1); | |
919 | table68k[opc].suse = usesrc; | |
920 | table68k[opc].duse = usedst; | |
921 | table68k[opc].stype = srctype; | |
922 | table68k[opc].plev = id.plevel; | |
923 | table68k[opc].clev = id.cpulevel; | |
924 | #if 0 | |
925 | for (i = 0; i < 5; i++) { | |
926 | table68k[opc].flaginfo[i].flagset = id.flaginfo[i].flagset; | |
927 | table68k[opc].flaginfo[i].flaguse = id.flaginfo[i].flaguse; | |
928 | } | |
929 | #endif | |
930 | table68k[opc].flagdead = flagdead; | |
931 | table68k[opc].flaglive = flaglive; | |
932 | table68k[opc].isjmp = isjmp; | |
933 | ||
934 | nomatch: | |
935 | /* FOO! */; | |
936 | } | |
937 | } | |
938 | ||
939 | ||
940 | void read_table68k(void) | |
941 | { | |
942 | int i; | |
943 | table68k = (struct instr *)malloc(65536 * sizeof(struct instr)); | |
944 | ||
945 | for(i=0; i<65536; i++) | |
946 | { | |
947 | table68k[i].mnemo = i_ILLG; | |
948 | table68k[i].handler = -1; | |
949 | } | |
950 | ||
951 | for(i=0; i<n_defs68k; i++) | |
952 | build_insn(i); | |
953 | } | |
954 | ||
955 | ||
956 | static int mismatch; | |
957 | ||
958 | ||
959 | static void handle_merges (long int opcode) | |
960 | { | |
961 | uint16_t smsk; | |
962 | uint16_t dmsk; | |
963 | int sbitdst, dstend; | |
964 | int srcreg, dstreg; | |
965 | ||
966 | //0011 DDDd ddss sSSS:00:-NZ00:-----:12: MOVE.W s,d[!Areg] | |
967 | //31C3 -> | |
968 | //0011 0001 1100 0011 : DDD = 0, ddd = 7, sss = 0, SSS = 3 | |
969 | ||
970 | if (table68k[opcode].spos == -1) | |
971 | { | |
972 | sbitdst = 1; | |
973 | smsk = 0; | |
974 | } | |
975 | else | |
976 | { | |
977 | switch (table68k[opcode].stype) | |
978 | { | |
979 | case 0: | |
980 | smsk = 7; sbitdst = 8; break; | |
981 | case 1: | |
982 | smsk = 255; sbitdst = 256; break; | |
983 | case 2: | |
984 | smsk = 15; sbitdst = 16; break; | |
985 | case 3: | |
986 | smsk = 7; sbitdst = 8; break; | |
987 | case 4: | |
988 | smsk = 7; sbitdst = 8; break; | |
989 | case 5: | |
990 | smsk = 63; sbitdst = 64; break; | |
991 | case 7: | |
992 | smsk = 3; sbitdst = 4; break; | |
993 | default: | |
994 | smsk = 0; sbitdst = 0; | |
995 | abort(); | |
996 | break; | |
997 | } | |
998 | ||
999 | smsk <<= table68k[opcode].spos; | |
1000 | } | |
1001 | ||
1002 | if (table68k[opcode].dpos == -1) | |
1003 | { | |
1004 | dmsk = 0; | |
1005 | dstend = 1; | |
1006 | } | |
1007 | else | |
1008 | { | |
1009 | dmsk = 7 << table68k[opcode].dpos; | |
1010 | dstend = 8; | |
1011 | } | |
1012 | ||
1013 | for(srcreg=0; srcreg<sbitdst; srcreg++) | |
1014 | { | |
1015 | for(dstreg=0; dstreg<dstend; dstreg++) | |
1016 | { | |
1017 | uint16_t code = opcode; | |
1018 | ||
1019 | code = (code & ~smsk) | (srcreg << table68k[opcode].spos); | |
1020 | code = (code & ~dmsk) | (dstreg << table68k[opcode].dpos); | |
1021 | ||
1022 | /* Check whether this is in fact the same instruction. | |
1023 | * The instructions should never differ, except for the | |
1024 | * Bcc.(BW) case. */ | |
1025 | if (table68k[code].mnemo != table68k[opcode].mnemo | |
1026 | || table68k[code].size != table68k[opcode].size | |
1027 | || table68k[code].suse != table68k[opcode].suse | |
1028 | || table68k[code].duse != table68k[opcode].duse) | |
1029 | { | |
1030 | mismatch++; | |
1031 | continue; | |
1032 | } | |
1033 | ||
1034 | if (table68k[opcode].suse | |
1035 | && (table68k[opcode].spos != table68k[code].spos | |
1036 | || table68k[opcode].smode != table68k[code].smode | |
1037 | || table68k[opcode].stype != table68k[code].stype)) | |
1038 | { | |
1039 | mismatch++; | |
1040 | continue; | |
1041 | } | |
1042 | ||
1043 | if (table68k[opcode].duse | |
1044 | && (table68k[opcode].dpos != table68k[code].dpos | |
1045 | || table68k[opcode].dmode != table68k[code].dmode)) | |
1046 | { | |
1047 | mismatch++; | |
1048 | continue; | |
1049 | } | |
1050 | ||
1051 | if (code != opcode) | |
1052 | { | |
1053 | table68k[code].handler = opcode; | |
1054 | ||
1055 | #if 0 | |
1056 | if (opcode == 0x31C3 || code == 0x31C3) | |
1057 | { | |
1058 | printf("Relocate... ($%04X->$%04X)\n", (uint16_t)opcode, code); | |
1059 | printf(" handler: %08X\n", table68k[code].handler); | |
1060 | printf(" dreg: %i\n", table68k[code].dreg); | |
1061 | printf(" sreg: %i\n", table68k[code].sreg); | |
1062 | printf(" dpos: %i\n", table68k[code].dpos); | |
1063 | printf(" spos: %i\n", table68k[code].spos); | |
1064 | printf(" sduse: %i\n", table68k[code].sduse); | |
1065 | printf("flagdead: %i\n", table68k[code].flagdead); | |
1066 | printf("flaglive: %i\n", table68k[code].flaglive); | |
1067 | } | |
1068 | #endif | |
1069 | /* | |
1070 | long int handler; | |
1071 | unsigned char dreg; | |
1072 | unsigned char sreg; | |
1073 | signed char dpos; | |
1074 | signed char spos; | |
1075 | unsigned char sduse; | |
1076 | int flagdead:8, flaglive:8; | |
1077 | unsigned int mnemo:8; | |
1078 | unsigned int cc:4; | |
1079 | unsigned int plev:2; | |
1080 | unsigned int size:2; | |
1081 | unsigned int smode:5; | |
1082 | unsigned int stype:3; | |
1083 | unsigned int dmode:5; | |
1084 | unsigned int suse:1; | |
1085 | unsigned int duse:1; | |
1086 | unsigned int unused1:1; | |
1087 | unsigned int clev:3; | |
1088 | unsigned int isjmp:1; | |
1089 | unsigned int unused2:4; | |
1090 | */ | |
1091 | } | |
1092 | } | |
1093 | } | |
1094 | } | |
1095 | ||
1096 | ||
1097 | // What this really does is expand the # of handlers, which is why the | |
1098 | // opcode has to be passed into the opcode handler... | |
1099 | // E.g., $F620 maps into $F621-F627 as well; this code does this expansion. | |
1100 | void do_merges(void) | |
1101 | { | |
1102 | long int opcode; | |
1103 | int nr = 0; | |
1104 | mismatch = 0; | |
1105 | ||
1106 | for(opcode=0; opcode<65536; opcode++) | |
1107 | { | |
1108 | if (table68k[opcode].handler != -1 || table68k[opcode].mnemo == i_ILLG) | |
1109 | continue; | |
1110 | ||
1111 | nr++; | |
1112 | handle_merges(opcode); | |
1113 | } | |
1114 | ||
1115 | nr_cpuop_funcs = nr; | |
1116 | } | |
1117 | ||
1118 | ||
1119 | int get_no_mismatches(void) | |
1120 | { | |
1121 | return mismatch; | |
1122 | } | |
1123 |