Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.sys.apple2.programmer > #2204 > unrolled thread

most efficient way to save/restore 6502 registers

Started byMark Lemmert <mark.lemmert@gmail.com>
First post2016-02-04 11:41 -0800
Last post2016-02-04 21:20 -0800
Articles 5 — 4 participants

Back to article view | Back to comp.sys.apple2.programmer


Contents

  most efficient way to save/restore 6502 registers Mark Lemmert <mark.lemmert@gmail.com> - 2016-02-04 11:41 -0800
    Re: most efficient way to save/restore 6502 registers Scott Hemphill <hemphill@hemphills.net> - 2016-02-04 15:31 -0500
      Re: most efficient way to save/restore 6502 registers Mark Lemmert <mark.lemmert@gmail.com> - 2016-02-04 19:22 -0800
        Re: most efficient way to save/restore 6502 registers Michael Barry <barrym95838@yahoo.com> - 2016-02-04 20:21 -0800
          Re: most efficient way to save/restore 6502 registers wssimms@gmail.com - 2016-02-04 21:20 -0800

#2204 — most efficient way to save/restore 6502 registers

FromMark Lemmert <mark.lemmert@gmail.com>
Date2016-02-04 11:41 -0800
Subjectmost efficient way to save/restore 6502 registers
Message-ID<61723ee6-c434-48d0-9bb0-bd44b545c922@googlegroups.com>
I am wondering if anybody knows why the most Apple II assembly subroutines save/restore registered via the stack (method 1 below), instead of using variables (method 2 below)? 

And, what are the advantages and disadvantages are for each method?

Thanks a lot for any insights!


I'm interested in knowing because when writing code where speed is a priority tend to use variables and wondering if I'm missing an important consideration. 


