|
|
|||||||||
|
|||||||||
| |||||||||
|
|
|
| |||||||||
![]() |
|
|
«
Previous Thread
|
Next Thread
»
|
Thread Tools | Search this Thread | Rate Thread | Display Modes |
|
|
|
Get inside! Sample the range of functionality easily built with JMSL Library for Time Series Data Analysis, Heat Maps, Portfolio Optimization, Monte Carlo Simulation, Stock Price Charting and more. Download Now! |
|
#1
|
|||
|
|||
|
Assembly - Local variable in subroutine
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 |
|
#2
|
||||
|
||||
|
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 equates 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:
; main program - note that it has to set up it's own local stack too
main_locals equ 4 ; 2 bytes for the main() locals
main_foo equ 2 ; offset for first local 16-bit variable
main_bar equ 0 ; offset for second local 16-bit variable
quux_ret_size equ 2 ; 16-bit return value size
main psha
pshb
leas -main_locals, sp ; set up locals for main()
ldaa 23
staa main_foo, sp ; set the value of foo
; do something here...
ldab main_foo, sp ; push foo as an argument
leas -quux_ret_size, sp ; make space for return value
bsr quux ; calling subroutine quux
pula ; get return value off of stack
leas quux_ret_size, sp ; clear off arguments
staa bar ; save returned value in bar
; do something else
end
;; offsets for quux, a function that adds 17 to it argument a
;; and returns the sum
quux_locals equ 2
quux_regs equ 2
quux_baz equ 0
quux_retval equ 6 ; offset for the return value - locals plus regs plus size of the return address
quux_arg equ 8 ; offset for the argument
quux psha ; save a
leas -quux_locals, sp ; set aside space for baz
ldaa 23
staa quux_baz, sp ; initialize the value of quux_baz
ldaa quux_arg, sp ; get the argument value
adda quux_baz, sp ; add argument with baz
staa quux_retval, sp ; ... and put it in th return value
leas quux_locals, sp ; clean up locals
pula ; restore registers
rts ; return
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.
__________________
Rev First Speaker Schol-R-LEA;2 JAM LCF ELF KoR KCO BiWM TGIF #define KINSEY (rand() % 7) λ Scheme is the Red Pill Scheme in Short • Understanding the C/C++ Preprocessor Taming Python • A Highly Opinionated Review of Programming Languages for the Novice, v1.1 FOR SALE: One ShapeSystem 2300 CMD, extensively modified for human use. Includes s/w for anthro, transgender, sex-appeal enhance, & Gillian Anderson and Jason D. Poit clone forms. Some wear. $4500 obo. tverres@et.ins.gov Last edited by Schol-R-LEA : March 6th, 2008 at 04:46 AM. |
|
#3
|
|||
|
|||
|
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 |
![]() |
| Viewing: Dev Shed Forums > Programming Languages - More > Other Programming Languages > Assembly - Local variable in subroutine |
| Thread Tools | Search this Thread |
| Display Modes | Rate This Thread |
|
|
|
|