inital_library.fs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. \ Copyright (C) 2017 Jeremiah Orians
  2. \ Copyright (C) 2017 Reepca
  3. \ This file is part of stage0.
  4. \
  5. \ stage0 is free software: you can redistribute it and/or modify
  6. \ it under the terms of the GNU General Public License as published by
  7. \ the Free Software Foundation, either version 3 of the License, or
  8. \ (at your option) any later version.
  9. \
  10. \ stage0 is distributed in the hope that it will be useful,
  11. \ but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. \ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. \ GNU General Public License for more details.
  14. \
  15. \ You should have received a copy of the GNU General Public License
  16. \ along with stage0. If not, see <http://www.gnu.org/licenses/>.
  17. \ Simply cat this file to the top of any forth program that leverages its functionality
  18. \ then execute the resulting out put as so:
  19. \ ./bin/vm --rom roms/forth --memory 1M --tape_01 The_combined_file
  20. \ All writes via WRITE8 will be written to tape_02 or whatever name you prefer via the --tape_02 option
  21. \ However should you wish to leverage readline for interacting with forth use vm-production but be warned
  22. \ WILL see duplicate lines being printed when you hit enter as both readline and the forth are echoing your key strokes
  23. \ Define our CELL size as 4 bytes
  24. : CELL 4 ;
  25. \ Save us from manually calculating how many bytes is a given number of CELLS
  26. : CELLS CELL * ;
  27. \ Setup an easy to reference FLAGS offset Constant
  28. : >FLAGS 2 CELLS + ;
  29. \ Update the flags of the latest defintion to IMMEDIATE
  30. : IMMEDIATE LATEST >FLAGS DUP @ 0x2 OR SWAP ! ;
  31. \ Define ALLOT to allocate a give number of bytes
  32. : ALLOT HERE + DP! ;
  33. \ Read a word, lookup and return pointer to its definition.
  34. : ' WORD DROP FIND >CFA ;
  35. \ Lookup a word and write the address of its definition
  36. : [COMPILE] ' , ; IMMEDIATE
  37. \ The literal code address of LIT. Don't think too hard about it.
  38. : LITERAL [ ' LIT DUP , , ] , , ;
  39. \ Compile the CFA of a word looked up as a literal
  40. : ['] ' LITERAL ; IMMEDIATE
  41. \ CONTROL STRUCTURES
  42. \ Compile a conditional forward branch, to be resolved by THEN or ELSE.
  43. : IF ['] 0BRANCH , HERE 0 , ; IMMEDIATE
  44. \ Get displacement between two address and write the difference to the address first given
  45. : TARGET! OVER - SWAP ! ;
  46. \ equivalent to "ENDIF".
  47. : THEN HERE TARGET! ; IMMEDIATE
  48. \ And our ELSE for our IF
  49. : ELSE HERE 2 CELLS + TARGET! ['] BRANCH , HERE 0 , ; IMMEDIATE
  50. \ A backwards branch destination, to be resolved by AGAIN, UNTIL, or REPEAT.
  51. : BEGIN HERE ; IMMEDIATE
  52. \ This forward conditional branch will be resolved by REPEAT.
  53. : WHILE [COMPILE] IF SWAP ; IMMEDIATE
  54. \ Resolve a backwards branch.
  55. : AGAIN ['] BRANCH , HERE SWAP TARGET! CELL ALLOT ; IMMEDIATE
  56. : UNTIL ['] 0BRANCH , HERE SWAP TARGET! CELL ALLOT ; IMMEDIATE
  57. \ Resolve the latest forward branch and compile a backwards branch.
  58. : REPEAT [COMPILE] AGAIN [COMPILE] THEN ; IMMEDIATE
  59. \ Note that it is possible to use multiple exits from a
  60. \ BEGIN ... WHILE ... REPEAT loop, as long as you resolve the forward branches
  61. \ manually. For example, BEGIN ... WHILE ... WHILE ... REPEAT THEN will allow
  62. \ an exit from either WHILE. You can even put other stuff between the REPEAT and
  63. \ THEN if you need to handle certain exits specially. Use sparingly unless
  64. \ you're sure you understand how it works.
  65. : [CHAR] KEY LITERAL ; IMMEDIATE
  66. \ If true put t otherwise put f
  67. : .BOOL IF [CHAR] t ELSE [CHAR] f THEN EMIT ;
  68. \ Writes a Byte to HEAP
  69. : C, HERE C! 1 ALLOT ;
  70. \ addr count -- high low
  71. : BOUNDS OVER + SWAP ;
  72. \ Prints Memory from address a to a + b when invoked as a b TYPE
  73. : TYPE BOUNDS BEGIN 2DUP > WHILE DUP C@ EMIT 1 + REPEAT 2DROP ;
  74. \ So we don't have to type 10 EMIT for newlines anymore
  75. : CR 10 EMIT ;
  76. \ Makes a string on the HEAP from everything between it and "
  77. : STR" HERE BEGIN KEY DUP [CHAR] " != WHILE C, REPEAT DROP HERE OVER - ;
  78. \ Extends STR" to work in Compile mode
  79. : S" STATE IF ['] BRANCH , HERE 0 , STR" ROT HERE TARGET! SWAP LITERAL LITERAL
  80. ELSE STR" THEN ; IMMEDIATE
  81. \ Extends S" to behave the way most users want
  82. : ." [COMPILE] S" STATE IF ['] TYPE , ELSE TYPE THEN ; IMMEDIATE
  83. \ add the ANS keyword for modulus
  84. : MOD % ;
  85. \ add ANS keyword for getting both Quotent and Remainder
  86. : /MOD 2DUP MOD >R / R> ;
  87. \ valid bases are from 2 to 36.
  88. CREATE BASE 10 ,
  89. \ Primitive needed for printing base 10 numbers
  90. : NEXT-DIGIT BASE @ /MOD ;
  91. \ Give us a 400bytes of storage to play with
  92. : PAD HERE 100 CELLS + ;
  93. \ Assuming 2's complement
  94. : NEGATE NOT 1 + ;
  95. \ Swap the contents of 2 Memory addresses
  96. : CSWAP! 2DUP C@ SWAP C@ ROT C! SWAP C! ;
  97. \ Given an address and a number of Chars, reverses a string (handy for little
  98. \ endian systems that have bytes in the wrong order)
  99. : REVERSE-STRING OVER + 1 -
  100. BEGIN 2DUP < WHILE 2DUP CSWAP! 1 - SWAP 1 + SWAP REPEAT 2DROP ;
  101. \ Given an address and number, writeout number at address and increment address
  102. : +C! OVER C! 1 + ;
  103. \ works for hex and stuff
  104. : >ASCII-DIGIT DUP 10 < IF 48 ELSE 55 THEN + ;
  105. \ Given a number and address write out string form of number at address and
  106. \ returns address and length (address should have at least 10 free bytes).
  107. : NUM>STRING DUP >R OVER 0 < IF SWAP NEGATE SWAP [CHAR] - +C!
  108. THEN DUP >R SWAP \ R: str-start digits-start
  109. BEGIN NEXT-DIGIT ROT SWAP >ASCII-DIGIT +C! SWAP DUP WHILE REPEAT
  110. DROP R> 2DUP - REVERSE-STRING R> SWAP OVER - ;
  111. \ A user friendly way to print a number
  112. : . PAD NUM>STRING TYPE ;
  113. \ A temp constant that is going to be replaced
  114. : STACK-BASE 0x00090000 ;
  115. \ Given current stack pointer calculate and display number of underflowed cells
  116. : .UNDERFLOW ." Warning: stack is underflowed by "
  117. STACK-BASE SWAP - CELL / . ." cells!" CR ;
  118. \ Display the number of entries on stack in <n> form
  119. : .HEIGHT STACK-BASE - CELL / ." <" . ." > " ;
  120. \ Display count and contents of stack or error message if Underflow
  121. : .S DSP@ DUP STACK-BASE < IF .UNDERFLOW
  122. ELSE DUP .HEIGHT STACK-BASE
  123. BEGIN 2DUP > WHILE DUP @ . 32 EMIT CELL + REPEAT
  124. 2DROP
  125. THEN ;
  126. \ Pop off contents of stack to Zero stack
  127. : CLEAR-STACK BEGIN DSP@ STACK-BASE > WHILE .S 10 EMIT DROP REPEAT STACK-BASE DSP! ;
  128. : ( BEGIN KEY [CHAR] ) = UNTIL ; IMMEDIATE
  129. \ Note: for further reading, see brad rodriguez's moving forth stuff.
  130. \ The return address currently on the stack points to the next word to be
  131. \ executed. DOER! should only be compiled by DOES> or other similar words, so
  132. \ the address on the return stack should be right past DOER!'s. Which should be
  133. \ the code to make the action for the latest word. Since we only want to set
  134. \ this code as the latest word's action, not actually execute it at this point,
  135. \ we don't bother putting anything back on the return stack - we'll return
  136. \ straight up past the word we came from.
  137. \ For example: consider this definition
  138. \ : CONSTANT CREATE , DOES> @ ;
  139. \ This compiles to the sequence: DOCOL CREATE , DOER! @ EXIT
  140. \ DOER! will point the latest word (the CREATEd one) to the code right past it -
  141. \ the @ EXIT - and then exit the definition it's in.
  142. : DOER! R> SWAP >CFA ! ;
  143. \ This is a tricky one. Basically, we need to compile a little bit of machine
  144. \ code that will invoke the code that follows. Notes: R12 should, at this point,
  145. \ have the address of the place we got here from. So we should just put
  146. \ that+cell on the stack (for use by what follows DOES>) and run DOCOL. (Note:
  147. \ implemented in forth.s)
  148. \ Assumes most significant byte is at lower address
  149. : 2C, DUP 0xFF00 AND 8 RSHIFT C, 0xFF AND C, ;
  150. \ Compiles an assembly-level jump to a location.
  151. \ We may have to compile more than just a jump in the future in order
  152. \ for DOES> to work properly - we'd need to load the address into a register,
  153. \ having the actual address nearby, and then use that coroutine jump thing.
  154. \ JUMP over the Address, the address, LOADRU32 R0 -4, JSR_COROUTINE R0
  155. : JUMP-TO, 0x3C000008 , , 0x2E60FFFC , 0x0D010000 , ;
  156. \ Sets the action of the latest word
  157. : DOES> ['] LATEST , ['] DOER! , 'DODOES JUMP-TO, ; IMMEDIATE
  158. \ Sets the action of a certain word
  159. : DOER> ['] DOER! , 'DODOES JUMP-TO, ; IMMEDIATE
  160. : TUCK SWAP OVER ;
  161. : MIN 2DUP < IF SWAP THEN DROP ;
  162. : HEX 16 BASE ! ;
  163. : DECIMAL 10 BASE ! ;
  164. CREATE LINE-SIZE CELL ,
  165. : PRINTABLE? DUP 127 < SWAP 31 > AND ;
  166. : EMIT-PRINTABLE DUP PRINTABLE? IF EMIT ELSE DROP [CHAR] . EMIT THEN ;
  167. : DUMP-TYPE BOUNDS BEGIN 2DUP > WHILE DUP C@ EMIT-PRINTABLE 1 + REPEAT 2DROP ;
  168. \ will always print two characters.
  169. : .HEX-BYTE DUP 16 / >ASCII-DIGIT EMIT 15 AND >ASCII-DIGIT EMIT ;
  170. : DUMP-LINE 2DUP BOUNDS BEGIN 2DUP > WHILE DUP C@ .HEX-BYTE ." " 1 + REPEAT
  171. 2DROP ." " DUMP-TYPE CR ;
  172. : DUMP-LINES LINE-SIZE @ * BOUNDS
  173. BEGIN 2DUP > WHILE DUP LINE-SIZE @ TUCK DUMP-LINE + REPEAT 2DROP ;
  174. : DUMP LINE-SIZE @ /MOD -ROT 2DUP DUMP-LINES LINE-SIZE @ * + SWAP DUMP-LINE ;
  175. : VARIABLE CREATE 0 , ;
  176. : CONSTANT CREATE , DOES> @ ;
  177. : NOOP ;
  178. : DEFER CREATE ['] NOOP , DOES> @ EXECUTE ;
  179. : IS ' CELL + STATE IF LITERAL ['] ! , ELSE ! THEN ; IMMEDIATE
  180. \ emits n spaces.
  181. : SPACES BEGIN DUP WHILE 32 EMIT 1 - REPEAT DROP ;
  182. ' NOOP @ CONSTANT 'DOCOL
  183. \ Starts a definition without a name, leaving the execution token (the thing
  184. \ that can be passed to EXECUTE) on the stack.
  185. : :NONAME HERE 'DOCOL , ] ;
  186. \ fill n bytes with char.
  187. \ addr n char --
  188. : FILL >R BOUNDS BEGIN 2DUP > WHILE DUP R@ C! 1 + REPEAT 2DROP R> DROP ;
  189. : <> != ;