The parenthetical numbers in the comment fields below are the clock cycles for each opcode according to the following reference guide (it's on an atari site but since both Apple and Atari use 6502 my understanding is that the opcodes cycle times are the same)

http://www.atarimax.com/jindroush.atari.org/aopc.html



Here is what I've come up with so far:


Advantages (Stack)
======================
Less Memory

Slightly better code readability (I think mainly because it's the standard so
it's immediately obvious what's going on)


Advantages (Variables)
=======================
Speed





=====METHOD 1 (Stack)=====

;SAVE REGISTERS
	TXA	;(2)
	PHA	;(3)
	TYA	;(2)
	PHA	;(3)


<SUBROUTINE CODE>


;RESTORE REGISTERS	
	PLA	;(4)
	TAY	;(2)
	PLA	;(4)
	TAX	;(2)



Total clock cycles: !22
Total Bytes: !16

=====METHOD 1 (Variables)=====


;SAVE REGISTERS	
	STX SAVED.XREG.LOCAL	;(4)
	STY SAVED.YREG.LOCAL	;(4)

<SUBROUTINE CODE>


;RESTORE REGISTERS
	LDX SAVED.XREG.LOCAL	;(4)
	LDY SAVED.YREG.LOCAL	;(4)



Total clock cycles: !16
Total bytes !24 (for code) + 2 (for variables) = !26

[toc] | [next] | [standalone]


#2205

FromScott Hemphill <hemphill@hemphills.net>
Date2016-02-04 15:31 -0500
Message-ID<87mvrgi5fa.fsf@hemphills.net>
In reply to#2204
Mark Lemmert <mark.lemmert@gmail.com> writes:

> I am wondering if anybody knows why the most Apple II assembly
> subroutines save/restore registered via the stack (method 1 below),
> instead of using variables (method 2 below)?
>
> And, what are the advantages and disadvantages are for each method?
>
> Thanks a lot for any insights!

(1) I think you pretty much covered it.  Note that if you do a lot of
saving/restoring, you could (with both schemes) reduce the per instance
memory usage by doing this:

  JSR XYSAVE
  ...
  JSR XYRESTORE

You could even omit the call to XYRESTORE if XYSAVE manipulates the
stack by putting the address to XYRESTORE on it, so that the RET from
your subroutine automatically restores the registers.

(2) If your subroutine calls itself recursively, you need to store the
registers on a stack.

(3) If your subroutine doesn't know which memory banks are switched in
(e.g. when processing an interrupt) then you may not want to store the
registers in memory.

(4) Saving the registers in memory allows you to restore them multiple
times.

Scott
-- 
Scott Hemphill	hemphill@alumni.caltech.edu
"This isn't flying.  This is falling, with style."  -- Buzz Lightyear

[toc] | [prev] | [next] | [standalone]


#2207

FromMark Lemmert <mark.lemmert@gmail.com>
Date2016-02-04 19:22 -0800
Message-ID<9daa1cb8-14a2-4e10-b3c5-785c1d53799e@googlegroups.com>
In reply to#2205
On Thursday, February 4, 2016 at 2:31:07 PM UTC-6, Scott Hemphill wrote:
Scott,

Thanks for the reply!

(1) Great idea. Perfect for programs with plenty of speed and tight on memory.

(2)-(4): This is just the kind of insight I was hoping to gain...I figured there was probably some more advanced bigger picture I was missing on the stack and these examples nail it. 


Thanks again. 

> Mark Lemmert  writes:
> 
> > I am wondering if anybody knows why the most Apple II assembly
> > subroutines save/restore registered via the stack (method 1 below),
> > instead of using variables (method 2 below)?
> >
> > And, what are the advantages and disadvantages are for each method?
> >
> > Thanks a lot for any insights!
> 
> (1) I think you pretty much covered it.  Note that if you do a lot of
> saving/restoring, you could (with both schemes) reduce the per instance
> memory usage by doing this:
> 
>   JSR XYSAVE
>   ...
>   JSR XYRESTORE
> 
> You could even omit the call to XYRESTORE if XYSAVE manipulates the
> stack by putting the address to XYRESTORE on it, so that the RET from
> your subroutine automatically restores the registers.
> 
> (2) If your subroutine calls itself recursively, you need to store the
> registers on a stack.
> 
> (3) If your subroutine doesn't know which memory banks are switched in
> (e.g. when processing an interrupt) then you may not want to store the
> registers in memory.
> 
> (4) Saving the registers in memory allows you to restore them multiple
> times.
> 
> Scott

[toc] | [prev] | [next] | [standalone]


#2209

FromMichael Barry <barrym95838@yahoo.com>
Date2016-02-04 20:21 -0800
Message-ID<63f8f033-1491-414f-8855-dcf92d08b695@googlegroups.com>
In reply to#2207
On Thursday, February 4, 2016 at 7:22:50 PM UTC-8, Mark Lemmert wrote:
> ...

If your subroutines are in RAM, and you do not need them to be re-
 entrant and/or recursive, you could try self-modifying code:

subroutine:
    stx  subzzz-3
    sty  subzzz-1
    ...  
    ...  
    ldx  #00  ; dummy operand
    ldy  #00  ; dummy operand
subzzz:
    rts  

It's just as fast as zero-page variables, and trades a couple
 of bytes of zero-page for a couple of bytes of code space.

Mike B.

[toc] | [prev] | [next] | [standalone]


#2210

Fromwssimms@gmail.com
Date2016-02-04 21:20 -0800
Message-ID<ab89178a-01c2-47c1-ba8e-edbbd736871a@googlegroups.com>
In reply to#2209
Am Freitag, 5. Februar 2016 13:21:49 UTC+9 schrieb Michael Barry:
> On Thursday, February 4, 2016 at 7:22:50 PM UTC-8, Mark Lemmert wrote:
> > ...
> 
> If your subroutines are in RAM, and you do not need them to be re-
>  entrant and/or recursive, you could try self-modifying code:
> 
> subroutine:
>     stx  subzzz-3
>     sty  subzzz-1
>     ...  
>     ...  
>     ldx  #00  ; dummy operand
>     ldy  #00  ; dummy operand
> subzzz:
>     rts  
> 
> It's just as fast as zero-page variables, and trades a couple
>  of bytes of zero-page for a couple of bytes of code space.
> 
> Mike B.

First off, I am a big fan of self-modifying code on 6502 processors. I like this example of register saving and reloading and I also like to use self-modifying code for manipulating things through pointers. For example, to copy memory.

Second off, I am a fan of using 65c02 opcodes. Given than enhanced IIes, IIcs, and IIgses are the vast majority of machines still being actively used, it seems reasonable to do so, in my opinion. Therefore:

; Save Registers
        pha
        phy
        phx
        ...
; Restore Registers
        plx
        ply
        pla
        rts

works great for me.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.sys.apple2.programmer


csiph-web