1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
|
\ *****************************************************************************
\ * 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 occurrence 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 up to 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 ;
|