Mercurial > repos > blastem
comparison 68kinst.c @ 1458:b81428ef0396
Fix a bunch of 68K instruction decoder bugs revealed by r57shell/realmonster's test ROM
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Wed, 06 Sep 2017 22:14:51 -0700 |
parents | 696a029d09e9 |
children | d276ec2fff11 |
comparison
equal
deleted
inserted
replaced
1457:bbba92f56f47 | 1458:b81428ef0396 |
---|---|
270 { | 270 { |
271 if (dst->addr_mode == MODE_AREG || dst->addr_mode > MODE_ABSOLUTE) { | 271 if (dst->addr_mode == MODE_AREG || dst->addr_mode > MODE_ABSOLUTE) { |
272 return 0; | 272 return 0; |
273 } | 273 } |
274 return 1; | 274 return 1; |
275 } | |
276 | |
277 uint8_t m68k_valid_movem_dst(m68k_op_info *dst) | |
278 { | |
279 if (dst->addr_mode == MODE_REG || dst->addr_mode == MODE_AREG_POSTINC) { | |
280 return 0; | |
281 } | |
282 return m68k_valid_immed_limited_dst(dst); | |
275 } | 283 } |
276 | 284 |
277 uint16_t *m68k_decode_op(uint16_t *cur, uint8_t size, m68k_op_info *dst) | 285 uint16_t *m68k_decode_op(uint16_t *cur, uint8_t size, m68k_op_info *dst) |
278 { | 286 { |
279 uint8_t mode = (*cur >> 3) & 0x7; | 287 uint8_t mode = (*cur >> 3) & 0x7; |
344 } | 352 } |
345 decoded->src.addr_mode = MODE_REG; | 353 decoded->src.addr_mode = MODE_REG; |
346 decoded->src.params.regs.pri = m68k_reg_quick_field(*istream); | 354 decoded->src.params.regs.pri = m68k_reg_quick_field(*istream); |
347 decoded->extra.size = OPSIZE_BYTE; | 355 decoded->extra.size = OPSIZE_BYTE; |
348 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst)); | 356 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst)); |
349 if (!istream) { | 357 if ( |
358 !istream || decoded->dst.addr_mode == MODE_AREG | |
359 || (decoded->op != M68K_BTST && !m68k_valid_immed_limited_dst(&decoded->dst)) | |
360 ) { | |
350 decoded->op = M68K_INVALID; | 361 decoded->op = M68K_INVALID; |
351 break; | 362 break; |
352 } | 363 } |
353 if (decoded->dst.addr_mode == MODE_REG) { | 364 if (decoded->dst.addr_mode == MODE_REG) { |
354 decoded->extra.size = OPSIZE_LONG; | 365 decoded->extra.size = OPSIZE_LONG; |
374 reg = *istream & 0x7; | 385 reg = *istream & 0x7; |
375 decoded->src.addr_mode = MODE_IMMEDIATE_WORD; | 386 decoded->src.addr_mode = MODE_IMMEDIATE_WORD; |
376 decoded->src.params.immed = *(++istream) & 0xFF; | 387 decoded->src.params.immed = *(++istream) & 0xFF; |
377 decoded->extra.size = OPSIZE_BYTE; | 388 decoded->extra.size = OPSIZE_BYTE; |
378 istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst)); | 389 istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst)); |
379 if (!istream) { | 390 if (!istream || !m68k_valid_immed_dst(&decoded->dst)) { |
380 decoded->op = M68K_INVALID; | 391 decoded->op = M68K_INVALID; |
381 break; | 392 break; |
382 } | 393 } |
383 if (decoded->dst.addr_mode == MODE_REG) { | 394 if (decoded->dst.addr_mode == MODE_REG) { |
384 decoded->extra.size = OPSIZE_LONG; | 395 decoded->extra.size = OPSIZE_LONG; |
519 break; | 530 break; |
520 } | 531 } |
521 break; | 532 break; |
522 case 4: | 533 case 4: |
523 //BTST, BCHG, BCLR, BSET | 534 //BTST, BCHG, BCLR, BSET |
535 //Seems like this should be unnecessary since bit instructions are explicitly handled above | |
536 //Possible this is redundant or the case above is overly restrictive | |
537 //TODO: Investigate whether this can be removed | |
524 switch ((*istream >> 6) & 0x3) | 538 switch ((*istream >> 6) & 0x3) |
525 { | 539 { |
526 case 0: | 540 case 0: |
527 decoded->op = M68K_BTST; | 541 decoded->op = M68K_BTST; |
528 break; | 542 break; |
534 break; | 548 break; |
535 case 3: | 549 case 3: |
536 decoded->op = M68K_BSET; | 550 decoded->op = M68K_BSET; |
537 break; | 551 break; |
538 } | 552 } |
539 decoded->src.addr_mode = MODE_IMMEDIATE; | 553 decoded->src.addr_mode = MODE_IMMEDIATE_WORD; |
540 decoded->src.params.immed = *(++istream) & 0xFF; | 554 decoded->src.params.immed = *(++istream) & 0xFF; |
541 istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst)); | 555 istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst)); |
542 if (!istream) { | 556 if ( |
557 !istream || !m68k_valid_immed_dst(&decoded->dst) | |
558 || (decoded->op != M68K_BTST && !m68k_valid_immed_limited_dst(&decoded->dst)) | |
559 ) { | |
543 decoded->op = M68K_INVALID; | 560 decoded->op = M68K_INVALID; |
544 break; | 561 break; |
545 } | 562 } |
546 break; | 563 break; |
547 case 5: | 564 case 5: |
641 if (!istream) { | 658 if (!istream) { |
642 decoded->op = M68K_INVALID; | 659 decoded->op = M68K_INVALID; |
643 break; | 660 break; |
644 } | 661 } |
645 istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst)); | 662 istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst)); |
646 if (!istream || decoded->dst.addr_mode == MODE_IMMEDIATE) { | 663 if (!istream || decoded->dst.addr_mode > MODE_ABSOLUTE || (decoded->dst.addr_mode == MODE_AREG && optype == MOVE_BYTE)) { |
647 decoded->op = M68K_INVALID; | 664 decoded->op = M68K_INVALID; |
648 break; | 665 break; |
649 } | 666 } |
650 break; | 667 break; |
651 case MISC: | 668 case MISC: |
679 #endif | 696 #endif |
680 } | 697 } |
681 decoded->dst.addr_mode = MODE_REG; | 698 decoded->dst.addr_mode = MODE_REG; |
682 decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); | 699 decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream); |
683 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); | 700 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); |
684 if (!istream) { | 701 if (!istream || decoded->src.addr_mode == MODE_AREG) { |
685 decoded->op = M68K_INVALID; | 702 decoded->op = M68K_INVALID; |
686 break; | 703 break; |
687 } | 704 } |
688 } else { | 705 } else { |
689 opmode = (*istream >> 3) & 0x7; | 706 opmode = (*istream >> 3) & 0x7; |
706 } | 723 } |
707 } else { | 724 } else { |
708 decoded->src.addr_mode = MODE_REG; | 725 decoded->src.addr_mode = MODE_REG; |
709 decoded->src.params.immed = *(++istream); | 726 decoded->src.params.immed = *(++istream); |
710 istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst)); | 727 istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst)); |
711 if (!istream) { | 728 if (!istream || !m68k_valid_movem_dst(&decoded->dst)) { |
712 decoded->op = M68K_INVALID; | 729 decoded->op = M68K_INVALID; |
713 break; | 730 break; |
714 } | 731 } |
715 } | 732 } |
716 } else { | 733 } else { |
726 } else { | 743 } else { |
727 decoded->op = M68K_NEGX; | 744 decoded->op = M68K_NEGX; |
728 } | 745 } |
729 decoded->extra.size = size; | 746 decoded->extra.size = size; |
730 istream= m68k_decode_op(istream, size, &(decoded->dst)); | 747 istream= m68k_decode_op(istream, size, &(decoded->dst)); |
731 if (!istream) { | 748 if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) { |
732 decoded->op = M68K_INVALID; | 749 decoded->op = M68K_INVALID; |
733 break; | 750 break; |
734 } | 751 } |
735 break; | 752 break; |
736 case 1: | 753 case 1: |
745 } else { | 762 } else { |
746 decoded->op = M68K_CLR; | 763 decoded->op = M68K_CLR; |
747 } | 764 } |
748 decoded->extra.size = size; | 765 decoded->extra.size = size; |
749 istream= m68k_decode_op(istream, size, &(decoded->dst)); | 766 istream= m68k_decode_op(istream, size, &(decoded->dst)); |
750 if (!istream) { | 767 if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) { |
751 decoded->op = M68K_INVALID; | 768 decoded->op = M68K_INVALID; |
752 break; | 769 break; |
753 } | 770 } |
754 break; | 771 break; |
755 case 2: | 772 case 2: |
756 //MOVE to CCR or NEG | 773 //MOVE to CCR or NEG |
757 if (size == OPSIZE_INVALID) { | 774 if (size == OPSIZE_INVALID) { |
758 decoded->op = M68K_MOVE_CCR; | 775 decoded->op = M68K_MOVE_CCR; |
759 size = OPSIZE_WORD; | 776 size = OPSIZE_WORD; |
760 istream= m68k_decode_op(istream, size, &(decoded->src)); | 777 istream= m68k_decode_op(istream, size, &(decoded->src)); |
761 if (!istream) { | 778 if (!istream || decoded->src.addr_mode == MODE_AREG) { |
762 decoded->op = M68K_INVALID; | 779 decoded->op = M68K_INVALID; |
763 break; | 780 break; |
764 } | 781 } |
765 } else { | 782 } else { |
766 decoded->op = M68K_NEG; | 783 decoded->op = M68K_NEG; |
767 istream= m68k_decode_op(istream, size, &(decoded->dst)); | 784 istream= m68k_decode_op(istream, size, &(decoded->dst)); |
768 if (!istream) { | 785 if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) { |
769 decoded->op = M68K_INVALID; | 786 decoded->op = M68K_INVALID; |
770 break; | 787 break; |
771 } | 788 } |
772 } | 789 } |
773 decoded->extra.size = size; | 790 decoded->extra.size = size; |
776 //MOVE to SR or NOT | 793 //MOVE to SR or NOT |
777 if (size == OPSIZE_INVALID) { | 794 if (size == OPSIZE_INVALID) { |
778 decoded->op = M68K_MOVE_SR; | 795 decoded->op = M68K_MOVE_SR; |
779 size = OPSIZE_WORD; | 796 size = OPSIZE_WORD; |
780 istream= m68k_decode_op(istream, size, &(decoded->src)); | 797 istream= m68k_decode_op(istream, size, &(decoded->src)); |
781 if (!istream) { | 798 if (!istream || decoded->src.addr_mode == MODE_AREG) { |
782 decoded->op = M68K_INVALID; | 799 decoded->op = M68K_INVALID; |
783 break; | 800 break; |
784 } | 801 } |
785 } else { | 802 } else { |
786 decoded->op = M68K_NOT; | 803 decoded->op = M68K_NOT; |
787 istream= m68k_decode_op(istream, size, &(decoded->dst)); | 804 istream= m68k_decode_op(istream, size, &(decoded->dst)); |
788 if (!istream) { | 805 if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) { |
789 decoded->op = M68K_INVALID; | 806 decoded->op = M68K_INVALID; |
790 break; | 807 break; |
791 } | 808 } |
792 } | 809 } |
793 decoded->extra.size = size; | 810 decoded->extra.size = size; |
838 default: | 855 default: |
839 if (!(*istream & 0x1C0)) { | 856 if (!(*istream & 0x1C0)) { |
840 decoded->op = M68K_NBCD; | 857 decoded->op = M68K_NBCD; |
841 decoded->extra.size = OPSIZE_BYTE; | 858 decoded->extra.size = OPSIZE_BYTE; |
842 istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst)); | 859 istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst)); |
843 if (!istream) { | 860 if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) { |
844 decoded->op = M68K_INVALID; | 861 decoded->op = M68K_INVALID; |
845 break; | 862 break; |
846 } | 863 } |
847 } else if((*istream & 0x1C0) == 0x40) { | 864 } else if((*istream & 0x1C0) == 0x40) { |
848 decoded->op = M68K_PEA; | 865 decoded->op = M68K_PEA; |
882 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); | 899 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); |
883 if (!istream) { | 900 if (!istream) { |
884 decoded->op = M68K_INVALID; | 901 decoded->op = M68K_INVALID; |
885 break; | 902 break; |
886 } | 903 } |
904 #ifndef M68020 | |
905 if (!m68k_valid_immed_limited_dst(&decoded->src)) { | |
906 decoded->op = M68K_INVALID; | |
907 break; | |
908 } | |
909 #endif | |
887 } | 910 } |
888 } | 911 } |
889 break; | 912 break; |
890 case 6: | 913 case 6: |
891 //MULU, MULS, DIVU, DIVUL, DIVS, DIVSL | 914 //MULU, MULS, DIVU, DIVUL, DIVS, DIVSL |