[comp.lang.forth] attention Steve Sheppard part 3

rob@idacom.uucp (Rob Chapman) (02/23/90)

( bot-Forth kernel adapted for 68k: Dec 6, 1989  Rob Chapman )

HEX
( ==== Target status ==== )
  NO VARIABLE target	( target definition flag )

: TARGET  ( -- )  YES target !  ?CR CR ." TARGET definitions: " CR ;
: META     ( -- )  NO target !  ?CR CR ." META definitions: "   CR ;
: TARGET?  ( -- flag )  target @ ;

( ==== Target memory management ==== )
  ( data stack | return stack | dp | latest | words... )
  400 CONSTANT origin#			( address of start of kernel )
  DATA tspace 3000 ALLOT		( 12 kbytes target dict. space )
       tspace 200 + CONSTANT tdp	( target dictionary pointer )
       tspace 202 + CONSTANT tlatest 	( address of latest word )
      origin# 204 + tdp !  0 tlatest !	( initial values )

: T>HOST  ( target address -- host address )  origin# -  tspace + ;
: HOST>T  ( host address -- target address )  tspace -  origin# + ;

: THERE  ( -- target here )  tdp @ ;
: TALLOT  ( n -- )  tdp +!  THERE origin# - 2F00 >
   IF ." target space overflow " ABORT THEN ;

: TC!  ( n \ taddr -- )  T>HOST C! ;
: T!  ( n \ taddr -- )  T>HOST ! ;
: TC@  ( target address -- value )  T>HOST C@ ;
: T@  ( target address -- value )  T>HOST @ ;
: T+!  ( n \ taddr -- )  DUP >R T@ + R> T! ;

: TC,  ( char -- )  THERE TC!  1 TALLOT ;
: T,  ( word -- )  THERE T!  2 TALLOT ;
: EVEN  ( -- )  THERE 1 AND IF 0 TC, ENDIF ;

( ==== Dictionary searching ==== Header structure: | link | name | code ... | )
0 VARIABLE meta-start	( contains nfa of start of meta compilers )

: TL>CODE  ( lfa -- cfa )  T>HOST 2 +  COUNT 1F AND +  DUP 1 AND +  HOST>T ;  
: TC>LINK  ( code -- link )  T>HOST C>LINK HOST>T ;

: COMPARE  ( string \ name -- flag )  1F SAME? ;

: TFIND  ( string -- cfa \ yes | -- string \ no )  tlatest @
   BEGIN DUP WHILE
     2DUP T>HOST 2 + COMPARE IF NIP  TL>CODE YES  EXIT ENDIF   T@
   REPEAT ;
: META-FIND  ( string -- cfa \ yes | -- string \ no )  latest  meta-start @ >R
   BEGIN @ DUP R - WHILE
     2DUP  2 +  COMPARE IF SWAP  R> 2DROP  L>CODE  YES EXIT ENDIF
   REPEAT  R> 2DROP  NO ; 

META  LATEST meta-start !	( record beginning of meta compilers )
( ==== Mini assembler for 68k ==== )
( ==== Definitions for assembler ==== )
: AHERE  ( -- a )  TARGET? IF THERE  ELSE HERE ENDIF ;
: A!  ( n \ a -- )  TARGET? IF T!  ELSE ! ENDIF ;
: A,  ( word -- )  TARGET? IF T,  ELSE , ENDIF ;
: A+!  ( n \ a -- )  TARGET? IF T+! ELSE +! ENDIF ;

( ==== Register and mode definitions ==== )
: **  ( n \ m -- n )  FOR 2* NEXT ;
: MODE  ( mode -- )  <BUILDS  8000 OR  3 **  DUP 3 ** OR ,
   DOES ( reg -- )  DUP 9 ** OR  R> @ OR  CONSTANT IMMEDIATE ;

   0 MODE Dn       1 MODE An        2 MODE An@        3 MODE An@+
	0 Dn alu	0 An ptr	 0 An@ ptr@	   0 An@+ ptr@+
	5 Dn index	5 An page	 5 An@ page@	   5 An@+ page@+
 	6 Dn next	6 An sp          6 An@ sp@         6 An@+ sp@+
	7 Dn top	7 An rp          7 An@ rp@         7 An@+ rp@+

   4 MODE An-@     5 MODE dAn@      6 MODE +An@       7 MODE Other
	0 An-@ ptr-@	5 dAn@ dpage@	 5 +An@ +page@	   0 Other lit@
	6 An-@ sp-@					   2 Other dpc@
	7 An-@ rp-@					   4 Other lit

8 base !
( ==== Masks to extract mode and register information ==== )
: UPPER  ( n -- n )  7700 AND ;
: LOWER  ( n -- n )  0077 AND ;
: MODES  ( n -- n )  0770 AND ;
: REGS   ( n -- n )  7007 AND ;

HEX
( ==== Math ==== )
: extb  ( r -- )  REGS LOWER  4880 OR A, ; IMMEDIATE
: extw  ( r -- )  REGS LOWER  48C0 OR A, ; IMMEDIATE
: not  ( r -- )  LOWER  4640 OR A, ; IMMEDIATE
: neg  ( r -- )  LOWER  4440 OR A, ; IMMEDIATE
: ALU  ( n -- )  <BUILDS , IMMEDIATE
   DOES> ( r \ r \ a -- )  @ >R  DUP MODES ( not data?)
     IF rp LITERAL  OVER XOR  MODES ( not areg? )
        IF SWAP 100  ELSE R 80 AND ( long?)  IF 140 ELSE 80 THEN ENDIF  R> OR >R
     ENDIF  REGS UPPER  SWAP LOWER OR  R> OR A, ;

	8040 ALU or		C040 ALU and
	8000 ALU orb		C000 ALU andb
	9040 ALU sub		D040 ALU add
	9080 ALU subl

