Page 1 of 1

Pointers

Posted: Tue Oct 17, 2006 9:03 am
by WedNESday
I have decided to use a pointer to the ROM to make my emulator faster. I have everything setup, apart from the value of the PC itself.

Code: Select all

*CPU.PC = 0x69 // ADC Immediate
&CPU.PC = Address
How do I calculate the value of the PC ($0000-FFFF)? I need it for pushing and popping the PC for JSR/RTS and for the function that handles memory mapping. I have managed to do some kind of 'Current Address - Start Address' kind of thing but have only come up with 0x2C, which seems odd.

Posted: Tue Oct 17, 2006 12:22 pm
by Quietust
That method will not work if you divide your NES memory into banks via pointers (the only efficient way of doing it).
Really, doing it that way won't gain any significant speed over doing Memory[CPU.PC].

Posted: Tue Oct 17, 2006 2:16 pm
by WedNESday
Quietust wrote:That method will not work if you divide your NES memory into banks via pointers (the only efficient way of doing it).
Really, doing it that way won't gain any significant speed over doing Memory[CPU.PC].
Could someone please provide an example of this?

Posted: Tue Oct 17, 2006 2:41 pm
by kyuusaku
My way:

decode addr into 8 w/ addr & 0xE000

0000 Y0 = wram[addr & 0x7FF]
2000 Y1 = ppu regs (furthur decode)
4000 Y2 = decode <4018 to apu regs, >= 4018 to mapper handler
6000 Y3 = decode to mapper handler or SRAM
else = decode to mapper handler
.....


----handler for 8k bankswitching----
if(addr & 0xC000 == 0x8000)
return *PRG_8_ptr + (addr & 0x1FFF);


.......ptrs for 8k bankswitching....

PRG_8_ptr = &PRGmem + bank*0x2000
..
..
PRG_E_ptr = &PRGmem + ((((sizeof(PRGmem))/8)-1)*0x2000) or whatever

Posted: Tue Oct 17, 2006 3:37 pm
by WedNESday
Thanks, but that still doesn't tell me the value of PC when I need it.

Posted: Tue Oct 17, 2006 3:49 pm
by kyuusaku
Encapsulate what I said into global_read(addr) then do cpu_instruction(global_read(cpu.pc)).

Posted: Tue Oct 17, 2006 4:12 pm
by blargg
It sounds like you want to store pc itself as a pointer, but I couldn't understand your question very well. Good luck:

Code: Select all

byte* pc_ptr = rom; // pc = 0x8000

int pc = pc_ptr - rom + 0x8000; // recover 16-bit program counter from pointer
The problem with this is that you can't easily handle bank changes. This is how most people handle banks:

Code: Select all

int pc; // 16-bit value of emulated program counter

// no banks
byte* rom = malloc( 0x8000 );
int data = rom [pc & 0x7FFF];

// 8 banks
byte* banks [8];
int data = banks [pc >> 12 & 7] [pc & 0x0FFF];

Posted: Mon Oct 23, 2006 3:01 am
by WedNESday
Finally! Now I understand thanks to blargg's explanation. Here is what I do:

Code: Select all

ROM_Pointer = Cartridge.ROM[Bank];
opcode = ROM_Pointer[PC & 0x7FFF];
Is that acceptable? Or is there a faster method?

Posted: Mon Oct 23, 2006 2:28 pm
by kyuusaku
Is ROM[bank] an array of pointers each pointing to a bank in the flat ROM image memory?

I'm having difficulty understanding what we're talking about, your idea seems very convoluted. Why not keep only one pointer to the ROM?

byte *ROM_pointer = malloc(sizeof(game));

opcode = *ROM_pointer[banknumber*sizeof(bank) | (PC & (sizeof(bank)-1))]

Posted: Tue Oct 24, 2006 9:23 am
by WedNESday

Code: Select all

$8000-BFFF

ROMBank1 = &Cartridge.ROM[Bank] // Bank = $8000 for the 3rd Bank

$C000-FFFF

ROMBank2 = &Cartridge.ROM[Bank] // Bank = $4000 for the 2rd Bank

opcode = ROMBankx[PC & $7FFF]
Read trapping designates which ROMBank to use.
kyuusaku wrote:opcode = *ROM_pointer[banknumber*sizeof(bank) | (PC & (sizeof(bank)-1))]
Is a lot of code for fetching an opcode.

Posted: Tue Oct 24, 2006 10:18 am
by kyuusaku
(bank*0x2000|pc&0x1FFF) doesn't seem so bad. It's your choice whether to modify pointers or variables. Generally it would be best to use more than less pointers since they needn't be modified as often as my example would need to be evaluated. From the description of the problem though, I couldn't tell if you had pointers to banks.