1
0
mirror of https://github.com/hsoft/collapseos.git synced 2024-11-02 10:30:55 +11:00

Compare commits

..

7 Commits

Author SHA1 Message Date
Virgil Dupras
8d78ca9dac tests: add test_sdc
The SD card driver is a bit too slow to be bearable. I'll write
_crc16 in z80 and see how it goes.
2020-04-24 18:23:29 -04:00
Virgil Dupras
b5c370a936 emul: embed blkfs in forth binary
This will allow us to read from blkfs in tests.
2020-04-24 18:01:55 -04:00
Virgil Dupras
1bd191e86a Move /emul/forth/* to /emul
Less noisy this way
2020-04-24 17:53:58 -04:00
Virgil Dupras
816563e2e3 Stop LOADing on ABORT
This is done by adding a "C<* override" layer that is reset to 0 on
ABORT.

The problem was that when ABORT happened during a LOAD, we had a
resetted RSP and started from a clean INTERPRET, but LOAD didn't
have the opportunity to restore C<*, which caused it to continue
interpreting from the faulty BLK.

With a C<* override, we don't need to *restore* C<*, we just need to
clear the override.
2020-04-24 14:10:40 -04:00
Virgil Dupras
af39b37dd1 Replace the "> " prompt with the more traditional "ok" one
This is more than cosmetic, it's also highly usable. The presence
or absence of the "ok" message allows us to know whether the command
aborted. Previously, the "> " prompt appeared when the system expected
a prompt in the INTERPRET context, whether the previous command aborted
or not.

Also, this allows us to get rid of that ugly FLAGS global variable.
2020-04-24 12:10:07 -04:00
Virgil Dupras
a699c93509 Print word that wasn't found on "word not found" error 2020-04-24 10:59:59 -04:00
Virgil Dupras
f19a5e1f71 Remove recipes/rc2014/zasm
That becomes irrelevant in Forth
2020-04-24 10:59:28 -04:00
37 changed files with 141 additions and 453 deletions

View File

@ -1,6 +1,6 @@
(cont.)
." xxx" -- *I* Compiles string literal xxx followed by a ." xxx" -- *I* Compiles string literal xxx followed by a
call to (print). call to (print).
C<? -- f Returns whether there's a char waiting in buf.
C< -- c Read one char from buffered input. C< -- c Read one char from buffered input.
DUMP n a -- Prints n bytes at addr a in a hexdump format. DUMP n a -- Prints n bytes at addr a in a hexdump format.
Prints in chunks of 8 bytes. Doesn't do partial Prints in chunks of 8 bytes. Doesn't do partial

View File

@ -2,10 +2,10 @@
RAMSTART INITIAL_SP +53 readln's variables RAMSTART INITIAL_SP +53 readln's variables
+02 CURRENT +55 adev's variables +02 CURRENT +55 adev's variables
+04 HERE +57 blk's variables +04 HERE +57 blk's variables
+06 FUTURE USES +59 z80a's variables +06 C<?* +59 z80a's variables
+08 FLAGS +5b FUTURE USES +08 C<* override +5b FUTURE USES
+0a PARSEPTR +70 DRIVERS +0a PARSEPTR +70 DRIVERS
+0c CINPTR +80 RAMEND +0c C<* +80 RAMEND
+0e WORDBUF +0e WORDBUF
+2e BOOT C< PTR +2e BOOT C< PTR
+4e INTJUMP +4e INTJUMP

10
blk/082
View File

@ -1,4 +1,4 @@
(cont.) INITIAL_SP holds the initial Stack Pointer value so INITIAL_SP holds the initial Stack Pointer value so
that we know where to reset it on ABORT that we know where to reset it on ABORT
CURRENT points to the last dict entry. CURRENT points to the last dict entry.
@ -7,10 +7,10 @@ HERE points to current write offset.
IP is the Interpreter Pointer IP is the Interpreter Pointer
FLAGS holds global flags. Only used for prompt output control
for now.
PARSEPTR holds routine address called on (parse) PARSEPTR holds routine address called on (parse)
CINPTR holds routine address called on C< C<* holds routine address called on C<. If the C<* override
at 0x08 is nonzero, this routine is called instead.
(cont.) (cont.)

12
blk/083
View File

@ -1,4 +1,7 @@
(cont.) WORDBUF is the buffer used by WORD C<?* is a pointer to a word being called by C<?. If 0 or 1,
will return that value as-is.
WORDBUF is the buffer used by WORD
BOOT C< PTR is used when Forth boots from in-memory BOOT C< PTR is used when Forth boots from in-memory
source. See "Initialization sequence" below. source. See "Initialization sequence" below.
@ -9,8 +12,5 @@ jump to this address. If you use one of those slots for an
interrupt, write a jump to the appropriate offset in that RAM interrupt, write a jump to the appropriate offset in that RAM
location. location.
CURRENTPTR points to current CURRENT. The Forth CURRENT word
doesn't return RAM+2 directly, but rather the value at this (cont.)
address. Most of the time, it points to RAM+2, but sometimes,
when maintaining alternative dicts (during cross compilation
for example), it can point elsewhere. (cont.)

14
blk/084
View File

@ -1,4 +1,10 @@
(cont.) FUTURE USES section is unused for now. CURRENTPTR points to current CURRENT. The Forth CURRENT word
doesn't return RAM+2 directly, but rather the value at this
address. Most of the time, it points to RAM+2, but sometimes,
when maintaining alternative dicts (during cross compilation
for example), it can point elsewhere.
FUTURE USES section is unused for now.
DRIVERS section is reserved for recipe-specific DRIVERS section is reserved for recipe-specific
drivers. Here is a list of known usages: drivers. Here is a list of known usages:
@ -8,9 +14,3 @@ drivers. Here is a list of known usages:

28
blk/380
View File

@ -1,16 +1,16 @@
: _err _sdcDesel ABORT" SDerr" ; : _err _sdcDesel ABORT" SDerr" ;
( Initialize a SD card. This should be called at least 1ms ( Tight definition ahead, pre-comment.
after the powering up of the card. )
: SDC$ Initialize a SD card. This should be called at least 1ms
( Wake the SD card up. After power up, a SD card has to receive after the powering up of the card. We begin by waking up the
at least 74 dummy clocks with CS and DI high. We send 80. ) SD card. After power up, a SD card has to receive at least
10 0 DO _idle DROP LOOP 74 dummy clocks with CS and DI high. We send 80.
( call cmd0 and expect a 0x01 response (card idle) Then send cmd0 for a maximum of 10 times, success is when
this should be called multiple times. we're actually we get 0x01. Then comes the CMD8. We send it with a 0x01aa
expected to. let's call this for a maximum of 10 times. ) argument and expect a 0x01aa argument back, along with a
0 ( dummy ) 0x01 R1 response. After that, we need to repeatedly run
10 0 DO ( r ) CMD55+CMD41 (0x40000000) until the card goes out of idle
DROP 0x40 0 0 SDCMDR1 ( CMD0 ) mode, that is, when it stops sending us 0x01 response and
DUP 0x01 = IF LEAVE THEN send us 0x00 instead. Any other response means that
LOOP 0x01 = NOT IF _err THEN ( cont. ) initialization failed. )

20
blk/381
View File

@ -1,10 +1,16 @@
( Then comes the CMD8. We send it with a 0x01aa argument and : SDC$
expect a 0x01aa argument back, along with a 0x01 R1 10 0 DO _idle DROP LOOP
response. ) 0 ( dummy ) 10 0 DO ( r )
0x48 0 0x1aa ( CMD8 ) DROP 0x40 0 0 SDCMDR1 ( CMD0 )
SDCMDR7 ( r arg1 arg2 ) DUP 0x01 = IF LEAVE THEN
LOOP 0x01 = NOT IF _err THEN
0x48 0 0x1aa ( CMD8 ) SDCMDR7 ( r arg1 arg2 )
0x1aa = NOT IF _err THEN ( arg2 check ) 0x1aa = NOT IF _err THEN ( arg2 check )
0 = NOT IF _err THEN ( arg1 check ) 0 = NOT IF _err THEN ( arg1 check )
0x01 = NOT IF _err THEN ( r check ) 0x01 = NOT IF _err THEN ( r check )
BEGIN
( cont. ) 0x77 0 0 SDCMDR1 ( CMD55 )
0x01 = NOT IF _err THEN
0x69 0x4000 0x0000 SDCMDR1 ( CMD41 )
DUP 0x01 > IF _err THEN
NOT UNTIL ; ( out of idle mode, success! )

13
blk/382
View File

@ -1,13 +0,0 @@
( Now we need to repeatedly run CMD55+CMD41 (0x40000000)
until the card goes out of idle mode, that is, when it stops
sending us 0x01 response and send us 0x00 instead. Any other
response means that initialization failed. )
BEGIN
0x77 0 0 SDCMDR1 ( CMD55 )
0x01 = NOT IF _err THEN
0x69 0x4000 0x0000 SDCMDR1 ( CMD41 )
DUP 0x01 > IF _err THEN
NOT UNTIL
( Out of idle mode! Success! )
;

View File

@ -1,5 +1,4 @@
: RAM+ [ RAMSTART LITN ] + ; : RAM+ [ RAMSTART LITN ] + ;
: FLAGS 0x08 RAM+ ;
: (parse*) 0x0a RAM+ ; : (parse*) 0x0a RAM+ ;
: HERE 0x04 RAM+ ; : HERE 0x04 RAM+ ;
: CURRENT* 0x51 RAM+ ; : CURRENT* 0x51 RAM+ ;
@ -9,7 +8,8 @@
: (find) CURRENT @ SWAP _find ; : (find) CURRENT @ SWAP _find ;
: QUIT : QUIT
0 FLAGS ! (resRS) (resRS)
0 0x08 RAM+ ! ( 08 == C<* override )
LIT< INTERPRET (find) DROP EXECUTE LIT< INTERPRET (find) DROP EXECUTE
; ;
394 407 LOADR 394 407 LOADR

View File

@ -2,7 +2,12 @@
for an abort message ) for an abort message )
: (parse) (parsed) NOT IF ABORT THEN ; : (parse) (parsed) NOT IF ABORT THEN ;
: C< 0x0c RAM+ @ EXECUTE ( 0c == CINPTR ) ; : C<? 0x06 RAM+ @ DUP 2 > IF EXECUTE THEN ( 06 == C<?* ) ;
: C<
0x08 RAM+ @ ( 08 == C<* override )
DUP NOT IF DROP 0x0c RAM+ @ THEN ( 0c == C<* )
EXECUTE
;
: , HERE @ ! HERE @ 2+ HERE ! ; : , HERE @ ! HERE @ 2+ HERE ! ;

View File

@ -2,13 +2,8 @@
BEGIN BEGIN
WORD WORD
(find) (find)
IF NOT IF (parse*) @ THEN EXECUTE
1 FLAGS ! C<? NOT IF LIT< (ok) (find) IF EXECUTE THEN THEN
EXECUTE
0 FLAGS !
ELSE
(parse*) @ EXECUTE
THEN
AGAIN AGAIN
; ;

View File

@ -3,8 +3,11 @@
LIT< (parse) (find) DROP (parse*) ! LIT< (parse) (find) DROP (parse*) !
( 2e == SYSTEM SCRATCHPAD ) ( 2e == SYSTEM SCRATCHPAD )
CURRENT @ 0x2e RAM+ ! CURRENT @ 0x2e RAM+ !
( 0c == CINPTR ) 0 0x08 RAM+ ! ( 08 == C<* override )
( 0c == C<* )
LIT< (boot<) (find) DROP 0x0c RAM+ ! LIT< (boot<) (find) DROP 0x0c RAM+ !
( boot< always has a char waiting. 06 == C<?* )
1 0x06 RAM+ !
LIT< INIT (find) LIT< INIT (find)
IF EXECUTE IF EXECUTE
ELSE DROP INTERPRET THEN ELSE DROP INTERPRET THEN

13
emul/.gitignore vendored
View File

@ -1,7 +1,8 @@
/forth/stage1 /stage1
/forth/stage1dbg /stage1dbg
/forth/stage2 /stage2
/forth/forth /forth
/*/*-bin.h /*-bin.h
/*/*.bin /core.bin
/forth?.bin
/blkfs /blkfs

