| \ ***************************************************************************** |
| \ * Copyright (c) 2004, 2008 IBM Corporation |
| \ * All rights reserved. |
| \ * This program and the accompanying materials |
| \ * are made available under the terms of the BSD License |
| \ * which accompanies this distribution, and is available at |
| \ * http://www.opensource.org/licenses/bsd-license.php |
| \ * |
| \ * Contributors: |
| \ * IBM Corporation - initial implementation |
| \ ****************************************************************************/ |
| |
| \ Hash for faster lookup |
| #include <find-hash.fs> |
| |
| : >name ( xt -- nfa ) \ note: still has the "immediate" field! |
| BEGIN char- dup c@ UNTIL ( @lastchar ) |
| dup dup aligned - cell+ char- ( @lastchar lenmodcell ) |
| dup >r - |
| BEGIN dup c@ r@ <> WHILE |
| cell- r> cell+ >r |
| REPEAT |
| r> drop char- |
| ; |
| |
| \ Words missing in *.in files |
| VARIABLE mask -1 mask ! |
| |
| VARIABLE huge-tftp-load 1 huge-tftp-load ! |
| \ Default implementation for sms-get-tftp-blocksize that return 1432 (decimal) |
| : sms-get-tftp-blocksize 598 ; |
| |
| : default-hw-exception s" Exception #" type . ; |
| |
| ' default-hw-exception to hw-exception-handler |
| |
| : diagnostic-mode? false ; \ 2B DOTICK'D later in envvar.fs |
| |
| : memory-test-suite ( addr len -- fail? ) |
| diagnostic-mode? IF |
| ." Memory test mask value: " mask @ . cr |
| ." No memory test suite currently implemented! " cr |
| THEN |
| false |
| ; |
| |
| : 0.r 0 swap <# 0 ?DO # LOOP #> type ; |
| |
| \ count the number of bits equal 1 |
| \ the idea is to clear in each step the least significant bit |
| \ v&(v-1) does exactly this, so count the steps until v == 0 |
| : cnt-bits ( 64-bit-value -- #bits=1 ) |
| dup IF |
| 41 1 DO dup 1- and dup 0= IF drop i LEAVE THEN LOOP |
| THEN |
| ; |
| |
| : bcd-to-bin ( bcd -- bin ) |
| dup f and swap 4 rshift a * + |
| ; |
| |
| \ calcs the exponent of the highest power of 2 not greater than n |
| : 2log ( n -- lb{n} ) |
| 8 cells 0 DO 1 rshift dup 0= IF drop i LEAVE THEN LOOP |
| ; |
| |
| \ calcs the exponent of the lowest power of 2 not less than n |
| : log2 ( n -- log2-n ) |
| 1- 2log 1+ |
| ; |
| |
| |
| CREATE $catpad 100 allot |
| : $cat ( str1 len1 str2 len2 -- str3 len3 ) |
| >r >r dup >r $catpad swap move |
| r> dup $catpad + r> swap r@ move |
| r> + $catpad swap ; |
| |
| \ WARNING: The following two ($cat-comm & $cat-space) are dirty in a sense |
| \ that they add 1 or 2 characters to str1 before executing $cat |
| \ The ASSUMPTION is that str1 buffer provides that extra space and it is |
| \ responsibility of the code owner to ensure that |
| : $cat-comma ( str2 len2 str1 len1 -- "str1, str2" len1+len2+2 ) |
| 2dup + s" , " rot swap move 2+ 2swap $cat |
| ; |
| |
| : $cat-space ( str2 len2 str1 len1 -- "str1 str2" len1+len2+1 ) |
| 2dup + bl swap c! 1+ 2swap $cat |
| ; |
| : $cathex ( str len val -- str len' ) |
| (u.) $cat |
| ; |
| |
| |
| : 2CONSTANT CREATE , , DOES> [ here ] 2@ ; |
| |
| \ Save XT of 2CONSTANT, put on the stack by "[ here ]" : |
| CONSTANT <2constant> |
| |
| : $2CONSTANT $CREATE , , DOES> 2@ ; |
| |
| : 2VARIABLE CREATE 0 , 0 , DOES> ; |
| |
| |
| : (is-user-word) ( name-str name-len xt -- ) -rot $CREATE , DOES> @ execute ; |
| |
| : zplace ( str len buf -- ) 2dup + 0 swap c! swap move ; |
| : rzplace ( str len buf -- ) 2dup + 0 swap rb! swap rmove ; |
| |
| : strdup ( str len -- dupstr len ) here over allot swap 2dup 2>r move 2r> ; |
| |
| : str= ( str1 len1 str2 len2 -- equal? ) |
| rot over <> IF 3drop false ELSE comp 0= THEN ; |
| |
| : test-string ( param len -- true | false ) |
| 0 ?DO |
| dup i + c@ \ Get character / byte at current index |
| dup 20 < swap 7e > OR IF \ Is it out of range 32 to 126 (=ASCII) |
| drop FALSE UNLOOP EXIT \ FALSE means: No ASCII string |
| THEN |
| LOOP |
| drop TRUE \ Only ASCII found --> it is a string |
| ; |
| |
| : #aligned ( adr alignment -- adr' ) negate swap negate and negate ; |
| : #join ( lo hi #bits -- x ) lshift or ; |
| : #split ( x #bits -- lo hi ) 2dup rshift dup >r swap lshift xor r> ; |
| |
| : /string ( str len u -- str' len' ) |
| >r swap r@ chars + swap r> - ; |
| : skip ( str len c -- str' len' ) |
| >r BEGIN dup WHILE over c@ r@ = WHILE 1 /string REPEAT THEN r> drop ; |
| : scan ( str len c -- str' len' ) |
| >r BEGIN dup WHILE over c@ r@ <> WHILE 1 /string REPEAT THEN r> drop ; |
| : split ( str len char -- left len right len ) |
| >r 2dup r> findchar IF >r over r@ 2swap r> 1+ /string ELSE 0 0 THEN ; |
| \ reverse findchar -- search from the end of the string |
| : rfindchar ( str len char -- offs true | false ) |
| swap 1 - 0 swap do |
| over i + c@ |
| over dup bl = if <= else = then if |
| 2drop i dup dup leave |
| then |
| -1 +loop = |
| ; |
| \ reverse split -- split at the last occurence of char |
| : rsplit ( str len char -- left len right len ) |
| >r 2dup r> rfindchar IF >r over r@ 2swap r> 1+ /string ELSE 0 0 THEN ; |
| |
| : left-parse-string ( str len char -- R-str R-len L-str L-len ) |
| split 2swap ; |
| : replace-char ( str len chout chin -- ) |
| >r -rot BEGIN 2dup 4 pick findchar WHILE tuck - -rot + r@ over c! swap REPEAT |
| r> 2drop 2drop |
| ; |
| \ Duplicate string and replace \ with / |
| : \-to-/ ( str len -- str' len ) strdup 2dup [char] \ [char] / replace-char ; |
| |
| : isdigit ( char -- true | false ) |
| 30 39 between |
| ; |
| |
| : // dup >r 1- + r> / ; \ division, round up |
| |
| : c@+ ( adr -- c adr' ) dup c@ swap char+ ; |
| : 2c@ ( adr -- c1 c2 ) c@+ c@ ; |
| : 4c@ ( adr -- c1 c2 c3 c4 ) c@+ c@+ c@+ c@ ; |
| : 8c@ ( adr -- c1 c2 c3 c4 c5 c6 c7 c8 ) c@+ c@+ c@+ c@+ c@+ c@+ c@+ c@ ; |
| |
| |
| : 4dup ( n1 n2 n3 n4 -- n1 n2 n3 n4 n1 n2 n3 n4 ) 2over 2over ; |
| : 4drop ( n1 n2 n3 n4 -- ) 2drop 2drop ; |
| |
| \ yes sometimes even something like this is needed |
| : 6dup ( 1 2 3 4 5 6 -- 1 2 3 4 5 6 1 2 3 4 5 6 ) |
| 5 pick 5 pick 5 pick 5 pick 5 pick 5 pick |
| ; |
| |
| \ convert a 32 bit signed into a 64 signed |
| \ ( propagate bit 31 to all bits 32:63 ) |
| : signed ( n1 -- n2 ) dup 80000000 and IF FFFFFFFF00000000 or THEN ; |
| |
| : <l@ ( addr -- x ) l@ signed ; |
| |
| : -leading BEGIN dup WHILE over c@ bl <= WHILE 1 /string REPEAT THEN ; |
| : (parse-line) skipws 0 parse ; |
| |
| |
| \ Append two character to hex byte, if possible |
| |
| : hex-byte ( char0 char1 -- value true|false ) |
| 10 digit IF |
| swap 10 digit IF |
| 4 lshift or true EXIT |
| ELSE |
| 2drop 0 |
| THEN |
| ELSE |
| drop |
| THEN |
| false EXIT |
| ; |
| |
| \ Parse hex string within brackets |
| |
| : parse-hexstring ( dst-adr -- dst-adr' ) |
| [char] ) parse cr ( dst-adr str len ) |
| bounds ?DO ( dst-adr ) |
| i c@ i 1+ c@ hex-byte IF ( dst-adr hex-byte ) |
| >r dup r> swap c! 1+ 2 ( dst-adr+1 2 ) |
| ELSE |
| drop 1 ( dst-adr 1 ) |
| THEN |
| +LOOP |
| ; |
| |
| \ Add special character to string |
| |
| : add-specialchar ( dst-adr special -- dst-adr' ) |
| over c! 1+ ( dst-adr' ) |
| 1 >in +! \ advance input-index |
| ; |
| |
| \ Parse upto next " |
| |
| : parse-" ( dst-adr -- dst-adr' ) |
| [char] " parse dup 3 pick + >r ( dst-adr str len R: dst-adr' ) |
| >r swap r> move r> ( dst-adr' ) |
| ; |
| |
| : (") ( dst-adr -- dst-adr' ) |
| begin ( dst-adr ) |
| parse-" ( dst-adr' ) |
| >in @ dup span @ >= IF ( dst-adr' >in-@ ) |
| drop |
| EXIT |
| THEN |
| |
| ib + c@ |
| CASE |
| [char] ( OF parse-hexstring ENDOF |
| [char] " OF [char] " add-specialchar ENDOF |
| dup OF EXIT ENDOF |
| ENDCASE |
| again |
| ; |
| |
| CREATE "pad 100 allot |
| |
| \ String with embedded hex strings |
| \ Example: " ba"( 12 34,4567)ab" -> >x62x61x12x34x45x67x61x62< |
| |
| : " ( [text<">< >] -- text-str text-len ) |
| state @ IF \ compile sliteral, pstr into dict |
| "pad dup (") over - ( str len ) |
| ['] sliteral compile, dup c, ( str len ) |
| bounds ?DO i c@ c, LOOP |
| align ['] count compile, |
| ELSE |
| pocket dup (") over - \ Interpretation, put string |
| THEN \ in temp buffer |
| ; immediate |
| |
| |
| \ Output the carriage-return character |
| : (cr carret emit ; |
| |
| |
| \ Remove command old-name and all subsequent definitions |
| |
| : $forget ( str len -- ) |
| 2dup last @ ( str len str len last-bc ) |
| BEGIN |
| dup >r ( str len str len last-bc R: last-bc ) |
| cell+ char+ count ( str len str len found-str found-len R: last-bc ) |
| string=ci IF ( str len R: last-bc ) |
| r> @ last ! 2drop clean-hash EXIT ( -- ) |
| THEN |
| 2dup r> @ dup 0= ( str len str len next-bc next-bc ) |
| UNTIL |
| drop 2drop 2drop \ clean hash table |
| ; |
| |
| : forget ( "old-name<>" -- ) |
| parse-word $forget |
| ; |
| |
| #include <search.fs> |
| |
| \ The following constants are required in some parts |
| \ of the code, mainly instance variables and see. Having to reverse |
| \ engineer our own CFAs seems somewhat weird, but we gained a bit speed. |
| |
| \ Each colon definition is surrounded by colon and semicolon |
| \ constant below contain address of their xt |
| |
| : (function) ; |
| defer (defer) |
| 0 value (value) |
| 0 constant (constant) |
| variable (variable) |
| create (create) |
| alias (alias) (function) |
| cell buffer: (buffer:) |
| |
| ' (function) @ \ ( <colon> ) |
| ' (function) cell + @ \ ( ... <semicolon> ) |
| ' (defer) @ \ ( ... <defer> ) |
| ' (value) @ \ ( ... <value> ) |
| ' (constant) @ \ ( ... <constant> ) |
| ' (variable) @ \ ( ... <variable> ) |
| ' (create) @ \ ( ... <create> ) |
| ' (alias) @ \ ( ... <alias> ) |
| ' (buffer:) @ \ ( ... <buffer:> ) |
| |
| \ now clean up the test functions |
| forget (function) |
| |
| \ and remember the constants |
| constant <buffer:> |
| constant <alias> |
| constant <create> |
| constant <variable> |
| constant <constant> |
| constant <value> |
| constant <defer> |
| constant <semicolon> |
| constant <colon> |
| |
| ' lit constant <lit> |
| ' sliteral constant <sliteral> |
| ' 0branch constant <0branch> |
| ' branch constant <branch> |
| ' doloop constant <doloop> |
| ' dotick constant <dotick> |
| ' doto constant <doto> |
| ' do?do constant <do?do> |
| ' do+loop constant <do+loop> |
| ' do constant <do> |
| ' exit constant <exit> |
| ' doleave constant <doleave> |
| ' do?leave constant <do?leave> |
| |
| |
| \ provide the memory management words |
| \ #include <claim.fs> |
| \ #include "memory.fs" |
| #include <alloc-mem.fs> |
| |
| #include <node.fs> |
| |
| : find-substr ( basestr-ptr basestr-len substr-ptr substr-len -- pos ) |
| \ if substr-len == 0 ? |
| dup 0 = IF |
| \ return 0 |
| 2drop 2drop 0 exit THEN |
| \ if substr-len <= basestr-len ? |
| dup 3 pick <= IF |
| \ run J from 0 to "basestr-len"-"substr-len" and I from 0 to "substr-len"-1 |
| 2 pick over - 1+ 0 DO dup 0 DO |
| \ substr-ptr[i] == basestr-ptr[j+i] ? |
| over i + c@ 4 pick j + i + c@ = IF |
| \ (I+1) == substr-len ? |
| dup i 1+ = IF |
| \ return J |
| 2drop 2drop j unloop unloop exit THEN |
| ELSE leave THEN |
| LOOP LOOP |
| THEN |
| \ if there is no match then exit with basestr-len as return value |
| 2drop nip |
| ; |
| |
| : find-isubstr ( basestr-ptr basestr-len substr-ptr substr-len -- pos ) |
| \ if substr-len == 0 ? |
| dup 0 = IF |
| \ return 0 |
| 2drop 2drop 0 exit THEN |
| \ if substr-len <= basestr-len ? |
| dup 3 pick <= IF |
| \ run J from 0 to "basestr-len"-"substr-len" and I from 0 to "substr-len"-1 |
| 2 pick over - 1+ 0 DO dup 0 DO |
| \ substr-ptr[i] == basestr-ptr[j+i] ? |
| over i + c@ lcc 4 pick j + i + c@ lcc = IF |
| \ (I+1) == substr-len ? |
| dup i 1+ = IF |
| \ return J |
| 2drop 2drop j unloop unloop exit THEN |
| ELSE leave THEN |
| LOOP LOOP |
| THEN |
| \ if there is no match then exit with basestr-len as return value |
| 2drop nip |
| ; |
| |
| : find-nextline ( str-ptr str-len -- pos ) |
| \ run I from 0 to "str-len"-1 and check str-ptr[i] |
| dup 0 ?DO over i + c@ CASE |
| \ 0x0a (=LF) found ? |
| 0a OF |
| \ if current cursor is at end position (I == "str-len"-1) ? |
| dup 1- i = IF |
| \ return I+1 |
| 2drop i 1+ unloop exit THEN |
| \ if str-ptr[I+1] == 0x0d (=CR) ? |
| over i 1+ + c@ 0d = IF |
| \ return I+2 |
| 2drop i 2+ ELSE |
| \ else return I+1 |
| 2drop i 1+ THEN |
| unloop exit |
| ENDOF |
| \ 0x0d (=CR) found ? |
| 0d OF |
| \ if current cursor is at end position (I == "str-len"-1) ? |
| dup 1- i = IF |
| \ return I+1 |
| 2drop i 1+ unloop exit THEN |
| \ str-ptr[I+1] == 0x0a (=LF) ? |
| over i 1+ + c@ 0a = IF |
| \ return I+2 |
| 2drop i 2+ ELSE |
| \ return I+1 |
| 2drop i 1+ THEN |
| unloop exit |
| ENDOF |
| ENDCASE LOOP nip |
| ; |
| |
| : string-at ( str1-ptr str1-len pos -- str2-ptr str2-len ) |
| -rot 2 pick - -rot swap chars + swap |
| ; |
| |
| \ appends the string beginning at addr2 to the end of the string |
| \ beginning at addr1 |
| \ !!! THERE MUST BE SUFFICIENT MEMORY RESERVED FOR THE STRING !!! |
| \ !!! BEGINNING AT ADDR1 (cp. 'strcat' in 'C' ) !!! |
| |
| : string-cat ( addr1 len1 addr2 len2 -- addr1 len1+len2 ) |
| \ len1 := len1+len2 |
| rot dup >r over + -rot |
| ( addr1 len1+len2 dest-ptr src-ptr len2 ) |
| 3 pick r> chars + -rot |
| ( ... dest-ptr src-ptr ) |
| 0 ?DO |
| 2dup c@ swap c! |
| char+ swap char+ swap |
| LOOP 2drop |
| ; |
| |
| \ appends a character to the end of the string beginning at addr |
| \ !!! THERE MUST BE SUFFICIENT MEMORY RESERVED FOR THE STRING !!! |
| \ !!! BEGINNING AT ADDR1 (cp. 'strcat' in 'C' ) !!! |
| |
| : char-cat ( addr len character -- addr len+1 ) |
| -rot 2dup >r >r 1+ rot r> r> chars + c! |
| ; |
| |
| \ Returns true if source and destination overlap |
| : overlap ( src dest size -- true|false ) |
| 3dup over + within IF 3drop true ELSE rot tuck + within THEN |
| ; |
| |
| : parse-2int ( str len -- val.lo val.hi ) |
| \ ." parse-2int ( " 2dup swap . . ." -- " |
| [char] , split ?dup IF eval ELSE drop 0 THEN |
| -rot ?dup IF eval ELSE drop 0 THEN |
| \ 2dup swap . . ." )" cr |
| ; |
| |
| \ peek/poke minimal implementation, just to support FCode drivers |
| \ Any implmentation with full error detection will be platform specific |
| : cpeek ( addr -- false | byte true ) c@ true ; |
| : cpoke ( byte addr -- success? ) c! true ; |
| : wpeek ( addr -- false | word true ) w@ true ; |
| : wpoke ( word addr -- success? ) w! true ; |
| : lpeek ( addr -- false | lword true ) l@ true ; |
| : lpoke ( lword addr -- success? ) l! true ; |
| |
| defer reboot ( -- ) |
| defer halt ( -- ) |
| defer disable-watchdog ( -- ) |
| defer reset-watchdog ( -- ) |
| defer set-watchdog ( +n -- ) |
| defer set-led ( type instance state -- status ) |
| defer get-flashside ( -- side ) |
| defer set-flashside ( side -- status ) |
| defer read-bootlist ( -- ) |
| defer furnish-boot-file ( -- adr len ) |
| defer set-boot-file ( adr len -- ) |
| defer mfg-mode? ( -- flag ) |
| defer of-prompt? ( -- flag ) |
| defer debug-boot? ( -- flag ) |
| defer bmc-version ( -- adr len ) |
| defer cursor-on ( -- ) |
| defer cursor-off ( -- ) |
| |
| : nop-reboot ( -- ) ." reboot not available" abort ; |
| : nop-halt ( -- ) ." halt not available" abort ; |
| : nop-disable-watchdog ( -- ) ; |
| : nop-reset-watchdog ( -- ) ; |
| : nop-set-watchdog ( +n -- ) drop ; |
| : nop-set-led ( type instance state -- status ) drop drop drop ; |
| : nop-get-flashside ( -- side ) ." Cannot get flashside" cr ABORT ; |
| : nop-set-flashside ( side -- status ) ." Cannot set flashside" cr ABORT ; |
| : nop-read-bootlist ( -- ) ; |
| : nop-furnish-bootfile ( -- adr len ) s" net:" ; |
| : nop-set-boot-file ( adr len -- ) 2drop ; |
| : nop-mfg-mode? ( -- flag ) false ; |
| : nop-of-prompt? ( -- flag ) false ; |
| : nop-debug-boot? ( -- flag ) false ; |
| : nop-bmc-version ( -- adr len ) s" XXXXX" ; |
| : nop-cursor-on ( -- ) ; |
| : nop-cursor-off ( -- ) ; |
| |
| ' nop-reboot to reboot |
| ' nop-halt to halt |
| ' nop-disable-watchdog to disable-watchdog |
| ' nop-reset-watchdog to reset-watchdog |
| ' nop-set-watchdog to set-watchdog |
| ' nop-set-led to set-led |
| ' nop-get-flashside to get-flashside |
| ' nop-set-flashside to set-flashside |
| ' nop-read-bootlist to read-bootlist |
| ' nop-furnish-bootfile to furnish-boot-file |
| ' nop-set-boot-file to set-boot-file |
| ' nop-mfg-mode? to mfg-mode? |
| ' nop-of-prompt? to of-prompt? |
| ' nop-debug-boot? to debug-boot? |
| ' nop-bmc-version to bmc-version |
| ' nop-cursor-on to cursor-on |
| ' nop-cursor-off to cursor-off |
| |
| : reset-all reboot ; |
| |
| \ Load base |
| 10000000 value load-base |
| 2000000 value flash-load-base |
| |
| \ provide first level debug support |
| #include "debug.fs" |
| \ provide 7.5.3.1 Dictionary search |
| #include "dictionary.fs" |
| \ block data access for IO devices - ought to be implemented in engine |
| #include "rmove.fs" |
| \ provide a simple run time preprocessor |
| #include <preprocessor.fs> |
| |
| : $dnumber base @ >r decimal $number r> base ! ; |
| : (.d) base @ >r decimal (.) r> base ! ; |
| |
| \ IP address conversion |
| |
| : (ipaddr) ( "a.b.c.d" -- FALSE | n1 n2 n3 n4 TRUE ) |
| base @ >r decimal |
| over s" 000.000.000.000" comp 0= IF 2drop false r> base ! EXIT THEN |
| [char] . left-parse-string $number IF 2drop false r> base ! EXIT THEN -rot |
| [char] . left-parse-string $number IF 2drop false r> base ! EXIT THEN -rot |
| [char] . left-parse-string $number IF 2drop false r> base ! EXIT THEN -rot |
| $number IF false r> base ! EXIT THEN |
| true r> base ! |
| ; |
| |
| : (ipformat) ( n1 n2 n3 n4 -- str len ) |
| base @ >r decimal |
| 0 <# # # # [char] . hold drop # # # [char] . hold |
| drop # # # [char] . hold drop # # #s #> |
| r> base ! |
| ; |
| |
| : ipformat ( n1 n2 n3 n4 -- ) (ipformat) type ; |
| |
| |