PDA

View Full Version : Game Boy



Pages : 1 2 3 [4] 5

aprentice
October 19th, 2005, 19:25
Bigger sample sizes simply give you higher resolution for the relative amplitude/volume of the wave. You can multiply/leftshift the sample to get a louder output.

The frequency of the sound wave usually refers to the time it takes for it to complete one oscillation (going from high to low and high again). A higher frequency will give a lighter tone, and a lower frequency will give a darker tone. A sample represents the amplitude of a position in the wave. In other words, if every alternating sample you output has a low value while the next one has a high value, you'll get a really high pitched square wave.

Now, if the game boy was sample-based, it would have something like a sample rate of 4194304/2=2097152 Hz. Your task will be to downsample this to the sample rate of the output. Probably the most crude way to do this, is to genereate a sample for every 2097152/SAMPLERATE Hz. A better way is to account for all samples, using a form of interpolation. Linear interpolation should be fine in most cases.

I'm sure what you're saying right now makes sense to you since you apparently mastered this stuff but to me it makes little sense, did you use direct sound for your emulator?

Each gameboy sample is 4 bits, and in direct sound i have it set up as 16 bits for each sample, so am i suppose to shift 8 or 12 bits to make it louder? And do i have to do anything to each sample to control the frequency because i see direct sound has a SetFrequency function but that wouldnt control it for every sample..

bcrew1375
October 19th, 2005, 22:45
Dark Stalker, I noticed your emulator has one of the same problems with Donkey Kong as mine. It shows a white blank area at the bottom where the status screen should be when you complete a level. Any idea what might be causing it? Also, I'm surprised that you already have the sound down. I've noticed a few jerks in it, but other than that it sounds great.

Dark Stalker
October 19th, 2005, 23:39
(By "amplitude value" I really mean the position on the y-axis of a typical wave-drawing. I can't find the right term, and in a square wave the displacement is always as big as the amplitude anyway.)


I'm sure what you're saying right now makes sense to you since you apparently mastered this stuff but to me it makes little sense, did you use direct sound for your emulator?
I used SDL, which wraps around DirectSound on windows.


Each gameboy sample is 4 bits, and in direct sound i have it set up as 16 bits for each sample, so am i suppose to shift 8 or 12 bits to make it louder?
There is no such thing as an actual game boy sample (unless you refer to ch3). The amplitude of the waves generated by each channel indeed has a range of 0-15. Additionally there is the output level of SO1 and SO2 which range from 0-7, which the final amplitude will be multiplied by. The value of a sample represents the "amplitude value" of a position in the sound wave. If you multiply each sample's value, you will get a louder output. There's no rule for what's the right average volume of the output, as long as one sample isn't amplified more than another. That said, I'm currently multiplying the value of the individual samples I'm generating by 64, since that seems to yield an overall volume similar to most other things outputting sound on my comp.


And do i have to do anything to each sample to control the frequency because i see direct sound has a SetFrequency function but that wouldnt control it for every sample..
No, you don't. As I said, each sample only represents an "amplitude value". Frequency refers to how often this value changes. The sample rate is how often a new sample is generated/expected (typically 44100 Hz). Generally, the higher the sample rate, the more accurate the representation of the sound wave, since you can support more fine grained changes and higher frequencies. What matters for the notes of the melody is how often the values of the samples you output change from high to low (and back). If you ignore a channel's volume/amplitude/envelope register, and just use a fixed value, you will generally still be able to produce the notes of the melody. You need to keep counters for how many high/low samples you've outputted depending on the frequency (and wave duty) of the channel.



Dark Stalker, I noticed your emulator has one of the same problems with Donkey Kong as mine. It shows a white blank area at the bottom where the status screen should be when you complete a level. Any idea what might be causing it? Also, I'm surprised that you already have the sound down. I've noticed a few jerks in it, but other than that it sounds great.
No, I haven't tested that game. Thanks for letting me know. What kind of sound jerks? Some of them are supposed to be there... :P

Dark Stalker
October 20th, 2005, 04:46
Tada! :P
http://home.tussa.com/iaamaas/screenshots/lameboy/dk.png

It seems that if the window is enabled, then disabled, and enabled again later the same frame, it will continue drawing from the same position in the tile map.

ShizZy
October 20th, 2005, 04:51
Nice work :P I don't know how you do it. About 3 commercial games run for me, but I don't no how or where to look for bugs. There's got to be tons of them. I'll spend hours without any luck. Any tricks?

Dark Stalker
October 20th, 2005, 07:46
More fixes for Donkey Kong: It appears that Donkey Kong was treating my emu as an sgb. This made some garbage appear on startup, and made the princess mute. The reason was that the game expects the unusable bits (6 and 7) of 0xFF00 to be set. The game did "ld a,(ff00); cp a,ff; jrnz;" which always ended in a jump.

ShizZie: I'm afraid there aren't any tricks. I usually try to find something that affects the bug as a starting point. Sometimes it's just easier to guess where to look than other times.

ShizZy
October 20th, 2005, 21:00
Alrighty thanks, I'll see if I have some better luck later tonight.

truth2
October 20th, 2005, 21:41
Well... I'd like to say that I recently started writing a GB emu and it didn't progress very well, but I can't.
I started writing the emu way back in September (although I did do a few large pauses and rewrote the whole thing from scratch twice) and now, it's pretty basic:

i have:
all GB opcodes are (hopefully) supported
all IO except sound and serial (hopefully) works correctly
video display (hopefully) works decently:
backgrounds are (hopefully) fully supported
windows might lack some special 'effects', not sure
sprites are so-so supported, but im sure there are priority issues

i dont have:
sound, serial and sgb (and i won't be doing that till/unless everything else will be mostly fine, and even then it's doubtful)
gbc (meh... maybe when most gb stuff is working)
nice features (savestates, non-violent user interface, etc..)
correct timing - im sure lots of my timing is brutally incorrect.
mbc (im currently working on this, but im getting kinda stuck...)

meh...

ShizZy
October 21st, 2005, 01:42
Nice... get it working and post some shots :P

truth2
October 21st, 2005, 02:11
Nice what?
And apperantely I got some CPU bugs too, because some othello game (the only commerical game I could find that is not using MBC) decided to take the scenic route through the code, passing through a few illegal opcodes (i didn't bother making the emulator stop when such are reached) and ending up in a nice loop of ff's
also the Big Scrolling Demo is acting weird : sometimes it does shows too much of the "cubes" background and too little of the "text" background, and sometimes the opposite...

i just tried tetris and it gives me a weird screen (white on top, black on bottom, nothing else) and when i checked my half assed debugger, it also got stuck in a loop of ff's.

ShizZy
October 21st, 2005, 04:09
Nice job on getting what you have gotten done so far. Try Asteroids, it doesn't use MBC and it runs fairly easily. You can also try Amida, Boxxle,Boulder Dash, Castelian, Motorcross Maniacs, and Missile Command. All are commercial games, and none of which use MBC.

truth2
October 21st, 2005, 13:39
Oh.. Ok.. Thanks.

By the way I fixed a silly mistake in which I was accessing rom bank 0 even if trying to access rom bank 1 and now both tetris and othello work flawlessly*!
now i guess i need to either focus on mbc or on correct timing...

*no sound, of course. also probably incorrect timing, also all serial registers are completely unimplemented, which probably what makes tetris 2player crash when selected.

ector
October 23rd, 2005, 04:54
Or flag bugs in your CPU emulator... they are a very common source of bugs.

aprentice
October 25th, 2005, 07:54
all i could get sound wise is pop and clicks in different frequencies, is the 16 samples in channel 3 per second? I'm using directsound, does anyone have any experiences in it? I know the buffer is circular, and i took that into account when writing to it.. I have my buffer size set to ~2kb, bits per sample to 8, and samples per second to 22050. Then i have it set to loop playback and every frame i mix the sound and write to the sound buffer. Am i not writing enough samples per second thus resulting in pops and clicks? I'm still confused about some aspects of sound but i understand more than what i started out with..

Dark Stalker
October 25th, 2005, 16:26
all i could get sound wise is pop and clicks in different frequencies, is the 16 samples in channel 3 per second? I'm using directsound, does anyone have any experiences in it? I know the buffer is circular, and i took that into account when writing to it.. I have my buffer size set to ~2kb, bits per sample to 8, and samples per second to 22050. Then i have it set to loop playback and every frame i mix the sound and write to the sound buffer. Am i not writing enough samples per second thus resulting in pops and clicks? I'm still confused about some aspects of sound but i understand more than what i started out with..
The 32 4-bit samples in ch3 are played back at a frequency between 1024 and 2097152 Hz (counting each sample), depending on the value of NR33 and NR34.

I think you should focus on ch2 first. You only need to emulate the frequency to get the melodies going, just keep the high samples at something like a value of 32, and the low ones at -32. The value of the frequency registers can be implemented as a down-counter, which increments a wave duty counter upon reaching 0/being reloaded. The wave duty counter in turn determines whether the sample should be high or low. You could simply dictate this to be 50% high/low for now, you'll be able to recognise melodies anyway. You'll also probably want to stick to mono sound for now, or you'll have to generate pairs of stereo samples.

What do you mean by "every frame"? The buffer will need more data at a rate of samplerate/(buffer_size*sample_size), but you'll have to generate samples at least as often as the values of the sound registers are changed if you want accuracy. Generating samples only when the sound buffer needs more data should still be enough to get "proof of concept" sound output however.

AFAIK DirectSound has a "play cursor" and a "write cursor" that move in parallel. You'll need to write to the area beyond the "write cursor"/before the "play cursor". I suppose you could always poll positions to determine how much has been played back, but I think it should be possible to set a callback-function that fills the buffer when needed (in a seperate thread), that's what I'm using in sdl. I hope someone that knows directsound can give some input here.


A mostly unrelated side note: Remeber that the sample rate needs to be at least twice as high as the frequency of the wave it's representing, which is why 44100 Hz is a popular rate (hearing has it's limit at around 22kHz waves).

ShizZy
October 25th, 2005, 22:35
Been working on mine like crazy over the weekend. I got a half assed sprite system implemented (no priorities, no limiting, crude flipping, slight glitching) but they work pretty well for now. I also reimplemented input similiar to how I did in the previous write up my emulator, but changed some things and now it works properly. It's much simpler than I expected it to be. Fixed a bunch of other bugs, and now Tetris, Amida, Space Command, and Asteroids are fully playable - and pretty much glitch-free. Also added support for the boot rom.

Still a lot doesn't work though. I havn't had any luck with mbc. I tried a sloppy mbc1 implementation, and I think had it setup right. But no games worked (tried Metroid, Super Mario Land, and Zelda). Maybe there are still too many bugs in my core? If anyone knows of any easy to emulate mbc1 games, or just some ones to try, please let me know. I'm pretty satisfied with my progress though, so I think I'll upload a build of my emu tonight and post it.

Regards

truth2
October 25th, 2005, 22:49
Well I implemented MBC1 (and 2, 3 and 5, but never actually got the guts to test them) and here are my experiences: (I wonder if any of you had the same/similar problems before and could help me out or at least guess what part of the code the problem lies at:

Super mario land (it's a hack where you cannot die, but it works fine on VBA/bgb as far as I know) - game randomly crashes or resets. very odd..

metroid 2 - the menu works fine, the game seems to work fine, samus, enemies, screen scrolling and all (only advanced through 3 screens, through, was too scared to go on :p), but i decided to check out the ship at the beginning, and when jumping high from the ship, i noticed some weird graphic glitches (a 'line' from the ship was in the air above).

zelda - well i was only brave enough to go through the intro, the menu, and the first two screens of the game, but it seemed to work fine so far :). EDIT: well i just checked the map screen and the image on the bottom right that tells you what is in the location the cursor is pointing to, is showing garbage. Damn.

edit :

great greed - it doesn't boot up at all, stuck in a glorious loop of ff's

another edit, to shizzie :
my suggestion to you is to double check the mbc code and everything affected by it (memory access, etc.).
but then again, that's just what usually helps me due to my sloppy coding, dunno how you code :).

bcrew1375
October 26th, 2005, 00:07
I had that very same problem with Metroid 2. Unfortunately, I don't know what it was that fixed it :/.

ShizZy
October 26th, 2005, 01:33
Wow... disabled P1 and Metroid 2 goes to the title screen! Strange, but I'm not complaining I guess. Must be buggers :P

aprentice
October 26th, 2005, 03:09
The 32 4-bit samples in ch3 are played back at a frequency between 1024 and 2097152 Hz (counting each sample), depending on the value of NR33 and NR34.

I think you should focus on ch2 first. You only need to emulate the frequency to get the melodies going, just keep the high samples at something like a value of 32, and the low ones at -32. The value of the frequency registers can be implemented as a down-counter, which increments a wave duty counter upon reaching 0/being reloaded. The wave duty counter in turn determines whether the sample should be high or low. You could simply dictate this to be 50% high/low for now, you'll be able to recognise melodies anyway. You'll also probably want to stick to mono sound for now, or you'll have to generate pairs of stereo samples.

What do you mean by "every frame"? The buffer will need more data at a rate of samplerate/(buffer_size*sample_size), but you'll have to generate samples at least as often as the values of the sound registers are changed if you want accuracy. Generating samples only when the sound buffer needs more data should still be enough to get "proof of concept" sound output however.

AFAIK DirectSound has a "play cursor" and a "write cursor" that move in parallel. You'll need to write to the area beyond the "write cursor"/before the "play cursor". I suppose you could always poll positions to determine how much has been played back, but I think it should be possible to set a callback-function that fills the buffer when needed (in a seperate thread), that's what I'm using in sdl. I hope someone that knows directsound can give some input here.


A mostly unrelated side note: Remeber that the sample rate needs to be at least twice as high as the frequency of the wave it's representing, which is why 44100 Hz is a popular rate (hearing has it's limit at around 22kHz waves).

i already give samples for right and left speakers, i have a 64 byte buffer set up, 32 for left and 32 for right, i know it has a play cursor and theres a write cursor that you have created yourself to keep track of where you are in the buffer. What confuses me is how many samples do i need to generate to play a full second of audio, and how do i generate that many if channel 3 is only 16 bytes in lenght, do i just keep checking the gameboy sound buffer when i need more sound? and to detect if i need to fill the buffer again do i need to do if playpos < writepos?

ShizZy
October 26th, 2005, 03:10
MBC1 works great with Tetris 2

http://host.11threvenant.com/tetris2.jpg

(Having fun with the pallette, almost looks GBC :P)

EDIT:
Here is the latest build: NhesGMB0.20.1.exe (http://host.11threvenant.com/NhesGMB0.20.1.exe).

Tetris 1 & 2, Asteroids, Space Command, Boulder Dash, and Amida all emulate perfectly, that I've tested. Not quite sure what else, MBC1 is somewhat working. Please try it and let me know what you think :)

Sagon
October 26th, 2005, 09:16
Good work ShizZie! Here what i noticed while testing your emu:
1) Input doesn't work in Asteroids, and there are some glitches with sprites in demo mode.
2) In Bomb Jack only logo working, looks like some bugs still in your cpu.
3) Heiankyo Alien, Shangai, Sprite Demo, Space Demo doesn't work.
4) Tetris, Missle Command works fine.
In summary there are still many bugs in cpu, if you debug Space Demo, Sprite Demo, Heiankyo Alien and Bomb Jack you'll find most of the them (that's how i've killed my bugs =)) ), and when these games will work, it will be wise to debug Motocross Maniacs, this game uses almost full potential of gb cpu. Anyway keep it up!

BTW: How did you implement VSync, i still obscured with frameskip techniques.

ShizZy
October 26th, 2005, 22:13
Hey Sagon, thanks for giving it a try :) Sprite Demo and Space Demo both work when the boot rom is disabled. Same goes for other emulators, the boot rom sets the true values, and I'm assuming these demos weren't meant to be played on the actual hardware. Huge thanks for the tips, I'll work on the those today.

As for vsync... in DirectX it's really easy. In your Flip Buffer function, you add:
lpDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN ,0);

I believe you are using SDL, correct? In my SDL version, I added a hack for it. I know it's not the proper way to do it, but it works, so maybe it'll help you.


