Discuss Scratch

DCPU-16
Scratcher
100+ posts

gbc.sb2 - Emulation in Scratch


http://phosphorus.github.io/#53005142 (much faster than flash player)
http://scratch.mit.edu/projects/53005142/

In February 2013 I started working on a gameboy emulator written entirely in Scratch, just to see if I could get such a thing working. I was pretty busy with other things throught the rest of the year, so I didn't get much of a chance to look into some of the worse problems with it. More recently I worked out a halt skip function for a version of the emulator in another source language, which prompted me to try it in scratch to see how it performed.

Right now the emulator is very slow on the flash Scratch player - most games only run 10% of the intended speed with idle skipping, slower without it. (and this is with frame skipping to only render every 4th frame!) A few places can be cleaned up, but things unfortunately aren't as encouraging as I would have liked.

Supports:
  • Fully passes Blargg's CPU Tests.

  • Importing any ROM.

  • Video Display with BG, sprites and Window.

  • Input!

  • Supports all instructions and interrupts.

  • Idle skipping for halt - improves performance greatly for simple games like Pokémon.

  • MBC 1, 3 and 5 games. There still may be some bugs in the MBC code.

  • Skipping the BIOS.


Issues:
  • It is impossible to render sprites in the “behind colors above 0” mode with the current setup.

  • Sprites currently do not render behind the bg and window layers.

  • Sprite rendering currently cycles through all 40 sprites every scanline, this can probably be simplified by implementing a few tricks in the OAM.

  • Right now I am compiling the tiles to a faster to render format when writing to the VRAM (slow initial step, but much faster for drawing) which encodes a list of colours and lengths for each horizontal line in all tiles. The rendering becomes faster because of instead of drawing individual pixels for filled tiles we can simply draw lines - however this leaves little room for per pixel manipulation, so implementing certain things may prove to be difficult in future.

  • The instruction lookup still uses a huge if/else chain that goes up to 31 (!) deep. I have a solution to this outlined below, thanks to something @gtoal brought to my attention.

  • The sound emulation is currently very primitive.

  • Halt skipping has a few small problems, specifically with rendering.

  • Memory access also has the if/else problem, which can probably solved in a similar manner.

Screenshots:



(Pre 1.2):



(pictured above: stairs bug in Pokemon Red)




Feel free to ask questions here, post suggestions and fork the emulator code.

Last edited by DCPU-16 (March 18, 2015 02:49:58)

bobbybee
Scratcher
1000+ posts

gbc.sb2 - Emulation in Scratch

All I can say is wow.

“Ooo, can I call you Señorita Bee?” ~Chibi-Matoran
elfin8er
Scratcher
100+ posts

gbc.sb2 - Emulation in Scratch

Holy… um… what can I say here… cow? This is amazing man! I guess this is pretty much a 16 bit computer? You should make a 16 bit computer in Scratch, and make it (somewhat) easy to program. That's be pretty neat!
blob8108
Scratcher
1000+ posts

gbc.sb2 - Emulation in Scratch

elfin8er wrote:

You should make a 16 bit computer in Scratch
DCPU-16's already done that.

tosh · slowly becoming a grown-up adult and very confused about it
elfin8er
Scratcher
100+ posts

gbc.sb2 - Emulation in Scratch

blob8108 wrote:

elfin8er wrote:

You should make a 16 bit computer in Scratch
DCPU-16's already done that.
Daaaang! DCPU-16 made a DCPU-16 in Scratch. What if DCPU-16 made a DCPU-16 on a DCPU-16? Or has he done that too? :O
DCPU-16
Scratcher
100+ posts

gbc.sb2 - Emulation in Scratch

The DCPU-16 is an imaginary machine with an incredibly low clock speed for its feature set, and has no I/O, which is why the emulator runs so fast. A real 16 bit CPU, such as ones uses in the SNES or 1980s sega systems will require a lot more horsepower than that and a gameboy cpu.
DCPU-16
Scratcher
100+ posts

gbc.sb2 - Emulation in Scratch

With various improvements along with the list replace fix here: http://scratch.mit.edu/discuss/topic/60388/, the Dr. Mario menu music is playing at about half speed with the gfx disabled (still got some optimisations planned!). I'll most likely update the project when the replace fix hits the public.
DCPU-16
Scratcher
100+ posts

gbc.sb2 - Emulation in Scratch

Here is the result of working on optimizing the CPU emulation and fully implementing audio (minus noise channel, and wave is just another square):

Realtime (lasts 6 minutes, about half of real gb speed):
https://dl.dropboxusercontent.com/u/12239448/gbrc/slow.ogg

2x sped up to normal speed (lasts about 3 minutes, better to listen to!):
https://dl.dropboxusercontent.com/u/12239448/gbrc/normal.ogg

These contain snippets from the 3 themes included in Dr Mario, recorded with display rendering off in the menu screen. The next goal is to improve the render speed and work on a few per cycle improvements that I've recently thought of.
DCPU-16
Scratcher
100+ posts

gbc.sb2 - Emulation in Scratch

Version 1.1: http://scratch.mit.edu/projects/31903442/

Adds full support for audio channels that are not noise, and is also much faster due to the inclusion of the previously mentioned instruction lookup improvements (plus an improvement to line cycle processing!)

