1
0
mirror of https://github.com/hsoft/collapseos.git synced 2024-11-26 13: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

4
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "emul/libz80"]
path = emul/libz80
[submodule "tools/emul/libz80"]
path = tools/emul/libz80
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
machine.
* `doc`: User guide for when you've successfully installed Collapse OS.
* `tools`: Tools for working with Collapse OS from "modern" environments. For
example, tools for facilitating data upload to a Collapse OS machine
through a serial port.
* `emul`: Emulated applications, such as zasm and the shell.
* `tests`: Automated test suite for the whole project.
* `tools`: Tools for working with Collapse OS from "modern" environments. Mostly
development tools, but also contains emulated zasm, which is
necessary to build Collapse OS from a non-Collapse OS machine.
Each folder has a README with more details.
## Status

View File

@ -65,9 +65,12 @@ look like:
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
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
@ -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
[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.
## 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.
[rc2014]: https://rc2014.co.uk/
[zasm]: ../emul/README.md
[zasm]: ../tools/emul/README.md
[libz80]: https://github.com/ggambetta/libz80

View File

@ -1,10 +1,9 @@
TARGET = os.bin
BASEDIR = ../..
ZASM = $(BASEDIR)/emul/zasm/zasm
KERNEL = $(BASEDIR)/kernel
APPS = $(BASEDIR)/apps
ZASM = ../../tools/zasm.sh
KERNEL = ../../kernel
APPS = ../../apps
.PHONY: all
all: $(TARGET)
$(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:
../../emul/zasm/zasm ../../kernel < glue.asm > os.bin
../../tools/zasm.sh ../../kernel < glue.asm > os.bin
Running `make` will also work.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,19 +1,18 @@
TARGET = os.rom
BASEDIR = ../..
ZASM = $(BASEDIR)/emul/zasm/zasm
KERNEL = $(BASEDIR)/kernel
APPS = $(BASEDIR)/apps
ZASM = ../../tools/zasm.sh
KERNEL = ../../kernel
APPS = ../../apps
MKTIUPGRADE = mktiupgrade
.PHONY: all
all: $(TARGET)
$(TARGET): glue.asm
$(ZASM) $(KERNEL) $(APPS) < glue.asm > $@
$(ZASM) $(KERNEL) $(APPS) < $< > $@
truncate -s 1M $@
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
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 clean -fxd
make -C emul
make -C tests
cd tools/emul
make
cd ../tests
make
# let's try again with an updated zasm
make -C emul updatebootstrap all
make -C tests
cd ../emul
make updatebootstrap all
cd ../tests
make

1
tools/.gitignore vendored
View File

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

View File

@ -1,12 +1,10 @@
TARGETS = cfspack cfsunpack
CFSPACK_OBJS = cfspack.o libcfs.o
.PHONY: all
all: $(TARGETS)
cfspack: $(CFSPACK_OBJS)
$(CC) $(LDFLAGS) -o $@ $(CFSPACK_OBJS)
cfspack: cfspack.c
$(CC) $(CFLAGS) -o $@ cfspack.c
cfsunpack: 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 <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()
{

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

View File

@ -8,7 +8,7 @@ emulator.
First, make sure that the `libz80` git submodule is checked out. If not, run
`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

View File

@ -4,7 +4,6 @@
#include <termios.h>
#include "../emul.h"
#include "shell-bin.h"
#include "../../tools/cfspack/cfs.h"
/* Collapse OS shell with filesystem
*
@ -139,17 +138,6 @@ int main(int argc, char *argv[])
fprintf(stderr, "Can't open %s\n", optarg);
return 1;
}
fprintf(stderr, "Initializing filesystem from %s\n", optarg);
int i = 0;
int c;
while ((c = fgetc(fp)) != EOF && i < MAX_FSDEV_SIZE) {
fsdev[i++] = c & 0xff;
}
if (i == MAX_FSDEV_SIZE) {
fprintf(stderr, "Filesytem image too large.\n");
return 1;
}
pclose(fp);
break;
default:
fprintf(stderr, "Usage: shell [-f fsdev]\n");
@ -158,14 +146,25 @@ int main(int argc, char *argv[])
}
// 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) {
fp = popen("../cfspack/cfspack cfsin", "r");
if (fp == NULL) {
fprintf(stderr, "Can't initialize filesystem. Leaving blank.\n");
}
fclose(fp);
}
if (fp != NULL) {
fprintf(stderr, "Initializing filesystem\n");
int i = 0;
int c;
while ((c = fgetc(fp)) != EOF && i < MAX_FSDEV_SIZE) {
fsdev[i++] = c & 0xff;
}
if (i == MAX_FSDEV_SIZE) {
fprintf(stderr, "Filesytem image too large.\n");
return 1;
}
pclose(fp);
}
bool tty = isatty(fileno(stdin));
struct termios termInfo;
if (tty) {

View File

@ -1,10 +1,7 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <libgen.h>
#include "../emul.h"
#include "../../tools/cfspack/cfs.h"
#include "kernel-bin.h"
#ifdef AVRA
#include "avra-bin.h"
@ -54,7 +51,6 @@
// By default, we don't spit what zasm prints. Too noisy. Define VERBOSE if
// you want to spit this content to stderr.
//#define VERBOSE
#define MAX_FSDEV_SIZE 0x80000
// STDIN buffer, allows us to seek and tell
static uint8_t inpt[STDIN_BUFSIZE];
@ -62,7 +58,8 @@ static int inpt_size;
static int inpt_ptr;
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 uint8_t fsdev_seek_tell_cnt = 0;
@ -91,7 +88,7 @@ static uint8_t iord_stdin_seek()
static uint8_t iord_fsdata()
{
if (fsdev_ptr < MAX_FSDEV_SIZE) {
if (fsdev_ptr < fsdev_size) {
return fsdev[fsdev_ptr++];
} else {
return 0;
@ -102,7 +99,7 @@ static uint8_t iord_fsseek()
{
if (fsdev_seek_tell_cnt != 0) {
return fsdev_seek_tell_cnt;
} else if (fsdev_ptr >= MAX_FSDEV_SIZE) {
} else if (fsdev_ptr >= fsdev_size) {
return 1;
} else {
return 0;
@ -133,7 +130,7 @@ static void iowr_stdin_seek(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;
}
}
@ -162,50 +159,11 @@ static void iowr_stderr(uint8_t val)
#endif
}
void usage()
{
fprintf(stderr, "Usage: zasm [-o org] [include-dir-or-file...] < source > binary\n");
}
int main(int argc, char *argv[])
{
char *init_org = "00";
while (1) {
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;
}
}
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);
if (argc > 3) {
fprintf(stderr, "Too many args\n");
return 1;
}
Machine *m = emul_init();
m->iord[STDIO_PORT] = iord_stdio;
@ -224,9 +182,31 @@ int main(int argc, char *argv[])
for (int i=0; i<sizeof(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.
m->mem[0xff00] = init_org[0];
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
inpt_size = 0;
inpt_ptr = 0;

View File

@ -1,4 +1,5 @@
EMULDIR = ../emul
CFSPACK = ../cfspack/cfspack
.PHONY: run
run:
@ -7,3 +8,10 @@ run:
cd zasm && ./runtests.sh
cd avra && ./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
ZASM=../../emul/zasm/avra
AVRINC=../../avr
ZASM=../../zasm.sh
AVRINC=../../../avr
cmpas() {
FN=$1
EXPECTED=$(xxd ${FN%.*}.expected)
ACTUAL=$(cat ${FN} | "${ZASM}" "${AVRINC}" | xxd)
ACTUAL=$(cat ${FN} | "${ZASM}" -a "${AVRINC}" | xxd)
if [ "$ACTUAL" = "$EXPECTED" ]; then
echo ok
else

View File

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

View File

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

View File

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

View File

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