// Count framerate & slow down emu, I call this every time the
// screen is rendered
void VIDEO::CountFrameRate()
{
/* fps counter */
static int Last;
const int Past = SDL_GetTicks() - Last;

if(Past == 0)
mFps = 1000;
else
mFps = (1000 / Past);

Last = SDL_GetTicks();

// Slow Down the Framerate if it is greater than 60
// these values I just played with so it worked at the right speed in my emu,
// they may need to be adjusted (the 60 and the 15).
if(mFps>60) SDL_Delay(mFps/15);
}

Dark Stalker
October 26th, 2005, 23:06
Good to see things loosening up a bit ShizZie, I'll give your emu a try the next time I'm on windows.


i already give samples for right and left speakers, i have a 64 byte buffer set up, 32 for left and 32 for right, i know it has a play cursor and theres a write cursor that you have created yourself to keep track of where you are in the buffer. What confuses me is how many samples do i need to generate to play a full second of audio, and how do i generate that many if channel 3 is only 16 bytes in lenght, do i just keep checking the gameboy sound buffer when i need more sound? and to detect if i need to fill the buffer again do i need to do if playpos < writepos?
I was of the impression that the write cursor moves with the play cursor, always staying a little bit ahead of the play cursor, to signal from which point on it's safe to write new data to the buffer.

I guess you know this, but sample rate is given in samples pr second, so <sample rate> number of samples are needed for one second of audio (or twice that for stereo cycles depending on how you look at it).

Ch3's wave pattern is repeated over and over again on playback. It is usually used for making simple tones rather than sample based playback, which would require constantly writing new data to the wave pattern memory. The wave pattern memory may change whenever ch3 is not being played back. The number of samples you are supposed to generate pr ch3 sample, depends on the ratio between your sample rate and ch3's frequency.

The game boy can sort of be seen as having a sample rate of 2097152 Hz, you'll have to resample this to your output sample rate. A crude way to do this, is to generate one sample every 44100 Hz (or every 4194304/44100=~95.11 cpu cycle), based on the channels' current output state, assuming a sample rate of 44100 Hz. A better way is to accumulate all of the samples produced by the game boy over a period of 4194304/samplerate cpu cycles, and use the average as your generated sample (a simple box filter). Of course this is easily optimised by only generating samples when either the output buffer needs more data, or the value of a sound register is changed. To know what a channel is outputting, you'll need to keep counters for frequency, sweep, envelope, length counters etc, based on number of cpu cycles passed.

aprentice
October 27th, 2005, 04:16
wow that sounds complicated as hell, i feel a lot less confident, but i havent given up :P

ShizZy
October 27th, 2005, 04:37
Went through each opcode by hand, didn't really find much (a couple of issues with the rotates where I was setting some bits wrong, but it didn't fix any games that I can see). I think the bugs are elsewhere... not memory handling, because you can disable most of that and many roms which should still work don't. Which basically leaves... STAT/LY/LYC/LCDC, DIV/Timers, and Interrupts. All of that is simple though, can't see where I could go wrong. I must be missing something :P

bcrew1375
October 27th, 2005, 07:49
If you want some help, you can post your code. I can look through it for you and try and find some problems. Or, if you don't like other people fixing your problems, I could just give you some hints :P.

ShizZy
October 27th, 2005, 21:06
Big thanks, it's kind of stressing me out. I'll post my code when I get home today. You don't need to go crazy, but any help you can give me would be great.

Regards,

ShizZy
October 27th, 2005, 23:44
bcrew: check your PM's. I sent you the source, wasn't quite ready to post it publically here yet.

truth2
October 28th, 2005, 00:59
what are those emulator test roms someone talked about before? what do they contain, and where can one get them (zophar's domain's dead, i think)

ShizZy
October 28th, 2005, 01:03
I think this is what you were looking for:

truth2
October 28th, 2005, 01:15
Thanks!
One more question, is the bootrom supposed to limit its writes to VRAM to modes 0 1 and 2? when i run the bootrom (and stop writes to VRAM at mode 3) it displayes corrupt graphics due to writes at mode 3...
or does it limit its writes but in a complicated, tricky way that does not work in my emulator due to the emulator's terrible timing?

ShizZy
October 28th, 2005, 01:24
No, I don't think it limits VRAM. At least I don't in my emulator. It's very very simple, though your emulater needs to be somewhat working for it to work. I'm sure yours will, if mine does :P It gets executed the same as any other rom. You write it over the first 256 bytes, set your program counter to 0, and execute as normal. You don't need to set the other regs, the bootrom does it, but I do anyways.

Also, some things about the bootrom. There are demos that don't work with it (SPRITE and SPACE from what I just gave you). I think this is because the documents aren't the exact values, and these demos rely on the documented values to run. IE- were never meant to run on the real hardware. Also, I converted the entire bootrom to an array if anyone wants to use it, instead of cluttering by loading the bootrom file each time:


const unsigned char boot_rom[0x100]=
{
0x31,0xFE,0xFF,0xAF,0x21,0xFF,0x9F,0x32, 0xCB,0x7C,0x20,0xFB,0x21,0x26,0xFF,0x0E,
0x11,0x3E,0x80,0x32,0xE2,0x0C,0x3E,0xF3, 0xE2,0x32,0x3E,0x77,0x77,0x3E,0xFC,0xE0,
0x47,0x11,0x04,0x01,0x21,0x10,0x80,0x1A, 0xCD,0x95,0x00,0xCD,0x96,0x00,0x13,0x7B,
0xFE,0x34,0x20,0xF3,0x11,0xD8,0x00,0x06, 0x08,0x1A,0x13,0x22,0x23,0x05,0x20,0xF9,
0x3E,0x19,0xEA,0x10,0x99,0x21,0x2F,0x99, 0x0E,0x0C,0x3D,0x28,0x08,0x32,0x0D,0x20,
0xF9,0x2E,0x0F,0x18,0xF3,0x67,0x3E,0x64, 0x57,0xE0,0x42,0x3E,0x91,0xE0,0x40,0x04,
0x1E,0x02,0x0E,0x0C,0xF0,0x44,0xFE,0x90, 0x20,0xFA,0x0D,0x20,0xF7,0x1D,0x20,0xF2,
0x0E,0x13,0x24,0x7C,0x1E,0x83,0xFE,0x62, 0x28,0x06,0x1E,0xC1,0xFE,0x64,0x20,0x06,
0x7B,0xE2,0x0C,0x3E,0x87,0xE2,0xF0,0x42, 0x90,0xE0,0x42,0x15,0x20,0xD2,0x05,0x20,
0x4F,0x16,0x20,0x18,0xCB,0x4F,0x06,0x04, 0xC5,0xCB,0x11,0x17,0xC1,0xCB,0x11,0x17,
0x05,0x20,0xF5,0x22,0x23,0x22,0x23,0xC9, 0xCE,0xED,0x66,0x66,0xCC,0x0D,0x00,0x0B,
0x03,0x73,0x00,0x83,0x00,0x0C,0x00,0x0D, 0x00,0x08,0x11,0x1F,0x88,0x89,0x00,0x0E,
0xDC,0xCC,0x6E,0xE6,0xDD,0xDD,0xD9,0x99, 0xBB,0xBB,0x67,0x63,0x6E,0x0E,0xEC,0xCC,
0xDD,0xDC,0x99,0x9F,0xBB,0xB9,0x33,0x3E, 0x3C,0x42,0xB9,0xA5,0xB9,0xA5,0x42,0x3C,
0x21,0x04,0x01,0x11,0xA8,0x00,0x1A,0x13, 0xBE,0x20,0xFE,0x23,0x7D,0xFE,0x34,0x20,
0xF5,0x06,0x19,0x78,0x86,0x23,0x05,0x20, 0xFB,0x86,0x20,0xFE,0x3E,0x01,0xE0,0x50
};

Regards

Edit: If it's working, but displaying garbage or looks really glitchy, it's probably a bug in your shifts and rotates. That initially happened to me, before I fixed it.

truth2
October 28th, 2005, 01:41
actually it works 100% fine if I enable writes to VRAM during mode3, but since the docs pretty much said that VRAM access is forbidden during mode3, allowing access is kinda cheating...
im pretty sure it's a problem with my timing : i bet if the timing was correct, nothing would be written to VRAM during mode3. I think..
also, sprite and space seem to work fine as long as you stop the bootrom from 'crashing' on a wrong header checksum.

ShizZy
October 28th, 2005, 02:09
Ahh thank you.

Edit: No luck here with VRAM limiting. I'm not really going to worry about it at the moment.

bcrew1375
October 28th, 2005, 06:04
truth2: Nothing should be written during mode 3, but I haven't disabled it either. I'm pretty sure it's just a hardware limitation. There should be no problem with allowing writes during that time. Though, are you sure that in denying writes during mode 3 you are not somehow denying writes in the other modes as well?

ShizZie: I just got home from work. I'll take a look at your code and see what I can find. Oh, also you don't need that hack for BLEM. Just try pressing the Start button :P.

truth2
October 28th, 2005, 11:43
if you stop writes at mode 3 in your emu, does the bootrom still show correctly, bcrew?

ShizZy
October 28th, 2005, 20:57
bcrew: haha thanks :P Didn't think to try that. Let me know if you find anything.

http://www.aep-emu.de/ <- popped up fast there, why don't they put up one of the emus here that work :D

XTale
October 28th, 2005, 21:56
http://www.aep-emu.de/ <- popped up fast there, why don't they put up one of the emus here that work :D
Shall I remove it again? :P

ShizZy
October 28th, 2005, 22:05
No no, keep it. Feel free to post again when I update. Was just surprised to see it there so fast :P

truth2
October 29th, 2005, 04:05
honestly, is the emulation community really so dying, that an incomplete gameboy emulator that is clearly not a lot more than a personal emulator project for the most emulated system of our time is considered news?
(no offense to you, shizzy)

smcd
October 29th, 2005, 05:55
honestly, is the emulation community really so dying, that an incomplete gameboy emulator that is clearly not a lot more than a personal emulator project for the most emulated system of our time is considered news?
(no offense to you, shizzy)

most emulated system? probably not. However it is always good to show people that emulation isn't dying and that there might be (is) up and coming talent to 'take the reins' of the people who are 'retiring'

bcrew1375
October 29th, 2005, 06:54
truth2: The bootrom does not work with mode 3 writes disabled. Shizzie, I've looked through your code and found numerous things that seem to have problems, but changes don't seem to effect games in the least. I have a feeling there is a major problem with your MBC code. I'll see what else I can find.

truth2
October 29th, 2005, 21:22
most emulated system? probably not. However it is always good to show people that emulation isn't dying and that there might be (is) up and coming talent to 'take the reins' of the people who are 'retiring'

Hmm.. Yeah, I guess you could see it that way. Again, no offense to anyone.

bcrew : well isn't that a problem? after all the docs clearly say that writes to vram during mode3 are ignored...
OOPS... I didn't realise that the bootrom enables video by itself, that means that using the bootrom, $ff40 must be set to 0 on powerup...

ShizZy
October 31st, 2005, 01:52
Shizzie, I've looked through your code and found numerous things that seem to have problems, but changes don't seem to effect games in the least. I have a feeling there is a major problem with your MBC code. I'll see what else I can find.
Thanks for taking a look. My MBC1 code is really simple, just a few lines. I'm sure that there is probably more to it. But still a lot of regular roms do not work. Did you look and see if any demos ran better with your fixes? I'm going to work on it some more tonight. Where did you find errors? I need some ideas of where to look for things.


honestly, is the emulation community really so dying, that an incomplete gameboy emulator that is clearly not a lot more than a personal emulator project for the most emulated system of our time is considered news? I don't agree with that, and not because the statement was directed at me. I think it's great that emu coverage has gotten so extensive that even small projects such as mine own find a little place in the emu scene :P Plus, it gives me motivation to work on it more, learn more, and maybe someday make something that people really do like.

bcrew1375
October 31st, 2005, 06:18
Good news! I may have found one of your emulator's largest problems! You are not counting cycles when the CPU is not turned on. If you don't do this, you won't have anything to generate interrupts or IO ports and your emu will get stuck at halts and stops. Simply add an else line in the EmulateCPU function that counts cycles if the CPU is not on(10 is probably a good value) and be amazed :D. I was able to get Metroid 2 ingame with this one simple change. Unfortunately, it is very glitchy and Samus falls through the ground :/.

Edit: You should also be able to get Donkey Kong in game(though it will glitch and reset) by changing the way you write to the P1 register. You are simply writing the entire byte of data into memory. AND the data with 0x30, AND the P1 register with 0xCF, then Inclusive OR the data with the P1 register. That will make sure only bits 4 and 5 are written(This is the same problem Dark Stalker and myself were having with Donkey Kong. There's probably a much simpler way to do it, but this is how I did it :P.)

Edit 2: One other thing. Do you realize you lack support for window drawing?

ShizZy
October 31st, 2005, 20:52
bcrew you are a god amoung mortals :P Thank you!

About the window drawing: yes, I do realize that. But I don't understand the concept of scrolling yet, so I couldn't finish my own drawing code (though it worked on some demos), so I didn't bother with the window until I fully grasped it. (Hence why the scanline function is a port of yours) Though I did figure out sprites on my own, rather easily. Weird :P

But yes, thank you, I will sift through it some more.

ShizZy
October 31st, 2005, 21:07
I'm not emulating OBP, hence color inversions (I think) My sprite code isn't complete anyways. But once again bcrew, fantastic! This is the one game I've strived to get running since the beginning :P Needs work, I know :D Mario boots too, minus a crash after the title screen. I'm really proud of my rotates and shifts, they used to kill me... now I have a good understanding of them and I think they're mostly bug free.

EDIT: Added OBP, seems to work well, fixed my problem... was much easier than I thought, or I would have added it earlier. Still that bg tile junk around the houses and stuff though. Mario1 also goes in game, but same problem with metroid - player falls through the floor. Mario2 goes to the title screen :)

bcrew1375
October 31st, 2005, 22:33
Glad I could help :P. I've noticed you haven't emulated any of the STAT interrupts aside from the LYC. If bits 3, 4, or 5 are on, you call an interrupt when the STAT mode hits 0, 1, or 2, respectively. That might account for some problems.

Edit: Nevermind that. I just noticed them :P. Hmm, I'm not sure what it would affect, but you should only be requesting one V-Blank per screen. You have "if (mem.IOR_LY>=144)", it should be "if (mem.IOR_LY==144)"

ShizZy
October 31st, 2005, 23:06
Awesome thanks! In the past 20min, I just emulated the Cartridge RAM/Battery Pack, so now all saving and loading works :D Really easy too, just got to save out the 0x2000 bytes from 0xA000 to 0xBfff, then load them again over memory at startup :P

Edit: About the VBlank thing, it doesn't make a difference, because once LY == 144, it gets set, and then that branch of the switch never gets hit again until VBlank is entirelly over.

bcrew1375
October 31st, 2005, 23:35
I think you need to look at the header to see how much external RAM the ROM has. Alot have 8K, but some have 32K, I think you need to save all four banks with those. Or, are you already doing that? :P

ShizZy
November 1st, 2005, 00:14
Yes, I am, but I don't think that part is working right. Oh well, works for Zelda and other games, good enough for now.

Edit: 9/10 side scrollers tested, the player immediatelly falls through the floor. Any ideas of what could cause that?

