cc68a136 |
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 |