1
0
mirror of https://github.com/hsoft/collapseos.git synced 2024-11-26 15:48:05 +11:00

Compare commits

..

No commits in common. "eed67c4768624d9169c190711f037ee725e42f4a" and "e3c885085d1603afece4e0d870d2ca775286c71f" have entirely different histories.

97 changed files with 344 additions and 341 deletions

1
.gitignore vendored
View File

@ -1,2 +1 @@
*.o
/kernel/user.h /kernel/user.h

4
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "emul/libz80"] [submodule "tools/emul/libz80"]
path = emul/libz80 path = tools/emul/libz80
url = https://github.com/ggambetta/libz80.git url = https://github.com/ggambetta/libz80.git

View File

@ -34,11 +34,11 @@ path to giving Collapse OS a try.
* `recipes`: collection of recipes that assemble parts together on a specific * `recipes`: collection of recipes that assemble parts together on a specific
machine. machine.
* `doc`: User guide for when you've successfully installed Collapse OS. * `doc`: User guide for when you've successfully installed Collapse OS.
* `tools`: Tools for working with Collapse OS from "modern" environments. For * `tools`: Tools for working with Collapse OS from "modern" environments. Mostly
example, tools for facilitating data upload to a Collapse OS machine development tools, but also contains emulated zasm, which is
through a serial port. necessary to build Collapse OS from a non-Collapse OS machine.
* `emul`: Emulated applications, such as zasm and the shell.
* `tests`: Automated test suite for the whole project. Each folder has a README with more details.
## Status ## Status

View File

@ -65,9 +65,12 @@ look like:
Once this is written, you can build it with `zasm`, which takes code from stdin Once this is written, you can build it with `zasm`, which takes code from stdin
and spits binary to stdout. Because out code has includes, however, you need and spits binary to stdout. Because out code has includes, however, you need
to supply zasm with include folders or files. The invocation would look like to supply zasm with a block device containing a CFS containing the files to
include. This sounds, compicated, but it's managed by the `tools/zasm.sh` shell
script. The invocation would look like (it builds a CFS with the contents of
both `kernel/` and `apps/` folders):
emul/zasm/zasm kernel/ apps/ < glue.asm > collapseos.bin tools/zasm.sh kernel/ apps/ < glue.asm > collapseos.bin
## Building zasm ## Building zasm
@ -76,7 +79,7 @@ Collapse OS has its own assembler written in z80 assembly. We call it
but because it is written in z80 assembler, it needs to be emulated (with but because it is written in z80 assembler, it needs to be emulated (with
[libz80][libz80]). [libz80][libz80]).
So, the first step is to build zasm. Open `emul/README.md` and follow So, the first step is to build zasm. Open `tools/emul/README.md` and follow
instructions there. instructions there.
## Platform constants ## Platform constants
@ -159,5 +162,5 @@ and this much depends on the part you select. But if you want a shell, you will
usually end it with `basStart`, which never returns. usually end it with `basStart`, which never returns.
[rc2014]: https://rc2014.co.uk/ [rc2014]: https://rc2014.co.uk/
[zasm]: ../emul/README.md [zasm]: ../tools/emul/README.md
[libz80]: https://github.com/ggambetta/libz80 [libz80]: https://github.com/ggambetta/libz80

View File

@ -1,10 +1,9 @@
TARGET = os.bin TARGET = os.bin
BASEDIR = ../.. ZASM = ../../tools/zasm.sh
ZASM = $(BASEDIR)/emul/zasm/zasm KERNEL = ../../kernel
KERNEL = $(BASEDIR)/kernel APPS = ../../apps
APPS = $(BASEDIR)/apps
.PHONY: all .PHONY: all
all: $(TARGET) all: $(TARGET)
$(TARGET): glue.asm $(TARGET): glue.asm
$(ZASM) $(KERNEL) $(APPS) < glue.asm > $@ $(ZASM) $(KERNEL) $(APPS) < $< > $@

View File

@ -77,7 +77,7 @@ is decoupled from the ACIA and can get its IO from anything. See comments in
We only have the shell to build, so it's rather straightforward: We only have the shell to build, so it's rather straightforward:
../../emul/zasm/zasm ../../kernel < glue.asm > os.bin ../../tools/zasm.sh ../../kernel < glue.asm > os.bin
Running `make` will also work. Running `make` will also work.

View File

@ -1,11 +1,10 @@
TARGET = os.bin TARGET = os.bin
BASEDIR = ../../.. ZASM = ../../../tools/zasm.sh
ZASM = $(BASEDIR)/emul/zasm/zasm KERNEL = ../../../kernel
KERNEL = $(BASEDIR)/kernel APPS = ../../../apps
APPS = $(BASEDIR)/apps
.PHONY: all .PHONY: all
all: $(TARGET) all: $(TARGET)
$(TARGET): glue.asm $(TARGET): glue.asm
$(ZASM) $(KERNEL) $(APPS) < glue.asm > $@ $(ZASM) $(KERNEL) $(APPS) < $< > $@

View File

@ -33,6 +33,7 @@ jp aciaInt
.equ STDIO_PUTC aciaPutC .equ STDIO_PUTC aciaPutC
.inc "stdio.asm" .inc "stdio.asm"
.inc "lib/args.asm"
.equ AT28W_RAMSTART STDIO_RAMEND .equ AT28W_RAMSTART STDIO_RAMEND
.inc "at28w/main.asm" .inc "at28w/main.asm"

