
#include "debug.h"

#define W D7
#define B D6
#define WP A3
#define BP A2

#define XBIT 0x10

#define xor(a,b) (((a) || (b)) && !((a) && (b)))
#define bxor(a,b) (((a) | (b)) & ~((a) & (b)))

#define copy() asm { move SR,bits(A6) } makefl(bits)

#define setxtoc() xbit=(flag(CARRY) ? XBIT : 0); asm { move xbit(A6),CCR }

exec()
{
    extern run,error,mnetab_len;
    extern unsigned regs[];
    extern MNETYPE mnetab[];
    extern *wdest();
    extern short *bdest();
    extern char *mem_base;

    register w,*wp;
    register short b,*bp;
    register unsigned opc;
    int bits,xbit,r;
    short bool;

    opc=fetch();
    error=FALSE;
    for (w=0; w<mnetab_len; w++)
        if (opc == mnetab[w].opc)
            break;
        else if (opc < mnetab[w].opc)
        {
            --w;
            break;
        }
    if (w == mnetab_len)
        --w;
    switch (mnetab[w].mode)
    {
        case NONE:
            if (opc != mnetab[w].opc)
                return 1;
            if (!opc)                               /* halt */
                return 2;
            setfl(opc & 020,opc & 15);              /* sec,clc,etc. */
            break;
        case ONE:
            if (opc&0100000)
                bp=bdest(opc&077);
            else
                wp=wdest(opc&077);
            if (error)
                return error;
            switch (opc&~077)
            {
                case 0005000:                       /* clr */
                    asm
                    {
                        clr (WP)
                    }
                    copy();
                    wshow(wp);
                    break;
                case 0105000:                       /* clrb */
                    asm
                    {
                        clr.b (BP)
                    }
                    copy();
                    bshow(bp);
                    break;
                case 0005100:                       /* com */
                    asm
                    {
                        eori #0xffff,(WP)
                    }
                    copy();
                    setfl(TRUE,CARRY);
                    wshow(wp);
                    break;
                case 0105100:                       /* comb */
                    asm
                    {
                        eori.b #0xff,(BP)
                    }
                    setfl(TRUE,CARRY);
                    bshow(bp);
                    break;
                case 0005200:                       /* inc */
                    bool=flag(CARRY);
                    asm
                    {
                        addq #1,(WP)
                    }
                    copy();
                    setfl(bool,CARRY);
                    wshow(wp);
                    break;
                case 0105200:                       /* incb */
                    bool=flag(CARRY);
                    asm
                    {
                        addq.b #1,(BP)
                    }
                    copy();
                    setfl(bool,CARRY);
                    bshow(bp);
                    break;
                case 0005300:                       /* dec */
                    bool=flag(CARRY);
                    asm
                    {
                        subq #1,(WP)
                    }
                    copy();
                    setfl(bool,CARRY);
                    wshow(wp);
                    break;
                case 0105300:                       /* decb */
                    bool=flag(CARRY);
                    asm
                    {
                        subq.b  #1,(BP)
                    }
                    copy();
                    setfl(bool,CARRY);
                    bshow(bp);
                    break;
                case 0005400:                       /* neg */
                    asm
                    {
                        neg (WP)
                    }
                    copy();
                    setfl(!flag(CARRY),CARRY);
                    wshow(wp);
                    break;
                case 0105400:                       /* negb */
                    asm
                    {
                        neg.b (BP)
                    }
                    copy();
                    setfl(!flag(CARRY),CARRY);
                    bshow(bp);
                    break;
                case 0005500:                       /* adc */
                    setxtoc()
                    asm
                    {
                        move #0,B
                        move (WP),W
                        addx B,W
                    }
                    copy();
                    asm
                    {
                        move W,(WP)
                    }
                    wshow(wp);
                    break;
                case 0105500:                       /* adcb */
                    setxtoc()
                    asm
                    {
                        move.b #0,W
                        move.b (BP),B
                        addx.b W,B
                    }
                    copy();
                    asm
                    {
                        move.b B,(BP)
                    }
                    bshow(bp);
                    break;
                case 0005600:                       /* sbc */
                    setxtoc()
                    asm
                    {
                        move #0,B
                        move (WP),W
                        subx B,W
                    }
                    copy();
                    asm
                    {
                        move W,(WP)
                    }
                    wshow(wp);
                    break;
                case 0105600:                       /* sbcb */
                    setxtoc()
                    asm
                    {
                        move.b #0,W
                        move.b (BP),B
                        subx.b W,B
                    }
                    copy();
                    asm
                    {
                        move.b B,(BP)
                    }
                    bshow(bp);
                    break;
                case 0005700:                       /* tst */
                    asm
                    {
                        tst (WP)
                    }
                    copy();
                    reexch(wp);
                    break;
                case 0105700:                       /* tstb */
                    asm
                    {
                        tst.b (BP)
                    }
                    copy();
                    break;
                case 0006000:                       /* ror */
                    setxtoc()
                    asm
                    {
                        roxr (WP)
                    }
                    copy();
                    setfl(xor(flag(CARRY),flag(NEGA)),OVER);
                    wshow(wp);
                    break;
                case 0106000:                       /* rorb */
                    setxtoc()
                    asm
                    {
                        move.b (BP),B
                        roxr.b #1,B
                    }
                    copy();
                    asm
                    {
                        move.b B,(BP)
                    }
                    setfl(xor(flag(CARRY),flag(NEGA)),OVER);
                    bshow(bp);
                    break;
                case 0006100:                       /* rol */
                    setxtoc()
                    asm
                    {
                        roxl (WP)
                    }
                    copy();
                    setfl(xor(flag(CARRY),flag(NEGA)),OVER);
                    wshow(wp);
                    break;
                case 0106100:                       /* rolb */
                    setxtoc()
                    asm
                    {
                        move.b (BP),B
                        roxl.b #1,B
                    }
                    copy();
                    asm
                    {
                        move.b B,(BP)
                    }
                    setfl(xor(flag(CARRY),flag(NEGA)),OVER);
                    bshow(bp);
                    break;
                case 0006200:                       /* asr */
                    asm
                    {
                        asr (WP)
                    }
                    copy();
                    setfl(xor(flag(CARRY),flag(NEGA)),OVER);
                    wshow(wp);
                    break;
                case 0106200:                       /* asrb */
                    asm
                    {
                        move.b (BP),B
                        asr.b #1,B
                    }
                    copy();
                    asm
                    {
                        move.b B,(BP)
                    }
                    setfl(xor(flag(CARRY),flag(NEGA)),OVER);
                    bshow(bp);
                    break;
                case 0006300:                       /* asl */
                    asm
                    {
                        asl (WP)
                    }
                    copy();
                    wshow(wp);
                    break;
                case 0106300:                       /* aslb */
                    asm
                    {
                        move.b (BP),B
                        asl.b #1,B
                    }
                    copy();
                    asm
                    {
                        move.b B,(BP)
                    }
                    bshow(bp);
                    break;
                case 0000100:                       /* jmp */
                    if (!(opc & 070))
                        return 3;
                    reexch(wp);
                    regs[7]=(int) ((char *)wp - mem_base);
                    break;
                case 0000300:                       /* swab */
                    asm
                    {
                        move (WP),D0
                        ror #8,D0
                        move D0,(WP)
                    }
                    setfl(FALSE,OVER | CARRY);
                    setfl(*wp & 0x80,NEGA);
                    setfl(!(*wp & 0xff),ZERO);
                    wshow(wp);
                    break;
                case 0006700:                       /* sxt */
                    *wp=(flag(NEGA) ? -1 : 0);
                    setfl(!flag(NEGA),ZERO);
                    setfl(FALSE,OVER);
                    wshow(wp);
                    break;
                default:
                    return 1;
            }
            break;
        case TWO:
            if ((opc & 0100000) && (opc & 0070000) != 0060000)
            {
                b=bsource((opc & 07700) >> 6);
                bp=bdest(opc & 077);
            }
            else
            {
                w=wsource((opc & 07700) >> 6);
                wp=wdest(opc & 077);
            }
            if (error)
                return error;
            switch (opc & ~0007777)
            {
                case 0010000:                       /* mov */
                    bool=flag(CARRY);
                    asm
                    {
                        move W,(WP)
                    }
                    copy();
                    setfl(FALSE,OVER);
                    setfl(bool,CARRY);
                    wshow(wp);
                    break;
                case 0110000:                       /* movb */
                    bool=flag(CARRY);
                    if (!(opc & 070))
                        asm
                        {
                            subq.l #1,BP
                            ext.w B
                            move B,(BP)
                        }
                    else
                        asm
                        {
                            move.b B,(BP)
                        }
                    copy();
                    setfl(FALSE,OVER);
                    setfl(bool,CARRY);
                    bshow(bp);
                    break;
                case 0020000:                       /* cmp */
                    asm
                    {
                        cmp (WP),W
                    }
                    copy();
                    reexch(wp);
                    break;
                case 0120000:                       /* cmpb */
                    asm
                    {
                        cmp.b (BP),B
                    }
                    copy();
                    break;
                case 0030000:                       /* bit */
                    bool=flag(CARRY);
                    asm
                    {
                        and (WP),W
                    }
                    copy();
                    setfl(bool,CARRY);
                    reexch(wp);
                    break;
                case 0130000:                       /* bitb */
                    bool=flag(CARRY);
                    asm
                    {
                        and.b (BP),B
                    }
                    copy();
                    setfl(bool,CARRY);
                    break;
                case 0040000:                       /* bic */
                    bool=flag(CARRY);
                    asm
                    {
                        eori #0xffff,W
                        and W,(WP)
                    }
                    copy();
                    setfl(bool,CARRY);
                    wshow(wp);
                    break;
                case 0140000:                       /* bicb */
                    bool=flag(CARRY);
                    asm
                    {
                        eori.b #0xff,B
                        and.b B,(BP)
                    }
                    copy();
                    setfl(bool,CARRY);
                    bshow(bp);
                    break;
                case 0050000:                       /* bis */
                    bool=flag(CARRY);
                    asm
                    {
                        or W,(WP)
                    }
                    copy();
                    setfl(bool,CARRY);
                    wshow(wp);
                    break;
                case 0150000:                       /* bisb */
                    bool=flag(CARRY);
                    asm
                    {
                        or.b B,(BP)
                    }
                    copy();
                    setfl(bool,CARRY);
                    bshow(bp);
                    break;
                case 0060000:                       /* add */
                    asm
                    {
                        add W,(WP)
                    }
                    copy();
                    wshow(wp);
                    break;
                case 0160000:                       /* sub */
                    asm
                    {
                        sub W,(WP)
                    }
                    copy();
                    wshow(wp);
                    break;
                default:
                    return 1;
            }
            break;
        case REG1ST:
            wp=wdest(opc & 077);
            if (error)
                return error;
            r=(opc & 0700) >> 6;
            switch (opc &~0777)
            {
                case 0004000:                       /* jsr */
                    if (!(opc & 070))
                        return 3;
                    reexch(wp);
                    regs[6]-=2;
                    putword(regs[6],regs[r]);
                    if (!run)
                        printf("%06o- %06o\n",regs[6],swap(*(int *)
((long)mem_base + regs[6])));
                    regs[r]=regs[7];
                    regs[7]=(int) ((char *)wp - mem_base);
                    break;
                case 0074000:                       /* xor */
                    bool=flag(CARRY);
                    w=regs[r];
                    asm
                    {
                        eor W,(WP)
                    }
                    copy();
                    setfl(bool,CARRY);
                    wshow(wp);
                    break;
                default:
                    return 1;
            }
            break;
        case REG2ND:
            r=(opc & 0700) >> 6;
            wp=wdest(r);
            w=wsource(opc & 077);
            if (error)
                return error;
            switch (opc & ~0777)
            {
                case 0070000:                       /* mul */
                    asm
                    {
                        muls (WP),W
                    }
                    copy();
                    if (r & 1)
                        asm
                        {
                            move W,(WP)
                        }
                    else
                        asm
                        {
                            move.l W,(WP)
                        } 
                    asm
                    {
                        cmpi.l #0x7fff,W
                        bgt setc1
                        cmpi.l #-0x8000,W
                        blt setc1
                        clr.b bool(A6)
                        bra end1
                 setc1: move.b #TRUE,bool(A6)
                  end1:
                    }
                    setfl(bool,CARRY);
                    break;
                case 0071000:                       /* div */
                    if (r & 1)
                        return 6;
                    if (!w)
                        setfl(TRUE,OVER | CARRY);
                    else
                    {
                        asm
                        {
                            move.l (WP),B
                            divs W,B
                        }
                        copy();
                        asm
                        {
                            swap B
                            move.l B,(WP)
                        }
                    }
                    break;
                case 0072000:                       /* ash */
                    if (w & 040)
                    {
                        asm
                        {
                            ori #0xffc0,W
                            neg W
                            move (WP),B
                            asr W,B
                        }
                        copy();
                        asm
                        {
                            move B,(WP)
                        }
                    }
                    else
                    {
                        asm
                        {
                            andi #0x3f,W
                            move (WP),B
                            asl W,B
                        }
                        copy();
                        asm
                        {
                            move B,(WP)
                        }
                    }
                    break;
                case 0073000:                       /* ashc */
                    if (w & 040)
                    {
                        asm
                        {
                            ori #0xffc0,W
                            neg W
                        }
                        if (r & 1)
                        {
                            asm
                            {
                                move (WP),B
                                smi bool(A6)
                                ror W,B
                            }
                            copy();
                            setfl(xor(bool,flag(NEGA)),OVER);
                            asm
                            {
                                move B,(WP)
                            }
                        }
                        else
                        {
                            asm
                            {
                                move.l (WP),B
                                asr.l W,B
                            }
                            copy();
                            asm
                            {
                                move.l B,(WP)
                            }
                        }

                    }
                    else
                    {
                        asm
                        {
                            andi #0x3f,W
                        }
                        if (r & 1)
                        {
                            asm
                            {
                                move (WP),B
                                asl W,B
                            }
                            copy();
                            asm
                            {
                                move B,(WP)
                            }
                        }
                        else
                        {
                            asm
                            {
                                move.l (WP),B
                                asl.l W,B
                            }
                            copy();
                            asm
                            {
                                move.l B,(WP)
                            }
                        }
                    }
                    break;
                default:
                    return 1;
            }
            break;
        case REGONLY:                               /* rts */
            if ((opc&~7) != 0000200)
                return 1;
            r=(opc & 7);
            regs[7]=regs[r];
            regs[r]=word(regs[6]);
            regs[6]+=2;
            break;
        case BRANCH:
            switch (opc & ~0xff)
            {
                case 0000400:                       /* br */
                    bool=TRUE;
                    break;
                case 0001000:                       /* bne */
                    bool=!flag(ZERO);
                    break;
                case 0001400:                       /* beq */
                    bool=flag(ZERO);
                    break;
                case 0100000:                       /* bpl */
                    bool=!flag(NEGA);
                    break;
                case 0100400:                       /* bmi */
                    bool=flag(NEGA);
                    break;
                case 0102000:                       /* bvc */
                    bool=!flag(OVER);
                    break;
                case 0102400:                       /* bvs */
                    bool=flag(OVER);
                    break;
                case 0103000:                       /* bcc */
                    bool=!flag(CARRY);
                    break;
                case 0103400:                       /* bcs */
                    bool=flag(CARRY);
                    break;
                case 0002000:                       /* bge */
                    bool=!(xor(flag(NEGA),flag(OVER)));
                    break;
                case 0002400:                       /* blt */
                    bool=xor(flag(NEGA),flag(OVER));
                    break;
                case 003000:                        /* bgt */
                    bool=!(flag(ZERO) || xor(flag(NEGA),flag(OVER)));
                    break;
                case 003400:                        /* ble */
                    bool=flag(ZERO) || xor(flag(NEGA),flag(OVER));
                    break;
                case 0101000:                       /* bhi */
                    bool=!(flag(ZERO) || flag(CARRY));
                    break;
                case 0101400:                       /* blos */
                    bool=flag(ZERO) || flag(CARRY);
                    break;
                default:
                    return 1;
            }
            if (bool)
                regs[7]+= 2 * (short) (opc & 0xff);
            break;
        case SOB:                                   /* sob */
            if ((opc&~0777) != 0077000)
                return 1;
            r=(opc & 0700) >> 6;
            regs[r]--;
            if (regs[r])
                regs[7]-= 2 * (opc & 077);
            break;
    }
    return FALSE;
}

