6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Jun 07, 2024 6:01 am

All times are UTC




Post new topic Reply to topic  [ 6 posts ] 
Author Message
PostPosted: Sat Apr 24, 2004 12:05 am 
Offline

Joined: Wed Dec 18, 2002 3:20 am
Posts: 113
Ok,

I wasn't sure if this little trick works or not, but....

Let's say I have a function that is meant to work in 8 bit mode.

and I do:

PHA
PHX
PHY
PHP
SEP #00110000B
.
. Function code
.
PLP
PLY
PLX
PLA
RTS

Will PHP/PLP save the previous state of the registers in terms of whether they were in 8bit or 16 bit mode?

right now, I'm testing the bits for 8 or 16 bit status and then modifying them, the problem is with nested subroutines that can be called individually or nested, it gets to be a lot of wasted space, so I was wondering if doing my PHP / PLP combo will save the register size setting on the stack and restore it so if it was in 16 bit mode before I started, it would be returned to it once I finished?

Does that make any sense?

_________________
-Tony
KG4WFX


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sat Apr 24, 2004 3:49 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8456
Location: Southern California
> Will PHP/PLP save the previous state of the registers in terms of
> whether they were in 8bit or 16 bit mode?

Sure. M and X (status bits 5 and 4) will be saved and restored. The only bit that does not get saved and restored this way is E, but the '816 does not have to be in emulation mode to do 8-bit operations.

BTW-- their SEP and REP instructions are awfully cryptic for this kind of thing. I always just make macros to replace something like

SEP #00100000B

with

ACCUM_8

which is a lot more legible for setting the accumulator to 8-bit mode.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sat Apr 24, 2004 4:00 am 
Offline

Joined: Wed Dec 18, 2002 3:20 am
Posts: 113
I'm actually still learning a lot about cross-32 - due to my need to get going with it I haven't been able to focus on all of its convenience features like macros, it is a really nice assembler tho. Of course, I also got sidetracked once I realized I have a major bug in my program and I'm not sure where/why ;)

_________________
-Tony
KG4WFX


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sat Apr 24, 2004 10:51 pm 
Offline
User avatar

Joined: Thu Mar 11, 2004 7:42 am
Posts: 362
To preserve the current values of the A, X, and Y registers and the m, x, and e flags, use:

Code:
CLC
XCE
PHP
REP #$30
PHA
PHX
PHY
SEP #$30 ; or SEP #$10 or SEP #$20


then exit with:

Code:
PLA
PLX
PLY
PLP
XCE
RTS ; or RTL


The reason for the REP #$30 is that:

Code:
SEP #$30
REP #$30


sets the high bytes of X and Y to $00 even when e=0.

Note that the above code always returns with the carry clear, since e=0 upon entering the final XCE. To allow the subroutine to return with the carry set or clear, use:

Code:
      PLA
      PLX
      PLY
      BCS LABEL
      PLP
      XCE
      RTS ; or RTL

LABEL PLP
      XCE
      SEC
      RTS ; or RTL


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sun Apr 25, 2004 7:00 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8456
Location: Southern California
If you're just now writing the subroutines though (as opposed to recycling 6502 routines) and they are to be called obviously from the '816 running in native mode (regardless of M or X), I can't think of any reason to save e. Just leave it in native mode. It's also rare to need a subroutine to push and pull all four registers A, X, Y, and P. It's not even very common to need to push and pull all three registers A, X, and Y in an interrupt service routine. (Of course the interrupt sequence and RTI take care of P for you already though.)


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Apr 26, 2004 12:02 am 
Offline
User avatar

Joined: Thu Mar 11, 2004 7:42 am
Posts: 362
I wrote that last post a little too fast, didn't I? The registers should be restored in the order Y, X, A, not A, X, Y and a REP #$30 should precede the PLY, PLX, and PLA instructions. In the interests of getting things right, here are a couple of facts to keep in mind when saving registers on the 65816 when switching between 8 and 16 bits or when switching between emulation and native mode.

Fact #1: Setting the x FLAG to 1 (8-bit index registers) overwrites the high bytes of the X and Y registers.

Setting the x flag to 1 with, for example, a SEP #$10 or SEP #$30 instruction, will set the high bytes (bits 15-8) of the X and Y registers to $00. This means that a PHX and/or PHY must come BEFORE the SEP instruction! For example, after the following:

