1
0
mirror of https://github.com/hsoft/collapseos.git synced 2024-11-26 08:38:06 +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 /kernel/user.h

4
.gitmodules vendored
View File

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

View File

@ -65,12 +65,9 @@ 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 a block device containing a CFS containing the files to to supply zasm with include folders or files. The invocation would look like
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):
tools/zasm.sh kernel/ apps/ < glue.asm > collapseos.bin emul/zasm/zasm kernel/ apps/ < glue.asm > collapseos.bin
## Building zasm ## 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 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 `tools/emul/README.md` and follow So, the first step is to build zasm. Open `emul/README.md` and follow
instructions there. instructions there.
## Platform constants ## 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. usually end it with `basStart`, which never returns.
[rc2014]: https://rc2014.co.uk/ [rc2014]: https://rc2014.co.uk/
[zasm]: ../tools/emul/README.md [zasm]: ../emul/README.md
[libz80]: https://github.com/ggambetta/libz80 [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 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)
$(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 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 $(OBJS) shell/shell-bin.h shell/shell: shell/shell.c $(SHELLOBJS) shell/shell-bin.h
$(CC) shell/shell.c $(OBJS) -o $@ $(CC) shell/shell.c $(SHELLOBJS) -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
@ -29,17 +30,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 $(OBJS) zasm/kernel-bin.h zasm/zasm-bin.h $(CFSPACK) $(ZASMBIN): zasm/zasm.c $(ZASMOBJS) zasm/kernel-bin.h zasm/zasm-bin.h
$(CC) zasm/zasm.c $(OBJS) -o $@ $(CC) zasm/zasm.c $(ZASMOBJS) -o $@
zasm/avra.bin: $(ZASMBIN) 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 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 $(OBJS) zasm/kernel-bin.h zasm/avra-bin.h $(AVRABIN): zasm/zasm.c $(ZASMOBJS) zasm/kernel-bin.h zasm/avra-bin.h
$(CC) -D AVRA zasm/zasm.c $(OBJS) -o $@ $(CC) -D AVRA zasm/zasm.c $(ZASMOBJS) -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 $@
@ -51,20 +52,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): $(CFSPACK_OBJ): ${@:%.o=%.c}
$(MAKE) -C ../cfspack $(MAKE) -C ../tools/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)
$(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 cfsin/user.h: shell/user.h
cp shell/user.h $@ cp shell/user.h $@
.PHONY: updatebootstrap .PHONY: updatebootstrap
updatebootstrap: $(ZASMBIN) updatebootstrap: $(ZASMBIN)
$(ZASMSH) $(KERNEL) < zasm/glue.asm > zasm/kernel.bin $(ZASMBIN) $(KERNEL) < zasm/glue.asm > zasm/kernel.bin
$(ZASMSH) $(KERNEL) $(APPS) zasm/user.h < $(APPS)/zasm/glue.asm > zasm/zasm.bin $(ZASMBIN) $(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 tools. After that, you can run `make` and it builds all applications.
## shell ## shell

View File

@ -4,6 +4,7 @@
#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
* *
@ -138,6 +139,17 @@ 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);
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; break;
default: default:
fprintf(stderr, "Usage: shell [-f fsdev]\n"); fprintf(stderr, "Usage: shell [-f fsdev]\n");
@ -146,25 +158,14 @@ int main(int argc, char *argv[])
} }
// Setup fs blockdev // Setup fs blockdev
if (fp == NULL) { if (fp == NULL) {
fp = popen("../cfspack/cfspack cfsin", "r"); fprintf(stderr, "Initializing filesystem from cfsin\n");
if (fp == NULL) { 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"); 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)); bool tty = isatty(fileno(stdin));
struct termios termInfo; struct termios termInfo;
if (tty) { if (tty) {

View File

@ -1,7 +1,10 @@
#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"
@ -51,6 +54,7 @@
// 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];
@ -58,8 +62,7 @@ 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[0x80000] = {0}; static uint8_t fsdev[MAX_FSDEV_SIZE] = {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;
@ -88,7 +91,7 @@ static uint8_t iord_stdin_seek()
static uint8_t iord_fsdata() static uint8_t iord_fsdata()
{ {
if (fsdev_ptr < fsdev_size) { if (fsdev_ptr < MAX_FSDEV_SIZE) {
return fsdev[fsdev_ptr++]; return fsdev[fsdev_ptr++];
} else { } else {
return 0; return 0;
@ -99,7 +102,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 >= fsdev_size) { } else if (fsdev_ptr >= MAX_FSDEV_SIZE) {
return 1; return 1;
} else { } else {
return 0; return 0;
@ -130,7 +133,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 < fsdev_size) { if (fsdev_ptr < MAX_FSDEV_SIZE) {
fsdev[fsdev_ptr++] = val; fsdev[fsdev_ptr++] = val;
} }
} }
@ -159,11 +162,50 @@ 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[])
{ {
if (argc > 3) { char *init_org = "00";
fprintf(stderr, "Too many args\n"); while (1) {
return 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(); Machine *m = emul_init();
m->iord[STDIO_PORT] = iord_stdio; m->iord[STDIO_PORT] = iord_stdio;
@ -182,31 +224,9 @@ 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,9 +1,10 @@
TARGET = os.bin TARGET = os.bin
ZASM = ../../tools/zasm.sh BASEDIR = ../..
KERNEL = ../../kernel ZASM = $(BASEDIR)/emul/zasm/zasm
APPS = ../../apps KERNEL = $(BASEDIR)/kernel
APPS = $(BASEDIR)/apps
.PHONY: all .PHONY: all
all: $(TARGET) all: $(TARGET)
$(TARGET): glue.asm $(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: 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. Running `make` will also work.

View File

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

View File

@ -33,7 +33,6 @@ 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,9 +2,10 @@ 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
ZASM = ../../../tools/zasm.sh BASEDIR = ../../..
KERNEL = ../../../kernel ZASM = $(BASEDIR)/emul/zasm/zasm
APPS = ../../../apps KERNEL = $(BASEDIR)/kernel
APPS = $(BASEDIR)/apps
# Rules # Rules
@ -14,13 +15,13 @@ all: $(TARGETS)
@echo Done! @echo Done!
send: $(PROGNAME).hex send: $(PROGNAME).hex
avrdude $(AVRDUDEARGS) -p $(AVRDUDEMCU) -U flash:w:$< avrdude $(AVRDUDEARGS) -p $(AVRDUDEMCU) -U flash:w:$(PROGNAME).hex
$(PROGNAME).hex: $(PROGNAME).asm $(PROGNAME).hex: $(PROGNAME).asm
avra -o $@ $< avra -o $@ $(PROGNAME).asm
os.bin: glue.asm os.bin: glue.asm
$(ZASM) $(KERNEL) $(APPS) < $< > $@ $(ZASM) $(KERNEL) $(APPS) < glue.asm > $@
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
TOOLS = ../../../tools BASEDIR = ../../..
ZASM = $(TOOLS)/zasm.sh ZASM = $(BASEDIR)/emul/zasm/zasm
KERNEL = ../../../kernel KERNEL = $(BASEDIR)/kernel
APPS = ../../../apps APPS = $(BASEDIR)/apps
CFSPACK = $(TOOLS)/cfspack/cfspack CFSPACK = $(BASEDIR)/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) < $< > $@ $(ZASM) $(KERNEL) $(APPS) < glue.asm > $@
$(CFSPACK): $(CFSPACK):
make -C $(TOOLS)/cfspack make -C $(BASEDIR)/tools/cfspack
sdcard.cfs: cfsin $(CFSPACK) sdcard.cfs: cfsin $(CFSPACK)
$(CFSPACK) $< > $@ $(CFSPACK) cfsin > $@

View File

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

View File

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

View File

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

View File

@ -1,20 +1,21 @@
ZASM = ../../../tools/zasm.sh BASEDIR = ../../..
KERNEL = ../../../kernel ZASM = $(BASEDIR)/emul/zasm/zasm
APPS = ../../../apps KERNEL = $(BASEDIR)/kernel
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 19 $(KERNEL) $(APPS) user.h < $< > $@ $(ZASM) -o 1f $(KERNEL) $(APPS) user.h < $(APPS)/ed/glue.asm > $@
# -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 1d $(KERNEL) $(APPS) user.h < $< > $@ $(ZASM) -o 24 $(KERNEL) $(APPS) user.h < $(APPS)/zasm/glue.asm > $@
os.sms: glue.asm ed.bin zasm.bin 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: clean:
rm -f os.sms ed.bin zasm.bin rm -f os.sms ed.bin zasm.bin

View File

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

View File

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

View File

@ -2,10 +2,9 @@
set -e set -e
# TODO: find POSIX substitute to that PIPESTATUS thing # TODO: find POSIX substitute to that PIPESTATUS thing
BASE=../../.. BASE=../..
TOOLS=../.. ZASM="${BASE}/emul/zasm/zasm"
ZASM="${TOOLS}/zasm.sh" RUNBIN="${BASE}/emul/runbin/runbin"
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=../../zasm.sh ZASM=../../emul/zasm/zasm
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
KERNEL=../../../kernel BASE=../..
APPS=../../../apps KERNEL="${BASE}/kernel"
ZASM=../../zasm.sh APPS="${BASE}/apps"
ASMFILE=${APPS}/zasm/instr.asm ZASM="${BASE}/emul/zasm/zasm"
cmpas() { cmpas() {
FN=$1 FN=$1

1
tools/.gitignore vendored
View File

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

View File

@ -1,10 +1,12 @@
TARGETS = cfspack cfsunpack TARGETS = cfspack cfsunpack
CFSPACK_OBJS = cfspack.o libcfs.o
.PHONY: all .PHONY: all
all: $(TARGETS) all: $(TARGETS)
cfspack: cfspack.c cfspack: $(CFSPACK_OBJS)
$(CC) $(CFLAGS) -o $@ cfspack.c $(CC) $(LDFLAGS) -o $@ $(CFSPACK_OBJS)
cfsunpack: cfsunpack.c cfsunpack: cfsunpack.c
$(CC) $(CFLAGS) -o $@ 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 <libgen.h>
#include <sys/stat.h> #include <sys/stat.h>
#define BLKSIZE 0x100 #include "cfs.h"
#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()
{ {

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