Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. Multi-Z80 32 Bit emulator
  2. Copyright 1996, 1997, 1998, 1999, 2000 - Neil Bradley, All rights reserved
  3.  
  4.                             MZ80 License agreement
  5.                             -----------------------
  6.  
  7. (MZ80 Refers to both the assembly code emitted by makez80.c and makez80.c
  8. itself)
  9.  
  10. MZ80 May be distributed in unmodified form to any medium.
  11.  
  12. MZ80 May not be sold, or sold as a part of a commercial package without
  13. the express written permission of Neil Bradley (neil@synthcom.com). This
  14. includes shareware.
  15.  
  16. Modified versions of MZ80 may not be publicly redistributed without author
  17. approval (neil@synthcom.com). This includes distributing via a publicly
  18. accessible LAN. You may make your own source modifications and distribute
  19. MZ80 in source or object form, but if you make modifications to MZ80
  20. then it should be noted in the top as a comment in makez80.c.
  21.  
  22. MZ80 Licensing for commercial applications is available. Please email
  23. neil@synthcom.com for details.
  24.  
  25. Synthcom Systems, Inc, and Neil Bradley will not be held responsible for
  26. any damage done by the use of MZ80. It is purely "as-is".
  27.  
  28. If you use MZ80 in a freeware application, credit in the following text:
  29.  
  30. "Multi-Z80 CPU emulator by Neil Bradley (neil@synthcom.com)"
  31.  
  32. must accompany the freeware application within the application itself or
  33. in the documentation.
  34.  
  35. Legal stuff aside:
  36.  
  37. If you find problems with MZ80, please email the author so they can get
  38. resolved. If you find a bug and fix it, please also email the author so
  39. that those bug fixes can be propogated to the installed base of MZ80
  40. users. If you find performance improvements or problems with MZ80, please
  41. email the author with your changes/suggestions and they will be rolled in
  42. with subsequent releases of MZ80.
  43.  
  44. The whole idea of this emulator is to have the fastest available 32 bit
  45. Multi-Z80 emulator for the x86, giving maximum performance.
  46.  
  47.                          MZ80 Contact information
  48.                           -------------------------
  49.  
  50. Author      : Neil Bradley (neil@synthcom.com)
  51. Distribution: ftp://ftp.synthcom.com/pub/emulators/cpu/makez80.zip (latest)
  52.  
  53. You can join the cpuemu mailing list on Synthcom for discussion of Neil
  54. Bradley's Z80 (and other) CPU emulators. Send a message to
  55. "cpuemu-request@synthcom.com" with "subscribe" in the message body. The
  56. traffic is fairly low, and is used as a general discussion and announcement
  57. for aforementioned emulators.
  58.  
  59.  
  60.                              MZ80 Documentation
  61.                              -------------------
  62.  
  63. MZ80 Is a full featured Z80 emulator coded in 32 bit assembly. It runs well
  64. over a hundred games, in addition to it supporting many undocumented Z80
  65. instructions required to run some of the Midway MCR games, Galaga, and
  66. countless other wonderful Z80 based arcade games.
  67.  
  68. MZ80 Contains a makez80.c program that must be compiled. It is the program
  69. that emits the assembly code that NASM will compile. This minimizes the
  70. possibility of bugs creeping in to MZ80 for the different addressing modes
  71. for each instruction. It requires NASM 0.97 or greater.
  72.  
  73. The goal of MZ80 is to have a high performance Z80 emulator that is capable
  74. of running multiple emulations concurrently at full speed, even on lower-end
  75. machines (486/33). MZ80 Harnesses the striking similarities of both the Z80
  76. and the x86 instruction sets to take advantage of flag handling which greatly
  77. reduces the time required to emulate a processor, so no extra time is spent
  78. computing things that are already available in the native x86 processor,
  79. allowing it to perform leaps and bounds over comparable C based Z80 emulators
  80. on the same platform.
  81.  
  82. MZ80 Is designed exclusively for use with NASM, the Netwide Assembler. This
  83. gives the ultimate in flexibility, as NASM can emit object files that work
  84. with Watcom, Microsoft Visual C++ (4.0-current), DJGPP, Borland C++, and
  85. gcc under FreeBSD or Linux. MZ80 Has been tested with each one of these
  86. compilers and is known to work properly on each.
  87.  
  88.  
  89.                             What's in the package
  90.                             ---------------------
  91.  
  92. MZ80.TXT               - This text file
  93.  
  94. MAKEZ80.C              - Multi Z80 32 Bit emulator emitter program
  95.  
  96. MZ80.H                 - C Header file for MZ80 functions
  97.  
  98.  
  99.                           What's new in this release
  100.                           --------------------------
  101.  
  102. Revision 3.4:
  103.  
  104.         * Fixed the overflow flag not getting cleared in the SetOverflow()
  105.           routine. It caused strange problems with a handful of Genesis games
  106.         * Removed invalid instruction in the C version so that more
  107.           instructions will execute
  108.  
  109. Revision 3.3:
  110.  
  111.         * Undocumented opcodes added to the C emitter
  112.         * Bug fix to the C emission that properly handles shared RAM regions
  113.           (I.E. with handlers that are NULL)
  114.         * Now using 32 bit registers to do register/memory access. Slight
  115.           speed increase (assembly version only)
  116.  
  117. Revision 3.2:
  118.        
  119.         * R Register emulation now accurate with a real Z80
  120.         * mz80int() Called when interrupts are disabled causes the
  121.           z80intPending flag to be set, and an interrupt will be caused after
  122.           the execution of EI and the next instruction. See "IMPORTANT NOTE
  123.           ABOUT INTERRUPTS" below
  124.         * The instruction after EI executes fully before interrupt status is
  125.           checked. (as does a real Z80)
  126.  
  127.  
  128. Revision 3.1:
  129.  
  130.         * Fixed bug in memory dereference when handler was set to NULL (keeps
  131.           system from crashing or faulting)
  132.         * Removed the only stricmp() from the entire file and replaced it
  133.           with strcmp() so that stdlibs without it will compile
  134.         * Changed cyclesRemaining > 0 to cyclesRemaining >= 0 to be compatible
  135.           with the ASM core
  136.         * Removed additional sub [dwCyclesRemaining], 5 at the beginning of
  137.           mz80exec() (ASM Core only). Increases timing accuracy.
  138.         * NMIs And INTs add additional time to dwElapsedTicks as it should
  139.         * mz80ReleaseTimeslice() Sets remaining clocks to 0 instead of 1
  140.  
  141.  
  142. Revision 3.0:
  143.  
  144.         * All instructions validated against a real Z80. Used an ISA card
  145.           with a Z80 on it to validate flag handling, instruction handling,
  146.           timing, and other goodies. The only thing not implemented/emulated
  147.           is flag bit 3 & 5 emulation. Believed to be 100% bug free!
  148.         * 80% Speed improvement over version 2.7 of mz80
  149.         * z80stb.c Removed. Use -c to emit a C version of mz80! API compatible!
  150.           Note that this is mostly, but not fully, debugged, so consider the
  151.           C version a beta! It's at least healthier than z80stb.c was. The C
  152.           version does not include the undocumented Z80 instructions.
  153.         * mz80nmi() No longer trashes registers it uses when using -cs
  154.         * IN/OUT Instructions work properly when using -16
  155.         * IN A, (xxh) uses A as high 8 bits of I/O fetch address when using -16
  156.         * IM 0/IM 1 Description in documentation fixed
  157.         * Sizes of all context registers increased to 32 bits - for speed!
  158.         * IFF1/IFF2 Now properly emulated
  159.         * JR Instruction offset can fetch from $ffff and properly wrap
  160.         * LDIR/LDDR Instruction now won't go to completion - instead it will
  161.           run until BC=0 or the # of cycles to execute have expired. These
  162.           instructions used to run to completion - even beyond the # of cycles
  163.           left to execute
  164.         * INI/IND/INIR/INDR countdown bug fixed - it was decrementing B twice
  165.           for each IN! Whoops!
  166.         * If you specify NULL as a handler address to a memory region, mz80 will
  167.           use vpData as a pointer to where that block of data resides. Quite
  168.           useful for multiprocessor emulations that share the same memory.
  169.         * EDI Now keeps track of cycle counting for faster execution
  170.         * Modified memory region scanning code to use 32 bit registers instead
  171.           of their 16 bit counterparts
  172.         * Get/SetContext() uses rep movsd/movsb. Insignificant overall, but
  173.           why waste the time?
  174.         * Debugging routines added. See the "DEBUGGING" section below for more
  175.           information. NOTE: The debugging routines are not yet available in
  176.           the C emission.
  177.         * Timing done slightly differently now. Mz80 now executes one
  178.           instruction past the timing given on input. For example, mz80exec(0)
  179.           will cause a single instruction to be executed (thusly -ss was
  180.           removed).
  181.  
  182. Revision 2.7:
  183.  
  184.         * Fixed OTIR/OTDR/INIR/INDR instructions so their 16 bit counterparts
  185.           work properly
  186.         * Emulation core 30-70% faster overall than 2.6 due to optimization to
  187.           the timing routines
  188.         * Replaced word reads/writes with a special word write routine rather
  189.           than the standard calling to read/write byte functions
  190.         * z80stb.c (the C equivalent of mz80) compiles properly now
  191.         * Fixed OS/2 text/segment issue
  192.         * Fixed bug in set/getCPU context that ensures that ES=DS and avoids
  193.           crashes. Caused crashes under OS/2 and other OS's
  194.  
  195. Revision 2.6:
  196.  
  197.         * Emulator core 5-30% faster overall. Some 16 and 8 bit instructions
  198.           sped up when using their 32 bit equivalents.
  199.         * Fix to -l so that proper labels without leading and trailing
  200.           underscores so Linux/FreeBSD compiles will work properly
  201.         * Single step now executes the # of instructions passed in to z80exec()
  202.           instead of just 1 as it had in prior releases. This is only active
  203.           when the -ss option is used.
  204.         * The -nt option was added. This will cause the timing information to
  205.           not be added in, speeding up execution. Warning: Only do this if your
  206.           emulated target does not require instruction timing!
  207.         * Updated documentation errors
  208.         * C Version of mz80 (mz80.c) that is API compliant is distributed with
  209.           the archive (With kind permission of Edward Massey).
  210.  
  211. Revision 2.5:
  212.  
  213.         * Fixed an unconditional flag being cleared in the ddcbxx instructions.
  214.           It caused Donkey Kong's barrels to not roll.
  215.  
  216. Revision 2.4:
  217.  
  218.         * Fixed improper HALT handling (didn't advance the PTR when it should)
  219.         * Fixed SRL (IX+$xx) instruction so that carry wasn't trashed
  220.         * Fixed single stepping problems with it giving too much time to
  221.           any given instruction
  222.         * Fixed half carry flag handling with 16 bit SBC and ADD instructions
  223.         * Fixed DAA emulation so that parity flags weren't getting trashed
  224.  
  225. Revision 2.3:
  226.  
  227.         * Fixed many stack handling bugs
  228.         * Timing problems fixed. The prior version was causing massive
  229.           overruns on maximum timeslices with some insutructions.
  230.  
  231. Revision 2.2:
  232.  
  233.         * Fixed a bug in CPI/CPD/CPIR/CPDR that mishandled flags
  234.         * All known bugs are out of mz80 now
  235.         * Added the -cs option to route all stack operations through the
  236.           handlers (required for games like Galaga)
  237.  
  238. Revision 2.1:
  239.  
  240.         * Fixed a bug in CPI/CPD/CPIR/CPDR that caused intermittent lockups.
  241.           Also fixed a bug that caused erratic behavior in several video games.
  242.         * Added INI/IND/INIR/INDR instruction group
  243.         * Added OUTI/OUTD/OTIR/OTDR instruction group
  244.  
  245. Revision 1.0:
  246.  
  247.         * First release! The whole thing is new!
  248.  
  249.  
  250. ASSEMBLING FOR USE WITH WATCOM C/C++
  251. ------------------------------------
  252.  
  253. Watcom, by default, uses register calling conventions, as does MZ80. To
  254. create a proper emulator for Watcom:
  255.  
  256.         makez80 MZ80.asm -x86
  257.  
  258. From here:
  259.  
  260.         nasm -f win32 MZ80.asm
  261.  
  262. Link the MZ80.obj with your Watcom linker.
  263.  
  264.  
  265. ASSEMBLING FOR USE WITH MICROSOFT VISUAL C++ AND BORLAND C++
  266. --------------------------------------------------------------------
  267.  
  268. Visual C++ and Borland C++ use stack calling conventions by default. To
  269. create a proper emulator for these compilers:
  270.  
  271.         makez80 MZ80.asm -s -x86
  272.  
  273. For Visual C++ or Borland C++:
  274.  
  275.         nasm -f win32 MZ80.asm
  276.  
  277. Link with your standard Visual C++ or Borland C++.
  278.  
  279.  
  280. ASSEMBLING FOR USE WITH DJGPP, GCC/FREEBSD, OR GCC/LINUX
  281. --------------------------------------------------------------------
  282.  
  283. DJGPP Uses stack calling conventions:
  284.  
  285.         makez80 MZ80.asm -s -x86
  286.  
  287. To assemble:
  288.  
  289.         nasm -f coff MZ80.asm
  290.  
  291. Link with your standard DJGPP linker. The same holds true for GCC under
  292. FreeBSD or Linux. If you're using GCC, use the -l option to generate "plain"
  293. labels so that gcc's linker will properly link things.
  294.  
  295.  
  296. MAKEZ80 COMMAND LINE OPTIONS
  297. ----------------------------
  298.  
  299. -s      - Use stack calling conventions (DJGPP, MSVC, Borland, etc...)
  300.  
  301. -cs     - Force all stack operations to go through the Read/Write memory handlers.
  302.           This slows things down, but is useful when needed.
  303.  
  304. -16     - Treat all I/O input and output as 16 bit (BC)
  305.  
  306. -l      - Create 'plain' labels - ones without leading and trailing underscores
  307.  
  308. -nt     - Do not generate timing code - this speeds the emulator up, but the
  309.           downside is that no timing info is available.
  310.  
  311. -c      - Emit a C mz80 emulator (API Compatible with the assembly version -
  312.           handy for porters!)
  313.  
  314. -x86    - Emit an assembly (x86) mz80 emulator
  315.  
  316. -os2    - Generate OS/2 compatible segmentation
  317.  
  318.  
  319. IMPORTANT NOTE ABOUT INTERRUPTS
  320. -------------------------------
  321.  
  322. A minor change was made between the 3.1 and 3.2 versions of makez80 in the
  323. way that interrupts were handled.
  324.  
  325. On a real Z80, the !INT line is a level triggered interrupt, meaning that if
  326. the interrupt line is held low, the Z80 will continue to take interrupts
  327. immediately after the instruction after the EI instruction is executed until
  328. the interrupt line is high again.
  329.  
  330. In 3.1, if an interrupt came in and interrupts were disabled, the interrupt
  331. would never be "latched" for later execution. The Z80 does not have any
  332. internal latching capabilities, however external hardware often does hold
  333. the interrupt line low until the interrupt is executed, in effect, a latch.
  334.  
  335. I've only found one video game so far that requires the "raising/lowering"
  336. of the interrupt line (Ataxx). In the games that I've tried, it has improved
  337. performance, in some cases drastically, and in others not at all. This can
  338. be accounted for by interrupts being taken now, where they were being dropped
  339. in prior mz80 releases.
  340.  
  341. mz80 Emulates the most commonly used scenario. Now when mz80int() is executed
  342. and a nonzero value is returned (indicating interrupts were disabled), it
  343. will set z80intPending, and the interrupt will be taken after execution of
  344. one instruction beyond the EI instruction.
  345.  
  346. So now, if mz80int() returns a nonzero value, that means an interrupt is
  347. latched. If clearing this latch is desired or the old behavior of 3.1 is
  348. desired, make a call to the mz80ClearPendingInterrupt() call. It's a 2
  349. instruction call that has extremely small overhead and will not affect
  350. performance in any measurable way.
  351.  
  352. In any case, MZ80 will now execute one instruction after EI regardless of
  353. how much time is available to avoid the possibility of an interrupt request
  354. coming in directly after the EI instruction.
  355.  
  356.  
  357. STEPS TO EMULATION
  358. ------------------
  359.  
  360. NOTE: -16 Is a command line option that will treat all I/O as 16 bit. That
  361. is, in an instruction like "IN AL, (C)", the addressed passed to the I/O
  362. handler will be BC instead of just C. Bear this in mind when considering your
  363. emulated platform.
  364.  
  365. There are a few steps you want to go through to get proper emulation, and a
  366. few guidelines must be followed.
  367.  
  368. 1) Create a MZ80CONTEXT
  369.  
  370. 2) Create your virtual 64K memory space using whatever means of obtaining
  371.    memory you need to do.
  372.  
  373. 3) Set mz80Base in your context to be the base of your 64K memory space
  374.  
  375. 4) Load up your image to be emulated within that 64K address space.
  376.  
  377. 5) Set z80IoRead and z80IoWrite to their appropriate structure arrays. Here's
  378.    an example:
  379.  
  380. struct z80PortRead ReadPorts[] =
  381. {
  382.         {0x10,  0x1f,   SoundChip1Read},
  383.         {0x20,  0x2f,   SoundChip2Read}
  384.         {(UINT32) -1,     (UINT32) -1, NULL}
  385. };
  386.  
  387. When an IN instruction occurs, mz80 will probe this table looking for a
  388. handler to the address of the "IN" instruction. If it is found in the list,
  389. it's up to the handler to return the proper value. Otherwise, a value of
  390. 0ffh is returned internally if no handler for that I/O address is found. In
  391. the case above, SoundChip1Read is called when the I/O address is between 0x10-
  392. 0x1f. A similar structure is used for I/O writes as well (OUT):
  393.  
  394. struct z80PortWrite WritePorts[] =
  395. {
  396.         {0x20,  0x2f,   SoundChip2Write},
  397.         {0x30,  0x36,   VideoCtrlWrite},
  398.         {(UINT32) -1,   (UINT32) -1, NULL}
  399. }
  400.  
  401. Of course, this does the opposite that the z80PortRead struct, and instead
  402. looks for a handler to hand some data to. If it doesn't find an appropriate
  403. handler, nothing happens.
  404.  
  405. 6) Set mz80MemoryRead & mz80MemoryWrite to their appropriate structure
  406.    arrays. Here is an example:
  407.  
  408. struct MemoryWriteByte GameWrite[] =
  409. {
  410.         {0x3000, 0x3fff,  VideoWrite},
  411.         {0x4000, 0x4fff,  SpriteWrite},
  412.         {(UINT32) -1,     (UINT32) -1, NULL}
  413. };
  414.  
  415. The above example says that any time a write occurs in the 0x3000-0x3fff
  416. range, call the VideoWrite routine. The same holds true for the SpriteWrite
  417. region as well.
  418.  
  419. NOTE: When your write handler is called, it is passed the address of the
  420. write and the data that is to be written to it. If your handler doesn't
  421. write the data to the virtual image, the mz80 internal code will not.
  422.  
  423. NOTE: These routines will *NOT* be called when execution asks for these
  424. addresses. It will only call them when a particular instruction uses the
  425. memory at these locations.
  426.  
  427. If you wish for a region to be RAM, just leave it out of your memory region
  428. exception list. The WriteMemoryByte routine will treat it as read/write
  429. RAM and will write to mz80Base + addr directly.
  430.  
  431. If you wish to protect ROM regions (not often necessary), create a range that
  432. encompasses the ROM image, and have it call a routine that does nothing. This
  433. will prevent data from being written back onto the ROM image.
  434.  
  435. Leave your last entry in the table as shown above, with a null handler and
  436. 0xffffffff-0xffffffff as your read address. Even though the Z80 only
  437. addresses 64K of space, the read/write handlers are defined as 32 bit so
  438. the compiler won't pass junk in the upper 16 bits of the address lines. Not
  439. only that, it allows orthoganality for future CPU emulators that may use
  440. these upper bits.
  441.  
  442. You can do a mz80GetContext() if you'd like to read the current context of
  443. the registers. Note that by the time your handler gets called, the program
  444. counter will be pointing to the *NEXT* instruction.
  445.  
  446. struct MemoryReadByte GameRead[] =
  447. {
  448.         {0x2000,        0x200f,         ReadHandler},
  449.         {(UINT32) -1,     (UINT32) -1,  NULL}
  450. };
  451.  
  452. Same story here. If you have a special handler for an attempted read at a
  453. particular address, place its range in this table and create a handler
  454. routine for it.  
  455.  
  456. If you don't define a handler for a particular region, then the ReadMemoryByte
  457. in mz80.ASM will actually read the value out of mz80Base + the offset
  458. required to complete the instruction.
  459.  
  460. 7) Set the intAddr and nmiAddr to the addresses where you want mz80 to start
  461.    executing when an interrupt or NMI happens. Take a look at the section
  462.    entitled "INTERRUPTS" below for more information on this.
  463.  
  464. 8) Call mz80SetContext() on your Z80 context
  465.  
  466. 9) Call mz80Reset(). This will prime the program counter and cause a virtual
  467.    CPU-wide reset.
  468.  
  469. 10) Once you have those defined, you're ready to begin emulation. There's some
  470.     sort of main loop that you'll want. Maybe something like:
  471.  
  472.         while (hit == 0)
  473.         {
  474.                 if (lastSec != (UINT32) time(0))
  475.                 {
  476.                         diff = (mz80clockticks - prior) / 3000000;
  477.                         printf("%ld Clockticks, %ld frames, %ld Times original speed\n", MZ80clockticks - prior, frames, diff);
  478.                         frames = 0;
  479.                         prior = mz80clockticks;
  480.                         lastSec = time(0);
  481.                         if (kbhit())
  482.                         {
  483.                                 getch();
  484.                                 hit = 1;
  485.                         }
  486.                 }
  487.  
  488.                 /* 9000 Cycles per NMI (~3 milliseconds @ 3MHZ) */
  489.  
  490.                 dwResult = mz80exec(9000);
  491.                 mz80clockticks += mz80GetElapsedTicks(TRUE);
  492.                 mz80nmi();
  493.  
  494.                 /* If the result is not 0x80000000, it's an address where
  495.                    an invalid instruction was hit. */
  496.  
  497.                 if (0x80000000 != dwResult)
  498.                 {
  499.                         mz80GetContext(&sCpu1);
  500.                         printf("Invalid instruction at %.2x\n", sCpu1.MZ80pc);
  501.                         exit(1);
  502.                 }
  503.         }
  504.  
  505. Call mz80exec() With the # of virtual CPU cycles you'd like mz80 to
  506. execute. Be sure to use the mz80GetElapsedTicks() call *AFTER* execution to
  507. see how many virtual CPU cycles it actually executed. For example, if you tell
  508. mz80 to execute 500 virtual CPU cycles, it will execute slightly more. Anything
  509. from 500 to 524 (24 cycles being the longest any 1 instruction takes in the
  510. Z80).
  511.  
  512. Use the mz80GetElapsedTicks() call for more accurate cycle counting. Of course,
  513. this is only if you have *NOT* included the -nt option.
  514.  
  515. If you pass FALSE to the mz80GetElapsedTicks() function, the internal CPU
  516. elapsed tick clock will not be reset. The elapsed tick counter is something
  517. that continues to increase every emulated instruction, and like an odometer,
  518. will keep counting unless you pass TRUE to mz80GetElapsedTicks(), of which
  519. case it will return you the current value of the elapsed ticks and set it to
  520. 0 when complete.
  521.  
  522. NOTE: The bigger value you pass to mz80exec, the greater benefit you get out
  523. of the virtual registers persisting within the emulator, and it will run
  524. faster. Pass in a value that is large enough to take advantage of it, but
  525. not so often that you can't handle nmi or int's properly.
  526.  
  527. If you wish to create a virtual NMI, call mz80nmi(), and it will be taken
  528. the next time you call mz80exec, or alternately if you have a handler call
  529. mz80nmi/mz80int(), the interrupt will be taken upon return. Note that
  530. mz80nmi() doesn't actually execute any code - it only primes the emulator to
  531. begin executing NMI/INT code.
  532.  
  533. NOTE: mz80int() is defined with a UINT32 as a formal parameter. Depending
  534. upon what interrupt mode you're executing in (described later), it may or may
  535. not take a value.
  536.  
  537. NMI's can interrupt interrupts, but not the other way around - just like a
  538. real Z80. If your program is already in an interrupt, another one will not be
  539. taken. The same holds true for an NMI - Just like a real Z80!
  540.  
  541.  
  542. MUTLI-PROCESSOR NOTES
  543. ---------------------
  544.  
  545. Doing multi processor support is a bit trickier, but is still fairly straight-
  546. forward.
  547.  
  548. For each processor to be emulated, go through steps 1-7 above - giving each
  549. CPU its own memory space, register storage, and read/write handlers.
  550.  
  551.  
  552. EXECUTION OF MULTI-CPUS:
  553. -------------------------
  554.  
  555. When you're ready to execute a given CPU, do the following:
  556.  
  557.         mz80SetContext(contextPointer);
  558.  
  559. This will load up all information saved before into the emulator and ready it
  560. for execution. Then execute step 7 above to do your virtual NMI's, interrupts,
  561. etc... All CPU state information is saved within a context.
  562.  
  563. When the execution cycle is complete, do the following to save the updated
  564. context away for later:
  565.  
  566.         mz80GetContext(contextPointer);
  567.  
  568. Give each virtual processor a slice of time to execute. Don't make the values
  569. too small or it will spend its time swapping contexts. While this in itself
  570. isn't particularly CPU expensive, the more time you spend executing the better.
  571. mz80 Keeps all of the Z80 register in native x86 register (including most
  572. of the flags, HL, BC, and A). If no context swap is needed, then you get the
  573. added advantage of the register storage. For example, let's say you were
  574. running two Z80s - one at 2.0MHZ and one at 3.0MHZ. An example like this
  575. might be desirable:
  576.  
  577.         mz80SetContext(cpu1Context);    // Set CPU #1's information
  578.         mz80exec(2000);         // 2000 Instructions for 2.0MHZ CPU
  579.         mz80GetContext(cpu1Context);    // Get CPU #1's state info
  580.  
  581.         mz80SetContext(cpu2Context);    // Set CPU #2's state information
  582.         mz80exec(3000);         // 3000 Instructions for 3.0MHZ CPU
  583.         mz80GetContext(cpu2Context);    // Get CPU #2's state information
  584.  
  585. This isn't entirely realistic, but if you keep the instruction or timing
  586. ratios between the emulated CPUs even, then timing is a bit more accurate.
  587.  
  588. NOTE: If you need to make a particular CPU give up its own time cycle because
  589. of a memory read/write, simply trap a particular address (say, a write to a
  590. slave processor) and call mz80ReleaseTimeslice(). It will not execute any
  591. further instructions, and will give up its timeslice. Put this in your
  592. read/write memory trap.
  593.  
  594. NOTE: You are responsible for "holding back" the processor emulator from
  595. running too fast.
  596.  
  597.  
  598. INTERRUPTS
  599. ----------
  600.  
  601. The Z80 has three interrupt modes: IM 0 - IM 2. Each act differently. Here's
  602. a description of each:
  603.  
  604. IM 0
  605.  
  606. This mode will cause the Z80 to be able to pull a "single byte instruction"
  607. off the bus when an interrupt occurs. Since we're not doing bus cycle
  608. emulation, it acts identically to mode 1 (described below). The formal
  609. parameter to mz80int() is ignored. There is really no point in actually
  610. emulating the instruction execution since any instruction that would be
  611. executed would be a branch instruction!
  612.  
  613. IM 1
  614.  
  615. This mode is the "default" mode that the Z80 (and mz80 for that matter) comes
  616. up in. When you call mz80reset(), the interrupt address is set to 38h and
  617. the NMI address is set to 66h. So when you're in IM 1 and mz80int() is
  618. called, the formal parameter is ignored and the z80intAddr/z80nmiAddr values
  619. are appropriately loaded into the program counter.
  620.  
  621. IM 2
  622.  
  623. This mode causes the Z80 to read the upper 8 bits from the current value
  624. of the "I" register, and the lower 8 bits from the value passed into mz80int().
  625. So, if I contained 35h, and you did an mz80int(0x64), then an interrupt at
  626. address 3564h would be taken. Simple!
  627.  
  628.  
  629. OTHER GOODIES
  630. -------------
  631.  
  632. MZ80 Has a nice feature for allowing the same handler to handle different
  633. data regions on a single handler. Here's an example:
  634.  
  635. struct PokeyDataStruct Pokey1;
  636. struct PokeyDataStruct Pokey2;
  637.  
  638. struct MemoryWriteByte GameWrite[] =
  639. {
  640.         {0x1000, 0x100f,  PokeyHandler, Pokey1},
  641.         {0x1010, 0x101f,  PokeyHandler, Pokey2},
  642.         {(UINT32) -1,     (UINT32) -1, NULL}
  643. };
  644.  
  645. void PokeyHandler(UINT32 dwAddr, UINT8 bData, struct sMemoryWriteByte *psMem)
  646. {
  647.         struct PokeyDataStruct *psPokey = psMem->pUserArea;
  648.  
  649.         // Do stuff with psPokey here....
  650. }
  651.  
  652. This passes in the pointer to the sMemoryWriteByte structure that caused
  653. the handler to be called. The pUserArea is a user defined address that can
  654. be anything. It is not necessary to fill it in with anything or even
  655. initialize it if the handler doesn't actually use it.
  656.  
  657. This allows a single handler to handle multiple data references. This is
  658. particularly useful when handling sound chip emulation, where there might
  659. be more than one of a given device. Sure beats having multiple unique
  660. handlers that are identical with the exception of the data area where it
  661. writes! This allows a good deal of flexibility.
  662.  
  663. The same construct holds for MemoryReadByte, z80PortRead, and z80PortWrite,
  664. so all can take advantage of this feature.
  665.  
  666.  
  667. SHARED MEMORY FEATURES
  668. ----------------------
  669.  
  670. MZ80 Also has another useful feature for dealing with shared memory regions:
  671.  
  672. UINT8 bSharedRAM[0x100];
  673.  
  674. struct MemoryWriteByte Processor1[] =
  675. {
  676.         {0x1000, 0x10ff, NULL, bSharedRAM},
  677.         {(UINT32) -1, (UINT32) -1, NULL}
  678. };
  679.  
  680. struct MemoryWriteByte Processor2[] =
  681. {
  682.         {0x1000, 0x10ff, NULL, bSharedRAM},
  683.         {(UINT32) -1, (UINT32) -1, NULL}
  684. };
  685.  
  686. If the handler address is NULL, mz80 will look at the pUserArea field as a
  687. pointer to RAM to read from/write to. This comes in extremely handy when you
  688. have an emulation that requires two or more processors writing to the same
  689. memory block. And it's lots faster than creating a handler that writes to
  690. a common area as well.
  691.  
  692.  
  693. DEBUGGING
  694. ---------
  695.  
  696. Several new functions have been added to mz80 that assist the emulator
  697. author by providing a standard set of functions for register access:
  698.  
  699. UINT8 mz80SetRegisterValue(void *pContext, UINT32 dwRegister, UINT32 dwValue)
  700.  
  701. This allows setting of any register within the Z80. The register field can be
  702. one of the following values (defined in mz80.h):
  703.  
  704.         CPUREG_PC
  705.         CPUREG_Z80_AF
  706.         CPUREG_Z80_BC
  707.         CPUREG_Z80_DE
  708.         CPUREG_Z80_HL
  709.         CPUREG_Z80_AFPRIME
  710.         CPUREG_Z80_BCPRIME
  711.         CPUREG_Z80_DEPRIME
  712.         CPUREG_Z80_HLPRIME
  713.         CPUREG_Z80_IX
  714.         CPUREG_Z80_IY
  715.         CPUREG_Z80_SP
  716.         CPUREG_Z80_I
  717.         CPUREG_Z80_R
  718.         CPUREG_Z80_A
  719.         CPUREG_Z80_B
  720.         CPUREG_Z80_C
  721.         CPUREG_Z80_D
  722.         CPUREG_Z80_E
  723.         CPUREG_Z80_H
  724.         CPUREG_Z80_L
  725.         CPUREG_Z80_F
  726.         CPUREG_Z80_CARRY
  727.         CPUREG_Z80_NEGATIVE
  728.         CPUREG_Z80_PARITY
  729.         CPUREG_Z80_OVERFLOW
  730.         CPUREG_Z80_HALFCARRY
  731.         CPUREG_Z80_ZERO
  732.         CPUREG_Z80_SIGN
  733.         CPUREG_Z80_IFF1
  734.         CPUREG_Z80_IFF2
  735.  
  736. Each individual register's value can be set, including the flags at the end.
  737. The only valid values for the flags are 1 and 0. Setting these will
  738. automatically adjust the "F" register.
  739.  
  740. If pContext is NULL, then the registers in the currently active context are
  741. changed. If pContext points to a non-NULL area, that area is assumed to be
  742. a CONTEXTMZ80 structure where the new register value will be written.
  743.  
  744. If mz80SetRegisterValue() returns a nonzero value, either the register value
  745. or register is out of range or invalid.
  746.  
  747.  
  748. UINT32 mz80GetRegisterValue(void *pContext, UINT32 dwRegister)
  749.  
  750. This returns the value of the register given on input (listed above as
  751. CPUREG_Z80_xxxxx). Flag values will be 1 or 0.
  752.  
  753. If pContext is NULL, then the registers in the currently active context are
  754. read. If pContext points to a non-NULL area, that area is assumed to be
  755. a CONTEXTMZ80 structure from which register values are pulled.
  756.  
  757.  
  758. UINT32 mz80GetRegisterTextValue(void *pContext, UINT32 dwRegister,
  759.                                  UINT8 *pbTextArea)
  760.  
  761. This returns the textual representation of the value of a given register.
  762. It is a text printable string that can be used in sprintf() statements and
  763. the like. This function is useful because different representations for
  764. registers (like flags) can be a group of 8 flag bytes instead of a single
  765. value.
  766.  
  767. On entry, pContext being set to NULL indicates that mz80 should get the
  768. register value from the currently active context. Otherwise, it is assumed
  769. to be pointing to a CONTEXTMZ80 structure, which contains the value of the
  770. registers to be read.
  771.  
  772. pbTextArea points to a buffer where the value text can be written. This points
  773. to a user supplied buffer.
  774.  
  775. On exit, if any nonzero value is encountered, either the register # is out
  776. of range or pbTextArea is NULL.
  777.  
  778.  
  779. UINT8 *mz80GetRegisterName(UINT32 dwRegister)
  780.  
  781. This returns a pointer to the textual name of the register passed in. NULL
  782. Is returned if the register index (CPUREG_Z80_xxxx table described above) is
  783. out of range. DO NOT MODIFY THE TEXT! It is static data.
  784.  
  785.  
  786. FINAL NOTES
  787. -----------
  788.  
  789. I have debugged MZ80.ASM to the best of my abilities. There might still be
  790. a few bugs floating around in it, but I'm not aware of any. I've validated
  791. all instructions (That I could) against a custom built Z80 on an ISA card
  792. (that fits in a PC) so I'm quite confident that it works just like a real
  793. Z80.
  794.  
  795. If you see any problems, please point them out to me, as I am eager to make
  796. mz80 the best emulator that I can.
  797.  
  798. If you have questions, comments, etc... about mz80, please don't hesitate
  799. to send me an email. And if you use mz80 in your emulator, I'd love to take
  800. a look at your work. If you have special needs, or need implementation
  801. specific hints, feel free to email me, Neil Bradley (neil@synthcom.com). I
  802. will do my best to help you.
  803.  
  804. Enjoy!
  805.  
  806. Neil Bradley
  807. neil@synthcom.com
  808.  
  809.  
  810.