truth2
November 1st, 2005, 18:12
That's weird... Can you show a pic of how it happens? (not because it'll help people solve your problem or anything (I'd say to recheck the flags altered by all cpu ops) , but because it sounds extremely funny!)

bcrew1375
November 2nd, 2005, 00:43
In Metroid 2, Samus falls through the floor into a cave of garbage.

ShizZie, I agree with truth2. The flags are more than likely the problem. I had a similar problem, but it was a while back, so I don't remember how I solved it :/

ShizZy
November 2nd, 2005, 00:46
Thank you, I'll look those over once I am done with my new drawing code. I got it working well, but I don't get scrolling. I tried adding the SCY&SCX pixels to the address, then wrapping around when it maxes out, but that just gave me a bunch of gargbage. What is the correct way to handle it?

truth2
November 2nd, 2005, 18:39
here's how I do it:


byte xp=HRAM[SCX]+x;
byte yp=HRAM[SCY]+y;
(byte is an unsigned char)
i no longer use x and y after these 2 lines of code (use xp and yp instead).

ShizZy
November 3rd, 2005, 00:52
Thank you. I was thinking too complex. I had to set mine up a little different, but it works well. Y scrolling was easy, but X scrolling was a bitch. (Because I ended up having to write my tile calling code again if the pixels scrolled to a tile before them). It's a little awkeward, but it works :P I also was able to grasp WX and WY, so I could finish my window drawing code. Glad to say my drawing is 100% mine... and both windows and bg work perfectly (sprites work really well too, but still some glitching with mirroring, and some weird inverted colors at times).

Zelda is almost 100% perfect :D

truth2
November 3rd, 2005, 15:43
Damn.. I'm too lazy to keep working on mine.. (I need to resolve some serious timing issues, not that I know which)
shizzie, what is not woking 100% for you in Zelda. also, can you show us a pic of metroid falling through the floor?

everyone, can you give some hints and tips regarding common timing errors? thanks!

ShizZy
November 4th, 2005, 21:33
Bugs in zelda... Two ships in the beginning. Still some weird bg tile glitching. Here's also the metroid shot. I think the route of all these bugs are flag errors.

Also, got tired of debugging and worked on a very premature GBC support. AFAIK it's some what working, but I'm reading (and or writing) pallette data wrong so my colors are far off. Got some demos working though. I think my HDMA is wrong too :P If anyone knows of any (or has any) MBC5 docs and GBC specific docs please let me know. I think I have a pretty good understanding of how the GBC pallette works, but obviouselly not enough - pan docs didn't give me everything I needed. I'll post a shot when I get the colors a little better.

Sagon
November 5th, 2005, 07:16
I've encountered stange bug, and still don't know what is it. My emu freezes at "Konami" screen in Zen - Intergalactic Ninja (U) or at "Palcom" screen at Zen - Intergalactic Ninja (E). If someone had this bug or know why this happens, please let me know.

2ShizZie:
Thanks for VSync help, in SDL i've used a similar code and wasn't satisfied with the results, but now i'm using DDraw and everything is smooth =) BTW I'm also searching for docs on MBC5 and on GBC, so if you find something interesting please let me know.

ShizZy
November 5th, 2005, 20:09
Added MBC2 support :P

@Sagon, I've searched around for MBC5... couldn't find much. I'm basically experimenting, seeing if I can get something working. Most of the MBC's are pretty similiar, so it can't be too difficult. As for GBC, I think everything you need is in the Pan Docs, but they don't go into much detail.

ShizZy
November 6th, 2005, 02:02
Added MBC5 :P Not trying to spam :D

Sagon: MBC5 is REALLY easy. It's very similiar to MBC1 through MBC3, except that the rom bank select is 9 bits. Okay, here is what you do. When your emulator writes a value between 0x2000 and 0x2FFF, that is the lower 8 bits of the address. So store that, and then when your emulator writes a value between 0x3000 and 0x3fff, the highest (9th bit) of the rom bank select is the least significant bit of that value. So, just combine the values as your 9 bit rom bank select, and then switch the rom banks (I believe you're supposed to switch the rom banks any time a value is written between 0x2000 and 0x3fff). This is how I did it. I havn't implemented RAM bank switching, but this should be all you need to get some MBC5 stuff working. If that explanation was unclear, here is my quick dirty implementation of it:



unsigned char mbc_lo,mbc_hi;
unsigned short RomBankRegister;

//.....

if(MBC5) // MBC5
{
// grab the rom bank select bits
if(address<0x3000)
mbc_lo=data;
else
mbc_hi=data&BIT7;

// assamble the 9bit rom bank select
RomBankRegister=(mbc_hi<<1)|mbc_lo;

// switch the rom bank
memcpy(&memory[0x4000],&rom.Buffer[RomBankRegister*0x4000],0x4000);
}

Sagon
November 6th, 2005, 07:00
Oooh thank you! Now i have MBC5 implemententation, too =)))
BTW: is Zen working for you?

Edit: i finally catched this stupid bug... Zen rom tries to select the high bits of rom bank number, but this rom only 128K, so i should ignore this value. I've constructed the masks for rom sizes and now ANDing it with number of the bank.

ShizZy
November 7th, 2005, 01:44
Well... you can faintly make out the character sprite amoungst a bunch of bg rubbish. So I guess you could say Zen goes in game :P But the title screen is all warped like this too. Probably the same bug that causes some issues with Zelda. I still have lots of bugs...

On a separate note, anyone try anything with SGB? Looks interesting, but a little bit quasi (and a little more work) than it's worth. Also, still looking for GBC docs... as well as MBC4 and MBC7.

Edit: weird Sagon, I don't mask for the rom sizes at all, and I still get past the Konami screen just fine. (no freezes at all, just garbage as you can see)

Sagon
November 7th, 2005, 06:00
Hmm strange... anyway it works and that good. MBC7? I haven't heard about this controller, it is GBC specific? What do you know about other controllers like MMM01, MBC4, HuC3, HuC1. I know only one game containing MMM01 - "Momotarou Collection 2 (J) [S]". On other controllers i haven't found any info and games too.

BTW i coded a tool for rom sorting by memory bank controllers, hope it will be helpful. Instructions: create a folder "Roms" in same folder with the tool, copy all roms in that folder.

Sagon
November 7th, 2005, 20:18
The time has come for the first release of my emulator of Game Boy - "DGB".
What's done:
1) CPU fully implemented, interrupts handling and others.
2) Background, Window, Sprites drawing
3) MBC 1,2,3,5 support
4) Battery load, save
Requires at least DirectX7.

ShizZy
November 7th, 2005, 21:12
Excellent work Sagon. Very well debugged. Yes, I believe MBC7 is GBC-specific. As for MBC4, I know very little (I'm assuming it's similiar to mbc5, without officially supporting double speed mode...and maybe some extra limitations?). I think I have a doc on the Hu's though somewhere. Still really need to nail a few bugs before I move on :(

Edit: Why'd you remove the dl? :P

Sagon
November 7th, 2005, 21:16
Thanks =)
Download returned, i've uploaded not the latest version =)

ShizZy
November 7th, 2005, 23:52
Tada! :happy: GBC. I have the buggiest emu out of all of us... but I just got plain tired of bug hunting. Still needs a lot of work. :P Nothing commercial runs quite right.

Edit: Most demos work mostly right. But I can't for the life of me find a commercial game that doesn't display the pallettes HORRIBLY wrong. Might be because I'm not emulating HDMA... though everything else is there.

ShizZy
November 8th, 2005, 06:55
All in a nights work :D

I'll squeeze in a little more coding, it's only 1... then it'll be bed time. Really need to get back to debugging gb monotone games :P

Sagon
November 8th, 2005, 07:25
Wow great job ShizZie! I still have no GBC support at all. Hope soon i'll have some time to implement it.
How about sound in your emu? I haven't ever worked with sound, so i do't know ever where to start.

ShizZy
November 8th, 2005, 16:05
Thank you! Sound scares me... a lot. I found this http://www.slack.net/~ant/libs/#Gb_Snd_Emu if anyone is interested. It's a portable sound system for GB emulators. Looked interested, but when I tried fooling around with it I was getting some weird build issues. But all the code is there. Then again, using that would be cheating... sound is gonna be tough :P

ShizZy
November 8th, 2005, 21:38
Hehe.. better slow down before I hurt myself :bouncy:

Good GBC compat requires really good GB compat... which I don't really have. Things are VERY buggy, even zelda I still have all the same tile glitching problems as I do in the GB version (I show just the clean shots :D). But go for it Sagon, I'm sure you'll have better luck with your emulator. I avoided the dirty work, and now I got to go back and do it. :P

Question for everyone: Where do you guys disable the Stop command? I had to disable stop in GBC mode because right at startup most games switch to double speed mode (and to do that they use the stop command) but then the emulator freezes because it isn't getting turned back on. The only place I disable stop is when an interrupt is executed. Enabling interrupts/turning off stop in KEY1 didn't fix it.

bcrew1375
November 9th, 2005, 12:27
You should continue from stop after a key is pressed. It shouldn't matter whether an interrupt is called. At anytime stop is enabled, if any of the bits 0-3 in P1 get turned off, you should disable stop.

ShizZy
November 10th, 2005, 03:23
If the cpu is stopped, how does it check if a key is pressed to turn it back on?

I've been kind of poking through my code tonight, rewriting tidbits here and there. I don't remember specifically spotting any bugs, but some glitches are getting fixed in some games. So at least I'm making progress.

Edit: Still can't fix my falling through the floor problems in Super Mario Land and Metroid 2. Which is interesting because Mario Deluxe is fully playable :P

bcrew1375
November 10th, 2005, 10:44
The same way interrupts are executed to terminate halt :P. If you're counting cycles when the CPU is off, you can update the I/O registers without executing instructions. The program doesn't check for the keypress, your emulator does. If bits 0-3 of P1 are lower than 0x0F, terminate stop.

Sagon
November 11th, 2005, 00:11
After a night of struggling with implentation of GBC support, i finally maked some progress. Here some shots.

ShizZy
November 11th, 2005, 00:36
Wow awesome job Sagon! I'm still debugging. Fixed a lot of issues with my gbc vram bank switching. With vertical mirroring, multiple banks and what not, my gbc sprite tile data retrieval is a very swisted mess :P

@bcrew.. thank you, I'll fix how I have mine set up.

ShizZy
November 11th, 2005, 06:13
After help from Blargg and getting his fixed version of his PAPU emulator, I managed to get sound working in my emulator with SDL. I wrapped it up nicelly with some basic audio calls for reading/writing audio io, and a frame counter. If anyone is interested in these files I'll post them, it's pretty much plug and play. I feel kind of cheating-ish for using it, but I have every intention to code my own sound when I get a better emulator. And hell, that's what he made it for.

Here's the latest version.


+GB/GBC Emulation
+MBC1, MBC2, and MBC5 Cartridge Support
+Sprites
+BG Tile maps
+Window Display
+Sound Emulation
+All CPU Opcodes
+Timings and IO Registers
+JoyPad
+Saving/Loading (Partial for MBC5)
+"Casual" Debugger, Logging, and Options

+DirectX7 For Video
+SDL and Blargg's GB PAPU Library for Sound
http://shizzy.emulation64.com/

Please let me know what you think! It's still pretty buggy, but getting there. Some good GBC games to try are the Bomberman Max games, Zelda DX, and Mario Deluxe.

Regards

Sagon
November 11th, 2005, 07:19
Great job, ShizZie! Sound is working good. I've tried many games and you right you have problems with retrieving gbc data from right banks, i had the same problem with my emulator.
And yeah, i'm interested how did you implement sound with SDL and Blargg's library, so please post your files.

ShizZy
November 11th, 2005, 17:24
Thanks for trying it out :) Any tips on vram bank switching? My code is really plain, I simply have 2 external banks and I switch them in and out into memory whenever VBK is written too. Then in my drawing code, I retrieve the data from whatever bank. (and if the bank is the current one in memory, I just read straight from mem).

As for the sound, here is all the included files. Set up is REALLY simple. Add all the files to your project. Boost is a library of common functions used, if you already have it setup in your compiler you don't need it, otherwise you can add the files that are there. Include Audio.h, which is the main wrapper which is very basic. Declare a AUDIO aud; somewhere. Then when the program initializes, call aud.Initialize(). In your write to memory function, do something like:


if(address>=0xff10 && address<=0xff26)
{
aud.WriteRegister(address,data);
return;
}

Same thing goes for aud.ReadRegister in your read register function, though this one isn't entirelly necessary. I think only some GBC games rely on reading back the values of the sound io registers.

Lastly, when LY=144 (when you just finished drawing the screen) call aud.EndFrame();

Voila! Sound. Just make sure that you include the sdl libs. Here is some extra information Blargg sent me in an email:


I guess you can tell by now that the simplified APU is simulating the Z80
as if it were writing to the sound chip every instruction at the beginning
of the frame. Once you are ready to switch to the full APU, you'll be
passing the actual number of clocks since the beginning of the frame.

> Also, reseting
> doesn't reset the sound properly. But none of that is anything I
> can't work out on my own.

I'll have to look into reset behavior. I originally wrote the APU only for
a GBS music player, so most problems are due this.

Even if you work out problems, let me know so I can fix the
library/documentation.

Here are a couple of features you could add in the future, once everything
else it working well (my standard pitch, heh):

You can adjust the treble and bass frequency response, good for simulating
the small speaker in a Game Boy:

Basic_Gb_Apu::Basic_Gb_Apu()
{
time = 0;
apu.treble_eq( -20.0 ); // lower values reduce treble
buf.bass_freq( 461 ); // higher values reduce bass
}

These can be adjusted at any time, not just during initialization.

There's also Effects_Buffer, which adds adjustable panning and stereo echo
to the sound channels. Since most Game Boy games never even use stereo, it
makes them sound a little better on headphones.

As you may of guessed, this isn't using his full APU, but a basic version for getting started.

EDIT: If anyone gets his APU working with DirectSound, please let me know. It was giving me a hard time, so I just stuck with SDL.

EDIT: Also note there was a bug in the sound in the last build of my emu that messed up the timings and it eventually turned to static. This is fixed in this code here, and in the current build of my emulator.

Regards

gunder
November 11th, 2005, 18:21
That looks great Sagon! Evertime I see screen shots like this it makes me want to drop my other projects and start up a game boy emulator. I know it's way beyond my skill level right now so I'm not letting myself. You people make it really hard though! :)

-gunder

ShizZy
November 11th, 2005, 21:22
Sagon, what methods do you use for debugging? Can't seem to figure out how you can do it so efficiently.

bcrew1375
November 12th, 2005, 00:26
ShizZie, I tried the sound library. I just get a bunch of errors in all the header files. Hmm, could it have to do with the fact I'm using C instead of C++?

These are the first couple of messages I get:



blip_buffer.h(12) : error C2061: syntax error : identifier 'Blip_Reader'
blip_buffer.h(12) : error C2059: syntax error : ';'
blip_buffer.h(18) : error C2059: syntax error : ':'
blip_buffer.h(20) : error C2061: syntax error : identifier 'Blip_Buffer'
blip_buffer.h(20) : error C2059: syntax error : ';'
blip_buffer.h(20) : error C2449: found '{' at file scope (missing function header?)
blip_buffer.h(114) : error C2059: syntax error : '}'
blip_buffer.h(129) : error C2061: syntax error : identifier 'Blip_Reader'
blip_buffer.h(129) : error C2059: syntax error : ';'
blip_buffer.h(129) : error C2449: found '{' at file scope (missing function header?)
blip_buffer.h(156) : error C2059: syntax error : '}'
blip_buffer.h(166) : error C2059: syntax error : ':'
blip_buffer.h(168) : error C2061: syntax error : identifier 'Blip_Impulse_'

Jsr
November 12th, 2005, 12:24
bcrew1375: Blip_buffer is written in C++, compile with a C++ compiler.

bcrew1375
November 12th, 2005, 15:01
I'm using MSVC++ 6.0 :P. I was just wondering if it's not allowing C++ syntax. It seems like each file should compile depending on it's extension, but could it somehow be in "C Mode" since my code is in C?

ShizZy
November 12th, 2005, 19:29
bcrew: change all your file's extensions to cpp, create a new empty win32 workspace, and copy all your files in, and all the audio library files. Include Audio.h. It is *important* that all the audio files are actually in the workspace, so add them all in. Also make sure it's getting the files in the boost folder. If you're still having problems, let me know, and I'll post a simple workspace that will build with the files in it.

Edit: Yes it's because you're using .C files, and the files you are including use classes. If the file is .C, the compiler automatically assumes it is strickly C code.

bcrew1375
November 13th, 2005, 02:07
Well, I had to type cast alot to get my code to compile :P, but it finally works. Sound seems to work nice. This should make debugging a little less boring :). I intend to code my own after my code is a bit more compatible. Thanks, ShizZie!