: eor  ( r \ r -- )    LOWER  SWAP  REGS UPPER OR  B140 OR A, ; IMMEDIATE
: addql  ( n \ r -- )  LOWER  SWAP 7 AND  9 ** OR  5080 OR  A, ; IMMEDIATE
: subq  ( n \ r -- )  LOWER  SWAP 7 AND  9 ** OR  5140 OR  A, ; IMMEDIATE

: 1SHIFT  ( n -- )  <BUILDS 1 9 ** OR , IMMEDIATE
   DOES  ( r -- )  REGS LOWER  R> @ OR A, ;
    E340 1SHIFT asl	E240 1SHIFT asr		E248 1SHIFT lsr

: mulu  ( s \ d -- )  REGS UPPER  SWAP LOWER OR  C0C0 OR A, ; IMMEDIATE
: divu  ( s \ d -- )  REGS UPPER  SWAP LOWER OR  80C0 OR A, ; IMMEDIATE

( ==== Comparison ==== )
  000 CONSTANT always
  500 CONSTANT carry
  600 CONSTANT notzero
  700 CONSTANT zero
  B00 CONSTANT minus
  C00 CONSTANT ge
  D00 CONSTANT lt

: difb  ( r \ r -- )  DUP MODES ( addr? ) ?ERROR  B000
   SWAP REGS UPPER OR  SWAP LOWER OR  A, ; IMMEDIATE
: dif  ( r \ r -- )  DUP MODES ( addr? ) IF B0C0  ELSE B040 ENDIF
   SWAP REGS UPPER OR  SWAP LOWER OR  A, ; IMMEDIATE
: scc  ( r \ c -- )  SWAP LOWER  OR  50C0 OR A, ; IMMEDIATE
: test  ( r -- )  LOWER  4A40 OR A, ; IMMEDIATE
: testb  ( r -- )  LOWER  4A00 OR A, ; IMMEDIATE
: invertz  ( -- )  0A3C A,  4 A, ; IMMEDIATE  ( lit ccr eorib [ 40 , ] )

( ==== Data movement ==== )
: swap  ( dn -- )  REGS LOWER  4840 OR A, ; IMMEDIATE
: moveb  ( r \ r -- )  UPPER  SWAP LOWER OR  1000 OR A, ; IMMEDIATE
: move   ( r \ r -- )  UPPER  SWAP LOWER OR  3000 OR A, ; IMMEDIATE
: movel  ( r \ r -- )  UPPER  SWAP LOWER OR  2000 OR A, ; IMMEDIATE
: moveq  ( n \ r -- )  REGS UPPER  7000 OR  SWAP FF AND OR A, ; IMMEDIATE
: exg  ( r \ r -- )  2DUP XOR MODES  ( mixed address and data modes? )
   IF OVER MODES ( addr? )  IF SWAP ( must be: exg dn,an) ENDIF  C188
   ELSE DUP MODES  C140 OR ENDIF
   >R  LOWER  SWAP UPPER OR  REGS  R> OR A, ; IMMEDIATE

( ==== Page relative data movement ==== )
: rd,  ( r \ d -- )  FF AND  SWAP C **  OR  A, ; IMMEDIATE
: r,  ( r -- )  0 \ rd, ; IMMEDIATE
: cfetch  ( r \ r -- )      \ +page@  SWAP  \ moveb     \ r, ; IMMEDIATE
: cstore  ( r \ r -- )  >R  \ +page@        \ moveb  R> \ r, ; IMMEDIATE
: fetch  ( r \ r -- )       \ +page@  SWAP  \ move     \ r, ; IMMEDIATE
: store  ( r \ r -- )   >R  \ +page@        \ move  R> \ r, ; IMMEDIATE
: pea  ( r -- )  \ +page@ LOWER  4840 OR A,  \ r, ; IMMEDIATE
: leal  ( r \ r -- )  REGS UPPER  SWAP LOWER OR  41C0 OR  A, ; IMMEDIATE
: lea  ( r \ r -- )  \ +page@ SWAP  \ leal  \ r, ; IMMEDIATE

( ==== Program counter ==== )
: nop  ( -- )  4E71 A, ; IMMEDIATE
: jump  ( r -- )  LOWER  4EC0 OR A, ; IMMEDIATE
: jsr   ( r -- )  LOWER  4E80 OR A, ; IMMEDIATE
: bsr   ( disp -- )  FF AND  6100 OR A, ; IMMEDIATE
: rts  ( -- )  4E75 A, ; IMMEDIATE
: bcc  ( cc -- )  6000 OR A, ;

: ?long  ( n -- n )  DUP ABS 7F U> IF ?CR ." long " ENDIF ;
: bcc> ( cc -- a )  THERE  SWAP bcc ;
: <bcc ( a \ cc -- )  SWAP THERE 2 +  - ?long  FF AND  OR  bcc ;

