d8888 888 d88888 888 d88P888 888 d88P 888 888d888 .d8888b 8888b. .d88888 .d88b. d88P 888 888P" d88P" "88b d88" 888 d8P Y8b d88P 888 888 888 .d888888 888 888 88888888 d8888888888 888 Y88b. 888 888 Y88b 888 Y8b. d88P 888 888 "Y8888P "Y888888 "Y88888 "Y8888 8888888888 888 888 d8b 888 888 888 Y8P 888 888 888 8888888 88888b.d88b. 888 888 888 8888b. 888888 888 .d88b. 88888b. 888 888 "888 "88b 888 888 888 "88b 888 888 d88""88b 888 "88b 888 888 888 888 888 888 888 .d888888 888 888 888 888 888 888 888 888 888 888 Y88b 888 888 888 888 Y88b. 888 Y88..88P 888 888 8888888888 888 888 888 "Y88888 888 "Y888888 "Y888 888 "Y88P" 888 888 888 888 88888888888 888 888 888 888 888 888 8888888888 .d88b. 888 888 888 888 .d88b. 888 888 d88""88b 888 888 888 888 d88""88b 888 888 888 888 888 888 888 888888 888 888 888 888 888 Y88..88P Y88b 888 d88P 888 Y88..88P 888 888 "Y88P" "Y8888888P" 888 "Y88P" Version 0.40 Compiled by Michael Adcock email: adcockm@usa.net March 31, 1997 THIS DOCUMENT, "The Arcade Emultion HowTo", AND THE INFORMATION CONTAINED HEREIN IS COPYRIGHT MICHAEL ADCOCK AND THE RESPECTIVE AUTHORS (AS NOTED IN THIS DOCUMENT). YOU MAY DISTRIBUTE THIS DOCUMENT FREELY, AS LONG AS THERE IS NO MONEY CHARGED FOR THE MEDIA THAT IT IS PLACED ON, AND THE ENTIRE DOCUMENT IS *NOT* ALTERED IN ANY WAY. IF ANYONE IS INTERESTED IN PUBLISHING THIS DOCUMENT FOR SALE, YOU *MUST* GET PERMISSION FROM MICHAEL ADCOCK AND THE RESPECTIVE AUTHORS (AS NOTED IN THIS DOCUMENT). -------------------------------------------------------------------- Yb dP 8 w w dP"Yb Yb db dP 8d8b. .d88 w8ww ." d88b 8d8b. .d88b Yb db dP " d8 YbdPYbdP 8P Y8 8 8 8 `Yb. 8P Y8 8.dP' YbdPYbdP dP YP YP 8 8 `Y88 Y8P Y88P 8 8 `Y88P YP YP w -------------------------------------------------------------------- - (7/2/98): It's been a long time since this HowTo was updated. I think it has long outlived it's usefulness, but it's interesting for historical reasons, and maybe someone will still find something useful in it! I have no plans to update it or release a new version. If anyone would like to pick it up and start updating it, let me know! - (7/2/98): Please note that any web links or FTP site addresses have not been checked since March of 1997! Some might be dead. I have also decided to remove section R.4, which was very incomplete. - Updated my email address. It is now: adcockm@usa.net. - Removed the Thanks To... section. I have tried to individually credit sources of information in each section. I apologize if someone isn't given credit where they should be. - Lots of changes and additions to various sections, check the *'d sections below... -------------------------------------- 888b. 8 .8 8 8 8d8b 88b. .d8b. d88b .d88b 8wwP' 8b d8 8P 8 8 8' .8 `Yb. 8.dP' 8 `Y8P8 8 88P' `Y8P' Y88P `Y88P 8 -------------------------------------- This document is designed to aid anyone considering whether to write an emulator for an arcade game machine. It will attempt to answer frequently asked questions, give some step by step tutorials, and provide the resources necessary for a capable programmer to begin work on an emulator for an arcade game. Please note that although some of the information provided is generic enough to apply to emulation of any system, the primary focus of this document, and the resources provided, is arcade game emulation. This document contains no information about the commercial emulation packages that are available. If you have any information that should be added to this document, or you find errors, then please email adcockm@usa.net ! -------------------------------------------- .d88b w w 8P .d8b. 8d8b. w8ww .d88b 8d8b. w8ww d88b 8b 8' .8 8P Y8 8 8.dP' 8P Y8 8 `Yb. `Y88P `Y8P' 8 8 Y8P `Y88P 8 8 Y8P Y88P -------------------------------------------- * What's New? ----------- Purpose ------- * Contents -------- Q and A ------- Q.0 Trying to write an arcade emulator is crazy, isn't it? Q.1 Which game would you recommend starting on? Q.1.1 Which games are 'easiest' to emulate? Q.1.2 Which games have the most available documentation? Q.2 How do I START? * Q.3 What language should I use? Q.3.1 Do I *have* to use Assembly? Q.3.1.1 Are you SURE about this Assembly business? :) Q.3.1.2 Doesn't the choice of language depend on the target game/system? Q.3.1.3 What about portability? Q.3.2 But haven't some arcade emulators been written in C/C++? Q.3.3 What about Java? Q.4 Could you explain CPU emulation? Q.4.1 CPU emulation sounds VERY complicated, how should I START? Q.4.1.1 Is the 68k series of processors 'easy' to emulate on PCs? Q.4.1.2 Why were only a handful of processors used in arcade games? Q.4.1.3 Should I try to learn the assembly of the target platform? Q.4.1.4 How did games with multiple CPUs work? Q.4.2 Should I use CPU emulation code that is freely available? Q.4.2.1 Where can I find freely available source code? Q.4.2.2 How do I install DJGPP and Allegro taking only *limited* space? Q.4.3 How do the CPU and ROMs interact? Q.4.4 How should I handle CPU opcodes? Q.4.5 What is Pokey? Q.4.6 What is Slapstic? Q.4.7 What about translation? Q.4.8 Is there anything else I should know about CPU emulation? * Q.4.9 How might I implement bank switching? * Q.4.10 Advice from a veteran arcade emulator author... (Neil Bradley) Q.5 How useful are the switch settings, pinouts, and schematics? Q.6 How do I produce a memory map? Q.7 How can I find what processor(s) the game uses? Q.7.1 Where can I find information for a specific processor? Q.8 Where might I find the ROMs? Q.8.1 How do I disassemble the ROMs? Q.8.2 How do I decode data from the ROMs? Q.9 Should the sound be emulated or should samples be used? Q.9.1 What about legal issues? Are samples copyrighted? Q.9.2 What is the difference between a speech synthesizer and a sample playback device? * Q.9.3 What was used in Williams Arcade Classics? (It sounds good!) Q.9.4 Why is sound so *hard* to emulate? Q.10 Where can I find other documentation for the game? Q.10.1 What about schematics for the game? Q.11 How might I contact someone who owns the machine hardware? Q.11.1 Todd Krueger's offer to help Q.12 Where can I find general descriptions of arcade games? Q.13 Did other emulator authors keep any notes while they were working? Q.14 Where can I find more information on the internet and WWW? Q.15 Should I release my source code when I'm finished? * Q.16 How well do arcade emulators work under Unix (X11)? Game Data --------- D.0 What is this section about anyway? D.1 Astro Blaster D.2 Commando D.3 Crazy Climber D.3.1 Video D.3.1.1 Palette D.3.2 Sound D.3.3 Other Details D.3.4 Memory Map D.3.5 Decrypting the ROMs D.3.6 Miscellaneous Information D.3.7 Different Versions, and Extra Credit(s) D.4 Crush Roller D.5 Dig Dug * D.X Elevator Action D.6 Gyruss D.7 I, Robot D.8 Juno First * D.X Kickman D.9 Kung Fu Master D.9.1 Background Graphics D.9.2 Sprites D.10 MCRII / MCRIII D.11 Moon Cresta D.12 Ms. PacMan / PacMan D.12.1 ROM Files D.12.2 Memory Layout D.12.3 Memory Mapped Ports D.12.4 OUT ports D.12.5 Character Sets D.12.5.1 Pascal Source (ZIPed an UUencoded) D.12.6 Ms. PacMan ROMs are identical to PacMan? D.13 Naughty Boy D.14 New Zealand Story D.15 Penia D.16 Phoenix D.16.1 Components D.16.2 Functionality D.16.3 Colors D.16.4 Memory Map D.16.5 Sound D.16.6 Miscellaneous D.17 R-Type D.18 Sega System 16 Games D.18.1 Hardware Information D.18.2 Memory Map D.18.3 Scroll Video RAM D.18.4 Fixed Video RAM D.18.5 Color Video RAM D.18.6 Main RAM D.18.7 Video Registers D.18.8 I/O Registers D.18.9 ROM Files D.18.10 Graphics Formats D.18.11 Sega GFX Viewer V1.0 Source Code (ZIPed an UUencoded) D.19 Sega Vector (Converta) Games D.19.1 Components D.19.2 Memory Map D.19.3 I/O Inputs D.19.4 I/O Outputs D.19.5 Vector Processor D.20 Side Arms D.21 Space Invaders D.21.1 Board Spec * D.21.2 Memory Map D.21.3 Sound Information D.22 Star Wars D.23 Tapper D.24 Toki D.25 Turbo D.26 Tutankham Graphics Hacking ---------------- G.1 Who wrote this section? G.2 Introduction G.3 Location of Graphics in Specific Game ROMs G.4 General Information G.4.1 Pixel Layout G.5 Notes and Requests * G.6 Mode Q (256x256x256) Source Code (ZIPed an UUencoded) Pokey ----- P.1 Who wrote this description? P.2 You mean Pokey isn't just that guy that hangs around with Gumby? P.3 Where did they come up with a name like Pokey? P.4 General Description P.5 Technical Description P.5.1 Pin-outs P.5.2 Address Lines P.6 Where can I find source code and more info. for Pokey emulation? P.7 Finding and using *real* Pokeys AY-3-8910 --------- A.1 Who wrote this description? A.2 Introduction and Disclaimer From Original Document A.3 Technical Information Step-by-Step ------------ S.1 Step-by-step implementation of an emulator for Phoenix S.1.1 Part I: Pre-coding S.1.2 Part II: Low/High Endian S.1.3 Part III: Let's start coding! S.1.4 Part IV: Run it! S.1.5 Part V: To be continued... S.1.6 Sound emulation... S.2 Step-by-step discussion of an emulator for Space Invaders S.2.1 My Background S.2.2 Getting started S.2.3 Disassemblers S.2.4 Space Invaders Specifics S.3 Step-by-Step discussion of how to make a memory map S.3.1 Memory Maps: The toolbox S.3.2 Memory Maps: The "Easy" way... S.3.3 Emulator Memory Maps: The "hard" way S.3.4 Other Common Chips S.4 How to Create a Memory Map for Moon Cresta References ---------- R.1 List of Currently Emulated Games R.2 List of Games People Want to See Emulated R.3 Internet Resources R.3.1 WWW Resources R.3.1.1 General Arcade Emulation Links R.3.1.2 ROM Images * R.3.1.3 Processor Information R.3.1.4 Schematics * R.3.1.5 Miscellaneous Information R.3.2 FTP Resources R.3.3 FSP Resources R.4 List of Arcade Games ------------------------------------- .d88b. 8 db 8P Y8 .d88 8d8b. .d88 dPYb 8b wd8 8 8 8P Y8 8 8 dPwwYb `Y88Pw `Y88 8 8 `Y88 dP Yb ------------------------------------- Q.0 Trying to write an arcade emulator is crazy, isn't it? Neil Bradley (author of Emu) said himself, "Being unbalanced REALLY helps." However, this has not stopped the dozens of emulator authors from pursuing their goal. Anyway, most programmers are a bit crazy, right?? :) Q.1 Which game would you recommend starting on? Neil Bradley suggests: "Good question. I'd recommend picking one you like, because if you're emulating a game just to emulating a game, there's no fun in it. Fun is what keeps an emulation project goin." Mike Perry suggests: "I will go off on limb and suggest that you try to successfully emulate a machine using the 6502 processor. The 6502 is a very simple and powerful processor with has the 'feature' of having an instruction set with a 1-1 correspondence to the x86 instruction set. By this, I mean that every instruction on the 6502 instruction set also exists on the intel x86. Better yet, in all but a few exceptions (1 or 2), the intel instructions modify the exact same flags as the corresponding 6502 instructions, so there is little work needed to generate the resulting 6502 flag register settings. To top it all off, the 6502 was WILDLY popular in the early-mid 80s so you can be sure that there are _many_ classic-era games which use this chip." Q.1.1 Which games are 'easiest' to emulate? I have been told by Moose that a number of sources suggest Phoenix is the easiest game to emulate. Wiretap appears to have some good documentation for Phoenix. See also Q.1.2. Chris Hardy (author of Phoenix emulator for Win95) agrees: "[Here are some reasons why I started with Phoenix...] - Most importantly it has a good concise accurate description of the hardware memory map. [Wiretap archive and section Q.1.2] - It uses a 8085 which has an instruction set which is a subset of the Z80, therefore you don't have to implement all the z80 instructions, only the 8085 ones. (or borrow Marat's one and solve the problem) - It only uses character graphics, which means you don't have to do any sprite routines. - The 8085 is slow enough to emulate completely in C. (ie. my emulator is completely C). Although it is important to remember that the graphics side of my emulator(s) is in assembler and hardware. It's just that I didn't have to write it ;-) (Microsoft did!)" Neil Bradley recommends: "I wouldn't attempt Crystal Castles or Marble Madness, for example, as a first emulation, because it has lots of custom chips that aren't documented anywhere. Something simple, like Space Invaders, might be a good place to start. Your biggest hurdle in making that one run will be the Z80 emulation. In a nutshell, don't bite off so much that you can't chew it. A new graphics system, new sound system, new processor, and new mathbox board all make things futile for you. Start with games that, for instance, use a CPU that you know, or a graphics chip that you know (if applicable)." Mike Perry has this to say: "Which game is easiest? Gah, thats relatively hard to say. As long as the game only has one processor (or two if one is used for sound) then it will probably not be a terribly difficult task. If the game is vector based, that will increase the difficulty level considerably. The simpler the processor, the easier the programming task will be and the more likely it is that the emulator will run at a decent speed on a slower computer. In other words, an emulated 8088/z80/6502/6809 will not be difficult to handle on intel 486, but a 68000 will be a challenge!" Q.1.2 Which games have the most available documentation? Dave Spicer says: "I can't think of any with detailed documentation. The easiest game I ever wrote a driver for was Space Invaders. It was a doddle!" Q.2 How do I START? Neil Bradley suggests: "If you don't know at least one assembly language, emulation is going to be a very difficult thing for someone to accomplish for two big reasons: Most games written prior to 1985 were written all in assembly. That means you're not going to have the luxury of looking at wonderful source code - you're going to have to guess what it's doing by what a disassembly is doing. Secondly, the concepts of I/O & memory, paging, etc... are all familiar to the assembly programmer. Knowing hardware, and how to read schematics helps immensely. I find a game I want to emulate. Then I find out what other games are similar enough to the platform of the game I want to emulate. If there aren't any, I seriously reconsider doing it. If there are others, I go ahead. Implement the CPU emulator before anything else. Writing sound & graphics engines won't do you any good if you don't have anything to drive them with. ;-) You need to know at least one high level language and an assembly language - preferably the one contained on the video game you're trying to emulate." Neil Bradley summed it up on the emulator mailing list: "Pick a game you want to emulate and stick with it. Get a CPU emulator that you know and trust and use it to get things running. Grab a disassembler and write yourself a small debugger to allow you to step through code, stop at specific points, etc..." Mike Perry offers this informative list of things to obtain: "[You will need] information on the microprocessors used in the game. Knowing the manufacturer and device number should be sufficient. You must then seek out a technical reference for the appropriate processors. In many cases you can mail the manufacturer for a free (or cheap) copy of the tech specs. You will need the specs for 1) The opcode matrix: This will have the hexidecimal values for the opcodes. 2) Instruction details: This will tell you exactly what each instruction does. If the processor has a flags register (it probably will!), it will tell you which flags are modified/set/cleared and under what conditions. 3) Instruction cycle counts: Depending on the machine, it may be necessary to keep an exact count of emulated cycles so that interrupts can be triggered at an _exact_ time eg 50 mhz, no more, no less. On vector machines, this may be a big deal. According to the author of the Vectrex emulator, the interrupts had to be trigged on the exact cycle or the whole display could be screwed. For raster games, I seriously doubt a few cycles will hurt anything. 4) Interrupt information: You need to know what interrupts can be triggered and when. If the processor uses an interrupt vector, you need to know the locations of the vector entries. You also need to know whether interrupts are prioritized. 5) Addressing information: You need to know exactly what kind of addressing modes are available on the microprocessor of the machine. These modes must be emulated for memory reads and writes, including instruction fetches and stack operations." Chris Hardy had this to say: "Hints on starting an emulator: - Write a 8bit binary dumper. This allows you to dump the ROMs in a form so you can work out which roms are the character roms and how the graphics are formatted. - Contrary to popular belief you don't have to have a complete character graphics system going to have some fun. Work out where the ASCII and number characters are in the character ROM's and display the display memory as ASCII on the text screen.(Just replace anything else with an "X" or something). I played my first emulated Phoenix game this way. (It even scrolled the background!). If you have a background and forground, just put them side by side. 80 columns is usually enough for most arcade displays. - As part of your processor emulator have a table in which you have a count of the reads and writes to every memory location. This allows you to immediately find what memory locations are being used by the emulated code, ie. screen memory, other "device" memory locations. If you need to, this can also be done for IN's and OUT's. - You don't have to always draw the whole screen. If you use offscreen buffers and a change table, you can work out which characters have been changed and just update them. This speeded Phoenix quite a bit, as drawing 1664 characters every frame took a while." Dave Spicer offered this: "I start on an individual emulation by finding the character hardware of the game in question and implementing a simple version of it. This is usually enough to see text on the screen and get some idea of what the game is doing. Martin Scragg suggests: "Get hold of some source (try the Arcade Emulation Repository). See what other people have done. Get a feel for how the games that you want to emulate work. Pick a game that you like and try and find out information about it. The less information there is about a game the harder your job will be. Don't try to go overboard with your first emulator, even doing a game that has already been done is good because you can compare your product with an existing one, and if it has been done befaore then there is a good chance that you can get some good info about it." Q.3 What language should I use? I suppose it's possible to use almost any language available. However, for performance, assembly is definately the language of choice. High level languages used in current emulators include C and C++. Neil Bradley had these comments about languages to use in an emulator: "You might be wise to learn C. The biggest reason is that it is the most widely used language, and there are plenty of experts in the field to help you out. Pascal is dead as a new development language, except maybe for hobbyists, though I must admit Borland did a pretty damn good job of making Turbo Pascal a viable entity. With all of their extensions and nicities, it rivals C in its functionality. The same holds true for Visual Basic. It's not really BASIC in the literal sense anymore - it's a C-like language. The other reason is that about 95% of the CPU emulators I've found are written in C. I think I found 1 that was written in Pascal." Mike Perry adds: "I can tell you now that you do NOT want to use Delphi. Delphi is for rapid prototyping and for developing graphical applications. An emulator is not an application that is suited for development in Delphi. Additionally, Delphi applications are only usable in Win95 and NT. DOS, being a single user, single-tasking OS, is more likely to bring better performance. [Using] Pascal is a possibility but Borland Pascal has serious limitations in terms of efficiency. For instance, someone was handling opcodes using a case statement case op1: blah blah blah; return; case op2: blah blah blah; return; case op3: blah.....; return; .... Now any reasonable C compiler, including Borland C++, converts this to a jump table (ie, code array) for fast case determination. BPascal on the other hands generates a series of mov, cmp (compare) and jmp instructions, like a big if-else. This means that opcode 212 will take around (212 * 4) cycles just to GET to the code using BPascal while it takes less than 6 cycles using C!! Even if you DO use C, your task is made MUCH easier using inline assembly. Better yet, make assembly the main language and link in external C or pascal function if necessary. The graphics routines should DEFINITELY be in assembly. [You] WILL be better off learning [assembly]." Dave Spicer warns: "IMHO, writing an emulator in Pascal is not a particulatly good idea. You'll be emulating machine code, so you want something that resembles that in form." Q.3.1 Do I *have* to use Assembly? Neil Bradley says: "Regardless of what some academics would like to believe, a compiler can't outclass a good assembly programmer. You'll spend plenty of time optimizing, and if you rewrote it in assembly, you're almost assuredly going to get a 30-40% speed improvement. C compilers (and others for that matter) solve for the general case, and make assumptions on what registers/variables need to be saved. In assembly, you know the code, and can write, at the CPU level, and write the most optimal instruction sequence to match the common-case path of your code. You really do need to know assembly to do a project like this - that is to do it in an effective amount of time." Mike Perry says: "Normally I would not recommend writing an application primarily or entirely in assembly. Assembly is minimally portable and if an application spends 90% of its time executing 5% of its code, it does precious little good to hand optimize the remaining 95% in assembly. An emulator, on the other hand, is not your normal application. An emulator's job is to emulate hardware. In emulation, you will be dealing with registers, memory addressing and memory reads/writes. The instructions the real processors use to do this sort of stuff are very "basic". They are so basic that its actually easier to use x86 asm and the intel registers to do what you want than it is to use a high level language. Assembly makes it easy to manipulate 8-bit, 16-bit and 32-bit values. C and Pascal make it downright tedious to manipulate more than one size variable in an expression. At the least, your HLL code will contain many many typecasts, making it very hard to read." Q.3.1.1 Are you SURE about this Assembly business? :) Paul Kahler points out: "A number of people indicated that assembly is the only way to get good performance on anything short of a pentium pro. I'd just like to say that the first rev of the Cinematronics emulator was written in TURBO PASCAL and seemed to run just fine on a Pentium-90. That was almost 2 years ago, so we were trying to run on a 486 and had to move on to assembly. TP allowed me to create an array of functions so I could grab the opcode and call the proper function. That's really good performance considering the CineProcessor doesn't map at all to x86 or anything else, and it ran at 1.7 MIPS! A 6502 should be no problem for C code on a Pentium or even a 486. But then there's graphics and sound also... I just wanted to point out that ASM isn't the only way to go, and if you do things in C they'll be portable. BTW I used the BGI drivers for the vector display back then too!" Pete Rittwage adds: "I've been able to get stellar performance out of my 6502 purely in C, including graphics overhead, even on my lowly 486/100. I've also seen people get pretty good performance out of Marat's Z80 code in such things as the Donkey Kong emulators, and that code is FAR from optimized. It accesses things a couple of structures deep at times, which is very inefficient." Q.3.1.2 Doesn't the choice of language depend on the target game/system? Neil Bradley clears things up: "Writing an emulator strictly in C++, including CPU emulation and graphics emulation will not give you good performance on anything short of a pentium pro. The author of the Tempest emulator that runs under Windows runs fine at 150MHZ, and it's written in C. If that's your target platform, great. And if your target platform is a 486/66 and your graphics are heavily intensive or running on a slow ISA card, you better not use C or C++. To give you some benchmarks on some "famous" CPU emulators, here are some #'s (not including graphics - just RAW CPU time) that indicate the emulated speed on a 486/66 running Asteroids, compiled under Watcom C++ 10.6 with the 486 compile option thrown: Emulator Emulated speed Marat's 6502 1.6MHZ Apple IIe emu 800KHZ Optimized Apple IIe emu 1.9MHZ EMU's first 6502 C emulator 2.5MHZ EMU's 100% Assembly 6502 6.8MHZ My background is assembly & C optimization. I've spent greater than 20 years on numerous processors, and have programmed everything from tiny microcontroller circuits to multi-CPU applications, so I'm no slouch when it comes to C or assembly optimization. ;-) . The results above speak for themselves. Keep in mind that there aren't any graphics routines or sound routines in this code under this test. So I'll reiterate what I've tried to say in the past: If your target machine is a 486/66 with a crappy ISA card, you'd better squeeze everything out of the emulator that you possibly can, because you'll need it. EMU Uses a single page of 256 color graphics. It erases the prior frame and draws the new one. Typical frames are 300 vectors. 600 Lines per "frame", and roughly 25 frames per second. That's 15000 lines per second that must be drawn, and if we say that the average line is 50 pixels, that's 750,000 pixels a second. Most games, such as Donkey Kong or Space Invaders aren't coming even close to moving that many pixels on the screen. So in that case, you can get away with having a less than totally optimized CPU. But with EMU, I couldn't get away with it. There was too much to do. Linedraws are extremely expensive, and I spent days working on high speed linedraw routines (those of you who've been with EMU since the early days know what I'm talking about). The point I'm trying to make is that the more you optimize your CPU emulation, the less of an impact it will have on your graphics emulation, and the faster your code will run on a slower machine. If you want to make your minimum platform a Pentium 166, you can probably get away with writing it in Quick Basic. I want as little intrusion from the CPU emulation as I possibly can get, and I got better emulation by almost a factor of 3 by rewriting it in assembly. I don't think anyone said that ASM was the only way to go. I remember saying that it is the most optimal way to go." Laurent Desnogues says: "I got a two times speed-up when converting a 6809 emulator written in C to SPARC assembly language. So I'm one of the exceptions... I wrote a Phoenix emulator that should run on any Unix/X platform (one or eight graphics planes); it uses Marat's Z80 emulator package and I get decent speed even on low end Suns. The problem with Unix is that most of its implementations can not handle real-time programs; the game often freezes while the kernel is doing internal jobs... So I have to admit these platforms are not very well suited to arcade game playing; but programming an emulator is by itself enjoing, isn't it?" Q.3.1.3 What about portability? Neil Bradley answers: "Just because you do things in C doesn't mean they're portable. There are basically two platforms that need any attention for gaming: PC & Mac. That's it. I don't know of anyone owning a Silicon Graphics workstation saying to themselves, "Gee, wouldn't it be cool to fire up an emulated version of Space Invaders on this thing?". The people I know who own SparcStations or run Unix aren't interested in emulation or gaming in general. Granted there are exceptions to that rule, but for the most part the "other" platforms aren't really in the running. But if I'm forced into a corner where I can get 3X performance out of something by coding it in assembly for a platform I know, I'll do it and blow off "portability". At the same time, as I've said before, I'd gladly help out others on other platforms, giving them hints and helping them with their emulation projects that are for a platform that I'm not familiar with. Besides, most code written to be "portable" isn't. It starts off that way, but ends up using OS specific calls to improve speed, etc... The road to non-portable code is paved with portability in mind. ;-) BTW, I run Unix on synthcom, Win 95 on my sequencer/sound studio, Windows NT 4.0 Server on one of my development machines, and DOS on the other. Guess which one I use for games..." Q.3.2 But haven't some arcade emulators been written in C/C++? According to what I've heard, C and C++ have been *used* in some emulators, but an entire emulator has not been written in only C or C++. Neil Bradley says: "Name one emulator that was written in C++ that runs reasonably on anything less than a Pentium Pro 200. ;-) I don't know of an emulator that is ENTIRELY written in C. EMU, for example, is written in C and assembly. C for all the glue code and non-speed critical things, and assembly for everything else. That's why it runs reasonably on a 486/66 with a decent PCI video card. [Chris Hardy's Phoenix emulator was coded in VC++ using Direct/X... Note that it was written in C (not C++!) and compiled on VC++] Not to lessen anything that Chris has done, but Phoenix isn't exactly a CPU hogging game, as is something like Tempest, Battle Zone, or Red Baron. The vector emulation is very time consuming, and even the originals slow down in spots." Q.3.3 What about Java? Neil Bradley, after cringing in terror, says: "The only way that you'd even have a prayer to get something to run fairly quickly in Java is to make sure the client compiles it for their native CPU (Visual J++, anyone?). In the case where you write an emulator in Java, and it runs on a browser, you'd have an interpreter interpreting an interpreter of a CPU in addition to the interpreter interpreting the hardware actions as well. Interpreted Java is not built for speed. The guys at Microsoft are getting almost identical performance out of Visual J++ as the Visual C++ guys are (according to a Java proponent at the last PDC), so compiled Java apps are a possibility. It's hard enough getting optimal assembly emulations to run at full tilt on a 486/66 without having an interpreter interpreting the emulator. Your hit by doing that would be about 30:1. If we had 2 Gigahertz Pentium PROs, it might be possible, but not with the speed of the Java virtual machine interpreter. Don't bother unless you're compiling it. You might have a chance then, but interpreted, no way. I wouldn't bother trying it. ;-)" Q.4 Could you explain CPU emulation? The CPU emulation is the heart of any emulator. If the code is correct, it will handle the ROM data, so you don't necessarily have to worry about how the game ROM itself operates. Since the CPU is the 'brains' of the machine, it can get very complicated. Neil Bradley had this to say: "When doing something with the Z80, for example, it's quite extensive. You've got the functions of 300+ opcodes to deal with, and permutations. Not to mention that some arcade manufacturers' code use the Z80 'undocumented' opcodes (though they're not so 'undocumented' anymore...). Grab yourself a book on Z80, 6502, 6809, or whatever CPU you're working with. That's the best way to start. The 8080->Z80 processors are actually much more complex than the 6502." Q.4.1 CPU emulation sounds VERY complicated, how should I START? Mike Perry offers the following: "I recommend that you read a few good books on computer architecture and digital circuits and/or boolean algebra. If you understand how the basics behind the following, you'll be well prepared to emulate a microprocessor: 1) Fetch-decode-execute process 2) Buses and memory/data reading/writing 3) Interrupts and their implementations 4) Stack operations 5) Registers and flags 6) Binary arithmetic, two's complement representation, boolean algebra I suggest 'Computer Hardware' by M. Mano. Another good book is 'Computer Architecture: A Practitioners Approach' (or something like that) by Patterson and Hennesey. These are both college textbooks. Of the two, the Patterson book would probably be the most helpful as it covers architecture on the system level rather than the gate level. It covers MIPS assembly language, pipelining (unimportant to emulation, although you could use a similar technique to speed up the emulation), memory addressing, virtual memory and IO devices/DMA." Q.4.1.1 Is the 68k series of processors 'easy' to emulate on PCs? Phil Morris found the following on a UseNet newsgroup: "68k emulation can be done VERY quickly on intel... Check out ARDI's Executor. They use a combination of an interpreter and a dynamic recompiler. It reaches 68030 speeds on pentiums. Very cool. Their white paper is good reading for anyone looking to write an emulator. Maybe this White Paper is available on Ardi's Web site? (www.ardi.com)" Q.4.1.2 Why were only a handful of processors used in arcade games? Neil Bradley offers us a bit of history: "Most of the issue was cost back then. The 6502, Z80, and 6809 CPU's were the cheapest, and most of the games in the early 80's and late 70's didn't need 68000's or 8086/80286's. The cost of a 6502 compared to an 8086 was about a quarter the price. The 6502 got its start by doing about 30% of the functionality of the 8080. Throughout the years, the 6502 has been known by many programmers as being a collosal piece of garbage. I always did hate the chip. It worked, but barely. No 16 bit pointer registers, only 256 bytes of stack, etc... It was the first CPU at the time that actually chaged its flags by a register load. It was a pretty weak CPU in terms of functionality (as evidenced by BattleZone & Red Baron). They could have implemented that game with a higher CPU (like a Z80 @4 MHZ) and eliminated the mathbox altogether. I think at the time it would have almost been cheaper to do it this way. The 6809 made quite a few improvements over the 6502 and the 8080/Z80. It had the opportunity to learn from the 8080's & 6502's mistakes and was an all around better chip. In some aspects the 8080 was superior (I.E. more registers), but the 6809 had lots of nice features and was extremely consistent. The Z80 started when some guys who worked for Intel split off and made their own company (Zilog). They took the 8080 design and added lots of nice features to it to make it a REAL powerful chip. Of that era, the Z80 was the most popular CPU and the most powerful. Built in block move commands & all kinds of register indirection. Most games of that era used the Z80." Q.4.1.3 Should I try to learn the assembly of the target platform? Martin Scragg says: "It would probably help, even if you get a memory map etc. there are going to be certain things that will require you to disassemble the code to figure out." SolarFox says: "Again, your task will be a _lot_ easier if you do, because you'll have a better understanding of what the game is up to if it starts poking values in odd places or behaving unexpectedly. Basically, it works out like this. It's _easiest_ if you understand _both_ the schematics _and_ the assembly-code of the game you're trying to emulate. It's considerably more difficult if you only know one, but not the other. If you don't understand _either_, then I'd guess it'd be all but impossible." Q.4.1.4 How did games with multiple CPUs work? Mike Cuddy says: "On classic arcade games, the usual method is to have them share a portion of the address space through an SRAM chip (if they need to share alot of data, like sprite control stuff), or sometimes they only share a couple of latches or a small register-file (there are single TTL chips which to this). Since SRAM is so much faster than these "slow" processors could ever deal with, the SRAM's is time-multiplexed between the two processors. (i.e: the SRAM is clocked at 6Mhz while the two cpus toddle along at 3mhz each... They never even know the other is using the ram -- no wait states, etc.) This makes it up to the programmers to decide how to synchronize the CPUs. Usually, one of the cpus is a "master" cpu, and the other CPUs will do thier work for one frame of animation and then spin-wait on a certain address; to get the most speed, I have disassembled the code used in the game looking for those "trigger" points, and then set up the cpu emulation to stop running where the original program would just be spin-waiting. And then when I detect the stimulus from the main cpu that would cause the subordinate CPU to start running, I run the subordinate cpu until it gets back into it's idle loop." Q.4.2 Should I use CPU emulation code that is freely available? Dave Spicer suggests: "Writing a processor emulator is a big job and is very difficult unless you know your your emulated processor fairly well. You might be better off starting out with Marat's C based emulation code as that's a proven, albeit slow, technology." Neil Bradley says: "If you are goal oriented, learn from their emulator first, then write your own. If you want an education, by all means, but that's a big chunk to bite off." Q.4.2.1 Where can I find freely available source code? Refer to the Arcade Emulation Programming Repository at: http://valhalla.ph.tn.tudelft.nl/emul8/arcade.html Q.4.2.2 How do I install DJGPP and Allegro taking only *limited* space? Vince Mayo instructs: "Here are the necessary files (that I know of) to install DJGPP, Make, and Allegro: djdev201.zip gcc2721b.zip bnu27b.zip mak375b.zip alleg211.zip When you go to uzip these, use -d option. And to make the install easier, install it to C:/djgpp. You will have to modify the *.env file to put it on a different drive or directory. Add these 2 entries accordingly to autoexec.bat: In path statement add c:\djgpp\bin In set statements add set djgpp=c:\djgpp\djgpp.env Unzip all these files -d to the c:\djgpp directory. Give allegro its own directory under djgpp. You will need to run make on Allegro because the libraries are not compiled to save space. I think this might take up around 13 meg on your hard drive. Some files might not be needed but I do not know which." Q.4.3 How do the CPU and ROMs interact? Neil Bradley instructs: "Create your entire memory space, including loading the ROMs, and start your execution wherever the processor starts. Don't try to interpret the ROMs - you'll never get it right because it's completely unpredictable." Mike Perry adds: "As for variables and stuff, thats the beauty. You aren't SUPPOSED to have to know how the processor is being used. You emulate all of the opcodes and interrupts, and have a simple fetch-decode-execute loop. You also emulate the supporting hardware (controls, gfx and sound) to be called during interrupts. If those are written correctly, the emulated game will run itself... You don't need to know the details of the game code." Q.4.4 How should I handle CPU opcodes? Neil Bradley has this to offer: "If you're going to be handing off a single opcode between classes, the overhead will completely nullify any speed you could even hope to get. Try using a pointer to the current virtual program counter and fetch bytes as you need them. Use an array of function calls - one for each opcode... Point invalid opcodes to a NOP function... [Pointers are] 4 bytes if you're doing 32 bit code." Q.4.5 What is Pokey? He is Gumby's friend! :) Seriously, for a great description of what the Atari Pokey is, see the Pokey section below. Q.4.6 What is Slapstic? It's a form of comedy. Nyyyuk nyyuuuk nyyyuuk... Woo woo woo woo woo! Actually, it's a security chip Atari introduced in some of their games. Suzanne Archibald provided this information: "Unfortunatly, I don't have any information on the chip per se, just how to avoid it in Gauntlet. See, for each machine using a slapstic chip (each was different - the name being a generic term to Atari's copy protection) the chip would have a unique function, in the case of Gauntlet I/II the chip decoded the top 2 bits of the Maze data. With this in mind, getting around Slapstic on Gauntlet isn't too difficult, you simply use a ROM that is available, that has the correct Maze layouts without needing decoding, you then disable the slapstic, and hey presto." Q.4.7 What about translation? Would it be easier to translate the code into a language the PC can compile rather than emulate the CPU? Here's what I mean by translation: Write a program that reads in each machine code instruction from the ROM (where the CPU instructions are stored) and outputs a line of code in say, Assembly or C. If you devise a set of translation rules from the machine code to your target code, and if this idea works, you should get a program that you can compile (and optimize if you like) that will perform the same operations as the original ROM. After I had this thought, Moose told me: "This idea was discussed in c.e.m years ago. The problem (as I understand it) with translation is : - How do you ever know when you have translated all instructions/data? Some bits of a game (say) only get called / run under real unusual conditions. - Where code is loopy, your translator would have to be super intelligent to recognise the loop (which might span 1,000's / millions of instructions). - How do you ever know when / if you have captured all instructions / data. The way I understand things, translation is extremely difficult, but not impossible. However, I think it is several orders of magnitude in difficulty above straight emulation. Then again, maybe it can be done." Neil remarked: "I've actually kicked around the idea of writing an emulation compiler, which would actually take the native object code of the game and convert it into the native machine's code, and execute THAT instead of emulating the processor. That would allow the game to run at the native processor's speed, and you'd get 5-10X speed improvement in CPU emulation. Even the simplest of instructions winds up taking 20-30 clock ticks in emulation land." Q.4.8 Is there anything else I should know about CPU emulation? Neil Bradley reminds: "[Don't forget] to include events that happen at regular or random intervals (like NMI's or interrupts)." Q.4.9 How might I implement bank switching? Neil Bradley suggests: "Maintain n 64K images that contain a snapshot of all possible bank settings (this is assuming ROM bank switching). Set up a common handler for the RAM region that intercepts all RAM writes and writes it to a single area. When you want to execute from a different image, change the pointer to the 64K image that contains the ROMs for the bank switch you need. The code underneath doesn't know the difference." Patrick O'Reilly instructs: "Microprocesors generally do not do the bank switching. In the case of the Zilog Z80, a very popular microprocessor in early-80s coin-operated video games, a discrete address was placed on the sixteen address lines (A0 through A15.) For a read operation, the RD device pin (active-low) was biased at logic "0" to alert either a discrete memory chip or the controlling logic (for many discrete memory chips) that the microprocessor was ready to reeive a discrete eight-bit value. This value was placed on the eight data lines (D0 through D7) as input for the microprocessor to read and process. A similar procedure was used for I/O. For a write operation, a discrete eight-bit value was placed on the eight data lines as output for the target memory chip to read and store. The WR device pin (active-low) was biased at logic "0" to alert either a discrete memory chip or the controlling logic (for many discrete memory chips) that the microprocessor was ready to write a discrete eight-bit value. Again, a similar procedure was used for I/O. Bank switching is performed using controlling logic. This logic, also called glue logic, consists of decoders and discrete logic gates that effectively manage more than one memroy chip ensuring that two memory chips are not pining for the same address in read/write operations. The above system does the bank switching. Generally, the main program has a discrete memory location dedicated to the purpose of bank switching. A value placed in this location controls the hardware responsible for selecting the memory chips requested or required. Memory chips share the same memory space, but only one group is active at a particular time. The group that is active is controlled by the main program. Turbo, a perspective auto racing coin-op video game produced by SEGA in 1981, used eight "levels." During gameplay, the scenary changed from a city, to a country, to a seaside, to a tunnel, to a snow-covered plain, and to a suspension bridge. The road was either straight, curved left, or curved right. The graphics data for each scene was stored in a pair of 2764 EPROMs. There were eight EPROM pairs, each pair corresponding to one of the "levels." All eight pairs shared the same address space. A particular EPROM pair was selected by the controlling logic depending on which scene the player was driving in. The Z80A microprocessor utilized by Turbo was not involved with the bank switching process." Q.4.10 Advice from a veteran arcade emulator author... (Neil Bradley) Neil Bradley once again provides valuable information for potential emulator authors. (Note: This is long, but very informative!) "To all authors who are working on a CPU emulator of any sort, I have a few bits of advice that has helped me immensely in debugging and writing (mostly) bug free emulators. I hope you all find this useful: * Always keep a disassembler handy. The first thing you need to do is either write your own disassembler or borrow one from somewhere. This is crucial to the code executing at the correct spot. * Implement your CPU emulator by executing it against known code (video games, etc...). This is a good way to see if your instruction implementations are acting the way they should. Even if you're not knowledgeable about what the code is actually doing, things like flag problems or incorrectly interpreting instructions pop up REALLY fast. * Implement instructions one at a time. Execute a known good piece of code, and when it hits an instruction that isn't implemented yet, implement the instruction and repeat. This allows you to watch each instruction be executed, and you can debug as you go. Later on when you're implementing similar instructions, you can cut/paste code, and the odds of it being debugged when you copy it is MUCH higher than debugging instruction by instruction. * Avoid implementing the instruction's "addressing" modes as a separate part of the instructions themselves. This makes implementing the instruction set much faster, but instead consider using macros. Calls are very expensive on just about every CPU, and the price you pay for those calls is about a 50% speed reduction. The code will be slightly larger, but you'll gain in performance. The speed gain is probably more when you're using C because most compiler create procedure call stacks that need to be created/burned. * Instead of on-the-fly computing zero and sign flags, create a 256 byte lookup table for all possible flag values. And out the zero/sign flags for your CPU, and OR in the index lookup. It sure beats anding & ORing twice, and two jumps when things aren't set. ;-) This gives you a 10%-15% speed improvement as well. * When fetching instructions, don't use RD_MEM macros. The only reason to do this is to be able to trap reads/writes to peripherals. To date I'm not aware of any games that execute code that requires a special handler to intervene. Simply read the data directly out of the memory space when executing instead of going through the macro. * If you're coding in assembly, instead of having a main loop that executes, use a macro at the end of each instruction that, instead, fetches the next instruction and jumps to the handler for it. You eliminate a jump in the process. * Create a 256 byte jump table for each instruction, and create a handler for each one. This sure beats a case statement with 256 possible values. Besides, you won't be at the mercy of a dumb compiler that can't table-ize a case statement. It also shortens your main loop considerably. * Do include instruction timing information in your instruction implementations. This is very handy for other developers who might be using your code who need a reference as to how fast the virtual processor is running. This is HIGHLY useful. I also encourage you to implement them as macros as well, because in some chips (like the 6502), if the clock cycle is > 5 ticks, certain lines (SYNC) are set high (or low if smaller than). Games like Missile Command rely on these things. Besides, it's quite easy to take it out later on if you don't need it. * Always have many reference guides around for the target processor. You'll find they don't always agree, and it's nice to have conflicting information presented to you so you can figure it out. ;-) * Consider borrowing someone else's emulator to debug against yours. There's nothing like being able to execute a single instruction on each, step by step, and watch the results of each, and binarily compare the output of each emulator. When it hits something that's wrong, you can have it stop, give you a disassembly (remember the disassembler thing above? ;-)) of where it screwed up, and you can fix it! (or fix theirs!) * If you're doing things in assembly, MINIMIZE MEMORY ACCESSES. These are killers. Store as many virtual CPU registers in native processor registers as possible - especially the program counter when you're fetching bytes. If you run out of registers, keep the most used registers in native registers (X, Y, A, and flags on the 6502, for example) and keep the others (S?) in memory location. Remember that every single instruction you shave off can make a BIG difference in operational speed. * (When in assembly) Take advantage of the native CPU's flag handling abilities into account. Consider the following "non-optimized" code: and dh, 0feh ; Knock out our virtual carry shl al, 1 ; Left shift! Virtual ASL! jnc noWay or dh, 01h ; Set carry noWay: .... Instead, do something like this: and dh, 0feh ; Knock out virtual carry shl al, 1 ; Left shift! Virtual ASL! adc dh, 0 ; Set carry (if applicable) It's several clock ticks shorter, and no jmp instruction which will clear your prefetch queue harming performance (hint hint... ;-)) * When executing, execute in groups of instructions rather than just one at a time. If you have an assembly emulator, it will be able to persist the virtual registers in native CPU registers. You also minimize the usage of the instruction cache for a "run" of code. * For known always-RAM areas on processors (6502 zero page and stack page for example), don't bother with the RD_MEM and WR_MEM macros. Just read directly from or write directly to those memory locations. * Make the most comman path NOT branch. If you come down to a choice where you need to branch (or not), think about how it's used. If a most common condition presents itself, make the most common decision fall through to the next instruction instead of taking a jump. * Group all CPU-state data together so it can be swapped with another set of data. This is highly useful to make your CPU emulator multi-CPU aware. * When compiling a C based CPU emulator, when you release your game to "production", remove stack probes (usually /s). This speeds CPU emulation up by a factor of 2 or 3 in a lot of cases. * Align your jump table on 4 byte boundaries. This is especially important for Pentiums and 486's, and will yield another 30% increase. Most compilers already do this when a jump table is defined, but you assembly hackers out there need to do this. * In addition to the jump table alignment, also align each instruction handler on at least a 4 byte boundary (16 is better for PPro and Pentium). This is the biggest time saver there is in Intel CISC CPU's. Hope you find this information useful! It is copywritten work, so give me credit if you copy it somewhere else. ;-) Here's to fast emulation... (clink)" Q.5 How useful are the switch settings, pinouts, and schematics? Mike Perry suggests: "Switch settings are important, but only because you'll probably want to let the user initialize them to whatever they want. Even if you don't, you still will need to emulate them because they are probably memory mapped and the game code uses the information to set things like number of lives, etc. If you dont know exactly what they do, you'll probably have really weird settings in your game." Neil Bradley adds: "The switch settings are useful only once, usually. That's the time when you first fire up the code and wonder whether or not the code is going into self-diagnostic mode. Knowing what the switch settings were once helped [Emu] get out of diag or halt mode. Knowing the pinouts didn't do anything. Knowing where the address (from the CPU's standpoint) of the switches were was MUCH more helpful!" Dave Spicer says: "[A knowledge of] electronics helps because it means you can use schematics to fill in some awkward gaps. That said, most of the time I just work from the original program code and make guesstimates as to what everything should do." Martin Scragg comments: "Schematics can help a great deal, they can help to generate a memory map that you will need to emulate a game. Basically when you write an emulator you are duplicating the hardware shown in the schematics with software, so the more you can get from them the easier it will be. Some memory maps for certain games are available in the HowTo or for download, so this is possibly a good place to start if you can't read schematics. If you can't get a memory map either off the net or by making it yourself from the schematics then writing an emulator is going to be a very slow process as you will have to disassemble the game and try to determine what it is doing with the hardware." SolarFox says [about using schematics]: "While probably not 100% essential, it will make your life a _lot_ easier... Otherwise, you _will_ have to disassemble a fair amount of the game code and try to figure out where the RAM, ROM, and I/O devices are based on what's being read from or written to the various addresses..." Q.6 How do I produce a memory map? First, read sections S.3 and S.4 of this document... Kevin Brisley offers: "Well, I've been plugging away at trying to figure out the inner workings of Burgertime and thought I'd try to get some discussion going in the area of trying to create a memory map for an arcade game. So far I've managed to determine the addresses the ROMs containing code mapped to by checking for IRQ/NMI/Reset vectors and then looking through the disassembled code for hints (eg. checking jmp's and jsr's to get an idea of where the ROM goes). The next step is determining where the rest of the ROMs go. I had planned on doing this by scouring the code for references to addresses that I had not found a ROM for and trying to determine the context of the access. For example, if a piece of code looks like it's copying the bits to make the letter 'A' and I know which ROM contains the charset then I'd have a place for the ROM. But I also have the schematic for Burgertime and was wondering if there was an easier way. I thought that there must be a way to determine from the schematic where the various ROMs go. Unfortunately I'm not an electrical engineer and my talent for interpreting schematics is not great. The question also holds for memory mapped I/O. I was going to apply the same logic to determining where the buttons mapped to but all of the buttons and joystick appear on the schematic. Is there a way to trace the connection to a button back through the schematic and figure out what bit gets flipped in memory? If this is not possible, how have the emulator authors out there determined this stuff? Through the scouring code method or some other method I haven't thought of?" [I'm sure everyone would be happy to get more information on this... anyone out there want to help?] (I received this information from someone who is staring to work on an emulator. He asked me not to reveal his name, because his time is limited and the emulator may not be finished any time soon) : "During the initial scan [of the ROMs] I used some tools that might be of use to other emulator developers. Specifically Marat's DASM that's supplied with the Z80 emulation package and a DOS tool that I found. It's intended for debugging PCB mounted CPU's but can also be used to disassemble and debug romfiles. It's called NOI25Z80.zip and is written by John Hartman. This one is specifically for the Z80 ,but there are versions for 6502 and other processors. It gives you a fully interactive disassembler and memory dumper (HEX and ASCII). It can also trace (debug) ROMS. Input files have to be in INTEL HEX format, so you need a utility like BIN2HEX to convert ROMS to HEX files. Use ftpsearch (http://ftpsearch.unit.no/ftpsearch) to find places to get it." Note: I found the files in the SimTel archives: Directory SimTel/msdos/debug/ Filename Type Length Date Description ============================================== noi25370.zip B 179655 951111 NoICE 2.5 remote debugger for TMS370 noi25_02.zip B 167495 951111 NoICE 2.5 remote debugger for 65(C)02 noi25_09.zip B 185554 951111 NoICE 2.5 remote debugger for 6809 noi25_11.zip B 178389 951111 NoICE 2.5 remote debugger for 68HC11 noi25_51.zip B 170645 951111 NoICE 2.5 remote debugger for 8051 noi25_96.zip B 170411 951111 NoICE 2.5 remote debugger for 80(1)96 noi25_z8.zip B 180580 951111 NoICE 2.5 remote debugger for Z8 noi25z80.zip B 191219 951111 NoICE 2.5 remote debugger for Z80 Q.7 How can I find what processor(s) the game uses? See section R.4 under References. Also take a look at the Game Data section... Q.7.1 Where can I find information for a specific processor? See section R.3.1.3 under References. Adam Roach also suggests: "...most processor manufacturers will provide free or cheap data on their processors if you call or write them." Dave Spicer had this to say: "I don't know of any really good info on the net. However, you might like to try and get hold of "Programming the Z80" by Rodney Zaks (ISBN 0-89588-069-5). This is the book I use if I need to look up any Z80 info... I'm not so sure about books for 6502. I always used to use the Commodore 64 programmer's reference guide!" Neil Bradley's source for the 6502 was: 'Programming the 6502' by Rodnay Zaks was my bible for developing the 6502 emulator used in EMU." Q.8 Where might I find the ROMs? Try the resources in R.3.1.2 and R.3.2. If all else fails, find someone who owns the machine, and see if they can help you (see Q.10). Q.8.1 How do I disassemble the ROMs? If you are lucky, someone may have already written a disassembler for the processor in your target game. Check sections R.3.1.3 and R.3.2 under References. Q.8.2 How do I decode instructions, variables, data, sprites, colors, graphics, etc. from the ROMs? Neil Bradley's answer: "Trial and error. Seriously. Anything beyond this explanation can't be described in 30 words or less... It's a mix of RAM and ROM in that space, in addition to hardware in that space as well. It's different for each platform." Dave Spicer says: "Use a debugger and a graphics viewer to find the data (I wrote my own). Other things require you to make sense of the original game code and work out what it's doing." Q.9 Should the sound be emulated or should sample be used? This has been a hotly debated question on Neil's emulator@synthcom.com mailing list, so I thought I'd address it here. It seems there are two factions in this debate: - Those who want an emulator to be 100% emulated. No samples should be used because this is 'cheating'. Even at the risk of having poorer quality sound, or slower overall emulation, these "purists" would like to see the sound emulated... - Those who want an emulator to be as close as possible to the real thing. Samples should be used because they provide better quality sound, and can produce bass effects that were produced by the arcade cabinet. Neil Bradley says: "The whole purpose of emulation is to EXACTLY DUPLICATE the look, feel, sound, etc... of the game. The Pokey uses a top octave divider that basically pulls pulses off the data & addressing bus to generate its sound. Because of the odd frequency of the Pokey, everything is slightly flat, and off key (musicians, ever notice this?). The sound of a top octave divider circuit sounds nothing like FM synthesis that's found on the SB and other boards. You can get somewhere in the ballpark, but you'll always find that FM synthesis in sound cards is somewhat thin. That's totally opposite of the Pokey. For other games that use more conventional synthesizer chips, sound is much easier, because they use standard waveforms, etc... Sampling gives you the truest to life representation of the real thing, which is exactly what emulation is going for. With all due respect, the average individual can't tell the difference between a sample and the real thing. The only thing that would make it fake to you is knowing that it was a sample. Sorry if I come across as a bit agressive about the sample issue, but it's one of my hot bottons. So I'll ask the question again - do you want the sound cards to attempt FM synthesis on something that doesn't sound like FM synthesis and won't sound like the original, or would you like it to sound like the original?" Ed Henciak adds: "I'd also like to emphasize sampling in game emulation. I have begun work on a Sega vector game emulator (primary focus is Star Trek). You may have seen this on Moose's page as my senior project here at Pitt. Anyway, I don't even plan on emulating the sound. I have a Star Trek set and will use samples for all audio. The goal of emulating old arcade games (to me) is to bring back the experience of playing these games. If you have a 'finished' emulator (i.e. the final revision you release) with weak/no sound, it just misses the point of emulation. I understand 'EMULATION' refers to emulating all hardware in the game, but I think an arcade emulation should be limited to only having to emulate the cpu and video. Audio is critical to any game playing experience (in my opinion, Gyruss would have been kinda lame w/o that killer soundtrack). And from what I have been reading in this group, it is way too wacky from game to game to make it 'perfectly emulated'. Plus, it hogs CPU time. In games such as Dave Spicer's Pac Man, the audio is perfectly emulated. I believe Pac Man uses 1 Z80 CPU and 1 Sound Chip. Not too much overhead!!! Star Wars, on the other hand, uses 4 POKEYS, and Major Havoc uses 3 CPUs in addition to the 4 POKEYS!!! I believe that if we want to see these games emulated w/o additional hardware, and, more importantly, the authors are up for it, we should focus on sampling audio from our games, make an 'audio archive' of sampled sounds at 44KHz (possibly make a small circuit to take this input from our machines directly to the sampler), and pray the authors take advantage of this. Granted, I have only been an 'emulator programmer in training' for a couple weeks now. I still have a long ways to go in this area and fully respect all you authors out there for such incredible work! I just want to push sampling because it helps to fully bring back the arcade experience!!! Q.9.1 What about legal issues? Are samples copyrighted? Neil Bradley counsels: "There are only two conditions where you can copyright a sound: #1 If the sound itself is a sample (as in the samples in the Star Wars & Empire Strikes Back games) #2 If the sound itself is contained within a sample playback unit (I.E. Joust, Robotron, etc...). There are some direct waveforms that can't be copyrighted (Sine/Sawtooth, etc...) If #1 is the case, the only way you can get legal right to redistribute is to license it. If #2 is the case, the only way you can legally utilize the sound is to re-sample it, otherwise you'd be copying the data right out of the EPROM. Both case #1 and Case #2 above are legally considered "creative works". The Pokey is a sound synthesizer chip (among other things). It is designed to generate a wide variety of sounds. If it were true that you couldn't legally sample a real world synthesized sound, then no one would be using synthesizers. Plenty of lawsuits were filed with large musical instrument corporations due to sample stealing (Roland & Yamaha both stole Fairlight's "chior" sample that's used on quite a few big-time hits in the 80's). In all cases, they were sample-sourced lawsuits. Not one has ever been filed where the source was synthesis. There have been suits filed under patches being stolen and reused in other synths, but under copyright law it's considered software since it's stored as data. Atari can't copyright the sound that the pokey generates. If that were the case, then any sample-playback synthesizer (like almost everything sold today) patch preset couldn't be used in a published song. As a published producer and musician, I can assure you all that this is not the case." Q.9.2 What is the difference between a speech synthesizer and a sample playback device? Joel Rosenzweig says: "The difference between a speech synthesizer and a sample playback device is a little fuzzy, but I'll describe the two so you'll see why I call Star Wars speech reproduction 'sample playback' instead of 'speech synthesis.' In sample playback, a waveform is stored in a compressed or decompressed state in memory. This waveform is generally longer than a phoneme, and when played, an entire word or phrase is heard. Generally, an entire sentence would be stored as 'one sample', so that when the microprocessor signals that some speech should occur, it says to the sound unit, play speech sample number 'x' which might be the entire sample 'Use the force, Luke.' This playback device then reads data from an EPROM starting at the location of the sound sample for this speech, and reads the data. After the decompression step, a digital to analog conversion step takes place, and the analog waveform is output. When this single operation is finished, the entire 'speech phrase' is complete. In a speech synthesizer, speech is produced by the catenation of small sounds called 'phonemes.' The English language has a little over 50 phonemes. You can create any English word with the right combination of phonemes. These phonemes can be stored as programming data for a 'synthesizer'' (it says to the FM synth, 'how to generate this sound programatically') OR the phoneme data could be live samples from a human. In order to create a 'WORD' the microprocessor determines the correct string of phonemes that need to be played in order to generate the correct sound. A string of phonemes are sent to the speech synthesizer which then will play the phonemes in order using the technology for that chip (either sample playback or by programming an FM synthesizer.) Many phonemes are read in precise order to generate a word, and then a sentence. Whereas only one read/playback cycle is needed to play a sentence with a sample playback device implementation, the speech synthesis implementation is required to do many shorter cycles to achieve a similar outcome. A speech synthesizer by nature, is able to reproduce ANY 'English' (say) word because rather than storing the words themselves, it just stores all the phonemes needed to produce these words. A sample playback device, is not capable of reproducing ANY English word because it only knows how to play back the samples that are stored in memory. (these might be words, or it could be a sound effect) Now, certainly, if you wanted to, you could record all the English phonemes, store them as samples, and then use a sample playback device and a microprocessor to ACT like a speech synthesizer. In fact, this scheme works quite well and you can get some 'human like' sounding speech out of them. But the main point is that a sample playback unit is capable of playing back ANY sampled sound and is not bounded to generate speech only. A speech synthesizer then is a more limited device that might employ the use of a sample playback device in order to play its phonemes (if they are stored that way). And yes, if perhaps a phoneme were stored as a sample, then you could store an entire speech sample as one 'phoneme' but then you'd technically have a sample playback device, and not a speech synthesizer. So, to wrap up, the biggest difference is that sample playback devices are used to play back any sample of sound imaginable, and can be used to play back whole samples of speech. A speech synthesizer is a device that in some instances behaves just like a sample playback device, but its VALUE is that it can produce any word from a set of phonemes, and is not limited to 'pre-recorded' speech or other sounds. In Star Wars, the TMS 5220 is a device that plays back pre-recorded samples of speech data, stored in the EPROMS of the sound board. It is not capable of producing any speech we could dream up, because it does not have individual phonemes stored anywhere accessable to it, hence it is not a speech synthesizer. The advantage here is that Luke's voice sounds like Luke, and Darth Vader sounds like Darth Vader, etc. A rudimentary speech synthesizer is not capable of copying different 'voices' and is usually limited to small changes in pitch, speed, etc. I believe that Atari named this chip a speech synthesizer because they used the word 'synthesizer' loosely, to mean 'speech production' which is what it does. Though, its not strictly limited to speech as they could have put any sounds in memory that they wanted to." Q.9.3 What was used in Williams Arcade Classics? (It sounds good!) Neil Bradley answers: "All of the WA classics are *SAMPLES*. Even the original sounds that go into the sound roms for Joust, Robotron, etc... are samples of synthesizers. They are mixed off line, and played back real-time." Joe Husosky says: "To recreate the sound they hooked up the sound board and instructed it to play each sound the game has one at a time. The really cool thing about the WIN95 WAC (DOS version also included) is that they have all the sounds included as WAV files. You can really customise WIN95 with all the WAC sounds." Peter Phillips clarifies: "This isn't quite accurate. The author of the games (Jeff Vavasour) wrote an emulator for the sound boards. It is true that samples were used but the samples came from an emulator. It sounds exactly the same as if the sound board emulator had been incorporated into the shipping product." Q.9.4 Why is sound so *hard* to emulate? Neil Bradley complains: "I've been asked multiple times why I don't 'just add sound'. Well, the lousy sound cards we've been cursed with have different structures from almost every other form of synthesis known to man. I'm talking filtering, pitch, etc... Sorry to say it, but not even the most expensive Sound Cards are high quality. They are cheap, piles of garbage. Compared to their big brother counterparts (I.E. the digital or analog synthesizer), they are noisy, brash, cranky, and of such low quality it's amazing they work at all. Just so you all know, my reference equipment consists of racks of synthesizers, and compared to them, no sound card is even moderately close to their quality. So partly the reason I don't bother with sound is that the quality is so poor. It's better than a PC speaker, and it gives SOME sound, but saying that it has synthesis capabilities is like saying a Moped is well suited for transportation in all weather conditions. For specifics: The Pokey. The only proper way to emulate this chip is to sample it. FM Syntehsis doesn't sound like top octave divided square waves. FM Sounds thin by comparison. So if you want the character of the Pokey, you sample it. This is called true emulation. Anything else is an imitation. Lots of circuits have bass boost and image enhancers to get their "sound", and without sampling the real thing, you're going to get thin & cheesy sounds in a lot of cases. There aren't enough oscillators on all sound cards to emulate a 2-4 Pokey configuration, either. So what do you do? Sounds like a mixed sample playback is the correct thing. That means you'd better have damned efficient mixing code! I keep telling people over and over that if you want good performance on a particular low-end platform, machine code the thing! I've seen mixing code speed up 4X after being recoded in assembly. It doesn't make much difference on a Pentium 166, but the 486 users will really appreciate it. Okay, now that we've all decided that sampling is the way to go for Pokey emulation, let's consider a few things. First, you need to have access to the game. Second, you need to get every sound that a game will make sampled. In most cases, getting all these sounds seperately isn't possible (I.E. Battlezone's engine noise & firing sounds). Lastly, once you have each individual sample, you need to reverse engineer the commands to the Pokey that would cause that sound to occur, and more importantly, when it should stop. These aren't straightforward steps. Getting a correct sample (and I don't mean sampling it with a $20 Radio Shack mic and a Sound Blaster) is hard work. You'd spend hours getting a good, high quality sample, necessary for true emulation. In a lot of cases, there aren't enough oscillators or waveforms to choose from when emulating other sound chips. The envlope types don't match, Sound Blasters lack resonant filters or other filter modes, and waveforms don't match up to the ones availale on the game to be emulated. So what do you do? Sampling is the answer. This means that the CPU spends time mixing sounds, which makes the game slower. Recoding in assembly (hint hint) is a good way to maximize your performance. ;-) In most cases, sound chips used in video games don't have primitives that match up to the primitives that your average sound card has, so using the synthesis part of the card to emulate the sound is in a lot of cases a lost cause. So the lack of sound emulation in all kinds of emulators should tell you something. ;-) The sound architecture in sound cards is almost completely different from that of your favorite video game, and emulation is a collosal pain in the ass, if not impossible, to pull off. So have some mercy on us emulator authors, will ya? ;-)" Q.10 Where can I find other documentation for the game? You might try to contact someone who owns the machine. See Q.10. Q.10.1 What about schematics for the game? You might try to contact someone who owns the machine. See Q.10. Also, see R.3.1.4 under References for some schematics available on the web. Q.11 How might I contact someone who owns the machine hardware? The Video Arcade Preservation Society (VAPS) maintains a list of people who own arcade games. These folks might have technical documents that came with the machines. They may also be able to dump ROMs if they are not already available on the internet. If you ask nicely, you might be able to find what you are looking for... See section R.3.1.5 for information about VAPS on the WWW. Q.11.1 Todd Krueger's offer to help This message was sent to the emulator mailing list by Todd Krueger [ToddK52685@aol.com] : [I've taken some parts out of it that do not relate to arcade emulation...] "To all it may concern, My name is Todd Krueger. I have been (for many years now) a video game collector. At first I started with the likes of the original Atari machines then it followed with the Nintendos, Turbo Grafixs ect. Then my collection continued to include arcade machines starting with Golden Axe then back to Space Invaders then Pacman and so on. To date, my collection includes 200+ arcade titles (Some with books and docs some without) and near every home video game machine released. (Alot were donated) My intention of this is to start a museum in Las Cruces, NM. My collection started as a hobby and now is an honest attempt to save this important part of history. I believe that emulation is an important part of this preservation. So I would like to be a source for emulator programers. I can provide photos, sounds, some schematics or the loan of the original boards (on a case by case basis). All I ask in return is to be a beta tester. Some of the popular titles in the collection are: Space Invaders (original b/w, part II b/w & color), Galaga (original and plus), Pacman (orig., MS. & super), Gauntlet, Dig Dug, Bubble Bobble, Asteroids (orig. & deluxe), Tempest, Battlezone, Arkanoid (orig. and Revenge of Doh), Ikari Warriors, Contra, Donkey Kong (1, 3, and junior), Frogger, 1942, Berzerk, Star Wars (orig. and Empire), Defender, Golden Axe, Street Fighter II, Mortal Kombat (orig. and II), Time Pilot 84, Time Soldiers, Mr. Do, Galaxian, Block Out, Shinobi, Altered Beasts, and many others (new titles in all the time). Some of the systems are: Atari (400, 800, 520ST, 1040ST, Jaguar), Coleco, Sega (master, Genisis, CD, 32X, 32X CD, Saturn), Turbo Grafx, Nintendo (8-bit, Super, Pocket, Super Gameboy, N64, Virtual), 3DO, Playstation, Vectrex, Amiga, TI 99/4, and many others. Many references. I will give any help I can in your programming endeavors and I promice I will not use any of your products or betas for personal profit nor would I even show your products to anyone without your permission. I further promise to be an honest and good beta tester if you choose to use me. Also, if you or anyone you know has old video game equipment that they would like to donate to our Video Game Museum project (We need name suggestions) you may do so to: Mission Computer Enterprises c/o Todd Krueger 412 LaCrosse St. W.S.M.R., NM 88002 This address is temporary because the store is not fully open and I am still in the midst of my Army Retirement, but this should be good for a couple of months. Just in case, before you do or send anything, email me at ToddK52685@aol.com Todd H. Krueger" [Sounds like a damn good deal to me!!] Q.12 Where can I find general descriptions of arcade games? The VAPS (see Q.10) also maintains a searchable database containing information about virtually every arcade game ever made. Most entries include the company resposible, the year released, and a brief description of gameplay. The database is the KLOV (Killer List Of Video games). The search engine can be found as a link off the main VAPS site. Q.13 Did other emulator authors keep any notes while they were working? In Neil Bradley's case: "Mental notes. Sometimes printouts of my code when I knew it was buggy. Sometimes I collected info about the game platform in stacks of paper for reference, but nothing proprietary or non-commonly available material was kept (at least in my case)." Dave Spicer's experience: "Yup, I have about 10 notebooks full of scribbles. Usually my notes consist of rom locations and register lists with occasional outlines of various techniques for implementing a game's hardware. Lately I've tried to get into the habit of documentating hardware within the driver source code." [When asked if he wrote detailed specifications for each game...] "Not for individual emulations, no. It's usually impossible as I'm finding out how a game works, and what's required, whilst I'm writing the emulation. You can't spec something that you don't fully understand! Emulator core resources are another matter. Before adding anything to the emulator core (something I haven't had to do for months now), I write documentation covering what's required and how the programming interface will work." Q.14 Where can I find more information on the internet and WWW? See section R.3 under References. Also, Neil Bradley suggests: "Do an infoseek search on '+cpu +emulator'. There is a page that has emulators, and many, many other links that will give you more than you asked for. ;-)" Q.15 Should I release my source code when I'm finished? By all means YES!! :D It's really up to each individual author. Some people (I won't name names) have chose to keep their emulators from the public, with thoughts of a commercial release. Others have released their emulators as freeware. Still others plan to release the source code with their freeware emulators. I, personally, think that emulation is a hobby to be shared with the rest of the world... Mike Cuddy says: "I plan on releasing every scrap of code, documentation, etc. when I'm done. Making emulators is hard-enough without charging people money, or hoarding information (dig, dig ... you know who you are ;-) -- besides, given the quasi-legal status of most of the ROM images, it's hard to justify charging people -- I'd rather have more emulators floating around! And like I said, when this ordeal is done, the release will be a SOURCE release." Q.16 How well do arcade emulators work under Unix (X11)? Some people have been surprised to see emulators written (and ported) to Unix. Aren't DOS and Windows versions better? Well, it all depends on your personal preferences, and which OS you find yourself running most of the time... Jeff Mitchell says: "Well, its Unix. The kernel will take away processing time whenever it feels it has to, for various pending tasks. [Some see] that as a fault. Why?! If your playing a game -- so what if it gets slow suddenly because your system is receiving a meg of email. Thats why your running Unix... You want background tasks to work sanely :) " --------------------------------------------------- .d88b 888b. w 8P www .d88 8d8b.d8b. .d88b 8 8 .d88 w8ww .d88 8b d8 8 8 8P Y8P Y8 8.dP' 8 8 8 8 8 8 8 `Y88P' `Y88 8 8 8 `Y88P 888P' `Y88 Y8P `Y88 --------------------------------------------------- D.0 What is this section about anyway? I've received lots of information from a number of different people. You'll find memory maps, hardware descriptions, and even snippets of code in this section. Whether you are just curious about the 'guts' of arcade machines, or you need specific information for an emulator, this section is for you! D.1 Astro Blaster [provided by Christopher Brooks (chrisb@pacificnet.net)] IRQ's were triggerable by video, Coin switch inputs and the Voice Board (?) NMI's were generated by a momentary contact switch on the CPU board to start a self-test sequence. I also seem to remember talking to a Sega Tech about a 60 Hz pulse that was to appear at the Reset pin of the Z-80A, which was a signal derived from the supply's transformer secondary, converted to square-wave TTL of course. Sounds for the game were generated from dedicated circuits enabled from data latches (3E & 3F). These were made mostly from cascaded 555 timers and 4000 series logic gates. A Speech synthesis subsystem was also used, but all I can remember about it was that the speech chip was NOT a Votrax (popular at the time) and that it was clocked at 3.10 MHz (the x-tal was hard to find). I/O Port; 0x3E - Sound Board Latch 1 Bit functions (write only) 7 - Warp Invader Sounds 6 - Refuel 5 - Not Used 4 - Asteroids 3 - Invader 4 2 - Invader 3=20 1 - Invader 2 0 - Invader 1 0x3F - Sound Board Latch 2 Bit functions (write only) 7 - Sonar 6 - Deedle 5 - Not Used 4 - Not Used 3 - Player Ship Explosion 2 - Enemy Ship Explosion 1 - Enemy Bullet Fire 0 - Player Bullet Fire 0xF8 - CPU Board Dip Sw. 1 (read only) 0xF9 - CPU Board Dip Sw. 2 (read only) 0xFA - CPU Board Input Port 7 - ? 6 - ? 5 - P1 Left 4 - P1 Right 3 - ? 2 - ? 1 - ? 0 - ? 0xFB - CPU Board Input Port 7 - ? 6 - ? 5 - P1 Fire 4 - P1 Warp 3 - ? 2 - ? 1 - ? 0 - ? 0xFC - CPU Board Input Port 7 - P2 Left 6 - P2 Right 5 - P2 Fire 4 - P2 Warp 3 - ? 2 - ? 1 - ? 0 - ? 0xC800-CFFF 2K RAM on CPU Board 0xE000-E3FF Video Memory (Dual Ported RAM 1K x 9) 0xF000-FFFF Ram on the Video board D.2 Commando [provided by edoardo (gambare@iol.it)] I've got the original commando's board and my dream is see this game on my PC... MANUFACTURER: CAPCOM of America YEAR: 1985 CPU(s): 2 Nec D780-1 (It's a Z80 compatible chip) SOUND: 2 Yamaha YM2203c D.3 Crazy Climber "CRAZY CLIMBER HARDWARE DETAILS AND MEMORY MAP" by Lionel Theunissen. (Updated 22/01/97) Special thanks to Nicola Salmoria for working out details of the small sprites. Thanks also to Andy Milne (andy@canetics.com) for confirming the sound sample data format D.3.1 Video The video circuitry for Crazy Climber is similar to other early 80's games, but has some unique features. The display is character generated - 32 characters across and 28 high - which makes 256*224 pixels. The 1k of screen RAM at 9000h addresses the character ROMs (ROMs 03-06). These are arranged as two pairs. One pair for each character set. The character ROMs give the two bits per pixel, which along with the colour RAM, determine the colour. Each vertical character column (32 in all) can be scrolled independantly using the column scroll registers at 9800h. Note that unlike most other games of the time, CC uses a horizontally oriented picture tube (as in a VGA monitor), rather than the vertically oriented tube as used in Pacman, Galaxians, and Space Invaders. An unusual feature of the display circuitry is what I call the "Bigsprite". There are 256 bytes of RAM at 8800h which are attached to a pair of character generator ROMs (ROMs 01-02). This can be moved as one big 16*16 character block (128*128 pixels) using the control registers at 98ddh-98dfh. This sprite is used for the logo on the title screen, the bird, and other large objects in the game. As in most character generated displays of the time, the colour of each pixel is determined by a combination of the lower 4 bits (Bits 0-3) of the colour RAM and the two bits per pixel from the character generator ROMs. Bit 4 of the colour RAM selects between the two character sets. Bit 5 of the colour RAM is also attached to an address decoder in the circuit, enabling more than two character sets to be selected, but this is not implemented in CC. Bit 6 x inverts a character. Bit 7 y inverts a character, but this doesn't seem to be used. Interestingly, while the colour RAM occupies 1k, there are really only 512 bytes of colour RAM. It is mapped to the 1k region between 9c00h and 9fffh, but address bit 5 is not connected. This means that each byte codes for colour at the same character position on two rows. The 32 bytes on even rows are mirrored by 32 bytes on odd rows. While the CC software will write as a block to the colour RAM most of the time (writing to even and odd rows) there are instances where only one row will be written to, which will leave the corresponding row incorrectly set if the mirroring is not emulated. D.3.1.1 Palette The 6 bit value (0-63) derived from the character generator ROMs and colour RAM are fed into two 32*8 bit palette PROMs. The output byte of the PROMs determines the colour as follows. Bits 0-2: Red (0-7), Bits 3-5: Green (0-7), Bits 6-7: Blue (0-3). Because a colour scheme can't be copyrighted I have decided to provide a dump of the PROMs: (0-31) 00 79 04 87 00 b7 ff 5f 00 c0 e8 f4 00 3f 04 38 00 0d 7a b7 00 07 26 02 00 27 16 30 00 b7 f4 0c (32-63) 00 4f f6 24 00 b6 ff 5f 00 33 00 b7 00 66 00 3a 00 c0 3f b7 00 20 f4 16 00 ff 7f 87 00 b6 f4 c0 For the Bigsprite a 5 bit value (0-31) is derived from its own character generator ROMs, and the lower three bits of the colour/attribute register at 98ddh, which is fed into a seperate palette PROM: (0-31) 00 ff 18 c0 00 ff c6 8f 00 0f ff 1e 00 ff c0 67 00 47 7f 80 00 88 47 7f 00 7f 88 47 00 40 08 ff The hardware supports eight 2*2 character sprites (16*16 pixels) controlled by registers at 9880h-989fh. The sprites use the same character generator ROMs and palette as the screen RAM. D.3.2 Sound Crazy Climber uses an AY-3-8910 addressed at I/O 8&9 for music, and has a sample playback system for other sounds controlled by the two ports on the AY-3-8910 and registers at a004h, a800h, and b000h. ROMs 12-13 contain the sample data. The sample information is 4 bit with two 4 bit nybbles per byte of ROM which are read sequentially, lower order bits first. The D/A is crude consisting of four CMOS switches (a 4066), which switch discrete resistors. There is no companding (sorry Andy!), but the output is fed through an LM3900 opamp configured as a low pass filter. PORT A on the AY-3-8910 determines the start position of the sample as follows: Bit 0-6: Start position address bits A5-A11 on ROM. Bit 7: Rom select 0=ROM13, 1=ROM12. The sample is triggered by writing to Bit 0 of a004h (0=load, 1=trigger). This loads the start address from the PORT on the AY-3-8910. The sample will then play until a decoder on the data bus of ROMs 12 and 13 detects a 70h or 80h byte. On 70h the sample will stop playing. From the circuit it appears that 80h will load the start address on PORT B of the AY-3-8910, but this doesn't seem to be used. A register at a800h determines the sample rate. This is a full byte value (0-255, 255 is fastest). The volume of the sample player is set by a 5 bit value (0-31, 31 is loudest) at b000h. D.3.3 Other Details There is a watchdog circuit which will reset the processor if the machine switches (coin, player start, etc) at b800h are not read for a certain period of time. This ensures that if the program crashes due to a power glitch or whatever, the program will reset. There is little point in emulating this. D.3.4 Memory Map Note that the address decoder on CC only decodes to 2k blocks. Therefore 1k of RAM at 9000h will also appear at 9400h. Sometimes the software will write to a mirror address; eg. I've found that the CC software will occasionally write to the screen RAM in the 9400h-97ffh block rather than the 9000h-93ffh block. This is probably due to a bug, but it gets away with it because the address is not fully decoded. 0000h-4fffh ;20k program ROMs. ROM11=0000h ROM10=1000h ROM09=2000h ROM08=3000h ROM07=4000h 8000h-83ffh ;1k scratchpad RAM. 8800h-87ffh ;256 bytes Bigsprite RAM. 9000h-93ffh ;1k screen RAM. 9800h-981fh ;Column smooth scroll position. Corresponds to each char column. 9880h-989fh ;Sprite controls. 8 groups of 4 bytes: 1st byte; code/attribute. Bits 0-5: sprite code. Bit 6: x invert. Bit 7: y invert. 2nd byte ;color. Bits 0-3: colour. (palette scheme 0-15) Bit 4: 0=charset1, 1 =charset 2. 3rd byte ;y position 4th byte ;x position 98ddh ;Bigsprite colour/attribute. Bit 0-2: Big sprite colour. Bit 4: x invert. Bit 5: y invert. (not used by CC) 98deh ;Bigsprite y position. 98dfh ;Bigsprite x position. 9c00h-9fffh ;1/2k colour RAM: Bits 0-3: colour. (palette scheme 0-15) Bit 4: 0=charset1, 1=charset2. Bit 5: (not used by CC) Bit 6: x invert. Bit 7: y invert. (not used by CC) a000h ;RD: Player 1 controls. Bit 0: Left up 1: Left down 2: Left left 3: Left right 4: Right up 5: Right down 6: Right left 7: Right right a000h ;WR: Non Maskable interrupt. Bit 0: 0=NMI disable, 1=NMI enable. a001h ;WR: Horizontal video direction (for table model). Bit 0: 0=Normal, 1=invert. a002h ;WR: Vertical video direction (for table model). Bit 0: 0=Normal, 1=invert. a004h ;WR: Sample trigger. Bit 0: 0=Trigger. a800h ;RD: Player 2 controls (table model only). Bit 0: Left up 1: Left down 2: Left left 3: Left right 4: Right up 5: Right down 6: Right left 7: Right right a800h ;WR: Sample rate speed. Full byte value (0-255). b000h ;RD: DIP switches. Bit 1,0: Number of climbers. 00=3, 01=4, 10=5, 11=6. Bit 2: Extra climber bonus. 0=30000, 1=50000. Bit 3: 1=Test Pattern (doesn't work!) Bit 5,4: Coins per credit. 00=1, 01=2, 10=3 11=4. Bit 7,6: Plays per credit. 00=1, 01=2, 10=3, 11=Freeplay. b000h ;WR: Sample volume. Bits 0-5: Volume (0-31). b800h ;RD: Machine switches. Bit 0: Coin 1. Bit 1: Coin 2. Bit 2: 1 Player start. Bit 3: 2 Player start. Bit 4: Upright/table select. 0=table, 1=upright. I/O 8 ;AY-3-8910 Control Reg. I/O 9 ;AY-3-8910 Data Reg. *If anyone can help fill in some of the blanks or has corrections please email me. Lionel Theunissen (lionelth@ozemail.com.au) D.3.5 Decrypting the ROMs "HOW TO DECRYPT THE CRAZY CLIMBER ROMS" by Lionel Theunissen (Updated 22-01-97) Please note that if anyone does use this info for their own CC emulator project I do ask that credit be given where credit is due. I'm not asking for any money, just to be acknowledged in the emulator credits. It was a LOT of work to crack this:- As for the decryption algorhythm, a few things; There are two sets of ROMs in the tant archive (Brian Peek's mirror). One is supposedly the genuine set, and the other a bootleg (Actually I am beginning to suspect that this is not really a bootleg at all, but just another version, possibly Japanese. About the only differences I have spotted between the two are that the sampled sounds are different, and the high score table only allows 3 characters instead of ten. Both versions credit Nichibutsu for the game). The program ROMs (7-11) and sound ROMS (12-13) on my boards are the same as the 'bootleg' set and the graphics ROMs seem to be the same as the 'genuine' set. The encryption on the bootleg set is different to the genuine set. The following description only applies to the bootleg program ROMs (Only the program ROMs are encrypted). If you look at ROM11 with a hex editor the first few bytes should be as follows if you have the right set:- FE FF FF EE 73 00 A0 96 AC 00 44 54 44 54 44 54 The encryption is quite sophisticated and cannot be decrypted without simultaneously disassembling the code, determining which bytes are opcodes and unscrambling the encrypted bytes. I actually had to write a special Z80 disassembler/unscrambler to do this (This was written on a C64 if you want the program). ***NOTE: Don't panic! A Z80 emulator program can be easily modified to decode the encrypted ROMs on the fly. Please don't ask me for decrypted versions of the ROMs. On the Z80 there is a pin called M1 or 'machine cycle one'. This signal indicates when the processor is doing the opcode fetch of an instruction execution. In other words, for an instruction like a Jump which consists of 3 bytes, the first byte is the opcode and the following two bytes are the address to jump to. The M1 pin will only be active while reading the first byte. The decryption is only applied when the M1 pin is active. in other words for a Z80 jump instruction:- ROM bytes xx 00 40 -----> would become C3 00 40 ;xx is encrypted byte. ^^ ^^ Note that the bytes containing the jump address stay the same. Similarly, for a two byte instruction which consists of an opcode and an operand, only the first byte will be encrypted, and of course all one byte instructions would be encrypted. There are also Z80 instructions which have more than one opcode byte (eg. the opcodes that start with cbh, ddh, edh, fdh) What this means is that decryption cannot be applied to the whole file because all data/operand reads are unencrypted. Only the opcodes are encrypted. The Z80 knows which bytes are opcodes and therefore it can tell the decryption circuit which bytes to decrypt. However, there is no easy way to simply look at the file and know which bytes are opcodes and which bytes are data/operands without decoding the instructions on two levels; firstly unscrambling the first opcode byte, determining what kind of instruction it was, and from that determining the appropriate number of bytes to the next opcode (That is what my disassembler/unscrambler program did). Just to make life a little more difficult, the encryption is different on odd and even addresses. The encryption involves scrambling bits 0,2,4,6 through a prom which is toggled by Address bit 0. The following index tables taken from my disassembler/unscrambler program decode the opcode bytes. Use evetab for even addresses and oddtab for odd addresses. The values in the tables are all decimal. For example for encrypted value of 1 on an even address you would read 84 (decimal). For an encrypted value of 4 on an odd address you would read 64 decimal). evetab: db 65, 84, 70, 19, 81, 20, 2, 82 db 73, 92, 78, 27, 89, 28, 10, 90 db 5, 16, 67, 86, 1, 85, 6, 22 db 13, 24, 75, 94, 9, 93, 14, 30 db 97, 116, 102, 51, 113, 52, 34, 114 db 105, 124, 110, 59, 121, 60, 42, 122 db 37, 48, 99, 118, 33, 117, 38, 54 db 45, 56, 107, 126, 41, 125, 46, 62 db 68, 17, 23, 66, 0, 80, 83, 87 db 76, 25, 31, 74, 8, 88, 91, 95 db 21, 64, 7, 18, 4, 69, 3, 71 db 29, 72, 15, 26, 12, 77, 11, 79 db 100, 49, 55, 98, 32, 112, 115, 119 db 108, 57, 63, 106, 40, 120, 123, 127 db 53, 96, 39, 50, 36, 101, 35, 103 db 61, 104, 47, 58, 44, 109, 43, 111 db 148, 193, 135, 215, 129, 196, 130, 210 db 156, 201, 143, 223, 137, 204, 138, 218 db 132, 208, 147, 194, 209, 197, 214, 150 db 140, 216, 155, 202, 217, 205, 222, 158 db 180, 225, 167, 247, 161, 228, 162, 242 db 188, 233, 175, 255, 169, 236, 170, 250 db 164, 240, 179, 226, 241, 229, 246, 182 db 172, 248, 187, 234, 249, 237, 254, 190 db 145, 192, 199, 211, 212, 149, 146, 134 db 153, 200, 207, 219, 220, 157, 154, 142 db 144, 128, 198, 131, 213, 133, 195, 151 db 152, 136, 206, 139, 221, 141, 203, 159 db 177, 224, 231, 243, 244, 181, 178, 166 db 185, 232, 239, 251, 252, 189, 186, 174 db 176, 160, 230, 163, 245, 165, 227, 183 db 184, 168, 238, 171, 253, 173, 235, 191 oddtab: db 80, 17, 18, 82, 64, 85, 86, 87 db 88, 25, 26, 90, 72, 93, 94, 95 db 81, 20, 3, 70, 69, 4, 66, 6 db 89, 28, 11, 78, 77, 12, 74, 14 db 112, 49, 50, 114, 96, 117, 118, 119 db 120, 57, 58, 122, 104, 125, 126, 127 db 113, 52, 35, 102, 101, 36, 98, 38 db 121, 60, 43, 110, 109, 44, 106, 46 db 84, 21, 22, 19, 16, 5, 2, 67 db 92, 29, 30, 27, 24, 13, 10, 75 db 68, 1, 71, 23, 0, 65, 83, 7 db 76, 9, 79, 31, 8, 73, 91, 15 db 116, 53, 54, 51, 48, 37, 34, 99 db 124, 61, 62, 59, 56, 45, 42, 107 db 100, 33, 103, 55, 32, 97, 115, 39 db 108, 41, 111, 63, 40, 105, 123, 47 db 129, 133, 215, 210, 193, 197, 151, 146 db 137, 141, 223, 218, 201, 205, 159, 154 db 212, 208, 131, 134, 213, 144, 195, 198 db 220, 216, 139, 142, 221, 152, 203, 206 db 161, 165, 247, 242, 225, 229, 183, 178 db 169, 173, 255, 250, 233, 237, 191, 186 db 244, 240, 163, 166, 245, 176, 227, 230 db 252, 248, 171, 174, 253, 184, 235, 238 db 145, 149, 199, 194, 209, 148, 135, 130 db 153, 157, 207, 202, 217, 156, 143, 138 db 196, 192, 147, 150, 132, 128, 211, 214 db 204, 200, 155, 158, 140, 136, 219, 222 db 177, 181, 231, 226, 241, 180, 167, 162 db 185, 189, 239, 234, 249, 188, 175, 170 db 228, 224, 179, 182, 164, 160, 243, 246 db 236, 232, 187, 190, 172, 168, 251, 254 I have been thinking that it would be a fairly simple matter to use these tables in a Z80 emulator so that when it decodes the opcodes it uses the encrypted value from the ROMS to index the above tables and return the appropriate opcode. This would allow an emulator to use the original encrypted ROM images. If anyone needs any other help regarding Crazy Climber please email. I have worked out most of the memory map and have a partly working CC reconstruction already. Lionel Theunissen (lionelth@ozemail.com.au) D.3.6 Miscellaneous Information [provided by Vince Mayo (14u2c@diamond.nb.net)] In case anyone might be intrested in emulating this game(besides me), here is some docs I have made to make Crazy Climber emulation: Uses one Z80, one AY3-8910 for sound ROMS Identification ----------------------- CC12 Sound CC13 Sound CC11 Loads at 0000 - 0fff CC10 Loads at 1000 - 1fff CC09 Loads at 2000 - 2fff CC08 Loads at 3000 - 3fff CC07 Loads at 4000 - 4fff CPU working area RAM is 8000-83ff (2 2114s) (1k x 4bit) CC06 All graphice ROMS I think. They are attached to six 2125s CC05 (512 x 4bit?) This would be 3000 bytes of RAM area (for video RAM CC04 possibly?) CC03 CC02 Character ROMS I think. They are attached to two 5101s CC01 (256 x 4bit) only 256 bytes being used. (also video RAM?) ------------------------- Other information in CC Schematics: RD0 - 8000 RD1 - 8800 RD2 - 9000 RD3 - 9800 RD4 - a000 RD5 - a800 RD6 - B000 RD7 - B800 I might be wrong about the 3K RAM from the six 2125s. (I believe they are (512 x 4) = (2 of them = 512 bytes) which would mean there would only be 1.5K total out of the six. D.3.7 Different Versions, and Extra Credit(s) [provided by Lionel Theunissen (lionelth@ozemail.com.au)] There are now three versions of Crazy Climber that I know of. Firstly there is the 'American' version which is available from TANT, the bootleg, which is also available on TANT, and what I call the 'Japanese' version, which is on my CC PCBs. The bootleg is a ripoff of the 'Japanese' version. In fact, you can make up a Japanese set by replacing the character ROMs (ROMs 1-6) of the bootleg with those in the 'American' set. I think I can say, having now examined all three versions, is that the 'Japanese' version is the 'official' original Crazy Climber. The 'American' version is a bug fix, which has english samples (I don't know if the samples on the other version are Japanese, but they're not english. They sound more cartoony). I found when disassembling the 'Japanese' version that there is a password. Enter the name 'jordan.ltd' into the highscore table and it gives you two free credits. This also works on the bootleg, because the program ROMs are the same. The American version also has the password code, but the highscore registration has been crippled to only allow 3 characters. Presumably this was changed in case the password leaked out. I haven't tried this myself, but Nicola reports that by changing location 0c8ah of ROM 11 from 03 to 0b, it enables you to enter in ten characters and the password works. D.4 Crush Roller [provided by Vince Mayo (14u2c@diamond.nb.net)] I have looked at the code from Crush Roller and Pacman posted at the Repository and have noticed serveral similarities (besides the same coding for graphics). I looked at the size of the ROMs and started placing them together, and gave this a try: copy /b cra+crc pacman.5e copy /b crb+crd pacman.5f copy /b cr1+cr5 pacman.6e copy /b cr2+cr6 pacman.6f copy /b cr3+cr7 pacman.6h copy /b cr4+cr8 pacman.6j After I have tried this, I loaded the appended ROMs into Dave Spicer's emulator (as Pacman), and it worked well with sound (except for the colors). One other thing about sound. After the game is over, the sound will hang on a note until a new game is started, or escape. Try it out. Its worth a look. I give avdbas@wi.leidenuniv.nl credit for this. I would not have known where to put the ROMs without the sample code. D.5 Dig Dug [provided by Ivan Mackintosh (ivan@rcp.co.uk)] Memory Map Taken from the "Dig Dug CPU PCB Schematic Diagram" - Sheet 3a HEXA- R/W DATA FUNCTION DECIMAL ADDRESS D7 D6 D5 D4 D3 D2 D1 D0 0000-3FFF R D D D D D D D D 1st Priority Z80 CPU ROM (16K) 0000-1FFF R D D D D D D D D 2nd Priority Z80 CPU ROM (8K) 0000-0FFF R D D D D D D D D 3rd Priority Z80 CPU ROM (4K) 6800-680F W D D D D Audio Control 6810-681F W D D D D Audio Control 6820 W D 0 =3D Reset IRQ1 (Latched) 6821 W D 0 =3D Reset IRQ2 (Latched) 6822 W D 0 =3D Enable NMI3 (Latched) 6823 W D 0 =3D Reset 2nd and 3rd Z80 CPUs (Latched) 6825 W D Custom Chip 53 Mode Control (Latched) 6826 W D Custom Chip 53 Mode Control (Latched) 6827 W D Custom Chip 53 Mode Control (Latched) 6830 W Watchdog Reset 7000 R/W D D D D D D D D Custom Chip 06 - Data 7100 R/W D D D D D D D D Custom Chip 06 - Command 8000-87FF R/W D D D D D D D D 2K Playfield RAM 8800-8BFF R/W D D D D D D D D 1K Motion RAM (HPOS, VPOS) 9000-93FF R/W D D D D D D D D 1K Motion RAM 9800-9BFF R/W D D D D D D D D 1K Motion RAM (PIC) A000 W D Playfield Select (Latched) A001 W D Playfield Select (Latched) A002 W D Playfield Color Select (Latched) A003 W D Alphanumeric Color Select (Latched) A004 W D Playfield Select (Latched) A005 W D Playfield Select (Latched) A007 W D Flip Video B800-B83F W D D D D D D D D Write EAROM Address and Data B800 R D D D D D D D D Read EAROM Data B840 W D D D D Write EAROM Control D.X Elevator Action [provided by James Twine (jtwine@bettynet.com)] A friend of mine brought over a Elevator Action boardset last night, and although it does not work (yet... I am working on it...), I do remember seeing 2 Z80 compatable CPUs, and *4* AY-3-8910s. D.6 Gyruss [provided by Mike Cuddy (mcuddy@scitexdv.com)] Mike Cuddy has now set up a WWW page for his Gyruss emulator. He has provided technical information about Gyruss on his page: http://www.fensende.com/Users/mcuddy/gyruss/ Since this information is likely to change as Mike digs deeper into the inner workings of the game, I've decided not to copy the information into the HowTo. Check the above URL for Gyruss information... D.7 I, Robot [provided by John Manfreda (jmanfred@fh.us.bosch.com)] Sound uses a custom IC. The IC is actually 4 pokey chips, using a 'chip on board' packaging technique (flat piece of fiberglass with chips placed directly on and covered with epoxy). From what I am told, this is identical to the sound scheme used on Major Havoc. D.8 Juno First [provided by Mike Perry (mj-perry@uiuc.edu)] Well, someone with a Juno First board gave me the chip numbers and described one as white NEC D780D which is also found on his Galaga board. This has been verified to be a Z80 so that is the processor I will be emulating. The sound chip has been verified to be a SONY AY-3-8910, which has already been emulated in the Vectrex and MSX emulators, so even if I don't know squat about sound programming right now, the adlib/OPL3 code is out there. D.X Kickman [provided by Kurt Mahan (kmahan@novell.com)] Kickman is a typical MCR game. I'd have to dig out the cpu set/schematics to confirm exactly which family but I know its a block of boards... I'd also have to find my boardset (I know I've got one along with Domino Man and a few others of that vintage...) D.9 Kung Fu Master [provided by Conny Melin (connymelin@hotmail.com)] Kung Fu Master (C)1985 Irem/Data East Rom file description: KF1 - Z80 code. KF2 - Not checked. KF3 - Not checked. KF4 - Not checked. KF5 - Z80 code. KF6 - Background graphics, Bitplane 1 (8192 bytes). KF7 - Background graphics, Bitplane 2 (8192 bytes). KF8 - Background graphics, Bitplane 3 (8192 bytes). KF9 - Sprite graphics (16384 bytes). KF10 - Sprite graphics (16384 bytes). KF11 - Sprite graphics (16384 bytes). KF12 - Sprite graphics (16384 bytes). KF13 - Sprite graphics (16384 bytes). KF14 - Sprite graphics (16384 bytes). D.9.1 Background Graphics Kung Fu Master uses 8x8 pixel tiles with three bitplanes per tile for the background graphics, giving a maximum 8 colors per tile. The tiles are stored like this in the rom files: Bitplane 1 - in rom file 'KF6' Line1 00011000 (Each lineX represents a byte) line2 00111000 line3 00011000 line4 00011000 line5 00011000 line6 00011000 line7 00111100 line8 00000000 Bitplane 2 - in rom file 'KF7' Line1 00000100 Line2 00000100 Line3 00100100 Line4 00000100 Line5 00000100 Line6 00000100 Line7 00000010 Line8 00111110 Bitplane 3 - in rom file 'KF8' Line1 00000000 Line2 00000000 Line3 00000000 Line4 00000000 Line5 00000000 Line6 00000000 Line7 00000000 Line8 00000000 Now each of these rom files (KF6,KF7,KF8) are 8192 bytes long, so if we put them after one eachother in memory we'd have to jump 8192 bytes forward each time we want a new bitplane. D.9.2 Sprites The sprite roms are each 16384 bytes in size, just as in the background the maximum colors are 8, thus 3 bitplanes. Now, the sprites are built up of 8x8 pixel tiles, just as the background, and here the first bitplane of a tile is in the first rom, the second bitplane in the second rom etc. Just as it were with the background tiles. Here is how the sprite rom-files are divided: KF9 - Sprites 1, Bitplane 1. KF11 - Sprites 1, Bitplane 2. KF14 - Sprites 1, Bitplane 3. KF10 - Sprites 2, Bitplane 1. KF12 - Sprites 2, Bitplane 2. KF13 - Sprites 2, Bitplane 3. Ok, so the sprites are built up of small 8x8 tiles, however, a single sprite consists of four of these 8x8 pixels, thus a sprite is in fact 16x16 pixels in size. In the rom files the 8x8 tiles that builds the sprite is stored sequentally like this: (each spritex.x represents a tile, 4 tiles per sprite) romfile = KF9 bitplane 1: sprite1.1, sprite1.2, sprite1.3, sprite1.4, sprite2.1, sprite2.2, sprite2.3, sprite2.4, romfile = KF11 bitplane 2: sprite1.1, sprite1.2, sprite1.3, sprite1.4, sprite2.1, sprite2.2, sprite2.3, sprite2.4, romfile = KF14 bitplane 3: yep, same as above... Ok, now when the sprites are displayed on screen the 4 tiles that build the sprite is displayed as follows: (a 16x16 sprite, built of 4 tiles) --------------------- | | | |sprite1.1|sprite1.3| | | | |---------|---------| | | | |sprite1.2|sprite1.4| | | | --------------------- Any corrections, comments or otherwise arcade-emulation related mail is gratefully received at connymelin@hotmail.com D.10 MCRII / MCRIII [provided by Ed Henciak (ethst3+@pitt.edu)] 1> They are not like System I/II games by Atari. They are not cartridge based and don't have that stupid security hell similar to what I am going through with Star Trek (I finally have access to a logic analyzer though!!!! YES!!!!!!!!!!) However, MCRII/III games are ROM swappable AS LONG AS they are the same platform (MCRII is not compatible with MCRIII ROMS and vice versa) 2> From what I can remember here are some compatibility lists... MCRII : Satan's Hollow, Tron, Two Tigers MCRIII : Journey, Tapper, Discs of Tron, Spy Hunter (this would need a 68000 based audio emulator for the music) Some other games that used the MCRII/III setup that I don't want to exactly commit to a specific MCR platform are : Timber, Wacko, Domino Man, (my memory is failing me!!! Help!!!) Of course, there are many more games. I think Bally's idea of security in these games were the controls. Look at the list of these games and think about all the various control panels (example... Satan's Hollow would need an encoder wheel to play Tron... if you wanted Tapper on Journey, you'd have to re-orient your monitor as well as add two momentary switches to serve beer... etc.) 3> Some games in this category are hybrids in that they may use an MCRII CPU board and an MCRIII video board (called a Super Video board or something like that...). 4> Like Spy Hunter, Journey used an auxillary board. It wasn't 68000 based. It was a cassete recorder!!!! If you remember the game, Journey actually played a concert in the "bonus round". If we see this emulated, none of you will care though. I think the game is horrible and have been trying to trade mine for months!!! If this emulation is completed, it will emulate many of our all time favorites!!!! Let us hope. I am impressed with the Time Pilot/Gyruss emus and thank Mr. Cuddy immensly for bringing back all those memories. Good luck and may the force be with you :)!!! D.11 Moon Cresta See section S.4, "How to Create a Memory Map for Moon Cresta" D.12 Ms. PacMan / PacMan [provided by Allard van der Bas (avdbas@wi.leidenuniv.nl)] I'm stuck at the moment, so it wouldn't hurt to get some feedback on what I found out so far. The information holds for mspacman (non bootleg version, the bootleg version is only different in how it processes it's interrupt). [Note: This information also applies to PacMan.] D.12.1 ROM Files name type location -------------------------------------- mspacman.6e code $0000-$0fff mspacman.6f code $1000-$1fff mspacman.6h code $2000-$2fff mspacman.6j code $3000-$3fff mspacman.5e char non memory mapped (see pascal source) mspacman.5f char ? non memory mapped (see pascal source) mspacman.u5 ??? non memory mapped mspacman.u6 ??? "" """ "" mspacman.u7 ??? "" """ "" D.12.2 Memory Layout ROM $0000-$3fff code + data RAM $4000-$43ff video 1 (filled with $40 means clear) $4400-$47ff video 2 (filled with $0f means clear) $4c00-$4fff general purpose RAM D.12.3 Memory Mapped Ports $5000-$5007,$5040,$5080,$50c0 ($5050-$505f). $5080 : dipswitches ? $50c0,$5040 : joystick / slots ? $5000 - $5007 : timers (for interrupt) ? $5050 - $505f : ??? <- referenced only once. D.12.4 OUT ports $00 : interrupt chooser An OUT $FA at port 00 chooses interrupt routine at $3000. This one is only activated once ($3000 has some sort of machine check). An OUT $FC at port 00 chooses interrupt routine at $008d. This is the general interrupt used throughout the game. The bootleg version handles interrupts in a different way, (not IM2). But accesses the same interrupt routines. D.12.5 Character Sets The chars are built up really weird, chars are encoded using 2 bits per pixel, but chars are 8x8, so 1 char takes 16 bytes. The first 8 bytes are the lower pixels and the second 8 bytes are the top pixels. Look at the include pascal source to figure the chars out. D.12.5.1 Pascal Source (ZIPed an UUencoded) I've ZIPed and UUencoded two pascal source files Allard van der Bas sent me. The information is much more compact in this form -- including the full pascal source would have taken up too much space! From the comments: { Used to find characters in rom files. Mspacman chars are really 2 bits per color, but use only one color to detect shapes, Dumps both character roms on a 320x200 screen } And Allard said: "The mode13h Unit isn't fast enough to support the screen updates needed for decent emulation. (I got about 30 fps using predefined sprites on my P120/Mach64; the overhead of the emulator will kill this to about 5 fps). But you're free to do what ever you want with it. (Just loose the (c) notice in mode13h.pas)." Just cut and paste this UUencoded block to a new file and decode it. If this is a problem, let me know and the source files can be distributed with the HowTo as separate files... begin 644 avdbas.zip M4$L#!!0````(`,^^,$:%^H[LO-`R8S9\^>.3.[SA7-[RE9P2#)PDNV)L&*9/V84':VO[>_]PS? M&(;`XP`+*&(&/Z7J;].+J41=YB&ZK5A5,GM:HXQ=D10Y1X`N]"@E3[=NL^D= MG]CBT;J#<03G3QS5"N%,@&$A2NF+6CA^C\@#?E^3%*QK0F%0?NN4G`UCF88+ M;2(K$FB#`YTN+%,2/-C`8^D-XS+T&"<"J#1?]R92W@^2%D*<(#4Z0'A39*)L M$1J*YSU2MX;8G3U`E&"_W$-P\M64%M M'3%0%_L'1*N&V,6X[W@A,V_;(#.O'2A]J)HLX5?UR5%@=>J0BZ@>3*?9/'"B M*%)3N2RG01ZXC*R$2S#E-,GN570`YM.!P?#KA8K-[449NQE/?+V'\57&+<5H^%V4`?"5.V1+FV M_.O5YWL<1;KL2I%17HNH=FVIJ::F7-X%I>;0/:D-W4+U0H[;Y]?3-N]TG:KM M2ERG:YIP:UB/!,,1G-Z=2<@SS$3CU%&+$LHX1'E!89UL,#6GKJ+13YA^F4![ M:PL/MI+E8%ZE.5=$EG;QJ/3Q:*$-:QC@<-2WYHW7E);F[(U\.'#:#47N_15R M3Y.['T5>Y_X(4E>2[K9Q(3I8:U^&&P[MMUJWW9[_>_?7>K=]-5:GLL=8&M,HW:O=,_^7EYKS[JIVK?ACH MX6D#+L>^_/UBC%O4T^`/KZ'M-.`03DU>WKJRSA)BS^U%WD4! MLN+CS_]%Q;HN$J:9KHD$#SR?X8;KV6K^`E!+`P04````"``&OW(A/Q9U)FL( M```A+```"P```$U/1$4Q,T@N4$%3[5IM;^)($OX>B?]0'R(-R3@CDV2S,\G- M*8"]"RL""#L)W&H^.*8G>&-LRS9A5]'\]^T7]YNQ(9D=Z70G/%+&75U=]51U M=757X]MAWX5E/$>ML\55XZ!Q\'(,*@V:_A&T/\"S%\$:9H&'.*_YA$= M>D`&C<-Z/\E87#QFGL8_FJQ1=`;Q@IZ`,8:^F@?<0H@R\5+H"^P&\$(N/ MO#QX1I`'2ZSJ&Y%WF\P]"O(2.G$<(B^BV-W`?\J`DN_C=,XGDCX$,)E,R-;K M(/<70?0(:9P'$=;:[/1'#K3,Q9'NYO%DU+6MVXD-&"//46S,]*Z9H2X1(H>,PSL?!GRAL3HT9-\6/PS@EYOZ5HR,-0V)T'"98&R"V0=7`?E]PL\!U1*,Y%(=)C=A1<] M(@>[(T1=`J5)`46QD:)Y8CRF46(\A*ND$F$G#-X"L(2P$WK1$POY>GS6:IGL MXAFORE96RK-CO25[0;+B*PRP;,C0G0= M0[0FJ/I^^T`ORM4^MZV+,(O.RP,CVP8"TZP'<.2O7VC M+1KM@4$!2<[+WZW^%Z,]J#+H^S*B9J.P"JE-V&4EJ*[Y!M,Z5''7`\N MZ3'@UND1P9H2YN>)/<9-QQTY]QHB9L!X-`8^,(SC!."ZTMU;-H!JGU)$%CVS M#"P'',VYV!Q3C9`S_R,U?73KDC8QC$1S%V2H8'M^OOB(#0ZIP8.1Y70VA@Q& MV)SKD!M&U&^:\N9-JFYA:-`I@4]3%'-H$AMG($JX>85]U8P$2'TO05CNK5@E M=;LBM&L70FD=8,=_-.EL622Z#R\NR/MT-*%Q3^+Z.FQ=5F?A%S@WZ9&.'(K3 M.`S1'+[&*60TSWXK"Q5!NB?NB7OBVXAVE^?QWX8VP'78D@GA-6?@ZHQ02N.E M/$Y/']KV3O9W9:^S^C+1DTQR3C()R1>J'7JZ6'I>6)LML)Q-'^R)>^*>N)M8 ME2'$&;#ZK/1#BEAQ0^3Y.3NBXQ?]E$YZLZ<@F1KD[XPG!+67%(F@/4KO$*VG M!OXSJ^AM''3L7_M#FBV)"KC\#.85;\YDDZDHFBI>(NTST->K@E[`)W3V*F!P M]9]ARFDS29L5HON_P!3^!2:X/9M"HZ3F%-XS/4?P;ZU3F$`>@8LHX2.N>"\S M4L$,)V*$8!+NQ$QT@.@1-@B_`-A#JW@9.'85"E.:-:LP:X9!,C?MLHN'!?84 M'M.3KN66S3BV@O-$CMHTCO"QQGMHLM''A7]5>V?P6H,E/,5B?=;.3DO6DWG6 MB;632=A.0,Y%MGLJ^9JMX/M`CZ>UR-H#RU**G@I MC2M3K"X.%_1>4AXPR,-/%47E+4@=MKP%C=3@K((ML0@:+70[I$(![7DY!@OE M*%T&$8)WYKN3),Z"/(@C&'V%N1JA&MJ4$7IP)%/X0)'`['H8M4W$@O)SJL8B/_^"E,3$)7 M=V>7LS+:Q!XKW:3V%H/)]M'5_2[N%U2`EB*.;D;**+HCR2U)R.61P<*<_U^[ M47W7#K7S`J,4E-RY\C9(WG=I-V$_(/PV0T\/.SE9/?U*"<-5PDP+&Q5K89(: M',4-5+NX@%(:,FAX="HW3DJ\%+%2<0I1N:UIE3G?>4IYW=TX#RW]>7M05%QT MG(+_EQ\&HDSA`;.3C032YK6)QL9"K$+I)SB!TTJ19>Z2R-KHE`#_6:2J(G_> MT$SGNU9S55S7.T<-]CJ#2TN@I%C!5UH:VR9/+IFMAFRNF"WL18"51=9$3O<5 MRD_E;2EL/B_PDRJ5W.F1N\7V8*MRMBZ?6YO2"D\VWR^/N#?)!46UZM+\%`M_ ME^5%4CBM50Y,.R;0^^SGU/,>Q_7(.^@\4 M.0@S7RJ9J'*.-B.3YKFM!KUZ0;S-0?6S`^]AN<,_2KZM4*>LERVY^)4U8W5* MWI:9]P7EOJ#<%Y3[@O+_O*#\GRHGMQ23Q8FFNK8D!Q3EQUSRT$,(.X6(XI!L MPN3$(1'18T6IG"Q5DUBV:-^,B]V>[??:;K]U/-OUE8)46O+]=>^&HK=5O9M? MRE07*\IO-*9YSGZC@=*O-#(RR.<6YL79H@@$9L[`N,`^6%]B?[%)L8I1KNVX MI/V1-7\;DBFZ7BLG@HT/?/[[(.LQD@^`(K1N9J4/@)2MGGUW*%+ZKRCO1_D= M\IN'+=^X+CY^]-DVX.B=_/,CUEDR?&" main(int argc, char *argv[]){ FILE *fp,*fp2; int c; int i; fp=fopen(argv[1],"rb"); fp2=fopen(argv[2],"wb"); i=0; while((c=fgetc(fp))!=EOF){ if(!i){ fputc(f(c^0x0a),fp2); }else{ fputc(f2(c^0x82),fp2); i=!i; } } } f(a){ unsigned int b,c; b=(a<<4)&0xa0; c=(a>>4)&0x0a; a=(a&0x55)|b|c; return a; }f2(a){ unsigned int b,c; b=(a<<6)&0x80; c=(a>>6)&0x02; a=(a&0x7D)|b|c; b=(a<<2)&0x08; c=(a>>2)&0x02; a=(a&0xf5)|b|c; return a; } D.16 Phoenix [provided by Ralph Kimmlingen (ub2f@rz.uni-karlsruhe.de)] D.16.1 Components - 8085 CPU @5.5 Mhz - 8x2kB ROM - Two plane display (CHARSET-A, CHARSET-B) CHAR-A: 2x2kB ROM, 4x0.5kB RAM CHAR-B: 2x2kB ROM, 4x0.5kB RAM - 2x3 bit color DAC - 8 bit vertical scroll register - MN6221AA 2voice melody module please note: as Phoenix uses a 90 degree rotated picture tube, all references to 'horizontal' positions actually mean VERTICAL ELECTRON BEAM positions. D.16.2 Functionality The picture consists of two independent planes, where each pixel is represented two bits. As the lower plane is used for scrolling (CHAR-A, starfield), the first row is always invisible (scroll-buffer). All sprites and text are displayed in the upper plane (except for eagles). _____26x8 pixel___________ |xxxxxxxxxxxxxxxxxxxxxxxx| <-- first row (score count etc.) | | | | | /+\ | . . : : <32x8 lines> | | | | | | | | | | |_____^__________________| The graphic data for each plane is drawn from a 8x8 charset and an attached video ram of 2x1024 bytes. Only 26*32 bytes are actually used, representing a screen size of 26*32 characters. Each video ram consists of two banks, which allows for double buffering (see video control register). Vertical scrolling is controlled by a 8 bit value, which determines the first line to be drawn by the video logic. Example: scrollreg= 9 --> video logic starts reading video ram at byte 32 and charset-rom at the second byte. After finishing row 26, row 0 is drawn (->wraparound). D.16.3 Colors Two 8-to-3 lookup-tables (PAL's) are responsible for color output. These PAL's allow for a palette of 6 bit (64 colors) : 7 bit value --> Lookup-Table1 --> 3x1bit (RGB) --> DAC ] video out 7 bit value --> Lookup-Table2 --> 3x1bit (RGB) --> DAC ] (RGB) RED BLUE GREEN 2bit 2bit 2bit The 8 bit value for lookup tables is composed of the following signals: Bit from --------------- 0 ] 1 ] bit 5-7 of video ram value (divides 256 chars in 8 color sections) 2 ] 3 ] 2 bit pixelcolor 4 ] (either from CHAR-A or CHAR-B, depends on Bit5) 5 0= CHAR-A, 1= CHAR-B 6 palette flag (see video control reg.) 7 always 0 D.16.4 Memory Map 0000-3fff 16kB ROM (code + tables) 4000-43ff RAM A (1kB) lower 32x26 bytes used for video ram (CHAR-A), remaining 192 bytes for variables 4800-4bff RAM B (1kB) lower 32x26 bytes used for video ram (CHAR-B), remaining 192 bytes for variables 5000 2 bit video control register (write only) Bit Used for --------------- 0 switching between VIDEO RAM banks (double buffering) 0: r/w access to 4000-43ff or 4800-4bff is directed to bank0 1: r/w access to 4000-43ff or 4800-4bff is directed to bank1 1 color palette swap (blue/red eagles etc.) this bit represents A6 of color PAL chip 2-7 not used 5000-53ff video control (mirrored) 5800 8 bit vertical scroll register (CHARSET-B) this value determines the first of 32x8 vertical pixels to be shown (wraparound fashion) 5800-5bff scroll register (mirrored) 6000 sound control A Bit Used for --------------- 0 ] 1 ] frequency voice1 2 ] 3 ] 4 ] volume voice1 (probably) 5 ] 6 ] melody module command: 7 ] { , , , } 6000-63ff sound control A (mirrored) 6800 sound control B Bit Used for --------------- 0 ] 1 ] frequency voice2 2 ] 3 ] 4 ] volume voice2 (probably) 5 ] 6 ] noise channel (probably volume 0-3) 7 ] 6800-6bff sound control B (mirrored) 7000 8 bit game control (read only) Bit Used for --------------- 0 coin 1 start1 2 start2 3 - 4 fire 5 right 6 left 7 barrier 7000-73ff game control (mirrored) 7800 8 bit dip-switch (read only) Bit Used for --------------- 0 dip-settings 1 dip-settings 2 dip-settings 3 dip-settings 4 dip-settings 5 dip-settings 6 dip-settings 7 for video ciruits : flip picture vertical when read by CPU: ->horizontal sync: this signal is logical HIGH during video output of row 0*8-25*8, otherwise LOW. 7801-7bff dip-switch (mirrored) D.16.5 Sound [provided by James Twine (jtwine@bettynet.com)] This is for anyone out there that has, or is trying to figure out how Phoenix makes its sounds. I played around with it for some time, and I think I have figured out about 50% of how sound works. This following information comes from what I think I have figured out. I cannot guarantee any of the information shown here, it is just what I think is right. Note that the values had to be modified so that they all read "0" when inactive. On Sound Control A (0x6000): o The first 4 (0-3) determine either the Frequency of a sound to play, or the number of birds flying in the air. o The next 2 (4-5) seem to be some kind of flag. If the value is "1", then play the specified frequency. If the value is "2" then the frequency value specifies the number of birds flying (moving in the air) , but the value will be "backwards": If the frequency reads "9", then 1 bird is in the air, if it reads "8", then there are 2 birds in the air, etc. If the value is "0", do nothing. o The last 2 (6-7) seen to be for the/a noise generator. It reads "2" right as your player's ship explodes (trigger the sound). It reads "1" when you fire a shot, but stays at "1" until your shot leaves the screen, or hits something. On Sound Control B (0x6000): o The first 4 (0-3) determine either the Frequency of a sound to play, or perhaps the "tune" to generate (when fighting the Eagles). The value is "0" when nothing is being played. o The next 2 (4-5) seem to be another kind of flag. When it is "0", play the specified frequency. When it reads "2", play the "tune" specified by the frequency value ("15", "13", and "12" are common when on the "Eagle" stages). It reads "3" for a brief instant when it is playing "tunes", and the tune number changes. o The last 2 (6-7) I am still confused about. It is normally "0", but jumps to "3" when you start a game. It then goes back to "0" at some point. Lastly... The values in Sound Control B seem to be affected by coining the game while playing it. Anyone out there can confirm this? Here is the code that I used to figure out the sound information above. The code is written as such that all of the indicators (volume/flags, frequency/tune, etc) are at "0" when "at rest", like in Attract Mode. This gave me a baseline to start from... Note: o All variables starting with "g_" are Global (yuck, I know...). o "iAddr" is the address that is being written to. o "iValue" is the value that is being written to "iAddr". o The EM_* constants equate to BitSet values. Eg, EM_Bit1 == 1, EM_Bit2 == 2, EM_Bit3 == 4, etc. ---- Cut Here ---- if( ( iAddr >= PHO_SoundCtrlBLo ) && ( iAddr < PHO_SoundCtrlBHi ) ) { g_iFreqV2 = 15; g_iVolV2 = 0; // Flag? g_iNoise = 0; // Play Game Tune? g_iVolV2 += ( iValue & EM_Bit6 ) ? 2 : 0; g_iVolV2 += ( iValue & EM_Bit5 ) ? 1 : 0; g_iFreqV2 -= ( iValue & EM_Bit4 ) ? 8 : 0; g_iFreqV2 -= ( iValue & EM_Bit3 ) ? 4 : 0; g_iFreqV2 -= ( iValue & EM_Bit2 ) ? 2 : 0; g_iFreqV2 -= ( iValue & EM_Bit1 ) ? 1 : 0; g_iNoise += ( iValue & EM_Bit8 ) ? 2 : 0; g_iNoise += ( iValue & EM_Bit7 ) ? 1 : 0; g_iFreqV2 *= 100; // Build Up Freq // // If "Flag" (g_iVol2) is "0" (Play Frequency), And // A Frequency Is Specified, Play It! // if( ( !g_iVolV2 ) && ( g_iFreqV2 ) ) MakeSound( g_iFreqV2 ); // Make Some Noise! else _outp( 0x61, 0 ); // Turn Off Any Sound } else if( ( iAddr >= PHO_SoundCtrlALo ) && ( iAddr < PHO_SoundCtrlAHi ) ) { g_iFreqV1 = 15; g_iVolV1 = 0; // Is This Really Vol.? g_iMelody = 0; g_iVolV1 += ( iValue & EM_Bit6 ) ? 2 : 0; g_iVolV1 += ( iValue & EM_Bit5 ) ? 1 : 0; g_iFreqV1 -= ( iValue & EM_Bit4 ) ? 8 : 0; g_iFreqV1 -= ( iValue & EM_Bit3 ) ? 4 : 0; g_iFreqV1 -= ( iValue & EM_Bit2 ) ? 2 : 0; g_iFreqV1 -= ( iValue & EM_Bit1 ) ? 1 : 0; g_iMelody += ( iValue & EM_Bit8 ) ? 2 : 0; g_iMelody += ( iValue & EM_Bit7 ) ? 1 : 0; g_iFreqV1 *= 100; // Build Up Freq // // If "Flag" (g_iVol1) is "1" (Play Frequency) // Then Play That Sound! // if( g_iVolV1 == 1 ) MakeSound( g_iFreqV1 ); // Make Some Noise! else _outp( 0x61, 0 ); // Turn Off Any Sound } ---- Cut Here ---- [For more information and more sample code, see section S.1.6] D.16.6 Miscellaneous [provided by James Twine (jtwine@bettynet.com)] Here are the memory locations for the number of ships remaining for the first and second player. First Player Ships Remaining (BYTE): 0x4390 Second Player Ships Remaining (BYTE): 0x4391 I am still looking for the location that contains either the number of shots allowed in the air at one time, or if "2 shot mode" is enabled (like on the second "Phoenix" stage). D.17 R-Type [provided by Alan Pope (Alan_Pope@deloitte.touche.co.uk)] BOARD 1 (Bottom board) ROMS R-13 through R20 (27256) 4 off Toshiba 2064P-10 3 off Toshiba 2016AP-12 Various 74xxx logic (and lots of it ;) BOARD 2 (middle board) Yamaha YM2151 2 off Sony CXK58256PM-12L Zilog Z80 (hurrah!) 5 off Toshiba TMM2016BP-10 NEC V30 NEC D71059C BOARD 3 (Top board - as if you couldn't guess!) Mfr Chip ID1 Chip ID2 Qty Board Legend ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Altera EP1800LC 2B28736 1 PK8706 Philko PK-RT-1 8744D 1 27512x2 " PK-RT-2 8744D 1 27512x2 Hyundai HY6264P-15 8749 2 6264 Philko PK-RT-3 8744 1 27512 " PK-RT-4 8744D 1 27512 " PK-RT-5 8744D 1 27512 " PK-RT-6 8744D 1 27512 D.18 Sega System 16 Games Games : Shinobi, Altered Beast & Time Scanner Version : 1.2 Author : Thierry Lescot (thierry.lescot@ping.be) First edition : 30-11-96 Last update : 05-01-97 D.18.1 Hardware Information Main CPU is a Motorola 68000 at 10 Mhz with 64K RAM ( + video RAM ) Sound CPU is a Zilog Z80 (at 4 Mhz ?) Sounds chip are Yamaha 2151 (FM) and 3012 (DAC) D.18.2 Memory Map Location Size Function -0000 0000 256 K Main 68000 code + misc. data to 0003 FFFF -0040 0000 64 K Scroll video RAM to FFFF -0041 0000 4 K Fixed video RAM (text page) to + video registers 0FFF -0044 0000 1 K Sprites control registers to 03FF -0084 0000 4 K Color memory (2048 palette registers) to 0FFF -00C4 0000 I/O Registers -FFFE 0007 1 byte Used to control the Z80 program (for sound) -FFFF 0000 64 K Main RAM to FFFF D.18.3 Scroll Video RAM The scroll video RAM can contain up to 16384 tiles (256 lines of 64 characters). There are 2 bytes for each tile, this is the format: AAAAAAAA BBBBBBBB B7->B0 Tiles number in the bank (256) +76543210+76543210+ A3->A0 Bank selector (16) +--------+--------+ A4 Bank page selection (32 banks/page, 256 chars/bank) A5 Priority flag A7->A6 *function not found yet* Colors: the color base register number is (BANK AND 0x1C)*4 Bank selection: If bit A4=0 the bank selected is the value of A3 to A0, if A4 is set to 1 the bank number is: (value of A3 to A0)*16*(value of byte $FFFFF095) D.18.4 Fixed Video RAM The fixed video RAM can contain up to 2048 tiles (but only 26 lines of 42 characters are used). There are 2 bytes for each tile, this is the format: AAAAAAAA BBBBBBBB B7->B0 Tiles number in the bank (256) +76543210+76543210+ A0 Bank selector (0 or 1 only) +--------+--------+ A7->A1 Color selector D.18.5 Color Video RAM The color video RAM can contain up to 2048 color registers. The 1024 first registers are used for text and scroll video display and the last 1024 are used for sprites. There are 2 bytes for each register, this is the format: ????BBBB GGGGRRRR R3->R0 Red value (0-15) +76543210+76543210+ G7->G4 Green value (0-15) +--------+--------+ B3->B0 Blue Value Note: The 4 first bytes (marked ?) have the values 0, 3, 6 or 9. Anyone know what that means? D.18.6 Main RAM This memory contains, RAM, registers and SRAM. If anyone has more information about this part, please E-Mail me, thanks. Some special bytes: F018: if bit5 is set 1, the screen is not updated F01C: Timer ? F01E: Sprites inactive if set to 0xFF FF00-FFFF : SRAM in Altered Beast and normal RAM in Shinobi. D.18.7 Video Registers 410E81: Video page selection register for foreground (Byte) 410E83: Video page selection register for background (Byte) 410E98: Horizontal foreground scroll register (Word) 410E9A: Horizontal background scroll register (Word) 410E91: Vertical background scroll register (Byte) 410E93: Vertical foreground scroll register (Byte) 440000-4403FF: The sprites registers. There are 16 control bytes for each sprite (64 sprites maximum). This is the function of the 16 bytes. 00 : last sprite line on the screen 01 : first sprites line on the screen (sprites height = [00]-[01]) 02 : high value of the sprite X position 03 : low value of the sprite X position (X = [02]*256+[03]) 04 : horizontal sprite flipping flag (flip if value = 01) 05 : sprite width (real width = [05]*2) (!! signed byte) if the bit7 is set to 1, the sprite is flipped vertically 06 : high value of sprite rom position 07 : low value of sprite rom position 08 : sprite bank selector bit7-bit4 are always at 1 if the sprite is active bit3-bit0 is the sprite bank number (0-F) 09 : sprites priority and base color register selector bit7-bit6: 10 - foreground sprite 01 - background sprite 11 - sprite over everything bit5-bit0: base color registers (is 1024+16*value) 0A : zoom function \ 0B : zoom function - unknown format (never used in Shinobi) 0C to 0F are not used in current emulated games The sprite location in bank is ([06]*256+[07]+[05])*2 D.18.8 I/O Registers C41003 - 1 BYTE - 1ST PLAYER CONTROL Bit 0 - Magic Bit 4 - Down Bit 1 - Attack Bit 5 - Up Bit 2 - Jump Bit 6 - Right Bit 3 - Unused Bit 7 - Left C41007 - 1 BYTE - 2ND PLAYER CONTROL same as 1P C41001 - 1 BYTE - GENERAL CONTROLS Bit 0 - Coin 1 Bit 4 - 1P Start Bit 1 - Coni 2 Bit 5 - 2P Start Bit 2 - Test Bit 6 - Unused Bit 3 - Service Bit 7 - Unused C42001 - 1 Byte - Dip Switch settings #1 - Game configuration C42003 - 1 Byte - Dip Switch settings #2 - Coin configuration There are some other registers in this area but I don't know the function. D.18.9 ROM Files Shinobi ------- When you load the A1-A5 and B1-B8 roms, you must load the rom like this: bytes N of ROM loaded at start address+1+N*2 and bytes N of complement ROM loaded at address start address+N*2 Shinobi.A1 68000 code, loaded at 0000-0001 Shinobi.A2 68000 code, loaded at 0001-0001 Shinobi.A4 68000 code, loaded at 0000-0000 (complement of A1) Shinobi.A5 68000 code, loaded at 0001-0000 (complement of A2) Shinobi.A7 Z80 code + music data, loaded at 0000 Shinobi.A8 Z80 ROM, samples Shinobi.A9 Z80 ROM, samples Shinobi.B1 gfx sprites, not memory mapped Shinobi.B2 gfx sprites, not memory mapped Shinobi.B3 gfx sprites, not memory mapped Shinobi.B4 gfx sprites, not memory mapped Shinobi.B5 gfx sprites, not memory mapped (complement of B1) Shinobi.B6 gfx sprites, not memory mapped (complement of B2) Shinobi.B7 gfx sprites, not memory mapped (complement of B3) Shinobi.B8 gfx sprites, not memory mapped (complement of B4) Shinobi.B9 gfx tiles, not memory mapped (bit 0 of each pixels) Shinobi.B10 gfx tiles, not memory mapped (bit 1 of each pixels) Shinobi.B11 gfx tiles, not memory mapped (bit 2 of each pixels) D.18.10 Graphics Formats The sprites: there are 4 bits / pixels (16 colors), colors 0 and 15 are used for transparency. There are 2 pixels coded in each byte, the first pixel coded in bit7 to 4 and the second in bit3 to 0. The tiles: the size is 8x8 pixels and there are 3 bits / pixels (8 colors), color 0 is used for transparency. I found the same format in the following roms: Shinobi, Altered Beast, Golden Axe, Quartet I and II, Time Scanner, Shadow Dancer, Moonwalker, Choplifter, Alien Syndrome, Out Run, Turbo Out Run, After Burner II, E-Swat, Hang-On. It seems to be a standard for Sega games. D.18.11 Sega GFX Viewer V1.0 Source Code (ZIPed an UUencoded) I've ZIPed and UUencoded a C source file that Thierry Lescot sent me. The information is much more compact in this form -- including the full source would have taken up too much space! From the comments: Sega Arcade Gfx Viewer v1.0 - Character Version Thierry Lescot, ShinobiZ@ping.be Usage : showchar.exe file1 file2 file3 game name file1 file2 file3 Shinobi shinobi.b9 shinobi.b10 shinobi.b11 Altered Beast ab11674.bin ab11675.bin ab11676.bin Golden Axe ga12385.bin ga12386.bin ga12387.bin Shadow Dancer sd12712.bin sd12713.bin sd12714.bin Time Scanner ts10543.bin ts10544.bin ts10545.bin Hang On 6841.rom 6842.rom 6843.rom After Burner II 11113.rom 11114.rom 11115.rom Alien Syndrome c09.as c10.as c11.as Choplifter 7127.rom 7128.rom 7129.rom E-Swat e12624r e12625r e12626r Moonwalker m13216r m13217r m13218.r Out Run 10230.rom 10231.rom 10232.rom Out Run 10266.rom 10267.rom 10268.rom Quartet quartet.c9 quartet.c10 quartet.c11 Quartet II q7698.bin q7699.bin q7700.bin Turbo Out Run 12323.rom 12324.rom 12325.rom WonderBoy II ml8 ml9 ml10 Just cut and paste this UUencoded block to a new file and decode it. If this is a problem, let me know and the source files can be distributed with the HowTo as separate files... begin 644 showchar.zip M4$L#!!0````(`">+)"*.+'^(808``%P0```*````4TA/5T-(05(N0[57;5/C M-A?]7&;V/P@Z2^TD!-MQ0F@P4UX"RRQ;MB2[V^?9,AG9EA,-CN3*#G':\M][ MY7<[T)$D0DTWU2JWKV&C@7I92J@75 MKS#M[=K'#:QK#:Q+DC,?LB8N.B2"Q)KKGO$H;. MXEHNPULYB13"O6< M.)BQ"@>*0EWKFZ53BLT&[NA:`^N`I?_%@@<^ M3714+BCE454TX&$#'^<*Q@>3-8ZJWO(BNC$P3%''_08>"$GP@7.VQOYC7<)2 M[QGZ0-3Q40.#*,EPMXK0_:HY$[IF]+1JW0!7IT9B(\_B58K!H.XRJ!9&XF%. M\=,*BX@T*_%KVMMUCALX>]!*K%=)BM60&AT-CH?%.DSQ<0T?:5JQN%?"YEL) MZ9!L;54!KJTJP,6J^L*92\0YW]1T+/UA+;6E?]S`NI;L.:U#>?N6,L=?N02= M8-\G<\&[B].DWR4>9039FXB@%0OIG!$7R8U0COJ\R`^19`78>9QX'`\5C'70U MNQ^?7:JC9)1Z2/$LZ\=/M[>Y`UR!H"SRE+VQ$%QTT`UR,/LN0I("O0W1[B]L MKX,@1,KQ_&;GN=!Q3[![B2,<*D"!W)PTR298=X#:TE*W1*B=_DX3LE>>1X2E MI$A=0KFXHZ0UR&*EN0@(HJ36G:Q&H"T[ MOYE^./N(6D^A`U*9!2V.R,RFT1('2L\`-8:I57+TN\*2[3QI;6O02XE"$LT< M[G.A&/U^!^W#:#%ATD[;-C-K9DDCU?$5F!`6":*DHF!B.8LZ:.]B)4*8N-OQ MU?3P_N;ZW12J(;-B2AL0T*OQ[-?^D<7GY M<&!+'_2&9DO&'.6=CD^P4+(ZJD5WF#U)2=TAG/1!;]W#MRY$DZ"M5R>\K9>N M#=U/=>$982(XD=LO/=/EO9'K>[,+8N$F%S\D\$TV%LNQ.!V+B['<57INY).Q MJ0[EH](WEJ.%(PS/@E44T)CXIGHZW':6>Z:2F5KOQ_^;R26I[N\K<@IW+4U5DZD].!B]ZI&L MW]*E7`&9;[M=C_J,U@OJ$Y21["8DX\E%L:W(S6")*4MV72SF3B=]X%LM`$_Y M/I,TV2$THPSJEQ\#+`0%_BRB2R*:G;),'`M7J3X1^1%1^U#`2Q(FGPN7JV50 M?BZ<^]QYS#\5?F%[51Y9&JGWQ'S]_(&)CW",OD>3=W=?IO(4W/I(*%GA$B1: M":;HY?E4C;:;[:J6=)R%]#@;EC,[3Q L x x x x x x x byte 2,3 X start (DAC initial) x axis up/down counters byte 4,5 Y start (DAC initial) y axis up/down counters byte 6,7 adr of line instructions vector address counter byte 8,9 appearance, angle symbol angle latch byte 10 size serial multiplier Line Instructions ( 4 bytes / line ) byte 1 L R R G G B B D byte 2 length vector length counters byte 3 line angle vector angle byte 4 screen quadrant vector angle D.20 Side Arms [provided by Alan Pope (Alan_Pope@deloitte.touche.co.uk)] BOARD 1 ROMS 6-23 (27256) CAPCOM 86S105 (?) Majority 74xxx logic 2 off CAPCOM 86S100 (?) Sony XCK5814P-45L (?) BOARD 2 ROMS 1-5 (27256) 2 off YM2203C (Audio) NEC D780-1 (CPU) CAPCOM 86S100 4 Socketed 16-way ICs SAB - 1 through 4 labelled MMI 63S141AN SAB - 1 through 3 are 8610, SAB - 4 is 8640 Also Rohm BUI8400H-PS Z80H CPU D.21 Space Invaders [provided by Nemoto Yohei (BYY03025@niftyserve.or.jp)] [additional info (*) provided by Ignacio Escalza (marconi@arrakis.es)] note - The Sound port is uncomplete! 1996.7.20 Ryusendo/Root D.21.1 Board Spec CPU 8080, i8080 is lower-compatible chip of Z80-CPU RAM 8kbytes, i8kSRAM @8 piece ROM 8kbytes, i16kEPROM @4 piece SOUND Sound Effect with analog circuit Input Device 2way stick + 1 button *2 coin switch, 1Player start, 2Player start TILT switch D.21.2 Memory Map 0000h +--------------------------+ | Program ROM | | | | | | | | | | | | | 1FFFh | | +--------------------------+ 2000h | Work RAM | 23ffh | | +--------------------------+ 2400h | | | Video RAM | | | | | | | 3FFFh +--------------------------+ | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FFFFh | Not Used | +--------------------------+ I/O map ------- *** Port 1 [IN]Controller bit 0=CREDIT (0 if deposit) bit 1=2P start(1 if pressed) bit 2=1P start(1 if pressed) bit 3=??? (not TILT) (*) bit 4=shot(1 if pressed) bit 5=left(1 if pressed) bit 6=right(1 if pressed) bit 7=Always 1 *** Port 2 [IN]Controller bit 0=Always 0 bit 1=Always 0 bit 2=1 if TILT (*) bit 3=Preset Mode button (in combination with 1P Start or 2P Start) (*) bit 4=shot(1 if pressed) \ (*) bit 5=left(1 if pressed) >Player 2 (*) bit 6=right(1 if pressed) / (*) bit 7=Always 0 [OUT]Shift Value *** Port 3 (*) [IN]Shifted Bitmap Port3= word formed by Port4(MSB) and the previous state of port 4(LSB) shifted left by the number of "Shift Value" (Port 2). Port 3 gets the MSB of the result. ex. LD a,3 OUT (2),a LD a,10110011b out (4),a in a,(3) ; reg a is 10011000b (If previous value of port 4 was 0) LD a,110010001b out (4),a in a,(3) ; reg a is 10001101b [OUT]Sound bit 0=UFO bit 1=Shot bit 2=Base Hit (*) bit 3=Invader Hit (*) bit 4=??? bit 5=Activated almost anytime while playing. (*) bit 6=??? bit 7=??? *** Port 4 [OUT]Bitmap *** Port 5 [OUT]Sound, port 2 (*) bit 0=Invader Walk 1 (*) bit 1=Invader Walk 2 (*) bit 2=Invader Walk 3 (*) bit 3=Invader Walk 4 (*) bit 4=UFO hit (*) bit 5=??? (*) bit 6=??? (*) bit 7=??? (*) *** Port 6 [OUT]??? D.21.3 Sound Information [provided by John Manfreda (jmanfred@fh.us.bosch.com)] Discrete circuits are used to generate all of the sound on space invaders. Each sound generated has its own unique analog circuit. D.22 Star Wars [provided by Peter McDermott] I'm just basing this on my schematics. The StarWars sound board which is the sole item in the machine responsible for sound output, has the following parts: 1) a single "TMS-5220 Speech Synthesizer" 2) a "Speech Synthesizer Clock Generator" 3) a "Speech Synthesizer Power Switch" (which is just a circut) Yes, the sound sounds a lot like the movie. Maybe the 5220 is a DAC, not a speech synthesizer... However, they did label the DACs in the analog vector generator "DAC" and not "vector synthesizer." D.23 Tapper [provided by Clay Cowgill (clay@supra.com)] Tapper is based on the Bally/Midway MCR III architecture. Basically you have three PCB's -- the Super CPU, Video Generator II, and the Super Sound I/O. The Super Sound I/O contains about 48 lines of digital I/O (tapper only uses a few), two 8910 sound chips (the 8-bit dataports on the chips are used to drive a vibrato/tremelo/filter setup), all run from a Z-80 (at 2MHz) with 2K of RAM and about 10K Max ROM. The Super CPU is a 6MHz Z-80 board with some RAM and about 48K of address space for game code. The Super CPU also generates a low(er) resolution "background" image from two 8K ROMs. The Super CPU talks to the SSIO through a communication port with a little bit of TTL RAM. The Super CPU also control the Video Generator II. Video Generator II is essentially a Sprite engine. Bitplanes of sprite data are stored in sets of 4-ROM wide banks, one bit per pixel. There's line buffer and position/character selection RAM on the board. It's non-trivial hardware to emulate (the Sound system could be particularly vexing), but if you get it going you should be able to run Spy Hunter, Demolition Derby, and Discs of TRON on the same emulator with just changing the ROM images. D.24 Toki [provided by David Winter (winter@worldnet.net)] The sound chip is an YM-3812, as seen on the board. D.25 Turbo [provided by Patrick J. O'Reilly (oreillyp@execpc.com)] The following is a description of the Turbo coin-op video game: Produced by SEGA in 1981. Utilizes a Z80A microprocessor operating at 5 MHz. Uses an on/off switch for the gearshift. Uses two on/off switches for the accelerator for four positions. Uses two photosensors for the steering wheel. Shift is digital, accelerator is digital, and wheel is analog. Each analog output of the photosensors is quantized by an A to D converter into an 8-bit value. Utilizes 11 2716 EPROMs (2Kx8) and 16 2764 EPROMs (8Kx8.) Test Mode verifies ROM, RAM, accelerator, steering wheel, coin switches, DIP switches, LEDs, and sounds. GAME CONCEPT Turbo, the newest game from SEGA/Gremlin, is a one-player experience, available in cockpit and upright models. It combines the highly successful driving format of yesterday's Monaco G.P. with today's advances in memory and programming, resulting in our "true perspective" display. The aerodynamic Turbo cockpit is fully equipped with an LED instrument panel that maps acceleration, indicates the top five scores to beat, score of the last game played, and measures record breaking speeds. Standard features include a pro rally steering wheel, responsive 2-speed gear stick shift, illuminated oil and temperature gauges, and a full power accelerator, all in the realistic cockpit of a Turbo charged race car. Turbo is also available in the compact upright, with score indicator, gauges, steering wheel, stick shift and accelerator for maximum space efficiency. Both models offer behind the wheel excitement in a grueling cross country race. Road handling skills are put to the test as the Turbo course winds through busy city streets, narrow suspension bridges, blind tunnels, and rambling country roads. Unexpected changes in road conditions, such as snow, wreckless competitors, and emergency routed ambulances, further challenge a player's driving abilities. No pit stops are permitted in this fast-paced race to the finish. Points are accumulated as Turbo successfully routes through each phase of the course, passing other cars. Drivers can monitor their progress at a glance with readouts for time remaining on the clock and number of cars passed at the top of the screen. A collision during the first lap sends drivers back to the starting line. In succeeding laps, however, a collision explodes the Turbo car on impact. Drivers run a high risk of collision when approaching a hill at top speed. The crest of the hill blocks the driver's view of fast oncoming vehicles. Drivers are advised to check their speed and exercise caution while climbing steep hills. An extended play victory lap is awarded when drivers pass 30 cars with time to spare. A spare player car is awarded for each extended play, up to 4 cars. Passing (lapping) cars during this phase tacks on bonus points. The game ends as lap time expires for last car, or the last car is lost in a collision. Special thanks to: SEGA: a great coin-op video game and indirect support. Alan McCormick: inexpensive Turbo boardset and support hardware. Martin Scragg: Turbo EPROM images. Micheal Schultz: Turbo operator's manual and schematics. Moose O'Malley: providing me fame and fortune on his WEB page. Neil Bradley: a great contribution to the Z80 emulator. All others who have contributed that I have forgotten or wish to remain anonymous. D.26 Tutankham [provided by Moose O' Malley (moose@rocknet.net.au)] Tutankham (1982 Konami, licensee Stern) Raid King Tut's tomb. Sideways-shooting only. CPU : 6809 Sound : Z80 and 2 x AY-3-8910's PinOut : Konami pinout (ala Amidar/Frogger) Hardware : Looks a lot like Amidar, Time Pilot and Scramble. Konami board number : GX350 - Tutankham BTW, Tutankham was my favourite arcade game !! ---------------------------------------------------------------------------- .d88b 8 w 8 8 8 w 8P www 8d8b .d88 88b. 8d8b. w .d8b d88b 8www8 .d88 .d8b 8.dP w 8d8b. .d88 8b d8 8P 8 8 8 8 8P Y8 8 8 `Yb. 8 8 8 8 8 88b 8 8P Y8 8 8 `Y88P' 8 `Y88 88P' 8 8 8 `Y8P Y88P 8 8 `Y88 `Y8P 8 Yb 8 8 8 `Y88 8 wwdP ---------------------------------------------------------------------------- G.1 Who wrote this section? Brad Thomas (bradt@nol.net) spent some time hacking on the graphics in various ROMs, and these are the results he sent me. Expect more information on this in the future... (All references to 'I' are referring to Brad.) [Note: This refers only to sections G.1 to G.5] G.2 Introduction I decided to take up the task of seeing how the graphic shapes were stored in rom images to better help my understanding of the internals of arcade games. Below you will find the discussion of how graphics are stored in various games. At this time I will be detailing two different methods I have discovered. G.3 Location of Graphics in Specific Game ROMs This section will detail the following games: (Tant archives used for file listing) Centipede 136001.201 136001.202 Millipede 136013.106 136013.107 Donkey Kong dk.3n dk.3p <--Background blocks dk.7c dk.7e <--Top Half of sprites dk.7d dk.7f <--Bottom half of sprites Vanguard sk4_ic13.bin <--Special case rom Contains both parts merged into one file Scramble 5f 5h Frogger frogger.606 frogger 607 Bagman a2_1e.bin a2_1j.bin <--1st set a2_1c.bin a2_1f.bin <--2nd set Amidar Japanese amidar.5f amidar.5h Pool (Billards Game) pool.d pool.e Lost Tomb lostt.5f lostt.5h The End ic30 ic31 Zaxxon zaxxon.14 zaxxon.15 Others that probably apply: (I can almost see them but not all there yet...) Xevious Dig Dug G.4 General Information It took me a while to see what was happening with the graphics. First I thought the two files should be merged together as one but after some experimenting I found that the two files work in conjunction with one another. G.4.1 Pixel Layout The best way to describe this is to give an example. I will be using the Donkey Kong file dk.3n which has the first 8 bytes of: 38 00111000 7c 01111100 c2 11000010 82 10000010 86 10000110 7c 01111100 38 00111000 00 00000000 As you can see this makes the shape of a 0 (zero). Now here's the rub... You have two files that look very similar and are wondering what to make of them. Did they just include two copies of the same graphics. No they didn't. What they did was devise a way to get another color on the screen. Let's look at an example from the two files: 26 00100110 24 00100100 6f 01101111 6d 01101101 71 01110001 cf 11001111 78 01111000 ee 11101110 78 01111000 8e 10001110 71 01110001 df 11011111 35 00110101 51 01010001 00 00000000 00 00000000 To plot the pixels you have to use same number position from each file. [Chris Hardy suggested a new representation...] Pseudo color defs: 0 & 0 :" " 0 & 1 : + 1 & 0 : * 1 & 1 : X Take 26 and 24 from the first line: 26 00100110 24 00100100 -------- " X X* " The final example looks like: " X X* " " XX XX*X" "+X**+++X" "+XX*X++ " "+***X++ " "+X*X+++X" " +*X * X" " " The result is what would be plotted given whatever color scheme. The bytes run to the right in the file of course, but the line plotting runs from the right to the left essentially. The above would be the rightmost slice of the 8 slices and the 00 and 00 combo would be the leftmost slice. If you plot this on a mode 13 screen the graphic would be sideways, As would be on a long vertical monitor (which I am speculating). What I have described will only show a 8 x 8 pixels block on the screen. Some games use more than one to make the full character. Donkey Kong sprites are 16 x 16 so you would use 16 bytes to get the first half of the sprite on the screen (from the first file set) and 16 from the second file set. Millipede uses more than one block to make up bigger sprites/characters. In some games, the numbers are shown backwards or mirrored. This is just how they were stored. The one item that I cannot comment on this time is the color schemes used for the various games. In my trials I just picked 4 colors that were different enough to show the differences. G.5 Notes and Requests I pretty sure this is correctly transcribed from my notes. If anyone finds any errors I have made please let me know. I have written a small utility to view these but it is not user friendly at all so at this point I'm not going to release it. If by some chance someone else decides to make one, please let me know. Also, if anyone has anything to add to this document please email me. (bradt@nol.net) I am also looking for the following: Memory layout for Scramble, Amidar, Bagman and any other Stern game. Schematics and memory layout for Vanguard. Everything relating to Krull (Schems, memory layout, ROMS!!!!) I will be working on another part of this section that covers graphics storage for other games. G.6 Mode Q (256x256x256) Source Code Gary Shepherdson (od67@dial.pipex.com) sent the following code to me. Emulator authors have recently been asking for code that would let them use a video mode suitable for their target game(s). It seems Mode Q, 256x256x256, is the answer for many... NOTE: Jean-Marc Leang reports Mode Q doesn't work on Matrox Millenium cards. Just cut and paste this UUencoded block to a new file and decode it. If this is a problem, let me know and the source files can be distributed with the HowTo as separate files... begin 644 modeq.zip M4$L#!!0 ( .?@B%IXM\LF0@ #,N ' ;6]D97$N8^T::V_C-O*S M N0_3'MH(26.(]M)-IMD%TCS6!2WKSAN[T-OL: ERB8J2P8E.W;W]K]WAJ1> MD;-)&GF! R(DLL0AA_/F#*G=K9T&KZW=S8W=+6CPTABM=Q_.+^ *[.[^P<+\ M.Y#R)(6IC$>231Z+L7D:FY;CYL:_1.2%,Y_#29+Z(FZ/7Y?;_#BYU>+%D>FE M1OL\$!&'T\&@?_;A_>?3\_.^9;F+GN<6P'>_7I\9B )U"]#O;TXOWI_^\O9" MPPG:*Z#7%U?E<7L%Y$W_M#H=+V!G_4%Y.K\T['IP.OCMNACF,\U&NIQR[ *S M*!&CB/O@C9F$X3+EQRN R3B6*=S$TC\N#TY2.?/2S8TOFQL6 :TI=L,>%N&Q M1.3S1?XV9^&,<'\E"9RSE!UK0KZA86-2V!\2GJ8B&B40Q!(F,:KEZC[[T,HV MD\$[''/UQR=XA?1\L;Z TDH+?UR7[KSWM840#?#W"L!^4 =TZ-Y; 5 (]]PZ MH$?WPVX=H.Y[IW7 /MU?K@ ';+J[&MNZ@#%>6<%58IS5A:)5U*4VZD#])V7 M ;P0>X4J SC0X#+ +62UUZD#>D;LV/[U^!Y+_X>Q#)T#(S9X<1C/)$Q9B%[" MGQAO&PS@&<;W'P871S 8<^B_^054($A@,L-59LA!1) B1+)HQ,%U80=ZEV#3 M[T'/N0-CTW+ZWK;TRZ%^(>WG3WE;-V_KYFV] MO*U7M%V64;J$E)I=M^/F3WE;-V_KYFV]O*U7M%V642)2W4Q(\Z>\K9NW=?.V M7M[6*]HN#I<:OGZBYD,SCGRJ";>;I&>4SRF>4SRB?43ZC?$;YC/+_ R46 MQ:885D5X@/];OPN?QWTV.2YR7\RDI[&(4BXAC555/.&36"Y!I[!K*S&N>4K5 M"S^3I4U;(C G M:AQ58LPB$4?0OWAS#5+9@B7;BS9;P"O=B[914/6'![8J.7^6^.?0;LKZ]&ZA MA8E(I UJJ<'+T/@K$BA8*!*L*,DC)&?^4FG>\_@T!18ML9J;#$7$4I)P'.!K M%(C13.J&&D;)1R(A'\NVG.XQEWMI?#JOMS%:@[%(L'">Q^$<^>81&X9(*=Q( MD>([]:TO8B\70J)OCC&10W%GTRY MA]$//(;Q[\CD 99%KY7SB2-JM3(/*!T).)A>((002XX!#^3N#02AF.X$83Q5 M"!&:.T(99PMD6_O]_]0.KW*9RH5(>92@)I69$))9"L+$*]3X?=C51J%!.\3 M_N=QB;W\A.4H;ZJ>K!Q5D6M)EM J BU?2.ZEX3(S614&U.;/#F6+*TJ%, MT9B?QJ@FGP=L%J9'%;GH *XS%M,!D[ET'/M'-;$4E"MQ9Y1KV2/9!,4F8ZSU MD=N="MXPMSPS])O,4.O2BQ1WG;-_&V+1FBMBD MM),'IRU)5*<0Z2"598>V$939<%:).&E6VVU%DP2"32/(Z*QR$^ M&C,H)TEG!_H4L)8]G1T:BW?JB=K9RY::I3X( :.[ $,#^!Z6Q<*P(3MH\"I; MUFP*1*-:ORJVE4 @XXF)3_I0Z^ZLZKL8&=%93=XM@6I47PA@@!FA9K6)4,BS M!>;M[C$(.*%S3GS <)+E0A)AJHQV;-NLN@_:LN;"^2YKZ,91MG*TSG'LFN M(3&DKW?*&)?Q#%>0R123557HFQ(K$R.Q&@/6+,ET+\8_-9_7_HPJOW?Z$<5?D8!?G-@-WLWZ;/S ()+8L85O>3=V:)^ M+XF&MM)B^QCM9_.?80F(L['R:8-1>7'>\&",)4]'WW[W[\^7'U&##)?0EOM8 MT\PH/)?L!L:Q%']AO<1"%2L3X'..Q'5MM##\,KCH4T>W"(,NXB!PIW>9[2^9JG" M0ZFMR &Y3H77B!3*,EC!3"Z#Q=TR6"&Z53)8/%D&]TOG/TRD*BR:"$F%.6;( M%#2QIAYR!'&][95F&]VER/;4H%61:"42%W',-7%,,?XW4$L! A0#% @ M Y^"(6GBWRR9" ,RX < 0 *2! &UO9&5Q+F-02P4& 2 $ 0 U O@@ end ----------------------------- 888b. 8 8 .8 .d8b. 8.dP .d88b Yb dP 8wwP' 8' .8 88b 8.dP' YbdP 8 `Y8P' 8 Yb `Y88P dP dP ----------------------------- P.1 Who wrote this description? Bryan Edewaard wrote this up and passed it along to Moose O' Malley, who passed it along to me... ;) P.2 You mean Pokey isn't just that guy that hangs around with Gumby? Nope. P.3 Where did they come up with a name like Pokey? POKEY (stands for: POts & KEYs) - Atari #CO12294 P.4 General Description Pokey is a custom IC developed by Atari for use in the Atari 400/800 Home Computers, but they eventually found their way into many classic Atari coin-ops, and are more flexible than the more common GI AY-3-8910 family of sound generators. Pokey sound effects have a unique sound that is easy to recognize once you know what to listen for. P.5 Technical Description The Pokey chip consists of 4 general purpose frequency dividers (cascadable), serial I/O ports, varying length feedback-shift registers (polynomial counters) to create unique sound effects, a keyboard decoding matrix, an IRQ line that can trigger on 8 separate events, 8 potentiometer inputs, and a random number generator that is used for noise effects and also to provide a RANDOM register for program use. P.5.1 Pin-outs 1. GND 40. D2 2. D3 39. D1 3. D4 38. D0 4. D5 37. Audio Out 5. D6 36. A0 6. D7 35. A1 7. Master Clock 34. A2 8. Pot 6 33. A3 9. Pot 7 32. R/!W 10. Pot 4 31. CS1 11. Pot 5 30. !CS0 12. Pot 2 29. !Interrupt 13. Pot 3 28. Ser. Out 14. Pot 0 27. Clk. Out 15. Pot 1 26. Clk. In 16. !Key Read1 25. !Key Read2 17. Vcc 24. Ser. In 18. !Key 5 23. !Key 0 19. !Key 4 22. !Key 1 20. !Key 3 21. !Key 2 CS1 & !CS0 are 2 chip select lines that are used in address decoding to put Pokey on the bus. One can be tied to Vcc(CS1) or GND(!CS0) if you do not need both. The Master Clock in the Atari Home Computer is 1.79MHz, the CPU clock. P.5.2 Address Lines The address lines of Pokey select the following registers: 00 AUDF1 - W 1st frequency divider POT0 - R Position of pot input 0 01 AUDC1 - W Each channel has a control register as follows: Bit 7,6,5 = Distortion 0-7 0 0 0 = 5 bit poly -> 17 bit poly 0 0 1 = 5 bit poly 0 1 0 = 5 bit poly -> 4 bit poly 0 1 1 = 5 bit poly 1 0 0 = 17 bit poly 1 0 1 = polys off - pure tone 1 1 0 = 4 bit poly 1 1 1 = polys off - pure tone Bit 4 = if 1, hold channel at vol level for D/A use Bit 3,2,1,0 = Volume POT1 - R Position of pot input 1 02 AUDF2 - W 2nd frequency divider POT2 - R Position of pot input 2 03 AUDC2 - W Control register 2 POT3 - R Position of pot input 3 04 AUDF3 - W 3rd frequency divider (used with AUDF4 for serial IO) POT4 - R Position of pot input 4 05 AUDC3 - W Control register 3 POT5 - R Position of pot input 5 06 AUDF4 - W 4th frequency divider POT6 - R Position of pot input 6 07 AUDC4 - W Control register 4 POT7 - R Position of pot input 7 08 AUDCTL W Master configuration for the sound channels Bit 7 = 17 or 9 bit poly counter (change noise sound) Bit 6 = Clock channel 1 with undivided clock Bit 5 = Clock channel 3 with undivided clock Bit 4 = Cascade dividers 2 and 1 (16 bit mode) Bit 3 = Cascade dividers 4 and 3 (16 bit mode) Bit 2 = Enable high-pass filter on channel 1, select frequency with channel 2 Bit 1 = Enable high-pass filter on channel 3, select frequency with channel 4 Bit 0 = Divided clock = clock/120 or clock/28 ALLPOT R Shows state of all 8 pot inputs (counting or done) 09 STIMER W Any non-zero value will start the dividers if they have been stopped KBCODE R Last key pressed Bit 7,6 = Modifier keys (Control & Shift on Atari Comp) 0A SKREST W Strobe this address to reset SKCTL bits 5-7 RANDOM R Returns the top 8 bits of the poly counter 0B POTGO - W Strobe this address to start testing the pots 0C unused 0D SEROUT W Put bytes to be sent serially here SERIN - R Read bytes received serially here 0E IRQEN - W Turn Pokey interrupts on and off Bit 7 = Special key ('BREAK' key on Atari Comp) Bit 6 = Any other key Bit 5 = Serial byte ready to read Bit 4 = Serial byte needed to send Bit 3 = Serial output done Bit 2 = Divider 4 reached 0 Bit 1 = Divider 2 reached 0 Bit 0 = Divider 1 reached 0 IRQST - R Determine what caused an interrupt - bits as above OF SKCTL - W Serial port control Bit 7 = Force break (zero state) in serial output Bit 6,5,4 = Serial mode 0 0 0 = Use external clock 0 0 1 = Use ex. clock for send, ch. 4 for read (A) 0 1 0 = Use channel 4 as clock 0 1 1 = undefined 1 0 0 = Use ch. 4 for send, ex. clock for read 1 0 1 = undefined 1 1 0 = Use ch. 2 for send, ch. 4 for read 1 1 1 = Use ch. 2 for send, ch. 4 for read (A) (A) = async. mode using ch. 4 as bit shift clock Bit 3 = Two tone mode (analog casette)/ Logic mode Bit 2 = Fast pot scan - less accurate pot reading Bit 1 = Enable keyboard scanning Bit 0 = Enable keyboard debounce SKSTAT R Serial Port Status Bit 7 = Serial frame error (SKREST clears bits 7,6,5) Bit 6 = Serial data in overrun Bit 5 = Keyboard overrun Bit 4 = Current bit at serial input port Bit 3 = Realtime version of KBCODE bit 6 (shift) Bit 2 = Key at KBCODE is still pressed Bit 1 = Serial byte not ready to read Bit 0 = Always 1 P.6 Where can I find source code and more info. for Pokey emulation? Try doing a search for 'pokey' on the web. You might find something useful. Also, check out the following site: http://www.htw.uni-sb.de/people/mgietzen/atari/xl_intern.html This page has some interesting information about emulating the old Atari home computers, but it might be useful to anyone doing arcade emulators as well! (6502 CPU emulation, graphics, collisions, sound, etc.) P.7 Finding and using *real* Pokeys Check section R.3.1.5 (Miscellaneous Information) for a link to a site that has schematics for a Pokey card to plug into the parallel port of a PC! Here are some vendors that still sell Pokeys: B&C ComputerVisions 1725 De La Cruz Blvd Ste 7 Santa Clara CA 95050-3011 USA tel: (408) 986-9960 Phone Orders: Tue - Fri 10am-6pm FAX: (408) 986-9968 Store Hours: Thur & Fri 10am-6pm / Saturday 10am-5pm Vendor: new/used hardware, commercial/PD/freeware/shareware. MAJOR ATARI PARTS SOURCE Best Electronics 2021 The Alameda Ste 290 San Jose CA 95126-1127 USA tel: (408) 243-6950 1-5pm Pacific Time Mon-Fri FAX: (408) 243-8274 Vendor: new hardware, commercial software Developer: "XE" Touch, Best Joystick, Best Light Gun. MAJOR ATARI PARTS SOURCE Here is a link to other Atari vendors and developers: http://www.cis.ohio-state.edu/hypertext/faq/usenet/atari-8-bit/vendev/faq.html ----------------------------------------------------- db Yb dP d88b .dPYb. .d88b d8 .d88b. dPYb YbdP wwP YbwwdP 8 8 8 8P Y8 dPwwYb YP wwww 8 wwww dP""Yb `8w88 8 8b d8 dP Yb 88 Y88P `YbdP' 8 8 `Y88P' ----------------------------------------------------- A.1 Who wrote this description? Chris Hardy sent this to me: "What follows is a description of the AY-3-8910 sound chip which was popular for many arcade games. (Bagman, Crazy Kong, Crazy Kong Jr., Gyruss, Juno First, Scramble, and others use this chip.) This came from a technical document about the Spectra Vision MSX machine which uses a AY-3-8910 for sound. (http://www.cs.umd.edu/users/fms/MSX/Portar.txt). I found it by doing a WWW search for "ay-3-8910". Also there is some source code for Marat's MSX emulator to emulate the AY-3-8910 (http://freeflight.com/fms/fMSX)" A.2 Introduction and disclaimer from original document MAYER's SV738 X'press I/O MAP version 1.5 Creation date: 1991. Last edition: Sunday 14-May-95 11:57:57. This I/O documentation was written 1991 by MAYER of WC HAKKERS. It consists of gathered info about the MSX computer SV738 X'Press (here upgraded to MSX 2 by changing ROM and VRAM - see documentation about MSX-2 upgrading). Thanks to Henrik Gilvad (Denmark) for info about the MSX-2 MVDP and the MSX-2 ROMs, to Pel F Hansen (Norway) for VRAM info and to Jonas Lindstrvm (Sweden) for some MVDP info. This documentation is not completed, but it includes the most important things when dealing with I/O ports on a MSX. I do not take any responsibility for changes done by anybody else later in the text. If you change anything I advise you to leave a note on the last page about the change. This text may not be sold, included in commercial software/hardware or firmware packages and it may not be duplicated by any means without the authors permission. This text is shareware; You might copy it an spread it as long as you don't sell the copies. So if you spread this documentation, leaving this page intact and without changes, you have my permission to duplicate it. A.3 Technical Information Note 6a1,6b1,6c1: PORT.A0,A1,A2 I AY-3-8910 PSG (Programmable Sound Generator) ---------- Port summary: A0 W 6a1 I AY-3-8910 PSG Register select A1 W 6b1 I AY-3-8910 PSG Data write A2 R 6c1 I AY-3-8910 PSG Data read The AY-3-8910 is a I/O chip whith 3 sound generators. It controls the three MSX std. audio channels, joystick and cassette. Function/register table: Frequency, audio channel A-C: 0...5 Noise freq.: 6 Mixer: 7 Volume: 8 ...10 Envelope: 11...13 Joystick and cassette: 14 Paddle,joystick sel,touchpad: 15 For register summary, see note 6a1 (port A0). For SOUND A,B (register write) example, see note 6b1 (port A1). For register read example, see note 6c1 (port A2). For joystick read example, see note 6c1 (port A2). Note 6a1: PORT.A0 I AY-3-8910 PSG Register select ------- Port A0h WRITE = PSG register select. This port selects the current PSG register (0-15). Registers are: 0 = Fine freq. channel A (0-255) 1 = Freq. channel A (0-15) 2 = Fine freq. channel B (0-255) 3 = Freq. channel B (0-15) 4 = Fine freq. channel C (0-255) 5 = Freq. channel C (0-15) Output frequency (tone): f = 3.579M/2 T ------------------- 16*(256*fine+coarse) Where "coarse" are one of the coarse frequency setting registers, 1, 3, or 5 and "fine" are one of the fine frequency setting registers, 1, 2 or 4. 6 = Noise period (0-31) Output frequency (noise): f = 3.579M/2 N -------------- 16*NoisePeriod Where "NoisePeriod" are register 6. 7 = Mixer bit Expl. 0 = Channel A tone enable (0=Enable,1=Disable) 1 = Channel B tone enable (0=Enable,1=Disable) 2 = Channel C tone enable (0=Enable,1=Disable) 3 = Channel A noise enable (0=Enable,1=Disable) 4 = Channel B noise enable (0=Enable,1=Disable) 5 = Channel C noise enable (0=Enable,1=Disable) 6 = I/O port A mode (0=input, 1=Output) 7 = I/O port B mode (0=input, 1=Output) 8 = Volume channel A (0-15, 16=Envelope) 9 = Volume channel B (0-15, 16=Envelope) 10= Volume channel C (0-15, 16=Envelope) 11= Envelope fine freq. (0-255) 12= Envelope freq. (0-255) Envelope frequency (tone or noise): f = 3.579M/2 E ---------------------- 256*(256*ECoarse+EFine) Where "ECoarse" are the coarse envelope frequency setting register 12 and "EFine" are the fine envelope frequency setting register 11. Note that the envelope period is 1 ----- f E 13= Envelope shape (0-15) C A A H O T L L N T T D T 0 0 X X \________ 0 0 1 X X /________ 4 1 0 0 0 \\\\\\\\\ 8 (Repeating, see figure) 1 0 0 1 \________ 9 1 0 1 0 \/\/\/\/\ 10 (Repeating, see figure) 1 0 1 1 \ 11 (See figure) 1 1 0 0 ///////// 12 (Repeating) 1 1 0 1 / 13 1 1 1 0 /\/\/\/\/\ 14 (Repeating) 1 1 1 1 / 15 14= I/O port A (Joystick and cassette) bit Expl. 0 = Joystick UP (0=Moved, 1=Not moved) 1 = Joystick DOWN (0=Moved, 1=Not moved) 2 = Joystick LEFT (0=Moved, 1=Not moved) 3 = Joystick RIGHT (0=Moved, 1=Not moved) 4 = Joystick trigger A 5 = Joystick trigger B 6 = Keyboard mode (On japanese machines only) 7 = Cassette input 15= I/O port B (Joystick select) bit Expl. 0 = 1 (Used as handshaking output if touchpad) 1 = 1 (Used as handshaking output if touchpad) 2 = 1 (Used as handshaking output if touchpad) 3 = 1 (Used as handshaking output if touchpad) 4 = Pulse 1 (Positive pulse starting a monostable timer) 5 = Pulse 2 (Positive pulse starting a monostable timer) 6 = Joystick select (0=Connector 1, 1=Connector 2) 7 = Kana LED (Keyboard mode indicator. On japanese machines only) Bits 4 and 5 is used by a program wich uses a paddle. A short positive edge pulse on bit 4 (or 5) starts a monostable timer (in the attatched paddle) and the paddle sets one of the joystick bits in register 14 low (FIRE A (FIRE B),L,R,D or U). When the monostable times out, the joystick bit in port 14 is set high again. The length of the counting period of the monostable timer is set (in the attatched paddle) by a variable resistor. The computer determine the position of the variable resistor by measuring the time while the joystick bit in register 14 is low. PULSE _________|-|______________________ FIRE A/B or ---------|______________|--------- L R D U | - - - - - - -| = Variable resistor Note 6b1: PORT.A1 I AY-3-8910 PSG Data write ------- Port A1h WRITE = PSG data write. Used to send data to current PSG register. Examples: This routine will do the same as the BASIC command SOUND A,B where A is the PSG register and B is the byte to write sound: out (0A0h),a ; Select register ld a,b out (0A1h),a ; Send data ret Note 6c1: PORT.A2 I AY-3-8910 PSG Data read ------- Port A2h READ = PSG data read. Used to read data from current PSG register. Examples: How to read a byte from a register is shown in this routine (Input: [a]=PSG register, Output: [a]=Data read) read_psg: out (0A0h),a ; Select register in a,(0A2h) ; Read data ret This routine will read joystick 1 or 2: F3 di 3E 0F ld a,0fh Write this for Write this for D3 A0 out (0a0h),a Joystick port 1: Joystick port 2: DB A2 in a,(0a2h) E6 DF / E6 AF and 11011111b; 0DFh and 10101111b; 0AFh F6 4C / F6 03 or 01001100b; 04Ch or 00000011b; 003h D3 A1 out (0a1h),a 3E 0E ld a,0eh D3 A0 out (0a0h),a DB A2 in a,(0a2h) Now register [a] will have the following configuration for joystick in port 1 (or port 2): Bit #: 76 5 4 3210 || | | |||| Name: 10 TRG2 TRG1 RLDU Where TRG2 is the second trigger button (not used on most Commodore joysticks). -------------------------------------------------------------------- .d88b. w 888b. .d88b. w YPwww. w8ww .d88b 88b. 8wwwP Yb dP YPwww. w8ww .d88b 88b. d8 8 8.dP' 8 8 wwww 8 b YbdP wwww d8 8 8.dP' 8 8 `Y88P' Y8P `Y88P 88P' 888P' dP `Y88P' Y8P `Y88P 88P' 8 dP 8 -------------------------------------------------------------------- S.1 Step-by-step implementation of an emulator for Phoenix Written by Brian Peek (peekb@union.edu) and Chris Hardy PLEASE NOTE: Do not send email to Chris asking for help. He's got a real job and plenty of other things to do...:) BUT, please DO feel free to send email to me (Brian) if something doesn't work. I'm the one who has actually typed all of this from his emails and my own experiences, so it's my fault if anything has been ommitted or typed incorrectly. So you want to write an emulator for your favorite arcade game, eh? Well, this will HOPEFULLY take you step by step through the creation process of an emulator using the game Phoenix. Almost all of the technical information in this discussion comes from Chris Hardy, author of the awesome Windows 95 Phoenix/Pleiades emulator using DirectX. Chris has helped me along with my own emulator project, and taught me much about writing an emulator by having me write my own Phoenix emulator. This step-by-step will use the game Phoenix, Chris' technical information, and my own experiences. Also, keep in mind that our emulators were written using Marat Fayzullin's Z80 CPU emulation core. With the CPU stuff out of the way, we can concentrate on graphics and whatever else needs to be done. I'll try to give some basic/generic information for each step, and then give an example of what I'm talking about by using Phoenix. After following all of the steps of this guide, you should actually have Phoenix up and running on your screen! Before you even attempt to write an emulator, please be aware that you will need to know the following: 1) More than a basic knowledge of the C/C++ programming language, especially things dealing with bit operators. 2) Assembly language. It's not necessary to know a great deal about it, but you should know what opcodes are, what registers are, how they differ, and what a few opcodes do. You don't need to know what the game is really doing while it's running, so a basic understanding of assembly should be OK. 3) Graphics programming. You should know what bitplanes are, how to draw pixels, use of blitting functions, etc. Again, not a great deal of knowledge is required, but you should know the basics. 4) Hardware. You need to know what interrupts, cycles, vertical blanks, and things of that nature are. 5) Your compiler. Each compiler had it's own little idiosyncracies that need to be known. I work with Borland C++ 5.01 and all of the code contained in this section is guaranteed to run on it. I haven't tested it on any other compiler, so I don't know how it will react. [Note: I've got it to work on DOS-based Turbo C++ 3.0, and Borland C++ 3.1 (I know, I have ancient compilers...)] I will try to explain as much of the above as I can while describing the creation process of the emulator, but without a basic understanding of the above, you might not understand what I'm trying to say. Now, let's get started! S.1.1 Part I: Pre-coding Before you start coding, you'll need to do the following: 1) Pick a game you want to emulate, preferably one with a Z80 processor since that's what this guide will use, however I'm going to try to make this as generic as possible so any processor will work. 2) If the game uses a Z80, congratulations! Now go download the Z80 CPU emulator from http://www.freeflight.com/fms 3) READ AND STUDY IT! It's important to know what functions need to be written by you and how they fit into the whole scheme of things. 4) Download the Virtual Gameboy source code from the same site as above. This is an excellent example for the use of Marat's Z80 emulator. 5) READ AND STUDY IT! With this, you'll understand even more how the functions fit into place. 6) Obtain a memory map or make one yourself. In the case of Phoenix, there's an excellent memory map right in this text file. S.1.2 Part II: Low/High Endian I'm giving this it's own section because it's so critical. And because I forgot to check it when I started my emulator. :) In the "gb.c" file, (you should have already downloaded it and read it!) there's a check for the "endian-ness" of the machine. This is very important because it determines which byte is the most significant for your machine/compiler. In my case (Borland C++ on a P166), it was requried that I had LSB_FIRST defined in the "z80.h" header file. I suggest you cut and paste the code from the "gb.c" file into a temporary file and run it. It will then tell you if it needs to be defined or not. The code is repeated here: /*** STARTUP CODE starts here: ***/ T=(int *)"\01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; #ifdef LSB_FIRST if(*T!=1) { puts("********** This machine is high-endian. *********"); puts("Take #define LSB_FIRST out and compile VGB again."); return(0); } #else if(*T==1) { puts("********* This machine is low-endian. *********"); puts("Insert #define LSB_FIRST and compile VGB again."); return(0); } #endif You should #define LSB_FIRST and try running it. If it doesn't give an error, you should define it in the actual Phoenix emulator we'll be writing. Otherwise, try undefining LSB_FIRST and run it again. If no error is shown this time, then do not define it in the acutal emulator. S.1.3 Part III: Let's start coding! 1) Read the ROMs into a "virtual" address space as they would be in the real game. In the example of Phoenix, the following would be done: byte *RAM; RAM = malloc(0x8000); if (!RAM) ERROR; FILE *in; in = fopen("phoenix.45", "rb"); //read in the phoenix ROM in binary mode if (!in) ERROR; fread(&RAM[0x0000], 0x800, 1, in); //read in 0x800 bytes at position fclose(in); //0x0000 in = fopen("phoenix.46", "rb"); if(!in) ERROR; fread(&RAM[0x800], 0x800, 1, in); //read in 0x800 bytes at position fclose(in); //position 0x800 ...and so on. I used a "for" loop to do this, but wrote the steps out here to show what is happening. For Phoenix, we're loading 8 ROMs that are 2K each, or 2048 bytes, or 0x800. That's 16K to you and me. So, 16K = 16,384 bytes = 0x4000. We also have 8K of RAM in Phoenix, so that's another 16K, or 16,384 bytes = 0x4000 for a grand total of 32K (32,768 bytes), or 0x8000. Now, all of your ROMs should be located in "RAM". Please note that we are only loading PROGRAM ROMs, and NOT character ROMs. 2) Since we're using Marat's Z80 core, we must code the functions that are needed for the emulator to operate. In most cases, this should only be M_RDMEM, M_WRMEM, DoIn, DoOut, Interrupt, and Debug. In M_RDMEM and M_WRMEM we need to check to make sure we can read/write to/from the location requested, and emulate any hardware that might be in any of these locations (i.e. dipswitches). For Phoenix, only M_RDMEM, M_WRMEM are needed. However, please keep in mind that just because DoIn, DoOut, etc. are not being used for anything doesn't mean they don't exist. You need to create empty functions for ALL of the functions in the "z80.h" header file that aren't being used. These functions should be DoIn, DoOut, Patch, Interrupt, and Debug. a) Now we need some background stuff. Phoenix uses vertical blanks to update the screen instead of triggering an interrupt. In order to trigger a vertical blank to update the screen, we need to count the number of "cycles" that have occurred since the last vertical blank. A "cycle" is a set period of time in which the processor will do something. It is generally a time frame determined by the clock speed of the processor. So, every instruction that is passed to the CPU takes X amount of cycles to execute. We know (or can guess...) the amount of cycles that can be executed in one video frame (60th of a second for the US (NTSC), 30th of a second for Europe (PAL)). Therefore, if we add up all of the cycle counts for each instruction that the emulator executes, we can tell when we have executed a "video frames" worth of instructions. When this has happened, we can get the emulator to trigger a vertical blank or an interrupt. Marat's Z80 code counts down instead of up and checks when the cycle count is less than zero. If you've read through Marat's code like I told you to above, you've probably noticed a #define for INTERRUPTS and a couple of variables for working with interrupts, namely ICount and IPeriod, in the file "z80.c". IPeriod should be set to the number of cycles that should occur before triggering an interrupt (or in our case, a vertical blank flag) which is 12000 for Phoenix. So, the line in "z80.c" will read: IPeriod = 12000; So, ICount will count the number of cycles that have occurred, and when it is less than 0, we can trigger a vertical blank. The way Phoenix triggers a vertical blank is by setting bit 7 of the dipswitch to 1. The dipswitch for Phoenix is located at 0x7800, which is mirrored from 0x7801-0x7bff. For Phoenix, what I did was create a variable which would hold the current dipswitch settings. When this location is then read, it knows it's time to update the screen. So, when you are coding your M_RDMEM function, you need to return the proper value of the vertical blank bit, as well as reset it back to 0. To do this, I created a variable of type "byte" (defined in the "z80.h" file if you read it) to hold the dipswitch settings. For this example, we'll just use an int variable which will toggle between 0 and 1 as desired. b) Now we can code our M_RDMEM function! int DipSwitchSYNC = 0; //global variable defined earlier byte M_RDMEM (word A) { // decode the addresses (A) if(A >= 0x7800 && A <=0x7bff) //are we reading dip switch memory? { if(DipSwitchSYNC == 1) //if SYNC bit of switch is 1 { DipSwitchSYNC = 0; //set it to 0 return 128; //return value where bit 7 is 1 } else return 0; //return value where bit 7 is 0 } else if (A < 0x8000) //We're reading from ROMs or RAM return RAM[A]; //Default: Display a warning and return memory value printf("WARNING! Reading from location %04X\n", A); return RAM[A]; } c) Our M_WRMEM function will be much similar, except here we're assigning a value to a particular position in RAM instead of returning it. void M_WRMEM (word A, byte V) { //decode the addresses (A) if(A < 0x4000) //We're reading from the ROMs { printf("WARNING! Attempting to write to ROM") return; } else if(A > 0x3fff && A < 0x8000) //We're reading from RAM RAM[A] = V; } 3) Now we need to toggle the DipSwitchSYNC to 1 when the IPeriod number of cycles has been reached. In the "z80.c" file, you'll see in the Z80() function some code that reads: #ifndef INTERRUPTS blah blah blah #else blah blah blah Well, since we've defined interrupts in the "z80.h" header file, we're going to add some code that will trigger the vertical blank (but remember, we're not REALLY doing an interrupt...). So, under the line: #else we're going to add our own vertical blank trigger. We've already created the global variable that toggles between 1 and 0, so we need to toggle it to 1 when a "vertical blank's" number of cycles has occured (12000 for Phoenix). Our added code will look like this: extern int DipSwitchSYNC; //defined at top of "z80.c" extern byte *RAM; //also defined at top of "z80.c" ... if(ICount<=0) { //if we've exceeded the number of cycles ICount+=IPeriod; //reset the count to 12000 if(!CPURunning) break; DipSwitchSYNC = 1; //set the switch to 1 so when the dipswitch } //is read again, it will know it's time for a //VBlank, and reset it to 0 4) OK. You may not realize it, but all of the code is now in place to actually run Phoenix! But, we now have to write a bit more so it will display something to the screen. For simplicity's sake, we'll just add it to the above section of code, but normally this wouldn't be done. a) More background information is needed. Phoenix uses nothing but characters to display it's alphanumeric characters as well as anything else you see on the screen. This is pretty rare. Normally games use sprites to move objects around the screen (i.e. Pacman is a sprite, but the dots are characters). For Phoenix, all we need to do is emulate the characters, and no sprite routines are needed. What we're about to write will update the ENTIRE screen everytime a vertical blank is triggered. Normally we'd keep track of the previous screen and only update the characters which have changed. But, for the sake of simplicity and length of this guide, we'll just redraw the entire screen. The other thing to keep in mind is that Phoenix used a vertical monitor, so we need to compensate for this when writing the characters to the screen. The Phoenix display was 26 characters horizontally by 32 characters vertically. We also need to remember that the characters aren't stored in anything even close to ASCII. What is stored in the video portion of memory is a reference to the position of the appropriate character in the character ROM. Since we're not doing true graphics right now, we only need to convert the character reference to it's ASCII equivalent. Let's watch.... int x, y, pos; //defined at top of function unsigned char c; ... if(ICount<=0) { //this is the same code as above...we're ICount+=IPeriod; //just adding a bit to it....:) if(!CPURunning) break; DipSwitchSYNC = 1; gotoxy(1, 1); //start drawing at the top left //ONLY FOR PC's!!! for(y = 0; y < 32; y++) { //rows of characters int pos = 0x4000+32*(26-1)+y; //position into video memory for (x = 0; x < 26; x++) { //columns of characters c = RAM[pos]; //get character at current pos if(c>=1 && c<=27) //if it's a letter c+='A'-1; //turn it into one! else if (c == 31) //this is an asterisk c = '*'; else if (c > 30 && c < 42) //these are numbers c+= 16; else if (c == 43) //this is a hyphen c = '-'; else if (c == 42) //this is a period c = '.'; else if (c > 0x00) //let's just draw X's for the rest c = 'X'; printf("%c", c); //spit it out! pos -= 32; //move to next character in VRAM } //end for printf("\n"); //we're at end of row! } //end for } //end if I suppose that position line could use some explanation. Our video area of RAM for the foreground characters starts at 0x4000 according to our memory map. So, we're starting at 0x4000, adding the screen height, multiplying by screen width minus 1, and adding the current row we're on. You SHOULD be able to replace 26 and 32 above with the width and height of the game you want to emulate. Now whenever a vertical blank is called, it will redraw the screen! Neat, eh? 5) We've got the ROMs loaded, vertical blanking is setup, and the screen will be redrawn when necessary. Only one thing left to do... finish the main() function! Here, we need to reset the Z80 and start the actual emulation. You might also want to clear the screen before actually starting the emulation. So, right after the code that loads the ROM we'll add these things: reg R; //defined at top of main function textmode(C4350); //set display to 50 lines - ONLY FOR PCs!!! clrscr(); //guess...:) - ONLY FOR PCs!!! ResetZ80(&R); //This resets the Z80 to its proper starting values Z80(R); //Actually starts the emulation S.1.4 Part IV: Run it! 1) If you have all of the above things in place, you should now be able to compile and run this program! Make sure your Phoenix ROMs are in the proper directory, and make sure all of your header files are included as needed. You should need to include stdio.h, alloc.h, and conio.h. You also need a reference to the "z80.h" header file in your main file. Lastly, be sure that BOTH your main file (i.e. phoenix.c) AND "z80.c" are being compiled together! In Borland C++, you would do this by adding "phoenix.c" and "z80.c" to your project before compiling. That should do it! Hopefully you should see Phoenix running on your screen in a text display and you'll see something similar to this: SCORE1 HI-SCORE SCORE2 000000 000000 000000 X0 COIN00 X0 INSERT COIN etc. If not, try checking the "endian-ness" again and make sure you haven't made any typos in the above functions. Also be sure you've put everything in the right place. S.1.5 Part V: To be continued... I'm going to end it here for now. At this point you should have a basic understanding of what vertical blanks/interrupts are, how characters are stored in memory, how to load ROMs into a virtual space, and a few other things. The next installment (hopefully...) will contain some information on how to do character graphics and keyboard input. S.1.6 Sound emulation... [provided by James R. Twine (jtwine@bettynet.com)] In the memory map, there are two (mirrored) locations for sound, lets call them "SoundA" and "SoundB". The bits for these memory locations equate to a frequency and a volume (according to the information in the AE-FAQ). I just detected when a write was done to SoundA or SoundB, and out()-ed the value of the first 4 bits * 100 to the sound port, if any of the volume bits were high. If anyone has any questions, I will be happy to answer them! Here is the code that I am using to get *some* sound out of the emulator... Attached you will find a file called "Phoenix.DEF" which #defines the constants used in the program. You might need this, if the values are not obvious from the memory map. NOTE: All of the information in the Phoenix.DEF file comes from the AE-HowTo. I started without looking at the step-by-step at first, and got as far as getting a single image on the display, but the image would not change. (After checking the Step-By-Step, I noticed that I was not setting Bit 8 (128) for the VSync/Redraw, but I was setting Bit 7 (64). No wonder it would not Frame-Advance! :) The emulator NEEDS to see that bit go hi! Note that I use generous amounts of Whitespace in my coding style... Some people like it, some do not. Oh well...! The emulator was coded using Visual C++ 1.5, but It should work under Borland/DJGPP with not-much-modification. I would hope! :P [Note, these files were MIME-ified by my mail reader. I cleaned them up as best I could. Let me know if they work, or if any changes need to be made...] ---- Here is my version of the M_WRMEM function CUT HERE --- void cdecl M_WRMEM( word iAddr, byte iValue ) { // if( ( ( iAddr >= PHO_SoundCtrlALo ) && ( iAddr < PHO_SoundCtrlAHi ) ) || // ( ( iAddr >= PHO_SoundCtrlBLo ) && ( iAddr < PHO_SoundCtrlBHi ) ) ) if( ( iAddr >= PHO_SoundCtrlALo ) && ( iAddr < PHO_SoundCtrlAHi ) ) // if( ( iAddr >= PHO_SoundCtrlBLo ) && ( iAddr < PHO_SoundCtrlBHi ) ) { // If Setting Sound Info int iFreq = 0; // Frequency if( ( iValue & EM_Bit5 ) || ( iValue & EM_Bit6 ) ) { // If Volume Bits Set if( iValue & EM_Bit1 ) iFreq += 1; // Extract Information if( iValue & EM_Bit2 ) iFreq += 2; // Not Sure If These if( iValue & EM_Bit3 ) iFreq += 4; // Values Are Right, if( iValue & EM_Bit4 ) iFreq += 8; // But They Work! iFreq *= 100; // Calculate Freq MakeSound( iFreq ); // Make Some Noise! } else // If No Volume _outp( 0x61, 0 ); // Turn Off Any Sound } else // If Not Sound Info g_pMemory[ iAddr ] = iValue; // Set Byte In RAM Area return; // Done! } ---- Here is my version of the M_WRMEM function CUT HERE --- And the following is the function that I used to make the sound. ---- Here is the MakeSound function CUT HERE --- void MakeSound( long iFreq ) { int iCtrl = 0; // From The Sample _outp( 0x43, 0xb6 ); // Ready For Sound iFreq = (unsigned)( 1193180L / iFreq ); // Build Freq. Value _outp( 0x42, (char)iFreq ); // Set Frequency _outp( 0x42, (char)( iFreq >> 8 ) ); iCtrl = inp( 0x61 ); // Get Sound On Command(?) _outp( 0x61, iCtrl | 0x3 ); // Set Sound On! return; // Done! } ---- Here is the MakeSound function CUT HERE --- This is the PHOENIX.DEF file... [I cleaned it up a bit, lines were too long...] ---- Here are the definitions CUT HERE --- /* | Constants And Memory Layout For The Phoenix ROMs | */ UCHAR iDIPSwitch1 =3D 0; // DIP Switch Settings UCHAR iDIPSwitch2 =3D 0; UCHAR iDIPSwitch3 =3D 0; UCHAR iDIPSwitch4 =3D 0; UCHAR iDIPSwitch5 =3D 0; UCHAR iDIPSwitch6 =3D 0; UCHAR iDIPSwitch7 =3D 0; // unsigned char iDIPSwitch8 =3D 0; // Used For VSync! #define PHO_ROMNumberStart 45 // ROM File Number Start #define PHO_ScreenWidth 26 // 26 = X #define PHO_ScreenHeight 32 // 32 = Y // Memory Area Limits // #define PHO_MemAreaLo 0x0000 // Beginning Of Memory Area #define PHO_MemAreaHi 0x8000 // End Of Memory Area // ROM Area (16Kb, Game Code) and RAM Area (16Kb) Limits // #define PHO_ROMAreaLo 0x0000 // ROM Area Start #define PHO_ROMAreaHi 0x3FFF // ROM Area End #define PHO_RAMAreaLo 0x4000 // RAM Area Start #define PHO_RAMAreaHi 0x8000 // RAM Area End // RAM Area "A" (1Kb) // 832 Bytes Used For Video RAM ("CHAR-A") // 192 Bytes Used For Variables // #define PHO_RAMAreaALo 0x4000 // RAM Area A Start (1K Bytes Total) #define PHO_RAMAreaAHi 0x43FF // RAM Area A End #define PHO_VRAMAreaALo PHO_RAMAreaALo // VRAM A Start (832 Bytes) #define PHO_VRAMAreaAHi 0x433F // VRAM A End #define PHO_VarAreaALo 0x4340 // Var Area A Start (192 Bytes) #define PHO_VarAreaAHi PHO_RAMAreaAHi // Var Area A End // RAM Area "B" (1Kb) // 832 Bytes Used For Video RAM ("CHAR-B") // 192 Bytes Used For Variables // #define PHO_RAMAreaBLo 0x4800 // RAM Area B Start (1K Bytes Total) #define PHO_RAMAreaBHi 0x4BFF // RAM Area B End #define PHO_VRAMAreaBLo PHO_RAMAreaBLo // VRAM B Start (832 Bytes) #define PHO_VRAMAreaBHi 0x4B3F // VRAM B End #define PHO_VarAreaBLo 0x4B40 // Var Area B Start (192 Bytes) #define PHO_VarAreaBHi PHO_RAMAreaBHi // Var Area B End // Video Control Registers (8 Bits/1 Byte, WRITE ONLY) // Bit 0 Switches Between VRAM Banks ("Double Buffering") // Off|0 R/W To VRAM "A" Or "B" Is Directed To Bank 0 // On |1 R/W To VRAM "A" Or "B" Is Directed To Bank 1 // // Bit 1 Pallette Swap (A6 On Pallette Chip) // // Bit 2 - 7 Not Used // #define PHO_VideoCtrlReg 0x5000 // VControl Register (Two Bits Used) #define PHO_VideoCtrlLo 0x5000 // VControl Start ("Mirrored") #define PHO_VideoCtrlHi 0x53FF // VControl End ("Mirrored") // Vertical Scroll Register ("Charset-B") // "This Value Determines The First Of 32x8 Vertical Pixels // To Be Shown (Wraparound Fashion)" (??? Gotta Work On This!) // #define PHO_VScrollReg 0x5800 // Vertical Scroll Reg #define PHO_VScrollLo 0x5800 // Vertical Scroll Start ("Mirrored") #define PHO_VScrollHi 0x5BFF // Vertical Scroll End ("Mirrored") // Sound Control A (8 Bits/1 Byte) // Bit 0 > // Bit 1 > Frequency For // Bit 2 > Voice 1 // Bit 3 > // Bit 4 } Volume For Voice 10 // Bit 5 } // Bit 6 ] Melody Module Command: // Bit 7 ] , <-??->, <-??->, // #define PHO_SoundCtrlA 0x6000 // Sound Control A #define PHO_SoundCtrlALo 0x6000 // SControl A Start ("Mirrored") #define PHO_SoundCtrlAHi 0x63FF // SControl A End ("Mirrored") // Sound Control B (8 Bits/1 Byte) // Bit 0 > // Bit 1 > Frequency For // Bit 2 > Voice 2 // Bit 3 > // Bit 4 } Volume For Voice 2 (?) // Bit 5 } // Bit 6 ] // Bit 7 ] Noise Channel (? Volume 0-3 ?) // #define PHO_SoundCtrlB 0x6800 // Sound Control B #define PHO_SoundCtrlBLo 0x6800 // SControl B Start ("Mirrored") #define PHO_SoundCtrlBHi 0x6BFF // SControl B End ("Mirrored") // Game Controls Registers (8 Bits/1 Byte, READ ONLY) // Bit 0 Coin // Bit 1 Start-1Player // Bit 2 Start-2Player // Bit 3 N/C (???) // Bit 4 Fire // Bit 5 Right // Bit 6 Left // Bit 7 Shield // #define PHO_GameCtrlReg 0x7000 // Game Input Control #define PHO_GameCtrlLo 0x7000 // GInput Control Start ("Mirrored") #define PHO_GameCtrlHi 0x73FF // GInput Control End ("Mirrored") // DIP Switch Registers (8 Bits/1 Byte, READ ONLY) // Bit 0 Switch (Which One?) // Bit 1 Switch (Which One?) // Bit 2 Switch (Which One?) // Bit 3 Switch (Which One?) // Bit 4 Switch (Which One?) // Bit 5 Switch (Which One?) // Bit 6 Switch (Which One?) // Bit 7 > Flip Picture, But When Read By Processor, // > Used As H-SYNC (High During Vid Output Of // > Rows 0 -25, Low Other Times). // #define PHO_DIPSwitchReg 0x7800 // DIP Switch Registers #define PHO_DIPSwitchLo 0x7800 // DIP Start ("Mirrored") #define PHO_DIPSwitchHi 0x7BFF // DIP End ("Mirrored") ---- Here are the definitions CUT HERE --- S.2 Step-by-step discussion of an emulator for Space Invaders How I wrote a Space Invaders emulator An essay in Arcade Emulation Neil Bradley - neil@synthcom.com Before I get into this, I want to stress that the Space Invaders mentioned in this document is not yet available in EMU 2.0, but it will be after mid-January 1997. It is basically a step by step of how I wrote a Space Invaders emulator from start to finish. S.2.1 My Background I spent 7 years at Intel corporation, most of that optimizing Intel based assembly language. I know many microprocessors and microcontrollers, and also have a hardware background. I also am fluent in C & C++ and have a good amount of PC hardware experience. I'm not trying to scare you off or brag at all, I'm just trying to explain where I am coming from when I say things. The "How did he know that?" question might come up during this document, and the answer most likely is "been there - done that". ;-) S.2.2 Getting started The SI emulator was to be the basis for me writing a Z80 emulator (which as of this writing is still in progress) in assembly for all to consume. One of the best ways to write a processor emulator is to make it emulate code you know runs. No video games I know of come up and execute garbage code, so you're pretty well assured that using video game code as a test case is a pretty good idea in the development stage. I must stress that the most valuable resource to us is the internet. Learn all you can from all that is available. That is partially how I did the Z80 emulator. Take what others have to offer, learn from it, and in turn produce something else that others can benefit or learn from. If you're not writing your own processor emulator, skip to section S.2.4, "Space Invaders Specifics". I had prior experience writing a 6502 emulator in assembly and knew what would work and what wouldn't. This time I wanted to write a general purpose extensible emulator that would be multi-processor aware, and would emulate as fast as possible. I also got beaten up for not "being portable". If you want portable, go grab any of the slower than desired CPU emulators available on the internet. If you want high performance on lower end machines, use assembly. Pick what architecture you're going to go with and do it! I also don't intend on getting into the C vs. Assembly argument. I'm getting 4X the performance AT A MINIMUM against various C emulators for the same CPU, so there is something to be said for assembly. The answer is written in stone for me. Judge for yourself. If you want it portable, you'll take a performance hit. Accept it now. I decided to first see what others had done with Z80 emulators, so I searched the web for "+z80 +emulator" and got a few links. It led me a few sites, so I downloaded Marat Fazyullin's Z80 emulator and xtrs (TRS-80 emulator for Unix) and had a peek. It's always good to have more than one person's interpretation as to how an emulated processor should function, so find as many as you can when something doesn't make sense. I also purchased several Z80 books, two of which I found to be particularly useful. One is "How to program the Z80" by Rodnay Zaks and "Z80 Assembly Language Programming" by Peter W. Steele and Ivan Tomek. These are handy references. Rodnay's book as timing information, but is missing some instructions. It's also nice to have two or more books to check against each other, as often there are discrepencies. Both books mentioned above are out of print, but can usually be found at tech book stores. I wrote the basic "main loop" routine to basically fetch instructions and jump into a large jump table to each of the corresponding Z80 instruction. I also predefined what some of the registers would hold while the Z80 was emulating. HL is stored in BX, BC is stored in CX, DH Contains the Z80's flags, and DL contains the accumulator. ESI Is the source execution address, and EAX & EDI are used for general purpose computation throughout the emulator. The only time I ever used the high part of EBX or ECX was to quickly save the state of some registers, do some operations that could use them, and shift them back. Something like this: shl edx, 16 ; Save flags & accumulator for later [do work with dx here] shr edx, 16 ; Restore flags & accumulator It functions just like a push, but doesn't take up a memory cycle and doesn't create a cache hit. There are several things you need to keep in mind when writing a processor emulator: 1) Get RID of CALL functions. They are very expensive. For example, the Z80 emulator has no calls. It's all handled by jumps. It might be convenient to have the different addressing modes in a nice callable table but your emulator will take a good hit when doing it this method. Consider using macros. 2) Minimize jumps whenever possible. 3) Keep the most commonly used virtual registers in native processor registers. 4) Minimize memory accesses. These are killers. 5) Keep total data & code accesses as far under 256K as possible. The smaller the total data & code accesses the better of a chance of fitting into the system's cache. 6) Use macros to handle things like flags - not jump or call tables. 7) Create a general purpose read memory/write memory (and read/write I/O if the processor you're emulating requires it). Use this when doing data access functions, but DO NOT use these to fetch instructions. Most of the time you'll be spending will be in emulating the actual instructions and not moving data around. 8) Don't branch if you don't have to. Keep the most commonly executed path one that doesn't take a conditional branch. This can cause performance hits as well. 9) Make use of the instructions available to you. Even if you think you know a processor through and through, I would advise sitting down for quite some time studying its instruction set and taking advantage of every possible instruction you can. 10) Use xchanges to temporarily save off registers you just aboslutely MUST use. 11) For flags, use lookup tables if you can find a convenient way to look up add/subtract/dec/inc flags. I did this with the Half carry & overflow flags in the Z80 emulator. 12) When using the Intel architecture, use the 486> instructions even if you're not doing 32 bit code (though I would recommend that you DO). You can still use the extended parts of registers even though you're in real mode. To anyone saying "I'd like my code to run on a 386 or lower", consider what you're saying. These are pretty weak machines, and even 486 motherboards with CPU's these days are going for $60-$100 new. The extra constraint you'll put on yourself by not having the extended registers and 32 bit addressing (and some 486 instructions) will cause you to spend more time trying to get good performance out of low end machines that would wind up hurting performance on a 486 or Pentium. Be careful, and consider the extra work for trying to go for a low-end system when the next to low end machines aren't that much more money. These are just some of the guidelines that have worked extremely well for me. S.2.3 Disassemblers Another thing that is a life saver for processor emulation is a disassembler. Get your hands on a disassembler that you can trust. I found such a beast at Riddle's Roost (Sean Riddle's excellent Williams page) at http://www.ionet.net/~sriddle/willy.shtml. (that is spelled correctly). Sean has given us a freeware disassembler to use (thank you Sean!). I modified the disassembler to do two things - disassemble a single instruction and display registers on a single line. I displayed all the registers I was interested in, and a disassembly including the program counter and the actual bytes that were being disassembled. This is what you need for a simple debugger. Before I did all this, I allocated 64K and loaded in the ROMs at the appropriate places, and set the program counter to 0 (for Z80's). Then it went into my main loop. The main loop would allow me to single step through the execution, run with a disassembly, and run to a specific address. This way you can watch the code modify the register & see if it's right or not, or if it takes a wrong turn somewhere. I started off with no instructions emulated. I ran the Space Invaders code and let it run until it hit an invalid opcode. I implemented that instruction, ran the code to that point, recompiled, etc... and kept going until things were completely implemented. This was a good way for me to keep an eye on each instruction, and to at least semi-verify that they were working as I implemented them. This is important, because once you have the basic code to handle one type of an instruction (like ADD or SUB), implementing other similar instructions using different registers is easier, and most likely your code will be debugged before the other variants are added. I kept at it until the code was running well enough to keep running without hitting unimplemented instructions. Onto the game information... S.2.4 Space Invaders Specifics The first thing I did was go looking for a memory map of this game. It turns out that I had gathered enough information just by watching what the code was doing to figure out where most everything was, but I wanted to see if things were where I thought they were. So I got ahold of Michael Adcock's Emulator How-To guide, and the Space Invaders memory map was there. It told me where the graphics RAM, ROM, and user RAM was, and a little bit of information about the I/O ports that were used. I also figured that SI used some form of interrupt because I did hit an "EI" instruction. On the Z80, you can either jump to a specific vector or have the hardware insert an instruction on the bus to execute when an interrupt happens. I didn't have schematics, but my guess was they were implementing an RST $xx instruction or something. Then I remembered - Space Invaders uses an 8080, where all interrupts go to 0008h and all NMI's go to 0010h. Sure enough, a quick disassembly of these addresses yielded intelligent code. ;-) So I threw down a magic interrupt to occur about every 20-30 milliseconds and now things started to happen. I didn't know the orientation of the graphics, but a few things I did know about graphics gave me some ideas. I knew that Space Invaders was black and white, so I figured 1 bit per pixel. I hooked any writes to Space Invaders video memory to call a function I had written to poke it directly into the monochrome card's memory. I got a blotchy image that looked as if my horizontal sync was off somehow. The width of the Space Invaders image turned out to be 20h bytes (32 * 8 pixles = 256 pixels). Once I mapped it to the video monitor, it displayed SI sideways! So I hacked together a routine to turn it from a horizontal image to a vertical image, and up came the game - until the invaders started to come. Space Invaders is 248 X 256 - bits packed vertically. I got one invader and that was it. After looking through all kinds of code, I came across a section that looped through 55 bytes checking to see if it was zero or non-zero. If it was zero, it would skip to the next byte. If it was non-zero, it would draw an alien. BTW, I modified the debugger to output to the monochrome card so I could watch what was going on. Also, there are 55 aliens in an invading fleet. ;-) That's where I made the connection. Something wasn't happening. I double checked the emulation of the instructions I had implemented, and everything looked in order (minus a few bugs and those didn't affect it). I hooked up another Z80 emulator to it and got the same results. At this point I wasn't debugging a problem with the CPU emulator itself - I was debugging a problem with game environment emulation. I then remembered that I hadn't implemented a periodic NMI, so I decided to hook it up with about 50 millisecond intervals. I reran it. Voila. The fleet came up and things worked great. I had also taken notes during the emulation process and discovered that several I/O addresses were being read. 02h, 03h, 04h, 05h, and 06h. 5 & 6 were being written to but never read from. I took a look in the emulation how-to and found a section on the actual I/O addresses. I hooked the port values up to basic keys on the keyboard and was able to start playing the game. I don't have schematics, and to this day still haven't figured out the correct NMI/INT ratio values, but increasing interrupts causes the shots to move much much faster, and increasing NMI's causes the fleet to invade faster. I must admit Space Invaders is a pretty simple game to emulate. Not much to it, so if you're considering emulating a video game for the first time, keep some of these ideas in mind, and try 'em out. The only thing I'd do differently is if I had a reference machine or schematics to work against. When a particular I/O address or memory address is puzzling me, I check the address decoders on the schematics to try and find out where it's wired to. It's similar to reading a roadmap without any road names or town names on it, and filling it in as you go. Having a good command of how hardware works will help immensely. S.3 Step-by-Step discussion of how to make a memory map [provided by Mike Cuddy (mcuddy@FensEnde.Com)] S.3.1 Memory Maps: The toolbox The first thing to do is to get a set of schematics, and hope that the game you are trying to emulate was created before the programmable logic explosion in the late 80's. You see, most early games used straight TTL logic to do the address decoding from the CPU, whereas later games, used programmable devices (which are _very_ difficult to reverse engineer, and almost impossible just from a schematic). The important pins to trace back are "Chip Select" (often labeled "CS" or "SEL" or "ENA" or "G") and "write" lines (often labeld "WR"). These will often be active-low signals, which means that they are enabled when they get a logic "0". The next thing you'll need is a TTL databook. Most college bookstores will have an TTL "LS" databook. This is the most extensive TTL family, so if the designers of your target hardware used an obscure TTL chip, it will probably be in here. S.3.2 Memory Maps: The "Easy" way... The easiest way to decode the memory map for the board you're emulating is to follow the address lines on the schematics as they leave the CPU; from the CPU they will go (usually directly) into an address decoder of some kind. The most common chip used in address decoding is a little beasty called the 74138 or 74139. ('138 or '139 for short; depending on the logic family used on the game, this may have 1 or two letters between the 74 and the 138, like 74S138 or 74LS139 -- From an emulation point of view, you can ignore those letters they relate to the power consumption and speed of the devices). The '138 is a three-to-8 address decoder. It has three inputs; labeled "A" "B" and "C" and 8 outputs (usually labeled "Y0" through "Y7"). There are also three enable lines (labled G1 through G3, G1 & G2 active-low, G1 active high) most of the time the enable lines will be tied active (i.e. ground or +5/Vcc accordingly), but sometimes they will be used as another decode bit. The '139 is just like the '138 except it does a two-to-four decode. The bit values of the inputs ("A" and "B" on '139, and "A", "B", "C" on the 138) are taken by the chip to be a binary number, 0-3 (or 0-8), and the corresponding output will be "driven low" (made active ... excellent for driving the active-low chip-select lines on most RAM/ROM chips. So, how does this relate to address decoding? Well, most games will have an LS138 tied to the upper 3 bits of address lines (A15, A14, A13 for 8-bit processors; 16-bit processors became common around the same time as PLD's so if you're emulating a game with a 68000, good luck); this divides the address space of the processor into 8 chunks of 8K (0000-1FFF, 2000-3FFF, 4000-5FFF ... E000-FFFF) each one of these chip-select lines (the Y# outputs from the '138) will probably run to one of: a rom chip (Z80's usually have the rom mapped at the bottom of memory, so look at the first few lines), a RAM chip (careful: if the size of the game's ram is less than 8K, then there might be another decoder chip, or the RAM might just be "aliased" throughout the 8K block) Sounds simple, right? Well for the most part it is. There are a few spanners to throw into the works: Some processors, most notably the Z80, have memory-space and I/O space. I/O accesses differ from memory accesses in a subtle way, when the z80 reads memory, it pulses the "MREQ" line, and when it accesses I/O locations, it pulses the "IOREQ" line. The other thing about I/O space is that there are only 256 supported locations, so the only address bus lines that will be asserted during an IOREQ cycle are A0-A7. (I know about the undocumented feature to get more I/O space, but it's not frequently used, and a discussion of it is beyond the scope of this document). So, to determine whether or not an address maps to I/O space or memory space, (on a Z80 at least ;-) just follow the IOREQ pins and the MREQ pins. Another gotcha to watch out for is reads and writes of the same address having different effects; look for the "WR" line off of the processor; it will often be used as a chip select. The CPU (again, for the Z80, but most CPU's are the same) will drive this line low (logic 0) when a write-cycle is happening, in the case where reads and writes have differing effects, the "read" chip will have an inverter on the cpu's "WR" line leading into one of the chip's select pins. S.3.3 Emulator Memory Maps: The "hard" way If you don't have a schematic, good luck. it's pretty tricky to discover all of the memory locations that a particular piece of hardware will use. One trick is to make your CPU code 'halt' when it accesses memory you haven't "mapped" into it's address space; this way, you'll be notified when memory accesses happen, and then you can "map" memory regions into the processor's address space as you discover what they are. One thing that most game ROMs will do is checksum the rom. They do this by starting at the lowest rom address and continuing to the highest rom address; adding up all of the bytes in that space, and ignoring overflow. Find this code in your game's roms; that will tell you if you have all of the program roms in the right place. Next, the CPU will probably clear game RAM and the "tile" memory (most 80's games have two types of graphics, "tile" or "background" graphics and "sprite" graphics), and possibly put up a test-pattern (a grid of some kind). Look for these writes to memory in your disassembly, and mark that memory as "RAM". Determining where the "sprites" go is more difficult; however, once you get into the disassembly of your game's roms, you'll start to get the flavor of things. RAM on 80's arcade games was usually static rams; drams were cheaper, but very little ram was used (often under 16K) and DRAM takes much more circuity to control. Also, most every 80's game multiplexes the RAM, so that (for example) the CPU gets access to the ram on "even" cycles, and the "sprite" or "tile" hardware gets access to the ram on "odd" cycles. If you have a 3MHz processor, there will be a 6 (or even 12 or 24) megahertz clock that is fed into a flip-flop to give distinct clock phases; look for this. Another sign of address multiplexing will be a chip like a 75157. These are quad 2-to-1 mulitplexer. It has a select line (usually labeled "S" or "SEL"), 8 inputs (labeled A0-A4 and B0-B4) and four outputs (Y0-Y4). When the "S" input is low (0), then "A" lines are directed to the Y lines. When the "S" input is high, the "B" lines are directed to the "Y" lines. This is where the address bus is split, you'll usually find that a collection of these outputs go to some SRAM, the A lines go back to the CPU, and the "B" lines go to some kind of custom address generator for the "sprite" or "tile" circuitry. S.3.4 Other Common Chips Some very common chips used in games of the 1980's: 2716 - 2K x 8 EPROM 2732 - 4K x 8 EPROM 2764 - 8K x 8 EPROM; used as program and graphics storage. 2564 - 8K x 8 EPROM, with a slightly different pinout than 2764 2128 - 2KB x 8 Static RAM. 2114 - 1K x 4 Static RAM (usually grouped in two's to get 1Kx8) 74273 - octal latch; this chip has 8 inputs and 8 outputs; it samples the inputs when a clock signal changes; the outputs do not change at any other time. These will be used to read control inputs, hold "temporary" values while the sprite or tile circuitry is gathering all of the information it needs for a sprite or tile, etc. 74245 - bi-directional buffer; this is used to isloate portions of a bus as well as buffer signals (bring them up to the correct electrical levels) that have to travel long distannces, or have to drive a large number of chips; often found just off of the CPU's data lines with the CPU's "WR" line running into this chip's select line. 74259 - 8x1 bit addressable latch; addressed with three address lines, it will latch (store) the value on the data line when it's clock line is strobed. These are used for driving panel LED's, and often as inputs to the amplifiers that drive the coin-counters S.4 How to Create a Memory Map for Moon Cresta [provided by Martin Scragg (mnm@onaustralia.com.au)] Firstly get hold of the schematics, without these making a memory map is going to be a real mongrel. Start at the CPU (Sheet 3, IC 7B), in this case a Z80, it has 16 address lines A0 to A15, 8 data lines D0 to D7, a read line /RD (All signals shown with a / in front eg. /RD are drawn in the schematics with a bar over the top which means that the logic level is low rather than the normal high), a write line /WR and a few others that we won't bother with at the moment. To convert these signals into something useful that selects certain pieces of hardware they must be decoded. Most of the decoding is done with a few simple binary decoders, these take two or more binary inputs plus a few qualifying signals and convert them to individual outputs. The first part of IC 8E takes address lines A14 and A15 and outputs 4 signals depending on the state of them (this is qualified with /MREQ which means the CPU is doing a memory request), the zero state goes into another part of decoder 8E with A13 (qualified by /RD so only reads to these locations will select the EPROMs). The zero state of this selects the EPROMs, the rest of the address lines A0 to 12 connect directly to the EPROMs. So if you look at the logic A15 =3D 0, A14 =3D 0 and A13 =3D 0 which means the high nibble of the address can be 0 or 1, A0 to A12 can be anything which means 000h to FFFh, therefore the address for the EPROMs is 0000h to 1FFFh. Go back to the first part of 8E, the 2 output (A15 =3D 1, A14=20 =3D 0) is connected to the qualifying signals of the next few decoders which means that the rest of the hardware is from 8000h to FFFFh. IC 8N is the next important decoder, it has A11 to A13 connected as the selection addresses and is qualified by our other output and the /RD signal. All the signals that get decoded from here are only valid when the CPU reads from them. The outputs are decoded as follows: A13 A12 A11 0 0 0 RAM 0 0 1 Not used 0 1 0 /VRAMRD 0 1 1 /OBJRAMRD 1 0 0 /SW0 1 0 1 /SW1 1 1 0 /DIPSW 1 1 1 /WDR Add to these the base address of 8000h and you get the following: 8000h RAM Main CPU RAM 8800h Not used 9000h /VRAMRD Video Memory Read (Characters) 9800h /OBJRAMRD Object memory Read (Sprites) A000h /SW0 Player input buttons A800h /SW1 Player input buttons B000h /DISPSW Dipswitch read B800h /WDR Watch dog reset Some of these inputs are only one byte eg. /SW0 but decode to 800h bytes of memory, to save on ICs most of the decoding is very course but the device is usually only accessed via the first memory location. IC 8M is the counterpart to 8N, the difference being that its outputs are qualified by /WR instead of /RD. These decode to the following: 8000h RAM Main CPU RAM 8800h Not used 9000h /VRAMWR Video Memory Write (Characters) 9800h /OBJRAMWR Object memory Write (Sprites) A000h /LAMP Used for sound and extra sprite select A800h /SOUND Sound select B000h Gets further decoded B800h /PITCH Pitch select IC 9N decodes the write signal for B000h further with address lines A0 to A2, qualified by BD0 (buffered D0) to the following: B000h NMI ON Non Maskable interrupt enable B001h Not used B002h Not used B003h Not used B004h STARS ON Background stars enable B005h Not used B006h HFLIP Horizontal video flip B007h VFLIP Vertical video flip Due to the partial decoding used, these select lines will be replicated every 8 bytes from B000h to B7FFh. The /SOUND and /LAMP outputs are similarly further decoded by ICs 9L and 9M respectively to produce the sound effects and select which bank of sprites to use. Still to come, how the video hardware works. ------------------------------------------------------- 888b. d8b 8 .8 .d88b 8' .d88b 8d8b .d88b 8d8b. .d8b .d88b d88b 8wwK' 8.dP' w8ww 8.dP' 8P 8.dP' 8P Y8 8 8.dP' `Yb. 8 Yb `Y88P 8 `Y88P 8 `Y88P 8 8 `Y8P `Y88P Y88P ------------------------------------------------------- R.1 List of Currently Emulated Games For a comprehensive list of games that have been emulated, please see: - Moose O' Malley's Arcade Emulation Page http://www.rocknet.net.au/~moose/arcade_emulation_game_info.html - Phil's Arcade Emulation Page http://www.netcomuk.co.uk/~pmorrisb/index.html - The PC Arcade http://dspace.dial.pipex.com/dodge/index.htm R.2 List of Games People Want to See Emulated Moose has been running an Arcade Emulation Survey. To see the current results, and to vote for the arcade game of your choice, please see: http://www.rocknet.net.au/~moose/arcade_emulation_survey.html It appears that Galaga is the most eagerly awaited game. This is definately one of the classics, and perhaps we will see one or more emulations of it soon! R.3 Internet Resources R.3.1 WWW Resources R.3.1.1 General Arcade Emulation Links - Moose O' Malley's homepage http://www.rocknet.net.au/~moose - Phil's Arcade Emulation Page http://www.netcomuk.co.uk/~pmorrisb/index.html - The PC Arcade http://dspace.dial.pipex.com/dodge/index.htm - The Australian Arcade Emulation Mirror http://www.onthenet.com.au/~hunter/arcade.htm - Dave's Video Game Classics http://www.gamepen.com/gamewire/classic/classic.html - Arcade Emulation Programming Repository http://valhalla.ph.tn.tudelft.nl/emul8/arcade.html R.3.1.2 ROM Images - Michael's Arcade ROMs http://www.fangz.com/~aladdin/ziped.htm - Arcade ROMs (mirror of ftp.tant.com in tabular form) http://www.vu.union.edu/~peekb/arcade/index.html - AROM - [The arcade ROM site] http://www.mygale.org/11/hpmaniac/arom.htm - Williams pinball ROMs http://www.pinball.wms.com/tech/roms.html R.3.1.3 Processor Information - Chipdir sites http://www.xs4all.nl/~ganswijk/chipdir/ http://www.hitex.com/chipdir/ http://www.civil.mtu.edu/chipdir/ http://ftp.unina.it/pub/chipdir/chipdir.html - 2901 AMD (Advanced Micro Devices) 4-bit - Wiretap archive ftp://www.spies.com/arcade/emulation/processors/2901 - 6502 MOS Technologies/Rockwell 8-bit - Programming card listing opcodes http://www.comlab.ox.ac.uk/archive/cards/cards.html#list - Wiretap archive ftp://www.spies.com/arcade/emulation/processors/6502 - Marat Fayzullin's 6502 emulation code http://freeflight.com/fms/CPUs/ - NoICE debugger for 6502 ftp://ftp.coast.net/Coast/msdos/debug/noi25_02.zip - "Monitor" -- a 6502 disassembler for the PC http://dales.rmplc.co.uk/ivan/atari/ - 6808 Motorola 8-bit (6802 without RAM) - Programming card listing opcodes http://www.comlab.ox.ac.uk/archive/cards/cards.html#list - Wiretap archive ftp://www.spies.com/arcade/emulation/processors/6808 - 6809 Motorola 8-bit - Programming card listing opcodes http://www.comlab.ox.ac.uk/archive/cards/cards.html#list - Wiretap archive ftp://www.spies.com/arcade/emulation/processors/6809 - 6809 disassembler and data files for Williams games http://www.ionet.net/~sriddle/willy3.html#soft - 6809 instruction set http://ironbark.bendigo.latrobe.edu.au/staff/mal/6809.htm - 6809 stuff http://www.brouhaha.com/~eric/embedded/6809/ - 6809 disassembler (Perl script!) http://www.oasis.leo.org/perl/scripts/misc/disassemble.6809.dsc.html - NoICE debugger for 6809 ftp://ftp.coast.net/Coast/msdos/debug/noi25_09.zip - 68000 Motorola 16-bit - Programming card listing opcodes http://www.comlab.ox.ac.uk/archive/cards/cards.html#list - Wiretap archive ftp://www.spies.com/arcade/emulation/processors/68k - 68KEMU http://www.arrakis.es/~ayo/ - 8080A Intel 8-bit - Programming card listing opcodes http://www.comlab.ox.ac.uk/archive/cards/cards.html#list - 8085A Intel 8-bit - Programming card listing opcodes http://www.comlab.ox.ac.uk/archive/cards/cards.html#list - 8910 (sound chip) - Source code for Marat's MSX emulator to emulate the AY-3-8910 http://freeflight.com/fms/fMSX - Schematics and information on 8910 and its family of processors http://andercheran.aiind.upv.es/~amstrad/CPC_Guide/index.html - Z80 Zilog 8-bit - Programming card listing opcodes http://www.comlab.ox.ac.uk/archive/cards/cards.html#list - Wiretap archive ftp://www.spies.com/arcade/emulation/processors/Z80 - Marat Fayzullin's Z80 emulation code http://freeflight.com/fms/CPUs/ - Marcel's new and improved Z80 emulation engine http://www.komkon.org/~dekogel/misc.html - Z80 description http://www.ee.washington.edu/eeca/micro/z80.html - Z80 assembler/disassembler (for MAC) http://www.emagic.de/mmm/z80 - Small C development system for Z80 http://www.cs.uwa.edu.au/~mafm/robot/small-c-readme.html - Z80 disassembler http://www.ionet.net/~sriddle/midway.html - NoICE debugger for Z80 ftp://ftp.coast.net/Coast/msdos/debug/noi25z80.zip - dZ80 v1.00 -- Freeware Z80 disassmbler http://www.inkland.demon.co.uk/dz80/index.htm R.3.1.4 Schematics - Schematics for sale ($15 each) http://www.webwrite.com/cgould/hbalde/lib3.html (Astro Fighter, Donkey Kong, Galaga, Mario Brothers, Pac Man, Popeye, Robotron, Space Invaders) - Free Schematics http://www.cyberpass.net/~jrok/schem.html (Burger Time, Dig Dug, Frogger, Galaga, Gyruss, Junior Pacman, Mappy, Moon Cresta, Q*Bert, Scramble, Time Pilot '84, Xevious) R.3.1.5 Miscellaneous Information - Adlib Sound Card Programming http://www.wam.umd.edu/~ghost/Arcology/Adlib/ - Arcade CPU Database and Emulator Matrix http://www.syspac.com/~sianara/games/arcade.html - Assault, Asteroids, Asteroids Deluxe, Battlezone, Black Widow, Dig Dug, Firefox, Lunar Lander, Majestic Twelve, Pengo, Quantum, Smash TV, Space Zap, Total Carnage, and more! (pinouts, switch settings) http://www.multipath.com/d.jefferys/vids/spacezap/spacezap.html - Cinematronics "CPU" information (detailed analysis) http://www.concentric.net/~Zonn/cineinst.txt - COMP.EMULATORS.MISC FAQ http://www.why.net/home/adam/cem - Denis Hruza'a Stern Page [Berserk/Frenzy info!] http://199.171.196.3/~king/stern.html - Denis Hruza's Crystal Castles Page http://199.171.196.3/~king/crystalc.html - Emulator Utilities (front-ends) http://people.delphi.com/tafoid/emulutil.htm - Galaga sounds (22 KHz direct-line WAV samples) http://www.pacificnet.net/~chrisb/archives/index.html - Gyruss Emulation Page http://www.fensende.com/Users/mcuddy/gyruss/ (scanned datasheets for the YM2203 and AY-3-8910 and 8912 and 8913) http://www.fensende.com/Users/mcuddy/ay8910.zip http://www.fensende.com/Users/mcuddy/ym2203.zip - History of Arcade Games and Home Systems http://www.foxnews.com/scitech/features/retro/index.sml - PacMan Fever Song in Real Audio!!! http://www.geocities.com/Vienna/4585/pacman.ra - PacMan Memory Map http://control.indigita.com/david/arcade/memory-map.html - PacMan Information and Resources (some programs and C source!) http://control.indigita.com/david/arcade/own.html - Pokey Board in your Parallel Port! http://w3.one.net/~mhill/pokey/sound.html - Programming the Sound Blaster and other sound boards... ftp://x2ftp.oulu.fi/pub/msdos/programming/mxinfo/00index.html (check out "sb_book.zip" and "sblast09.zip") - SoundBlaster Sound Card Programming http://www.informatik.hu-berlin.de/~baresel/sbdoc/sbdoc.html http://www.xraylith.wisc.edu/~ebrodsky/sb16doc/sb16doc.html - The Soundchip Emulation page... http://www.interlog.com/~cyrel/sound - Video Arcade Preservation Society http://www.vaps.org - Windows 95 Classic Arcade Themes http://www.geocities.com/Hollywood/Hills/5234/vgames.htm - Wiretap Archive http://www.spies.com/arcade/ R.3.2 FTP Resources The following FTP sites provide useful files for the development of arcade emulators: - Arcade ROM archive FTP.TANT.COM /pub/game_archive /incoming - Mirror of FTP.TANT.COM FTP.VESATEC.COM /pub/arcade/roms - Wiretap's arcade emulation information www.spies.com /arcade R.3.3 FSP Resources Note: Don't ask me what FSP is, or how to use it. If you don't know, just use the FTP/WWW resources instead. There is a FAQ on FSP... - Arcade ROMs (a mirror of Brian Peek's archive) host: 129.7.12.229 port: 1980 R.4 List of Arcade Games (Compiled from the KLOV, ftp.tant.com, and others) REMOVED. This list was very incomplete, and in the past year, MAME and other emulators have managed to get most of these games working!