mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-02 10:30:55 +11:00
Compare commits
7 Commits
521ff84ca4
...
79527976ab
Author | SHA1 | Date | |
---|---|---|---|
|
79527976ab | ||
|
6652125d47 | ||
|
ba918d0fef | ||
|
d4324292fb | ||
|
e37f4c2551 | ||
|
217df20d77 | ||
|
f65c189e9b |
@ -89,6 +89,8 @@ I' -- n Copy RS second item to PS
|
||||
J -- n Copy RS third item to PS
|
||||
|
||||
*** 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
|
||||
! n a -- Store n in address a
|
||||
? a -- Print value of addr a
|
||||
|
6
emul/.gitignore
vendored
6
emul/.gitignore
vendored
@ -1,14 +1,8 @@
|
||||
/shell/shell
|
||||
/forth/stage1
|
||||
/forth/stage1dbg
|
||||
/forth/stage2
|
||||
/forth/stage2dbg
|
||||
/forth/forth
|
||||
/zasm/zasm
|
||||
/zasm/avra
|
||||
/runbin/runbin
|
||||
/*/*-bin.h
|
||||
/*/*.bin
|
||||
/cfsin/zasm
|
||||
/cfsin/ed
|
||||
/cfsin/user.h
|
||||
|
@ -1,7 +1,7 @@
|
||||
TARGETS = runbin/runbin forth/forth
|
||||
BIN2C = ../tools/bin2c
|
||||
# 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 \
|
||||
link.fs
|
||||
FORTHSRCS = core.fs cmp.fs print.fs str.fs parse.fs readln.fs fmt.fs z80a.fs
|
||||
FORTHSRC_PATHS = ${FORTHSRCS:%=../forth/%} forth/run.fs
|
||||
OBJS = emul.o libz80/libz80.o
|
||||
SLATEST = ../tools/slatest
|
||||
@ -12,6 +12,7 @@ all: $(TARGETS)
|
||||
|
||||
$(STRIPFC):
|
||||
$(SLATEST):
|
||||
$(BIN2C):
|
||||
$(MAKE) -C ../tools
|
||||
|
||||
# z80c.bin and boot.bin are not in the prerequisites because they're bootstrap
|
||||
@ -21,8 +22,8 @@ forth/forth0.bin: $(SLATEST)
|
||||
$(SLATEST) $@
|
||||
cat forth/emul.fs >> $@
|
||||
|
||||
forth/forth0-bin.h: forth/forth0.bin
|
||||
./bin2c.sh KERNEL < forth/forth0.bin | tee $@ > /dev/null
|
||||
forth/forth0-bin.h: forth/forth0.bin $(BIN2C)
|
||||
$(BIN2C) KERNEL < forth/forth0.bin | tee $@ > /dev/null
|
||||
|
||||
forth/stage1: forth/stage.c $(OBJS) forth/forth0-bin.h
|
||||
$(CC) forth/stage.c $(OBJS) -o $@
|
||||
@ -39,8 +40,8 @@ forth/forth1.bin: forth/core.bin $(SLATEST)
|
||||
cat forth/boot.bin forth/z80c.bin forth/core.bin > $@
|
||||
$(SLATEST) $@
|
||||
|
||||
forth/forth1-bin.h: forth/forth1.bin
|
||||
./bin2c.sh KERNEL < forth/forth1.bin | tee $@ > /dev/null
|
||||
forth/forth1-bin.h: forth/forth1.bin $(BIN2C)
|
||||
$(BIN2C) KERNEL < forth/forth1.bin | tee $@ > /dev/null
|
||||
|
||||
forth/stage2: forth/stage.c $(OBJS) forth/forth1-bin.h
|
||||
$(CC) -DSTAGE2 forth/stage.c $(OBJS) -o $@
|
||||
@ -67,3 +68,4 @@ updatebootstrap: forth/stage2
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(TARGETS) emul.o forth/*-bin.h forth/forth?.bin
|
||||
$(MAKE) -C ../tools clean
|
||||
|
@ -1,5 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "unsigned char $1[] = { "
|
||||
xxd -i -
|
||||
echo " };"
|
Binary file not shown.
18
forth/dict.fs
Normal file
18
forth/dict.fs
Normal file
@ -0,0 +1,18 @@
|
||||
( 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,6 +67,23 @@
|
||||
: (parse*) 0x0a _c RAM+ ;
|
||||
: HERE 0x04 _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
|
||||
0 _c FLAGS _c ! _c (resRS)
|
||||
@ -204,6 +221,7 @@
|
||||
;
|
||||
|
||||
: BOOT
|
||||
0 0x51 _c RAM+ _c _!
|
||||
LIT< (parse) _c (find) _c DROP _c (parse*) _c !
|
||||
( 60 == SYSTEM SCRATCHPAD )
|
||||
_c CURRENT _c @ 0x60 _c RAM+ _c !
|
||||
@ -233,7 +251,7 @@
|
||||
( 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 ,
|
||||
[ 32 H@ _! 2 ALLOT 14 H@ _! 2 ALLOT ] _c ,
|
||||
BEGIN
|
||||
_c WORD
|
||||
_c (find)
|
||||
@ -250,10 +268,10 @@
|
||||
;
|
||||
|
||||
( Give ":" and ";" their real name and make them IMMEDIATE )
|
||||
0x81 ' X 1 - C!
|
||||
':' ' X 4 - C!
|
||||
0x81 ' Y 1 - C!
|
||||
';' ' Y 4 - C!
|
||||
0x81 ' X 1 - _C!
|
||||
':' ' X 4 - _C!
|
||||
0x81 ' Y 1 - _C!
|
||||
';' ' Y 4 - _C!
|
||||
|
||||
( Add dummy entry. we use CREATE because (entry) is, at this
|
||||
point, broken. Adjust H@ durint port 2 ping. )
|
||||
|
162
forth/link.fs
162
forth/link.fs
@ -1,162 +0,0 @@
|
||||
( 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,
|
||||
;CODE
|
||||
|
||||
CODE !
|
||||
CODE _!
|
||||
HL POPqq,
|
||||
DE POPqq,
|
||||
chkPS,
|
||||
@ -241,7 +241,7 @@ CODE !
|
||||
(HL) D LDrr,
|
||||
;CODE
|
||||
|
||||
CODE @
|
||||
CODE _@
|
||||
HL POPqq,
|
||||
chkPS,
|
||||
E (HL) LDrr,
|
||||
@ -250,14 +250,14 @@ CODE @
|
||||
DE PUSHqq,
|
||||
;CODE
|
||||
|
||||
CODE C!
|
||||
CODE _C!
|
||||
HL POPqq,
|
||||
DE POPqq,
|
||||
chkPS,
|
||||
(HL) E LDrr,
|
||||
;CODE
|
||||
|
||||
CODE C@
|
||||
CODE _C@
|
||||
HL POPqq,
|
||||
chkPS,
|
||||
L (HL) LDrr,
|
||||
|
32
notes.txt
32
notes.txt
@ -88,7 +88,8 @@ RAMSTART INITIAL_SP
|
||||
+0e WORDBUF
|
||||
+2e SYSVNXT
|
||||
+4e INTJUMP
|
||||
+51 RESERVED
|
||||
+51 MMAPPTR
|
||||
+53 RESERVED
|
||||
+60 SYSTEM SCRATCHPAD
|
||||
+80 RAMEND
|
||||
|
||||
@ -116,6 +117,9 @@ 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
|
||||
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
|
||||
by low-level drivers. These are the current usages of this space throughout the
|
||||
project:
|
||||
@ -154,3 +158,29 @@ 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
|
||||
in dict entry creation overwriting the code before it has the chance to be
|
||||
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,6 +6,7 @@ STAGE2 = $(EDIR)/stage2
|
||||
EMUL = $(BASEDIR)/emul/hw/rc2014/classic
|
||||
PATHS = pre.fs \
|
||||
$(FDIR)/core.fs \
|
||||
$(FDIR)/cmp.fs \
|
||||
$(FDIR)/str.fs \
|
||||
$(FDIR)/parse.fs \
|
||||
$(BASEDIR)/drv/acia.fs \
|
||||
|
@ -108,11 +108,135 @@ 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. We already have our
|
||||
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.
|
||||
being in source form takes precious space from our 8K ROM. That brings us to
|
||||
building stage 2.
|
||||
|
||||
TODO: write this, do this.
|
||||
### 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.
|
||||
|
||||
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
|
||||
[romwrite]: https://github.com/hsoft/romwrite
|
||||
|
@ -1 +1 @@
|
||||
96 RAM+ HERE !
|
||||
112 RAM+ HERE !
|
||||
|
1
tools/.gitignore
vendored
1
tools/.gitignore
vendored
@ -6,3 +6,4 @@
|
||||
/pingpong
|
||||
/slatest
|
||||
/stripfc
|
||||
/bin2c
|
||||
|
@ -6,8 +6,10 @@ TTYSAFE_TGT = ttysafe
|
||||
PINGPONG_TGT = pingpong
|
||||
SLATEST_TGT = slatest
|
||||
STRIPFC_TGT = stripfc
|
||||
BIN2C_TGT = bin2c
|
||||
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
|
||||
|
||||
all: $(TARGETS)
|
||||
@ -24,6 +26,7 @@ $(TTYSAFE_TGT): $(TTYSAFE_TGT).c
|
||||
$(PINGPONG_TGT): $(PINGPONG_TGT).c
|
||||
$(SLATEST_TGT): $(SLATEST_TGT).c
|
||||
$(STRIPFC_TGT): $(STRIPFC_TGT).c
|
||||
$(BIN2C_TGT): $(BIN2C_TGT).c
|
||||
$(TARGETS): $(OBJS)
|
||||
$(CC) $(CFLAGS) $@.c $(OBJS) -o $@
|
||||
|
||||
|
50
tools/bin2c.c
Normal file
50
tools/bin2c.c
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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