Sunday, December 14, 2014

Adventures in 32X Homebrew - Part 3: 2D Graphics

Previous: Part 2: 32X Hello World

Drawing Stuff

Now that I had the ability to compile a program, run it and get it to display something, the next step to making my masterpiece game would be to get the thing to display some graphics.

Here is one of the first "working" attempts I made at creating a 2D sprite and animating a few frames of action with 32X.

While this sort of worked, there were problems with my implementation that were visibly apparent. As there is no standard library for graphics when working with 32X you pretty much need to implement your own.

Principles

To keep in mind the objective, in order to draw something to the screen on any system you will need to the following tasks.
  1. Convert source images to a format and size that can be processed by tools for 32X, including the right resolution and color depth that our hardware supports.
  2. Provide a mechanism to represent the image data in our ROM which we can reference from our code.
  3. In the game code be able to load the graphic image data to RAM.
  4. At the appropriate times in the game logic draw the image from memory to specified coordinates in the frame buffer.
  5. When finished rendering everything in the frame, flip the frame buffers.
Recall the 32X Video specs:
Video Memory: 256Kb (two 128 Kb framebuffers)
Screen Resolution: 320x224 or 320x240 (PAL)
Color depth: Up to 15 bits, 32768 unique colors, two-bytes per pixel, can use paletted color (Packed Pixel, 8BPP) mode, using up to 256 on-screen colors with one byte per pixel to save memory.

If you use the Packed Pixel mode, you will save on memory (RAM) to store your image files or your the read only memory in your ROM. I started with this approach thinking I might run out of memory on the 32X with all the 2d sprite graphics I wanted to display for my game. In my case I wanted to try to make a "16-bit plus" kind of game, so a ton of colors wasn't really necessary.

Most of this information I have taken from the excellent reference in Devster's Guide to the 32X.

Drawing Blocks

I thought the best way to start giving examples how to draw things on the screen for 32X was to not involve the whole image formatting/importing processing that would need to be done to load an image into your ROM during build time, and to reference the image data, load into memory and draw it out in your game code. Instead will begin with drawing colored blocks of pixels to the screen procedurally, instead of going loading an image. In this example we'll look at setting an RGB color in the color palette memory and drawing rectangles to the 32X framebuffer to create the images on the display.
Starting with the hello world tutorial code from the previous post, I am going to invoke some new methods that we didn't use before.

Global Variables and Constants

Just to note for further sections, the following global variables were added in the main.c

#define BLOCK_COLOR_1 32
#define BLOCK_COLOR_2 34


int r1 = 6;
int g1 = 0;
int b1 = 0;


These were used to set the color for the blocks when they are drawn.

Setting up the Color Palette

In this demo, like HelloWorld, we continue to use the 256 color, packed pixel mode, as a reminder this mode is set in the main.c before the main game loop using function Hw32xInit(MARS_VDP_MODE_256, 0);. The palette is a memory buffer called the CRAM, it holds up to 256 colors, each color being a 16 bit word of memory that can be any of the supported 32768 colors. The color in memory is stored in RGB format with the following bits:
15             0
PBBBBBGGGGGRRRRR

Bits 0-4: Red Value
Bits 5-9: Green Value
Bits 10-14: Blue Value
Bit 15: Represents a flag for "priority" of whether to draw 32X in front of Genesis VDP or behind.

For each of the Red, Green, Blue values you have 5 bits, which allows you to specify a numeric value for each color from 0-31, where 0 is basically black and 31 would be the "full" color (this is how you get 32768 colors, 32 red x 32 green x 32 blue = 32768 total possible color combinations).

To set a value in the CRAM, you need to write this data to that memory location, offset by the index of the color, you then refer to that index when drawing pixels of that color to the main framebuffer used to display. The CRAM can be referenced directly using MARS_CRAM define from 32x.h. It is the memory location: 0x20004200. However, there are utility functions which you may use in hw_32x.h,
extern void Hw32xSetFGColor(int s, int r, int g, int b);
extern void Hw32xSetBGColor(int s, int r, int g, int b);


To set a color "white" in the CRAM, at index 1 for example you may do the following:
//set block color in CRAM
Hw32xSetFGColor(1,31,31,31);

To set additional colors at other indices:
Hw32xSetFGColor(BLOCK_COLOR_1,r1,g1,b1);
Hw32xSetFGColor(BLOCK_COLOR_2,31-r1,31-g1,31-b1);

In this case, I use the global int variables I defined above, and the defines as constants to keep track of which index is being used for which color in the CRAM. In my demo I will vary the values of these ints from 0-31 to get various different combinations of colors which I will use when drawing the blocks.

While you can certainly set up all the values you want to use in your color palette up front, before your main game loop, you can also change them dynamically on the fly, for a "palette" swap effect without having to have a different image in memory.

Setting up Line Table in 32X Framebuffer

Now that we have the colors we want to draw in the CRAM. We need to write to the framebuffer what colors we want to draw at what pixels. There are two DRAM framebuffers in the 32x hardware, and so the general flow of your program is to write to one of the framebuffers, set a flag to "flip" the framebuffers, this causes the 32X hardware to write one of the framebuffers to the display while allowing you to know write to the other framebuffer again, and so on.

