2020-10-30 20:31:47 -04:00
|
|
|
# TRS-80 Model 4p
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
# 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?
|
|
|
|
|
|
|
|
There are many ways to get Collapse OS to run on it. One would
|
|
|
|
involve writing it to a floppy. I bought myself old floppy
|
|
|
|
drives for that purpose, but I happen to not have any functional
|
|
|
|
computer with a floppy port on it. I still have the motherboard
|
|
|
|
of my old pentium, but I don't seem to have a video card for it
|
|
|
|
any more.
|
|
|
|
|
|
|
|
Because my 4p has a RS-232 port and because I have equipment to
|
|
|
|
do serial communication from modern machines (I didn't have a
|
|
|
|
DB-9 to DB-25 adapter though, I had to buy one), I chose that
|
|
|
|
route.
|
|
|
|
|
|
|
|
# Gathering parts
|
|
|
|
|
|
|
|
* A TRS-80 model 4p with a RS-232 port
|
|
|
|
* A TRSDOS 6.x disk
|
|
|
|
* A means to do serial communication. In my case, that meant:
|
|
|
|
* A USB-to-serial device
|
|
|
|
* A null modem cable
|
|
|
|
* A DB-9 gender changer
|
|
|
|
* A DB-9 to DB-25 adapter
|
|
|
|
|
|
|
|
# Overview
|
|
|
|
|
|
|
|
We need to send sizeable binary programs through the RS-232 port
|
|
|
|
and then run it. The big challenge here is ensuring data
|
|
|
|
integrity. Sure, serial communication has parity check, but it
|
|
|
|
has no helpful way of dealing with parity errors. When parity
|
|
|
|
check is enabled and that a parity error occurs, the byte is
|
|
|
|
simply dropped on the receiving side. Also, a double bit error
|
|
|
|
could be missed by those checks.
|
|
|
|
|
|
|
|
What we'll do here is to ping back every received byte back and
|
|
|
|
have the sender do the comparison and report mismatched data.
|
|
|
|
|
|
|
|
Another problem is ASCII control characters. When those are sent
|
|
|
|
across serial communication channels, all hell breaks lose. When
|
|
|
|
sending binary data, those characters have to be avoided. We use
|
|
|
|
tools/ttysafe for that.
|
|
|
|
|
|
|
|
Does TRSDOS have a way to receive this binary inside these
|
|
|
|
constraints? Not to 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...
|
|
|
|
|
2020-12-17 15:32:13 -05:00
|
|
|
# Keyboard cheatcheet
|
2020-10-30 20:31:47 -04:00
|
|
|
|
2020-12-17 15:32:13 -05:00
|
|
|
The TRS-80 4P keyboard doesn't show all available characters.
|
|
|
|
When you hold CLEAR, you can do:
|
|
|
|
|
|
|
|
_ --> ENTER
|
|
|
|
[] --> <>
|
|
|
|
^ --> ;
|
|
|
|
\ --> /
|
2020-10-30 20:31:47 -04:00
|
|
|
|
|
|
|
# Building the binary
|
|
|
|
|
|
|
|
You can build the binary to send to the TRS-80 with "make" in
|
|
|
|
/arch/z80/trs80, which will yield
|
|
|
|
"os.bin". You'll need it later.
|
|
|
|
|
|
|
|
# Testing serial communication
|
|
|
|
|
|
|
|
The first step here is ensuring that you have bi-directional
|
|
|
|
serial communication. To do this, first prepare your TRS-80:
|
|
|
|
|
|
|
|
set *cl to com
|
|
|
|
setcomm (word=8,parity=no)
|
|
|
|
|
|
|
|
The first line loads the communication driver from the COM/DRV
|
|
|
|
file on the TRSDOS disk and binds it to *cl, the name generally
|
|
|
|
used for serial communication devices. The second line sets
|
|
|
|
communication parameters in line with what is generally the
|
|
|
|
default on modern machine. Note that I left the default of 300
|
|
|
|
bauds as-is.
|
|
|
|
|
|
|
|
Then, you can run "COMM *cl" to start a serial communication
|
|
|
|
console.
|
|
|
|
|
|
|
|
Then, on the modern side, use your favorite serial communication
|
|
|
|
program and set the tty to 300 baud with option "raw". Make sure
|
|
|
|
you have -parenb.
|
|
|
|
|
|
|
|
If your line is good, then what you type on either side should
|
|
|
|
echo on the other side. If it does not, something's wrong.
|
|
|
|
Debug.
|
|
|
|
|
|
|
|
# Punching in the goodie
|
|
|
|
|
|
|
|
As stated in the overview, we need a program on the TRS-80 that:
|
|
|
|
|
|
|
|
1. Listens to *cl
|
|
|
|
2. Echoes each character back to *cl
|
|
|
|
3. Adjusts ttysafe escapes
|
|
|
|
4. Stores received bytes in memory
|
|
|
|
|
|
|
|
You're in luck: that program has already been written. It's in
|
|
|
|
B612 and B613 in /arch/z80/trs80/blk. By running "make" earlier,
|
|
|
|
you have, in your current folder, a blkfs that contains those
|
|
|
|
blocks. To have a forth running on it, you could overwrite
|
|
|
|
/cvm/blkfs and run /cvm/forth. You can then compile it with:
|
|
|
|
|
|
|
|
5 LOAD ( z80 assembler )
|
|
|
|
0x0238 CONSTANT COM_DRV_ADDR
|
|
|
|
0x3000 CONSTANT DEST_ADDR
|
|
|
|
612 LOAD
|
|
|
|
613 LOAD
|
|
|
|
|
|
|
|
Then, you can use "DUMP" to visualize the data you'll need to
|
|
|
|
punch in:
|
|
|
|
|
|
|
|
H@ ORG @ - ORG @ DUMP
|
|
|
|
|
|
|
|
It can run from any offset (all jumps in it are relative), but
|
|
|
|
writes to DEST_ADDR. Make sure you don't place it in a way to be
|
|
|
|
overwritten by its received data.
|
|
|
|
|
|
|
|
Wondering what is that COM_DRV_ADDR constant? That's the DCB
|
|
|
|
handle of your *cl device. You will need to get that address
|
|
|
|
before you continue. Go read the following section and come back
|
|
|
|
here.
|
|
|
|
|
|
|
|
How will you punch that in? The "debug" program! This very
|
|
|
|
useful piece of software is supplied in TRSDOS. To invoke it,
|
|
|
|
first run "debug (on)" and then 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 0x5000 which is the offset it's
|
|
|
|
designed for.
|
|
|
|
|
|
|
|
For reference: to go back to the TRSDOS prompt, it's
|
|
|
|
"o<return>".
|
|
|
|
|
|
|
|
First, display the 0x5000-0x503f range with the d5000<space>
|
|
|
|
command (I always press Enter by mistake, but it's space you
|
|
|
|
need to press). Then, you can begin punching in with
|
|
|
|
h5000<space>. This will bring up a visual indicator of the
|
|
|
|
address being edited. Punch in the stuff with a space in between
|
|
|
|
each byte and end the edit session with "x".
|
|
|
|
|
|
|
|
# Getting your DCB address
|
|
|
|
|
|
|
|
In the previous step, you need to set COM_DRV_ADDR to your "DCB"
|
|
|
|
address for *cl. That address is your driver "handle". To get
|
|
|
|
it, first get the address where the driver is loaded in memory.
|
|
|
|
You can get this by running "device (b=y)". That address you see
|
|
|
|
next to *cl? that's it. But that's not our DCB.
|
|
|
|
|
|
|
|
To get your DBC, go explore that memory area. Right after the
|
|
|
|
part where there's the *cl string, there's the DCB address
|
|
|
|
(little endian). On my setup, the 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.
|
|
|
|
|
|
|
|
# Saving that program for later
|
|
|
|
|
|
|
|
If you want to save yourself typing for later sessions, why not
|
|
|
|
save the program you've painfully typed to disk? TRSDOS enables
|
|
|
|
that easily. Let's say that you typed your program at 0x5000 and
|
|
|
|
that you want to save it to RECV/CMD on your second floppy
|
|
|
|
drive, you'd do:
|
|
|
|
|
|
|
|
dump recv/cmd:1 (start=x'5000',end=x'5030',tra='5000')
|
|
|
|
|
|
|
|
A memory range dumped this way will be re-loaded at the same
|
|
|
|
offset through "load recv/cmd:1". Even better, TRA indicates
|
|
|
|
when to jump after load when using the RUN command. Therefore,
|
|
|
|
you can avoid all this work above in later sessions by simply
|
|
|
|
typing "recv" in the DOS prompt.
|
|
|
|
|
|
|
|
Note that you might want to turn "debug" off for these commands
|
|
|
|
to run. I'm not sure why, but when the debugger is on, launching
|
|
|
|
the command triggers the debugger.
|
|
|
|
|
|
|
|
# Sending binary through the RS-232 port
|
|
|
|
|
|
|
|
Once you're finished punching your program in memory, you can
|
|
|
|
run it with g5000<enter> (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 < stage1.bin > stage1.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.
|
|
|
|
|
|
|
|
*debugging tip*: Sometimes, the communication channel can be a
|
|
|
|
bit stubborn and always fail, as if some leftover data was
|
|
|
|
consistently blocking the channel. It would cause a data
|
|
|
|
mismatch at the very beginning of the process, all the time.
|
|
|
|
What I do in these cases is start a "COMM *cl" session on one
|
|
|
|
side and a screen session on the other, type a few characters,
|
|
|
|
and try pingpong again.
|
|
|
|
|
|
|
|
# Saving to disk
|
|
|
|
|
|
|
|
If everything went well, you could run Collapse OS with
|
|
|
|
g3000<return>. But instead of doing that, why not save it to
|
|
|
|
disk?
|
|
|
|
|
|
|
|
dump cos/cmd:1 (start=x'5000',end=x'7000',tra='5000')
|
|
|
|
|
|
|
|
And there we go! A Collapse OS launchable from floppy!
|
|
|
|
|
|
|
|
# Sending blkfs to floppy
|
|
|
|
|
|
|
|
As it is, your system fully supports reading and writing to
|
2020-12-25 16:54:02 -05:00
|
|
|
floppy drive 1. It also had CL< to read a char from its RS-232
|
|
|
|
port and CL> to emit to it.
|
2020-10-30 20:31:47 -04:00
|
|
|
|
|
|
|
That's all you need to have a full Collapse OS with access to
|
|
|
|
disk blocks.
|
|
|
|
|
|
|
|
First, make sure your floppies are formatted. Collapse OS is
|
|
|
|
currently hardcoded to single side and single density, which
|
|
|
|
means there's a limit of 100 blocks per disk.
|
|
|
|
|
2020-12-25 16:54:02 -05:00
|
|
|
You'll need to send those blocks through RS-232. First, let's
|
|
|
|
initialize the driver with CL$. This driver does not require
|
|
|
|
the TRS-DOS driver to be loaded. Also, it is hardcoded to
|
2021-01-03 13:56:53 -05:00
|
|
|
"no parity, 8 bit words". And takes a "baud code" as an argu-
|
|
|
|
ment. It's a 0-15 value with these meanings:
|
|
|
|
|
|
|
|
00 50 01 75 02 110 03 134.5
|
|
|
|
04 150 05 300 06 600 07 1200
|
|
|
|
08 1800 09 2000 0a 2400 0b 3800
|
|
|
|
0c 4800 0d 7200 0e 9600 0f 19200
|
|
|
|
|
|
|
|
After CL$ is called, let's have the CL take over the prompt:
|
2020-10-30 20:31:47 -04:00
|
|
|
|
2020-12-25 16:54:02 -05:00
|
|
|
' CL> ' EMIT **!
|
|
|
|
' CL< ' KEY **!
|
2020-10-30 20:31:47 -04:00
|
|
|
|
2020-12-25 16:54:02 -05:00
|
|
|
See "Aliases" in usage.txt for details. Your serial link now has
|
|
|
|
the prompt. You will also have to make your newlines CRLF. The
|
|
|
|
TRS-80 wants CR only, but serial communications (and blkup)
|
|
|
|
expect CRLF:
|
2020-10-30 20:31:47 -04:00
|
|
|
|
|
|
|
' CRLF ' NL **!
|
|
|
|
|
|
|
|
Now, you can use /tools/blkup to send a disk's contents. First,
|
|
|
|
extract the first 100 blocks from blkfs:
|
|
|
|
|
|
|
|
dd if=emul/blkfs bs=1024 count=100 > d1
|
|
|
|
|
|
|
|
Now, insert your formatted disk in drive 1 and push your blocks:
|
|
|
|
|
|
|
|
tools/blkup /dev/ttyUSB0 0 d1
|
|
|
|
|
|
|
|
It takes a while, but you will end up having your first 100
|
|
|
|
blocks on floppy! Go ahead, LIST around. Then, repeat for other
|
|
|
|
disks.
|
|
|
|
|
|
|
|
# Floppy organisation
|
|
|
|
|
|
|
|
Making blkfs span multiple disk is a bit problematic with
|
|
|
|
regards to absolute block references in the code. You'll need to
|
|
|
|
work a bit to design your very own Collapse OS floppy set. See
|
|
|
|
/doc/usage.txt for details.
|
|
|
|
|
|
|
|
# Coming back to keyboard
|
|
|
|
|
|
|
|
Once you're done, you will want to go back to local control:
|
|
|
|
|
|
|
|
' CR ' NL **!
|
|
|
|
' (emit) ' EMIT **!
|
|
|
|
' (key) ' KEY **!
|
|
|
|
|
|
|
|
# Self-hosting
|
|
|
|
|
|
|
|
As it is, your installment of Collapse OS is self-hosting using
|
|
|
|
instructions from /doc/selfhost.txt. The difference is that
|
|
|
|
instead of writing the binary you have in memory to EEPROM,
|
|
|
|
you'll quit to TRSDOS with BYE and use TRSDOS' DUMP utility to
|
|
|
|
save to disk like you already did before.
|