home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume15 / upm / part01 / z80.c < prev   
C/C++ Source or Header  |  1990-12-17  |  3KB  |  152 lines

  1. /*
  2.  
  3. z80.c - Z-80 microprocessor emulator.
  4.  
  5. Copyright MCMXC - Nick Sayer - All rights reserved.
  6.  
  7. See COPYRIGHT file for details.
  8.  
  9. v0.0   - 04/08/90 - epoch
  10. v0.0A0 - 04/13/90 - alpha-test.
  11. v0.0A1 - 08/04/90 - alpha-test 2.
  12. v0.0A2 - 09/04/90 - alpha-test 3.
  13.  
  14. global data types:
  15.  
  16. WORD = unsigned short - i.e. an address or register pair.
  17. BYTE = unsigned char  - i.e. a memory location or register.
  18.  
  19. global data:
  20.  
  21. BYTE z80_mem[65536];
  22. WORD AF,BC,DE,HL,SP,PC,IX,IY,IR,AF2,BC2,DE2,HL2,INT_FLAGS;
  23.  
  24. global routines:
  25.  
  26. z80_run();
  27.  
  28.     Start running at addr. PRESUMES PC AND OTHER REGISTERS SET PROPERLY!!!
  29.     Returns if Z-80 executes a HALT. Returns with PC set to address of HALT
  30.     instruction.
  31.  
  32. z80_instr();
  33.  
  34.     Execute a single instruction.
  35.  
  36. wrport(addr,data);
  37. BYTE addr,data;
  38.  
  39. BYTE rdport(addr);
  40. BYTE addr;
  41.  
  42.     These routines are called by the Z-80 when it wants to read or write
  43.     to the port-space.
  44.  
  45. char INT,NMI,RESET;
  46.  
  47.     Each of these starts at 0. If some event makes any of these true, the
  48.     event each represents will take place. Think of them as the coresponding
  49.     wires that go into the CPU, except that in the real CPU these wires are
  50.     inverse logic.
  51.  
  52. BYTE int_read();
  53.  
  54.     This routine called on an interrupt. It should return the proper
  55.     interrupt acknowledgement cycle data.
  56.  
  57. KNOWN "FEATURES":
  58.  
  59.     This actually simulates a MOSTEK MK 3880. Whether or not this
  60.     device differs from the Zilog product, I don't know. But I
  61.     doubt it.
  62.  
  63.     If you single-step using z80_instr(), memory refresh, interrupt
  64.     checking, and similar housekeeping will NOT take place.
  65.  
  66.     If the processor is in interrupt mode 0, the int_read()
  67.         value MUST be an RST instruction.
  68.  
  69.     Undefined opcode sequences WILL have truely bizarre and twisted
  70.     results. Count on it. Especially undefined DD/FD operations.
  71.  
  72.     "Interrupting devices" at this time can't tell when an interrupt
  73.     service routine is finished. Normally they monitor the bus
  74.     waiting for a RETI instruction. There's no way to do that with
  75.     this code yet.
  76.  
  77. */
  78.  
  79. #include "z80.h"
  80.  
  81. BYTE real_z80_mem[65536];
  82. char STOP_FLAG; /* hack to stop us on HALT */
  83. char INT=0,NMI=0,RESET=0;
  84. WORD AF,BC,DE,HL,PC,SP,IX,IY,IR,AF2,BC2,DE2,HL2,INT_FLAGS;
  85. int TRAPval = -1, lastPC = -1;
  86.  
  87. z80_run()
  88. {
  89.   STOP_FLAG=0;
  90.   do
  91.   {
  92.  
  93. /* do an instruction */
  94.  
  95.     if (PC == TRAPval) {
  96.       printf("\n\rTrapping at 0x%04x (last=0x%04x)\n\r",PC,lastPC);
  97.       debugit();
  98.     }
  99.     lastPC = PC;
  100.     z80_instr();
  101.  
  102. /* If we did an EI instruction before last, set both IFFs */
  103.  
  104.   if (INT_FLAGS&IFTMP)
  105.   {
  106.     INT_FLAGS-=0x10;
  107.     if (!(INT_FLAGS&IFTMP))
  108.       INT_FLAGS|=IFF1|IFF2;
  109.   }
  110.  
  111. /* If an interrupt is pending and they're enabled, do it */
  112.  
  113.   if (INT && INT_FLAGS&IFF1)
  114.   {
  115.     register WORD operand;
  116.  
  117.     INT_FLAGS&=~(IFF1|IFF2);
  118.     push(PC);
  119.     switch (INT_FLAGS&IM_STAT)
  120.     {
  121.       case 0:PC=int_read()&0x38; /* DANGEROUSLY assumes an RST op... */
  122.       break;
  123.       case 1:PC=0x38; int_read(); /* we have to fetch, then spike it */
  124.       break;
  125.       case 2:operand=(IR&0xff80)|(int_read()&0xfe);
  126.          PC=z80_mem(operand)|(z80_mem(operand+1)<<8);
  127.       break;
  128.     }
  129.     INT=0;
  130.   }
  131.  
  132. /* If an NMI is pending, do it */
  133.  
  134.   if (NMI)
  135.   {
  136.     INT_FLAGS&=~IFF1;
  137.     push(PC);
  138.     PC=0x66;
  139.     NMI=0;
  140.   }
  141.  
  142. /* if a RESET is pending, that has absolute priority */
  143.  
  144.   if (RESET)
  145.   {
  146.     INT=0; NMI=0; RESET=0; INT_FLAGS=0; PC=0;
  147.   }
  148.  
  149. /* Now do a "refresh" cycle (really just increment low 7 bits of IR) */
  150.  
  151.   IR=(IR&0xff00)|((IR+1)&0x7f);
  152.