What's new

Nes

aprentice

Moderator
hap said:
aprentice: will you ever continue with your NES emu ?

these are the basics for when to hit vblank.

dummy scanline (341 ppu cycles)
240 visible scanlines (341*240 ppu cycles)
dummy scanline (256 ppu cycles, so no hblank here), then hit vblank, and let the cpu run out of cycles before starting a new frame

1 cpu cycle=3 ppu cycles
cpu cycles start at ~1789773/60, so vblank hits at cycle (1789773/60)-((256+341+(240*341))/3)=~2350

what specifies hblank and vblank and what does dummy scanlines mean?
are you also saying scanline 240 is 85 cpu cycles?
 

hap

New member
I was away for a few days, so I didn't see your PM until now. I'll have a look at it later and if you're OK with it, I'll give info/hints in this thread instead of PM world.

hblank: nothing specifies it.
vblank: most significant bit of ppu status register is set.
As for the dummy scanlines, i think the first one is there so the PPU can put the first few tilelines into the pipeline, and prefetch the sprites for the next scanline. Last scanline (242, not 240) I'm unsure about why it's there, but the docs say so, and I'm also unsure whether to hit vblank at cc 113 or cc 85, but 85 gives better results here.

*edit* oh, and don't let this timing thing scare you about black screens and non-booting games. i've had plenty of bugs fixed in my timing, and games were already up and running way before that
 
Last edited:

aprentice

Moderator
hap said:
I was away for a few days, so I didn't see your PM until now. I'll have a look at it later and if you're OK with it, I'll give info/hints in this thread instead of PM world.

hblank: nothing specifies it.
vblank: most significant bit of ppu status register is set.
As for the dummy scanlines, i think the first one is there so the PPU can put the first few tilelines into the pipeline, and prefetch the sprites for the next scanline. Last scanline (242, not 240) I'm unsure about why it's there, but the docs say so, and I'm also unsure whether to hit vblank at cc 113 or cc 85, but 85 gives better results here.

its fine with me.
Btw, which is the dummy scanline, 242, or 0?
 

hap

New member
not 0, but 1. or 0 and 241 ;p

But anyway, i'd say they're both dummies, since no graphics are drawn onto the screen at these 2 scanlines. but if you want the dummiest one, it's 242, cause the ppu seems to be doing nothing useful at all there.
 

hap

