What's new

Nes

hap

New member
You mean the black n white pics a few pages back ? I still have that version (backed up). And what's emulated:

- CPU with a few bugs left (stack and and the overflow flag I think), and the only IRQ emulation is NMI (and reset)
- PPU without sprites or bg attribute. All registers emulated with the exception of sprite and scroll related ones. Pixel based renderer (but line-based shouldn't be a problem for simple games).
- APU and input and sprite DMA registers not hooked up (returning open bus: address>>8)
- mappers 0,2,3,9 emulated


SMB without sprite 0 emulation will show its titlescreen, and gets stuck there.

Check NMI emulation, and *every* CPU opcode function. With bugfree NMI and CPU emulation, almost all NROM games should boot, and many will go to demo mode.
 

aprentice

Moderator
hap said:
You mean the black n white pics a few pages back ? I still have that version (backed up). And what's emulated:

- CPU with a few bugs left (stack and and the overflow flag I think), and the only IRQ emulation is NMI (and reset)
- PPU without sprites or bg attribute. All registers emulated with the exception of sprite and scroll related ones. Pixel based renderer (but line-based shouldn't be a problem for simple games).
- APU and input and sprite DMA registers not hooked up (returning open bus: address>>8)
- mappers 0,2,3,9 emulated


SMB without sprite 0 emulation will show its titlescreen, and gets stuck there.

Check NMI emulation, and *every* CPU opcode function. With bugfree NMI and CPU emulation, almost all NROM games should boot, and many will go to demo mode.

what do you mean by open bus address and do you think not emulating apu registers can be a factor in compat here?
 

hap

New member
With open bus I mean that when reading unmapped memory space, eg. 0x6000-0x7fff when the mapper has no WRAM/SRAM, you get the last value that was on the bus, and for CPU reads, that usually is the high byte of the address, so reading 0x6010 when that's unmapped returns 0x60.

Not emulating APU registers will affect compatibility a bit: some games rely on correct DMC behaviour, or DMC IRQs/frame IRQs. But for NROM hardly any (the only commercial game I've seen using frame IRQs on NROM is 'Door Door (J)').
 

aprentice

Moderator
hap said:
With open bus I mean that when reading unmapped memory space, eg. 0x6000-0x7fff when the mapper has no WRAM/SRAM, you get the last value that was on the bus, and for CPU reads, that usually is the high byte of the address, so reading 0x6010 when that's unmapped returns 0x60.

oh i havent emulated this behavior, would this break games? only game i can get running is donkey kong. donkey kong 3 has messed up gfx
 

hap

New member
Maybe, but not that many that you can only get Donkey Kong running. Does Donkey Kong go to the demo ?

Do a simple test: printf("blah!"); when the CPU is executing an illegal opcode. If this happens to almost all the games that you can't get working, you're pretty certain the CPU emulation is broken, somewhere.

If not, it could be your PPU that is broken: check the registers, and the memorymap, and NMI.
0x2002: do you reset 0x2002.7 when it's read ? and don't reset it before returning the value :p
0x2007: do you correctly increment the address by 1 or 32 ? have you correctly emulated the read delay ? (read 0x2007, and you'll get the value that you requested the previous time you read 0x2007, except when reading the palette)
NMI: you should only request one when 0x2000.7 is set
 

aprentice

Moderator
hap said:
Maybe, but not that many that you can only get Donkey Kong running. Does Donkey Kong go to the demo ?

Do a simple test: printf("blah!"); when the CPU is executing an illegal opcode. If this happens to almost all the games that you can't get working, you're pretty certain the CPU emulation is broken, somewhere.

If not, it could be your PPU that is broken: check the registers, and the memorymap, and NMI.
0x2002: do you reset 0x2002.7 when it's read ? and don't reset it before returning the value :p
0x2007: do you correctly increment the address by 1 or 32 ? have you correctly emulated the read delay ? (read 0x2007, and you'll get the value that you requested the previous time you read 0x2007, except when reading the palette)
NMI: you should only request one when 0x2000.7 is set

I'll try the printf on illegal opcodes idea, and i've done all that except the read delay, i didnt know it existed. So the first time it reads it gets no data but the second time it reads it gets the data from the first read? pretty wierd.

edit: no illegal opcodes, and donkey kong doesnt go into demo mode, sometimes the screeen blinks, i assume it was *trying* to go into demo mode but didnt for some reason

edit2: emulated temp delay with no results :p

case 0x2007:
unsigned char temp_delay;
temp_delay=ppu.read_delay_data;
unsigned short temp_addr;
temp_addr=ppu.mem_addr;
ppu.mem_addr+=ppu.cr1.ppu_inc;
ppu.read_delay_data = ppu_read8(temp_addr);
return temp_delay;
break;

also looked at op logs and nothing stood out, looked like its doing its job perfectly fine
 
Last edited:

hap

New member
you're incrementing the address too early, and the delay doesn't happen on palette reads (though the delay buffer (ppu.read_delay_data) will be filled):

case 0x2007:
unsigned char temp_delay;
temp_delay=ppu.read_delay_data;
ppu.read_delay_data = ppu_read8(ppu.mem_addr);
if ((ppu.mem_addr&0x3f00)==0x3f00) temp_delay=ppu.read_delay_data;
ppu.mem_addr+=ppu.cr1.ppu_inc;
return temp_delay;
break;
 

aprentice

Moderator
hmm, that produced no change in compat, how about this, does it look right?

writes:

case 0x2006: //PPU Memory Address
if(ppu.flipflop==0)
{
ppu.flipflop=1;
ppu.mem_addr=(data&0x3F)<<8;
}
else
{
ppu.flipflop=0;
ppu.mem_addr|=data;
}
break;

case 0x2007: //PPU Memory Data
ppu_write8(ppu.mem_addr,data);
ppu.mem_addr+=ppu.cr1.ppu_inc;
break;

reads:

case 0x2002:
unsigned char temp_sr;
temp_sr = ppu.sr;
ppu.sr&=0x7F;
ppu.flipflop=0;
return temp_sr;
break;
 
Last edited:

hap

New member
Yeah, I thought it wouldn't; it wasn't a big bug.

Keeping in mind there's no scrolling yet, the above looks to be correct.


*edit* how's your NMI timing ? mine's like this (not counting even/odd frame behaviour):
242*341 ppu cycles -> NMI
20*341 ppu cycles -> new frame
(3 ppu cycles=1 cpu cycle)

and, do you do ppu.sr=0; at the start of each frame ?
 
Last edited:

aprentice

Moderator
hap said:
Yeah, I thought it wouldn't; it wasn't a big bug.

Keeping in mind there's no scrolling yet, the above looks to be correct.


*edit* how's your NMI timing ? mine's like this (not counting even/odd frame behaviour):
242*341 ppu cycles -> NMI
20*341 ppu cycles -> new frame
(3 ppu cycles=1 cpu cycle)

and, do you do ppu.sr=0; at the start of each frame ?

i just execute 341/3 cycles per scanline, thats about it. I'm a little confused about this timing stuff in the nes..
 

aprentice

Moderator
hap said:
You're having any luck ?

nope, i hit a dead wall, i cant possibly imagine whats broken, everything looks in perfect working order, only thing that i was foggy about was timing, i execute 114 cycles per scanline, thats all i do for timing but i doubt that would break compat, mem/ppu maps look fine. If you have time i can send you my source, since your fluent with the nes, you'd probably notice something im overlooking... i'm close to calling it a quits, i seriously cant see whats wrong :whistling
 

hap

New member
I'm currently in a fix something->break something else-phase, that kinda sucks :p

You can send the source (and a binary in the case I can't compile it).
 

hap

New member
something silly with frame interrupts not getting acknowledged, i can fix that by fiddling with power-up-timing, but that breaks some other games that probably base their timing on calculations done on power-up.

Your emu compiled fine in VS6, and it's running 'Zelda Simulator' now. Normally I use MinGW for programming. I do have VS6, but I hardly use it.
 

hap

New member
The most problematic bugs have been taken care of. I have not looked at everything though.

Do you want me to send the updated version ?
Don't just overwrite it, but apply the changes manually, and confirm/understand them. I might have made errors (no not on purpose, I'm not evil ;p )

Or do you want to fix them yourself (by me giving hints) ? Better to choose this one I guess
- SBC is wrong
- branches are wrong: if ((blah&0x80)==1) will never go (I bet you smacked yourself for this one just now)
- attribute calculation is wrong
- zero flag calculation is wrong sometimes: 16 bit number==0. number can be 0x100, so mask with 0xff
- memmap mirrors: cpu 0x2000-0x3fff=ppu regs, so mask with 7. ppu 0x3f00-0x3fff=palette, so mask with 0x1f
- render timing is wrong: line 0=dummy, lines 1-240=render, line 241=dummy, lines 242-261=vblank
 
Last edited:

aprentice

Moderator
hap said:
The most problematic bugs have been taken care of. I have not looked at everything though.

Do you want me to send the updated version ?
Don't just overwrite it, but apply the changes manually, and confirm/understand them. I might have made errors (no not on purpose, I'm not evil ;p )

Or do you want to fix them yourself (by me giving hints) ? Better to choose this one I guess
- SBC is wrong
- branches are wrong: if ((blah&0x80)==1) will never go (I bet you smacked yourself for this one just now)
- attribute calculation is wrong
- zero flag calculation is wrong sometimes: 16 bit number==0. number can be 0x100, so mask with 0xff
- memmap mirrors: cpu 0x2000-0x3fff=ppu regs, so mask with 7. ppu 0x3f00-0x3fff=palette, so mask with 0x1f
- render timing is wrong: line 0=dummy, lines 1-240=render, line 241=dummy, lines 242-261=vblank

I fixed all the branch ops and super mario bros and a few other games started running, i didnt smack myself, i knocked myself out, thats what i get for copy and pasting the bcc op and changing the 0 to a 1, really stupid mistake :p thanks btw dude, i got my motivation back, you rock ;)

The only change i need from you is the attribute flag one and i couldnt quiet understand the sbc op, i just fixed the other ones :p

edit: every mapper #0 i tested works, guess its time to add more mappers :p
 
Last edited:

hap

New member
SBC basically is an inverted ADC: unsigned short temp=(reg.sr&0x01)+reg.acc+((~mem_read8(cpu.mempc))&0xff); (flag-changing calculations can be copied from ADC)

Attribute calculation is the same as I posted earlier: int attribute=((ppu_read8(ppu.cr1.name_table_addr+0x3C0+(x>>5|line>>2&0xf8))>>((x>>3&2)|(line>>2&4)))&3)<<2;
and then pixel=blah|attribute; except if pixel==0

Also: to get a blue sky instead of black in SMB1, you need to know that palette entries 0 4 8 c are the same as 10 14 18 1c (so writing to 4 changes 14 too and vice versa)
 

aprentice

Moderator
hap said:
SBC basically is an inverted ADC: unsigned short temp=(reg.sr&0x01)+reg.acc+((~mem_read8(cpu.mempc))&0xff); (flag-changing calculations can be copied from ADC)

Attribute calculation is the same as I posted earlier: int attribute=((ppu_read8(ppu.cr1.name_table_addr+0x3C0+(x>>5|line>>2&0xf8))>>((x>>3&2)|(line>>2&4)))&3)<<2;
and then pixel=blah|attribute; except if pixel==0

Also: to get a blue sky instead of black in SMB1, you need to know that palette entries 0 4 8 c are the same as 10 14 18 1c (so writing to 4 changes 14 too and vice versa)

so basically you mean like:

if(addr>=0x3F00)
{
vmem.vram[addr&0x1F]=data;
vmem.vram[(addr+0x10)&0x1F]=data;
}

and by dummy line you mean no rendering at all, like scanline 0 i just execute the cycles but start rendering on line 1?
 

hap

New member
yes, though a xor 0x10 is simpler, oh, and remember to do an if addr&3==0.

yes, start rendering on line 1, just feed the render function with (line-1). vblank still ends at scanline 0 (sr=0).
 

Top