The Making of Arcadia
By Syntax/Northern Dragons
Hello everyone and welcome to this article about the making of the Arcadia, a demo released to the Wild compo at Assembly 2003 (in Helsinki). I'm writing this article because the demo was written to run on an unusual platform, namely an arcade (coin-op) machine, the same type you'd find in any video Game arcade.
Note: I'd like to make it clear that Arcadia was basically just a technology demo that was released "just for the hell of it". It was a program that was used by myself to learn what could be done on the platform in question. Much more exciting thing can be done with the same hardware and I'll endeavor to make those in the future, just as I hope to be surprised by other demo coders creations using this technique.
Why did I think an arcade machine was a good platform for a demo? Well, several reasons:
1. It sounded cool.
2. It hadn't been done too much in the past.
3. To make you fear the name of the Northern Dragons (bwuhahahahaha :) )
But seriously, it was exciting to think that something could be made to run on the hardware. The hardware is question, by the way, is the Sega System 16 hardware, home to many popular games including Altered Beast, SDI, Alien Syndrome, Golden Axe, Hang-On, Outrun and Shinobi. All of them are very good games. Here are the specifications for the System 16 hardware:
- Motorola 68000 @ 10Mhz (Main CPU)
- Zilog Z80 @ 4Mhz (sound chip)
- Yamaha YM2151 (Sound generator)
- Screen Resolution is 320x224
- Palette is 4096 colours
Quite low spec hardware, yes? Well the platform was made in the late 1980's so it's using common components and the arcade machines seem to favor certain components, mostly on a cost reduction basis, so if you continue the journey into this field, you'll notice the use of the MOS 6502, Z80, M6800, M6809 and M68000 as CPU's, which is ideal for you oldskoolers out there. Sound chips are usually Yamaha chips (YM2151), OKI chips and Atari used the Pokey (proprietary) chip in their games.
An important note is that although multiple games can share the same hardware, they're not exactly the same. Yes, they have the same CPU and sound chip, but the ROM code/data position will probably not be identical and the number and size of each ROM could be different. Small differences like this mean that you can just continue to explore and explore arcade hardware for quite some time and always learn new and interesting things.
Ok, so how do you (How did we?) learn this stuff?
Well, I learned most of this info from 2 sources:
1. Charles Doty's arcadedev.emuvibes.com site. It's wonderful, go there. Now!
2. Reading the MAME source code. Yes, really.
One comment made repeatedly about Arcadia is the lack of sound. Yes, it doesn't have sound. There's a reason for this: I didn't understand how the YM2151 sound generator chip worked, simple as that. I couldn't find any information on how to program it at the time. This leads me to another important note: writing anything for arcade machines mean you sill be spending a lot of time researching on the net, reading data sheets for components and hacking code. There is very little useful (programming) information available for programming on arcade hardware.
Ok, so can we get started with this postmortem please?
All right then. Arcadia was based on the System 16 demo which can be downloaded from arcadedev.emuvibes.com which uses the game Tetris (Bootleg) as the chosen platform. Eventually the actual ROM setup of Tetris was used as we didn't want to be associated with a bootleg version :)
If you look at the original demo and Arcadia, you might notice they look nothing alike. This is because a lot of work went into Arcadia to remove as much of the original code data as possible. I think some of the original set-up code is still in there, and some code has been moved into their own modules, but the rest is original. This meant understanding the silly way in which the data and code were stored in the ROMs, by separating the information into odd and even bytes and storing one ROM of odd bytes and one ROM of even bytes.
Pretty whacked, eh? It's especially fun when creating the graphics. Good thing we have tools for this......such as the tools that were packaged with the original arcadedev demo. Sprs16.exe was used to create the graphic roms, given a PCX image which was a multiple of 2 in width. Split.exe was used to split the code into odd and even roms.
The other tools used when creating the demo were:
- JAS - really quite good M68000 cross assembler.
- MACCER - preprocessor unit.
- A Linker - we use the linker from the Sega Genesis dev package (but don't tell anyone ;). )
- Paintshop Pro - excellent program.
- Hex Workshop - another excellent workshop, invaluable for ROM work.
One large drawback with the hardware from a demo coding perspective is that there is no direct video writing. Yes, that's right! No pixel plotting. It's a sprite based system and you can have 64 sprites on the screen in total. Arcadia used 44 in total, 1 for the logo, 16 for the flag and 27 for the message sprites and I had plans to add more if I got audio working, using sprites for some VU meters which only adds to the oldskool feel.
Also, video objects can either be sprites or tiles. Whats the difference? Well, anyone who's hacked with the gameboy or gameboy advance will probably know. Tiles are used to store background information, graphics that don't move. Sprites do move. Well, That's not strictly true as the System 16 hardware has what it calls "scroll video" and "fixed video". I haven't experimented much with these, but scroll video can be used to scroll tiles in the background and fixed video keeps the tiles in a fixed position. Arcadia used no tiles and only sprites.
Another drawback to video is that we're limited to 16 colours for sprites. The palette itself is 4096 colours (1024 for normal scroll video colours, 1024 for "shadow" scroll video colours, 1024 for normal fixed video colours and 1024 for "shadow" fixed video), but the pixels in sprites are stored as 4 bits each, so that's 2^4 = 16. Tiles also are restricted in the number of colours, only 8 colours for tiles.
I'm guessing that the other colours can be used for palette manipulation, or it seems like a big waste of space.
The way the sprites are stored in memory are also interesting. Here is a run down of the format (from the System 16 document on arcadedev.emuvibes.com):
Notice byte $00...yes, you have to calculate height by (stop line - start line), not by just giving it a height, which means if you move the sprite vertically, you have to do 2 calculations.
Bytes $06 and $07 are used to store the address offset in the graphic roms of the data you want to use for the sprite. The graphic roms are 64k in size *each* (remember, odd and even ROMs), so a lot of data can be stored. In Arcadia, I used a fraction of the ROM space for the logo, flag and font letters, so many interesting things can be accomplished with the space given if you push the platform hard enough.
Ok, Can we see some code now?
Along with this article, you'll find the source code to Arcadia in the bonus pack. Looking in the directory, you'll see several files. The most important one is MAIN.ASM. This is the main code for Arcadia. Open up MAIN.ASM.
After the header comment, there's the definition for the vector jump table, which is used by the M68000 for defining interrupt processing. Almost all of the vectors point to the null interrupt INT, but vectors 1 and 28 are the interesting ones. MainLoop points to the start code for the demo and vector 28 is VBL, the vertical blank interrupt.
In Arcadia, the main loop took care of rendering and the vertical blank interrupt was almost empty except for a flag to signal the redraw to the MainLoop code. I have found that the vertical blank interrupt can also be used to time audio signals (turning sounds/notes on and off) and timers, so there are many possibilities there for experimentation.
The MainLoop code initializes the CPU stack and then calls InitMachine to set the system 16 hardware into a suitable state. In Arcadia, the video registers ($410exxxx-$418xxxxx) are set to safe values and data is loaded into the palette area ($840000), sprite area ($440000) and some variables are reset.
The majority of the remaining code in MainLoop is the main loop, which is an infinite loop that renders the demo. V-blank synchronization is achieved by using the VertBlank variable which is set to 1 in the vertical blank interrupt code and checked in the main loop and reset to 0 in the main loop.
The render code itself is in three pieces, the scroll manager, the flag waving and the writing of the modified sprite data to sprite area ($440000). The Scroll was achieved by simply decreasing the x position (bytes $02 and $03) of the sprite. When it reaches the left of the screen and is off screen, the next message letter is allocated to that sprite and the x position is reset to a position off and to the right of the screen.
A few words should be said about the screen and the visible portion. The screen resolution is 320 by 224. The left most visible pixel x position is 64. This means with a font letter of width 16 when the letter reaches x position 48, It has reached the left side of the screen. When it's off the screen it can be reallocated.
The Flag is created by cutting a flag into 16 horizontal strips of 4 pixel lines each. The waving was originally supposed to be achieved by adding a sine offset to the flag x position, creating a waving effect, but this was troublesome with the deadline approaching. What was used instead is simply positioning the flag strips in a staggered formation and using a far left and far right boundary for them to bounce between.
Animation of the flag was achieved by incrementing or decreasing the x position, depending on which direction the strip was moving in, left or right. How did we track the direction? variables? That would mean a lot of variables in a cramped variable space. To do it, lets cheat a little. In the sprite definition above, there's some free space not being used. We could use those... so that's what I did.
Byte $0C in each sprite used for a flag strip contains either 0 or 1 depending on which direction the strip is moving in and this is reset when it hits a boundary. This is sufficient for this basic animation, but for further animation actual variables would have to be used.
How can we build Arcadia from the source given?
Good question. To build the source we gave you, you will need the tools mentioned above in "The other tools used when creating the demo were."
You may have to edit the binaries path in the MK.BAT file as this is my tree for working:
After finding the tools, installing the source and modifying the paths in the batch file, you should be able to run the batch file. This makes two files for you, tetris.a5 and tetris.a7. These are the odd and even roms for code.
Move these over to the bin sub directory in the arcadia source directory. With the other rom files in this directory zip them up into a zip file called TETRISA.ZIP. Move this zip file into your ROMS sub directory in the MAME distribution and run tetrisa.zip or "Sega Tetris (Set 1)".
Don't worry about any warning messages and hopefully, you'll see Arcadia running on your machine.
The font data and sprite data are held in obj-e.rom and obj-o.rom. If you just want to run Arcadia, no other modifications are needed, but if you want to experiment a little, that's where to find the sprite data.
Scr01.rom, scr02.rom and scr03.rom hold tile data and are currently empty.
S-prog.rom is where sound data is stored and also where the Z80 sound driver program should be stored, except this ROM is empty for Arcadia.
So, there you go, kind and inquisitive Hugi reader. There's the lowdown on the Arcadia demo and how to do cool stuff on emulated arcade hardware. If you found this article informative, any suggestions, want to show me some cool stuff you did on exotica hardware or you would like me to write some more articles, please feel free to email me at firstname.lastname@example.org. I look forward to hearing from you.
- Meet the 68000 (Antic, Volume 4, No.1)
- Jimmy Mardell's M68000 Assembly Guide
- M680x0 reference by Flint/DARKNESS
- Amiga M68000 prgramming