: begin  ( -- a )  THERE ;
: <br   ( a -- )  always <bcc ;
: <0br  ( a -- )  zero <bcc ;
: br>  ( -- a )  always bcc> ;
: if  ( -- a )  zero bcc> ;
: endif  ( a -- )  THERE OVER 2 +  - ?long  FF AND  SWAP A+! ;
: <dbr ( a \ dr -- )  REGS LOWER  51C8 OR A,  THERE - A, ;

( ==== Tools ==== )
: PUSH  ( -- n )  R> @+ >R ;
: >alu  ( n -- n )  PUSH top alu move A, ;
: alu>  ( n -- m )  PUSH alu top move A, ;

( ==== Automatic page register setting by using pc ==== )
: RAM  ( -- )  PUSH dpc@ page leal T,  THERE NEGATE T, ; SMUDGE

( ==== Meta Threader ==== )
  0 VARIABLE last  ( address of last compiled instruction )

: T'  ( -- cfa )  BL WORD  HERE TFIND 0= ?ERROR  \ LITERAL ; IMMEDIATE
: TMEASURE  ( -- )  tlatest @  THERE OVER TL>CODE - 2/  SWAP 2 - T+! ;

: TCALLED  ( -- )  80 tlatest @ 2 - T>HOST  +BITS ;
: TCOMPILE  ( cfa -- )  T>HOST  DUP C>LINK 2 - @  DUP 5 U< ( # to inline)
   IF  FOR  @+  SWAP T,  NEXT  DROP
   ELSE DROP  HOST>T  DUP THERE 2 + -  DUP ABS 80 U<
        IF \ bsr  DROP  TCALLED  ELSE  DROP  PUSH dpage@ jsr T,  T, THEN
   ENDIF ;
: TINSERT  ( string -- )  TFIND 0= ?ERROR  TCOMPILE ;
: TLITERAL  ( n -- )  " DUP" TINSERT  DUP ABS 80 U<
   IF \ top \ moveq  ELSE  PUSH lit top move  T,  T, ENDIF ;
: ]  ( -- )  TARGET? 0= IF ] EXIT ENDIF  0 last !
   BEGIN  BEGIN  BL WORD  HERE  DUP C@  WHILE  META-FIND 
      IF EXECUTE  0
      ELSE THERE  SWAP TFIND
           IF TCOMPILE  ELSE NUMBER TLITERAL ENDIF
      ENDIF  last !
   REPEAT DROP  INPUT-LINE  0 in !  AGAIN ;

( ==== Target word creators ==== )
: .NAME  ( lfa -- )  2 + COUNT 1F AND  out @ OVER + 2 + 4E >
   IF ?CR ENDIF  TYPE 2 SPACES ;
: THEADER  ( -- )  0 T,  THERE  tlatest @ T,  tlatest !
   BL WORD  HERE COUNT DUP>R  80 OR TC,  THERE T>HOST  R CMOVE  R> TALLOT EVEN
   tlatest @ T>HOST .NAME ;

: CONSTANT  ( n -- )  TARGET?
   IF THEADER  TLITERAL  TMEASURE  PUSH rts T,
   ELSE CONSTANT ENDIF ;
: VARIABLE  ( n -- )  TARGET?
   IF THEADER  " DUP" TINSERT
      PUSH lit top move T, THERE 0 T,  TMEASURE  PUSH rts T,  THERE SWAP T!  T,
   ELSE VARIABLE ENDIF ;
