Looking for the latest version? Download forth92-1.00.zip (142.1 kB)
Home
Name Modified Size Downloads / Week Status
Totals: 2 Items   197.3 kB 2
README.txt 2012-11-25 55.3 kB 11 weekly downloads
forth92-1.00.zip 2011-09-12 142.1 kB 11 weekly downloads
=========================================================================== Forth92 - An ANS-Forth for the TI-92 programmable calculator Author: David Kuehling <dvdkhlng TA gmx TOD de> =========================================================================== Foreword, March 31 2003 I stopped working on that project some years ago, since nobody seemed to use the original TI-92/TI-92 II any more and since I became busy with other stuff. Still from time to time people asked me for a copy of Forth92, so I suppose, it might still be useful to some people out there... This is the first and probably last release of Forth92. Consider all this work as in the "Public Domain" -- do with it whatever you want. Maybe somebody will be able to turn this into something useful. This release should contain all sources; if you think I forgot something, please tell me. Unfortunately I wasn't a very experienced programmer when I started programming Fargo back in 1997(?). It seemed fun to reinvent the wheel, especially since I worked with a very common but extremely restricted OS, so I created the "PreFargo" preprocessor, which is needed to compile Forth92. A copy is contained in the `prefargo' subdir. It was developed with DJGPP, a (DOS) executable is included. With some (little) effort this should compile on Linux as well... (source included). I also didn't know about Makefiles back then; sorry for all the inconveniences ;-) Should I write something about designing a Forth system for the TI-92 here? Yes, I learned from my mistakes :-) If you ever get into the situation of wanting (having?) to write a Forth for some platform; please take smarter approach than me: * Write a small kernel containing all the "primitives" (very basic functions like + - * ! @ AND OR etc) either in ASM or C. * All the more "high level" functions should be written in the virtual machine language your Forth system is using (Forth92 uses indirect threaded code). Forth92 uses a hell lot of (unreadable) macros to generate this machine language -- just have a look at forth92.s:2933 (definition of `LIST'). A much smarter (and more common?) approach is to use a Forth target compiler on your development platform. Such a target compiler can easily be written using some ANS Forth. Some mechanism is required, to "link" it with your kernel... shouldn't be difficult though. * Have a look at `GForth': it uses a kernel of primitives (written in C), and a kernel of Forth code (generated using a Forth target compiler). This minimalistic Forth system is then used to compile all the other (non-kernel) words, dumping the resulting dictionary into a file. That's smart, no? * If you're an Emacs user, write your Forth code using `gforth.el', which comes with GForth -- GForth 0.6.0's gforth.el even has some neat syntax hilighting for Forth :-) And I shouldn't also forget to tell you the TRUTH about the TI-92's memory managment: ASM will never be stable :-(( The details: All variables on your TI-92 are stored in memory blocks, referenced via "handles". If a program allocates memory, the TIOS creates a new memory block out of unused memory and passes it's handle to the program. But if there's no unfragmented memory reagion of sufficient size available, the TIOS starts defragmenting all memory blocks. This will probably move the running Fargo program in memory, making your calc crash horribly. So before running any Fargo program, visit the Var-Link screen first. This will unfragment memory (AFAIR..) and make crashes less probable. At least I hope so... it's such a long time ago that I did Fargo hacking... Have fun! =========================================================== Forth92 - by David Kuehling =========================================================== ========================================================== Introduction ========================================================== Well, when I started to work at Forth92, I wanted to release the first version in February 1999. That's now one and half a year ago, and I still have so many ideas of what should be added to Forth92... But since I'm currently busy with some other projects, I thought it would be ok to release that version, before the last TI-92 user died. ;-) If you want to port Forth92 to the TI-92+ or TI-89, have a look at forthlib.s, which contains most of (all?) the TI-92 specific code. Forth92.s should be source text compatible. Unfortunately you'll need the PreFargo precompiler for compilation. Have a look at http://www.ticalc.org, or send me a mail: Bug reports, questions, suggestions and comments are also welcome! email: dvdkhlng <ta> gmx <tod> de This documentation is meant to be used by people already knowing the basics about Forth. If you don't know it, try to find some beginner's guide at http://www.forth.org. Forth92 is (should be?) compliant to the ANS Forth specification from 1994. However, this can't be guaranteed since I hadn't access to the original ANS Forth Standard. Instead I used a free inofficial version, which I got from http://www.forth.org. I don't have time to explain all words of my implementation, so I'll restrict it to only document extensions to the ANS Forth Standard and all the so-called implementation - defined items. If you want to know more about the implementation than this document describes, watch the source text 'forth92.s' for more details. It contains Forth-code for a lot of words and a lot of comments... Please keep in mind, that this version is far from being completed. There may be bugs in some words, so if you write programs you will have to look for your programs' bugs as well as for bugs in Forth92. There are also some words missing that you may need. In some cases you should be able to implement that word yourself (e.g 'ENVIRONMENT?'). ========================================================== Installation ========================================================== Install Fargo on your TI-92 calculator, then upload the files forth92.92p, forthlib.92p, fortherr.92t into the main\ folder and launch the forth92 program variable. ========================================================== Implementation ========================================================== This section describes some details about the implementation which should help you to find and understand bugs which may occure. Forth92 was developed with the implementation of FIG-Forth in mind. This is because the first (and only) book that I found about Forth described the complete implementation of a FIG-Forth system. When I read that book, I didn't know anything about Forth, and the first Forth programs that I created I developed with Forth92. So you might find some points about my implementation which will seem strange to you... As in FIG-Forth, Forth92 uses indirect threaded code. Since the 68000 processor is a 16 bit processor, Forth92 had to become a 16 bit Forth system. As you may imagine, this causes problems with the 24bit addresses that are needed to access the TI-92's RAM and ROM. The solution was, to make all addresses 16 bit to fit into one cell. Those addresses are relative to the address in the register 'a3'. So my assembly code accesses addresses like: 'move.w 0(a3, d0.w), d1' The consequence is, that the whole Forth92 dictionary has to be in the 64K range of the accessable addresses. For that reason the user dictionary (which is currently 8K) is included as a part of forth92.92p, so its contents are kept even when you exit Forth92 and restart it. If you need to empty the dictionary, use the word 'COLD', which causes a "cold system reboot", which will initialize everything to defaults. Additionally there is a "warm system reboot", which is done whenever you enter Forth92 and which is executed on errors. It clears data and return stacks, sets the search order to default and sets the base for number conversion to 10. ========================================================== System documentation ========================================================== ---------------------------------------------------- Basic stuff ---------------------------------------------------- About crash-proofness ------------------------- Although Forth92 does a lot of things to keep your calc from crashing, I recommend to use 'FPL' for executing Forth92. That little proggie does even more anti-crash things. If Forth92 hangs, you may try to press [hand]+[On], this will abort any running Forth-loop (DO...LOOP, BEGIN...UNTIL etc.). If you can't exit from Forth92 (e.g. you somehow overwrote parts in the dictionary, so Forth92 doesn't recognize 'BYE' any more), try pressing [diamond]+[c], which will make Forth92 to exit. (This is somehow dangerous. Only use it if necessary). If nothing works and you executed Forth92 from FPL, try FPL's [On]+[Esc] shortcut. If you're using FPL, don't hesitate to use it's compression feature. The only thing you should notice about it, that the dictionary is restored at startup when using a compressed archive. (Normaly Forth92 keeps the dictionary between differen sessions). System implementation defined items --------------------------------------- The ANS Forth standard leaves some choices about the implementation to the implementor. The following is a list about the values and behaviours of those items. aligned address requirements Only address which are a multiple of 2 are cell-aligned. Reading or writing cells ('@', '?', '!' etc.) to address which are not aligned in this way causes an exception. behaviour of 'EMIT' for non-graphic characters The following characters are interpreted as control-characters: 1 invert text color 2 toggle underlining 3 toggle bold 7 bell, flash the screen 8 backspace, move cursor one character backwards 9 tabulator, align cursor at 8-character tabulator 10 line-feed, move cursor to begin of next line 12 form-feed, clear screen and move cursor to begin of first line 13 cariage-return, go to current line's start character editing of accept characters and backspace only character set All non-control characters display like described in the TI-92's manual. character-aligned address requirements Any address is character-aligned. character-set-extensions matching characteristics Words are looked up in the dictionary by simple binary comparison, so all the ANS Forth words can only be found uppercase. conditions under which control characters match a space delimiter never! format of the control flow stack The control flow stack is implemented using the data stack. For details watch the source code in 'forth92.s'. conversion of digits, larger than thirty-five Digits, greater than 9 are represented by the characters beginning from #65 ('A') up to #255. Consequently, you have to use uppercase letters for numbers with a base smaller than 36. display after input terminates in ACCEPT nothing is done to the display exception abort sequence Clear data and return stack, set the search order to defaults, set the base for number conversion ('BASE') to 10. Display a reagion of the input buffer with the word which caused the exception underlined. Look in a file named 'fortherr' for a textual description of the exception. If that file exists and contains a description for the exception display the exceptions description, else only display it's number. input line terminator enter-key (when 'EKEY' returns 13) maximum size of a counted string in characters: 255 maximum size of a parsed string in characters: 255 maximum size of a definition name in characters: 31 maximum string length for 'ENVIRONMENT?' in characters 'ENVIRONMENT?' hasn't been implemented yet method of selecting the user input device The user input device is always the keyboard. method of selecting the user output device The output device is always the screen. methods of dictionary compilation ?? number of bits in one address unit: 8 bits number representation and address arithmetics Arithmetic architecture is two's complement. Division behaviour is round towards zero (symetric). ranges for n, +n, u d, +d and ud -32768 <= n <= 32767 0 <= +n <= 32767 0 <= u <= 65536 -2147483648 <= d <= 2147483647 0 <= +d <= 2147483647 0 <= ud <= 4294967295 read-only data space regions none size of buffer at 'WORD': 256 characters size of one cell in address units: 2 size of one character in address units: 1 size of the keyboard terminal input buffer: 84 size of the pictured numeric output string buffer: 64 size of the scrach area whose address is returned by 'PAD': 84 system case sensitive characteristics Forth92 is case sensitive. system propmpt "<OK", where '<' is the TI-92's character #25 which can't be displayed with the ASCII character set of that documentation. type of division rounding round towards zero (symetric rounding) values of 'STATE' when true: 1 values returned after arithmetic overflow '+', '-', 'D+', 'D-' return the result as if the operation would have been done with one additional most significant bit (and thus without overflow) and with that additional bit removed in the result. The values returned by multiplication and division operations are undefined. whether the current definition can be found after DOES> It can't be found Ambiguous conditions ------------------------ a name is neither a valid definition name nor a valid number during text interpretation: exception #-13 a definition name exceeds the maximum length allowed: exception #-19 addressing a reagion, which isn't data space: ignore argument incompatible with specified input parameter This depends on the word. If due to the wrong argument the stack underflows, exception -4 may be triggered. If wrong control flow arguments are passed to a word (e.g. 'ELSE', 'ENDOF' etc.), exception #-22 is triggered. All the other words ignore wrong argument types. attempting to obtain the execution token of a definition with undefined interpretation semantics: ignore dividing by zero: exception #-10 insufficient data stack space or return stack space Continue execution until end of a loop ('LOOP', 'REPEAT' etc) is reached. Then trigger exception #-3. insufficient space for loop control parameters: exceptoin #-3 insufficient space in the dictionary: exception #-8 interpreting a word with undefined interpretation semantics: ignore modifying the contents of the input buffer or a string literal: ignore overflow of a pictured numeric output string: exception #-17 parsed string overflow: cut string producing a result out of range ignore, return undefined value reading from empty data stack or return stack: Continue execution until end of a loop ('LOOP', 'REPEAT' etc) is reached. Then trigger exception #-4. unexpected end of input buffer, resulting in an attempt to use a zero-length string as a name: exception #-16 Other system documentation ------------------------------ list of words using 'PAD': none program data space available, in address units: 8192 operator's terminal facilities available: ???? return stack space available, in cells: 512 stack space available, in cells: 4096 system dictionary space required, in address units: ???? ---------------------------------------------------- Documentation for the Block word set ---------------------------------------------------- In Forth92 all blocks are stored into files in a folder named 'blocks'. Those files will look to the TIOS like empty string variables. Since blocks are stored compressed, they can save quite a lot of memory, especially when they contain highly redundant data. The algorithm that I'm currently using is very much speed optimized. On my 256K TI-92 it compresses about 6 to 7 blocks per second (it would be about half the speed at a 128K TI-92). However, I would be able to increase the algorithm's compression strength by about 20%, which would make it about 2 times slower. I'm waiting for your opinion about it... Since you are able use 9999 blocks in the files 'blk0000' up to 'blk9999', the memory of the calc would be messed up quite a lot if all those files would be existent. That's why only blocks which contain nonzero bytes will actually exist as files. If you write a block only containg zeroes, the corresponding file is deleted and it's memory freed. If you read a block, with its corresponding file not existing, a block full of zeroes will be returned. So here some code for deleting blocks and their corresponding files: : DELETE-BLOCK ( u -- ) BLOCK 1024 ERASE UPDATE FLUSH ; System implementation defined items --------------------------------------- the format used for display by 'LIST' 'LIST' displays a full-screen scrollable view of the specified block, splitting it into 16 lines with 64 characters each. You may scroll by the arrow-keys (left/right). The characters in the first column are displayed inverted and indicate the (block-relative) line number beginning at '0' up to 'F' (=line 15). T the length of a line affected by '\' The length of lines in blocks is 64. I added an additional word, C/L which allways returns that line-length. ('64 CONSTANT C/L') Ambigous conditions ----------------------- Correct block read was not possible: exception #-33 Correct block write was not possible: exception #-34 Invalid block number: exception #-35 A program directly alters the contents of 'BLK': ignored No current block buffer for 'UPDATE': ignored other system documentation ------------------------------ the number of blocks available for source text and data: 9999 ---------------------------------------------------- Documentation for the Facility word set ---------------------------------------------------- System implementation defined items --------------------------------------- encoding of keyboard events ('EKEY') It uses the keycodes, which would also be returned by the TI-92's 'getkey' function, which are documented in the TI-92's manual. duration of a system clock tick 'MS' hasn't been implemented yet, however when I implement it, I will use the timer counter byte at port address 600017(hex), which is incremented 1580 times per second. ---------------------------------------------------- Documentation for the File-Access word set ---------------------------------------------------- Before you move over to the next section please note that file names are represented by _lowercase_ strings, containg a folder and a file name. You _have_ to specify a folder! For example: S" main\source" INCLUDED Although variables on the TI-92 are not realy files, I decided to implement the File-Access word set to be able to write Forth programs using the TI-92's editor. It is also useful for performing operations on data which doesn't fit into Forth92's data space or for whose the Block word set with its data compression is too slow. But as I said, variables on the TI-92 are not like files on a PC. For example the layout of a text variable: Address size of Data Meaning 0000 word size of variable, excluding this word 0002 word cursor position offset from text begin 0004 n the actual text data: 0004 byte This is the command which is displayed before the first colon of each line in the TI-92's text editor. Normaly it's a space. It may also be 'P' (print object) or 'C' (command) or 0F(hex) (form feed). 0005 l one line of text 0005+l byte A byte of 0D(hex) indicates the line break. ... (more lines) ... 0004+n byte zero-byte, indicating the end of the text 0005+n byte all text variables have to end on this E0(hex) byte, else the TI-92 won't recoginze them to be texts. As you can see, under those conditions a text file can't be constructed as on the PC, just by subsequently appending lines to a file. The user would have to take care of the end of the file (00(hex) E0(hex)) and set the cursor position correctly. The calculator could even crash if the cursor postion is wrong or if the end-of-text mark is missing. For I wanted to be able to load Forth sources from text files, I had to develop a method to access text variables in a way, that simulates "raw" text files. In Forth92 you can't access the begin and the end of a file. Any file operation which resizes the file will automatically create a new end-of-text mark. If you seek to the file's begin, you will seek to the text's begin, just behind the cursor-position-word. All of this is done completely transparent. If you access a text variable's size via 'FILE-SIZE', you will get the size of the variable, minus the begin and the end (the parts you can't access, for the user they're as if they wouldn't even exist). So after all the "file" you access is actually just a part of a text variable. But another problem that arises here is how to manage line breaks. The TI-92's line break character in text variables is 0D(hex). But there's also always a control-character or a space in front of a line (the byte at 0005 in the above layout description). It would be very impractical if you would always have to put a space in front of any line you write into a text file. Text files generated by some ANS standard program which doesn't know of the anomaly with the spaces of line's begin would generate text variables which couldn't be edited with the TI-92's editor. The solution is, to write a space _behind_ line breaks ('WRITE-LINE'). So if you end the current line you always put a space to the next line's begin. The problem remaining is how to handle the first line in the file, which isn't preceded by any other line break. For that reason I always put a space to the first line's begin, and the part of the file, the user accesses via the File Access word set goes from (including)0005 to just before the trailing zero. And even some more details... The file-id returned by 'OPEN-FILE' and 'CREATE-FILE' is the variable's TIOS handle. The current file position is stored in the cursor-position-word of the variable. Closing and opening a variable sets the cursor position to the variable's begin. If you don't close a file, the cursor position remains, thus you can open text files at the position you just read/write. This is also useful in the process of loading Forth sources from text variables ('INCLUDE-FILE' and 'INCLUDED'). When an error exception occures during a text variable is parsed, the cursor remains just behind the line which caused the exception. This should help you to find errors faster... This concept does not include checking whether a file has been opened for reading or writing, thus you can write to a file opened read-only ('R/O') or read from a file, opened for write only ('W/O'), but please do not try to create a new empty file for reading, this is nonsens and will be punished by a file I/O exception. Your program should not depend on this specific behaviour, since it may change in future versions and its anything else than Forth standard. But the File Access words pay attention to whether you open a file in binary or text mode ('BIN'). Files opened/created for binary access will be locked in the TI-92's variable system for to prevent the editor crashing (It might realy crash if you write too long lines or some special characters...). Binary files containing zero-bytes would also be truncated, as soon as you open them in the TI-92's editor. ... I hoped this long description didn't bored you, now I'm moving on to the stuff that should be more interesting to the Forth programmer: System implementation defined items --------------------------------------- file exceptions / ior values any errors during file access will return an I/O result code of #-37 ("file I/O exception") file line terminator 0D(hex) 20(hex) (look the above descriptions...) file name format Files have to be given lowercase, they may begin on letters but not on numbers. Any characters in the name except the first character may be letters, numbers and underbar. No other special characters are excepted. File names have to consist of a folder name and a file name, separated by a backslash. Examples for valid file names are: main\source main\test forth\source Examples for invalid file names: source main\_source main\2file maximum level of file input nesting I don't know. Nesting information are stored on the return stack so it depends on the data already stored on it. 8 levels should work in all cases maximum size of input line: 128 characters number of string buffers provided by 'S"': 1 buffer only size of string buffer used by 'S"': 80 characters Ambigous conditions ----------------------- fileid is invalid This error won't be detected and will corrupt memory reagions of your TI-92. Which means your calc may crash! using 'SOURCE-ID' when BLK is not zero Ignored, value returned by 'SOURCE-ID' is undefined. ---------------------------------------------------- Documentation for the Floating-Point wordset ---------------------------------------------------- System implementation defined items --------------------------------------- format and range of floating point numbers I decided to use 48 bit floating point numbers which consist of a 32 bit significant and a 16 bit base-two exponent. Those entities can be handled in the most efficient way by the assembler emulation routines. The significant is always in the range from [-2^31; -2^30+1] for negetive numbers or in the range [2^30; 2^31-1] for positive numbers. The exponenent's range is [-2^15; 2^15-1]. The significant is always kept in it's range by mulitplication/division by two and according decrease / increase of the exponent. As an example the floating-point representation of the number number would be exponent=2^30, significant=-30. As you can see the range of representable floating-point numbers is enormous: about [-2^(32798); 2^32797]. But unfortunately the accuracy of my implementation of 'FEXP' gets lower the greater values you work with. Since 'FEXP' is used for input and output number conversion, you can neither input nor output great values with a high accuracy. I recommend not to use numbers with an exponent outside the range [-100; 100]. I would appreciate very much if someone could tell me a better way to calculate 'FEXP'. I didn't have much information on floating-point when I implemented the floating-point word set. So watch the source ('forthlib.s') and tell me your ideas about optimization. I'd especially like to know good algorithms (better than just using taylor polynomen) for 'FEXP', 'FLN', 'FSQR', 'FSIN' and 'FCOS'. rounding and truncation of floating point numbers This depends on the specific floating point operations. I don't want to try to predict. Watch the sourcecode 'forthlib.s', especialy the floating-point division routine and you'll see what I mean. size of floating point stack: 32 items ---------------------------------------------------- Documentation for the Search-Order word set ---------------------------------------------------- System implementation defined items --------------------------------------- maximum number of wordlists in the search order: 8 number of wordlists which may be defined additionally via 'WORDLIST': 8 minimum search order ('ONLY', 'SET-ORDER') The complete vocabulary of Forth92 is contained within one wordlist, whose wid is returned 'FORTH-WORDLIST'. The minimum search order consists of that wordlist only. ---------------------------------------------------------- Glossary ---------------------------------------------------------- Core Words -------------- ! ( x a-addr -- ) Ambigous conditions: Incorrect address alignment: Exception #-23 # ( ud1 -- ud2 ) Ambigous conditions: Use outside <# ... #> This is ignored but may cause Forth92 to crash... #> ( xd -- c-addr u ) #S ( ud1 -- ud2 ) Ambigous conditions: Use outside <# ... #> This is ignored but may cause Forth92 to crash... ' ( "<spaces>name" -- xt ) Ambigous conditions: Name not found: Exception #-13 ( ( "ccc<paren>" -- ) * ( n1 n2 -- n3 ) */ ( n1 n2 n3 -- n4 ) */MOD ( n1 n2 n3 -- n4 n5 ) + ( n1|u1 n2|u2 -- n3|u3 ) +! ( n|u a-addr -- ) +LOOP Compilation: ( C: do-sys -- ) Run-time: ( n -- ) ( R: loop-sys1 -- | loop-sys2 ) , ( x -- ) Ambigous conditions: Data-space pointer not properly aligned: Exception #-23 - ( n1|u1 n2|u2 -- n3|u3 ) . ( n -- ) ." Compilation: ( "ccc<quote>" -- ) Run-time: ( -- ) / ( n1 n2 -- n3 ) /MOD ( n1 n2 -- n3 n4 ) 0< ( n -- flag ) 0= ( x -- flag ) 1+ ( n1|u1 -- n2|u2 ) 1- ( n1|u1 -- n2|u2 ) 2! ( x1 x2 a-addr -- ) 2* ( x1 -- x2 ) 2/ ( x1 -- x2 ) 2@ ( a-addr -- x1 x2 ) 2DROP ( x1 x2 -- ) 2DUP ( x1 x2 -- x1 x2 x1 x2 ) 2OVER ( x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 ) 2SWAP ( x1 x2 x3 x4 -- x3 x4 x1 x2 ) : ( C: "<spaces>name" -- colon-sys ) name Initiation: ( i*x -- i*x ) ( R: -- nest-sys ) name Execution: ( i*x -- j*x ) ; Compilation: ( C: colon-sys -- ) Run-time: ( -- ) ( R: nest-sys -- ) < ( n1 n2 -- flag ) <# ( -- ) = ( x1 x2 -- flag ) > ( n1 n2 -- flag ) >BODY ( xt -- a-addr ) >IN ( -- a-addr ) Ambigous conditions: '>IN' is greater than the size of the input buffer Is ignored. 'WORD' and 'PARSE' will return empty strings. >NUMBER ( ud1 c-addr1 u1 -- ud2 c-addr2 u2 ) >R ( x -- ) ( R: -- x ) ?DUP ( x -- 0 | x x ) @ ( a-addr -- x ) Ambigous conditions: Incorrect address alignment: Exception #-23 ABORT ( i*x -- ) ( R: j*x -- ) ABORT" Compilation: ( "ccc<quote>" -- ) Run-time: ( i*x x1 -- | i*x ) ( R: j*x -- | j*x ) ABS ( n -- u ) ACCEPT ( c-addr u +n1 -- +n2 ) ALIGN ( -- ) ALIGNED ( addr -- a-addr ) ALLOT ( n -- ) Ambigous conditions: Data space containing definitions is de-allocated: This error isn't recognized and will destroy parts of Forth92's dictionary. This may make it impossible fort Forth92 to look up any word in the dictionary, including 'BYE'. Use [On]+[C] to exit from Forth92 in that case and install a new copy. AND ( x1 x2 -- x3 ) BASE ( -- a-ddr ) BEGIN Compilation: ( C: -- dest ) Run-time ( -- ) BL ( -- char ) C! ( c-addr char -- ) C, ( char -- ) C@ ( c-addr -- char ) CELL+ ( a-addr1 -- a-addr2 ) CELLS ( n1 -- n2 ) CHAR ( "<spaces>name" -- char ) CHAR+ ( c-addr1 -- c-addr2 ) CHARS ( n1 -- n2 ) CONSTANT ( x "<spaces>name" -- ) name Execution: ( -- x ) COUNT ( c-addr1 -- c-addr2 u ) CR ( -- ) CREATE ( "<spaces>name" -- ) name Execution: ( -- a-addr ) DECIMAL ( -- ) DEPTH ( -- +n ) DO Compilation: ( C: -- do-sys ) Run-time: ( n1|u1 n2|u2 -- ) ( R: -- loop-sys ) DOES> Compilation: ( C: colon-sys1 -- colon-sys2 ) Run-time ( -- ) ( R: nest-sys1 -- ) name Initiation: ( i*x -- i*x a-addr ) ( R: -- nest-sys2 ) name Execution: ( i*x -- j*x ) DROP ( x -- ) DUP ( x -- x x ) ELSE Compilation: ( C: orig1 -- orig2 ) Run-time: ( -- ) EMIT ( x -- ) ENVIRONMENT? ( c-addr u -- flase | i*x true ) **** This routine has not been implemented yet **** EVALUATE ( i*x c-addr u -- j*x ) EXECUTE ( i*x xt -- j*x ) EXIT ( -- ) ( R: nest-sys -- ) FILL ( c-addr u char -- ) FIND ( c-addr -- c-addr 0 | xt 1 | xt -1 ) FM/MOD ( d1 n1 -- n2 n3 ) HERE ( -- addr ) HOLD ( -- char ) Ambigous conditions: Use outside <# ... #> This is ignored but may cause Forth92 to crash... I ( -- n|u ) ( R: loop-sys -- loop-sys ) Ambigous conditions: Loop control parameters not available This kind of error can't be detected. In case you manipulated the return-stack ('>R', 'R>' etc.) or 'I' is executed outside a loop, n|u will be undefined. IF Compilation: ( C: -- orig ) Run-time ( x -- ) IMMEDIATE ( -- ) Ambigous conditions: Most recent definition does not have a name (e.g. ':NONAME') 'IMMEDIATE' will allways effect the word which has most recently been defined _with_ a name. 'IMMEDIATE' just ignores definitions of unnamed words as if they wouldn't exist. INVERT ( x1 -- x2 ) J ( -- n|u ) ( R: loop-sys1 loop-sys2 -- loop-sys1 loop-sys2 ) Ambigous conditions: Loop control parameters not available This kind of error can't be detected. In case you manipulated the return-stack ('>R', 'R>' etc.) or 'J' is executed outside a twice nested loop, n|u will be undefined. KEY ( -- char ) LEAVE ( -- ) ( R: loop-sys -- ) LITERAL Compilation: ( x -- ) Run-time: ( -- x ) LOOP Compilation: ( C: do-sys -- ) Run-time: ( -- ) ( R: loop-sys1 -- | loop-sys2 ) LSHIFT ( x1 u -- x2 ) Ambigous conditions: u greater than the number of bits in a cell Shift is performed without errors, but only the 5 least significant bits of u are taken for the shift. M* ( n1 n2 -- d ) MAX ( n1 n2 -- n3 ) MIN ( n1 n2 -- n3 ) MOD ( n1 n2 -- n3 ) MOVE ( addr1 addr2 u -- ) NEGATE ( n1 -- n2 ) OR ( x1 x2 -- x3 ) OVER ( x1 x2 -- x1 x2 x1 ) POSTPONE Compilation: ( "<spaces>name" -- ) Ambigous conditions: Name not found: Exception #-13 QUIT ( -- ) ( R: i*x -- ) R> ( -- x ) ( R: x -- ) R@ ( -- x ) ( R: x -- x ) RECURSE Compilation: ( -- ) Ambigous conditions: 'RECURSE' appears after 'DOES>' Is ignored, the correct code for execution of the most recently defined word is appended to the 'DOES>' part of the definition. REPEAT Compilation: ( C: orig dest -- ) Run-time: ( -- ) ROT ( x1 x2 x3 -- x2 x3 x1 ) RSHIFT ( x1 u -- x2 ) Ambigous conditions: u greater than the number of bits in a cell Shift is performed without errors, but only the 5 least significant bits of u are taken for the shift. S" Interpretation: ( "ccc<quote>" -- c-addr u ) Compilation: ( "ccc<quote>" -- ) Run-time: ( -- c-addr u ) S>D ( n -- d ) SIGN ( n -- ) SM/REM ( d1 n1 -- n2 n3 ) SOURCE ( -- c-addr u ) SPACE ( -- ) SPACES ( n -- ) STATE ( -- a-addr ) SWAP ( x1 x2 -- x2 x1 ) THEN Compilation: ( C: orig -- ) Run-time: ( -- ) TYPE ( c-addr u -- ) U. ( u -- ) U< ( u1 u2 -- flag ) UM* ( u1 u2 -- ud ) UM/MOD ( ud u1 -- u2 u3 ) UNLOOP Execution: ( -- ) ( R: loop-sys -- ) UNTIL Compilation: ( C: dest -- ) Run-time: ( x -- ) VARIABLE ( "<spaces>name" -- ) name Execution: ( -- a-addr ) WHILE Compilation: ( C: dest -- orig dest ) Run-time: ( x -- ) WORD ( char "<chars>ccc<char>" -- c-addr ) XOR ( x1 x2 -- x3 ) [ ( -- ) ['] Compilation: ( "<spaces>name" -- ) Run-time: ( -- xt ) Ambigous conditions: Name not found: Exception #-13 [CHAR] Compilation: ( "<spaces>name" -- ) Run-time: ( -- char ) ] ( -- ) Core Extension Words ------------------------ Not all words of the standard's core extension wordset specification have been implemented. I only concentrated on words that have not been declared obsolescent. This is the list of all (currently) implemented words: .( Execution: ( "ccc<paren>" -- ) .R ( n1 n2 -- ) 0<> ( x -- flag ) 0> ( n -- flag ) 2>R ( x1 x2 -- ) ( R: -- x1 x2 ) 2R> ( -- x1 x2 ) ( R: x1 x2 -- ) 2R@ ( -- x1 x2 ) ( R: x1 x2 -- x1 x2 ) :NONAME ( C: -- colon-sys ) ( -- xt ) xt Initiation: ( i*x -- i*x ) ( R: -- nest-sys ) xt Execution: ( i*x -- j*x ) <> ( x1 x2 -- flag ) ?DO Compilation: ( C: -- do-sys ) Run-time: ( n1|u1 n2|u2 -- ) ( R: -- loop-sys ) REPEAT Compilation: ( C: dest -- ) Run-time: ( -- ) CASE Compilation: ( C: -- case-sys ) Run-time: ( -- ) COMPILE, Execution: ( xt -- ) ENDCASE Compilation: ( C: case-sys -- ) Run-time: ( x -- ) ENDOF Compilation: ( C: case-sys1 of-sys -- case-sys2 ) Run-time: ( -- ) ERASE ( addr u -- ) FALSE ( -- false ) HEX ( -- ) MARKER ( "<spaces>name" -- ) name Execution: ( -- ) NIP ( x1 x2 -- x2 ) OF Compilation: ( C: -- of-sys ) Run-time: ( x1 x2 -- | x1 ) PAD ( -- c-addr ) PARSE ( char "ccc<char>" -- c-addr u ) PICK ( xu ... x1 x0 u -- xu ... x1 x0 xu ) Ambigous conditions: Less than u+2 stack items: ignored REFILL ( -- flag ) RESTORE-INPUT ( xn ... x1 n -- flag ) Ambigous conditions: Argument input source different than current input source for 'RESTORE-INPUT': exception #-257 ROLL ( xu xu-1 ... x0 u -- xu-1 ... x0 xu ) Ambigous conditions: Less than u+2 stack items Is ignored, so it might crash Forth92... be careful! SAVE-INPUT ( -- xn ... x1 n ) SOURCE-ID ( -- 0 | -1 | fileid ) TO Interpretation: ( x "<spaces>name" -- ) Compilation: ( "<spaces>name" -- ) Run-time: ( x -- ) Ambigous conditions: Name not defined by 'VALUE' used with 'TO': exception #-32 TRUE ( -- true ) TUCK ( x1 x2 -- x2 x1 x2 ) U.R ( u n -- ) U> ( u1 u2 -- flag ) UNUSED ( -- u ) VALUE ( x "<spaces>name" -- ) name Execution: ( -- x ) WITHIN ( n1|u1 n2|u2 n3|u3 -- flag ) [COMPILE] ( "<spaces>name" -- ) Ambigous conditions: Name not found: Exception #-13 \ Compilation: ( "ccc<eol>" -- ) Execution: ( "ccc<eol>" -- ) Block Words --------------- BLK ( -- a-addr ) BLOCK ( u -- a-addr ) BUFFER ( u -- a-addr ) FLUSH ( -- ) LOAD ( i*x u -- j*x ) SAVE-BUFFERS ( -- ) UPDATE ( -- ) Block Extension Words ------------------------- EMPTY-BUFFERS ( -- ) LIST ( u -- ) SCR ( -- a-addr ) THRU ( i*x u1 u2 -- j*x ) Double Number Words ----------------------- 2CONSTANT ( x1 x2 "<spaces>name" -- ) name Execution: ( -- x1 x2 ) 2LITERAL Compilation: ( x1 x2 -- ) Run-time: ( -- x1 x2 ) 2VARIABLE ( "<spaces>name" -- ) name Execution: ( -- a-addr ) D+ ( d1|ud1 d2|ud2 -- d3|ud3 ) D- ( d1|ud1 d2|ud2 -- d3|ud3 ) D. ( d -- ) D.R ( d n -- ) D0< ( d -- flag ) D0= ( xd -- flag ) D2* ( xd1 -- xd2 ) D2/ ( xd1 -- xd2 ) D< ( d1 d2 -- flag ) D= ( xd1 xd2 -- flag ) D>S ( d -- n ) Ambigous conditions d lies outside the range of a signed single-cell number ignored (n undefined) DABS ( d -- ud ) DMAX ( d1 d2 -- d3 ) DMIN ( d1 d2 -- d3 ) DNEGATE ( d1 -- d2 ) M*/ ( d1 n1 +n2 -- d2 ) M+ ( d1|ud1 n -- d2|ud2 ) Double Number Extension Words --------------------------------- 2ROT ( x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2 ) DU< ( ud1 ud2 -- flag ) Exception Words ------------------- CATCH ( i*x xt -- j*x 0 | i*x n ) THROW ( k*x n -- k*x | i*x n ) Exception Extension Words ----------------------------- ABORT ( i*x -- ) ( R: j*x -- ) Performs the function of '-1 THROW'. ABORT" Compilation: ( "ccc<quote>" -- ) Run-time: ( i*x x1 -- | j*x ) ( R: j*x -- | j*x ) Performs the function of '-2 THROW', displaying ccc if there is no exception frame on the exception stack. Facility Words ------------------ AT-XY ( u1 u2 -- ) Ambigous conditions: The cursor position given by u1 and u2 is outside the range of u1=0..39, u2=0..15 The value will be increased or decreased appropriately to fit in that range. KEY? ( -- flag) PAGE ( -- ) Facility Extension Words ---------------------------- EKEY ( -- u ) EKEY>CHAR ( u -- u false | char true ) EKEY? ( -- flag ) MS ( u -- ) ****** Not yet implemented! But I'm going to do soon... ****** File Access Words --------------------- BIN ( fam1 -- fam2 ) CLOSE-FILE ( fileid -- ior ) CREATE-FILE ( c-addr u fam -- fileid ior ) DELETE-FILE ( c-addr u -- ior ) FILE-POSITION ( fileid -- ud ior ) FILE-SIZE ( fileid -- ud ior ) INCLUDE-FILE ( i*x fileid -- j*x ) INCLUDED ( i*x c-addr u -- j*x ) Ambigous conditions: the named file cannot be opened: exception #-37 OPEN-FILE ( c-addr u fam -- fileid ior ) R/O ( -- fam ) R/W ( -- fam ) READ-FILE ( c-addr u1 fileid -- u2 ior ) Ambigous conditions: the requested operation attempts to read portions of the file not yet written Ignored, but the read data are undefined. READ-LINE ( c-addr u1 fileid -- u2 flag ior ) REPOSITION-FILE ( ud1 fileid -- ior ) Ambigous conditions: the file is positioned outside its boundaries Nothing is done and ior is -36. RESIZE-FILE ( ud1 fileid -- ior ) W/O ( -- fam ) WRITE-FILE ( c-addr u fileid -- ior ) WRITE-LINE ( c-addr u fileid -- ior ) File Access Extension Words ------------------------------- RENAME-FILE ( c-addr1 u1 c-addr2 u2 -- ior ) Floating-Point Words ------------------------ >FLOAT ( c-addr u -- true | false ) ( F: -- r | ) D>F ( d -- ) ( F: -- r ) F! ( f-addr -- ) ( F: r -- ) Ambigous conditions: 'c-addr' is not float aligned: exception #-23 F* ( F: r1 r2 -- r3 ) F+ ( F: r1 r2 -- r3 ) F- ( F: r1 r2 -- r3 ) F/ ( F: r1 r2 -- r3 ) Ambigous conditions: 'r2' is zero: return-value 'r3' will be zero F0< ( -- flag ) ( F: r -- ) F0= ( -- flag ) ( F: r -- ) F< ( -- flag ) ( F: r1 r2 -- ) F>D ( -- d ) ( F: r -- ) Ambigous conditions: 'r' cannot be represented as a double-cell signed integer In this case 'd' is zero. F@ ( f-addr -- ) (F: -- r ) Ambigous conditions: 'c-addr' is not float-algined: exception #-23 FALIGN ( -- ) FALGINED ( addr -- f-addr ) FCONSTANT ( "<spaces>name -- ) ( F: r -- ) name Execution: ( -- ) ( F: -- r ) FDEPTH ( -- +n ) FDROP ( F: r -- ) FDUP ( F: r -- r r ) FLITERAL Compilation: ( F: r -- ) Run-time: ( F: -- r ) FLOAT+ ( f-addr1 -- f-addr2 ) FLOATS ( n1 -- n2 ) FLOOR ( F: r1 -- r2 ) FMAX ( F: r1 r2 -- r3 ) FMIN ( F: r1 r2 -- r3 ) FNEGATE ( F: r1 -- r2 ) FOVER ( F: r1 r2 -- r1 r2 r1 ) FROT ( F: r1 r2 r3 -- r2 r3 r1 ) FROUND ( F: r1 -- r2 ) FSWAP ( F: r1 r2 -- r2 r1 ) FVARIABLE ( "<spaces>name" -- ) name Execution: ( -- f-addr ) REPRESENT ( c-addr u -- n flag1 flag2 ) ( F: r -- ) Floating-Point Extension Words ---------------------------------- F** ( F: r1 r2 -- r3 ) F. ( F: r -- ) FE. ( F: r -- ) FEXP ( F: r1 -- r2 ) FLN ( F: r1 -- r2 ) FLOG ( F: r1 -- r2 ) FS. ( F: r -- ) PRECISION ( -- u ) SET-PRECISION ( u -- ) Note: Precision is bounded to a value in the range 1...9. Programming Tools Words --------------------------- .S ( -- ) ? ( a-addr -- ) DUMP ( addr u -- ) WORDS ( -- ) Programming-Tools Extension Words ------------------------------------- ;CODE Compilation: ( C: colon-sys -- ) Run-time: ( R: nest-sys -- ) name Execution: ( i*x -- j*x ) Look 'CODE' for a further details on machine code. AHEAD Compilation: ( C: -- orig ) Run-time: ( -- ) BYE ( -- ) CODE Compilation: ( "<spaces>name" -- ) name Execution: ( i*x -- j*x ) 'CODE' creates the definition of a word containing machine code. Currently there is no assembler, so you'll have to use hex-code to define the word. The end of the definition is marked by 'END-CODE'. Note that your machine code may only modify registers a0-a1/d0-d2. All other registers must be restored, else your program will crash. Assembly Forth words do not end on 'rts', they are ended by a jump to the address interpreter. That routine is always pointed to by 'a4', so you should use a "jmp (a4)" instruction. Example: CODE SWITCH-OFF ( -- ) \ switches the calculator off, waits for [On] BASE @ 2 BASE ! \ remember number base, change to binary 0100111001000100 , \ TRAP #4 ( switches off ) 0100111011010100 , \ JMP (a4) ( go back to the address interpreter ) BASE ! \ restore previous number base END-CODE \ end of assembly definition CS-PICK ( destu ... orig0|dest0 u -- destu ... orig0|dest0 destu ) Ambigous conditions: There are less than u+1 dest/orig - items on the stack 'destu' will be undefined. CS-ROLL ( origu|destuu origu-1|destu-1 ... orig0|dest0 u -- origu-1|destu-1 ... orig0|dest0 origu|destu ) Ambigous conditions: There are less than u+1 dest/orig - items on the stack 'destu' will be undefined and Forth92 may crash. [ELSE] Compilatoin or execution: ( "<spaces>name" ... -- ) [IF] Compilation or execution: ( flag | flag "<spaces>name" ... -- ) [THEN] Compilation or execution: ( -- ) Search-Order Words ---------------------- DEFINITIONS ( -- ) FORTH-WORDLIST ( -- wid ) GET-CURRENT ( -- wid ) GET-ORDER ( -- widn ... wid1 n ) SEARCH-WORDLIST ( c-addr u wid -- 0 | xt 1 | xt -1 ) SET-ORDER ( widn ... wid1 n -- ) Ambigous conditions: Too many wordlists in search order: exception #-49 WORDLIST ( -- wid ) Search-Order Extension Words -------------------------------- ALSO ( -- ) FORTH ( -- ) ONLY ( -- ) ORDER ( -- ) PREVIOUS ( -- ) Ambigous conditions: Search order was empty before 'PREVIOUS' was executed: exception #-50 String Words ---------------- -TRAILING ( c-addr1 u1 -- c-addr2 u2 ) /STRING ( c-addr1 u1 n -- c-addr2 u2 ) BLANK ( c-addr u -- ) CMOVE ( c-addr1 c-addr2 u -- ) CMOVE> ( c-addr1 c-addr2 u -- ) COMPARE ( c-addr1 u1 c-addr2 u2 -- n ) SEARCH ( c-addr1 u1 c-addr2 u2 -- c-addr3 u3 flag ) SLITERAL Compilation: ( c-addr1 u -- ) Run-time: ( -- c-addr2 u ) Forth92 specific (non-standard) words ========================================= Memory Access ----------------- 1+! ( a-addr -- ) Increase the memory cell at 'a-addr' by one. Possible definition: : 1+! ( a-addr -- ) 1 SWAP +! ; 1-! ( a-addr -- ) Decrease the memory cell at 'a-addr' by one. Possible definition: : 1-! ( a-addr -- ) -1 SWAP +! ; TOGGLE ( c-addr char -- ) Perform a binary exclusive or of the value in 'c-addr' and 'char' and store the result back to 'c-addr'. This routine is quite useful for working with bitfields (This routine is one of FIG-FORTH's, and is used for handling the dictonary word headers). Possible definition: : TOGGLE ( c-addr char -- ) OVER C@ XOR SWAP C! ; R>A ( addr -- far-addr ) Convert the (relative) Forth92, single-cell address 'addr' to a 32bit (double-cell) TI-92 native address. A>R ( far-addr -- addr ) Convert the 32bit (double-cell) TI-92 native address 'abs-addr' to a Forth92, single-cell address 'addr'. A! ( x far-addr -- ) CA! ( char far-addr -- ) 2A! ( x x far-addr -- ) Store a single-cell/character/double-cell value into the 32bit address 'abs-addr'. Example: : SET-TIMER-SPEED ( u -- ) \ set the programmable rate generator's speed [ HEX ] 600017. CA! ; \ store u at 600017h (set timer's initial value) A@ ( far-addr -- x ) CA@ ( far-addr -- char ) 2A@ ( far-addr -- x x ) Read a single-cell/character/double-cell value from a 32bit address 'abs-addr'. Example: : ON-KEY? ( -- flag ) \ read [On]-Key status even if ints. are disabled [ HEX ] 60001A. CA@ \ bit1 in 60001Ah is inverted [On]-key status 2 AND 0= ; \ extract and invert bit1 DEREF ( u -- far-addr ) Return the 32bit native address of the handle 'u'. This is exactly the same as the well-known ASM macro 'tios::DEREF'. Example: : GRAPH-SCREEN ( -- far-addr ) \ get address of Graph screen bitmap 13 DEREF ; Graphic Words ----------------- +GRAPHIC ( -- ) Enable graphics mode (4 greyshades). The cursor will be disabled and any text-output via 'EMIT', 'TYPE' etc. will be dark-grey. If graphic mode is already enabled, does nothing. -GRAPHIC ( -- ) Disable graphics mode. Darkgrey or black pixels on the screen will turn black, all other pixels willb become white. Cursor is enabled. PIXEL! ( color x y -- ) Set the pixel at (x|y) to the color 'color'. Only the two least-significant bits of 'color' are important. Color 0 is white, 1 is light-grey, 2 is dark-grey and 3 is black. 'x' should be in the range 0...239, 'y' should be 0...127. If x or y are out of range, the pixel is not drawn (clipped). PIXEL@ ( x y -- color ) Return the color of the pixel at (x|y). If (x|y) are out of the screen, 'color' is -1. Example: : INVERT-SCREEN ( -- ) \ invert the screen 128 0 DO 240 0 DO I J PIXEL@ INVERT I J PIXEL! LOOP LOOP ; : FILL-SCREEN ( u -- ) Fill screen with color 'u'. : BLANK-SCREEN ( -- ) Clear screen to color white. Faster than '0 FILL-SCREEN'. Textmode Words ------------------ INV ( -- ) Toggle text output inverting. The first call will switch font output to white on black, the second call will switch back to black on white, and so on. Example: : TYPE-WARNING ( c-addr u -- ) INV ." Warning: " INV TYPE ; UL ( -- ) Toggle underlining. The first call switches underlining on, the second off, and so on. Example: : TYPE-WARNING ( c-addr u -- ) UL ." Warning: " UL TYPE ; BOLD ( -- ) Toggle bold text output. The first call switches bold on, the secon off, and son on. WHERE-XY ( -- u1 u2 ) Return the current cursor position. (Opposite of 'AT-XY') Example: : LINE-START ( -- ) \ go to begin of line WHERE-XY ( S: x y ) NIP 0 SWAP ( S: 0 y ) AT-XY ; SCROLL/ ( -- ) SCROLL\ ( -- ) SCROLL> ( -- ) SCROLL< ( -- ) Scroll the text screen up/down/right/left by one character. -CURSOR ( -- ) Hide the textmode cursor. If '-CURSOR' is executed more than one times, '+CURSOR' has to be executed equally times, until the cursor is visible again. +CURSOR ( -- ) Show the textmode cursor, after it had been hidden by '-CURSOR'. If '-CURSOR' has been called more than one times, show the cursor only if '+CURSOR' has been called the same number of times as '-CURSOR'. CURSOR-HEIGHT ( u -- ) Set the cursor's height (default: 2). If 'u' is not in the range 1...8, it will be adjusted to fall into that range. Example: : OVERWRITE-MODE ( -- ) \ switch overwrite mode on 1 TO EDIT-MODE 8 CURSOR-HEIGHT ; Other Words --------------- COLD ( i*x -- ) ( R: j*x -- ) ( F: k*x -- ) Cold system reboot. Clear the dictionary, set BASE and searchorder to defaults, clear the stacks, set input-source to terminal input. 2+ ( n1|u1 -- n2|u2 ) 2- ( n1|u1 -- n2|u2 ) Similar to '1+' and '1-': Increase/decrease the value 'n1|u1' by two. VOCABULARY Execution: ( "name<space>" -- ) Create a new wordlist and a new definition named 'name'. If that new definition is invoked, replace the first wordlist in the search order by the wordlist which was created together with 'name'. Definition: : VOCABULARY ( "name<space>" -- ) CREATE WORDLIST , DOES> @ >R GET-ORDER NIP R> SWAP SET-ORDER ; F, ( F: r -- ) Analog word to ',' or 'C,', but works with floating point numbers. Definition: : F, ( F: r -- ) HERE 1 FLOATS ALLOT F! ; C/L ( -- 64 ) Return the number of characters per line used by block display 'LIST'.
Source: README.txt, updated 2012-11-25