#include <nds.h>
#include "bang.h"
#include "core.h"
#include "debug.h"


void reset_br(Bedrock *br) {
    *br = (Bedrock) {0};
}

// Load a program into an instance.
void start_br(Bedrock *br, u8 program[], int size) {
    reset_br(br);
    memcpy(&br->prg.mem, program, size);
    br->alive = TRUE;
    br->awake = TRUE;
    // br->scr.nds = &scr_main;
}

void run_br(Bedrock *br) {
    if (br->awake) {
        switch (evaluate(br, 1000)) {
        case SIG_HALT:   br->alive = FALSE; black_screen(br->scr.nds); br = NULL; return;
        case SIG_SLEEP:  br->awake = FALSE;            return;
        case SIG_DB1:     debug_stacks(br);            return;
        case SIG_DB4:     debug_assert(br);            return;
        default:                                       return;
        }
    }
}

void rouse_br(Bedrock *br) {
    if (TEST(br->sys.sleep, 0x8000)) {  // SYSTEM
        br->awake = TRUE;
        br->sys.wake = 0x0;
        return;
    }
    if (TEST(br->sys.sleep, 0x0800)) {  // INPUT
        if (br->inp.wake) {
            br->inp.wake = FALSE;
            br->awake = TRUE;
            br->sys.wake = 0x4;
            return;
        }
    }
    if (TEST(br->sys.sleep, 0x1000)) {  // CLOCK
        if (check_timers(&br->clk)) {
            br->awake = TRUE;
            br->sys.wake = 0x3;
            return;
        }
    }
}

u8 dev_read(Bedrock *br, u8 port) {
    switch(port) {
// SYSTEM DEVICE
    // TODO: name and author
    case 0x00: return rb_read(&br->sys.name);
    case 0x01: return rb_read(&br->sys.authors);
    case 0x02: return 0x00;              // program memory size
    case 0x03: return 0x00;              // program memory size
    case 0x04: return 0x00;              // working stack size
    case 0x05: return 0x00;              // return stack size
    case 0x06: return devices_high();
    case 0x07: return devices_low();
    case 0x0A: return br->sys.wake;
// MEMORY DEVICE
    case 0x10: return mem_read1(&br->mem);
    case 0x11: return mem_read1(&br->mem);
    case 0x12: return HIGH(br->mem.offset1);
    case 0x13: return  LOW(br->mem.offset1);
    case 0x14: return      br->mem.page1;
    case 0x15: return      br->mem.byte1;
    case 0x16: return HIGH(br->mem.count);
    case 0x17: return  LOW(br->mem.count);
    case 0x18: return mem_read2(&br->mem);
    case 0x19: return mem_read2(&br->mem);
    case 0x1A: return HIGH(br->mem.offset2);
    case 0x1B: return  LOW(br->mem.offset2);
    case 0x1C: return      br->mem.page2;
    case 0x1D: return      br->mem.byte2;
// MATH DEVICE
    case 0x20: return HIGH(br->math.op1);
    case 0x21: return  LOW(br->math.op1);
    case 0x22: return HIGH(br->math.op2);
    case 0x23: return  LOW(br->math.op2);
    case 0x24: return HIGH(get_sqrt(&br->math));
    case 0x25: return  LOW(get_sqrt(&br->math));
    case 0x26: return HIGH(get_atan(&br->math));
    case 0x27: return  LOW(get_atan(&br->math));
    case 0x28: return H_HIGH(get_prod(&br->math));
    case 0x29: return  H_LOW(get_prod(&br->math));
    case 0x2A: return L_HIGH(get_prod(&br->math));
    case 0x2B: return  L_LOW(get_prod(&br->math));
    case 0x2C: return HIGH(get_quot(&br->math));
    case 0x2D: return  LOW(get_quot(&br->math));
    case 0x2E: return HIGH( get_rem(&br->math));
    case 0x2F: return  LOW( get_rem(&br->math));
// CLOCK DEVICE
    case 0x30: return   YEAR(get_datetime());
    case 0x31: return  MONTH(get_datetime());
    case 0x32: return    DAY(get_datetime());
    case 0x33: return   HOUR(get_datetime());
    case 0x34: return MINUTE(get_datetime());
    case 0x35: return SECOND(get_datetime());
    case 0x36: return HIGH(get_uptime()-br->clk.start);
    case 0x37: return  LOW(get_uptime()-br->clk.start);
    case 0x38: return get_timer_high(&br->clk.t1);
    case 0x39: return get_timer_low( &br->clk.t1);
    case 0x3A: return get_timer_high(&br->clk.t2);
    case 0x3B: return get_timer_low( &br->clk.t2);
    case 0x3C: return get_timer_high(&br->clk.t3);
    case 0x3D: return get_timer_low( &br->clk.t3);
    case 0x3E: return get_timer_high(&br->clk.t4);
    case 0x3F: return get_timer_low( &br->clk.t4);
// INPUT DEVICE
    case 0x40: return BOOL(br->inp.pointer);
    case 0x41: return br->inp.pointer << 7;
    case 0x44: return HIGH(br->inp.x);
    case 0x45: return  LOW(br->inp.x);
    case 0x46: return HIGH(br->inp.y);
    case 0x47: return  LOW(br->inp.y);
    case 0x48: return BOOL(br->inp.keyboard);
    // TODO: Keyboard input
    case 0x4A: return br->inp.navigation;
    case 0x4C: return br->inp.gamepad;
// SCREEN DEVICE
    case 0x50: return HIGH(PIXELS_WIDTH);
    case 0x51: return  LOW(PIXELS_WIDTH);
    case 0x52: return HIGH(PIXELS_HEIGHT);
    case 0x53: return  LOW(PIXELS_HEIGHT);
    case 0x54: return HIGH(br->scr.x);
    case 0x55: return  LOW(br->scr.x);
    case 0x56: return HIGH(br->scr.y);
    case 0x57: return  LOW(br->scr.y);
// FILE DEVICE
    case 0xA0: return BOOL(br->fs.open);
    case 0xA1: return BOOL(br->fs.success);
    case 0xA2: return pb_read(&br->fs.path);
    case 0xA3: return BOOL(br->fs.is_dir);
    case 0xA4: return fs_read_byte(&br->fs);
    case 0xA5: return fs_read_byte(&br->fs);
    case 0xA6: return pb_read(&br->fs.child_path);
    case 0xA7: return BOOL(br->fs.child_is_dir);
    case 0xA8: return H_HIGH(br->fs.pointer);
    case 0xA9: return  H_LOW(br->fs.pointer);
    case 0xAA: return L_HIGH(br->fs.pointer);
    case 0xAB: return  L_LOW(br->fs.pointer);
    case 0xAC: return H_HIGH(br->fs.length);
    case 0xAD: return  H_LOW(br->fs.length);
    case 0xAE: return L_HIGH(br->fs.length);
    case 0xAF: return  L_LOW(br->fs.length);

    default: return 0;
    }
}

