6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Nov 23, 2024 8:44 pm

All times are UTC




Post new topic Reply to topic  [ 11 posts ] 
Author Message
PostPosted: Tue Oct 30, 2018 10:20 am 
Offline

Joined: Tue Oct 30, 2018 10:12 am
Posts: 1
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:
LDA #$80
STA $1
ROL $1


does not set Z.

But even more confusingly:

Code:
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:
LDA #$80
STA $1
LDA #$AA
ROL $1

should set Z.

Can a guru please clear this up for me?


Top
 Profile  
Reply with quote  
PostPosted: Tue Oct 30, 2018 11:22 am 
Offline

Joined: Wed Nov 18, 2015 8:36 am
Posts: 102
Location: UK
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.


Top
 Profile  
Reply with quote  
PostPosted: Tue Oct 30, 2018 11:51 am 
Offline
User avatar

Joined: Fri Nov 09, 2012 5:54 pm
Posts: 1431
Hi funkybro, and welcome to the forum.

From the MOS MCS6500 family programming manual, page 169 of the PDF:

Attachment:
6502_shift.png
6502_shift.png [ 43.73 KiB | Viewed 2672 times ]


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:
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:
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.


Top
 Profile  
Reply with quote  
PostPosted: Tue Oct 30, 2018 12:28 pm 
Offline

Joined: Wed Nov 18, 2015 8:36 am
Posts: 102
Location: UK
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:
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!


Top
 Profile  
Reply with quote  
PostPosted: Tue Oct 30, 2018 1:05 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
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.)


Top
 Profile  
Reply with quote  
PostPosted: Tue Oct 30, 2018 2:16 pm 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
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.

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
PostPosted: Tue Oct 30, 2018 2:29 pm 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
In mine, I have separate code for accumulator and memory:
Code:
   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;
   }


Top
 Profile  
Reply with quote  
PostPosted: Tue Oct 30, 2018 3:03 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
Ah, I see you have a type uint8_t to help you out! So you don't need explicit masking to 8 bits.


Top
 Profile  
Reply with quote  
PostPosted: Tue Oct 30, 2018 3:05 pm 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
Yes, that's a standard feature of modern editions of C and C++. Just #include <stdint.h>.


Top
 Profile  
Reply with quote  
PostPosted: Tue Oct 30, 2018 3:14 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
Great if coding in C! JavaScript and Python have their own foibles...


Top
 Profile  
Reply with quote  
PostPosted: Sun Nov 04, 2018 9:42 am 
Offline

Joined: Tue Jul 24, 2012 2:27 am
Posts: 679
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:
;; inside ROL
val = setnz((val<<1) | input_c);

_________________
WFDis Interactive 6502 Disassembler
AcheronVM: A Reconfigurable 16-bit Virtual CPU for the 6502 Microprocessor


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 11 posts ] 

All times are UTC


Who is online

Users browsing this forum: barnacle and 59 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: