blob: da990f3af8065521e320ab36bce795ba1ffe3ba3 [file] [log] [blame]
\ *****************************************************************************
\ * 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 ;