Signal dev_write(Bedrock *br, u8 port, u8 v) {
    switch(port) {
// SYSTEM DEVICE
    case 0x00: rb_reset(&br->sys.name);                  return 0;
    case 0x01: rb_reset(&br->sys.authors);               return 0;
    case 0x08: SET_HIGH(br->sys.sleep,v);                return 0;
    case 0x09:  SET_LOW(br->sys.sleep,v);        return SIG_SLEEP;
// MEMORY DEVICE
    case 0x10: mem_write1(&br->mem,v);                                  return 0;
    case 0x11: mem_write1(&br->mem,v);                                  return 0;
    case 0x12: SET_HIGH(br->mem.offset1,v); mem_load_cache1(&br->mem);  return 0;
    case 0x13:  SET_LOW(br->mem.offset1,v); mem_load_cache1(&br->mem);  return 0;
    case 0x14: br->mem.page1=v; mem_get_page1(&br->mem);                return 0;
    case 0x15: br->mem.byte1=v;                                         return 0;
    case 0x16: SET_HIGH(br->mem.count_write,v);                         return 0;
    case 0x17:  SET_LOW(br->mem.count_write,v); mem_allocate(&br->mem); return 0;
    case 0x18: mem_write2(&br->mem,v);                                  return 0;
    case 0x19: mem_write2(&br->mem,v);                                  return 0;
    case 0x1A: SET_HIGH(br->mem.offset2,v); mem_load_cache2(&br->mem);  return 0;
    case 0x1B:  SET_LOW(br->mem.offset2,v); mem_load_cache2(&br->mem);  return 0;
    case 0x1C: br->mem.page2=v; mem_get_page2(&br->mem);                return 0;
    case 0x1D: br->mem.byte2=v;                                         return 0;
    case 0x1E: SET_HIGH(br->mem.copy_write,v);                          return 0;
    case 0x1F:  SET_LOW(br->mem.copy_write,v); mem_do_copy(&br->mem);   return 0;
// MATH DEVICE
    case 0x20: set_op1_high(&br->math,v);          return 0;
    case 0x21: set_op1_low( &br->math,v);          return 0;
    case 0x22: set_op2_high(&br->math,v);          return 0;
    case 0x23: set_op2_low( &br->math,v);          return 0;
// CLOCK DEVICE
    // TODO: Set time and date
    case 0x38: set_timer_high(&br->clk.t1,v);      return 0;
    case 0x39: set_timer_low( &br->clk.t1,v);      return 0;
    case 0x3A: set_timer_high(&br->clk.t2,v);      return 0;
    case 0x3B: set_timer_low( &br->clk.t2,v);      return 0;
    case 0x3C: set_timer_high(&br->clk.t3,v);      return 0;
    case 0x3D: set_timer_low( &br->clk.t3,v);      return 0;
    case 0x3E: set_timer_high(&br->clk.t4,v);      return 0;
    case 0x3F: set_timer_low( &br->clk.t4,v);      return 0;
// SCREEN DEVICE
    case 0x54: SET_HIGH(br->scr.x,v);              return 0;
    case 0x55: SET_LOW( br->scr.x,v);              return 0;
    case 0x56: SET_HIGH(br->scr.y,v);              return 0;
    case 0x57: SET_LOW( br->scr.y,v);              return 0;
    case 0x58: set_palette_high(&br->scr,v);       return 0;
    case 0x59: set_palette_low( &br->scr,v);       return 0;
    case 0x5A: SET_HIGH(br->scr.colours,v);        return 0;
    case 0x5B: SET_LOW( br->scr.colours,v);        return 0;
    case 0x5C: push_sprite(&br->scr.sprite,v);     return 0;
    case 0x5D: push_sprite(&br->scr.sprite,v);     return 0;
    case 0x5E: draw_dispatch(&br->scr,v);          return 0;
    case 0x5F: move_cursor(&br->scr,v);            return 0;
// LOCAL DEVICE
    case 0x86: printf("%c", v);                    return 0;
    case 0x87: printf("%c", v);                    return 0;
// FILE DEVICE
    case 0xA0: fs_push_entry(&br->fs,v);                              return 0;
    case 0xA1: fs_push_action(&br->fs,v);                             return 0;
    case 0xA2: pb_reset(&br->fs.path,v);                              return 0;
    case 0xA3: fs_ascend(&br->fs);                                    return 0;
    case 0xA4: fs_write_byte(&br->fs,v);                              return 0;
    case 0xA5: fs_write_byte(&br->fs,v);                              return 0;
    case 0xA6: pb_reset(&br->fs.child_path,v);                        return 0;
    case 0xA7: fs_descend(&br->fs);                                   return 0;
    case 0xA8: SET_H_HIGH(br->fs.pointer_write,v);                    return 0;
    case 0xA9:  SET_H_LOW(br->fs.pointer_write,v);                    return 0;
    case 0xAA: SET_L_HIGH(br->fs.pointer_write,v);                    return 0;
    case 0xAB:  SET_L_LOW(br->fs.pointer_write,v); fs_seek(&br->fs);  return 0;
    case 0xAC: SET_H_HIGH(br->fs.length_write,v);                     return 0;
    case 0xAD:  SET_H_LOW(br->fs.length_write,v);                     return 0;
    case 0xAE: SET_L_HIGH(br->fs.length_write,v);                     return 0;
    case 0xAF:  SET_L_LOW(br->fs.length_write,v); fs_resize(&br->fs); return 0;

    default: return SIG_NONE;
    }
}