View File

@ -2,10 +2,9 @@ PROGNAME = ps2ctl
AVRDUDEMCU ?= t45 AVRDUDEMCU ?= t45
AVRDUDEARGS ?= -c usbtiny -P usb AVRDUDEARGS ?= -c usbtiny -P usb
TARGETS = $(PROGNAME).hex os.bin TARGETS = $(PROGNAME).hex os.bin
BASEDIR = ../../.. ZASM = ../../../tools/zasm.sh
ZASM = $(BASEDIR)/emul/zasm/zasm KERNEL = ../../../kernel
KERNEL = $(BASEDIR)/kernel APPS = ../../../apps
APPS = $(BASEDIR)/apps
# Rules # Rules
@ -15,13 +14,13 @@ all: $(TARGETS)
@echo Done! @echo Done!
send: $(PROGNAME).hex send: $(PROGNAME).hex
avrdude $(AVRDUDEARGS) -p $(AVRDUDEMCU) -U flash:w:$(PROGNAME).hex avrdude $(AVRDUDEARGS) -p $(AVRDUDEMCU) -U flash:w:$<
$(PROGNAME).hex: $(PROGNAME).asm $(PROGNAME).hex: $(PROGNAME).asm
avra -o $@ $(PROGNAME).asm avra -o $@ $<
os.bin: glue.asm os.bin: glue.asm
$(ZASM) $(KERNEL) $(APPS) < glue.asm > $@ $(ZASM) $(KERNEL) $(APPS) < $< > $@
clean: clean:
rm -f $(TARGETS) *.eep.hex *.obj os.bin rm -f $(TARGETS) *.eep.hex *.obj os.bin

View File

@ -1,19 +1,19 @@
TARGETS = os.bin cfsin/helo TARGETS = os.bin cfsin/helo
BASEDIR = ../../.. TOOLS = ../../../tools
ZASM = $(BASEDIR)/emul/zasm/zasm ZASM = $(TOOLS)/zasm.sh
KERNEL = $(BASEDIR)/kernel KERNEL = ../../../kernel
APPS = $(BASEDIR)/apps APPS = ../../../apps
CFSPACK = $(BASEDIR)/tools/cfspack/cfspack CFSPACK = $(TOOLS)/cfspack/cfspack
.PHONY: all .PHONY: all
all: $(TARGETS) sdcard.cfs all: $(TARGETS) sdcard.cfs
os.bin: glue.asm os.bin: glue.asm
cfsin/helo: helo.asm cfsin/helo: helo.asm
$(TARGETS): $(TARGETS):
$(ZASM) $(KERNEL) $(APPS) < glue.asm > $@ $(ZASM) $(KERNEL) $(APPS) < $< > $@
$(CFSPACK): $(CFSPACK):
make -C $(BASEDIR)/tools/cfspack make -C $(TOOLS)/cfspack
sdcard.cfs: cfsin $(CFSPACK) sdcard.cfs: cfsin $(CFSPACK)
$(CFSPACK) cfsin > $@ $(CFSPACK) $< > $@

View File

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

View File

@ -1,10 +1,9 @@
TARGET = os.sms TARGET = os.sms
BASEDIR = ../.. ZASM = ../../tools/zasm.sh
ZASM = $(BASEDIR)/emul/zasm/zasm KERNEL = ../../kernel
KERNEL = $(BASEDIR)/kernel APPS = ../../apps
APPS = $(BASEDIR)/apps
.PHONY: all .PHONY: all
all: $(TARGET) all: $(TARGET)
$(TARGET): glue.asm $(TARGET): glue.asm
$(ZASM) $(KERNEL) $(APPS) < glue.asm > $@ $(ZASM) $(KERNEL) $(APPS) < $< > $@

View File

@ -2,10 +2,9 @@ PROGNAME = ps2ctl
AVRDUDEMCU ?= t45 AVRDUDEMCU ?= t45
AVRDUDEARGS ?= -c usbtiny -P usb AVRDUDEARGS ?= -c usbtiny -P usb
TARGETS = $(PROGNAME).hex os.sms TARGETS = $(PROGNAME).hex os.sms
BASEDIR = ../../.. ZASM = ../../../tools/zasm.sh
ZASM = $(BASEDIR)/emul/zasm/zasm KERNEL = ../../../kernel
KERNEL = $(BASEDIR)/kernel APPS = ../../../apps
APPS = $(BASEDIR)/apps
# Rules # Rules
@ -15,13 +14,13 @@ all: $(TARGETS)
@echo Done! @echo Done!
send: $(PROGNAME).hex send: $(PROGNAME).hex
avrdude $(AVRDUDEARGS) -p $(AVRDUDEMCU) -U flash:w:$(PROGNAME).hex avrdude $(AVRDUDEARGS) -p $(AVRDUDEMCU) -U flash:w:$<
$(PROGNAME).hex: $(PROGNAME).asm $(PROGNAME).hex: $(PROGNAME).asm
avra -o $@ $(PROGNAME).asm avra -o $@ $<
os.sms: glue.asm os.sms: glue.asm
$(ZASM) $(KERNEL) $(APPS) < glue.asm > $@ $(ZASM) $(KERNEL) $(APPS) < $< > $@
clean: clean:
rm -f $(TARGETS) *.eep.hex *.obj os.bin rm -f $(TARGETS) *.eep.hex *.obj os.bin

