It may be smaller by $100

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
It may be smaller by $100
by on (#202100)
6502_cpu.txt says for Absolute indexed:

Quote:
Absolute indexed addressing

Read instructions (LDA, LDX, LDY, EOR, AND, ORA, ADC, SBC, CMP, BIT,
LAX, LAE, SHS, NOP)

# address R/W description
--- --------- --- ------------------------------------------
1 PC R fetch opcode, increment PC
2 PC R fetch low byte of address, increment PC
3 PC R fetch high byte of address,
add index register to low address byte,
increment PC
4 address+I* R read from effective address,
fix the high byte of effective address
5+ address+I R re-read from effective address

Notes: I denotes either index register (X or Y).

* The high byte of the effective address may be invalid
at this time, i.e. it may be smaller by $100.

+ This cycle will be executed only if the effective address
was invalid during cycle #4, i.e. page boundary was crossed.


I know that "crossing pages" takes 1 more cc, but i don't understand the:

Quote:
* The high byte of the effective address may be invalid
at this time, i.e. it may be smaller by $100.


can someone explain me??
Re: It may be smaller by $100
by on (#202101)
That means if page crossing happens, the address read in the 4th cycle is incorrect, say if you do:
LDA $02FF, X
where X = 4, at the 4th cycle the CPU actually reads from $0203(low byte $(FF + 4) = $03 with carry, but at this point the high byte is not "fixed" by adding the carry yet, so the high byte is still $02), instead of the correct $0303. That's why it needs an extra 5th cycle to re-read from the correct address $0303.

That's just how the CPU works internally. I think for accurate CPU emulation it doesn't really matter as long as the cycles are correct and yields the expected output.
Re: It may be smaller by $100
by on (#202103)
Gilbert wrote:
That's just how the CPU works internally. I think for accurate CPU emulation it doesn't really matter as long as the cycles are correct and yields the expected output.

Occasionally the extra read or write cycles have side effects.

For example, using STA (indirect), Y on $2007 can end up writing two bytes to the PPU.

Most of the time an extra read doesn't have a consequence, but there are some effects that are read-triggered (e.g. $2002). I don't know if there's any games out there that rely on the dummy read, though.
Re: It may be smaller by $100
by on (#202108)
Certainly tepples's console/controller identification ROM relies on being able to "precharge" the data bus with the value from $2007 ($3F17) before the intended read from $4017 ...
Re: It may be smaller by $100
by on (#202131)
Lidnariq is referring to this test ROM that distinguishes among Control Deck variants (Famicom, front-loading NES, or top-loading NES) by exploiting the open bus behavior when the CPU reads $3F16 then $4016 in quick succession without an intervening instruction. In case you lack time to read the other topic, I'll summarize:

An "open bus" is a data bus that is read while nothing is connected. For example, if you LDA $4021 on an ordinary NES with an ordinary cartridge, the PRG ROM drives $AD, $21, and $40 in succession onto the data bus. But because no circuit responds to reading $4021, capacitance of the data bus holds the value $40 in place momentarily to be read by the CPU. One might think of this value as "riding" the open bus, boarding at the PRG ROM and debarking at $4021.

In normal operation, when the CPU reads $4016 (the first joystick port), the PRG ROM puts $40 on the data bus, and then the joystick circuit replaces but some but not all of these bits with joystick bits. Bits 7-5 are always unconnected (NC) except on Vs. System, bits 1 and 0 are always driven, and bits 4-2 are either driven or NC depending on which port (1 vs. 2) and which Control Deck variant. Because bits 7-5 are NC, those bits from the $40 value remain, and the port normally returns $41 for a pressed button or $40 for one not pressed. But the program can't tell an NC bit from a bit always driven to 0 because all driven bits are already precharged to 0.

The PPU has a video memory address port at $2006 and a video memory data port at $2007. These ports are mirrored every eight bytes up through $3FFE and $3FFF, including $3F16 and $3F17. Though $2006 is nominally write-only, the PPU's I/O has its own internal data bus, and reading a write-only PPU port will return the last byte written to any PPU port. The test program puts $BF into this internal PPU latch and then uses an indexed read (LDX #$20 LDA $3FF6,X) to cause the PPU to read $3F16, which puts $BF on the data bus, and $4016, which replaces some bits. Comparing the value when the PPU loads $BF to the value when the PRG ROM loads $40 lets a program tell which joystick bits aren't connected to the data bus.
Re: It may be smaller by $100
by on (#202144)
Never thought of that. So, does it mean that it is possible that in any 6502 systems (MOST 6502 systems I suppose) with memory ports mapped to other devices, there could be potentially hard to track bugs because of the (discarded) read/write when a page crossing occurs in index mode(however rare this could happen)?
Re: It may be smaller by $100
by on (#202152)
In practice, only if there are peripherals that care only that a read happened. In the NES/FC, that includes $2002, $2007, $4016, and $4017, but not much else.

In the 2600, only the bankswitching registers count. I guess that means you could deliberately trigger a bankswitch that would then fall over into a read from the RAM portion of the RIOT?

I don't think the C64 or VIC-20 do anything in response to just a read... It looks like some of the Apple 2 I/O registers do.
Re: It may be smaller by $100
by on (#202155)
Gilbert wrote:
Never thought of that. So, does it mean that it is possible that in any 6502 systems (MOST 6502 systems I suppose) with memory ports mapped to other devices, there could be potentially hard to track bugs because of the (discarded) read/write when a page crossing occurs in index mode(however rare this could happen)?

A bunch of things have to align for it to matter.

Using an indexed instruction to write such a register while also crossing a page is a but of an unusual occurrence in itself.

The most common places I've seen indexed writes to memory mapped registers on the NES is in initialization code (e.g. write 0 to all registers in a loop), and sometimes in audio code. A page crossing wouldn't normally happen in these cases, since the base address is going to be $2000 (PPU) or $4000 (APU). A doubled write might matter in some cases, but probably not during an initialization blanking.

I've heard that Bill and Ted bizarrely relies on the MMC1 filtering out writes on consecutive cycles from an INC.
Re: It may be smaller by $100
by on (#202159)
Gilbert wrote:
Never thought of that. So, does it mean that it is possible that in any 6502 systems (MOST 6502 systems I suppose) with memory ports mapped to other devices, there could be potentially hard to track bugs because of the (discarded) read/write when a page crossing occurs in index mode(however rare this could happen)?

It is possible, but the memory mapped I/Os are typically adressed through direct adressing only. The only exeption in NES' case would be the APU registers which are commonly accessed as indexed adressing because they're basically an array of registers - but there will never be an overflow so it doesn't matter. I even adressed them using indirect adressing in one of my engines (the pointer would decide which of the 4 sound register is written to, and the Y register which sound channel is written to), but even that doesn't cause problems as there is no page crossing.