commit bd6172d0e89eaa8699b091676ef6f830eb1edf35
parent 43ca2ad80219e69f81495e95a89fbe7a15e4699b
Author: Virgil Dupras <hsoft@hardcoded.net>
Date: Wed, 21 Sep 2022 10:52:48 -0400
app/cos: import blk.fs from latest COS snapshot
The CRC32 checksum for the packed version matches!
Diffstat:
2 files changed, 1405 insertions(+), 8 deletions(-)
diff --git a/fs/app/cos/blk.fs b/fs/app/cos/blk.fs
@@ -1,3 +1,1398 @@
( ----- 000 )
-Hello...
-World!
+MASTER INDEX
+
+001 Useful little words 010 RX/TX tools
+020 Block editor 035 Memory Editor
+040 AVR SPI programmer 045 Sega ROM signer
+050 Virgil's workspace 060-199 unused
+200 Cross compilation
+210 Core words 230 BLK subsystem
+235 RX/TX subsystem 237 Media Span subsystem
+240 Grid subsystem
+245 PS/2 keyboard subsystem 250 SD Card subsystem
+260 Fonts 280-289 unused
+290 Automated tests 300 Arch-specific content
+( ----- 001 )
+\ Useful little words. CRC16[] MOVE-
+'? CRC16[] [IF] \S [THEN]
+\ Compute CRC16 over a memory range
+: CRC16[] ( a u -- c ) >R >A 0 BEGIN AC@+ CRC16 NEXT ;
+: MOVE- ( a1 a2 u -- ) \ *A* MOVE starting from the end
+ ?DUP IF >R OVER - ( a1 diff ) SWAP R@ + >A
+ BEGIN ( diff ) A- A> OVER + AC@ SWAP C! NEXT DROP
+ ELSE 2DROP THEN ;
+( ----- 002 )
+\ Useful little words. MEM>BLK BLK>MEM
+\ *A* Copy an area of memory into blocks.
+: MEM>BLK ( addr blkno blkcnt )
+ >R BEGIN ( a blk )
+ DUP BLK@ 1+ SWAP DUP BLK( $400 MOVE BLK!! $400 + SWAP NEXT
+ DROP FLUSH ;
+\ *A* Copy subsequent blocks in an area of memory
+: BLK>MEM ( blkno blkcnt addr )
+ ROT> >R BEGIN ( a blk )
+ DUP BLK@ 1+ SWAP BLK( OVER $400 MOVE $400 + SWAP NEXT
+ DROP ;
+( ----- 003 )
+\ Context. Allows multiple concurrent dictionaries.
+\ See doc/usage.txt
+
+0 VALUE saveto \ where to save CURRENT in next switch
+: context DOER CURRENT , DOES> ( a -- )
+ saveto IF CURRENT TO saveto THEN ( a )
+ DUP TO saveto ( a )
+ @ CURRENT ! ;
+( ----- 004 )
+\ string manipulation.
+'? >s [IF] \S [THEN]
+2 VALUES sa sl
+: >s ( sa sl -- ) TO sl TO sa ; : s> sa sl ;
+: cutr ( n -- ) sl -^ DUP 0< IF DROP 0 THEN TO sl ;
+: cutl ( n -- ) sl SWAP cutr sl - sa + TO sa ;
+: prefix? ( sa sl -- f )
+ DUP sl > IF 2DROP 0 EXIT THEN sa ROT> []= ;
+: suffix? ( sa sl -- f )
+ DUP sl > IF 2DROP 0 EXIT THEN sl OVER - ( sa sl off ) sa +
+ ( sa sl sa2 ) SWAP []= ;
+( ----- 005 )
+\ Word table. See doc/wordtbl
+: WORDTBL ( n -- a ) CREATE HERE SWAP << ALLOT0 1 HERE C! ;
+: W+ ( a -- a+2? ) 1+ 1+ DUP @ IF DROP THEN ;
+: :W ( a -- a+2? ) HERE XTCOMP OVER ! W+ ;
+: 'W ( a -- a+2? ) ' OVER ! W+ ;
+: WEXEC ( tbl idx -- ) << + @ EXECUTE ;
+( ----- 006 )
+\ Pager. See doc/pager
+4 VALUES ''EMIT ''KEY? chrcnt lncnt
+20 VALUE PGSZ
+: realKEY BEGIN ''KEY? EXECUTE UNTIL ;
+: back ''EMIT 'EMIT ! ''KEY? 'KEY? ! ;
+: emit ( c -- )
+ chrcnt 1+ TO chrcnt
+ DUP CR = chrcnt LNSZ = OR IF
+ 0 TO chrcnt lncnt 1+ TO lncnt THEN
+ ''EMIT EXECUTE lncnt PGSZ = IF
+ 0 TO lncnt NL> ." Press q to quit, any key otherwise" NL>
+ realKEY 'q' = IF back QUIT THEN THEN ;
+: key? back KEY? ;
+: page 'EMIT @ TO ''EMIT 'KEY? @ TO ''KEY?
+ ['] emit 'EMIT ! ['] key? 'KEY? ! ;
+( ----- 007 )
+\ Flow words
+'? PC NOT [IF] ALIAS HERE PC [THEN]
+'? PC2A NOT [IF] : PC2A ; [THEN]
+ALIAS PC BEGIN,
+: LSET PC TO ;
+: BR PC - 2 - _bchk ;
+: FJR BEGIN, 1+ 0 ;
+: IFZ, FJR JRNZi, ; : IFNZ, FJR JRZi, ;
+: IFC, FJR JRNCi, ; : IFNC, FJR JRCi, ;
+\ warning: l is a PC value, not a mem addr!
+\ also, in 6502, JRi, is 3b instead of 2, hence the hack.
+: FMARK ( l -- ) PC2A DUP C@ IF ( hack ) 1+ THEN DUP HERE -^ 1-
+ SWAP C! ;
+: THEN, FMARK ; : ELSE, FJR JRi, SWAP FMARK ;
+( ----- 010 )
+\ Communicate blocks with block server. See doc/blksrv.
+CREATE h16 '$' C, 4 ALLOT
+: RX>h16 ( -- n ) \ *A*
+ h16 1+ >A 4 >R BEGIN RX< DUP EMIT SPC> AC!+ NEXT
+ h16 5 PARSE NOT IF 0 THEN ;
+: csumchk ( c1 c2 ) = NOT IF ABORT" bad csum" THEN ;
+: blksrv< ( blkno -- ) \ *A*
+ RX<< TX[ 'G' EMIT .X ]TX 0 ( csum ) BLK( >A 1024 >R BEGIN
+ RX< DUP AC!+ + NEXT RX>h16 csumchk ;
+: blksrv> ( blkno -- ) \ *A*
+ RX<< TX[ 'P' EMIT .X ]TX 0 ( csum ) BLK( >A 1024 >R BEGIN
+ AC@+ DUP TX> + NEXT TX[ .X ]TX ;
+( ----- 011 )
+\ Remote shell. See doc/rxtx
+: RX<?? RX<? ?DUP NOT IF 100 TICKS RX<? THEN ;
+: _<< \ print everything available from RX<?
+ BEGIN RX<?? IF EMIT ELSE EXIT THEN AGAIN ;
+: _<<1r RX< EMIT _<< ;
+: rsh BEGIN
+ KEY? IF DUP EOT = IF DROP EXIT ELSE TX> THEN THEN _<< AGAIN ;
+( ----- 012 )
+\ rupload. See doc/rxtx
+: CR> CR EMIT ;
+: unpack DUP $f0 OR SWAP $0f OR ;
+: out unpack TX> TX> ; : out2 L|M out out ;
+: rdok \ read RX until after "ok"
+ BEGIN RX< WS? NOT UNTIL _<<1r ;
+: rupload ( loca rema u -- )
+ TX[ ." : in KEY $f0 AND KEY $0f AND OR ;" CR> rdok
+ ." : in2 in <<8 in OR ;" CR> rdok
+ \ sig: chk -- chk, a and then u are KEYed in
+ ." : _ in2 >A in2 >R BEGIN in TUCK + SWAP AC!+ NEXT ;"
+ CR> rdok DUP ROT ( loca u u rema )
+ ." 0 _" CR> out2 out2 ]TX
+ >R >A 0 BEGIN ( chk ) '.' EMIT AC@ out AC@+ + NEXT
+ _<<1r TX[ ." .X FORGET in" CR> ]TX rdok .X ;
+( ----- 013 )
+\ XMODEM routines. See doc/rxtx
+: _<<s BEGIN RX<? IF DROP ELSE EXIT THEN AGAIN ;
+: _rx>mem1 ( addr -- f, Receive single packet, f=eot )
+ RX< 1 = NOT IF ( EOT ) $6 ( ACK ) TX> 1 EXIT THEN
+ '.' EMIT RX< RX< 2DROP ( packet num )
+ >A 0 ( crc ) 128 >R BEGIN ( crc )
+ RX< DUP ( crc n n ) AC!+ ( crc n ) CRC16 NEXT
+ RX< <<8 RX< OR ( sender's CRC )
+ = IF $6 ( ACK ) ELSE $15 'N' EMIT ( NACK ) THEN TX> 0 ;
+: RX>MEM ( addr --, Receive packets into addr until EOT )
+ _<<s 'C' TX> BEGIN ( a )
+ DUP _rx>mem1 SWAP 128 + SWAP UNTIL DROP ;
+: RX>BLK ( -- )
+ _<<s 'C' TX> BLK( BEGIN ( a )
+ DUP BLK) = IF DROP BLK( BLK! BLK> 1+ 'BLK> ! THEN
+ DUP _rx>mem1 SWAP 128 + SWAP UNTIL 2DROP ;
+( ----- 014 )
+: _snd128 ( A:a -- A:a )
+ 0 128 >R BEGIN ( crc )
+ AC@+ DUP TX> ( crc n ) CRC16 ( crc ) NEXT
+ L|M TX> TX> ;
+: _ack? 0 BEGIN DROP RX< DUP 'C' = NOT UNTIL
+ DUP $06 ( ACK ) = IF DROP 1
+ ELSE $15 = NOT IF ABORT" out of sync" THEN 0 THEN ;
+: _waitC
+ ." Waiting for C..." BEGIN RX<? IF 'C' = ELSE 0 THEN UNTIL ;
+: _mem>tx ( addr pktstart pktend -- )
+ OVER - >R SWAP >A BEGIN ( pkt )
+ 'P' EMIT DUP . SPC> $01 ( SOH ) TX> ( pkt )
+ 1+ ( pkt start at 1 ) DUP TX> $ff OVER - TX> ( pkt+1 )
+ _snd128 _ack? NOT IF LEAVE THEN NEXT DROP ;
+( ----- 015 )
+: MEM>TX ( a u -- Send u bytes to TX )
+ _waitC 128 /MOD SWAP IF 1+ THEN ( pktcnt ) 0 SWAP _mem>tx
+ $4 ( EOT ) TX> RX< DROP ;
+: BLK>TX ( b1 b2 -- )
+ _waitC OVER - ( cnt ) >R BEGIN ( blk )
+ 'B' EMIT DUP . SPC> DUP BLK@ BLK( ( blk a )
+ OVER 8 * DUP 8 + ( a pktstart pktend ) _mem>tx 1+ NEXT
+ $4 ( EOT ) TX> RX< DROP ;
+( ----- 020 )
+\ Block editor. see doc/ed.
+\ Cursor position in buffer. EDPOS/64 is line number
+0 VALUE EDPOS
+CREATE IBUF LNSZ 1+ ALLOT0 \ counted string, first byte is len
+CREATE FBUF LNSZ 1+ ALLOT0
+: L BLK> ." Block " DUP . NL> LIST ;
+: B BLK> 1- BLK@ L ; : N BLK> 1+ BLK@ L ;
+: IBUF+ IBUF 1+ ; : FBUF+ FBUF 1+ ;
+: ILEN IBUF C@ ; : FLEN FBUF C@ ;
+: EDPOS! TO EDPOS ; : EDPOS+! EDPOS + EDPOS! ;
+: 'pos ( pos -- a, addr of pos in memory ) BLK( + ;
+: 'EDPOS EDPOS 'pos ;
+( ----- 021 )
+\ Block editor, private helpers
+: _lpos ( ln -- a ) LNSZ * 'pos ;
+: _pln ( ln -- ) \ print line no ln with pos caret
+ DUP _lpos DUP >A LNLEN 1 MAX >R BEGIN ( lno )
+ A> 'EDPOS = IF '^' EMIT THEN
+ AC@+ SPC MAX EMIT NEXT ( lno ) SPC> 1+ . ;
+: _zline ( a -- ) LNSZ SPC FILL ; \ zero-out a line
+: _type ( buf -- ) \ *A* type into buf until end of INBUF
+ IN<? ?DUP NOT IF DROP EXIT THEN OVER 1+ DUP _zline >A BEGIN
+ ( buf c ) AC!+ IN<? ?DUP NOT UNTIL ( buf )
+ A> OVER - 1- ( buf len ) SWAP C! ;
+( ----- 022 )
+\ Block editor, T P U
+\ user-facing lines are 1-based
+: T 1- DUP LNSZ * EDPOS! _pln ;
+: P IBUF _type IBUF+ 'EDPOS LNSZ MOVE BLK!! ;
+: _mvln+ ( ln -- move ln 1 line down )
+ DUP 14 > IF DROP EXIT THEN
+ _lpos DUP LNSZ + LNSZ MOVE ;
+: _U ( U without P, used in VE )
+ 15 EDPOS LNSZ / - ?DUP IF
+ >R 14 BEGIN DUP _mvln+ 1- NEXT DROP THEN ;
+: U _U P ;
+( ----- 023 )
+\ Block editor, F i
+: _F ( F without _type and _pln. used in VE )
+ 'EDPOS 1+ BEGIN ( a )
+ FBUF+ C@ OVER BLK) OVER - ( a c a u ) [C]?
+ DUP 0< IF 2DROP EXIT THEN ( a idx ) + ( a )
+ DUP FBUF+ FLEN []= IF BLK( - EDPOS! EXIT THEN 1+ AGAIN ;
+: F FBUF _type _F EDPOS LNSZ / _pln ;
+: _rbufsz ( size of linebuf to the right of curpos )
+ EDPOS LNSZ MOD LNSZ -^ ;
+: _I ( I without _pln and _type. used in VE )
+ _rbufsz ILEN OVER < IF ( rsize )
+ ILEN - ( chars-to-move )
+ 'EDPOS DUP ILEN + ROT ( a a+ilen ctm ) MOVE- ILEN
+ THEN ( len-to-insert )
+ IBUF+ 'EDPOS ROT MOVE ( ilen ) BLK!! ;
+: I IBUF _type _I EDPOS LNSZ / _pln ;
+( ----- 024 )
+\ Block editor, X E Y
+: icpy ( n -- copy n chars from cursor to IBUF )
+ DUP IBUF C! IBUF+ _zline 'EDPOS IBUF+ ( n a buf ) ROT MOVE ;
+: _del ( n -- ) ?DUP NOT IF EXIT THEN _rbufsz MIN
+ 'EDPOS 2DUP + ( n a1 a1+n ) SWAP _rbufsz MOVE ( n )
+ \ get to next line - n
+ DUP EDPOS $ffc0 AND $40 + -^ 'pos ( n a )
+ SWAP SPC FILL BLK!! ;
+: _X ( n -- ) ?DUP NOT IF EXIT THEN _rbufsz MIN DUP icpy _del ;
+: X _X EDPOS LNSZ / _pln ;
+: _E FLEN _X ;
+: E FLEN X ;
+: Y FBUF IBUF LNSZ 1+ MOVE ;
+( ----- 025 )
+\ Visual text editor. VALUEs, lg? width pos@ mode! ...
+3 VALUES PREVPOS xoff ACC
+LNSZ 3 + VALUE MAXW
+10 VALUE MARKCNT
+CREATE MARKS MARKCNT << << ALLOT0 \ 4b: blk/edpos
+: nspcs ( pos n ) SPC FILLC ;
+: lg? COLS MAXW > ; : col- MAXW COLS MIN -^ ;
+: width lg? IF LNSZ ELSE COLS THEN ;
+: acc@ ACC 1 MAX ; : pos@ ( x y -- ) EDPOS LNSZ /MOD ;
+: num ( c -- ) \ c is in range 0-9
+ '0' - ACC 10 * + TO ACC ;
+: mode! ( c -- ) 4 col- CELL! ;
+( ----- 026 )
+\ VE, rfshln contents selblk pos! xoff? setpos
+: _ ( ln -- ) \ refresh line ln
+ DUP _lpos xoff + SWAP 3 + COLS * lg? IF 3 + THEN
+ width CELLS! ;
+: rfshln pos@ NIP _ ; \ refresh active line
+: contents 16 >R 0 BEGIN DUP _ 1+ NEXT DROP ;
+: selblk BLK@ contents ;
+: pos! ( newpos -- ) EDPOS TO PREVPOS
+ DUP 0< IF DROP 0 THEN 1023 MIN EDPOS! ;
+: xoff? pos@ DROP ( x )
+ xoff ?DUP IF < IF 0 TO xoff contents THEN ELSE
+ width >= IF LNSZ COLS - TO xoff contents THEN THEN ;
+: setpos ( -- ) pos@ 3 + ( header ) SWAP ( y x ) xoff -
+ lg? IF 3 + ( gutter ) THEN SWAP AT-XY ;
+: 'mark ( -- a ) ACC MARKCNT MOD << << MARKS + ;
+( ----- 027 )
+\ VE, cmv buftype bufprint bufs
+: cmv ( n -- , char movement ) acc@ * EDPOS + pos! ;
+: buftype ( buf ln -- ) \ type into buf at ln
+ 3 OVER AT-XY KEY DUP SPC < IF 2DROP DROP EXIT THEN ( b ln c )
+ SWAP COLS * 3 + 3 col- nspcs ( buf c )
+ IN( SWAP LNTYPE DROP BEGIN ( buf a ) KEY LNTYPE UNTIL
+ IN( - ( buf len ) SWAP C!+ IN( SWAP LNSZ MOVE IN$ ;
+: _ ( buf sa sl pos )
+ DUP >R STYPEC ( buf ) C@+ ( buf sz ) R> 3 + STYPEC ;
+: bufs ( -- ) \ refresh I and F lines
+ IBUF S" I: " COLS _ FBUF S" F: " COLS 2 * _ ;
+: insl _U EDPOS $3c0 AND DUP pos! 'pos _zline BLK!! contents ;
+( ----- 028 )
+\ VE cmds
+31 VALUE cmdcnt
+CREATE cmdl ," G[]IFnNYEXChlkjHLg@!wWb&mtfROoD"
+cmdcnt WORDTBL cmds
+:W ( G ) ACC selblk ;
+:W ( [ ) BLK> acc@ - selblk ; :W ( ] ) BLK> acc@ + selblk ;
+: insert 'I' mode! IBUF 1 buftype _I bufs rfshln ;
+'W insert ( I )
+:W ( F ) 'F' mode! FBUF 2 buftype _F bufs setpos ;
+:W ( n ) _F setpos ;
+:W ( N ) EDPOS _F EDPOS = IF 0 EDPOS! acc@ >R BEGIN
+ BLK> 1+ BLK@ _F EDPOS IF LEAVE THEN NEXT
+ contents setpos THEN ;
+:W ( Y ) Y bufs ; :W ( E ) _E bufs rfshln ;
+:W ( X ) acc@ _X bufs rfshln ;
+:W ( C ) FLEN _del rfshln insert ;
+( ----- 029 )
+\ VE cmds
+:W ( h ) -1 cmv ; :W ( l ) 1 cmv ;
+:W ( k ) -64 cmv ; :W ( j ) 64 cmv ;
+: bol EDPOS $3c0 AND pos! ;
+'W bol ( H )
+:W ( L ) EDPOS DUP $3f OR 2DUP = IF 2DROP EXIT THEN SWAP BEGIN
+ ( res p ) 1+ DUP 'pos C@ WS? NOT IF NIP DUP 1+ SWAP THEN
+ DUP $3f AND $3f = UNTIL DROP pos! ;
+:W ( g ) ACC 1 MAX 1- 64 * pos! ;
+:W ( @ ) BLK> BLK( (blk@) 0 BLKDTY ! contents ;
+:W ( ! ) BLK> FLUSH 'BLK> ! ;
+( ----- 030 )
+\ VE cmds
+: C@- DUP 1- SWAP C@ ;
+: word>> BEGIN C@+ WS? UNTIL ;
+: ws>> BEGIN C@+ WS? NOT UNTIL ;
+: word<< BEGIN C@- WS? UNTIL ;
+: ws<< BEGIN C@- WS? NOT UNTIL ;
+: bpos! BLK( - pos! ;
+:W ( w ) 'EDPOS acc@ >R BEGIN word>> ws>> NEXT 1- bpos! ;
+:W ( W ) 'EDPOS acc@ >R BEGIN ws>> word>> NEXT 1- bpos! ;
+:W ( b ) 'EDPOS acc@ >R BEGIN 1- ws<< word<< NEXT 1+ 1+ bpos! ;
+:W ( & ) WIPE contents ;
+:W ( m ) BLK> 'mark ! EDPOS 'mark 1+ 1+ ! ;
+:W ( t ) 'mark 1+ 1+ @ pos! 'mark @ selblk ;
+( ----- 031 )
+\ VE cmds
+:W ( f ) EDPOS PREVPOS 2DUP = IF 2DROP EXIT THEN
+ 2DUP > IF DUP pos! SWAP THEN
+ ( p1 p2, p1 < p2 ) OVER - LNSZ MIN ( pos len ) DUP FBUF C!
+ FBUF+ _zline SWAP 'pos FBUF+ ( len src dst ) ROT MOVE bufs ;
+:W ( R ) 'R' mode! BEGIN
+ setpos KEY DUP BS? IF -1 EDPOS+! DROP 0 THEN
+ DUP SPC >= IF
+ DUP EMIT 'EDPOS C! 1 EDPOS+! BLK!! 0 THEN UNTIL ;
+'W insl ( O )
+:W ( o ) EDPOS $3c0 < IF EDPOS 64 + EDPOS! insl THEN ;
+:W ( D ) bol LNSZ icpy acc@ LNSZ * ( delsz ) BLK) 'EDPOS - MIN
+ >R 'EDPOS R@ + 'EDPOS ( src dst )
+ BLK) OVER - MOVE BLK) R@ - R> SPC FILL BLK!! bufs contents ;
+( ----- 032 )
+\ VE final: status nums gutter handle VE
+: status 0 $20 nspcs 0 0 AT-XY ." BLK" SPC> BLK> . SPC> ACC .
+ SPC> pos@ 1+ . ',' EMIT . xoff IF '>' EMIT THEN SPC>
+ BLKDTY @ IF '*' EMIT THEN SPC mode! ;
+: nums 16 >R BEGIN R@ HERE FMTD R@ 2 + COLS * STYPEC NEXT ;
+: gutter lg? IF 19 >R BEGIN
+ '|' R@ 1- COLS * MAXW + CELL! NEXT THEN ;
+: handle ( c -- f )
+ DUP '0' '9' =><= IF num 0 EXIT THEN
+ DUP cmdl cmdcnt [C]? 1+ ?DUP IF 1- cmds SWAP WEXEC THEN
+ 0 TO ACC 'q' = ;
+: VE BLK> 0< IF 0 BLK@ THEN
+ CLRSCR 0 TO ACC 0 TO PREVPOS
+ nums bufs contents gutter
+ BEGIN xoff? status setpos KEY handle UNTIL 0 19 AT-XY ;
+( ----- 035 )
+\ Memory Editor. See doc/me
+CREATE CMD '#' C, 0 C,
+CREATE BUF '$' C, 4 ALLOT \ always hex
+\ POS is relative to ADDR
+4 VALUES ADDR POS HALT? ASCII?
+16 VALUE AWIDTH
+LINES 2 - VALUE AHEIGHT
+AHEIGHT AWIDTH * VALUE PAGE
+COLS 33 < [IF] 8 TO AWIDTH [THEN]
+: addr ADDR POS + ;
+CREATE _ ," 0123456789abcdef"
+: hex! ( c pos -- )
+ OVER 16 / _ + C@ OVER CELL! ( c pos )
+ 1+ SWAP $f AND _ + C@ SWAP CELL! ;
+: bottom 0 LINES 1- AT-XY ;
+( ----- 036 )
+\ Memory Editor, line rfshln contents showpos
+: line ( ln -- )
+ DUP AWIDTH * ADDR + >A 1+ COLS * ( pos )
+ ':' OVER CELL! A> <<8 >>8 OVER 1+ hex! 4 + ( pos+4 )
+ AWIDTH >> >R A> SWAP BEGIN ( a-old pos )
+ AC@+ ( a-old pos c ) OVER hex! ( a-old pos )
+ 1+ 1+ AC@+ OVER hex! 3 + ( a-old pos+5 ) NEXT
+ SWAP >A AWIDTH >R BEGIN ( pos )
+ AC@+ DUP SPC - $5e > IF DROP '.' THEN OVER CELL! 1+ NEXT
+ DROP ;
+: rfshln POS AWIDTH / line ;
+: contents LINES 2 - >R BEGIN R@ 1- line NEXT ;
+: showpos
+ POS AWIDTH /MOD ( r q ) 1+ SWAP ( y r ) ASCII? IF
+ AWIDTH >> 5 * + ELSE DUP 1 AND << SWAP >> 5 * + THEN
+ 4 + ( y x ) SWAP AT-XY ;
+( ----- 037 )
+\ Memory Editor, addr! pos! status type typep
+: addr! $fff0 AND TO ADDR contents ;
+: pos! DUP 0< IF PAGE + THEN DUP PAGE >= IF PAGE - THEN
+ TO POS showpos ;
+: status 0 COLS SPC FILLC
+ 0 0 AT-XY ." A: " ADDR .X SPC> ." C: " POS .X SPC> ." S: "
+ PSDUMP POS pos! ;
+: type ( cnt -- sa sl ) BUF 1+ >A >R BEGIN
+ KEY DUP SPC < IF DROP LEAVE ELSE DUP EMIT AC!+ THEN NEXT
+ BUF A> BUF - ;
+: typep ( cnt -- n? f )
+ type ( sa sl ) DUP IF PARSE ELSE NIP THEN ;
+( ----- 038 )
+\ Memory Editor, almost all actions
+: #] ADDR PAGE + addr! ; : #[ ADDR PAGE - addr! ;
+: #J ADDR $10 + addr! POS $10 - pos! ;
+: #K ADDR $10 - addr! POS $10 + pos! ;
+: #l POS 1+ pos! ; : #h POS 1- pos! ;
+: #j POS AWIDTH + pos! ; : #k POS AWIDTH - pos! ;
+: #m addr ; : #@ addr @ ; : #! addr ! contents ;
+: #g SCNT IF DUP ADDR - PAGE < IF
+ ADDR - pos! ELSE DUP addr! $f AND pos! THEN THEN ;
+: #G bottom 4 typep IF #g THEN ;
+: #a ASCII? NOT TO ASCII? showpos ;
+: #f #@ #g ; : #e #m #f ;
+: _h SPC> showpos 2 typep ;
+: _a showpos KEY DUP SPC < IF DROP 0 ELSE DUP EMIT 1 THEN ;
+: #R BEGIN SPC> ASCII? IF _a ELSE _h THEN ( n? f ) IF
+ addr C! rfshln #l 0 ELSE 1 THEN UNTIL rfshln ;
+( ----- 039 )
+\ Memory Editor, #q handle ME
+: #q 1 TO HALT? ;
+: handle ( c -- f )
+ CMD 1+ C! CMD 2 FIND IF EXECUTE THEN ;
+: ME 0 TO HALT? CLRSCR contents 0 pos! BEGIN
+ status KEY handle HALT? UNTIL bottom ;
+( ----- 040 )
+\ AVR Programmer, B160-B163. doc/avr.txt
+\ page size in words, 64 is default on atmega328P
+64 VALUE aspfpgsz
+0 VALUE aspprevx
+: _x ( a -- b ) DUP TO aspprevx (spix) ;
+: _xc ( a -- b ) DUP (spix) ( a b )
+ DUP aspprevx = NOT IF ABORT" AVR err" THEN ( a b )
+ SWAP TO aspprevx ( b ) ;
+: _cmd ( b4 b3 b2 b1 -- r4 ) _xc DROP _xc DROP _xc DROP _x ;
+: asprdy ( -- ) BEGIN 0 0 0 $f0 _cmd 1 AND NOT UNTIL ;
+: asp$ ( spidevid -- )
+ ( RESET pulse ) DUP (spie) 0 (spie) (spie)
+ ( wait >20ms ) 220 TICKS
+ ( enable prog ) $ac (spix) DROP
+ $53 _x DROP 0 _xc DROP 0 _x DROP ;
+: asperase 0 0 $80 $ac _cmd asprdy ;
+( ----- 041 )
+( fuse access. read/write one byte at a time )
+: aspfl@ ( -- lfuse ) 0 0 0 $50 _cmd ;
+: aspfh@ ( -- hfuse ) 0 0 $08 $58 _cmd ;
+: aspfe@ ( -- efuse ) 0 0 $00 $58 _cmd ;
+: aspfl! ( lfuse -- ) 0 $a0 $ac _cmd ;
+: aspfh! ( hfuse -- ) 0 $a8 $ac _cmd ;
+: aspfe! ( efuse -- ) 0 $a4 $ac _cmd ;
+( ----- 042 )
+: aspfb! ( n a --, write word n to flash buffer addr a )
+ SWAP L|M SWAP ( a hi lo ) ROT ( hi lo a )
+ DUP ROT ( hi a a lo ) SWAP ( hi a lo a )
+ 0 $40 ( hi a lo a 0 $40 ) _cmd DROP ( hi a )
+ 0 $48 _cmd DROP ;
+: aspfp! ( page --, write buffer to page )
+ 0 SWAP aspfpgsz * L|M ( 0 lsb msb )
+ $4c _cmd DROP asprdy ;
+: aspf@ ( page a -- n, read word from flash )
+ SWAP aspfpgsz * OR ( addr ) L|M ( lsb msb )
+ 2DUP 0 ROT> ( lsb msb 0 lsb msb )
+ $20 _cmd ( lsb msb low )
+ ROT> 0 ROT> ( low 0 lsb msb ) $28 _cmd <<8 OR ;
+( ----- 043 )
+: aspe@ ( addr -- byte, read from EEPROM )
+ 0 SWAP L|M SWAP ( 0 msb lsb )
+ $a0 ( 0 msb lsb $a0 ) _cmd ;
+: aspe! ( byte addr --, write to EEPROM )
+ L|M SWAP ( b msb lsb )
+ $c0 ( b msb lsb $c0 ) _cmd DROP asprdy ;
+( ----- 045 )
+( Sega ROM signer. See doc/sega.txt )
+: segasig ( addr size -- )
+ $2000 OVER LSHIFT ( a sz bytesz ) $10 - >R ( a sz )
+ SWAP >A 0 BEGIN ( sz csum ) AC@+ + NEXT ( sz csum )
+ 'T' AC!+ 'M' AC!+ 'R' AC!+ SPC AC!+ 'S' AC!+
+ 'E' AC!+ 'G' AC!+ 'A' AC!+ 0 AC!+ 0 AC!+
+ ( sum's LSB ) DUP AC!+ ( MSB ) >>8 AC!+
+ ( sz ) 0 AC!+ 0 AC!+ 0 AC!+ $4a + AC!+ ;
+( ----- 050 )
+CREATE MSPAN_DISK 0 C,
+CREATE (msdsks) 100 C, 100 C, 180 C, 0 C,
+
+: _ ( dsk -- ) DUP MSPAN_DISK C! S" Need disk " STYPE . SPC> ;
+: prompt _ KEY DROP ;
+: dskchk ( blk -- newblk ) A>R (msdsks) >A BEGIN
+ AC@+ - DUP 0< AC@ NOT OR UNTIL A- AC@ + ( newblk )
+ A> (msdsks) - ( newblk dsk ) DUP MSPAN_DISK C@ = NOT IF
+ prompt ELSE DROP THEN ( blk ) R>A ;
+( ----- 051 )
+\ utility to quickly examine freshly written asm words
+0 VALUE mark
+: see mark >A HERE mark - >R BEGIN
+ AC@+ .x SPC> NEXT mark 'HERE ! ;
+\ HERE TO mark
+( ----- 200 )
+\ Cross compilation program, generic part. See doc/cross
+0 VALUE BIN( \ binary start in target's addr
+0 VALUE XORG \ binary start address in host's addr
+0 VALUE BIGEND? \ is target big-endian?
+3 VALUES L1 L2 L3
+: PC HERE XORG - BIN( + ;
+: PC2A ( pc -- a ) HERE PC - ( org ) + ;
+: XSTART ( bin( -- ) TO BIN( HERE TO XORG ;
+: OALLOT ( oa -- ) XORG + HERE - ALLOT0 ;
+: |T L|M BIGEND? NOT IF SWAP THEN ;
+: T! ( n a -- ) SWAP |T ROT C!+ C! ;
+: T, ( n -- ) |T C, C, ;
+: T@ C@+ SWAP C@ BIGEND? IF SWAP THEN <<8 OR ;
+: XCOMPC 201 205 LOADR ; : FONTC 262 263 LOADR ;
+( ----- 201 )
+\ Cross compilation program. COS-specific. See doc/cross
+: COREL 210 224 LOADR ; : COREH 225 229 LOADR ;
+: BLKSUB 230 234 LOADR ; : GRIDSUB 240 241 LOADR ;
+: PS2SUB 246 248 LOADR ; : RXTXSUB 235 LOAD ;
+: MSPANSUB 237 LOAD ; : SDCSUB 250 258 LOADR ;
+'? HERESTART NOT [IF] 0 VALUE HERESTART [THEN]
+0 VALUE XCURRENT \ CURRENT in target system, in target's addr
+8 VALUES lblnext lblcell lbldoes lblxt lblval
+ lblhere lblmain lblboot
+'? 'A NOT [IF] SYSVARS $06 + VALUE 'A [THEN]
+'? 'N NOT [IF] SYSVARS $08 + VALUE 'N [THEN]
+6 VALUES (n)* (b)* (br)* (?br)* EXIT* (next)*
+CREATE '~ 2 ALLOT
+( ----- 202 )
+\ Cross compilation program
+: _xoff ( a -- a ) XORG BIN( - ;
+: _wl ( w -- len ) 1- C@ $7f AND ;
+: _ws ( w len -- sa ) - 3 - ;
+: _xfind ( sa sl -- w? f ) >R >A XCURRENT BEGIN ( w R:sl )
+ _xoff + DUP _wl R@ = IF ( w ) DUP R@ _ws A> R@ ( w a1 a2 u )
+ []= IF ( w ) R~ 1 EXIT THEN THEN
+ 3 - ( prev field ) T@ ?DUP NOT UNTIL R~ 0 ( not found ) ;
+: XFIND ( sa sl -- w ) _xfind NOT IF (wnf) THEN _xoff - ;
+: X' WORD XFIND ;
+: '? WORD _xfind DUP IF NIP THEN ;
+: ENTRY
+ WORD TUCK MOVE, XCURRENT T, C, HERE _xoff - TO XCURRENT ;
+( ----- 203 )
+\ Cross compilation program
+: ;CODE lblnext JMPi, ;
+: ALIAS X' ENTRY JMPi, ; : *ALIAS ENTRY JMP(i), ;
+: CONSTANT ENTRY i>, ;CODE ;
+: CONSTS >R BEGIN RUN1 CONSTANT NEXT ;
+: CONSTS+ ( off n -- )
+ >R BEGIN RUN1 OVER + CONSTANT NEXT DROP ;
+: *VALUE ENTRY (i)>, ;CODE ; : CREATE ENTRY lblcell CALLi, ;
+: _ ( lbl str -- )
+ CURWORD S= IF XCURRENT SWAP TO EXECUTE ELSE DROP THEN ;
+: CODE ENTRY ['] EXIT* S" EXIT" _ ['] (b)* S" (b)" _
+ ['] (n)* S" (n)" _ ['] (br)* S" (br)" _
+ ['] (?br)* S" (?br)" _ ['] (next)* S" (next)" _ ;
+: LITN DUP $ff > IF (n)* T, T, ELSE (b)* T, C, THEN ;
+( ----- 204 )
+\ Cross compilation program
+: imm? ( w -- f ) 1- C@ $80 AND ;
+: compile BEGIN WORD S" ;" S= IF EXIT* T, EXIT THEN
+ CURWORD PARSE IF LITN ELSE CURWORD _xfind IF ( w )
+ DUP imm? IF ABORT" immed!" THEN _xoff - T,
+ ELSE CURWORD FIND IF ( w )
+ DUP imm? IF EXECUTE ELSE (wnf) THEN
+ ELSE (wnf) THEN
+ THEN ( _xfind ) THEN ( PARSE ) AGAIN ;
+: :~ HERE _xoff - '~ ! lblxt CALLi, compile ;
+: ~ '~ @ T, ; IMMEDIATE
+: _ CODE lblxt CALLi, compile ; \ : can't have its name now
+: ?: '? IF S" ;" WAITW ELSE CURWORD WORD! _ THEN ;
+: ~DOER ENTRY lbldoes CALLi, [COMPILE] ~ ;
+( ----- 205 )
+\ Cross compilation program
+: XWRAP COREH XCURRENT lblhere PC2A T!
+ HERESTART ?DUP NOT IF PC THEN lblhere PC2A 1+ 1+ T! ;
+: ['] WORD XFIND LITN ; IMMEDIATE
+: COMPILE [COMPILE] ['] S" ," XFIND T, ; IMMEDIATE
+: IF (?br)* T, HERE 1 ALLOT ; IMMEDIATE
+: ELSE (br)* T, 1 ALLOT [COMPILE] THEN HERE 1- ; IMMEDIATE
+: AGAIN (br)* T, HERE - C, ; IMMEDIATE
+: UNTIL (?br)* T, HERE - C, ; IMMEDIATE
+: NEXT (next)* T, HERE - C, ; IMMEDIATE
+: S" (br)* T, HERE 1 ALLOT HERE ," TUCK HERE -^ SWAP
+ [COMPILE] THEN SWAP _xoff - LITN LITN ; IMMEDIATE
+: [COMPILE] WORD XFIND T, ; IMMEDIATE
+: IMMEDIATE XCURRENT _xoff + 1- DUP C@ $80 OR SWAP C! ;
+':' ' _ 4 - C! \ give : its real name now
+0 XSTART
+( ----- 210 )
+\ Core Forth words. See doc/cross. SYSVARS
+SYSVARS 12 CONSTS+
+ $00 IOERR $02 'CURRENT $04 'HERE $0a NL $0c LN<
+ $0e 'EMIT $10 'KEY? $12 'CURWORD $16 '(wnf)
+ $1c 'IN( $1e 'IN> $20 INBUF
+SYSVARS $02 + *VALUE CURRENT SYSVARS $04 + *VALUE HERE
+SYSVARS $0e + *ALIAS EMIT SYSVARS $10 + *ALIAS KEY?
+SYSVARS $1c + *VALUE IN( SYSVARS $1e + *VALUE IN>
+$40 CONSTANT LNSZ
+CODE NOOP ;CODE
+( ----- 211 )
+\ Core words, basic arithmetic and stack management
+?: = - NOT ;
+?: > SWAP < ;
+?: 0< $7fff > ; ?: 0>= $8000 < ; ?: >= < NOT ; ?: <= > NOT ;
+?: 1+ 1 + ; ?: 1- 1 - ;
+?: 2DROP DROP DROP ;
+?: 2DUP OVER OVER ;
+?: NIP SWAP DROP ;
+?: TUCK SWAP OVER ;
+?: ROT> ROT ROT ;
+?: =><= ( n l h -- f ) OVER - ROT> ( h n l ) - >= ;
+: / /MOD NIP ; : MOD /MOD DROP ;
+?: <> ( n n -- l h ) 2DUP > IF SWAP THEN ;
+?: MIN <> DROP ; ?: MAX <> NIP ; ?: -^ SWAP - ;
+( ----- 212 )
+\ Core words, bit shifting, A register, LEAVE VAL L|M +!
+?: << 2 * ; ?: >> 2 / ;
+?: <<8 $100 * ; ?: >>8 $100 / ;
+?: RSHIFT ?DUP IF >R BEGIN >> NEXT THEN ;
+?: LSHIFT ?DUP IF >R BEGIN << NEXT THEN ;
+?: L|M DUP <<8 >>8 SWAP >>8 ;
+?: +! ( n a -- ) TUCK @ + SWAP ! ;
+?: A> [ 'A LITN ] @ ; ?: >A [ 'A LITN ] ! ;
+?: A>R R> A> >R >R ; ?: R>A R> R> >A >R ;
+?: A+ 1 [ 'A LITN ] +! ; ?: A- -1 [ 'A LITN ] +! ;
+?: AC@ A> C@ ; ?: AC! A> C! ;
+: AC@+ AC@ A+ ; : AC!+ AC! A+ ;
+: LEAVE R> R~ 1 >R >R ;
+?: TO 1 [ SYSVARS $18 + LITN ] C! ;
+( ----- 213 )
+\ Core words, C@+ ALLOT FILL IMMEDIATE , L, M, MOVE MOVE, ..
+?: C@+ DUP 1+ SWAP C@ ;
+?: C!+ TUCK C! 1+ ;
+: ALLOT 'HERE +! ;
+?: FILL ( a u b -- ) \ *A*
+ ROT> >R >A BEGIN DUP AC!+ NEXT DROP ;
+: ALLOT0 ( u -- ) HERE OVER 0 FILL ALLOT ;
+: IMMEDIATE CURRENT 1- DUP C@ $80 OR SWAP C! ;
+: , HERE ! 2 ALLOT ; : C, HERE C! 1 ALLOT ;
+: L, DUP C, >>8 C, ; : M, DUP >>8 C, C, ;
+?: MOVE ( src dst u -- ) ?DUP IF
+ >R >A BEGIN ( src ) C@+ AC!+ NEXT DROP THEN ;
+: MOVE, ( a u -- ) HERE OVER ALLOT SWAP MOVE ;
+( ----- 214 )
+\ Core words, [C]? CRC16 []= JMPi! CALLi!
+?: JMPi! [ X' NOOP PC2A C@ ( jmp op ) LITN ] SWAP C!+ ! 3 ;
+?: CALLi! [ X' MOVE, PC2A C@ ( call op ) LITN ] SWAP C!+ ! 3 ;
+?: [C]? ( c a u -- i ) \ Guards A
+ ?DUP NOT IF 2DROP -1 EXIT THEN A>R OVER >R >R >A ( c )
+ BEGIN DUP AC@+ = IF LEAVE THEN NEXT ( c )
+ A- AC@ = IF A> R> - ( i ) ELSE R~ -1 THEN R>A ;
+?: []= ( a1 a2 u -- f ) \ Guards A
+ ?DUP NOT IF 2DROP 1 EXIT THEN A>R >R >A ( a1 )
+ BEGIN AC@+ OVER C@ = NOT IF R~ R>A DROP 0 EXIT THEN 1+ NEXT
+ DROP R>A 1 ;
+?: CRC16 ( c n -- c )
+ <<8 XOR 8 >R BEGIN ( c )
+ DUP 0< IF << $1021 XOR ELSE << THEN NEXT ;
+( ----- 215 )
+\ Core words, STYPE SPC> NL> STACK? LITN
+: STYPE >R >A BEGIN AC@+ EMIT NEXT ;
+5 CONSTS $04 EOT $08 BS $0a LF $0d CR $20 SPC
+: SPC> SPC EMIT ;
+: NL> NL @ L|M ?DUP IF EMIT THEN EMIT ;
+: STACK? SCNT 0< IF S" stack underflow" STYPE ABORT THEN ;
+: LITN DUP >>8 IF COMPILE (n) , ELSE COMPILE (b) C, THEN ;
+( ----- 216 )
+\ Core words, number formatting
+: FMTD ( n a -- sa sl ) \ *A*
+ 6 + >A A>R DUP >R DUP 0< IF 0 -^ THEN BEGIN ( n )
+ 10 /MOD ( d q ) A- SWAP '0' + AC! ?DUP NOT UNTIL
+ R> 0< IF A- '-' AC! THEN R> A> TUCK - ;
+PC TO L1 ," 0123456789abcdef"
+:~ ( n a 'len -- sa sl ) \ *A*
+ C@ DUP >R DUP >R + >A BEGIN ( n ) 16 /MOD ( d q ) A- SWAP
+ [ L1 LITN ] + C@ AC! NEXT DROP A> R> ;
+~DOER FMTx 2 C, ~DOER FMTX 4 C,
+:~ ( n 'w -- sa sl ) @ A>R HERE SWAP EXECUTE STYPE R>A ;
+~DOER . X' FMTD T,
+~DOER .x X' FMTx T,
+~DOER .X X' FMTX T,
+( ----- 217 )
+\ Core words, literal parsing
+:~ ( sl -- n? f ) \ parse unsigned decimal
+ >R 0 BEGIN ( r )
+ 10 * AC@+ ( r c ) '0' - DUP 9 > IF
+ 2DROP R~ 0 EXIT THEN + NEXT ( r ) 1 ;
+: PARSE ( sa sl -- n? f ) \ *A*
+ OVER C@ ''' = IF ( sa sl )
+ 3 = IF 1+ DUP 1+ C@ ''' = IF C@ 1 EXIT THEN THEN
+ DROP 0 EXIT THEN ( sa sl )
+ OVER C@ '$' = IF ( sa sl ) 1- >R 1+ >A 0 BEGIN ( r )
+ 16 * AC@+ ( r c ) $20 OR [ L1 LITN ] ( B216 ) $10 [C]?
+ DUP 0< IF 2DROP R~ 0 EXIT THEN + NEXT ( r ) 1 EXIT THEN
+ SWAP >A DUP 1 > AC@ '-' = AND IF ( sl )
+ A+ 1- ~ IF 0 -^ 1 ELSE 0 THEN ELSE ~ THEN ;
+( ----- 218 )
+\ Core words, input buffer
+: KEY BEGIN KEY? UNTIL ;
+: IN) IN( LNSZ + ;
+PC BS C, $7f ( DEL ) C,
+: BS? [ ( PC ) LITN ] 2 [C]? 0>= ;
+: WS? SPC <= ;
+\ type c into ptr inside INBUF. f=true if typing should stop
+: LNTYPE ( ptr c -- ptr+-1 f )
+ DUP BS? IF ( ptr c )
+ DROP DUP IN( > IF 1- BS EMIT THEN SPC> BS EMIT 0
+ ELSE ( ptr c ) \ non-BS
+ DUP SPC < IF DROP DUP IN) OVER - 0 FILL 1 ELSE
+ TUCK EMIT C!+ DUP IN) = THEN THEN ;
+( ----- 219 )
+\ Core words, input buffer, ,"
+: RDLN ( -- ) \ Read 1 line in IN(
+ S" ok" STYPE NL> IN( BEGIN KEY LNTYPE UNTIL DROP NL> ;
+: IN<? ( -- c-or-0 )
+ IN> IN) < IF IN> C@+ SWAP 'IN> ! ELSE 0 THEN ;
+: IN< ( -- c ) IN<? ?DUP NOT IF
+ LN< @ EXECUTE IN( 'IN> ! SPC THEN ;
+: IN$ ['] RDLN LN< ! INBUF 'IN( ! IN) 'IN> ! ;
+: ," BEGIN IN< DUP '"' = IF DROP EXIT THEN C, AGAIN ;
+( ----- 220 )
+\ Core words, WORD parsing
+: TOWORD ( -- ) BEGIN IN< WS? NOT UNTIL ;
+: CURWORD ( -- sa sl ) 'CURWORD 1+ @ 'CURWORD C@ ;
+:~ ( f sa sl -- ) 'CURWORD C!+ TUCK ! 1+ 1+ C! ;
+: WORD ( -- sa sl )
+ 'CURWORD 3 + C@ IF CURWORD ELSE
+ TOWORD IN> 1- 0 ( sa sl ) BEGIN 1+ IN<? WS? UNTIL THEN
+ ( sa sl ) 2DUP 0 ROT> ~ ;
+: WORD! 1 ROT> ~ ;
+( ----- 221 )
+\ Core words, FIND (wnf) RUN1 INTERPRET nC,
+?: FIND ( sa sl -- w? f ) \ Guards A
+ A>R >R >A CURRENT BEGIN ( w R:sl )
+ DUP 1- C@ $7f AND ( wlen ) R@ = IF ( w )
+ DUP R@ - 3 - A> R@ ( w a1 a2 u )
+ []= IF ( w ) R~ 1 R>A EXIT THEN THEN
+ 3 - ( prev field ) @ ?DUP NOT UNTIL R~ 0 R>A ( not found ) ;
+: (wnf) CURWORD STYPE S" word not found" STYPE ABORT ;
+: RUN1 ( -- ) \ interpret next word
+ WORD PARSE NOT IF
+ CURWORD FIND NOT IF '(wnf) @ THEN EXECUTE STACK? THEN ;
+: INTERPRET BEGIN RUN1 AGAIN ;
+: nC, ( n -- ) >R BEGIN RUN1 C, NEXT ;
+( ----- 222 )
+\ Core words, CODE '? ' TO FORGET
+: CODE WORD TUCK MOVE, ( len )
+ CURRENT , C, \ write prev value and size
+ HERE 'CURRENT ! ;
+: '? WORD FIND DUP IF NIP THEN ;
+: ' WORD FIND NOT IF (wnf) THEN ;
+: FORGET
+ ' DUP ( w w )
+ \ HERE must be at the end of prev's word, that is, at the
+ \ beginning of w.
+ DUP 1- C@ ( len ) $7f AND ( rm IMMEDIATE )
+ 3 + ( fixed header len ) - 'HERE ! ( w )
+ ( get prev addr ) 3 - @ 'CURRENT ! ;
+( ----- 223 )
+\ Core words, S= WAITW [IF] _bchk
+: S= ( sa1 sl1 sa2 sl2 -- f )
+ ROT OVER = IF ( same len, s2 s1 l ) []=
+ ELSE DROP 2DROP 0 THEN ;
+: WAITW ( sa sl -- ) BEGIN 2DUP WORD S= UNTIL 2DROP ;
+: [IF] NOT IF S" [THEN]" WAITW THEN ;
+ALIAS NOOP [THEN]
+: _bchk DUP $80 + $ff > IF S" br ovfl" STYPE ABORT THEN ;
+( ----- 224 )
+\ Core words, DUMP .S
+: DUMP ( n a -- ) \ *A*
+ >A 8 /MOD SWAP IF 1+ THEN >R BEGIN
+ ':' EMIT A> DUP .x SPC> ( a )
+ 4 >R BEGIN AC@+ .x AC@+ .x SPC> NEXT ( a ) >A
+ 8 >R BEGIN AC@+ DUP SPC - $5e > IF DROP '.' THEN EMIT NEXT
+ NL> NEXT ;
+: PSDUMP SCNT NOT IF EXIT THEN
+ SCNT >A BEGIN DUP .X SPC> >R SCNT NOT UNTIL
+ BEGIN R> SCNT A> = UNTIL ;
+: .S ( -- )
+ S" SP " STYPE SCNT .x SPC> S" RS " STYPE RCNT .x SPC>
+ S" -- " STYPE STACK? PSDUMP ;
+( ----- 225 )
+\ Core high, CREATE DOER DOES> CODE ALIAS VALUE
+: ;CODE [ lblnext LITN ] HERE JMPi! ALLOT ;
+: CREATE CODE [ lblcell LITN ] HERE CALLi! ALLOT ;
+: DOER CODE [ lbldoes LITN ] HERE CALLi! 1+ 1+ ALLOT ;
+: _ R> CURRENT 3 + ! ; \ Popping RS makes us EXIT from parent
+: DOES> COMPILE _ [ lblxt LITN ] HERE CALLi! ALLOT ; IMMEDIATE
+: ALIAS ' CODE HERE JMPi! ALLOT ;
+: VALUE CODE [ lblval LITN ] HERE CALLi! ALLOT , ;
+: VALUES >R BEGIN 0 VALUE NEXT ;
+: CONSTS >R BEGIN RUN1 VALUE NEXT ;
+( ----- 226 )
+\ Core high, BOOT
+:~ IN$ INTERPRET BYE ;
+'~ @ lblmain PC2A T! \ set jump in QUIT
+PC TO lblhere 4 ALLOT \ CURRENT, HERESTART
+: BOOT [ lblhere LITN ] 'CURRENT 4 MOVE
+ ['] (emit) 'EMIT ! ['] (key?) 'KEY? ! ['] (wnf) '(wnf) !
+ 0 'CURWORD 3 + C!
+ 0 IOERR ! $0d0a ( CR/LF ) NL !
+ 0 [ SYSVARS $18 ( TO? ) + LITN ] C!
+ INIT S" Collapse OS" STYPE ABORT ;
+XCURRENT lblboot PC2A T! \ initial jump to BOOT
+( ----- 227 )
+\ Core high, :
+: XTCOMP [ lblxt LITN ] HERE CALLi! ALLOT BEGIN
+ WORD S" ;" S= IF COMPILE EXIT EXIT THEN
+ CURWORD PARSE IF LITN ELSE CURWORD FIND IF
+ DUP 1- C@ $80 AND ( imm? ) IF EXECUTE ELSE , THEN
+ ELSE '(wnf) @ EXECUTE THEN THEN
+ AGAIN ;
+: : CODE XTCOMP ;
+( ----- 228 )
+\ Core high, IF..ELSE..THEN ( \
+: IF ( -- a | a: br cell addr )
+ COMPILE (?br) HERE 1 ALLOT ( br cell allot ) ; IMMEDIATE
+: THEN ( a -- | a: br cell addr )
+ DUP HERE -^ _bchk SWAP ( a-H a ) C! ; IMMEDIATE
+: ELSE ( a1 -- a2 | a1: IF cell a2: ELSE cell )
+ COMPILE (br) 1 ALLOT [COMPILE] THEN
+ HERE 1- ( push a. 1- for allot offset ) ; IMMEDIATE
+: ( S" )" WAITW ; IMMEDIATE
+: \ IN) 'IN> ! ; IMMEDIATE
+: S"
+ COMPILE (br) HERE 1 ALLOT HERE ," TUCK HERE -^ SWAP
+ [COMPILE] THEN SWAP LITN LITN ; IMMEDIATE
+( ----- 229 )
+\ Core high, .", ABORT", BEGIN..AGAIN..UNTIL, many others.
+: ." [COMPILE] S" COMPILE STYPE ; IMMEDIATE
+: ABORT" [COMPILE] ." COMPILE ABORT ; IMMEDIATE
+: BEGIN HERE ; IMMEDIATE
+: AGAIN COMPILE (br) HERE - _bchk C, ; IMMEDIATE
+: UNTIL COMPILE (?br) HERE - _bchk C, ; IMMEDIATE
+: NEXT COMPILE (next) HERE - _bchk C, ; IMMEDIATE
+: [ INTERPRET ; IMMEDIATE
+: ] R~ R~ ; \ INTERPRET+RUN1
+: COMPILE ' LITN ['] , , ; IMMEDIATE
+: [COMPILE] ' , ; IMMEDIATE
+: ['] ' LITN ; IMMEDIATE
+( ----- 230 )
+\ BLK subsystem. See doc/blk
+BLK_MEM CONSTANT BLK( \ $400 + "\S "
+BLK_MEM $400 + CONSTANT BLK)
+\ Current blk pointer -1 means "invalid"
+BLK_MEM $403 + DUP CONSTANT 'BLK> *VALUE BLK>
+\ Whether buffer is dirty
+BLK_MEM $405 + CONSTANT BLKDTY
+BLK_MEM $407 + CONSTANT BLKIN>
+: BLK$ 0 BLKDTY ! -1 'BLK> ! S" \S " BLK) SWAP MOVE ;
+( ----- 231 )
+: BLK! ( -- ) BLK> BLK( (blk!) 0 BLKDTY ! ;
+: FLUSH BLKDTY @ IF BLK! THEN -1 'BLK> ! ;
+: BLK@ ( n -- )
+ DUP BLK> = IF DROP EXIT THEN
+ FLUSH DUP 'BLK> ! BLK( (blk@) ;
+: BLK!! 1 BLKDTY ! ;
+: WIPE BLK( 1024 SPC FILL BLK!! ;
+: COPY ( src dst -- ) FLUSH SWAP BLK@ 'BLK> ! BLK! ;
+( ----- 232 )
+: LNLEN ( a -- len ) \ len based on last visible char in line
+ 1- LNSZ >R BEGIN
+ DUP R@ + C@ SPC > IF DROP R> EXIT THEN NEXT DROP 0 ;
+: EMITLN ( a -- ) \ emit LNSZ chars from a or stop at CR
+ DUP LNLEN ?DUP IF
+ >R >A BEGIN AC@+ EMIT NEXT ELSE DROP THEN NL> ;
+: LIST ( n -- ) \ print contents of BLK n
+ BLK@ 16 >R 0 BEGIN ( n )
+ DUP 1+ DUP 10 < IF SPC> THEN . SPC>
+ DUP LNSZ * BLK( + EMITLN 1+ NEXT DROP ;
+: INDEX ( b1 b2 -- ) \ print first line of blocks b1 through b2
+ OVER - 1+ >R BEGIN
+ DUP . SPC> DUP BLK@ BLK( EMITLN 1+ NEXT DROP ;
+( ----- 233 )
+: \S BLK) 'IN( ! IN( 'IN> ! ;
+:~ ( -- ) IN) 'IN( ! ;
+: LOAD
+ IN> BLKIN> ! [ '~ @ LITN ] LN< ! BLK@ BLK( 'IN( ! IN( 'IN> !
+ BEGIN RUN1 IN( BLK) = UNTIL IN$ BLKIN> @ 'IN> ! ;
+\ >R R> around LOAD is to avoid bad blocks messing PS up
+: LOADR OVER - 1+ >R BEGIN
+ DUP . SPC> DUP >R LOAD R> 1+ NEXT DROP ;
+( ----- 234 )
+\ Application loader, to include in boot binary
+: ED 1 LOAD ( MOVE- ) 20 24 LOADR ;
+: VE 5 LOAD ( wordtbl ) ED 25 32 LOADR ;
+: ME 35 39 LOADR ;
+: ARCHM 301 LOAD ;
+: RXTX 10 15 LOADR ;
+: XCOMP 200 LOAD ;
+( ----- 235 )
+\ RX/TX subsystem. See doc/rxtx
+RXTX_MEM CONSTANT _emit
+RXTX_MEM 2 + CONSTANT _key
+: RX< BEGIN RX<? UNTIL ;
+: RX<< 0 BEGIN DROP RX<? NOT UNTIL ;
+: TX[ 'EMIT @ _emit ! ['] TX> 'EMIT ! ;
+: ]TX _emit @ 'EMIT ! ;
+: RX[ 'KEY? @ _key ! ['] RX<? 'KEY? ! ;
+: ]RX _key @ 'KEY? ! ;
+( ----- 237 )
+\ Media Spanning subsystem. see doc/mspan
+MSPAN_MEM CONSTANT MSPAN_DISK
+
+?: DRVSEL ( drv -- ) DROP ;
+: prompt ( dsk -- )
+ DUP MSPAN_DISK C! S" Need disk " STYPE . SPC> KEY '0' -
+ DUP 10 < IF DRVSEL ELSE DROP THEN ;
+: MSPAN$ 0 MSPAN_DISK C! ;
+: dskchk ( blk -- newblk ) A>R (msdsks) >A BEGIN
+ AC@+ - DUP 0< AC@ NOT OR UNTIL A- AC@ + ( newblk )
+ A> (msdsks) - ( newblk dsk ) DUP MSPAN_DISK C@ = NOT IF
+ prompt ELSE DROP THEN ( blk ) R>A ;
+:~ ( blk dest 'w -- ) ROT dskchk ROT> @ EXECUTE ;
+~DOER (blk@) X' (ms@) T,
+~DOER (blk!) X' (ms!) T,
+( ----- 240 )
+\ Grid subsystem. See doc/grid.
+GRID_MEM DUP CONSTANT 'XYPOS *VALUE XYPOS
+?: CURSOR! 2DROP ;
+: XYPOS! COLS LINES * MOD DUP XYPOS CURSOR! 'XYPOS ! ;
+: AT-XY ( x y -- ) COLS * + XYPOS! ;
+?: NEWLN ( oldln -- newln )
+ 1+ LINES MOD DUP COLS * ( pos )
+ COLS >R BEGIN SPC OVER CELL! 1+ NEXT DROP ;
+?: CELLS! ( a pos u -- )
+ ?DUP IF >R SWAP >A BEGIN ( pos ) AC@+ OVER CELL! 1+ NEXT
+ ELSE DROP THEN DROP ;
+: STYPEC ( sa sl pos -- ) SWAP CELLS! ;
+?: FILLC ( pos n c )
+ SWAP >R SWAP BEGIN ( b pos ) 2DUP CELL! 1+ NEXT 2DROP ;
+: CLRSCR 0 COLS LINES * SPC FILLC 0 XYPOS! ;
+( ----- 241 )
+:~ ( line feed ) XYPOS COLS / NEWLN COLS * XYPOS! ;
+?: (emit)
+ DUP BS? IF
+ DROP SPC XYPOS TUCK CELL! ( pos ) 1- XYPOS! EXIT THEN
+ DUP CR = IF DROP SPC XYPOS CELL! ~ EXIT THEN
+ DUP SPC < IF DROP EXIT THEN
+ XYPOS CELL!
+ XYPOS 1+ DUP COLS MOD IF XYPOS! ELSE DROP ~ THEN ;
+: GRID$ 0 'XYPOS ! ;
+( ----- 245 )
+PS/2 keyboard subsystem
+
+Provides (key?) from a driver providing the PS/2 protocol. That
+is, for a driver taking care of providing all key codes emanat-
+ing from a PS/2 keyboard, this subsystem takes care of mapping
+those keystrokes to ASCII characters. This code is designed to
+be cross-compiled and loaded with drivers.
+
+Requires PS2_MEM to be defined.
+
+Load range: 246-249
+( ----- 246 )
+: PS2_SHIFT [ PS2_MEM LITN ] ; : PS2$ 0 PS2_SHIFT C! ;
+\ A list of the values associated with the $80 possible scan
+\ codes of the set 2 of the PS/2 keyboard specs. 0 means no
+\ value. That value is a character that can be read in (key?)
+\ No make code in the PS/2 set 2 reaches $80.
+\ TODO: I don't know why, but the key 2 is sent as $1f by 2 of
+\ my keyboards. Is it a timing problem on the ATtiny?
+CREATE PS2_CODES $80 nC,
+0 0 0 0 0 0 0 0 0 0 0 0 0 9 '`' 0
+0 0 0 0 0 'q' '1' 0 0 0 'z' 's' 'a' 'w' '2' '2'
+0 'c' 'x' 'd' 'e' '4' '3' 0 0 32 'v' 'f' 't' 'r' '5' 0
+0 'n' 'b' 'h' 'g' 'y' '6' 0 0 0 'm' 'j' 'u' '7' '8' 0
+0 ',' 'k' 'i' 'o' '0' '9' 0 0 '.' '/' 'l' ';' 'p' '-' 0
+0 0 ''' 0 '[' '=' 0 0 0 0 13 ']' 0 '\' 0 0
+0 0 0 0 0 0 8 0 0 '1' 0 '4' '7' 0 0 0
+'0' '.' '2' '5' '6' '8' 27 0 0 0 '3' 0 0 '9' 0 0
+( ----- 247 )
+( Same values, but shifted ) $80 nC,
+0 0 0 0 0 0 0 0 0 0 0 0 0 9 '~' 0
+0 0 0 0 0 'Q' '!' 0 0 0 'Z' 'S' 'A' 'W' '@' '@'
+0 'C' 'X' 'D' 'E' '$' '#' 0 0 32 'V' 'F' 'T' 'R' '%' 0
+0 'N' 'B' 'H' 'G' 'Y' '^' 0 0 0 'M' 'J' 'U' '&' '*' 0
+0 '<' 'K' 'I' 'O' ')' '(' 0 0 '>' '?' 'L' ':' 'P' '_' 0
+0 0 '"' 0 '{' '+' 0 0 0 0 13 '}' 0 '|' 0 0
+0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 27 0 0 0 0 0 0 0 0 0
+( ----- 248 )
+: _shift? ( kc -- f ) DUP $12 = SWAP $59 = OR ;
+: (key?) ( -- c? f )
+ (ps2kc) DUP NOT IF EXIT THEN ( kc )
+ DUP $e0 ( extended ) = IF ( ignore ) DROP 0 EXIT THEN
+ DUP $f0 ( break ) = IF DROP ( )
+ ( get next kc and see if it's a shift )
+ BEGIN (ps2kc) ?DUP UNTIL ( kc )
+ _shift? IF ( drop shift ) 0 PS2_SHIFT C! THEN
+ ( whether we had a shift or not, we return the next )
+ 0 EXIT THEN
+ DUP $7f > IF DROP 0 EXIT THEN
+ DUP _shift? IF DROP 1 PS2_SHIFT C! 0 EXIT THEN
+ ( ah, finally, we have a gentle run-of-the-mill KC )
+ PS2_CODES PS2_SHIFT C@ IF $80 + THEN + C@ ( c, maybe 0 )
+ ?DUP ( c? f ) ;
+( ----- 250 )
+\ SD Card subsystem Load range: B250-B258
+SDC_MEM CONSTANT SDC_SDHC
+: _idle ( -- n ) $ff (spix) ;
+
+( spix $ff until the response is something else than $ff
+ for a maximum of 20 times. Returns $ff if no response. )
+: _wait ( -- n )
+ 0 ( dummy ) 20 >R BEGIN
+ DROP _idle DUP $ff = NOT IF LEAVE THEN NEXT ;
+
+( adjust block for LBA for SD/SDHC )
+: _badj ( arg1 arg2 -- arg1 arg2 )
+ SDC_SDHC @ IF 0 SWAP ELSE DUP 128 / SWAP <<8 << THEN ;
+( ----- 251 )
+( The opposite of sdcWaitResp: we wait until response is $ff.
+ After a successful read or write operation, the card will be
+ busy for a while. We need to give it time before interacting
+ with it again. Technically, we could continue processing on
+ our side while the card it busy, and maybe we will one day,
+ but at the moment, I'm having random write errors if I don't
+ do this right after a write, so I prefer to stay cautious
+ for now. )
+: _ready ( -- ) BEGIN _idle $ff = UNTIL ;
+( ----- 252 )
+( Computes n into crc c with polynomial $09
+ Note that the result is "left aligned", that is, that 8th
+ bit to the "right" is insignificant (will be stop bit). )
+: _crc7 ( c n -- c )
+ XOR 8 >R BEGIN ( c )
+ << ( c<<1 ) DUP >>8 IF
+ ( MSB was set, apply polynomial )
+ <<8 >>8 $12 XOR ( $09 << 1, we apply CRC on high bits )
+ THEN NEXT ;
+( send-and-crc7 )
+: _s+crc ( n c -- c ) SWAP DUP (spix) DROP _crc7 ;
+( ----- 253 )
+( cmd arg1 arg2 -- resp )
+( Sends a command to the SD card, along with arguments and
+ specified CRC fields. (CRC is only needed in initial commands
+ though). This does *not* handle CS. You have to
+ select/deselect the card outside this routine. )
+: _cmd
+ _wait DROP ROT ( a1 a2 cmd )
+ 0 _s+crc ( a1 a2 crc )
+ ROT L|M ROT ( a2 h l crc )
+ _s+crc _s+crc ( a2 crc )
+ SWAP L|M ROT ( h l crc )
+ _s+crc _s+crc ( crc )
+ 1 OR ( ensure stop bit )
+ (spix) DROP ( send CRC )
+ _wait ( wait for a valid response... ) ;
+( ----- 254 )
+( cmd arg1 arg2 -- r )
+( Send a command that expects a R1 response, handling CS. )
+: SDCMDR1 [ SDC_DEVID LITN ] (spie) _cmd 0 (spie) ;
+
+( cmd arg1 arg2 -- r arg1 arg2 )
+( Send a command that expects a R7 response, handling CS. A R7
+ is a R1 followed by 4 bytes. arg1 contains bytes 0:1, arg2
+ has 2:3 )
+: SDCMDR7
+ [ SDC_DEVID LITN ] (spie)
+ _cmd ( r )
+ _idle <<8 _idle + ( r arg1 )
+ _idle <<8 _idle + ( r arg1 arg2 )
+ 0 (spie) ;
+: _rdsdhc ( -- ) $7A ( CMD58 ) 0 0 SDCMDR7 DROP $4000
+ AND SDC_SDHC ! DROP ;
+( ----- 255 )
+: _err 0 (spie) S" SDerr" STYPE ABORT ;
+
+( Tight definition ahead, pre-comment.
+
+ Initialize a SD card. This should be called at least 1ms
+ after the powering up of the card. We begin by waking up the
+ SD card. After power up, a SD card has to receive at least
+ 74 dummy clocks with CS and DI high. We send 80.
+ Then send cmd0 for a maximum of 10 times, success is when
+ we get $01. Then comes the CMD8. We send it with a $01aa
+ argument and expect a $01aa argument back, along with a
+ $01 R1 response. After that, we need to repeatedly run
+ CMD55+CMD41 ($40000000) until the card goes out of idle
+ mode, that is, when it stops sending us $01 response and
+ send us $00 instead. Any other response means that
+ initialization failed. )
+( ----- 256 )
+: SDC$
+ 10 >R BEGIN _idle DROP NEXT
+ 0 ( dummy ) 10 >R BEGIN ( r )
+ DROP $40 0 0 SDCMDR1 ( CMD0 )
+ 1 = DUP IF LEAVE THEN
+ NEXT NOT IF _err THEN
+ $48 0 $1aa ( CMD8 ) SDCMDR7 ( r arg1 arg2 )
+ ( expected 1 0 $1aa )
+ $1aa = ROT ( arg1 f r ) 1 = AND SWAP ( f&f arg1 )
+ NOT ( 0 expected ) AND ( f&f&f ) NOT IF _err THEN
+ BEGIN
+ $77 0 0 SDCMDR1 ( CMD55 )
+ 1 = NOT IF _err THEN
+ $69 $4000 0 SDCMDR1 ( CMD41 )
+ DUP 1 > IF _err THEN
+ NOT UNTIL _rdsdhc ; ( out of idle mode, success! )
+( ----- 257 )
+:~ ( dstaddr blkno -- )
+ [ SDC_DEVID LITN ] (spie)
+ $51 ( CMD17 ) SWAP _badj ( a cmd arg1 arg2 ) _cmd IF _err THEN
+ _wait $fe = NOT IF _err THEN
+ >A 512 >R 0 BEGIN ( crc1 )
+ _idle ( crc1 b ) DUP AC!+ ( crc1 b ) CRC16 NEXT ( crc1 )
+ _idle <<8 _idle + ( crc1 crc2 )
+ _wait DROP 0 (spie) = NOT IF _err THEN ;
+: SDC@ ( blkno blk( -- )
+ SWAP << ( 2x ) 2DUP ( a b a b ) ~
+ ( a b ) 1+ SWAP 512 + SWAP ~ ;
+( ----- 258 )
+:~ ( srcaddr blkno -- )
+ [ SDC_DEVID LITN ] (spie)
+ $58 ( CMD24 ) SWAP _badj ( a cmd arg1 arg2 ) _cmd IF _err THEN
+ _idle DROP $fe (spix) DROP
+ >A 512 >R 0 BEGIN ( crc )
+ AC@+ ( crc b ) DUP (spix) DROP CRC16 NEXT ( crc )
+ DUP >>8 ( crc msb ) (spix) DROP (spix) DROP
+ _wait $1f AND 5 = NOT IF _err THEN _ready 0 (spie) ;
+: SDC! ( blkno blk( -- )
+ SWAP << ( 2x ) 2DUP ( a b a b ) ~
+ ( a b ) 1+ SWAP 512 + SWAP ~ ;
+( ----- 260 )
+Fonts
+
+Fonts are kept in "source" form in the following blocks and
+then compiled to binary bitmasks by the following code. In
+source form, fonts are a simple sequence of '.' and 'X'. '.'
+means empty, 'X' means filled. Glyphs are entered one after the
+other, starting at $21 and ending at $7e. To be space
+efficient in blocks, we align glyphs horizontally in the blocks
+to fit as many character as we can. For example, a 5x7 font
+would mean that we would have 12x2 glyphs per block.
+
+261 Font compiler 265 3x5 font
+267 5x7 font 271 7x7 font
+( ----- 261 )
+\ Converts "dot-X" fonts to binary "glyph rows". One byte for
+\ each row. In a 5x7 font, each glyph thus use 7 bytes.
+\ Resulting bytes are aligned to the left of the byte.
+\ Therefore, for a 5-bit wide char, "X.X.X" translates to
+\ 10101000. Left-aligned bytes are easier to work with when
+\ compositing glyphs.
+( ----- 262 )
+2 VALUES _w _h
+: _g ( given a top-left of dot-X in BLK(, spit H bin lines )
+ DUP >A _h >R BEGIN _w >R 0 BEGIN ( a r )
+ << AC@+ 'X' = IF 1+ THEN NEXT
+ 8 _w - LSHIFT C, 64 + DUP >A NEXT DROP ;
+: _l ( a u -- a, spit a line of u glyphs )
+ >R DUP BEGIN ( a ) DUP _g _w + NEXT DROP ;
+( ----- 263 )
+: CPFNT3x5 3 TO _w 5 TO _h
+ _h ALLOT0 ( space char )
+ 265 BLK@ BLK( 21 _l 320 + 21 _l 320 + 21 _l DROP ( 63 )
+ 266 BLK@ BLK( 21 _l 320 + 10 _l DROP ( 94! ) ;
+: CPFNT5x7 5 TO _w 7 TO _h
+ _h ALLOT0 ( space char )
+ 3 >R 267 BEGIN ( b )
+ DUP BLK@ BLK( 12 _l 448 + 12 _l DROP 1+ NEXT ( 72 )
+ ( 270 ) BLK@ BLK( 12 _l 448 + 10 _l DROP ( 94! ) ;
+: CPFNT7x7 7 TO _w 7 TO _h
+ _h ALLOT0 ( space char )
+ 5 >R 271 BEGIN ( b )
+ DUP BLK@ BLK( 9 _l 448 + 9 _l DROP 1+ NEXT ( 90 )
+ ( 276 ) BLK@ BLK( 4 _l DROP ( 94! ) ;
+( ----- 265 )
+.X.X.XX.X.XXX...X..X...XX...X...............X.X..X.XX.XX.X.XXXX
+.X.X.XXXXXX...XX.X.X..X..X.XXX.X............XX.XXX...X..XX.XX..
+.X........XX.X..X.....X..X..X.XXX...XXX....X.X.X.X..X.XX.XXXXX.
+......XXXXX.X..X.X....X..X.X.X.X..X.......X..X.X.X.X....X..X..X
+.X....X.X.X...X.XX.....XX........X......X.X...X.XXXXXXXX...XXX.
+.XXXXXXXXXXX........X...X..XX..X..X.XX..XXXX.XXXXXX.XXX.XXXXXXX
+X....XX.XX.X.X..X..X.XXX.X...XXXXX.XX.XX..X.XX..X..X..X.X.X...X
+XXX.X.XXXXXX......X.......X.X.XXXXXXXX.X..X.XXX.XX.X.XXXX.X...X
+X.XX..X.X..X.X..X..X.XXX.X....X..X.XX.XX..X.XX..X..X.XX.X.X...X
+XXXX..XXXXX....X....X...X...X..XXX.XXX..XXXX.XXXX...XXX.XXXXXX.
+X.XX..X.XXX.XXXXX.XXXXX..XXXXXX.XX.XX.XX.XX.XXXXXXXX..XXX.X....
+XX.X..XXXX.XX.XX.XX.XX.XX...X.X.XX.XX.XX.XX.X..XX..X....XX.X...
+X..X..XXXX.XX.XXX.X.XXX..X..X.X.XX.XXXX.X..X..X.X...X...X......
+XX.X..X.XX.XX.XX..XXXX.X..X.X.X.XX.XXXXX.X.X.X..X....X..X......
+X.XXXXX.XX.XXXXX...XXX.XXX..X.XXX.X.X.XX.X.X.XXXXXX..XXXX...XXX
+!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
+( ----- 266 )
+X.....X.......X....XX...X...X...XX..XX.......................X.
+.X.XX.X...XX..X.X.X...X.X........X.X.X.X.XXX..X.XX..XX.XX.XXXXX
+.....XXX.X...XXX.XXX.X.XXX..X...XXX..X.XXXX.XX.XX.XX.XX..XX..X.
+...XXXX.XX..X.XXX.X...XXX.X.X...XX.X.X.X.XX.XX.XXX..XXX....X.X.
+...XXXXX..XX.XX.XXX..XX.X.X.X.XX.X.X.XXX.XX.X.X.X....XX..XX..XX
+...................XX.X.XX.....................................
+X.XX.XX.XX.XX.XXXX.X..X..X..XX
+X.XX.XX.X.X..X..XXX...X...XXX.
+X.XX.XXXX.X..X.XX..X..X..X....
+XXX.X.X.XX.X.X.XXX.XX.X.XX....
+`abcdefghijklmnopqrstuvwxyz{|}~
+( ----- 267 )
+..X...X.X........X..............X....X....X.................
+..X...X.X..X.X..XXXXX...X.XX....X...X......X.X.X.X..X.......
+..X.......XXXXXX.......X.X..X......X........X.XXX...X.......
+..X........X.X..XXX...X...XX.......X........XXXXXXXXXXX.....
+..........XXXXX....X.X....XX.X.....X........X.XXX...X.......
+..X........X.X.XXXX.X...XX..X.......X......X.X.X.X..X.....X.
+..X..............X.......XXX.X.......X....X..............X..
+................XXX...XX..XXX..XXX...XX.XXXXX.XXX.XXXXX.XXX.
+..............XX...X.X.X.X...XX...X.X.X.X....X........XX...X
+.............X.X..XX...X.....X....XX..X.XXXX.X........XX...X
+XXXXX.......X..X.X.X...X....X...XX.XXXXX....XXXXX....X..XXX.
+...........X...XX..X...X...X......X...X.....XX...X..X..X...X
+......XX..X....X...X...X..X...X...X...X.X...XX...X.X...X...X
+......XX........XXX..XXXXXXXXX.XXX....X..XXX..XXX.X.....XXX.
+!"#$%&'()*+,-./012345678
+( ----- 268 )
+.XXX...............X.....X.....XXX..XXX..XXX.XXXX..XXX.XXXX.
+X...X..X....X....XX.......XX..X...XX...XX...XX...XX...XX...X
+X...X..X....X...XX..XXXXX..XX.....XX..XXX...XX...XX....X...X
+.XXX...........X.............X...X.X..XXXXXXXXXXX.X....X...X
+....X..X....X...XX..XXXXX..XX...X..X....X...XX...XX....X...X
+....X..X...X.....XX.......XX.......X...XX...XX...XX...XX...X
+.XXX...............X.....X......X...XXX.X...XXXXX..XXX.XXXX.
+XXXXXXXXXX.XXX.X...X.XXX....XXX..X.X....X...XX...X.XXX.XXXX.
+X....X....X...XX...X..X......XX.X..X....XX.XXXX..XX...XX...X
+X....X....X....X...X..X......XXX...X....X.X.XXX..XX...XX...X
+XXXX.XXXX.X..XXXXXXX..X......XX....X....X...XX.X.XX...XXXXX.
+X....X....X...XX...X..X......XXX...X....X...XX..XXX...XX....
+X....X....X...XX...X..X..X...XX.X..X....X...XX..XXX...XX....
+XXXXXX.....XXX.X...X.XXX..XXX.X..X.XXXXXX...XX...X.XXX.X....
+9:;<=>?@ABCDEFGHIJKLMNOP
+( ----- 269 )
+.XXX.XXXX..XXX.XXXXXX...XX...XX...XX...XX...XXXXXXXXX.......
+X...XX...XX...X..X..X...XX...XX...XX...XX...XX...XX....X....
+X...XX...XX......X..X...XX...XX...X.X.X..X.X....X.X.....X...
+X...XXXXX..XXX...X..X...XX...XX...X..X....X....X..X......X..
+X.X.XX.X......X..X..X...XX...XX.X.X.X.X...X...X...X.......X.
+X..XXX..X.X...X..X..X...X.X.X.X.X.XX...X..X..X...XX........X
+.XXXXX...X.XXX...X...XXX...X...X.X.X...X..X..XXXXXXXX.......
+..XXX..X.........X..........................................
+....X.X.X.........X.........................................
+....XX...X...........XXX.X.....XXX.....X.XXX..XX....XXXX....
+....X...................XX....X...X....XX...XX..X..X..XX....
+....X................XXXXXXX..X......XXXXXXXXX......XXXXXX..
+....X...............X...XX..X.X...X.X..XX....XXX......XX..X.
+..XXX.....XXXXX......XXXXXXX...XXX...XXX.XXXXX......XX.X..X.
+QRSTUVWXYZ[\]^_`abcdefgh
+( ----- 270 )
+............................................................
+............................................................
+..X......XX..X..XX...X.X.XXX...XXX.XXX....XXXX.XX..XXX..X...
+..........X.X....X..X.X.XX..X.X...XX..X..X..XXX...X....XXX..
+..X......XXX.....X..X...XX...XX...XXXX....XXXX.....XXX..X...
+..X...X..XX.X....X..X...XX...XX...XX........XX........X.X...
+..X....XX.X..X...XX.X...XX...X.XXX.X........XX.....XXX...XX.
+................................XX...X...XX.......
+...............................X.....X.....X......
+X...XX...XX...XX...XX...XXXXXX.X.....X.....X..X.X.
+X...XX...XX...X.X.X..X.X....X.X......X......XX.X..
+X...XX...XX...X..X....X....X...X.....X.....X......
+X...X.X.X.X.X.X.X.X..X....X....X.....X.....X......
+.XXX...X...X.X.X...XX....XXXXX..XX...X...XX.......
+ijklmnopqrstuvwxyz{|}~
+( ----- 271 )
+..XX....XX.XX..XX.XX....XX..XX......XXX......XX.....XX...XX....
+..XX....XX.XX..XX.XX..XXXXXXXX..XX.XX.XX....XX.....XX.....XX...
+..XX....XX.XX.XXXXXXXXX.X......XX..XX.XX...XX.....XX.......XX..
+..XX...........XX.XX..XXXXX...XX....XXX...........XX.......XX..
+..XX..........XXXXXXX...X.XX.XX....XX.XX.X........XX.......XX..
+...............XX.XX.XXXXXX.XX..XX.XX..XX..........XX.....XX...
+..XX...........XX.XX...XX.......XX..XXX.XX..........XX...XX....
+...........................................XXXX....XX....XXXX..
+..XX.....XX............................XX.XX..XX..XXX...XX..XX.
+XXXXXX...XX...........................XX..XX.XXX...XX.......XX.
+.XXXX..XXXXXX........XXXXXX..........XX...XXXXXX...XX......XX..
+XXXXXX...XX.........................XX....XXX.XX...XX.....XX...
+..XX.....XX.....XX............XX...XX.....XX..XX...XX....XX....
+...............XX.............XX...........XXXX..XXXXXX.XXXXXX.
+!"#$%&'()*+,-./012
+( ----- 272 )
+.XXXX.....XX..XXXXXX...XXX..XXXXXX..XXXX...XXXX................
+XX..XX...XXX..XX......XX........XX.XX..XX.XX..XX...............
+....XX..XXXX..XXXXX..XX........XX..XX..XX.XX..XX...XX.....XX...
+..XXX..XX.XX......XX.XXXXX....XX....XXXX...XXXXX...XX.....XX...
+....XX.XXXXXX.....XX.XX..XX..XX....XX..XX.....XX...............
+XX..XX....XX..XX..XX.XX..XX..XX....XX..XX....XX....XX.....XX...
+.XXXX.....XX...XXXX...XXXX...XX.....XXXX...XXX.....XX....XX....
+...XX.........XX......XXXX...XXXX...XXXX..XXXXX...XXXX..XXXX...
+..XX...........XX....XX..XX.XX..XX.XX..XX.XX..XX.XX..XX.XX.XX..
+.XX....XXXXXX...XX......XX..XX.XXX.XX..XX.XX..XX.XX.....XX..XX.
+XX...............XX....XX...XX.X.X.XXXXXX.XXXXX..XX.....XX..XX.
+.XX....XXXXXX...XX.....XX...XX.XXX.XX..XX.XX..XX.XX.....XX..XX.
+..XX...........XX...........XX.....XX..XX.XX..XX.XX..XX.XX.XX..
+...XX.........XX.......XX....XXXX..XX..XX.XXXXX...XXXX..XXXX...
+3456789:;<=>?@ABCD
+( ----- 273 )
+XXXXXX.XXXXXX..XXXX..XX..XX.XXXXXX..XXXXX.XX..XX.XX.....XX...XX
+XX.....XX.....XX..XX.XX..XX...XX......XX..XX.XX..XX.....XXX.XXX
+XX.....XX.....XX.....XX..XX...XX......XX..XXXX...XX.....XXXXXXX
+XXXXX..XXXXX..XX.XXX.XXXXXX...XX......XX..XXX....XX.....XX.X.XX
+XX.....XX.....XX..XX.XX..XX...XX......XX..XXXX...XX.....XX.X.XX
+XX.....XX.....XX..XX.XX..XX...XX...XX.XX..XX.XX..XX.....XX...XX
+XXXXXX.XX......XXXX..XX..XX.XXXXXX..XXX...XX..XX.XXXXXX.XX...XX
+XX..XX..XXXX..XXXXX...XXXX..XXXXX...XXXX..XXXXXX.XX..XX.XX..XX.
+XX..XX.XX..XX.XX..XX.XX..XX.XX..XX.XX..XX...XX...XX..XX.XX..XX.
+XXX.XX.XX..XX.XX..XX.XX..XX.XX..XX.XX.......XX...XX..XX.XX..XX.
+XXXXXX.XX..XX.XXXXX..XX..XX.XXXXX...XXXX....XX...XX..XX.XX..XX.
+XX.XXX.XX..XX.XX.....XX.X.X.XX.XX......XX...XX...XX..XX.XX..XX.
+XX..XX.XX..XX.XX.....XX.XX..XX..XX.XX..XX...XX...XX..XX..XXXX..
+XX..XX..XXXX..XX......XX.XX.XX..XX..XXXX....XX....XXXX....XX...
+EFGHIJKLMNOPQRSTUVWXYZ[\]^_
+( ----- 274 )
+XX...XXXX..XX.XX..XX.XXXXXX.XXXXX.........XXXXX....XX..........
+XX...XXXX..XX.XX..XX.....XX.XX.....XX........XX...XXXX.........
+XX.X.XX.XXXX..XX..XX....XX..XX......XX.......XX..XX..XX........
+XX.X.XX..XX....XXXX....XX...XX.......XX......XX..X....X........
+XXXXXXX.XXXX....XX....XX....XX........XX.....XX................
+XXX.XXXXX..XX...XX...XX.....XX.........XX....XX................
+XX...XXXX..XX...XX...XXXXXX.XXXXX.........XXXXX.........XXXXXXX
+.XX...........XX................XX..........XXX.........XX.....
+..XX..........XX................XX.........XX.....XXXX..XX.....
+...XX...XXXX..XXXXX...XXXX...XXXXX..XXXX...XX....XX..XX.XXXXX..
+...........XX.XX..XX.XX..XX.XX..XX.XX..XX.XXXXX..XX..XX.XX..XX.
+........XXXXX.XX..XX.XX.....XX..XX.XXXXXX..XX.....XXXXX.XX..XX.
+.......XX..XX.XX..XX.XX..XX.XX..XX.XX......XX........XX.XX..XX.
+........XXXXX.XXXXX...XXXX...XXXXX..XXXX...XX.....XXX...XX..XX.
+WXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
+( ----- 275 )
+..XX.....XX...XX......XXX......................................
+..............XX.......XX......................................
+.XXX....XXX...XX..XX...XX....XX.XX.XXXXX...XXXX..XXXXX...XXXXX.
+..XX.....XX...XX.XX....XX...XXXXXXXXX..XX.XX..XX.XX..XX.XX..XX.
+..XX.....XX...XXXX.....XX...XX.X.XXXX..XX.XX..XX.XX..XX.XX..XX.
+..XX.....XX...XX.XX....XX...XX.X.XXXX..XX.XX..XX.XXXXX...XXXXX.
+.XXXX..XX.....XX..XX..XXXX..XX...XXXX..XX..XXXX..XX.........XX.
+...............XX..............................................
+...............XX..............................................
+XX.XX...XXXXX.XXXXX..XX..XX.XX..XX.XX...XXXX..XX.XX..XX.XXXXXX.
+XXX.XX.XX......XX....XX..XX.XX..XX.XX.X.XX.XXXX..XX..XX....XX..
+XX......XXXX...XX....XX..XX.XX..XX.XX.X.XX..XX...XX..XX...XX...
+XX.........XX..XX....XX..XX..XXXX..XXXXXXX.XXXX...XXXXX..XX....
+XX.....XXXXX....XXX...XXXXX...XX....XX.XX.XX..XX.....XX.XXXXXX.
+ijklmnopqrstuvwxyz{|}~
+( ----- 276 )
+...XX....XX...XX......XX...X
+..XX.....XX....XX....XX.X.XX
+..XX.....XX....XX....X...XX.
+XXX......XX.....XXX.........
+..XX.....XX....XX...........
+..XX.....XX....XX...........
+...XX....XX...XX............
+{|}~
+( ----- 290 )
+\ Automated tests. "1 LOAD 290 296 LOADR" to run.
+\ "#" means "assert". We ABORT on failure.
+: fail SPC> ABORT" failed" ;
+: # IF SPC> ." pass" NL> ELSE fail THEN ;
+: #eq 2DUP SWAP . SPC> '=' EMIT SPC> . '?' EMIT = # ;
+( ----- 291 )
+\ Arithmetics
+48 13 + 61 #eq
+48 13 - 35 #eq
+48 13 * 624 #eq
+48 13 / 3 #eq
+48 13 MOD 9 #eq
+5 3 LSHIFT 40 #eq
+155 5 RSHIFT 4 #eq
+( ----- 292 )
+\ Comparisons
+$22 $8065 < #
+-1 0 > #
+-1 0< #
+( ----- 293 )
+\ Memory
+42 C, 43 C, 44 C,
+HERE 3 - HERE 3 MOVE
+HERE C@ 42 #eq HERE 1+ C@ 43 #eq HERE 2 + C@ 44 #eq
+HERE HERE 1+ 3 MOVE ( demonstrate MOVE's problem )
+HERE 1+ C@ 42 #eq HERE 2 + C@ 42 #eq HERE 3 + C@ 42 #eq
+HERE 3 - HERE 3 MOVE
+HERE HERE 1+ 3 MOVE- ( see? better )
+HERE 1+ C@ 42 #eq HERE 2 + C@ 43 #eq HERE 3 + C@ 44 #eq
+
+HERE ( ref )
+HERE 3 - 3 MOVE,
+( ref ) HERE 3 - #eq
+HERE 3 - C@ 42 #eq HERE 2 - C@ 43 #eq HERE 1- C@ 44 #eq
+( ----- 294 )
+\ Parse
+'b' $62 #eq
+( ----- 295 )
+\ Stack
+42 43 44 ROT
+42 #eq 44 #eq 43 #eq
+42 43 44 ROT>
+43 #eq 42 #eq 44 #eq
+( ----- 296 )
+\ CRC
+$0000 $00 CRC16 $0000 #eq
+$0000 $01 CRC16 $1021 #eq
+$5678 $34 CRC16 $34e4 #eq
diff --git a/fs/app/cos/tools/blkpack.c b/fs/app/cos/tools/blkpack.c
@@ -67,10 +67,7 @@ extern void blkpack() {
for (blkline=0; blkline<16; blkline++) {
lineno++;
line = freadline(StdIn());
- if (!line) {
- emptylines(16-blkline);
- return;
- }
+ if (!line) { break; }
cnt = strlen(line);
if (cnt > 64) {
fprintf(
@@ -83,8 +80,13 @@ extern void blkpack() {
// pad line to 64 chars
for (i=cnt; i<64; i++) { stdout(' '); }
}
+ if (blkline == 16) {
+ lineno++;
+ line = freadline(StdIn());
+ if (!line) { return; }
+ } else {
+ emptylines(16-blkline);
+ }
prevblkid = blkid;
- lineno++;
- line = freadline(StdIn());
}
}