Sagon
November 14th, 2005, 00:12
Sagon, what methods do you use for debugging? Can't seem to figure out how you can do it so efficiently.
I'm using just plain look and guess method, nothing more. And of couse I spent hours in my own coded debugger to catch and kill non trivial bugs.
Thanks for the sound framework and explainations!

ShizZy
November 14th, 2005, 05:40
No problem guys.

bcrew: you should release a build of your emulator, havn't seen much from it in a while :P

Nailed a couple of bugs this weekend that were really hurting my emu, and I got to say compatability is finally starting to get fairly good. Fixed my metroid, mario, and zelda bug, DK and DKLand are now flawless, and every single GB Mono game in my roms folder boots as it's supposed to. (Granted one or two of them crash in game). It was all two simple things, I was rotating instead of shifting for one of my shifts, and one of my loads was HL=SP instead of SP=HL.

Questions... documents say to delay interrupt enables/disables by one instruction. Do you guys do this? I tried doing it, and it breaks Waverace, which otherwise runs flawless. Also, most of my games display scores in hex. How did you guys fix this? And does anyone know of any MBC3 games?

Sagon
November 14th, 2005, 09:05
GB:
MBC3+RAM+BATTERY: Pokemon Series (Blue,Red)
MBC3+TIMER+RAM+BATTERY: Berutomo Kurabu (J) [S][!], Bokujou Monogatari GB (J) (V1.0) [S], Itsudemo Nyanto Wonderful (J) [S][!], Kandume Monsters (J) [S].
GBC:
MBC3: Columns DX (PD) [C]
MBC3+RAM: Putty Squad Demo by Thalamus Interactive (PD) [C]
MBC3+TIMER+RAM+BATTERY: Harvest Moon, Pokemon Series

I have only one delay of 6 cycles if VBlank is requested during HBlank, because without it Addams Family 2 and other games will not go in game. Have never got hex scores bug =) And don't have any idea about what may cause it.

ShizZy
November 15th, 2005, 05:04
Alrighty, thank you. Another completelly random question, how are you handling video with directx? Are you using some type of pixel drawing function (and then drawing multiple pixels for each gb pixel to scale it) or are you writing directly to the video buffer then scaling the window up? Trying to find the most efficient, fastest, and most compatable drawing method. What I have now works great, but I'm just curious. Thanks.

bcrew1375
November 15th, 2005, 05:37
ShizZie, I don't think my emu is ready to release again yet. There's just not enough changes to it. My method is pretty slow in my opinion. Using SDL, I just draw rectangles to scale the picture. Also, I have a buffer that contains the last frame drawn. I check it against the current screen data, and if a pixel is the same, I don't draw it. I'm not sure if this is faster or not, since I do an "if" on each individual pixel :P.

ShizZy
November 15th, 2005, 05:42
Yeah, I previouselly used SDL, using SetRect (or whatever the command was) to draw a rectangle for each pixel. It was kind of slow, and didn't have really any options to do any interesting gfx filters or anything (blur pixels etc) but for some reason I still hold a weird attachment to the API. :P Dark Stalker seems to have it working pretty well for him.

Sagon
November 16th, 2005, 21:37
For the video i have two arrays one for gb colors and one for gbc colors. When screen update is needed i'm locking surface and drawing colors directly to video buffer from one of the arrays and scale it if needed.

bcrew1375
November 17th, 2005, 07:41
Can anyone give an accurate description of the priority bits? I've seen so many conflicting sources and I'm not sure if I'm using them correctly. I'm talking about bit 1 of 0xFF40(The document I have says if the bit is on, the window appears above all sprites, if the bit is off, it appears above sprites with a priority of 1.

The description I have for the sprite bits(Byte 4 of sprite data, bit 7) says that if it's on, the sprites appear under everything except background color 0. If it is off, they appear above the background and behind or above the window depending on bit 1 of 0xFF40.

Is this information correct? I have a feeling I'm not emulating these priorities correctly.

Edit: Can someone that has them working right tell me? I've looked through several documents and tried their methods, but none seem to work properly.

bcrew1375
November 22nd, 2005, 06:18
Okay. Messed around with priorities for quite a while, and now I believe I have the right combination. Everything seems happy with it. My emulator is about flawless now except for ONE problem. Donkey Kong still seems to have a one pixel offset problem. All the sprites in this game seem to appear over the very top line. I also notice when Donkey Kong is knocking the scaffold apart, you can see an extra rung on the ladder. Here's some pics:

Edit: It seems to be tied to the LYC interrupt.

ShizZy
November 22nd, 2005, 17:11
Awesome work bcrew. I don't have priorities right at the moment, but not really worrying about it until I fix a few more bugs (though right now compat is quite good). One thing that's bugging me though, is it's not getting past the title screen to Mario2. Any ideas?

Edit: When do you do an LYC check? I do it each time after LY is incremented (in HBlank) and each time before and after each vblank is called. Don't know if it's right, but it seems to work well for gb mono, and I don't have any issues like the ones you have.

bcrew1375
November 23rd, 2005, 21:17
About Mario 2, Dark Stalker mentioned a problem a long while back that fixed it for aprentice. If you're not, keep the STAT mode flag at 0 when the display is disabled.

Hmm, I have a very strong feeling my problem with Donkey Kong is in the way I'm handling the end of the V-Blank. You said you didn't have problems with it, right? Do you think you could post your current code so I could get some ideas? I can't find anything in the docs that suggests I'm doing something wrong.

ShizZy
November 23rd, 2005, 22:34
Thanks for the fix. Still doesn't get past the title screen, but at least it doesn't crash anymore. Here's my really messy poorly commented stat code, hope it helps. handleSTAT() is called every cpu loop, and I subtract cycles from cpu.timerLCD.


void SetSTAT(int mode)
{
mem.IOR_STAT=(mem.IOR_STAT&0xFC)|mode;

switch(mode)
{
case STAT_HBLANK: //HBlank 0
dbg.lcdc_phase=1;
if(mem.IOR_STAT&BIT3) reqINT(BIT1);
break;
case STAT_VBLANK: //VBlank 1
dbg.lcdc_phase=4;
if(mem.IOR_STAT&BIT4) reqINT(BIT1);
break;
case STAT_OAM: //OAM 2
dbg.lcdc_phase=2;
if(mem.IOR_STAT&BIT5) reqINT(BIT1);
break;
case STAT_TRANSFER: //Transfer 3
dbg.lcdc_phase=3;
if(mem.hdma_on){ // GBC only
for(int f=0; f<0x10; f++)
{
mem.hdma_transfered+=f;

if(mem.hdma_transfered>mem.hdma_length)
{mem.hdma_transfered=0; mem.hdma_on=0; break;}

mem.memory[0x8000+mem.hdma_destination+mem.hdma_tra nsfered]=mem.memory[mem.hdma_source+mem.hdma_transfered];
}

}

break;
}
}

void handleLYC()
{
if(mem.IOR_LY==mem.IOR_LYC)
{
mem.IOR_STAT|=BIT2;
if(mem.IOR_STAT&BIT6) reqINT(BIT1);
}else{
mem.IOR_STAT&=~BIT2;
}
}

//

void handleSTAT() // in order - 0, 2, 3 etc until hits VBLANK period (LY>144)
{
if(cpu.timerLCD<=0)
{
switch(mem.IOR_STAT&0x3)
{
case STAT_HBLANK: // HBLANK 0
++mem.IOR_LY;
handleLYC();

if(mem.IOR_LY==144)
{ // time for vblank
SetSTAT(STAT_VBLANK);
cpu.timerLCD+=CYC_LCD_MODE1;
}else{ // otherwise goto mode 2
SetSTAT(STAT_OAM);
cpu.timerLCD+=CYC_LCD_MODE2;
}

break;
case STAT_VBLANK: // VBLANK 1
handleLYC();
switch(mem.IOR_LY)
{
case 0:
++mem.IOR_LY;
SetSTAT(STAT_OAM);
cpu.timerLCD+=CYC_LCD_MODE2;
break;

case 144:
++mem.IOR_LY;
reqINT(BIT0);
cpu.timerLCD+=CYC_LCD_MODE1;

aud.EndFrame();
break;

default:
if(mem.IOR_LY<153)
{ // repeat mode 1
++mem.IOR_LY;
cpu.timerLCD+=CYC_LCD_MODE1;
}else{ // goto mode 0
mem.IOR_LY=0;
cpu.timerLCD+=CYC_LCD_MODE1;
}
break;
}
handleLYC();

break;
case STAT_OAM: // OAM TRANSFER 2
// goto mode 3
//handleLYC();
vid.LCD_DrawScanline();

SetSTAT(STAT_TRANSFER);
cpu.timerLCD+=CYC_LCD_MODE3;
break;
case STAT_TRANSFER: // TRANSFER 3
// mode 0
SetSTAT(STAT_HBLANK);
cpu.timerLCD+=CYC_LCD_MODE0;
break;
}
}
}

bcrew1375
November 24th, 2005, 04:52
Hmm, this is weird. It worked, but it had flicker. I changed stuff some more, then decided to put it back the way it was. Now, there is no flicker. What the...? So, if I'm understanding this correctly, V-Blank lasts from LY = 144 to LY = 1? Anyway, big thanks ShizZie! :happy: Now, can anyone suggest some "picky" games I can test? Mono only please.

ShizZy
November 24th, 2005, 05:06
NP :)


So, if I'm understanding this correctly, V-Blank lasts from
LY = 144 to LY = 1?
:plain: Hmmm... can't verify whether or not that is correct, no docs seem to support it, but it works best for me. It's probably wrong.

Games to try... "Asteroids & Missile Command" (the combination game). Seems like it would be easy to emulate based on the two games it's made up of, but it's the only game I know of so far to completelly crash my emulator without displaying any real graphics. Alleyway also is giving me some funky results.

As Sagon stated earlier, Motorcross Maniacs uses most of the GB cpu, and is a good one to debug with.

bcrew1375
November 24th, 2005, 05:36
"Motocross Maniacs" and "Asteroids and Missile Command" work without issue, but Alleyway has a joypad problem. It seems to think I'm holding down the Start button, then won't respond to directional keys. I'll look into that. Anymore? :P

bcrew1375
November 26th, 2005, 10:59
Geez, is it just me and ShizZie now? Come on guys, I want to hear if you've made any progress(That means you, Dark Stalker and aprentice :P).

Sagon
November 26th, 2005, 16:06
I'm still working on my emu. I've fixed a tons of bugs with GBC games, and now nearly all are fully playable. But I haven't implemented some priorities that GBC specific, my emu haven't MBC7, MMM01 support cause i haven't any info on it, and i don't 100% sure that games using Rumble works exactly as without it. And i have one stange bug that occurs only in Blaster Master when i press right button wait a little and then press left, the tank will flip on y axis. Shot included. If anybody know what is it, please tell me.
Right now i'm using Blargg GB PAPU Library for sound, but i'm fighting with my sound implementation, hope soon it'll be finished.

bcrew1375
November 27th, 2005, 14:48
Hmm, Anyone else been using the KiGB site for games to test?

I notice a few of the emulators have a graphic glitch with Altered Space where the top half of the screen is left when going from room to room. If you guys have this problem, just clear your screen data and immediately redraw the screen.

ShizZy
November 28th, 2005, 03:28
Havn't had a chance to test Altered Space. In fact, havn't had much chance to work on my emu at all latelly... been busy with the holidays/work/school. Hopefully I'll get back to it soon. Been playing it more than working on it :P

@Sagon, awesome job. I'm no where near as complete as you, still have a long ways to go before I'm bug free. My GBC is lame too, I think I'm handling HDMA completelly wrong, and my vbank switching is bad.

bcrew1375
November 28th, 2005, 05:44
Another one that's hard is Prehistorik Man. I haven't seen an emulator aside from KiGB get that one in-game.

Sagon
November 28th, 2005, 07:59
2 bcrew1375, thanks for the good site, now I have more games to test.
2 ShizZie, thanks, my development process is slowed down too because of study, exams are near =))

bcrew1375
November 30th, 2005, 00:57
Has anyone gotten Interrupts Demo (PD) working? According to KiGB it's supposed to have a flashing line half way down the screen. I've never got that to show up. I even tried drawing the screen in blocks of eight instead of a whole line at a time.

ShizZy
November 30th, 2005, 04:13
Here's what I get. It's the exact same on Aprentice's and Darkstalker's emulators. Sagon's only has the garbage at the top, like KiGB, but no tiny blinking line (looks more like a glitch to me). The really old version of yours has no garbage. My old version didn't have the garbage, but I think that's supposed to be there. BGP is the exact same as mine. No$Gmb and VGBC both freeze, I think it has to do with checksum issues.

All and all, I don't think it's a good rom to test with, just about every emu handles it differently. Maybe it would be best to see it on the actual hardware.:P

bcrew1375
November 30th, 2005, 04:39
Well, I tried Prehistorik Man on a slightly older version of my emu, and it works! Yet I get a blank screen after the first two in the latest version. -_- I think it might be because I changed the way I was handling STAT modes, or the LY register. Mortal Kombat and Wave Race seem to love conflicting. If I don't emulate the serial interrupt, Mortal Kombat freezes at "Midway presents." If I do, Wave Race makes the program crash. -_-

ShizZie, got a flash cart? :P

smcd
November 30th, 2005, 05:38
Another one that's hard is Prehistorik Man. I haven't seen an emulator aside from KiGB get that one in-game.

bgb (1.11 is the latest) has no problems that i can tell with Prehistorik Man, it goes in game and is playable.

bcrew1375
November 30th, 2005, 07:41
Ah, so it can :). You know, since part of KiGB's goal is to make Gameboy emulators perfect, they should release some documentation. There's obviously some things that aren't mentioned in the documents I have.

Dark Stalker
November 30th, 2005, 15:24
Preshistoric Man works in-game on lameboy since before the first test release I made. Interrupts Demo looks the same as on vba on recent builds. The last release didn't include the fixes I made to window drawing, which is why it has garbage on the bottom too. KiGB and BGB seem to be the best emus compatibility-wise, the rest seem to do about the same as lameboy or worse from the games I've tested. I'm up to my neck in exams, so I haven't been able to do anything for lameboy lately, but I do have some plans for things that may improve accuracy further.

ShizZy
December 2nd, 2005, 22:11
Preshistoric Man goes in game here and is perfectly playable, but there's some slight glitching in the transition from the titlescreen to the actual game.

ShizZy
December 6th, 2005, 03:32
@bcrew... no flash cart, unfortunetly :( Almost bought one a while back too. As for the whole serial interrupt thing, my emu elso freezes at the Midway Presents screen in MK, even with serial emulated. (And Waverace is still fine) I guess one of us is doing something wrong, it's probably me.

bcrew1375
December 6th, 2005, 12:36
I forgot to mention I solved the serial thing a while back. Try requesting a serial interrupt if bit 0 and bit 7 of 0xFF02 are on, if bit 0 is not on, don't request one. This seems to keep Alleyway, Mortal Kombat, and Wave Race happy.

ShizZy
December 6th, 2005, 21:08
Nice catch bcrew. All 3 run perfectly here. Now the only game that doesn't work fully of my whole GB rom folder is SML2. Still crashes at the titlescreen :P

Edit: I noticed in your old old build of your emulator that you released a while back you have the same problem bcrew. You remember how you fixed it?

Also Edit, got Orcale Games working. Goes in game, but I have some nasty issues with vram bank switching. My GBC compat isn't half bad considering the little time I put into it though as I'm just finding out, but it's kind of buggy.

http://www.emutalk.net/attachments/programming/29941-game-boy-zeldaoracleshot.jpg

Atomizer
December 23rd, 2005, 01:43
Wow, ive finally reached the end! :)

Been reading this thread over the past few days, and have started on my own GB emulator, and this thread had kept me inspired, and has also helped me out quite a bit.
This is the first time ive worked on an emulator, and although I almost decided to switch to a chip-8 emulator, I stuck with GB and I now have some cpu instructions working, I know it probably doesnt sound like much, but I started with window and OpenGL drawing code, got a logger, memory manager and timer.

Anyway, I should get alot of the cpu instructions done today, if not all of them, and mainly just wanted to thank everyone who has been a part of this thread, and for those still around, keep at it! :)


