OpenCores
URL https://opencores.org/ocsvn/forth-cpu/forth-cpu/trunk

Subversion Repositories forth-cpu

[/] [forth-cpu/] [trunk/] [embed.fth] - Blame information for rev 5

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 5 howe.r.j.8
system +order 0  !
2
 
3
.( FORTH META COMPILATION START ) cr
4
 
5
\ ============================================================================
6
\ # The Meta-Compiler
7
\
8
only forth definitions hex
9
system +order 0  !
10
variable meta          ( Metacompilation vocabulary )
11
meta +order definitions
12
variable assembler.1         ( Target assembler vocabulary )
13
variable target.1            ( Target dictionary )
14
variable tcp                 ( Target dictionary pointer )
15
variable tlast               ( Last defined word in target )
16
variable tdoVar              ( Location of doVar in target )
17
variable tdoConst            ( Location of doConst in target )
18
variable tdoNext             ( Location of doNext in target )
19
variable tdoPrintString      ( Location of .string in target )
20
variable tdoStringLit        ( Location of string-literal in target )
21
variable fence               ( Do not peephole optimize before this point )
22
5000 constant #target        ( Location where target image will be built )
23
2    constant =cell          ( Target cell size )
24
$3A00 constant pad-area      ( area for pad storage )
25
( 1   constant verbose ( verbosity level, higher is more verbose )
26
#target 2000 0 fill    ( Erase the target memory location )
27
: ]asm assembler.1 +order ; immediate    ( -- )
28
: a: current @ assembler.1 current ! : ; ( "name" -- wid link )
29
: a; [compile] ; current ! ; immediate   ( wid link -- )
30
: ( [char] ) parse 2drop ; immediate ( "comment" -- discard until parenthesis )
31
: \ source drop @ >in ! ; immediate  ( "comment" -- discard until end of line )
32
: there tcp @ ;                      ( -- a : target dictionary pointer value )
33
: tc! #target + c! ;                 ( u a -- : store character in target )
34
: tc@ #target + c@ ;                 ( a -- u : retrieve character in target )
35
: [last] tlast @ ;                   ( -- a : last defined word in target )
36
: t! over $FF and over tc! swap 8 rshift swap 1+ tc! ; ( u a -- )
37
: t@ dup tc@ swap 1+ tc@ 8 lshift or ; ( a -- u )
38
: 2/ 1 rshift ;                ( u -- u : non-standard definition divide by 2 )
39
\ : 2* 1 lshift ;                ( u -- u : multiple by two, non-standard )
40
: talign there 1 and tcp +! ;  ( -- : align target dictionary pointer value )
41
: tc, there tc! 1 tcp +! ;     ( c -- : write byte into target dictionary )
42
: t,  there t!  =cell tcp +! ; ( u -- : write cell into target dictionary )
43
\ : tallot tcp +! ;            ( n -- : allocate memory in target dictionary )
44
: update-fence there fence ! ; ( -- : update optimizer fence location )
45
: $literal                     ( , -- )
46
  [char] " word count dup tc, 1- for count tc, next drop talign update-fence ;
47
: tcells =cell * ;             ( u -- a )
48
: tbody 1 tcells + ;           ( a -- a )
49
: tcfa cfa ;                   ( PWD -- CFA )
50
: tnfa nfa ;                   ( PWD -- NFA )
51
: meta! ! ;                    ( u a --  )
52
: checksum #target there crc ; ( -- u : calculate CRC of target image )
53
: finished ( -- : save target image and display statistics )
54
   hex
55
  ." COMPLETE" cr
56
  ." HOST:   " here  . cr
57
  ." TARGET: " there . cr
58
   only forth definitions hex
59
   ." SAVING..."  #target #target there + (save) throw ." DONE" cr
60
   ." STACK>" .s cr ;
61
: [a] ( "name" -- : find word and compile an assembler word )
62
  bl word assembler.1 search-wordlist 0= abort" [a]? "
63
  cfa compile, ; immediate
