Something simple to emulate


I think Chip8 was a pretty good suggestion to get some quick satisfaction, learn a few 'obvious' things, and get prepared for something a bit more interesting. So thanks for the suggestion and I certainly would recommend anyone interested who hasn't written an emulator before to dive in and have a go. Maybe if a bunch of people did this, in a bunch of months/years (or perhaps decades in my case) we might have a bunch more people on the boards working on cool emulators (that people actually want to use)!
Congrats, now next logical strep would be to try something more serious like Saturn or the joyful fun of Megadrive+MegaCD+32X combo. 5+ CPUs, bunch of custom chips with incomplete documentation all running at the same time, all for your synchronization enjoyment. Try to make it perfect, and you won't be bored for the rest of your life!
But that's the whole bloody point, is it not? The fact that your users can play games is a side-effect of your crusade to perfect the emulation and hardware synch. Admit it :)

D.
 
@notaz I am sure you are joking, but just in case any offence was taken, my suggestion that Chip8 is a step towards doing useful emulators like the ones you have done was really meant as one very very very very very tiny step towards emulating something useful, so maybe in a decade after Chip8 something useful may come! But then again, going on my next problem (below) even a decade might be too short...

I thought I should get Chip8 running at the right speed, and after scratching my head for a while, I haven't come up with a way to do it. Assuming it is going to be something obvious and easy, but can't quite think what yet. For a system that syncs to a TV at 60Hz there is a pretty clear way to keep in sync (on a per frame level at least). But for Chip8, it seems when you draw, it is meant to draw to the screen right away, so I can't sync on draw. I thought I could just process one instruction then sleep, but obviously that doesn't work if SDL_GetTicks has accuracy in milliseconds (as does SDL_Delay probably).

I thought that if the Chip8 runs at 0.6 MHz (600,000Hz), then I could emulate 1/60th of this, so emulate 10000 instructions and then wait draw/sync to 60hz. But I'm not sure this is working. Something obvious I am missing?
 
I think Chip8 was a pretty good suggestion to get some quick satisfaction, learn a few 'obvious' things, and get prepared for something a bit more interesting. So thanks for the suggestion and I certainly would recommend anyone interested who hasn't written an emulator before to dive in and have a go. Maybe if a bunch of people did this, in a bunch of months/years (or perhaps decades in my case) we might have a bunch more people on the boards working on cool emulators (that people actually want to use)!
Congrats, now next logical strep would be to try something more serious like Saturn or the joyful fun of Megadrive+MegaCD+32X combo. 5+ CPUs, bunch of custom chips with incomplete documentation all running at the same time, all for your synchronization enjoyment. Try to make it perfect, and you won't be bored for the rest of your life!
Hmmmm must not read too much into this...

...

...Just to clarify - Notaz, you are not working on a Saturn emulator on the sly? :p
 
I thought that if the Chip8 runs at 0.6 MHz (600,000Hz), then I could emulate 1/60th of this, so emulate 10000 instructions and then wait draw/sync to 60hz. But I'm not sure this is working. Something obvious I am missing?
Each instruction takes a set time to run. Emulate the correct number of instructions for a frame. I use 15. At the end of the frame, signal a display update. I use a timer that triggers every 20ms (50Hz in the UK), it emulates the required instructions and then if the display requires an update you go for it.

D.
 
