home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 5 / DATAFILE_PDCD5.iso / utilities / f / forthmac / !Forthmacs / docs / html / armastut < prev    next >
Encoding:
Text File  |  1997-05-01  |  20.7 KB  |  463 lines

  1. <!-- Forthmacs Formatter generated HTML V.2 output -->
  2. <html>
  3. <head>
  4. <title>Assembler Tutorial</title>
  5. </head>
  6. <body>
  7. <h1>Assembler Tutorial</h1>
  8. <hr>
  9. <p>
  10. This chapter explains how to use the RISC OS Forthmacs ARM assembler in order to 
  11. create short machine language code sequences.  This chapter is a companion to 
  12. the "ARM Assembler" chapter.  That chapter describes the syntax of individual 
  13. assembly language instructions.  This chapter addresses "higher level" issues, 
  14. such as how to begin and end the assembly process and how to communicate 
  15. arguments and result between Forth and assembly language.  
  16. <p>
  17. <p>
  18. <h2>Motivation</h2>
  19. <p>
  20. For nearly all debugging jobs, writing assembly language is unnecessary.  Test 
  21. loops can be usually be written more quickly and easily in high-level Forth, and 
  22. will execute quickly enough to get the job done.  
  23. <p>
  24. However, in some cases the ultimate in speed is needed for certain critical 
  25. operations, and assembly language may be the best way to go.  In other cases, 
  26. very specific combinations of machine instructions may exhibit problem behavior, 
  27. and those combinations may need to be reproduced.  Finally, some maintainers of 
  28. the RISC OS Forthmacs system software itself may need to understand the 
  29. assembler.  
  30. <p>
  31. <p>
  32. <h2>Assumptions</h2>
  33. <p>
  34. The chapter assumes that you already understand the ARM instruction set, 
  35. including such issues as processor modes, interrupts and registers sets.  If 
  36. not, you should first study a ARM reference, such as the manual published by the 
  37. chip manufacturer.  
  38. <p>
  39. Please note the sysntax of this ARM assembler, it uses - as most Forth 
  40. assemblers - the operand first - operator last syntax.  
  41. <p>
  42. <p>
  43. <h2>Example: a simple "code word"</h2>
  44. <p>
  45. Here is a very simple assembly language program.  It adds "1" to the contents of 
  46. a register then returns to the Forth interpreter.  This register r10 holds the 
  47. top of stack value.  
  48. <p>
  49. <p><pre>  code addone  ( n -- n+1 )</pre><p>
  50. <p><pre>  r10 r10  1 # add</pre><p>
  51. <p><pre>  c;</pre><p>
  52. <p>
  53. To execute it and display the result, you would type, for example, 
  54. <p>
  55. <p><pre>  5 addone .</pre><p>
  56. <p>
  57. Here's what is happening, line by line: 
  58. <p>
  59. <p><pre>  code addone  ( n -- n+1 )</pre><p>
  60. <p>
  61. <code><A href="_smal_AC#182">code</A></code> is a "defining word"; it creates a 
  62. new command which can be executed by typing its name.  The name of the new 
  63. command in this case is <strong>addone</strong> .  The name could have been 
  64. anything; I have chosen the name <strong>addone</strong> because it describes 
  65. the action of the program.  You may already be familiar with another Forth 
  66. defining word " <strong>:</strong> or <strong>colon</strong> <code><A href="_smal_AL#6B">".</A></code> 
  67. ":" also creates a new command; the difference between <code><A href="_smal_AC#182">code</A></code> 
  68. and ":" is that ":" creates a new command whose behavior is described by a 
  69. sequence of other Forth commands, whereas <code><A href="_smal_AC#182">code</A></code> 
  70. creates a new command whose behavior is described by a sequence of assembly 
  71. language instructions.  After <code><A href="_smal_AC#182">code</A></code> 
  72. creates the new command, it starts the assembler so that assembly language 
  73. instructions may be entered.  
  74. <p>
  75. The stuff inside the parentheses is a comment; this particular comment indicates 
  76. that the new command expects one argument ("n") on the stack before the word is 
  77. executed, and after the command is executed, one result ("n+1") is left on the 
  78. stack.  The comment is optional, but its inclusion is strongly recommended.  
  79. <p>
  80. <p><pre>  r10 r10  1 # add</pre><p>
  81. <p>
  82. This is the assembly language instruction which defines the action of the new 
  83. command.  As you will recall from the "ARM Assembler" chapter, the 
  84. RISC OS Forthmacs assembler syntax has the destination register first, followed 
  85. by the source operand(s), followed by the operation name.  So, in this case, the 
  86. source operands are the global register r10 and the immediate number 1, the 
  87. destination operand is the global register r10, and the operation is add, i.e.  
  88. 1 is added to the contents of register r10, and the result is placed back in 
  89. register r10.  
  90. <p>
  91. <p><pre>  c;</pre><p>
  92. <p>
  93. <code><A href="_smal_BD#16B">c;</A></code> terminates the definition of a code 
  94. definition.  At the end of the instructions you have assembled, <code><A href="_smal_BD#16B">c;</A></code> 
  95. automatically appends one machine instruction, its effect is to return to Forth 
  96. after the user-specified instructions have been executed.  
  97. <p>
  98. <p><pre>  5 addone .</pre><p>
  99. <p>
  100. In order to invoke the new command, we enter the number 5 on the Forth stack, 
  101. type the name of the command <strong>addone</strong> , and then display the 
  102. result by typing the print command <code>"<A href="_smal_AO#CE">."</A></code> .  
  103. <p>
  104. Perhaps you now wonder how the number got off the Forth stack and into the 
  105. register r10, and afterwards how the number got out of r10 and back onto the 
  106. Forth stack.  The answer is simple: the top element of the Forth stack is always 
  107. (!) kept in r10 , so no movement was necessary.  That is why I chose r10 for the 
  108. register in this example.  
  109. <p>
  110. <p>
  111. <h2>Register Usage in Forth</h2>
  112. <p>
  113. To use the assembler effectively, you need to know which registers are available 
  114. for use, and which of them must be left alone.  Here are the rules: 
  115. <p>
  116. r8, r9, r12, and r14 are used internally by the Forth interpreter or operating 
  117. system, their values must be left alone (otherwise the system will crash).  
  118. <p>
  119. r10 contains the top of the Forth stack.  It is used for passing arguments and 
  120. results back and forth between Forth and assembly language.  
  121. <p>
  122. r13 contains a pointer to a memory area containing the rest of the Forth stack 
  123. (all elements other than the topmost one).  That stack area is used for extra 
  124. arguments and results.  The section entitled "Stack Usage" tells you more about 
  125. managing the stack area.  
  126. <p>
  127. r0 - r6 may be used freely within assembly language code sequences.  Forth does 
  128. not depend on the contents of these registers.  However, some Forth commands <code><A href="_smal_AP#1BF">do</A></code> 
  129. use these registers as scratch registers, so your code should not attempt to 
  130. keep important values in these registers from one time to the next.  While your 
  131. code is being executed, Forth will not change the contents of any of these 
  132. registers, so you can depend on them for the duration of your assembly language 
  133. sequence.  When your code finishes and returns to Forth, the next time that you 
  134. execute your code the register values may have changed.  
  135. <p>
  136. You can find more information about this subject in the "ARM Assembler" and 
  137. "Forthmacs Implementation" chapters.  
  138. <p>
  139. While your machine code is executing, it will run at the full speed of the 
  140. system, without any interference or overhead imposed by RISC OS Forthmacs.  
  141. RISC OS Forthmacs does not itself use interrupts, so the processor will execute 
  142. exactly the sequence of instructions which you have coded.  It is possible that 
  143. other software in the system may have set up some interrupts, but that is beyond 
  144. the control of RISC OS Forthmacs.  
  145. <p>
  146. <p>
  147. <h2>Disassembler</h2>
  148. <p>
  149. The RISC OS Forthmacs disassembler may be used to review the assembly language 
  150. you have created: 
  151. <p>
  152. <p><pre>  see addone</pre><p>
  153. <p>
  154. The result will look something like this: 
  155. <p><pre>  code addone</pre><p>
  156. <p><pre>  (  1e878 )  add     r10,r10,#1</pre><p>
  157. <p><pre>  (  1e87c )  ldr     pc,[r8],#4</pre><p>
  158. <p>
  159. <p>
  160. The numbers along the left hand side are the addresses at which the various 
  161. instructions appear.  The addresses shown here will almost certainly be 
  162. different from the addresses that you see.  
  163. <p>
  164. You will notice that even though our example contained only one assembly 
  165. language instruction the disassembler shows 1 extra instruction.  This extra 
  166. instruction was automatically assembled by the <code><A href="_smal_BD#16B">c;</A></code> 
  167. command.  Their purpose is to return control to Forth after the assembly 
  168. language sequence has finished its execution (this is called the <code><A href="_smal_AG#36">next</A></code> 
  169. instruction).  
  170. <p>
  171. The <code><A href="_smal_BR#2C9">see</A></code> command reads the name of a 
  172. Forth command (in this case "addone"), determines what type of command it is (in 
  173. this case "code <code><A href="_smal_AK#6A">",</A></code> meaning that the 
  174. command's behavior was defined by the assembler), and then displays a 
  175. reconstruction of the source code for that command.  <code><A href="_smal_BR#2C9">see</A></code> 
  176. also works for "colon" definitions, whose behaviour is defined in Forth instead 
  177. of in assembly language.  For an example of this, type "see find".  
  178. <p>
  179. Many of the normal Forth commands are defined in assembly language, and <code><A href="_smal_BR#2C9">see</A></code> 
  180. can be used to look at how they are implemented.  For example, type "see @" to 
  181. see how the Forth "@" operator works (pronounced fetch, this operator takes an 
  182. address from the top of the stack, reads the 32-bit contents of that address, 
  183. and puts those contents back on top of the stack).  You should try this right 
  184. now and make sure you understand how it works.  Note that the last instructions 
  185. of "@" is exactly the same as the last instruction of "addone".  Every code 
  186. definition in RISC OS Forthmacs ends with these same three instructions.  
  187. <p>
  188. <code><A href="_smal_BR#2C9">see</A></code> automatically locates the address 
  189. where the code for particular command begins.  That address was allocated by <code><A href="_smal_AC#182">code</A></code> 
  190. when the new command was defined.  The disassembler can also be used to inspect 
  191. machine code beginning at arbitrary addresses, not only that code which is 
  192. created by <code><A href="_smal_AC#182">code</A></code> .  Suppose that you know 
  193. there is some code starting at address 100000 and you wish to look at it: 
  194. <p>
  195. <p><pre>  100000 dis</pre><p>
  196. <p>
  197. On your system, this example probably won't work exactly as shown because your 
  198. system may not have any code at address 100000 (in fact, it may not even have 
  199. any memory there.  The main point, though, is that you type the address of the 
  200. code you wish to disassemble, followed by "dis".  
  201. <p>
  202. The disassembler will continue until it reaches a "definition ending" 
  203. instruction, or until you stop it by typing the character "q", for "quit".  It 
  204. will also pause at the end of a screen and prompt you for a continuation 
  205. character.  
  206. <p>
  207. After the disassembler has stopped, you can make it continue where it left off 
  208. by typing <code><A href="_smal_AE#C4">+dis</A></code> 
  209. <p>
  210. <p>
  211. <h2>Setting the Starting Address</h2>
  212. <p>
  213. In most cases, you won't need to specify a starting address for the code you 
  214. assemble.  When you use the <code><A href="_smal_AC#182">code</A></code> 
  215. defining word to begin assembling, RISC OS Forthmacs will find some appropriate 
  216. memory for you and assemble your code there ( at <code><A href="_smal_AP#21F">here)</A>.</code> 
  217. You can then locate the memory RISC OS Forthmacs has chosen by using the <code><A href="_smal_BR#2C9">see</A></code> 
  218. command to disassemble the code, looking at the addresses displayed alongside 
  219. the machine instructions.  
  220. <p>
  221. If you really need to assemble at a specific address, you can do so as follows 
  222. (Note: in nearly all cases, this technique is unnecessary; very rarely does it 
  223. matter where exactly you locate a bit of code, and allowing RISC OS Forthmacs to 
  224. allocate the memory for you is sufficient and convenient).  
  225. <p>
  226. Set the <code><A href="_smal_BE#1CC">dp</A></code> by 
  227. <p><pre>  here @</pre><p>
  228. <p><pre>  your-adr dp !</pre><p>
  229. <p><pre>  code demo</pre><p>
  230. <p><pre>         ...... c;</pre><p>
  231. <p><pre>  here !</pre><p>
  232. <p>
  233. <p>
  234. <h2>Conditional branches</h2>
  235. <p>
  236. In order to implement conditional operations and loops, most assemblers provide 
  237. branch instructions and labels.  RISC OS Forthmacs has branches and labels too, 
  238. but it also has a much better way, which eliminates most of the troublesome 
  239. aspects of coding conditionals and loops in assembly language.  The 
  240. RISC OS Forthmacs way is called "structured conditionals".  For example, suppose 
  241. we want to test a condition and execute some code only if the condition is true.  
  242. Specifically, we want to compare r0 and r1, and execute some code only if r0 is 
  243. less than r1 .  
  244. <p>
  245. <p><pre>  Traditional assembler:</pre><p>
  246. <p><pre>  </pre><p>
  247. <p><pre>               cmp   r0, r1</pre><p>
  248. <p><pre>               bge   temp</pre><p>
  249. <p><pre>                  ..some code we want to conditionally execute</pre><p>
  250. <p><pre>       temp:</pre><p>
  251. <p>
  252. <p><pre>       Forthmacs assembler with structured conditionals:</pre><p>
  253. <p><pre>  </pre><p>
  254. <p><pre>               r0 r1  cmp</pre><p>
  255. <p><pre>               < if</pre><p>
  256. <p><pre>                  ..some code we want to conditionally execute..</pre><p>
  257. <p><pre>               then</pre><p>
  258. <p>
  259. As you can see, RISC OS Forthmacs eliminates the need to mentally reverse the 
  260. sense of the comparison, eliminates the need to invent and keep track of label 
  261. names, and uses conventional mathematical comparison symbols (e.g.  "<"), 
  262. rather then alphabetic mnemonics.  The complete set of comparison symbols is 
  263. given in the "ARM Assembler" chapter.  
  264. <p>
  265. The "if ..  then" construct can also include an "else" clause: 
  266. <p>
  267. <p><pre>               r0 r1 s cmp  \ the s is optional</pre><p>
  268. <p><pre>               < if</pre><p>
  269. <p><pre>                  ..code to execute if r0 < r1..</pre><p>
  270. <p><pre>               else</pre><p>
  271. <p><pre>                  ..code to execute if r0 >= r1..</pre><p>
  272. <p><pre>               then</pre><p>
  273. <p>
  274. Of course, the assembler actually generates conditional branch instructions 
  275. because that's what the hardware supports directly, but RISC OS Forthmacs takes 
  276. care of the "bookkeeping" for you.  
  277. <p>
  278. Another way would be to use the conditional instructions offered by the ARM cpu.  
  279. <p>
  280. <p><pre>               r0  r1 cmp</pre><p>
  281. <p><pre>               xx xx  lt xxx</pre><p>
  282. <p><pre>               yy yy  ge xxx</pre><p>
  283. <p>
  284. <p>
  285. <p>
  286. <h2>Delayed Branches</h2>
  287. <p>
  288. ARM doesn't uses delayed branches at all, so don't worry.  
  289. <p>
  290. <p>
  291. <h2>Loops</h2>
  292. <p>
  293. RISC OS Forthmacs structured conditionals also have features for easily creating 
  294. loops.  Here is a loop which executes forever: 
  295. <p>
  296. <p><pre>               Source                  Generates</pre><p>
  297. <p><pre>  </pre><p>
  298. <p><pre>               begin                   Label1:</pre><p>
  299. <p><pre>                  top  r0 ) ldr              ldr  r10,[r10,#0]</pre><p>
  300. <p><pre>               again                         b Label1</pre><p>
  301. <p>
  302. This code assumes that the r10 register (top of stack, remember?) contains the 
  303. address of a memory location, and the contents of that memory location is 
  304. continuously read into the r0 register.  This is an infinite loop; it won't stop 
  305. until the system is reset, or power cycled, or externally interrupted in some 
  306. way.  
  307. <p>
  308. Suppose we want the loop to execute 9 times then quit: 
  309. <p>
  310. <p><pre>
  311.   r1  9 #    mov
  312.   begin
  313.      r0   top ) ldr
  314.      r1   r1 1 # s sub
  315.   <= until
  316. </pre><p>
  317. <p>
  318. <p>
  319. We continue to loop "until" r1 <code><A href="_smal_BH#10F"><=</A></code> 1 .  
  320. <p>
  321. Finally, here's an example where we perform a test at the top of the loop rather 
  322. than at the bottom, illustrating "while": 
  323. <p>
  324. <p><pre>
  325.   r1  9 #     mov
  326.   begin
  327.       r1 r1 1 s sub
  328.   > while
  329.       r0  top ) ldr
  330.   repeat
  331. </pre><p>
  332. <p>
  333. <p>
  334. This loop continues to execute "while" r11 > 1, and the "repeat" sends it 
  335. back to the "begin".  
  336. <p>
  337. Structured conditionals and loops nest in the expected manner, to an arbitrary 
  338. depth.  For instance, a "begin ..  until" can be completely contained within an 
  339. "if ..  then", which itself may be contained within a "begin ..  while ..  
  340. repeat".  
  341. <p>
  342. <p>
  343. <h2>Scope Loops - Assembler vs. Forth</h2>
  344. <p>
  345. You can use assembly language for creating scope loops, but it is usually 
  346. preferable to write them in Forth, because the Forth version is usually easier 
  347. to write, easier to read, and easier to debug.  The one advantage of an assembly 
  348. language loop is that it is tighter.  However this rarely matters.  For 
  349. comparison, suppose that you want to continually read location 1000 so that you 
  350. can observe the action on an oscilloscope.  This is how you would do it in 
  351. assembly language: 
  352. <p>
  353. <p><pre>       code test</pre><p>
  354. <p><pre>       r0 th 1000 # mov</pre><p>
  355. <p><pre>          begin</pre><p>
  356. <p><pre>            r1  r0 ) ldr</pre><p>
  357. <p><pre>          again</pre><p>
  358. <p>
  359. Here's how you would do the same thing in Forth: 
  360. <p>
  361. <p><pre>  begin  1000 @ drop  again</pre><p>
  362. <p>
  363. Additionally, the Forth version may be easily adapted to stop looping as soon as 
  364. a key is typed: 
  365. <p>
  366. <p><pre>  begin  1000 @ drop  key? until</pre><p>
  367. <p>
  368. More importantly, many of today's complicated chips require fairly extensive 
  369. initialization sequences in order to configure them to the correct operating 
  370. mode.  Such code is much easier to write and debug in Forth, because you can 
  371. "try things out" by typing commands at the keyboard, the looking at the 
  372. registers to see what happened.  
  373. <p>
  374. A set of simple Forth commands sufficient to do most hardware debugging jobs can 
  375. easily be described on a single page, and many engineers and technicians have 
  376. learned enough Forth in 30 minutes to be able to write sophisticated diagnostics 
  377. for complicated hardware.  
  378. <p>
  379. <p>
  380. <h2>Stack Usage</h2>
  381. <p>
  382. A previous example has shown how to access the top element on the stack which is 
  383. stored in r10.  Things get a little more complicated if more than 1 stack 
  384. argument is needed.  Remember that the top of the stack is stored in r10, and 
  385. subsequent stack items are stored in a memory area whose address is contained in 
  386. r13.  For convenience, the assembler provides alternate names for r10 and r13, 
  387. reflecting the use of these registers for the stack.  r10 is also known as <code><A href="_smal_BE#1C">top</A></code> 
  388. (Top of Stack), and r13 is also known as <code><A href="_smal_BJ#51">sp</A></code> 
  389. (Stack Pointer).  
  390. <p>
  391. The basic rules for the Forth stack are: 
  392. <p>
  393. a) Upon entry to a <code><A href="_smal_AC#182">code</A></code> definition 
  394. (assembly language), the top of the stack is contained in <code><A href="_smal_BE#1C">top</A>.</code> 
  395. The next item on the stack is in the memory location whose address is contained 
  396. in <code><A href="_smal_BJ#51">sp</A>.</code> The item after that is in memory 
  397. at <strong>sp+4</strong> , the next at <strong>sp+8</strong> , etc.  Note that 
  398. successive stack items are 4 bytes (32-bits) apart.  
  399. <p>
  400. b) A definition may modify the stack contents, and upon exit from the definition 
  401. the new top of the stack should be in <code><A href="_smal_BE#1C">top</A>,</code> 
  402. and the next item should be in memory at that address contained in <code><A href="_smal_BJ#51">sp</A>.</code> 
  403. <p>
  404. c) Assembly code should not access memory at negative offsets from <code><A href="_smal_BJ#51">sp</A>.</code> 
  405. This restriction safeguards against problems in an interrupt-driven environment, 
  406. in case the same stack happens to be used for interrupt handlers.  
  407. <p>
  408. If items are removed from the stack by a code definition, care must be taken to 
  409. make sure the correct top of stack value is left in <code><A href="_smal_BE#1C">top</A>.</code> 
  410. Also remember that the RISC OS Forthmacs assembler provides macros to assist in 
  411. managing the stack.  Here are some examples; study them carefully: 
  412. <p>
  413. <p><pre>
  414. code and        (s n1 n2 -- n3 )
  415.                 r0      sp      pop
  416.                 top     top     r0 and c;
  417. code min        (s n1 n2 -- n1|n2 )
  418.                 r0      sp      pop
  419.                 top     r0      cmp
  420.                 top     r0      gt mov c;
  421. code drop       (s n1 n2 -- n1 )
  422.                 top     sp      pop c;
  423. code dup        (s n1 -- n1 n1 )
  424.                 top     sp      push c;
  425. code 1+         (s n -- n+1 )    top 1     incr c;
  426. code @          (s a_adr -- n )
  427.                 top     top )   ldr c;
  428. \ a somewhat optimized fill
  429. code fill       (s adr cnt char -- )
  430.                 r2      top     top  8 #lsl orr
  431.                 r0 r1 top 3 sp ia!  ldm \ r0-cnt r1-adr r2-data
  432.                 r0      4 #     cmp
  433.   gt if
  434.         begin   r3      r1      3 # s and
  435.                 r0      1       ne decr
  436.                 r2      r1 byte )+ ne str
  437.         eq until
  438.                 r0      8       s decr
  439.                 r2      r2      r2  10 #lsl orr
  440.                 r3      r2      mov
  441.         begin   r2 r3 2 r1 ia!  ge stm
  442.                 r0      8       ge s decr
  443.         lt until
  444.                 r0      4       s incr
  445.                 r2      r1 )+   ge str
  446.                 r0      4       lt decr
  447.   then
  448.         begin   r0      1       s decr
  449.                 r2      r1 byte )+ ge str
  450.         lt until c;
  451. code >name      \ (s cfa -- nfa )
  452.                 top     1       decr    \ skip flag byte
  453.         begin   r0      top byte -( ldr
  454.                 r0      0 #     cmp
  455.         ne until
  456.         begin   r0      top byte -( ldr
  457.                 r0      20 #    cmp
  458.         lt until c;
  459. </pre><p>
  460. <p>
  461. </body>
  462. </html>
  463.