home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 5 / DATAFILE_PDCD5.iso / utilities / f / forthmac / !Forthmacs / docs / ascii / arm_hardw next >
Encoding:
Text File  |  1997-05-01  |  14.1 KB  |  325 lines

  1.  
  2. Hardware Diagnostics in Forth
  3. *****************************
  4.  
  5.  
  6. fine tools ...
  7. ==============
  8.  
  9. Forth has been long used for large numbers of hardware projects, both 
  10. commercial and private.  RISC OS Forthmacs is exceptionally stable and needs 
  11. only very few resources on the computer.  
  12.  
  13. Here's how you can write Forth programs to diagnose your hardware.  The 
  14. programs can range from very simple things like reading a register to very 
  15. complicated things like performing communications protocols.  Each higher 
  16. level of tests can build on the lower levels.  At any time, you can 
  17. interactively execute any part of the test, without having to build a command 
  18. interpreter into your program.  
  19.  
  20. This document describes how to do very simple things interactively.  It is 
  21. also possible to save your work in a file and to make sequences of tests run 
  22. automatically.  
  23.  
  24.  
  25. Warning
  26. =======
  27.  
  28. The examples in the rest of this document assume that you are running on a 
  29. stand-alone system, and that there really are I/O devices located at the 
  30. addresses mentioned.  If you are running RISC OS Forthmacs under RISC OS or 
  31. Unix, both won't allow you to access device registers, so the examples in this 
  32. paper will cause a core dump of the Forth process.  
  33.  
  34. In fact, most of these examples assume that you are trying to debug a board 
  35. whose registers begin at virtual address (hex) 3340000.  In RISC OS computers 
  36. this would be a Simple Exp.  card with fast access, this might not be right 
  37. for your system, so please pick an address for your system where you know 
  38. there is some device or memory.  
  39.  
  40.  
  41. Getting started
  42. ===============
  43.  
  44. The way to get Forth running on your machine is system-dependent, so we won't 
  45. go into that topic here.  We assume that you have already figured out how to 
  46. get Forth going, and that it is prompting you with 'ok' .  
  47.  
  48.  
  49. Poking at registers
  50. ===================
  51.  
  52. The first hurdle to cross when debugging a new board is usually reading and 
  53. writing the device registers.  With most programming environments or monitors, 
  54. if the register doesn't work, you are stuck.  Not so with Forth.  Suppose that 
  55. you have a 32-bit register at address (hex) 3340000.  You can read it with: 
  56.       3340000  @  .
  57. @ says to read a 32-bit word from the preceding address.  . says to print the 
  58. result.  @ is pronounced "fetch".  In general, the @ symbol is pronounced 
  59. 'fetch' in Forth terminology.  There must be one or more spaces separating 
  60. symbols! 
  61.  
  62. Note: The Forth parser is really simple; it just grabs the next sequence of 
  63. non-blank characters (called a 'word' in the jargon) from the terminal and 
  64. looks up that word in its internal dictionary.  If it finds the word, it 
  65. executes some associated code.  If it doesn't find the word, it tries to parse 
  66. the word as a number.  If that fails, it complains.  
  67.  
  68. Note: @ accesses a 32-bit location, the address must be long-aligned.  If your 
  69. device is 8 bits wide, use c@ in this and future examples; also use c! instead 
  70. of ! .  
  71.  
  72. There is a problem with 16-bit registers in ARM based computers, ARM cpus 
  73. don't support word-wide 16-bit data access.  You can use W@ and W! but both 
  74. instructions use two byte-wide memory accesses, so this might not be what you 
  75. wanted.  Or you use 32-bit normal accesses and mask-off the other 
  76.  
  77. The most likely result of trying this exercise on a prototype peripheral board 
  78. is that the board won't respond to the cycle, so the CPU will get a bus error, 
  79. print a message, and abort back to Forth.  
  80.  
  81. On a working device, instead of getting an error, Forth will display the 
  82. contents of the register you accessed.  
  83.  
  84.  
  85. Scope Loops
  86. ===========
  87.  
  88. No, you don't have to get out your assembly language reference manual and try 
  89. to figure out how to poke in a tiny loop.  Here's how to make a loop: 
  90.  
  91. 3340000 constant reg-addr
  92. : test   begin  reg-addr @    drop  key? until  ;
  93.  
  94. This creates a loop which will repeatedly read a register at location 3340000.  
  95. begin ...  key? until means to keep doing everything between the begin and the 
  96. key? until a key is typed on the keyboard.  The drop is needed to get rid of 
  97. the value that was read from the register, which is left on a stack.  That 
  98. stack would eventually overflow if not for the drop. The loop is called TEST , 
  99. and it is a new command which you have just created, you could have called it 
  100. anything you wanted, instead of TEST .  
  101.  
  102. Remember that there will be an address exception if the physical address 
  103. hasn't been accepted by the MMU.  Now you can try the loop.  
  104.     test
  105.  
  106. In general, the way to execute a Forth command is by typing its name.  
  107.  
  108. So now the machine is sitting there banging away at your register.  You can 
  109. try to find a scope that still has some probes attached and figure out why 
  110. your register isn't responding.  
  111.  
  112. It wasn't actually necessary to have given the loop a name.  You could have 
  113. just typed: 
  114.     begin  reg-addr @ drop  again
  115.  
  116. This is different from almost all Forth dialects, RISC OS Forthmacs knows 
  117. about temporary compilation and forgets about the compiled code afterwards.  
  118.  
  119. However, by giving the command a name, you save it away so you can use it 
  120. later, just by typing the name.  It's not saved on disk, just in memory, so if 
  121. you reboot, the new command will be lost.  It would be nice if you could save 
  122. your work on disk, but in a lot of stand-alone debugging cases there is no 
  123. disk on the machine.  To learn how you can save your work, read the "Creating 
  124. Stand-Alone Forths" chapter 
  125.  
  126.  
  127. Writing to registers
  128. ====================
  129.  
  130. Now that you can read your register, no doubt you want to write to it too.  
  131.     1234 reg-addr !
  132. writes the 32-bit word 1234 (hex) to the address left by the word REG-ADDR 
  133. (which we defined earlier).  If you want to write a byte instead of a 32-bit 
  134. word, use c!. 
  135.     reg-addr @ .
  136. reads back the register and prints the value, so you can verify that the write 
  137. actually worked.  
  138.  
  139.  
  140. Do Loops
  141. ========
  142.  
  143. An obvious thing to do now is to write a bunch of different values to the 
  144. register and see if they all work.  
  145.  
  146. : test-loop
  147.    ffff 0  do
  148.       i  reg-addr !     ( write a value to the register )
  149.       reg-addr @        ( read it back )  ( register value on stack )
  150.       i <>   ( see if the value read back is different from the one written )
  151.       if    ." Error - wrote "    i .    ." read "   reg-addr @ .  cr
  152.       then
  153.    loop ;
  154.  
  155. The indentation is optional.  If you were writing this test on-the-fly while 
  156. sitting in the lab, you would probably not bother with indentation.  
  157. Similarly, everything inside parentheses is a comment and may be omitted.  
  158. When you are writing Forth programs to save (presumably using a Unix editor), 
  159. please don't omit the comments or the indentation, because that would make 
  160. your work hard to understand later.  
  161.  
  162. How does this test-loop work? Let's go over it line-by-line.  'ffff 0' are the 
  163. arguments to the do ...  loop construct.  The loop starts at 0 and ends when 
  164. the loop index reaches (hex) ffff.  The last time through the loop, the index 
  165. has the value (hex) fffe.  The firs thing inside the loop is 'i reg-addr !' .  
  166. Previously we used the literal number '1234' as the value to store into 
  167. location reg-addr.  This time we use the loop index I .  The loop index is 
  168. 'always' called I .  If you use nested loops, the index of the next outer loop 
  169. is called J .  
  170.  
  171. The next thing we do inside the loop is read back the register.  Previously we 
  172. printed the value as soon as we read it; this time we will let the program 
  173. look at and decide if it's okay.  But where is the value kept? It's on the 
  174. stack, just like on an HP calculator.  In fact almost every operator in Forth 
  175. takes its operands from the stack and leaves its results on the same stack.  I 
  176. will assume that this concept is familiar to you; if it isn't, let me know and 
  177. I will either explain it to you or loan you a book which does so.  Anyway, the 
  178. register value is now sitting on the stack.  The next thing we do is compare 
  179. that value to the loop index I .  The operator <> (not-equal) compares the top 
  180. two things on the stack and leaves true if they are not equal or false if they 
  181. are equal.  
  182.  
  183. If the numbers are equal, all is well.  If they are different, we need to 
  184. print an error message.  That is where the if ...  then construct comes in.  
  185. Here is the strange part: The stuff you want to do if the condition is true 
  186. goes between if and then, not after then as one would expect.  This is 
  187. unfortunate, but it is not the end of the world.  The condition that is tested 
  188. comes BEFORE the if; in this case the condition is the true/false value left 
  189. on the stack by the <> operator.  If this seems strange to you, consider that 
  190. it is very simple, yet completely general.  It is also possible to specify an 
  191. else clause (details later).  
  192.  
  193. The only thing remaining for this test-loop is to describe how the error 
  194. message is printed.  The construct '." ... "' , pronounced "dot-quote, prints 
  195. whatever is inside the quotes.  The first space after the first quote is 
  196. mandatory and is not printed.  Any subsequent spaces before the next quote are 
  197. part of the string and are printed.  Next we print the loop index with I . .  
  198. As you have probably guessed, . just means print whatever number is on the 
  199. stack.  Next we print another string, followed by the value read back from the 
  200. register.  Finally, cr prints a carriage-return and linefeed.  
  201.  
  202.  
  203. Extensibility
  204. =============
  205.  
  206. Earlier we saw how to make a word called 'test' which could then be executed 
  207. by typing its name.  Once you have made a word, you can then use it as part of 
  208. another word, thus building on top of your previous work.  For example, 
  209. suppose that there is a dma address register on your board, and that its 
  210. address is (hex) 3340804.  You can define a word to store a value into that 
  211. register as follows: 
  212.     : dma!  3340804 !  ;
  213. This defines a new word called DMA! which takes an argument and stores it into 
  214. the prescribed location.  This word can be used as: 
  215.     f00000 dma!
  216. which will store f00000 into the dma register.  Now, suppose that as part of a 
  217. test, you need to automatically set the dma register.  You can use your word 
  218. dma! as part of another word.  
  219.     : init-dma  f00000 dma!  ;
  220. This is a trivial example, but it serves to illustrate the style of building 
  221. up your application in small incremental steps.  Don't hesitate to build words 
  222. which only have a few components; the overhead of calling a word from one at 
  223. higher level is quite small, and the advantages of small words are many 
  224. (readability, ease of debugging, possibility of reuse).  
  225.  
  226.  
  227. Variables
  228. =========
  229.  
  230. Define a variable with 
  231.     variable foo
  232. The new variable FOO has space for a 32-bit word.  Put a number in the 
  233. variable with: 
  234.     129876 foo !
  235. and get it back with 
  236.     foo @
  237. The number to be stored is taken from the stack, and the number fetched is 
  238. left on the stack.  When you typed the 129876, that number was actually left 
  239. on the stack, and FOO ! picked it up and put in the variable foo.  FOO @ 
  240. retrieved it from the variable and returned it to the stack.  
  241.  
  242.  
  243. Constants
  244. =========
  245.  
  246. A constant is a symbolic name for a number.  In other words, when you type the 
  247. name of a constant, it just leaves its number on the stack.  One way of making 
  248. a constant is the obvious: 
  249.     : mem-base  100000  ;
  250. Now the word mem-base is equivalent to the number 100000.  A slightly more 
  251. efficient form of this is: 
  252.     100000 constant mem-base
  253. A word defined with constant will execute somewhat faster than one defined the 
  254. other way (but you would probably never notice the difference).  
  255.  
  256.  
  257. C Language Analogies
  258. ====================
  259.  
  260.         C                               Forth
  261. while( condition ) {                    BEGIN  condition  WHILE
  262.         loop-body                               loop-body
  263. }                                       REPEAT
  264. do {                                    BEGIN
  265.         loop-body                               loop-body
  266. until ( condition )                     condition  UNTIL
  267. for( i=start_value;                     end_value
  268.       i<end_value;                      start_value
  269.       i += increment ) {                DO
  270.         loop-body                               loop-body
  271. }                                       increment +LOOP
  272. for( i=start value;                     end value
  273.       i<end value;                      start value
  274.       i++ ) {                           DO
  275.         loop-body                               loop-body
  276. }                                       LOOP
  277. if ( condition ) {                      condition
  278.         true_clause                     IF      true_clause
  279. } else {                                ELSE    false_clause
  280.         false_clause                    THEN
  281. }
  282. if ( condition ) {                      condition
  283.         true_clause                     IF      true_clause
  284. }                                       THEN
  285.  
  286. Forth Notes: 
  287.  
  288. "condition" is any sequence of Forth words that has the effect of leaving a 
  289. number on the stack.  If the number the stack is 0, the condition value is 
  290. false, otherwise it is true.  
  291.  
  292. Within a do loop, the word I will put the loop index on the stack.  
  293.  
  294.  
  295. One More Thing ...
  296. ==================
  297.  
  298. You may want to do a scope loop which can be easily interrupted.  You can 
  299. always abort back to RISC OS Forthmacs with Shift-Ctrl-F12.  A nicer way, 
  300. however, is the following: 
  301.     : scope-loop   begin  1234 reg-addr !  key? until  ;
  302. This word will continuously write 1234 to location 'reg-addr' until you type 
  303. any key.  The word key? returns true (which happens to be equal to -1) if a 
  304. key has been depressed, and false (0) if not.  
  305.  
  306.  
  307. Other Wonderful Features
  308. ========================
  309.  
  310. Forth includes, among other things, a resident assembler, so you can write 
  311. little bits of assembly code if you need to.  It has a built-in visual line 
  312. editor, so you can edit command lines as you type them.  There are packages 
  313. for defining structures and bit fields, similar to C.  A built-in decompiler 
  314. allows you to interactively decompile any Forth word that you have previously 
  315. defined.  Try typing see followed by the name of any Forth command, or any 
  316. Forth word you have already defined.  
  317.  
  318.  
  319. Line Editing
  320. ============
  321.  
  322. While you are typing a Forth command line, you can move around in the line and 
  323. edit it.  Have a look at the chapter TYPING FORTH COMMAND LINES .  
  324.  
  325.