📄 tandt.html
字号:
<!doctype html public "-//W3C//DTD HTML 3.2//EN"><html><head><title>Tips and Tricks</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/tandt.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">Tips and Tricks</font></h1> </td> <td align=center width=100> <img src="arm3.gif" width=79 height=78 align = middle> </td></table><p> <p><h4>Count down, rather than up</h4>When you count from zero to <i>n</i>, you will need code like:<pre> MOV R1, #0.loop ...do something... ADD R1, R1, #1 CMP R1, #255 BNE loop</pre>That is braindead code to do something 255 times. You could replace that code with:<pre> MOV R1, #255.loop ...do something... SUBS R1, R1, #1 BNE loop</pre>What, no comparison - but a conditional?<br>Yup, that's right. The <code>SUB</code> operation has the <code>S</code> suffix, so it affectsthe flags. An <code>EQ</code> condition is when the Z bit is set, and a <code>NE</code> conditionis when the Z bit is unset. And the Z bit being set means....<i>zero!</i>.<br>So this loop looks after itself, really. When the countdown ends, the result is zero, the Z bitis set, the NE condition is no longer true, so the branching ceases.<p> <p><h4>Don't abuse the stack</h4>If you are programming APCS code, you will know that the APCS rules state that only registersa0 to a4 (R0-R3) are corruptable. That doesn't mean you should start your code with a<pre> STMFD R13!, {v1-v6, sl, fp, ip, sp, lr}</pre>unless you actually need to store those registers. If you can work your code in the first fourregisters with no branching, you don't need to store anything.<br>I was unable to find a reference to which registers should be saved in BASIC, so my code haserred on the generous side. I would suggest that R0-R7 are corruptable, the remainder should bepreserved. But again, if you only use R0 to R3 (or so), you don't need to preserve anything.<p>Say you use R0, R1 and R2, and you do a few <code>BL</code>s. Should you be pushing the linkregister to the stack?<br><pre> LDMFD R13!, {R14} ...doing stuff... STMFD R13!, {PC}</pre>The code, above, is terribly wasteful. Not only do you use a multiple load/store instruction topreserve one register, but you waste stack space.<br>Even under APCS, this might be better:<pre> MOV R3, R14 ...doing stuff... MOV PC, R3</pre>The <code>S</code> suffix causes the PSR to be restored.<p>An optimisation, when it is required to store R14 (and <i>only</i> R14) to the stack is to dosomething like:<pre> STR R14, [R13, #-4]! ...do stuff... LDR R14, [R13], #4 MOVS PC, R14 <font color="red">(not 32bit compatible)</font></pre>The above version preserves the PSR. If preserving is not required, then reload directly into PCand omit the <code>MOVS</code> instruction.<p> <p><h4>Large numbers</h4>There are two ways to load a register with a large number (say, &FFFF00FF).<p>1. Synthesise it<pre> MOV R0, #&FF000000 ADD R0, R0, #&00FF0000 ADD R0, R0, #&000000FF</pre><p>2. Load it<pre> ADR R1, big_word LDR R0, [R1] ....big_word EQUD &FFFF00FF</pre>I prefer to use the Load method, as it tends to make the code clearer, especially when generatinglarge numbers involves trickery with <code>BIC</code>, <code>EOR</code>, and <code>TEQ</code>.<p>Loading may save program space - it depends upon how you generate your large number - but causesthe processor to jump around to load the word.<br>Execution speed depends upon the processor. For example, it has been reported that a load isfaster on a StrongARM, where an ARM 6 gets more speed out of generating the large value fromthree instructions.<p> <p><h4>Multiple IFs</h4><pre>IF x% = 4 OR x% = 1 THEN ...</pre>can be implemented as something like:<pre> [we assume x% has been loaded into R0] CMP R0, #4 CMPNE R0, #1 BEQ ...the code to call when x% = 4 OR 1 ...the ELSE code</pre><p> <p><h4>Branch tables</h4>You can implement code such as:<pre> CASE something% OF WHEN 0 : PROCzero WHEN 1 : PROCone WHEN 2 : PROCtwo OTHERWISE : PROCinvalid ENDCASE</pre>in assembler by code such as (assuming something% is in R0):<pre> CMP R0, #2 ; The immediate value is the range LDRLS PC, [PC, R0, LSL#8] ; Program Counter set to the first EQUD B invalid ; We come here if R0 > 2 EQUD zero EQUD one EQUD two</pre><p>Or an alternative method:<pre>.entry CMP R0, #((endoftable - table) / 4) ADDCC PC, PC, R0, LSL#2 B invalid.table B zero B one B two.endoftable</pre><p>My personal favourite method is the latter, but both will have the desired effect.<p> <p> <p><hr size = 3><a href="index.html#06">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 + -