64
: asm[ assembler.1 -order ; immediate ( -- )
65
a: #literal $8000 a; ( literal instruction - top bit set )
66
a: #alu     $6000 a; ( ALU instruction, further encoding below... )
67
a: #call    $4000 a; ( function call instruction )
68
a: #?branch $2000 a; ( branch if zero instruction )
69
a: #branch  $0000 a; ( unconditional branch )
70
 
71
a: #t      $0000 a; ( T = t )
72
a: #n      $0100 a; ( T = n )
73
a: #t+n    $0200 a; ( T = t+n )
74
a: #t&n    $0300 a; ( T = t&n )
75
a: #t|n    $0400 a; ( T = t|n )
76
a: #t^n    $0500 a; ( T = t^n )
77
a: #~t     $0600 a; ( T = ~t )
78
a: #t==n   $0700 a; ( T = n == t? )
79
a: #n
80
a: #n>>t   $0900 a; ( T = n right shift by t places )
81
a: #t-1    $0A00 a; ( T == t - 1 )
82
a: #r      $0B00 a; ( T = Top of Return Stack )
83
a: #[t]    $0C00 a; ( T = memory[t] )
84
a: #n<
85
a: #sp@    $0E00 a; ( T = depth )
86
a: #nu
87
a: #cpu!   $1000 a; ( T = set interrupts )
88
a: #cpu?   $1100 a; ( T = interrupts set? )
89
a: #rp@    $1200 a; ( T = r-depth )
90
a: #t==0   $1300 a; ( T = t == 0? )
91
a: #cpu-id $1400 a; ( T = CPU ID )
92
\ a: #alu-lit $1500 a; ( T = instruction, hidden )
93
 
94
a: d+1     $0001 or a; ( increment variable stack by one )
95
a: d-1     $0003 or a; ( decrement variable stack by one )
96
a: d-2     $0002 or a; ( decrement variable stack by two, not used )
97
a: r+1     $0004 or a; ( increment variable stack by one )
98
a: r-1     $000C or a; ( decrement variable stack by one )
99
a: r-2     $0008 or a; ( decrement variable stack by two, not used )
100
a: r->pc   $0010 or a; ( Set Program Counter to Top of Return Stack )
101
a: n->[t]  $0020 or a; ( Set Next on Variable Stack to Top on Variable Stack )
102
a: t->r    $0040 or a; ( Set Top of Return Stack to Top on Variable Stack )
103
a: t->n    $0080 or a; ( Set Next on Variable Stack to Top on Variable Stack )
104
: ?set dup $E000 and abort" argument too large" ; ( u -- )
105
a: branch  2/ ?set [a] #branch  or t, a; ( a -- : an Unconditional branch )
106
a: ?branch 2/ ?set [a] #?branch or t, a; ( a -- : Conditional branch )
107
a: call    2/ ?set [a] #call    or t, a; ( a -- : Function call )
108
a: ALU        ?set [a] #alu     or    a; ( u -- : Make ALU instruction )
109
a: alu                    [a] ALU  t, a; ( u -- : ALU operation )
110
a: literal ( n -- : compile a number into target )
111
  dup [a] #literal and if   ( numbers above $7FFF take up two instructions )
112
    invert recurse  ( the number is inverted, and 'literal' is called again )
113
    [a] #~t [a] alu ( then an invert instruction is compiled into the target )
114
  else
115
    [a] #literal or t, ( numbers below $8000 are single instructions )
116
  then a;
117
a: return ( -- : Compile a return into the target )
118
   [a] #t [a] r->pc [a] r-1 [a] alu a;
119
: previous there =cell - ;                      ( -- a )
120
: lookback previous t@ ;                        ( -- u )
121
: call? lookback $E000 and [a] #call = ;        ( -- t )
122
: call>goto previous dup t@ $1FFF and swap t! ; ( -- )
123
: fence? fence @  previous u> ;                 ( -- t )
124
: safe? lookback $E000 and [a] #alu = lookback $001C and 0= and ; ( -- t )
125
: alu>return previous dup t@ [a] r->pc [a] r-1 swap t! ; ( -- )
126
: exit-optimize                                 ( -- )
127
  fence? if [a] return exit then
128
  call?  if call>goto  exit then
129
  safe?  if alu>return exit then
130
  [a] return ;
131
: exit, exit-optimize update-fence ;            ( -- )
132
: compile-only tlast @ tnfa t@ $20 or tlast @ tnfa t! ; ( -- )
133
: immediate    tlast @ tnfa t@ $40 or tlast @ tnfa t! ; ( -- )
134
: mcreate current @ >r target.1 current ! create r> current ! ;
135
: thead ( b u -- : compile word header into target dictionary )
136
  talign
137
  there [last] t, tlast !
138
  there #target + pack$ c@ 1+ aligned tcp +! talign ;
139
: lookahead ( -- b u : parse a word, but leave it in the input stream )
140
  >in @ >r bl parse r> >in ! ;
141
: literal [a] literal ;       ( u --  )
142
: [ ' literal    ! ; ( -- )
143
: ] ' (literal)  ! ; ( -- )
144
: h: ( -- : create a word with no name in the target dictionary )
145
 [compile] [
146
 $F00D mcreate there , update-fence does> @ [a] call ;
147
: t: ( "name", -- : creates a word in the target dictionary )
148
  lookahead thead h: ;
149
: ?unstructured $F00D xor if source type cr 1 abort" unstructured! " then ;
150
: fallthrough; [compile] ] ?unstructured ; ( u -- )
151
: t; fallthrough; exit, ; \ "[a] return" <- unoptimized version
152
: ;; t; ?unstructured ;
153
: fetch-xt @ dup 0= abort" (null) " ; ( a -- xt )
154
: tconstant ( "name", n --, Run Time: -- )
155
  >r
156
  lookahead
157
  thead
158
  there tdoConst fetch-xt [a] call r> t, >r
159
  mcreate r> ,
160
  does> @ tbody t@ [a] literal ;
161
: tvariable ( "name", n -- , Run Time: -- a )
162
  >r
163
  lookahead
164
  thead
165
  there tdoVar fetch-xt [a] call r> t, >r
166
  mcreate r> ,
167
  does> @ tbody [a] literal ;
168
: tlocation ( "name", n -- : Reserve space in target for a memory location )
169
  there swap t, mcreate , does> @ [a] literal ;
170
: [t] ( "name", -- a : get the address of a target word )
171
  bl word target.1 search-wordlist 0= abort" [t]?"
172
  cfa >body @ ;
173
: [f] ( "name", -- execute word in host Forth vocabulary )
174
  bl word forth-wordlist search-wordlist 0= abort" [f]?"
175
  cfa execute ;
176
: [v] [t] =cell + ; ( "name", -- a )
177
: xchange ( "name1", "name2", -- : exchange target vocabularies )
178
  [last] [t] t! [t] t@ tlast meta! ;
179
: begin  there update-fence ;                ( -- a )
180
: until  [a] ?branch ;                       ( a -- )
181
: if     there update-fence 0 [a] ?branch  ; ( -- a )
182
: skip   there update-fence 0 [a] branch ;   ( -- a )
183
: then   begin 2/ over t@ or swap t! ;       ( a -- )
184
: else   skip swap then ;                    ( a -- a )
185
: while  if swap ;                           ( a -- a a )
186
: repeat [a] branch then update-fence ;      ( a -- )
187
: again  [a] branch update-fence ;           ( a -- )
188
: aft    drop skip begin swap ;              ( a -- a )
189
: constant mcreate , does> @ literal ;       ( "name", a -- )
190
: [char] char literal ;                      ( "name" )
191
: postpone [t] [a] call ;                    ( "name", -- )
192
: next tdoNext fetch-xt [a] call t, update-fence ; ( a -- )
193
: exit exit, ;                               ( -- )
194
: ' [t] literal ;                            ( "name", -- )
195
: recurse tlast @ tcfa [a] call ;            ( -- )
196
: ." tdoPrintString fetch-xt [a] call $literal ; ( "string", -- )
197
: $" tdoStringLit   fetch-xt [a] call $literal ; ( "string", -- )
198
: nop      ]asm #t                             alu asm[ ;
199
: dup      ]asm #t      t->n               d+1 alu asm[ ;
200
: over     ]asm #n      t->n               d+1 alu asm[ ;
201
: invert   ]asm #~t                            alu asm[ ;
202
: +        ]asm #t+n                       d-1 alu asm[ ;
203
: swap     ]asm #n      t->n                   alu asm[ ;
204
: nip      ]asm #t                         d-1 alu asm[ ;
205
: drop     ]asm #n                         d-1 alu asm[ ;
206
: >r       ]asm #n             t->r    r+1 d-1 alu asm[ ;
207
: r>       ]asm #r      t->n           r-1 d+1 alu asm[ ;
208
: r@       ]asm #r      t->n               d+1 alu asm[ ;
209
: @        ]asm #[t]                           alu asm[ ;
210
: rshift   ]asm #n>>t                      d-1 alu asm[ ;
211
: lshift   ]asm #n<
212
: =        ]asm #t==n                      d-1 alu asm[ ;
213
: u<       ]asm #nu
214
: <        ]asm #n
215
: and      ]asm #t&n                       d-1 alu asm[ ;
216
: xor      ]asm #t^n                       d-1 alu asm[ ;
217
: or       ]asm #t|n                       d-1 alu asm[ ;
218
: sp@      ]asm #sp@    t->n               d+1 alu asm[ ;
219
: 1-       ]asm #t-1                           alu asm[ ;
220
: rp@      ]asm #rp@    t->n               d+1 alu asm[ ;
221
: 0=       ]asm #t==0                          alu asm[ ;
222
: rdrop    ]asm #t                     r-1     alu asm[ ;
223
\ : 2rdrop ]asm #t                     r-2     alu asm[ ;
224
\ : rdrop>r ]asm #n            t->r        d-1 alu asm[ ;
225
: dup>r    ]asm #t             t->r    r+1     alu asm[ ;
226
: over-and ]asm #t&n                           alu asm[ ;
227
: over+    ]asm #t+n                           alu asm[ ;
228
\ : over-xor ]asm #t^n                         alu asm[ ;
229
: >r-dup   ]asm #n             t->r    r+1     alu asm[ ;
230
: 2dup=    ]asm #t==n  t->n                d+1 alu asm[ ;
231
: 2dup<    ]asm #nn                d+1 alu asm[ ;
232
: 2dupu<   ]asm #nun                d+1 alu asm[ ;
233
: 2dup-xor ]asm #t^n   t->n                d+1 alu asm[ ;
234
: store    ]asm #n     n->[t]              d-1 alu asm[ ;
235
: tuck!    ]asm #t     n->[t]              d-1 alu asm[ ;
236
: cpu-id   ]asm #cpu-id                    d+1 alu asm[ ;
237
: cpu!     ]asm #cpu!                      d-1 alu asm[ ;
238
: cpu?     ]asm #cpu?  t->n                d+1 alu asm[ ;
239
: dup@     ]asm #[t]   t->n                d+1 alu asm[ ;
240
: r>rdrop  ]asm #r     t->n            r-2 d+1 alu asm[ ;
241
: rxchg    ]asm #r             t->r            alu asm[ ;
242
: nip-nip  ]asm #t                         d-2 alu asm[ ;
243
: for >r begin ;
244
: meta: : ;
245
( : :noname h: ; )
246
: : t: ;
247
meta: ; t; ;
248
hide meta:
249
hide t:
250
hide t;
251
]asm #~t              ALU asm[ constant =invert ( invert instruction )
252
]asm #t  r->pc    r-1 ALU asm[ constant =exit   ( return/exit instruction )
253
]asm #n  t->r d-1 r+1 ALU asm[ constant =>r     ( to r. stk. instruction )
254
$20   constant =bl         ( blank, or space )
255
$D    constant =cr         ( carriage return )
256
$A    constant =lf         ( line feed )
257
$8    constant =bs         ( back space )
258
$7F   constant =del        ( delete key )
259
\ $1B   constant =escape     ( escape character )
260
$50   constant tib-length  ( size of terminal input buffer )
261
$40   constant word-length ( maximum length of a word )
262
$40   constant c/l         ( characters per line in a block )
263
$10   constant l/b         ( lines in a block )
264
$2BAD constant magic       ( magic number for compiler security )
265
( Volatile variables )
266
$3B02 constant last-def    ( last, possibly unlinked, word definition )
267
$3B06 constant id          ( used for source id )
268
$3B0A constant handler     ( current handler for throw/catch )
269
$3B0C constant block-dirty ( -1 if loaded block buffer is modified )
270
$3B14 constant     ( "accept" vector )
271
$3B16 constant        ( "tap" vector, for terminal handling )
272
$3B18 constant       ( c -- : emit character )
273
$3B1A constant context     ( holds current context for search order )
274
  ( area for context is #vocs large )
275
$3B2A constant #tib        ( Current count of terminal input buffer )
276
$3B2C constant tib-buf     ( ... and address )
277
$3B2E constant tib-start   ( backup tib-buf value )
278
$3C00 constant block-buffer ( block buffer is stored here )
279
 
280
$10   constant header-length ( location of length in header )
281
$12   constant header-crc    ( location of CRC in header )
282
$14   constant header-options ( location of options bits in header )
283
target.1         +order ( Add target word dictionary to search order )
284
meta -order meta +order ( Reorder so *meta* has a higher priority )
285
system           -order ( Remove system vocabulary to previously accidents )
286
forth-wordlist   -order ( Remove normal Forth words to prevent accidents )
287
 
288
\ ============================================================================
289
\ # Start of Image
290
 
291
 
292
 
293
 
294
 
295
 
296
 
297
 
298
 
299
 
300
 
301
 
302
 
303
$0001    t, \ $14: Header options
304
h: doVar   r> ;    ( -- a : push return address and exit to caller )
305
h: doConst r> @ ;  ( -- u : push value at return address and exit to caller )
306
[t] doVar   tdoVar   meta!
307
[t] doConst tdoConst meta!
308
 
309
 
310
pad-area tconstant pad   ( pad variable - offset into temporary storage )
311
$8       constant  #vocs ( number of vocabularies in allowed )
312
$2       tconstant cell  ( size of a cell in bytes )
313
$400     tconstant b/buf ( size of a block )
314
 
315
 
316
 
317
 
318
$0       tvariable >in   ( Hold character pointer when parsing input )
319
1        tlocation seed1 ( PRNG seed; never set to zero )
320
1        tlocation seed2 ( PRNG seed; never set to zero )
321
$0       tvariable state ( compiler state variable )
322
$0       tvariable hld   ( Pointer into hold area for numeric output )
323
$A       tvariable base  ( Current output radix )
324
$0       tvariable span  ( Hold character count received by expect   )
325
 
326
$FFFF    tvariable dpl   ( number of places after fraction )
327
 
328
xchange _forth-wordlist _system
329
 
330
 
331
 
332
 
333
 
334
 
335
( : nop    nop      ; ( -- : do nothing )
336
: cpu-id  cpu-id    ; ( -- u : returns CPU ID )
337
: cpu?    cpu?      ; ( -- u : returns CPU status )
338
: cpu!    cpu!      ; ( u -- : sets CPU status )
339
xchange _system _forth-wordlist
340
: dup      dup      ; ( n -- n n : duplicate value on top of stack )
341
: over     over     ; ( n1 n2 -- n1 n2 n1 : duplicate second value on stack )
342
: invert   invert   ; ( u -- u : bitwise invert of value on top of stack )
343
: +        +        ; ( u u -- u : addition without carry )
344
: swap     swap     ; ( n1 n2 -- n2 n1 : swap two values on stack )
345
: nip      nip      ; ( n1 n2 -- n2 : remove second item on stack )
346
: drop     drop     ; ( n -- : remove item on stack )
347
: @        @        ; ( a -- u : load value at address )
348
: !        store drop ; ( u a -- : store *u* at address *a* )
349
: rshift   rshift   ; ( u1 u2 -- u : shift u2 by u1 places to the right )
350
: lshift   lshift   ; ( u1 u2 -- u : shift u2 by u1 places to the left )
351
: =        =        ; ( u1 u2 -- t : does u2 equal u1? )
352
: u<       u<       ; ( u1 u2 -- t : is u2 less than u1 )
353
: <        <        ; ( u1 u2 -- t : is u2 less than u1, signed version )
354
: and      and      ; ( u u -- u : bitwise and )
355
: xor      xor      ; ( u u -- u : bitwise exclusive or )
356
: or       or       ; ( u u -- u : bitwise or )
357
: 1-       1-       ; ( u -- u : decrement top of stack )
358
: 0=       0=       ; ( u -- t : if top of stack equal to zero )
359
: sp@      sp@      ; ( -- u : stack position [equivalent to depth] )
360
there constant inline-start
361
( : rp@ rp@   fallthrough; compile-only ( -- u )
362
: exit  exit  fallthrough; compile-only ( -- )
363
: >r    >r    fallthrough; compile-only ( u --, R: -- u )
364
: r>    r>    fallthrough; compile-only ( -- u, R: u -- )
365
: r@    r@    fallthrough; compile-only ( -- u )
366
: rdrop rdrop fallthrough; compile-only ( --, R: u -- )
367
there constant inline-end
368
 
369
\ ============================================================================
370
\ # Core Words
371
 
372
( 0        tvariable hidden  ( vocabulary for hidden words )
373
h: [-1] -1 ;                 ( -- -1 : space saving measure, push -1 )
374
h: 0x8000 $8000 ;            ( -- $8000 : space saving measure, push $8000 )
375
h: 2drop-0 drop fallthrough; ( n n -- 0 )
376
h: drop-0 drop fallthrough;  ( n -- 0 )
377
h: 0x0000 $0000 ;            ( -- $0000 : space/optimization, push $0000 )
378
h: state@ state @ ;          ( -- u )
379
h: first-bit 1 and ;         ( u -- u )
380
h: in@ >in @ ;               ( -- u )
381
h: base@ base @ ;            ( -- u )
382
h: hld@ hld @ ;              ( -- u )
383
h: blk-@ blk @ ;
384
 
385
h: ?exit if rdrop exit then ; ( u --, R: xt -- xt| : conditional return )
386
: 2drop drop drop ;         ( n n -- )
387
: 1+ 1 + ;                  ( n -- n : increment a value  )
388
: negate 1- invert ;        ( n -- n : negate a number )
389
: - negate + ;              ( n1 n2 -- n : subtract n1 from n2 )
390
h: over- over - ;           ( u u -- u u )
391
: aligned dup first-bit + ; ( b -- a )
392
h: cell- cell - ;           ( a -- a : adjust address to previous cell )
393
: cell+  cell + ;           ( a -- a : move address forward to next cell )
394
: cells 1 lshift ;          ( n -- n : convert cells count to address count )
395
: chars 1 rshift ;          ( n -- n : convert bytes to number of cells )
396
: ?dup dup if dup exit then ; ( n -- 0 | n n : duplicate non zero value )
397
: >  swap  < ;              ( n1 n2 -- t : signed greater than, n1 > n2 )
398
: u> swap u< ;              ( u1 u2 -- t : unsigned greater than, u1 > u2 )
399
:  <>  = invert ;           ( n n -- t : not equal )
400
: 0<> 0= invert ;           ( n n -- t : not equal  to zero )
401
: 0> 0 > ;                  ( n -- t : greater than zero? )
402
: 0< 0 < ;                  ( n -- t : less than zero? )
403
: 2dup over over ;          ( n1 n2 -- n1 n2 n1 n2 )
404
: tuck swap over ;          ( n1 n2 -- n2 n1 n2 )
405
: +! tuck @ +  fallthrough; ( n a -- : increment value at *a* by *n* )
406
h: swap! swap ! ;           ( a u -- )
407
h: zero 0 swap! ;           ( a -- : zero value at address )
408
: 1+!   1  h: s+! swap +! ;; ( a -- : increment value at address by 1 )
409
: 1-! [-1] s+! ;            ( a -- : decrement value at address by 1 )
410
: 2! ( d a -- ) tuck! cell+ ! ;      ( n n a -- )
411
: 2@ ( a -- d ) dup cell+ @ swap @ ;  ( a -- n n )
412
h: get-current current @ ;            ( -- wid )
413
: bl =bl ;                            ( -- c )
414
: within over- >r - r> u< ;           ( u lo hi -- t )
415
h: s>d dup 0< ;                       ( n -- d )
416
: abs s>d if negate exit then ;       ( n -- u )
417
: source #tib 2@ ;                    ( -- a u )
418
h: tib source drop ;                  ( -- a )
419
: source-id id @ ;                    ( -- 0 | -1 )
420
: rot >r swap r> swap ;               ( n1 n2 n3 -- n2 n3 n1 )
421
: -rot rot rot ;                      ( n1 n2 n3 -- n3 n1 n2 )
422
h: rot-drop rot drop ;                ( n1 n2 n3 -- n2 n3 )
423
h: d0= or 0= ;                        ( d -- t )
424
( : 2swap >r -rot r> -rot ; ( n1 n2 n3 n4 -- n3 n4 n1 n2 )
425
( : d< rot   )
426
(     2dup   )
427
(     > if = nip-nip if 0 exit then [-1] exit then 2drop u< ; ( d -- f )
428
( : d>  2swap d< ;                    ( d -- t )
429
( : du> 2swap du< ;                   ( d -- t )
430
( : d=  rot = -rot = and ;            ( d d -- t )
431
( : d- dnegate d+ ;                   ( d d -- d )
432
( : dabs  s>d if dnegate exit then ;  ( d -- ud )
433
( : even first-bit 0= ;               ( u -- t )
434
( : odd even 0= ;                     ( u -- t )
435
( : pow2? dup dup 1- and 0= and ;     ( u -- u|0 : is u a power of 2? )
436
( : opposite? xor 0< ;                ( n n -- f : true if opposite signs )
437
: execute >r ;                   ( cfa -- : execute a function )
438
h: @execute @ ?dup if execute exit then ;  ( cfa -- )
439
: c@ dup@ swap first-bit 3 lshift rshift h: lsb $FF and ;; ( b--c: char load )
440
: c! ( c b -- : store character at address )
441
  tuck first-bit 3 lshift dup>r swap lsb swap
442
  lshift over @
443
  $FF r> 8 xor lshift and or swap! ;
444
: here cp @ ;                         ( -- a )
445
: align here fallthrough;             ( -- )
446
h: cp! aligned cp ! ;                 ( n -- )
447
: allot cp +! ;                       ( n -- )
448
h: 2>r rxchg swap >r >r ;        ( u1 u2 --, R: -- u1 u2 )
449
h: 2r> r> r> swap rxchg nop ;    ( -- u1 u2, R: u1 u2 -- )
450
h: doNext 2r> ?dup if 1- >r @ >r exit then cell+ >r ;
451
[t] doNext tdoNext meta!
452
: min 2dup< fallthrough;              ( n n -- n )
453
h: mux if drop exit then nip ;        ( n1 n2 b -- n : multiplex operation )
454
: max 2dup > mux ;                    ( n n -- n )
455
( : 2over 2>r 2dup 2r> 2swap ; )
456
( : 2nip 2>r 2drop 2r> nop ; )
457
( : 4dup 2over 2over ; )
458
( : dmin 4dup d< if 2drop exit else 2nip ; )
459
( : dmax 4dup d> if 2drop exit else 2nip ; )
460
\ : um+ ( w w -- w carry )
461
\       over over+ >r
462
\       r@ 0 < invert >r
463
\       over over-and
464
\       0 < r> or >r
465
\       or 0 < r> and 1- invert
466
\       r> swap ;
467
\ h: upivot ( u1 u2 -- min max ) 2dupu< if exit then swap ;
468
: um+ 2dupu< 0= if swap then over+ swap over swap u< 1 and ; ( u u -- u carry )
469
 
470
h: dnegate invert >r invert 1 um+ r> + ; ( d -- d )
471
h: d+ >r swap >r um+ r> + r> + ;         ( d d -- d )
472
: um* ( u u -- ud )
473
 
474
        for dup um+ >r >r-dup um+ r> + r>
475
                if >r over um+ r> + then
476
        next rot drop ;
477
: *    um* drop ;            ( n n -- n )
478
h: rp! ( n -- , R: ??? -- ??? : set the return stack pointer )
479
        r> swap begin dup rp@ = 0= while rdrop repeat drop >r ;
480
: key?  @execute ;                   ( -- c -1 | 0 )
481
: key begin key? until ;                  ( -- c )
482
: /string over min rot over+ -rot - ;  ( b u1 u2 -- b u : advance string u2 )
483
h: +string 1 /string ;                 ( b u -- b u : )
484
: count dup 1+ swap c@ ;               ( b -- b u )
485
h: string@ over c@ ;                   ( b u -- b u c )
486
xchange _forth-wordlist _system
487
h: lshift-xor lshift xor ;
488
h: rshift-xor rshift xor ;
489
: crc ( b u -- u : calculate ccitt-ffff CRC )
490
  [-1] ( -1 = 0xffff ) >r
491
  begin
492
    ?dup
493
  while
494
   string@ r> swap
495
     ( CCITT polynomial $1021, or "x16 + x12 + x5 + 1" )
496
     over $8 rshift-xor ( crc x )
497
     dup  $4 rshift-xor ( crc x )
498
     dup  $5 lshift-xor ( crc x )
499
     dup  $C lshift-xor ( crc x )
500
     swap $8 lshift-xor ( crc )
501
   >r +string
502
  repeat r> nip ;
503
xchange _system _forth-wordlist
504
h: last get-current @ ;         ( -- pwd )
505
h: echo  @execute ;              ( c -- )
506
: emit  @execute ;               ( c -- : write out a char )
507
: cr =cr emit =lf emit ;               ( -- : emit a newline )
508
: space     1 fallthrough;             ( -- : emit a space )
509
h: spaces =bl fallthrough;             ( +n -- )
510
h: nchars                              ( +n c -- : emit c n times )
511
   swap 0 max for aft dup emit then next drop ;
512
h: colon-space [char] : emit space ;   ( -- )
513
\ This version of pick mashes the return stack for large pick depths, an
514
\ alternative would be to move non-destructively up and down the stack with
515
\ special instructions.
516
( vn...v0 u -- vn...v0 vu )
517
: pick ?dup if swap >r 1- pick r> swap exit then dup ;
518
h: ndrop for aft drop then next ;
519
h: >char dup $7F =bl within if drop [char] _ then ; ( c -- c )
520
: type 0 fallthrough;                  ( b u -- )
521
h: typist                              ( b u f -- : print a string )
522
  >r begin dup while
523
    swap count r@
524
    if
525
      >char
526
    then
527
    emit
528
    swap 1-
529
  repeat
530
  rdrop 2drop ;
531
h: $type [-1] typist ;                   ( b u --  )
532
: cmove for aft >r-dup c@ r@ c! 1+ r> 1+ then next 2drop ; ( b b u -- )
533
: fill  swap for swap aft 2dup c! 1+ then next 2drop ;     ( b u c -- )
534
 
535
: catch  ( xt -- exception# | 0 : return addr on stack )
536
  sp@ >r        ( xt : save data stack depth )
537
  handler @ >r  ( xt : and previous handler )
538
  rp@ handler ! ( xt : set current handler )
539
  execute       (      execute returns if no throw )
540
  r> handler !  (      restore previous handler )
541
  rdrop         (      discard saved stack ptr )
542
  0x0000 ;      ( 0  : normal completion )
543
 
544
: throw  ( ??? exception# -- ??? exception# )
545
  ?dup if ( exc# \ 0 throw is no-op )
546
    handler @ rp! ( exc# : restore prev return stack )
547
    r> handler !  ( exc# : restore prev handler )
548
    rxchg         ( saved-sp : exc# on return stack )
549
    sp@ swap - ndrop r>   ( exc# : restore stack )
550
    ( return to the caller of catch because return )
551
    ( stack is restored to the state that existed )
552
    ( when catch began execution )
553
  then ;
554
h: -throw negate throw ;  ( u -- : negate and throw )
555
[t] -throw 2/ 4 tcells t!
556
: um/mod ( ud u -- ur uq )
557
  ?dup 0= if $A -throw exit then
558
  2dupu<
559
  if negate $F
560
    for >r-dup um+ >r >r-dup um+ r> + dup
561
      r> r@ swap >r um+ r> or
562
      if >r drop 1 + r> else drop then r>
563
    next
564
    drop swap exit
565
  then 2drop drop [-1] dup ;
566
: m/mod ( d n -- r q ) \ floored division
567
  dup 0< dup>r
568
  if
569
    negate >r dnegate r>
570
  then
571
  >r-dup 0< if r@ + then r> um/mod r>
572
  if swap negate swap exit then ;
573
\ : */ >r um* r> m/mod nip ; ( n n n -- )
574
: /mod  over 0< swap m/mod ; ( n n -- r q )
575
: mod  /mod drop ;           ( n n -- r )
576
: /    /mod nip ;            ( n n -- q )
577
h: 1depth 1 fallthrough; ( ??? -- : check depth is at least one )
578
h: ?depth dup 0= if drop exit then sp@ 1- u> if 4 -throw exit then ; ( u -- )
579
: decimal  $A fallthrough;  ( -- : set base to decimal )
580
h: base!  base ! ;          ( u -- : set base )
581
: hex     $10 base! ;                      ( -- )
582
\ h: radix base@ dup 2 - $23 u< ?exit decimal $28 -throw ; ( -- u )
583
: hold hld@ 1- dup hld ! c! hld@ pad $80 - u> ?exit $11 -throw ; ( c -- )
584
h: extract dup>r um/mod rxchg um/mod r> rot ;  ( ud ud -- ud u )
585
h: digit 9 over < 7 and + [char] 0 + ;         ( u -- c )
586
: #> 2drop hld@ pad over- ;                ( w -- b u )
587
: #  2 ?depth 0 base@ extract digit hold ;  ( d -- d )
588
: #s begin # 2dup d0= until ;               ( d -- 0 )
589
: <# pad hld ! ;                            ( -- )
590
: sign 0< 0= ?exit [char] - hold ; ( n -- )
591
h: (.) ( n -- b u : convert a signed integer to a numeric string )
592
  dup>r abs 0 <# #s r> sign #> ;
593
h: (u.) 0 <# #s #> ;             ( u -- b u : turn *u* into number string )
594
: u.r >r (u.) r> fallthrough;    ( u +n -- : print u right justified by +n)
595
h: adjust over- spaces type ;    ( b n n -- )
596
h: d5u.r dup fallthrough;        ( u -- u )
597
h: 5u.r space 5 u.r space ;      ( u -- )
598
( :  .r >r (.)( r> adjust ;      ( n n -- : print n, right justified by +n )
599
: u.  (u.) h: blt space type ;;  ( u -- : print unsigned number )
600
:  .  (.) blt ;                  ( n -- print number )
601
( : >base swap base @ >r base ! execute r> base ! ; )
602
( : d. $a  '  . >base ; )
603
( : h. $10 ' u. >base ; )
604
h: adown cell negate and ; ( a -- a : align down )
605
xchange _forth-wordlist _system
606
: pack$ ( b u a -- a ) \ null fill
607
  aligned dup>r over
608
  dup adown
609
  - over+ zero 2dup c! 1+ swap ( 2dup 0 fill ) cmove r> ;
610
xchange _system _forth-wordlist
611
: compare ( a1 u1 a2 u2 -- n : string equality )
612
  rot
613
  over- ?dup if >r 2drop r> nip exit then
614
  for ( a1 a2 )
615
    aft
616
      count rot count rot - ?dup
617
      if rdrop nip-nip exit then
618
    then
619
  next 2drop-0 ;
620
h: ^h ( bot eot cur -- bot eot cur )
621
  >r over r@ < dup
622
  if
623
    =bs dup echo =bl echo echo
624
  then r> + ;
625
h: tap dup echo over c! 1+ ; ( bot eot cur c -- bot eot cur )
626
h: delete? dup =bs = swap =del = or 0= ; ( c -- t : delete key pressed? )
627
h: ktap                                  ( bot eot cur c -- bot eot cur )
628
 dup =cr xor
629
 if delete? \ =bs xor
630
   if =bl tap exit then ^h exit
631
 then drop nip dup ;
632
\ h: ktap? dup =bl - $5F u< swap =del xor and ; ( c -- t : possible ktap? )
633
: accept ( b u -- b u )
634
  over+ over
635
  begin
636
    2dup-xor
637
  while
638
    key dup =bl - $5F u< if tap else  @execute then
639
  repeat drop over- ;
640
: expect  @execute span ! drop ;   ( b u -- )
641
: query tib tib-length  @execute #tib ! drop-0 fallthrough;
642
h: in! >in ! ;                             ( u -- )
643
h: word.count count fallthrough; ( nfa -- u : get a words length )
644
h: word.length $1F and ;
645
xchange _forth-wordlist _system
646
: nfa cell+ ; ( pwd -- nfa : move to name field address)
647
: cfa nfa dup c@ word.length + cell+ adown ; ( pwd -- cfa )
648
xchange _system _forth-wordlist
649
h: .id nfa word.count type space ; ( pwd -- : print out a word )
650
h: immediate? nfa $40 fallthrough; ( pwd -- t : is word immediate? )
651
h: set? swap @ and 0<> ;           ( a u -- t : is any of 'u' set? )
652
h: compile-only? nfa $20 set? ;    ( pwd -- t : is word compile only? )
653
h: inline? inline-start inline-end within ; ( pwd -- t : is word inline? )
654
h: (search-wordlist) ( a wid -- PWD PWD 1|PWD PWD -1|0 a 0: find word in WID )
655
  swap >r-dup
656
  begin
657
    dup
658
  while
659
    dup nfa count $9F ( $1F:word-length + $80:hidden ) and r@ count compare 0=
660
    if ( found! )
661
      rdrop
662
      dup immediate? 1 or negate exit
663
    then
664
    nip dup@
665
  repeat
666
  rdrop 2drop-0 ;
667
h: (find) ( a -- pwd pwd 1 | pwd pwd -1 | 0 a 0 : find a word dictionary )
668
  >r
669
  context
670
  begin
671
    dup@
672
  while
673
    dup@ @ r@ swap (search-wordlist) ?dup
674
    if
675
      >r rot-drop r>rdrop exit
676
    then
677
    cell+
678
  repeat drop-0 r> 0x0000 ;
679
: search-wordlist (search-wordlist) rot-drop ; ( a wid -- PWD 1|PWD -1|a 0 )
680
: find ( a -- pwd 1 | pwd -1 | a 0 : find a word in the dictionary )
681
  (find) rot-drop ;
682
h: digit? ( c base -- u f )
683
  >r [char] 0 - 9 over <
684
  if
685
    7 -
686
    dup $A < or
687
  then dup r> u< ;
688
: >number ( ud b u -- ud b u : convert string to number )
689
  begin
690
    ( get next character )
691
    2dup 2>r drop c@ base@ digit?
692
    0= if                                 ( d char )
693
      drop                                ( d char -- d )
694
      2r>                                 ( restore string )
695
      nop exit                            ( ..exit )
696
    then                                  ( d char )
697
    swap base@ um* drop rot base@ um* d+  ( accumulate digit )
698
    2r>                                   ( restore string )
699
    +string dup 0=                         ( advance string and test for end )
700
  until ;
701
h: number? ( a u -- d -1 | a u 0 )
702
  [-1] dpl !
703
  base@ >r
704
  string@ [char] - = dup>r if     +string then
705
  string@ [char] $ =       if hex +string then
706
  2>r 0 dup 2r>
707
  begin
708
    >number dup
709
  while string@ [char] .  ( fsp @ ) xor
710
    if rot-drop rot r> 2drop-0 r> base! exit then
711
    1- dpl ! 1+ dpl @
712
  repeat 2drop r> if dnegate then r> base! [-1] ;
713
h: -trailing ( b u -- b u : remove trailing spaces )
714
  for
715
    aft =bl over r@ + c@ <
716
      if r> 1+ exit then
717
    then
718
  next 0x0000 ;
719
h: lookfor ( b u c xt -- b u : skip until *xt* test succeeds )
720
  swap >r -rot
721
  begin
722
    dup
723
  while
724
    string@ r@ - r@ =bl = 4 pick execute
725
    if rdrop rot-drop exit then
726
    +string
727
  repeat rdrop rot-drop ;
728
h: no-match if 0> exit then 0<> ; ( n f -- t )
729
h: match no-match invert ;        ( n f -- t )
730
h: parser ( b u c -- b u delta )
731
  >r over r> swap 2>r
732
  r@ ' no-match lookfor 2dup
733
  r> ' match    lookfor swap r> - >r - r> 1+ ;
734
: parse ( c -- b u ;  )
735
   >r tib in@ + #tib @ in@ - r@ parser >in +!
736
   r> =bl = if -trailing then 0 max ;
737
: ) ; immediate ( -- : do nothing )
738
:  ( [char] ) parse 2drop ; immediate \ ) ( parse until matching paren )
739
: .( [char] ) parse type ; ( print out text until matching parenthesis )
740
: \ #tib @ in! ; immediate ( comment until new line )
741
h: ?length dup word-length u< ?exit $13 -throw ;
742
: word 1depth parse ?length here pack$ ; ( c -- a ;  )
743
h: token =bl word ;                      ( -- a )
744
: char token count drop c@ ;             ( -- c;  )
745
h: ?dictionary dup $3B00 u< ?exit 8 -throw ;
746
: , here dup cell+ ?dictionary cp! ! ; ( u -- : store *u* in dictionary )
747
: 2, , , ;                             ( u u -- )
748
: c, here ?dictionary c! cp 1+! ;      ( c -- : store *c* in the dictionary )
749
h: doLit 0x8000 or , ;                 ( n+ -- : compile literal )
750
: literal ( n -- : write a literal into the dictionary )
751
  dup 0x8000 and ( n > $7FFF ? )
752
  if
753
    invert doLit =invert , exit ( store inversion of n the invert it )
754
  then
755
  doLit ; compile-only immediate ( turn into literal, write into dictionary )
756
h: make-callable chars $4000 or ;    ( cfa -- instruction )
757
: compile, make-callable , ;         ( cfa -- : compile a code field address )
758
h: $compile dup inline? if cfa @ , exit then cfa compile, ; ( pwd -- )
759
h: not-found source type $D -throw ; ( -- : throw 'word not found' )
760
h: ?compile dup compile-only? 0= ?exit source type $E -throw ;
761
xchange _forth-wordlist _system
762
: (literal) state@ 0= ?exit postpone literal ; ( u -- u | )
763
xchange _system _forth-wordlist
764
: interpret ( ??? a -- ??? : The command/compiler loop )
765
  \ dup count type space ( <- for tracing the parser )
766
  find ?dup if
767
    state@
768
    if
769
      0> if cfa execute exit then \ <- immediate word are executed
770
      $compile exit               \ <- compiling word are...compiled.
771
    then
772
    drop ?compile     \ <- check it's not a compile only word word
773
    cfa execute exit  \ <- if its not, execute it, then exit *interpreter*
774
  then
775
  \ not a word
776
  dup>r count number? if rdrop \ it's a number!
777
    dpl @ 0< if \ <- dpl will -1 if its a single cell number
778
       drop     \ drop high cell from 'number?' for single cell output
779
    else        \ <- dpl is not -1, it's a double cell number
780
       state@ if swap then
781
        @execute \  is executed twice if it's a double
782
    then
783
     @execute exit
784
  then
785
  r> not-found ; \ not a word/number, it's an error! NB. We could vector this
786
: compile  r> dup@ , cell+ >r ; compile-only ( --:Compile next compiled word )
787
: immediate $40 last nfa fallthrough; ( -- : previous word immediate )
788
h: toggle tuck @ xor swap! ;        ( u a -- : xor value at addr with u )
789
h: count+ count + ;         ( b -- b : advance address over counted string )
790
h: do$ 2r> dup count+ aligned >r swap >r ; ( -- a )
791
h: string-literal do$ nop ; ( -- a : do string NB. nop to fool optimizer )
792
h: .string do$ fallthrough; ( -- : print string  )
793
h: print count type ;                    ( b -- )
794
[t] .string        tdoPrintString meta!
795
[t] string-literal tdoStringLit   meta!
796
( , --, Run: -- b )
797
: $" compile string-literal fallthrough; immediate compile-only
798
h: parse-string [char] " word count+ cp! ; ( ccc" -- )
799
: ." compile .string parse-string ; immediate compile-only ( , -- )
800
: abort [-1] throw ;                                    ( -- )
801
h: ?abort swap if print cr abort exit then drop ;              ( u a -- )
802
h: (abort) do$ ?abort ;                                        ( -- )
803
: abort" compile (abort) parse-string ; immediate compile-only ( u -- )
804
 
805
\ See:
806
\ 
807
\
808
\ For a super tiny N-bit PRNG use; "x+=(x*x) | 5;", you can only use the
809
\ highest bit however.
810
\ See: 
811
: random
812
  seed1 @ dup 5 lshift-xor
813
  seed2 @ seed1 !
814
  dup 3 rshift-xor
815
  seed2 @ dup 1 rshift-xor xor dup seed2 !  ;
816
 
817
h: 40ns begin dup while 1- repeat drop ; ( n -- : wait for 'n'*40ns + 30us )
818
: ms for 25000 40ns next ; ( n -- : wait for 'n' milliseconds )
819
 
820
\ ============================================================================
821
\ # I/O wordset
822
 
823
 
824
xchange _forth-wordlist _system
825
: segments! $400E ! ; ( u -- : write to 4 7-segment hex displays )
826
: led!      $4006 ! ; ( u -- : write to 8 LEDs )
827
: switches  $4006 @ ; ( -- u : retrieve switch on/off for 8 switches )
828
: timer!    $4004 ! ; ( u -- : set timer and timer control )
829
: timer     $4004 @ ; ( -- u : get timer and timer control )
830
\ NB. Perhaps this could be vectored?
831
h: (irq)
832
  ( cpu? 0 cpu! )
833
  switches led!
834
   #irq dup@ segments! 1+!
835
  ( cpu! ) ;
836
[t] (irq) 2/ $C t!
837
: irq $0040 $4010 ! [-1] timer! 1 cpu! ;
838
 
839
\ FIFO: Write Read Enable after Read
840
\ h: uart? ( uart-register -- c -1 | 0 : generic UART input functions )
841
\ dup@ $0100 and if drop 0x0000 exit then dup@ $FF and swap $0400 swap! [-1] ;
842
\ FIFO: Write Read Enable before Read
843
h: uart? ( uart-register -- c -1 | 0 : generic UART input functions )
844
 dup@ $0100 and if drop-0 exit then dup $0400 swap! @ lsb [-1] ;
845
 
846
: rx?  $4000 uart? if [-1] exit then $4002 uart? ; ( -- c -1|0: rx uart/ps2 )
847
h: uart! ( c uart-register -- )
848
        begin dup@ $1000 and 0= until swap $2000 or swap! ;
849
: tx! dup $4002 uart! ( VGA/VT-100 ) $4000 uart! ( UART )  ;
850
h: (ok) state@ if cr exit then ."  ok" cr ;  ( -- : default state aware prompt )
851
h: preset tib-start #tib cell+ ! 0 in! id zero ;  ( -- : reset input )
852
: io! \ preset
853
  ( 115200 / 9600 )
854
  $35    ( $28B ) $4012 ! ( set TX baud rate - 54 )
855
  $34    ( $28A ) $4014 ! ( set RX baud rate - 53, hack! )
856
  $8080 $4016 ! ( set UART control register; 8 bits, 1 stop, no parity )
857
 
858
 
859
  fallthrough;  ( -- : initialize I/O )
860
h: console ' rx?  ! ' tx!  ! fallthrough;
861
h: hand
862
   ' (ok)
863
   ' emit ' ktap
864
   fallthrough;
865
h: xio  ' accept  !  !  !  ! ;
866
h: pace [char] . emit ;
867
: file ' pace ' drop ' ktap xio ;
868
 
869
\ ============================================================================
870
\ # Evaluation, Control Structures and Vocabulary Words
871
 
872
\ h: pace 11 emit ;
873
\ : file ' pace ' drop ' ktap xio ;
874
xchange _system _forth-wordlist
875
: ] [-1] state !    ;                                ( -- : compile mode )
876
: [      state zero ; immediate                      ( -- : command mode )
877
h: empty sp@ ndrop ; ( 0..n -- : empty variable stack )
878
h: ?error ( n -- : perform actions on error )
879
  ?dup 0= ?exit
880
  .             ( print error number )
881
  [char] ? emit ( print '?' )
882
  cr            ( and terminate the line )
883
  empty         ( empty the variable stack )
884
  fallthrough;
885
h: prequit      ( perform actions needed to start 'quit' off )
886
  preset        ( reset I/O streams )
887
  postpone [ ;  ( back into interpret mode )
888
h: eval ( -- : evaluation loop, get token, evaluate, loop, prompt )
889
  begin
890
    token dup c@
891
  while
892
    interpret 0 ?depth
893
  repeat drop  @execute ;
894
: quit prequit begin query ' eval catch ?error again ;
895
h: get-input source in@ source-id  @ ; ( -- n1...n5 )
896
h: set-input  ! id ! in! #tib 2! ;     ( n1...n5 -- )
897
: evaluate ( a u -- )
898
  get-input 2>r 2>r >r
899
 
900
  ' eval catch
901
  r> 2r> 2r> set-input
902
  throw ;
903
h: ?check ( magic-number -- : check for magic number on the stack )
904
   magic = ?exit $16 -throw ;
905
h: ?unique ( a -- a : print a message if a word definition is not unique )
906
  dup get-current (search-wordlist) 0= ?exit
907
    ( source type )
908
  space
909
  2drop last-def @ .id ." redefined" cr ;
910
h: ?nul ( b -- : check for zero length strings )
911
   dup c@ ?exit $A -throw ;
912
h: find-token token find fallthrough; ( -- pwd,   )
913
h: ?not-found ?exit not-found ;       ( t -- )
914
h: find-cfa find-token cfa ;          ( -- xt,  )
915
: ' find-cfa state@ if postpone literal exit then ; immediate
916
: [compile] find-cfa compile, ; immediate compile-only  ( --,  )
917
: [char] char postpone literal ; immediate compile-only ( --,  )
918
: ; ?check =exit , postpone [ ( -- wid )
919
( h: get-current! ) ?dup if get-current ! exit then ;  immediate compile-only
920
: : align here dup last-def ! ( "name", -- colon-sys )
921
  last , token ?nul ?unique count+ cp! magic postpone ] ;
922
: begin here    ; immediate compile-only ( -- a )
923
: again chars , ; immediate compile-only ( a -- )
924
: until $4000 or postpone again ; immediate compile-only ( a --, NB. again !? )
925
h: here-0 here 0x0000 ;
926
h: >mark here-0 postpone again ;
927
: if here-0 postpone until ; immediate compile-only
928
( : unless ' 0= compile, postpone if ; immediate compile-only )
929
: then fallthrough; immediate compile-only
930
h: >resolve here chars over @ or swap! ;
931
: else >mark swap >resolve ; immediate compile-only
932
: while postpone if ; immediate compile-only
933
: repeat swap postpone again postpone then ; immediate compile-only
934
h: last-cfa last-def @ cfa ;  ( -- u )
935
: recurse last-cfa compile, ; immediate compile-only
936
: create postpone : drop compile doVar get-current ! postpone [ ;
937
: >body cell+ ; ( a -- a )
938
h: doDoes r> chars here chars last-cfa dup cell+ doLit h: !, ! , ;;
939
: does> compile doDoes nop ; immediate compile-only
940
: variable create 0 , ;
941
: constant create ' doConst make-callable here cell- !, ;
942
: :noname here-0 magic postpone ] ; ( NB. need postpone! )
943
: for =>r , here ; immediate compile-only
944
: next compile doNext , ; immediate compile-only
945
: aft drop >mark postpone begin swap ; immediate compile-only
946
: marker ( "name", -- : create an eraser )
947
  here >r current @ dup@ r>
948
  create , 2,
949
  doDoes ( <- meta-compiler version of does> )
950
  dup cell+ 2@ swap! @ here - allot ;
951
 
952
\ h: (do) r@ swap rot >r >r cell+ >r ; ( hi lo -- index )
953
\ : do compile (do) 0 , here ; compile-only immediate ( hi lo -- )
954
\ h: (leave) rdrop rdrop rdrop ; compile-only
955
\ : leave compile (leave) nop ; compile-only immediate
956
\ h: (loop)
957
\    r> r> 1+ r> 2dup-xor if
958
\     >r >r @ >r exit
959
\    then >r 1- >r cell+ >r ; compile-only
960
\ h: (unloop) r>rdrop rdrop rdrop >r ; compile-only
961
\ : unloop compile (unloop) nop ; compile-only immediate
962
\ h: (?do)
963
\   2dup-xor if r@ swap rot >r >r cell+ >r exit then 2drop ; compile-only
964
\ : ?do compile (?do) 0 , here ; compile-only immediate ( hi lo -- )
965
\ : loop  compile (loop) dup , compile (unloop) cell- here chars ( -- )
966
\     swap! ; compile-only immediate
967
\ h: (+loop)
968
\    r> swap r> r> 2dup - >r
969
\    2 pick r@ + r@ xor 0< 0=
970
\    3 pick r> xor 0< 0= or if
971
\     >r + >r @ >r exit
972
\    then >r >r drop cell+ >r ; compile-only
973
\ : +loop ( n -- ) compile (+loop) dup , compile
974
\   (unloop) cell- here chars swap! ; compile-only immediate
975
\ h: (i)  2r> tuck 2>r nop ; compile-only ( -- index )
976
\ : i  compile (i) nop ; compile-only immediate ( -- index )
977
 
978
xchange _forth-wordlist _system
979
: hide find-token nfa $80 swap toggle ; ( --,  : hide word by name )
980
xchange _system _forth-wordlist
981
: get-order ( -- widn ... wid1 n : get the current search order )
982
  context
983
 
984
  ( : find-cell ) >r begin dup@ r@ xor while cell+ repeat rdrop ( ; u a -- a )
985
  dup cell- swap
986
  context - chars dup>r 1- s>d if $32 -throw exit then
987
  for aft dup@ swap cell- then next @ r> ;
988
xchange _forth-wordlist root-voc
989
: forth-wordlist _forth-wordlist ; ( -- wid : push forth vocabulary )
990
: system _system ;                 ( -- wid : push system vocabulary )
991
: set-order ( widn ... wid1 n -- : set the current search order )
992
  dup [-1] = if drop root-voc 1 set-order exit then ( NB. Recursion! )
993
  dup #vocs > if $31 -throw exit then
994
  context swap for aft tuck! cell+ then next zero ;
995
: forth root-voc forth-wordlist 2 set-order ; ( -- )
996
: words
997
  get-order begin ?dup while
998
  swap dup cr u. colon-space @
999
    begin
1000
      ?dup
1001
    while dup
1002
      nfa c@ $80 and 0= ( <- not-hidden? )
1003
      if dup .id then @
1004
    repeat cr
1005
  1- repeat ;
1006
xchange root-voc _forth-wordlist
1007
( : previous get-order nip 1- set-order ; ( -- )
1008
( : also get-order over swap 1+ set-order ;     ( wid -- )
1009
: only [-1] set-order ;                         ( -- )
1010
( : order get-order for aft . then next cr ;    ( -- )
1011
( : anonymous get-order 1+ here 1 cells allot swap set-order ; ( -- )
1012
: definitions context @ current ! ( <- set current ) ; ( -- )
1013
h: (order)                                      ( w wid*n n -- wid*n w n )
1014
  dup if
1015
    1- swap >r (order) over r@ xor
1016
    if
1017
      1+ r> -rot exit
1018
    then rdrop
1019
  then ;
1020
: -order get-order (order) nip set-order ;             ( wid -- )
1021
: +order dup>r -order get-order r> swap 1+ set-order ; ( wid -- )
1022
: editor editor-voc +order ; ( -- : load editor vocabulary )
1023
 
1024
\ ============================================================================
1025
\ # Block Wordset
1026
 
1027
\ h: updated? block-dirty @ ;          ( -- f )
1028
: update [-1] block-dirty ! ;          ( -- )
1029
\ h: +block blk-@ + ;                  ( n -- k )
1030
\ h: clean-buffers 0 block-dirty ! ;
1031
\ h: empty-buffers clean-buffers 0 blk ! ;  ( -- )
1032
: flush
1033
  blk-@ 0= block-dirty @ d0= ?exit
1034
  block-buffer b/buf blk-@  @execute throw
1035
 
1036
 
1037
h: ?block if $23 -throw exit then ;
1038
: block ( k -- a )
1039
  1depth
1040
  dup 0= ?block ( check validity of block number )
1041
  dup blk-@ = if drop block-buffer exit then ( block already loaded )
1042
  flush
1043
  dup>r block-buffer b/buf r>  @execute throw
1044
  blk!
1045
  block-buffer ;
1046
 
1047
\ xchange _forth-wordlist _system
1048
\ : (block) ( a u k -- f )
1049
\       1- dup $C u> ?block
1050
\       $A lshift ( <- b/buf * )
1051
\       -rot cmove 0x0000 ;
1052
\ : (save) 2drop drop-0 ; ( a u k -- f )
1053
\ xchange _system _forth-wordlist
1054
 
1055
\ ============================================================================
1056
\ # Memory Interface
1057
 
1058
\ The manual for the Nexys 3 board specifies that there is a PCM
1059
\ memory device called the NP8P128A13T1760E, this is a device behaves like
1060
\ normal flash with the addition that individual cells can be written to
1061
\ without first erasing the block, this is accomplished with an extension
1062
\ to the Common Flash Interface that most flash devices support. However,
1063
\ there are boards with the PC28F128P33BF60 on in lieu of this, which is a
1064
\ normal flash device without the "bit alterable write" extension. Normal
1065
\ flash memory works by erasing a block of data, which sets all the bits.
1066
\ Writing to the memory works by masking in a value as bits can be cleared in
1067
\ a memory cell but not set, they can only be set by erasing a block.
1068
\
1069
\ The Nexys 3 has three memory devices, two of which are accessed over
1070
\ a parallel interface. They share the same data and address bus, and
1071
\ can be selected with a chip select. The signals to be controlled
1072
\ are:
1073
\
1074
\       +-----+-------------------------+
1075
\       | Bit | Description             |
1076
\       |-----|-------------------------|
1077
\       | 0-9 | Upper Memory Bits       |
1078
\       | 10  | Flash chip select       |
1079
\       | 11  | SRAM chip select        |
1080
\       | 12  | Memory Wait [not used]  |
1081
\       | 13  | Flash Reset             |
1082
\       | 14  | Output Enable           |
1083
\       | 15  | Write Enable            |
1084
\       +-----+-------------------------+
1085
\
1086
\ The usage of the output enable and write enable are mutually exclusive,
1087
\ as are both of the chip selects.  )
1088
\
1089
xchange _forth-wordlist _system
1090
 
1091
 
1092
 
1093
 
1094
 
1095
h: mdelay 5 40ns ;
1096
 
1097
h: mcontrol! ( u -- : write to memory control register )
1098
  $F3FF and
1099
  memory-select @ $400 + or               ( select correct memory device )
1100
  $1FF invert and            ( mask off control bits )
1101
  memory-upper @ $1FF and or ( or in higher address bits )
1102
  $400A ! ; ( and finally write in control )
1103
 
1104
: m! ( n a -- : write to non-volatile memory )
1105
  $400C !
1106
  $4008 !
1107
  mdelay
1108
  0x8000 mcontrol!
1109
  mdelay
1110
  $0000 mcontrol! ;
1111
 
1112
: m@ ( a -- n : read from non-volatile memory )
1113
  $400C !
1114
  $4000 mcontrol! ( read enable mode )
1115
  mdelay
1116
  $4008 @        ( get input )
1117
  $0000 mcontrol! ;
1118
 
1119
: sram   $400 memory-select ! ;
1120
h: nvram $000 memory-select ! ;
1121
h: block-mode memory-upper @ memory-upper zero ; ( -- hi )
1122
h: flash-reset ( -- : reset non-volatile memory )
1123
  $2000 mcontrol! mdelay $0000 mcontrol! ;
1124
h: flash! dup>r m! r> m! ; ( u u a )
1125
: flash-status nvram $70 0 m! 0 m@ ; ( -- status )
1126
: flash-read   $FF 0 m! ;      ( -- )
1127
: flash-setup  memory-select @
1128
   if flush then nvram flash-reset block-mode drop 20 ms ;
1129
h: flash-wait begin flash-status $80 and until ;
1130
: flash-clear $50 0 m! ; ( -- clear status )
1131
: flash-write $40 swap flash! flash-wait ; ( u a -- )
1132
\ : flash-unlock block-mode >r $d0 swap $60 swap flash! r> memory-upper ! ;
1133
\ : flash-lock block-mode >r $01 swap $60 swap flash! r> memory-upper ! ;
1134
\ : flash-lock-down block-mode >r $2f swap $60 swap flash! r> memory-upper ! ;
1135
: flash-erase block-mode >r flash-clear $D0 swap $20 swap
1136
    flash! flash-wait r> memory-upper ! ; ( ba -- )
1137
: flash-query $98 0 m! ; ( -- : query mode )
1138
 
1139
( -- read id mode : does the same as flash-query on the PC28F128P33BF60 )
1140
\ : flash-read-id   $90 0 m! ;
1141
 
1142
h: flash->sram ( a a : transfer flash memory cell to SRAM )
1143
  nvram flash-clear flash-read
1144
  m@ sram swap m! ;
1145
 
1146
: transfer ( a a u -- : transfer memory block from Flash to SRAM )
1147
  ?dup 0= if 2drop exit then
1148
  1-
1149
  for
1150
    2dup
1151
    flash->sram
1152
    cell+ swap cell+ swap
1153
  next 2drop ;
1154
\ .set flash-voc $pwd
1155
 
1156
h: c>m swap @ swap m! ; ( a a --  )
1157
h: m>c m@ swap! ;      ( a a -- )
1158
 
1159
h: mblock ( a u k -- f )
1160
  1- b/buf um* memory-upper ! >r
1161
  begin
1162
    dup
1163
  while
1164
    over r@ _blockop @execute r> cell+ >r
1165
    cell /string
1166
  repeat
1167
  rdrop 2drop-0 ;
1168
 
1169
: (save)  ' c>m _blockop ! mblock ;
1170
: (block) ' m>c _blockop ! mblock ;
1171
 
1172
\ ============================================================================
1173
\ # ANSI Escape Sequences
1174
 
1175
h: CSI $1B emit [char] [ emit ;                     ( -- )
1176
h: 10u. base@ >r decimal 0 <# #s #> type r> base! ; ( u -- )
1177
: ansi swap CSI 10u. emit ;                         ( n c -- )
1178
xchange _system _forth-wordlist
1179
: at-xy CSI 10u. $3B emit 10u. [char] H emit ; ( x y -- ) \  @execute
1180
: page 2 [char] J ansi 1 1 at-xy ;             ( -- )     \   @execute
1181
xchange _forth-wordlist _system
1182
: sgr   [char] m ansi ; ( -- : emit an SGR )
1183
: up    [char] A ansi ; ( u -- : move the cursor up )
1184
: down  [char] B ansi ; ( u -- : move the cursor down )
1185
: right [char] C ansi ; ( u -- : move the cursor right )
1186
: left  [char] D ansi ; ( u -- : move the cursor left )
1187
 
1188
\ 0 constant black 1 constant red 2 constant green 4 constant blue
1189
\ red green        + constant yellow
1190
\     green blue   + constant cyan
1191
\ red       blue   + constant magenta
1192
\ red green blue + + constant white
1193
\ : background $A + ;
1194
\ : color $1E + sgr ;
1195
 
1196
h: tableu ( -- )
1197
   $7 for
1198
     $A right $7 r@ - $28 + dup sgr u. colon-space
1199
     $7   for $7 r@ - $1E + dup sgr u. next cr
1200
   next ;
1201
 
1202
: table page $2 down tableu 1 sgr $2 down tableu 0 sgr ; ( -- )
1203
\ : nuf? key? if drop [-1] exit then 0x0000 ; ( -- f )
1204
xchange _system _forth-wordlist
1205
 
1206
\ ============================================================================
1207
\ # Higher Level Block Words
1208
 
1209
h: c/l* ( c/l * ) 6 lshift ;             ( u -- u )
1210
h: line c/l* swap block + c/l ;          ( k u -- a u )
1211
\ h: loadline line evaluate ;            ( k u -- )
1212
: load 0 $F for 2dup 2>r line evaluate 2r> 1+ next 2drop ; ( k -- )
1213
h: pipe [char] | emit ;                  ( -- )
1214
\ h: .line line -trailing $type ;        ( k u -- )
1215
h: .border 3 spaces c/l [char] - nchars cr ; ( -- )
1216
: thru over- for dup load 1+ next drop ; ( k1 k2 -- )
1217
( : message l/b extract .line cr ;       ( u -- )
1218
h: retrieve block drop ;                 ( k -- )
1219
: list                                   ( k -- )
1220
  dup retrieve
1221
  cr
1222
  .border
1223
 
1224
    dup l/b <
1225
  while
1226
    2dup dup 2 u.r pipe line $type pipe cr 1+
1227
  repeat .border 2drop ;
1228
 
1229
\ : list  block l/b for dup l/b 1- r@ - c/l * + c/l type cr next ;
1230
 
1231
: index ( k1 k2 -- : show titles for block k1 to k2 )
1232
  over- cr
1233
  for
1234
    dup 5u.r pipe space dup 0 line $type cr 1+
1235
  next drop ;
1236
( : --> blk-@ 1+ load ; immediate )
1237
\ ============================================================================
1238
\ # Boot Sequence
1239
 
1240
\ We could select different behaviors depending on what switches were set at
1241
\ at start up, some for debugging, others for functionality.
1242
 
1243
h: bist ( -- u : built in self test )
1244
  header-options @ first-bit 0= if 0x0000 exit then ( is checking disabled? )
1245
  header-length @ here xor if 2 exit then ( length check )
1246
  header-crc @ header-crc zero            ( retrieve and zero CRC )
1247
 
1248
  1 header-options toggle 0x0000 ;        ( disable check, success )
1249
: bye fallthrough;
1250
h: cold ( -- : performs a cold boot  )
1251
  bist ?dup if negate dup bye exit then
1252
  io! forth
1253
  empty 0 rp!
1254
  hex cr ." eFORTH v" cpu-id 0 u.r cr here .  $4000 here - u. cr
1255
  ." loading..."
1256
 
1257
  1 block c@ 32 127 within ( <- ASCII? ) if
1258
    (ok) ( 1 load ) else ." failed" cr
1259
  then quit ;
1260
 
1261
\ ============================================================================
1262
\ # Decompiler / Tools
1263
 
1264
h: validate over cfa xor if drop-0 exit then nfa ; ( pwd cfa -- nfa | 0 )
1265
h: search-for-cfa ( wid cfa -- nfa | 0 : search for CFA in a word list )
1266
  cells $1FFF and >r
1267
  begin
1268
    dup
1269
  while
1270
    dup@ over r@ -rot  within
1271
    if dup@ r@ validate ?dup if rdrop nip exit then then
1272
    @
1273
  repeat rdrop ;
1274
h: name ( cwf -- a | 0 )
1275
   >r
1276
   get-order
1277
   begin
1278
     dup
1279
   while
1280
     swap r@ search-for-cfa ?dup if >r 1- ndrop r>rdrop exit then
1281
   1- repeat rdrop ;
1282
( h: neg? dup 2 and if $FFFE or then ;  )
1283
( h: .alu  ( u -- )
1284
(   dup 8 rshift $1F and 5u.r )
1285
(   dup $80 and if ." t->n  " then   )
1286
(   dup $40 and if ." t->r  " then  )
1287
(   dup $10 and if ." r->pc " then  )
1288
(   dup $0C and [char] r emit 2 rshift neg? . space )
1289
(       $03 and [char] d emit          neg? . ;  )
1290
h: ?instruction ( i m e -- i t )
1291
   >r over-and r> = ;
1292
( a -- : find word by address, and print )
1293
h: .name dup $1FFF and cells 5u.r ( a -- )
1294
         name ?dup if word.count type then ;
1295
h: decompile ( u -- : decompile a single instruction )
1296
   0x8000 0x8000 ?instruction if [char] L emit $7FFF and 5u.r exit then
1297
    $6000  $6000 ?instruction if [char] A emit  drop ( .alu ) exit then
1298
    $6000  $4000 ?instruction if [char] C emit .name exit then
1299
    $6000  $2000 ?instruction if [char] Z emit .name exit then
1300
   [char] B emit .name ;
1301
h: decompiler ( previous current -- : decompile starting at address )
1302
  >r
1303
  begin dup r@ u< while
1304
    d5u.r colon-space
1305
    dup@
1306
    d5u.r decompile cr cell+
1307
  repeat rdrop drop ;
1308
: see ( --,  : decompile a word )
1309
  token (find) ?not-found
1310
  swap 2dup= if drop here then >r
1311
  cr colon-space dup .id dup cr
1312
  cfa r> decompiler space [char] ; emit
1313
  dup compile-only? if ."  compile-only" then
1314
  dup inline?       if ."  inline"       then
1315
      immediate?    if ."  immediate"    then cr ;
1316
: .s ( -- ) cr sp@ for aft r@ pick . then next ."  
1317
: dump ( a u -- )
1318
  $10 + \ align up by dump width
1319
  4 rshift ( <-- equivalent to "dump-width /" )
1320
  for
1321
    aft
1322
      cr $10 2dup
1323
      over 5u.r colon-space
1324
      chars for aft dup@ 5u.r cell+ then next ( <- dm+; [ a u -- ] )
1325
      -rot
1326
      2 spaces $type
1327
    then
1328
  next drop ;
1329
\ ============================================================================
1330
\ # Block Editor
1331
 
1332
[last]              [t] _forth-wordlist t!
1333
[t] _forth-wordlist [v] current         t!
1334
 
1335
h: [block] blk-@ block ;       ( k -- a : loaded block address )
1336
h: [check] dup b/buf 6 rshift u< ?exit $18 -throw ;
1337
h: [line] [check] c/l* [block] + ; ( u -- a )
1338
: b retrieve ;                 ( k -- : Load a block )
1339
: l blk-@ list ;               ( -- : list current block )
1340
: n   1  h: +blv blk-@ + b l ;;   ( -- : load and list Next block )
1341
: p [-1]    +blv ;             ( -- : load and list Previous block )
1342
: d [block] b/buf h: blank =bl fill ;;   ( -- : Zero/blank loaded block )
1343
: k [line] c/l blank ;         ( u -- : delete/Kill line )
1344
: s update flush ;             ( -- : Save changes to disk )
1345
: q editor-voc -order ;        ( -- : Quit editor )
1346
: x q blk-@ load editor ;      ( -- : eXecute/evaluate block )
1347
: ia c/l* + [block] + tib in@ + ( u u -- Insert At )
1348
   swap source nip in@ - cmove postpone \ ;
1349
: i 0 swap ia ;                ( u -- : Insert line )
1350
( : u update ;                 ( -- : set block set as dirty )
1351
( : w words ; )
1352
( : yank pad c/l ; )
1353
( : c [line] yank >r swap r> cmove ; )
1354
( : y [line] yank cmove ; )
1355
( : ct swap y c ; )
1356
( : xa [line] c/l evaluate ; )
1357
( : sw 2dup y [line] swap [line] swap c/l cmove c ; )
1358
[last] [t] editor-voc t! 0 tlast meta!
1359
 
1360
\ ============================================================================
1361
\ # Final Touches
1362
there [t] cp t!
1363
[t] (literal)      [v]  t! ( set literal execution vector )
1364
[t] (block)        [v]    t! ( set block execution vector )
1365
[t] (save)         [v]     t! ( set block execution vector )
1366
[t] cold 2/            0         t! ( set starting word in boot-loader )
1367
there    [t] header-length t! \ Set Length First!
1368
checksum [t] header-crc t!    \ Calculate image CRC
1369
finished
1370
bye

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.