Using a subroutine to push blocks of memory on the stack ======================================================== J.G.Harston, 15-Mar-2002 There is often the need to push blocks of memory on the stack and restore them later to prevent them being changed. When doing this many times there is the temptation to put the repeated code in a subroutine. But, of course, you can't simply push things on the stack in a subroutine, as calling and returning also uses the stack. For instance, the following code will not work as expected: .PushWS LDA data PHA RTS It pushes a value onto the stack ont top of the return addess, and then returns to the trashed return address. With careful programming, though, you can write subroutines to push data into the stack. You have to also move the stacked return address so it can be used after the data has been pushed or popped. The two routines here, PushWS and PopWS demonstate this. \ stacknumber = number of bytes to stack \ baseaddress = base address of memory to stack .PushWS \ On entry, stack will hold \ ret_lo ret_hi PHA:TXA:PHA :\ Stack holds X A ret_lo ret_hi LDX #stacknumber-1 .PushLp LDA baseaddress,X:PHA :\ Push memory onto stack DEX:BPL PushLp :\ Loop without changing Carry TSX :\ Point X to bottom of stack LDA &104+stacknumber,X:PHA :\ Push stacked ret_hi onto stack LDA &104+stacknumber,X:PHA :\ Push stacked ret_lo onto stack LDA &104+stacknumber,X:PHA :\ Push stacked A onto stack LDA &104+stacknumber,X:TAX :\ Get stacked X into X PLA:RTS :\ Pop restacked A and return .PopWS \ On entry, stack will hold \ ret_lo ret_hi stacked_data old_X old_A old_ret_lo old_ret_hi PHA:TXA:PHA :\ Push A and X TSX :\ Point X to bottom of stack PLA:STA &120+stacknumber,X :\ Copy stacked X to old_X PLA:STA &120+stacknumber,X :\ Copy stacked A to old_A PLA:STA &120+stacknumber,X :\ Copy ret_lo to old_ret_lo PLA:STA &120+stacknumber,X :\ Copy ret_hi to old_ret_hi LDX #0 .PopLp PLA:STA baseaddress,X:INX :\ Pop memory from stack TXA:EOR #stacknumber:BNE PopLp :\ Loop without changing Carry PLA:TAX :\ Pop restacked X PLA:RTS :\ Pop restacked A and return PopWS must be called with the same level of stack data as a preceded PushWS, for instance: JSR PushWS \ do some processing, all Pushes balanced by Pops JSR PopWS Something that is not immediately obvious is you cannot JMP PopWS, as PopWS needs a return address as the first stacked item. Jumping to PopWS will have the stacked data as the first stacked items and no return address. If PopWS is the last thing called at the end of some code it must be written as: JSR PopWS :\ NB! Must be called RTS