initial import
[picodrive.git] / cpu / mz80 / mz80.txt
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