home *** CD-ROM | disk | FTP | other *** search
/ ftp.whtech.com / ftp.whtech.com.7z / ftp.whtech.com / emulators / v9t9 / linux / sources / V9t9 / source / 9900.c < prev    next >
Encoding:
C/C++ Source or Header  |  2006-10-19  |  26.0 KB  |  1,154 lines

  1.  
  2. /*
  3.     9900.C
  4.     ======
  5.  
  6.     9900 emulator.  "execute" executes one instruction at (PC,WP).
  7.  
  8.     Define GNU_X86_ASM to implement some instructions in GCC x86 assembly.
  9.         These implement shift, add, multiply, divide, and other 
  10.         instructions in assembly to avoid complicated work re-calculating
  11.         status bits.
  12.     Define FAST_X86_STATUS to implement status register in 
  13.         terms of x86 flags register.  This avoids setting lastval/lastcmp.
  14. */
  15.  
  16. /*
  17.     Updated 7/99 with iffy list of clock speeds per instruction.
  18.     Updated 8/99 with better info from http://www.stanford.edu/~thierry1/ti99/
  19.     11/99:  clock timings are WAY TOO SLOW!  Can't possibly be right.
  20.     Whoops, the IS_PE_MEM macro was reversed.... ;)
  21. */
  22.  
  23. #define __9900__
  24.  
  25. #if __MWERKS__
  26. #pragma optimization_level 4
  27. //#pragma auto_inline on
  28. //#pragma inline_depth 8
  29. #endif
  30.  
  31. #include "v9t9_common.h"
  32. #include "cru.h"
  33. #include "memory.h"
  34. #include "emulate.h"
  35. #include "debugger.h"
  36. #include "log.h"
  37. #include "9900.h"
  38.  
  39. #define _L     LOG_CPU | LOG_INFO
  40. #include "9900st.h"
  41. #include "9900asm.h"
  42. #include "opcode_callbacks.h"
  43.  
  44. void        execute(uop op);
  45.  
  46. uaddr       pc, wp;
  47. u16        *wpptr;
  48. uword       status;
  49.  
  50.  
  51. s16         lastcmp,lastval;
  52.  
  53. u8          intlevel9900;
  54. u8          intpins9900;
  55.  
  56. extern long instcycles;    // # cycles estimated per instruction
  57.  
  58. /*    Penalties for accessing memory other than scratch pad or ROMs. */
  59.  
  60. static int  _is_pe_mem[] = { 
  61.     0,        // 0x0000
  62.     4,        // 0x2000
  63.     4,        // 0x4000
  64.     2,        // 0x6000
  65.     0,        // 0x8000
  66.     4,        // 0xa000
  67.     4,        // 0xc000
  68.     4,        // 0xe000
  69. };
  70. #define IS_PE_MEM(x)    _is_pe_mem[((x) >> 13) & 7]
  71. //#define IS_PE_MEM(x)  (((x) & 0xe000) != 0)*4
  72.  
  73.  
  74. /*    In the following, instcycles is incremented first by
  75.     the number of cycles taken to execute the instruction,
  76.     then by the number of cycles needed to read the instruction
  77.     from memory -- it looks like the 9900 reads the instruction
  78.     word several times for decoding!
  79.     
  80.     Time is taken for the instruction read by 'fetch'.
  81.     Time is taken for argument decoding by 'decipheraddr'.
  82.     Instructions also have added time for the transfer of
  83.     arguments to and from memory, which is added in along
  84.     with the execution time.
  85. */
  86.  
  87. //  Use this before reading the instruction, unless it
  88. //  doesn't matter much that pc is pc+2 by now
  89. #define CYCLES(base,mem)    (base) + (mem) * IS_PE_MEM(pc)
  90.  
  91.  
  92. #if defined(GNU_X86_ASM) || defined(FAST_X86_STATUS)
  93.  
  94. /*
  95.     LAE bits maintained in lastcmp/lastval.
  96.     
  97.     ALWAYS, lastcmp is 0<=lastcmp<=0xffff.
  98.     ALWAYS, status has 0xf mask for interrupt level, ST_X for XOP, etc.
  99. */
  100. u16 statusto9900(void)
  101. {
  102.     status=(status&~(ST_L|ST_E|ST_A)) |
  103.             ( (u16)lastval > (u16)lastcmp ? ST_L : 0) |
  104.             ( (s16)lastval > (s16)lastcmp ? ST_A : 0) |
  105.             (lastval==lastcmp ? ST_E : 0);
  106.     return status;
  107. }
  108.  
  109. void T9900tostatus(u16 stat)
  110. {
  111.     lastval=lastcmp=0;
  112.     status=stat;
  113.     if (!(status&ST_E)) {
  114.         if (!(status&(ST_L|ST_A)))
  115.             lastcmp++;
  116.         else {
  117.             lastval++;
  118.             if (!(status&ST_L))
  119.                 lastcmp=0xffff;
  120.             else
  121.                 if (!(status&ST_A))
  122.                     lastval=(-lastval)&0xffff;
  123.         }
  124.     }
  125.         
  126. }
  127.  
  128. #else
  129.  
  130. u8 st_o, st_c, st_p;
  131.  
  132. /*
  133.     LAE bits maintained in lastcmp/lastval.
  134.     
  135.     ALWAYS, lastcmp is 0<=lastcmp<=0xffff.
  136.     ALWAYS, status has 0xf mask for interrupt level, ST_X for XOP, etc.
  137.     st_o, st_c, and st_p maintain those bits.
  138. */
  139. u16 statusto9900(void)
  140. {
  141.     status= ( status & ~(ST_C|ST_O|ST_P|ST_L|ST_A|ST_E)) |
  142.             ( st_o ? ST_O : 0 ) |
  143.             ( st_c ? ST_C : 0 ) |
  144.             ( st_p ? ST_P : 0 ) |
  145.             ( (u16)lastval > (u16)lastcmp ? ST_L : 0) |
  146.             ( (s16)lastval > (s16)lastcmp ? ST_A : 0) |
  147.             (lastval==lastcmp ? ST_E : 0);
  148.     return status;
  149. }
  150.  
  151. void T9900tostatus(u16 stat)
  152. {
  153.     lastval=lastcmp=0;
  154.     status=stat;
  155.     if (!(status&ST_E)) {
  156.         if (!(status&(ST_L|ST_A)))
  157.             lastcmp++;
  158.         else {
  159.             lastval++;
  160.             if (!(status&ST_L))
  161.                 lastcmp=0xffff;
  162.             else
  163.                 if (!(status&ST_A))
  164.                     lastval=(-lastval)&0xffff;
  165.         }
  166.     }
  167.     st_o = (status & ST_O) != 0;
  168.     st_c = (status & ST_C) != 0;
  169.     st_p = (status & ST_P) != 0;
  170. }
  171.  
  172. #endif
  173.  
  174.  
  175. /**************************************************************************/
  176.  
  177. void        
  178. hold9900pin(u8 mask)
  179. {
  180.     intpins9900 |= mask;
  181.     stateflag |= ST_INTERRUPT;
  182. }
  183.  
  184. void
  185. change9900intmask(u16 mask)
  186. {
  187.     intlevel9900 = mask & 0xf;
  188. }
  189.  
  190.  
  191. u16 
  192. fetch(void)
  193. {
  194.     register u16 op = memory_read_word(pc);
  195.  
  196.     instcycles += IS_PE_MEM(pc);
  197.     pc = (pc + 2) & 0xfffe;
  198.     return op;
  199. }
  200.  
  201. bool 
  202. verifywp(uaddr addr)
  203. {
  204.     return true; //(HAS_RAM_ACCESS(md_cpu, addr) && HAS_RAM_ACCESS(md_cpu, addr + 31));
  205. }
  206.  
  207. void 
  208. setandverifywp(uaddr addr)
  209. {
  210.     static u16 zero16[16];
  211.     wp = addr & 0xfffe;
  212.     wpptr = registerptr(0);
  213.     if (wpptr < (u16 *)0x10000) wpptr = zero16;
  214.     
  215.     if (!verifywp(wp)) {
  216.         logger(_L | LOG_USER, "Illegal workspace pointer set (>%04X)\n",
  217.              wp);
  218.         command_parse_text("Interactive on\n");
  219.     }
  220. }
  221.  
  222. bool
  223. verifypc(uaddr addr)
  224. {
  225.     return true; //(HAS_ROM_ACCESS(md_cpu, pc) || (pc >= 0x4000 && pc < 0x6000));
  226. }
  227.  
  228. void
  229. setandverifypc(uaddr addr)
  230. {
  231.     pc = addr & 0xfffe;
  232.     if (!verifypc(pc)) {
  233.         logger(_L | LOG_USER, "Invalid program counter set (>%04X), aborting\n",
  234.              pc);
  235.         command_parse_text("Interactive on\n");
  236.     }
  237. }
  238.  
  239. void
  240. contextswitch(uaddr addr)
  241. {
  242.     u16         oldwp, oldpc, newwp, newpc;
  243.     u16        *rptr;
  244.  
  245. //  instcycles += CYCLES(14,4);
  246.     oldwp = wp;
  247.     oldpc = pc;
  248.     newwp = memory_read_word(addr);
  249.     newpc = memory_read_word(addr + 2);
  250.  
  251.     if (oldwp == newwp && addr) {
  252.         logger(_L, "*** BLWP'ing to same workspace, may be hosed\n");
  253. //      debugger_enable();
  254.     }
  255.     setandverifywp(newwp);
  256.     setandverifypc(newpc);
  257.     rptr = wpptr + 13;
  258.     *rptr++ = oldwp;
  259.     *rptr++ = oldpc;
  260.     *rptr = statusto9900();
  261.  
  262.     if (addr == 0) {
  263.         /*  this mimics the behavior
  264.            where holding down fctn-quit
  265.            keeps the program going */
  266.         trigger9901int(M_INT_VDP);
  267.         hold9900pin(INTPIN_INTREQ);
  268.     }
  269. }
  270.  
  271. /*
  272.     thierry times for address decodes:
  273.     "memory access" means if the memory is over the PE box link;
  274.     this is four cycles each!
  275.  
  276.    Address mode    Clock cycles     Memory access
  277.    Rx            0                  0
  278.    *Rx             4                 1
  279.    *Rx+ (byte)    6                2
  280.            (word)    8                2
  281.    @>xxxx         8                 1
  282.    @>xxxx(Rx)     8                 2
  283.  
  284. */
  285.  
  286.  
  287. u16         INLINE
  288. decipheraddr(uop op, int regmask, int tmask, int shiftright)
  289. {
  290.     register uword reg = (op & regmask) >> shiftright;
  291.     uword       ts = ((op & tmask) >> shiftright);
  292.     register u16 imm;
  293.     uword       addr;
  294.  
  295.     if (ts == 0) {
  296.         addr = (wp + reg + reg) & 0xffff;
  297.         instcycles += 0 * 4;
  298.     } else if (ts == 0x10) {
  299.         addr = memory_read_word((wp + reg + reg) & 0xffff);
  300.         instcycles += 4 + IS_PE_MEM((wp + reg + reg) & 0xffff) * 1;
  301.     } else if (ts == 0x20) {
  302.         imm = fetch();
  303.         if (reg) {
  304.             addr =
  305.                 (memory_read_word((wp + reg + reg) & 0xffff) + imm) & 0xffff;
  306.             instcycles += 8 + IS_PE_MEM((wp + reg + reg) & 0xffff) * 2;
  307.         } else {
  308.             addr = imm;
  309.             instcycles += 8 + IS_PE_MEM(imm) * 1;
  310.         }
  311.     } else {
  312.         register u16 *regval = wpptr + reg;
  313.  
  314.         addr = *regval;
  315.         (*regval) += 2;
  316.         instcycles += 8 + IS_PE_MEM((wp + reg + reg) & 0xffff) * 2;
  317.  
  318.     }
  319.  
  320.     return addr;
  321.  
  322. }
  323.  
  324.  
  325. u16         INLINE
  326. decipheraddrbyte(uop op, int regmask, int tmask, int shiftright)
  327. {
  328.     register uword reg = (op & regmask) >> shiftright;
  329.     uword       ts = ((op & tmask) >> shiftright);
  330.     register u16 imm;
  331.     uaddr       addr;
  332.  
  333.     if (ts == 0) {
  334.         addr = (wp + reg + reg) & 0xffff;
  335.         instcycles += 0 * 4;
  336.     } else if (ts == 0x10) {
  337.         addr = memory_read_word((wp + reg + reg) & 0xffff);
  338.         instcycles += 4 + IS_PE_MEM((wp + reg + reg) & 0xffff) * 1;
  339.     } else if (ts == 0x20) {
  340.         imm = fetch();
  341.         instcycles += 2;
  342.         if (reg) {
  343.             addr =
  344.                 (memory_read_word((wp + reg + reg) & 0xffff) + imm) & 0xffff;
  345.             instcycles += 8 + IS_PE_MEM((wp + reg + reg) & 0xffff) * 2;
  346.         } else {
  347.             addr = imm;
  348.             instcycles += 8 + IS_PE_MEM(imm) * 1;
  349.         }
  350.     } else {
  351.         register u16 *regval = wpptr + reg;
  352.  
  353.         addr = *regval;
  354.         (*regval)++;
  355.         instcycles += 6 + IS_PE_MEM((wp + reg + reg) & 0xffff) * 2;
  356.  
  357.     }
  358.  
  359.     return addr;
  360.  
  361. }
  362.  
  363.  
  364.  
  365. /*************************************************************************/
  366.  
  367. /*
  368. ;==========================================================================
  369. ;       Data instructions,                                      >0000->01FF
  370. ;==========================================================================
  371. */
  372. void        INLINE
  373. h0000(uop op)
  374. {
  375.     instcycles += CYCLES(6, 1);
  376. }
  377.  
  378.  
  379. /*
  380. ;==========================================================================
  381. ;       Immediate, Control instructions,                        >0200->03FF
  382. ;--------------------------------------------------------------------------
  383. ;
  384. ;         0 1 2 3-4 5 6 7+8 9 A B-C D E F               LI, AI, ANDI, ORI,
  385. ;       ----------------------------------              CI, STWP, STST,
  386. ;       |      o p c o d e     |0| reg # |              LIMI, LWPI, IDLE,
  387. ;       ----------------------------------              RSET, RTWP, CKON,
  388. ;                                                       CKOF, LREX
  389. ;==========================================================================
  390. */
  391. void        INLINE
  392. h0200(uop op)
  393. {
  394.     register int reg = op & 0xf;
  395.     register int imm;
  396.  
  397.     switch ((op & 0x1e0) >> 5) {
  398.     case 0:                    /* LI */
  399.         instcycles += CYCLES(12, 3);
  400.         imm = fetch();
  401.         register    (reg) = imm;
  402.  
  403.         setst_lae(imm);
  404.  
  405.         break;
  406.     case 1:                    /* AI */
  407.         instcycles += CYCLES(14, 4);
  408.         imm = fetch();
  409.         radd(reg, imm);
  410.         break;
  411.     case 2:                    /* ANDI */
  412.         instcycles += CYCLES(14, 4);
  413.         imm = fetch();
  414.         rchange(reg,, &, imm, setst_lae);
  415.         break;
  416.     case 3:                    /* ORI */
  417.         instcycles += CYCLES(14, 4);
  418.         imm = fetch();
  419.         rchange(reg,, |, imm, setst_lae);
  420.         break;
  421.     case 4:                    /* CI */
  422.         instcycles += CYCLES(14, 3);
  423.         lastval = register (reg);
  424.  
  425.         lastcmp = fetch();
  426.         break;
  427.     case 5:                    /* STWP */
  428.         instcycles += CYCLES(8, 2);
  429.         register    (reg) = wp;
  430.  
  431.         break;
  432.     case 6:                    /* STST */
  433.         instcycles += CYCLES(8, 2);
  434.         register    (reg) = statusto9900();
  435.  
  436.         break;
  437.     case 7:                    /* LWPI */
  438.         instcycles += CYCLES(10, 2);
  439.         imm = fetch();
  440.         setandverifywp(imm);
  441.         break;
  442.     case 8:                    /* LIMI */
  443.         instcycles += CYCLES(16, 2);
  444.         imm = fetch();
  445.         status = (status & ~0xf) | (imm & 0xf);
  446.         change9900intmask(imm);
  447.         logger(LOG_CPU | L_2, "*** LIMI %d\n", imm);
  448.         break;
  449.     case 10:                    /* IDLE */
  450.         instcycles += CYCLES(12, 1);
  451.         /*  should activate CRUCLK  */
  452.         break;
  453.     case 11:                    /* RSET */
  454.         instcycles += CYCLES(12, 1);
  455.         change9900intmask(0);
  456.         /*  should activate CRUCLK  */
  457.         break;
  458.     case 12:                    /* RTWP */
  459.     {
  460.         u16        *rptr;
  461.  
  462.         instcycles += CYCLES(14, 4);
  463.         rptr = wpptr + 15;
  464.         T9900tostatus(*rptr--);
  465.         pc = *rptr--;
  466.         setandverifywp(*rptr);
  467.         //intlevel9900 = (status & 0xf);  // moved to emulate.c
  468.         break;
  469.     }
  470.     case 13:                    /* CKON */
  471.     case 14:                    /* CKOF */
  472.     case 15:                    /* LREX */
  473.         instcycles += CYCLES(12, 1);
  474.         /*  should activate CRUCLK  */
  475.         break;
  476.     }
  477. }
  478.  
  479. /*
  480. ;==========================================================================
  481. ;       Single-operand instructions,                            >0400->07FF
  482. ;--------------------------------------------------------------------------
  483. ;
  484. ;         0 1 2 3-4 5 6 7+8 9 A B-C D E F               BLWP, B, X, CLR,
  485. ;       ----------------------------------              NEG, INV, INC, INCT,
  486. ;       |      o p c o d e   |TS |   S   |              DEC, DECT, BL, SWPB,
  487. ;       ----------------------------------              SETO, ABS
  488. ;
  489. ;       Inputs:         SI=opcode
  490. ;       Outputs:        SI=address of operand
  491. ;                       AX,BX,CX destroyed
  492. ;
  493. ;==========================================================================
  494. */
  495.  
  496.  
  497. static void
  498. h0400(uop op)
  499. {
  500.     register uaddr addr;
  501.  
  502.     addr = decipheraddr(op, 0xf, 0x30, 0);
  503.  
  504.     switch ((op & 0x3c0) >> 6) {
  505.     case 0:                    /* BLWP */
  506.         instcycles += CYCLES(26, 6);
  507.         contextswitch(addr);
  508.         break;
  509.  
  510.     case 1:                    /* B */
  511.         instcycles += CYCLES(8, 2);
  512.         pc = addr;
  513.         break;
  514.  
  515.     case 2:                    /* X */
  516.         instcycles += CYCLES(8, 2);
  517.         op = memory_read_word(addr);
  518.         execute(op);
  519.         break;
  520.  
  521.     case 3:                    /* CLR */
  522.         instcycles += CYCLES(10, 3);
  523.         memory_write_word(addr, 0);
  524.         break;
  525.  
  526.     case 4:                    /* NEG */
  527.         instcycles += CYCLES(12, 3);
  528.         wchange(addr, -,,, setst_laeo);
  529.         break;
  530.  
  531.     case 5:                    /* INV */
  532.         instcycles += CYCLES(10, 3);
  533.         wchange(addr, ~,,, setst_lae);
  534.         break;
  535.  
  536.     case 6:                    /* INC */
  537.         instcycles += CYCLES(10, 3);
  538.         wadd(addr, 1);
  539.         break;
  540.  
  541.     case 7:                    /* INCT */
  542.         instcycles += CYCLES(10, 3);
  543.         wadd(addr, 2);
  544.         break;
  545.  
  546.     case 8:                    /* DEC */
  547.         instcycles += CYCLES(10, 3);
  548.         wadd(addr, 0xffff);
  549.         break;
  550.  
  551.     case 9:                    /* DECT */
  552.         instcycles += CYCLES(10, 3);
  553.         wadd(addr, 0xfffe);
  554.         break;
  555.  
  556.     case 10:                    /* BL */
  557.         instcycles += CYCLES(12, 3);
  558.         register(11) = pc;
  559.  
  560.         pc = addr;
  561.         break;
  562.  
  563.     case 11:                    /* SWPB */
  564.         instcycles += CYCLES(10, 3);
  565.         wchange(addr, swpb,,,);
  566.         break;
  567.  
  568.     case 12:                    /* SETO */
  569.         instcycles += CYCLES(10, 3);
  570.         memory_write_word(addr, 0xffff);
  571.         break;
  572.  
  573.     case 13:                    /* ABS */
  574.     {
  575.         u16         val;
  576.  
  577.         instcycles += CYCLES(12, 2);
  578.  
  579.         val = memory_read_word(addr);
  580.         setst_lae(val);
  581.         if (val >= 0x8000) {
  582.             memory_write_word(addr, -setst_o(val));
  583.             instcycles += CYCLES(2, 1);
  584.         }
  585.         break;
  586.     }
  587.  
  588.     }
  589. }
  590.  
  591. /*
  592. ;==========================================================================
  593. ;       Shift instructions,                                     >0800->0BFF
  594. ;       AND my own instructions,                                >0C00->0FFF
  595. ;--------------------------------------------------------------------------
  596. ;
  597. ;         0 1 2 3-4 5 6 7+8 9 A B-C D E F               SRA, SRL, SLA, SRC
  598. ;       ----------------------------------              ------------------
  599. ;       |  o p c o d e   |   C   |   W   |              DSR, KEYS, SPRI,
  600. ;       ----------------------------------              TRAN, INT1, BRK,
  601. ;                                                       TIDSR, KEYSLOW,
  602. ;       Inputs:         SI=opcode                       SCREEN, DBG, -DBG
  603. ;       Outputs:        SI=address of operand
  604. ;                       CL=shift count
  605. ;                       Destroys BX
  606. ;
  607. ;==========================================================================
  608. */
  609.  
  610.  
  611. static void
  612. h0800(uop op)
  613. {
  614.     register u32 reg = (op & 0xf);
  615.     register u32 cnt = (op & 0xf0) >> 4;
  616.     u16        *rptr = wpptr + reg;
  617.  
  618.     if (cnt == 0) {
  619.         cnt = register (0) & 0xf;
  620.  
  621.         if (cnt == 0)
  622.             cnt = 16;            // whoops!  archiver-3 needs this
  623.         instcycles += CYCLES(20, 3);
  624.     } else {
  625.         instcycles += CYCLES(12, 4);
  626.     }
  627.  
  628.     instcycles += cnt * 2;
  629.  
  630.     /* ONLY shift now */
  631.     switch ((op & 0x700) >> 8) {
  632.     case 0:                    /* SRA */
  633.         *rptr = setst_sra_laec(*rptr, cnt);
  634.         break;
  635.  
  636.     case 1:                    /* SRL */
  637.         *rptr = setst_srl_laec(*rptr, cnt);
  638.         break;
  639.  
  640.     case 2:                    /* SLA */
  641.         *rptr = setst_sla_laeco(*rptr, cnt);
  642.         break;
  643.  
  644.     case 3:                    /* SRC */
  645.         *rptr = setst_src_laec(*rptr, cnt);
  646.         break;
  647.  
  648.     default:
  649.         switch ((op & 0x3e0) >> 5) {
  650.             // 0xc00
  651.         case 0:                /* DSR, OP_DSR */
  652.             emulate_dsr();
  653.             break;
  654.  
  655.             // 0xd80
  656.         case 10:                /* KEYSLOW */
  657.             emulate_keyslow();
  658.             break;
  659.  
  660.             // 0xdc0
  661.         case 14:                /* EMITCHAR */
  662.             if ((*rptr >> 8) == 0xd)
  663.                 printf("\n");
  664.             else
  665.                 printf("%c", (*rptr) >> 0x8);
  666.             break;
  667.  
  668.             // 0xde0
  669.         case 15:                /* DBG, -DBG */
  670.             debugger_enable(!(op & 0xf));
  671.             if (!(op & 0xf))
  672.                 execution_pause(1);
  673.             break;
  674.         default:
  675.             logger(LOG_CPU | L_1,
  676.                    "unhandled extended opcode >%04X at >%04X [%d]\n", op, pc,
  677.                    (op & 0x3e0) >> 5);
  678.             break;
  679.         }
  680.         break;
  681.     }
  682. }
  683.  
  684. /*
  685. ;==========================================================================
  686. ;       Jump, CRU bit instructions,                             >1000->1FFF
  687. ;--------------------------------------------------------------------------
  688. ;
  689. ;         0 1 2 3-4 5 6 7+8 9 A B-C D E F               JMP, JLT, JLE, JEQ,
  690. ;       ----------------------------------              JHE, JGT, JNE, JNC,
  691. ;       |   o p c o d e  | signed offset |              JOC, JNO, JL,JH,JOP
  692. ;       ----------------------------------              ---------------------
  693. ;                                                       SBO, SBZ, TB
  694. ;       Inputs:         SI=opcode
  695. ;       Outputs:        AX=signed word offset
  696. ;                       Destroys SI
  697. ;
  698. ;==========================================================================
  699. */
  700. static void
  701. h1000(uop op)
  702. {
  703.     register s32 offs = (s8) (op) << 1;
  704.  
  705.     if (op < 0x1D00)            /* jumps */
  706.         instcycles = CYCLES(8, 1);
  707.     else
  708.         instcycles = CYCLES(12, 2);
  709.  
  710.     switch ((op & 0xf00) >> 8) {
  711.     case 0:                    /* JMP */
  712.         setandverifypc(pc + offs);
  713.         instcycles += 2;
  714.         break;
  715.     case 1:                    /* JLT */
  716.         if ((s16) lastval < (s16) lastcmp) {
  717.             setandverifypc(pc + offs);
  718.             instcycles += 2;
  719.         }
  720.  
  721.         break;
  722.     case 2:                    /* JLE */
  723.         if ((u16) lastval <= (u16) lastcmp) {
  724.             setandverifypc(pc + offs);
  725.             instcycles += 2;
  726.         }
  727.         break;
  728.     case 3:                    /* JEQ */
  729.         if (lastval == lastcmp) {
  730.             setandverifypc(pc + offs);
  731.             instcycles += 2;
  732.         }
  733.         break;
  734.     case 4:                    /* JHE */
  735.         if ((u16) lastval >= (u16) lastcmp) {
  736.             setandverifypc(pc + offs);
  737.             instcycles += 2;
  738.         }
  739.         break;
  740.     case 5:                    /* JGT */
  741.         if ((s16) lastval > (s16) lastcmp) {
  742.             setandverifypc(pc + offs);
  743.             instcycles += 2;
  744.         }
  745.         break;
  746.     case 6:                    /* JNE */
  747.         if (lastval != lastcmp) {
  748.             setandverifypc(pc + offs);
  749.             instcycles += 2;
  750.         }
  751.         break;
  752.     case 7:                    /* JNC */
  753. #if defined(FAST_X86_STATUS) || defined(GNU_X86_ASM)
  754.         if ((status & ST_C) == 0) {
  755.             setandverifypc(pc + offs);
  756.             instcycles += 2;
  757.         }
  758. #else
  759.         if (!st_c) {
  760.             setandverifypc(pc + offs);
  761.             instcycles += 2;
  762.         }
  763. #endif
  764.         break;
  765.     case 8:                    /* JOC */
  766. #if defined(FAST_X86_STATUS) || defined(GNU_X86_ASM)
  767.         if (status & ST_C) {
  768.             setandverifypc(pc + offs);
  769.             instcycles += 2;
  770.         }
  771. #else
  772.         if (st_c) {
  773.             setandverifypc(pc + offs);
  774.             instcycles += 2;
  775.         }
  776. #endif
  777.         break;
  778.     case 9:                    /* JNO */
  779. #if defined(FAST_X86_STATUS) || defined(GNU_X86_ASM)
  780.         if ((status & ST_O) == 0) {
  781.             setandverifypc(pc + offs);
  782.             instcycles += 2;
  783.         }
  784. #else
  785.         if (!st_o) {
  786.             setandverifypc(pc + offs);
  787.             instcycles += 2;
  788.         }
  789. #endif
  790.         break;
  791.     case 10:                    /* JL */
  792.         if ((u16) lastval < (u16) lastcmp) {
  793.             setandverifypc(pc + offs);
  794.             instcycles += 2;
  795.         }
  796.         break;
  797.     case 11:                    /* JH */
  798.         if ((u16) lastval > (u16) lastcmp) {
  799.             setandverifypc(pc + offs);
  800.             instcycles += 2;
  801.         }
  802.         break;
  803.     case 12:                    /* JOP */
  804. #if defined(FAST_X86_STATUS) || defined(GNU_X86_ASM)
  805.         if (status & ST_P) {
  806.             setandverifypc(pc + offs);
  807.             instcycles += 2;
  808.         }
  809. #else
  810.         if (st_p) {
  811.             setandverifypc(pc + offs);
  812.             instcycles += 2;
  813.         }
  814. #endif
  815.         break;
  816.  
  817.     case 13:                    /* SBO */
  818.         cruwrite(register (12) + offs, 1, 1);
  819.  
  820.         break;
  821.     case 14:                    /* SBZ */
  822.         cruwrite(register (12) + offs, 0, 1);
  823.  
  824.         break;
  825.     case 15:                    /* TB */
  826.     {
  827.         u8          ans = cruread(register (12) + offs, 1);
  828.  
  829.         setst_e(ans & 1, 1);
  830.     }
  831.         break;
  832.     }
  833. }
  834.  
  835. /*
  836. ;==========================================================================
  837. ;       General and One-Register instructions                   >2000->3FFF
  838. ;--------------------------------------------------------------------------
  839. ;
  840. ;         0 1 2 3-4 5 6 7+8 9 A B-C D E F               COC, CZC, XOR,
  841. ;       ----------------------------------              LDCR, STCR, XOP,
  842. ;       |   opcode   |   D   |TS |   S   |              MPY, DIV
  843. ;       ----------------------------------
  844. ;
  845. ;       Inputs:         SI=opcode
  846. ;       Outputs:        BX=source address               (S)
  847. ;                       SI=destination register offset  (D)
  848. ;
  849. ;==========================================================================
  850. */
  851.  
  852.  
  853. static void
  854. h2000(uop op)
  855. {
  856.     register u32 reg = (op & 0x3c0) >> 6;
  857.     register u32 src;
  858.     register u16 val;
  859.     u16        *rptr;
  860.  
  861.     if (op < 0x3000 || op >= 0x3800) {
  862.         src = decipheraddr(op, 0xf, 0x30, 0);
  863.     } else {
  864.         // CRU instructions:  'reg' is treated
  865.         // as # of bits, where 0 == 16.  0-7 bits
  866.         // causes a byte operation, 8-16 causes a word
  867.         // operation.
  868.  
  869.         if (reg == 0)
  870.             reg = 16;
  871.         if (reg <= 8)
  872.             src = decipheraddrbyte(op, 0xf, 0x30, 0);
  873.         else
  874.             src = decipheraddr(op, 0xf, 0x30, 0);
  875.     }
  876.  
  877.     switch ((op & 0x1c00) >> 10) {
  878.     case 0:                    /* COC */
  879.         val = memory_read_word(src);
  880.         setst_e(val & register (reg), val);
  881.  
  882.         instcycles += CYCLES(14, 3);
  883.         break;
  884.  
  885.     case 1:                    /* CZC */
  886.         val = memory_read_word(src);
  887.         setst_e(val & (~register (reg)), val);
  888.  
  889.         instcycles += CYCLES(14, 3);
  890.         break;
  891.  
  892.     case 2:                    /* XOR */
  893.         rptr = wpptr + reg;
  894.         *rptr = setst_lae((*rptr) ^ memory_read_word(src));
  895.  
  896.         instcycles += CYCLES(14, 4);
  897.         break;
  898.  
  899.     case 3:                    /* XOP */
  900.         contextswitch(0x40 + reg * 4);
  901.         status |= ST_X;            // done here so it is reset on rtwp
  902.         register    (11) = src;
  903.  
  904.         instcycles += CYCLES(36, 8);
  905.         break;
  906.  
  907.     case 4:                    /* LDCR */
  908.         cruwrite(register (12),
  909.                  (reg <= 8 ? setst_byte_laep(memory_read_byte(src)) :
  910.                   setst_lae(memory_read_word(src))), reg);
  911.  
  912.         instcycles += CYCLES(20 + 2 * reg, 3);
  913.         break;
  914.  
  915.     case 5:                    /* STCR */
  916.         if (reg <= 8)
  917.             memory_write_byte(src,
  918.  
  919.                               setst_byte_laep(cruread(register (12), reg)));
  920.         else
  921.             memory_write_word(src, setst_lae(cruread(register (12), reg)));
  922.  
  923.         instcycles +=
  924.             CYCLES(reg <= 7 ? 42 : reg == 8 ? 44 : reg <= 15 ? 58 : 60, 4);
  925.         break;
  926.  
  927.     case 6:                    /* MPY */
  928.     {
  929.         // oops, egcs fucks it up
  930. #if 0 && defined GNU_X86_ASM
  931.         register u16 a asm("ax");
  932.         register u16 b asm("dx");
  933.         register u16 *r asm("ebx");
  934.         a = register (reg);
  935.  
  936.         b = memory_read_word(src);
  937.         r = wpptr + reg;
  938.       asm("\tmulw %1\n" "\tmovw %1,(%2)\n" "\tmovw %0,2(%2)\n":
  939.       :"r"(a), "r"(b), "r"(r)
  940.       :"ax", "dx");
  941. #else
  942.  
  943.         u32         prod;
  944.  
  945.         rptr = wpptr + reg;
  946.         prod = *rptr * memory_read_word(src);
  947.         *rptr++ = prod >> 16;
  948.         *rptr = prod & 0xffff;
  949.  
  950. #endif
  951.  
  952.  
  953.         instcycles += CYCLES(52, 5);
  954.     }
  955.         break;
  956.  
  957.     case 7:                    /* DIV */
  958.     {
  959.         // oops, egcs fucks this up
  960. #if 0 && defined( GNU_X86_ASM)
  961.         register u16 hi asm("dx");
  962.         register u16 lo asm("ax");
  963.         register u16 d;
  964.         register u16 *r;        // asm ("ebx");
  965.  
  966.         d = memory_read_word(src);
  967.         hi = wpptr[reg];
  968.         lo = wpptr[reg+1];
  969.         r = wpptr + reg;
  970.         if (d <= hi) {
  971.             status |= ST_O;
  972.             instcycles += CYCLES(16, 3);
  973.         } else {
  974.           asm("\tdivw %2,%0\n" "\tmovw %0,(%3)\n" "\tmovw %1,2(%3)\n":
  975.           :"r"(lo), "r"(hi), "g"(d), "r"(r)
  976.           :"ax", "dx");
  977.             status &= ~ST_O;
  978.             instcycles += CYCLES(124, 6);
  979.         }
  980.  
  981. #else
  982.  
  983.         u16         hi, lo;
  984.         u32         dividend;
  985.         u16         d;
  986.  
  987.         rptr = wpptr + reg;
  988.         hi = *rptr++;
  989.         lo = *rptr;
  990.         dividend = ((u32) hi << 16) | lo;
  991.         d = memory_read_word(src);
  992.  
  993.         if (d <= hi) {
  994. #if defined(FAST_X86_STATUS) || defined(GNU_X86_ASM)
  995.             status |= ST_O;
  996. #else
  997.             st_o = 1;
  998. #endif
  999.             instcycles += CYCLES(16, 3);
  1000.         } else {
  1001.             *rptr-- = dividend % d;
  1002.             *rptr = dividend / d;
  1003.  
  1004. #if defined(FAST_X86_STATUS) || defined(GNU_X86_ASM)
  1005.             status &= ~ST_O;
  1006. #else
  1007.             st_o = 0;
  1008. #endif
  1009.             instcycles += CYCLES(124, 6);    // assume avg case (92-124)
  1010.         }
  1011. #endif
  1012.     }
  1013.     }
  1014. }
  1015.  
  1016. /*
  1017. ;==========================================================================
  1018. ;       Two-Register instructions                               >4000->FFFF
  1019. ;--------------------------------------------------------------------------
  1020. ;
  1021. ;         0 1 2 3-4 5 6 7+8 9 A B-C D E F               SZC, SZCB, S, SB,
  1022. ;       ----------------------------------              C, CB, A, AB, MOV,
  1023. ;       |opcode|B|TD |   D   |TS |   S   |              MOVB, SOC, SOCB
  1024. ;       ----------------------------------
  1025. ;
  1026. ;       Inputs:         SI=opcode
  1027. ;       Outputs:        SI=address of source            (S)
  1028. ;                       BX=address of destination       (D)
  1029. ;
  1030. ;==========================================================================
  1031. */
  1032. static void
  1033. h4000(uop op)
  1034. {
  1035.     register u32 src;
  1036.     register u32 dest;
  1037.  
  1038.     if (op & 0x1000) {
  1039.         src = decipheraddrbyte(op, 0xf, 0x30, 0);
  1040.         dest = decipheraddrbyte(op, 0x3c0, 0xc00, 6);
  1041.     } else {
  1042.         src = decipheraddr(op, 0xf, 0x30, 0);
  1043.         dest = decipheraddr(op, 0x3c0, 0xc00, 6);
  1044.     }
  1045.  
  1046.     switch ((op & 0xf000) >> 12) {
  1047.     case 4:                    /* SZC */
  1048.         memory_write_word(dest,
  1049.                           setst_lae(memory_read_word(dest) &
  1050.                                     ~memory_read_word(src)));
  1051.         instcycles += CYCLES(14, 4);
  1052.         break;
  1053.     case 5:                    /* SZCB */
  1054.         memory_write_byte(dest,
  1055.                           setst_byte_laep(memory_read_byte(dest) &
  1056.                                           ~memory_read_byte(src)));
  1057.         instcycles += CYCLES(14, 4);
  1058.         break;
  1059.  
  1060.     case 6:                    /* S */
  1061.         memory_write_word(dest,
  1062.                           setst_sub_laeco(memory_read_word(dest),
  1063.                                           memory_read_word(src)));
  1064.         instcycles += CYCLES(14, 4);
  1065.         break;
  1066.     case 7:                    /* SB */
  1067.         memory_write_byte(dest,
  1068.                           setst_subbyte_laecop(memory_read_byte(dest),
  1069.                                                memory_read_byte(src)));
  1070.         instcycles += CYCLES(14, 4);
  1071.         break;
  1072.  
  1073.     case 8:                    /* C */
  1074.         lastval = memory_read_word(src);
  1075.         lastcmp = memory_read_word(dest);
  1076.         instcycles += CYCLES(14, 3);
  1077.         break;
  1078.     case 9:                    /* CB */
  1079.         lastval = (s8) memory_read_byte(src);
  1080.         lastcmp = (s8) memory_read_byte(dest);
  1081.         instcycles += CYCLES(14, 3);
  1082.         break;
  1083.  
  1084.     case 10:                    /* A */
  1085.         memory_write_word(dest,
  1086.                           setst_add_laeco(memory_read_word(dest),
  1087.                                           memory_read_word(src)));
  1088.         instcycles += CYCLES(14, 4);
  1089.         break;
  1090.     case 11:                    /* AB */
  1091.         memory_write_byte(dest,
  1092.                           setst_addbyte_laecop(memory_read_byte(dest),
  1093.                                                memory_read_byte(src)));
  1094.         instcycles += CYCLES(14, 4);
  1095.         break;
  1096.  
  1097.     case 12:                    /* MOV */
  1098.         memory_write_word(dest, setst_lae(memory_read_word(src)));
  1099.         instcycles += CYCLES(14, 4);
  1100.         break;
  1101.     case 13:                    /* MOVB */
  1102.         memory_write_byte(dest, setst_byte_laep(memory_read_byte(src)));
  1103.         instcycles += CYCLES(14, 4);
  1104.         break;
  1105.  
  1106.     case 14:                    /* SOC */
  1107.         memory_write_word(dest,
  1108.                           setst_lae(memory_read_word(dest) |
  1109.                                     memory_read_word(src)));
  1110.         instcycles += CYCLES(14, 4);
  1111.         break;
  1112.     case 15:                    /* SOCB */
  1113.         memory_write_byte(dest,
  1114.                           setst_byte_laep(memory_read_byte(dest) |
  1115.                                           memory_read_byte(src)));
  1116.         instcycles += CYCLES(14, 4);
  1117.         break;
  1118.     }
  1119. }
  1120.  
  1121. void
  1122. execute(uop op)
  1123. {
  1124.     static void (*jumptable[]) (uop) = {
  1125.         &h0000, &h0200, &h0400, &h0400, &h0800, &h0800, &h0800, &h0800,
  1126.         &h1000, &h1000, &h1000, &h1000, &h1000, &h1000, &h1000, &h1000,
  1127.         &h2000, &h2000, &h2000, &h2000, &h2000, &h2000, &h2000, &h2000,
  1128.         &h2000, &h2000, &h2000, &h2000, &h2000, &h2000, &h2000, &h2000,
  1129.         &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
  1130.         &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
  1131.         &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
  1132.         &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
  1133.         &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
  1134.         &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
  1135.         &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
  1136.         &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
  1137.         &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
  1138.         &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
  1139.         &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
  1140.         &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000
  1141.     };
  1142.  
  1143.     (jumptable[op >> 9]) (op);
  1144. }
  1145.  
  1146. void
  1147. init9900(void)
  1148. {
  1149. #if defined(FAST_X86_STATUS)
  1150.     setup_status();
  1151. #endif
  1152.     wpptr = registerptr(0);
  1153. }
  1154.