1
0
mirror of https://github.com/hsoft/collapseos.git synced 2024-11-26 17:38:06 +11:00

Compare commits

...

17 Commits

Author SHA1 Message Date
Virgil Dupras
b606dbf9af rc2014: move xcomp unit's contents to blkfs 2020-05-14 12:29:34 -04:00
Virgil Dupras
a8e8204eba trs80: adapt recipe to single stage xcomp 2020-05-14 12:08:17 -04:00
Virgil Dupras
8a58449776 Add word ERR 2020-05-14 11:57:26 -04:00
Virgil Dupras
303b34b483 ti84: adapt recipe to single stage xcomp 2020-05-14 11:36:10 -04:00
Virgil Dupras
0703da928e rc2014: adapt recipe to single stage xcomp
It's now much easier...
2020-05-14 11:32:51 -04:00
Virgil Dupras
b0258f5bba Fix tests 2020-05-14 10:58:41 -04:00
Virgil Dupras
5446afd87d emul: rename stage2 to stage 2020-05-14 10:55:39 -04:00
Virgil Dupras
9d4d9de511 emul: remove stage1 2020-05-14 10:49:24 -04:00
Virgil Dupras
e6bac985fa Cross-compiles in a single stage!
Finally got rid of the XPACKed core and managed to cross-compile
all core words, which greatly simplifies the bootstrapping process.
2020-05-14 10:17:38 -04:00
Virgil Dupras
68262f925b Almost done De-XPACKing! 2020-05-14 09:58:48 -04:00
Virgil Dupras
640e3321fc Move a bunch of words from XPACKed core to xcomp core 2020-05-14 09:54:33 -04:00
Virgil Dupras
4143e2a699 Improve late-stage xcomp 2020-05-14 09:45:42 -04:00
Virgil Dupras
179c66be8a Move a bunch of words from XPACKed core to xcomp core 2020-05-14 08:50:43 -04:00
Virgil Dupras
74896051bb Move BOOT, (boot<) and INTEPRET to high xcomp
Saves us an (ok) indirection and will save us more soon.
2020-05-14 08:45:01 -04:00
Virgil Dupras
b17bd4dca0 wip 2020-05-14 08:33:06 -04:00
Virgil Dupras
40a756cf1c Move a bunch of words from XPACKed core to xcomp core 2020-05-14 08:18:53 -04:00
Virgil Dupras
51997533ff Move a bunch of words from XPACKed core to xcomp core 2020-05-14 07:58:55 -04:00
54 changed files with 273 additions and 565 deletions

View File

@ -6,7 +6,6 @@ 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

View File

@ -12,4 +12,5 @@ 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.
EXECUTE a -- Execute wordref at addr a
ERR a -- Prints a and ABORT. Defined early and used by
drivers. (cont.)

View File

@ -1,3 +1,4 @@
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.

View File

@ -1,14 +1,13 @@
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

View File

@ -1,4 +1,5 @@
: 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
View File

