Space Invaders!

Posted by Astryl on June 20, 2013, 4:42 a.m.

Official Chip8 Roms working in my emulator:

Words cannot accurately describe how awesome it feels to load a ROM and it works…

Hi guys. Decided to write another blog before I potentially disappear from the face of the world for three months. Which now depends on whether the people who needed me to look after that house for them go on their vacation or not.

Anyway, I've been doing having trouble working with game development recently. No such problem though when it comes to making useless things that aren't really needed…

On that note, I've been studying various CPU architectures, emulation techniques, and VMs, mostly because they're interesting. And thus, at some unknown hour on I-forget-which-day-sometime-last-week, I decided to write an emulator… or a VM, actually.

I chose the CHIP8 system, one of the earlier VMs designed for game development on a couple of old computers (The VIP something or other and one of the RC1805 based systems). Later, this became the S-CHIP system that was eventually used in several graphing calculators.

Anyway, the CHIP8 has a few simple specs. It is limited to 4K of memory, has a very low resolution of 64x32 pixels, monotone (On and off, basically). It only has 35 opcodes.

Interestingly for an 8-bit system, it has 16 general purpose registers. This means that with a bit of clever programming, you can combine registers to work with larger numbers. At the same time, it has built in sprite handling (Bit sprites. Each byte is a line of the sprite, since these are essentially 1 bit images).

Let me not ramble too much about it. I didn't actually get around to writing the emulator. Though I did write something… an assembler for the system; because obviously if I'm going to bother writing an emulator, I want to be able to write my own code for it too :P

I took some liberty when designing the language. There are several basic directives that don't make it to the binary. One of these is EQU, which I have chosen to treat similarly to C's #define pre-processor directive, via substitution during the assembly.

I added a couple of 'fake' keywords that improve code readability too, such as an END keyword that helps when working with loops.

Anyway, here's a bit of sample code:

; Test code for both ASM8 and EMUL8
; Does something really simple (Adds numbers, loops)

EQU random_var 0x200

SUBROUTINE add_loop
	ADD V1 V4 ; Adds contents of V4 to V1
ENDSUB ; Fake keyword

; Main program begins here.

MAIN 
SET V1 0x00
SET V4 0x01

LABEL lp1
	CALLSUB add_loop
	JMP lp1
END 

The MAIN directive causes the assembler to add the offset of the instruction following MAIN to be stored in the symbol table, and a JMP <address of main> opcode is added to the beginning of the code (With all offsets shifted by one, naturally).

This allows for easier program design, in my opinion, allowing me to have the subroutines wherever I want them.

Interesting little factoid about the hex numbers. I had to write a simple parser that could convert them from strings to numbers.

This is done in two parts. First is a function that's basically a giant switch statement. In hindsight, this should be a lookup table. Though I'm not optimizing for speed here.

int get_num_from_hex(char c)
{
    switch(c)
    {
    case '0':
        return 0;
    case '1':
        return 1;
    case '2':
        return 2;
    case '3':
        return 3;
    case '4':
        return 4;
    case '5':
        return 5;
    case '6':
        return 6;
    case '7':
        return 7;
    case '8':
        return 8;
    case '9':
        return 9;
    case 'A':
        return 10;
    case 'B':
        return 11;
    case 'C':
        return 12;
    case 'D':
        return 13;
    case 'E':
        return 14;
    case 'F':
        return 15;
    case 'a':
        return 10;
    case 'b':
        return 11;
    case 'c':
        return 12;
    case 'd':
        return 13;
    case 'e':
        return 14;
    case 'f':
        return 15;
    default:
        return 0;
    }
}

It basically takes a char, returns the value required. Simple enough.

The second part of the code is basically a string parser. I work backwards from the end of the string to make things easier.

word str_to_hex(string in)
{
    // Parses an input hex string into it's decimal equivalent.
    word t = 0;
    int base = 1;

    // First check that this -is- hex. Return it's value immediately otherwise.
    bool ishex = false;
    for(unsigned int i = 0; i < in.length(); i++)
    {
        if(in[[i] == 'x' || in[[i] == 'X' || in[[i] == 'h' || in[[i] == 'H')ishex = true;
    }

    if(!ishex)
    {
        t = atoi(in.c_str());
        return t;
    }

    for(unsigned int i = in.length()-1; i >= 0; i--)
    {

        if(in[i] == 'x' || in[i] == 'X')break;
        if(in[i] == 'h' || in[i] == 'H')continue; // For the 000h style numbers.

        int v = get_num_from_hex(in[[i]);
        t += (v)*(base);
        base <<= 4;
    }
    return t;
}

This works on both common hex representations (0x000 and 000h). Knowing the language, there was probably a stupidly simple standard library or Boost function that does this conversion that I forgot about, but knowing me, I enjoyed making it myself.

Anyway… I have some amusing plans for this. I want to make a Java VM for the S-CHIP soon, and work on adding it to Minecraft as a 'wrist' computer, fully programmable in-game. Just the kind of project I like.

Well I forgot what the rest of this blog was going to be about… so I'll close it off for now.

Comments

Pirate-rob 11 years, 3 months ago

This is pretty cool, has the assembler been made already or are you still busy?

Astryl 11 years, 3 months ago

The assembler is complete, and I finished the emulator itself last night, and have been running tests on it. My next test is going to be running some of the official ROMS for the system, and seeing if they work.

Screenshot:

Cesque 11 years, 3 months ago

I read your blog, but I don't know shit about emulation, so I had nothing to say.

But now that you're a successful creator of emulators, could you make me a PS2 emulator that can run the Shadow of the Colossus .iso at a decent framerate?

Thanks.

JuurianChi 11 years, 3 months ago

Quote:
But now that you're a successful creator of emulators, could you make me a PS2 emulator that can run the Shadow of the Colossus .iso at a decent framerate?

Running it now at 48FPS

:SWAG:

Unaligned 11 years, 3 months ago

Quote: Cesque
I read your blog, but I don't know shit about emulation, so I had nothing to say.
Regardless, in my own completely uninformed opinion, I think it's pretty cool.

Astryl 11 years, 3 months ago

Quote:
But now that you're a successful creator of emulators, could you make me a PS2 emulator that can run the Shadow of the Colossus .iso at a decent framerate?

Sure, just deposit your soul in the self-addressed envelope I'm posting to you now. Ignore the red, it isn't blood…

On a serious note, nope.

panzercretin 11 years, 3 months ago

Quote:
But now that you're a susemulcrator

fix'd

Astryl 11 years, 3 months ago

Quote:
susemulcrator

I have spent the afternoon trying to decipher what two or more words of the English language could conjoin to possibly come up with this….

aeron 11 years, 3 months ago

Nice progress! But emulation is too slow these days, you should work on making it a dynamic recompiler so I can play my chip8 collection at slightly closer-to-native speeds.

/me doesn't actually have a chip8 collection, /s

Astryl 11 years, 3 months ago

Heh. Well, since the Chip8 runs at 60hz, I'll assume you're running a Commodore 64. :P