The drawing works by writing to memory locations in the framebuffer, in 256 color mode, for each pixel you have to write one byte for the index of the color in the CRAM. For the Direct Color mode (15 BPP) you need to write two bytes to draw a pixel. The location where that pixel is drawn depends on what location in the framebuffer memory location you write to. Determining which memory address is what on-screen pixel is sometimes complicated. First thing to understand is something called the Line Table which informs the 32X VDP where in the framebuffer each line of pixels should start, and for each line the VDP will display the next 320 pixels starting from the line address. The Line table itself is just the first 256 words of the framebuffer, so the first line of the display is generally after that 256th line table address. Here is a diagram of the relationship between line table and framebuffer lines, if you think about X, Y coordinates each line refers to an X on the screen, while the 320 bytes after the line address are the Y coordinates for pixels.
The line table doesn't say what addresses you need to point to, so the above example uses no offset, each line is right after the previous one in contiguous memory. In my own development, I came across a number of issues where objects being written to either the start or end of the line might go past line ending and then wrap around the the start of the next line. In some cases this made it difficult to fix without a lot of expensive checking. What I ended up doing was putting an offset of 4 words before and after every line, and updating the Line table accordingly.

This padding enabled my drawing code to be more efficient and allow some pixels to be written into the padding without corrupting the next line. All of my drawing functions in my sample currently depend on this four word offset. To set up the Line Table, in my main.c at the end of every loop I call
        //draw the 32X framebuffer line table with offset of 4
        drawLineTable(4);


This function is defined in 32x_images.c.

Drawing Rectangle to the Framebuffer

With all that work so far, now comes the "easy" part, drawing the darn thing. Objective here is to write out pixel data to the line address in memory, and to place the pixels at the write point in the line so it shows up in the correct place on the screen. In my code, I do all the heavy lifting for this inside the 32x_images.c's
void drawFillRect(const int16 x, const int16 y, const int xWidth,  const int yWidth, vu8* color)
void drawRect(const int16 x, const int16 y, const int xWidth,  const int yWidth, vu8* color)

These functions will draw a rectangle to the x, y pixel coordinates in the display, with a certain height and width in pixels, using a pointer to a color array. Wait, why is the color parameter a pointer to an array? Well this is basically a performance optimization that was suggested by the SpritesMind forum folks. Basically the fastest possible memory operation are when you write 8 bytes in one shot, so when filling or drawing a rectangle we are going to copy 8 bytes of a single color value from the palette to the framebuffer. To set up the color array I did this before the game loop.
vu8 blockColor[8] = {BLOCK_COLOR_1,BLOCK_COLOR_1,BLOCK_COLOR_1,BLOCK_COLOR_1, BLOCK_COLOR_1,BLOCK_COLOR_1,BLOCK_COLOR_1,BLOCK_COLOR_1};

This array references just the index number for the color in the CRAM we want to use. I then use this in some calls to draw the colored rectangles inside of the game loop.
drawRect(10,70,296,144,(vu8*)&whiteColor);
drawFillRect(20,80,40,40,(vu8*)&blockColor);
drawFillRect(60,80,40,40,(vu8*)&blockColor2);


Flipping the Framebuffers

To get the rectangles to display you need to flip the framebuffer after everything has been drawn to it. To trigger the flip you need to set a special register at the end of the main game loop.

//flip the FB, without waiting on flip
currentFB ^= 1;
MARS_VDP_FBCTL = currentFB;


This can actually take some cycles, so you want to ensure that your code doesn't start trying to drawn anything to the framebuffer again until the flip has completed. Use the following check to wait for the flip to complete near the start of the main game loop, before you draw anything.
   
// wait on flip to finish
while ((MARS_VDP_FBCTL & MARS_VDP_FS) != currentFB) {}


Final Game

Putting it all together, and adding some dynamic color changes by updating the palette with new RGB values each game loop iteration, I created a simple flashing effect. Take a look at it on youtube.


Source code for this project is on GitHub 32XHombrew : drawingblocks

Feel free to send any feedback on this or other tutorials. There is so much information it is hard to put it all down on paper in a cohesive way. Hopefully these are useful to the next person who wants to try out 32X programming.

Saturday, July 19, 2014

Adventures in 32X Homebrew - Part 2

Previous part: Part 1: Introduction to the 32X system

Building a ROM

So as I said in my last post, there is no IDE or standard dev kit to use when building a 32X Game. Fortunately some of the heroes of the homebrew community have pieced together the parts to get a simple game functioning.

Where to begin.

Building a Toolchain for 32X

Let's assume you have a basic familiarity with the C language and compilers and you want to write your game in C as opposed to SH2 assembly language. In order to build a 32X ROM you will need to compile your code for the architecture of the 32X which happens to be the 32-bit Hitachi SH2 processor (as well as a secondary tool chain for the 16-bit M68k of the Genesis). Your standard C compiler or IDE is probably using a toolchain which is designed to target your 32-bit or 64-bit architecture of the PC, based on x86. This will of course produce a binary set of instructions that would not be readable by our friend the 32X. So before going further you must find (or build) a 32X compatible toolchain.