@ -1,7 +1,16 @@
: 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 ;
( 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 ;

22
blk/410
View File

@ -1,11 +1,13 @@
( 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 )
: '? WORD (find) ;
: '
'? (?br) [ 4 , ] EXIT
LIT< (wnf) (find) DROP EXECUTE
;
: 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
View File

@ -1,13 +1,13 @@
: 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 ;
: 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 @ - ;

27
blk/412
View File

@ -1,16 +1,13 @@
( 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!
: 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 !
;
: +! 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
View File

@ -1,13 +1,15 @@
: '? WORD (find) ;
: '
'? (?br) [ 4 , ] EXIT
LIT< (wnf) (find) DROP EXECUTE
: 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 )
;
: 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 ;
: CONSTANT CREATE , DOES> @ ;

18
blk/414
View File

@ -1,13 +1,5 @@
: 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 @ - ;
: [IF]
IF EXIT THEN
LIT< [THEN] BEGIN DUP WORD S= UNTIL DROP ;
: [THEN] ;

13
blk/415
View File

@ -1,13 +0,0 @@
: 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 !
;

View File

@ -1 +1 @@
1 16 LOADR+ ( xcomp core high )
1 20 LOADR+ ( xcomp core high )

12
blk/421
View File

@ -1,14 +1,16 @@
: 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
;
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
View File

@ -1,15 +1,7 @@
: ,"
BEGIN
C<
( 34 is ASCII for " )
DUP 34 = IF DROP EXIT THEN C,
C< DUP 34 ( ASCII " ) = IF DROP EXIT THEN C,
AGAIN ;
: ."
34 , ( 34 == litWord ) ," 0 C,
COMPILE (print)
; IMMEDIATE
: LIT" 34 , ( litWord ) ," 0 C, ; IMMEDIATE
: ." [COMPILE] LIT" 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
View File

@ -1,3 +1,14 @@
: 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
View File

@ -1,14 +0,0 @@
( 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
View File

@ -1,16 +1,13 @@
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!
: 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 ;

15
blk/437 Normal file
View File

@ -0,0 +1,15 @@
( 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 Normal file
View File

@ -0,0 +1,14 @@
: 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
View File

@ -1,14 +1,9 @@
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
: 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

19
blk/440
View File

@ -1,10 +1,11 @@
: [ INTERPRET ; IMMEDIATE
: ] R> DROP ;
: LIT< WORD 34 , SCPY 0 C, ; IMMEDIATE
: LITA 36 , , ;
( ';' 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
: ['] ' LITA ; IMMEDIATE
: COMPILE ' LITA ['] , , ; IMMEDIATE
: [COMPILE] ' , ; IMMEDIATE
: BEGIN H@ ; IMMEDIATE
: AGAIN COMPILE (br) H@ - , ; IMMEDIATE
: UNTIL COMPILE (?br) H@ - , ; IMMEDIATE
';' X' _ 4 - C! ( give ; its name )
':' X' _ 4 - C! ( give : its name )
'(' X' _ 4 - C!

13
blk/441
View File

@ -1,13 +0,0 @@
: _ 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
View File

@ -1,11 +0,0 @@
: 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
View File

@ -1,12 +0,0 @@
: 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
View File

@ -1,14 +0,0 @@
: 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 )
;

View File

@ -1,8 +0,0 @@
: 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 )

View File

@ -1,3 +0,0 @@
: (ok) SPC ." ok" NL ;
: (uflw) ABORT" stack underflow" ;
: (wnf) (print) SPC ABORT" word not found" ;

View File

@ -4,8 +4,7 @@ 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 the Z80 words with "492 LOAD" and the high level part
with "498 LOAD".
Load with "492 LOAD".
There is also the RECV program at B502 and the XCOMP unit at
B504

View File

@ -1 +1 @@
1 5 LOADR+
1 8 LOADR+

View File

@ -1 +0,0 @@
1 2 LOADR+

View File

@ -1,4 +1,4 @@
: _err ABORT" FDerr" ;
: _err LIT" FDerr" ERR ;
: _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 )

View File

@ -2,6 +2,6 @@
: FD! ['] @WRSEC SWAP FD@! ;
: FD$ ['] FD@ BLK@* ! ['] FD! BLK!* ! ;
: _err ABORT" *CLerr" ;
: _err LIT" *CLerr" ERR ;
: *CL< 0 BEGIN DROP 0x0238 @GET UNTIL ;
: *CL> 0x0238 @PUT NOT IF _err THEN ;

View File

@ -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
600 SD card 618 Xcomp unit

15
blk/618 Normal file
View File

@ -0,0 +1,15 @@
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
View File

@ -1,7 +1,4 @@
/stage1
/stage1dbg
/stage2
/stage
/forth
/*-bin.h
/stage0.bin
/blkfs

View File

@ -1,4 +1,4 @@
TARGETS = forth stage2
TARGETS = forth stage
OBJS = emul.o libz80/libz80.o
BIN2C = ../tools/bin2c
BLKPACK = ../tools/blkpack
@ -14,24 +14,12 @@ $(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 > $@
stage2: stage.c $(OBJS) forth-bin.h blkfs-bin.h
$(CC) -DSTAGE2 stage.c $(OBJS) -o $@
stage: stage.c $(OBJS) forth-bin.h blkfs-bin.h
$(CC) stage.c $(OBJS) -o $@
blkfs: $(BLKPACK)
$(BLKPACK) ../blk > $@
@ -51,8 +39,8 @@ emul.o: emul.c
.PHONY: updatebootstrap
updatebootstrap: stage1 stage1.fs
./stage1 < stage1.fs > forth.bin
updatebootstrap: stage xcomp.fs
./stage < xcomp.fs > forth.bin
.PHONY: pack
pack:

Binary file not shown.

View File

@ -2,12 +2,8 @@
#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
@ -74,7 +70,6 @@ static void iowr_here(uint8_t val)
end_here |= val;
}
#ifdef STAGE2
static void iowr_blk(uint8_t val)
{
blkid <<= 8;
@ -86,7 +81,6 @@ static uint8_t iord_blkdata()
{
return BLKFS[blkpos++];
}
#endif
int main(int argc, char *argv[])
{
@ -95,10 +89,8 @@ 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];

View File

@ -1,28 +0,0 @@
: 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!

View File

@ -9,12 +9,32 @@
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 ! "
440 446 XPACKR
," ' (key) 12 RAM+ ! "
," : INIT "
," BLK$ "
," ['] EFS@ BLK@* ! "
," ['] EFS! BLK!* ! "
," RDLN$ "
," LIT< _sys [entry] "
," LIT< CollapseOS (print) NL "
," ; INIT "
ORG @ 256 /MOD 2 PC! 2 PC!
H@ 256 /MOD 2 PC! 2 PC!

View File

@ -1,14 +1,14 @@
TARGET = stage1.bin
TARGET = os.bin
BASEDIR = ../..
FDIR = $(BASEDIR)/forth
EDIR = $(BASEDIR)/emul
STAGE2 = $(EDIR)/stage2
STAGE = $(EDIR)/stage
EMUL = $(BASEDIR)/emul/hw/rc2014/classic
.PHONY: all
all: $(TARGET)
$(TARGET): xcomp.fs $(STAGE2)
cat xcomp.fs | $(STAGE2) > $@
$(TARGET): xcomp.fs $(STAGE)
cat xcomp.fs | $(STAGE) > $@
$(SLATEST):
$(MAKE) -C $(BASEDIR)/tools

View File

@ -40,7 +40,7 @@ device I use in this recipe.
### Gathering parts
* A "classic" RC2014 with Serial I/O
* [Forth's stage 2 binary][stage2]
* [Forth's stage binary][stage]
* [romwrite][romwrite] and its specified dependencies
* [GNU screen][screen]
* A FTDI-to-TTL cable to connect to the Serial I/O module
@ -50,24 +50,10 @@ 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 stage 1
### Build the binary
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.
Building the binary is as simple as running `make`. This will yield `os.bin`
which can then be written to EEPROM.
### Emulate
@ -100,131 +86,9 @@ identify the tty bound to it (in my case, `/dev/ttyUSB0`). Then:
screen /dev/ttyUSB0 115200
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.
Press the reset button on the RC2014 and the "ok" prompt should appear.
[rc2014]: https://rc2014.co.uk
[romwrite]: https://github.com/hsoft/romwrite
[stage2]: ../../emul
[stage]: ../../emul
[screen]: https://www.gnu.org/software/screen/

View File

@ -8,7 +8,6 @@ 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.
@ -33,46 +32,21 @@ in write protection mode, but I preferred building my own module.
I don't think you need a schematic. It's really simple.
### Assembling stage 3
### Building the binary
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.
You build the binary by modifying the base recipe's `xcomp` unit. This binary
is missing 2 things: Addressed devices and the AT28 Driver.
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.
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.
Do the same thing with the AT28 driver (B590)
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.
You also have to modify the initialization sequence at the end of the `xcomp`
unit to include `ADEV$`.
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$`.
Build again, write `os.com` to EEPROM.
## Writing contents to the AT28

View File

@ -70,35 +70,23 @@ instead.
## Building your binary
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:
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:
602 616 LOADR ( sdc )
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.
You also need to add `BLK$` to the init sequence.
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 stage3.bin ../../../emul/blkfs
../../../emul/hw/rc2014/classic os.bin ../../../emul/blkfs
You will then run with a SD card having the contents from `/blk`.

View File

@ -9,24 +9,34 @@ 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 stage 1
## Building the binary
Build Collapse OS' stage 1 from within Collapse OS is very similar to how we do
Build Collapse OS' 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 | $(STAGE2)`. That's the thing. Open
`xcomp.fs` in a text editor and take a look at it.
`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.
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.
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`.
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
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
documentation for more information.
The first part is configuration of your new system. When RAM starts, where RSP
starts, what ports to use for what device, etc. These configuration declarations
are expected in the boot code and driver code.
and PSP start, 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.
@ -41,41 +51,15 @@ 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 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!
Then, we spit the init source code that will be interpreted on boot.
And... that's it!
### 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. 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.
inconsistent state. The easiest thing to do it to restart the operation from
scratch. Those error are not frequent unless hardware is faulty.
### Verifying

View File

@ -1,25 +1,3 @@
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) ; _ "
618 LOAD
ORG @ 256 /MOD 2 PC! 2 PC!
H@ 256 /MOD 2 PC! 2 PC!

View File

@ -1,15 +1,15 @@
TARGET = stage1.bin
TARGET = os.bin
BASEDIR = ../..
FDIR = $(BASEDIR)/forth
EDIR = $(BASEDIR)/emul
STAGE2 = $(EDIR)/stage2
STAGE = $(EDIR)/stage
EMUL = $(BASEDIR)/emul/hw/ti/ti84
MKTIUPGRADE = mktiupgrade
.PHONY: all
all: $(TARGET)
$(TARGET): xcomp.fs $(STAGE2)
cat xcomp.fs | $(STAGE2) > $@
$(TARGET): xcomp.fs $(STAGE)
cat xcomp.fs | $(STAGE) > $@
$(EMUL):
$(MAKE) -C ${@:%/ti84=%}

View File

@ -38,7 +38,7 @@ screen as output and its builtin keyboard as input.
## Build the ROM
Running `make` will result in `stage1.rom` being created.
Running `make` will result in `os.rom` being created.
## Emulate

View File

@ -68,7 +68,6 @@ 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!

View File

@ -1,8 +1,8 @@
TARGET = stage1.bin
TARGET = os.bin
EDIR = ../../emul
STAGE2 = $(EDIR)/stage2
STAGE = $(EDIR)/stage
.PHONY: all
all: $(TARGET)
$(TARGET): xcomp.fs $(STAGE2)
cat xcomp.fs | $(STAGE2) > $@
$(TARGET): xcomp.fs $(STAGE)
cat xcomp.fs | $(STAGE) > $@

View File

@ -67,10 +67,10 @@ kind of reception! You're gonna feel real badass about it too...
* `_` is `CLEAR+ENTER`.
## Building the stage 1
## Building the binary
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.
You can build the binary to send to the TRS-80 with `make`, which will yield
`os.bin`. You'll need it later.
## Testing serial communication

View File

@ -7,15 +7,13 @@ 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!

View File

@ -2,8 +2,7 @@
: SDC_SPI 4 ;
: SDC_CSLOW 5 ;
: SDC_CSHIGH 6 ;
372 LOAD ( sdc.z80 )
374 LOAD ( sdc.fs )
602 616 LOADR ( sdc )
0x0000 0x00 _crc16 0x0000 #eq
0x0000 0x01 _crc16 0x1021 #eq