It is currently Thu Oct 19, 2017 10:31 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 5 posts ] 
Author Message
PostPosted: Wed Aug 12, 2009 6:53 am 
Offline
User avatar

Joined: Tue Jun 24, 2008 8:38 pm
Posts: 1517
Location: Fukuoka, Japan
After this conversation with Miau about function parameters, I started to think a little bit about the subject. I'm sorry but this message will be like a brain storming session but I hope that some interesting ideas will comes up out of it.

The biggest problem with temp variable is that you may re-use by accident the same variable. So what I'm thinking is why not trying to emulate what is done in higher level language like C to avoid those issues? I don't know how much will be the cost on performance but here's the concept, which I have to put in code later based on the message and clean up after.

I always under use the stack so why not use it like it should be? Before calling a function, you would have a macro lpr (Load ParameteR) that will stores the parameters on the stack.

ex: lpr myFunction(param1, param2) etc.

Now param1 and 2 are on the stack. The macro will be in charge of (in that order):

- storing the localVariable/frame pointer on the stack (explained later)
- putting the variables on the stack
- calling the function
- clean up once the function is finished (means restoring localVariable/frame pointer and unpop parameters)

Once I call the function, I will have my parameters and the return address on the stack. Now that I'm inside the function, I must get a copy of the stack pointer and store it in a variable, the frame pointer.

To access my parameters, I must define some constant to locate the position of the parameter. The only drawback I see is that each constant must be unique. Maybe some fancy trick with scoping could fix that issue.

param1 = sizeOfFunctionAddress + sizeOfVariable
param2 = sizeOfFunctionAddress + param1 + sizeOfVariable

Maybe order is wrong, for now let's say it's right. So if I want to access my parameters, I could define a macro that use my frame pointer variable. hmm.. the real code in the macro would look something like:

ldx framePointerAdr + param1

will get me the first parameter.

Now that my function parameters are handled I may want to have some local variable too. So when I enter the function, I must define right away all my local variables on the stack. A macro could do the job. The only drawback again is the constant for the variable location must be unique. Once the variable are defined, I must get the stack pointer again and save it in the LocalVariable pointer variable. With LocalVariable and defined constant I can access all my local variables on the stack.

I don't have to worry about the content of the frame/LocalVariable pointer when I call a function since the macro will take care of saving them on the stack and restoring it at the end.

Basically, this is the concept I thought tonight very fast. I don't know how pratical and fast it is yet but it seems interesting and it may fix the issue Miau have with parameters. My only concern is the constants for parameters, how to handle them. I must figure out a solution. If scoping can take care of it that could be a solution. Must make a proof of concept to see how it goes.

Does what I say make sense? All what I said is theoretical and based on some ideas on how stack work for higher level language. It seems something you could do with some macro in ca65.

Any comment on the subject will be appreciated.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 12, 2009 8:45 am 
Offline
User avatar

Joined: Wed Nov 10, 2004 6:47 pm
Posts: 1845
Quote:
lpr (Load ParameteR) that will stores the parameters on the stack.


That threw me for a loop when I read it. If what you're doing is storing parameters, calling it Load Parameter doesn't make much sense at all.

Quote:
To access my parameters, I must define some constant to locate the position of the parameter. The only drawback I see is that each constant must be unique. Maybe some fancy trick with scoping could fix that issue.


If your addresses are constant, it defeats the entire point of using a stack-like structure. The purpose of having a stack is that your routines parameters are on the top of the stack (the exact address is relative to how large the stack is). Or maybe I'm misunderstanding what you mean.

The TSX instruction, in combination with LDA Abs,X can be used to read parameters off the stack without pulling them:

Code:
myfunction:
  tsx
  lda $101,X  ; last pushed value (low byte of return address)
  lda $102,X  ; high byte of return address
  lda $103,X  ; param 1  (assuming parameters are pushed in reverse order)
  lda $104,X  ; param 2
    ..  etc


Quote:
Now that my function parameters are handled I may want to have some local variable too.


Which complicates this setup.


