Page 1 of 1

Behaviour of Z flag for ROL and ROR

Posted: Tue Oct 30, 2018 10:20 am
by funkybro
I am confused by the wording of the behaviour of the Z flag for ROL and ROR given here:
http://www.obelisk.me.uk/6502/reference.html#ROL

For Z the documentation for both ROL and ROR states
Quote:
Set if A = 0
I am confused about whether this applies even in non-accumulator mode. If you are doing e.g. zero page ROL, why should we care about the accumulator contents at the end?

I am further confused by the behaviour of easy6502 in this regard.

The following:

Code: Select all

LDA #$80
STA $1
ROL $1
does not set Z.

But even more confusingly:

Code: Select all

LDA #$1
STA $1
ROR $1
does set Z!?!

My current thinking is:
  • Z should reflect the result of the operation, rather than the contents of A
  • Easy6502 ROL has a bug
And therefore the following:

Code: Select all

LDA #$80
STA $1
LDA #$AA
ROL $1
should set Z.

Can a guru please clear this up for me?

Re: Behaviour of Z flag for ROL and ROR

Posted: Tue Oct 30, 2018 11:22 am
by dolomiah
It's a mistake, it should say if A or M = 0. Your interpretation it right, it's the result of the operation that determines Z (and indeed C)

So, the behaviour is that if the result of ROR or ROL on whatever it is acting upon (A or M) is zero then Z is set.

Re: Behaviour of Z flag for ROL and ROR

Posted: Tue Oct 30, 2018 11:51 am
by ttlworks
Hi funkybro, and welcome to the forum.

From the MOS MCS6500 family programming manual, page 169 of the PDF:
6502_shift.png
To make it short:

LSR, ROR, ASL, ROL are shifting a Byte (by one Bit position).

Depending on the addressing mode of the instruction,
the Byte either is in the accumulator A,
or in memory (CPU reads the Byte from memory, then shifts it, then writes it back to memory).
;---

Now about what happens with the C flag:

LSR shifts the Byte right, 0 goes into the MSB (Bit 7) of the Byte, the LSB (Bit 0) of the Byte goes into the C flag. //shift right into C flag.

ASL shifts the Byte left, 0 goes into the LSB of the Byte, the MSB of the Byte goes into the C flag. //shift left into C flag.

ROR shifts the Byte right, C flag goes into the MSB of the Byte, the LSB of the Byte goes into the C flag. //rotate right through C flag.

ROL shifts the Byte left, C flag goes into the LSB of the Byte, the MSB of the Byte goes into the C flag. //rotate left through C flag.

;---

Flags N Z are set or cleared according to the result after the shifting:

If the Byte is $00 after the shifting, Z flag is set, else it's cleared. //checking if the result was $00.
A copy of the MSB (Bit 7) of the Byte after the shifting goes into the N flag. //the sign of the result.

;===

So if you do a ROR or a ROL instruction, the interesting question is what was in the C flag before you do it.

Code: Select all

CLC //clear C flag to 0
LDA #$80
STA $1
ROL $1
Would give you $00 as a result.
Flags after the ROL: C=1, Z=1, N=0.

;---

Code: Select all

SEC //set C flag to 1
LDA #$80
STA $1
ROL $1
Would give you $01 as a result.
Flags after the ROL: C=1, Z=0, N=0.

Hope, this helps.

Re: Behaviour of Z flag for ROL and ROR

Posted: Tue Oct 30, 2018 12:28 pm
by dolomiah
Good spot ttlworks, I hadn't read the example code closely enough.

It is very important know the value of C or set it to the required value before using ROL or ROR.

Use of C is necessary to do multi-byte shifts for example:

Code: Select all

ASL $00
ROL $01
In the above, ASL is like ROL but as ttlworks says, will always shifts a zero in to the LSB (it ignores the value of C). ROL however will shift in the value of C.

For example, if the contents of location $00 is 128 (decimal) and $01 is 0, then the above code will result in location $00 containing 0 and location $01 containing 1.

I hope I haven't complicated the answer by giving this example!

Re: Behaviour of Z flag for ROL and ROR

Posted: Tue Oct 30, 2018 1:05 pm
by BigEd
Oops, all that's said above looks right to me, but indeed easy6502 seems to have had a bug. Or, eight bugs, because of the way it's written. I've just pushed a fix, I believe, to ROL and ASL code, so the zero flag should now be correct.

Sorry for the confusion - it does mean that easy6502 will now behave slightly differently, and more correctly, if you refresh your easy6502 page. (Unless my fix is wrong!)

(Lessons to emulator writers: watch out when left-shifting that you mask off to a byte-sized result, and preferably organise your code so you do this in one place for each operation, not in many.)

Re: Behaviour of Z flag for ROL and ROR

Posted: Tue Oct 30, 2018 2:16 pm
by BitWise
dolomiah wrote:
It's a mistake, it should say if A or M = 0. Your interpretation it right, it's the result of the operation that determines Z (and indeed C)

So, the behaviour is that if the result of ROR or ROL on whatever it is acting upon (A or M) is zero then Z is set.
I'll update it.

All the flag tables are preceded by 'Processor Status after use:' so they represent the result of executing the opcode.

Re: Behaviour of Z flag for ROL and ROR

Posted: Tue Oct 30, 2018 2:29 pm
by Chromatix
In mine, I have separate code for accumulator and memory:

Code: Select all

	void rol(uint16_t ea) {
		uint8_t B = read(ea);
		bool CC = B >> 7;
		B = (B << 1) | C;
		write(ea, B);
		C = CC;
		N = B >> 7;
		Z = !B;
	}

	void rola(uint16_t ea) {
		bool CC = A >> 7;
		A = (A << 1) | C;
		C = CC;
		N = A >> 7;
		Z = !A;
	}

	void ror(uint16_t ea) {
		uint8_t B = read(ea);
		bool CC = B & 1;
		B = (B >> 1) | (C << 7);
		write(ea, B);
		C = CC;
		N = B >> 7;
		Z = !B;
	}

	void rora(uint16_t ea) {
		bool CC = A & 1;
		A = (A >> 1) | (C << 7);
		C = CC;
		N = A >> 7;
		Z = !A;
	}

Re: Behaviour of Z flag for ROL and ROR

Posted: Tue Oct 30, 2018 3:03 pm
by BigEd
Ah, I see you have a type uint8_t to help you out! So you don't need explicit masking to 8 bits.

Re: Behaviour of Z flag for ROL and ROR

Posted: Tue Oct 30, 2018 3:05 pm
by Chromatix
Yes, that's a standard feature of modern editions of C and C++. Just #include <stdint.h>.

Re: Behaviour of Z flag for ROL and ROR

Posted: Tue Oct 30, 2018 3:14 pm
by BigEd
Great if coding in C! JavaScript and Python have their own foibles...

Re: Behaviour of Z flag for ROL and ROR

Posted: Sun Nov 04, 2018 9:42 am
by White Flame
Since Javascript offers JIT inlining, I pipe most operations through a common "setnz" function, which also masks to 8 bits. It really collapses the source code, while still compiling to a fast implementation:

Code: Select all

;; inside ROL
val = setnz((val<<1) | input_c);