Signal dev_write_16(Bedrock *br, u8 port, u8 high, u8 low) {
    Signal s1 = dev_write(br, port, high);
    Signal s2 = dev_write(br, port+1, low);
    if (s1) { return s1; } else { return s2; }
}

Signal evaluate(Bedrock *br, u16 count) {
    #define SIGNAL(s) if (s) { return s; } else { continue; };

    register u8  a, b, c, d, e, f;
    register u16 x, y;
    register Signal sig;

    for (u16 i=0; i < count; i++) {
    switch (MLIT) {
/* HLT    */ case 0x00:                                                                        return SIG_HALT;
/* JMP    */ case 0x01: WPOP2(a,b); PC=DOUBLE(a,b);                                                   continue;
/* JCN    */ case 0x02: WPOP2(b,c); WPOP1(a); if(a) PC=DOUBLE(b,c);                                   continue;
/* JCK    */ case 0x03: WPOP2(b,c); WGET1(a); if(a) PC=DOUBLE(b,c);                                   continue;
/* LDA    */ case 0x04: WPOP2(a,b); x=DOUBLE(a,b); WPSH1(MEM[x]);                                     continue;
/* STA    */ case 0x05: WPOPD(x); WPOP1(a); MEM[x]=a;                                                 continue;
/* LDD    */ case 0x06: WPOP1(a); WPSH1(dev_read(br,a));                                              continue;
/* STD    */ case 0x07: WPOP1(b); WPOP1(a); sig=dev_write(br,b,a);                                 SIGNAL(sig);
/* PSH    */ case 0x08: RPOP1(a); WPSH1(a);                                                           continue;
/* POP    */ case 0x09: WST.p-=1;                                                                     continue;
/* CPY    */ case 0x0A: RGET1(a); WPSH1(a);                                                           continue;
/* SPL    */ case 0x0B: WPOP1(a); WPSH2(LEFT(a),RIGHT(a));                                            continue;
/* DUP    */ case 0x0C: WGET1(a); WPSH1(a);                                                           continue;
/* OVR    */ case 0x0D: WPOP1(b); WGET1(a); WPSH1(b); WPSH1(a);                                       continue;
/* SWP    */ case 0x0E: WPOP1(b); WPOP1(a); WPSH1(b); WPSH1(a);                                       continue;
/* ROT    */ case 0x0F: WPOP1(c); WPOP1(b); WPOP1(a); WPSH1(b); WPSH1(c); WPSH1(a);                   continue;
/* ADD    */ case 0x10: WPOP1(b); WSTV(-1)+=b;                                                        continue;
/* SUB    */ case 0x11: WPOP1(b); WSTV(-1)-=b;                                                        continue;
/* INC    */ case 0x12: WSTV(-1)+=1;                                                                  continue;
/* DEC    */ case 0x13: WSTV(-1)-=1;                                                                  continue;
/* LTH    */ case 0x14: WPOP1(b); WPOP1(a); WPSH1(BOOL(a<b));                                         continue;
/* GTH    */ case 0x15: WPOP1(b); WPOP1(a); WPSH1(BOOL(a>b));                                         continue;
/* EQU    */ case 0x16: WPOP1(b); WPOP1(a); WPSH1(BOOL(a==b));                                        continue;
/* NQK    */ case 0x17: b=WSTV(-1); a=WSTV(-2); WPSH1(BOOL(a!=b));                                    continue;
/* IOR    */ case 0x18: WPOP1(b); WSTV(-1)|=b;                                                        continue;
/* XOR    */ case 0x19: WPOP1(b); WSTV(-1)^=b;                                                        continue;
/* AND    */ case 0x1A: WPOP1(b); WSTV(-1)&=b;                                                        continue;
/* NOT    */ case 0x1B: WSTV(-1)=~WSTV(-1);                                                           continue;
/* SHF    */ case 0x1C: WPOP1(b); WPOP1(a); x=SHF(a,b); WPSH1(x);                                     continue;
/* SHC    */ case 0x1D: WPOP1(b); WPOP1(a); x=shc(a,b); WPSH1(x);                                     continue;
/* TAL    */ case 0x1E: WSTV(-1)=TAL(WSTV(-1));                                                       continue;
/* REV    */ case 0x1F: WSTV(-1)=rev(WSTV(-1));                                                       continue;

/* NOP    */ case 0x20:                                                                               continue;
/* JMS    */ case 0x21: WPOP2(a,b); RPSHD(PC); PC=DOUBLE(a,b);                                        continue;
/* JCS    */ case 0x22: WPOP2(b,c); WPOP1(a); if(a) {RPSHD(PC); PC=DOUBLE(b,c);}                      continue;
/* JCK*   */ case 0x23: WPOP2(c,d); WGETD(x); if(x) {PC=DOUBLE(c,d);}                                 continue;
/* LDA*   */ case 0x24: WPOP2(a,b); x=DOUBLE(a,b); WPSH1(MEM[x]); WPSH1(MEM[x+1]);                    continue;
/* STA*   */ case 0x25: WPOPD(x); WPOP2(a,b); MEM[x]=a; MEM[x+1]=b;                                   continue;
/* LDD*   */ case 0x26: WPOP1(a); WPSH1(dev_read(br,a)); WPSH1(dev_read(br,a+1));                     continue;
/* STD*   */ case 0x27: WPOP1(c); WPOP2(a,b); sig=dev_write_16(br,c,a,b);                          SIGNAL(sig);
/* PSH*   */ case 0x28: RPOP2(a,b); WPSH2(a,b);                                                       continue;
/* POP*   */ case 0x29: WST.p-=2;                                                                     continue;
/* CPY*   */ case 0x2A: RGET2(a,b); WPSH2(a,b);                                                       continue;
/* SPL*   */ case 0x2B: WPOP2(a,b); WPSH2(LEFT(a),RIGHT(a)); WPSH2(LEFT(b),RIGHT(b));                 continue;
/* DUP*   */ case 0x2C: WGET2(a,b); WPSH2(a,b);                                                       continue;
/* OVR*   */ case 0x2D: WPOP2(c,d); WGET2(a,b); WPSH2(c,d); WPSH2(a,b);                               continue;
/* SWP*   */ case 0x2E: WPOP2(c,d); WPOP2(a,b); WPSH2(c,d); WPSH2(a,b);                               continue;
/* ROT*   */ case 0x2F: WPOP2(e,f); WPOP2(c,d); WPOP2(a,b); WPSH2(c,d); WPSH2(e,f); WPSH2(a,b);       continue;
/* ADD*   */ case 0x30: WPOPD(y); WPOPD(x); WPSHD(x+y);                                               continue;
/* SUB*   */ case 0x31: WPOPD(y); WPOPD(x); WPSHD(x-y);                                               continue;
/* INC*   */ case 0x32: WPOPD(x); WPSHD(x+1);                                                         continue;
/* DEC*   */ case 0x33: WPOPD(x); WPSHD(x-1);                                                         continue;
/* LTH*   */ case 0x34: WPOPD(y); WPOPD(x); WPSH1(BOOL(x<y));                                         continue;
/* GTH*   */ case 0x35: WPOPD(y); WPOPD(x); WPSH1(BOOL(x>y));                                         continue;
/* EQU*   */ case 0x36: WPOP2(c,d); WPOP2(a,b); WPSH1(BOOL(a==c && b==d));                            continue;
/* NQK*   */ case 0x37: d=WSTV(-1); c=WSTV(-2); b=WSTV(-3); a=WSTV(-4); WPSH1(BOOL(a!=c || b!=d));    continue;
/* IOR*   */ case 0x38: WPOP2(c,d); WSTV(-1)|=d; WSTV(-2)|=c;                                         continue;
/* XOR*   */ case 0x39: WPOP2(c,d); WSTV(-1)^=d; WSTV(-2)^=c;                                         continue;
/* AND*   */ case 0x3A: WPOP2(c,d); WSTV(-1)&=d; WSTV(-2)&=c;                                         continue;
/* NOT*   */ case 0x3B: WSTV(-1)=~WSTV(-1); WSTV(-2)=~WSTV(-2);                                       continue;
/* SHF*   */ case 0x3C: WPOP1(c); WPOPD(x); x=SHF(x,c); WPSHD(x);                                     continue;
/* SHC*   */ case 0x3D: WPOP1(c); WPOPD(x); x=shcd(x,c); WPSHD(x);                                    continue;
/* TAL*   */ case 0x3E: WPOP2(a,b); WPSH1(TAL(a)+TAL(b));                                             continue;
/* REV*   */ case 0x3F: WPOP2(a,b); WPSH1(rev(b)); WPSH1(rev(a));                                     continue;

/* DB1    */ case 0x40:                                                                         return SIG_DB1;
/* JMP:   */ case 0x41: MLIT2(a,b); PC=DOUBLE(a,b);                                                   continue;
/* JCN:   */ case 0x42: MLIT2(b,c); WPOP1(a); if(a) PC=DOUBLE(b,c);                                   continue;
/* JCK:   */ case 0x43: MLIT2(b,c); WGET1(a); if(a) PC=DOUBLE(b,c);                                   continue;
/* LDA:   */ case 0x44: MLIT2(a,b); x=DOUBLE(a,b); WPSH1(MEM[x]);                                     continue;
/* STA:   */ case 0x45: MLITD(x); WPOP1(a); MEM[x]=a;                                                 continue;
/* LDD:   */ case 0x46: MLIT1(a); WPSH1(dev_read(br,a));                                              continue;
/* STD:   */ case 0x47: MLIT1(b); WPOP1(a); sig=dev_write(br,b,a);                                 SIGNAL(sig);
/* PSH:   */ case 0x48: MLIT1(a); WPSH1(a);                                                           continue;
/* POP:   */ case 0x49: PC+=1;                                                                        continue;
/* CPY:   */ case 0x4A: MLIT1(a); RPSH1(a); WPSH1(a);                                                 continue;
/* SPL:   */ case 0x4B: MLIT1(a); WPSH2(LEFT(a),RIGHT(a));                                            continue;
/* DUP:   */ case 0x4C: MLIT1(a); WPSH1(a); WPSH1(a);                                                 continue;
/* OVR:   */ case 0x4D: MLIT1(b); WGET1(a); WPSH1(b); WPSH1(a);                                       continue;
/* SWP:   */ case 0x4E: MLIT1(b); WPOP1(a); WPSH1(b); WPSH1(a);                                       continue;
/* ROT:   */ case 0x4F: MLIT1(c); WPOP1(b); WPOP1(a); WPSH1(b); WPSH1(c); WPSH1(a);                   continue;
/* ADD:   */ case 0x50: MLIT1(b); WSTV(-1)+=b;                                                        continue;
/* SUB:   */ case 0x51: MLIT1(b); WSTV(-1)-=b;                                                        continue;
/* INC:   */ case 0x52: MLIT1(a); WPSH1(a+1);                                                         continue;
/* DEC:   */ case 0x53: MLIT1(a); WPSH1(a-1);                                                         continue;
/* LTH:   */ case 0x54: MLIT1(b); WPOP1(a); WPSH1(BOOL(a<b));                                         continue;
/* GTH:   */ case 0x55: MLIT1(b); WPOP1(a); WPSH1(BOOL(a>b));                                         continue;
/* EQU:   */ case 0x56: MLIT1(b); WPOP1(a); WPSH1(BOOL(a==b));                                        continue;
/* NQK:   */ case 0x57: MLIT1(b); WGET1(a); WPSH1(b); WPSH1(BOOL(a!=b));                              continue;
/* IOR:   */ case 0x58: MLIT1(b); WSTV(-1)|=b;                                                        continue;
/* XOR:   */ case 0x59: MLIT1(b); WSTV(-1)^=b;                                                        continue;
/* AND:   */ case 0x5A: MLIT1(b); WSTV(-1)&=b;                                                        continue;
/* NOT:   */ case 0x5B: MLIT1(a); WPSH1(~a);                                                          continue;
/* SHF:   */ case 0x5C: MLIT1(b); WPOP1(a); x=SHF(a,b); WPSH1(x);                                     continue;
/* SHC:   */ case 0x5D: MLIT1(b); WPOP1(a); x=shc(a,b); WPSH1(x);                                     continue;
/* TAL:   */ case 0x5E: MLIT1(a); WPSH1(TAL(a));                                                      continue;
/* REV:   */ case 0x5F: MLIT1(a); WPSH1(rev(a));                                                      continue;

/* DB2    */ case 0x60:                                                                         return SIG_DB2;
/* JMS:   */ case 0x61: MLIT2(a,b); RPSHD(PC); PC=DOUBLE(a,b);                                        continue;
/* JCS:   */ case 0x62: MLIT2(b,c); WPOP1(a); if(a) {RPSHD(PC); PC=DOUBLE(b,c);}                      continue;
/* JCK:*  */ case 0x63: MLIT2(c,d); WGETD(x); if(x) {PC=DOUBLE(c,d);}                                 continue;
/* LDA:*  */ case 0x64: MLIT2(a,b); x=DOUBLE(a,b); WPSH1(MEM[x]); WPSH1(MEM[x+1]);                    continue;
/* STA:*  */ case 0x65: MLITD(x); WPOP2(a,b); MEM[x]=a; MEM[x+1]=b;                                   continue;
/* LDD:*  */ case 0x66: MLIT1(a); WPSH1(dev_read(br,a)); WPSH1(dev_read(br,a+1));                     continue;
/* STD:*  */ case 0x67: MLIT1(c); WPOP2(a,b); sig=dev_write_16(br,c,a,b);                          SIGNAL(sig);
/* PSH:*  */ case 0x68: MLIT2(a,b); WPSH2(a,b);                                                       continue;
/* POP:*  */ case 0x69: PC+=2;                                                                        continue;
/* CPY:*  */ case 0x6A: MLIT2(a,b); RPSH2(a,b); WPSH2(a,b);                                           continue;
/* SPL:*  */ case 0x6B: MLIT2(a,b); WPSH2(LEFT(a),RIGHT(a)); WPSH2(LEFT(b),RIGHT(b));                 continue;
/* DUP:*  */ case 0x6C: MLIT2(a,b); WPSH2(a,b); WPSH2(a,b);                                           continue;
/* OVR:*  */ case 0x6D: MLIT2(c,d); WGET2(a,b); WPSH2(c,d); WPSH2(a,b);                               continue;
/* SWP:*  */ case 0x6E: MLIT2(c,d); WPOP2(a,b); WPSH2(c,d); WPSH2(a,b);                               continue;
/* ROT:*  */ case 0x6F: MLIT2(e,f); WPOP2(c,d); WPOP2(a,b); WPSH2(c,d); WPSH2(e,f); WPSH2(a,b);       continue;
/* ADD:*  */ case 0x70: MLITD(y); WPOPD(x); WPSHD(x+y);                                               continue;
/* SUB:*  */ case 0x71: MLITD(y); WPOPD(x); WPSHD(x-y);                                               continue;
/* INC:*  */ case 0x72: MLITD(x); WPSHD(x+1);                                                         continue;
/* DEC:*  */ case 0x73: MLITD(x); WPSHD(x-1);                                                         continue;
/* LTH:*  */ case 0x74: MLITD(y); WPOPD(x); WPSH1(BOOL(x<y));                                         continue;
/* GTH:*  */ case 0x75: MLITD(y); WPOPD(x); WPSH1(BOOL(x>y));                                         continue;
/* EQU:*  */ case 0x76: MLIT2(c,d); WPOP2(a,b); WPSH1(BOOL(a==c && b==d));                            continue;
/* NQK:*  */ case 0x77: MLIT2(c,d); WGET2(a,b); WPSH2(c,d); WPSH1(BOOL(a!=c || b!=d));                continue;
/* IOR:*  */ case 0x78: MLIT2(c,d); WSTV(-1)|=d; WSTV(-2)|=c;                                         continue;
/* XOR:*  */ case 0x79: MLIT2(c,d); WSTV(-1)^=d; WSTV(-2)^=c;                                         continue;
/* AND:*  */ case 0x7A: MLIT2(c,d); WSTV(-1)&=d; WSTV(-2)&=c;                                         continue;
/* NOT:*  */ case 0x7B: MLIT2(a,b); WPSH2(~a,~b);                                                     continue;
/* SHF:*  */ case 0x7C: MLIT1(c); WPOPD(x); x=SHF(x,c); WPSHD(x);                                     continue;
/* SHC:*  */ case 0x7D: MLIT1(c); WPOPD(x); x=shcd(x,c); WPSHD(x);                                    continue;
/* TAL:*  */ case 0x7E: MLIT2(a,b); WPSH1(TAL(a)+TAL(b));                                             continue;
/* REV:*  */ case 0x7F: MLIT2(a,b); WPSH1(rev(b)); WPSH1(rev(a));                                     continue;

/* DB3    */ case 0x80:                                                                         return SIG_DB3;
/* JMPr   */ case 0x81: RPOP2(a,b); PC=DOUBLE(a,b);                                                   continue;
/* JCNr   */ case 0x82: RPOP2(b,c); RPOP1(a); if(a) PC=DOUBLE(b,c);                                   continue;
/* JCKr   */ case 0x83: RPOP2(b,c); RGET1(a); if(a) PC=DOUBLE(b,c);                                   continue;
/* LDAr   */ case 0x84: RPOP2(a,b); x=DOUBLE(a,b); RPSH1(MEM[x]);                                     continue;
/* STAr   */ case 0x85: RPOPD(x); RPOP1(a); MEM[x]=a;                                                 continue;
/* LDDr   */ case 0x86: RPOP1(a); RPSH1(dev_read(br,a));                                              continue;
/* STDr   */ case 0x87: RPOP1(b); RPOP1(a); sig=dev_write(br,b,a);                                 SIGNAL(sig);
/* PSHr   */ case 0x88: WPOP1(a); RPSH1(a);                                                           continue;
/* POPr   */ case 0x89: RST.p-=1;                                                                     continue;
/* CPYr   */ case 0x8A: WGET1(a); RPSH1(a);                                                           continue;
/* SPLr   */ case 0x8B: RPOP1(a); RPSH2(LEFT(a),RIGHT(a));                                            continue;
/* DUPr   */ case 0x8C: RGET1(a); RPSH1(a);                                                           continue;
/* OVRr   */ case 0x8D: RPOP1(b); RGET1(a); RPSH1(b); RPSH1(a);                                       continue;
/* SWPr   */ case 0x8E: RPOP1(b); RPOP1(a); RPSH1(b); RPSH1(a);                                       continue;
/* ROTr   */ case 0x8F: RPOP1(c); RPOP1(b); RPOP1(a); RPSH1(b); RPSH1(c); RPSH1(a);                   continue;
/* ADDr   */ case 0x90: RPOP1(b); RSTV(-1)+=b;                                                        continue;
/* SUBr   */ case 0x91: RPOP1(b); RSTV(-1)-=b;                                                        continue;
/* INCr   */ case 0x92: RSTV(-1)+=1;                                                                  continue;
/* DECr   */ case 0x93: RSTV(-1)-=1;                                                                  continue;
/* LTHr   */ case 0x94: RPOP1(b); RPOP1(a); RPSH1(BOOL(a<b));                                         continue;
/* GTHr   */ case 0x95: RPOP1(b); RPOP1(a); RPSH1(BOOL(a>b));                                         continue;
/* EQUr   */ case 0x96: RPOP1(b); RPOP1(a); RPSH1(BOOL(a==b));                                        continue;
/* NQKr   */ case 0x97: b=RSTV(-1); a=RSTV(-2); RPSH1(BOOL(a!=b));                                    continue;
/* IORr   */ case 0x98: RPOP1(b); RSTV(-1)|=b;                                                        continue;
/* XORr   */ case 0x99: RPOP1(b); RSTV(-1)^=b;                                                        continue;
/* ANDr   */ case 0x9A: RPOP1(b); RSTV(-1)&=b;                                                        continue;
/* NOTr   */ case 0x9B: RSTV(-1)=~RSTV(-1);                                                           continue;
/* SHFr   */ case 0x9C: RPOP1(b); RPOP1(a); x=SHF(a,b); RPSH1(x);                                     continue;
/* SHCr   */ case 0x9D: RPOP1(b); RPOP1(a); x=shc(a,b); RPSH1(x);                                     continue;
/* TALr   */ case 0x9E: RSTV(-1)=TAL(RSTV(-1));                                                       continue;
/* REVr   */ case 0x9F: RSTV(-1)=rev(RSTV(-1));                                                       continue;

/* DB4    */ case 0xA0:                                                                         return SIG_DB4;
/* JMSr   */ case 0xA1: RPOP2(a,b); WPSHD(PC); PC=DOUBLE(a,b);                                        continue;
/* JCSr   */ case 0xA2: RPOP2(b,c); RPOP1(a); if(a) {WPSHD(PC); PC=DOUBLE(b,c);}                      continue;
/* JCKr*  */ case 0xA3: RPOP2(c,d); RGETD(x); if(x) {PC=DOUBLE(c,d);}                                 continue;
/* LDAr*  */ case 0xA4: RPOP2(a,b); x=DOUBLE(a,b); RPSH1(MEM[x]); RPSH1(MEM[x+1]);                    continue;
/* STAr*  */ case 0xA5: RPOPD(x); RPOP2(a,b); MEM[x]=a; MEM[x+1]=b;                                   continue;
/* LDDr*  */ case 0xA6: RPOP1(a); RPSH1(dev_read(br,a)); RPSH1(dev_read(br,a+1));                     continue;
/* STDr*  */ case 0xA7: RPOP1(c); RPOP2(a,b); sig=dev_write_16(br,c,a,b);                          SIGNAL(sig);
/* PSHr*  */ case 0xA8: WPOP2(a,b); RPSH2(a,b);                                                       continue;
/* POPr*  */ case 0xA9: RST.p-=2;                                                                     continue;
/* CPYr*  */ case 0xAA: WGET2(a,b); RPSH2(a,b);                                                       continue;
/* SPLr*  */ case 0xAB: RPOP2(a,b); RPSH2(LEFT(a),RIGHT(a)); RPSH2(LEFT(b),RIGHT(b));                 continue;
/* DUPr*  */ case 0xAC: RGET2(a,b); RPSH2(a,b);                                                       continue;
/* OVRr*  */ case 0xAD: RPOP2(c,d); RGET2(a,b); RPSH2(c,d); RPSH2(a,b);                               continue;
/* SWPr*  */ case 0xAE: RPOP2(c,d); RPOP2(a,b); RPSH2(c,d); RPSH2(a,b);                               continue;
/* ROTr*  */ case 0xAF: RPOP2(e,f); RPOP2(c,d); RPOP2(a,b); RPSH2(c,d); RPSH2(e,f); RPSH2(a,b);       continue;
/* ADDr*  */ case 0xB0: RPOPD(y); RPOPD(x); RPSHD(x+y);                                               continue;
/* SUBr*  */ case 0xB1: RPOPD(y); RPOPD(x); RPSHD(x-y);                                               continue;
/* INCr*  */ case 0xB2: RPOPD(x); RPSHD(x+1);                                                         continue;
/* DECr*  */ case 0xB3: RPOPD(x); RPSHD(x-1);                                                         continue;
/* LTHr*  */ case 0xB4: RPOPD(y); RPOPD(x); RPSH1(BOOL(x<y));                                         continue;
/* GTHr*  */ case 0xB5: RPOPD(y); RPOPD(x); RPSH1(BOOL(x>y));                                         continue;
/* EQUr*  */ case 0xB6: RPOP2(c,d); RPOP2(a,b); RPSH1(BOOL(a==c && b==d));                            continue;
/* NQKr*  */ case 0xB7: d=RSTV(-1); c=RSTV(-2); b=RSTV(-3); a=RSTV(-4); RPSH1(BOOL(a!=c || b!=d));    continue;
/* IORr*  */ case 0xB8: RPOP2(c,d); RSTV(-1)|=d; RSTV(-2)|=c;                                         continue;
/* XORr*  */ case 0xB9: RPOP2(c,d); RSTV(-1)^=d; RSTV(-2)^=c;                                         continue;
/* ANDr*  */ case 0xBA: RPOP2(c,d); RSTV(-1)&=d; RSTV(-2)&=c;                                         continue;
/* NOTr*  */ case 0xBB: RSTV(-1)=~RSTV(-1); RSTV(-2)=~RSTV(-2);                                       continue;
/* SHFr*  */ case 0xBC: RPOP1(c); RPOPD(x); x=SHF(x,c); RPSHD(x);                                     continue;
/* SHCr*  */ case 0xBD: RPOP1(c); RPOPD(x); x=shcd(x,c); RPSHD(x);                                    continue;
/* TALr*  */ case 0xBE: RPOP2(a,b); RPSH1(TAL(a)+TAL(b));                                             continue;
/* REVr*  */ case 0xBF: RPOP2(a,b); RPSH1(rev(b)); RPSH1(rev(a));                                     continue;

/* DB5    */ case 0xC0:                                                                         return SIG_DB5;
/* JMPr:  */ case 0xC1: MLIT2(a,b); PC=DOUBLE(a,b);                                                   continue;
/* JCNr:  */ case 0xC2: MLIT2(b,c); RPOP1(a); if(a) PC=DOUBLE(b,c);                                   continue;
/* JCKr:  */ case 0xC3: MLIT2(b,c); RGET1(a); if(a) PC=DOUBLE(b,c);                                   continue;
/* LDAr:  */ case 0xC4: MLIT2(a,b); x=DOUBLE(a,b); RPSH1(MEM[x]);                                     continue;
/* STAr:  */ case 0xC5: MLITD(x); RPOP1(a); MEM[x]=a;                                                 continue;
/* LDDr:  */ case 0xC6: MLIT1(a); RPSH1(dev_read(br,a));                                              continue;
/* STDr:  */ case 0xC7: MLIT1(b); RPOP1(a); sig=dev_write(br,b,a);                                 SIGNAL(sig);
/* PSHr:  */ case 0xC8: MLIT1(a); RPSH1(a);                                                           continue;
/* POPr:  */ case 0xC9: PC+=1;                                                                        continue;
/* CPYr:  */ case 0xCA: MLIT1(a); WPSH1(a); RPSH1(a);                                                 continue;
/* SPLr:  */ case 0xCB: MLIT1(a); RPSH2(LEFT(a),RIGHT(a));                                            continue;
/* DUPr:  */ case 0xCC: MLIT1(a); RPSH1(a); RPSH1(a);                                                 continue;
/* OVRr:  */ case 0xCD: MLIT1(b); RGET1(a); RPSH1(b); RPSH1(a);                                       continue;
/* SWPr:  */ case 0xCE: MLIT1(b); RPOP1(a); RPSH1(b); RPSH1(a);                                       continue;
/* ROTr:  */ case 0xCF: MLIT1(c); RPOP1(b); RPOP1(a); RPSH1(b); RPSH1(c); RPSH1(a);                   continue;
/* ADDr:  */ case 0xD0: MLIT1(b); RSTV(-1)+=b;                                                        continue;
/* SUBr:  */ case 0xD1: MLIT1(b); RSTV(-1)-=b;                                                        continue;
/* INCr:  */ case 0xD2: MLIT1(a); RPSH1(a+1);                                                         continue;
/* DECr:  */ case 0xD3: MLIT1(a); RPSH1(a-1);                                                         continue;
/* LTHr:  */ case 0xD4: MLIT1(b); RPOP1(a); RPSH1(BOOL(a<b));                                         continue;
/* GTHr:  */ case 0xD5: MLIT1(b); RPOP1(a); RPSH1(BOOL(a>b));                                         continue;
/* EQUr:  */ case 0xD6: MLIT1(b); RPOP1(a); RPSH1(BOOL(a==b));                                        continue;
/* NQKr:  */ case 0xD7: MLIT1(b); RGET1(a); RPSH1(b); RPSH1(BOOL(a!=b));                              continue;
/* IORr:  */ case 0xD8: MLIT1(b); RSTV(-1)|=b;                                                        continue;
/* XORr:  */ case 0xD9: MLIT1(b); RSTV(-1)^=b;                                                        continue;
/* ANDr:  */ case 0xDA: MLIT1(b); RSTV(-1)&=b;                                                        continue;
/* NOTr:  */ case 0xDB: MLIT1(a); RPSH1(~a);                                                          continue;
/* SHFr:  */ case 0xDC: MLIT1(b); RPOP1(a); x=SHF(a,b); RPSH1(x);                                     continue;
/* SHCr:  */ case 0xDD: MLIT1(b); RPOP1(a); x=shc(a,b); RPSH1(x);                                     continue;
/* TALr:  */ case 0xDE: MLIT1(a); RPSH1(TAL(a));                                                      continue;
/* REVr:  */ case 0xDF: MLIT1(a); RPSH1(rev(a));                                                      continue;

/* DB6    */ case 0xE0:                                                                         return SIG_DB6;
/* JMSr   */ case 0xE1: MLIT2(a,b); WPSHD(PC); PC=DOUBLE(a,b);                                        continue;
/* JCSr   */ case 0xE2: MLIT2(b,c); RPOP1(a); if(a) {WPSHD(PC); PC=DOUBLE(b,c);}                      continue;
/* JCKr*  */ case 0xE3: MLIT2(c,d); RGETD(x); if(x) {PC=DOUBLE(c,d);}                                 continue;
/* LDAr*  */ case 0xE4: MLIT2(a,b); x=DOUBLE(a,b); RPSH1(MEM[x]); RPSH1(MEM[x+1]);                    continue;
/* STAr*  */ case 0xE5: MLITD(x); RPOP2(a,b); MEM[x]=a; MEM[x+1]=b;                                   continue;
/* LDDr*  */ case 0xE6: MLIT1(a); RPSH1(dev_read(br,a)); RPSH1(dev_read(br,a+1));                     continue;
/* STDr*  */ case 0xE7: MLIT1(c); RPOP2(a,b); sig=dev_write_16(br,c,a,b);                          SIGNAL(sig);
/* PSHr*  */ case 0xE8: MLIT2(a,b); RPSH2(a,b);                                                       continue;
/* POPr*  */ case 0xE9: PC+=2;                                                                        continue;
/* CPYr*  */ case 0xEA: MLIT2(a,b); WPSH2(a,b); RPSH2(a,b);                                           continue;
/* SPLr*  */ case 0xEB: MLIT2(a,b); RPSH2(LEFT(a),RIGHT(a)); RPSH2(LEFT(b),RIGHT(b));                 continue;
/* DUPr*  */ case 0xEC: MLIT2(a,b); RPSH2(a,b); RPSH2(a,b);                                           continue;
/* OVRr*  */ case 0xED: MLIT2(c,d); RGET2(a,b); RPSH2(c,d); RPSH2(a,b);                               continue;
/* SWPr*  */ case 0xEE: MLIT2(c,d); RPOP2(a,b); RPSH2(c,d); RPSH2(a,b);                               continue;
/* ROTr*  */ case 0xEF: MLIT2(e,f); RPOP2(c,d); RPOP2(a,b); RPSH2(c,d); RPSH2(e,f); RPSH2(a,b);       continue;
/* ADDr*  */ case 0xF0: MLITD(y); RPOPD(x); RPSHD(x+y);                                               continue;
/* SUBr*  */ case 0xF1: MLITD(y); RPOPD(x); RPSHD(x-y);                                               continue;
/* INCr*  */ case 0xF2: MLITD(x); RPSHD(x+1);                                                         continue;
/* DECr*  */ case 0xF3: MLITD(x); RPSHD(x-1);                                                         continue;
/* LTHr*  */ case 0xF4: MLITD(y); RPOPD(x); RPSH1(BOOL(x<y));                                         continue;
/* GTHr*  */ case 0xF5: MLITD(y); RPOPD(x); RPSH1(BOOL(x>y));                                         continue;
/* EQUr*  */ case 0xF6: MLIT2(c,d); RPOP2(a,b); RPSH1(BOOL(a==c && b==d));                            continue;
/* NQKr*  */ case 0xF7: MLIT2(c,d); RGET2(a,b); RPSH2(c,d); RPSH1(BOOL(a!=c || b!=d));                continue;
/* IORr*  */ case 0xF8: MLIT2(c,d); RSTV(-1)|=d; RSTV(-2)|=c;                                         continue;
/* XORr*  */ case 0xF9: MLIT2(c,d); RSTV(-1)^=d; RSTV(-2)^=c;                                         continue;
/* ANDr*  */ case 0xFA: MLIT2(c,d); RSTV(-1)&=d; RSTV(-2)&=c;                                         continue;
/* NOTr*  */ case 0xFB: MLIT2(a,b); RPSH2(~a,~b);                                                     continue;
/* SHFr*  */ case 0xFC: MLIT1(c); RPOPD(x); x=SHF(x,c); RPSHD(x);                                     continue;
/* SHCr*  */ case 0xFD: MLIT1(c); RPOPD(x); x=shcd(x,c); RPSHD(x);                                    continue;
/* TALr*  */ case 0xFE: MLIT2(a,b); RPSH1(TAL(a)+TAL(b));                                             continue;
/* REVr*  */ case 0xFF: MLIT2(a,b); RPSH1(rev(b)); RPSH1(rev(a));                                     continue;
    }
    }
    return SIG_NONE;
}