Using the native 6502 stack for this is less than ideal because it leads to a lot of repeated/redundant code. IE, the code CALLING the function must pop all parameters. This means that you will have parameter popping code repeated every time the function is called, instead of just putting it in the function body. You can't [easily] put it in the function body though, because it would mess up your RTS address.

I say... screw trying to use the normal stack and just make your own stack.

You can share the $01xx page if you really want to, or you could use any other area in memory. Zero Page would be preferable due to faster access.

Here's an example which uses the following ideas:

- param/local var stack starts at $00FF and grows down
- 'stack' is the param stack variable (ie: stack=0 for zero page)
- X is the stack pointer
- MyFunction takes 2 parameters, each 1 byte
- MyFunction has a single local variable, 1 byte

Code:
; code which calls the function
lda param_1
sta stack,X
dex
lda param_2
sta stack,X
dex
jsr MyFunction

; code can resume here normally, no pulling necessary

;;----------------------------------

MyFunciton:
dex  ; single local variable allocated

    ; in this function now...
lda stack+1,X    ; gets the local variable
lda stack+2,X    ; gets the 2nd param
lda stack+3,X    ; gets the 1st param

    ; clean up for function
inx
inx  ; or if the number of pops is excessive
inx  ;  you can TXA, add, then TAX

rts


If you want to allow for a larger stack (larger than 256 bytes) the math gets a lot heavier, and you need to use indirect addressing instead of indexing, which results in bigger performance hits. But a 256 byte stack for local variables and function parameters, as well as ANOTHER 256 byte stack for return addresses should be more than enough for most things.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 12, 2009 8:24 pm 
Offline
User avatar

Joined: Tue Jun 24, 2008 8:38 pm
Posts: 1517
Location: Fukuoka, Japan
Thanks for you comment Disch.

Some of the names are maybe not appropriate. That's what happen when you just brainstorm those things I guess :) I see now many flaws in my example but not the one I expected at first. Some are caused by error using the 6502 in impossible way (will explain later). I guess the lesson from this is that instead of brainstorming in a message thread for something complicated as this, I should try it first and ask question later. I wanted to talk about a possible software stack too but I decided to drop it since it would have made the message longer (and maybe I would have talked more non-sense too).

My first goal is to see how I can (ab)use the stack a little bit more. I feel like I'm not using much of it and it such a waste to have 256 bytes lying around, only used occasionally. Maybe one way is to share one part of it like you mentioned.

About the constant, I will explain what I wanted to do but it's not possible in 6502. You store the stack pointer in a variable. You define the location of the variable relative to the current position of the stack pointer. So param1Pos contains just where it should be after pushing it on the stack, relative to the stack pointer address. So to get the location of param1, you need to do curentStackAdress + locationOfParam1 to get the memory location.

I wanted to do is lda varMyStackPointerAdr + param1Pos (which is the wrong address) but actually is more like lda (varMyStackPointerAdr) + param1Pos. BUT.. that's not possible. I always make that stupid mistake. What I meant is lda (varMyStackPointerAdr), param1Pos. But param1Pos must be put in y index register so that increase the code a little bit. And before you mention it, the varMyStackPointerAdr high byte is always $01 and you only update the low byte with the value taken from tsx.

Your example on how to access the stack gives me more idea. I will try to meditate on the subject.

As for the local variables on the stack, instead of unpoping them, restoring the stack pointer that I saved at the beginning of the function would do the job I think. I'm thinking to see how much I can manipulate the value of the stack pointer but I don't know if it's too risky to do so. They must have put those tsx/txs for a reason.

I will try to test my ideas, either with the real stack or my own. Your comment helped me see some new way of achieving it. Now it's time to test it. Thanks again for your comment.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Aug 13, 2009 1:13 am 
Offline
User avatar

Joined: Tue Jun 24, 2008 8:38 pm
Posts: 1517
Location: Fukuoka, Japan
Sorry for the double post.

During lunch time, I wrote some code of what I had in mind. The code is not tested so I don't know if the concept work. With the stack is seems like a lot of work. Maybe with my own made stack it would make things easier.

Here's the code snippet:
Code:
.segment "ZEROPAGE"
zpFramePointer:      .res 1      ; Contain stack pointer to access param
zpLocalVarPointer:   .res 1      ; Tentative: contain stack pointer to access local var

