|
From: pito <pi...@vo...> - 2010-09-07 06:42:54
|
Hi Matthias and co., I'd like to ask how to start working with assembler in amforth. This might be of general interest, therefore HOW TO. The example could be the timer int routine: : tick_isr _one timer 2@ d+ timer 2! ; which does "timer = timer + 1" where timer is double integer. I've seen usart routines and Lubos' routines in asm, however generaly the Q: 1. is there any recommended structure or frame for writing assembler words 1a. is there any recomemnded structure or frame for writing assembler interrupt handlers 2. how the data from data stack (or from return stack) are passed to assembler 3. how the data are passed from asm. back to data stack or return stack 4. how the external variables (defined as words) are accessed from assembler 5. how the data stack is duped or droped from assembler 6. what shall be poped and pushed in asm. routine (when entering and leaving it) 7. how the asm return stack is handled (imagine we need nested calls in asm) 8. how the ram, eprom can be accessed from asm 9. how the asm code shall be compiled (? via LP's asm or via avrasm.) Thanks, Pito |
|
From: pito <pi...@vo...> - 2010-09-07 06:51:28
|
10. how the local .asm variables (used in asm rouitne shall be handled (e.g. where in ram to place the local variables). ----- PŮVODNÍ ZPRÁVA ----- Od: "pito" <pi...@vo...> Komu: amf...@li... Předmět: HOW TO - Assembler in anmforth Datum: 7.9.2010 - 8:42:46 > Hi Matthias and co., > I'd like to ask how to start working with > assembler in amforth. This > might be of general interest, therefore HOW TO. > The example could be the timer int routine: > : tick_isr _one timer 2@ d+ timer 2! ; > which does "timer = timer + 1" where timer is > double integer. I've > seen usart routines and Lubos' routines in asm, > however generaly the > Q: > > 1. is there any recommended structure or frame for > writing assembler > words > 1a. is there any recomemnded structure or frame > for writing > assembler interrupt handlers > 2. how the data from data stack (or from return > stack) are passed to > assembler > 3. how the data are passed from asm. back to data > stack or return > stack > 4. how the external variables (defined as words) > are accessed from > assembler > 5. how the data stack is duped or droped from > assembler > 6. what shall be poped and pushed in asm. routine > (when entering and > leaving it) > 7. how the asm return stack is handled (imagine we > need nested calls > in asm) > 8. how the ram, eprom can be accessed from asm > 9. how the asm code shall be compiled (? via LP's > asm or via > avrasm.) > > Thanks, Pito > |
|
From: Matthias T. <mt...@we...> - 2010-09-09 18:33:41
|
him > 10. how the local .asm variables (used in asm rouitne shall be > handled (e.g. where in ram to place the local variables). If you use Lubos assembler, you can allocate RAM and use the address. The assembler is, after all, forth code which compiles machine code. When using the avrasm, there are examples in the source tree: e.g. base.asm or any other variable. IMHO not trivial, but no real secrets. Matthias |
|
From: Matthias T. <mt...@we...> - 2010-09-09 18:29:59
|
Pito, > The example could be the timer int routine: > : tick_isr _one timer 2@ d+ timer 2! ; > which does "timer = timer + 1" where timer is double integer. I've > seen usart routines and Lubos' routines in asm, however generaly the > Q: > > 1. is there any recommended structure or frame for writing assembler > words Just look at Lubos' examples. He has written quite a lot (e.g. for sd card access via SPI or optimized bit level access) > 1a. is there any recomemnded structure or frame for writing > assembler interrupt handlers A definition starts with "code", which creates the dictionary entry. Everything else need to compile real machine code, the last instruction has to be end-code, which compiles the jump instruction back to forth. Everything in between is yours, completly. > 2. how the data from data stack (or from return stack) are passed to > assembler > 3. how the data are passed from asm. back to data stack or return > stack > 4. how the external variables (defined as words) are accessed from > assembler > 5. how the data stack is duped or droped from assembler The assembler has full control once the code is started. And the full responsibility to keep everything intact. If you modify vital registers, you may crash the system easily. > 6. what shall be poped and pushed in asm. routine (when entering and > leaving it) > 7. how the asm return stack is handled (imagine we need nested calls > in asm) > 8. how the ram, eprom can be accessed from asm RAM is easy: there are machine instruction like ld and st (with variants). I'd recommend studying the atmel assembler document (doc0856.pdf) from there website. There are >>100 different instructions available. Everything else is increasingly complex, you can read (and duplicate) the code from the words/*.asm files, there are some code words. > 9. how the asm code shall be compiled (? via LP's asm or via > avrasm.) I use the avrasm. Lubos' assembler has been checked to work correctly so I think its a matter of taste: flashing a completly new hex image or using the terminal prompt. YMMV Matthias |
|
From: Marcin C. <sa...@sa...> - 2010-09-10 00:18:12
|
Two quick remarks: >> 2. how the data from data stack (or from return stack) are passed to >> assembler - data stack (all elements EXCEPT top of the stack) are kept close to the end of RAM (end of RAM - 128), growing down. - TOP of the stack is kept in register pair (tosh:tosl) >> 3. how the data are passed from asm. back to data stack or return >> stack - if you just change top of the stack (say remove 1 parameter and put 1 cell of results) just change contents of tosh:tosl registers - "loadtos" macro fetches the second item on stack and loads it into the tosh:tosl, while moving stack pointer down - - so it effectively the same as DROP. Of course, if one needs to preserve top of stack another "ld" command can be used to load 2nd, 3rd, etc. elements into other registers. - "storetos" macro stores the TOS on to the stack, therefore it is how DUP is implemented. If you want just to push something on stack just "storetos" and modify tosh:tosl. - return stack is the machine stack. it starts at the end of RAM and grows downward (toward smaller addresses), the same direction as the data stack. It means you have 128 bytes (64 16-bit words) for the return stack available by default. - second item on a data stack is pointed by the YH:YL register pair - push, pop operate on the return stack then (see >r, r>, r@) - inner interpreter stores current Forth instruction pointer in the register pair XH:XL and pushes it/pops off the return stack as necessary. It's all in amforth.asm - first 87 lines --Marcin |
|
From: pito <pi...@vo...> - 2010-09-10 21:12:51
|
Matthias, Marcin, thanks a lot for the infos - I've spent a time to work in order to write my first amforth routine ++_ - based on Lubos sources so I've got the first touch.. Basically my problem is not the assembler of any processor, but what are the limitation for a specific integration in the forth. Imagine following case (an example only): 1. I want to write a new word full in asm called fuX (a b c -- y ) 2 I want to use an existing "code" written in assembler, it is relocable. 3. I will take a "template" from a word, I can see the header etc. 4. the input and output is now clear to me, loadtos, savetos indirect via Y. Q: which registers (Rx) can I freely use without ANY limitation in my fuX? I can see the register used in .lst of course, however I need a proven list which really can be used. Q: there are registers named tempx - again - which can be used? There is a difference when using those tempx in Lubos' assmbler vs. usage in normal asm - Lubos' asm is based on forth words, which may use internally some registers, this was what I saw - some registers combinations did garbage. Q: which registers can we use in Lubos' asm, which in normal asm (again - we can see the .lst allocation, but pls confirm. Q: Lubos is using Z registers frequently - is it allowed (both in L asm or normal asm)? We need some indirect addressing so is Z fully free to use? Q: When using L.asm (Lubos') or normal asm - which regs shall be pushed, popped? Q: When RAM space is required in the asm code - can you give us some RAM ragion where we may do what we really want? Q: It is understood we cannot use calls inside fuX, only jumps. L.asm needs a kind of table for jumps, normal asm does not I guess. Q: shall the interrupts be disabled when in fuX? Q: accessing vars - can we define a specific place in RAM where we can place the local asm variables and which will not be interfered by forth? 6. the fuX will read the data from data stack, it will process it (about 500 lines of assembler) and at the end it writes results to data stack. Q: Can we create such long word? Any restriction on the lenght of a word? 8. forth's Return stack - my understanding is we cannot use it for any assembler routine, can we? how? 9. so now I have an asm word fuX - with header (copied from other words and adjusted accordingly), body (~500lines asm) and it will end with "rjmp DO_NEXT". I will include this fuX.asm into dictionary and compile together with amforth. This is the basic Idea. I DO UNDERSTAND THIS WAY OF WORKING WITH AMFORTH IS NOT THE PREFFERED ONE FROM PRINCIPLE (PORTABILITY), but I still cope with an idea to be able to "link" _ANY_ asm code into an amforth word (input output via dstack). Interrupts: 1. it is understood you handle intrpts forth's way - the generic-isr.asm is an interface to forth only, which sets Tflag and translates vector to forth. What is the worst case latency? 2. how to work with several interrupts enabled (priority handling in forth?), e.g. as we register ['] tick_isr TIMER2_OVFAddr int!, what happens when I register for example 15 interrupts sources that way? Pito. |
|
From: Matthias T. <mt...@we...> - 2010-09-11 07:47:06
|
Pito, I'll start here, the upper "half" will take more time. But make yourself clear, what do you want to achieve: add an assembly word to the initial hex file or implement it on a running system. The assemblers only look similiar, they are not inter-changeable. > Interrupts: The interrupt support in amforth is weak. It lakes some features one may urgently need. > 1. it is understood you handle intrpts forth's way - the > generic-isr.asm is an interface to forth only, which sets Tflag and > translates vector to forth. What is the worst case latency? 1ms (if the interrupt occures at the beginning of the word 1ms.) I believe, that division is faster, but did not test it yet. Generally speaking: interrupts are handled by the inner interpreter. Any primitive word is atomar wrt to (forth-level) interrupts. > 2. how to work with several interrupts enabled (priority handling in > forth?), e.g. as we register ['] tick_isr TIMER2_OVFAddr int!, what > happens when I register for example 15 interrupts sources that way? The last registered code gets called. A problem arises, if interrupt x has fired and interrupt y comes before the x has been handled. In that case x will be completly unhandled (the curint variable is overwritten). Matthias |
|
From: Marcin C. <sa...@sa...> - 2010-09-10 22:03:57
|
On Fri, 10 Sep 2010, pito wrote:
First, I am assuming that "Luboš assembler" is a set of words
from the lib/assembler.frt file in the amforth distribution.
Is this correct?
> 1. I want to write a new word full in asm called fuX (a b c -- y )
> 2 I want to use an existing "code" written in assembler, it is
> relocable.
> 3. I will take a "template" from a word, I can see the header etc.
(I don't understand this - what is your "header" etc.)
> 4. the input and output is now clear to me, loadtos, savetos
> indirect via Y.
If you want to return only one cell ("y") you need just to set the
TOS in tosh:tosl register pair. No need to use savetos.
> Q: which registers (Rx) can I freely use without ANY limitation in
> my fuX? I can see the register used in .lst of course, however I
> need a proven list which really can be used.
> Q: there are registers named tempx - again - which can be used?
> There is a difference when using those tempx in Lubos' assmbler vs.
> usage in normal asm - Lubos' asm is based on forth words, which may
> use internally some registers, this was what I saw - some registers
> combinations did garbage.
Yes, tempx are left for free use of FORTH words. That's what
Matthias wrote before already.
First, from what I understand - Matthias please correct me if I am
wrong - the "code" word creates a new word for you but
it does not switch FORTH into the compilation mode (unlike ":"
or "]").
So that means that all words (like "ld,", "st,") are executed
immediately and they can produce compiled machine
code entered into the dictionary only in the explicit way
by using "," (comma) word.
Practically means that all FORTH code in the assembler is executed
immediately (think of it as they all were IMMEDIATE words) and
the only thing you are left in your newly defined word is pure
assembler code as defined by you. Luboš code is gone by the time
you are executing a word. So it does not matter whether you
use some registers when using code ... end-code or whether
using direct assembly (like adding .asm file to your amforth).
If you have some problems with "garbage" - please be more specific,
it is possible that the error is somewhere else.
> Q: which registers can we use in Lubos' asm, which in normal asm
> (again - we can see the .lst allocation, but pls confirm.
> Q: Lubos is using Z registers frequently - is it allowed (both in L
> asm or normal asm)? We need some indirect addressing so is Z fully
> free to use?
I don't know - where does assembler use Z? See above - it probably
does not matter at all.
> Q: When using L.asm (Lubos') or normal asm - which regs shall be
> pushed, popped?
If you are only using tosh, tosl, tempX registers - none.
Please be aware that push and pop goes to the machine stack
which is FORTH return stack (therefore they are an equivalent
of >r and r>).
> Q: When RAM space is required in the asm code - can you give us some
> RAM ragion where we may do what we really want?
Please feel free to "allot" something and use that.
There is also "pad" available as well.
> Q: It is understood we cannot use calls inside fuX, only jumps.
> L.asm needs a kind of table for jumps, normal asm does not I guess.
I don't understand this problem. I think you can define labels
using the assembler.frt. (I didn't use them though).
I am not sure whether the code is correct in assembler.frt -
it uses "here" to indicated labels in the code, where
it should probably use "dp" (dictionary pointer) - due to
RAM (last position pointed to by "here", advanced by "allot") and dictionary
in flash (managed by "dp", advanced by comma) are different thing
in amforth.
> Q: shall the interrupts be disabled when in fuX?
I don't think so.
> Q: accessing vars - can we define a specific place in RAM where we
> can place the local asm variables and which will not be interfered
> by forth?
Use "here" and "allot".
> 6. the fuX will read the data from data stack, it will process it
> (about 500 lines of assembler) and at the end it writes results to
> data stack. Q: Can we create such long word? Any restriction on the
> lenght of a word?
No limits on length except size of your flash.
> 8. forth's Return stack - my understanding is we cannot use it for
> any assembler routine, can we? how?
Of course you can use it. It's what "push" and "pop" do. See question
above regarding push/pop.
> 9. so now I have an asm word fuX - with header (copied from other
> words and adjusted accordingly), body (~500lines asm) and it will
> end with "rjmp DO_NEXT". I will include this fuX.asm into dictionary
> and compile together with amforth. This is the basic Idea.
You do not need "rjmp DO_NEXT" (or most probably "jmp DO_NEXT")
if using "end-code" word ($940c and DO_NEXT address will be
compiled - see "end-code.asm").
> I DO UNDERSTAND THIS WAY OF WORKING WITH AMFORTH IS NOT THE
> PREFFERED ONE FROM PRINCIPLE (PORTABILITY), but I still cope with an
> idea to be able to "link" _ANY_ asm code into an amforth word (input
> output via dstack).
I don't know what kind of portability you mean. Forth code is
way more portable between different platforms than assembly code
(with obvious limitations related to the low-level words).
So writing words is assembler is not really the Forth way.
The other thing you might mean is interoperability (not portability)
as in "I want to write some code in C or assembly and attach
it to my forth words". Sure you can. I was thinking
about uploading .hex files or even ready-to-run
object or ELF files that could be executed by the
FORTH word. FORTH does not really limit you in this
unless you need a bootloader-specific code.
> Interrupts:
No answers from me on that this time :-)
--Marcin |
|
From: pito <pi...@vo...> - 2010-09-11 07:50:09
|
Marcin, thanks!
> First, I am assuming that "Luboš assembler" is a
> set of words
> from the lib/assembler.frt file in the amforth
> distribution.
> Is this correct?
Yes
> (I don't understand this - what is your "header"
> etc.)
E.g.:
; ( n1 -- n2 ) Arithmetics
; R( -- )
; optimized increment
VE_1PLUS:
.dw $ff02
.db "1+"
.dw VE_HEAD
.set VE_HEAD = VE_1PLUS
XT_1PLUS:
.dw PFA_1PLUS
PFA_1PLUS:
> If you want to return only one cell ("y") you need
> just to set the
> TOS in tosh:tosl register pair. No need to use
> savetos.
tosh:tosl contains the value - you need to execute st -Y, rx to
write it to ram, don'you?
> First, from what I understand - Matthias please
> correct me if I am
> wrong - the "code" word creates a new word for you
> but
> it does not switch FORTH into the compilation mode
> (unlike ":"
> or "]").
>
M?
> I don't know - where does assembler use Z?
Lubos is using Z in his assembler source e.g.
code high ( pinmask portadr -- )
\ dup c@ rot or swap c! \ replaced by assembler
ZL TOSL movw, \ tos->z
R16 Z ld, \ addr c@
loadtos, \ delete portadr
R16 TOSL or, \ or pinmask
Z R16 st, \ c!
loadtos, \ delete pinmask
end-code
> Please feel free to "allot" something and use
> that.
> There is also "pad" available as well.
>From my assembler source, how? Or it shall be done before?
> I am not sure whether the code is correct in
> assembler.frt -
> it uses "here" to indicated labels in the code,
> where
> it should probably use "dp" (dictionary pointer) -
> due to
> RAM (last position pointed to by "here", advanced
> by "allot") and dictionary
> in flash (managed by "dp", advanced by comma) are
> different thing
> in amforth.
M?
> Use "here" and "allot".
>From asm sorce?
> Of course you can use it. It's what "push" and
> "pop" do.
So when calling within an asm source properly I will not destroy
Rstack, it means it will stay as before I executed my asm?
> You do not need "rjmp DO_NEXT" (or most probably
> "jmp DO_NEXT")
> if using "end-code" word ($940c and DO_NEXT
> address will be
> compiled - see "end-code.asm").
I meant normal asm (L.asm=lubos's forth asm asm-normal asm)
> I don't know what kind of portability you mean.
When writing _any_ "words" (e.g. fuX) in asm. Portability means use
ANS forth words only..
> I was
> thinking
> about uploading .hex files or even ready-to-run
> object
Yes this is exactly what I am talking about..
Pito
|
|
From: Matthias T. <mt...@we...> - 2010-09-11 11:52:32
|
Hi, > > > First, from what I understand - Matthias please > > correct me if I am > > wrong - the "code" word creates a new word for you > > but > > it does not switch FORTH into the compilation mode > > (unlike ":" > > or "]"). > > > M? "code" creates the full dictionary header and sets the XT of that newly defined word to its data field. That means, that whenever the XT of that word is called by the inner interpreter, the content of the data field is executed as machine code. Whatever that code may do, the final operation should be a jmp to DO_EXIT. Since the label DO_EXIT is only known at compile time of the initial hex file, the forth word "end-code" does exactly that: writes the machine instruction "jmp DO_EXIT". It is up to the developer to make sure that the forth vm can continue its work. Otherwise anything strange can happen... > > > I don't know - where does assembler use Z? > Lubos is using Z in his assembler source e.g. > code high ( pinmask portadr -- ) > \ dup c@ rot or swap c! \ replaced by assembler > ZL TOSL movw, \ tos->z > R16 Z ld, \ addr c@ R16/17 was used as tosl/tosh in earlier versions, now its slightly different. Probably no-one has noticed that yet. > > I am not sure whether the code is correct in > > assembler.frt - > > it uses "here" to indicated labels in the code, > > where > > it should probably use "dp" (dictionary pointer) - > > due to > > RAM (last position pointed to by "here", advanced > > by "allot") and dictionary > > in flash (managed by "dp", advanced by comma) are > > different thing > > in amforth. > M? see above, sounds like a regression. > > I was > > thinking > > about uploading .hex files or even ready-to-run > > object > Yes this is exactly what I am talking about.. Good luck. You do know that even C has some assumptions about its runtime environment? And portable assembler code is something I've never seen yet. AS a general hint: there are so many existing code samples that work well enough. Please read them first. Most of your questions can be answered by "read the source and do it that way". Matthias |
|
From: pito <pi...@vo...> - 2010-09-11 11:01:41
|
Matthias, Marcin - here is the template for function fuX. Is the construction ok? It will be assembled by normal asm. Pito. ; amforth 4.1 ; ..core\words\fuX.asm ; ( a b c -- m l k ) Function fuX ; R( ? -- ? ) ; calculates a special function fuX ; it uses ALL registers except Y ; it calls subroutines placed within the word fuX ; does not use Y - points the data stack VE_FUX: .dw $ff03 ;? .db "fuX",0 .dw VE_HEAD .set VE_HEAD = VE_FUX XT_FUX: .dw PFA_FUX PFA_FUX: push R0 ; worst case - store everything push R1 push R2 ..... push R31 ld R10, Y+ ld R11, Y+ ; takes c from stack ld R12, Y+ ld R13, Y+ ; takes b from stack ld R14, Y+ ld R15, Y+ ; takes a from stack do_something work_with_RAM_indirect_Using_Z work_with_RAM_indirect_Using_X call sub3 do_something jmp label1 do_something label1: do_something jmp label2 ; ijmp rjmp as well do_something call sub3 do_something jmp label3 label2: do_something call sub1 ; rcall icall as well call sub2 do_something label3: do_something call sub2 st -Y, R16 st -Y, R17 ; puts m on stack st -Y, R18 st -Y, R19 ; puts l on stack st -Y, R20 st -Y, R21 ; puts k on stack pop R31 ; worst case housekeeping .... pop R2 pop R1 pop R0 jmp label_end ; jmp to the end of the word "fuX" sub1: do_something call sub3 ret sub2: do_something call sub1 ret sub3: do_something work_with_RAM_indirect_Using_Z work_with_RAM_indirect_Using_X ret label_end: jmp_ DO_NEXT ; this is the end of the word "fuX" |
|
From: Marcin C. <sa...@sa...> - 2010-09-11 12:01:27
|
On Sat, 11 Sep 2010, pito wrote: > push R0 ; worst case - store everything > push R1 > push R2 > ..... > push R31 Please be careful NOT to restore r28, r29 (register Y - your data stack pointer) and r24, r25 - top of your stack. > > ld R10, Y+ > ld R11, Y+ ; takes c from stack > > ld R12, Y+ > ld R13, Y+ ; takes b from stack > > ld R14, Y+ > ld R15, Y+ ; takes a from stack This is wrong - TOS is in r26:r25 (tosh:tosl) *NOT* in RAM! > st -Y, R16 > st -Y, R17 ; puts m on stack > > st -Y, R18 > st -Y, R19 ; puts l on stack > > st -Y, R20 > st -Y, R21 ; puts k on stack Same as above - just leave TOS in r26:r25 and don't restore it via pop: > pop R31 ; worst case housekeeping > .... > pop R2 > pop R1 > pop R0 Don't restore tosl, tosh, Y (r24, r25, r28, r29) - since then your stack effects will be void (or just corrupted). No need to save temp0..temp5 (r14, r15, r16, r17, r18, r19, r20, r21). r30 and r31 (zl, zh) are used as a scratchapad register, so no need to save these too. r2 and r3 should be zero, so no need to save that on stack (use it or restore it to zero at exit). (Matthias: I noticed that techdoc says R22:R23 are TOS and R24:R25 are W, in my case on ATmega328P it's the other way around) Please keep in mind that machine stack is not indefinite (64 bytes only). So if your routine is pushing something on stack and doing some calls it can get tight. Regarding you other email, regarding "here", "dp" etc. DP and HERE are stored in EEPROM (in my case EEPROM address $6 and $8, respectively), please see PFA_EFETCH how to read EEPROM from assembly or push them on the data stack before running your asm routing as parameters. --Marcin |
|
From: pito <pi...@vo...> - 2010-09-11 15:17:44
|
> Please keep in mind that machine stack is not > indefinite (64 bytes only). So if your routine > is pushing something on stack and doing some > calls it can get tight. I've changed that to 256: .set rstackstart = RAMEND ; start address of return stack, grows downward .set stackstart = RAMEND - 256 ; 80 start address of data stack, grows downward > Regarding you other email, regarding "here", "dp" > etc. DP and HERE are stored in EEPROM (in my case > EEPROM So when RAM is needed within fuX word and only there, I have to read HERE and DP and from that point to allocate RAM fro fuX. When leaving fuX, I do not need to write the new pointers to EEPROM, I just leave that as they are (as I do not need RAM anymore.. So the template for fictious word 'fuX' is now (based on my amforth .lst as the Registers are concerned): ; amforth 4.1 ; ..core\words\fuX.asm ; Function fuX( a b c -- m l k ) ; R( ? -- ? ) ; calculates a special function fuX ; it uses ALL registers except Y ; it calls subroutines placed within the word fuX ; does not use Y - points the data stack VE_FUX: .dw $ff03 ;? .db "fuX",0 .dw VE_HEAD .set VE_HEAD = VE_FUX XT_FUX: .dw PFA_FUX PFA_FUX: push R0 push R1 ; R2 you may use, restore to 0 ; R3 you may use, restore to 0 push R4 push R5 push R6 push R7 push R8 push R9 push R10 push R11 push R12 push R13 ; R14 you may use, no need to push/pop, = temp4 ; R15 you may use, no need to push/pop, = temp5 ; R16 you may use, no need to push/pop, = temp0 ; R17 you may use, no need to push/pop, = temp1 ; R18 you may use, no need to push/pop, = temp2 ; R19 you may use, no need to push/pop, = temp3 ; R20 you may use, no need to push/pop, = temp6 ; R21 you may use, no need to push/pop, = temp7 push R22 push R23 ; R24 do not push/pop, = tosl ; R25 do not push/pop, = tosh push R26 push R27 ; R28 do not use, = Y ; R29 do not use, = Y ; R30 you may use, no need to push/pop, = Z ; R31 you may use, no need to push/pop, = Z do_something ld R24, Y+ ld R25, Y+ ; takes c from stack do_something ld R24, Y+ ld R25, Y+ ; takes b from stack do_something ld R24, Y+ ld R25, Y+ ; takes a from stack do_something work_with_RAM_indirect_Using_Z work_with_RAM_indirect_Using_X call sub3 do_something jmp label1 do_something label1: do_something jmp label2 ; ijmp rjmp as well do_something call sub3 do_something jmp label3 label2: do_something call sub1 ; rcall icall as well call sub2 do_something label3: do_something call sub2 do_something st -Y, R25 st -Y, R24 ; puts m on stack do_something st -Y, R25 st -Y, R24 ; puts l on stack do_something st -Y, R24 st -Y, R25 ; puts k on stack pop R27 ; RESTORE REGISTERS IN REVERSE ORDER .... pop R4 ldi R3, 0 ldi R2, 0 pop R1 pop R0 jmp label_end ; jmp to the end of the word "fuX" sub1: do_something call sub3 ret sub2: do_something call sub1 ret sub3: do_something work_with_RAM_indirect_Using_Z work_with_RAM_indirect_Using_X ret label_end: jmp_ DO_NEXT ; this is the end of the word "fuX" |
|
From: Matthias T. <mt...@we...> - 2010-09-11 18:23:11
|
Marcin, > on stack (use it or restore it to zero at exit). > > (Matthias: I noticed that techdoc says R22:R23 > are TOS and R24:R25 are W, in my case on ATmega328P > it's the other way around) Fixed, thank you. Matthias |