I would like to ask a question though, unfortunatly not GB related, with my emulator, yesterday I decided I needed a second window to display debug info, however, it seems that when my second window turns up, I am unable to move it, theres no text in its title bar, and no other input seems to work on it, yet after trying to move the second window, if I click on the title bar of the first window it jumps to about where I tried to move the second window to.
Now im using standard win32 code to create my windows, and I have 2 seperate WndProc functions to handle messages, and ive logged the window handles and such on each message and the second window seems to be getting its messages properly, ive tried playing around with various window styles, including a child window(which just made the window appear inside the first one, rather then external), and im stumped.
Im sorry for asking this here since I know this should be about GB emulation, but im completely stumped, and msdn and google dont seem to help, if someone here can help, then ill accept any help I can get, but if not, you can just ignore this part :)

Cheers

bcrew1375
December 23rd, 2005, 04:04
Welcome to the group :P. I assume this is your first emulator? If so, it's probably not going to be easy. I had trouble understanding the IO registers when I started :D. I stopped and wrote a Chip 8 emulator, and I managed to understand it when I came back. Sorry, I'm not too experienced with Windows programming, so I can't help with your problem. I'll be happy to help with any GB questions if I can.

ShizZy
December 23rd, 2005, 04:18
I stopped and wrote a Chip 8 emulator, and I managed to understand it when I came back.
Unfortunetly, is chip8 isn't a "real" system, and thus it doesn't have io ports, interrupts, or timings. So you can only learn so much from the project. I think it's been pretty much the same for all of us, things just click once you've had enough experience with the emulation - and suddenly it all makes sense.

As for your win32 code, gonna need to see your source.

Atomizer
December 23rd, 2005, 04:27
Yep this is my first attempt, and yeah, while reading this thread, and I was having trouble understanding quite alot of stuff, and some people had mentioned trying chip8 first, so I actually started reading the chip8 thread(man these forums are a good resource :) ), but I was kind of starting to understand what I was reading about the GB, so I decided to stick it through, and im making decent progress now, so im glad I decided to stick with it.

At the moment I seem to be doing fine on the emulation side of things, anything I needed to understand previously I have mostly figured out, so things seem to be going ok, apart from the debug window, but ive decided to ignore that for now and just focus on doing the opcodes :)


EDIT: Adding my source, im still in the process of doing the CPU, and the rom location is currently hardcoded, im likely going to rearrange the memory variable locations though, since they need to be seperate, the registers too.

Oh right, almost forgot, the debug menu item is grayed, just remove the MF_GRAYED part from the following line(in gabe_main.cpp, line 231):
AppendMenu(g_hMainMenu, MF_STRING | MF_GRAYED, ID_DEBUG, "&Debug" );

bcrew1375
December 23rd, 2005, 04:51
Wow, looks like a nice start. Now, I don't want to seem big-headed, but it seems from the way some of your code looks, you may be getting ideas from the source I posted a while back. If so, it is horribly outdated, and I wouldn't rely on it too much. It is infested with bugs.

Atomizer
December 23rd, 2005, 05:30
Yeah I did borrow some, mainly just the defines and some register stuff, though I can see some of it is wrong and/or im not making much sense of it, but I am going through each instruction(from GMB%2D~1.TXT) and doing them myself, and using http://www.work.de/nocash/pandocs.htm#cpuinstructionset for flag/cycle info.
I am a little confused about the RLCA instruction though, in terms of the carry flag, but ive never come across rotation in variables before so im not sure what it should be doing.(I think it was answered in this thread, so ill be going back and going through it later)

HyperHacker
December 25th, 2005, 14:47
I haven't worked on mine in quite a while, but it's not cancelled, I just haven't got around to it. :p

Anyway, someone mentioned a bug where their scores were displayed in hex... this means your DAA opcode isn't working. It's a tricky bastard, I had a lot of problems with it as well (my score kept jumping to 999999 in Tetris :D). I still don't think it works right. Mainly I think I just have flag bugs and some timing problems though.

Can anyone provide info on MBC7? And there must be an MBC6 as well, info on that is also welcome. I've never heard of either.

LotsArs
January 12th, 2006, 13:06
Hi there,

Could anyone explain me the GBx rendering scheme (in terms of LCDC modes/stats/cycles)? I mean, how many cycles are executed while rendering a scanline, how many are spent on the HBlank, and how many on the VBlank. How are your emulator schemes handling this?

Thanks.

synch
January 12th, 2006, 14:33
Let's see, this is how it's handled in my emulator, but I don't think it's 100% correct (as of today, it runs only a few games).

A whole screen redraw lasts 17556 cycles, that are divided in:

One scanline lasts 110 cycles. The 20 first cycles are OAM Search (mode 10), from 20 to 70 are Data Transfer (mode 11), if cycles greater than that (70 to 110), then HBLANK is enabled, and I increment the LY (0xFF44) register.

Then, when cycles are greater than 16416, I enable the VBLANK (mode 00).

I should repeat, that it's probably very wrong, but it works for me as of today, enabling some games to work, but I guess someone will correct me, or give some proper numbers.

ShizZy
January 12th, 2006, 21:18
One scanline lasts 110 cycles.
That's wrong, it should be 114 machine cycles (456clcks/4) - the same period as a full vblank. Otherwise what synch said looks correct enough to get you started, and things working. Can't remember the exact details off the top of my head, but it's described in detail in the pan docs.

If I can remember, basically each scanline is as I said 114 cycles, in the order OAM, Transfer, HBlank. (all three periods occur each scanline) At the end of the scanline (HBlank) you draw that line and increment LY. When LY reaches 143 (end of the screen) you continue for 10 more lines (114cycles*10) in vblank period, without actually drawing anything. LY is still incremented, and remember to request a VBlank interrupt.

LotsArs
January 13th, 2006, 00:17
Thanks both, that clears it up.

Well, almost. What is the exact cycle count for each mode (0, 2, 3)? PAN docs just say "it lasts between m and n cycles". By taking the highest values, we have 207, 83, 175 (respectively), so we get 465 cycles per scanline, while it should be 456.

bcrew1375
January 13th, 2006, 00:25
I use the average of the two. So, (207 + 201 = 408), (408 / 2 = 204). So, H-Blank should last 204 clock cycles, or 51 machine cycles(204 / 4 = 51). Using the average of each should give you a total of 456 clocks, or 114 machine cycles.

aprentice
January 22nd, 2006, 21:02
decided to release my gameboy emus source so people could learn off it and maybe even help me track down bugs or hell even fix sound :P

i havent touched it in ages so theres some incomplete features but emulation wise its 99.9% complete, minus sound and 1 priority mode that ive never seen a game use yet..

contructive opinions on source welcome :P

synch
January 25th, 2006, 23:45
As this thread seems a bit too quiet, I'll post about my emulator :)

A few years ago, I coded a little (and VERY incomplete) cpu core, that didn't even run the simplest PD roms. Not to mention that it was totally lacking any LCD emulation.

As I always wanted to get some commercial roms to work, and as a break from bigger (and more complex) projects, I decided to give it another go 3 weeks ago. As all the code was done for MS-Dos, first I had to do a proper GUI. After getting a tile viewer and a dissasembler in the app, I started trying to get the Distortion rom to run. I noticed my cpu core was rather bad written, as it had about 6 years, so I rewrote about the 90% of it, and started emulating the display and all the rest.

It took me two full days without any sleep (aren't holydays nice?) to get it working properly, but it had some rather ugly timing and cpu bugs. The next week, I got the few other PD roms that were in my HD to work, and after a lot of debugging, got all them running nicely. Then, commercial games were the next target.

So I've spent the other 2 weeks fixing all the cpu/timing bugs that I could find, implementing mbc1 and mbc2, a memory and dissasembler dumper, and getting the dissasembler to a more usable state.

So, right now, I've about a 95% compatibility with the "Rom Only" games, and a less (maybe 70-80%, or less, I really hate testing hundreds of roms) for the mbcs, but I'm getting there.

As for speed, I get about 390-410 fps for the more cpu demanding games, running in a p4 2ghz with small cache (notebook computer :P), but I plan to get it to run faster when I spend some time profiling, as for now I've only applied common sense. The current bottleneck seems to be in the cpu core, as some early and hacky tests showed.

Nothing else, already wrote a lot, just two screenshots :)

Bye!

ShizZy
January 26th, 2006, 01:30
Nice job, really great to see others working on gb emus. Mine isn't dead, but I've been focusing all my programming time (what little I have) on some bigger more interesting projects.

Need to clean mine up a bit more, add some more options, and fix some very slight bugs and I think it'll be release ready.

aprentice
February 6th, 2006, 01:50
i've gotten requests for a compiled version of my source for executaboy, so here it is. For those of you that could compile it yourself, ignore this :P

wrayal
February 6th, 2006, 10:08
Hehe, many thanks aprentice.

Wrayal

Garstyciuks
February 20th, 2006, 13:27
Ok, I have just started making my 1337 GB emulator. I am using gb.pdf posted somewhere around 2-4 page of this thread for information about GB. I have got a question about the load instruction at page 65. Here is the description of it:

LD nn,n; nn = B, C, D, E, H, L, BC, DE, HL, SP
load nn into n
n = 8bit immediate value
cycles = 8
LD B,n 06
LD C,n 0E
LD D,n 16
LD E,n 1E
LD H,n 26
LD L,n 2E

How should I get the value of n? Is it in pc+1 (the byte after this instruction)? And shouldn't it be put n into nn, not opposite? Since all the other load instructions put the second parameter into first one.

Garstyciuks
February 20th, 2006, 18:32
Another question: How to emulate ADC A,n instruction? Its description is Add n + carry flag to A. As I understand this, it should add n to A and if carry flag is 1, add 1 to A?

synch
February 20th, 2006, 22:14
For the intructions like:

LD R, N (where R is a 8 bit register, and N is a 8 bit value)

The value is actually something alike to rom[pc+1].

For the ADC R, N it is like you told, so:

R += N+carry

Where carry is a boolean value, so either 1 or 0. I'll elaborate more if you need to, but right now I'm very tired :P

Garstyciuks
February 21st, 2006, 14:21
I am a bit confused about how to properly calculate the flags. Right now I use this to calculate the flags:
//ADD A,n
case 0x87:
F = 0;
if ((A&0x0F)+A>0x0F) F|= HALF_FLAG;
if ((u16)(A + A)>0xFF) F |= CARR_FLAG;
if (A+A==0) F|= ZERO_FLAG;
A += A;
cycles+=4;
pc++;
break;Is this correct? How should I calculate the carry (borrow) flags for SUB instruction?

HyperHacker
February 21st, 2006, 23:38
I'm not sure how correct this is, but this is what I use for subtraction. (It's probably slow being in its own function; I haven't optimized much yet. Hopefully you can guess what the other functions do based on their names.)


void Sub8(BYTE* reg1, BYTE* reg2, BOOL Carry)
{
ClearFlag(regF,FLAG_N);
if((*reg1) || (*reg2)) //If either is nonzero
{
int x = (int)(*reg1); //(*reg1) means value pointed to by reg1
x -= (int)(*reg2);
if(Carry) x -= (int)CheckFlag(regF,FLAG_C);
SetFlagTo(regF,FLAG_N,(((*reg1) & 0xF) - ((*reg2) & 0xF)) < 0); //Todo: should this be FLAG_C? (Probably not - using N fixes things)
(*reg1) = (BYTE)x & 0xFF;
SetFlagTo(regF,FLAG_Z,(*reg1) == 0); //Set Z flag if reg1 is 0, else clear it.
SetFlagTo(regF,FLAG_H,((*reg1) & 0xF) == 0xF); //Set H flag if reg1 & 0xF is 0xF, else clear it.
}
else //If both are zero, we only need to do this.
{
SetFlag(regF,FLAG_Z);
ClearFlag(regF,FLAG_H | FLAG_C);
}
}

Notice I use a single regF to hold the flag status, like the real GB does. This makes it easier to correctly emulate AF being pushed/popped. (Very important to note that a GB game can access the unused bits of F by pushing it, then popping it into another register. I've yet to try this on the real hardware though.)

Garstyciuks
February 24th, 2006, 14:53
SetFlagTo(regF,FLAG_H,((*reg1) & 0xF) == 0xF); //Set H flag if reg1 & 0xF is 0xF, else clear it.

When 00001000 is substracted from 00010011, the result would be 00001011 and it wouldn't generate half borrow flag? Maybe it should be if it is smaller or equal to 0x0F, not only equal.

HyperHacker
February 25th, 2006, 07:31
You may be on to something there. I'll make a note in the code, but it's not in a compilable state at the moment.

refraction
February 25th, 2006, 11:27
holy crap dude, hex posting ;p

seriously, i think you need to delete a few lol

Garstyciuks
February 25th, 2006, 16:20
This site is sometimes lagging really much, so he probably got a little angry that he can't post, so he clicked the post button a few times :P Does anyone know a site containing information about various types of flags?

refraction
February 25th, 2006, 17:44
all i can remmeber is

zero = when the result is zero (i think)
half carry = when bit 4 is carried over to bit 5
carry = when bit 8 is carried over to bit 9 / overflows (been so long since i touched GB i cant remember if its 8 or 16 bit registers :P)

Garstyciuks
February 25th, 2006, 19:34
How to actually find if bit 4 was carried to bit 5?

refraction
February 25th, 2006, 21:22
How to actually find if bit 4 was carried to bit 5?

dunno, never really figured it :D

i guess its something to do with if the original byte was less than 0xf and the result is higher, or something.

Garstyciuks
February 25th, 2006, 22:12
I guess something like ((A&0x0F)+(B&0x0F)>0x0F) would determine the half carry flag. A and B are 8bit values. What is the simplest rom with some kind of video output? I would like to test what I have made :)

I edited the half carry formula to a correct one, probably I was too sleepy when I was posting...

bcrew1375
February 26th, 2006, 02:38
Try Blem or Big Scroller Demo. Those were the first to show anything for me.

Garstyciuks
February 26th, 2006, 10:51
I can't find those two anywhere, could you upload it here? (I guess they are freeware, aren't they?)

hap
February 26th, 2006, 12:22
They're PD, see attachment. Visit http://www.pdroms.de/ for more..

I'm not gonna tell you how/where to get it, and you're not allowed to ask, but if you want to do proper testing, I suggest to get the GoodGBx romset.

|\/|-a-\/
February 27th, 2006, 17:48
please split this thread into different sub topics. i can hardly find any informations, because reading through 91 pages would take some time!
there are many pages with senseless content... if somebody here has ISDN, he'd understand, what i mean...

Falcon4ever
February 27th, 2006, 20:02
perhaps we should close this topic and create a newone. The first post should include all important hints and links to usefull documents.

Garstyciuks
February 27th, 2006, 21:54
Yeah, that would be good.

bcrew1375
February 28th, 2006, 01:58
perhaps we should close this topic and create a newone. The first post should include all important hints and links to usefull documents.

Couldn't the posts just be bumped down and an admin create a new first post?

|\/|-a-\/
March 1st, 2006, 17:24
so where should i ask my questions now?

I'm against changing the first post in this thread...
i think this thread is too big.

important informations for writing an emulator are:
1. where to get the docs (of course)
2. where to get demos
(demos for starting with the emu, demos for gfx and demos for testing)
3. informations which are not covered in the docs (e.g. big endian/little
endian)

question:
how do you think of


char regs[8]; //buffer for registers
char *A = &(regs[1]), *F = &(regs[0]);
char *B = &(regs[3]), *C = &(regs[2]);
char *D = &(regs[5]), *E = &(regs[4]);
char *H = &(regs[7]), *L = &(regs[6]);
short *AF = (short*) &(regs[0]);
short *BC = (short*) &(regs[2]);
short *DE = (short*) &(regs[4]);
short *HL = (short*) &(regs[0]);

Garstyciuks
March 1st, 2006, 20:07
For all the registers you could use a C++ (or is it C?) union. My one looks like this:


union reg_t
{
u16 r16;
struct r8_t
{
//u8 h;
//u8 l;
u8 l;
u8 h;
}r8;
};

I don't know if hi and lo order is right, but that is easy to change :P

ShizZy
March 1st, 2006, 21:26
You have it backwards, hi then lo, right?

