mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-26 17:48:05 +11:00
Compare commits
No commits in common. "79527976abaefc8daee6f3715ea0d0bbe694b599" and "521ff84ca4b6d9dbe07b08716ec2cf763626cf6a" have entirely different histories.
79527976ab
...
521ff84ca4
@ -89,8 +89,6 @@ I' -- n Copy RS second item to PS
|
|||||||
J -- n Copy RS third item to PS
|
J -- n Copy RS third item to PS
|
||||||
|
|
||||||
*** Memory ***
|
*** Memory ***
|
||||||
(mmap*) -- a Address of active memory mapper. 0 for none. See
|
|
||||||
"Memory maps" in notes.txt.
|
|
||||||
@ a -- n Set n to value at address a
|
@ a -- n Set n to value at address a
|
||||||
! n a -- Store n in address a
|
! n a -- Store n in address a
|
||||||
? a -- Print value of addr a
|
? a -- Print value of addr a
|
||||||
|
6
emul/.gitignore
vendored
6
emul/.gitignore
vendored
@ -1,8 +1,14 @@
|
|||||||
|
/shell/shell
|
||||||
/forth/stage1
|
/forth/stage1
|
||||||
/forth/stage1dbg
|
/forth/stage1dbg
|
||||||
/forth/stage2
|
/forth/stage2
|
||||||
/forth/stage2dbg
|
/forth/stage2dbg
|
||||||
/forth/forth
|
/forth/forth
|
||||||
|
/zasm/zasm
|
||||||
|
/zasm/avra
|
||||||
/runbin/runbin
|
/runbin/runbin
|
||||||
/*/*-bin.h
|
/*/*-bin.h
|
||||||
/*/*.bin
|
/*/*.bin
|
||||||
|
/cfsin/zasm
|
||||||
|
/cfsin/ed
|
||||||
|
/cfsin/user.h
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
TARGETS = runbin/runbin forth/forth
|
TARGETS = runbin/runbin forth/forth
|
||||||
BIN2C = ../tools/bin2c
|
|
||||||
# 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 str.fs parse.fs readln.fs fmt.fs z80a.fs
|
FORTHSRCS = core.fs cmp.fs print.fs str.fs parse.fs readln.fs fmt.fs z80a.fs \
|
||||||
|
link.fs
|
||||||
FORTHSRC_PATHS = ${FORTHSRCS:%=../forth/%} forth/run.fs
|
FORTHSRC_PATHS = ${FORTHSRCS:%=../forth/%} forth/run.fs
|
||||||
OBJS = emul.o libz80/libz80.o
|
OBJS = emul.o libz80/libz80.o
|
||||||
SLATEST = ../tools/slatest
|
SLATEST = ../tools/slatest
|
||||||
@ -12,7 +12,6 @@ all: $(TARGETS)
|
|||||||
|
|
||||||
$(STRIPFC):
|
$(STRIPFC):
|
||||||
$(SLATEST):
|
$(SLATEST):
|
||||||
$(BIN2C):
|
|
||||||
$(MAKE) -C ../tools
|
$(MAKE) -C ../tools
|
||||||
|
|
||||||
# z80c.bin and boot.bin are not in the prerequisites because they're bootstrap
|
# z80c.bin and boot.bin are not in the prerequisites because they're bootstrap
|
||||||
@ -22,8 +21,8 @@ forth/forth0.bin: $(SLATEST)
|
|||||||
$(SLATEST) $@
|
$(SLATEST) $@
|
||||||
cat forth/emul.fs >> $@
|
cat forth/emul.fs >> $@
|
||||||
|
|
||||||
forth/forth0-bin.h: forth/forth0.bin $(BIN2C)
|
forth/forth0-bin.h: forth/forth0.bin
|
||||||
$(BIN2C) KERNEL < forth/forth0.bin | tee $@ > /dev/null
|
./bin2c.sh KERNEL < forth/forth0.bin | tee $@ > /dev/null
|
||||||
|
|
||||||
forth/stage1: forth/stage.c $(OBJS) forth/forth0-bin.h
|
forth/stage1: forth/stage.c $(OBJS) forth/forth0-bin.h
|
||||||
$(CC) forth/stage.c $(OBJS) -o $@
|
$(CC) forth/stage.c $(OBJS) -o $@
|
||||||
@ -40,8 +39,8 @@ forth/forth1.bin: forth/core.bin $(SLATEST)
|
|||||||
cat forth/boot.bin forth/z80c.bin forth/core.bin > $@
|
cat forth/boot.bin forth/z80c.bin forth/core.bin > $@
|
||||||
$(SLATEST) $@
|
$(SLATEST) $@
|
||||||
|
|
||||||
forth/forth1-bin.h: forth/forth1.bin $(BIN2C)
|
forth/forth1-bin.h: forth/forth1.bin
|
||||||
$(BIN2C) KERNEL < forth/forth1.bin | tee $@ > /dev/null
|
./bin2c.sh KERNEL < forth/forth1.bin | tee $@ > /dev/null
|
||||||
|
|
||||||
forth/stage2: forth/stage.c $(OBJS) forth/forth1-bin.h
|
forth/stage2: forth/stage.c $(OBJS) forth/forth1-bin.h
|
||||||
$(CC) -DSTAGE2 forth/stage.c $(OBJS) -o $@
|
$(CC) -DSTAGE2 forth/stage.c $(OBJS) -o $@
|
||||||
@ -68,4 +67,3 @@ updatebootstrap: forth/stage2
|
|||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
rm -f $(TARGETS) emul.o forth/*-bin.h forth/forth?.bin
|
rm -f $(TARGETS) emul.o forth/*-bin.h forth/forth?.bin
|
||||||
$(MAKE) -C ../tools clean
|
|
||||||
|
5
emul/bin2c.sh
Executable file
5
emul/bin2c.sh
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "unsigned char $1[] = { "
|
||||||
|
xxd -i -
|
||||||
|
echo " };"
|
Binary file not shown.
@ -1,18 +0,0 @@
|
|||||||
( Get word header length from wordref. That is, name length
|
|
||||||
+ 3. a is a wordref )
|
|
||||||
( a -- n )
|
|
||||||
: WHLEN
|
|
||||||
1 - C@ ( name len field )
|
|
||||||
0x7f AND ( remove IMMEDIATE flag )
|
|
||||||
3 + ( fixed header len )
|
|
||||||
;
|
|
||||||
|
|
||||||
( Get word addr, starting at name's address )
|
|
||||||
: '< ' DUP WHLEN - ;
|
|
||||||
|
|
||||||
( Get word's prev offset )
|
|
||||||
( a -- a )
|
|
||||||
: PREV
|
|
||||||
3 - DUP @ ( a o )
|
|
||||||
- ( a-o )
|
|
||||||
;
|
|
@ -67,23 +67,6 @@
|
|||||||
: (parse*) 0x0a _c RAM+ ;
|
: (parse*) 0x0a _c RAM+ ;
|
||||||
: HERE 0x04 _c RAM+ ;
|
: HERE 0x04 _c RAM+ ;
|
||||||
: CURRENT 0x02 _c RAM+ ;
|
: CURRENT 0x02 _c RAM+ ;
|
||||||
: (mmap*) 0x51 _c RAM+ ;
|
|
||||||
|
|
||||||
( The goal here is to be as fast as possible *when there is
|
|
||||||
no mmap*, which is the most frequent situation. That is why
|
|
||||||
we don't DUP and we rather refetch. That is also why we
|
|
||||||
use direct literal instead of RAM+ or (mmap*). )
|
|
||||||
: (mmap)
|
|
||||||
[ RAMSTART 0x51 + LITN ] _c _@
|
|
||||||
IF
|
|
||||||
[ RAMSTART 0x51 + LITN ] _c _@ EXECUTE
|
|
||||||
THEN
|
|
||||||
;
|
|
||||||
|
|
||||||
: @ _c (mmap) _c _@ ;
|
|
||||||
: C@ _c (mmap) _c _C@ ;
|
|
||||||
: ! _c (mmap) _c _! ;
|
|
||||||
: C! _c (mmap) _c _C! ;
|
|
||||||
|
|
||||||
: QUIT
|
: QUIT
|
||||||
0 _c FLAGS _c ! _c (resRS)
|
0 _c FLAGS _c ! _c (resRS)
|
||||||
@ -221,7 +204,6 @@
|
|||||||
;
|
;
|
||||||
|
|
||||||
: BOOT
|
: BOOT
|
||||||
0 0x51 _c RAM+ _c _!
|
|
||||||
LIT< (parse) _c (find) _c DROP _c (parse*) _c !
|
LIT< (parse) _c (find) _c DROP _c (parse*) _c !
|
||||||
( 60 == SYSTEM SCRATCHPAD )
|
( 60 == SYSTEM SCRATCHPAD )
|
||||||
_c CURRENT _c @ 0x60 _c RAM+ _c !
|
_c CURRENT _c @ 0x60 _c RAM+ _c !
|
||||||
@ -251,7 +233,7 @@
|
|||||||
( We cannot use LITN as IMMEDIATE because of bootstrapping
|
( We cannot use LITN as IMMEDIATE because of bootstrapping
|
||||||
issues. Same thing for ",".
|
issues. Same thing for ",".
|
||||||
32 == NUMBER 14 == compiledWord )
|
32 == NUMBER 14 == compiledWord )
|
||||||
[ 32 H@ _! 2 ALLOT 14 H@ _! 2 ALLOT ] _c ,
|
[ 32 H@ ! 2 ALLOT 14 H@ ! 2 ALLOT ] _c ,
|
||||||
BEGIN
|
BEGIN
|
||||||
_c WORD
|
_c WORD
|
||||||
_c (find)
|
_c (find)
|
||||||
@ -268,10 +250,10 @@
|
|||||||
;
|
;
|
||||||
|
|
||||||
( Give ":" and ";" their real name and make them IMMEDIATE )
|
( Give ":" and ";" their real name and make them IMMEDIATE )
|
||||||
0x81 ' X 1 - _C!
|
0x81 ' X 1 - C!
|
||||||
':' ' X 4 - _C!
|
':' ' X 4 - C!
|
||||||
0x81 ' Y 1 - _C!
|
0x81 ' Y 1 - C!
|
||||||
';' ' Y 4 - _C!
|
';' ' Y 4 - C!
|
||||||
|
|
||||||
( Add dummy entry. we use CREATE because (entry) is, at this
|
( Add dummy entry. we use CREATE because (entry) is, at this
|
||||||
point, broken. Adjust H@ durint port 2 ping. )
|
point, broken. Adjust H@ durint port 2 ping. )
|
||||||
|
162
forth/link.fs
Normal file
162
forth/link.fs
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
( depends: cmp, parse
|
||||||
|
Relink a dictionary by applying offsets to all word
|
||||||
|
references in words of the "compiled" type.
|
||||||
|
|
||||||
|
A typical usage of this unit would be to, right after a
|
||||||
|
bootstrap-from-icore-from-source operation, identify the
|
||||||
|
root word of the source part, probably "H@", and run
|
||||||
|
" ' thatword COMPACT ". Then, take the resulting relinked
|
||||||
|
binary, concatenate it to the boot binary, and write to
|
||||||
|
boot media.
|
||||||
|
)
|
||||||
|
|
||||||
|
( Skip atom, considering special atom types. )
|
||||||
|
( a -- a+n )
|
||||||
|
: ASKIP
|
||||||
|
DUP @ ( a n )
|
||||||
|
( ?br or br or NUMBER )
|
||||||
|
DUP <>{ 0x70 &= 0x58 |= 0x20 |= <>}
|
||||||
|
IF DROP 4 + EXIT THEN
|
||||||
|
( regular word )
|
||||||
|
0x22 = NOT IF 2 + EXIT THEN
|
||||||
|
( it's a lit, skip to null char )
|
||||||
|
( a )
|
||||||
|
1 + ( we skip by 2, but the loop below is pre-inc... )
|
||||||
|
BEGIN 1 + DUP C@ NOT UNTIL
|
||||||
|
( skip null char )
|
||||||
|
1 +
|
||||||
|
;
|
||||||
|
|
||||||
|
( Get word header length from wordref. That is, name length
|
||||||
|
+ 3. a is a wordref )
|
||||||
|
( a -- n )
|
||||||
|
: WHLEN
|
||||||
|
1 - C@ ( name len field )
|
||||||
|
0x7f AND ( remove IMMEDIATE flag )
|
||||||
|
3 + ( fixed header len )
|
||||||
|
;
|
||||||
|
|
||||||
|
( Get word addr, starting at name's address )
|
||||||
|
: '< ' DUP WHLEN - ;
|
||||||
|
|
||||||
|
( Relink atom at a, applying offset o with limit ol.
|
||||||
|
Returns a, appropriately skipped.
|
||||||
|
)
|
||||||
|
( a o ol -- a+n )
|
||||||
|
: RLATOM
|
||||||
|
ROT ( o ol a )
|
||||||
|
DUP @ ( o ol a n )
|
||||||
|
ROT ( o a n ol )
|
||||||
|
< IF ( under limit, do nothing )
|
||||||
|
SWAP DROP ( a )
|
||||||
|
ELSE
|
||||||
|
( o a )
|
||||||
|
SWAP OVER @ ( a o n )
|
||||||
|
-^ ( a n-o )
|
||||||
|
OVER ! ( a )
|
||||||
|
THEN
|
||||||
|
ASKIP
|
||||||
|
;
|
||||||
|
|
||||||
|
( Relink a word with specified offset. If it's not of the type
|
||||||
|
"compiled word", ignore. If it is, advance in word until a2
|
||||||
|
is met, and for each word that is above ol, reduce that
|
||||||
|
reference by o.
|
||||||
|
Arguments: a1: wordref a2: word end addr o: offset to apply
|
||||||
|
ol: offset limit. don't apply on refs under it.
|
||||||
|
)
|
||||||
|
( ol o a1 a2 -- )
|
||||||
|
: RLWORD
|
||||||
|
SWAP DUP @ ( ol o a2 a1 n )
|
||||||
|
( 0e == compiledWord )
|
||||||
|
0x0e = NOT IF
|
||||||
|
( unwind all args )
|
||||||
|
2DROP 2DROP
|
||||||
|
EXIT
|
||||||
|
THEN
|
||||||
|
( we have a compiled word, proceed )
|
||||||
|
( ol o a2 a1 )
|
||||||
|
2 + ( ol o a2 a1+2 )
|
||||||
|
BEGIN ( ol o a2 a1 )
|
||||||
|
2OVER ( ol o a2 a1 ol o )
|
||||||
|
SWAP ( ol o a2 a1 o ol )
|
||||||
|
RLATOM ( ol o a2 a+n )
|
||||||
|
2DUP < IF ABORT THEN ( Something is very wrong )
|
||||||
|
2DUP = ( ol o a2 a+n f )
|
||||||
|
IF
|
||||||
|
( unwind )
|
||||||
|
2DROP 2DROP
|
||||||
|
EXIT
|
||||||
|
THEN
|
||||||
|
AGAIN
|
||||||
|
;
|
||||||
|
|
||||||
|
( Get word's prev offset )
|
||||||
|
( a -- a )
|
||||||
|
: PREV
|
||||||
|
3 - DUP @ ( a o )
|
||||||
|
- ( a-o )
|
||||||
|
;
|
||||||
|
|
||||||
|
( Copy dict from target wordref, including header, up to HERE.
|
||||||
|
We're going to compact the space between that word and its
|
||||||
|
prev word. To do this, we're copying this whole memory area
|
||||||
|
in HERE and then iterate through that copied area and call
|
||||||
|
RLWORD on each word. That results in a dict that can be
|
||||||
|
concatenated to target's prev entry in a more compact way.
|
||||||
|
|
||||||
|
This copy of data doesn't allocate anything, so H@ doesn't
|
||||||
|
move. Moreover, we reserve 4 bytes at H@ to write our target
|
||||||
|
and offset because otherwise, things get too complicated
|
||||||
|
with the PSP.
|
||||||
|
|
||||||
|
This word prints the top copied address, so when comes the
|
||||||
|
time to concat boot binary with this relinked dict, you
|
||||||
|
can use H@+4 to printed addr.
|
||||||
|
)
|
||||||
|
( target -- )
|
||||||
|
: COMPACT
|
||||||
|
( First of all, let's get our offset. It's easy, it's
|
||||||
|
target's prev field, which is already an offset, minus
|
||||||
|
its name length. We expect, in COMPACT, that a target's
|
||||||
|
prev word is a "hook word", that is, an empty word. )
|
||||||
|
( H@ == target )
|
||||||
|
DUP H@ !
|
||||||
|
DUP 1 - C@ 0x7f AND ( t namelen )
|
||||||
|
SWAP 3 - @ ( namelen po )
|
||||||
|
-^ ( o )
|
||||||
|
( H@+2 == offset )
|
||||||
|
H@ 2 + ! ( )
|
||||||
|
( We have our offset, now let's copy our memory chunk )
|
||||||
|
H@ @ DUP WHLEN - ( src )
|
||||||
|
DUP H@ -^ ( src u )
|
||||||
|
DUP ROT SWAP ( u src u )
|
||||||
|
H@ 4 + ( u src u dst )
|
||||||
|
SWAP ( u src dst u )
|
||||||
|
MOVE ( u )
|
||||||
|
( Now, let's iterate that dict down )
|
||||||
|
( wr == wordref we == word end )
|
||||||
|
( To get our wr and we, we use H@ and CURRENT, which we
|
||||||
|
offset by u+4. +4 before, remember, we're using 4 bytes
|
||||||
|
as variable space. )
|
||||||
|
4 + ( u+4 )
|
||||||
|
DUP H@ + ( u we )
|
||||||
|
DUP .X LF
|
||||||
|
SWAP CURRENT @ + ( we wr )
|
||||||
|
BEGIN ( we wr )
|
||||||
|
DUP ROT ( wr wr we )
|
||||||
|
( call RLWORD. we need a sig: ol o wr we )
|
||||||
|
H@ @ ( wr wr we ol )
|
||||||
|
H@ 2 + @ ( wr wr we ol o )
|
||||||
|
2SWAP ( wr ol o wr we )
|
||||||
|
RLWORD ( wr )
|
||||||
|
( wr becomes wr's prev and we is wr-header )
|
||||||
|
DUP ( wr wr )
|
||||||
|
PREV ( oldwr newwr )
|
||||||
|
SWAP ( wr oldwr )
|
||||||
|
DUP WHLEN - ( wr we )
|
||||||
|
SWAP ( we wr )
|
||||||
|
( Are we finished? We're finished if wr-4 <= H@ )
|
||||||
|
DUP 4 - H@ <=
|
||||||
|
UNTIL
|
||||||
|
;
|
@ -232,7 +232,7 @@ L2 FSET ( skip )
|
|||||||
BC PUSHqq,
|
BC PUSHqq,
|
||||||
;CODE
|
;CODE
|
||||||
|
|
||||||
CODE _!
|
CODE !
|
||||||
HL POPqq,
|
HL POPqq,
|
||||||
DE POPqq,
|
DE POPqq,
|
||||||
chkPS,
|
chkPS,
|
||||||
@ -241,7 +241,7 @@ CODE _!
|
|||||||
(HL) D LDrr,
|
(HL) D LDrr,
|
||||||
;CODE
|
;CODE
|
||||||
|
|
||||||
CODE _@
|
CODE @
|
||||||
HL POPqq,
|
HL POPqq,
|
||||||
chkPS,
|
chkPS,
|
||||||
E (HL) LDrr,
|
E (HL) LDrr,
|
||||||
@ -250,14 +250,14 @@ CODE _@
|
|||||||
DE PUSHqq,
|
DE PUSHqq,
|
||||||
;CODE
|
;CODE
|
||||||
|
|
||||||
CODE _C!
|
CODE C!
|
||||||
HL POPqq,
|
HL POPqq,
|
||||||
DE POPqq,
|
DE POPqq,
|
||||||
chkPS,
|
chkPS,
|
||||||
(HL) E LDrr,
|
(HL) E LDrr,
|
||||||
;CODE
|
;CODE
|
||||||
|
|
||||||
CODE _C@
|
CODE C@
|
||||||
HL POPqq,
|
HL POPqq,
|
||||||
chkPS,
|
chkPS,
|
||||||
L (HL) LDrr,
|
L (HL) LDrr,
|
||||||
|
32
notes.txt
32
notes.txt
@ -88,8 +88,7 @@ RAMSTART INITIAL_SP
|
|||||||
+0e WORDBUF
|
+0e WORDBUF
|
||||||
+2e SYSVNXT
|
+2e SYSVNXT
|
||||||
+4e INTJUMP
|
+4e INTJUMP
|
||||||
+51 MMAPPTR
|
+51 RESERVED
|
||||||
+53 RESERVED
|
|
||||||
+60 SYSTEM SCRATCHPAD
|
+60 SYSTEM SCRATCHPAD
|
||||||
+80 RAMEND
|
+80 RAMEND
|
||||||
|
|
||||||
@ -117,9 +116,6 @@ those slots...) in boot binaries are made to jump to this address. If you use
|
|||||||
one of those slots for an interrupt, write a jump to the appropriate offset in
|
one of those slots for an interrupt, write a jump to the appropriate offset in
|
||||||
that RAM location.
|
that RAM location.
|
||||||
|
|
||||||
MMAPPTR: Address behind (mmap), which is called before every !/C!/@/C@ world
|
|
||||||
to give the opportunity to change the address of the call.
|
|
||||||
|
|
||||||
SYSTEM SCRATCHPAD is reserved for temporary system storage or can be reserved
|
SYSTEM SCRATCHPAD is reserved for temporary system storage or can be reserved
|
||||||
by low-level drivers. These are the current usages of this space throughout the
|
by low-level drivers. These are the current usages of this space throughout the
|
||||||
project:
|
project:
|
||||||
@ -158,29 +154,3 @@ can't have comments. This leads to peculiar code in this area. If you see weird
|
|||||||
whitespace usage, it's probably because not using those whitespace would result
|
whitespace usage, it's probably because not using those whitespace would result
|
||||||
in dict entry creation overwriting the code before it has the chance to be
|
in dict entry creation overwriting the code before it has the chance to be
|
||||||
interpreted.
|
interpreted.
|
||||||
|
|
||||||
*** Memory maps
|
|
||||||
|
|
||||||
We have a mechanism to map memory ranges to something else. We call this memory
|
|
||||||
maps. There is a reserved address in memory for a memory mapping routine. The
|
|
||||||
word (mmap*) returns that address. By default, it's zero which means no mapping.
|
|
||||||
|
|
||||||
Each call to @, C@, ! or C! call that word, if nonzero, before executing. This
|
|
||||||
allows you to do pretty much anything. Try to be efficient in your programming,
|
|
||||||
however, because those words are called *very* often.
|
|
||||||
|
|
||||||
Here's a toy example of memory map usage:
|
|
||||||
|
|
||||||
> 8 0x8000 DUMP
|
|
||||||
:00 0000 0000 0000 0000 ........
|
|
||||||
> : foo DUP 0x8000 = IF 2 + THEN ;
|
|
||||||
> ' foo (mmap*) !
|
|
||||||
> 8 0x8000 DUMP
|
|
||||||
:00 0000 0000 0000 0000 ........
|
|
||||||
> 0x1234 0x8000 !
|
|
||||||
> 8 0x8000 DUMP
|
|
||||||
:00 3412 3412 0000 0000 4.4.....
|
|
||||||
> 0 (mmap*) !
|
|
||||||
> 8 0x8000 DUMP
|
|
||||||
:00 0000 3412 0000 0000 ..4.....
|
|
||||||
>
|
|
||||||
|
@ -6,7 +6,6 @@ STAGE2 = $(EDIR)/stage2
|
|||||||
EMUL = $(BASEDIR)/emul/hw/rc2014/classic
|
EMUL = $(BASEDIR)/emul/hw/rc2014/classic
|
||||||
PATHS = pre.fs \
|
PATHS = pre.fs \
|
||||||
$(FDIR)/core.fs \
|
$(FDIR)/core.fs \
|
||||||
$(FDIR)/cmp.fs \
|
|
||||||
$(FDIR)/str.fs \
|
$(FDIR)/str.fs \
|
||||||
$(FDIR)/parse.fs \
|
$(FDIR)/parse.fs \
|
||||||
$(BASEDIR)/drv/acia.fs \
|
$(BASEDIR)/drv/acia.fs \
|
||||||
|
@ -108,135 +108,11 @@ Once bootstrapping is done you should see the Collapse OS prompt. That's a full
|
|||||||
Forth interpreter. You can have fun right now.
|
Forth interpreter. You can have fun right now.
|
||||||
|
|
||||||
However, that long boot time is kinda annoying. Moreover, that bootstrap code
|
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
|
being in source form takes precious space from our 8K ROM. We already have our
|
||||||
building stage 2.
|
compiled dictionary in memory. All we need to have a instant-booting Forth is
|
||||||
|
to combine our stage1 with our compiled dict in memory, after some relinking.
|
||||||
|
|
||||||
### Building stage 2
|
TODO: write this, do this.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
We can't simply adjust offsets. For complicated reasons, that can't be reliably
|
|
||||||
done. We have to re-interpret that same source code, but from a ROM offset. But
|
|
||||||
how are we going to do that? After all, ROM is called ROM for a reason.
|
|
||||||
|
|
||||||
Memory maps.
|
|
||||||
|
|
||||||
What we're going to do is to set up a memory map targeting our ROM and point it
|
|
||||||
to our RAM. Then we can recompile the source as if we were in ROM, right after
|
|
||||||
our boot binary. Forth won't ever notice it's actually in RAM.
|
|
||||||
|
|
||||||
Alright, let's do this. First, let's have a look around. Where is the end of
|
|
||||||
our boot binary? To know, find the word ";", which is the last word of icore:
|
|
||||||
|
|
||||||
> ' ; .X
|
|
||||||
097d>
|
|
||||||
> 64 0x0970 DUMP
|
|
||||||
:70 0035 0958 00da ff43 .5.X...C
|
|
||||||
:78 003b 3500 810e 0020 .;5....
|
|
||||||
:80 0043 0093 07f4 03ef .C......
|
|
||||||
:88 0143 005f 0f00 0131 .C._...1
|
|
||||||
:90 3132 2052 414d 2b20 12 RAM+
|
|
||||||
:98 4845 5245 2021 0a20 HERE !.
|
|
||||||
:a0 3a20 4840 2048 4552 : H@ HER
|
|
||||||
:a8 4520 4020 3b0a 203a E @ ;. :
|
|
||||||
|
|
||||||
See that `_` at 0x98b? That's the name of our hook word. 4 bytes later is its
|
|
||||||
wordref. That's the end of our boot binary. 0x98f, that's an address to write
|
|
||||||
down.
|
|
||||||
|
|
||||||
Right after that is our appended source code. The first part is `pre.fs` and
|
|
||||||
can be ignored. What we want starts at the definition of the `H@` word, which
|
|
||||||
is at 0x9a0. Another address to write down.
|
|
||||||
|
|
||||||
So our memory map will target 0x98f. Where will we place it? It doesn't matter
|
|
||||||
much, we have plenty of RAM. Where's `HERE`?
|
|
||||||
|
|
||||||
> H@ .X
|
|
||||||
8c3f>
|
|
||||||
|
|
||||||
Alright, let's go wide and use 0xa000 as our map destination. But before we do,
|
|
||||||
let's copy the content of our ROM into RAM because there's our source code
|
|
||||||
there and if we don't copy it before setting up the memory map, we'll shadow it.
|
|
||||||
|
|
||||||
Let's be lazy and don't even check where the source stop. Let's assume it stops
|
|
||||||
at 0x1fff, the end of the ROM.
|
|
||||||
|
|
||||||
> 0x98f 0xa000 0x2000 0x98f - MOVE
|
|
||||||
> 64 0xa000 DUMP
|
|
||||||
:00 3131 3220 5241 4d2b 112 RAM+
|
|
||||||
:08 2048 4552 4520 210a HERE !.
|
|
||||||
:10 203a 2048 4020 4845 : H@ HE
|
|
||||||
:18 5245 2040 203b 0a20 RE @ ;.
|
|
||||||
:20 3a20 2d5e 2053 5741 : -^ SWA
|
|
||||||
:28 5020 2d20 3b0a 203a P - ;. :
|
|
||||||
:30 205b 2049 4e54 4552 [ INTER
|
|
||||||
:38 5052 4554 2031 2046 PRET 1 F
|
|
||||||
|
|
||||||
Looks fine. Now, let's create a memory map. A memory map word is rather simple.
|
|
||||||
It is called before each `@/C@/!/C!` operation and is given the opportunity to
|
|
||||||
tweak the address on PSP's TOS. Let's go with our map:
|
|
||||||
|
|
||||||
> : MMAP
|
|
||||||
DUP 0x98f < IF EXIT THEN
|
|
||||||
DUP 0x1fff > IF EXIT THEN
|
|
||||||
[ 0xa000 0x98f - LITN ] +
|
|
||||||
;
|
|
||||||
> 0x98e MMAP .X
|
|
||||||
098e> 0x98f MMAP .X
|
|
||||||
a000> 0xabc MMAP .X
|
|
||||||
a12b> 0x1fff MMAP .X
|
|
||||||
b66e> 0x2000 MMAP .X
|
|
||||||
2000>
|
|
||||||
|
|
||||||
This looks good. Let's apply it for real:
|
|
||||||
|
|
||||||
> ' MMAP (mmap*) !
|
|
||||||
> 64 0x980 DUMP
|
|
||||||
|
|
||||||
:80 0043 0093 07f4 03ef .C......
|
|
||||||
:88 0143 005f 0f00 0131 .C._...1
|
|
||||||
:90 3132 2052 414d 2b20 12 RAM+
|
|
||||||
:98 4845 5245 2021 0a20 HERE !.
|
|
||||||
:a0 3a20 4840 2048 4552 : H@ HER
|
|
||||||
:a8 4520 4020 3b0a 203a E @ ;. :
|
|
||||||
:b0 202d 5e20 5357 4150 -^ SWAP
|
|
||||||
:b8 202d 203b 0a20 3a20 - ;. :
|
|
||||||
|
|
||||||
But how do we know that it really works? Because we can write in ROM!
|
|
||||||
|
|
||||||
> 'X' 0x98f !
|
|
||||||
> 64 0x980 DUMP
|
|
||||||
|
|
||||||
:80 0043 0093 07f4 03ef .C......
|
|
||||||
:88 0143 005f 0f00 0131 .C._...X
|
|
||||||
:90 0032 2052 414d 2b20 .2 RAM+
|
|
||||||
:98 4845 5245 2021 0a20 HERE !.
|
|
||||||
:a0 3a20 4840 2048 4552 : H@ HER
|
|
||||||
:a8 4520 4020 3b0a 203a E @ ;. :
|
|
||||||
:b0 202d 5e20 5357 4150 -^ SWAP
|
|
||||||
:b8 202d 203b 0a20 3a20 - ;. :
|
|
||||||
> 64 0xa000 DUMP
|
|
||||||
|
|
||||||
:00 5800 3220 5241 4d2b X.2 RAM+
|
|
||||||
:08 2048 4552 4520 210a HERE !.
|
|
||||||
:10 203a 2048 4020 4845 : H@ HE
|
|
||||||
:18 5245 2040 203b 0a20 RE @ ;.
|
|
||||||
:20 3a20 2d5e 2053 5741 : -^ SWA
|
|
||||||
:28 5020 2d20 3b0a 203a P - ;. :
|
|
||||||
:30 205b 2049 4e54 4552 [ INTER
|
|
||||||
:38 5052 4554 2031 2046 PRET 1 F
|
|
||||||
|
|
||||||
TODO: continue
|
|
||||||
|
|
||||||
[rc2014]: https://rc2014.co.uk
|
[rc2014]: https://rc2014.co.uk
|
||||||
[romwrite]: https://github.com/hsoft/romwrite
|
[romwrite]: https://github.com/hsoft/romwrite
|
||||||
|
@ -1 +1 @@
|
|||||||
112 RAM+ HERE !
|
96 RAM+ HERE !
|
||||||
|
1
tools/.gitignore
vendored
1
tools/.gitignore
vendored
@ -6,4 +6,3 @@
|
|||||||
/pingpong
|
/pingpong
|
||||||
/slatest
|
/slatest
|
||||||
/stripfc
|
/stripfc
|
||||||
/bin2c
|
|
||||||
|
@ -6,10 +6,8 @@ TTYSAFE_TGT = ttysafe
|
|||||||
PINGPONG_TGT = pingpong
|
PINGPONG_TGT = pingpong
|
||||||
SLATEST_TGT = slatest
|
SLATEST_TGT = slatest
|
||||||
STRIPFC_TGT = stripfc
|
STRIPFC_TGT = stripfc
|
||||||
BIN2C_TGT = bin2c
|
|
||||||
TARGETS = $(MEMDUMP_TGT) $(BLKDUMP_TGT) $(UPLOAD_TGT) $(FONTCOMPILE_TGT) \
|
TARGETS = $(MEMDUMP_TGT) $(BLKDUMP_TGT) $(UPLOAD_TGT) $(FONTCOMPILE_TGT) \
|
||||||
$(TTYSAFE_TGT) $(PINGPONG_TGT) $(SLATEST_TGT) $(STRIPFC_TGT) \
|
$(TTYSAFE_TGT) $(PINGPONG_TGT) $(SLATEST_TGT) $(STRIPFC_TGT)
|
||||||
$(BIN2C_TGT)
|
|
||||||
OBJS = common.o
|
OBJS = common.o
|
||||||
|
|
||||||
all: $(TARGETS)
|
all: $(TARGETS)
|
||||||
@ -26,7 +24,6 @@ $(TTYSAFE_TGT): $(TTYSAFE_TGT).c
|
|||||||
$(PINGPONG_TGT): $(PINGPONG_TGT).c
|
$(PINGPONG_TGT): $(PINGPONG_TGT).c
|
||||||
$(SLATEST_TGT): $(SLATEST_TGT).c
|
$(SLATEST_TGT): $(SLATEST_TGT).c
|
||||||
$(STRIPFC_TGT): $(STRIPFC_TGT).c
|
$(STRIPFC_TGT): $(STRIPFC_TGT).c
|
||||||
$(BIN2C_TGT): $(BIN2C_TGT).c
|
|
||||||
$(TARGETS): $(OBJS)
|
$(TARGETS): $(OBJS)
|
||||||
$(CC) $(CFLAGS) $@.c $(OBJS) -o $@
|
$(CC) $(CFLAGS) $@.c $(OBJS) -o $@
|
||||||
|
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020 Byron Grobe
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define BUFSZ 32
|
|
||||||
|
|
||||||
static const char intro[] = "static const unsigned char %s[] = {\n ";
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
int n;
|
|
||||||
int col = 0;
|
|
||||||
uint8_t buf[BUFSZ];
|
|
||||||
|
|
||||||
if (argc < 2) {
|
|
||||||
fprintf(stderr, "Specify a name for the data structure...\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf(intro, argv[1]);
|
|
||||||
|
|
||||||
while(!feof(stdin)) {
|
|
||||||
n = fread(buf, 1, BUFSZ, stdin);
|
|
||||||
for(int i = 0; i < n; ++i) {
|
|
||||||
if (col+4 >= 76) {
|
|
||||||
printf("\n ");
|
|
||||||
col = 0;
|
|
||||||
}
|
|
||||||
printf("0x%.2x, ", buf[i]);
|
|
||||||
col += 6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("};\n");
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user