home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / Z80 emulator / PPC version / Z80.ppc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-06  |  7.2 KB  |  256 lines  |  [TEXT/CWIE]

  1. /*    Z80 Emulator
  2.     Copyright (C) 1995 G.Woigk
  3.     
  4.     This file is part of Mac Spectacle and it is free software
  5.     See application.c for details
  6.             
  7.     This program is distributed in the hope that it will be useful,
  8.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  10.  
  11.     based on fMSX; Copyright (C) Marat Fayzullin 1994,1995
  12.  
  13.     28.Mrz.95     Started work on this file                        KIO !
  14.     01.Apr.95    Finished, yee it works!                            KIO !
  15.     06.Apr.95    Removed "final bug": im2 interrupt handling        KIO !
  16.     12.Jun.95    revised EI_WITH_DELAY handling                    KIO !
  17.     12.Jun.95    all Info-Calls and profiling added                KIO !
  18.     12.Jun.95    exact r register emulation completed            KIO !
  19.     13.Jun.95    All opcodes covered, no unsupported opcodes!    KIO !
  20. */
  21.  
  22. #include    "kio.h"
  23. #include    "z80.options"
  24. #include    "z80.h"
  25. #include    "profiler.h"
  26. #include    "z80_opcodes.h"
  27. #include    "Z80.ppc.macros"
  28.  
  29.  
  30. #if GENERATINGPOWERPC
  31. #define    EI_WITH_DELAY        true        // emulate one instruction delay after ei
  32. #define    COMPACT_CODE        true        // compact code is faster anyway (more cache hits ?!)
  33. #define    REFERENCE_ENGINE    false        // true: use REF_CORE, ref_zreg and do dummy i/o
  34.  
  35. #else
  36. #define    EI_WITH_DELAY        true
  37. #define    COMPACT_CODE        true        // generate shorter code to fit in a 32k segment
  38. #define    REFERENCE_ENGINE    false
  39. #endif
  40.  
  41.  
  42. #if REFERENCE_ENGINE
  43. #define    zreg                ref_zreg        // 2nd register set for Z80_Ref()
  44. #define    CORE                REF_CORE        // 2nd core for Z80_Ref()
  45. #define    Do_Output(A,B)        No_Output(A,B)     // ignore out's of Z80_Ref()
  46. #define    Do_Input(A)            Do_Input(A)        // note: don't poll events between input of Z80_T() and Z80_Ref()
  47. #define    write_to_rom(A,B)    Dont_Write(A,B)    // don't write to ROM; Z80_T() shouldn't write to ROM too
  48. #endif
  49.  
  50.  
  51. /* ----    The Z80 Engine -------------------------------------------------------
  52.  
  53.     Z80_PPC()
  54.  
  55.     Features:
  56.     •    all legal instructions
  57.     •    all known illegal instructions (nearly no opcode gaps)
  58.     •    all flags (8 bit)
  59.     •    exact T cycle counting
  60.         -> exact speed
  61.         -> timing loop depending sound
  62.         -> timing loop depending tape i/o
  63.         -> highres screen update
  64.     •    ROM write protection (except stack operations)
  65.     •    exact R register emulation
  66.     •    1 instruction latency after EI
  67.     •    Info() calls for all illegal and some interesting instructions
  68.     •    instruction and address profiling
  69.     •    Single stepping
  70.  
  71.     global struct zreg keeps z80 registers on entry/return of Z80_PPC()
  72.     some registers are copied to local variables while Z80_PPC() is running
  73.     global pointer CORE points to 0x10000 bytes of memory to use as z80 memory
  74.     macro rompoke(A,N) and rompoke2(A,nn) provide means for ROM write protection
  75.     
  76.     Z80_PPC() does this:
  77.     1.    process NMI, if NMI is pending
  78.     2.    process interrupt, if IRPT is pending and not disabled
  79.     3.    execute z80 instructions, until T cycle counter expires
  80.         IRPTs are only tested again after an EI instruction
  81.     4.    if T cycle counter reaches 0, Do_Cycles() is called and may
  82.         •    reload the T cycle counter
  83.         •    trigger NMI or IRPT
  84.         •    require Z80_PPC() to exit
  85.  
  86.     If Z80() returns, it's result value indicates one of the following conditions:
  87.     •  EXIT was set by Do_Cycles()
  88.     •  not supported instruction at zreg.IP
  89.     •  halt instruction executed at zreg.IP-1
  90.     •  rst0 instruction executed at zreg.IP-1
  91.     •  illegal interrupt mode / not supported instruction in interrupt mode 0
  92.  
  93.     Single instructions may be executed by calling Z80_PPC() with CYCLES=4
  94.     Then one of the following is processed: (in priority order)
  95.     •  handle nmi request
  96.     •  handle irpt request (if interrupts are enabled)
  97.     •  execute one instruction, except:
  98.     •  if instruction is EI, handle EI and next instruction in one go
  99. */
  100.  
  101.  
  102. // ----    jumping -----------------------------------------------------------
  103. #define    loop        goto nxtcmnd            // loop to next instruction
  104. #define    exit(N)        { c=N; goto exit_z80; }    // exit Z80()
  105.  
  106.  
  107. // ----    load and store local variables from/to zreg struct ------------
  108. #define    load_registers                                \
  109.     load_r;                /* refresh counter R    */    \
  110.     cc = CYCLES;        /* T cycle counter        */    \
  111.     pc = PC;            /* program counter PC    */    \
  112.     sp = SP;            /* stack pointer SP        */    \
  113.     ra = RA;            /* register A            */    \
  114.     rf = RF;            /* register F            */
  115.  
  116. #define    save_registers                                \
  117.     store_r;            /* refresh counter R    */    \
  118.     CYCLES = cc;        /* T cycle counter        */    \
  119.     PC = pc;            /* program counter PC    */    \
  120.     SP = sp;            /* stack pointer SP        */    \
  121.     RA = ra;            /* register A            */    \
  122.     RF = rf;            /* register F            */
  123.  
  124.  
  125. // ====    The Z80 ENGINE ====================================================
  126. short Z80_PPC()
  127. {    
  128. register Short    pc;                    // z80 program counter
  129. register Short    sp;                    // z80 stack pointer
  130. register Char    ra;                    // z80 a register
  131. register Char    rf;                    // z80 flags
  132.         
  133. register long    cc;                    // T cycle counter
  134. #define            sto_cc    CYCLES = cc
  135. #define            ld_cc    cc = CYCLES
  136. #define            time(N)    cc-=N-4        // T cycles for instruction
  137. #define            more(N)    cc-=N        // adjust T cycles after use of time()
  138.  
  139. register dreg    *izp;
  140. #define            iz        izp->rr
  141. #define            rzh        izp->r.hi
  142. #define            rzl        izp->r.lo
  143.  
  144. register Char    c;                    // general purpose byte register
  145.  
  146. register Short    w;                    // general purpose word register
  147. #define            wl        (Char)w        // access low byte of w
  148. #define            wh        (w>>8)        // access high byte of w
  149.  
  150. register Short    wm;                    // help register for macro internal use
  151. #define            wml        (Char)wm    // access low byte of wm
  152. #define            wmh        (wm>>8)        // access high byte of wm
  153.  
  154. #if EI_WITH_DELAY
  155. register long    ccx = 0;            // limit for cc
  156. #else
  157. #define            ccx        0
  158. #endif
  159.  
  160. #if EXACT_R
  161. register Char    r;                    // r register bit 0...6
  162. #endif
  163.  
  164.  
  165.     load_registers;
  166.     
  167.  
  168. // check WUFF to see, whether an NMI or IRPT is pending:
  169. // also called after ei processing!
  170. check_wuff:
  171.     if (WUFF)
  172.     {    if (WUFF&0x80)                    // NMI:  0x0066; 11 T cycles
  173.         {    do_info_nmi;
  174.             WUFF&=0x7F;
  175.             IFF2=IFF1;
  176.             IFF1=disabled;
  177.             push(pc);
  178.             pc = 0x0066;
  179.             more(11);
  180.             loop;
  181.         }
  182.         if (IFF1==enabled)                // interrupts enabled?
  183.         {    do_info_irpt;
  184.             WUFF--;                        // clear interrupt request
  185.             IFF1=IFF2=disabled;            // disable iff1 & iff2
  186.             switch (IM)
  187.             {
  188.             case 0:            // mode 0: read instr; 1 T cycle + normal instr timing
  189.             //    if (IRPTCMD==RST38)
  190.             //    {    push(pc);
  191.             //        pc = 0x0038;
  192.             //        more(12);        // RST==11T + 1T
  193.             //        loop;
  194.             //    };
  195.             //    exit(irpt_error);    // not supported instruction read in irpt ackn cycle
  196.             case 1:            // mode 1:  rst 56; 13 T cycles
  197.                 push(pc);
  198.                 pc = 0x0038;
  199.                 more(13);
  200.                 loop;
  201.             case 2:            // mode2:  jmp via table; 19 T cycles
  202.                 push(pc);
  203.                 w = IRPTVEK;
  204.                 pc = ((Short)peek(w+1)<<8) + peek(w);
  205.                 more(19);
  206.                 loop;
  207.             default:
  208.                 exit(irpt_error);
  209.             };
  210.         };
  211.     };
  212.  
  213. // -----    THE MAIN INSTRUCTION DISPATCHER --------------------------------
  214.  
  215. nxtcmnd:
  216.     if ((cc-=4)>=ccx)                // -4 T cycles for most frequent instructions
  217.     {    
  218. #include "Codes.c"
  219.     }
  220.     else
  221.     {    cc+=4;
  222. #if EI_WITH_DELAY
  223.         if (ccx) { ccx=0; goto check_wuff; }    // for correct ei handling
  224. #endif
  225.         sto_cc; 
  226.         Do_Cycles(); 
  227.         ld_cc;
  228.         if (!EXIT) goto check_wuff;
  229.         exit(watchdog_irpt);
  230.     };
  231.  
  232.  
  233. // -----    Exit points -------------------------------------------------------------
  234.  
  235. #if INFO_ILLEGALS
  236. ill2:    exit(ill_instr2);
  237. ill3:    exit(ill_instr3);
  238. ill4:    exit(ill_instr4);
  239. #endif
  240.  
  241. #if INFO_WEIRD
  242. weird1:    exit(weird_instr1);
  243. weird2:    exit(weird_instr2);
  244. weird3:    exit(weird_instr3);
  245. weird4:    exit(weird_instr4);
  246. #endif
  247.  
  248.  
  249. exit_z80:                    // write back registers and return
  250.         save_registers;
  251.         return c;            // result code
  252. }
  253.  
  254.  
  255.  
  256.