albertwesker
March 1st, 2006, 21:49
a few months back, before i decided to write Mega, i had considered doing a gb emu. in an effort to make searching this thread for info better, i went through and copied the posts and wrote a script to parse the data and arrange it as html.

i've posted that doc on my server for anyone who wants it. it's outdated probably by a few months now, and the last few posts are being held in place with 'pre' tag, but if it's of any use to anyone, take it now. I'll leave it up for a few days.

http://www.infourmation.com/misc/emutalkgb.html

also, i only kept posts that seemed relevent. for example, statements like 'good job on your emu!!!111!!' or 'my emu now supports the new l337 scroller demo', were discarded. =]

Garstyciuks
March 1st, 2006, 22:12
You have it backwards, hi then lo, right?
I have commented te other variant of it. When I was trying to run something on my emulator, it didn't work quite well, so I tried the other order and didn't change back :)

ShizZy
March 1st, 2006, 22:41
It's been a while since I worked on my emu, so here's an early release. From the readme:


Nhes is an "experimental" Gameboy/GBC emulator. Currently, it runs ~95% of GameBoy games,
and about ~30% of Gameboy Color games. It was created as a learning project, and therefore
I have not taken the time to fully maximize its compatability. TBH as much as I enjoyed doing
this project, I've implemented all of the interesting features, so I no longer have any
motivation to work on it (there's nothing new and special to implement, and there's a million
other emulators with much better compatibility). At this point, the emu pretty much stands
final, though I will probably eventually get around to completing the menus, and reimplementing
a debugger.

Until then, Enjoy! (and a screenshot for possible motivation to any future gb emu coders)

http://shizzy.emulation64.com/Files/NhesBetaMar1/nhes_sample.jpg

Comments and Crits Welcome :)
(http://shizzy.emulation64.com/Files/NhesBetaMar1/NhesBeta.zip)

hap
March 2nd, 2006, 00:21
- timing's good
- controls are responsive
- nice icon ;)

Double Dragon, I played until the forest level boss.. and died :(
- pressing left+right makes the main char do a cool moonwalk (the GB has a d-pad, so left+right or up+down should not be possible)
- some sprite priority errors (easily visible at baddies/throwable objects)
- one sound channel missing, the bassline... probably the waveram channel ?

Super Mario Land, I played until world 2-1
- some sprite priority errors (eg when jumping near a moving platform)
- one sound channel missing, probably same as in DD
- score and #of coins are messed up (in hex)
- top statusbar scanline sometimes glitches when scrolling

Attachment is a short remix of the 1st level boss music of Double Dragon I've made for fun :P

|\/|-a-\/
March 2nd, 2006, 19:36
i think, i never need to do a byte swap in my code, because
A points to regs[0]
F points to regs[1]
(yea, it was wrong in my code...)

i heard that A is hi byte in AF. if i write 0xAABB to AF for example, my c++ compiler would write 0xAA to regs[0] (A) and 0xBB to regs[1] (F), exactly what i need.

so my conclusion is that byte swapping is only needed, if i write 16 bit values into memory, and if i understood everything right, i only must take care of instruction $08, LD (nn), SP

is this correct?

|\/|-a-\/
March 2nd, 2006, 21:07
I don't like this CPU...
being a lazy programmer my first target in writing a program is keeping the code in general as possible.

when i started the gb emu, the first thing i did, was to create a big table with all opcodes. an array of a struct, which defines the things i need to know later like, cycles for this operation, ptr to the function which emulates the respective instruction, parameters, and the type of their parameter.

"type of parameter" was an enumeration. if the param was a register, the type was "Ptr8", if the operand was placed immediately after opcode, type was called "PcVal8", if the parameter was an address kept in a reg, the type was "AddrPtr16", ...

later i had to realize, that this concept won't work. i realized, that flags are affected differently adding 8 bit values or 16 bit values.
so the function ptrs changed into:
ADD8 and ADD16 and ADDSP...

i became slowly angry, because my "clean" code structure was ruined more or less.

now i know it was just the beginning, there are exceptions over exceptions, which don't fit in my code structure, and every time i handle those "exceptions" the code gets a bit harder to read.

I never had those problems with emulating the 6502 in my nes emu...

the current problem is:
LD (nn), SP
LD (nn), A
the first parameter is "AddrPc16" in both cases... i'm very happy i realized, that in the first case a 16 bit value is written to (nn) and in the 2nd a 8bit value

the "general" way is to say "if source is 16 bit, destination has to be 16 bit, too", but this would need one of those ugly ifs

the easier way is to say "this is an exception, which appears once in the whole opcode list, change the function for emulating this (e.g. LDSP)"


now, i'm really interested, how you solved those problems... or better: do you ever have had such problems?

bcrew1375
March 3rd, 2006, 00:27
The Gameboy does have alot of annoying little bugs or design flaws that are annoying to take care of. The P1 controller register for instance. P1 has 8-bits, Gameboy controls have 8 buttons. Yet, the P1 register only allows you to read 4 buttons at a time by turning on/off 2 switches. Anyone seeing something wrong with this? Unless there was some kind of hardware limitation, there was no excuse for this.

As far as clean code, I did the best I could, but I had to make alot of compromises you just mentioned.

zenogais
March 5th, 2006, 21:25
I was actually able to keep my GameBoy emu relatively clean by picking up on certain patterns in the opcodes. Granted there's no 100% clean way to do this, but it did work quite nicely. When I get on my other comp I'll post some sources so you can see what I'm talking about.

aprentice
March 6th, 2006, 09:07
I was actually able to keep my GameBoy emu relatively clean by picking up on certain patterns in the opcodes. Granted there's no 100% clean way to do this, but it did work quite nicely. When I get on my other comp I'll post some sources so you can see what I'm talking about.

you're so focused on clean code, will your emu ever run anything? :P

Runik
March 6th, 2006, 09:57
@zenogais : stop starting emus you never finish :P

zenogais
March 7th, 2006, 05:00
@aprentice: It runs basic stuff, but as for whether I finish it or not...we'll see.

HyperHacker
March 10th, 2006, 06:39
Damn this lag... *deletes 5 duplicate posts from last time*

Anyway I tried using <= in place of == when setting the H flag during subtraction... just broke things. The line count in Mode B in Tetris jumps from 25 to 2A when clearing a line. o_O Course there seems to be a lot of bugs in my DAA handling code (actually just Aprentice's he posted a while back) and/or flags (my score jumps to 999999 when I clear a line) so who knows...

HyperHacker
March 10th, 2006, 08:19
I'm getting really weird results with the DAA instruction. I've hacked up a quick test ROM (not done yet, still some things to add) which can test it, among other things. (Go to TEST DAA OPCODE to start the test; feel free to test other things with it too.)

What I'm noticing here is that if I do this:

ld a,b
and a
call printhex
[...]
ld a,b
and a
daa
call printhex
I get weird results; 0 comes out as 6 and so on. If I omit the 2 "and a" instructions (as ld a,b doesn't set the flags), then it seems to function mostly normally. The results are the same on both No$GMB and bgb; I don't have any way to test it on a real GB at the moment. Can anyone explain this?

(BTW, if you want to assemble that big mess of code, use tniASM; a simple batch file is included, but it probably won't be of much use to you. :p tniASM is simple enough to use, though. Or just run the test.gb included.)

wrayal
March 10th, 2006, 20:02
Just out of interest, I am actually working on an emu - I've got every opcode except DAA emulated (I'm determined to write that for myself in spite of it being posted copy-and-paste-ready earlier in this thread ;) ). I'm fiddling with Memory and timings at the moment, but all my opcodes seem to work perfectly once I stopped being an idiot and wondering why the LY reg compare kepy failing for me sending me into an infinite loop (I didn't have it being incremented since I hadn't implemented timings).

Thanks for all the interesting chat on this thread guys - it's brilliant stuff to read.

Two questions though - which ver of the pandocs should I use? I've been using ver 1.01, but it seems to disagree on some flag settings when I trace through in both bgb and executa boy?

The other thing is, Shizzy, aprentice, I take it you are the two I've heard mentioned as working on a quickly progressing GC emu? If so, congrats!!

Wrayal

bcrew1375
March 15th, 2006, 06:37
I'm fiddling with Memory and timings at the moment, but all my opcodes seem to work perfectly once I stopped being an idiot and wondering why the LY reg compare kepy failing for me sending me into an infinite loop (I didn't have it being incremented since I hadn't implemented timings).

I had that exact same problem when I was started. It just sort of came to me as I got more experience :P.


Two questions though - which ver of the pandocs should I use? I've been using ver 1.01, but it seems to disagree on some flag settings when I trace through in both bgb and executa boy?

To my knowledge, this is the latest version http://www.work.de/nocash/pandocs.htm None of the docs seem to fully agree, but that one is the most reliable. All of them seem to have incorrect information, so you will probably have to collect what is right from different docs. Such as the halt bug. Some docs say it skips the next instruction, some say it repeats the next instruction. Unfortunately, many games require these bugs to operate correctly.

refraction
March 15th, 2006, 10:52
To my knowledge, this is the latest version http://www.work.de/nocash/pandocs.htm None of the docs seem to fully agree, but that one is the most reliable. All of them seem to have incorrect information, so you will probably have to collect what is right from different docs. Such as the halt bug. Some docs say it skips the next instruction, some say it repeats the next instruction. Unfortunately, many games require these bugs to operate correctly.


That sounds to me like an original limitation of the hardware rather than a miss informed document. The docs probably describe how it is suppose to work, but neglects the fact that this might have bugs in the original hardware.

HyperHacker
March 15th, 2006, 13:02
Well the behaviour the docs describe is a bug. :p Supposedly, the instruction after a halt is either skipped or repeated if interrupts are disabled.

What I most often hear is the first byte is repeated. That is, 12 34 56 is executed as 12 12 34 56. Again, no way to test on a real GB to find out. :(

bcrew1375
March 15th, 2006, 19:12
What I most often hear is the first byte is repeated. That is, 12 34 56 is executed as 12 12 34 56. Again, no way to test on a real GB to find out. :(

That's what I meant to say, It's the byte, not the instruction.

HyperHacker
March 16th, 2006, 02:10
Come to think of it, when people say it skips a byte, they could mean it repeats it, like how a record skips.

Falcon4ever
April 20th, 2006, 23:22
Finally after being punched by Shizzy a few times ;P
I decided to continue my Gameboy emu.

Currently I have quite some z80 opcodes implented. Altough I'm now struggling with the interrupts and IME.

This IME thing, do I need to create a BOOL for it? or is it a place in the memory. Because by looking at the docs i see 0xFFFF represents the Interrupt Enable Register. Not sure if this is the same.

hopefully one of you guys can help me out :)


attached a layout of the emu :P no gfx was implented yet so :P it's all black =]

Miretank
April 21st, 2006, 00:08
will it play Charlie Brown Jr.? :P

Falcon4ever
April 21st, 2006, 00:43
will it play Charlie Brown Jr.? :P
/me kicks Miretanks in the nuts

Charlie Brown Jr. is nice mkay :P?

ShizZy
April 21st, 2006, 01:28
Looks good. Yeah, just create a bool, set it in EI, and clear it in DI. Then check that bool when going to execute requested interrupts.

HyperHacker
April 21st, 2006, 02:13
Don't forget about RETI. Also 0xFFFF is Interrupt Enable, but it's not the same as IME.

bcrew1375
April 21st, 2006, 06:18
IME is Interrupt Master Enable, it's like a register. It's basically a universal interrupt on-off switch. It's turned on by EI or RETI, it's turned off by DI or when an interrupt is executed. The IF register is the interrupt request register. The IE register determines which interrupts are enabled. So, even if an interrupt is requested in IF, that doesn't mean it will be executed. An interrupt will only be executed if the IME is on, it is requested in the IF register, and it is enabled in the IE register. If IME is not on, then no interrupts are executed, even if enabled. You have to turn on the IF flags yourself when an interrupt situation occurs and clear them when the interrupt is executed. The IME and IE flags should be handled by the program for the most part. Sometimes the program will turn on the IF flags itself, usually to get some kind of special effect.

yosh64
April 24th, 2006, 19:27
hey

Well I just came across both Otaku No Zoku's GB Crib Sheet at http://www.otakunozoku.com, AND Adrian Brown's HTML version of it at http://www.enliten.force9.co.uk, and thought people here might find it handy.

Anyhows that's all... will have to complete my own Gameboy emulator oneday soon also. :)

Ohh yea, almost forgot to mention... I also found http://www.rawer.de/marc/Gameboy/Docs/GBCPU_Instr.html AND http://www.rawer.de/marc/Gameboy/Docs/Opcodes.htm FROM "B.2 Useful documents" section of http://www.rawer.de/marc/Gameboy/. =]

ALSO, http://www.z80.info maybe handy too... :plain:

cyas

Opfer
May 10th, 2006, 19:41
Alright, my gameboy emulator finally reached a state where I thought I could release it as version 1.0.

It's a gameboy emulator written in Visual C++, using unmanaged (native) code to do the emulation core and managed .NET and managed DirectX to do the GUI, graphics, sound and input.

I'm planning to release the unmanaged core as a dll so that other people can program some sort of client for the emulator.

I get about 10% processor load on my P4 3GHz, but if any of you have a rather old PC around, I'd be very glad if you could try to run it on that one and post how/if it works in the "Feedback" board on my site.

And since this is version 1.0 and I plan do release improved versions, I'd be really glad if you could give detailed feedback (in the "Feedback" board on my site) on how you like it, what you think I should add to it, and what you think I should improve or leave out, since I don't have an idea what features would actually be used by the common user, and I don't want to flood it with features that nobody actually uses. So feedback is greatly appreciated.

Oh and: Please report any bugs using the forum.

And finally, here's the link: http://multiserver.ath.cx/PowerCoding/

If you have any questions, feel free to ask.

synch
May 13th, 2006, 06:03
Probably my fault, but crashes when opening a rom. I can be more precise tomorrow, when I will have rested a bit. And why requiring the .net framework? My emulator uses winforms and .net, without requiring it, but probably due to using vc2003. (Didn't even care to check which version 2005 uses).

Seems that more or less, we have the "same" structure for the emulator: Managed (winforms rules!) for the gui, unmanaged for core. I'll try to compare speed when I'm able to run it to give some proper feedback :)

Opfer
May 13th, 2006, 09:32
Well, I don't know about older versions (like 2003), but in the .NET Framework 2.0, which is the only one you can use with VC++ 2005, Windows Forms and the .NET Framework is basically one package.

If it crashes when opening the rom, make sure you've got the most recent version of the .NET Framework (v2.0) and DirectX (April 2006 release). Also, while the emulation core seems to be pretty much bugless now, the GUI still does some random crashes that I haven't been able to track down yet (because they are random and therefore not reproducable). This includes some crash on startup, when it fails to initialize the managed JIT Debugger. So make sure you try it more than once. If it still crashes, I'd be happy if you could either email me the error report or post it on the forum.

ShizZy
May 14th, 2006, 04:11
Crashes for me right when I try and open it (the program itself). Why not just use a win32 gui? Emulators don't require extensive gui's, and win32 is much more compatable :)

Opfer
May 14th, 2006, 10:04
Well, after you made sure that you've got both the .NET Framework 2.0 and the DirectX Runtime (April 2006) installed (in the right order), and you still get the crashes, you could copy and paste the error report, which you get. (along with the module information on the second dialog window of the error report) and post it somewhere so that I can have a look at it.

I'm using the .NET Framework because it's far easier to use than native Win32 (especially since I don't have a forms designer for Win32). Also, the DirectX functions are accessible in a more comfortable way when using .NET.

And for the compatibility, in Windows Vista, .NET will be the language of choice when developing applications. Right now, there is a runtime that wraps the managed code into Win32 code, but on Vista, the managed code will be executed directly, and the native Win32 programming will be declared as deprecated and will sooner or later not be supported anymore.

Also, portability to other systems is easier, there is even a way to easily port .NET applications to Linux, since it doesn't depend on the OS's functions anymore.

And since the emulation core is completely independent from the gui, I don't have any speed problems, too, because the core is programmed using unmanaged code (unmanaged isn't a synonym for native Win32, I don't use a single windows library in that core code, it just means that I don't use .NET).

So .NET is the language of choice for me.

smcd
May 14th, 2006, 10:31
Also, portability to other systems is easier, there is even a way to easily port .NET applications to Linux, since it doesn't depend on the OS's functions anymore.


Not really.



So .NET is the language of choice for me.

Technically it's a platform ;)

Opfer
May 14th, 2006, 10:35
Not really.

Well, atleast that's what a friend of mine said, who is doing suff with linux.


Technically it's a platform ;)

Well okay, call it a platform then... ;)

HyperHacker
May 14th, 2006, 10:37
I'm using the .NET Framework because it's far easier to use than native Win32 (especially since I don't have a forms designer for Win32).
XN Resource Editor is... well, it's the only one I've found that works. <_<

Opfer
May 14th, 2006, 17:24
Okay, I released a new version of my emulator (check my website for more information).

The new version checks if managed DirectX is installed when being run, so that the ones of you that experience crashes should be able to get a useful error message (and if it isn't useful to you, post it somewhere, I will likely be able to tell you what it's about).

Also, I have now splitted the emulator completely into the managed GUI and the unmanaged DLL. There is also a SDK available on my site (on the forum), so that you can write your own GUI if you'd like to.

It also includes a few bugfixes (see changelog for more details).

smcd
May 14th, 2006, 22:05
The Mono project for linux is coming along rather nicely, though it still lacks support for some critical things such as Forms. Plus, it isn't compatible for .Net 2.0 as far as I know. I did some class projects using it a couple years ago. I was just being picky, but nice work and an interesting idea to make it separated like you did so if people don't like the interface they can make their own.

Opfer
May 14th, 2006, 22:13
Thanks and yea, that's the idea behind it.

To be honest, a friend of mine is already developing a GUI using Visual Basic and OpenGL. It's coming along pretty nice, was a bit of a mess in the beginning, because Visual Basic really doesn't like pointers that much ;), but right now, it already has input support and from what I hear from my friend, the graphics are working really nice, too. He's still having trouble with syncing but taking that not even 12 hours went into it so far, it's advancing nicely. It'll probably be put on the site, once it's done, too, so people can pick and choose and aren't required to download the .NET Framework and DirectX.

And now that you say it, I think it was mono that he was talking about, but him being a Windows hater he proabably overstated the capabilities of mono running .NET applications.

But, to another topic, I didn't get any feedback so far, I'd be really interested in how you like it, and what you'd change, so I can improve it.

Thanks

cloudy
June 9th, 2006, 18:37
hey all,

i coded a chip8 emu awhile ago, and am thinking of starting a gameboy emu now. I remember how the chip8 worked but cant seem to use that knowledge to start on the gameboy. My main problem is with the opcodes. For the chip8 you read in 2 bytes of data and combined them to form the opcode. You then converted this opcode to its hex equivelent so you knew what do with it as the opcodes for the chip8 were hex values. Looking at the gameboy opcodes they seem to be of form "ADD x,y" which is simple enough to understand but how do you derive these opcodes from the memory?

Thanks and sorry for the n00b question.

ShizZy
June 9th, 2006, 22:07
Each opcode is stored as a single byte in memory, the cpu doc should say what it is. If it has an immediate value, then that value follows the 8bit opcode as either one or two bytes.

huarifaifa
June 10th, 2006, 01:33
Hello guys,

This is my first post. I have been developing a Gameboy emulator (mono only) in Java in the last 6 weeks. I'm quite proud of the performance of the emulator (for Java, that's it). Right now, most of the CPU time is spent drawing the frame buffer on screen (roughtly 75-80% of the total CPU usage when the window size is 320x288).

