diff --git a/kernel/trs80/kbd.asm b/kernel/trs80/kbd.asm new file mode 100644 index 0000000..49cc088 --- /dev/null +++ b/kernel/trs80/kbd.asm @@ -0,0 +1,10 @@ +; kbd - TRS-80 keyboard +; +; Implement GetC for TRS-80's keyboard using the system's SVCs. + +trs80GetC: + push de ; altered by SVC + ld a, 0x01 ; @KEY + rst 0x28 ; --> A + pop de + ret diff --git a/kernel/trs80/vid.asm b/kernel/trs80/vid.asm new file mode 100644 index 0000000..9ba6e7c --- /dev/null +++ b/kernel/trs80/vid.asm @@ -0,0 +1,16 @@ +; vid - TRS-80's video +; +; Implement PutC using TRS-80's SVC calls so that character it put on video +; display. + +trs80PutC: + push af + push bc + push de ; altered by SVC + ld c, a + ld a, 0x02 ; @DSP + rst 0x28 + pop de + pop bc + pop af + ret diff --git a/recipes/trs80/Makefile b/recipes/trs80/Makefile new file mode 100644 index 0000000..190d3aa --- /dev/null +++ b/recipes/trs80/Makefile @@ -0,0 +1,10 @@ +TARGET = os.bin +BASEDIR = ../.. +ZASM = $(BASEDIR)/emul/zasm/zasm +KERNEL = $(BASEDIR)/kernel +APPS = $(BASEDIR)/apps + +.PHONY: all +all: $(TARGET) +$(TARGET): glue.asm + $(ZASM) $(KERNEL) $(APPS) < glue.asm > $@ diff --git a/recipes/trs80/README.md b/recipes/trs80/README.md index 072cdf4..b3f49c5 100644 --- a/recipes/trs80/README.md +++ b/recipes/trs80/README.md @@ -4,7 +4,20 @@ The TRS-80 (models 1, 3 and 4) are among the most popular z80 machines. They're very nicely designed and I got my hands on a 4p with two floppy disk drives and a RS-232 port. In this recipe, we're going to get Collapse OS running on it. -**This is a work in progress. Collapse OS doesn't run on it yet.** +![Collapse OS on a TRS-80 Model 4P](collapseos-on-trs80.jpg) + +## Not entirely standalone + +Collapse OS uses the TRS-80 drivers rather than its own. On most TRS-80 models, +those drivers are on ROM, but in the case of the 4P model, those drivers are on +the TRSDOS disk (well, from what I understand, not all of it, but still, a big +part of it). + +It would be preferable to develop drivers from scratch, but it represents a +significant effort for a modest payout (because it's only actually useful when +you want to use a 4P model that has no TRSDOS disk). + +Maybe those drivers will be developed later, but it's not a priority for now. ## Floppy or RS-232? @@ -50,6 +63,11 @@ my knowledge. As far as I know, the COMM program doesn't allow this. What are we going to do? We're going to punch in a binary program to handle that kind of reception! You're gonna feel real badass about it too... +## Building the binary + +You can start the process by building the binary. Running `make` in this folder +will yield a `os.bin` file. You'll need it later. + ## Testing serial communication The first step here is ensuring that you have bi-directional serial @@ -93,6 +111,8 @@ press the `BREAK` key. You'll get the debug interface which allows you to punch in any data in any memory address. Let's use `0x4000` which is the offset it's designed for. +For reference: to go back to the TRSDOS prompt, it's `o`. + First, display the `0x4000-0x403f` range with the `d4000` command (I always press Enter by mistake, but it's space you need to press). Then, you can begin punching in with `h4000`. This will bring up a visual indicator of @@ -117,34 +137,6 @@ driver was loaded in `0x0ff4` and the DCB address was 8 bytes after that, with a value of `0x0238`. Don't forget that z80 is little endian. `38` will come before `02`. -## Sending data through the RS-232 port - -Once you're finished punching your program in memory, you can run it with -`g4000` (not space). Because it's an infinite loop, your screen will -freeze. You can start sending your data. - -To that end, there's the `tools/pingpong` program. It takes a device and a -filename to send. As a test, send anything, but make it go through -`tools/ttysafe` first (which just takes input from stdin and spits tty-safe -content to stdout). - -On OpenBSD, the invocation can look like: - - doas ./pingpong /dev/ttyU0 mystuff.ttysafe - -You will be prompted for a key before the contents is sent. This is because on -OpenBSD, TTY configuration is lost as soon as the TTY is closed, which means -that you can't just run `stty` before running `pingpong`. So, what you'll do is, -before you press your key, run `doas stty -f /dev/ttyU0 300 raw` and then press -any key on the `pingpong` invocation. - -If everything goes well, the program will send your contents, verifying every -byte echoed back, and then send a null char to indicate to the receiving end -that it's finished sending. This will end the infinite loop on the TRS-80 side -and return. That should bring you back to a refreshed debug display and you -should see your sent content in memory, at the specified address (`0x3040` if -you didn't change it). - ## Saving that program for later If you want to save yourself typing for later sessions, why not save the @@ -159,4 +151,47 @@ A memory range dumped this way will be re-loaded at the same offset through using the `RUN` command. Therefore, you can avoid all this work above in later sessions by simply typing `recv` in the DOS prompt. -**WIP: that's where we are for now...** +## Sending binary through the RS-232 port + +Once you're finished punching your program in memory, you can run it with +`g4000` (not space). If you've saved it to disk, run `recv` instead. +Because it's an infinite loop, your screen will freeze. You can start sending +your data. + +To that end, there's the `tools/pingpong` program. It takes a device and a +filename to send. Before you send the binary, make it go through +`tools/ttysafe` first (which just takes input from stdin and spits tty-safe +content to stdout): + + ./ttysafe < os.bin > os.ttysafe + +On OpenBSD, the invocation can look like: + + doas ./pingpong /dev/ttyU0 os.ttysafe + +You will be prompted for a key before the contents is sent. This is because on +OpenBSD, TTY configuration is lost as soon as the TTY is closed, which means +that you can't just run `stty` before running `pingpong`. So, what you'll do is, +before you press your key, run `doas stty -f /dev/ttyU0 300 raw` and then press +any key on the `pingpong` invocation. + +If everything goes well, the program will send your contents, verifying every +byte echoed back, and then send a null char to indicate to the receiving end +that it's finished sending. This will end the infinite loop on the TRS-80 side +and return. That should bring you back to a refreshed debug display and you +should see your sent content in memory, at the specified address (`0x3000` if +you didn't change it). + +If there was no error during `pingpong`, the content should be exact. +Nevertheless, I recommend that you manually validate a few bytes using TRSDOS +debugger before carrying on. + +## Running Collapse OS + +If everything went well, you can run Collapse OS with `g3000`. You'll +get a usable Collapse OS prompt! + +Like with the `recv` program, nothing stops you from dumping that binary to a +floppy. + +Have fun! diff --git a/recipes/trs80/collapseos-on-trs80.jpg b/recipes/trs80/collapseos-on-trs80.jpg new file mode 100644 index 0000000..867068d Binary files /dev/null and b/recipes/trs80/collapseos-on-trs80.jpg differ diff --git a/recipes/trs80/glue.asm b/recipes/trs80/glue.asm new file mode 100644 index 0000000..8718164 --- /dev/null +++ b/recipes/trs80/glue.asm @@ -0,0 +1,47 @@ +; RAMSTART is a label at the end of the file +.equ RAMEND 0xcfff + +; Free memory in TRSDOS starts at 0x3000 +.org 0x3000 + jp init + +.inc "err.h" +.inc "ascii.h" +.inc "core.asm" +.inc "str.asm" + +.inc "trs80/kbd.asm" +.inc "trs80/vid.asm" + +.equ STDIO_RAMSTART RAMSTART +.equ STDIO_GETC trs80GetC +.equ STDIO_PUTC trs80PutC +.inc "stdio.asm" + +; *** BASIC *** + +; RAM space used in different routines for short term processing. +.equ SCRATCHPAD_SIZE STDIO_BUFSIZE +.equ SCRATCHPAD STDIO_RAMEND +.inc "lib/util.asm" +.inc "lib/ari.asm" +.inc "lib/parse.asm" +.inc "lib/fmt.asm" +.equ EXPR_PARSE parseLiteralOrVar +.inc "lib/expr.asm" +.inc "basic/util.asm" +.inc "basic/parse.asm" +.inc "basic/tok.asm" +.equ VAR_RAMSTART SCRATCHPAD+SCRATCHPAD_SIZE +.inc "basic/var.asm" +.equ BUF_RAMSTART VAR_RAMEND +.inc "basic/buf.asm" +.equ BAS_RAMSTART BUF_RAMEND +.inc "basic/main.asm" + +init: + ld sp, RAMEND + call basInit + jp basStart + +RAMSTART: