mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-02 08:30:55 +11:00
Compare commits
No commits in common. "b606dbf9af1d9b22565dfde8b1558d6441c5a938" and "80d730318a6358dadba84406af2945f6d92fd4b1" have entirely different histories.
b606dbf9af
...
80d730318a
1
blk/001
1
blk/001
@ -6,6 +6,7 @@ MASTER INDEX
|
|||||||
150 Extra words
|
150 Extra words
|
||||||
200 Z80 assembler 260 Cross compilation
|
200 Z80 assembler 260 Cross compilation
|
||||||
280 Z80 boot code 390 Cross-compiled core
|
280 Z80 boot code 390 Cross-compiled core
|
||||||
|
439 XPACKed core
|
||||||
490 TRS-80 Recipe 520 Fonts
|
490 TRS-80 Recipe 520 Fonts
|
||||||
550 TI-84+ Recipe 580 RC2014 Recipe
|
550 TI-84+ Recipe 580 RC2014 Recipe
|
||||||
|
|
||||||
|
3
blk/043
3
blk/043
@ -12,5 +12,4 @@ have to consume it to avoid PSP leak.
|
|||||||
] -- End interpretative mode.
|
] -- End interpretative mode.
|
||||||
ABORT -- Resets PS and RS and returns to interpreter.
|
ABORT -- Resets PS and RS and returns to interpreter.
|
||||||
ABORT" x" -- *I* Compiles a ." followed by a ABORT.
|
ABORT" x" -- *I* Compiles a ." followed by a ABORT.
|
||||||
ERR a -- Prints a and ABORT. Defined early and used by
|
EXECUTE a -- Execute wordref at addr a
|
||||||
drivers. (cont.)
|
|
||||||
|
1
blk/044
1
blk/044
@ -1,4 +1,3 @@
|
|||||||
EXECUTE a -- Execute wordref at addr a
|
|
||||||
INTERPRET -- Get a line from stdin, compile it in tmp memory,
|
INTERPRET -- Get a line from stdin, compile it in tmp memory,
|
||||||
then execute the compiled contents.
|
then execute the compiled contents.
|
||||||
LEAVE -- In a DO..LOOP, exit at the next LOOP call.
|
LEAVE -- In a DO..LOOP, exit at the next LOOP call.
|
||||||
|
3
blk/263
3
blk/263
@ -1,13 +1,14 @@
|
|||||||
VARIABLE XCURRENT
|
VARIABLE XCURRENT
|
||||||
|
|
||||||
: XCON XCURRENT CURRENT* ! ;
|
: XCON XCURRENT CURRENT* ! ;
|
||||||
: XCOFF 0x02 RAM+ CURRENT* ! ;
|
: XCOFF 0x02 RAM+ CURRENT* ! ;
|
||||||
|
|
||||||
: (xentry) XCON (entry) XCOFF ;
|
: (xentry) XCON (entry) XCOFF ;
|
||||||
: XCREATE (xentry) 11 C, ;
|
: XCREATE (xentry) 11 C, ;
|
||||||
: XCODE XCON CODE XCOFF ;
|
: XCODE XCON CODE XCOFF ;
|
||||||
: XIMM XCON IMMEDIATE XCOFF ;
|
: XIMM XCON IMMEDIATE XCOFF ;
|
||||||
: _xapply ( a -- a-off )
|
: _xapply ( a -- a-off )
|
||||||
DUP ORG @ > IF ORG @ - BIN( @ + THEN ;
|
DUP ORG @ > IF ORG @ - BIN( @ + THEN ;
|
||||||
: X' XCON ' XCOFF ;
|
|
||||||
: X['] XCON ' _xapply LITA XCOFF ;
|
: X['] XCON ' _xapply LITA XCOFF ;
|
||||||
: XCOMPILE
|
: XCOMPILE
|
||||||
XCON ' _xapply LITA
|
XCON ' _xapply LITA
|
||||||
|
1
blk/394
1
blk/394
@ -1,5 +1,4 @@
|
|||||||
: ABORT (resSP) QUIT ;
|
: ABORT (resSP) QUIT ;
|
||||||
: ERR LIT< (print) (find) IF EXECUTE THEN ABORT ;
|
|
||||||
: = CMP NOT ; : < CMP -1 = ; : > CMP 1 = ;
|
: = CMP NOT ; : < CMP -1 = ; : > CMP 1 = ;
|
||||||
: 0< 32767 > ; : >= < NOT ; : <= > NOT ; : 0>= 0< NOT ;
|
: 0< 32767 > ; : >= < NOT ; : <= > NOT ; : 0>= 0< NOT ;
|
||||||
( n l h -- f )
|
( n l h -- f )
|
||||||
|
23
blk/409
23
blk/409
@ -1,16 +1,7 @@
|
|||||||
( Words here until the end of the low part, unlike words
|
: INTERPRET
|
||||||
preceeding them, aren't immediately needed for boot. But its
|
BEGIN
|
||||||
better to have as many words as possible in the xcomp part. )
|
WORD DUP C@ EOT? IF DROP EXIT THEN
|
||||||
: H@ HERE @ ;
|
(find)
|
||||||
: IMMEDIATE
|
NOT IF (parse) ELSE EXECUTE THEN
|
||||||
CURRENT @ 1-
|
C<? NOT IF LIT< (ok) (find) IF EXECUTE THEN THEN
|
||||||
DUP C@ 128 OR SWAP C! ;
|
AGAIN ;
|
||||||
: IMMED? 1- C@ 0x80 AND ;
|
|
||||||
: +! SWAP OVER @ + SWAP ! ;
|
|
||||||
: -^ SWAP - ;
|
|
||||||
: / /MOD SWAP DROP ;
|
|
||||||
: MOD /MOD DROP ;
|
|
||||||
: ALLOT HERE +! ;
|
|
||||||
: CREATE (entry) 11 ( 11 == cellWord ) C, ;
|
|
||||||
: VARIABLE CREATE 2 ALLOT ;
|
|
||||||
: LEAVE R> R> DROP I 1- >R >R ;
|
|
||||||
|
22
blk/410
22
blk/410
@ -1,13 +1,11 @@
|
|||||||
: '? WORD (find) ;
|
( system c< simply reads source from binary, starting at
|
||||||
: '
|
LATEST. Convenient way to bootstrap a new system. )
|
||||||
'? (?br) [ 4 , ] EXIT
|
: (boot<)
|
||||||
LIT< (wnf) (find) DROP EXECUTE
|
( 2e == BOOT C< PTR )
|
||||||
|
0x2e RAM+ @ ( a )
|
||||||
|
DUP C@ ( a c )
|
||||||
|
SWAP 1 + ( c a+1 )
|
||||||
|
0x2e RAM+ ! ( c )
|
||||||
;
|
;
|
||||||
: ROLL
|
|
||||||
DUP NOT IF EXIT THEN
|
|
||||||
1+ DUP PICK ( n val )
|
|
||||||
SWAP 2 * (roll) ( val )
|
|
||||||
SWAP DROP
|
|
||||||
;
|
|
||||||
: 2OVER 3 PICK 3 PICK ;
|
|
||||||
: 2SWAP 3 ROLL 3 ROLL ;
|
|
||||||
|
26
blk/411
26
blk/411
@ -1,13 +1,13 @@
|
|||||||
: MOVE ( a1 a2 u -- )
|
: BOOT
|
||||||
( u ) 0 DO ( a1 a2 )
|
0x02 RAM+ CURRENT* !
|
||||||
SWAP C@+ ( a2 a1+1 x )
|
CURRENT @ 0x2e RAM+ ! ( 2e == BOOT C< PTR )
|
||||||
ROT C!+ ( a1+1 a2+1 )
|
0 0x08 RAM+ ! ( 08 == C<* override )
|
||||||
LOOP 2DROP ;
|
0 0x53 RAM+ ! ( 53 == (emit) override )
|
||||||
: MOVE- ( a1 a2 u -- )
|
0 0x55 RAM+ ! ( 55 == (key) override )
|
||||||
SWAP OVER + 1- ( a1 u a2+u-1 )
|
0 0x0a RAM+ ! ( NLPTR )
|
||||||
ROT 2 PICK + 1- ( u a2+u-1 a1+u-1 )
|
( 0c == C<* )
|
||||||
ROT ( u ) 0 DO ( a2 a1 )
|
['] (boot<) 0x0c RAM+ !
|
||||||
C@- ( a2 a1-1 x )
|
( boot< always has a char waiting. 06 == C<?* )
|
||||||
ROT C!- ( a1-1 a2-1 ) SWAP ( a2 a1 )
|
1 0x06 RAM+ !
|
||||||
LOOP 2DROP ;
|
INTERPRET BYE ;
|
||||||
: PREV 3 - DUP @ - ;
|
|
||||||
|
27
blk/412
27
blk/412
@ -1,13 +1,16 @@
|
|||||||
: WORD(
|
( Words here until the end of the low part, unlike words
|
||||||
DUP 1- C@ ( name len field )
|
preceeding them, aren't immediately needed for boot. But its
|
||||||
127 AND ( 0x7f. remove IMMEDIATE flag )
|
better to have as many words as possible in the xcomp part. )
|
||||||
3 + ( fixed header len )
|
: H@ HERE @ ;
|
||||||
-
|
: IMMEDIATE
|
||||||
;
|
CURRENT @ 1-
|
||||||
: FORGET
|
DUP C@ 128 OR SWAP C!
|
||||||
' DUP ( w w )
|
|
||||||
( HERE must be at the end of prev's word, that is, at the
|
|
||||||
beginning of w. )
|
|
||||||
WORD( HERE ! ( w )
|
|
||||||
PREV CURRENT !
|
|
||||||
;
|
;
|
||||||
|
: +! SWAP OVER @ + SWAP ! ;
|
||||||
|
: -^ SWAP - ;
|
||||||
|
: / /MOD SWAP DROP ;
|
||||||
|
: MOD /MOD DROP ;
|
||||||
|
|
||||||
|
: ALLOT HERE +! ;
|
||||||
|
: CREATE (entry) 11 ( 11 == cellWord ) C, ;
|
||||||
|
: LEAVE R> R> DROP I 1- >R >R ;
|
||||||
|
26
blk/413
26
blk/413
@ -1,15 +1,13 @@
|
|||||||
: DOES>
|
: '? WORD (find) ;
|
||||||
( Overwrite cellWord in CURRENT )
|
: '
|
||||||
( 43 == doesWord )
|
'? (?br) [ 4 , ] EXIT
|
||||||
43 CURRENT @ C!
|
LIT< (wnf) (find) DROP EXECUTE
|
||||||
( When we have a DOES>, we forcefully place HERE to 4
|
|
||||||
bytes after CURRENT. This allows a DOES word to use ","
|
|
||||||
and "C," without messing everything up. )
|
|
||||||
CURRENT @ 3 + HERE !
|
|
||||||
( HERE points to where we should write R> )
|
|
||||||
R> ,
|
|
||||||
( We're done. Because we've popped RS, we'll exit parent
|
|
||||||
definition )
|
|
||||||
;
|
;
|
||||||
: CONSTANT CREATE , DOES> @ ;
|
: ROLL
|
||||||
|
DUP NOT IF EXIT THEN
|
||||||
|
1+ DUP PICK ( n val )
|
||||||
|
SWAP 2 * (roll) ( val )
|
||||||
|
SWAP DROP
|
||||||
|
;
|
||||||
|
: 2OVER 3 PICK 3 PICK ;
|
||||||
|
: 2SWAP 3 ROLL 3 ROLL ;
|
||||||
|
18
blk/414
18
blk/414
@ -1,5 +1,13 @@
|
|||||||
: [IF]
|
: MOVE ( a1 a2 u -- )
|
||||||
IF EXIT THEN
|
( u ) 0 DO ( a1 a2 )
|
||||||
LIT< [THEN] BEGIN DUP WORD S= UNTIL DROP ;
|
SWAP C@+ ( a2 a1+1 x )
|
||||||
: [THEN] ;
|
ROT C!+ ( a1+1 a2+1 )
|
||||||
|
LOOP 2DROP ;
|
||||||
|
: MOVE- ( a1 a2 u -- )
|
||||||
|
SWAP OVER + 1- ( a1 u a2+u-1 )
|
||||||
|
ROT 2 PICK + 1- ( u a2+u-1 a1+u-1 )
|
||||||
|
ROT ( u ) 0 DO ( a2 a1 )
|
||||||
|
C@- ( a2 a1-1 x )
|
||||||
|
ROT C!- ( a1-1 a2-1 ) SWAP ( a2 a1 )
|
||||||
|
LOOP 2DROP ;
|
||||||
|
: PREV 3 - DUP @ - ;
|
||||||
|
13
blk/415
Normal file
13
blk/415
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
: WORD(
|
||||||
|
DUP 1- C@ ( name len field )
|
||||||
|
127 AND ( 0x7f. remove IMMEDIATE flag )
|
||||||
|
3 + ( fixed header len )
|
||||||
|
-
|
||||||
|
;
|
||||||
|
: FORGET
|
||||||
|
' DUP ( w w )
|
||||||
|
( HERE must be at the end of prev's word, that is, at the
|
||||||
|
beginning of w. )
|
||||||
|
WORD( HERE ! ( w )
|
||||||
|
PREV CURRENT !
|
||||||
|
;
|
12
blk/421
12
blk/421
@ -1,16 +1,14 @@
|
|||||||
: EMIT
|
: EMIT
|
||||||
( 0x53==(emit) override )
|
( 0x53==(emit) override )
|
||||||
0x53 RAM+ @ DUP IF EXECUTE ELSE DROP (emit) THEN ;
|
0x53 RAM+ @ DUP IF EXECUTE ELSE DROP (emit) THEN ;
|
||||||
|
|
||||||
: (print)
|
: (print)
|
||||||
BEGIN
|
BEGIN
|
||||||
C@+ ( a+1 c )
|
C@+ ( a+1 c )
|
||||||
( exit if null or 0xd )
|
( exit if null or 0xd )
|
||||||
DUP 0xd = OVER NOT OR IF 2DROP EXIT THEN
|
DUP 0xd = OVER NOT OR IF 2DROP EXIT THEN
|
||||||
EMIT ( a )
|
EMIT ( a )
|
||||||
AGAIN ;
|
AGAIN
|
||||||
: BS 8 EMIT ; : LF 10 EMIT ; : CR 13 EMIT ;
|
;
|
||||||
: CRLF CR LF ; : SPC 32 EMIT ;
|
|
||||||
: NL 0x0a RAM+ @ ( NLPTR ) DUP IF EXECUTE ELSE DROP CRLF THEN ;
|
|
||||||
: (ok) SPC LIT" ok" (print) NL ;
|
|
||||||
: (uflw) LIT" stack underflow" ERR ;
|
|
||||||
: (wnf) (print) SPC LIT" word not found" ERR ;
|
|
||||||
|
14
blk/422
14
blk/422
@ -1,7 +1,15 @@
|
|||||||
: ,"
|
: ,"
|
||||||
BEGIN
|
BEGIN
|
||||||
C< DUP 34 ( ASCII " ) = IF DROP EXIT THEN C,
|
C<
|
||||||
|
( 34 is ASCII for " )
|
||||||
|
DUP 34 = IF DROP EXIT THEN C,
|
||||||
AGAIN ;
|
AGAIN ;
|
||||||
: LIT" 34 , ( litWord ) ," 0 C, ; IMMEDIATE
|
|
||||||
: ." [COMPILE] LIT" COMPILE (print) ; IMMEDIATE
|
: ."
|
||||||
|
34 , ( 34 == litWord ) ," 0 C,
|
||||||
|
COMPILE (print)
|
||||||
|
; IMMEDIATE
|
||||||
: ABORT" [COMPILE] ." COMPILE ABORT ; IMMEDIATE
|
: ABORT" [COMPILE] ." COMPILE ABORT ; IMMEDIATE
|
||||||
|
: BS 8 EMIT ; : LF 10 EMIT ; : CR 13 EMIT ;
|
||||||
|
: CRLF CR LF ; : SPC 32 EMIT ;
|
||||||
|
: NL 0x0a RAM+ @ ( NLPTR ) DUP IF EXECUTE ELSE DROP CRLF THEN ;
|
||||||
|
11
blk/432
11
blk/432
@ -1,14 +1,3 @@
|
|||||||
: INTERPRET
|
|
||||||
BEGIN
|
|
||||||
WORD DUP C@ EOT? IF DROP EXIT THEN
|
|
||||||
(find) NOT IF (parse) ELSE EXECUTE THEN
|
|
||||||
C<? NOT IF (ok) THEN
|
|
||||||
AGAIN ;
|
|
||||||
( Read from BOOT C< PTR and inc it. )
|
|
||||||
: (boot<)
|
|
||||||
( 2e == BOOT C< PTR )
|
|
||||||
0x2e ( BOOT C< PTR ) RAM+ @ DUP C@ ( a c )
|
|
||||||
SWAP 1 + 0x2e RAM+ ! ( c ) ;
|
|
||||||
( pre-comment for tight LOAD: The 0x08==I check after INTERPRET
|
( pre-comment for tight LOAD: The 0x08==I check after INTERPRET
|
||||||
is to check whether we're restoring to "_", the word above.
|
is to check whether we're restoring to "_", the word above.
|
||||||
if yes, then we're in a nested load. Also, the 1 in 0x06 is
|
if yes, then we're in a nested load. Also, the 1 in 0x06 is
|
||||||
|
14
blk/435
Normal file
14
blk/435
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
( LITN has to be defined after the last immediate usage of
|
||||||
|
it to avoid bootstrapping issues )
|
||||||
|
: LITN 32 , , ( 32 == NUMBER ) ;
|
||||||
|
|
||||||
|
: IMMED? 1- C@ 0x80 AND ;
|
||||||
|
|
||||||
|
( ';' can't have its name right away because, when created, it
|
||||||
|
is not an IMMEDIATE yet and will not be treated properly by
|
||||||
|
xcomp. )
|
||||||
|
: _
|
||||||
|
['] EXIT ,
|
||||||
|
R> DROP ( exit : )
|
||||||
|
; IMMEDIATE
|
||||||
|
|
29
blk/436
29
blk/436
@ -1,13 +1,16 @@
|
|||||||
: BOOT
|
XCURRENT @ ( to PSP )
|
||||||
0x02 RAM+ CURRENT* !
|
: :
|
||||||
CURRENT @ 0x2e RAM+ ! ( 2e == BOOT C< PTR )
|
(entry)
|
||||||
0 0x08 RAM+ ! ( 08 == C<* override )
|
( We cannot use LITN as IMMEDIATE because of bootstrapping
|
||||||
0 0x53 RAM+ ! ( 53 == (emit) override )
|
issues. Same thing for ",".
|
||||||
0 0x55 RAM+ ! ( 55 == (key) override )
|
32 == NUMBER 14 == compiledWord )
|
||||||
0 0x0a RAM+ ! ( NLPTR )
|
[ 32 H@ ! 2 ALLOT 14 H@ ! 2 ALLOT ] C,
|
||||||
( 0c == C<* )
|
BEGIN
|
||||||
['] (boot<) 0x0c RAM+ !
|
WORD
|
||||||
( boot< always has a char waiting. 06 == C<?* )
|
(find)
|
||||||
1 0x06 RAM+ !
|
( is word )
|
||||||
INTERPRET BYE ;
|
IF DUP IMMED? IF EXECUTE ELSE , THEN
|
||||||
|
( maybe number )
|
||||||
|
ELSE (parse) LITN THEN
|
||||||
|
AGAIN ;
|
||||||
|
( from PSP ) ';' SWAP 4 - C!
|
||||||
|
15
blk/437
15
blk/437
@ -1,15 +0,0 @@
|
|||||||
( Now we have "as late as possible" stuff )
|
|
||||||
: DO COMPILE 2>R H@ ; IMMEDIATE
|
|
||||||
: LOOP COMPILE (loop) H@ - , ; IMMEDIATE
|
|
||||||
( LEAVE is implemented in low xcomp )
|
|
||||||
: LITN 32 , , ( 32 == NUMBER ) ;
|
|
||||||
( gets its name at the very end. can't comment afterwards )
|
|
||||||
: _ BEGIN LIT< ) WORD S= UNTIL ; IMMEDIATE
|
|
||||||
: _ ( : will get its name almost at the very end )
|
|
||||||
(entry)
|
|
||||||
[ 14 ( == compiledWord ) LITN ] C,
|
|
||||||
BEGIN
|
|
||||||
WORD (find)
|
|
||||||
IF ( is word ) DUP IMMED? IF EXECUTE ELSE , THEN
|
|
||||||
ELSE ( maybe number ) (parse) LITN THEN
|
|
||||||
AGAIN ;
|
|
14
blk/438
14
blk/438
@ -1,14 +0,0 @@
|
|||||||
: IF ( -- a | a: br cell addr )
|
|
||||||
COMPILE (?br) H@ 2 ALLOT ( br cell allot )
|
|
||||||
; IMMEDIATE
|
|
||||||
: THEN ( a -- | a: br cell addr )
|
|
||||||
DUP H@ -^ SWAP ( a-H a ) !
|
|
||||||
; IMMEDIATE
|
|
||||||
: ELSE ( a1 -- a2 | a1: IF cell a2: ELSE cell )
|
|
||||||
COMPILE (br)
|
|
||||||
2 ALLOT
|
|
||||||
DUP H@ -^ SWAP ( a-H a )
|
|
||||||
!
|
|
||||||
H@ 2- ( push a. -2 for allot offset )
|
|
||||||
; IMMEDIATE
|
|
||||||
|
|
23
blk/439
23
blk/439
@ -1,9 +1,14 @@
|
|||||||
: BEGIN H@ ; IMMEDIATE
|
XPACKed core
|
||||||
: AGAIN COMPILE (br) H@ - , ; IMMEDIATE
|
|
||||||
: UNTIL COMPILE (?br) H@ - , ; IMMEDIATE
|
Most of Collapse OS' core words are cross compiled (B390).
|
||||||
: [ INTERPRET ; IMMEDIATE
|
However, some of them are too dynamically referenced to be
|
||||||
: ] R> DROP ;
|
cross-compiled without great pain, so we XPACK (B267) them,
|
||||||
: LIT< WORD 34 , SCPY 0 C, ; IMMEDIATE
|
that is, we put them in source form in the target's
|
||||||
: LITA 36 , , ;
|
initialization section (see B89).
|
||||||
: COMPILE ' LITA ['] , , ; IMMEDIATE
|
|
||||||
: [COMPILE] ' , ; IMMEDIATE
|
These words will be compiled into RAM at initialization, which
|
||||||
|
is a bit wasteful both in RAM and in boot time, so we will
|
||||||
|
typically relink (B120) that newly compiled binary and append
|
||||||
|
it to our existing binary for optimal resource usage.
|
||||||
|
|
||||||
|
Load range: 440-446
|
||||||
|
19
blk/440
19
blk/440
@ -1,11 +1,10 @@
|
|||||||
( ';' can't have its name right away because, when created, it
|
: [ INTERPRET ; IMMEDIATE
|
||||||
is not an IMMEDIATE yet and will not be treated properly by
|
: ] R> DROP ;
|
||||||
xcomp. )
|
: LIT< WORD 34 , SCPY 0 C, ; IMMEDIATE
|
||||||
: _
|
: LITA 36 , , ;
|
||||||
['] EXIT ,
|
|
||||||
R> DROP ( exit : )
|
|
||||||
; IMMEDIATE
|
|
||||||
: ['] ' LITA ; IMMEDIATE
|
: ['] ' LITA ; IMMEDIATE
|
||||||
';' X' _ 4 - C! ( give ; its name )
|
: COMPILE ' LITA ['] , , ; IMMEDIATE
|
||||||
':' X' _ 4 - C! ( give : its name )
|
: [COMPILE] ' , ; IMMEDIATE
|
||||||
'(' X' _ 4 - C!
|
: BEGIN H@ ; IMMEDIATE
|
||||||
|
: AGAIN COMPILE (br) H@ - , ; IMMEDIATE
|
||||||
|
: UNTIL COMPILE (?br) H@ - , ; IMMEDIATE
|
||||||
|
13
blk/441
Normal file
13
blk/441
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
: _ BEGIN LIT< ) WORD S= UNTIL ; IMMEDIATE
|
||||||
|
40 CURRENT @ 4 - C!
|
||||||
|
( Hello, hello, krkrkrkr... do you hear me?
|
||||||
|
Ah, voice at last! Some lines above need comments
|
||||||
|
BTW: Forth lines limited to 64 cols because of default
|
||||||
|
input buffer size in Collapse OS
|
||||||
|
|
||||||
|
40 is ASCII for '('. We do this to simplify XPACK's task of
|
||||||
|
not mistakenly consider '(' definition as a comment.
|
||||||
|
LIT<: 34 == litWord
|
||||||
|
LITA: 36 == addrWord
|
||||||
|
COMPILE: Tough one. Get addr of caller word (example above
|
||||||
|
(br)) and then call LITA on it. )
|
11
blk/442
Normal file
11
blk/442
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
: IF ( -- a | a: br cell addr )
|
||||||
|
COMPILE (?br)
|
||||||
|
H@ ( push a )
|
||||||
|
2 ALLOT ( br cell allot )
|
||||||
|
; IMMEDIATE
|
||||||
|
|
||||||
|
: THEN ( a -- | a: br cell addr )
|
||||||
|
DUP H@ -^ SWAP ( a-H a )
|
||||||
|
!
|
||||||
|
; IMMEDIATE
|
||||||
|
|
12
blk/443
Normal file
12
blk/443
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
: ELSE ( a1 -- a2 | a1: IF cell a2: ELSE cell )
|
||||||
|
COMPILE (br)
|
||||||
|
2 ALLOT
|
||||||
|
DUP H@ -^ SWAP ( a-H a )
|
||||||
|
!
|
||||||
|
H@ 2- ( push a. -2 for allot offset )
|
||||||
|
; IMMEDIATE
|
||||||
|
|
||||||
|
: [IF]
|
||||||
|
IF EXIT THEN
|
||||||
|
LIT< [THEN] BEGIN DUP WORD S= UNTIL DROP ;
|
||||||
|
: [THEN] ;
|
14
blk/444
Normal file
14
blk/444
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
: DOES>
|
||||||
|
( Overwrite cellWord in CURRENT )
|
||||||
|
( 43 == doesWord )
|
||||||
|
43 CURRENT @ C!
|
||||||
|
( When we have a DOES>, we forcefully place HERE to 4
|
||||||
|
bytes after CURRENT. This allows a DOES word to use ","
|
||||||
|
and "C," without messing everything up. )
|
||||||
|
CURRENT @ 3 + HERE !
|
||||||
|
( HERE points to where we should write R> )
|
||||||
|
R> ,
|
||||||
|
( We're done. Because we've popped RS, we'll exit parent
|
||||||
|
definition )
|
||||||
|
;
|
||||||
|
|
8
blk/445
Normal file
8
blk/445
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
: VARIABLE CREATE 2 ALLOT ;
|
||||||
|
: CONSTANT CREATE , DOES> @ ;
|
||||||
|
|
||||||
|
( In addition to pushing H@ this compiles 2>R so that loop
|
||||||
|
variables are sent to PS at runtime )
|
||||||
|
: DO COMPILE 2>R H@ ; IMMEDIATE
|
||||||
|
: LOOP COMPILE (loop) H@ - , ; IMMEDIATE
|
||||||
|
( LEAVE is implemented in xcomp )
|
3
blk/446
Normal file
3
blk/446
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
: (ok) SPC ." ok" NL ;
|
||||||
|
: (uflw) ABORT" stack underflow" ;
|
||||||
|
: (wnf) (print) SPC ABORT" word not found" ;
|
3
blk/490
3
blk/490
@ -4,7 +4,8 @@ Support code for the TRS-80 recipe. Contains drivers for the
|
|||||||
keyboard, video and floppy. At the moment, they are thin layer
|
keyboard, video and floppy. At the moment, they are thin layer
|
||||||
over the drivers provided by TRSDOS' SVC.
|
over the drivers provided by TRSDOS' SVC.
|
||||||
|
|
||||||
Load with "492 LOAD".
|
Load the Z80 words with "492 LOAD" and the high level part
|
||||||
|
with "498 LOAD".
|
||||||
|
|
||||||
There is also the RECV program at B502 and the XCOMP unit at
|
There is also the RECV program at B502 and the XCOMP unit at
|
||||||
B504
|
B504
|
||||||
|
2
blk/499
2
blk/499
@ -1,4 +1,4 @@
|
|||||||
: _err LIT" FDerr" ERR ;
|
: _err ABORT" FDerr" ;
|
||||||
: _cylsec ( sec -- cs, return sector/cylinder for given secid )
|
: _cylsec ( sec -- cs, return sector/cylinder for given secid )
|
||||||
( 4 256b sectors per block, 10 sec per cyl, 40 cyl max )
|
( 4 256b sectors per block, 10 sec per cyl, 40 cyl max )
|
||||||
10 /MOD ( sec cyl )
|
10 /MOD ( sec cyl )
|
||||||
|
2
blk/500
2
blk/500
@ -2,6 +2,6 @@
|
|||||||
: FD! ['] @WRSEC SWAP FD@! ;
|
: FD! ['] @WRSEC SWAP FD@! ;
|
||||||
: FD$ ['] FD@ BLK@* ! ['] FD! BLK!* ! ;
|
: FD$ ['] FD@ BLK@* ! ['] FD! BLK!* ! ;
|
||||||
|
|
||||||
: _err LIT" *CLerr" ERR ;
|
: _err ABORT" *CLerr" ;
|
||||||
: *CL< 0 BEGIN DROP 0x0238 @GET UNTIL ;
|
: *CL< 0 BEGIN DROP 0x0238 @GET UNTIL ;
|
||||||
: *CL> 0x0238 @PUT NOT IF _err THEN ;
|
: *CL> 0x0238 @PUT NOT IF _err THEN ;
|
||||||
|
2
blk/580
2
blk/580
@ -4,4 +4,4 @@ Support code for the RC2014 recipe. Contains drivers for the
|
|||||||
ACIA, SD card and AT28 EEPROM.
|
ACIA, SD card and AT28 EEPROM.
|
||||||
|
|
||||||
581 ACIA 590 AT28 EEPROM
|
581 ACIA 590 AT28 EEPROM
|
||||||
600 SD card 618 Xcomp unit
|
600 SD card
|
||||||
|
15
blk/618
15
blk/618
@ -1,15 +0,0 @@
|
|||||||
0x8000 CONSTANT RAMSTART
|
|
||||||
0xf000 CONSTANT RS_ADDR 0xfffa CONSTANT PS_ADDR
|
|
||||||
0x80 CONSTANT ACIA_CTL 0x81 CONSTANT ACIA_IO
|
|
||||||
4 CONSTANT SDC_SPI
|
|
||||||
5 CONSTANT SDC_CSLOW 6 CONSTANT SDC_CSHIGH
|
|
||||||
RAMSTART 0x70 + CONSTANT ACIA_MEM
|
|
||||||
212 LOAD ( z80 assembler )
|
|
||||||
262 LOAD ( xcomp ) 270 LOAD ( xcomp overrides )
|
|
||||||
282 LOAD ( boot.z80 ) 393 LOAD ( xcomp core low )
|
|
||||||
582 LOAD ( acia )
|
|
||||||
420 LOAD ( xcomp core high )
|
|
||||||
(entry) _
|
|
||||||
( Update LATEST )
|
|
||||||
PC ORG @ 8 + !
|
|
||||||
," : _ ACIA$ RDLN$ (ok) ; _ "
|
|
5
emul/.gitignore
vendored
5
emul/.gitignore
vendored
@ -1,4 +1,7 @@
|
|||||||
/stage
|
/stage1
|
||||||
|
/stage1dbg
|
||||||
|
/stage2
|
||||||
/forth
|
/forth
|
||||||
/*-bin.h
|
/*-bin.h
|
||||||
|
/stage0.bin
|
||||||
/blkfs
|
/blkfs
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
TARGETS = forth stage
|
TARGETS = forth stage2
|
||||||
OBJS = emul.o libz80/libz80.o
|
OBJS = emul.o libz80/libz80.o
|
||||||
BIN2C = ../tools/bin2c
|
BIN2C = ../tools/bin2c
|
||||||
BLKPACK = ../tools/blkpack
|
BLKPACK = ../tools/blkpack
|
||||||
@ -14,12 +14,24 @@ $(BLKPACK):
|
|||||||
$(BIN2C): $(BLKPACK)
|
$(BIN2C): $(BLKPACK)
|
||||||
$(BLKUNPACK): $(BLKPACK)
|
$(BLKUNPACK): $(BLKPACK)
|
||||||
|
|
||||||
|
stage0.bin: stage2 xcomp.fs
|
||||||
|
cat xcomp.fs | ./stage2 > stage0.bin
|
||||||
|
|
||||||
|
stage0-bin.h: stage0.bin $(BIN2C)
|
||||||
|
$(BIN2C) KERNEL < stage0.bin > $@
|
||||||
|
|
||||||
|
stage1: stage.c $(OBJS) stage0-bin.h
|
||||||
|
$(CC) stage.c $(OBJS) -o $@
|
||||||
|
|
||||||
|
stage1dbg: stage.c $(OBJS) stage0-bin.h
|
||||||
|
$(CC) -DDEBUG stage.c $(OBJS) -o $@
|
||||||
|
|
||||||
# not dependent on forth.bin to avoid circular deps.
|
# not dependent on forth.bin to avoid circular deps.
|
||||||
forth-bin.h: $(BIN2C)
|
forth-bin.h: $(BIN2C)
|
||||||
$(BIN2C) KERNEL < forth.bin > $@
|
$(BIN2C) KERNEL < forth.bin > $@
|
||||||
|
|
||||||
stage: stage.c $(OBJS) forth-bin.h blkfs-bin.h
|
stage2: stage.c $(OBJS) forth-bin.h blkfs-bin.h
|
||||||
$(CC) stage.c $(OBJS) -o $@
|
$(CC) -DSTAGE2 stage.c $(OBJS) -o $@
|
||||||
|
|
||||||
blkfs: $(BLKPACK)
|
blkfs: $(BLKPACK)
|
||||||
$(BLKPACK) ../blk > $@
|
$(BLKPACK) ../blk > $@
|
||||||
@ -39,8 +51,8 @@ emul.o: emul.c
|
|||||||
|
|
||||||
|
|
||||||
.PHONY: updatebootstrap
|
.PHONY: updatebootstrap
|
||||||
updatebootstrap: stage xcomp.fs
|
updatebootstrap: stage1 stage1.fs
|
||||||
./stage < xcomp.fs > forth.bin
|
./stage1 < stage1.fs > forth.bin
|
||||||
|
|
||||||
.PHONY: pack
|
.PHONY: pack
|
||||||
pack:
|
pack:
|
||||||
|
BIN
emul/forth.bin
BIN
emul/forth.bin
Binary file not shown.
@ -2,8 +2,12 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "emul.h"
|
#include "emul.h"
|
||||||
|
#ifdef STAGE2
|
||||||
#include "forth-bin.h"
|
#include "forth-bin.h"
|
||||||
#include "blkfs-bin.h"
|
#include "blkfs-bin.h"
|
||||||
|
#else
|
||||||
|
#include "stage0-bin.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Staging binaries
|
/* Staging binaries
|
||||||
|
|
||||||
@ -70,6 +74,7 @@ static void iowr_here(uint8_t val)
|
|||||||
end_here |= val;
|
end_here |= val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef STAGE2
|
||||||
static void iowr_blk(uint8_t val)
|
static void iowr_blk(uint8_t val)
|
||||||
{
|
{
|
||||||
blkid <<= 8;
|
blkid <<= 8;
|
||||||
@ -81,6 +86,7 @@ static uint8_t iord_blkdata()
|
|||||||
{
|
{
|
||||||
return BLKFS[blkpos++];
|
return BLKFS[blkpos++];
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -89,8 +95,10 @@ int main(int argc, char *argv[])
|
|||||||
m->iord[STDIO_PORT] = iord_stdio;
|
m->iord[STDIO_PORT] = iord_stdio;
|
||||||
m->iowr[STDIO_PORT] = iowr_stdio;
|
m->iowr[STDIO_PORT] = iowr_stdio;
|
||||||
m->iowr[HERE_PORT] = iowr_here;
|
m->iowr[HERE_PORT] = iowr_here;
|
||||||
|
#ifdef STAGE2
|
||||||
m->iowr[BLK_PORT] = iowr_blk;
|
m->iowr[BLK_PORT] = iowr_blk;
|
||||||
m->iord[BLKDATA_PORT] = iord_blkdata;
|
m->iord[BLKDATA_PORT] = iord_blkdata;
|
||||||
|
#endif
|
||||||
// initialize memory
|
// initialize memory
|
||||||
for (int i=0; i<sizeof(KERNEL); i++) {
|
for (int i=0; i<sizeof(KERNEL); i++) {
|
||||||
m->mem[i] = KERNEL[i];
|
m->mem[i] = KERNEL[i];
|
||||||
|
28
emul/stage1.fs
Normal file
28
emul/stage1.fs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
: EFS@
|
||||||
|
256 /MOD 3 PC! 3 PC!
|
||||||
|
1024 0 DO
|
||||||
|
4 PC@
|
||||||
|
BLK( I + C!
|
||||||
|
LOOP
|
||||||
|
;
|
||||||
|
: EFS!
|
||||||
|
256 /MOD 3 PC! 3 PC!
|
||||||
|
1024 0 DO
|
||||||
|
BLK( I + C@ 4 PC!
|
||||||
|
LOOP
|
||||||
|
;
|
||||||
|
|
||||||
|
: INIT
|
||||||
|
CURRENT @ HERE !
|
||||||
|
BLK$
|
||||||
|
['] EFS@ BLK@* !
|
||||||
|
['] EFS! BLK!* !
|
||||||
|
RDLN$
|
||||||
|
LIT< _sys [entry]
|
||||||
|
." Collapse OS" NL
|
||||||
|
;
|
||||||
|
|
||||||
|
(entry) _
|
||||||
|
H@ 0x08 BIN+ ! ( update LATEST )
|
||||||
|
," INIT "
|
||||||
|
H@ 256 /MOD 2 PC! 2 PC!
|
@ -9,32 +9,12 @@
|
|||||||
393 LOAD ( xcomp core low )
|
393 LOAD ( xcomp core low )
|
||||||
: (emit) 0 PC! ;
|
: (emit) 0 PC! ;
|
||||||
: (key) 0 PC@ ;
|
: (key) 0 PC@ ;
|
||||||
: EFS@
|
|
||||||
256 /MOD 3 PC! 3 PC!
|
|
||||||
1024 0 DO
|
|
||||||
4 PC@
|
|
||||||
BLK( I + C!
|
|
||||||
LOOP
|
|
||||||
;
|
|
||||||
: EFS!
|
|
||||||
256 /MOD 3 PC! 3 PC!
|
|
||||||
1024 0 DO
|
|
||||||
BLK( I + C@ 4 PC!
|
|
||||||
LOOP
|
|
||||||
;
|
|
||||||
|
|
||||||
420 LOAD ( xcomp core high )
|
420 LOAD ( xcomp core high )
|
||||||
(entry) _
|
(entry) _
|
||||||
( Update LATEST )
|
( Update LATEST )
|
||||||
PC ORG @ 8 + !
|
PC ORG @ 8 + !
|
||||||
," CURRENT @ HERE ! "
|
," CURRENT @ HERE ! "
|
||||||
," : INIT "
|
440 446 XPACKR
|
||||||
," BLK$ "
|
," ' (key) 12 RAM+ ! "
|
||||||
," ['] EFS@ BLK@* ! "
|
|
||||||
," ['] EFS! BLK!* ! "
|
|
||||||
," RDLN$ "
|
|
||||||
," LIT< _sys [entry] "
|
|
||||||
," LIT< CollapseOS (print) NL "
|
|
||||||
," ; INIT "
|
|
||||||
ORG @ 256 /MOD 2 PC! 2 PC!
|
ORG @ 256 /MOD 2 PC! 2 PC!
|
||||||
H@ 256 /MOD 2 PC! 2 PC!
|
H@ 256 /MOD 2 PC! 2 PC!
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
TARGET = os.bin
|
TARGET = stage1.bin
|
||||||
BASEDIR = ../..
|
BASEDIR = ../..
|
||||||
FDIR = $(BASEDIR)/forth
|
FDIR = $(BASEDIR)/forth
|
||||||
EDIR = $(BASEDIR)/emul
|
EDIR = $(BASEDIR)/emul
|
||||||
STAGE = $(EDIR)/stage
|
STAGE2 = $(EDIR)/stage2
|
||||||
EMUL = $(BASEDIR)/emul/hw/rc2014/classic
|
EMUL = $(BASEDIR)/emul/hw/rc2014/classic
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
$(TARGET): xcomp.fs $(STAGE)
|
$(TARGET): xcomp.fs $(STAGE2)
|
||||||
cat xcomp.fs | $(STAGE) > $@
|
cat xcomp.fs | $(STAGE2) > $@
|
||||||
|
|
||||||
$(SLATEST):
|
$(SLATEST):
|
||||||
$(MAKE) -C $(BASEDIR)/tools
|
$(MAKE) -C $(BASEDIR)/tools
|
||||||
|
@ -40,7 +40,7 @@ device I use in this recipe.
|
|||||||
### Gathering parts
|
### Gathering parts
|
||||||
|
|
||||||
* A "classic" RC2014 with Serial I/O
|
* A "classic" RC2014 with Serial I/O
|
||||||
* [Forth's stage binary][stage]
|
* [Forth's stage 2 binary][stage2]
|
||||||
* [romwrite][romwrite] and its specified dependencies
|
* [romwrite][romwrite] and its specified dependencies
|
||||||
* [GNU screen][screen]
|
* [GNU screen][screen]
|
||||||
* A FTDI-to-TTL cable to connect to the Serial I/O module
|
* A FTDI-to-TTL cable to connect to the Serial I/O module
|
||||||
@ -50,10 +50,24 @@ device I use in this recipe.
|
|||||||
Modules used in this build are configured through the `conf.fs` file in this
|
Modules used in this build are configured through the `conf.fs` file in this
|
||||||
folder. There isn't much to configure, but it's there.
|
folder. There isn't much to configure, but it's there.
|
||||||
|
|
||||||
### Build the binary
|
### Build stage 1
|
||||||
|
|
||||||
Building the binary is as simple as running `make`. This will yield `os.bin`
|
Self-bootstrapping is in Forth's DNA, which is really nice, but it makes
|
||||||
which can then be written to EEPROM.
|
cross-compiling a bit tricky. It's usually much easier to bootstrap a Forth
|
||||||
|
from itself than trying to compile it from a foreign host.
|
||||||
|
|
||||||
|
This makes us adopt a 2 stages strategy. A tiny core is built from a foreign
|
||||||
|
host, and then we run that tiny core on the target machine and let it bootstrap
|
||||||
|
itself, then write our full interpreter binary.
|
||||||
|
|
||||||
|
We could have this recipe automate that 2 stage build process all automatically,
|
||||||
|
but that would rob you of all your fun, right? Instead, we'll run that 2nd
|
||||||
|
stage on the RC2014 itself!
|
||||||
|
|
||||||
|
To build your stage 1, run `make` in this folder, this will yield `stage1.bin`.
|
||||||
|
This will contain that tiny core and, appended to it, the Forth source code it
|
||||||
|
needs to run to bootstrap itself. When it's finished bootstrapping, you will
|
||||||
|
get a prompt to a full Forth interpreter.
|
||||||
|
|
||||||
### Emulate
|
### Emulate
|
||||||
|
|
||||||
@ -86,9 +100,131 @@ identify the tty bound to it (in my case, `/dev/ttyUSB0`). Then:
|
|||||||
|
|
||||||
screen /dev/ttyUSB0 115200
|
screen /dev/ttyUSB0 115200
|
||||||
|
|
||||||
Press the reset button on the RC2014 and the "ok" prompt should appear.
|
Press the reset button on the RC2014 to have Forth begin its bootstrap process.
|
||||||
|
Note that it has to build more than half of itself from source. It takes about
|
||||||
|
30 seconds to complete.
|
||||||
|
|
||||||
|
Once bootstrapping is done you should see the Collapse OS prompt. That's a full
|
||||||
|
Forth interpreter. You can have fun right now.
|
||||||
|
|
||||||
|
However, that long boot time is kinda annoying. Moreover, that bootstrap code
|
||||||
|
being in source form takes precious space from our 8K ROM. That brings us to
|
||||||
|
building stage 2.
|
||||||
|
|
||||||
|
### Building stage 2
|
||||||
|
|
||||||
|
You're about to learn a lot about this platform and its self-bootstrapping
|
||||||
|
nature, but its a bumpy ride. Grab something. Why not a beer?
|
||||||
|
|
||||||
|
Our stage 1 prompt is the result of Forth's inner core interpreting the source
|
||||||
|
code of the Full Forth, which was appended to the binary inner core in ROM.
|
||||||
|
This results in a compiled dictionary, in RAM, at address 0x8000+system RAM.
|
||||||
|
|
||||||
|
Wouldn't it be great if we could save that compiled binary in ROM and save the
|
||||||
|
system the trouble of recompiling itself on boot?
|
||||||
|
|
||||||
|
Unfortunately, this compiled dictionary isn't usable as-is. Offsets compiled in
|
||||||
|
there are compiled based on a 0x8000-or-so base offset. What we need is a
|
||||||
|
0xa00-or-so base offset, that is, something suitable to be appended to the boot
|
||||||
|
binary, in ROM, in binary form.
|
||||||
|
|
||||||
|
Fortunately, inside the compiled source is the contents of the Linker (B120)
|
||||||
|
which will allow us to relink our compiled dictionary so that in can be
|
||||||
|
relocated in ROM, next to our boot binary. I won't go into relinking details.
|
||||||
|
Look at the source. For now, let's just use it:
|
||||||
|
|
||||||
|
RLCORE
|
||||||
|
|
||||||
|
That command will take the dict from `' H@` up to `CURRENT`, copy it in free
|
||||||
|
memory and then relocate it. It will print 3 addresses during its processing.
|
||||||
|
|
||||||
|
The first address is the top copied address. The process didn't touch memory
|
||||||
|
above this point. The second address is the wordref of the last copied entry.
|
||||||
|
The 3rd is the bottom address of the copied dict. When that last address is
|
||||||
|
printed, the processing is over (because we don't have a `>` prompt, we don't
|
||||||
|
have any other indicator that the process is over).
|
||||||
|
|
||||||
|
### Assembling the stage 2 binary
|
||||||
|
|
||||||
|
At that point, we have a fully relocated binary in memory. Depending on our
|
||||||
|
situations, the next steps differ.
|
||||||
|
|
||||||
|
* If we're on a RC2014 that has writing capabilities to permanent storage,
|
||||||
|
we'll want to assemble that binary directly on the RC2014 and write it to
|
||||||
|
permanent storage.
|
||||||
|
* If we're on a RC2014 that doesn't have those capabilities, we'll want to dump
|
||||||
|
memory on our modern environment using `/tools/memdump` and then assemble that
|
||||||
|
binary there.
|
||||||
|
* If we're in the emulator, we'll want to dump our memory using `CTRL+E` and
|
||||||
|
then assemble our stage 2 binary from that dump.
|
||||||
|
|
||||||
|
In these instructions, we assume an emulated environment. I'll use actual
|
||||||
|
offsets of an actual assembling session, but these of course are only examples.
|
||||||
|
It is very likely that these will not be the same offsets for you.
|
||||||
|
|
||||||
|
So you've pressed `CTRL+E` and you have a `memdump` file. Open it with a hex
|
||||||
|
editor (I like `hexedit`) to have a look around and to decide what we'll extract
|
||||||
|
from that memdump. `RLCORE` already gave you important offsets (in my case,
|
||||||
|
`9a3c`, `99f6` and `8d60`), but although the beginning of will always be the
|
||||||
|
same (`8d60`), the end offset depends on the situation.
|
||||||
|
|
||||||
|
If you look at data between `99f6` and `9a3c`, you'll see that this data is not
|
||||||
|
100% dictionary entry material. Some of it is buffer data allocated at
|
||||||
|
initialization. To locate the end of a word, look for `0042`, the address for
|
||||||
|
`EXIT`. In my case, it's at `9a1a` and it's the end of the `INIT` word.
|
||||||
|
|
||||||
|
Moreover, the `INIT` routine that is in there is not quite what we want,
|
||||||
|
because it doesn't contain the `HERE` adjustment that we find in `pre.fs`.
|
||||||
|
We'll want to exclude it from our binary, so let's go a bit further, at `99cf`,
|
||||||
|
ending at `99de`.
|
||||||
|
|
||||||
|
So, the end of our compiled dict is actually `99de`. Alright, let's extract it:
|
||||||
|
|
||||||
|
dd if=memdump bs=1 skip=36192 count=3198 > dict.bin
|
||||||
|
|
||||||
|
`36192` is `8d60` and `3198` is `99de-8d60`. This needs to be prepended by the
|
||||||
|
boot binary. We already have `stage1.bin`, but this binary contains bootstrap
|
||||||
|
source code we don't need any more. To strip it, we'll need to `dd` it out to
|
||||||
|
`LATEST`, in my case `098b`:
|
||||||
|
|
||||||
|
dd if=stage1.bin bs=1 count=2443 > s1pre.bin
|
||||||
|
|
||||||
|
Now we can combine our binaries:
|
||||||
|
|
||||||
|
cat s1pre.bin dict.bin > stage2.bin
|
||||||
|
|
||||||
|
Is it ready to run yet? no. There are 3 adjustments we need to manually make
|
||||||
|
using our hex editor.
|
||||||
|
|
||||||
|
1. We need to link `H@` to the hook word of the boot binary. In my case, it's
|
||||||
|
a matter of writing `02` at `08ec` and `00` at `08ed`, `H@`'s prev field.
|
||||||
|
2. We need to end our binary with a hook word. It can have a zero-length name
|
||||||
|
and the prev field needs to properly point to the previous wordref. In my
|
||||||
|
case, that was `RLCORE` at offset `1559` for a `stage2.bin` size of `1568`,
|
||||||
|
which means that I appended `0F 00 00` at the end of the file.
|
||||||
|
3. Finally, we need to adjust `LATEST` which is at offset `08`. This needs to
|
||||||
|
point to the last wordref of the file, which is equal to the length of
|
||||||
|
`stage2.bin` because we've just added a hook word. This means that we write
|
||||||
|
`6B` at offset `08` and `15` at offset `09`.
|
||||||
|
|
||||||
|
Now are we ready yet? ALMOST! There's one last thing we need to do: add runtime
|
||||||
|
source. In our case, because we have a compiled dict, the only source we need
|
||||||
|
to include is initialization code. We've stripped it from our stage1 earlier,
|
||||||
|
we need to re-add it.
|
||||||
|
|
||||||
|
Look at `xcomp.fs`. You see that `," bla bla bla"` line? That's initialization
|
||||||
|
code. Copy it to a file like `run.fs` (without the `,"`) and build your final
|
||||||
|
binary:
|
||||||
|
|
||||||
|
cat stage2.bin run.fs > stage2r.bin
|
||||||
|
|
||||||
|
That's it! our binary is ready to run!
|
||||||
|
|
||||||
|
../../emul/hw/rc2014/classic stage2r.bin
|
||||||
|
|
||||||
|
And there you have it, a stage2 binary that you've assembled yourself.
|
||||||
|
|
||||||
[rc2014]: https://rc2014.co.uk
|
[rc2014]: https://rc2014.co.uk
|
||||||
[romwrite]: https://github.com/hsoft/romwrite
|
[romwrite]: https://github.com/hsoft/romwrite
|
||||||
[stage]: ../../emul
|
[stage2]: ../../emul
|
||||||
[screen]: https://www.gnu.org/software/screen/
|
[screen]: https://www.gnu.org/software/screen/
|
||||||
|
@ -8,6 +8,7 @@ itself.
|
|||||||
## Gathering parts
|
## Gathering parts
|
||||||
|
|
||||||
* A RC2014 Classic
|
* A RC2014 Classic
|
||||||
|
* `stage2.bin` from the base recipe
|
||||||
* An extra AT28C64B
|
* An extra AT28C64B
|
||||||
* 1x 40106 inverter gates
|
* 1x 40106 inverter gates
|
||||||
* Proto board, RC2014 header pins, wires, IC sockets, etc.
|
* Proto board, RC2014 header pins, wires, IC sockets, etc.
|
||||||
@ -32,21 +33,46 @@ in write protection mode, but I preferred building my own module.
|
|||||||
|
|
||||||
I don't think you need a schematic. It's really simple.
|
I don't think you need a schematic. It's really simple.
|
||||||
|
|
||||||
### Building the binary
|
### Assembling stage 3
|
||||||
|
|
||||||
You build the binary by modifying the base recipe's `xcomp` unit. This binary
|
Stage 2 gives you a full interpreter, but it's missing the "Addressed devices"
|
||||||
is missing 2 things: Addressed devices and the AT28 Driver.
|
module and the AT28 driver. We'll need to assemble a stage 3.
|
||||||
|
|
||||||
Addressed devices are at B140. If you read that block, you'll see that it tells
|
When you'll have a system with function disk block system, you'll be able to
|
||||||
you to load block 142. Open the `xcomp` unit and locate the ACIA driver loading
|
directly `LOAD` them, but for this recipe, we can't assume you have, so what
|
||||||
line. Insert your new load line after that one.
|
you'll have to do is to manually paste the code from the appropriate blocks.
|
||||||
|
|
||||||
|
Addressed devices are at B140. To know what you have to paste, open the loader
|
||||||
|
block (B142) and see what blocks it loads. For each of the blocks, copy/paste
|
||||||
|
the code in your interpreter.
|
||||||
|
|
||||||
Do the same thing with the AT28 driver (B590)
|
Do the same thing with the AT28 driver (B590)
|
||||||
|
|
||||||
You also have to modify the initialization sequence at the end of the `xcomp`
|
If you're doing the real thing and not using the emulator, pasting so much code
|
||||||
unit to include `ADEV$`.
|
at once might freeze up the RC2014, so it is recommended that you use
|
||||||
|
`/tools/exec` that let the other side enough time to breathe.
|
||||||
|
|
||||||
Build again, write `os.com` to EEPROM.
|
After your pasting, you'll have a compiled dict of that code in memory. You'll
|
||||||
|
need to relocate it in the same way you did for stage 2, but instead of using
|
||||||
|
`RLCORE`, which is a convenience word hardcoded for stage 1, we'll parametrize
|
||||||
|
`RLDICT`, the word doing the real work.
|
||||||
|
|
||||||
|
`RLDICT` takes 2 arguments, `target` and `offset`. `target` is the first word
|
||||||
|
of your relocated dict. In our case, it's going to be `' ADEVMEM+`. `offset` is
|
||||||
|
the offset we'll apply to every eligible word references in our dict. In our
|
||||||
|
case, that offset is the offset of the *beginning* of the `ADEVMEM+` entry (that
|
||||||
|
is, `' ADEVMEM+ WORD(` minus the offset of the last word (which should be a hook
|
||||||
|
word) in the ROM binary.
|
||||||
|
|
||||||
|
That offset can be conveniently fetched from code because it is the value of
|
||||||
|
the `LATEST` constant in stable ABI, which is at offset `0x08`. Therefore, our
|
||||||
|
offset value is:
|
||||||
|
|
||||||
|
' ADEVMEM+ WORD( 0x08 @ -
|
||||||
|
|
||||||
|
You can now run `RLDICT` and proceed with concatenation (and manual adjustments
|
||||||
|
of course) as you did with stage 2. Don't forget to adjust `run.fs` so that it
|
||||||
|
runs `ADEV$`.
|
||||||
|
|
||||||
## Writing contents to the AT28
|
## Writing contents to the AT28
|
||||||
|
|
||||||
|
@ -70,23 +70,35 @@ instead.
|
|||||||
|
|
||||||
## Building your binary
|
## Building your binary
|
||||||
|
|
||||||
The binary built in the base recipe doesn't have SDC drivers. Using the same
|
Your Collapse OS binary needs the SDC drivers which need to be inserted during
|
||||||
instructions as in the `eeprom` recipe, you'll need to insert those drivers.
|
Cross Compilation, which needs you need to recompile it from stage 1. First,
|
||||||
The SDC driver is at B600. It gives you a load range. This means that what
|
look at B600. You'll see that it indicates a block range for the driver. That
|
||||||
you need to insert in `xcomp` will look like:
|
needs to be loaded.
|
||||||
|
|
||||||
|
Open xcomp.fs from base recipe and locate acia loading. You'll insert a line
|
||||||
|
right after that that will look like:
|
||||||
|
|
||||||
602 616 LOADR ( sdc )
|
602 616 LOADR ( sdc )
|
||||||
|
|
||||||
You also need to add `BLK$` to the init sequence.
|
Normally, that's all you need to do. However, you have a little problem: You're
|
||||||
|
busting the 8K ROM limit. But it's ok, you can remove the linker's XPACKing
|
||||||
|
line: because you'll have access to the blkfs from SD card, you can load it
|
||||||
|
from there!
|
||||||
|
|
||||||
|
Removing the linker from XPACKing will free enough space for your binary to fit
|
||||||
|
in 8K. You also have to add `BLK$` to initialization routine.
|
||||||
|
|
||||||
Build it and write it to EEPROM.
|
Build it and write it to EEPROM.
|
||||||
|
|
||||||
|
If you want, once you're all set with the SD card, you can relink core words
|
||||||
|
like you did in the base recipe for optimal resource usage.
|
||||||
|
|
||||||
## Testing in the emulator
|
## Testing in the emulator
|
||||||
|
|
||||||
The RC2014 emulator includes SDC emulation. You can attach a SD card image to
|
The RC2014 emulator includes SDC emulation. You can attach a SD card image to
|
||||||
it by invoking it with a second argument:
|
it by invoking it with a second argument:
|
||||||
|
|
||||||
../../../emul/hw/rc2014/classic os.bin ../../../emul/blkfs
|
../../../emul/hw/rc2014/classic stage3.bin ../../../emul/blkfs
|
||||||
|
|
||||||
You will then run with a SD card having the contents from `/blk`.
|
You will then run with a SD card having the contents from `/blk`.
|
||||||
|
|
||||||
|
@ -9,34 +9,24 @@ either for another RC2014 or for an OS upgrade.
|
|||||||
* stage3 from `sdcard` recipe. If you want to write to EEPROM as the final step,
|
* stage3 from `sdcard` recipe. If you want to write to EEPROM as the final step,
|
||||||
you'll need a hybrid stage3 that also includes stuff from the `eeprom` recipe.
|
you'll need a hybrid stage3 that also includes stuff from the `eeprom` recipe.
|
||||||
|
|
||||||
## Building the binary
|
## Building stage 1
|
||||||
|
|
||||||
Build Collapse OS' from within Collapse OS is very similar to how we do
|
Build Collapse OS' stage 1 from within Collapse OS is very similar to how we do
|
||||||
it from the makefile. If you take the time to look at the base recipe
|
it from the makefile. If you take the time to look at the base recipe
|
||||||
`Makefile`, you'll see `cat xcomp.fs | $(STAGE)`. That's the thing. Open
|
`Makefile`, you'll see `cat xcomp.fs | $(STAGE2)`. That's the thing. Open
|
||||||
`xcomp.fs` in a text editor and take a look at it. You'll see that it loads
|
`xcomp.fs` in a text editor and take a look at it.
|
||||||
B618, which contains the meat, and then spits stuff to port 2, which is a
|
|
||||||
special signal for the `stage` binary.
|
|
||||||
|
|
||||||
To assemble from RC2014, all you need to do is load B618. This will
|
To assemble stage 1 from RC2014, all you need to do is to type those commands
|
||||||
yield a binary in memory. To know the start/end offset of the binary, you'll
|
in the same order, and replace the `/MOD 2 PC! 2 PC!` words with `.X`.
|
||||||
type the same two commands and in `xcomp.fs`, but replace the `/MOD 2 PC! 2 PC!`
|
Those commands will inform you of the begin/end offsets of the assembled binary.
|
||||||
words with `.X`. Then, write that binary between those offsets on your target
|
|
||||||
media. That binary should be the exact same as what you get in `os.bin`
|
|
||||||
when you run `make`.
|
|
||||||
|
|
||||||
Go ahead, run that. However, one thing you should know is that because the SD
|
I'm not going to explain in detail what each command do, but only give you an
|
||||||
card driver is a bit slow, some of these commands take a long time. Multiple
|
overview of what is happening. You are encouraged to read the in-system
|
||||||
minutes. Be patient.
|
|
||||||
|
|
||||||
Is that it? Yes. But for your own enlightenment, open B618 and look at it, I'll
|
|
||||||
give you an overview of its contents. I'm not going to explain in detail what
|
|
||||||
each command do, however. You are encouraged to read the in-system
|
|
||||||
documentation for more information.
|
documentation for more information.
|
||||||
|
|
||||||
The first part is configuration of your new system. When RAM starts, where RSP
|
The first part is configuration of your new system. When RAM starts, where RSP
|
||||||
and PSP start, what ports to use for what device, etc. These configuration
|
starts, what ports to use for what device, etc. These configuration declarations
|
||||||
declarations are expected in the boot code and driver code.
|
are expected in the boot code and driver code.
|
||||||
|
|
||||||
Then, we load the Z80 assembler and the cross compiler (xcomp for short), which
|
Then, we load the Z80 assembler and the cross compiler (xcomp for short), which
|
||||||
we'll of course need for the task ahead.
|
we'll of course need for the task ahead.
|
||||||
@ -51,15 +41,41 @@ close the binary with a hook word. We're finished with cross-compiling.
|
|||||||
|
|
||||||
We're at the offset that will be `CURRENT` on boot, so we update `LATEST`.
|
We're at the offset that will be `CURRENT` on boot, so we update `LATEST`.
|
||||||
|
|
||||||
Then, we spit the init source code that will be interpreted on boot.
|
Then, we spit the source code that will be interpreted by stage 1 on boot so
|
||||||
And... that's it!
|
that it bootstraps itself to a full interpreter. Not all units are there
|
||||||
|
because they don't fit in 8K, but they're sufficient for our needs. We also
|
||||||
|
need the linker so that we can relink ourselves to stage 2.
|
||||||
|
|
||||||
|
Finally, we have initialization code, then a spit of the ending offset.
|
||||||
|
|
||||||
|
Go ahead, run that. However, one thing you should know is that because the SD
|
||||||
|
card driver is a bit slow, some of these commands take a long time. Multiple
|
||||||
|
minutes. Be patient.
|
||||||
|
|
||||||
|
Once all your commands are run and that you have your begin/end offset (write
|
||||||
|
them down somewhere), you're at the same point as you were after the `make`
|
||||||
|
part of the base recipe. The contents between your start and end offset is the
|
||||||
|
exact same as the contents of `stage1.bin` when you run `make`. Continue your
|
||||||
|
deployment from there.
|
||||||
|
|
||||||
|
Good luck!
|
||||||
|
|
||||||
### What to do on SDerr?
|
### What to do on SDerr?
|
||||||
|
|
||||||
If you get `SDerr` in the middle of a LOAD operation, something went wrong with
|
If you get `SDerr` in the middle of a LOAD operation, something went wrong with
|
||||||
the SD card. The bad news is that it left your xcomp operation in an
|
the SD card. The bad news is that it left your xcomp operation in an
|
||||||
inconsistent state. The easiest thing to do it to restart the operation from
|
inconsistent state. If your at the beginning of it, it's easier to restart it
|
||||||
scratch. Those error are not frequent unless hardware is faulty.
|
entirely.
|
||||||
|
|
||||||
|
If you're towards the end, you might want to repair it. To do so, you'll have to
|
||||||
|
bring your `XCURRENT` and `HERE` values to where they were before the LOAD
|
||||||
|
operation. You could have thought ahead and printed them before the LOAD, but if
|
||||||
|
you didn't, you'll just have to dig in your memory with `DUMP`.
|
||||||
|
|
||||||
|
You're looking at the offset of the last wordref of the *previous* LOAD
|
||||||
|
operation. That offset is going in `XCURRENT`. Then, you're looking at the end
|
||||||
|
of that word. That offset goes in `HERE`. Once you've done that, relaunch your
|
||||||
|
LOAD.
|
||||||
|
|
||||||
### Verifying
|
### Verifying
|
||||||
|
|
||||||
|
@ -1,3 +1,25 @@
|
|||||||
618 LOAD
|
0x8000 CONSTANT RAMSTART
|
||||||
|
0xf000 CONSTANT RS_ADDR
|
||||||
|
0xfffa CONSTANT PS_ADDR
|
||||||
|
0x80 CONSTANT ACIA_CTL
|
||||||
|
0x81 CONSTANT ACIA_IO
|
||||||
|
4 CONSTANT SDC_SPI
|
||||||
|
5 CONSTANT SDC_CSLOW
|
||||||
|
6 CONSTANT SDC_CSHIGH
|
||||||
|
RAMSTART 0x70 + CONSTANT ACIA_MEM
|
||||||
|
212 LOAD ( z80 assembler )
|
||||||
|
262 LOAD ( xcomp )
|
||||||
|
270 LOAD ( xcomp overrides )
|
||||||
|
|
||||||
|
282 LOAD ( boot.z80 )
|
||||||
|
393 LOAD ( xcomp core low )
|
||||||
|
582 LOAD ( acia )
|
||||||
|
420 LOAD ( xcomp core high )
|
||||||
|
(entry) _
|
||||||
|
( Update LATEST )
|
||||||
|
PC ORG @ 8 + !
|
||||||
|
440 446 XPACKR ( core )
|
||||||
|
123 132 XPACKR ( linker )
|
||||||
|
," : _ ACIA$ RDLN$ (ok) ; _ "
|
||||||
ORG @ 256 /MOD 2 PC! 2 PC!
|
ORG @ 256 /MOD 2 PC! 2 PC!
|
||||||
H@ 256 /MOD 2 PC! 2 PC!
|
H@ 256 /MOD 2 PC! 2 PC!
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
TARGET = os.bin
|
TARGET = stage1.bin
|
||||||
BASEDIR = ../..
|
BASEDIR = ../..
|
||||||
FDIR = $(BASEDIR)/forth
|
FDIR = $(BASEDIR)/forth
|
||||||
EDIR = $(BASEDIR)/emul
|
EDIR = $(BASEDIR)/emul
|
||||||
STAGE = $(EDIR)/stage
|
STAGE2 = $(EDIR)/stage2
|
||||||
EMUL = $(BASEDIR)/emul/hw/ti/ti84
|
EMUL = $(BASEDIR)/emul/hw/ti/ti84
|
||||||
MKTIUPGRADE = mktiupgrade
|
MKTIUPGRADE = mktiupgrade
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
$(TARGET): xcomp.fs $(STAGE)
|
$(TARGET): xcomp.fs $(STAGE2)
|
||||||
cat xcomp.fs | $(STAGE) > $@
|
cat xcomp.fs | $(STAGE2) > $@
|
||||||
|
|
||||||
$(EMUL):
|
$(EMUL):
|
||||||
$(MAKE) -C ${@:%/ti84=%}
|
$(MAKE) -C ${@:%/ti84=%}
|
||||||
|
@ -38,7 +38,7 @@ screen as output and its builtin keyboard as input.
|
|||||||
|
|
||||||
## Build the ROM
|
## Build the ROM
|
||||||
|
|
||||||
Running `make` will result in `os.rom` being created.
|
Running `make` will result in `stage1.rom` being created.
|
||||||
|
|
||||||
## Emulate
|
## Emulate
|
||||||
|
|
||||||
|
@ -68,6 +68,7 @@ CREATE ~FNT CPFNT3x5
|
|||||||
(entry) _
|
(entry) _
|
||||||
( Update LATEST )
|
( Update LATEST )
|
||||||
PC ORG @ 8 + !
|
PC ORG @ 8 + !
|
||||||
|
440 446 XPACKR ( core )
|
||||||
," : _ LCD$ KBD$ (ok) RDLN$ ; _ "
|
," : _ LCD$ KBD$ (ok) RDLN$ ; _ "
|
||||||
ORG @ 0x100 - 256 /MOD 2 PC! 2 PC!
|
ORG @ 0x100 - 256 /MOD 2 PC! 2 PC!
|
||||||
H@ 256 /MOD 2 PC! 2 PC!
|
H@ 256 /MOD 2 PC! 2 PC!
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
TARGET = os.bin
|
TARGET = stage1.bin
|
||||||
EDIR = ../../emul
|
EDIR = ../../emul
|
||||||
STAGE = $(EDIR)/stage
|
STAGE2 = $(EDIR)/stage2
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
$(TARGET): xcomp.fs $(STAGE)
|
$(TARGET): xcomp.fs $(STAGE2)
|
||||||
cat xcomp.fs | $(STAGE) > $@
|
cat xcomp.fs | $(STAGE2) > $@
|
||||||
|
@ -67,10 +67,10 @@ kind of reception! You're gonna feel real badass about it too...
|
|||||||
|
|
||||||
* `_` is `CLEAR+ENTER`.
|
* `_` is `CLEAR+ENTER`.
|
||||||
|
|
||||||
## Building the binary
|
## Building the stage 1
|
||||||
|
|
||||||
You can build the binary to send to the TRS-80 with `make`, which will yield
|
You can start the process by building the stage 1 binary. Running `make` in
|
||||||
`os.bin`. You'll need it later.
|
this folder will yield a `stage1.bin` file. You'll need it later.
|
||||||
|
|
||||||
## Testing serial communication
|
## Testing serial communication
|
||||||
|
|
||||||
|
@ -7,13 +7,15 @@ RS_ADDR 0x80 - CONSTANT RAMSTART
|
|||||||
|
|
||||||
0x3000 BIN( !
|
0x3000 BIN( !
|
||||||
282 LOAD ( boot.z80 )
|
282 LOAD ( boot.z80 )
|
||||||
|
492 LOAD ( trs80.z80 )
|
||||||
393 LOAD ( xcomp core low )
|
393 LOAD ( xcomp core low )
|
||||||
492 LOAD ( trs80 )
|
|
||||||
420 LOAD ( xcomp core high )
|
420 LOAD ( xcomp core high )
|
||||||
(entry) _
|
(entry) _
|
||||||
( Update LATEST )
|
( Update LATEST )
|
||||||
PC ORG @ 8 + !
|
PC ORG @ 8 + !
|
||||||
," CURRENT @ HERE ! "
|
," CURRENT @ HERE ! "
|
||||||
|
440 446 XPACKR ( core )
|
||||||
|
499 500 XPACKR ( trs80.fs )
|
||||||
( 0x0a == NLPTR. TRS-80 wants CR-only newlines )
|
( 0x0a == NLPTR. TRS-80 wants CR-only newlines )
|
||||||
," : _ ['] CR 0x0a RAM+ ! BLK$ FD$ (ok) RDLN$ ; _ "
|
," : _ ['] CR 0x0a RAM+ ! BLK$ FD$ (ok) RDLN$ ; _ "
|
||||||
ORG @ 256 /MOD 2 PC! 2 PC!
|
ORG @ 256 /MOD 2 PC! 2 PC!
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
: SDC_SPI 4 ;
|
: SDC_SPI 4 ;
|
||||||
: SDC_CSLOW 5 ;
|
: SDC_CSLOW 5 ;
|
||||||
: SDC_CSHIGH 6 ;
|
: SDC_CSHIGH 6 ;
|
||||||
602 616 LOADR ( sdc )
|
372 LOAD ( sdc.z80 )
|
||||||
|
374 LOAD ( sdc.fs )
|
||||||
|
|
||||||
0x0000 0x00 _crc16 0x0000 #eq
|
0x0000 0x00 _crc16 0x0000 #eq
|
||||||
0x0000 0x01 _crc16 0x1021 #eq
|
0x0000 0x01 _crc16 0x1021 #eq
|
||||||
|
Loading…
Reference in New Issue
Block a user