What's new

Game Boy

refraction

PCSX2 Coder
that was a question i was going to ask, now im actually working on the development of a GB emu (yes i know i said i started ages ago, but i gave up on programming for a bit :p)

The timing seems to be a big factor in compatability, and now ive written the Z80 core from scratch, i would like someone to explain (aprentice this is where you jump in!) how the time works, what it triggers, where is it kept to be counted etc..

If its mentioned in some docs tell me which n ill have a look, but ive got so many now i dont know which one to look at!
 

bcrew1375

New member
The menu problem is definitely something to do with the window. I can pretty much guarantee that. You should look into your window drawing code for problems.

refraction: The time counter is kept at 0xFF05. It goes from 0-255. When it exceeds 255, it is loaded with the value at 0xFF06. The timer on/off switch and the frequency is kept at 0xFF07.
 
Last edited:

refraction

PCSX2 Coder
bcrew1375 said:
The menu problem is definitely something to do with the window. I can pretty much guarantee that. You should look into your window drawing code for problems.

refraction: The time counter is kept at 0xFF05. It goes from 0-255. When it exceeds 255, it is loaded with the value at 0xFF06. The timer on/off switch and the frequency is kept at 0xFF07.


is it incremented by the number of cpu cycles each opcode takes? or by one every cycle?
 

bcrew1375

New member
It's incremented according to the frequency. So, if the frequency is set at 4096 Hz, then the time counter is incremented 4096 times a second. To get the number of cycles, you would take the total cycles ran a second and divide by the times the time is updated per second. So, if you use the machine speed(1.048576 MHz, I think), 1048576 / 4096 = 256. Not entirely sure this is correct. Can you back me up aprentice? :p
 

refraction

PCSX2 Coder
i see, but what i mean is with the CPU cycles, as each one takes a certain number of cycles, say one takes 4 and another takes 3 cycles, what would i do to implement them?

i understand what you mean tho, divider set to 4096, clock speed is 1.436395634mhz or whatever lol (just slapped a load of numbers) and the divided number is the amount of opcodes it runs per second yes?

actually what do i do with my result number? :p

where is aprentice when you need him!!
 

Dark Stalker

New member
I'm just do this every 455th cpu-cycle (one line is drawn every 455 cycle, which I wouldn't want to miss), so the precision is limited to that. Each opcode processed by the cpu subtracts from the CycleCounter.
Code:
const Uint32 timaClock[4]={ 1024, 16, 64, 256 };
for(;;) {
  z80.process();
  if(CycleCounter<=0) {
    CycleCounter+=455;
  ...
  ...
  if(memory.read(0xFF07)&4)
    updateTima(timaClock[(memory.read(0xFF07)&3)]);
  ...
  }
}
Code:
//Updates TIMA register according to cycles passed and frequency given by TAC reg. Requests interrupt if overflow
inline void GameBoy::updateTima(const Uint32 &timaClock) {
  //Increases timaCounter by cycles passed.
  timaCounter+=455;
  //temp is set to cycles passed divided by cycles required to pass per update.
  temp=timaCounter/timaClock;
  //If the TIMA reg is about to overflow, reset to value in TMA reg (and adds back overflowed value) and request interrupt.
  if((memory.read(0xFF05)+temp)&256) { 
    memory.write(0xFF05)=memory.read(0xFF06)+((memory.read(0xFF05)+temp)%256); 
    memory.write(0xFF0F)|=4; 
  }
  else //Increment TIMA by cycles passed divided by cycles required to pass pr update.
    memory.write(0xFF05)+=temp;
  //Find number of cycles left to use for future calculations.
  timaCounter-=temp*timaClock;
}
EDITed in update on progress, and a bit context for my code :whistling :
I finished implementing sprites (except x-position priority) yesterday, and was a bit reluctant to implement yflip since it got sort of hilarious looking at link swinging his sword by the wrong end when faced north :p. Additionally I added regular saveram support, and support for pressing all buttons at once (so I can actually get to the savescreen in zelda :p). I did some testing and a few games surprisingly seem to work with hardly any flaws at all.

skjermbilde11112.png

skjermbilde1115.png
skjermbilde1117.png
 
Last edited:

refraction

PCSX2 Coder
explaining it woulda been nicer instead of having to decypher your code :p

but i get the general idea cheers. Aprentice? can you give you take on timing?
 

Dark Stalker

New member
I don't have the time to explain further right now, but I edited my previous post to add some more context for my code. I guess aprentice would know better anyway though :p
 

bcrew1375