Code:
CLC
XCE
PHP
REP #$10   ; 16-bit index registers
LDX #$1234
LDY #$5678
SEP #$10   ; 8-bit index registers
REP #$10   ; 16-bit index registers
STX XREG
STY YREG
PLP
XCE


XREG contains $34
XREG+1 contains $00
YREG contains $78
YREG+1 contains $00

Fact #2: Setting the e FLAG to 1 (emulation mode) sets the m and x flags to 1 and overwrites the high byte of the stack pointer (S register).

Note that since the x flag is set to 1, the high bytes of the of the X and Y registers will be overwritten! The high bytes of the X and Y register get set to $00, and the high byte of the stack pointer gets set to $01. Because the high byte of the stack pointer will be overwritten, caution should be used when calling emulation mode routines from native mode! The code above can be modified to illustrate that the high bytes of the S, X and Y registers get overwritten. After:

Code:
CLC
XCE
PHP
REP #$30   ; 16-bit mode
TSC        ; save stack pointer in accumulator
LDX #$ABCD
TXS
LDX #$1234
LDY #$5678
SEC
XCE
CLC
XCE
REP #$30   ; 16-bit mode
STX XREG
STY YREG
TSX
STX STKPTR
TCS        ; restore stack pointer
PLP
XCE


STKPTR contains $CD
STKPTR+1 contains $01
XREG contains $34
XREG+1 contains $00
YREG contains $78
YREG+1 contains $00

The following code illustrates that the m and x get set to 1.

Code:
CLC
XCE
PHP
REP #$30   ; 16-bit mode
SEC
XCE
CLC
XCE
PHP        ; push m and x flag values onto stack
SEP #$20   ; 8-bit accumulator
PLA        ; pull m and x flag values from stack
AND #$30   ; mask m and x flags
STA MXFLGS
PLP
XCE


After the code above, MXFLAGS will contain $30.

To save and restore the A, X, and Y registers while preserving the m, x and e flags, start with:

Code:
PHX
PHY
CLC      ; * see below
XCE      ; * see below
PHP
REP #$30 ; ** see below
PHA
SEP #$30


and exit with:

Code:
REP #$30 ; ** see below
PLA
PLP
XCE      ; * see below
PLY
PLX


To return with the carry flag clear or set, exit with:

Code:
      REP #$30 ; ** see below
      PLA
      BCS LABEL
      PLP
      XCE      ; * see below
      PLY
      PLX
      CLC      ; not necessary if the preceding XCE is used
      RTS      ; or RTL

LABEL PLP
      XCE      ; * see below
      PLY
      PLX
      SEC
      RTS      ; or RTL


By saving X and Y first (and restoring them last) you can save a couple of bytes of stack space if the routine is called when the x flag is already 1 (8-bit index registers). Of course, you won't need to save A, X, or Y if your routine doesn't overwrite them, but it might be a good idea leave those instructions in place until your routine is fully debugged.

* These instructions can be eliminated if the routine will always be called from native mode (the most common case). This will save 3 bytes and 8 cycles. However, you may wish to leave these instructions in place while debugging or if you are using both emulation mode routines and native mode routines.

** These instructions can be eliminated if the high byte of the accumulator isn't overwritten (it would be overwritten if you used, for example, a XBA instruction). This will save 4 bytes and 6 cycles. Note that TDC and TSC ALWAYS overwrite all 16-bits of the accumulator (including both in native mode when the m and x flags are 1 and in emulation mode)!

In fact, if you don't overwrite the high byte of the accumulator, you can move the PHA before the PHP and the PLA after the PLP. This would allow you use ROL and LSR to return with the carry flag clear or set. In this case, you would enter with:

Code:
PHA
PHX
PHY
CLC      ; * see above
XCE      ; * see above
PHP
SEP #$30


and exit with:

Code:
ROL      ; save carry flag
PLP
XCE      ; * see above
LSR      ; restore carry flag
PLY
PLX
PLA


Note that using ROR and ASL won't necessarily work, since the accumulator may be a different width before the PLP than after. (For example, if the m flag is 1 before the PLP, the accumulator will be 8 bits wide, and if the m flag is 0 after the PLP the accumulator will be 16 bits wide.)


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

All times are UTC


Who is online

Users browsing this forum: No registered users and 7 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: