📄 str.html
字号:
<!doctype html public "-//W3C//DTD HTML 3.2//EN"><html><head><title>Register Load and Store</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/str.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">Register<br>Load and Store</font></h1> </td> <td align=center width=100> <img src="arm3.gif" width=79 height=78 align = middle> </td></table><p> <p>These are, arguably, the most useful instructions available. It is all very well being able todo stuff with the registers, but if you cannot load and store them to the main memory, then...<grin><p> <p><a name="str"></a><a name="ldr"></a><h2>Single Data Transfer</h2>The single data transfer instructions (STR and LDR) are used to load and store single bytes orwords of data from/to main memory. The addressing is very flexible.<p>First, we'll look at the instruction:<pre> LDR R0, address STR R0, address LDRB R0, address STRB R0, address</pre>These instructions load and store the value of R0 to the specified address. If 'B' is alsospecified, as in the latter two instructions, then only a single byte is loaded or saved. Thethree unused bytes in the word are zeroed upon loading.<p>The address can be a simple value, or an offset, or a shifted offset. Writeback may beperformed (to remove the need for adding/subtracting).<p><pre> STR R0, [Rbase] Store R0 at Rbase. STR R0, [Rbase, Rindex] Store R0 at Rbase + Rindex. STR R0, [Rbase, #index] Store R0 at Rbase + index. Index is an immediate value. STR R0, [R1, #16] would load R0 from R1+16. STR R0, [Rbase, Rindex]! Store R0 at Rbase + Rindex, & write back new address to Rbase. STR R0, [Rbase, #index]! Store R0 at Rbase + index, & write back new address to Rbase. STR R0, [Rbase], Rindex Store R0 at Rbase, & write back Rbase + Rindex to Rbase. STR R0, [Rbase, Rindex, LSL #2] will store R0 at the address Rbase + (Rindex * 4) STR R0, place Will generate a PC-relative offset to 'place', and store R0 there.</pre>You can, of course, use conditional execution on any of these instructions. Note, however, thatthe conditional flag comes before the byte flag, so if you wish to load a byte when the resultis equal, the instruction would be <code>LDREQB Rx, address</code> (not <code>LDRBEQ...</code>).<p>If you specify pre-indexed addressing (where the base and index are both within square brackets),the write-back is controlled by the presence or absence of the '!'. The fourth and fifthexamples above reflect this. Using this, you can automatically move forward or backward inmemory. A string print routine could then become:<pre> .loop LDRB R0, [R1, #1]! SWI "OS_WriteC" CMP R0, #0 BNE loop</pre>instead of:<pre> .loop LDRB R0, [R1] SWI "OS_WriteC" ADD R1, R1, #1 CMP R0, #0 BNE loop</pre><p>The use of '!' is invalid for post-indexed addressing (where the index is outside of the squarebrackets, as in example six above) as writeback is implied.<p>As you can see, the offset may be shifted. Additionally, the index offset may be subtracted fromthe base. In this case, you might use code such as:<pre> LDRB R0, [R1, #-1]</pre><p>You cannot modify the PSR with a load or store instruction, though you can store or load the PC.In order to load a stored 'state' and correctly restore it, use:<pre> LDR R0, [Rbase] MOVS R15, R0</pre>The MOVS will cause the PSR bits to be updated, provided that you are privileged.<br><font color="red">Using <code>MOVS</code> with PC is not 32-bit compliant.</font><p>According to the ARM assembler manual:<br><i>A byte load (LDRB) expects the data on bits 0 to 7 if the supplied address is on a word boundary, on bits 8 to 15 if it is a word address plus one byte, and so on. The selected byte isplaced in the bottom 8 bits of the destination register, and the remaining bits of the registerare filled with zeroes.<br>A byte store (STRB) repeats the bottom 8 bits of the source register four times across the databus. The external memory system should activate the appropriate byte subsystem to store thedata.<br>A word load (LDR) or word store (STR) should generate a word aligned address. Using anon-word-aligned addresses has non-obvious and unspecified results.</i><p>The only thing of real note here is that you cannot use LDR to load a word from a non-alignedaddress.<p> <p><a name="ldr"></a><a name="stm"></a><h2>Multiple Data Transfer</h2>The multiple data transfer instructions (LDM and STM) are used to load and store multiple wordsof data from/to main memory.<p>The main use of LDM/STM is to dump registers that need to be preserved onto the stack. We'veall seen <code>STMFD R13!, {R0-R12, R14}</code>.<p>The instruction is:<pre> xxM type base writeback, {register list}</pre><p>'xx' is LD to load, or ST to store.<p>'type' is:<pre> Stack Other LDMED LDMIB Pre-incremental load LDMFD LDMIA Post-incremental load LDMEA LDMDB Pre-decremental load LDMFA LDMDA Post-decremental load STMFA STMIB Pre-incremental store STMEA STMIA Post-incremental store STMFD STMDB Pre-decremental store STMED STMDA Post-decremental store</pre>The assembler takes care of how to map the mnemonics. Note that ED is not IB; it is only the samefor a pre-decremental load. When storing, ED is post-decrement.<p>FD, ED, FA, and EA refer to a Full or Empty stack which is either Ascending or Descending.<br>A full stack is where the stack pointer points to the last data item written, and empty stack iswhere the stack pointer points to the first free slot.<br>A descending stack grows downwards in memory (ie, from the end of application space down) andan ascending stack is one which grows upwards in memory.<p>The other forms simply describe the behaviour of the instruction, and mean Increment After,Increment Before, Decrement After, Decrement Before.<p>RISC OS, by tradition, uses a Fully Descending stack. When writing in APCS assembler, it iscommon to set your stack pointer to the end of application space and then use a Full Descendingstack. If you are working with a high level language (either BASIC or C), then you don't get achoice. The stack pointer (traditionally R13) points to the end of a fully descending stack. Youmust continue this format, or create and manage your own stack (if you're the sort of die-hardperson that would do something like this!).<p>'base' is the register containing the address to begin with. Traditionally under RISC OS, thestack pointer is R13, though you can use any available register except R15.<p>If you would like the stack pointer to be updated with the new register contents, simply set thewriteback bit by following the stack pointer register with an '!'.<p>The register list is given in {curly brackets}. It doesn't matter what order you specify theregisters in, they are stored from lowest to highest. As a single bit determines whether or nota register is saved, there is no point to trying to specify it twice.<br>A side effect of this is that code such as:<pre> STMFD R13!, {R0, R1} LDMFD R13!, {R1, R0}</pre>will <i>not</i> swap the contents of two registers.<br>A useful shorthand has been provided. To encompass a range of registers, simply say the first andthe last, and put a dash between them. For example <code>R0-R3</code> is identical to <code>R0,R1, R2, R3</code>, only tidier and saner...<p>When R15 is stored to memory, the PSR bits are also saved. When R15 is reloaded, the PSR bits areNOT restored unless you request it. The method of requesting is to follow the register list witha '^'.<p><pre> STMFD R13!, {R0-R12, R14} ... LDMFD R13!, {R0-R12, PC}</pre>This saves all registers, does some stuff, then reloads all registers. PC is loaded from R14which was probably set by a BL instruction or somesuch. The PSR flags are untouched.<p><pre> STMFD R13!, {R0-R12, R14} ... LDMFD R13!, {R0-R12, PC}^</pre>This saves all registers, does some stuff, then reloads all registers. PC is loaded from R14which was probably set by a BL instruction or somesuch. The PSR flags are updated.<br><font color="red" size = -1><i>Warning: </i>This code is not 32 bit compliant. You need to useMRS and MSR to handle the PSR. You <i>cannot</i> use the '^' suffix.</font><p>Note that in both examples, R14 is loaded directly into PC. This saves the need to MOV(S) R14into R15.<br><font color="red" size = -1><i>Warning: </i>Using <code>MOVS PC, ...</code> is not 32 bitcompliant. You need to use MRS and MSR to handle the PSR.</font><p> <p><hr size = 3><a href="index.html#02">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 + -