New member
your cpu core:
zero page, zp x, zp y: why pc+1 ? a typo i hope ? :p
abs x, ind x, ind y: be sure to burn an extra cycle on page overflow
stack: stackpointer is 1 byte, not 2, stack however is at 0x100-0x1ff
adc: overflow is about twos complement, so it will be set when the result is lower than -128, or higher than 127
other flag manipulators: reset the affected flags first before setting them, eg. result of asl is not 0, and the zero flag was set before asl was called, the zero flag should be 0 (now that i've looked further, it only seems to be bugged at asl)
jsr: push pc-- on stack, not pc++
 

aprentice

Moderator
hap said:
your cpu core:
zero page, zp x, zp y: why pc+1 ? a typo i hope ? :p
abs x, ind x, ind y: be sure to burn an extra cycle on page overflow
stack: stackpointer is 1 byte, not 2, stack however is at 0x100-0x1ff

Fixed a bunch of the addressing modes and a couple opcodes, stupid mistakes, thats what happens when you write the whole cpu core in an hour :p

adc: overflow is about twos complement, so it will be set when the result is lower than -128, or higher than 127

another stupid mistake :p

other flag manipulators: reset the affected flags first before setting them, eg. result of asl is not 0, and the zero flag was set before asl was called, the zero flag should be 0 (now that i've looked further, it only seems to be bugged at asl)

you kinda lost me here :p

jsr: push pc-- on stack, not pc++

i thought it was push pc+2 to stack?
 

hap

New member
you kinda lost me here :p

at asl you do:
if result=0, status=status|2
while it should be:
if result=0, status=status|2, else status=status&~2


i thought it was push pc+2 to stack?

hmm, only if you're not executing that opcode like any other, in my case i do:

fetch opcode (jsr)
pc++

do addressingmode:
it's abs, so pc++, and pc++ again

execute opcode (jsr):
pc--
push pc
pc=addressbus
 

hap

New member
and you've got stackpointer incrementing/decrementing wrong:

your version is reversed:
pull: read, sp--
push: sp++, write

correct:
pull: sp--, read
push: write, sp++
 

aprentice

Moderator
hap said:
and you've got stackpointer incrementing/decrementing wrong:

your version is reversed:
pull: read, sp--
push: sp++, write

correct:
pull: sp--, read
push: write, sp++

eh, are you sure about that? I have it that way in my gameboy emu and it works perfectly fine, i dont understand why we decrement before we pull if its last on first off.
 

aprentice

Moderator
hap said:
and you've got stackpointer incrementing/decrementing wrong:

your version is reversed:
pull: read, sp--
push: sp++, write

correct:
pull: sp--, read
push: write, sp++

i've copied and pasted that routine from my gameboy emu, guess its backwards on the nes :p

is this correct?

#define PUSH8(x) mem_write8(0x100+reg.sp,x); reg.sp++
#define PUSH16(x) mem_write16(0x100+reg.sp,x); reg.sp+=2

#define POP8() mem_read8(0x100+reg.sp-1); reg.sp--
#define POP16() mem_read16(0x100+reg.sp-2); reg.sp-=2
 
Last edited:

refraction

PCSX2 Coder
aprentice said:
i've copied and pasted that routine from my gameboy emu, guess its backwards on the nes :p

is this correct?

#define PUSH8(x) mem_write8(0x100+reg.sp,x); reg.sp++
#define PUSH16(x) mem_write16(0x100+reg.sp,x); reg.sp+=2

#define POP8() mem_read8(0x100+reg.sp-1); reg.sp--
#define POP16() mem_read16(0x100+reg.sp-2); reg.sp-=2


close

yeh but itd require less maths if you did it like this

#define PUSH8(x) mem_write8(0x100+reg.sp,x); reg.sp++
#define PUSH16(x) mem_write16(0x100+reg.sp,x); reg.sp+=2

#define POP8() reg.sp--; mem_read8(0x100+reg.sp)
#define POP16() reg.sp-=2; mem_read16(0x100+reg.sp)
 

hap

New member
sorry, i was wrong in my explanation. this is how i have it:

#define PUSH(x) WRITE_BYTE_RAM(0x100|cpu.S--,x)
#define PULL() READ_BYTE_RAM(++cpu.S|0x100)

so for you that would become:
#define PUSH8(x) mem_write8(0x100+reg.sp,x); reg.sp--
#define PUSH16(x) mem_write16(0x100+reg.sp,x); reg.sp-=2

#define POP8() mem_read8(0x100+reg.sp+1); reg.sp++
#define POP16() mem_read16(0x100+reg.sp+2); reg.sp+=2


refraction: indeed, but now you can't do blah=POP8() anymore
 

refraction

PCSX2 Coder
yeh i did find that a bit odd there, he was incrementing the stack every time something was pushed on to it, i know on the gameboy the start address is 0xFFFE so it would have to stack downwards to avoid overwriting any important data.

dont know what its like on the NES so i wasnt totally sure there :)
 

hap

New member
Hmm, i'll have to correct my earlier self on timing :p I've fixed some things and the mid-scanline test works much better now. One thing i did: making vblank hit at the end of scanline 242, and not at its hblank.
 

aprentice

Moderator
scrapped all my gfx code, its was all totally wrong, after reading the ppu docs over and over a few times i have come to this conclusion :p

What baffles me the most is the usage of the attribute table, i dont understand why each attribute tables represents a group of 4x4 tiles and why.
 

hap

New member
Why ? to store colours as compact as possible; ppu only has 2kb internal nametable ram.
How ? Well, the docs describe it very well, but maybe an example would help:

Visualise Super Mario Bros, you can see that the world is built with many blocks sized 2x2 tiles (16x16 pixels). Each block is using 2 bits out of the attribute table. Take 4 of those blocks and form a square; 4x4 tiles, and you've got an attribute table byte.

Visualise the top left corner of SMB, comprising 4 typical SMB blocks:
block a, block b
block c, block d
Block a gets its high 2 bits for the palette colour at bits 0 and 1 of the attribute table byte. Block b from bits 2 and 3, block c from bits 4 and 5, block d from bits 6 and 7.

Now 1 step further: tiles, from the same space:
tile 1, tile 2, tile 3, tile 4, (5,6,7,8,9,10,etc)
tile 33, tile 34, tile 35, tile 36, (...)
tile 65, tile 66, tile 67, tile 68, (...)
tile 97, tile 98, tile 99, tile 100, (...)
Tile 1,2,33,34 get their high 2 bits for the palette colour at bits 0 and 1 of the attribute table byte, tile 3,4,35,36 get theirs at bits 2 and 3, etc.

This specific attribute table byte is located at name_table_start+0x3c0 (ntstart=0x2000, 0x2400, 0x2800 or 0x2c00).


*edit* can you boot games yet ? what i mean is running the cpu for a few frames without it calling bad opcodes

*edit2* typo
 
Last edited:

hap

New member
scrolling works, joypad 1 works, mmc1 works with a few problems, sprites work but no 8x16 mode or sprite overflow or overlapping yet (see zelda pic)
Seems the shopkeeper owns a rockinghorse, too bad he won't sell that :(

*edit* oh, and the emu's got a proper name now
 
Last edited:

aprentice

Moderator
nice job, looking good. I took a few days off on mine, got kind of frustrated figuring out the gfx. Prolly getting back to work on it today or tomorrow :p
 

hap

New member
Poor Doc, looks like he could use a doctor himself, or maybe he's just pissed off at Glass Joe for stealing his bike :p
 

Top