View File

@ -1,21 +1,20 @@
BASEDIR = ../../.. ZASM = ../../../tools/zasm.sh
ZASM = $(BASEDIR)/emul/zasm/zasm KERNEL = ../../../kernel
KERNEL = $(BASEDIR)/kernel APPS = ../../../apps
APPS = $(BASEDIR)/apps
.PHONY: all clean .PHONY: all clean
all: os.sms all: os.sms
# -o value synced with offset in glue.asm # -o value synced with offset in glue.asm
ed.bin: $(APPS)/ed/glue.asm ed.bin: $(APPS)/ed/glue.asm
$(ZASM) -o 1f $(KERNEL) $(APPS) user.h < $(APPS)/ed/glue.asm > $@ $(ZASM) -o 19 $(KERNEL) $(APPS) user.h < $< > $@
# -o value synced with offset in glue.asm # -o value synced with offset in glue.asm
zasm.bin: $(APPS)/zasm/glue.asm zasm.bin: $(APPS)/zasm/glue.asm
$(ZASM) -o 24 $(KERNEL) $(APPS) user.h < $(APPS)/zasm/glue.asm > $@ $(ZASM) -o 1d $(KERNEL) $(APPS) user.h < $< > $@
os.sms: glue.asm ed.bin zasm.bin os.sms: glue.asm ed.bin zasm.bin
$(ZASM) $(KERNEL) $(APPS) ed.bin zasm.bin < glue.asm > $@ $(ZASM) $(KERNEL) $(APPS) ed.bin zasm.bin < $< > $@
clean: clean:
rm -f os.sms ed.bin zasm.bin rm -f os.sms ed.bin zasm.bin

View File

@ -1,19 +1,18 @@
TARGET = os.rom TARGET = os.rom
BASEDIR = ../.. ZASM = ../../tools/zasm.sh
ZASM = $(BASEDIR)/emul/zasm/zasm KERNEL = ../../kernel
KERNEL = $(BASEDIR)/kernel APPS = ../../apps
APPS = $(BASEDIR)/apps
MKTIUPGRADE = mktiupgrade MKTIUPGRADE = mktiupgrade
.PHONY: all .PHONY: all
all: $(TARGET) all: $(TARGET)
$(TARGET): glue.asm $(TARGET): glue.asm
$(ZASM) $(KERNEL) $(APPS) < glue.asm > $@ $(ZASM) $(KERNEL) $(APPS) < $< > $@
truncate -s 1M $@ truncate -s 1M $@
os.8xu: $(TARGET) os.8xu: $(TARGET)
$(MKTIUPGRADE) -p -k keys/0A.key -d TI-84+ $(TARGET) $@ 00 $(MKTIUPGRADE) -p -k keys/0A.key -d TI-84+ $< $@ 00
.PHONY: send .PHONY: send
send: os.8xu send: os.8xu
tilp -n --calc ti84+ --cable DirectLink os.8xu tilp -n --calc ti84+ --cable DirectLink $<

View File

@ -4,9 +4,15 @@ git submodule init
git submodule update git submodule update
git clean -fxd git clean -fxd
make -C emul cd tools/emul
make -C tests make
cd ../tests
make
# let's try again with an updated zasm # let's try again with an updated zasm
make -C emul updatebootstrap all cd ../emul
make -C tests make updatebootstrap all
cd ../tests
make

1
tools/.gitignore vendored
View File

@ -1,3 +1,4 @@
*.o
/memdump /memdump
/blkdump /blkdump
/upload /upload

View File

@ -1,12 +1,10 @@
TARGETS = cfspack cfsunpack TARGETS = cfspack cfsunpack
CFSPACK_OBJS = cfspack.o libcfs.o
.PHONY: all .PHONY: all
all: $(TARGETS) all: $(TARGETS)
cfspack: $(CFSPACK_OBJS) cfspack: cfspack.c
$(CC) $(LDFLAGS) -o $@ $(CFSPACK_OBJS) $(CC) $(CFLAGS) -o $@ cfspack.c
cfsunpack: cfsunpack.c cfsunpack: cfsunpack.c
$(CC) $(CFLAGS) -o $@ cfsunpack.c $(CC) $(CFLAGS) -o $@ cfsunpack.c

View File

@ -1,10 +0,0 @@
#define BLKSIZE 0x100
#define HEADERSIZE 0x20
#define MAX_FN_LEN 25 // 26 - null char
#define MAX_FILE_SIZE (BLKSIZE * 0x100) - HEADERSIZE
void set_spit_stream(FILE *stream);
int is_regular_file(char *path);
void spitempty();
int spitblock(char *fullpath, char *fn);
int spitdir(char *path, char *prefix, char **patterns);

View File