View File

@ -1,7 +1,7 @@
TARGETS = forth/forth forth/stage2 TARGETS = forth stage2
# Those Forth source files are in a particular order # Those Forth source files are in a particular order
FORTHSRCS = core.fs cmp.fs print.fs parse.fs readln.fs fmt.fs blk.fs FORTHSRCS = core.fs cmp.fs print.fs parse.fs readln.fs fmt.fs blk.fs
FORTHSRC_PATHS = ${FORTHSRCS:%=../forth/%} forth/run.fs FORTHSRC_PATHS = ${FORTHSRCS:%=../forth/%} run.fs
OBJS = emul.o libz80/libz80.o OBJS = emul.o libz80/libz80.o
SLATEST = ../tools/slatest SLATEST = ../tools/slatest
STRIPFC = ../tools/stripfc STRIPFC = ../tools/stripfc
@ -23,43 +23,43 @@ $(BLKUNPACK): $(BLKPACK)
# z80c.bin is not in the prerequisites because it's a bootstrap # z80c.bin is not in the prerequisites because it's a bootstrap
# binary that should be updated manually through make updatebootstrap. # binary that should be updated manually through make updatebootstrap.
forth/forth0.bin: $(SLATEST) forth0.bin: $(SLATEST)
cp forth/z80c.bin $@ cp z80c.bin $@
$(SLATEST) $@ $(SLATEST) $@
cat forth/pre.fs forth/emul.fs >> $@ cat pre.fs emul.fs >> $@
forth/forth0-bin.h: forth/forth0.bin $(BIN2C) forth0-bin.h: forth0.bin $(BIN2C)
$(BIN2C) KERNEL < forth/forth0.bin | tee $@ > /dev/null $(BIN2C) KERNEL < forth0.bin | tee $@ > /dev/null
forth/stage1: forth/stage.c $(OBJS) forth/forth0-bin.h stage1: stage.c $(OBJS) forth0-bin.h
$(CC) forth/stage.c $(OBJS) -o $@ $(CC) stage.c $(OBJS) -o $@
forth/stage1dbg: forth/stage.c $(OBJS) forth/forth0-bin.h stage1dbg: stage.c $(OBJS) forth0-bin.h
$(CC) -DDEBUG forth/stage.c $(OBJS) -o $@ $(CC) -DDEBUG stage.c $(OBJS) -o $@
# We don't really need to use stripfc, but we do it anyway to test that we # We don't really need to use stripfc, but we do it anyway to test that we
# don't mistakenly break our code with that tool. It's easier to debug here. # don't mistakenly break our code with that tool. It's easier to debug here.
forth/core.bin: $(FORTHSRC_PATHS) forth/stage1 core.bin: $(FORTHSRC_PATHS) stage1
cat $(FORTHSRC_PATHS) ./forth/stop.fs | $(STRIPFC) | ./forth/stage1 > $@ cat $(FORTHSRC_PATHS) stop.fs | $(STRIPFC) | ./stage1 > $@
forth/forth1.bin: forth/core.bin $(SLATEST) forth1.bin: core.bin $(SLATEST)
cat forth/z80c.bin forth/core.bin > $@ cat z80c.bin core.bin > $@
$(SLATEST) $@ $(SLATEST) $@
forth/forth1-bin.h: forth/forth1.bin $(BIN2C) forth1-bin.h: forth1.bin $(BIN2C)
$(BIN2C) KERNEL < forth/forth1.bin > $@ $(BIN2C) KERNEL < forth1.bin > $@
forth/stage2: forth/stage.c $(OBJS) forth/forth1-bin.h forth/blkfs-bin.h stage2: stage.c $(OBJS) forth1-bin.h blkfs-bin.h
$(CC) -DSTAGE2 forth/stage.c $(OBJS) -o $@ $(CC) -DSTAGE2 stage.c $(OBJS) -o $@
blkfs: $(BLKPACK) blkfs: $(BLKPACK)
$(BLKPACK) ../blk > $@ $(BLKPACK) ../blk > $@
forth/blkfs-bin.h: blkfs $(BIN2C) blkfs-bin.h: blkfs $(BIN2C)
$(BIN2C) BLKFS < blkfs > $@ $(BIN2C) BLKFS < blkfs > $@
forth/forth: forth/forth.c $(OBJS) forth/forth1-bin.h blkfs forth: forth.c $(OBJS) forth1-bin.h blkfs-bin.h
$(CC) forth/forth.c $(OBJS) -o $@ $(CC) forth.c $(OBJS) -o $@
libz80/libz80.o: libz80/z80.c libz80/libz80.o: libz80/z80.c
$(MAKE) -C libz80/codegen opcodes $(MAKE) -C libz80/codegen opcodes
@ -70,8 +70,8 @@ emul.o: emul.c
.PHONY: updatebootstrap .PHONY: updatebootstrap
updatebootstrap: forth/stage2 updatebootstrap: stage2
cat ./forth/xcomp.fs | ./forth/stage2 > ./forth/z80c.bin cat xcomp.fs | ./stage2 > z80c.bin
.PHONY: pack .PHONY: pack
pack: pack:
@ -83,5 +83,5 @@ unpack:
.PHONY: clean .PHONY: clean
clean: clean:
rm -f $(TARGETS) emul.o forth/*-bin.h forth/forth?.bin blkfs rm -f $(TARGETS) emul.o *-bin.h forth?.bin blkfs
$(MAKE) -C ../tools clean $(MAKE) -C ../tools clean

View File

@ -2,8 +2,9 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <termios.h> #include <termios.h>
#include "../emul.h" #include "emul.h"
#include "forth1-bin.h" #include "forth1-bin.h"
#include "blkfs-bin.h"
// in sync with glue.asm // in sync with glue.asm
#define RAMSTART 0x900 #define RAMSTART 0x900
@ -102,6 +103,12 @@ int main(int argc, char *argv[])
return 1; return 1;
} }
blkfp = fopen("blkfs", "r+"); blkfp = fopen("blkfs", "r+");
if (blkfp) {
fprintf(stderr, "Using blkfs file\n");
} else {
blkfp = fmemopen((char*)BLKFS, sizeof(BLKFS), "r");
fprintf(stderr, "Using in-memory read-only blkfs\n");
}
Machine *m = emul_init(); Machine *m = emul_init();
m->ramstart = RAMSTART; m->ramstart = RAMSTART;
m->iord[STDIO_PORT] = iord_stdio; m->iord[STDIO_PORT] = iord_stdio;

View File

@ -19,5 +19,6 @@
['] EFS! BLK!* ! ['] EFS! BLK!* !
RDLN$ RDLN$
LIT< _sys [entry] LIT< _sys [entry]
." Collapse OS" CRLF
INTERPRET INTERPRET
; ;

View File

@ -1,7 +1,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include "../emul.h" #include "emul.h"
#ifdef STAGE2 #ifdef STAGE2
#include "forth1-bin.h" #include "forth1-bin.h"
#include "blkfs-bin.h" #include "blkfs-bin.h"

View File

@ -61,28 +61,28 @@
; ;
: LOAD : LOAD
( save BLK>, CINPTR and boot< ptr to RSP ) ( save BLK>, C<* override and boot< ptr to RSP )
BLK> @ >R BLK> @ >R
0x0c RAM+ @ >R 0x08 RAM+ @ >R
0x2e RAM+ @ >R 0x2e RAM+ @ >R
BLK@ BLK@
( Point to beginning of BLK ) ( Point to beginning of BLK )
BLK( 0x2e RAM+ ! BLK( 0x2e RAM+ !
( 0c == CINPTR ) ( 08 == C<* override )
['] _ 0x0c RAM+ ! ['] _ 0x08 RAM+ !
INTERPRET INTERPRET
R> 0x2e RAM+ ! R> 0x2e RAM+ !
( Before we restore CINPTR, are we restoring it to "_"? ( Before we restore C<* are we restoring it to "_"?
if yes, it means we're in a nested LOAD which means we if yes, it means we're in a nested LOAD which means we
should also load back the saved BLK>. Otherwise, we can should also load back the saved BLK>. Otherwise, we can
ignore the BLK> from RSP. ) ignore the BLK> from RSP. )
I 0x0c RAM+ @ = IF I 0x08 RAM+ @ = IF
( nested load ) ( nested load )
R> DROP ( CINPTR ) R> DROP ( C<* )
R> BLK@ R> BLK@
ELSE ELSE
( not nested ) ( not nested )
R> 0x0c RAM+ ! R> 0x08 RAM+ !
R> DROP ( BLK> ) R> DROP ( BLK> )
THEN THEN
; ;

View File

@ -3,7 +3,7 @@
CURRENT @ 1- CURRENT @ 1-
DUP C@ 128 OR SWAP C! DUP C@ 128 OR SWAP C!
; ;
: [ INTERPRET 1 FLAGS ! ; IMMEDIATE : [ INTERPRET ; IMMEDIATE
: ] R> DROP ; : ] R> DROP ;
: LITS 34 , SCPY ; : LITS 34 , SCPY ;
: LIT< WORD LITS ; IMMEDIATE : LIT< WORD LITS ; IMMEDIATE

View File

@ -26,10 +26,12 @@
: ABORT" [COMPILE] ." COMPILE ABORT ; IMMEDIATE : ABORT" [COMPILE] ." COMPILE ABORT ; IMMEDIATE
: (uflw) ABORT" stack underflow" ; : (uflw) ABORT" stack underflow" ;
: (wnf) ABORT" word not found" ;
: BS 8 EMIT ; : BS 8 EMIT ;
: LF 10 EMIT ; : LF 10 EMIT ;
: CR 13 EMIT ; : CR 13 EMIT ;
: CRLF CR LF ; : CRLF CR LF ;
: SPC 32 EMIT ; : SPC 32 EMIT ;
: (wnf) (print) SPC ABORT" word not found" ;
: (ok) SPC ." ok" CRLF ;

View File

@ -54,17 +54,16 @@
( Read one line in input buffer and make IN> point to it ) ( Read one line in input buffer and make IN> point to it )
: (rdln) : (rdln)
( Should we prompt? if we're executing a word, FLAGS bit
0, then we shouldn't. )
FLAGS @ 0x1 AND NOT IF '>' EMIT SPC THEN
(infl) (infl)
BEGIN (rdlnc) NOT UNTIL BEGIN (rdlnc) NOT UNTIL
LF IN( IN> ! LF IN( IN> !
; ;
: RDLN<? IN> @ C@ ;
( And finally, implement a replacement for the (c<) routine ) ( And finally, implement a replacement for the (c<) routine )
: (rdln<) : RDLN<
IN> @ C@ ( c ) RDLN<? ( c )
( not EOL? good, inc and return ) ( not EOL? good, inc and return )
DUP IF 1 IN> +! EXIT THEN ( c ) DUP IF 1 IN> +! EXIT THEN ( c )
( EOL ? readline. we still return typed char though ) ( EOL ? readline. we still return typed char though )
@ -79,6 +78,7 @@
the last typed 0x0a and one for the following NULL. ) the last typed 0x0a and one for the following NULL. )
INBUFSZ 4 + ALLOT INBUFSZ 4 + ALLOT
(infl) (infl)
['] (rdln<) 0x0c RAM+ ! ['] RDLN<? 0x06 RAM+ !
['] RDLN< 0x0c RAM+ !
; ;

View File

@ -1,7 +1,7 @@
TARGET = stage1.bin TARGET = stage1.bin
BASEDIR = ../.. BASEDIR = ../..
FDIR = $(BASEDIR)/forth FDIR = $(BASEDIR)/forth
EDIR = $(BASEDIR)/emul/forth EDIR = $(BASEDIR)/emul
STAGE2 = $(EDIR)/stage2 STAGE2 = $(EDIR)/stage2
EMUL = $(BASEDIR)/emul/hw/rc2014/classic EMUL = $(BASEDIR)/emul/hw/rc2014/classic
@ -36,4 +36,3 @@ $(EMUL):
.PHONY: emul .PHONY: emul
emul: $(EMUL) $(TARGET) emul: $(EMUL) $(TARGET)
$(EMUL) $(TARGET) $(EMUL) $(TARGET)

View File

@ -1,9 +1,7 @@
: (c<) KEY DUP EMIT ; : (c<) KEY DUP EMIT ;
: INIT : _
ACIA$ ACIA$
." Collapse OS" CRLF ." Collapse OS" CRLF
( 0c == CINPTR ) ( 0c == CINPTR )
['] (c<) 0x0c RAM+ ! ['] (c<) 0x0c RAM+ !
; ; _
INIT

View File

@ -1,2 +0,0 @@
/cfsin/zasm
/cfsin/user.h

View File

@ -1,30 +0,0 @@
SHELLAPPS = zasm sdct memt at28w
APPTARGETS = ${SHELLAPPS:%=cfsin/%}
CFSTARGETS = $(APPTARGETS) cfsin/user.h
BASEDIR = ../../..
ZASM = $(BASEDIR)/emul/zasm/zasm
KERNEL = $(BASEDIR)/kernel
APPS = $(BASEDIR)/apps
CFSPACK = $(BASEDIR)/tools/cfspack/cfspack
.PHONY: all
all: os.bin sdcard.cfs
os.bin: glue.asm
$(ZASM) $(KERNEL) $(APPS) < glue.asm > $@
$(CFSPACK):
make -C $(BASEDIR)/tools/cfspack
sdcard.cfs: $(CFSTARGETS) $(CFSPACK)
$(CFSPACK) cfsin > $@
$(APPTARGETS): $(ZASMBIN)
$(ZASM) $(KERNEL) $(APPS) user.h < $(APPS)/${@:cfsin/%=%}/glue.asm > $@
cfsin/user.h: user.h
cp user.h $@
.PHONY: clean
clean:
rm -f $(CFSTARGETS) sdcard.cfs os.bin

View File

@ -1,109 +0,0 @@
# Assembling binaries
For a system to be able to self-reproduce, it needs to assemble source z80
assembly to binary.
## Goals
Have a RC2014 assemble a Collapse OS kernel with its source living on a CFS on
a SD card.
## Gathering parts
* Same parts as the [SD card recipe](../sdcard).
## The zasm binary
To achieve our goal in this recipe, we'll need a zasm binary on the SD card.
This zasm binary needs to be compiled with the right jump offsets for the kernel
we build in this recipe. These offsets are in `user.h` and are closely in sync
with the configuration in `glue.asm`.
`user.h` is then included in `apps/zasm/glue.asm`.
The makefile in this recipe takes care of compiling zasm with the proper
`user.h` file and place it in `cfsin/zasm`
## The userland source
The code we're going to compile is `cfsin/hello.asm`. As you can see, we also
include `user.h` in this source code or else `ld hl, sAwesome` would load the
wrong offset.
Because of this, the Makefile takes care of copying `user.h` in our filesystem.
## Preparing the card and kernel
After running `make`, you'll end up with `sdcard.cfs` which you can load the
same way you did in the SD card recipe.
You will also have `os.bin`, which you can flash on your EEPROM the same way
you already did before.
## Running it
Compiling and running `hello.asm` is done very much like in
[the shell emulator](../../../doc/zasm.md):
Collapse OS
> sdci
> fson
> fopen 0 hello.asm
> fnew 1 dest
> fopen 1 dest
> zasm 1 2
> dest
Assembled from a RC2014
>
That RC2014 is starting to feel powerful now, right?
## Test your hardware
Now that you have a fully functional filesystem that can load programs and run
them easily, you'll see that this recipe's CFS include a couple of programs
besides `zasm`. Among them, there's `sdct` that stress tests reading and
writing on the SD card and `memt` that stress tests RAM. You might be
interested in running them. Look at their description in `apps/`. All you need
to to do run them is to type their name.
## Assembling the kernel
Now let's go for something a little more fun! Jiu-jitsu? No, you're not going to
learn jiu-jitsu! You're going to assemble the kernel from within your RC2014!
The makefile doesn't prepare a CFS blob for this, let's learn to build that blob
yourself. First of all, we'll need to have what we already had in `sdcard.cfs`
because it has `zasm` and `user.h`. But we're going to add the contents of
the `/kernel/` directory to it.
$ cp ../../../kernel/*.{h,asm} cfsin
You'll also need your glue file:
$ cp glue.asm cfsin
You're now ready to re-make your CFS:
$ rm sdcard.cfs && make
Now you can write this into your card and boot Collapse OS:
Collapse OS
> sdci
> fson
> fopn 0 glue.asm
> fnew 10 dest
> fopen 1 dest
> zasm 1 2 # This takes a while. About 7 minutes.
> sdcf # success! sdcf flushes SD card buffers to the card.
Now let's go verify that we assembled the right thing. Pop out the card and
plug it in your "modern" computer. Pipe the device directly through `cfsunpack`
to unpack the FS into a directory (it will stop reading when it stops seeing
CFS blocks):
$ sudo cat /dev/sdX | ../../../tools/cfspack/cfsunpack cfsout
$ cmp cfsout/dest ../os.bin
They're the same! Your RC2014 assembled a full Collapse OS kernel all by itself!

View File

@ -1,10 +0,0 @@
.inc "user.h"
ld hl, sAwesome
call printstr
xor a ; success
ret
sAwesome:
.db "Assembled from a RC2014", 0x0d, 0x0a, 0

View File

@ -1,151 +0,0 @@
; classic RC2014 setup (8K ROM + 32K RAM) and a stock Serial I/O module
; The RAM module is selected on A15, so it has the range 0x8000-0xffff
.equ RAMSTART 0x8000
; Kernel RAMEND last check: 0x9933
; We allocate at least 0x100 bytes for the stack, which is why we have this
; threshold.
.equ RAMEND 0x9b00
.equ USER_CODE RAMEND ; in sync with user.h
.equ ACIA_CTL 0x80 ; Control and status. RS off.
.equ ACIA_IO 0x81 ; Transmit. RS on.
jp init ; 3 bytes
; *** Jump Table ***
jp strncmp
jp upcase
jp findchar
jp blkSel
jp blkSet
jp fsFindFN
jp fsOpen
jp fsGetB
jp printstr
jp printcrlf
jp _blkGetB
jp _blkPutB
jp _blkSeek
jp _blkTell
jp sdcGetB
jp sdcPutB
jp blkGetB
; interrupt hook
.fill 0x38-$
jp aciaInt
; *** cont. ***
jp stdioPutC
.inc "err.h"
.inc "ascii.h"
.inc "blkdev.h"
.inc "fs.h"
.inc "core.asm"
.inc "str.asm"
.equ ACIA_RAMSTART RAMSTART
.inc "acia.asm"
.equ BLOCKDEV_RAMSTART ACIA_RAMEND
.equ BLOCKDEV_COUNT 4
.inc "blockdev.asm"
; List of devices
.dw sdcGetB, sdcPutB
.dw blk1GetB, blk1PutB
.dw blk2GetB, blk2PutB
.dw mmapGetB, mmapPutB
.equ MMAP_START 0xe000
.inc "mmap.asm"
.equ STDIO_RAMSTART BLOCKDEV_RAMEND
.equ STDIO_GETC aciaGetC
.equ STDIO_PUTC aciaPutC
.inc "stdio.asm"
.equ FS_RAMSTART STDIO_RAMEND
.equ FS_HANDLE_COUNT 2
.inc "fs.asm"
; *** BASIC ***
; RAM space used in different routines for short term processing.
.equ SCRATCHPAD_SIZE STDIO_BUFSIZE
.equ SCRATCHPAD FS_RAMEND
.inc "lib/util.asm"
.inc "lib/ari.asm"
.inc "lib/parse.asm"
.inc "lib/fmt.asm"
.equ EXPR_PARSE parseLiteralOrVar
.inc "lib/expr.asm"
.inc "basic/util.asm"
.inc "basic/parse.asm"
.inc "basic/tok.asm"
.equ VAR_RAMSTART SCRATCHPAD+SCRATCHPAD_SIZE
.inc "basic/var.asm"
.equ BUF_RAMSTART VAR_RAMEND
.inc "basic/buf.asm"
.inc "basic/blk.asm"
.inc "basic/sdc.asm"
.equ BFS_RAMSTART BUF_RAMEND
.inc "basic/fs.asm"
.equ BAS_RAMSTART BFS_RAMEND
.inc "basic/main.asm"
.equ SDC_RAMSTART BAS_RAMEND
.equ SDC_PORT_CSHIGH 6
.equ SDC_PORT_CSLOW 5
.equ SDC_PORT_SPI 4
.inc "sdc.asm"
.out SDC_RAMEND
init:
di
ld sp, RAMEND
im 1
call aciaInit
call fsInit
call basInit
ld hl, basFindCmdExtra
ld (BAS_FINDHOOK), hl
xor a
ld de, BLOCKDEV_SEL
call blkSel
ei
jp basStart
basFindCmdExtra:
ld hl, basFSCmds
call basFindCmd
ret z
ld hl, basBLKCmds
call basFindCmd
ret z
ld hl, basSDCCmds
call basFindCmd
ret z
jp basPgmHook
; *** blkdev 1: file handle 0 ***
blk1GetB:
ld ix, FS_HANDLES
jp fsGetB
blk1PutB:
ld ix, FS_HANDLES
jp fsPutB
; *** blkdev 2: file handle 1 ***
blk2GetB:
ld ix, FS_HANDLES+FS_HANDLE_SIZE
jp fsGetB
blk2PutB:
ld ix, FS_HANDLES+FS_HANDLE_SIZE
jp fsPutB

View File

@ -1,23 +0,0 @@
.org 0x9b00
; *** JUMP TABLE ***
.equ strncmp 0x03
.equ upcase @+3
.equ findchar @+3
.equ blkSel @+3
.equ blkSet @+3
.equ fsFindFN @+3
.equ fsOpen @+3
.equ fsGetB @+3
.equ printstr @+3
.equ printcrlf @+3
.equ _blkGetB @+3
.equ _blkPutB @+3
.equ _blkSeek @+3
.equ _blkTell @+3
.equ sdcGetB @+3
.equ sdcPutB @+3
.equ blkGetB @+3
; *** cont. ***
.equ stdioPutC 0x3b

View File

@ -2,5 +2,5 @@ EMULDIR = ../emul
.PHONY: run .PHONY: run
run: run:
$(MAKE) -C $(EMULDIR) forth/forth $(MAKE) -C $(EMULDIR) all
cd forth && ./runtests.sh cd forth && ./runtests.sh

View File

@ -1,8 +1,7 @@
#!/bin/sh -e #!/bin/sh -e
BASE=../.. BASE=../..
EXEC="${BASE}/emul/forth/forth" EXEC="${BASE}/emul/forth"
FDIR="${BASE}/forth"
TMP=$(mktemp) TMP=$(mktemp)
chk() { chk() {

10
tests/forth/test_sdc.fs Normal file
View File

@ -0,0 +1,10 @@
212 LOAD ( z80a )
: SDC_SPI 4 ;
: SDC_CSLOW 5 ;
: SDC_CSHIGH 6 ;
372 LOAD ( sdc.z80 )
374 LOAD ( sdc.fs )
0x0000 0x0000 _crc16 0x0000 #eq
0x0000 0x0001 _crc16 0x1021 #eq
0x5678 0x1234 _crc16 0x43c4 #eq