📄 stack.html
字号:
<!doctype html public "-//W3C//DTD HTML 3.2//EN"><html><head><title>The Stack</title><meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" /><meta http-equiv="content-language" content="en" /><meta name="resource-type" content="document"><meta name="copyright" content="This document copyright 2001 by Richard Murray. Use for non-profit and education purposes explicitly granted."><meta name="author" content="Richard Murray"><meta name="rating" content="general"></head><!-- /assembler/stack.html --><!-- --><!-- (C) Copyright 2001 Richard Murray --><!-- Designed by Richard Murray --><!-- rmurray@heyrick.co.uk --><!-- --><body bgcolor="#f0f0f0" text="#000000" link="#0022dd" vlink="#002288"><table border = "0" width="100%"> <tr> <td align=center width=100> <img src="arm3.gif" width=79 height=78 align = middle> </td> <td> <h1 align="center"><font color="#800080">The Stack</font></h1> </td> <td align=center width=100> <img src="arm3.gif" width=79 height=78 align = middle> </td></table><p> <p>The 6502 microprocessor features support for a stack, located at &1xx in memory, andextending for 256 bytes. It also featured instructions which performed instructions more quicklyrelative to page zero (&0xx).<p>Both of these are inflexible, and not in keeping with the RISC concept.<br>The ARM processor provides instructions for manipulating the stack (<a href="str.html">LDM andSTM</a>). The actual location where your stack lays it's hat is entirely up to you and the rulesof good programming.<p>For example:<pre> MOV R13, #&8000 STMFD R13!, {R0-R12, R14}</pre>would work, but is likely to scribble your registers over something important. So typically youwould set R13 to the end of your workspace, and stack backwards from there.<p>These are conventions used in RISC OS. You can replace R13 with any register except R14 (if youneed it) and R15. As R14 and R15 have a defined purpose, the next register down is R13, so thatis used as the stack pointer.<br>Likewise, in RISC OS, the stacks are fully descending (FD, or IA) which means the stack growsdownwards in memory, and the updated stack pointer points to the next <i>free</i> location.<p>You can, quite easily, shirk convention and stack using whatever register you like (R0-R13 andR14 if you don't need it) and also you can set up any kind of stack you like, growing up, growingdown, pointer to next free or last used... But be aware that when RISC OS provides you withstack information (if you are writing a module, APCS assembler, BASIC assembler, or being atransient utility, for example) it will pass the address in R13 and expect you to be using afully descending stack. So while you can use whatever type of stack/location that suits you, itis suggested you follow the OS style. It makes life easier.<p>If you are not sure what a stack is, exactly, then consider it a temporary dumping area. Whenyou start your program, you will want to put R14 somewhere so you know where to branch to inorder to exit. Likewise, every time you <code>BL</code>, you will want to put R14 someplace ifyou plan to call another <code>BL</code>.<br>To make this clearer:<pre> ; ...entry, R14 points to exit location BL one BL two MOV PC, R14 ; exit.one ; R14 points to instruction after 'BL one' ...do stuff... MOV PC, R14 ; return.two ; R14 points to instruction after 'BL two' ...do stuff... BL three MOV PC, R14 ; return.three ; R14 points to instruction after 'BL three' B four ; no return.four ; Not a BL, so R14 unchanged MOV PC, R14 ; returns from .three because R14 not changed.</pre>Take a moment to work through that code. It is fairly simple. And fairly obvious is thatsomething needs to be done with R14, otherwise you won't be able to exit. Now, a viable answeris to shift R14 into some other register. So now consider that the "...do stuff..."parts use ALL of the remaining registers.<br>Now what? Well, what we need is a controlled way to dump R14 into memory until we come to needit.<br>That's what a stack is.<p>That code again:<pre> ; ...entry, R14 points to exit location, we assume R13 is set up STMFD R13!, {R14} BL one BL two LDMFD R13!, {PC} ; exit.one ; R14 points to instruction after 'BL one' STMFD R13!, {R14} ...do stuff... LDMFD R13!, {PC} ; return.two ; R14 points to instruction after 'BL two' STMFD R13!, {R14} ...do stuff... BL three LDMFD R13!, {PC} ; return.three ; R14 points to instruction after 'BL three' B four ; no return.four ; Not a BL, so R14 unchanged LDMFD R13!, {PC} ; returns from .three because R14 not changed.</pre>A quick note, you can write:<pre> STMFD R13!, {R14} ...do stuff... LDMFD R13!, {R14} MOV PC, R14</pre>but the STM/LDM does NOT keep track of which stored values belong in which registers, so you canstore R14, and reload it directly into PC thus disposing of the need to do a MOV afterwards.<p>The caveat is that the registers are saved in ascending order...<pre> STMFD R13!, {R7, R0, R2, R1, R9, R3, R14}</pre>will save R0, R1, R2, R3, R7, R9, and R14 (in that order). So code like:<pre> STMFD R13!, {R0, R1} LDMFD R13!, {R1, R0}</pre>to swap two registers will not work.<p> <p>Please refer to <a href="str.html">this document</a> for details on STM/LDM and how to use astack.<hr size = 3><a href="index.html#03">Return to assembler index</a><hr size = 3><address>Copyright © 2001 Richard Murray</address></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -