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

  1.  
  2. Forthmacs Implementation
  3. ************************
  4.  
  5. This chapter describes how RISC OS Forthmacs implements the Forth virtual 
  6. machine on the ARM processors.  It assumes that you have a fairly good 
  7. knowledge of conventional Forth implementations; it does not attempt to be a 
  8. tutorial on how Forth works.  
  9.  
  10.  
  11. Dialect
  12. =======
  13.  
  14. RISC OS Forthmacs has been an implementation of the Forth-83 standard, with a 
  15. few exceptions.  It is now far on it's way to be an ANS compliant 
  16. implementation.  It is still rather compatible with the other implementations 
  17. for Sun-68k, Sparc, Atari, Macintosh and OS-9 computers.  
  18.  
  19.  
  20. Stack Width and Addressing
  21. ==========================
  22.  
  23. In RISC OS Forthmacs, all stack items as well as memory cells are 32-bit wide, 
  24. remember this when writing portable programs.  Use the portable ANS operators 
  25. like cell+ cells or the RISC OS Forthmacs specific words like /cell cells+. 
  26.  
  27. The address could conceivably grow to 2 to the 32nd power (4 gigabytes), but 
  28. this is restricted by the current CPU/MMU versions to 16/256 MBytes.  16-bit 
  29. or 2-byte memory accesses are not supported any longer and must be emulated if 
  30. necessary.  
  31.  
  32. Note: word accesses are simulated by two byte accesses, take care about 
  33. interrupts occurring here! 
  34.  
  35. The current ARM MMUs don't support non-aligned memory accesses.  NOTE: They 
  36. don't abort or run any exception vector but just do something UNDEFINED and 
  37. CPU core dependent.  Take care of this, it took me hours to find a bug! 
  38.  
  39. All accesses must be one of: 
  40.  
  41. 1) byte-wide access to any address in the address area 
  42.  
  43. 2) cell-wide ( 32-bit ) access to any aligned address 
  44.  
  45. The word wide access possible at least on StrongARM and ARM8 cpus is NOT 
  46. supported by the RiscPC platforms.  Special source extensions are available 
  47. for single-board platforms.  
  48.  
  49.  
  50. Both stacks are pre-decrementing/post-incrementing.  The parameter stack holds 
  51. its top-of-stack in the top-register top - r10, this allows much faster code 
  52. definitions because of the CPUs load-and-store architecture.  
  53.  
  54.  
  55. Register Usage
  56. ==============
  57.  
  58.  
  59.     r9      user area pointer       up
  60.     r10     top-of-stack register   top
  61.     r11     returnstack pointer     rp
  62.     r12     instruction pointer     ip
  63.     r13     stack pointer           sp
  64.     r14     link register           lk
  65.     r15     pc + status + flags     pc
  66.     r15     sr                      sr  hold the flags part of r15
  67.  
  68. Note: The internal structure of the pc and flags registers differs between 
  69. cpus.  It seems to be better, to generally imagine pc and status register as 
  70. two registers.  The hardware-errors and the .registers instruction know about 
  71. this.  
  72.  
  73. r0, r1, r2, r3, r4, r5, and r6 are available for use within code definitions.  
  74. Don't try to use them for permanent storage, because they are used by many 
  75. code words with no attempt to preserve the previous contents.  
  76.  
  77. Registers r7-r14 can be used within code definitions with great care, but you 
  78. have to save and restore their values at the beginning/end of the definition.  
  79.  
  80.  
  81. Inner <address> Interpreter
  82. ===========================
  83.  
  84. The inner interpreter next is direct threaded, post incrementing.  The 
  85. compilation address of all definitions contain machine code to be executed, 
  86. not a pointer.  Each code definition ends with the next code, assembled 
  87. in-line.  The next code is: 
  88.          pc      ip )+   ldr
  89. This means: Load the program-counter pc ( don't affect the CPU status ) from 
  90. the 4-byte cell pointed to by the instruction pointer ip, postincrement the 
  91. instruction-pointer.  So the next is only one CPU instruction and very fast.  
  92. It is much faster than 
  93.          address  dolink branch
  94.          ...
  95.          pc link mov
  96. constructions because of only one pipeline reload per next. But on the other 
  97. hand, there is definitely a larger overhead for calling secondaries.  
  98.  
  99. RISC OS Forthmacs versions >= 3.1/2.70 can switch to another next scheme.  The 
  100. first 8 cells in the user area are free debugging purposes.  SLOW-NEXT  ( you 
  101. find this in lib.arm.debugm ) patches all next as well as conditional next 
  102. calls to 
  103.     pc up mov
  104. Normall there is a normal next instruction at up@ but may install any service 
  105. routine there to do additional checking at run time.  The new debugger uses 
  106. this to branch into the debugger handler.  After 'debugging' you switch back 
  107. to the normal next with FAST-NEXT 
  108.  
  109. If you want to use this scheme, there is one thing to remember.  As SLOW-NEXT 
  110. patches all instructions 
  111.     pc ip )+ condition ldr
  112. your handler might be patches as well.  In these cases you should use 
  113.     pc 1  ip ia!  ldm
  114. instead.  This does the same - at least from RISC OS Forthmacs point of view - 
  115. but isn't patched.  See lib.arm.debugm again for an example in the debugger.  
  116.  
  117. For discussions about subroutine threaded ( macro extended ) versus threaded 
  118. code implementations see the Forth literature.  Generally, macros do bring 
  119. some advantage in execution speed but give less information about the code 
  120. itself, so debuggers are less useful.  The penalty for direct threaded code is 
  121. hard to predict, it depends very much on the type of application.  Something 
  122. like 50% sounds reasonable, so optimising the bottlenecks could bring big 
  123. advantages.  The 'runtimer ' utilities might help you doing this.  
  124.  
  125. The assembler macro c; assembles the next instruction and ends assembling by 
  126. end-code. A fast conditional next can be done by 
  127.          ...
  128.          r2 0 cmp
  129.          eq next
  130.          ...
  131.  
  132.  
  133. Other Definitions
  134. =================
  135.  
  136. Any word that is not a code definition contains a branch+link instruction at 
  137. the code-field, this makes a relative branch to an inline-address and saves 
  138. the pc+sr to the lk register.  
  139.          runtime-addr    dolink branch
  140. The inline address points to a code fragment (headerless in most cases) that 
  141. implements the run-time action of the word.  The parameter field starts just 
  142. after this branch+link instruction and can be found by clearing the flags in 
  143. the link register like this: 
  144.          r0 lk    th fc000003 #   bic
  145.          r0  get-link
  146.  
  147. The run-time codes may have to push the top-register to the stack, save the 
  148. return pointer to the return-stack and set the instruction or stack pointer to 
  149. the parameter field address.  All standard runtime codes (those of variables, 
  150. constants, colon definitions, user variables ...) have been optimized for best 
  151. cache-hit rates.  
  152.  
  153. Note: word-type ( cfa -- addr ) finds the address of the words runtime code in 
  154. this implementation.  
  155.  
  156.  
  157. Colon definitions
  158. =================
  159.  
  160. The runtime code: 
  161.     mlabel docolon  assembler
  162.          ip      rp      push
  163.          ip      get-link c;
  164. The body of a Colon Definition starts 4 bytes after the compilation address.  
  165. The body contains a list of compilation addresses of other words.  Each such 
  166. compilation address is a 32-bit number which is an absolute address.  
  167.  
  168.  
  169. Variable
  170. ========
  171.  
  172. The Parameter Field of a variable contains a 32-bit number which is the value 
  173. of the variable.  The runtime code: 
  174.     mlabel dovariable  assembler
  175.          top     sp      push
  176.          top     get-link c;
  177.  
  178.  
  179. Constants
  180. =========
  181.  
  182. The Parameter Field of a constant contains the 32-bit value of the constant.  
  183. The runtime code: 
  184.     mlabel doconstant  assembler
  185.          top     sp      push
  186.          r0      get-link
  187.          top     r0 )    ldr c;
  188.  
  189.  
  190. User Variables
  191. ==============
  192.  
  193. The value of a user variable is stored in the user area as a 32-bit number.  
  194. The Parameter Field of a user variable contains a 32-bit offset into the user 
  195. area of the current task.  r8 contains the base address of the current user 
  196. area.  r8 is symbolically defined as up in the assembler.  The runtime code: 
  197.     mlabel douser  assembler
  198.          top     sp      push
  199.          r0      get-link
  200.          r0      r0 )    ldr
  201.          top     r0      up add c;
  202.  
  203.  
  204. Deferred words
  205. ==============
  206.  
  207. The compilation address of the word to be executed by a defer word is stored 
  208. as a 32-bit absolute address in the user area.  The Parameter Field of a 
  209. deferred word contains a 32-bit number which is an offset into the user area 
  210. of the current task.  The runtime code: 
  211.     mlabel dodefer  assembler
  212.          r0      get-link
  213.          r0      r0 )    ldr
  214.          pc      r0      up  ib ldr end-code
  215. The last line holds a somewhat optimized next instruction, it means: Load the 
  216. pc from the address in the user area with the offset r0.  
  217.  
  218.  
  219. ;code
  220. =====
  221.  
  222. The compilation address of a word created by a create ...  ;code data type 
  223. construction contains the standard branch+link instruction that branches to 
  224. the runtime code.  
  225.  
  226. The runtime code is defined by the programmer in the ;code part of the 
  227. definition.  
  228.  
  229. In versions up to 3.1/2.62 ;code assembled two instructions for your 
  230. convenience 
  231.          top     sp      push
  232.          top     get-link
  233. this is not the case any more.  I changed this to be more portable with the 
  234. FirmWorks implementation and i feel that all Forth programmers using ;code 
  235. should be able to handle this.  
  236.  
  237.  
  238. does>
  239. =====
  240.  
  241.  
  242.     mlabel dodoes  assembler
  243.          ip      rp      push
  244.          ip      get-link c;
  245. The runtime code is defined by the programmer in the does> part of the 
  246. definition.  Before branching to the dodoes code, the does> instruction 
  247. assembles 
  248.          top     sp      push
  249.          top     lk      th fc000003 # bic
  250. to get the parameter field address.  
  251.  
  252.  
  253. local variables
  254. ===============
  255.  
  256. RISC OS Forthmacs has built in ANS Forth conforming local variables spending 
  257. their lifetime on the return-stack in stack-frames.  The stack-frames are 
  258. linked via a user variable LOCAL-FRAME which is also used to locate a local 
  259. variables value.  The frame structure is like: 
  260.     | cfa:frame>   | old-frame     | old-rs        | loc   | loc   | .........
  261. with cfa:pop-frame on top of the return-stack.  pop-frame removes the current 
  262. frame and switches to the last frame.  
  263.     headerless code pop-frame \ this routine is pushed on return stack by push-locals
  264.          here /cell+ token,
  265.         r0 rp 2    rp ia    ldm
  266.         r0    'user local-frame str
  267.         ip    rp    pop c;
  268.     
  269. The local variables are accessed using (loc) followed by an stack frame index.  
  270.     code (loc)    \ ( -- n )  runtime-code of any local
  271.         r0    'user local-frame ldr
  272.         r1    ip )+    ldr
  273.         top    sp    push
  274.         top    r0 r1 2 #asl db ldr c;
  275.  
  276. Note: The decompiler can not know the local variables names, so it assumes 
  277. names like ( v0 v1 ...).  
  278.  
  279.  
  280. Tokens
  281. ======
  282.  
  283. Within the body of a colon definition, calls to other Forth words are compiled 
  284. as the 32-bit absolute compilation address of those words.  These tokens have 
  285. a corresponding bit in the relocation table.  
  286.  
  287.  
  288. Branching
  289. =========
  290.  
  291. Branch targets are offsets relative to the location that contains the branch 
  292. offset.  They are stored as 32-bit twos-complement numbers representing the 
  293. number of bytes between the offset location and the branch target.  For 
  294. example, a branch to the following location could be compiled with: 
  295.  
  296.          postpone branch   4 ,
  297.  
  298. NOTE: This is implemented different in version 3.1/2.00.  The relative offset 
  299. is replaced by an immediate absolute relocated address.  
  300.  
  301.  
  302. Doubles
  303. =======
  304.  
  305. RISC OS Forthmacs versions newer than 1.83 have full double number support, 
  306. all conversion tools convert, number?, d. use doubles, the 'scaling' words */ 
  307. */mod um/mod use double intermediate results.  
  308.  
  309. Also the text-interpreter and compiler accept literals as doubles when there 
  310. is a period at the end of it.  
  311.          : test 1234. d. ;
  312. 1234.  is a double number and d. displays it.  
  313.  
  314. This could only be achieved with changing stack effects in a number of words.  
  315. So these new RISC OS Forthmacs versions are no longer compatible when these 
  316. words are used.  The lib.compatible tool does not cover these changes.  
  317.  
  318. The advantage of the new stack behaviour is it's ANS compliancy and the 
  319. improved arithmetic capabilities.  
  320.  
  321.  
  322. Floats
  323. ======
  324.  
  325. RISC OS Forthmacs versions newer than 3.1/2.13 have the ANS Floating and 
  326. Floating Extended wordsets included.  There isn't any further documentation 
  327. available so far, please use the ANS docs for this purpose.  
  328.  
  329.  
  330. StrongARM compatibility
  331. =======================
  332.  
  333. Versions from 3.1/2.30 run on StronARM based machines but optimized code is 
  334. available from 3.1/2.40 onwards.  
  335.  
  336.  
  337. Cache
  338. =====
  339.  
  340. The newer ARM based cpus ( ARM8, StrongARM ) have a different cache structure 
  341. than the elder versions.  Separate instruction- and data caches are used and 
  342. code synchronizing has to be done after change of the code space.  
  343.  
  344. flush-cache and sync-cache are both implemented in current RISC OS Forthmacs 
  345. versions >3.1/2.40 in such a way, that the compiler is not significantly 
  346. slowed down, in fact a StrongARM compilation is much faster than on the older 
  347. ARM710.  
  348.  
  349.  
  350. Header format - # of bytes in parentheses
  351. =========================================
  352.  
  353. Source Field (4), Link Field (4), Name Field (n), Padding (0 to 3), Flags (1), 
  354. Code Field (4), Parameter Field (n).  
  355.  
  356. As all addresses need to be, the Link Field, Name Field, and Code Field are 
  357. all aligned.  
  358.  
  359. Links point to links ( not to Name Fields, as in FIG Forth! ) 
  360.  
  361. The name field is a normal Forth packed string.  (Many Forth implementations 
  362. set the high bit in the first and last characters of the name field; 
  363. RISC OS Forthmacs does not).  
  364.  
  365. Name Field: length-byte, 0-31 character name.  
  366.  
  367.  
  368.  
  369. Vocabularies
  370. ============
  371.  
  372. Vocabularies have #threads - way hashing.  This means that each vocabulary has 
  373. 16 separate linked lists of words.  The threads are stored in the user area.  
  374. The Parameter Field of a vocabulary contains the 32-bit offset of the threads 
  375. in the user area, followed by the vocabulary-link, a 32-bit pointer to the 
  376. previous vocabulary. The runtime high-level code is: 
  377.          does> body> context token!
  378.  
  379. Before searching a vocabulary, a hashing function is applied to the name to be 
  380. located.  The hashing function selects one of the 16 linked lists to search.  
  381.  
  382. The hashing function is very simple.  The lower 4 bits of the first character 
  383. in the name (the first name character, not the length byte) are interpreted as 
  384. a number from 0 to 15, selecting a linked list.  
  385.  
  386. Vocabularies are not chained to one another.  Search order is implemented 
  387. using the also / only scheme.  Each vocabulary thread is terminated with a 
  388. special link field in the final word.  The special link address is the address 
  389. of the origin of the Forth system (which may change from session to session 
  390. due to the relocation that the operating system applies when loading and 
  391. executing the Forth system.  
  392.  
  393. The parameter field for a vocabulary looks like: 
  394.  
  395. User number (/cell), Voc-link (/cell) 
  396.  
  397. The user number selects the place in the user area where the head of list 
  398. pointers for the 16 vocabulary threads are stored.  Each vocabulary requires 
  399. 16 cells bytes of user area storage for these 16 threads.  The values stored 
  400. in the user area are the Link field Addresses for the top word in each thread.  
  401.  
  402.  
  403. Relocation
  404. ==========
  405.  
  406. In the RISC OS environment all programs of the absolute type are loaded at 
  407. $8000 and executed from there.  So on first sight the relocation table doesn't 
  408. make much sense in this version if you don't care about being portable to 
  409. other RISC OS Forthmacs implementations.  
  410.  
  411. But the relocation table can be used for target/meta-compiling or for 
  412. relocating code during run-time.  This is necessary for producing turnkey 
  413. applications with an 'Application Stripper', use of the application stripper 
  414. requires strict adherence to the rules of relocatability.  
  415.  
  416. If the program is not relocatable, then a file saved with save-forth will work 
  417. only if it is later executed at the same address where it was executing when 
  418. it was saved.  If saved with save-forth, a program that is not relocatable 
  419. will not work at all, regardless of the address where it is later executed.  
  420. Consequently, use of the application stripper requires strict adherence to the 
  421. rules of relocatability.  
  422.  
  423. In most cases, the relocation bitmap is maintained automatically, without 
  424. requiring any special effort on the part of the programmer.  However, there 
  425. are some cases where the programmer must take explicit actions to ensure that 
  426. the program is relocatable.  
  427.  
  428. The executable file contains a relocation list used to identify the locations 
  429. in the program's binary image which contain absolute addresses.  When the 
  430. program is loaded, each of these locations is modified by adding the starting 
  431. address of the program to the number contained in that location.  Only 32-bit 
  432. numbers may be so modified.  
  433.  
  434. While RISC OS Forthmacs is running, it maintains its own relocation table, 
  435. identifying those locations in the Forth dictionary which must be relocated 
  436. during cold-code. Each bit in the map represents the address of one aligned 
  437. location.  This relocation table is completely different from the standard 
  438. RISC OS relocation tables, it is only used from within RISC OS Forthmacs.  
  439.  
  440. In order for this to work properly, the programmer must be careful to use 
  441. token, A, link, token!, A! or link! to store an address or token in the 
  442. dictionary, all six set the relocation flags.  
  443.  
  444. Addresses may be stored into variables with ! ( without requiring the use of 
  445. token! ) if the variable is re-initialized every time that the application is 
  446. started.  token! is only necessary if the variables value must be set before 
  447. save-forth is executed, and then is used when the saved application is later 
  448. invoked, without being re-initialized by the application's initialization 
  449. code.  
  450.  
  451. If , or ! is used instead, the address will not be properly relocated if 
  452. save-forth has been used to write the dictionary image to an executable file.  
  453.  
  454. Note: The lib/checkrel.fth program can help you catch relocation problems in 
  455. your applications.  It should be loaded before you load your application, and 
  456. will warn you if your application does things that may not be relocatable.  
  457. After you have fixed the relocation problems, you can load your application 
  458. without lib/checkrel.fth .  
  459.  
  460.  
  461. See: .buffers .pointers token! token, A! A, link! link, set-relocation-bit 
  462. relocation-map 
  463.  
  464.  
  465. Program header
  466. ==============
  467.  
  468. The header of the executable binary image looks like this: 
  469.  
  470.  h_magic   (  0)    \ Magic Number
  471.  h_tlen    (  4)    \ length of text (code)
  472.  h_dlen    (  8)    \ length of initialised data
  473.  h_blen    (  c)    \ length of BSS unitialised data
  474.  h_slen    (  10)   \ length of symbol table
  475.  h_entry   (  14)   \ Entry address
  476.  h_trlen   (  18)   \ Text Relocation Table length
  477.  h_drlen   (  1c)   \ Data Relocation Table length
  478.  
  479. the magic number is the branch+link instruction just behind this header.  
  480. Note: this header might be changed with future releases according to Acorns 
  481. executable binary code standard.  
  482.  
  483.  
  484. Heap memory
  485. ===========
  486.  
  487. RISC OS Forthmacs is loaded to $8000 and will have as much memory available as 
  488. was defined by 'WimpSlot' .  
  489.  
  490. The main-tasks user area immediately follows the first instructions and some 
  491. permanent data at $8040.  
  492.  
  493. $600 byte will be allocated in the module-heap RMA, it will hold the env-area, 
  494. the command-line area plus all handlers used by shelled programs.  
  495.  
  496. The implementation of the dynamic memory manager has changed in Version 
  497. 3.1-2.00.  From now on the dictionary and the heap share the same memory area, 
  498. the dictionary grows from lower addresses and the heap can be as large as the 
  499. area between the stacks and here. 
  500.  
  501. Note: Of course you may install another memory manager or add more heaps.  
  502.  
  503.  
  504. Dictionary memory
  505. =================
  506.  
  507. At the top of the dictionary are both stacks defined by rp0 - rs-size and sp0 
  508. - ps-size and the tib, below this are MBytes of free memory (well, hopefully).  
  509. here marks the end of the allocated dictionary, classically pad is here plus 
  510. something.  
  511.  
  512. RISC OS Forthmacs knows about two dictionary areas, the resident (which is the 
  513. dictionary you know in all implementations) and the transient. The transient 
  514. dictionary is in the heap memory, definitions defined here won't use 
  515. dictionary space in the target application.  So it might be useful to do: 
  516.     transient
  517.       fload assembler
  518.       fload debugger
  519.     resident
  520.       fload myapplication
  521. Now the debugger and assembler will be in transient address space.  To remove 
  522. all links, pointers etc.  into the transient address space use dispose, it 
  523. will do this for you.  .dispose will also give some informations what is 
  524. removed while executing dispose. 
  525.  
  526.