The latest 2 weeks were spent testing and debugging the emulator with 1228 games. Most of them seem to be working fine, there are just 1 or 2 (as far I know) that are unplayable. I got bored of testing and re-testing so many games, so now I'd like to release it for the very first time in this forum, hoping to get some feedback :-)

For those willing to test it, just type:

java -jar gameboy.jar <romfile.gb>

in the command prompt. It should work fine with Java 1.5 in Windows and Linux (It should also work with Java 1.4, but I haven't tested it).

In the mean time, I'd like to ask :-) if someone can help me with the following issues:

- Information about HuC1, HuC3 and what is the "Rumble" thing of MBC5 (HuC1 seems to be almost identical to MBC1)

- LCD interlacing. How does it work?

- Sound. I still hear some glitches here and there. Also, anyone has more information about "zombie" channels? (ie. for Prehistorik Man and Little Endian in Big City).

- Muhammad Ali's Boxing. Anyone had problems with the graphics of this game?

- Star Trek - 25th Anniversary. My emulator gets locked. Any ideas?

- Mortal Kombat 3. The game gets locked randomly when the IRQ handler is called when LY=152 (the game gets locked waiting for LY=154). After a lot of tweaking, MK3 seems to work fine most of the time, but the race condition is still be there.

- Sonic 3D Blast 5. This is a pirate game as far I know. I don't emulate it because it has CPU instructions in the cartridge header! (ie. the cartridge type in the header is 0xEA, the opcode of a CPU instruction!). How do I determine the MBC type, ROM/RAM size, etc. in this case?


That's all for now :-)

Thanks in advance!

Lordus
June 10th, 2006, 11:11
As i am interested in Java emulation myself, I tried your emu and it works really good here. Great job.

bcrew1375
June 11th, 2006, 00:59
hey all,

i coded a chip8 emu awhile ago, and am thinking of starting a gameboy emu now. I remember how the chip8 worked but cant seem to use that knowledge to start on the gameboy. My main problem is with the opcodes. For the chip8 you read in 2 bytes of data and combined them to form the opcode. You then converted this opcode to its hex equivelent so you knew what do with it as the opcodes for the chip8 were hex values. Looking at the gameboy opcodes they seem to be of form "ADD x,y" which is simple enough to understand but how do you derive these opcodes from the memory?

Thanks and sorry for the n00b question.

The attached file has alot of information on the Gameboy along with the instructions and their opcodes. The opcodes are near the bottom.

huarifaifa: I'm not sure about the other games, but I tried Star Trek. I'm not sure if it's the same one. It doesn't have 25th Anniversary in the name. Anyway, it works flawlessly.

HyperHacker
June 11th, 2006, 03:13
FYI, the HTML version (http://www.work.de/nocash/pandocs.htm) seems to be more up to date.

bcrew1375
June 11th, 2006, 05:29
Yeah, but I'm not sure that has all the opcode numbers.

huarifaifa
June 11th, 2006, 06:33
Thank you Lordus and bcrew1375 for testing my (unnamed) emulator :)

Today I fixed Muhammad Ali and Star-Trek (I wasn't raising the H-Blank IRQ under certain conditions, and I had to change the timing of the Transfer and H-Blank to avoid timing/race-conditions with Star-Trek).

I'm now quite lost about how to correctly handle the OAM, H-Blank, and LY=LYC interrupts. Currently what works best for me is:



// raise OAM interrupt if LY=LYC IRQ is(was) not raised in this line
if ((stat & 0x20) != 0 && (stat & 0x44) != 0x44)
interrupt.raise(LCD)

// the same thing for H-Blank interrupt
if ((stat & 0x08) != 0 && (stat & 0x44) != 0x44)
interrupt.raise(LCD)


does that makes any sense?

Also, when the CPU writes the LYC register, when should it raise the LY=LYC interrupt? If I don't raise it, Muhammad Ali fails, and if I raise it, Prehistorik Man fails. What I do now is:



void setLYC(int value)
{
lyc = value
if ((lcdc & 0x80) != 0) {
if (ly == lyc) {
if ((stat & 0x04) == 0) { // do not raise it "again" for the same line.
stat |= 0x04;
if ((stat & 0x40) != 0)
interrupt.raise(LCD)
}
}
else {
stat &= 0xFB;
}
}
}


is that right?

PS: Edited to add Code tags and fix a bug in the sample code :)

HyperHacker
June 11th, 2006, 09:53
Code tags, man!

void setLYC(int value)
{
lyc = value
if ((lcdc & 0x80) != 0) {
if (ly == lyc) {
if ((stat & 0x04) == 0) { // do not raise it "again" for the same line.
stat |= 0x04;
if ((stat & 0x40) != 0)
interrupt.raise(LCD)
}
}
else {
stat &= 0xFB;
}
}
}

bcrew1375
June 11th, 2006, 21:57
Well, HyperHacker is right, but I can't find anything wrong with it aside from that.

huarifaifa
June 11th, 2006, 22:22
Well, HyperHacker is right, but I can't find anything wrong with it aside from that.

The "patch" is the "if" line:



// avoid raising the interrupt multiple times in the same line
if ((stat & 0x04) == 0) {
...
}


I haven't seen that in other emulators (VisualBoyAdvance, gnuboy, etc), so I'm wondering if that is right (or if I'm just hiding the real bug with this "patch").

huarifaifa
June 17th, 2006, 01:48
Since this thread is quite quiet lately, I'd like to report the progress of my emulator :-)

I have managed to emulate Zerd no Densetsu's scrolling text in the menu perfectly! I had to tweak the HALT instruction, for those who might be interested.

Now all the games I have (1228+) are running without any known problems, including Muhammad Ali, A-Force, Star Trek 25th Anniversary, King of Fighters 95, Mortal Kombat 3, Stunt Race FX, Prehistorik Man, Railway, Sonic 3D Blast 5, Double Dragon 3, Mr. Do!, Thunderbirds, Ant Soldiers, Ghost 'N Goblins, Amazing Penguin, Alfred Chicken, Cliffhanger, Out of Gas, NHL Hockey 95/96, Undoukai, Killer Instinct, F-1 Pole Position, Magic Maze, Total Carnage, Super Scrabble, Altered Space, and Jeep Jamboree!

I'm now porting the Java code to C++. Hopefully I will have a working emulator running in my Palm in a few weeks :)

Cheers.

huarifaifa
June 20th, 2006, 00:40
I took me 2 days to fully port the Java code to C++ using mingw32 (g++) and the SDL library! I get 1250+ fps on my P4 1.40 GHz machine playing Kirby's Dream Land 2 :-)

huarifaifa
July 3rd, 2006, 22:07
Since this thread is so damn quiet lately :) I'll make some noise.

I finished the port of my GameBoy emulator to the Palm OS platform. It runs quite well given the limited resources of my Tungsten T2 (ARM 144 MHz, 32MB RAM). I'm able to play Super Mario Land 2, Donkey Kong Land 3, etc. at 320x288 30 fps with audio at 22050 Hz.

Now, I will start working in the GUI and hopefully release it in a few weeks.

TJA
July 4th, 2006, 09:59
Hi all,
Well after almost 8 mounths without touching my emu, I finally finished uni and have a job lined up that doesn't start till next month. Therefore I have plenty of free time at the moment. Anyway, I have a question. I'm ready to implement some graphics for my emu but I'm unsure when I should be updating the display, do I update it straight after writing to video memory, any help on this and inplementing gameboy graphics in general would be appreciated.

Cheers, TJA.

ShizZy
July 4th, 2006, 17:39
huarifaifa - sounds great.

TJA - every 114 machine cycles, or 456 clock cycles, you draw one of the 144 screen lines - if I recall correctly. After that there is a vblank period for 10 scanlines.

huarifaifa
July 6th, 2006, 20:58
I'm ready to implement some graphics for my emu but I'm unsure when I should be updating the display


As ShizZy said. Draw each line every 114 machine cycles on your offscreen bitmap, and then blit it on screen during the V-Blank period, ie. something like:



while LCD Enabled do

for LY = 0 to 143 do
// OAM
LCD Mode = 2
wait 20 cycles

// Transfer
LCD Mode = 3
wait 43 cycles

// draw line using the current LCD registers (LY, LCDC, STAT, SCX, etc.)
drawLine(LY, LCDC, STAT, ...)

// H-Blank
LCD Mode = 0
wait 51 cycles
end for

// show the offscreen bitmap on screen
showFrame()

// V-Blank
LCD Mode = 1
for LY = 144 to 153 do
wait 114 cycles
end for

end while


It's usually implemented as a state machine (unless your programming language supports continuations :).

There's some "weirdness" in the line 153 not shown here, and some games (like Prehistorik Man, Parodius, etc.) that need a more accurate way to draw each line, but most games should run fine.

TJA
July 6th, 2006, 21:42
Thanks, huarifaifa and shizzy. I understand this now thanks to your posts and examining the tech docs I have. Hopfully I shall have this implemented by the end of tommorrow, or if not the end of the weekend ( looking a my code I found some other things I need to implement first ).
Anyway wish me luck hopefully I should have a screenshot to show off sometime next week.

Cheers, TJA.

TJA
July 12th, 2006, 20:02
Hey guys I’ve implemented the start of my graphics, but are now stumped.

Here is the code I’m currently working on:

void draw_win()
{
unsigned char *tile_map, *tile_data;

if( LCDC&0x40) // select Windows tile map display
tile_map = &RAM[0x9C00];
else
tile_map = &RAM[0x9800];

if ( WX > 166 ) // makes sure window is visable
return;

if ( LY >= WY ) // only draw if LCD y position up to or equal the window position
{
what do I do now???
}
}
//draw line using the current LCD registers (LY, LCDC, STAT, SCX, etc.)
void h_blank()
{
//if (LCDC&0x01) draw_back();
if (LCDC&0x20) draw_win();
//if (LCDC&0x02) draw_obj();
}

It seems the document I have do not have enough detail to implement this from them.
For instance how do I know which pattern in the tile data table to draw?

Any help would be appreciated.

Cheers, TJA.

huarifaifa
July 13th, 2006, 17:03
It seems the document I have do not have enough detail to implement this from them.
For instance how do I know which pattern in the tile data table to draw?
Cheers, TJA.

Check out the Pan Docs:

http://www.work.de/nocash/pandocs.htm#vramtiledata

It's (almost) all explained there.

The tile data for BG and WIN starts at address 0x8000 or 0x8800, ie:



if(LCDC&0x10)
tile_data = &RAM[0x8000];
else
tile_data = &RAM[0x8800];


The format of the 8x8 / 8x16 tiles is explained in the Pan Docs.

Carlos

TJA
July 18th, 2006, 22:27
Thanks huarifaifa, I already had this document but had forgot about it, this should help alot, hopefully I will have some graphics displaying by next week, little busy at the moment as I are moving to a different city in a couple of weeks to start my new job.

TJA.

Helius
July 24th, 2006, 23:46
Hi all!!

After writing a Chip8 emulator for J2ME devices (http://www.emutalk.net/showpost.php?p=336235&postcount=697) I decided to start a GameBoy emulator using C#.

I have spent a month on and off to code all CPU opcodes and now I have finally completed it. Still buggy opcodes but it can load some games like Dr Mario to the splash screen.

A lot of work to do now, interrupts, io ports, input... but things are getting more interesting :)

Keep up the good work guys.

ShizZy
July 24th, 2006, 23:49
Nice job dude :)

aprentice
July 25th, 2006, 14:51
ah the good ol' gameboy coding days :P

huarifaifa
July 27th, 2006, 23:22
I have finally released my GameBoy emulator at SourceForge:

http://sourceforge.net/projects/mario

There're binaries for PalmOS, Windows and Java.

