From the WDC W65C816S datasheet, page 42 (emphasis added):
Here's what the 65816 core in higan v098 does for direct page address calculation (from higan/processor/r65816/memory.hpp):
Assuming the datasheet is correct, the emulation flag and DP low byte test should not be done for pei and indirect long addressing modes. There should either be an "alwaysnative" argument to the functions, or a second pair of "readdpn" and "writedpn" functions that always do the native mode behaviour. The second is the prevailing style in the r65816 core, but the first is more DRY, and weren't you planning to update the code style in the older parts of higan anyway?
Of course there's a possibility that the datasheet is wrong (I noticed that it incorrectly claims that indexed indirect jmp fetches the vector from bank 0--it's actually from the PB) But the datasheet seems highly plausible to me--there's a definite pattern in the 65816 where emulation mode preserves 6502 behaviour only for instructions and addressing modes that actually exist on a 6502, while new 65816 instructions and modes always have "native mode" behaviour.
Also, the masking in those direct page functions is extremely redundant. The following much simpler and more readable formulas are exactly equivalent to what you have:
Quote:
8.2.1 The Direct Addressing modes are often used to access memory registers and pointers.
The effective address generated by Direct; Direct,X and Direct,Y addressing modes will always be in the Native mode range 000000 to 00FFFF. When in the Emulation mode, the direct addressing range is 000000 to 0000FF, except for [Direct] and [Direct],Y addressing modes and the PEI instruction which will increment from 0000FE or 0000FF into the Stack area.
8.2.2 When in the Emulation mode and DH is not equal to zero, the direct addressing range is 00DH00 to 00DHFF, except for [Direct] and [Direct],Y addressing modes and the PEI instruction which will increment from 00DHFE or 00DHFF into the next higher page.
The effective address generated by Direct; Direct,X and Direct,Y addressing modes will always be in the Native mode range 000000 to 00FFFF. When in the Emulation mode, the direct addressing range is 000000 to 0000FF, except for [Direct] and [Direct],Y addressing modes and the PEI instruction which will increment from 0000FE or 0000FF into the Stack area.
8.2.2 When in the Emulation mode and DH is not equal to zero, the direct addressing range is 00DH00 to 00DHFF, except for [Direct] and [Direct],Y addressing modes and the PEI instruction which will increment from 00DHFE or 00DHFF into the next higher page.
Here's what the 65816 core in higan v098 does for direct page address calculation (from higan/processor/r65816/memory.hpp):
Code:
alwaysinline auto readdp(uint32 addr) -> uint8 {
if(regs.e && regs.d.l == 0x00) {
return read((regs.d & 0xff00) + ((regs.d + (addr & 0xffff)) & 0xff));
} else {
return read((regs.d + (addr & 0xffff)) & 0xffff);
}
}
// snip
alwaysinline auto writedp(uint32 addr, uint8 data) -> void {
if(regs.e && regs.d.l == 0x00) {
write((regs.d & 0xff00) + ((regs.d + (addr & 0xffff)) & 0xff), data);
} else {
write((regs.d + (addr & 0xffff)) & 0xffff, data);
}
}
if(regs.e && regs.d.l == 0x00) {
return read((regs.d & 0xff00) + ((regs.d + (addr & 0xffff)) & 0xff));
} else {
return read((regs.d + (addr & 0xffff)) & 0xffff);
}
}
// snip
alwaysinline auto writedp(uint32 addr, uint8 data) -> void {
if(regs.e && regs.d.l == 0x00) {
write((regs.d & 0xff00) + ((regs.d + (addr & 0xffff)) & 0xff), data);
} else {
write((regs.d + (addr & 0xffff)) & 0xffff, data);
}
}
Assuming the datasheet is correct, the emulation flag and DP low byte test should not be done for pei and indirect long addressing modes. There should either be an "alwaysnative" argument to the functions, or a second pair of "readdpn" and "writedpn" functions that always do the native mode behaviour. The second is the prevailing style in the r65816 core, but the first is more DRY, and weren't you planning to update the code style in the older parts of higan anyway?
Of course there's a possibility that the datasheet is wrong (I noticed that it incorrectly claims that indexed indirect jmp fetches the vector from bank 0--it's actually from the PB) But the datasheet seems highly plausible to me--there's a definite pattern in the 65816 where emulation mode preserves 6502 behaviour only for instructions and addressing modes that actually exist on a 6502, while new 65816 instructions and modes always have "native mode" behaviour.
Also, the masking in those direct page functions is extremely redundant. The following much simpler and more readable formulas are exactly equivalent to what you have:
Code:
if(regs.e && regs.d.l == 0x00) {
return read(regs.d + (addr & 0xff)); // we've just tested that (regs.d & 0xff00) == regs.d
} else {
return read((regs.d + addr) & 0xffff); // we only need to mask with 0xffff once
}
return read(regs.d + (addr & 0xff)); // we've just tested that (regs.d & 0xff00) == regs.d
} else {
return read((regs.d + addr) & 0xffff); // we only need to mask with 0xffff once
}