.segment "CODE"

; >--------------------------------------------------------------
; Macro spos -> Store Parameters On Stack 

; Note: Methods that requires high performance will not use this macro.
;       You have to decide when it's appropriate to use it or not.
; Note2: Maybe framePointer is enough and could do everyting with it.
;        This is just example of code.
;   
; How to call a function with param:
; - Save current value of frame/LocalVar pointer on the stack
; - Save state of stack pointer before adding parameter in X
; - Add parameters on the stack
; - Save on stack previous stack pointer state (X)
; - call function
; - When returning from call, pop back stack pointer
; - restore stack pointer
;<----------------------------------------------------------------
.macro spos functionName, param1, param2   ; only 2 param for this example
   lda zpFramePointer         ; Save stack pointers
   pha
   lda zpLocalVarPointer
   pha
   
   tsx               ; Get current stack pointer for later use
   
   lda param2            ; Store param 2
   pha
   lda param1            ; Store param 1
   pha
   
   txa               ; Now save state of stack pointer before param
   pha

   jsr functionName         ; Call the function
   
   pla                ; Restore stack pointer.  Note: If param count is small,
   tax               ; maybe to popup param would be faster. Macro should decide the right
   txs               ; case based on param count.
   
   pla               ; Restore stack pointers
   sta zpLocalVarPointer
   pla
   sta zpFramePointer
.endmacro
   
   ; Call my function with macro
   spos myFunctionWithParam #$01 #$05
   
   ;
   ; skip some code
   ;

; Define my constants here

; Location of param = address of stack + size of return address (2 bytes) + size of stack pointer + size of previous variable(s)
;
; Note: Maybe I'm not using symbols properly. Maybe ".define" is what I have
;       to use here. This is what I would like to do.
addressOfStack       = #$0100
sizeOfReturnAdress    = #$02
sizeOfFramePointer    = #$01
   
; Tentative: Create symbols for the function only
;
.scope myFunctWithParamVar
; Location of param on stack
   myParam1 = addressOfStack + sizeOfReturnAdress + sizeOfFramePointer
   myParam2 = addressOfStack + sizeOfReturnAdress + sizeOfFramePointer + 1   

; Now for my local variables
   localVar1 = addressOfStack
   localVar2 = addressOfStack + 1
   localVar3 = addressOfStack + 2
.endScope
   
;
; My function
;   
.proc myFunctionWithParam
   tsx               ; Get stack pointer
   stx zpFramePointer         ; and save it (macro could do it)
   
   dex               ; Alocate 3 variables on the stack
   dex               ; (macro could do it)
   dex            
   
   stx zpLocalVarPointer         ; save state of stack in the local var pointer
   txs               ; and adjust the stack.
   
   ldx zpFramePointer         ; Get back frame pointer
   
   lda myFunctWithParamVar::myParam1, x   ; Do something with my parameters
   ; Do something with it
   lda myFunctWithParamVar::myParam2, x
   ; Do something with it
   
   ldx zpLocalVarPointer         ; Now let's use the local variables
   
   lda #$05            ; Now let's use my local variables
   sta myFunctWithParamVar::localVar1, x
   ; do something
   lda myFunctWithParamVar::localVar2, x
   ; etc
   
   ; Just call another function
   spos myFunctionWithParam #$11 #$22   
   
   ; Do something here
   
   ldx zpFramePointer         ; Now we will "free" the local variables
   txs               ; by restoring the stack pointer to it's original state
   
   rts
.endproc


It doesn't keep the formatting of my editor so it's a little bit hard to read.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Aug 13, 2009 6:27 am 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7231
Location: Chexbres, VD, Switzerland
Yeah using the hardware stack is completely unoptimal, the better way is definitely the one Dish says (altough I don't use it, at the cost of having annoying variable conflicts frequently).

_________________
Life is complex: it has both real and imaginary components.


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

All times are UTC - 7 hours


Who is online

Users browsing this forum: Bing [Bot] and 6 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:  
Powered by phpBB® Forum Software © phpBB Group