# z80mbc2

## Conversion scripts for CP/M file transfers

To code on the Z80-MBC2 and V20-MBC homebrew computers I often transfer text files to and from their CP/M environments.

In one direction I send files from Crostini Linux by dumping them to CP/M, where PIP saves the text to CP/M files. In the opposite direction I run PIP on CP/M to print the files to the screen, where Minicom captures the text and saves it to files on Crostini.

CP/M and Unix have different line break and end of file encodings. In addition, the transfer process may introduce unwanted text. That's why the text files exchanged between the systems need some conversion, to automate which I wrote two short Bash scripts.

The first script, unix2cpm, converts line breaks and the end of file marker in the input to the CP/M encoding and prints the result to stdout. If the optional file name argument isn't supplied the script reads from stdin with a technique I researched. This is the script:

#!/usr/bin/env bash

# Convert line breaks and end of file from Unix to CP/M.
#
# Usage:
#
#   unix2cpm [filename]
#
# Reads from stdin if the optional argument is missing.

input_file="${1:-/dev/stdin}" cat "$input_file" | unix2dos
echo -e -n '\x1a'


The script calls unix2dos distributed with the dos2unix / unix2dos tools. unix2dos converts line breaks from Unix to MS-DOS, which borrows the encoding from CP/M. unix2cpm needs only to append with echo the ^Z end of file control character.

Once converted, the file is ready to be dumped from Linux to CP/M.

I initiate file transfers in the oppostite direction by executing the Minicom command to capture the terminal output to a file, Ctrl-A L (Capture on/off). Then, at the CP/M prompt, I execute a command like this to print a file to the console:

A>a:pip con:=filename.txt


When printing ends and the A> prompt reappears, I turn off output capture in Minicom to close the capture file. The captured output contains the PIP command in the first line, then the text of the file, and finally the A> prompt in the last line.

To remove the unwanted first and last line I wrote the second script, skipfl (skip first and last). Again, the script reads from stdin if the optional file name isn't supplied and writes to stdout. The code is:

#!/usr/bin/env bash

# Skip the first and last file of the argument file
#
# Usage:
#
#   skipfl [filename]
#
# Reads from stdin if the optional argument is missing.

input_file="${1:-/dev/stdin}" cat "$input_file" | sed '1d' | sed '$d'  The script calls sed to delete the first and last line with the d command. No further processing of the captured CP/M output file is necessary as Minicom takes care of inserting the proper line break and end of file encodings. ## Fixing the Turbo Pascal terminal configuration on CP/M Turbo Pascal 3.0 for CP/M has a display issue I noticed on the Z80-MBC2 and V20-MBC homebrew computers. When using the development environment, text in the terminal remained stuck with boldface turned on. It was enough to launch Turbo Pascal and execute any command (e.g. compiler Options), or exit Turbo Pascal, to turn on boldface and leave it stuck in the IDE, in CCP, and when running other programs. Everything went bold such as code in source files edited in Turbo Pascal, CCP command lines, and the output of transient programs. The issue occurred under CP/M 3.0 on the Z80-MBC2 and CP/M-86 1.1 on the V20-MBC, both accessed from the Minicom terminal emulator under Crostini Linux on my Chromebox. I tried ANSI and VT102 emulation in Minicom and run the Turbo Pascal configuration utility TINST to set the terminal to ANSI, but the issue persisted. The only workaround was to resize the terminal window, which reinitializes the display. I posted to comp.os.cpm for help and learnt Borland left the terminal reset string blank in the ANSI entry, which thus doesn't reset text attributes. The fix was simple. I run TINST, selected the ANSI terminal, and edited the definition to insert the following reset string via the option Send a reset string to the terminal (the corresponding escape code strings and descriptions are below the hex values): $1b $63$1b  $5b$32 \$4a

