mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-26 09:48:05 +11:00
Compare commits
2 Commits
ffe61a12f8
...
ca7c21d49f
Author | SHA1 | Date | |
---|---|---|---|
|
ca7c21d49f | ||
|
5387e08437 |
@ -33,11 +33,11 @@ forth/forth0.bin: forth/glue0.asm $(ZASMBIN)
|
||||
forth/forth0-bin.h: forth/forth0.bin
|
||||
./bin2c.sh KERNEL < forth/forth0.bin | tee $@ > /dev/null
|
||||
|
||||
forth/stage1: forth/stage1.c $(OBJS) forth/forth0-bin.h
|
||||
$(CC) forth/stage1.c $(OBJS) -o $@
|
||||
forth/stage1: forth/stage.c $(OBJS) forth/forth0-bin.h
|
||||
$(CC) forth/stage.c $(OBJS) -o $@
|
||||
|
||||
forth/stage1dbg: forth/stage1.c $(OBJS) forth/forth0-bin.h
|
||||
$(CC) -DDEBUG forth/stage1.c $(OBJS) -o $@
|
||||
forth/stage1dbg: forth/stage.c $(OBJS) forth/forth0-bin.h
|
||||
$(CC) -DDEBUG forth/stage.c $(OBJS) -o $@
|
||||
|
||||
forth/core.bin: $(FORTHSRC_PATHS) forth/stage1
|
||||
cat $(FORTHSRC_PATHS) | ./forth/stage1 | tee $@ > /dev/null
|
||||
|
@ -1,13 +1,4 @@
|
||||
; RAM disposition
|
||||
;
|
||||
; Because this glue code also serves stage0 which needs HERE to start right
|
||||
; after the code, we have a peculiar RAM setup here: it lives at the very end
|
||||
; of the address space, just under RS_ADDR at 0xf000
|
||||
; Warning: The offsets of native dict entries must be exactly the same between
|
||||
; glue0.asm and glue1.asm
|
||||
.equ RAMSTART 0xe800
|
||||
.equ HERE 0xe700 ; override, in sync with stage1.c
|
||||
.equ CURRENT 0xe702 ; override, in sync with stage1.c
|
||||
.equ HERE_INITIAL CODE_END ; override
|
||||
.equ STDIO_PORT 0x00
|
||||
|
||||
|
@ -4,20 +4,19 @@
|
||||
#include "../emul.h"
|
||||
#include "forth0-bin.h"
|
||||
|
||||
/* Stage 1
|
||||
/* Staging binaries
|
||||
|
||||
The role of the stage 1 executable is to start from a bare Forth executable
|
||||
(stage 0) that will compile core non-native definitions into binary form and
|
||||
append this to existing bootstrap binary to form our final Forth bin.
|
||||
The role of a stage executable is to compile definitions in a dictionary and
|
||||
then spit the difference between the starting binary and the new binary.
|
||||
|
||||
That binary can then be grafted to an exiting Forth binary to augment its
|
||||
dictionary.
|
||||
|
||||
We could, if we wanted, run only with the bootstrap binary and compile core
|
||||
defs at runtime, but that would mean that those defs live in RAM. In may system,
|
||||
RAM is much more constrained than ROM, so it's worth it to give ourselves the
|
||||
trouble of compiling defs to binary.
|
||||
|
||||
This stage 0 executable has to be layed out in a particular manner: HERE must
|
||||
directly follow executable's last byte so that we don't waste spce and also
|
||||
that wordref offsets correspond.
|
||||
*/
|
||||
|
||||
// When DEBUG is set, stage1 is a core-less forth that works interactively.
|
||||
@ -28,13 +27,12 @@ that wordref offsets correspond.
|
||||
// in sync with glue.asm
|
||||
#define RAMSTART 0x900
|
||||
#define STDIO_PORT 0x00
|
||||
// In sync with glue code. This way, we can know where HERE was when we stopped
|
||||
// running
|
||||
#define HERE 0xe700
|
||||
// We also need to know what CURRENT is so we can write our first two bytes
|
||||
#define CURRENT 0xe702
|
||||
// To know which part of RAM to dump, we listen to port 2, which at the end of
|
||||
// its compilation process, spits its HERE addr to port 2 (MSB first)
|
||||
#define HERE_PORT 0x02
|
||||
|
||||
static int running;
|
||||
static uint16_t ending_here = 0;
|
||||
|
||||
static uint8_t iord_stdio()
|
||||
{
|
||||
@ -54,12 +52,19 @@ static void iowr_stdio(uint8_t val)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void iowr_here(uint8_t val)
|
||||
{
|
||||
ending_here <<= 8;
|
||||
ending_here |= val;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Machine *m = emul_init();
|
||||
m->ramstart = RAMSTART;
|
||||
m->iord[STDIO_PORT] = iord_stdio;
|
||||
m->iowr[STDIO_PORT] = iowr_stdio;
|
||||
m->iowr[HERE_PORT] = iowr_here;
|
||||
// initialize memory
|
||||
for (int i=0; i<sizeof(KERNEL); i++) {
|
||||
m->mem[i] = KERNEL[i];
|
||||
@ -71,8 +76,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
#ifndef DEBUG
|
||||
// We're done, now let's spit dict data
|
||||
uint16_t here = m->mem[HERE] + (m->mem[HERE+1] << 8);
|
||||
for (int i=sizeof(KERNEL); i<here; i++) {
|
||||
fprintf(stderr, "hey, %x\n", ending_here);
|
||||
for (int i=sizeof(KERNEL); i<ending_here; i++) {
|
||||
putchar(m->mem[i]);
|
||||
}
|
||||
#endif
|
@ -42,7 +42,7 @@
|
||||
; IMMEDIATE
|
||||
|
||||
: CREATE
|
||||
WORD (entry) ( empty header with name )
|
||||
(entry) ( empty header with name )
|
||||
ROUTINE C [LITN] ( push cellWord addr )
|
||||
, ( write it )
|
||||
;
|
||||
|
@ -1,4 +1,11 @@
|
||||
( When building a compiled dict, always include this unit at
|
||||
the end of it so that Forth knows how to hook LATEST into
|
||||
it )
|
||||
WORD _______ (entry)
|
||||
(entry) _______
|
||||
|
||||
( After each dummy word like this, we poke IO port 2 with our
|
||||
current HERE value. The staging executable needs it to know
|
||||
what to dump. )
|
||||
|
||||
HERE @ 256 / 2 PC!
|
||||
HERE @ 2 PC!
|
||||
|
@ -883,7 +883,6 @@ ENDDEF:
|
||||
.db 1 ; IMMEDIATE
|
||||
DEFINE:
|
||||
.dw compiledWord
|
||||
.dw WORD
|
||||
.dw ENTRYHEAD
|
||||
.dw NUMBER
|
||||
.dw compiledWord
|
||||
@ -1238,6 +1237,12 @@ PARSEI:
|
||||
.dw $-PARSE
|
||||
.db 0
|
||||
ENTRYHEAD:
|
||||
.dw compiledWord
|
||||
.dw WORD
|
||||
.dw .private
|
||||
.dw EXIT
|
||||
|
||||
.private:
|
||||
.dw nativeWord
|
||||
pop hl
|
||||
ld de, (HERE)
|
||||
@ -1272,7 +1277,6 @@ ENTRYHEAD:
|
||||
.db 0
|
||||
SYSV:
|
||||
.dw compiledWord
|
||||
.dw WORD
|
||||
.dw ENTRYHEAD
|
||||
.dw NUMBER
|
||||
.dw sysvarWord
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
: CODE
|
||||
( same as CREATE, but with ROUTINE V )
|
||||
WORD (entry)
|
||||
(entry)
|
||||
ROUTINE V [LITN] ,
|
||||
;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user