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