ESC c      ESC  [   2   J
Reset      Clear screen


ESC c is not enough as it only resets the terminal but doesn't clear the screen. With the new string the text attributes are now properly handled and the terminal is no longer stuck in boldface after using Turbo Pascal.

## Rediscovering Turbo Pascal

Turbo Pascal 3 for CP/M comes preinstalled with the Z80-MBC2 and V20-MBC homebrew computers. Checking out the development environment made me rediscover Turbo Pascal and realize its potential for programming these computers.

Although I owned Turbo Pascal for MS-DOS in the early 1990s, I didn't use it much. Between other languages later getting my attention and Borland losing its market leadership, I eventually forgot about Turbo Pascal. Now, with the development environment handy on the Z80-MBC2 and V20-MBC, I began checking out the Turbo Pascal CP/M version I had never played with.

Being familiar with the Turbo Pascal MS-DOS IDE, which features a nice text user interface with pull-down menus and dialogs, the CP/M version seemed spartan and primitive.

But I pressed ahead, tried the various commands, edited and compiled some code, and got familiar with the keystrokes and workflow. I soon felt at ease with Turbo Pascal for CP/M. The environment is still suprisingly usable and productive, allowing fast edit-compile-run cycles with short compilation times even on the 8-bit Z80-MBC2.

I now understand why Turbo Pascal made such a sensation at the time and revolutionized development tools.

To learn the Turbo Pascal environment and language I began reading the manual, as well as books about Turbo Pascal and Pascal. The more I used Turbo Pascal and read about it, the more I enjoyed it and wanted to learn and explore.

Next thing I knew, I was down a rabbit hole.

This experimentation and reading made me realize the potential of Turbo Pascal as an ideal tool for hobby projects with these homebrew computers.

Pascal is an easy to understand, readbale, and expressive language. Despite the age and design flaws, it allows to write fairly advanced code. Pascal makes practicality win over language purity.

Sitting at a sweet spot between ease of use, features, and power, Turbo Pascal is a perfect fit for CP/M as it consumes limited resources, generates moderatly small and fast executables, and can access all the features of the system. That's why it's a good environment for quickly developing small tools or programs for the Z80-MBC2 and V20-MBC.

## October 26, 2022

On this blog I regularly share my retrocomputing experience and projects with the Z80-MBC2 and the V20-MBC homebrew computers. In addition, on my Mastodon account @amoroso@fosstodon.org I often post screenshots, links, videos, and other short updates grouped under the #z80mbc2 and #v20mbc hashtags.

## A minimal CP/M file transfer channel

Delivering files to the Z80-MBC2 and V20-MBC homebrew computers is an essential capability for bringing new software and data to these CP/M devices.

In particular I need a file upload capability, a way of transferring text files from the host system to the remote CP/M devices. Why just text? Because a text stream is the lowest common denominator. The simplest, most ubiquitous, and versatile communication channel.

Encoding binary files as text, such as the Intel HEX format for executables or uuencoding, enables moving arbitrary files over text streams.

## The problem

I want to transfer files in the most practical way, i.e. via the serial USB connection from the host system, my Chromebox (where the terminal emulator for controlling the devices runs under Crostini Linux), to the remote devices. I could copy the files to the microSD cards the homebrew computers use to simulate storage devices like hard disks, but this would require additional steps.

An obvious solution would be a file transfer protocol like the XMODEM utility that comes with the Z80-MBC2. But XMODEM file upload to the Z80-MBC2 has issues and the V20-MBC doesn't have XMODEM or other file transfer software preinstalled.

My initial workaround, dumping a text file from the terminal into a CP/M text editor, does the job but creates friction. I wanted a minimal upload channel with less friction, that relies only on native CP/M features, and can work also on the V20-MBC.

## The solution: a minimal file transfer channel

I came up with a similar but more streamlined solution.

Like in the workaround, on Linux the process consists in dumping a text file from the terminal emulator.

But on CP/M, instead of running the ed editor to collect the file and manually save it, PIP automatically receives and saves the file. An additional advantage is PIP can handle arbitrarily long files whereas ed is limited to available memory.

There's a reason the CP/M system utility PIP is called Peripheral Interchange Program — emphasis mine. In addition to copying, renaming, and combining files, PIP can transfer data to and from the console and other peripherals. The new transfer channel relies on this feature by receiving the text coming from the console associated with the terminal emulator, and saving it to a file.

## The process

How does transfers over this channel work? I initiate file uploads on Linux from the Minicom terminal emulator.

First, to introduce a character trasmission delay I change Minicom's settings with the Ctrl-A T F command, Terminal settings > Character tx delay (ms). A value of 1 ms works well on both the Z80-MBC2 and the V20-MBC.

Why a delay? Although the homebrew computers are connected via a 115200 bps serial link, these 8-bit and 16-bit systems can't keep up with the full speed with which the 64-bit Intel i7 Chrombox can pump data. Hence the need for a transmission delay.

Next, at the CP/M prompt I launch PIP:

G>pip filename.txt=con:


Since the destination of the data before the = symbol preceeds the source, the command instructs PIP save to FILENAME.TXT the data coming from the logical device con:, the source. By default CON: is associated with the console, i.e. Minicom on Linux.

The above command makes PIP receive the text stream Minicom sends over the serial line as if typed by the user at the keyboard. How can Minicom type text virtually? The program's Ctrl-A Y Paste file command allows to select and dump a Linux file, which is the last step of the transfer.

Then, on CP/M, the incoming text is saved to a file and rapidly printed on the screen line by line. The transfer may take up to a few minutes depending on the file size.

When PIP terminates, the new file is ready. A caveat is CP/M expects text files to be encoded with specific line break and end of file control characters, i.e. ^M^J and ^Z, not ^J and ^D like on Linux. If the end of file is missing, PIP pauses until the ^Z keystroke is entered manually.

The procedure works well on both the Z80-MBC2 and the V20-MBC.

## Next steps

Dumping text files over a serial line is slow and more involved than dedicated file transfer protocols such as XMODEM, and works only one file at a time.

But text streams are universal, easy to use, and reliable. More importantly, these streams are the only way of uploading binary files encoded as text, such as executable programs not already stored on the remote device. For example, neither XMODEM nor other file transfer utilities are preinstalled under CP/M-86 on the V20-MBC.

I'll leverage this text channel to upload to the V20-MBC the Kermit communication program, which implements the transfer protocol by the same name. I'll see if Kermit can upload from Linux to the V20-MBC, and then the Z80-MBC2.

## Configuring disk drives for WordStar on CP/M

My memories of WordStar are fuzzy as I haven't been using it since the late 1980s and, even then, only on MS-DOS and not set up by me. So the errors for basic disk drive access functions I got from WordStar on CP/M surprised me.

My Z80-MBC2 and V20-MBC computers come with the word processor preinstalled, which runs under CP/M-80 on the former and CP/M-86 on the latter.

The e: drive holds the WordStar Release 4 files on the Z80-MBC2 with CP/M 3.0. I got an error about the program not finding its overlay files when starting it from a different drive, e.g. executing e:ws from F:. And the program's L command to change the logged drive to one other than A: or B: issued a file not found error.

Reading the manual clarified that, on CP/M-80, WordStar recognizes only A: and B: by default, but other drives can be accessed by installing the program with the INSTALL.COM utility or configuring it with WSCHANGE.COM.

The INSTALL.COM executable that ships with the Z80-MBC2 is designed for a version of WordStar different from the release 4 actually on the microcomputer. Therefore, I had to run WSCHANGE to change the settings with the option C (Computer: Disk Drives, WordStar Files > A (Disk Drives, Valid disk drives) > A (Valid disk drives).

The resulting configuration screen listed the valid disk drives, i.e. the floppy drives A: and B:, with the default where WordStar looks for the overlay files marked with an asterisk:

The screen also allowed to add the letters of valid drives one by one, with the first set as the default drive. I typed E as that's where WordStar's files are on the Z80-MBC2 under CP/M 3.0. Then I added more drive letters as the mciroSD storage of the device emulates the hard disks from A: to P:. For each drive I answered no to the question on whether it's a floppy:

Finally, the configuration program listed the new valid drives, i.e. A: through P: with E: coming first to indicate the default drive:

On the V20-MBC under CP/M-86, WordStar release 3.30 detects all the drives A: to P: out of the box, but the default drive where the program looks for its files still needed to be configured. No WSCHANGE utility comes with the word processor on my device, so I used the installation program WINSTALL.CMD to set C: as the default. C is where WordStar's files are stored on the V20-MBC.

## Files left out of the V20-MBC and Z80-MBC2

Just4Fun, the maker of the Z80-MBC2 and V20-MBC homebrew computers, clarfied to me the absence of some files is intentional.

Under CP/M-86, the TOD.CMD command for displaying and changing the date and time was left out because, on the V20-MBC, the date can be changed only from the boot and configuration menu. ASSIGN.CMD, a command for assigning physical to logical devices, is specific to the CP/M-86 version for the IBM PC and hence redundant on the V20-MBC.

Just4Fun doesn't recall exactly, but the absence of the Turbo Pascal sample .PAS files on the Z80-MBC2 is likely a consequence of the development process, possibly an early mass storage space constraint.

## A quick look at UCSD p-System on the Z80-MBC2

The Z80-MBC2 homebrew Z80 computer is a living retrocomputing museum that runs early microcomputer operating systems such as CP/M, QP/M, and UCSD p-System. Since the latter is the one I know least, I explore it with the Z80-MBC2.

On UCSD p-System the user runs programs and manages the system through a series of hierarchical menus, unlike the command interpreters of other operating systems. Navigating the menus down the hierarchy is easy, but sometimes I'm not sure how to get up one level. Pressing the Q key works most of the times, but occasionally nothing happens and I get stuck.

Running UCSD p-System gives a sense of how slow the output is on serial terminals. For example, a demo program to plot an ASCII sine wave takes almost 20 seconds over a 115200 bps serial line to the 8 MHz Z80-MBC2.

It's best demonstrated by this video, which shows the output as well as the menus:

Here the Z80-MBC2 runs in a Minicom terminal emulator session under Crostini Linux on my Chromebox.

## First attempt at porting a Z80 led blink demo to 8080

I ported to Intel 8080 Assembly the Z80-MBC2 Z80 code of the led blink demo, assembled it with the Suite8080 assembler, and uploaded the HEX binary to the Z80-MBC2. Instead of printing a message to the console and blinking the User led, the program made the led turn on and the board reset, booting up the default operating system.

I have no tools to debug software that runs on the bare metal. So the next step is to investigate these clues, starting from a comparison of the Z80 and 8080 sources.

## Testing HEX file upload to the Z80-MBC2

One of the Z80-MBC2 boot menu options, iLoad, allows uploading an executable program in Intel HEX format. This is cool because it enables running code on the bare metal with no operating system, such as a resident monitor or software that directly accesses the hardware.

To test iLoad I uploaded and run a demo to the Z80-MBC2, a Z80 Assembly program that prints a message to the console and blinks the board's User LED.

The source file, Blink demo Z80-MBC2.asm, is included in the sources of the Z80-MBC2 firmware in directory src. I assembled the program with the zasm Z80 assembler and converted it to HEX format with the bin2hex tool that comes with the z80pack Z80 emulator.

The screenshot shows the steps for uploading the demo to the Z80-MBC2 and running it. It's a Minicom session under Crostini Linux on my Chromebox.

First off, I brought up the Z80-MBC2 boot menu. After selecting the iLoad option, the Z80-MBC2 waited for the file transfer to start.

Next, in Minicom I executed the Paste file command (activated by the Ctrl+A Y keystroke), which reads an ASCII file and sends its contents as if it were typed in, and selected the program file blink.hex. A few seconds later the message Z80-MBC2 User led blink demo running... appeared on the console and the board's User led started blinking.

I completed the process successfully only after tweaking the transmission parameters.

The Z80-MBC2 developer notes the board's serial port can't handle high-speed data transfers, and advises to set a 50-90 ms newline transmission delay in the settings of the terminal emulator used for the transfer.

In Minicon I set the delay with the Newline Tx delay (Ctrl+A T D) option. But with my setup iLoad transfers abort even with delays up to 150 ms, causing the Z80-MBC2 to display a checksum error and halt.

To overcome the issue I set a character transmission delay of at least 5 ms with the Character Tx delay option (Ctrl+a T F).