delphi programming forums mysql charset mget recursive synonimos
free ventrilo servers hosting cs javascript delay python find in list
Back Forum New
abstract:

All registers for the microprocessor are used now!
when I leave the subroutine, I just pull all the registers used.
Is it possible to manage to have another local variable? if yes how to store it when I leave the subroutine since all registers are used?
thank you
B


hi,
I would like to know how to return local variables from a subroutine (for HCS12 assembly). To create local variables, I know I can use the stack pointer and allocate one or two memory bytes by moving the stack up.
My problem is that I dont know how to return an extra variable.
Say, we have this problem:
I want to compare two arrays and count the number of elements that are equal in both arrays.
X register stores the address of Array1
Y register stores the address of Array2

A is used to going through the Array1 and compare.
B is the number of matches.

All registers for the microprocessor are used now!
when I leave the subroutine, I just pull all the registers used.
Is it possible to manage to have another local variable? if yes how to store it when I leave the subroutine since all registers are used?
thank you
B

TOP

I found some lecture notes and a chapter from a book and another. Still one more book has large sections available which, significantly, include a section specifically on subroutines (unfortunately, important parts of that aren't in the book preview). Lastly, there is also at least one message board specific to the 68HC12, where you may get more helpful answers - most of the people here don't really know the processor.
From what is shown in the available parts of that one book, the usual approach is one pretty typical for this sort of accumulator-based CPU: basically, you do it all through the stack. This is complicated by the lack of a frame pointer, but not all that much. The main thing is to use
leas
to offset the stack pointer by a fixed amount to set up local space. Along with the subroutine you would use a number of
equ
ates which act as offsets from where the top of the stack will be as the function runs. These will
all
be set up at the start of the function, forming what is known as an activation record for the subroutine. All of the arguments and local variables will be accessed using these offsets relative to SP. You will furthermore need offsets for the stack space for any registers you save at the start of the function.You will also - and this is very important - need an offset for the 16-bit value just before the first local variable. This value will hold the return address, and you will later reset the stack to it at the end of the function.
When one subroutine calls another, it starts by pushing the values for any function arguments it is passing, as well as a space for whatever return value it will get. Note that when I say 'pushing', it doesn't necessarily use psha, pshb, etc.; if it is expedient to do so, sure, but it can also use leas and memory-to-memory copies if it is easier. But I digress.
Anyway, only after the arguments are pushed, does it bsr or jsr to the function it is calling. This does two things: it pushes the return address (the address immediately following the subroutine call instruction) onto the stack, then jumps/branches to the start of the subroutine.
Now the subroutine itself has to set up it's activation record. It starts by pushing any registers other than IP and SP which it is going to use at any point in the function, so that they don't get trashed. Then it uses leas to subtract the total size of all of the local variables to the stack, moving the top of the stack down by that much and creating the activation record. The subroutine will not use the stack again, except for calling other subroutines, until finishes. When it is finished, it uses leas again to
add
the size of the activation record, then pops the registers in the reverse or from which it pushed them. At that point, if you've done things right, the return value is back at the top of the stack and you can safely rts back to where you were called. The caller then has to copy the return value somewhere safe, then clean up the arguments, before going on.
Here's a simple example of what I mean (not tested code, but it should get the idea across):
Code:
  1. ; main program - note that it has to set up it's own local stack too
  2. main_locals equ 4  ; 2 bytes for the main() locals
  3. main_foo  equ  2    ; offset for first local 16-bit variable
  4. main_bar equ   0    ; offset for second local 16-bit variable
  5. quux_ret_size equ 2      ; 16-bit return value size
  6. main psha
  7.        pshb
  8.        leas -main_locals, sp  ; set up locals for main()
  9.        ldaa 23
  10.        staa main_foo, sp    ; set the value of foo
  11.        ;  do something here...
  12.        ldab main_foo, sp    ; push foo as an argument
  13.        leas -quux_ret_size, sp          ; make space for return value
  14.        bsr quux            ; calling subroutine quux
  15.        pula                  ; get return value off of stack
  16.        leas quux_ret_size, sp         ; clear off arguments
  17.        staa bar            ; save returned value in bar
  18.        ; do something else
  19.        end
  20. ;;  offsets for quux, a function that adds 17 to it argument a
  21. ;; and returns the sum
  22. quux_locals  equ 2
  23. quux_regs equ 2
  24. quux_baz  equ 0
  25. quux_retval equ 6  ; offset for the return value - locals plus regs plus size of the return address
  26. quux_arg  equ 8  ; offset for the argument
  27. quux psha   ; save a
  28.        leas -quux_locals, sp ; set aside space for baz
  29.        ldaa 23
  30.        staa quux_baz, sp     ; initialize the value of quux_baz
  31.        ldaa quux_arg, sp    ; get the argument value
  32.        adda quux_baz, sp  ; add argument with baz
  33.        staa quux_retval, sp ; ... and put it in th return value
  34.        leas  quux_locals, sp  ; clean up locals
  35.        pula                        ; restore registers
  36.        rts        ; return
Copy Code
OK, this isn't a very sensible example, and I'm not sure if it would work, but it ought to give you an idea of how this works. You may want to compare this to the GCC approach, which is different. You may also want to see a previous posting of mine for more information - it covers a different CPU's assembly language, but the ideas are similar. HTH, comments and corrections welcome.

TOP

Thank you Schol-R-LEA,
It makes more sense now.
I will read your previous post on this topic to see what is in there.
B



All registers for the microprocessor are used now!
when I leave the subroutine, I just pull all the registers used.
Is it possible to manage to have another local variable? if yes how to store it when I leave the subroutine since all registers are used?
thank you
B

TOP

Back Forum