Courtesy SpritesMind.net forum poster Chilly Willy
Building a Genesis/32X toolchain

 0 - System Prerequisites (based on testing on various Ubuntu Linux distros as of 1/18/2015):

  • Package gcc-4.6 (I have run into issues using default gcc on Mac OSX, as well as higher versions of gcc on linux e.g. 4.8.2). I have had success with gcc-4.6.4
  • Package texinfo (e.g. sudo apt-get install texinfo)
  • Package p7zip-full for extracting .7z using Archive Manager (e.g. sudo apt-get install p7zip-full)

1 - Go here and download the following:

gcc-4.6.2.tar.bz2

Decompress it to wherever you keep your projects; you should end up with a folder called gcc-4.6.2.

2.1 - Go here and download mpfr-2.4.2.tar.bz2.
2.2 - Go here and download mpc-0.9.tar.gz.
2.3 - Go here and download gmp-5.0.4.tar.bz2.

Decompress them all in the same folder. You should have three folders called mpfr-2.4.2, mpc-0.9, and gmp-5.0.4. Rename them to get rid of the version numbers, leaving you with mpfr, mpc, and gmp. Copy them into the gcc-4.6.2 folder.

3 - Go here and download binutils-2.22.tar.bz2.

Decompress it in the same folder as the gcc folder so that you have two folders - gcc-4.6.2 and binutils-2.22.

4 - Go here and download newlib-1.20.0.tar.gz.

Decompress it in the same folder as gcc and binutils, leaving you with the folders - gcc-4.6.2, binutils-2.22, and newlib-1.20.0.

5 - Get this archive and decompress it to the same place as the previous directories. You should have two more directories, bin and ldscripts, in addition to the file, makefile-sega.

6 - If you wish to leave the makefile with the default path of /opt/toolchains/sega, make sure you have permission to write to /opt or the toolchain will fail to install to the path. Since there's nothing critical in /opt, it's easiest just to do "sudo chmod 777 -R /opt" which allows anyone to do anything they want in /opt.

7 - Run "make -f makefile-sega" - depending on the speed of your computer, in an hour or two you should have two toolchains in /opt/toolchains/sega: m68k-elf and sh-elf. Copy the ldscripts and bin directories to /opt/toolchains/sega.

You now have the latest gcc, binutils, and newlib for both the 68000 and the SH2. Both have compilers for C, C++, Objective-C, and Objective-C++. The bin directory has a few common tools one might use for compiling Z80 code for the MD. Copy whatever other tools you use into it, like sixpack or bin2c.

Note: The size of the built toolchain can be reduced by stripping the debug symbols from the executables in the bin directories, and by deleting the libraries meant for CPUs other than the 68000 and SH2. For example, you don't need the libraries for the 68020 or 68040 or SH3 or SH4, etc. 


If you do not want to build the toolchain yourself with the above steps, you may be able to find posters who have posted their copy of the resulting binaries which you could then take and use (for Windows OS for example). Furthermore most of the steps above are for a Linux environment, to build for Windows you'll first need software to emulate a Linux environment such as MinGW. I did not have too much luck with Cygwin personally, but it should also work in theory.