@ -7,7 +7,139 @@
#include <libgen.h> #include <libgen.h>
#include <sys/stat.h> #include <sys/stat.h>
#include "cfs.h" #define BLKSIZE 0x100
#define HEADERSIZE 0x20
#define MAX_FN_LEN 25 // 26 - null char
#define MAX_FILE_SIZE (BLKSIZE * 0x100) - HEADERSIZE
int is_regular_file(char *path)
{
struct stat path_stat;
stat(path, &path_stat);
return S_ISREG(path_stat.st_mode);
}
void spitempty()
{
putchar('C');
putchar('F');
putchar('S');
for (int i=0; i<0x20-3; i++) {
putchar(0);
}
}
int spitblock(char *fullpath, char *fn)
{
FILE *fp = fopen(fullpath, "r");
fseek(fp, 0, SEEK_END);
long fsize = ftell(fp);
if (fsize > MAX_FILE_SIZE) {
fclose(fp);
fprintf(stderr, "File too big: %s %ld\n", fullpath, fsize);
return 1;
}
/* Compute block count.
* We always have at least one, which contains 0x100 bytes - 0x20, which is
* metadata. The rest of the blocks have a steady 0x100.
*/
unsigned char blockcount = 1;
int fsize2 = fsize - (BLKSIZE - HEADERSIZE);
if (fsize2 > 0) {
blockcount += (fsize2 / BLKSIZE);
}
if (blockcount * BLKSIZE < fsize + HEADERSIZE) {
blockcount++;
}
putchar('C');
putchar('F');
putchar('S');
putchar(blockcount);
// file size is little endian
putchar(fsize & 0xff);
putchar((fsize >> 8) & 0xff);
int fnlen = strlen(fn);
for (int i=0; i<MAX_FN_LEN; i++) {
if (i < fnlen) {
putchar(fn[i]);
} else {
putchar(0);
}
}
// And the last FN char which is always null
putchar(0);
char buf[MAX_FILE_SIZE] = {0};
rewind(fp);
fread(buf, fsize, 1, fp);
fclose(fp);
fwrite(buf, (blockcount * BLKSIZE) - HEADERSIZE, 1, stdout);
fflush(stdout);
return 0;
}
int spitdir(char *path, char *prefix, char **patterns)
{
DIR *dp;
struct dirent *ep;
int prefixlen = strlen(prefix);
dp = opendir(path);
if (dp == NULL) {
fprintf(stderr, "Couldn't open directory.\n");
return 1;
}
while (ep = readdir(dp)) {
if ((strcmp(ep->d_name, ".") == 0) || strcmp(ep->d_name, "..") == 0) {
continue;
}
if (ep->d_type != DT_DIR && ep->d_type != DT_REG) {
fprintf(stderr, "Only regular file or directories are supported\n");
return 1;
}
int slen = strlen(ep->d_name);
if (prefixlen + slen> MAX_FN_LEN) {
fprintf(stderr, "Filename too long: %s/%s\n", prefix, ep->d_name);
return 1;
}
char fullpath[0x1000];
strcpy(fullpath, path);
strcat(fullpath, "/");
strcat(fullpath, ep->d_name);
char newprefix[MAX_FN_LEN];
strcpy(newprefix, prefix);
if (prefixlen > 0) {
strcat(newprefix, "/");
}
strcat(newprefix, ep->d_name);
if (ep->d_type == DT_DIR) {
int r = spitdir(fullpath, newprefix, patterns);
if (r != 0) {
return r;
}
} else {
char **p = patterns;
// if we have no pattern, we match all
int matches = (*p) == NULL ? 1 : 0;
while (*p) {
if (fnmatch(*p, ep->d_name, 0) == 0) {
matches = 1;
break;
}
p++;
}
if (!matches) {
continue;
}
int r = spitblock(fullpath, newprefix);
if (r != 0) {
return r;
}
}
}
closedir(dp);
return 0;
}
void usage() void usage()
{ {

View File

@ -1,152 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <fnmatch.h>
#include <libgen.h>
#include <sys/stat.h>
#include "cfs.h"
#define PUTC(c) putc(c, spitstream)
static FILE *spitstream = NULL;
void set_spit_stream(FILE *stream)
{
spitstream = stream;
}
int is_regular_file(char *path)
{
struct stat path_stat;
stat(path, &path_stat);
return S_ISREG(path_stat.st_mode);
}
void spitempty()
{
if (spitstream == NULL) spitstream = stdout;
PUTC('C');
PUTC('F');
PUTC('S');
for (int i=0; i<0x20-3; i++) {
PUTC(0);
}
}
int spitblock(char *fullpath, char *fn)
{
if (spitstream == NULL) spitstream = stdout;
FILE *fp = fopen(fullpath, "r");
fseek(fp, 0, SEEK_END);
long fsize = ftell(fp);
if (fsize > MAX_FILE_SIZE) {
fclose(fp);
fprintf(stderr, "File too big: %s %ld\n", fullpath, fsize);
return 1;
}
/* Compute block count.
* We always have at least one, which contains 0x100 bytes - 0x20, which is
* metadata. The rest of the blocks have a steady 0x100.
*/
unsigned char blockcount = 1;
int fsize2 = fsize - (BLKSIZE - HEADERSIZE);
if (fsize2 > 0) {
blockcount += (fsize2 / BLKSIZE);
}
if (blockcount * BLKSIZE < fsize + HEADERSIZE) {
blockcount++;
}
PUTC('C');
PUTC('F');
PUTC('S');
PUTC(blockcount);
// file size is little endian
PUTC(fsize & 0xff);
PUTC((fsize >> 8) & 0xff);
int fnlen = strlen(fn);
for (int i=0; i<MAX_FN_LEN; i++) {
if (i < fnlen) {
PUTC(fn[i]);
} else {
PUTC(0);
}
}
// And the last FN char which is always null
PUTC(0);
char buf[MAX_FILE_SIZE] = {0};
rewind(fp);
fread(buf, fsize, 1, fp);
fclose(fp);
fwrite(buf, (blockcount * BLKSIZE) - HEADERSIZE, 1, spitstream);
fflush(spitstream);
return 0;
}
int spitdir(char *path, char *prefix, char **patterns)
{
DIR *dp;
struct dirent *ep;
int prefixlen = strlen(prefix);
dp = opendir(path);
if (dp == NULL) {
fprintf(stderr, "Couldn't open directory.\n");
return 1;
}
while ((ep = readdir(dp))) {
if ((strcmp(ep->d_name, ".") == 0) || strcmp(ep->d_name, "..") == 0) {
continue;
}
if (ep->d_type != DT_DIR && ep->d_type != DT_REG) {
fprintf(stderr, "Only regular file or directories are supported\n");
return 1;
}
int slen = strlen(ep->d_name);
if (prefixlen + slen> MAX_FN_LEN) {
fprintf(stderr, "Filename too long: %s/%s\n", prefix, ep->d_name);
return 1;
}
char fullpath[0x1000];
strcpy(fullpath, path);
strcat(fullpath, "/");
strcat(fullpath, ep->d_name);
char newprefix[MAX_FN_LEN];
strcpy(newprefix, prefix);
if (prefixlen > 0) {
strcat(newprefix, "/");
}
strcat(newprefix, ep->d_name);
if (ep->d_type == DT_DIR) {
int r = spitdir(fullpath, newprefix, patterns);
if (r != 0) {
return r;
}
} else {
char **p = patterns;
// if we have no pattern, we match all
if (p && *p) {
int matches = 0;
while (*p) {
if (fnmatch(*p, ep->d_name, 0) == 0) {
matches = 1;
break;
}
p++;
}
if (!matches) {
continue;
}
}
int r = spitblock(fullpath, newprefix);
if (r != 0) {
return r;
}
}
}
closedir(dp);
return 0;
}

View File

@ -1,28 +1,27 @@
CFSPACK_OBJ = ../tools/cfspack/libcfs.o CFSPACK = ../cfspack/cfspack
TARGETS = shell/shell zasm/zasm runbin/runbin TARGETS = shell/shell zasm/zasm runbin/runbin
KERNEL = ../kernel KERNEL = ../../kernel
APPS = ../apps APPS = ../../apps
ZASMBIN = zasm/zasm ZASMBIN = zasm/zasm
AVRABIN = zasm/avra AVRABIN = zasm/avra
ZASMSH = ../zasm.sh
SHELLAPPS = zasm ed SHELLAPPS = zasm ed
SHELLTGTS = ${SHELLAPPS:%=cfsin/%} SHELLTGTS = ${SHELLAPPS:%=cfsin/%}
CFSIN_CONTENTS = $(SHELLTGTS) cfsin/user.h CFSIN_CONTENTS = $(SHELLTGTS) cfsin/user.h
OBJS = emul.o libz80/libz80.o OBJS = emul.o libz80/libz80.o
SHELLOBJS = $(OBJS) $(CFSPACK_OBJ)
ZASMOBJS = $(SHELLOBJS)
.PHONY: all .PHONY: all
all: $(TARGETS) $(AVRABIN) $(CFSIN_CONTENTS) all: $(TARGETS) $(AVRABIN) $(CFSIN_CONTENTS)
# -o in sync with SHELL_CODE in shell/glue.asm # -o in sync with SHELL_CODE in shell/glue.asm
shell/shell.bin: shell/glue.asm $(ZASMBIN) shell/shell.bin: shell/glue.asm $(ZASMBIN)
$(ZASMBIN) $(KERNEL) shell/user.h $(APPS) < shell/glue.asm | tee $@ > /dev/null $(ZASMSH) $(KERNEL) shell/user.h $(APPS) < shell/glue.asm | tee $@ > /dev/null
shell/shell-bin.h: shell/shell.bin shell/shell-bin.h: shell/shell.bin
./bin2c.sh KERNEL < shell/shell.bin | tee $@ > /dev/null ./bin2c.sh KERNEL < shell/shell.bin | tee $@ > /dev/null
shell/shell: shell/shell.c $(SHELLOBJS) shell/shell-bin.h shell/shell: shell/shell.c $(OBJS) shell/shell-bin.h
$(CC) shell/shell.c $(SHELLOBJS) -o $@ $(CC) shell/shell.c $(OBJS) -o $@
zasm/kernel-bin.h: zasm/kernel.bin zasm/kernel-bin.h: zasm/kernel.bin
./bin2c.sh KERNEL < zasm/kernel.bin | tee $@ > /dev/null ./bin2c.sh KERNEL < zasm/kernel.bin | tee $@ > /dev/null
@ -30,17 +29,17 @@ zasm/kernel-bin.h: zasm/kernel.bin
zasm/zasm-bin.h: zasm/zasm.bin zasm/zasm-bin.h: zasm/zasm.bin
./bin2c.sh USERSPACE < zasm/zasm.bin | tee $@ > /dev/null ./bin2c.sh USERSPACE < zasm/zasm.bin | tee $@ > /dev/null
$(ZASMBIN): zasm/zasm.c $(ZASMOBJS) zasm/kernel-bin.h zasm/zasm-bin.h $(ZASMBIN): zasm/zasm.c $(OBJS) zasm/kernel-bin.h zasm/zasm-bin.h $(CFSPACK)
$(CC) zasm/zasm.c $(ZASMOBJS) -o $@ $(CC) zasm/zasm.c $(OBJS) -o $@
zasm/avra.bin: $(ZASMBIN) zasm/avra.bin: $(ZASMBIN)
$(ZASMBIN) $(KERNEL) $(APPS) zasm/user.h < $(APPS)/zasm/gluea.asm > $@ $(ZASMSH) $(KERNEL) $(APPS) zasm/user.h < $(APPS)/zasm/gluea.asm > $@
zasm/avra-bin.h: zasm/avra.bin zasm/avra-bin.h: zasm/avra.bin
./bin2c.sh USERSPACE < zasm/avra.bin | tee $@ > /dev/null ./bin2c.sh USERSPACE < zasm/avra.bin | tee $@ > /dev/null
$(AVRABIN): zasm/zasm.c $(ZASMOBJS) zasm/kernel-bin.h zasm/avra-bin.h $(AVRABIN): zasm/zasm.c $(OBJS) zasm/kernel-bin.h zasm/avra-bin.h
$(CC) -D AVRA zasm/zasm.c $(ZASMOBJS) -o $@ $(CC) -D AVRA zasm/zasm.c $(OBJS) -o $@
runbin/runbin: runbin/runbin.c $(OBJS) runbin/runbin: runbin/runbin.c $(OBJS)
$(CC) runbin/runbin.c $(OBJS) -o $@ $(CC) runbin/runbin.c $(OBJS) -o $@
@ -52,20 +51,20 @@ libz80/libz80.o: libz80/z80.c
emul.o: emul.c emul.o: emul.c
$(CC) -c -o emul.o emul.c $(CC) -c -o emul.o emul.c
$(CFSPACK_OBJ): ${@:%.o=%.c} $(CFSPACK):
$(MAKE) -C ../tools/cfspack $(MAKE) -C ../cfspack
# -o in sync with USER_CODE in shell/user.h # -o in sync with USER_CODE in shell/user.h
$(SHELLTGTS): $(ZASMBIN) $(SHELLTGTS): $(ZASMBIN)
$(ZASMBIN) -o 42 $(KERNEL) $(APPS) shell/user.h < $(APPS)/${@:cfsin/%=%}/glue.asm > $@ $(ZASMSH) -o 42 $(KERNEL) $(APPS) shell/user.h < $(APPS)/${@:cfsin/%=%}/glue.asm > $@
cfsin/user.h: shell/user.h cfsin/user.h: shell/user.h
cp shell/user.h $@ cp shell/user.h $@
.PHONY: updatebootstrap .PHONY: updatebootstrap
updatebootstrap: $(ZASMBIN) updatebootstrap: $(ZASMBIN)
$(ZASMBIN) $(KERNEL) < zasm/glue.asm > zasm/kernel.bin $(ZASMSH) $(KERNEL) < zasm/glue.asm > zasm/kernel.bin
$(ZASMBIN) $(KERNEL) $(APPS) zasm/user.h < $(APPS)/zasm/glue.asm > zasm/zasm.bin $(ZASMSH) $(KERNEL) $(APPS) zasm/user.h < $(APPS)/zasm/glue.asm > zasm/zasm.bin
.PHONY: clean .PHONY: clean
clean: clean:

View File

@ -8,7 +8,7 @@ emulator.
First, make sure that the `libz80` git submodule is checked out. If not, run First, make sure that the `libz80` git submodule is checked out. If not, run
`git submodule init && git submodule update`. `git submodule init && git submodule update`.
After that, you can run `make` and it builds all applications. After that, you can run `make` and it builds all tools.
## shell ## shell

View File

@ -4,7 +4,6 @@
#include <termios.h> #include <termios.h>
#include "../emul.h" #include "../emul.h"
#include "shell-bin.h" #include "shell-bin.h"
#include "../../tools/cfspack/cfs.h"
/* Collapse OS shell with filesystem /* Collapse OS shell with filesystem
* *
@ -139,7 +138,21 @@ int main(int argc, char *argv[])
fprintf(stderr, "Can't open %s\n", optarg); fprintf(stderr, "Can't open %s\n", optarg);
return 1; return 1;
} }
fprintf(stderr, "Initializing filesystem from %s\n", optarg); break;
default:
fprintf(stderr, "Usage: shell [-f fsdev]\n");
return 1;
}
}
// Setup fs blockdev
if (fp == NULL) {
fp = popen("../cfspack/cfspack cfsin", "r");
if (fp == NULL) {
fprintf(stderr, "Can't initialize filesystem. Leaving blank.\n");
}
}
if (fp != NULL) {
fprintf(stderr, "Initializing filesystem\n");
int i = 0; int i = 0;
int c; int c;
while ((c = fgetc(fp)) != EOF && i < MAX_FSDEV_SIZE) { while ((c = fgetc(fp)) != EOF && i < MAX_FSDEV_SIZE) {
@ -150,22 +163,8 @@ int main(int argc, char *argv[])
return 1; return 1;
} }
pclose(fp); pclose(fp);
break;
default:
fprintf(stderr, "Usage: shell [-f fsdev]\n");
return 1;
}
}
// Setup fs blockdev
if (fp == NULL) {
fprintf(stderr, "Initializing filesystem from cfsin\n");
fp = fmemopen(fsdev, MAX_FSDEV_SIZE, "w");
set_spit_stream(fp);
if (spitdir("cfsin", "", NULL) != 0) {
fprintf(stderr, "Can't initialize filesystem. Leaving blank.\n");
}
fclose(fp);
} }
bool tty = isatty(fileno(stdin)); bool tty = isatty(fileno(stdin));
struct termios termInfo; struct termios termInfo;
if (tty) { if (tty) {

View File

@ -1,10 +1,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <libgen.h>
#include "../emul.h" #include "../emul.h"
#include "../../tools/cfspack/cfs.h"
#include "kernel-bin.h" #include "kernel-bin.h"
#ifdef AVRA #ifdef AVRA
#include "avra-bin.h" #include "avra-bin.h"
@ -54,7 +51,6 @@
// By default, we don't spit what zasm prints. Too noisy. Define VERBOSE if // By default, we don't spit what zasm prints. Too noisy. Define VERBOSE if
// you want to spit this content to stderr. // you want to spit this content to stderr.
//#define VERBOSE //#define VERBOSE
#define MAX_FSDEV_SIZE 0x80000
// STDIN buffer, allows us to seek and tell // STDIN buffer, allows us to seek and tell
static uint8_t inpt[STDIN_BUFSIZE]; static uint8_t inpt[STDIN_BUFSIZE];
@ -62,7 +58,8 @@ static int inpt_size;
static int inpt_ptr; static int inpt_ptr;
static uint8_t middle_of_seek_tell = 0; static uint8_t middle_of_seek_tell = 0;
static uint8_t fsdev[MAX_FSDEV_SIZE] = {0}; static uint8_t fsdev[0x80000] = {0};
static uint32_t fsdev_size = 0;
static uint32_t fsdev_ptr = 0; static uint32_t fsdev_ptr = 0;
static uint8_t fsdev_seek_tell_cnt = 0; static uint8_t fsdev_seek_tell_cnt = 0;
@ -91,7 +88,7 @@ static uint8_t iord_stdin_seek()
static uint8_t iord_fsdata() static uint8_t iord_fsdata()
{ {
if (fsdev_ptr < MAX_FSDEV_SIZE) { if (fsdev_ptr < fsdev_size) {
return fsdev[fsdev_ptr++]; return fsdev[fsdev_ptr++];
} else { } else {
return 0; return 0;
@ -102,7 +99,7 @@ static uint8_t iord_fsseek()
{ {
if (fsdev_seek_tell_cnt != 0) { if (fsdev_seek_tell_cnt != 0) {
return fsdev_seek_tell_cnt; return fsdev_seek_tell_cnt;
} else if (fsdev_ptr >= MAX_FSDEV_SIZE) { } else if (fsdev_ptr >= fsdev_size) {
return 1; return 1;
} else { } else {
return 0; return 0;
@ -133,7 +130,7 @@ static void iowr_stdin_seek(uint8_t val)
static void iowr_fsdata(uint8_t val) static void iowr_fsdata(uint8_t val)
{ {
if (fsdev_ptr < MAX_FSDEV_SIZE) { if (fsdev_ptr < fsdev_size) {
fsdev[fsdev_ptr++] = val; fsdev[fsdev_ptr++] = val;
} }
} }
@ -162,51 +159,12 @@ static void iowr_stderr(uint8_t val)
#endif #endif
} }
void usage()
{
fprintf(stderr, "Usage: zasm [-o org] [include-dir-or-file...] < source > binary\n");
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
char *init_org = "00"; if (argc > 3) {
while (1) { fprintf(stderr, "Too many args\n");
int c = getopt(argc, argv, "o:");
if (c < 0) {
break;
}
switch (c) {
case 'o':
init_org = optarg;
if (strlen(init_org) != 2) {
fprintf(stderr, "Initial org must be a two-character hex string");
}
break;
default:
usage();
return 1; return 1;
} }
}
if (argc-optind > 0) {
FILE *fp = fmemopen(fsdev, MAX_FSDEV_SIZE, "w");
set_spit_stream(fp);
char *patterns[4] = {"*.h", "*.asm", "*.bin", 0};
for (int i=optind; i<argc; i++) {
int res;
if (is_regular_file(argv[i])) {
// special case: just one file
res = spitblock(argv[i], basename(argv[i]));
} else {
res = spitdir(argv[i], "", patterns);
}
if (res != 0) {
fprintf(stderr, "Error while building the include CFS.\n");
fclose(fp);
return 1;
}
}
fclose(fp);
}
Machine *m = emul_init(); Machine *m = emul_init();
m->iord[STDIO_PORT] = iord_stdio; m->iord[STDIO_PORT] = iord_stdio;
m->iord[STDIN_SEEK_PORT] = iord_stdin_seek; m->iord[STDIN_SEEK_PORT] = iord_stdin_seek;
@ -224,9 +182,31 @@ int main(int argc, char *argv[])
for (int i=0; i<sizeof(USERSPACE); i++) { for (int i=0; i<sizeof(USERSPACE); i++) {
m->mem[i+USER_CODE] = USERSPACE[i]; m->mem[i+USER_CODE] = USERSPACE[i];
} }
char *init_org = "00";
if (argc >= 2) {
init_org = argv[1];
if (strlen(init_org) != 2) {
fprintf(stderr, "Initial org must be a two-character hex string");
}
}
// glue.asm knows that it needs to fetch these arguments at this address. // glue.asm knows that it needs to fetch these arguments at this address.
m->mem[0xff00] = init_org[0]; m->mem[0xff00] = init_org[0];
m->mem[0xff01] = init_org[1]; m->mem[0xff01] = init_org[1];
fsdev_size = 0;
if (argc == 3) {
FILE *fp = fopen(argv[2], "r");
if (fp == NULL) {
fprintf(stderr, "Can't open file %s\n", argv[1]);
return 1;
}
int c = fgetc(fp);
while (c != EOF) {
fsdev[fsdev_size] = c;
fsdev_size++;
c = fgetc(fp);
}
fclose(fp);
}
// read stdin in buffer // read stdin in buffer
inpt_size = 0; inpt_size = 0;
inpt_ptr = 0; inpt_ptr = 0;

View File

@ -1,4 +1,5 @@
EMULDIR = ../emul EMULDIR = ../emul
CFSPACK = ../cfspack/cfspack
.PHONY: run .PHONY: run
run: run:
@ -7,3 +8,10 @@ run:
cd zasm && ./runtests.sh cd zasm && ./runtests.sh
cd avra && ./runtests.sh cd avra && ./runtests.sh
cd shell && ./runtests.sh cd shell && ./runtests.sh
$(CFSPACK):
$(MAKE) -C ../cfspack
.PHONY: cfs
cfs: $(CFSPACK)
$(CFSPACK) shell/cfsin > shell/test.cfs

View File

@ -1,12 +1,12 @@
#!/bin/sh -e #!/bin/sh -e
ZASM=../../emul/zasm/avra ZASM=../../zasm.sh
AVRINC=../../avr AVRINC=../../../avr
cmpas() { cmpas() {
FN=$1 FN=$1
EXPECTED=$(xxd ${FN%.*}.expected) EXPECTED=$(xxd ${FN%.*}.expected)
ACTUAL=$(cat ${FN} | "${ZASM}" "${AVRINC}" | xxd) ACTUAL=$(cat ${FN} | "${ZASM}" -a "${AVRINC}" | xxd)
if [ "$ACTUAL" = "$EXPECTED" ]; then if [ "$ACTUAL" = "$EXPECTED" ]; then
echo ok echo ok
else else

View File

@ -1,7 +1,7 @@
#!/bin/sh -e #!/bin/sh -e
EMULDIR=../../emul EMULDIR=../../emul
SHELL="${EMULDIR}/shell/shell" SHELL=../../emul/shell/shell
replay() { replay() {
fn=$1 fn=$1

View File

@ -2,9 +2,10 @@
set -e set -e
# TODO: find POSIX substitute to that PIPESTATUS thing # TODO: find POSIX substitute to that PIPESTATUS thing
BASE=../.. BASE=../../..
ZASM="${BASE}/emul/zasm/zasm" TOOLS=../..
RUNBIN="${BASE}/emul/runbin/runbin" ZASM="${TOOLS}/zasm.sh"
RUNBIN="${TOOLS}/emul/runbin/runbin"
KERNEL="${BASE}/kernel" KERNEL="${BASE}/kernel"
APPS="${BASE}/apps" APPS="${BASE}/apps"

View File

@ -2,7 +2,7 @@
# no "set -e" because we test errors # no "set -e" because we test errors
ZASM=../../emul/zasm/zasm ZASM=../../zasm.sh
chkerr() { chkerr() {
echo "Check that '$1' results in error $2" echo "Check that '$1' results in error $2"

View File

@ -1,9 +1,9 @@
#!/bin/sh -e #!/bin/sh -e
BASE=../.. KERNEL=../../../kernel
KERNEL="${BASE}/kernel" APPS=../../../apps
APPS="${BASE}/apps" ZASM=../../zasm.sh
ZASM="${BASE}/emul/zasm/zasm" ASMFILE=${APPS}/zasm/instr.asm
cmpas() { cmpas() {
FN=$1 FN=$1

44
tools/zasm.sh Executable file
View File

@ -0,0 +1,44 @@
#!/usr/bin/env bash
# Calls tools/emul/zasm/zasm in a convenient manner by wrapping specified
# paths to include in a single CFS file and then pass that file to zasm.
# Additionally, it takes a "-o" argument to set the initial ".org" of the
# binary. For example, "zasm.sh -o 4f < foo.asm" assembles foo.asm as if it
# started with the line ".org 0x4f00".
# The -a flag makes us switch to the AVR assembler
# readlink -f doesn't work with macOS's implementation
# so, if we can't get readlink -f to work, try python with a realpath implementation
ABS_PATH=$(readlink -f "$0" || python -c "import os; print(os.path.realpath('$0'))")
DIR=$(dirname "${ABS_PATH}")
ZASMBIN="${DIR}/emul/zasm/zasm"
usage() { echo "Usage: $0 [-a] [-o <hexorg>] <paths-to-include>..." 1>&2; exit 1; }
org='00'
while getopts ":ao:" opt; do
case "${opt}" in
a)
ZASMBIN="${DIR}/emul/zasm/avra"
;;
o)
org=${OPTARG}
;;
*)
usage
;;
esac
done
shift $((OPTIND-1))
# wrapper around ./emul/zasm/zasm that prepares includes CFS prior to call
CFSPACK="${DIR}/cfspack/cfspack"
INCCFS=$(mktemp)
"${CFSPACK}" -p "*.h" -p "*.asm" -p "*.bin" "$@" > "${INCCFS}"
"${ZASMBIN}" "${org}" "${INCCFS}"
RES=$?
rm "${INCCFS}"
exit $RES