Page 1 of 1

Check my understanding of page crossing w/indexed addressing

Posted: Thu Aug 31, 2023 1:22 am
by Dan Moos
Working on my emulator. I'm trying to make my instructions require the correct amount of cycles. Tell me if the following is correct.


Let's say the instruction is LDA, Absolute X addressing.

After I ingest the LSB of the address, I just check if (LSB + X) > 0xff, and if it is, I add a cycle.

Sound good?

EDIT: I realize my math isn't taking the LSB wrapping around into account. Assume my code does.

EDIT: Is the carry flag a better way to check?

EDIT:Never mind concerning the carry flag. I forgot the carry flag only changes when I tell it to (which I will in this case of course).

Re: Check my understanding of page crossing w/indexed addres

Posted: Thu Aug 31, 2023 5:45 am
by barrym95838
Dan Moos wrote:
I forgot the carry flag only changes when I tell it to (which I will in this case of course).
LDA should never affect the 65xx carry flag, regardless of addressing mode.

Regarding page-crossing indexing, the cycle counts do typically increase by one, but I seem to remember an exception or two, where the non-page-crossing timing was the same as the page-crossing timing for certain instructions. I'm link-challenged at the moment, so someone please correct me if I'm wrong.

Re: Check my understanding of page crossing w/indexed addres

Posted: Thu Aug 31, 2023 7:12 am
by BigEd
> I just check if (LSB + X) > 0xff, and if it is, I add a cycle.

Sounds right to me - you will of course need to be sure about signedness and byte-sizedness of your inputs there. What you're looking for is a carry from the LSB of the effective address to the MSB. (Which is unrelated to the C bit of your model.) Another way to do that, perhaps, is to see if the MSB in is different from the MSB out. Much depends on the data types in your code, as to what is efficient and maintainable.

Re: Check my understanding of page crossing w/indexed addres

Posted: Fri Sep 01, 2023 2:22 am
by Dan Moos
Here's the actual code I've come up with:

Code: Select all

//LDA Absolute, X. 3 bytes 4 cycles (+1 if page cross)
if (Address_Mode == ABSOLUTE_X) { 
	uint8_t MSB, LSB, LSB_Temp;
	cycle(1);
	LSB_Temp = DataBus ;
	LSB = DataBus + X;
	cycle(1);
	MSB = DataBus;
	if (LSB < LSB_Temp) { //add cycle if page crossed
		MSB++;
		cycle(0);
	}
	cycle(0);
	AddressBus = (MSB << 8) | LSB;
	A = Memory[AddressBus];
	if (A == 0)
		PS |= ZERO_FLAG;
	else
		PS &= ~(ZERO_FLAG);
	if (A & 0b10000000)
		PS |= NEGATIVE_FLAG;
	else
		PS &= ~(NEGATIVE_FLAG);
	cycle(1);
}
seems to work. Cycle(1) advances the PC and puts it on the address bus. Cycle(0) does nothing (for now).

Re: Check my understanding of page crossing w/indexed addres

Posted: Thu Sep 07, 2023 8:05 am
by White Flame
Probably the best reference for writing accurate NMOS 6502 emulators is 64doc. It'll step through what goes on every single cycle of an instruction, and you can simplify from there if you're just going for total number of cycles. For instance, LDA abs,X does a redundant read if a page boundary is crossed by the indexing:

Code: Select all

  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.
Also, computing the N & Z flags are pretty much always done together, so creating an inline function or macro for computing those two is useful.