Let us assume you have your toolchain built and in place. On my system I decided to put it here C:\bin\_gcc\gen
My gen\ directory contained:
  • bin
  • ldscripts
  • m68k-elf (toolchain for Sega Genesis M68k CPU)
  • sh-elf (toolchain for 32X's SH2 CPUs)

Hello World ROM

32x Hello World

You can download the source code and the ROM binary that this produces from my GitHub repo
https://github.com/ammianus/32xHomebrew/tree/master/32xhelloworld

Using the toolchain, I have created a simple HelloWorld 32X application. Besides displaying the text "Hello World" it also will print some text which corresponds to controls pressed (A, B, C, Up, Down, Left, Right, Start)

If you download the 32xhelloworld.zip I linked to, extract it to some folder. Note that I am on a Windows 7 Home Premium environment. To compile it you will need to run the Make command from the toolchain we've installed. First edit the 'Makefile' in a text editor of your choice ( I use the extremely productive Notepad++ ). Make sure to change the path of variable:
GENDEV=C:/bin/_gcc/gen
To whatever the path of your toolchain from above steps.

To run use a command a prompt (Run As Administrator on Windows 7). Change directory (cd) to the directory of the extracted 32xhelloworld directory. Then run the 'make' command.
C:\Users\ammianus\Documents\roms\homebrew\32xhelloworld>make
C:/bin/_gcc/gen/m68k-elf/bin/m68k-elf-as -m68000 --register-prefix-optional -o m
68k_crt0.o m68k_crt0.s
C:/bin/_gcc/gen/m68k-elf/bin/m68k-elf-ld -T C:/bin/_gcc/gen/ldscripts/md.ld --of
ormat binary -o m68k_crt0.bin m68k_crt0.o
C:/bin/_gcc/gen/m68k-elf/bin/m68k-elf-as -m68000 --register-prefix-optional -o m
68k_crt1.o m68k_crt1.s
C:/bin/_gcc/gen/m68k-elf/bin/m68k-elf-ld -T C:/bin/_gcc/gen/ldscripts/md.ld --of
ormat binary -o m68k_crt1.bin m68k_crt1.o
C:/bin/_gcc/gen/sh-elf/bin/sh-elf-as --small -o sh2_crt0.o sh2_crt0.s
C:/bin/_gcc/gen/sh-elf/bin/sh-elf-gcc -m2 -mb -O3 -Wall -Wformat -c -fomit-frame
-pointer main.c -o main.o
C:/bin/_gcc/gen/sh-elf/bin/sh-elf-gcc -m2 -mb -O3 -Wall -Wformat -c -fomit-frame
-pointer slave.c -o slave.o
C:/bin/_gcc/gen/sh-elf/bin/sh-elf-gcc -m2 -mb -O1 -Wall -c -fomit-frame-pointer
hw_32x.c -o hw_32x.o
C:/bin/_gcc/gen/sh-elf/bin/sh-elf-gcc -m2 -mb -O3 -Wall -Wformat -c -fomit-frame
-pointer font.c -o font.o
C:/bin/_gcc/gen/sh-elf/bin/sh-elf-as --small -o lzss_decode.o lzss_decode.s
C:/bin/_gcc/gen/sh-elf/bin/sh-elf-gcc -m2 -mb -O3 -Wall -Wformat -c -fomit-frame
-pointer 32x_images.c -o 32x_images.o
C:/bin/_gcc/gen/sh-elf/bin/sh-elf-gcc -m2 -mb -O3 -Wall -Wformat -c -fomit-frame
-pointer graphics.c -o graphics.o
C:/bin/_gcc/gen/sh-elf/bin/sh-elf-gcc -m2 -mb -O3 -Wall -Wformat -c -fomit-frame
-pointer shared_objects.c -o shared_objects.o
C:/bin/_gcc/gen/sh-elf/bin/sh-elf-gcc -T mars-helloworld.ld -Wl,-Map=output.map
-nostdlib --warn-section-align --sort-common sh2_crt0.o main.o slave.o hw_32x.o
font.o lzss_decode.o 32x_images.o graphics.o shared_objects.o  -LC:/bin/_gcc/gen
/sh-elf/sh-elf/lib -LC:/bin/_gcc/gen/sh-elf/lib/gcc/sh-elf/4.5.2 -lc -lgcc -lgcc
-Os-4-200 -lnosys -lm -o helloworld.elf
C:/bin/_gcc/gen/sh-elf/bin/sh-elf-objcopy -O binary helloworld.elf temp.bin
dd if=temp.bin of=helloworld.32x bs=64K conv=sync
0+1 records in
1+0 records out
65536 bytes (66 kB) copied, 0.00307811 s, 21.3 MB/s

This results in a bunch of new binary files generated in the same directory. One should be called helloworld.32x, this is the ROM file which you may load with your favorite Genesis/32X emulator (Fusion 3.64, Gens, etc...)

You can try it out and see what happens if you press your controller keys for up, up, down, down, left, right, left, right, b, a, b, a, start (for example).

A 32X Hello World: How It's Made


I apologize in advance for those who would expect at this point a tutorial where I tell you how to write every line of code from scratch in an easy to follow, incremental process. If my time and resources were infinite I would do that. But creating a working game in 32X is no easy process. I have been mostly copying code from other tutorials (especially from the hero, Chilly Willy of the SpritesMind forums) and modifying for what I wanted to do.

I have tried to strip out most of my code that isn't required for this tutorial, but it is still a complex animal after all.

Let's look at what the various files are in the 32helloworld.zip and what they do:
  • 32x.h - General 32x / MD constants and function signatures for assembly file sh2_crt0.s
  • 32x_images.h/.c -  functions for drawing image (sprites) to different memory locations of 32x, e.g. the framebuffer
  • font.c - Open Source default font characters for printing text to screen
  • game_constants.h - my own set of game specific constants, some not used for helloworld
  • graphics.h/.c - my own set of graphics functions for drawing circle, calculating sin values
  • hw_32x.h/.c - Chilly Willy's set of 32X functions for various operations and for controlling the MegaDrive (MD)
  • lzss_decode.h/.s - LZSS compression decoder for 32X which was used for decoding images compressed with lzss by the "sixpack" tool tile conversion and compression utility
  • m68k_crt0.s - Chilly Willy's first part of the ROM header for MegaDrive and initial exception vectors. MegaDrive 68k assembly!
  • m68k_crt1.s - Chilly Willy's  third part of rom header, standard 32X header code. MegaDrive 68k assembly!
  • main.c - the main code for the Master CPU, all logic for Hello World and handling input
  • Makefile - the make file for this project
  • mars-helloworld.ld - linker script for this project which puts the generated binaries into the right places in the ROM which sega/32x will be able to process.
  • sh2_crt0.s - Chilly Willy's Rom header and SH2 init/exception code - must be first in object list
  • shared_objects.h/.c - My own shared global variables
  • slave.c - the main code for the Slave CPU, mostly just idle looping in Hello World.
  • types.h - typedefs for various commonly used types e.g. typdef unsigned char uint8 //unsigned 8-bit integer
If we look a little closely at the main.c we can see where the Hello World is being printed.

main.c source (thanks to Chilly Willy for some of the code):
/*
* Copyright 2014 ammianus
*/
#include <stdlib.h>
#include <math.h>
#include "types.h"
#include "32x.h"
#include "hw_32x.h"
#include "32x_images.h"
#include "game_constants.h"
#include "graphics.h"
#include "shared_objects.h"



#define DEBUG 1
#define MAP_WIDTH 320


#define IMAGE_START_ADDRESS 0
#define IMAGE_END_ADDRESS 1
#define NINJA_STANDING_INDEX 0

//global variable
char keyPressedText[100];

//const int world_width = WORLD_WIDTH;
//int paused = UNPAUSED;
//stores the previous buttons pressed for handle_input
unsigned short prev_buttons = 0;


/*
* Converts an integer to the relevant ascii char where 0 = ascii 65 ('A')
*/
char ascii(int letterIndex){
    int asciiOffset = 65;
    char newChar;
    newChar = (char)(asciiOffset + letterIndex);
    return newChar;
}

/*
* Call 32x hardware initialization routine
*/
void mars_init(void)
{
  //using 256 color mode using palette
  Hw32xInit(MARS_VDP_MODE_256, 0);
}

/*
* Check the current SEGA Controllers for inputs, update player, direction
* , speed, and action accordingly.
*/
void handle_input()
{
    unsigned short new_buttons, curr_buttons;
    //unsigned short buttons = 0;

    //The type is either 0xF if no controller is present, 1 if a six button pad is present, or 0 if a three button pad is present. The buttons are SET to 1 if the corresponding button is pressed, and consist of:
    //(0 0 0 1 M X Y Z S A C B R L D U) or (0 0 0 0 0 0 0 0 S A C B R L D U)

    // MARS_SYS_COMM10 holds the current button values: - - - - M X Y Z S A C B R L D U
    curr_buttons = MARS_SYS_COMM8;
    if ((curr_buttons & SEGA_CTRL_TYPE) == SEGA_CTRL_NONE)
        curr_buttons = MARS_SYS_COMM10; // if no pad 1, try using pad 2
   
    // set if button changed
    new_buttons = (curr_buttons & 0x0FFF) ^ prev_buttons;
    prev_buttons = curr_buttons & 0x0FFF;
   
    while (MARS_SYS_COMM6 == SLAVE_LOCK) ; // wait until slave isn't blocking
    MARS_SYS_COMM6 = MASTER_LOCK; //tell slave to wait
   
    //pause when start is first pressed only
    if (curr_buttons & SEGA_CTRL_START )
    {
        sprintf(keyPressedText,"Key Pressed: Start");
    }
    else if (curr_buttons & SEGA_CTRL_UP )
    {
        sprintf(keyPressedText,"Key Pressed: Up");
    }
    else if (curr_buttons & SEGA_CTRL_DOWN )
    {
        sprintf(keyPressedText,"Key Pressed: Down");   
    }
    else if (curr_buttons & SEGA_CTRL_LEFT )
    {
        sprintf(keyPressedText,"Key Pressed: Left");
    }
    else if (curr_buttons & SEGA_CTRL_RIGHT )
    {
        sprintf(keyPressedText,"Key Pressed: Right");
    }
    else if (curr_buttons & SEGA_CTRL_A)
    {
        sprintf(keyPressedText,"Key Pressed: A");
    }
   
    else if (curr_buttons & SEGA_CTRL_B)
    {
        sprintf(keyPressedText,"Key Pressed: B");
    }
   
    else if (curr_buttons & SEGA_CTRL_C)
    {
        sprintf(keyPressedText,"Key Pressed: C");
    }
   
    MARS_SYS_COMM6 = MASTER_STATUS_OK; //tell slave to resume
}


/*
* Starts application
*/
int main(void)
{
    //
    // Declarations
    //
    int more = 1;
    int frameDelay = 5;
   
   
    MARS_SYS_COMM6 = 0; //init COMM6 for slave
   

   
    //
    // Init Graphics
    //
    mars_init();

   
    //init screen
    Hw32xScreenClear();
    HwMdClearScreen();
    Hw32xSetBGColor(0,0,0,0);
    sprintf(keyPressedText,"Key Pressed: ...");
   
    currentFB = MARS_VDP_FBCTL & MARS_VDP_FS;
   
   
    MARS_SYS_COMM6 = MASTER_STATUS_OK; // tells slave to start
   
    //game loop
    while ( more ) {
        handle_input();
        HwMdClearScreen();

       
        // wait on flip to finish
        while ((MARS_VDP_FBCTL & MARS_VDP_FS) != currentFB) {}
       
        //print paused to screen
        HwMdPuts("Hello World", 0x2000, 16, 14);
        HwMdPuts(keyPressedText, 0x2000, 10, 16);
        //
        // draw to FB
        //
        //redraw background 10*BG_TILE_SIZE
        while (MARS_SYS_COMM6 == SLAVE_LOCK) ; // wait until slave isn't blocking
        MARS_SYS_COMM6 = 4; //tell slave to wait
       
       
       
        MARS_SYS_COMM6 = 1; //tell slave to resume
       

       
        //draw the 32X framebuffer line table with offset of 4
        drawLineTable(4);
       

       
        //flip the FB, without waiting on flip
        currentFB ^= 1;
        MARS_VDP_FBCTL = currentFB;
       
        //do game loo
        //artificially introduce delay
        Hw32xDelay(frameDelay);
    }
   
    HwMdClearScreen ();
    return 0;
} // end of main function



In the main function int main(void), there is a while loop which is where the main action takes place. First when the program initializes it will set various attributes of the 32X and the synchronization between the master CPU running the main.c and slave CPU. The place where any real logic is happening in this game loop are where handle_input(); function is called for each loop iteration. The handle_input() function reads the current control inputs and determines if a button has been pressed, then sets a char[] with some text to say which has been pressed. The place where this gets printed to the output is with the lines:

        HwMdPuts("Hello World", 0x2000, 16, 14);
        HwMdPuts(keyPressedText, 0x2000, 10, 16);


The HwMdPuts() function is a function from hw_32x.h. As the name suggests, this actually is sending a command to the MegaDrive (Md aka Genesis) to print some text to the sprite layer of the Genesis. This is displayed on top of the 32X display output, which was only a black background.

This is certainly not the only way to achieve the same result, if you wished you would be able to create functions to print directly the the 32X display, but it is slightly more involved and get's into the 32X graphics systems. This just shows how you can get a ROM to be build and run in an emulator, as well as offload some processing work to the M68k cpu in the Genesis.

More on how to display graphics in my next installment!

Further reading:

Further references to other simple projects to get you started, courtesy of SpritesMind forums:
32X ROM Template [ASM]
Toolchain with links to several demos program projects

Monday, June 2, 2014

Adventures in 32X Homebrew - Part 1

I have not been posting a lot recently, one of the reasons has been a project that I started in early 2012, which as it never quite reached completion I did not want to let the cat out of the bag with premature posts, more importantly I was a novice in the areas that contributed to this project so to write a bunch of posts without knowing a thing about what I was writing would have been fruitless exercise. This mysterious project consumed my nights and weekends, on and off for at least a year and although I think what I originally intended to do is feasible, I do believe I have learned enough that sharing this knowledge may be useful to someone else, at least as a cautionary tale of things not to do.

As you may conclude from the title of this piece, the subject of my project was the Sega 32X game console, and specifically developing "homebrew" games for it. For the sake of brevity I will refer to all consoles and games by their U.S. titles, for example the Sega Genesis was titled Sega Megadrive in other markets.

Background

Sega 32X

Sega 32X ( was released in 1994 as an add-on unit for the Sega Genesis/Megadrive video game console. The 32X was considered as a way to "upgrade" the 16-bit Genesis to be a 32-bit console without having to buy an entire new console that were starting to enter the market, such as the 3DO, Atari Jaguar and even NeoGeo, this would have been nice for the millions of owners of Genesis unit's with large libraries of existing games that would still be playable on the 32X expansion. In addition, at the time, Sega was already being edged out in the 16-bit console wars by the Super Nintendo (SNES) where games like Donkey Kong Counter, Starfox, Killer Instinct and Final Fantasy 3/VI were beginning to eclipse the Genesis titles visually and even in other areas like game sound and the sheer amount of content. Whether the concept was sound or not, the result was 32-bit capable system that was less powerful than the other 32-bit consoles on the market or the next generation that was coming, the so-called "fifth generation" consoles, of Sega Saturn, Sony Playstation or Nintendo 64.  The result of the release of this console was that while initially popular with American genesis owners, the lack of third party development support and poor quality titles crippled the platform, sales fell when people realized that this wasn't going to get the games that were coming out for the real 32-bit systems. Sega ended up completely pulling the plug on the 32X in 1996 with no new games being released. The saga of the development and release of the 32X in this context is a fascinating story by itself, and excellent accounting of that can be found in Project Mars: Anatomy of a Failure.

I will out myself by admitting to owning the 32X (and still do), and in my blind brand loyalty to Sega I had at the time, tried as hard as I could to like the 32X and the games that were released for it. Looking back with almost 20 years of hindsight, I was rather naive over the state of the market at the time. for one thing, I did not have any subscriptions to gaming magazines at the time, so I really did not have any critical analysis of the 32X, it's expected game library or system specifications and capabilities. I did not recall that the Sega Saturn and Sony Playstation came out so soon after the 32X did. I also remember believing some things initially, don't know where I heard it, such as that the Sega 32X + Sega CD add-ons would create a combined system "equivalent" to the Saturn, even that the games would physically be compatible, or that there was some kind of hardware acceleration for 3D games. I was in school at the time, and couldn't have afforded a Saturn in any case, with my meager part-time home chore income, the idea we could have a 32-bit system instead of a 16-bit one, was very appealing. The initial lineup of games that were released were promising as well, Doom being of the biggest titles, probably one of the biggest PC games at the time, Star Wars Arcade looked incredible, and it was Star Wars! Virtua Racing was another cool 3D polygonal car racing game, that was pretty impressive for the time. Both of these Sega titles I had actually played a few times in Arcades around '94. Again I was not a very educated consumer, I did not go to arcades all that often, while in the 8-bit era, it seemed pretty obvious that arcade games were far superior, as 32-bit era approached, it wasn't clear that the arcades still had far better graphics than what we were going to be getting at home. Even for 16-bit, at the time I was not really sophisticated enough to realize that the Mortal Kombat I played at home was a different experience to the one in the arcades. In any case, the games looked "good enough" and surely, more and better games would be coming out?

Its a trap: Repetitive arcade game play from one of
the best 32X games
Now, I loved Sega at the time, but overall, my impression of the 32X was a major let down, even if I didn't want to admit it. In my opinion, the games were generally just boring, it's hard to pin-point why, I think mainly the game play was lacking, and the 3d effects and fairly limited worlds were underwhelming after a while. For example Virtua Racing Deluxe, had really nice, crisp polygonal graphics in true 3d world with multiple camera angles, decent sound and music, but it in the end, it lacked the rush and thunder of the arcade version, especially after going around the same tracks 2-3 times, there isn't much else going on. I've never been a fan of racing games, but there was only so much you could drive around, and you could never get outside the track and explore. Motocross Championship, was basically like EA's Road Rash series, except the graphics were barely better, the locations were always the same dusty dirt track and the sound effects were particularly terrible. The best 32X game was Star Wars arcade, which again, as an arcade port, was repetitive, fly through hyperspace to an area and chase TIE fighters in circles. Now it was beautiful 3d space environment with asteroid fields and star destroyers, but it did lose it's edge after the 15th tie fighter blew up in a small yellow virtua-explosion off in the distance after 20 other similar laser shots failed to do any damage. I don't think I ever actually made it to the Death Star trench run level. I was also disappointed that you couldn't damage the star destroyers, it was my dream to  blow up their deflector shield domes, ala Return of the Jedi (Intensify forward firepower!....Too Late!!!). I don't think I actually had any other 32X games. I probably played Sonic & Knuckles alone twice as much as all those games combined while I owned that system.

Making Dreams a Reality

So money spent, dreams shattered, I always wished that they made better games for the 32X. Many years later, I had heard that one of the reasons that the games weren't that impressive was due to the developers not utilizing the hardware to it's fullest. Now being a developer myself, I wondered, what if I made the next great 32X game? The context is that I have been interested in gaming and computer programming all my life, I have made some game-ish programs for university courses and I briefly dabbled in libSDL programming on Unix. I have a few game ideas I have been kicking around in notebooks and in my head for years, and it was always a dream to someday put them down into reality. Why the 32X, well it just so happens that the genre's of games I want to make are generally side-scrolling, 2D affairs. For me and probably a generation of gamers, there is nostalgia for games that look and act like the ones we grew up immersing ourselves in on our old sega's and nintendo's. My grand vision was to take some of game story ideas, using genre's that were mostly done in the 16-bit era, and make even better versions of those for the 32X! Not only would these retro games be good in their own-right, they would be unique for being released for one of the most maligned and obscure platforms ever, nobody would be able to compete with me! I own a Sega Genesis and 32X although it had been sitting in a box in my parent's basement for 10 years or so, I planned to eventually resurect it and play my homebrew masterpieces on it one day. So I set out to "teach myself" how to program for 32X and make the best darn game anyone had ever played on that system.

Hardware and Development Environment

The 32X is an interesting piece of hardware, the overall system combined with the Genesis (+ Sega CD) is a complex multi-processor machine with heterogeneous CPU architectures, video processing capabilities, memory spaces, but sharing the main inputs/outputs (Cartridge ROM, controllers, video and audio out). Unfortunately to learn the 32X you have to know at least a little about the way the Genesis works and some of the ways it differs. This is a crucial point to keep in mind for later, because often you'll be amazed by things that Genesis games could do with apparent ease which seem to require vast computing power in the 32X.

There is relatively scant documentation on the internet, and most of it, that does exist is useful as background reading, rather than being actionable step-by-step guides to do anything. There is a small community of homebrew developers who are mostly self-taught, extremely technical and interested in all the bits and bytes of hardware in both the Genesis and 32X. Without their help and guidance I would never have been able to get a Hello World to run on the 32X.

Specifications

CPUs: Dual Hitachi SuperH RISC processers (SH-2, SH7064)
Clock Speed: 23 Mhz
Main Memory: 256Kb SDRAM

Video:
Video Memory: 256Kb (two 128 Kb framebuffers) 

Screen Resolution: 320x224 or 320x240 (PAL)
Color depth: Up to 15 bits, 32768 unique colors, two-bytes per pixel, can use paletted color mode, using up to 256 on-screen colors with one byte per pixel to save memory.

Sound: 

Stereo 2-channel PWM (Pulse Wave Modulation mixer)

And that's about it for the 32X. As I mentioned the 32X combines with the Genesis base, and a 32X game can actually leverage the Genesis hardware in addition to just the 32X components (as well as Sega CD). The Genesis specs are:

CPUs: Motorola 68000
Clock Speed: 7.67 MHz
Main Memory: 64Kb RAM
 

Video:
CPU: Dedicated "Video Display Processor" based on Texas Instruments TMS9918
Video Memory: 64Kb and 64 x 9-bits of CRAM (Color RAM)
Resolution:
Maximum same as 32X, 320x224, 256x224, 320x240 (PAL only), 256x240 (PAL only)
Supports 3 planes, 2 background layers and 1 sprite layer

Sound:
CPU: Z80 @ 4 MHz (Not Present in MK-1631)
Controls PSG (Programmable Sound Generator, TI 76489) & FM (Yamaha YM 2612) Chips
Sound Memory: 8Kb

Cartridge

32X cartridges although physically different are essentially the same as Genesis carts, and can hold typically 4Mb of ROM data although the size of ROM could be larger if used with bank switching capability to access a larger memory space.


Development

  Game software can either be developed in assembly language (a mix of SH2 assembly plus 68000 assembly for Genesis in the same game) or a higher level language such as C that is compiled into machine code for one or the other processor architecture. An "art" of the 32X development is being able to write software for both the Genesis and 32X that can coexist peacefully on the shared hardware.

There are no IDEs, there really isn't a standard SDK, toolkit or any libraries for the 32X available, other than a few home brew examples that are out there. If you can set up an IDE and configure a custom tool chain you may be able to use it to build your C source code into your game. There are appears to be more of a homebrew community for the Genesis. I used a combination of text editors with syntax highlighting and various command line tools and shell scripts for my own build environment which I will cover in Part 2 (coming soon)


Background Resources & Reading


It helps to have an overview of the hardware and reference material handy, there isn't much documentation or specific resources on the web for 32X development, so what is out there is gold.

Collection of Sega 32X Manuals including the most important "32X Hardware Manual".

Reverse engineered introduction to 32X capabilities and hardware.

Devster's site also has a few other documents, example homebrew ROMs and utilities.


"Project Mars: Anatomy of a Failure" – a good overview of the development, marketing and failure of the 32X and the impact it had on Sega.

"Hitachi SH7604 Hardware Manual" – The manufacturers manual for the main RISC CPUs used in the 32X aka SH2, Super-H. Has the details for all of the assembly language instructions for the processors.

Gallery: 32X Development – includes some utilities, assemblers and 32X BIOS files as well as more Hitachi SH2 documentation.



Places to get support


The only places to ask questions about 32X development are a few Sega/gamer enthusiast sites' forums where there is still a small homebrew scene of people who have taught themselves how to program.


Saturday, March 29, 2014

Malicious redirects from this blog (resolved)

Dear readers,

It has recently come to my attention that there was a problem when viewing my blog with javascript enabled in your browser where you would be redirected to some obvious spam/malware/phishing sites (fake Flash or Java download pages). This was happening due to a third party gadget that was part of my Blogger template and apparently had only recently been causing this behavior. My apologies for anyone whose browser was hijacked by this.

These third party gadgets are submitted to Google and available for a blogger to choose to add to their blog's layout template. All indications are that the blog has not been "hacked" and the problem is resolved now.

Information about this problem on the Google support forums seems to indicate that this has happened to many other bloggers as well. If you run a blog, you should remove the Sociable or Share It gadgets as they are known malware gadget.

https://productforums.google.com/d/msg/blogger/aLsGFogJraw/6eU71c8g9ZMJ



Oh Ubuntu, won't you ever win?

After several months of idling in my basement. I decided to fire up the ol' Ubuntu desktop in order to use one of the few apps I have on that OS that I don't currently have an equivalent on Windows. After successfully using the intended software, Ubuntu's Update Manager helpfully notified me that I needed hundreds of critical and recommended updates to software packages. I am fine with that, and figured it wouldn't hurt to update since it had been some months and I expected to need to use Ubuntu again more regularly.

After downloading and installing all the updates, I needed a reboot. After doing so, my desktop wouldn't come up due to errors like this: Xorg says the kernel module is of version 304.88 (The old version before I updated) but the driver components are of version 319.32 (The new version).

This isn't the first time I've gone down that road, and it usually doesn't end well. I don't know why security fixes can bring down the GUI of my desktop. But oh well.

Thankfully, to Google and AskUbuntu, the answer is so simple it brought tears to my weary eyes.

Thanks to a Mr. "Joren" for the solution:
 
First remove all the old drivers:
sudo apt-get purge nvidia*
Then reinstall the current drivers:
sudo apt-get install nvidia-current
Reboot, and your're good to go!
sudo reboot 

Worked like a charm.
 

Source: http://askubuntu.com/questions/349129/12-04-lts-wont-boot-after-nvidia-driver-upgrade