Saturday, November 15, 2014

z88dk Programming Sample

In the previous post, we checked out z88dk Programming Setup. The z88dk is a portable Z80 / C cross compiler that targets hardware such as the 8-bit video games console: the Sega Master System (SMS).

Using z88dk, it is possible to write game code in high level C language rather than pure Z80 assembly.
Therefore, we would now like to extend this knowledge and write more detailed programming sample.

Let's check it out!

Software
Follow all instructions from the previous post: this documents how to setup the pre-requisite software.

Here is a summary of all required software to be installed:
 Name Version
 Z80 Editor ConTEXT
 Assembler WLA DX
 Emulators Fusion, Meka
 Disassembler SMS Examine
 
 Name Version
 C IDE Editor Crimson IDE
 Cross compiler Z88 Dev Kit
 Make files Cygwin
 Hex Editor HxD

Example
As an example, let's write the main loop of a simple "Shoot 'em up" style game, similar to the previous post, that simply moves a target sprite around the screen based on user input; preferably the joystick.

Graphics
Graphics on the Sega Master System are built up from four things: Palette, Tiles, Tilemap, Sprite table.
In our example, convert target sprite into a programming format the Sega Master System understands.

Here we will use the BMP2Tile utility from Maxim to convert the 16x16 pixel target sprite into SMS data.
Create 16x16 pixel target sprite (as above). Save target sprite as BMP (bitmap) file. Load in MS Paint:

Note: sprite / tile data on the SMS must be max. 4bpp (bits per pixel). Save as type 16 Color Bitmap:

BMP2Tile
Download and launch BMP2Tile. Drag n' drop 16x16 pixel target sprite onto open "Source" tab.

Choose "Tiles" tab. Ensure that "Remove duplicates" and "Planar tile output" are both checked.
Set "Index of first tile" to 1. It seems best practice to leave empty background tile at index 0.

Choose "Tilemap" tab. Leave "Use sprite palette" and "In front of sprites" options unchecked.

Choose "Palette" tab. Leave the "Output hex (SMS)" option checked for Sega Master System.
Click Save button on "Tiles", "Tilemap", "Palette" tabs. All data here is used in the game code.

Target Sprite
As an example, let's build on the existing test.c program found here at C:\z88dk\examples\sms.
First, create new directory: C:\TargetSprite. Next, add the following 2x files: test.s and linkfile.

test.s
.MEMORYMAP
SLOTSIZE $8000
DEFAULTSLOT 0
SLOT 0 $0000
SLOT 1 $8000
.ENDME

.ROMBANKMAP
BANKSTOTAL 1
BANKSIZE $8000
BANKS 1
.ENDRO

.SDSCTAG 1.0, "Target Sprite", "Shoot 'em up game main loop", "StevePro Studios"

.EMPTYFILL $C9                ;ret.
.COMPUTESMSCHECKSUM           ;compute sms checksum for this rom.

.BANK 0 SLOT 0
.ORG 0

.INCBIN "test.bin"
linkfile
[objects]
test.o
Launch Crimson IDE. File | New file. Save test.c. Next, type in the following source code: test.c.

test.c
#include <sms.h>

unsigned char pal1[] = {0x00, 0x02, 0x08, 0x0A, 0x20, 0x22, 0x28, 0x2A, 0x3F, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F};
unsigned char pal2[] = {0x00, 0x02, 0x08, 0x0A, 0x20, 0x22, 0x28, 0x2A, 0x3F, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x00};

unsigned char all_tiles[] =
{
  // blank tile.
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 
  // target sprite.
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x39, 0x20, 0x00, 0x00, 0x20, 0x21, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x2A, 0x00, 0x00, 0x2A,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x9C, 0x04, 0x00, 0x00, 0x04, 0x84, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x54, 0x00, 0x00, 0x54,
  0x2A, 0x00, 0x00, 0x2A, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x21, 0x20, 0x00, 0x00, 0x20, 0x39, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x54, 0x00, 0x00, 0x54, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x84, 0x04, 0x00, 0x00, 0x04, 0x9C, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

void setSprite(int x, int y)
{
  // priority, x, y, tile.
  set_sprite(0, x+0, y+0, 1);
  set_sprite(1, x+8, y+0, 2);
  set_sprite(2, x+0, y+8, 3);
  set_sprite(3, x+8, y+8, 4); 
}

void main()
{
  int idx, off, x, y; 
  set_vdp_reg(VDP_REG_FLAGS1, VDP_REG_FLAGS1_SCREEN);

  // array, start, count, bpp.
  load_tiles(all_tiles, 0, 5, 4);

  // array, start, count.
  load_palette(pal1,  0, 16);
  load_palette(pal2, 16, 16);

  x=120, y=88; 
  setSprite(x, y);
  for (;;)
  {
    off = 2;
    idx = read_joypad1();
    if (idx & JOY_FIREB) { off = 4; }
    if (idx & JOY_LEFT)
    {      
      x -= off;
      if (x < 0)      { x = 0; }
    }
    if (idx & JOY_RIGHT)
    {
      x += off;
      if (x > 240)    { x = 240; }
    }
    if (idx & JOY_UP)
    {      
      y -= off;
      if (y < 0)      { y = 0; }
    }
    if (idx & JOY_DOWN)
    {
      y += off;
      if (y > 176)    { y = 176; }
    }
    wait_vblank_noint();
    setSprite(x, y);
  }
}
 
If you have C:\PerfomBuild.bat setup as per previous post then simply hit Ctrl+1 hot key to run!
Note: move target sprite left, right, up or down. Press "Fire2" button to double movement speed.

Disassemble
Finally, disassemble the compiled binary file test.sms generated from the Crimson IDE batch script.
In directory C:\TargetSprite, copy the 2x files Opcodes.dat + smsexamine.exe from SMS Examine zip.

Launch command prompt, change directory cd C:\TargetSprite. Type: smsexamine.exe test.sms.
This action will generate test.sms.asm and any data files. Launch ConTEXT. Open test.sms.asm:

Follow instructions from the previous post to setup hotkeys: F9 (compile) F10 (run) F11 (debug).

Press F9 to compile and link "test.sms.asm". This generates the "output.sms" binary file.
Press F10 to run program in the Fusion emulator. Press F11 to debug in Meka emulator:

Compare machine code in the debugger with the raw binary output file from test.sms.

Summary
This simple programming sample creates building blocks necessary to produce an 8-bit video game for Sega Master System. The next steps would be to build an 8-bit Homebrew video game to completion!