home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 25 / amigaformatcd25.iso / -in_the_mag- / emulation / z80 / z80.a < prev    next >
Text File  |  1998-02-13  |  27KB  |  839 lines

  1. ** Main file of the Z80 emulator. Compiles to linkable code, using the
  2. ** following settings:
  3.  
  4. ** VERBOSE
  5. ** Boring Messages During Compilation.
  6.  
  7. PROCESSOR EQU 68030
  8. ** Define to any of 68000, 68010, 68020, 68030 or 68040. The 68000 version
  9. ** uses the Move from Status Register instruction. Presently, the > 68000
  10. ** versions are all the same.
  11.  
  12. ** GENERIC_OBJECT SET 1
  13. ** Define to compile generic Z80 emulator object file, which needs
  14. ** linking with separately compiled routines for implementation-
  15. ** dependent instructions. If not defined, macros from "machine_macs.i"
  16. ** are used and are inline expanded. See the files "extern_instr.a" and
  17. ** "impldept.i" for more information about this.
  18.  
  19. Z80_MEMCHECK SET 1
  20. ** Define to use memory write access checking.
  21. ** See MemoryHandler below for more information about this.
  22.  
  23. UPDATECACHE SET 1
  24. ** Define to update the cache on every write to Z80 memory. This is done
  25. ** by simply clearing the corresponding word in the cache. If this option
  26. ** is not used, modified code will never work.
  27.  
  28. MODIFIEDCODE SET 1
  29. ** Define to detect (and allow) modified code even in multi-byte opcodes.
  30. ** Pretty damn useless if UPDATECACHE is not defined. If this option is
  31. ** not used, then such modifications that only change the second or third
  32. ** bytes of an opcode, but not the first byte, will not be detected.
  33.  
  34. ** UNDOCINSTR_UNDEF SET 1
  35. ** Define if you want the "undocumented" instructions to be considered
  36. ** as undefined instructions.
  37.  
  38. BCDFLAGS
  39. ** Define if you want the arithmetic instructions to store information
  40. ** so that a following Daa will work correctly (see the file "notes.txt"
  41. ** for details). BASIC interpreters and other programs that work in
  42. ** decimal base often use BCD, while most games do not. The main use there
  43. ** seems to be for score counter displays.
  44. **   If this flag is not defined, then calling the Daa instruction will
  45. ** write a nonzero value into the Z80_BCD_OP field, which otherwise will
  46. ** always be zero. That way it should be easy to see if it is the missing
  47. ** BCD handling that causes any erroneous behaviour.
  48.  
  49. ** AFPUSHPOP_CCR
  50. ** Define if you want the Push/Pop AF instructions to store the F register
  51. ** on 680x0 CCR form, instead of the real Z80 form. The difference lies in
  52. ** how the flags are ordered within the byte. For instance, in the 680x0,
  53. ** bit 3 is the sign flag; in the Z80, it is bit 7. Only programs that
  54. ** inspect the pushed flags (like a debugger) will ever notice this. The
  55. ** CCR version is, of course, a bit quicker, and could be used for games.
  56. **   In neither case are bits in the unused positions (including H and N)
  57. ** guaranteed to survive an operation that affects any of the flags.
  58. ** Is IS guaranteed, that a Pop AF with a following Push AF (or vice versa)
  59. ** and no flag-affecting instructions there inbetween, will preserve all
  60. ** the transferred bits.
  61.  
  62. ** AFPUSHPOP_BCD
  63. ** Define if you want the Push/Pop AF instructions to preserve BCD data.
  64. ** If used, the information used for BCD will be stored separately in an
  65. ** internal circular stack that keeps the last 7 pushed data units.
  66. ** The time penalty is reasonable, but this option is hardly ever needed.
  67. ** (Interrupts could be a problem. See the file "notes.txt" for details.)
  68. **   For game-playing only, this should definitely be turned off. Many
  69. ** games use Push/Pop AF/BC/DE/HL/IX/IY to transfer graphics data quickly.
  70.  
  71. ** ======================================================================
  72.  
  73.  
  74. ** Register aliases used (see the file Z80_coding.i for definitions):
  75.  
  76. **     TableB    pointer to TableBase
  77. **     Work    pointer to the Z80_Workspace longword
  78. **     PPC    Pseudo-PC
  79. **     ZSP    Z80 Stack Pointer (only lower word used)
  80. **     Z0    pointer to Z80 address zero
  81. **     CacheB    pointer to CacheBase (corresponding to Z0)
  82. **     FlagsB    pointer to FlagsBase (corresponding to Z0)
  83. **     InstrB    pointer to InstructionBase
  84.  
  85. ** Be careful!! Some aliases might stand for the same register!
  86. ** (TableB and Work are presently the same.)
  87.  
  88. ** ---------------------------------------------------------------------
  89.  
  90. Z80_MAIN = -1    ;Tell include file we are compiling the main file.
  91.  
  92.     INCLUDE user.i    ;User definitions. ALWAYS included first of all.
  93.  
  94.     INCLUDE    Z80.i
  95.  
  96.     INCLUDE Z80_struct.i
  97.  
  98.     INCLUDE Z80_coding.i
  99.  
  100.     INCLUDE tables.i
  101.  
  102.     INCLUDE helpfuncts.i
  103.  
  104. ** ----------------------------------------------------------------------
  105.  
  106. ** When calling Z80_Init, Z80_Coldstart or Z80_Continue, a pointer to the
  107. ** control structure is always passed in a0, and a return value is passed
  108. ** in d0. All other registers are automatically protected
  109.  
  110. ProtectedRegs REG    d1-d7/a1-a6    ;push/pop these at entry/exit
  111.  
  112. ** Registers stored at Z80_RegStorage at exit,
  113. ** and restored upon continuing:
  114.  
  115. StoredRegs REG    d0-d5/a2-a6
  116.     ;a0 (TableB) always comes as a parameter.
  117.     ;a1 (PPC) is recalculated from Real-PC at Continue.
  118.     ;d6 is recalculated from F at Continue.
  119.     ;d7 is garbage anyway.
  120.  
  121. **    Remember: if you change this, you must also change the labels
  122. **    in the Z80_RegStorage table in Z80_struct.i.
  123.  
  124. ** ======================================================================
  125.  
  126. ** EMULATOR ENTRY POINTS
  127.  
  128.  
  129. ** Before beginning emulation, the control structure must be initialised
  130. ** by calling Z80_Init.
  131. **   a0 must point to the control structure. The fields Z80_Memory and
  132. **      Z80_Cachemem must be pointing to allocated memory.
  133. **      If the memory write access checking feature is used, the field
  134. **      Z80_Flagmem must also be set, and if Z80_MemHandler is nonzero
  135. **      it is supposed to point to a user memory exception handler. See
  136. **      MemoryHandler below for details.
  137. **      The user environment data area is not changed. All other fields
  138. **      are automatically initialised to zero.
  139. **   The return value in d0 is nonzero if an error occurred, and zero
  140. ** otherwise. All other registers are automatically protected.
  141.  
  142. Z80_Init
  143.         movem.l    a0/a1/a2,-(sp)    ;temporaries
  144.  
  145.     ;Save the protected control structure entries on the stack:
  146.         move.w    #(PROT_SIZE>>1)-1,d0    ;word count
  147.         lea    PROT_FIELDS(a0),a2    ;source ptr in a2
  148. .prot_save    move.w    (a2)+,-(sp)
  149.         dbf    d0,.prot_save
  150.  
  151.     ;Then clear all entries below envdata:
  152.         move.l    a0,a1
  153.         move.w    #(Z80_Envdata>>1)-1,d0    ;envdata offset is even
  154. .clr_struct    clr.w    (a1)+
  155.         dbf    d0,.clr_struct
  156.  
  157.     ;and restore the saved entries (a2 has retained its value):
  158.         move.w    #(PROT_SIZE>>1)-1,d0    ;word count
  159. .prot_rest    move.w    (sp)+,-(a2)
  160.         dbf    d0,.prot_rest
  161.  
  162.     ;Set all entries in the cache (skipping the low end buffer)
  163.     ;to 'changed', that is, not decoded:
  164.         move.l    Z80_Cachemem(a0),a1
  165.         add.l    #Z80_LBUFSIZE,a1
  166.         move.l    #Z80_MEMSIZE,d0 ;word count
  167. .clr_cache    clr.w    (a1)+
  168.         subq.l    #1,d0    ;possibly too large to use dbf
  169.         bne.s    .clr_cache
  170.     ;(a1 should now point to the first entry in the high buffer)
  171.  
  172.     ;Set all entries in the high buffer to 'out of bounds':
  173.         move.w    #(Z80_HBUFSIZE>>1)-1,d0   ;buffers are even sized
  174. .set_hibuf    move.w    #out_of_bounds,(a1)+
  175.         dbf    d0,.set_hibuf
  176.  
  177.     ;Now copy the tables to their places in the structure:
  178.  
  179.         ;The parity table
  180.         lea    ParityTable(pc),a1
  181.         lea    Z80_Parity(a0),a2
  182.         move.w    #256-1,d0
  183. .cp_parity    move.b    (a1)+,(a2)+
  184.         dbf    d0,.cp_parity
  185.  
  186.     ;Calculate the 'address zero' pointers:
  187.     
  188.         move.l    Z80_Memory(a0),a1
  189.         add.l    #Z80_0_OFFSET,a1
  190.         move.l    a1,Z80_zero(a0)
  191.  
  192.         move.l    Z80_Cachemem(a0),a1
  193.         add.l    #CACHE_0_OFFSET,a1
  194.         move.l    a1,Z80_cachezero(a0)
  195.  
  196.         IFD    Z80_MEMCHECK
  197.         move.l    Z80_Flagmem(a0),a1
  198.         add.l    #FLAGS_0_OFFSET,a1
  199.         move.l    a1,Z80_flagzero(a0)
  200.         ENDC
  201.  
  202.     ;Create an initial "saved CPU status" frame, so we can
  203.     ;call Z80_Continue without calling Z80_Coldstart first.
  204.         movem.l ProtectedRegs,-(sp)
  205.         bsr    InitRegisters    ;(only use aliases from now)
  206.         ;Initially look like after a reset.
  207.         move.l    CacheB,PPC        ;PC = address zero
  208.         move.b    #-1,Z80_INTMOD(TableB)    ;Intmode 0
  209.         movem.l StoredRegs,Z80_RegStorage(TableB)
  210.         movem.l (sp)+,ProtectedRegs
  211.  
  212.         movem.l    (sp)+,a0/a1/a2 ;restore temporaries
  213.  
  214.         moveq    #0,d0    ;signal 'no error'
  215.         rts
  216.  
  217. ** ----------------------------------------------------------------------
  218.  
  219.  
  220. ** Enter here to start emulation 'from scratch', with a CPU reset.
  221. **   a0 must point to the control structure, which must be initialised
  222. ** (see Z80_Init above).
  223. **   The return value in d0 is nonzero if an error occurred, and zero
  224. ** otherwise. All other registers are automatically protected.
  225.  
  226. Z80_Coldstart
  227.         movem.l ProtectedRegs,-(sp)
  228.  
  229.         bsr    InitRegisters
  230.  
  231.     ;From this point on, registers may only be referred to
  232.     ;by their aliases.
  233.  
  234.         move.w    #-1,Z80_Running(TableB)
  235.  
  236.         bra    RESEThandler      ;reset and start emulation
  237.  
  238.  
  239.     ;Subroutine common to Z80_Init and Z80_Coldstart.
  240.     ;Initialises the registers that need initialisation.
  241. InitRegisters
  242.         move.l    Z80_zero(TableB),Z0
  243.  
  244.         move.l    Z80_cachezero(TableB),CacheB
  245.  
  246.         IFD    Z80_MEMCHECK
  247.         move.l    Z80_flagzero(TableB),FlagsB
  248.         ELSE
  249.         lea    0.w,FlagsB
  250.         ENDC
  251.  
  252.         lea    InstrBase(pc),InstrB
  253.  
  254.         moveq    #0,A    ;The high byte of the words used to
  255.         moveq    #0,B    ; hold 8-bit registers must be zero
  256.         moveq    #0,C    ; for indexing into parity table.
  257.         moveq    #0,D
  258.         moveq    #0,E
  259.  
  260.         rts
  261.  
  262. ** ----------------------------------------------------------------------
  263.  
  264.  
  265. ** Enter here to continue as if nothing happened since last exit
  266. ** (unless the saved processor status has been manipulated).
  267. **   Changes to other fields than the CPU status structure entries
  268. ** are not recommended; calling Z80_Continue does not guarantee
  269. ** that such changes have any effect (see Z80_NewSettings in helpfuncts.i).
  270. **   a0 must point to the control structure.
  271. **   The return value in d0 is the same as for Z80_Coldstart. All other
  272. ** registers are automatically protected.
  273.  
  274. Z80_Continue
  275.         movem.l ProtectedRegs,-(sp)
  276.  
  277.     ;Calculate alt_CCR and d6 from F' and F (method from 'Pop AF' routine)
  278.     ;We need a scratch register, so do this before restoring the rest.
  279.         lea    Pop_AF_table(pc),a1    ;use a1 as scratch
  280.  
  281.         move.b    Z80_alt_F(a0),d6
  282.         rol.b    #2,d6    ;SZ-h-VnC -> -h-VnCSZ
  283.         move.b    d6,d7
  284.         and.w    #$001F,d7    ;d7 = 000VnCSZ
  285.         and.w    #%11100000,d6    ;d6 = -h-00000
  286.         or.b    (a1,d7.w),d6    ;d6 = -h-XNZVC
  287.         move.w    d6,Z80_alt_CCR(a0)
  288.  
  289.         move.b    Z80_F(a0),d6
  290.         rol.b    #2,d6    ;SZ-h-VnC -> -h-VnCSZ
  291.         move.b    d6,d7
  292.         and.w    #$001F,d7    ;d7 = 000VnCSZ
  293.         and.w    #%11100000,d6    ;d6 = -h-00000
  294.         or.b    (a1,d7.w),d6    ;d6 = -h-XNZVC
  295.         ;now d6 holds the active flags on CCR form
  296.  
  297.     ;Restore the other registers, apart from PPC
  298.         movem.l Z80_RegStorage(a0),StoredRegs
  299.  
  300.     ;from here on, we refer to a0 as TableB:
  301.  
  302.     ;Calculate Pseudo-PC from (possibly modified) Real-PC
  303.         move.w    Z80_PC(TableB),d7
  304.         makePPC
  305.  
  306.     ;Signal 'emulator running'
  307.         move.w    #-1,Z80_Running(TableB)
  308.  
  309.         next    ;go on emulating
  310.  
  311. ** ----------------------------------------------------------------------
  312.  
  313.  
  314. ** This emulation of processor request lines makes sure that the interrupts
  315. ** behave as they should. Requests are currently only tested for after flow
  316. ** control instructions, but that seems to be quite sufficient.
  317. **   A request overrides those of lower priority. The priority order is:
  318. ** EXIT, RESET, (BUSRQ), NMI and INT. BUSRQ is currently not implemented.
  319. ** The status of the requests of lower priority is stored, so no requests
  320. ** are lost. (The highest priority request of course never needs storing).
  321. ** The priorities are hard coded; here and in each of the handlers.
  322.  
  323. **   The requests could be called from hardware interrupts, keypresses,
  324. ** menus or whatever. They do not affect any registers (apart from CCR),
  325. ** and return nothing.
  326. ** a0 must contain a pointer to the control structure.
  327.  
  328.     ;In order of priority:
  329.  
  330. Z80_EXITreq    ;unconditional
  331.         move.w    #20,Z80_ReqLvl(a0)    ;highest priority
  332.         move.w    #EXIThandler-InstrBase,Z80_Request(a0)
  333.         rts
  334.  
  335. Z80_RESETreq    cmpi.w    #2,Z80_ReqLvl(a0)
  336.         bge.s    .queued
  337.         move.w    #2,Z80_ReqLvl(a0)
  338.         move.w    #RESEThandler-InstrBase,Z80_Request(a0)
  339. .queued        move.w    #RESEThandler-InstrBase,Z80_RES_FF(a0)
  340.         rts
  341.  
  342. Z80_NMIreq    cmpi.w    #1,Z80_ReqLvl(a0)
  343.         bge.s    .queued
  344.         move.w    #1,Z80_ReqLvl(a0)
  345.         move.w    #NMIhandler-InstrBase,Z80_Request(a0)
  346. .queued        move.w    #NMIhandler-InstrBase,Z80_NMI_FF(a0)
  347.         rts
  348.  
  349. Z80_INTreq    btst    #6,Z80_IFF(a0)    ;Test IFF1
  350.         beq.s    .disabled
  351.         tst.w    Z80_ReqLvl(a0)
  352.         bne.s    .queued        ;any nonzero level is higher
  353.         ;doesn't have to raise the level - this is the lowest
  354.         move.w    #INThandler-InstrBase,Z80_Request(a0)
  355. .queued        move.w    #INThandler-InstrBase,Z80_INT_FF(a0)
  356. .disabled    rts
  357.  
  358.  
  359. ** ========================================================================
  360.  
  361. ** EMULATOR INTERNALS
  362.  
  363.  
  364. ** The routines between this line and InstrBase are called using a negative
  365. ** word offset from InstrBase. I do not expect address space problems here.
  366.  
  367. ** ------------------------------------------------------------------------
  368.  
  369. ** The following routines handle accepted requests. They are executed
  370. ** exactly as a z80 instruction routine, which means: don't thrash any
  371. ** registers but the 'scratch' ones, and end with a "next" macro call.
  372.  
  373. **  The exception detection is simple. Every now and then, the Z80_Request
  374. ** word is tested, and if it is nonzero it is taken as offset from
  375. ** InstrBase to a handler. When the corresponding handler is reached, the
  376. ** PPC points to the first word of the instruction to execute after
  377. ** returning from the exception.
  378.  
  379. ** Any waiting requests have to be considered. The priority levels are hard
  380. ** coded, which makes testing easier, but you'll have to watch out if you
  381. ** change any of this.
  382.  
  383. ** --------------
  384.  
  385. EXIThandler
  386.  
  387. ** Returns from emulator call. A nonzero value is returned in d0 if an
  388. ** error occurred, and zero otherwise.
  389. **   The registers are stored upon exit, to make it possible to continue
  390. ** later. PPC is not stored, instead Real PC is stored in Z80_PC, which can
  391. ** be changed in order to continue at another address.
  392. **   For instance, assume an instruction patched to cause EXIT, directly
  393. ** followed by the string  17,'horace.code',0  is reached. Z80_zero+Z80_PC
  394. ** would after exit point to the number 17, which could mean 'Load, using
  395. ** the following zero-terminated string as filename'. After loading,
  396. ** Z80_PC would be set to point to the byte following the zero, and
  397. ** Z80_Continue would be called. This way, a Z80-program could call host
  398. ** system services without affecting the processor status (apart from the
  399. ** Program Counter).
  400.  
  401.     ;Here, any other request could be waiting.
  402.         move.w    Z80_RES_FF(TableB),d7
  403.         beq.s    .not_reset
  404.  
  405.         ;if RESET:
  406.         move.w    d7,Z80_Request(TableB)
  407.         clr.w    Z80_RES_FF(TableB)
  408.         move.w    #2,Z80_ReqLvl(TableB)
  409.         bra.s    .go_on
  410.  
  411. .not_reset    move.w    Z80_NMI_FF(TableB),d7
  412.         beq.s    .not_nmi
  413.  
  414.         ;if NMI:
  415.         move.w    d7,Z80_Request(TableB)
  416.         clr.w    Z80_NMI_FF(TableB)
  417.         move.w    #1,Z80_ReqLvl(TableB)
  418.         bra.s    .go_on
  419.  
  420. .not_nmi    ;then INT is the only one left
  421.         clr.w    Z80_ReqLvl(TableB)
  422.         move.w    Z80_INT_FF(TableB),Z80_Request(TableB)
  423.         clr.w    Z80_INT_FF(TableB)
  424.  
  425. .go_on
  426.     ;Store registers:
  427.         movem.l StoredRegs,Z80_RegStorage(TableB)
  428.  
  429.     ;Calculate and store Real PC
  430.         getRPC
  431.         move.w    d7,Z80_PC(TableB)
  432.  
  433.     ;Calculate and store F and F' (method from 'Push AF' routine)
  434.     ;  d6 holds CCR form of F.
  435.         lea    Push_AF_table(pc),ZSP    ;use ZSP as scratch pointer
  436.  
  437.         move.w    d6,d7
  438.         and.w    #%11100000,d6    ;d6 = ---00000
  439.         and.w    #$001F,d7    ;d7 = 000XNZVC
  440.         or.b    (ZSP,d7.w),d6    ;d6 = ---VnCSZ
  441.         ror.b    #2,d6        ;d6 = SZ---VnC
  442.         move.b    d6,Z80_F(TableB)
  443.  
  444.         move.w    Z80_alt_CCR(TableB),d6
  445.         move.w    d6,d7
  446.         and.w    #%11100000,d6    ;d6 = ---00000
  447.         and.w    #$001F,d7    ;d7 = 000XNZVC
  448.         or.b    (Work,d7.w),d6    ;d6 = ---VnCSZ
  449.         ror.b    #2,d6        ;d6 = SZ---VnC
  450.         move.b    d6,Z80_alt_F(TableB)
  451.  
  452.     ;Signal that emulation has stopped
  453.         clr.w    Z80_Running(TableB)
  454.  
  455.     ;Restore caller's registers
  456.         movem.l (sp)+,ProtectedRegs
  457.  
  458.         moveq    #0,d0    ;signal No Error
  459.         rts
  460.  
  461. ** --------------
  462.  
  463. RESEThandler
  464.     ;All waiting requests (of lower priority than RESET)
  465.     ;will be cleared anyway.
  466.  
  467. ** These are the only well-defined actions at reset:
  468.  
  469.         move.l    CacheB,PPC        ;PC = address zero
  470.         clr.b    Z80_I(TableB)        ;I register = 0
  471.         clr.b    Z80_R(TableB)        ;R register = 0
  472.         clr.b    Z80_IFF(TableB)        ;clear IFF
  473.         move.b    #-1,Z80_INTMOD(TableB)    ;Intmode 0
  474.  
  475.     ;and some of my internal flags must be reset:
  476.         clr.w    Z80_Request(TableB)
  477.         clr.w    Z80_ReqLvl(TableB)
  478.         clr.w    Z80_INT_FF(TableB)
  479.         clr.w    Z80_NMI_FF(TableB)
  480.         clr.w    Z80_RES_FF(TableB)
  481.  
  482.         next
  483. ** --------------
  484.  
  485. NMIhandler
  486.  
  487. ** Nonmaskable interrupt: Call $66
  488.  
  489.     ;Here, the priority level is 1 and only an INT could be waiting.
  490.         clr.w    Z80_ReqLvl(TableB)
  491.         move.w    Z80_INT_FF(TableB),Z80_Request(TableB)
  492.         clr.w    Z80_INT_FF(TableB)
  493.  
  494.         move.b    Z80_IFF(TableB),d7
  495.         add.b    d7,d7    ;Neverneverland <- IFF2 <- IFF1 <- 0
  496.         move.b    d7,Z80_IFF(TableB)
  497.         getRPC
  498.         move.w    d7,(Work)       ;push PC
  499.         decw    ZSP
  500.         putz    (Work),ZSP
  501.         decw    ZSP
  502.         putz    d7,ZSP,2 ;2nd use
  503.         lea    2*$66(CacheB),PPC
  504.         next
  505. ** -------------
  506.  
  507. INThandler
  508.  
  509. ** For faster selection,INTmode holds -1 to 1 instead of 0 to 2.
  510.  
  511.     ;The priority level is 0 and only another INT could be waiting.
  512.         move.w    Z80_INT_FF(TableB),Z80_Request(TableB)
  513.         clr.w    Z80_INT_FF(TableB)
  514.  
  515.         clr.b    Z80_IFF(TableB)    ;clear IFF:s
  516.         tst.b    Z80_INTMOD(TableB)
  517.         bne.s    .not_1
  518.  
  519. ** Intmode 1: Call $38
  520.  
  521.         getRPC
  522.         move.w    d7,(Work)       ;push real PC onto Z80 stack
  523.         decw    ZSP
  524.         putz    (Work),ZSP
  525.         decw    ZSP
  526.         putz    d7,ZSP,2 ;2nd use
  527.         lea    2*$38(CacheB),PPC
  528.         next
  529.  
  530. .not_1        bmi.s    .mode0
  531.  
  532. ** Intmode 2:
  533. ** ( I register * 256 + byte on data bus ) AND $fffe (even address)
  534. ** forms the pointer to the interrupt vector.
  535.  
  536.         getRPC
  537.         move.w    d7,(Work)       ;push PC
  538.         decw    ZSP
  539.         putz    (Work),ZSP,3 ;3rd use
  540.         decw    ZSP
  541.         putz    d7,ZSP,4 ;4th use
  542.         move.b    Z80_I(TableB),(Work)
  543.         move.w    (Work),d7       ;get I * 256
  544.         clr.b    d7        ;(data bus assumed =00)
  545.         getz    d7,1(Work)
  546.         incw    d7
  547.         getz    d7,(Work)       ;get vector
  548.         move.w    (Work),d7
  549.         makePPC
  550.         next
  551.  
  552. ** Intmode 0 is currently not implemented. It should wait for
  553. ** external hardware to put an instruction on the data bus.
  554.  
  555. .mode0        next
  556.  
  557. ** --------------
  558.  
  559.     IFD    Z80_MEMCHECK
  560.  
  561. ** The memory handler is called when a write to a marked address is
  562. ** detected. (That is, when the corresponding memory flag is nonzero
  563. ** upon a write to some address.)
  564. ** The following types of actions are possible:
  565.  
  566. **     Read-only (writes are ignored)
  567. **     Access counter increment
  568. **     Call user-defined handler
  569.  
  570. ** The user-defined handler call has some overhead, and is not
  571. ** recommended for memory addresses/areas that are written to very often,
  572. ** like bit-mapped display memory.
  573.  
  574. ** When the memory handler is reached, the address (word) and value (byte)
  575. ** are found on the user stack. The offsets are WRITE_ADDR and WRITE_VAL,
  576. ** and are defined together with the putz() macro in "Z80_coding.i".
  577.  
  578. ** The memory handler is called in mid-execution of an instruction. All
  579. ** registers may contain important information and must be protected
  580. ** before use. Only the base pointer registers can be assumed to have their
  581. ** proper values. Not even the Pseudo-PC can be guaranteed to be valid.
  582. **   Because of this, it is not possible to extract any information about
  583. ** the current Z80 Cpu status during a memory handler call (I'm sorry).
  584. ** Single-step procedures _in_combination_with_ memory write access
  585. ** checking could be used for such purposes.
  586.  
  587.     ;Memory flag values (signed byte):
  588.     ;  negative (-1 to -128)        read-only
  589.     ;  0                    ok to write (no detection)
  590.     ;  1 to Z80_MEM_CNTNUM             access counters
  591.     ;  Z80_MEM_CNTNUM+1 to Z80_MEM_USR-1    reserved
  592.     ;  Z80_MEM_USR to 127            user-defined handler call
  593.     ;The constants are defined in Z80.i, but are fairly hard-coded
  594.     ;in the detection routine below.
  595.  
  596. MemoryHandler
  597.     ;It is assumed here that a1 and a2 correspond to PPC
  598.     ;and ZSP (the ordering is unimportant) !
  599.  
  600.         movem.l d1/a1,-(sp)
  601.         move.w    8+WRITE_ADDR(sp),a1 ;get Z80 address off stack
  602.         move.b    (FlagsB,a1.w),d1    ;get flag. it is never 0.
  603.         bmi.s    .ROMexit  ;if flag negative, just don't write.
  604.  
  605.         ext.w    d1    ;make flag a whole (positive) word.
  606.  
  607.     ;access counters range from 1 to Z80_MEMCNT_NUM
  608.         cmp.w    #Z80_MEM_CNTNUM,d1
  609.         bgt.s    .notcnt
  610.  
  611.     ;if access counter:
  612.         subq.w    #1,d1        ;index from 0
  613.         add.w    d1,d1
  614.         add.w    d1,d1        ;counters are longword-sized
  615.         addq.l    #1,Z80_AccessCnt(TableB,d1.w)
  616.         lsr.w    #2,d1        ;get byte-size back
  617.         tst.b    Z80_CntType(TableB,d1.w) ;test counter type
  618.         bne.s    .ROMexit    ;no write if nonzero
  619.  
  620. .write_exit    move.b    8+WRITE_VAL(sp),d1 ;get value
  621.         writemem d1,a1        ;write value to dest
  622. .ROMexit    movem.l (sp)+,d1/a1
  623.         rts
  624.  
  625. .notcnt        cmp.w    #Z80_MEM_USR,d1
  626.         blt.s    .write_exit    ;if 'reserved', treat as 0 flag
  627.  
  628.          ;make exception numbers range from 0 to Z80_MEMUSR_NUM-1
  629.         sub.w    #Z80_MEM_USR,d1
  630.  
  631.     ;Call user exception handler:
  632.     ; d1 contains the exception number (word).
  633.     ; d2 contains the value (byte).
  634.     ; a1 contains the Z80 address (word).
  635.     ; a2 is scratch (address of user-def routine).
  636.     ;Handler return values:
  637.     ; d1 zero (longword) if value should be written, nonzero if not.
  638.     ; d2 contains the value (byte).
  639.     ;Changes to a1 and a2 have no effect. All other registers
  640.     ;must be protected before using.
  641.  
  642.         move.l    d2,-(sp)    ;protect register d2
  643.         movem.l    a1/a2,-(sp)    ;protect Z80 address and a2
  644.  
  645.         move.l    Z80_MemHandler(TableB),d2 ;get handler pointer
  646.         beq.s    .usr_nocall    ;only if pointer nonzero
  647.  
  648.         movea.l    d2,a2        ;use a2 for call
  649.         move.b    8+4+8+WRITE_VAL(sp),d2    ;get value off stack
  650.         jsr    (a2)        ;make the call
  651.  
  652. .usr_cont    movem.l (sp)+,a1/a2    ;restore Z80 address and a2
  653.         tst.l    d1        ;test the returned d1
  654.         bne.s    .usr_exit    ;no write if nonzero
  655.         writemem d2,a1        ;write value to Z80 address
  656.  
  657. .usr_exit    move.l    (sp)+,d2    ;restore d2
  658.         movem.l (sp)+,d1/a1    ;same as .ROMexit above
  659.         rts
  660.  
  661. .usr_nocall    moveq    #0,d1        ;signal "write"
  662.         move.b    8+4+8+WRITE_VAL(sp),d2    ;get value off stack
  663.         bra.s    .usr_cont    ;pretend we did call
  664.  
  665.     ENDC ;IFD Z80_MEMCHECK
  666. ** --------------
  667.  
  668. ** End of 'exception handlers'. The following are assorted routines
  669. ** that are also called using "jmp offset(InstrB)":
  670.  
  671. ** --------------
  672.  
  673. ** Offsets and instruction decoding routines for prefixed instructions
  674.  
  675.     INCLUDE prefix_offsets.i
  676.  
  677. ** --------------
  678.  
  679. ** This routine is jumped to when a prefix decoding routine detects an
  680. ** 'out of bounds' pointer. It sets the pointer being updated to
  681. ** 'changed', to assure a re-decode at next execution. This is necessary
  682. ** since the modified-code tests cannot handle wrap-around themselves.
  683. ** Then it moves the PPC to its corresponding location in the lower buffer,
  684. ** and restarts decoding.
  685.  
  686. GoLowBuf    clr.w    -2(PPC)         ;clear the current pointer
  687.         sub.l    #$20000,PPC    ;back 128 K
  688.         bra    DecodeInstr    ;decode instruction all over again
  689.     ;Note: there should really be a testreq here as well,
  690.     ;or we could end up with an eternal run-around-memory loop.
  691. ** --------------
  692.  
  693. ** This label is jumped to when a modified multi-byte instruction is
  694. ** found. PPC is pointing to the word after the one just executed. Any
  695. ** instruction whose opcode bytes cross the 7fff border will always be
  696. ** redecoded before execution. The actual wrap-around handling is done by
  697. ** the decoding routines.
  698.  
  699. StalePtr
  700.         ;Fall through into 'decode instruction':
  701.  
  702. ** --------------
  703.  
  704. ** This routine corresponds to the negative cache pointer used to mark an
  705. ** address as read, used, and unchanged since, but not itself decoded.
  706.  
  707. NotDecoded    Nop    ;Fastest way to get a negative offset.
  708.         ;Fall through straight into 'decode instruction':
  709.  
  710. ** --------------
  711.  
  712. ** All routines not handling normal Z80 instructions, but which will still
  713. ** be jumped to using "jmp offset(InstrB)" should have a negative offset,
  714. ** and thus be placed on this side of InstrBase. This is to save address
  715. ** space for positive offsets.
  716. **   Presently, the only negative pointer that may occur in the cache is
  717. ** the 'unchanged' offset used with prefixed instructions.
  718.  
  719. ** ==============
  720.  
  721. InstrBase
  722.  
  723. base = InstrBase    ;An abbreviation used by the offset tables.
  724.  
  725. ** ==============
  726.  
  727. ** It is assumed throughout the program that the 'decode instruction'
  728. ** routine is placed here, and so corresponds to a zero word in the
  729. ** cache. Upon entry, PPC points to the (word corresponding to the) byte
  730. ** following the first opcode byte of the instruction.
  731.  
  732. DecodeInstr
  733.         getRPC
  734.         decw    d7    ;get first byte
  735.         getz    d7,d7
  736.         and.w    #$00ff,d7
  737.         add.w    d7,d7
  738.         move.w    offsets(PC,d7.w),d7
  739.         move.w    d7,-2(PPC)
  740.         jmp    (InstrB,d7.w)
  741.  
  742. ** In case the read byte was a prefix, the jump will be straight to the
  743. ** corresponding prefixed instruction decoding routine, which will
  744. ** overwrite the same cache address with a new pointer.
  745.  
  746. ** The unprefixed instruction offsets are placed here for the PC-relative
  747. ** addressing mode above.
  748.  
  749.     INCLUDE std_offsets.i
  750.  
  751. ** --------------
  752.  
  753. ** This routine does wrap-around, if it is executed. A pointer to it pads
  754. ** the end of the cache memory, and should be detected as invalid by the
  755. ** 'modified opcode?' tests of the prefixed instructions. Presently, this
  756. ** means it has a nonnegative pointer. PPC points to the word after the
  757. ** one that was just executed.
  758.  
  759. OutOfBounds    sub.l    #$20002,PPC    ;back 128K and one word
  760.         testreq    ;so we can EXITreq even if memory is all non-jumps
  761.  
  762. ** --------------
  763.  
  764. ** This is the normal case of undefined opcode: a 2-byte no-op.
  765.  
  766. Undef_Opcode_2    opcode_2_bytes
  767.         skip 1
  768.         next
  769.  
  770. ** And a more rare form: a 3-byte opcode no-op with an unused offset
  771. ** byte, giving a total of 4 bytes.
  772.  
  773. Undef_Opcode_3    opcode_3_bytes
  774.         skip 3
  775.         next
  776.  
  777. ** --------------
  778.  
  779. ** Calculate the standard offsets:
  780.  
  781. unchanged = NotDecoded-InstrBase
  782. stale_ptr = StalePtr-InstrBase
  783. go_low_buf = GoLowBuf-InstrBase
  784. out_of_bounds = OutOfBounds-InstrBase
  785. undef = Undef_Opcode_2-InstrBase
  786. undef_3byte = Undef_Opcode_3-InstrBase
  787.     IFD Z80_MEMCHECK
  788. memhandler = MemoryHandler-InstrBase
  789.     ENDC
  790.  
  791. ** If a 'generic object' is compiled, some of these _constants_
  792. ** could be referred to externally, and must thus be exported.
  793.  
  794.     IFD    GENERIC_OBJECT
  795.     XDEF    unchanged
  796.     XDEF    stale_ptr
  797.     XDEF    go_low_buf
  798.     XDEF    out_of_bounds
  799.     IFD Z80_MEMCHECK
  800.     XDEF    memhandler
  801.     ENDC
  802.     ENDC
  803.  
  804. ** --------------
  805.  
  806.     INCLUDE std_instr.i     ;Non-implementation-dependent instructions
  807.  
  808.     INCLUDE impldept.i    ;Implementation-dependent instructions
  809.  
  810.     INCLUDE undoc_instr.i    ;The "undocumented" instructions. Refers
  811.                 ;to labels in impldept.i
  812.     EVEN
  813. endrange    ;Actually the address after the last routine, but if
  814.         ;margins are that small, you'd want to rewrite some
  815.         ;stuff anyway. Perhaps move it to distant.i.
  816.  
  817.     IFD VERBOSE
  818.     LIST
  819. ** Offset of (the address after) the last "near" instruction routine.
  820. maxoffset = endrange-InstrBase
  821.     NOLIST
  822.     ELSE
  823. maxoffset = endrange-InstrBase
  824.     ENDC
  825.  
  826.     IFNE    maxoffset>$7FFF
  827.     FAIL    Not enough address space for instruction routines.
  828.     ENDC
  829.  
  830. ** --------------
  831.  
  832.     INCLUDE distant.i    ;Routines removed from the 0-7FFF range.
  833.                 ;The instruction labels must be within the
  834.                 ;range, but jump (absolute long) straight
  835.                 ;on to these labels, named "d_<instr>".
  836.  
  837.  
  838. ** ========================================================================
  839.