hap
July 28th, 2006, 10:57
Looks and sounds good! But playing games on it was annoying:
- The window is SO small (add a window zoom option, eg. mario xxx.gb -4 quadruples the window size, or a fullscreen option even, but that's a bit harder to implement).
- Buttons are placed wrongly, B should be to the left of A, Select to the left of Start (Select/Start shouldn't on top of eachother).

huarifaifa
July 28th, 2006, 20:45
> Looks and sounds good! But playing games on it was annoying:

Thanks!

> The window is SO small [...]

The Java version has the window size doubled (320x288). I'll check out if there's an easy way to scale the window in the C++ version (which uses SDL).

> Buttons are placed wrongly, B should be to the left of A, [...]

Yes, I "naturally" defined that layout (I'm left-handed) without knowing the actual button placement in a real GameBoy. I will change that to make it "not wrong." :-)

Carlos

EdgEy
August 8th, 2006, 00:26
After looking at this topic for a while I decided to start coding a GB emulator.. so far I just have most of the core done (interrupt related opcodes aren't done).. nothing else really. this screenshot is me just dumping areas of ram to the screen ..

ShizZy
August 8th, 2006, 03:24
Nice job

EdgEy
August 11th, 2006, 00:35
Thanks ShiZzY :)

Unknown bugs are stopping me from running a lot of games

Tetris... doesn't seem to write tiles to vram or anything, but i have gotten a few demos to work (Big scroller works exactly the same as in VBA, landscape demo works, Merry Christmas demo works with a few bugs - neither have sprites yet)

:bouncy:

_Zack_
February 25th, 2007, 15:09
wow this thread hasnt seen activity in a while. Now that my chip8 emu is almost done im looking to port a gameboy emu.

bcbrew i noted that you used sdl in your emulator...

i wondered if i could have your latest source so i can port it to the psp?

or if anyone else has a early working emulator that would be great too :)

cheers

hap
February 25th, 2007, 15:33
or write one from scratch :)

1: You get to know the Gameboy ins and outs better: much easier to fix imperfections and bugs.
2: It's a lot more fun!

_Zack_
February 25th, 2007, 15:54
or write one from scratch :)

1: You get to know the Gameboy ins and outs better: much easier to fix imperfections and bugs.
2: It's a lot more fun!

yeah not a bad idea hap ;)

Do you think i would be able for the challenge of making a gameboy emu from scratch after only porting a chip8 emu?

if so il start ;)

i assume writing the cpu core is the first thing to start with

cloudy
July 19th, 2007, 20:18
Hey all,

I just need confirmation about how the gameboy opcodes work. All opcodes are 1 byte in size and the immediate data can be between 0 and 2 bytes correct?

So when i read the gb game into a byte array, i take it i should read the opcode first and the read the next index in the array as the immediate value (assuming of course that the opcodes immediate data is 1 byte).

So for instance the opcode 06 loads 1 byte of immediate data into register B.

So if for example i hexedited the gb game and seen the instruction 06AA. I would then load the value AA into register B?

So for example is this correct (psudo code):



opcode = byteMemory[instructionPointer] ;

switch(opcode)
{
case 06:
register[REG_B] = byteMemory[instructionPointer+1];
instructionPointer += 2; // is this correct? for a load opcode anyway
}


Thanks for any help

Edit:

Whats the deal with opcode 7F?

You have to Load RegisterA into RegisterA... whats the point?

Cyberman
July 20th, 2007, 03:08
opcode = byteMemory[instructionPointer] ;

switch(opcode)
{
case 06:
register[REG_B] = byteMemory[instructionPointer+1];
instructionPointer += 2; // is this correct? for a load opcode anyway
}
Thanks for any help

Edit:

Whats the deal with opcode 7F?

You have to Load RegisterA into RegisterA... whats the point?It's another variant of the NO OP Op Code :)
And try posting in the Game Boy thread next time (moved).

cloudy
July 20th, 2007, 11:56
sorry for wrong thread. Can anyone help me with my original question though? Thanks

bcrew1375
July 23rd, 2007, 04:38
The basic operation is correct. However, don't forget you also need to account for timing. You need to keep track of the CPU cycles if you don't want your emu to go insanely fast. Some operations will also require manipulation of flags. There are Z, N, H, C. Some of the redirection operations require the flags be set properly in order for the program to run as intended. If you need more help, feel free to ask.

cloudy
July 23rd, 2007, 12:37
Thanks for the reply,

Although I am aware of the timing issues with the gameboy i havent thought of the best way to implement them, i'll need to think about that.

Another question I have is to do with the following Opcode

Load Register HL into Register A

Registers are 1 bytes large and to get 2 byte registers they combine two of the registers (as im sure you are aware). Now the above instruction seems to be copying 2 bytes of data into 1 byte of storage space. As this isnt possible im guessing that the HL register in this case is acting as a pointer and i need to dereference and then copy that content into the regiser A?

So if i Register H contained 0x2A and Register L contained 0xFF, would i need to do the following?

Register A = m_GameMemory[0x2AFF] ; // this is a byte array

Thanks for any help

bcrew1375
July 23rd, 2007, 22:11
Yes, that's exactly what you're supposed to do with that instruction. As far as timing, I'm not sure if my own is right, so it's probably better to let someone with a more compatible emu answer that.

aprentice
September 1st, 2007, 00:29
Was reading through some of the programming thread and realized i've released the source to my chip8 emu but not gameboy emu, so here it is! my cpu uses precalculated flags for speed if anyone is interested in having a look. I never got around to getting sound to work although theres sound code in there for staters. Theres also zip support if anyone is interested if seeing how its done. Hopefully new emu coders can learn off this code and make some use of it rather than it just dusting on my hd. Any feedback welcome.

Exophase
September 1st, 2007, 09:01
Was reading through some of the programming thread and realized i've released the source to my chip8 emu but not gameboy emu, so here it is! my cpu uses precalculated flags for speed if anyone is interested in having a look. I never got around to getting sound to work although theres sound code in there for staters. Theres also zip support if anyone is interested if seeing how its done. Hopefully new emu coders can learn off this code and make some use of it rather than it just dusting on my hd. Any feedback welcome.

Using tables for flags are an interesting approach.. the biggest concern I have would be cache thrashing. Especially if the higher order index changes a lot (happens to be a loop variable, for instance) you'll lose a lot of locality for it. Other than that, you could make the add table 257x256, rather than 257x257, then have the carry potential be in the first part. That way you won't have to do a multiplication to get to the index. And I'd get rid of the zero flag table.

hap
September 1st, 2007, 10:10
Yes, big tables will definitely have an impact on speed, try to stay away from them with simple calculations (the reason I use one table is for the P flag). Or did you use a profiler and found out this method was faster?

You've released your GB emu source already in Jan. 2006 btw ;)

aprentice
September 1st, 2007, 22:49
Yes, big tables will definitely have an impact on speed, try to stay away from them with simple calculations (the reason I use one table is for the P flag). Or did you use a profiler and found out this method was faster?

You've released your GB emu source already in Jan. 2006 btw ;)

i've compared my tables to a non tabled build and the speed increase was huge, but when i coded it i kind of expected more, oh well, you learn from trying and i always like to try new approaches when it comes to things to find out what works better

Cyberman
September 2nd, 2007, 01:18
How about a Dynamic Recompiler? :)
Actually a static recompiler might work well, it would however take a LONG time to recompile a game into new code. Dynamic Recompile has an advantage over static in that it requires no optimization passes. Self modifying code though is a nasty habit of certain programers.

Cyb

Exophase
September 4th, 2007, 18:24
How about a Dynamic Recompiler? :)
Actually a static recompiler might work well, it would however take a LONG time to recompile a game into new code. Dynamic Recompile has an advantage over static in that it requires no optimization passes. Self modifying code though is a nasty habit of certain programers.

Cyb

Assuming pure static recompilation is really possible in the first place (self modifying code was very common in old games, and in consoles with RAM and ROM spaces you often saw code copied around to RAM for higher performance), why would it require optimization where dynamic recompilation wouldn't? And it wouldn't take that long, even if you recompiled the entire cartridge, which you'd have to (and have a table for all possible entry points).

bronxbomber92
October 17th, 2007, 00:36
Hi,

I'm just starting my CPU, and I think I found a mistake in the doc (it's the GB.pdf posted earlier, page 65).



1. LD nn,n
Description:
Put value nn into n.
Use with:
nn = B,C,D,E,H,L,BC,DE,HL,SP
n = 8 bit immediate value

Opcodes:
Instruction Parameters Opcode Cycles
LD B,n 06 8

So, that's saying: n = register B. Isn't it suppose to be the other way around? If this is an error, does anyone know of any other errors?

Thanks

Edit - I also can't find this specific opcode (written like in this format) in any other docs. Which is the most complete document for the cpu I can follow?

Exophase
October 17th, 2007, 02:03
Edit - I also can't find this specific opcode (written like in this format) in any other docs. Which is the most complete document for the cpu I can follow?

Try this:

http://www.work.de/nocash/pandocs.htm

And this:

http://www.romhacking.net/docs/GBCribSheet000129.zip

Pan docs appears to be missing some vital information. Judging by the crib sheet here are some ambiguous ones:

First, 8bit registers are encoded like this:

0 - b
1 - c
2 - d
3 - e
4 - h
5 - l
6 - (hl) (memory location)
7 - a

16bit registers are encoded like this:

0 - bc
1 - de
2 - hl
3 - sp

Now for the unclear instructions.


ld r,n xx nn
00XXX110 NN

X is destination register, NN is 8bit immediate.

ld r,r xx
ld r,(HL) xx
01XXXYYY

X is source register, Y is destination register.

ld rr,nn x1 nn nn
00XX0001 NNNN

X is destination, NNNN is 16bit immediate.

ALU operations are identified by an 3bit code:

0 - add
1 - adc
2 - sub
3 - sbc
4 - and
5 - xor
6 - or

ALU operations against against A are as follows:

10OOOXXX

O is the operation, X is an 8bit register (destination)

ALU operations against an immediate are:

11OOO110 NN

push rr x5
110XX101

pop rr x1
110XX001

X is a 16bit register.


... I don't feel like doing anymore, you can probably figure them out from here. >_<

bronxbomber92
October 20th, 2007, 04:22
Hi, I've got another question.

I'm working on opcode 0xF8 - LDHL SP, n

The part I'm unsure is setting the half carry and carry flags. In the docs it says if a carry occurred in the lower nibble then you set this the half carry flag. So, that would mean the lowest 4 bits. But in the pandocs here: http://www.work.de/nocash/pandocs.htm#cpuregistersandflags it says 0xFF, not 0xF. I'm not sure what to go by.

Here's what I've got. Does it seem correct? I think it is... But if everything I thought was right, was.. Well then, I think the world would be a very odd place :)

//0xf8
void ldhl_sp_n()
{
int n = Fetch();
int value = (sp + n) & 0xFFFF;
h = value >> 8;//value & 0xFF00;
l = value & 0x00FF;
SetFlag(Z);
SetFlag(N);
if( sp + n > 0xFFFF )
SetFlag(C);
else
ResetFlag(C);

if( (sp & 0xF) + (n & 0xF) > 0xF )
SetFlag(H);
else
ResetFlag(H);
}

Ananke
October 28th, 2007, 17:10
Hi

I'm also working on a gameboy emulator and my question is if it is essential when I call the Hblank Interrupt.
Until now I did it like this, but I couldn't get anything on the screen:



while (Halt ==false)
{
opcode = GetOpcode(PC);
PC++;

ExecuteOpcode(opcode);

if(MachineCycles>=451)
{
Hblank();
MachineCycles = 0;
}
}

Exophase
October 28th, 2007, 19:38
Hi, I've got another question.

I'm working on opcode 0xF8 - LDHL SP, n

The part I'm unsure is setting the half carry and carry flags. In the docs it says if a carry occurred in the lower nibble then you set this the half carry flag. So, that would mean the lowest 4 bits. But in the pandocs here: http://www.work.de/nocash/pandocs.htm#cpuregistersandflags it says 0xFF, not 0xF. I'm not sure what to go by.

Here's what I've got. Does it seem correct? I think it is... But if everything I thought was right, was.. Well then, I think the world would be a very odd place :)

//0xf8
void ldhl_sp_n()
{
int n = Fetch();
int value = (sp + n) & 0xFFFF;
h = value >> 8;//value & 0xFF00;
l = value & 0x00FF;
SetFlag(Z);
SetFlag(N);
if( sp + n > 0xFFFF )
SetFlag(C);
else
ResetFlag(C);

if( (sp & 0xF) + (n & 0xF) > 0xF )
SetFlag(H);
else
ResetFlag(H);
}

I think you're right about carry/halfcarry (and didn't see anything in the Pan Docs to suggest otherwise..). However, both docs confirm that Z and N should be set to 0 by this operation (not 1).

You might want to factor this out for the other two 16bit adds since the logic is basically the same for both (except the increment HL one doesn't set Z to 0)

|\/|-a-\/
October 28th, 2007, 20:02
I searched in this thread for the keyword "sound", but found nothing what could help me. I don't understand exactly, when to play sound. Only after a write to the channel's "initialize" flag?

Ananke
November 11th, 2007, 01:07
Can anyone tell me how to calculate the number of cycles till the HBlank period?
Because when I calculate 4194304/9198000 the result is not an even number.

yosh64
January 10th, 2008, 03:24
hey

@Ananke: Well I think you should only need to worry about HBlank timing for the STAT interrupt, which is explained in the Pan Docs.

Hmm, if you are just trying to get video then all you need to worry about is the VBlank timing/interrupt.

I think the STAT interrupt is used only for special effects and such, so most games should work with just the VBlank interrupt. Hmm, maybe the Timer counter/interrupt, and maybe the DIV counter also, but I don't really remember.

Anyhows for VBlank, I just calculated how many instruction cycles occur per scanline, and used a counter... so when the counter hits 144, you are in VBlank.

Scanline Rate = Clock Speed / Horiz Sync = 4194304Hz / 9198Hz = 456.001739509.

So every 456 instruction cycles you increment the scanline counter :).

BTW, I think alot of docs refer to Horiz Sync as 9198KHz, but I think it is really 9198Hz, and all my calcs indicate so.

Well if you do... Clock Speed / Vert Sync = Refresh Rate (number of instruction cycles per screen refresh), and then... Refresh Rate / Number of Scanlines = Scanline Rate (number of instruction cycles per scanline)???

So... 4194304Hz / 59.73Hz = 70221.061443160890674702829398962 and... 70221.061443160890674702829398962 / 154 = 455.98091846208370567988850259065.

Anyhows someone might wanna confirm all of this, as I'm not completly sure on things.

edit
To answer you question I will just quote from the LCD Status Register (http://nocash.emubase.de/pandocs.htm#lcdstatusregister) section of the Pan Docs (http://nocash.emubase.de/pandocs.htm)...



Mode 0 is present between 201-207 clks, 2 about 77-83 clks, and 3 about 169-175 clks. A complete cycle through these states takes 456 clks. VBlank lasts 4560 clks. A complete screen refresh occurs every 70224 clks.)


I think all this seems to agree with what I have said above :). As they say a complete cycle through these states is 456 cycles, and a complete screen refresh occurs every 70224 cycles. Although the later figure differs slightly? Hmm, not exactly sure why either?

cya

CodeSlinger
May 27th, 2008, 09:35
Hi Guys,

After finishing my chip8 emu I thought the next logical step would be a gameboy emulator. I'm currently implementing the cpu opcodes but getting stuck on the basics. Without knowing any assembler language and only codng a chip8 emulator the learning curve is seeming very steep at the moment. Much steeper than learning the chip8 was.

Still sounds like a fun project.

So please excuse my n00b questions:

1. Opcode 0xC3 is a jump opcode and the description is the following:

Jump to address nn, where nn is two byte immediate data, LS byte first.

So if i had the following in memory

C3 AB CD

the C3 command will do the following?



int jmp = m_MemoryAddress[m_ProgramCounter+2] << 8 ;
jmp |= m_MemoryAddress[m_ProgramCounter+1] ;
m_ProgramCounter = jmp ;


2. As you can see with the above opcode, when it uses 2 immediate data bytes does it always do LS byte first, or only if it specifies?

For example opcode 0x01 loads two immediate byte into register BC. But this doesn't specify if it is LS byte first.

3. One of my main issues is with the difference between the following:

ld HL, nn ;
ld (HL), nn ;

What difference does putting brackets around the register signify and how is this implemented?

I'm guessing that it is something to do with the address of the register and not its contents, but im getting a bit lost with how it works.

Actually i just had an idea, could (HL) be reffering to the actual game memory, for example if the contents of HL was 0xAB then would it be the following:

m_GameMemory[0xAB] = nn ;

4. Last question :-P

Opcode E2 is LD ($FF00+C), A

what does $FF00 represent? Is it game memory again? So if C was 0xBC would i have the following:

m_GameMemory[0xFFBC] = A;


Thanks guys for any help.

BTW im reading the entire rom into a byte array and not accessing it via pages or anything, just one big byte array. Anything wrong with this?