Unfortunately, there is still a bug in the CPU that I haven't found which is causing unexpected behaviour, like the stairs not working in pokemon red and all of the cpu tests failing. There is also room for more performance improvement in the rendering, memory and individual instruction procedures.
novice27b
Scratcher
1000+ posts

gbc.sb2 - Emulation in Scratch

I have almost finished a CHIP-8 emulator in JavaScript, so I might port it to scratch when i'm done. How do you debug your emulators?

i use arch btw
DCPU-16
Scratcher
100+ posts

gbc.sb2 - Emulation in Scratch

In javascript I use the ‘debugger;’ command in places I believe the problem lies, then look through the stack to determine where the problem has occurred. I also double check the implementations of various functions with their documented descriptions to see if I missed anything. If the documentation is lacking, it's always good to do tests on real hardware, though I was not able to do this for the gb emulator.

In scratch things become much more difficult. To see if functions/conditions are called you can always play a simple pop sound when they are run. You can also stop all scripts to check the machine state at the time you'd normally use ‘debugger;’, but you won't be able to resume the code afterwards eg. if the problem doesn't happen on the first call, but instead you'd like to check the third. It is generally much harder to debug things in scratch…

It's also useful to check the disassembly (or ideally, the source) of broken programs so that you can identify where the problem occurs in the actual machine code, then trace that back to a problematic instruction, memory address or other behaviour. I have done this extensively with blargg's gameboy hardware tests, and it'll probably help me find the bug with my scratch port too.
JamesOuO
Scratcher
500+ posts

gbc.sb2 - Emulation in Scratch

How do you make the different wavetypes with the play note blocks? I would really love to incorporate them in a famitracker-like project!

GrannyCookies
Scratcher
100+ posts

gbc.sb2 - Emulation in Scratch

Wow…

DCPU-16
Scratcher
100+ posts

gbc.sb2 - Emulation in Scratch

JamesOuO wrote:

How do you make the different wavetypes with the play note blocks? I would really love to incorporate them in a famitracker-like project!
Synth lead is a square wave, so I'm using that for the two square channels and the wave channel. Unfortunately, it's not possible to use custom waves for the play note blocks - so I'm not able to correctly simulate the specific wave they want to play (triangle wave in dr mario, pikachu voice in pokemon yellow (though that's more of an atomic volume switching problem!))

Because the square wave in scratch has no fade out or cutoff, I can play it indefinitely until the frequency changes and just change the volume.
gtoal
Scratcher
1000+ posts

gbc.sb2 - Emulation in Scratch

DCPU-16 wrote:

To see if functions/conditions are called you can always play a simple pop sound when they are run. You can also stop all scripts to check the machine state at the time you'd normally use ‘debugger;’, but you won't be able to resume the code afterwards eg. if the problem doesn't happen on the first call, but instead you'd like to check the third. It is generally much harder to debug things in scratch…

It's also useful to check the disassembly (or ideally, the source) of broken programs so that you can identify where the problem occurs in the actual machine code, then trace that back to a problematic instruction, memory address or other behaviour. I have done this extensively with blargg's gameboy hardware tests, and it'll probably help me find the bug with my scratch port too.

If you have a working emulator on another system, do this:

Identify an area in your emulated program that you want to start debugging (eg by PC value)

Write out the value of all the registers after executing each instruction

Load this array into your emulator

At the same trigger point, start comparing the values of the registers in the Scratch emulation to those in the recording from the working emulator

Wherever you get the first mismatch, that's probably where you're not emulating an instruction properly

If your program requires user input, have the working program on the other system record whenever a use input changes and store it along with a cycle count - replay the user input when testing so that it happens on the known exact cycle every time you test rather than relying on human timing. This makes comparing two runs of the same program much easier. Same input means same output. If the output differs, you've either fixed something or broken something :-)

Another useful thing to add is a pop-over text window with a disassembly and single-step/debug options. (IE a debugger for the emulated machine, not for the Scratch code)

Graham

Last edited by gtoal (Nov. 2, 2014 22:58:28)

DCPU-16
Scratcher
100+ posts

gbc.sb2 - Emulation in Scratch

That sounds like a fantastic idea, I'll give that a shot! I completely forgot about debugging via single step as well, since usually I just step through with a realtime debugger anyways.

Last edited by DCPU-16 (Nov. 2, 2014 23:42:35)

DCPU-16
Scratcher
100+ posts

gbc.sb2 - Emulation in Scratch

One flaw with the first method - slightly different timings are causing the display to desync, resulting in me being unable to find the actual problematic instruction. Unfortunately the timing needs to be completely matched between both emulators to test in this manner… I've even went through all instructions, corrected their timings and I'm still getting a 10 cycle or so desync…

Also, due to the volume of data I could only capture one set of the registers+PC+SP every 10 instructions or so - any more and the output data would be too large to handle reasonably.
gtoal
Scratcher
1000+ posts

gbc.sb2 - Emulation in Scratch

DCPU-16 wrote:

Also, due to the volume of data I could only capture one set of the registers+PC+SP every 10 instructions or so - any more and the output data would be too large to handle reasonably.

Record only the changes and the cycle count when they change. Then apply the changes to your shadow register set at the same cycle counts. That should get the size down considerably.

G
DCPU-16
Scratcher
100+ posts

gbc.sb2 - Emulation in Scratch

I'm getting ridiculous performance with nathan's phosphorus player, now that the bug stopping it from running has been fixed:

https://phosphorus.herokuapp.com/#34791164

Powered by DjangoBB