New member
refraction, you should create a variable to hold the number of cycles until the timer is updated(which is machine speed / timer frequency. example: 1048576 / 4096 = 256) and subtract the opcode's cycles from that. When it is lower than or equal to 0, increment 0xFF05. When 0xFF05 exceeds 255, load it with the contents of 0xFF06. Hope that is what you're talking about.
 

refraction

PCSX2 Coder
bcrew1375 said:
refraction, you should create a variable to hold the number of cycles until the timer is updated(which is machine speed / timer frequency. example: 1048576 / 4096 = 256) and subtract the opcode's cycles from that. When it is lower than or equal to 0, increment 0xFF05. When 0xFF05 exceeds 255, load it with the contents of 0xFF06. Hope that is what you're talking about.

now THAT made sense, a variable holding the result of that equasion depending on the divider, so a number of opcodes run, subtracting the number of cpu cylces it takes from that figure each time until it reaches zero, at which point 0xFF05 is filled with 0xFF06 and a timer interrupt is called yes?
 

bcrew1375

New member
refraction said:
now THAT made sense, a variable holding the result of that equasion depending on the divider, so a number of opcodes run, subtracting the number of cpu cylces it takes from that figure each time until it reaches zero, at which point 0xFF05 is filled with 0xFF06 and a timer interrupt is called yes?

Only after 0xFF05 has exceeded 255(It is reset to 0, by the way) should it be loaded with 0xFF06 and the interrupt called. Otherwise, yes, but as Dark Stalker said, there's a bit more. You need to limit the number of cycles the emulation can run per second, or you could limit it by screen updates.
 
Last edited:

aprentice

Moderator
yeah, timing is a pretty big issue, which i myself haven't got working accurately yet.

basically you have to execute 70,224 cycles per frame.

in my emu i have pretty much estimated the oam transfer mode to be 80 cycles, the hblank to last 204 cycles, the transfer to be 172 cycles and vblank to last 4560 cycles. basically every scanline has to be 456 cycles, and although the gameboy mono isnt too timing sensative, a handful of games wont work if its not done right.

Not sure how accurate my timing is, but its causing me problems in a lot of games like sprites not showing up in some gameboy mono and hdma transfers happening at the wrong times (and locations) in some color gameboy.

bccrew is right about the DIV, and tima stuff, heres my code on how i did the div, incase the other code examples given were too confusing.

PHP:
void inc_div(int cycles)
{
       cpu.div_counter+=cycles;
       if(cpu.div_counter>=256)
       {
            cpu.div_counter-=256;
            DIV++;
       }
}

if anyone makes any breakthroughs on timing, let me know :p
 
Last edited:

refraction

PCSX2 Coder
ok so i see its something people havent perfected yet, well if i manage to fluke the ultimate soluition (haha) then ill let you know :p
 

aprentice

Moderator
refraction said:
ok so i see its something people havent perfected yet, well if i manage to fluke the ultimate soluition (haha) then ill let you know :p

actually thats true, but i have errors in my own timing as well :p
 

refraction

PCSX2 Coder
aprentice said:
actually thats true, but i have errors in my own timing as well :p

well nobody is perfect :)

ill have a look around see if i can find anything more in depth about timing, most documents just say "the DIV register is updated 16355 times a second, if any value is written to this it becomes 00"

thats kinda confusing, but im assuming it means it increments itself so many times a second, BUT if something else tries to write to it, it resets to 00 yeh?
 

aprentice

Moderator
refraction said:
well nobody is perfect :)

ill have a look around see if i can find anything more in depth about timing, most documents just say "the DIV register is updated 16355 times a second, if any value is written to this it becomes 00"

thats kinda confusing, but im assuming it means it increments itself so many times a second, BUT if something else tries to write to it, it resets to 00 yeh?

yep, writing any value to this register would reset its value and
it incraments every 256 cycles on its own.
 

refraction

PCSX2 Coder
aprentice said:
yep, writing any value to this register would reset its value and
it incraments every 256 cycles on its own.


ah good, so i dont have to touch that then? im sure i saw someone in here with a loop round their main function to do something every 256 cycles :plain:
 

aprentice

Moderator
refraction said:
ah good, so i dont have to touch that then? im sure i saw someone in here with a loop round their main function to do something every 256 cycles :plain:

by on its own, i mean the hardware does it, and your the one emulating the hardware :p
 

refraction

PCSX2 Coder
aprentice said:
by on its own, i mean the hardware does it, and your the one emulating the hardware :p


now your trying to confuse me :p right so i need a routine incrementing that and checking it for overflow got it.

thats the DIV register that increments right?

TIMA increments in 1/4 the time of DIV if TAC is set to 4096 (which is 1/4 the number of times DIV updates)

that sound right to you?

thisd be so much easier if you could contact me on msn :p
 

Top