Ah, thanks, implemented that, speed seems reasonable now (haven't tested it particularly thoroughly). Has sound and stuff in now, all instructions implemented. Only tested a couple of ROMs so will need to test a few more. Code/data/project all on repository, source code here:

https://github.com/Scraft/chip8emulator/blob/master/src/main.cpp

Can't remember if there was anything else I wanted to add/fix, or whether that is Chip8 finished for now, ready to move onto something more exciting!
 
Can't remember if there was anything else I wanted to add/fix, or whether that is Chip8 finished for now, ready to move onto something more exciting!
Take it steady - pick something with a CPU clocked at 1MHz - 4MHz that you enjoyed as a kid. Then aim to get the boot-up sequence done, then the user interface (if there was one) working. After that, you can move onto something more complex, or start to optimise and add more esoteric behaviours.

Once you have that under your belt, you're flying.

D.
 
As someone else said, this topic is very inspiring. I've also coded up a chip-8 emulator in the past days because of this thread.

But it's a very simple task, all of the opcodes are listed on the wikipedia link etc.

I'd like to try something a bit more advanced, a system I played and had so much fun with was the Philips VideoPac G7000, or Magnavox Odyssey 2 as called in the US.

Where do I find detailed hardware-related info that I would need to put up a plan on how to start out?

Maybe the system is too advanced for me at this stage.. I'd still like to give it a shot. ;)

edit: found some stuff here http://atarihq.com/danb/o2.shtml
 
Last edited by a moderator:
@Burb Fantastic - feel free to post your progress, thoughts, difficulties, videos etc. for your emulation to this thread if you like (obviously you are welcome to start another thread, but I certainly don't mind if this thread becomes a dumping ground for anyone experimenting with emulation work).

For what it is worth, I hadn't heard of the Magnavox Odyssey 2 before (don't hate me), but this video had a nice summary of a few games:

https://www.youtube.com/watch?v=EuXlNfgtPqI

I look forward to seeing your progress!
 
So, after 'completing' my Chip8 emulator (I only actually tested 2 or 3 ROMs on it, which all seemed fine, so enough for me, but possibly not complete), I had a little downtime, but have recently started working on a Intel 8080 CPU emulator. Specifically, I am going to start by (attempting) to emulate the original Space Invaders. I have emulated 25% of the instructions so far (no idea if I've done it correctly yet!), also I haven't started work on the status flags yet. So, all in all (taking into account debugging, and the fact this is a fair bit more complicated than Chip8) I reckon I'm about 10% of the way through this project. I haven't bothered keeping a developer diary for this one, but so far have just been following the same steps as with my Chip8 emulator, and have spent an evening getting started.

I was put onto trying the 8080 next as someone said:

If you think CHIP8 is too easy, or GameBoy/NES/MasterSystem is too hard, writing a Space Invaders emulator is not
I would love to be writing a GameBoy/NES/MasterSystem emulator (GameBoy and MasterSystem in particular, as both have games I would play through in my own emulator), but feel they are quite a stretch after the simple Chip8 experiment, so 8080 next and then see where I can go from there...

If anyone else cares to join me (not collaboratively) and also write a 8080 emulator, I can provide links for the data I am working from (8080ds.pdf, 8080_Data_Sheet.pdf and http://www.emutalk.net/threads/38177-Space-Invaders?s=e949e144f5c3d855d5c8534070d9be79 being a good starting point).
 
Last edited by a moderator:
Space Invaders is a good choice. It's real hardware but very single purpose, just have to worry about debugging one game. I see you found the emutalk thread so I don't have to link it.. that should be more than enough.

Gameboy or SMS/GG would be a good step after Space Invaders since they use processors that extend 8080. I'd recommend SMS over Gameboy if you want the simpler of the two.
 
8080 is an excellent choice. Someone has written a Space Invaders emulator in PandaBAS, which was quite surprising... And is a good launchpad towards more complex systems.

D.
 
Space Invaders was my first emu; wrote the cpu emu and the arcade game emu .. the mono bitmapped display was great fun to work through :) Simple sound system as well. Not too sensitive to timing issues either, due to the way video is generated.

(Sound was always a weak side for me; you often just want to run some batch of opcodes and then update the display.. piece of cake, works fine; but with audio, you can end up missing audio events or timing them wrong, and the ear picks up on these things .. so if you want to emulate audio, you're either emualting real time, or you're doing audio-event logging (say), so that if you run a batch of opcodes, you can generate audio for some period of time and still have the timing and audio instructions right, etc..)

Anyway, cool stuff you picked SI :)

(I've got a couple SI arcade boardsets, so I was comparing to the hardware, and modifying the hw ROMs to see what would happen etc.)

After SI, I went to Phoenix I think, since it used a character based background and sprite system (and then to Galaxian, with a more proper sprite system.)

Good times..

Good luck with it all; its not too hard at all to write an SI emulator, but its great fun. The processor is one of the first 'real processors', reasonably complex, but not too complex.

jeff

(and as luck would have it, I'm building my own retro computer from scratch, and currently working on a Z80 based design; the Z80 is essentially an 8080 with some bonuses tossed in, so after all these years, I'm working in z80 assembly again :p (and 6809 and 6502 a bit as well, since the machine designs are similar.) You can sometimes never escape your past :p
 
I had a little more of a mess around in the code today at lunchtime, mostly everything is looking good. A couple of things (will be obvious to you guys I'm sure), I am not completely sure about (both to do with flags):

  • I need to set the parity flag for certain instructions, I have currently stolen some code to generate a parity table (see spoiler below), does this seem like a sensible way to do it? I kind of feel there should be something more elegant, but the solutions I found from Google all looked a bit weird and I didn't fancy using them as if they didn't work right I wouldn't know and would just end up with a dud implementation.
  • I need to set the auxiliary carry flag correctly. I think my biggest issue is not really being familiar with BCD, for which I should probably become more familiar (I have a feeling it is something that should have been taught sometime during my educations, although I've got thus far without worrying about it so maybe it isn't so bad). Anyway, my understanding of the auxiliary carry flag is that if an addition takes place, where the lower nibble (bits 0-3) of each value added together exceed 0xf, and thus set bit 4, the AC flag is set (otherwise it is reset). Does that sound right? If so, I understand from the documentation that I also need to set this flag when performing a decrement, would the logic here be that if the two lower nibbles subtracted from each other equals a negative value, then the AC flag is set? So something like: 0x10 - 0x1 = 0xf, or in binary: 0b00010000 - 0b0000001 = 0xf, although subtraction yields a positive result, the lower nibble (by itself) would require a carry.
Thanks for the help; I appreciate I could just look at source code for someone elses 8080 emulator, but I really want to avoid doing that, I want to just have all my own code, without other ideas coming in, with the view to review other peoples code once I'm done (which is exactly what I did with the Chip8 emulator).

Parity table:

static const bool ParityTable256[ 256 ] =
{
# define ParityTable256_2(n) n, n^1, n^1, n
# define ParityTable256_4(n) ParityTable256_2(n), ParityTable256_2(n^1), ParityTable256_2(n^1), ParityTable256_2(n)
# define ParityTable256_6(n) ParityTable256_4(n), ParityTable256_4(n^1), ParityTable256_4(n^1), ParityTable256_4(n)
ParityTable256_6(0), ParityTable256_6(1), ParityTable256_6(1), ParityTable256_6(0)
# undef ParityTable256_6
# undef ParityTable256_4
# undef ParityTable256_2
};

EDIT: For what it is worth, my WIP source is here, https://github.com/Scraft/8080emulator/blob/master/src/main.cpp it is basically just a copy + paste from my Chip8Emulator, with the instruction switch statement being updated. Until I am finished it probably isn't worth any critiquing...
 
Last edited by a moderator:
You can do parity with a GCC intrinsic if you're okay with limiting portability:

Code:
__builtin_parity(value)
 
Last edited by a moderator:
Hmm, calculating parity is pretty simple

boolean parity_2(int n){
return (n&1)^(n>>1)
}
boolean parity_4(int n){
return parity_2((n&3)^(n>>2))
}
boolean parity_8(int n){
return parity_4((n&15)^(n>>4))
}(my C may be a little rusty - it's a long time since I've seriously coded in it)

That should compile down to 12 instructions on even the most primitive processor (I reckon it'd fit in 6 instructions on the Pandora's ARM CPU). Depending on where the lookup table resides in the various caches, it might take longer than that to do a lookup.


GCC's __builtin_parity should be no worse than that, but the above code should port to almost anything supported by a C compiler.
 
Last edited by a moderator:
So, I have moved along a little bit, after hitting the debugger for a while, the first glimpse of graphics on screen:

oj1kx5.png

 

At the moment the text draws to screen, one character at a time, and stops after 'PLA', so obviously not there yet, but I am happy to see something on screen.

I'm not sure what lessons I have learned so far on this, seem to have made a few minor mistakes implementing opcodes (to be expected), made a couple of sillier errors when setting up structures for registers, and had a very stupid misunderstanding about byte layout on the machine I am on*. I guess the main thing I have had to do a lot more of with this so far is debugging (the Chip8Emulator didn't require too much, the only issues that came up I resolved very quickly, but this time I've had to do a fair bit of stepping through diassembly working out what the code is meant to be doing, and what could potentially be going wrong). Obviously there are a lot more instructions on 8080 vs Chip8 so lots more potential to get things wrong.

Will keep plodding on and hope to get a bit further and do another update.

*For some reason I was thinking that a union { u8 regs[ 2 ]; u16 regPairs[ 1 ] }; would mean that regs[ 0 ] sets the higher byte of regPairs[ 0 ] (and regs[ 1 ] would set the lower). 
 
Last edited by a moderator:
Back
Top