: QUEUE  ( #words -- )  TARGET? 0= IF QUEUE EXIT ENDIF
   0 VARIABLE -2 TALLOT  THERE 6 +  DUP T, T,  1 + 2*  DUP THERE + T,  TALLOT ;
   ( Queues: | >insert | >remove | >end | queue... | )

: V,  ( -- )  \ T'  DUP TC>LINK  2 - T@  2*  2 +  +  T, ; ( compile var address)
: TEXIT  ( -- )  last @ ?DUP
   IF T@  DUP FF00 AND  6100 =
      IF DROP  1 last @ T>HOST     -BITS  TCALLED  EXIT ENDIF
      FFC0 AND  4E80 =  IF      40 last @ T>HOST 1 + +BITS  TCALLED  EXIT ENDIF
   ENDIF  PUSH rts T, ; 
: :  ( -- )  TARGET? IF THEADER  ]  ELSE \ : ENDIF ; 
: ;  ( -- )  TMEASURE  TEXIT  R>DROP ; SMUDGE
: [  ( -- )  R>DROP ; SMUDGE
: \  ( -- )  BL WORD  HERE TFIND IF  TCOMPILE  ELSE ABORT  ENDIF ; SMUDGE
: EXIT  ( -- )  TEXIT ; SMUDGE
: '  ( -- )  \ T' TLITERAL ; SMUDGE
: (  ( -- )  \ ( ; SMUDGE
: IMMEDIATE  ( -- )
   TARGET? IF 40  tlatest @  2 +  T>HOST  +BITS  ELSE IMMEDIATE ENDIF ;

TARGET
( ==== Stacks ==== )
: SP!  ( ? -- )  lit alu move [ origin# 100 + T, ]  alu sp lea ;
: RP!  ( -- )    lit alu move [ origin# 1FC + T, ]  alu rp lea ;
: DEPTH  ( -- n )  sp alu movel  page alu subl  next sp-@ move  top next movel
   lit top move  [ origin# 100 + T, ]  alu top sub  top asr ;

( ==== Stack Operators ==== )
: SWAP  ( a \ b -- b \ a )  top next exg ;

: NUP  ( a \ b -- a \ a \ b )  next sp-@ move ;
: TUCK  ( a \ b -- b \ a \ b )  top sp-@ move ;
: DUP  ( n -- n \ n )  NUP  top next movel ;
: OVER  ( a \ b -- a \ b \ a )  SWAP TUCK ;

: NIP  ( a \ b -- b )  sp@+ next move ;
: DROP  ( n -- )  next top movel  NIP ;

: 2DUP  ( a \ b -- a \ b \ a \ b )  NUP TUCK ;
: 2DROP  ( a \ b -- )  sp@+ top move  NIP ;
: ROT  ( a \ b \ c -- b \ c \ a )
   sp@ alu move  next sp@ move  top next movel  alu top movel ;

META
( ==== Control structures ==== )
: IF  ( -- addr )  >alu  T' DROP TCOMPILE  PUSH alu test T, if ; SMUDGE
: ENDIF  ( addr -- )  endif ; SMUDGE
: ELSE  ( addr -- addr )  br>  SWAP endif ; SMUDGE
: THEN  ( addr -- )  endif ; SMUDGE

: BEGIN  ( -- addr )  begin ;  SMUDGE
: UNTIL  ( addr -- )  >alu  T' DROP TCOMPILE  PUSH alu test T, <0br ; SMUDGE
: AGAIN  ( addr -- )  <br ; SMUDGE

( BEGIN ... top test  if DROP  ...  <br endif  DROP )
( BEGIN ...        WHILE       ...        REPEAT      )
: WHILE  ( -- addr )  >alu  if  T' DROP TCOMPILE ; SMUDGE
: REPEAT ( addr \ addr -- )  SWAP <br  endif  T' DROP TCOMPILE ; SMUDGE

: FOR  ( -- a )  PUSH index rp-@ move T,  PUSH top index move T,
   T' DROP TCOMPILE   br> ; SMUDGE
: NEXT  ( a -- )  DUP endif
   2 +  index LITERAL  <dbr  PUSH rp@+ index move A, ; SMUDGE

TARGET
( ==== Return stack primitives ==== )
: DUP>R  ( n -- n )  top pea ;
: R>DROP  ( -- )  [ 4 ] rp addql ;
: >R  ( n -- )   DUP>R  DROP ;
: R>  ( -- n )  DUP  rp@+ top movel  page top sub ;
: R   ( -- n )  DUP  rp@  top movel  page top sub ;

: EXECUTE  ( cfa -- )  >alu  DROP  +page@ jsr  alu r, ;

( ==== Arithmetic operators ==== )
: +  ( a \ b -- c )  next top add  NIP ;
: -  ( a \ b -- c )  top next sub  DROP ;
: AND  ( a \ b -- c )  next top and  NIP ;
: OR   ( a \ b -- c )  next top or   NIP ;
: XOR  ( a \ b -- c )  next top eor  NIP ;

: 2*  ( n -- m )  top asl ;
: 2/  ( n -- m )  top asr ;
: U2/  ( n -- n )  top lsr ;
: NEGATE  ( n -- -n )  top neg ;
: NOT  ( n -- m )  top not ;

META
( ==== Optimizers ==== )
: SEQ  ( n -- )  <BUILDS , ( # of bytes to compare )
   DOES> ( seq -- f )  NO >R  last @ ?DUP
   IF T>HOST  SWAP @+ SWAP  R> SWAP FOR  >R  DIFFER?  R> OR  NEXT  0=  NIP NIP
   ELSE DROP  R> ENDIF ;

  6 SEQ LIT?  next sp-@ move  top next movel  lit top move
  5 SEQ SLIT? next sp-@ move  top next movel  0 top moveq

: UNLIT?  ( -- [n] \ f )  SLIT?  IF  THERE 1 - TC@  YES  -6 TALLOT  EXIT ENDIF
   LIT?  IF  THERE 2 - T@  YES  -8 TALLOT  EXIT ENDIF  NO ;
   
: +  ( -- )  UNLIT?
   IF DUP 9 U<  IF  \ top \ addql  ELSE  PUSH lit top add T,  T, ENDIF
   ELSE  T' + TCOMPILE  ENDIF ; SMUDGE
: -  ( -- )  UNLIT?
   IF DUP 9 U<  IF  \ top \ subq   ELSE  PUSH lit top sub T,  T, ENDIF
   ELSE  T' - TCOMPILE  ENDIF ; SMUDGE
: AND  ( -- )  UNLIT?
   IF PUSH lit top and T,  T,  ELSE  T' AND TCOMPILE  ENDIF ; SMUDGE

TARGET
( ==== Memory primitives ==== )
: @  ( a -- n )  top top fetch ;
: !  ( n \ a -- )  next top store  2DROP ;
: C@  ( a -- n )  top top cfetch  FF AND ;
: C!  ( n \ a -- )  next top cstore  2DROP ;

META
( ==== Memory optimizers ==== )
: @  ( -- )  UNLIT?
   IF T' DUP TCOMPILE  PUSH dpage@ top move T,  T,
   ELSE T' @ TCOMPILE ENDIF ; SMUDGE
: !  ( -- )  UNLIT?
   IF PUSH top dpage@ move T,  T,  T' DROP  ELSE T' ! ENDIF  TCOMPILE ; SMUDGE
: C@  ( -- )  UNLIT?
   IF T' DUP TCOMPILE  0 \ top \ moveq  PUSH dpage@ top moveb T,  T,
   ELSE T' C@ TCOMPILE ENDIF ; SMUDGE
: C!  ( -- )  UNLIT?
   IF PUSH top dpage@ moveb T,  T,  T' DROP  ELSE T' C! ENDIF  TCOMPILE ; SMUDGE

TARGET
( ==== Incrementing/Decrementing memory operators ==== )
: @+  ( a -- n \ a+ )  NUP  top next fetch  2 + ;
: @-  ( a -- n \ a- )  NUP  top next fetch  2 - ;
: C@+ ( a -- c \ a+ )  NUP  [ 0 ] next moveq  top next cfetch  1 + ;
: C@- ( a -- c \ a- )  NUP  [ 0 ] next moveq  top next cfetch  1 - ;
: !+  ( n \ a -- a+ )  next top store  NIP  2 + ;
: !-  ( n \ a -- a- )  next top store  NIP  2 - ;
: C!+ ( c \ a -- a+ )  next top cstore  NIP  1 + ;
: C!- ( c \ a -- a- )  next top cstore  NIP  1 - ;

( ==== signed multiply and unsigned divide ==== )
: /MOD  ( n \ m -- rem \ quot )  next swap  next next eor  next swap
   top next divu  next top movel  next swap ;
: /  ( m \ n -- quot )  next swap  next next eor  next swap
   top next divu  DROP ;
: MOD  ( n \ m -- rem )  /  top swap ;

: *  ( n \ m -- nm* )  next top mulu  NIP ;

( ==== Comparison ==== )
   0 CONSTANT NO
  -1 CONSTANT YES

: 0=  ( n -- f )  top test  top zero scc  top extb ;
: 0<  ( n -- f )  top test  top minus scc  top extb ;

: =   ( n \ m -- flag )  top next dif  top zero scc   top extb  NIP ;
: <   ( n \ m -- flag )  top next dif  top lt scc     top extb  NIP ;
: >   ( n \ m -- flag )  next top dif  top lt scc     top extb  NIP ;
: U<  ( n \ m -- flag )  top next dif  top carry scc  top extb  NIP ;
: U>  ( n \ m -- flag )  next top dif  top carry scc  top extb  NIP ;

: ABS  ( n -- n )  top test  ge bcc>  top neg  endif ;
: MAX  ( n \ m -- p )  top next dif  lt bcc>  DROP  EXIT  endif  NIP ;
: MIN  ( n \ m -- p )  next top dif  lt bcc>  DROP  EXIT  endif  NIP ;
: ?DUP  ( n -- [n] \ n )  top test  if DUP endif ;

( ==== Memory Manipulation ==== )
  20 CONSTANT BL

: COUNT  ( addr -- addr' \ count )  C@+ SWAP ;
: CMOVE  ( s \ d \ count -- )  next ptr lea  NIP  page alu movel  next page lea
   FOR  page@+ ptr@+ moveb  NEXT  alu page movel  DROP ;
: <CMOVE  ( src \ dest \ count -- )  >R  SWAP R 1 - +  SWAP R 1 - +
   R> FOR >R  C@- SWAP  R> C!-  NEXT 2DROP ;
: MOVE  ( src \ dest \ count -- )  FOR >R @+ SWAP R> !+ NEXT 2DROP ;

: FILL  ( addr \ count \ char -- )
   >alu  DROP  FOR  alu next cstore  [ 1 ] next addql  NEXT  2DROP ;
: ERASE ( addr \ count -- )  0 FILL ;
: BLANKS ( addr \ count -- )  BL FILL ;

( ==== Memory Management ==== )
  origin# 200 + CONSTANT dp	  	  ( dictionary pointer )

: +!  ( n \ addr -- )  next +page@ add  top r,  2DROP ;

: HERE  ( -- addr )  dp @ ;
: ALLOT  ( n -- )  dp +! ;

: ,  ( n -- )  HERE !  2 ALLOT ;
: C,  ( n -- )  HERE C!  1 ALLOT ;
: EVEN  ( -- )  HERE 1 AND IF 0 C, ENDIF ;

( ==== Header Status Bits ==== )
  origin# 202 + CONSTANT latest

: +BITS  ( bits \ addr -- )  next +page@ orb  top r,  2DROP ;
: -BITS  ( bits \ addr -- )  next not  next +page@ andb  top r,  2DROP ;

: LATEST ( -- nfa )  latest @ ;
: IMMEDIATE ( -- )  40 LATEST 2 + +BITS ;
: SMUDGE    ( -- )  20 LATEST 2 + +BITS ;
: RECURSE   ( -- )  20 LATEST 2 + -BITS ; IMMEDIATE

( ==== State ==== )
 0 VARIABLE compile	( set to 80 if compiling; immediate words are C0 )

: ]  ( -- )  80 compile ! ;
: [  ( -- )  0 compile ! ; IMMEDIATE

( ==== Queues ===== )
: >Q  ( n \ queue -- )  top alu fetch
   4 +  [ 2 ] alu subq  top alu dif
   if  alu +page@ move  top [ -4 ] rd,
   ELSE  +page@ +page@ move  top r,  top [ -4 ] rd,  ENDIF
   next +page@ move  alu [ 2 ] rd,  2DROP ;
: Q>  ( queue -- n )  +page@ alu move  top [ 2 ] rd,
   4 +  [ 2 ] alu subq  top alu dif
   if  alu +page@ move  top [ -2 ] rd,
   ELSE  +page@ +page@ move  top r,  top [ -2 ] rd,  ENDIF
   +page@ top move  alu [ 2 ] rd, ;
: Q  ( queue -- n )  +page@ top move  top [ 2 ] rd,  @ ;

: 0Q  ( queue -- )  +page@ +page@ move  top r,  top [ 2 ] rd,  DROP ;
: Q?  ( queue -- n )
   @+ @+ >R  SWAP -  DUP 0< IF  R @  R> -  + 2/ EXIT ENDIF  R>DROP  2/ ;

( ==== BARON Tasker ==== )
  80 QUEUE peasantq	( maximum of 80H peasants )

: >BARON  ( cfa -- )  peasantq >Q ;
: BARON  ( -- )  peasantq Q> EXECUTE ;

: KILL  ( cfa -- )  peasantq  DUP Q?
   FOR  DUP>R Q>  2DUP - IF  R >Q  ELSE DROP  ENDIF  R>  NEXT  2DROP ;
: RUN  ( cfa -- )  DUP KILL  >BARON ;

( ==== Forth character I/O ==== )
  100 QUEUE keyq   ( 256; enough for one string )
  100 QUEUE emitq  ( 256; enough for one string )
    0 VARIABLE out ( characters output since last cr )

: KEY?  ( -- flag )  keyq Q? ;
: KEY   ( -- char )  BEGIN  KEY? 0=  WHILE  BARON  REPEAT  keyq Q> ;

: ?WAIT  ( -- )  BEGIN emitq Q? 100 = WHILE BARON  REPEAT ;
: EMIT  ( char -- )  >R  ?WAIT  out @
   R A -  IF  R 8 =  IF  1 -  ELSE  R D =  IF  DROP 0  ELSE  1 +
          ENDIF      ENDIF                 ENDIF  out !  R> emitq >Q ;

: CR  ( -- )  D EMIT  A EMIT ;
: SPACE ( -- )  BL EMIT ;
: SPACES  ( n -- )  0 MAX  FOR SPACE NEXT ;
: TYPE ( addr \ count -- )  FOR  C@+  SWAP EMIT  NEXT  DROP ;

( ==== Numerical Output ==== )
  10 VARIABLE base

: HEX  ( -- )  10 base ! ;
: BIN  ( -- )  2 base ! ;
: DECIMAL  ( -- )  A base ! ;

: PAD ( -- addr )  HERE 50 + ;
: HOLD  ( char -- )  -1 PAD +!  PAD @ C! ;

: <#  ( -- )  PAD DUP ! ;
: #>  ( n -- addr \ count )  DROP PAD @ PAD OVER - ;
: SIGN  ( m \ n -- n )  SWAP 0< IF 2D HOLD ENDIF ;
: #  ( n -- n )  base @ /MOD  SWAP  9 OVER <  IF 7 + ENDIF  30 +  HOLD ;
: #S  ( n -- n )  BEGIN # DUP 0= UNTIL ;

: .R  ( n \ m -- )  >R  <# base @ A = IF DUP ABS #S SIGN ELSE #S ENDIF #>
   R> OVER - SPACES TYPE ;
: .  ( n -- )  0 .R SPACE ;

( ==== Parser ==== )
  0 VARIABLE tib  52 TALLOT  ( tib points to terminal input buffer )
  0 VARIABLE in		     ( index into TIB )

: INPUT  ( -- addr )  DUP  dpage@ top move  V, tib  dpage@ top add  V, in ;
: +IN  ( addr -- )  dpage@ ptr move  V, tib  dpage@ ptr add  V, in  ptr top sub
   lit alu move  V, in  top +page@ add  alu r,  DROP ;

: SKIP  ( char -- )  INPUT  top ptr lea
   begin  ptr@+ alu moveb  if  next alu difb  invertz  endif  notzero <bcc
   page ptr subl  [ 1 ] ptr subq  ptr top move  NIP  +IN ;
: SCAN  ( char -- )  INPUT  top ptr lea
   begin  ptr@+ alu moveb  if  next alu difb  endif  notzero <bcc
   page ptr subl  alu testb  notzero bcc>  [ 1 ] ptr subq  endif
   ptr top move  NIP  +IN ;

: PARSE  ( char -- )  INPUT  top ptr lea  HERE  NIP
   begin  ptr@+ alu moveb
          if  1 +  alu top cstore  next alu difb  endif
   notzero <bcc
   alu testb  if 1 -  ELSE  [ 1 ] ptr subq  endif
   HERE -  HERE C!  page ptr subl  ptr top move  +IN ;

: WORD  ( char -- )  DUP SKIP PARSE ;
: (  ( -- )  29 SCAN ; IMMEDIATE

( ==== Word compiler ==== )
: PUSH  ( -- n )  DUP  lit top move ;
: C>LINK  ( code -- link )  BEGIN 2 - DUP C@  80 AND  UNTIL  2 - ;
: L>CODE  ( link -- code )  2 +  C@+ SWAP  1F AND  +  EVEN ;
: COMPILE  ( cfa -- )  DUP C>LINK 2 - @  DUP 6 U< ( # to inline)
   IF  FOR  @+ SWAP ,  NEXT  DROP  ELSE  DROP  \ PUSH dpage@ jsr  ,  , ENDIF ;

( ==== Strings ==== )
: QUOTE  ( -- )  22 PARSE  HERE C@ 1 + ALLOT  EVEN ;
: (")  ( -- addr )  R  DUP C@ 2 +  -2 AND  R> + >R ;
: "  ( -- [addr] )  compile @
   IF ' (") COMPILE  ELSE HERE ENDIF  QUOTE ; IMMEDIATE
: (.")  ( -- )  R COUNT  DUP 2 +  -2 AND  R> + >R  TYPE ;
: ."  ( -- )  compile @ IF ' (.") COMPILE  QUOTE
   ELSE 22 PARSE  HERE COUNT TYPE  ENDIF ; IMMEDIATE

META
: ."  ( -- )  T' (.") TCOMPILE  22 WORD HERE
   COUNT >R  R TC,  THERE T>HOST R CMOVE  R> TALLOT  EVEN ; SMUDGE

TARGET
( ==== Errors ==== )
: ABORT  ( -- )  RP! ;
: ERROR  ( -- )  HERE COUNT TYPE  ." <- eh?" ABORT ;
: ?ERROR  ( flag -- )  IF ERROR ENDIF ;

( ==== Number Conversion ==== )
: DIGIT  ( char -- n \ flag )
   30 -  DUP 9 >  IF 7 -  DUP A <  OR ENDIF  DUP base @ U< ;
: NUMBER  ( string -- n )  COUNT >R  COUNT 2D = TUCK
   IF R> 1 - >R  ELSE 1 -  ENDIF  0 SWAP
   R> FOR C@+ >R  DIGIT NOT ?ERROR  SWAP base @ * +  R> NEXT DROP
   SWAP IF NEGATE ENDIF ;

( ==== Dictionary Searching ==== )
: C>LINK  ( code -- link )  BEGIN 2 - DUP C@  80 AND  UNTIL  2 - ;
: L>CODE  ( link -- code )  2 +  C@+ SWAP  1F AND +  DUP 1 AND + ;

: DIFFER?  ( a \ a -- a+ \ a+ \ f )
   +page@ alu moveb  next r,  [ 1 ] next addql  DUP
   +page@ top moveb  next r,  [ 1 ] next addql  alu top eor  top extb ;
: BIT-DIFFER?  ( a \ a \ mask -- a+ \ a+ \ f )  >R  DIFFER?  R> AND ;
: SAME?  ( string \ name \ mask -- flag )  BIT-DIFFER? IF 2DROP NO EXIT ENDIF
   OVER 1 - C@ 
   FOR  DIFFER?  IF 2DROP  NO  rp@+ index move  EXIT  ENDIF  NEXT  2DROP YES ;
: COMPARE  ( string \ name -- flag )  3F SAME? ;

: SEARCH?  ( string \ >list -- lfa \ yes | -- string \ no )  
   BEGIN @ ?DUP WHILE  2DUP 2 + COMPARE  IF NIP YES EXIT ENDIF  REPEAT  NO ;

: FIND?  ( -- cfa \ status | -- string \ no )  BL WORD
   HERE latest SEARCH?  DUP IF DROP  DUP L>CODE  SWAP 2 + C@  E0 AND  ENDIF ;
: ?FIND  ( -- addr )  FIND? 0= ?ERROR ;

( ==== Interpreter ==== )
: \  ( -- )  ?FIND  COMPILE ; IMMEDIATE
: LITERAL  ( n -- )  compile @ IF ' PUSH COMPILE  , ENDIF ; IMMEDIATE

: '  ( -- pfa )  ?FIND  \ LITERAL ; IMMEDIATE

: INTERPRET  ( -- )
   BEGIN
       BEGIN FIND? ?DUP WHILE
         compile @ = IF COMPILE  ELSE EXECUTE ENDIF
       REPEAT
   DUP C@ WHILE  NUMBER \ LITERAL  REPEAT  DROP ;

( ==== Key collector ==== )
: ?CR  ( -- )  dpage@ test V, out  if CR endif ;
: PROMPT  ( -- )  ?CR  compile @ IF ."    : "  ELSE ." 68k: " ENDIF ;
: PREPARE  ( key -- key )  DUP 1A >
   IF out @ 4E <  IF DUP INPUT C!+ +IN  ELSE DROP 7 ENDIF  EXIT ENDIF
   DUP D = IF DROP 0  0 INPUT C!  EXIT ENDIF
   DUP 8 = IF in @ ?DUP  IF 1 - in !  ELSE DROP 7 ENDIF  EXIT ENDIF
   DROP 7 ;
: COLLECTOR  ( -- )
   KEY? IF KEY PREPARE  ?DUP
           IF EMIT  ELSE  SPACE  0 in !  INTERPRET 0 in !  PROMPT  ENDIF
        ENDIF  ' COLLECTOR >BARON ;

( ==== SIO access on page 1 ==== )
: SIO  ( -- )  lit page movel [ 1 T, tspace T, ( insert real sio addr here) ] ;
: SIO@  ( a -- c )  SIO  C@  RAM ;
: SIO!  ( c \ a -- )  SIO  C!  RAM ;

( ==== SIO chip: DUART SCN2681 with a 3.6864mhz crystal ==== )
: RESET-SIO   ( -- )  SIO  ( set page reg. to base address of sio chip )
   10  DUP 02 C!  0A C! ( command register: reset MR pointer )
   20  DUP 02 C!  0A C!                   ( reset receiver )
   30  DUP 02 C!  0A C!                   ( reset transmitter )
   40  DUP 02 C!  0A C!                   ( reset error status )
   50  DUP 02 C!  0A C!                   ( reset break status )
   13  DUP 00 C!  08 C! ( mode register 1: 8bits no parity )
   07  DUP 00 C!  08 C! ( mode register 2: 1 stop bit )
   BB  DUP 01 C!  09 C! ( 9600 baud )
   05  DUP 02 C!  0A C!                   ( enable transmitter/receiver )
   24 05 C!  ( interrupt mask register: channel breaks; channel b input )
   FF 0F C!  ( reset output port bits )  RAM ;

( ==== SIO porta primitives ==== )
: RX?  ( -- flag )  01 SIO@  1 AND ;
: TX?  ( -- flag )  01 SIO@  8 AND ;
: TX  ( char -- )  03 SIO! ;
: RX  ( -- char )  03 SIO@ ;

( ==== Sio port servicing ==== )
  0 VARIABLE sio-in	( points to queue used to hold input )
  0 VARIABLE sio-out	( points to queue used to hold output )

: POLL-SIO  ( -- )  RX? IF  RX  sio-in @ >Q  ENDIF  
   sio-out @ Q? IF  TX? IF  sio-out @ Q>  TX  THEN ENDIF  ' POLL-SIO >BARON ;

( ==== Control loop ==== )
: INIT  ( -- )  keyq 0Q  0 in !  tib 2 + tib !  0 INPUT C!  RESET-SIO
   keyq sio-in !  emitq sio-out !  ' POLL-SIO RUN   ' COLLECTOR RUN ;

: QUIT  ( -- )  RAM  SP!  RP!  R>DROP  ' QUIT >R ( for error return )  \ [
   INIT  CR PROMPT  BEGIN BARON AGAIN ;

( ==== Conditionals ==== )
: 0BRANCH  ( n -- )  >alu  DROP  alu test  zero bcc ;
: BRANCH  ( -- )  always bcc ;

: IF  ( -- addr )  ' 0BRANCH COMPILE  HERE 0 , ; IMMEDIATE
: ENDIF  ( addr -- )  HERE OVER -  SWAP ! ; IMMEDIATE
: ELSE  ( addr -- addr )  ' BRANCH COMPILE  HERE 0 ,  SWAP \ ENDIF ; IMMEDIATE
: THEN  ( addr -- )  \ ENDIF ; IMMEDIATE

: BEGIN  ( -- addr )  HERE ;  IMMEDIATE
: UNTIL  ( addr -- )  ' 0BRANCH COMPILE  HERE - , ; IMMEDIATE
: AGAIN  ( addr -- )  ' BRANCH COMPILE  HERE - , ; IMMEDIATE

: WHILE  ( -- addr )  \ IF ; IMMEDIATE
: REPEAT  ( addr \ addr -- )  SWAP  \ AGAIN  \ ENDIF ; IMMEDIATE

: (FOR)  ( n -- )  index rp-@ move  top index move  DROP  BRANCH ;
: (NEXT)  ( -- )  [ 0 ] index <dbr  rp@+ index move ;
: FOR  ( -- a )  ' (FOR) COMPILE  HERE 0 , ; IMMEDIATE
: NEXT  ( a -- )  DUP \ ENDIF  2 +
   ' (NEXT) COMPILE  HERE 4 -  DUP>R  -  R> ! ; IMMEDIATE

( ==== Defining Words ==== )
: CALLED  ( -- )  80  latest @ 2 -  +BITS ;
: MEASURE  ( -- )  latest @  HERE OVER L>CODE - 2/  SWAP 2 - ! ;
: ?UNIQUE  ( -- )  FIND? IF HERE COUNT TYPE ."  is not unique.  "
   ELSE  DUP C@ 0= ?ERROR  ENDIF  DROP ;
: HEADER  ( -- )  EVEN  0 ,  HERE latest @ ,  ?UNIQUE  latest !
   HERE C@ DUP 80 OR C,  ALLOT EVEN ;
: FORGET ( -- )  ?FIND C>LINK  DUP @ latest !  HERE -  2 - ALLOT ;

: EXIT  ( -- )  rts ;

: :  ( -- )  HEADER  SMUDGE  \ ] ;
: ;  ( -- )  MEASURE  ' EXIT COMPILE  \ [  \ RECURSE ; IMMEDIATE

: DATA  ( -- )  \ :  ' PUSH COMPILE  HERE 0 ,  \ ;  HERE SWAP ! ;
: VARIABLE  ( n -- )  DATA , ;
: CONSTANT  ( n -- )  \ :  \ LITERAL  \ ; ;

: <BUILDS  ( -- )  HEADER  CALLED  ' ERROR COMPILE ;
: DOES  ( -- )  R> LATEST L>CODE 2 + ! ;
: DOES>  ( -- addr )  ' DOES COMPILE  ' R> COMPILE ; IMMEDIATE

: QUEUE  ( #words -- ) ( Queues: | >insert | >remove | >end | queue... | )
   DATA  HERE 6 +  DUP , ,  1 + 2*  DUP HERE + ,  ALLOT ;

( ==== File Loader: FF emitted to request a line of input ==== )
: INPUT-LINE  ( -- )  FF EMIT  ( signal for input )
   0 in !  INPUT  BEGIN KEY DUP D - WHILE SWAP C!+ REPEAT DROP  0 SWAP C! ;
: LD  ( -- )  BEGIN  INPUT-LINE INTERPRET AGAIN ;

( ==== Version ==== )
: VERSION  ( -- )  ." 68k-Forth V.14" ;  ( derived from 68k-Forth V.13 )
( ==== End of kernel ==== )

CR THERE origin# - .D ." bytes."  META
QUIT