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

  1.  
  2. /*
  3.     =========
  4.     EMULATE.C
  5.     =========
  6.     
  7.     Handle emulation functions --
  8.     
  9.     -    Emulation loop
  10.     -    Stateflag handling
  11.     -    Interrupt functions
  12. */
  13.  
  14. #define __EMULATE__
  15.  
  16. //#include "winv9t9.h"
  17.  
  18. #include <stdio.h>
  19. #include <signal.h>
  20. #include <stdlib.h>
  21. #include <time.h>
  22. #include <unistd.h>
  23. #include <setjmp.h>
  24. #if __MWERKS__
  25. #include <time.h>
  26. #else
  27. #include <sys/time.h>
  28. #include <sys/types.h>
  29. #endif
  30.  
  31. #include "v9t9_common.h"
  32. #include "v9t9.h"
  33. #include "9900.h"
  34. #include "grom.h"
  35. #include "vdp.h"
  36. #include "video.h"
  37. #include "sound.h"
  38. #include "cru.h"
  39. #include "roms.h"
  40. #include "keyboard.h"
  41. #include "emulate.h"
  42. #include "timer.h"
  43. #include "debugger.h"
  44. #include "memory.h"
  45. #include "command.h"
  46. #include "system.h"
  47. #include "9900st.h"
  48. #include "opcode_callbacks.h"
  49. #include "speech.h"
  50.  
  51. #define _L     LOG_CPU | LOG_INFO
  52.  
  53. u32 features;
  54. u32 stateflag;
  55.  
  56.  
  57. /*
  58.  *    The emulator functions from the perspective of
  59.  *    a 3 MHz clock, which drives the instruction speed of
  60.  *    the processor, and secondarily, the 9901 timer, which
  61.  *    is derived from it.
  62.  */
  63.  
  64. /*    Variables for controlling a "real time" emulation of the 9900
  65.     processor.  Each call to execute() sets an estimated cycle count
  66.     for the instruction and parameters in "instcycles".  We waste
  67.     time in 1/BASE_EMULATOR_HZ second quanta to maintain the appearance of a
  68.     3.0 MHz clock. */
  69.  
  70. int         realtime = 0;
  71. u32         baseclockhz = 3300000;
  72.  
  73. u32         instcycles;    // cycles for each instruction
  74.  
  75. u64         targetcycles;    // target # cycles to be executed per second
  76. u64         totaltargetcycles;    // total # target cycles expected
  77. u64         currentcycles = 0;    // current cycles per 1/BASE_EMULATOR_HZ second
  78. u64         totalcurrentcycles;    // total # current cycles executed
  79.  
  80. u32         currenttime;    /* time, [0..baseclockhz / BASE_EMULATOR_HZ) */
  81. u64         totalticks;    /* total number of BASE_EMULATOR_HZ events passed */
  82.  
  83. u32         executed;        /* # instructions executed in this tick */
  84. u64         totalexecuted;    /* total # executed */
  85.  
  86.  
  87. /*    Old way of controlling time */
  88.  
  89. unsigned long delaybetweeninstructions = 0;
  90.  
  91.  
  92. u64         delaycycles = 0;    // delay cycles used to maintain time per 1/BASE_EMULATOR_HZ
  93.  
  94. int     allow_debug_interrupts = 0;    // interrupt processor while debugging
  95.  
  96. ///////////
  97.  
  98. /*
  99. char       *modulespath;
  100. char       *romspath;
  101.  
  102. char        cpuromfilename[OS_NAMESIZE] = "994arom.bin";
  103. char        cpugromfilename[OS_NAMESIZE] = "994agrom.bin";
  104.  
  105. char        modulegrom[OS_NAMESIZE] = "";
  106. char        modulerom1[OS_NAMESIZE] = "";
  107. char        modulerom2[OS_NAMESIZE] = "";
  108. */
  109.  
  110. static void 
  111. inserthacks(void)
  112. {
  113.     if (!realtime && MEMORY_READ_WORD(0x496) == 0x45B) {
  114.         logger(_L | 0, "inserting keyboard delay hack\n");
  115.         MEMORY_WRITE_WORD(0x496, OP_KEYSLOW);
  116.     }
  117. }
  118.  
  119. void
  120. execution_pause(bool enable)
  121. {
  122.     if (enable) {
  123.         stateflag |= ST_PAUSE;
  124.     } else {
  125.         stateflag &= ~ST_PAUSE;
  126.     }
  127.     system_execution_paused(execution_paused());
  128. }
  129.  
  130.  
  131. #if 0
  132. static sigjmp_buf bogocalc;
  133. static void
  134. stop_bogo(int unused)
  135. {
  136.     siglongjmp(bogocalc, 1);
  137. }
  138.  
  139. static void
  140. calibrate_processor(void)
  141. {
  142.     /* Calibrate processor. */
  143.     unsigned char flag = 0;
  144.     long long   cnt;
  145.     int         tmtag = TM_UniqueTag();
  146.     int         killtimer = 0;
  147.     int         origtime;
  148.  
  149.     logger(_L | LOG_USER, "Calibrating processor... ");
  150.  
  151.     stateflag = 0;
  152.  
  153.     killtimer = TM_Start();
  154.     origtime = TM_GetTicks();
  155.     while (origtime == TM_GetTicks());
  156.     if (sigsetjmp(bogocalc, ~0) == 0) {
  157.         TM_SetEvent(tmtag, TM_HZ * BASE_EMULATOR_HZ, 0, TM_FUNC, stop_bogo);
  158.         cnt = ~0;
  159.         while (--cnt && !stateflag);
  160.     }
  161.     TM_ResetEvent(tmtag);
  162.     if (killtimer)
  163.         TM_Stop();
  164.  
  165.     bogocycles = (~cnt) / BASE_EMULATOR_HZ;
  166.     logger(_L | LOG_USER |  0, "%Ld bogocycles.\n\n", bogocycles);
  167. }
  168. #endif
  169.  
  170. /*************************************************/
  171.  
  172. static bool calibrated_processor;
  173.  
  174. static vmResult emulate9900_restart(void);
  175. static vmResult emulate9900_restop(void);
  176.  
  177.  
  178. static
  179. DECL_SYMBOL_ACTION(emulate_reset_computer)
  180. {
  181.     /* Upon restart, save volatile RAMs and reload all ROMs,
  182.        in case they were overwritten by a bug or something.  ;) */
  183.     if (task == csa_WRITE) {
  184.         memory_volatile_save();
  185.         memory_complete_load();
  186.         stateflag &= ~ST_INTERRUPT;
  187.         reset9901();
  188.         init9900();
  189.         hold9900pin(INTPIN_RESET);
  190.         contextswitch(0);
  191.     }
  192.     return 1;
  193. }
  194.  
  195. static
  196. DECL_SYMBOL_ACTION(emulate_debugger_enable)
  197. {
  198.     if (task == csa_READ) {
  199.         if (iter)
  200.             return 0;
  201.         command_arg_set_num(SYM_ARG_1st, debugger_enabled());
  202.     } else {
  203.         int val;
  204.         command_arg_get_num(SYM_ARG_1st, &val);
  205.         debugger_enable(val);
  206.     }
  207.     return 1;
  208. }
  209.  
  210. static
  211. DECL_SYMBOL_ACTION(emulate_execution_pause)
  212. {
  213.     if (task == csa_READ) {
  214.         if (iter)
  215.             return 0;
  216.         command_arg_set_num(SYM_ARG_1st, execution_paused());
  217.     } else {
  218.         int val;
  219.         command_arg_get_num(SYM_ARG_1st, &val);
  220.         execution_pause(val);
  221.     }
  222.     return 1;
  223. }
  224.  
  225. static
  226. DECL_SYMBOL_ACTION(emulate_single_step)
  227. {
  228.     execution_pause(true);
  229.     execution_pause(false);
  230.     stateflag |= ST_SINGLESTEP;
  231.     return 1;
  232. }
  233.  
  234. static
  235. DECL_SYMBOL_ACTION(emulate_change_clock_speed)
  236. {
  237.     if (task == csa_WRITE) {
  238.         emulate9900_restart();
  239.     }
  240.     return 1;
  241. }
  242.  
  243. static 
  244. DECL_SYMBOL_ACTION(emulate_set_pc)
  245. {
  246.     int val;
  247.     if (task == csa_READ)
  248.         if (!iter) {
  249.             command_arg_set_num(sym->args, pc);
  250.             return 1;
  251.         } else {
  252.             return 0;
  253.         }
  254.     
  255.     command_arg_get_num(sym->args, &val);
  256.     if (verifypc(val)) {
  257.         setandverifypc(val);
  258.     } else {
  259.         logger(_L | LOG_ERROR, "Cannot set PC to %04X, ignoring\n", val);
  260.     }
  261.     return 1;
  262. }
  263.  
  264. static 
  265. DECL_SYMBOL_ACTION(emulate_set_wp)
  266. {
  267.     int val;
  268.  
  269.     if (task == csa_READ)
  270.         if (!iter) {
  271.             command_arg_set_num(sym->args, wp);
  272.             return 1;
  273.         } else {
  274.             return 0;
  275.         }
  276.  
  277.     command_arg_get_num(sym->args, &val);
  278.     if (verifywp(val)) {
  279.         setandverifywp(val);
  280.     } else {
  281.         logger(_L | LOG_ERROR, "Cannot set WP to %04X, ignoring\n", val);
  282.     }
  283.     return 1;
  284. }
  285.  
  286. static 
  287. DECL_SYMBOL_ACTION(emulate_set_st)
  288. {
  289.     int val;
  290.     if (task == csa_READ)
  291.         if (!iter) {
  292.             statusto9900();
  293.             command_arg_set_num(sym->args, status);
  294.             return 1;
  295.         } else {
  296.             return 0;
  297.         }
  298.  
  299.     command_arg_get_num(sym->args, &val);
  300.     
  301.     T9900tostatus(val);
  302.     change9900intmask(status & 0xf);
  303.     return 1;
  304. }
  305.  
  306. #define HEXNUM(x) (((x)>='0' && (x)<='9') ? (x)-'0' : tolower(x)-'a'+10)
  307. #define NUMHEX(x)  ((x) < 10 ? (x)+'0' : (x)-10+'A')
  308.  
  309. //    Utility function to make a hex string for machine_state routines
  310. //    If 'hex' is NULL, we xmalloc() space and return a pointer to it,
  311. //    else the buffer at 'hex' should have size*2+1 bytes available.
  312. char    *emulate_bin2hex(u8 *mem, char *hex, int size)
  313. {
  314.     char *str;
  315.  
  316.     if (!hex) hex = (char *)xmalloc(size*2+1);
  317.     str = hex;
  318.     while (size--) {
  319.         u8 byt = *mem++;
  320.         *str++ = NUMHEX(byt>>4);
  321.         *str++ = NUMHEX(byt&0xf);
  322.     }
  323.     *str = 0;
  324.     return hex;
  325. }
  326.  
  327. //    Utility for converting hex string to binary.
  328. //    'size' is the upper limit on the expected size of the
  329. //    string.  If 'hex' is smaller, we zero-fill the memory.
  330. void emulate_hex2bin(char *hex, u8 *mem, int size)
  331. {
  332.     while (*hex && *(hex+1) && size) {
  333.         u8 byt = (HEXNUM(*hex) << 4) + HEXNUM(*(hex+1));
  334.         hex += 2;
  335.         *mem++ = byt;
  336.         size--;
  337.     }
  338.     while (size--) {
  339.         *mem++ = 0;
  340.     }
  341. }
  342.  
  343. /*
  344.  *    Attempt to RLE compress 'len' bytes of 'data' 
  345.  *    into 'compress' but not using more than 'maxlen' bytes.
  346.  *
  347.  *    Returns length of 'compress' or 0 if compression failed.
  348.  */
  349. int rle_compress(u8 *data, int len, u8 *compress, int maxlen)
  350. {
  351.     u8 curseglen;
  352.     u8 curtok;
  353.     int curlen = 0;
  354.     
  355.     while (len && curlen < maxlen) {
  356.         curtok = *data;
  357.         
  358.         // use 0xc0-0xff as repeat counts 1-64
  359.         curseglen = 1;
  360.         while (curseglen < len && 
  361.                data[curseglen] == curtok && 
  362.                curseglen < 64) 
  363.         {
  364.             curseglen++;
  365.         }
  366.  
  367.         // due to using 0xc0 through 0xff as repeat counts, we must
  368.         // allow a repeat of one for these tokens themselves.
  369.         // However, we can only use RLE when there are two bytes 
  370.         // available in the output buffer.
  371.         if ((curtok >= 0xc0 || curseglen > 2) && curlen <= maxlen - 2) {
  372.             *compress++ = 0xC0 + curseglen - 1;
  373.             *compress++ = curtok;
  374.             curlen += 2;
  375.         } else {
  376.             *compress++ = curtok;
  377.             curlen++;
  378.             curseglen = 1;
  379.         }
  380.         data += curseglen;
  381.         len -= curseglen;
  382.     }
  383.     
  384.     // whoops, ran out of output space before finishing the input
  385.     if (len || (len == 0 && curlen == maxlen))
  386.         return 0;
  387.     else
  388.         return curlen;
  389. }
  390.  
  391. /*
  392.  *    Attempt to RLE uncompress 'len' bytes of 'data' 
  393.  *    into 'uncompress' using at most 'maxlen' bytes.
  394.  *
  395.  *    Returns zero if uncompressed data cannot fit, else 
  396.  *    the length of that data.
  397.  */
  398. int rle_uncompress(u8 *data, int len, u8 *uncompress, int maxlen)
  399. {
  400.     u8 curseglen;
  401.     u8 curtok;
  402.     int curlen = 0;
  403.     
  404.     while (len && curlen < maxlen) {
  405.         curtok = *data++; len--;
  406.         
  407.         // a repeat count and available data?
  408.         // 0xc0==1, and 0xff==64
  409.         if (curtok >= 0xC0 && len > 0) {
  410.             curseglen = curtok - 0xC0 + 1;
  411.             
  412.             curtok = *data++; len--;
  413.                 
  414.             memset(uncompress, curtok, curseglen > (maxlen - curlen) ? 
  415.                                 (maxlen - curlen) : curseglen);
  416.             uncompress += curseglen;
  417.             curlen += curseglen;
  418.         } else {
  419.             *uncompress++ = curtok;
  420.             curlen++;
  421.         }
  422.     }
  423.  
  424.     // unused compressed data?    
  425.     if (len)
  426.         return 0;
  427.     else
  428.         return curlen;
  429. }
  430.  
  431. static
  432. DECL_SYMBOL_ACTION(emulate_set_mem)
  433. {
  434.     char *str, *typ;
  435.     int addr;
  436.     char hexstr[256];        
  437.     char memtyp[4];
  438.     mem_domain dmn;
  439.     u8 vector[64];
  440.     u8 rle[64];
  441.     int vectorlen, rlelen, idx;
  442.  
  443.     if (task == csa_READ) {
  444.         static int saveaddr;
  445.         u8 verify[64];
  446.         
  447.         /* Write memory to a hex string, CPU RAM followed by VDP RAM */
  448.         if (!iter)
  449.             saveaddr = 0;
  450.  
  451.         addr = saveaddr;
  452.  
  453.         // spit out 64 bytes at a time
  454.         if (addr < 65536) {
  455.  
  456.             /* Note: this may not seem right, when we could have a
  457.              *    MemoryEntry for a MEMENT_STORED RAM block covering
  458.              *    this area already, but this preserves the state of
  459.              *    that RAM at the time of the session being saved.  */
  460.             mrstruct  *mrarea;
  461.             while (!HAS_RAM_ACCESS(md_cpu, addr))
  462.                 addr = (addr & ~4095) + 4096;
  463.             dmn = md_cpu;
  464.             mrarea = THE_AREA(md_cpu, addr);
  465.             memtyp[0] = 'C';
  466.             memtyp[1] = 0;        // not compressed
  467.             memtyp[2] = 0;
  468.         } else if (addr < 65536 + 16384) {
  469.             addr -= 65536;
  470.             memtyp[0] = 'V';
  471.             memtyp[1] = 0;        // not compressed
  472.             memtyp[2] = 0;
  473.             dmn = md_video;
  474.         } else {
  475.             return 0;
  476.         }
  477.  
  478.         command_arg_set_num(sym->args->next, addr);
  479.  
  480.         /* Read 64 bytes from memory */
  481.         vectorlen = 0;
  482.         do {
  483.             vector[vectorlen++] = domain_read_byte(dmn, addr);
  484.             addr++;
  485.         } while (addr & 63);
  486.         
  487.         /* RLE compress the vector */
  488.         rlelen = rle_compress(vector, vectorlen, rle, sizeof(rle));
  489.         
  490.         /* Returns zero if it couldn't compress any */
  491.         if (rlelen) {
  492.             memtyp[1] = '*';    // compressed
  493.  
  494.             rle_uncompress(rle, rlelen, verify, sizeof(verify));
  495.             if (memcmp(vector, verify, vectorlen)) {
  496.                 logger(_L|LOG_FATAL, "Mismatched on RLE compress:\n"
  497.                        "In : %s\n"
  498.                        "Out: %s\n"
  499.                        "Ver: %s\n",
  500.                        emulate_bin2hex(vector, 0L, vectorlen),
  501.                        emulate_bin2hex(rle, 0L, rlelen),
  502.                        emulate_bin2hex(verify, 0L, sizeof(verify)));
  503.             }
  504.         } else {
  505.             rlelen = vectorlen;
  506.             memcpy(rle, vector, rlelen);
  507.         }
  508.         
  509.         str = hexstr;
  510.         idx = 0;
  511.         while (idx < rlelen) {
  512.             u8 byt;
  513.  
  514.             byt = rle[idx++];
  515.             
  516.             *str++ = NUMHEX(byt>>4);
  517.             *str++ = NUMHEX(byt&0xf);
  518.         }
  519.  
  520.         *str = 0;
  521.         saveaddr = addr + (dmn == md_video ? 65536 : 0);
  522.         
  523.         command_arg_set_string(sym->args, memtyp);
  524.         command_arg_set_string(sym->args->next->next, hexstr);
  525.         return 1;
  526.     }
  527.  
  528.     // write memory
  529.     
  530.     command_arg_get_string(sym->args, &typ);
  531.     command_arg_get_num(sym->args->next, &addr);
  532.     addr &= 0xffff;
  533.     command_arg_get_string(sym->args->next->next, &str);
  534.  
  535.     if (toupper(*typ) == 'C' || *typ == '>')
  536.         dmn = md_cpu;
  537.     else if (toupper(*typ) == 'V')
  538.         dmn = md_video;
  539.     else if (toupper(*typ) == 'G')
  540.         dmn = md_graphics;
  541.     else if (toupper(*typ) == 'S')    
  542.         dmn = md_speech;
  543.     else {
  544.         logger(_L | LOG_ERROR | LOG_USER, "Can't access memory type '%s'\n", typ);
  545.         return 0;
  546.     }
  547.  
  548.     // decode string, assuming it's rle-encoded
  549.     rlelen = 0;
  550.     
  551.     while (*str) {
  552.         u8 byt = (HEXNUM(*str) << 4) + HEXNUM(*(str+1));
  553.         rle[rlelen++] = byt;
  554.         str+=2;
  555.     }
  556.  
  557.     // second char of memory type indicates compression
  558.     if (typ[1] && typ[1] == '*') {
  559.         vectorlen = rle_uncompress(rle, rlelen, vector, sizeof(vector));
  560.     } else {
  561.         memcpy(vector, rle, rlelen);
  562.         vectorlen = rlelen;
  563.     }
  564.  
  565.     idx = 0;
  566.     while (idx < vectorlen) {
  567.         domain_write_byte(dmn, addr, vector[idx++]);
  568.         addr++;
  569.     }
  570.     return 1;
  571. }
  572.  
  573. static
  574. DECL_SYMBOL_ACTION(do_vdp_mmio_set_addr)
  575. {
  576.     int num;
  577.  
  578.     if (task == csa_READ) {
  579.         if (iter) return 0;
  580.         command_arg_set_num(SYM_ARG_1st, vdp_mmio_get_addr());
  581.         return 1;
  582.     } else {
  583.         command_arg_get_num(SYM_ARG_1st, &num);
  584.         vdp_mmio_set_addr(num);
  585.         return 1;
  586.     }
  587. }
  588.  
  589. static
  590. DECL_SYMBOL_ACTION(do_grom_mmio_set_addr)
  591. {
  592.     int num;
  593.  
  594.     if (task == csa_READ) {
  595.         if (iter) return 0;
  596.         command_arg_set_num(SYM_ARG_1st, grom_mmio_get_addr());
  597.         return 1;
  598.     } else {
  599.         command_arg_get_num(SYM_ARG_1st, &num);
  600.         grom_mmio_set_addr(num);
  601.         return 1;
  602.     }
  603. }
  604.  
  605. static
  606. DECL_SYMBOL_ACTION(do_speech_mmio_set_addr)
  607. {
  608.     int num;
  609.  
  610.     if (task == csa_READ) {
  611.         if (iter) return 0;
  612.         command_arg_set_num(SYM_ARG_1st, speech_mmio_get_addr());
  613.         return 1;
  614.     } else {
  615.         command_arg_get_num(SYM_ARG_1st, &num);
  616.         speech_mmio_set_addr(num);
  617.         return 1;
  618.     }
  619. }
  620.  
  621. /***************************************/
  622.  
  623. static int  emulate_tag, slowdown_tag;
  624.  
  625. void        EmulateEvent(void);
  626.  
  627. static      vmResult
  628. emulate9900_detect(void)
  629. {
  630.     return vmOk;
  631. }
  632.  
  633. static      vmResult
  634. emulate9900_init(void)
  635. {
  636.     command_symbol_table *internal =
  637.         command_symbol_table_new("Internal Emulator Commands",
  638.                                  "These options affect the mechanics of 99/4A emulation",
  639.  
  640.      command_symbol_new
  641.          ("RealTimeEmulation",
  642.           "Toggle real-time emulation mode (attempts to operate at the "
  643.           "same speed of the original 9900)",
  644.           c_STATIC,
  645.           NULL /* action */ ,
  646.           RET_FIRST_ARG,
  647.           command_arg_new_num
  648.             ("on|off",
  649.              "on:  execute at 9900 speed; "
  650.              "off:  execute with DelayBetweenInstructions",
  651.              NULL,
  652.              ARG_NUM(realtime),
  653.              NULL /* next */ )
  654.           ,
  655.  
  656.       command_symbol_new
  657.           ("DelayBetweenInstructions",
  658.            "Sets a constant delay between instructions (when not in real-time mode)",
  659.            c_STATIC,
  660.            NULL /* action */ ,
  661.            RET_FIRST_ARG,
  662.            command_arg_new_num
  663.              ("cycles",
  664.               "number of cycles to count",
  665.               NULL,
  666.               ARG_NUM(delaybetweeninstructions),
  667.               NULL /* next */ )
  668.            ,
  669.  
  670.       command_symbol_new
  671.           ("ResetComputer",
  672.            "Resets the 99/4A via RESET",
  673.            c_DONT_SAVE,
  674.            emulate_reset_computer,
  675.            NULL /* ret */ ,
  676.            NULL    /* args */
  677.       ,
  678.  
  679.       command_symbol_new
  680.           ("PauseComputer",
  681.            "Pauses emulation of the 99/4A",
  682.            c_DONT_SAVE,
  683.            emulate_execution_pause /* action */ ,
  684.            RET_FIRST_ARG,
  685.            command_arg_new_num
  686.              ("on|off", 
  687.               NULL /* help */,
  688.               NULL /* action */ ,
  689.               NEW_ARG_NUM(bool),
  690.               NULL /* next */ )
  691.            ,
  692.  
  693.       command_symbol_new
  694.           ("Debugger",
  695.            "Enable the debugger/tracer",
  696.            c_DYNAMIC,
  697.            emulate_debugger_enable /* action */ ,
  698.            RET_FIRST_ARG,
  699.            command_arg_new_num
  700.              ("on|off", 
  701.               NULL /* help */,
  702.               NULL /* action */ ,
  703.               NEW_ARG_NUM(bool),
  704.               NULL /* next */ )
  705.            ,
  706.  
  707.       command_symbol_new
  708.           ("AllowDebuggingInterrupts",
  709.            "Allow interrupts to occur while debugging",
  710.            c_STATIC,
  711.            NULL /* action */ ,
  712.            RET_FIRST_ARG,
  713.            command_arg_new_num
  714.              ("on|off", 
  715.               NULL /* help */,
  716.               NULL /* action */ ,
  717.               ARG_NUM(allow_debug_interrupts),
  718.               NULL /* next */ )
  719.            ,
  720.  
  721.       command_symbol_new
  722.           ("SingleStep",
  723.            "Execute one instruction and stop",
  724.            c_DONT_SAVE,
  725.            emulate_single_step /* action */ ,
  726.            RET_FIRST_ARG,
  727.            NULL /* args */
  728.            ,
  729.  
  730.       command_symbol_new
  731.           ("BaseClockHZ",
  732.            "Set HZ speed base clock (usually 3.0 MHz)",
  733.            c_STATIC,
  734.            emulate_change_clock_speed,
  735.            RET_FIRST_ARG,
  736.            command_arg_new_num
  737.              ("hertz",
  738.               "number of times per second",
  739.               NULL  /* action */,
  740.               ARG_NUM(baseclockhz),
  741.               NULL /* next */),
  742.  
  743.     NULL    /* next */ )))))))),
  744.  
  745.     NULL /* sub */ ,
  746.  
  747.     NULL    /* next */
  748. );
  749.  
  750.     command_symbol_table *state =
  751.         command_symbol_table_new("Memory / Debugging Commands",
  752.                                  "These options allow you to change the running state of the virtual machine",
  753.          command_symbol_new("ProgramCounter|PC", 
  754.                             "Set the program counter",
  755.                             c_DYNAMIC|c_SESSION_ONLY,
  756.                             emulate_set_pc,
  757.                             RET_FIRST_ARG,
  758.                             command_arg_new_num
  759.                             ("address", 
  760.                              "illegal addresses will be ignored",
  761.                              NULL /* action */,
  762.                              NEW_ARG_NUM(u16),
  763.                              NULL /* next */)
  764.                             ,
  765.  
  766.             command_symbol_new
  767.                             ("WorkspacePointer|WP",
  768.                              "Set the workspace pointer",
  769.                              c_DYNAMIC|c_SESSION_ONLY,
  770.                              emulate_set_wp,
  771.                              RET_FIRST_ARG,
  772.                              command_arg_new_num
  773.                              ("address",
  774.                               "illegal addresses will be ignored",
  775.                               NULL /* action */,
  776.                               NEW_ARG_NUM(u16),
  777.                               NULL /* next */)
  778.                              ,
  779.  
  780.  
  781.             command_symbol_new
  782.                             ("StatusRegister|ST",
  783.                              "Set the status register",
  784.                              c_DYNAMIC|c_SESSION_ONLY,
  785.                              emulate_set_st,
  786.                              RET_FIRST_ARG,
  787.                              command_arg_new_num
  788.                              ("address",
  789.                               "illegal addresses will be ignored",
  790.                               NULL /* action */,
  791.                               NEW_ARG_NUM(u16),
  792.                               NULL /* next */)
  793.                              ,
  794.  
  795.             command_symbol_new
  796.                             ("VDPAddress",
  797.                              "Set the VDP address register",
  798.                              c_DYNAMIC|c_SESSION_ONLY,
  799.                              do_vdp_mmio_set_addr /* action */,
  800.                              RET_FIRST_ARG,
  801.                              command_arg_new_num
  802.                              ("address",
  803.                               "0->3FFF sets read address, "
  804.                               ">4000->7FFF sets write address, "
  805.                               ">8000->87FF sets VDP write register",
  806.                               NULL /* action */,
  807.                               NEW_ARG_NUM(u16),
  808.                               NULL /* next */)
  809.                              ,
  810.  
  811.             command_symbol_new
  812.                             ("VDPRegister",
  813.                              "Set a VDP register",
  814.                              c_DYNAMIC|c_SESSION_ONLY,
  815.                              vdp_set_register,
  816.                              NULL,
  817.                              command_arg_new_num
  818.                              ("register",
  819.                               "register number, 0-7",
  820.                               NULL /* action */,
  821.                               NEW_ARG_NUM(u8),
  822.                              command_arg_new_num
  823.                              ("value",
  824.                               "value for register",
  825.                               NULL /* action */,
  826.                               NEW_ARG_NUM(u8),
  827.  
  828.                               NULL /* next */))
  829.                              ,
  830.  
  831.             command_symbol_new
  832.                             ("VDPReadAhead",
  833.                              "Set VDP read-ahead value",
  834.                              c_DYNAMIC|c_SESSION_ONLY,
  835.                              vdp_set_read_ahead,
  836.                              NULL,
  837.                              command_arg_new_num
  838.                              ("value",
  839.                               "value for register",
  840.                               NULL /* action */,
  841.                               NEW_ARG_NUM(u8),
  842.  
  843.                               NULL /* next */)
  844.                              ,
  845.  
  846.             command_symbol_new
  847.                             ("VDPAddrFlag",
  848.                              "Set VDP address",
  849.                              c_DYNAMIC|c_SESSION_ONLY,
  850.                              vdp_set_addr_flag,
  851.                              NULL,
  852.                              command_arg_new_num
  853.                              ("register",
  854.                               "register number, 0-7",
  855.                               NULL /* action */,
  856.                               NEW_ARG_NUM(u8),
  857.                              command_arg_new_num
  858.                              ("value",
  859.                               "value for register",
  860.                               NULL /* action */,
  861.                               NEW_ARG_NUM(u8),
  862.  
  863.                               NULL /* next */))
  864.                              ,
  865.  
  866.             command_symbol_new
  867.                             ("GROMAddress",
  868.                              "Set the GROM address register",
  869.                              c_DYNAMIC|c_SESSION_ONLY,
  870.                              do_grom_mmio_set_addr /* action */,
  871.                              RET_FIRST_ARG,
  872.                              command_arg_new_num
  873.                              ("address",
  874.                               NULL,
  875.                               NULL /* action */,
  876.                               NEW_ARG_NUM(u16),
  877.                               NULL /* next */)
  878.                              ,
  879.  
  880.             command_symbol_new
  881.                             ("SpeechState",
  882.                              NULL /* help */,
  883.                              c_DYNAMIC|c_SESSION_ONLY,
  884.                              speech_machine_state,
  885.                              RET_FIRST_ARG,
  886.                              command_arg_new_string("sp",
  887.                                 NULL /* help */,
  888.                                 NULL /* action */,
  889.                                 NEW_ARG_NEW_STRBUF,
  890.                              command_arg_new_string("lpc",
  891.                                 NULL /* help */,
  892.                                 NULL /* action */,
  893.                                 NEW_ARG_NEW_STRBUF,
  894.                             NULL /* next */)),
  895.  
  896.             command_symbol_new
  897.                             ("HW9901State",
  898.                              NULL /* help */,
  899.                              c_DYNAMIC|c_SESSION_ONLY,
  900.                              hw9901_machine_state,
  901.                              RET_FIRST_ARG,
  902.                              command_arg_new_string("hw9901",
  903.                                 NULL /* help */,
  904.                                 NULL /* action */,
  905.                                 NEW_ARG_NEW_STRBUF,
  906.                              command_arg_new_string("audiogate",
  907.                                 NULL /* help */,
  908.                                 NULL /* action */,
  909.                                 NEW_ARG_NEW_STRBUF,
  910.                                 NULL /* next */)),
  911.  
  912.             command_symbol_new
  913.                             ("SetRAM",
  914.                              "Change contents of RAM",
  915.                              c_DYNAMIC|c_SESSION_ONLY,
  916.                              emulate_set_mem,
  917.                              NULL /* ret */,
  918.                              command_arg_new_string
  919.                              ("type",
  920.                               "memory type: C/V/G/S",
  921.                               NULL  /* action */,
  922.                               NEW_ARG_STR (16),
  923.                              command_arg_new_num
  924.                              ("address",
  925.                               "illegal addresses will be ignored",
  926.                               NULL /* action */,
  927.                               NEW_ARG_NUM(u16),
  928.                              command_arg_new_string
  929.                              ("string",
  930.                               "hexadecimal string",
  931.                               NULL  /* action */,
  932.                               NEW_ARG_NEW_STRBUF,
  933.                               NULL /* next */)))
  934.                              ,
  935.  
  936.                              NULL /* next */))))))))))),
  937.  
  938.          NULL /* sub */,
  939.          NULL /* next */
  940.         );
  941.  
  942.     command_symbol_table_add_subtable(universe, internal);
  943.     command_symbol_table_add_subtable(universe, state);
  944.  
  945.     delaybetweeninstructions = 0;
  946. #if 0
  947.     bogocycles = 0;
  948.     calibrate_processor();
  949. #endif
  950.  
  951.     emulate_tag = TM_UniqueTag();
  952.     slowdown_tag = TM_UniqueTag();    /* one shot */
  953.  
  954.     totalticks = 0;
  955.     totalexecuted = 0;
  956.     executed = 0;
  957.  
  958.     memory_init();
  959.  
  960.     return vmOk;
  961. }
  962.  
  963. static      vmResult
  964. emulate9900_enable(void)
  965. {
  966.     return vmOk;
  967. }
  968.  
  969. static      vmResult
  970. emulate9900_disable(void)
  971. {
  972.     return vmOk;
  973. }
  974.  
  975. static      vmResult
  976. emulate9900_term(void)
  977. {
  978.     return vmOk;
  979. }
  980.  
  981. static      vmResult
  982. emulate9900_restart(void)
  983. {
  984.     targetcycles = baseclockhz / BASE_EMULATOR_HZ;
  985.     currenttime = 0;
  986.     totalcurrentcycles = totalticks = totalexecuted = executed = 0;
  987.  
  988.     TM_ResetEvent(emulate_tag);
  989.     TM_SetEvent(emulate_tag, TM_HZ * 100 / BASE_EMULATOR_HZ, 0,
  990.                 TM_FUNC | TM_REPEAT, EmulateEvent);
  991.  
  992.     calibrated_processor = false;
  993.     command_parse_text("LoadMemory\n");
  994.  
  995.     // be sure our register pointer is set up
  996.     setandverifywp(wp);
  997.  
  998.     return vmOk;
  999. }
  1000.  
  1001. static      vmResult
  1002. emulate9900_restop(void)
  1003. {
  1004.     TM_ResetEvent(emulate_tag);
  1005.     command_parse_text("SaveMemory\n");
  1006.     return vmOk;
  1007. }
  1008.  
  1009. /*********************************************************/
  1010.  
  1011. static int  keep_going;
  1012.  
  1013. int         handlestateflag(void);
  1014.  
  1015. static void
  1016. emulate9900_stop(void)
  1017. {
  1018.     keep_going = 0;
  1019. }
  1020.  
  1021. static long emulate_stopwatch;
  1022.  
  1023. static int
  1024. emulate9900_execute(void)
  1025. {
  1026.     int ret;
  1027.  
  1028.     // if we're already speeding along...
  1029.     if (!stateflag && realtime && currentcycles >= targetcycles)
  1030.         return em_TooFast;
  1031.  
  1032.     emulate_stopwatch = TM_GetTicks();
  1033.  
  1034.     while (1) {
  1035.         if (debugger_check_breakpoint(pc))
  1036.         {
  1037.             debugger_enable(1);
  1038.             stateflag |= ST_SINGLESTEP;
  1039.         }
  1040.  
  1041.         if (stateflag && (ret = handlestateflag()) != em_KeepGoing) {
  1042.             break;
  1043.         }
  1044.  
  1045.         // execute() updates this for the current instruction
  1046.         instcycles = 0;
  1047.  
  1048.         execute(fetch());
  1049.         executed++;
  1050.  
  1051.         /*  Check for 9901 timer, which is keyed
  1052.            on baseclockhz / 64 */
  1053.  
  1054.         if ((currentcycles & ~63) != ((currentcycles + instcycles) & ~63)) {
  1055.             // tick at the baseclockhz/64 rate; 9901.c will handle
  1056.             // correlating this to the clock interrupt
  1057.             if (currenttime < baseclockhz / 64 / BASE_EMULATOR_HZ) {
  1058.                 currenttime++;
  1059.                 handle9901tick();
  1060.             }
  1061.         }
  1062.  
  1063.         currentcycles += instcycles;
  1064.  
  1065.         // store new interrupt level, if any
  1066.         // (prevents an interrupt right after RTWP from one)
  1067.         change9900intmask(status & 0xf);
  1068.  
  1069.         if (!realtime) {
  1070.             ret = delaybetweeninstructions;
  1071.             while (ret--)
  1072.                 ;
  1073.         } else if (currentcycles >= targetcycles) {
  1074.             ret = em_TooFast;
  1075.             break;
  1076.         }
  1077.  
  1078.         // finally, don't take too long here
  1079.         if (TM_GetTicks() > emulate_stopwatch + TM_HZ/10) {
  1080.             ret = em_Interrupted;
  1081.             break;
  1082.         }
  1083.     }
  1084.  
  1085.     return ret;
  1086. }
  1087.  
  1088. /*********************************************/
  1089.  
  1090. static void
  1091. getcommands(void)
  1092. {
  1093.     stateflag |= ST_INTERACTIVE;
  1094.     system_getcommands();
  1095.     stateflag &= ~ST_INTERACTIVE;
  1096. }
  1097.  
  1098. int
  1099. handlestateflag(void)
  1100. {
  1101.     int         ret = em_KeepGoing;
  1102.  
  1103.     logger(_L | L_2, "handlestateflag %X\n", stateflag);
  1104.  
  1105.     // set when we want to quit
  1106.     if (stateflag & ST_TERMINATE)
  1107.         return em_Quitting;
  1108.  
  1109.     // set when we want to enter commands
  1110.     while (stateflag & ST_INTERACTIVE) {
  1111.         getcommands();
  1112.         ret = em_Interrupted;
  1113.     }
  1114.     
  1115.     // set to force emulation to halt
  1116.     if (stateflag & ST_STOP) {
  1117.         stateflag &= ~ST_STOP;
  1118.         ret = em_Interrupted;
  1119.         return ret;
  1120.     }
  1121.  
  1122.     if (stateflag & ST_SINGLESTEP) {
  1123.         stateflag &= ~(ST_SINGLESTEP | ST_STOP);
  1124.         stateflag |= ST_PAUSE;
  1125.     }
  1126.     else if (stateflag & ST_PAUSE)
  1127.         return em_TooFast;
  1128.  
  1129.     // set when we want to monitor execution
  1130.     if (stateflag & ST_DEBUG) {
  1131.         debugger();
  1132.     }
  1133.  
  1134.     // any sort of interrupt that sets intpins9900
  1135.     if ((stateflag & ST_INTERRUPT)) {
  1136.         // non-maskable
  1137.         if (intpins9900 & INTPIN_LOAD) {
  1138.             intpins9900 &= ~INTPIN_LOAD;
  1139.             logger(_L | 0, "**** NMI ****");
  1140.             contextswitch(0xfffc);
  1141.             instcycles += 22;
  1142.             execute(fetch());
  1143.         } else
  1144.             // non-maskable (?)
  1145.         if (intpins9900 & INTPIN_RESET) {
  1146.             intpins9900 &= ~INTPIN_RESET;
  1147.             logger(_L | 0, "**** RESET ****\n");
  1148.             contextswitch(0);
  1149.             instcycles += 26;
  1150.             execute(fetch());
  1151.         } else
  1152.             // maskable
  1153.         if (intpins9900 & INTPIN_INTREQ) {
  1154.             u16         highmask = 1 << (intlevel9900 + 1);
  1155.  
  1156.             // 99/4A console hardcodes all interrupts as level 1,
  1157.             // so if any are available, level 1 is it.
  1158.             if (intlevel9900 && read9901int() && 
  1159.                 (!(stateflag & ST_DEBUG) || (allow_debug_interrupts)))
  1160.             {
  1161.                 intpins9900 &= ~INTPIN_INTREQ;
  1162.                 contextswitch(0x4);
  1163.                 intlevel9900--;
  1164.                 instcycles += 22;
  1165.                 execute(fetch());
  1166.             }
  1167.         } else
  1168.             intpins9900 = 0;    // invalid
  1169.  
  1170.         if (!intpins9900)
  1171.             stateflag &= ~ST_INTERRUPT;
  1172.     }
  1173.  
  1174.     return ret;
  1175. }
  1176.  
  1177. /*    Ensure that a restore of machine state succeeds without a reboot */
  1178. void
  1179. emulate_setup_for_restore(void)
  1180. {
  1181.     // video module needs a jab
  1182.     TM_Start();
  1183.     vdpcompleteredraw();
  1184.     VIDEO(resetfromblank,());
  1185.     intpins9900 &= ~INTPIN_RESET;
  1186.     stateflag &= ~(ST_REBOOT | ST_INTERRUPT);
  1187. }
  1188.  
  1189. /*
  1190.     Always called BASE_EMULATOR_HZ times a second.
  1191. */
  1192. void
  1193. EmulateEvent(void)
  1194. {
  1195.     totalcurrentcycles += currentcycles;
  1196.     totaltargetcycles += targetcycles;
  1197.  
  1198.     currentcycles = 0;
  1199.     currenttime = 0;
  1200.  
  1201.     totalexecuted += executed;
  1202.     executed = 0;
  1203.     totalticks++;
  1204.  
  1205.     if (totalticks % (BASE_EMULATOR_HZ * 10) == 0) {
  1206.         report_status(STATUS_CYCLES_SECOND, 
  1207.                       (long)(totalcurrentcycles / (totalticks / BASE_EMULATOR_HZ)),
  1208.                       (long)(totalexecuted / (totalticks / BASE_EMULATOR_HZ)));
  1209.         executed = 0;
  1210.     }
  1211.  
  1212. }
  1213.  
  1214. static vmCPUModule myCPUModule = {
  1215.     2,
  1216.     emulate9900_execute,
  1217.     emulate9900_stop
  1218. };
  1219.  
  1220. vmModule    emulate9900CPU = {
  1221.     3,
  1222.     "9900 emulator",
  1223.     "cpu9900",
  1224.  
  1225.     vmTypeCPU,
  1226.     vmFlagsExclusive,
  1227.  
  1228.     emulate9900_detect,
  1229.     emulate9900_init,
  1230.     emulate9900_term,
  1231.     emulate9900_enable,
  1232.     emulate9900_disable,
  1233.     emulate9900_restart,
  1234.     emulate9900_restop,
  1235.     {(vmGenericModule *) & myCPUModule}
  1236. };
  1237.  
  1238. ///////////////
  1239. static int  round, timeout, slowing;
  1240. static u8   lastkey = 0xff;
  1241. static volatile int resume;
  1242. void
  1243. emulate_keyslow(void)
  1244. {
  1245.     u8          curkey;
  1246.  
  1247.     logger(_L | L_2, "emulate_keyslow; slowing=%d, resume=%d\n", slowing, resume);
  1248.     if (pc == 0x496 + 2) {
  1249.         if (slowing && resume) {
  1250.             resume = slowing = 0;
  1251.             pc = register (11);
  1252.  
  1253.             return;
  1254.         }
  1255.         // is the same key pressed?
  1256.         curkey = (u8) memory_read_byte(0x8375);
  1257.         if (curkey != 0xff && curkey == lastkey) {
  1258.             logger(_L | L_2, "got a keypress [%02X]\n", curkey);
  1259.             if (!slowing) {
  1260.                 logger(_L | L_2, "slowing down...\n");
  1261.                 round = (round + 1) & 0x7;
  1262.                 if (!round) {
  1263.                     resume = 0;
  1264.                     slowing = 1;
  1265.                     TM_SetEvent(slowdown_tag, 1 * 100 / TM_HZ, 0, 0, &resume);
  1266.                 } else {
  1267.                     timeout = 1000;
  1268.                     slowing = 1;
  1269.                     resume = 0;
  1270.                 }
  1271.             } else if (round) {
  1272.                 if (!timeout--)
  1273.                     resume = 1;
  1274.             }
  1275.  
  1276.             pc -= 2;
  1277.         } else {
  1278.             if (curkey != 0xff)
  1279.                 lastkey = curkey;
  1280.             slowing = 0;
  1281.             pc = register (11);
  1282.         }
  1283.     }
  1284. }
  1285.