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

Compare commits

...

7 Commits

Author SHA1 Message Date
Virgil Dupras
eed67c4768 tests/shell: bring back the static test.cfs
I had forgotten about that ordering thing: depending on the platform
cfspack doesn't read files in a directory in the same order.
2019-12-31 15:17:22 -05:00
Virgil Dupras
359991c005 cfspack: fix compilation error
Some compilers don't like assigning stdout statically.
2019-12-31 15:12:17 -05:00
Virgil Dupras
097c677641 emul/zasm: use libcfs
This allows us to get rid of the zasm.sh wrapper.
2019-12-31 15:07:39 -05:00
Virgil Dupras
4cde58fd83 cfspack: make into a library
Use it in shell instead of using popen()
2019-12-31 13:57:52 -05:00
Virgil Dupras
72357fec86 Move "emul" folder to root 2019-12-31 13:34:24 -05:00
Virgil Dupras
40f56dd6dc cfspack: silence compilation warning 2019-12-31 13:08:24 -05:00
Virgil Dupras
c5c6ef4c6c Move "tests" folder to root 2019-12-31 13:07:05 -05:00
97 changed files with 341 additions and 344 deletions

1
.gitignore vendored
View File

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

4
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "tools/emul/libz80"]
path = tools/emul/libz80
[submodule "emul/libz80"]
path = 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. 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.
* `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.
## Status

View File

@ -65,12 +65,9 @@ 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 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):
to supply zasm with include folders or files. The invocation would look like
tools/zasm.sh kernel/ apps/ < glue.asm > collapseos.bin
emul/zasm/zasm kernel/ apps/ < glue.asm > collapseos.bin
## Building zasm
@ -79,7 +76,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 `tools/emul/README.md` and follow
So, the first step is to build zasm. Open `emul/README.md` and follow
instructions there.
## Platform constants
@ -162,5 +159,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]: ../tools/emul/README.md
[zasm]: ../emul/README.md
[libz80]: https://github.com/ggambetta/libz80

View File

@ -1,27 +1,28 @@
CFSPACK = ../cfspack/cfspack
CFSPACK_OBJ = ../tools/cfspack/libcfs.o
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)
$(ZASMSH) $(KERNEL) shell/user.h $(APPS) < shell/glue.asm | tee $@ > /dev/null
$(ZASMBIN) $(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 $(OBJS) shell/shell-bin.h
$(CC) shell/shell.c $(OBJS) -o $@
shell/shell: shell/shell.c $(SHELLOBJS) shell/shell-bin.h
$(CC) shell/shell.c $(SHELLOBJS) -o $@
zasm/kernel-bin.h: zasm/kernel.bin
./bin2c.sh KERNEL < zasm/kernel.bin | tee $@ > /dev/null
@ -29,17 +30,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 $(OBJS) zasm/kernel-bin.h zasm/zasm-bin.h $(CFSPACK)
$(CC) zasm/zasm.c $(OBJS) -o $@
$(ZASMBIN): zasm/zasm.c $(ZASMOBJS) zasm/kernel-bin.h zasm/zasm-bin.h
$(CC) zasm/zasm.c $(ZASMOBJS) -o $@
zasm/avra.bin: $(ZASMBIN)
$(ZASMSH) $(KERNEL) $(APPS) zasm/user.h < $(APPS)/zasm/gluea.asm > $@
$(ZASMBIN) $(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 $(OBJS) zasm/kernel-bin.h zasm/avra-bin.h
$(CC) -D AVRA zasm/zasm.c $(OBJS) -o $@
$(AVRABIN): zasm/zasm.c $(ZASMOBJS) zasm/kernel-bin.h zasm/avra-bin.h
$(CC) -D AVRA zasm/zasm.c $(ZASMOBJS) -o $@
runbin/runbin: runbin/runbin.c $(OBJS)
$(CC) runbin/runbin.c $(OBJS) -o $@
@ -51,20 +52,20 @@ libz80/libz80.o: libz80/z80.c
emul.o: emul.c
$(CC) -c -o emul.o emul.c
$(CFSPACK):
$(MAKE) -C ../cfspack
$(CFSPACK_OBJ): ${@:%.o=%.c}
$(MAKE) -C ../tools/cfspack
# -o in sync with USER_CODE in shell/user.h
$(SHELLTGTS): $(ZASMBIN)
$(ZASMSH) -o 42 $(KERNEL) $(APPS) shell/user.h < $(APPS)/${@:cfsin/%=%}/glue.asm > $@
$(ZASMBIN) -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)
$(ZASMSH) $(KERNEL) < zasm/glue.asm > zasm/kernel.bin
$(ZASMSH) $(KERNEL) $(APPS) zasm/user.h < $(APPS)/zasm/glue.asm > zasm/zasm.bin
$(ZASMBIN) $(KERNEL) < zasm/glue.asm > zasm/kernel.bin
$(ZASMBIN) $(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 tools.
After that, you can run `make` and it builds all applications.
## shell

View File

@ -4,6 +4,7 @@
#include <termios.h>
#include "../emul.h"
#include "shell-bin.h"
#include "../../tools/cfspack/cfs.h"
/* Collapse OS shell with filesystem
*
@ -138,21 +139,7 @@ int main(int argc, char *argv[])
fprintf(stderr, "Can't open %s\n", optarg);
return 1;
}
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");
fprintf(stderr, "Initializing filesystem from %s\n", optarg);
int i = 0;
int c;
while ((c = fgetc(fp)) != EOF && i < MAX_FSDEV_SIZE) {
@ -163,8 +150,22 @@ int main(int argc, char *argv[])
return 1;
}
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));
struct termios termInfo;
if (tty) {

View File

@ -1,7 +1,10 @@
#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"
@ -51,6 +54,7 @@
// 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];
@ -58,8 +62,7 @@ static int inpt_size;
static int inpt_ptr;
static uint8_t middle_of_seek_tell = 0;
static uint8_t fsdev[0x80000] = {0};
static uint32_t fsdev_size = 0;
static uint8_t fsdev[MAX_FSDEV_SIZE] = {0};
static uint32_t fsdev_ptr = 0;
static uint8_t fsdev_seek_tell_cnt = 0;
@ -88,7 +91,7 @@ static uint8_t iord_stdin_seek()
static uint8_t iord_fsdata()
{
if (fsdev_ptr < fsdev_size) {
if (fsdev_ptr < MAX_FSDEV_SIZE) {
return fsdev[fsdev_ptr++];
} else {
return 0;
@ -99,7 +102,7 @@ static uint8_t iord_fsseek()
{
if (fsdev_seek_tell_cnt != 0) {
return fsdev_seek_tell_cnt;
} else if (fsdev_ptr >= fsdev_size) {
} else if (fsdev_ptr >= MAX_FSDEV_SIZE) {
return 1;
} else {
return 0;
@ -130,7 +133,7 @@ static void iowr_stdin_seek(uint8_t val)
static void iowr_fsdata(uint8_t val)
{
if (fsdev_ptr < fsdev_size) {
if (fsdev_ptr < MAX_FSDEV_SIZE) {
fsdev[fsdev_ptr++] = val;
}
}
@ -159,12 +162,51 @@ 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[])
{
if (argc > 3) {
fprintf(stderr, "Too many args\n");
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);
}
Machine *m = emul_init();
m->iord[STDIO_PORT] = iord_stdio;
m->iord[STDIN_SEEK_PORT] = iord_stdin_seek;
@ -182,31 +224,9 @@ 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,9 +1,10 @@
TARGET = os.bin
ZASM = ../../tools/zasm.sh
KERNEL = ../../kernel
APPS = ../../apps
BASEDIR = ../..
ZASM = $(BASEDIR)/emul/zasm/zasm
KERNEL = $(BASEDIR)/kernel
APPS = $(BASEDIR)/apps
.PHONY: all
all: $(TARGET)
$(TARGET): glue.asm
$(ZASM) $(KERNEL) $(APPS) < $< > $@
$(ZASM) $(KERNEL) $(APPS) < glue.asm > $@

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:
../../tools/zasm.sh ../../kernel < glue.asm > os.bin
../../emul/zasm/zasm ../../kernel < glue.asm > os.bin
Running `make` will also work.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

1
tools/.gitignore vendored
View File

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

View File

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

10
tools/cfspack/cfs.h Normal file
View File

@ -0,0 +1,10 @@
#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,139 +7,7 @@
#include <libgen.h>
#include <sys/stat.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;
}
#include "cfs.h"
void usage()
{

152
tools/cfspack/libcfs.c Normal file
View File

@ -0,0 +1,152 @@
#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,44 +0,0 @@
#!/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