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
|
||||
200 Z80 assembler 260 Cross compilation
|
||||
280 Z80 boot code 390 Cross-compiled core
|
||||
439 XPACKed core
|
||||
490 TRS-80 Recipe 520 Fonts
|
||||
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.
|
||||
ABORT -- Resets PS and RS and returns to interpreter.
|
||||
ABORT" x" -- *I* Compiles a ." followed by a ABORT.
|
||||
ERR a -- Prints a and ABORT. Defined early and used by
|
||||
drivers. (cont.)
|
||||
EXECUTE a -- Execute wordref at addr a
|
||||
|
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,
|
||||
then execute the compiled contents.
|
||||
LEAVE -- In a DO..LOOP, exit at the next LOOP call.
|
||||
|
3
blk/263
3
blk/263
@ -1,13 +1,14 @@
|
||||
VARIABLE XCURRENT
|
||||
|
||||
: XCON XCURRENT CURRENT* ! ;
|
||||
: XCOFF 0x02 RAM+ CURRENT* ! ;
|
||||
|
||||
: (xentry) XCON (entry) XCOFF ;
|
||||
: XCREATE (xentry) 11 C, ;
|
||||
: XCODE XCON CODE XCOFF ;
|
||||
: XIMM XCON IMMEDIATE XCOFF ;
|
||||
: _xapply ( a -- a-off )
|
||||
DUP ORG @ > IF ORG @ - BIN( @ + THEN ;
|
||||
: X' XCON ' XCOFF ;
|
||||
: X['] XCON ' _xapply LITA XCOFF ;
|
||||
: XCOMPILE
|
||||
XCON ' _xapply LITA
|
||||
|
1
blk/394
1
blk/394
@ -1,5 +1,4 @@
|
||||
: ABORT (resSP) QUIT ;
|
||||
: ERR LIT< (print) (find) IF EXECUTE THEN ABORT ;
|
||||
: = CMP NOT ; : < CMP -1 = ; : > CMP 1 = ;
|
||||
: 0< 32767 > ; : >= < NOT ; : <= > NOT ; : 0>= 0< NOT ;
|
||||
( 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
|
||||
preceeding them, aren't immediately needed for boot. But its
|
||||
better to have as many words as possible in the xcomp part. )
|
||||
: H@ HERE @ ;
|
||||
: IMMEDIATE
|
||||
CURRENT @ 1-
|
||||
DUP C@ 128 OR SWAP C! ;
|
||||
: 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 ;
|
||||
: INTERPRET
|
||||
BEGIN
|
||||
WORD DUP C@ EOT? IF DROP EXIT THEN
|
||||
(find)
|
||||
NOT IF (parse) ELSE EXECUTE THEN
|
||||
C<? NOT IF LIT< (ok) (find) IF EXECUTE THEN THEN
|
||||
AGAIN ;
|
||||
|
22
blk/410
22
blk/410
@ -1,13 +1,11 @@
|
||||
: '? WORD (find) ;
|
||||
: '
|
||||
'? (?br) [ 4 , ] EXIT
|
||||
LIT< (wnf) (find) DROP EXECUTE
|
||||
( system c< simply reads source from binary, starting at
|
||||
LATEST. Convenient way to bootstrap a new system. )
|
||||
: (boot<)
|
||||
( 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 -- )
|
||||
( u ) 0 DO ( a1 a2 )
|
||||
SWAP C@+ ( a2 a1+1 x )
|
||||
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 @ - ;
|
||||
: BOOT
|
||||
0x02 RAM+ CURRENT* !
|
||||
CURRENT @ 0x2e RAM+ ! ( 2e == BOOT C< PTR )
|
||||
0 0x08 RAM+ ! ( 08 == C<* override )
|
||||
0 0x53 RAM+ ! ( 53 == (emit) override )
|
||||
0 0x55 RAM+ ! ( 55 == (key) override )
|
||||
0 0x0a RAM+ ! ( NLPTR )
|
||||
( 0c == C<* )
|
||||
['] (boot<) 0x0c RAM+ !
|
||||
( boot< always has a char waiting. 06 == C<?* )
|
||||
1 0x06 RAM+ !
|
||||
INTERPRET BYE ;
|
||||
|
||||
|
27
blk/412
27
blk/412
@ -1,13 +1,16 @@
|
||||
: 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 !
|
||||
( Words here until the end of the low part, unlike words
|
||||
preceeding them, aren't immediately needed for boot. But its
|
||||
better to have as many words as possible in the xcomp part. )
|
||||
: H@ HERE @ ;
|
||||
: IMMEDIATE
|
||||
CURRENT @ 1-
|
||||
DUP C@ 128 OR SWAP C!
|
||||
;
|
||||
: +! 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>
|
||||
( 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 )
|
||||
: '? WORD (find) ;
|
||||
: '
|
||||
'? (?br) [ 4 , ] EXIT
|
||||
LIT< (wnf) (find) DROP EXECUTE
|
||||
;
|
||||
: 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]
|
||||
IF EXIT THEN
|
||||
LIT< [THEN] BEGIN DUP WORD S= UNTIL DROP ;
|
||||
: [THEN] ;
|
||||
|
||||
: MOVE ( a1 a2 u -- )
|
||||
( u ) 0 DO ( a1 a2 )
|
||||
SWAP C@+ ( a2 a1+1 x )
|
||||
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
|
||||
( 0x53==(emit) override )
|
||||
0x53 RAM+ @ DUP IF EXECUTE ELSE DROP (emit) THEN ;
|
||||
|
||||
: (print)
|
||||
BEGIN
|
||||
C@+ ( a+1 c )
|
||||
( exit if null or 0xd )
|
||||
DUP 0xd = OVER NOT OR IF 2DROP EXIT THEN
|
||||
EMIT ( a )
|
||||
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 ;
|
||||
AGAIN
|
||||
;
|
||||
|
||||
|
||||
|
14
blk/422
14
blk/422
@ -1,7 +1,15 @@
|
||||
: ,"
|
||||
BEGIN
|
||||
C< DUP 34 ( ASCII " ) = IF DROP EXIT THEN C,
|
||||
C<
|
||||
( 34 is ASCII for " )
|
||||
DUP 34 = IF DROP EXIT THEN C,
|
||||
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
|
||||
: 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
|
||||
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
|
||||
|
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
|
||||
0x02 RAM+ CURRENT* !
|
||||
CURRENT @ 0x2e RAM+ ! ( 2e == BOOT C< PTR )
|
||||
0 0x08 RAM+ ! ( 08 == C<* override )
|
||||
0 0x53 RAM+ ! ( 53 == (emit) override )
|
||||
0 0x55 RAM+ ! ( 55 == (key) override )
|
||||
0 0x0a RAM+ ! ( NLPTR )
|
||||
( 0c == C<* )
|
||||
['] (boot<) 0x0c RAM+ !
|
||||
( boot< always has a char waiting. 06 == C<?* )
|
||||
1 0x06 RAM+ !
|
||||
INTERPRET BYE ;
|
||||
|
||||
XCURRENT @ ( to PSP )
|
||||
: :
|
||||
(entry)
|
||||
( We cannot use LITN as IMMEDIATE because of bootstrapping
|
||||
issues. Same thing for ",".
|
||||
32 == NUMBER 14 == compiledWord )
|
||||
[ 32 H@ ! 2 ALLOT 14 H@ ! 2 ALLOT ] C,
|
||||
BEGIN
|
||||
WORD
|
||||
(find)
|
||||
( is word )
|
||||
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
|
||||
: AGAIN COMPILE (br) H@ - , ; IMMEDIATE
|
||||
: UNTIL COMPILE (?br) H@ - , ; IMMEDIATE
|
||||
: [ INTERPRET ; IMMEDIATE
|
||||
: ] R> DROP ;
|
||||
: LIT< WORD 34 , SCPY 0 C, ; IMMEDIATE
|
||||
: LITA 36 , , ;
|
||||
: COMPILE ' LITA ['] , , ; IMMEDIATE
|
||||
: [COMPILE] ' , ; IMMEDIATE
|
||||
XPACKed core
|
||||
|
||||
Most of Collapse OS' core words are cross compiled (B390).
|
||||
However, some of them are too dynamically referenced to be
|
||||
cross-compiled without great pain, so we XPACK (B267) them,
|
||||
that is, we put them in source form in the target's
|
||||
initialization section (see B89).
|
||||
|
||||
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
|
||||
is not an IMMEDIATE yet and will not be treated properly by
|
||||
xcomp. )
|
||||
: _
|
||||
['] EXIT ,
|
||||
R> DROP ( exit : )
|
||||
; IMMEDIATE
|
||||
: [ INTERPRET ; IMMEDIATE
|
||||
: ] R> DROP ;
|
||||
: LIT< WORD 34 , SCPY 0 C, ; IMMEDIATE
|
||||
: LITA 36 , , ;
|
||||
: ['] ' LITA ; IMMEDIATE
|
||||
';' X' _ 4 - C! ( give ; its name )
|
||||
':' X' _ 4 - C! ( give : its name )
|
||||
'(' X' _ 4 - C!
|
||||
: COMPILE ' LITA ['] , , ; IMMEDIATE
|
||||
: [COMPILE] ' , ; IMMEDIATE
|
||||
: 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
|
||||
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
|
||||
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 )
|
||||
( 4 256b sectors per block, 10 sec per cyl, 40 cyl max )
|
||||
10 /MOD ( sec cyl )
|
||||
|
2
blk/500
2
blk/500
@ -2,6 +2,6 @@
|
||||
: FD! ['] @WRSEC SWAP FD@! ;
|
||||
: FD$ ['] FD@ BLK@* ! ['] FD! BLK!* ! ;
|
||||
|
||||
: _err LIT" *CLerr" ERR ;
|
||||
: _err ABORT" *CLerr" ;
|
||||
: *CL< 0 BEGIN DROP 0x0238 @GET UNTIL ;
|
||||
: *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.
|
||||
|
||||
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
|
||||
/*-bin.h
|
||||
/stage0.bin
|
||||
/blkfs
|
||||
|
@ -1,4 +1,4 @@
|
||||
TARGETS = forth stage
|
||||
TARGETS = forth stage2
|
||||
OBJS = emul.o libz80/libz80.o
|
||||
BIN2C = ../tools/bin2c
|
||||
BLKPACK = ../tools/blkpack
|
||||
@ -14,12 +14,24 @@ $(BLKPACK):
|
||||
$(BIN2C): $(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.
|
||||
forth-bin.h: $(BIN2C)
|
||||
$(BIN2C) KERNEL < forth.bin > $@
|
||||
|
||||
stage: stage.c $(OBJS) forth-bin.h blkfs-bin.h
|
||||
$(CC) stage.c $(OBJS) -o $@
|
||||
stage2: stage.c $(OBJS) forth-bin.h blkfs-bin.h
|
||||
$(CC) -DSTAGE2 stage.c $(OBJS) -o $@
|
||||
|
||||
blkfs: $(BLKPACK)
|
||||
$(BLKPACK) ../blk > $@
|
||||
@ -39,8 +51,8 @@ emul.o: emul.c
|
||||
|
||||
|
||||
.PHONY: updatebootstrap
|
||||
updatebootstrap: stage xcomp.fs
|
||||
./stage < xcomp.fs > forth.bin
|
||||
updatebootstrap: stage1 stage1.fs
|
||||
./stage1 < stage1.fs > forth.bin
|
||||
|
||||
.PHONY: pack
|
||||
pack:
|
||||
|
BIN
emul/forth.bin
BIN
emul/forth.bin
Binary file not shown.
@ -2,8 +2,12 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "emul.h"
|
||||
#ifdef STAGE2
|
||||
#include "forth-bin.h"
|
||||
#include "blkfs-bin.h"
|
||||
#else
|
||||
#include "stage0-bin.h"
|
||||
#endif
|
||||
|
||||
/* Staging binaries
|
||||
|
||||
@ -70,6 +74,7 @@ static void iowr_here(uint8_t val)
|
||||
end_here |= val;
|
||||
}
|
||||
|
||||
#ifdef STAGE2
|
||||
static void iowr_blk(uint8_t val)
|
||||
{
|
||||
blkid <<= 8;
|
||||
@ -81,6 +86,7 @@ static uint8_t iord_blkdata()
|
||||
{
|
||||
return BLKFS[blkpos++];
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@ -89,8 +95,10 @@ int main(int argc, char *argv[])
|
||||
m->iord[STDIO_PORT] = iord_stdio;
|
||||
m->iowr[STDIO_PORT] = iowr_stdio;
|
||||
m->iowr[HERE_PORT] = iowr_here;
|
||||
#ifdef STAGE2
|
||||
m->iowr[BLK_PORT] = iowr_blk;
|
||||
m->iord[BLKDATA_PORT] = iord_blkdata;
|
||||
#endif
|
||||
// initialize memory
|
||||
for (int i=0; i<sizeof(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 )
|
||||
: (emit) 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 )
|
||||
(entry) _
|
||||
( Update LATEST )
|
||||
PC ORG @ 8 + !
|
||||
," CURRENT @ HERE ! "
|
||||
," : INIT "
|
||||
," BLK$ "
|
||||
," ['] EFS@ BLK@* ! "
|
||||
," ['] EFS! BLK!* ! "
|
||||
," RDLN$ "
|
||||
," LIT< _sys [entry] "
|
||||
," LIT< CollapseOS (print) NL "
|
||||
," ; INIT "
|
||||
440 446 XPACKR
|
||||
," ' (key) 12 RAM+ ! "
|
||||
ORG @ 256 /MOD 2 PC! 2 PC!
|
||||
H@ 256 /MOD 2 PC! 2 PC!
|
||||
|
@ -1,14 +1,14 @@
|
||||
TARGET = os.bin
|
||||
TARGET = stage1.bin
|
||||
BASEDIR = ../..
|
||||
FDIR = $(BASEDIR)/forth
|
||||
EDIR = $(BASEDIR)/emul
|
||||
STAGE = $(EDIR)/stage
|
||||
STAGE2 = $(EDIR)/stage2
|
||||
EMUL = $(BASEDIR)/emul/hw/rc2014/classic
|
||||
|
||||
.PHONY: all
|
||||
all: $(TARGET)
|
||||
$(TARGET): xcomp.fs $(STAGE)
|
||||
cat xcomp.fs | $(STAGE) > $@
|
||||
$(TARGET): xcomp.fs $(STAGE2)
|
||||
cat xcomp.fs | $(STAGE2) > $@
|
||||
|
||||
$(SLATEST):
|
||||
$(MAKE) -C $(BASEDIR)/tools
|
||||
|
@ -40,7 +40,7 @@ device I use in this recipe.
|
||||
### Gathering parts
|
||||
|
||||
* A "classic" RC2014 with Serial I/O
|
||||
* [Forth's stage binary][stage]
|
||||
* [Forth's stage 2 binary][stage2]
|
||||
* [romwrite][romwrite] and its specified dependencies
|
||||
* [GNU screen][screen]
|
||||
* 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
|
||||
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`
|
||||
which can then be written to EEPROM.
|
||||
Self-bootstrapping is in Forth's DNA, which is really nice, but it makes
|
||||
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
|
||||
|
||||
@ -86,9 +100,131 @@ identify the tty bound to it (in my case, `/dev/ttyUSB0`). Then:
|
||||
|
||||
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
|
||||
[romwrite]: https://github.com/hsoft/romwrite
|
||||
[stage]: ../../emul
|
||||
[stage2]: ../../emul
|
||||
[screen]: https://www.gnu.org/software/screen/
|
||||
|
@ -8,6 +8,7 @@ itself.
|
||||
## Gathering parts
|
||||
|
||||
* A RC2014 Classic
|
||||
* `stage2.bin` from the base recipe
|
||||
* An extra AT28C64B
|
||||
* 1x 40106 inverter gates
|
||||
* 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.
|
||||
|
||||
### Building the binary
|
||||
### Assembling stage 3
|
||||
|
||||
You build the binary by modifying the base recipe's `xcomp` unit. This binary
|
||||
is missing 2 things: Addressed devices and the AT28 Driver.
|
||||
Stage 2 gives you a full interpreter, but it's missing the "Addressed devices"
|
||||
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
|
||||
you to load block 142. Open the `xcomp` unit and locate the ACIA driver loading
|
||||
line. Insert your new load line after that one.
|
||||
When you'll have a system with function disk block system, you'll be able to
|
||||
directly `LOAD` them, but for this recipe, we can't assume you have, so what
|
||||
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)
|
||||
|
||||
You also have to modify the initialization sequence at the end of the `xcomp`
|
||||
unit to include `ADEV$`.
|
||||
If you're doing the real thing and not using the emulator, pasting so much code
|
||||
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
|
||||
|
||||
|
@ -70,23 +70,35 @@ instead.
|
||||
|
||||
## Building your binary
|
||||
|
||||
The binary built in the base recipe doesn't have SDC drivers. Using the same
|
||||
instructions as in the `eeprom` recipe, you'll need to insert those drivers.
|
||||
The SDC driver is at B600. It gives you a load range. This means that what
|
||||
you need to insert in `xcomp` will look like:
|
||||
Your Collapse OS binary needs the SDC drivers which need to be inserted during
|
||||
Cross Compilation, which needs you need to recompile it from stage 1. First,
|
||||
look at B600. You'll see that it indicates a block range for the driver. That
|
||||
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 )
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
The RC2014 emulator includes SDC emulation. You can attach a SD card image to
|
||||
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`.
|
||||
|
||||
|
@ -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,
|
||||
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
|
||||
`Makefile`, you'll see `cat xcomp.fs | $(STAGE)`. That's the thing. Open
|
||||
`xcomp.fs` in a text editor and take a look at it. You'll see that it loads
|
||||
B618, which contains the meat, and then spits stuff to port 2, which is a
|
||||
special signal for the `stage` binary.
|
||||
`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.
|
||||
|
||||
To assemble from RC2014, all you need to do is load B618. This will
|
||||
yield a binary in memory. To know the start/end offset of the binary, you'll
|
||||
type the same two commands and in `xcomp.fs`, but replace the `/MOD 2 PC! 2 PC!`
|
||||
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`.
|
||||
To assemble stage 1 from RC2014, all you need to do is to type those commands
|
||||
in the same order, and replace the `/MOD 2 PC! 2 PC!` words with `.X`.
|
||||
Those commands will inform you of the begin/end offsets of the assembled binary.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
I'm not going to explain in detail what each command do, but only give you an
|
||||
overview of what is happening. You are encouraged to read the in-system
|
||||
documentation for more information.
|
||||
|
||||
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
|
||||
declarations are expected in the boot code and driver code.
|
||||
starts, what ports to use for what device, etc. These configuration declarations
|
||||
are expected in the boot code and driver code.
|
||||
|
||||
Then, we load the Z80 assembler and the cross compiler (xcomp for short), which
|
||||
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`.
|
||||
|
||||
Then, we spit the init source code that will be interpreted on boot.
|
||||
And... that's it!
|
||||
Then, we spit the source code that will be interpreted by stage 1 on boot so
|
||||
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?
|
||||
|
||||
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
|
||||
inconsistent state. The easiest thing to do it to restart the operation from
|
||||
scratch. Those error are not frequent unless hardware is faulty.
|
||||
inconsistent state. If your at the beginning of it, it's easier to restart it
|
||||
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
|
||||
|
||||
|
@ -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!
|
||||
H@ 256 /MOD 2 PC! 2 PC!
|
||||
|
@ -1,15 +1,15 @@
|
||||
TARGET = os.bin
|
||||
TARGET = stage1.bin
|
||||
BASEDIR = ../..
|
||||
FDIR = $(BASEDIR)/forth
|
||||
EDIR = $(BASEDIR)/emul
|
||||
STAGE = $(EDIR)/stage
|
||||
STAGE2 = $(EDIR)/stage2
|
||||
EMUL = $(BASEDIR)/emul/hw/ti/ti84
|
||||
MKTIUPGRADE = mktiupgrade
|
||||
|
||||
.PHONY: all
|
||||
all: $(TARGET)
|
||||
$(TARGET): xcomp.fs $(STAGE)
|
||||
cat xcomp.fs | $(STAGE) > $@
|
||||
$(TARGET): xcomp.fs $(STAGE2)
|
||||
cat xcomp.fs | $(STAGE2) > $@
|
||||
|
||||
$(EMUL):
|
||||
$(MAKE) -C ${@:%/ti84=%}
|
||||
|
@ -38,7 +38,7 @@ screen as output and its builtin keyboard as input.
|
||||
|
||||
## Build the ROM
|
||||
|
||||
Running `make` will result in `os.rom` being created.
|
||||
Running `make` will result in `stage1.rom` being created.
|
||||
|
||||
## Emulate
|
||||
|
||||
|
@ -68,6 +68,7 @@ CREATE ~FNT CPFNT3x5
|
||||
(entry) _
|
||||
( Update LATEST )
|
||||
PC ORG @ 8 + !
|
||||
440 446 XPACKR ( core )
|
||||
," : _ LCD$ KBD$ (ok) RDLN$ ; _ "
|
||||
ORG @ 0x100 - 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
|
||||
STAGE = $(EDIR)/stage
|
||||
STAGE2 = $(EDIR)/stage2
|
||||
|
||||
.PHONY: all
|
||||
all: $(TARGET)
|
||||
$(TARGET): xcomp.fs $(STAGE)
|
||||
cat xcomp.fs | $(STAGE) > $@
|
||||
$(TARGET): xcomp.fs $(STAGE2)
|
||||
cat xcomp.fs | $(STAGE2) > $@
|
||||
|
@ -67,10 +67,10 @@ kind of reception! You're gonna feel real badass about it too...
|
||||
|
||||
* `_` 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
|
||||
`os.bin`. You'll need it later.
|
||||
You can start the process by building the stage 1 binary. Running `make` in
|
||||
this folder will yield a `stage1.bin` file. You'll need it later.
|
||||
|
||||
## Testing serial communication
|
||||
|
||||
|
@ -7,13 +7,15 @@ RS_ADDR 0x80 - CONSTANT RAMSTART
|
||||
|
||||
0x3000 BIN( !
|
||||
282 LOAD ( boot.z80 )
|
||||
492 LOAD ( trs80.z80 )
|
||||
393 LOAD ( xcomp core low )
|
||||
492 LOAD ( trs80 )
|
||||
420 LOAD ( xcomp core high )
|
||||
(entry) _
|
||||
( Update LATEST )
|
||||
PC ORG @ 8 + !
|
||||
," CURRENT @ HERE ! "
|
||||
440 446 XPACKR ( core )
|
||||
499 500 XPACKR ( trs80.fs )
|
||||
( 0x0a == NLPTR. TRS-80 wants CR-only newlines )
|
||||
," : _ ['] CR 0x0a RAM+ ! BLK$ FD$ (ok) RDLN$ ; _ "
|
||||
ORG @ 256 /MOD 2 PC! 2 PC!
|
||||
|
@ -2,7 +2,8 @@
|
||||
: SDC_SPI 4 ;
|
||||
: SDC_CSLOW 5 ;
|
||||
: SDC_CSHIGH 6 ;
|
||||
602 616 LOADR ( sdc )
|
||||
372 LOAD ( sdc.z80 )
|
||||
374 LOAD ( sdc.fs )
|
||||
|
||||
0x0000 0x00 _crc16 0x0000 #eq
|
||||
0x0000 0x01 _crc16 0x1021 #eq
|
||||
|
Loading…
Reference in New Issue
Block a user