Paolo Amoroso's Journal

cpm

I cross-develop CP/M programs on Linux with the Suite8080 assembler and run them on a number of platforms, from software emulators to the Z80-MBC2 computer. But to test the code I use an emulator for Linux called ANSI CP/M Emulator and disk image tool, or just CPM.

CPM is unique in that it reduces development and testing friction. The emulator can execute CP/M programs stored on the Linux file system by passing CP/M executable files as arguments, such as:

$ cpm cpmprog

where cpm is the emulator and cpmprog.com is a .COM file on Linux. In addition, the current Linux directory appears as the A: drive from CP/M, so any .COM files there on Linux can be executed from CP/M like this:

A>cpmprog

Again, cpmprog.com is a .COM file on Linux.

This feature shortens the development cycle, as the emulator can access program files cross-assembled on the same file system it runs on.

Other emulators require copying files to disk images and mounting the images from the emulated environment. And before they can be run on the Z80-MBC2 or other hardware, CP/M programs need to be transferred via XMODEM or other means.

Once a .COM program is tested and debugged, I run it on richer CP/M environments like the z80pack emulator or the Z80-MBC2.

#retrocomputing #cpm

Discuss... Email | Reply @amoroso@oldbytes.space

I develop programs for the Z80-MBC2 in Intel 8080 Assembly with the Suite8080 8080 assembler. Aside from the binary compatibility, the Z80-MBC2 is a Z80 system, so I wondered what Assembly mnemonics and register set the CP/M development tools work with.

It turns out my favorite CP/M debugger, the SID symbolic debugger, comes in two versions specialized on the CPU, SID and ZSID.

SID accepts as input and outputs 8080 mnemonics and registers, ZSID Z80 mnemonics and registers. For example, in this CP/M 3.0 SID session on the Z80-MBC2 I loaded my Twirl 8080 program and disassembled it with SID's l (list) command:

A>sid f:twirl.com
CP/M 3 SID - Version 3.0
NEXT MSZE  PC  END
0180 0180 0100 D4FF
#l
  0100  MVI  C,09
  0102  LXI  D,0139
  0105  CALL 0005
  0108  LXI  H,0142
  010B  MVI  B,08
  010D  PUSH H
  010E  PUSH B
  010F  MVI  C,09
  0111  LXI  D,013E
  0114  CALL 0005
  0117  POP  B7

The output contains 8080 mnemonics. An analogous ZSID session running the same disassembly command outputs Z80 mnemonics:

A>zsid f:twirl.com
SID VERS 1.4
NEXT  PC  END
0180 0100 CDFF
#l
  0100  LD   C,09
  0102  LD   DE,0139
  0105  CALL 0005
  0108  LD   HL,0142
  010B  LD   B,08
  010D  PUSH HL
  010E  PUSH BC
  010F  LD   C,09
  0111  LD   DE,013E
  0114  CALL 0005
  0117  POP  BC

SID thus lets me work in a 8080 environment on a Z80 system.

#z80mbc2 #Suite8080 #CPM #Assembly

Discuss... Email | Reply @amoroso@oldbytes.space

I ported to CP/M Twirl, a twirling bar animation demo in Intel 8080 Assembly. I originally developed it for emuStudio, an emulator and development environment that recreates a number of classic computers and CPUs. The port runs on any CP/M system with an ANSI terminal or display.

I recorded a screencast that shows Twirl running under CP/M 3.0 on the Z80-MBC2 computer, controlled from a Minicom terminal emulator session under Crostini Linux on my Chromebox.

How it works

The demo displays an ASCII animation of a bar twirling clockwise at the home position of the console, i.e. the top left corner. After clearing the screen, Twirl repeatedly moves the cursor to the console home, prints the current animation frame, and checks for key presses to decide whether to terminate.

Although visually simple, the program demonstrates some key Assembly programming techniques such as looping, calling BDOS functions, and doing output with ANSI escape codes.

Porting

The original Twirl runs on a virtual Altair 8800 computer with a Lear Siegler ADM-3A terminal emulated by emuStudio.

However, I designed the program intending to port it to CP/M. The necessary work consisted in replacing the Altair-specific I/O rutines with equivalent BDOS calls for printing a single character (function 02h) and a string (09h) of ANSI escape codes, and checking the console status for key presses (0bh).

The program logic works as is, but I had to modify the CP/M version for defining the appropriate constants and ANSI escape strings, as well as adapting to the execution environment of the operating system and returning control to it.

Building and running

For me, the whole point of writing programs like Twirl and getting Z80 hardware is to use Suite8080, the suite of Intel 8080 Assembly cross-development tools I'm writing in Python. The CP/M port is a new Suite8080 Assembly demo I built from source on Linux with asm80, the Suite8080 assembler:

$ asm80 twirl.asm

I tested the resulting 74 bytes twirl.com executable under CP/M 2.2 with the CP/M software emulators ANSI CP/M emulator and z80pack.

Running the demo at the CP/M prompt is straightoward:

B>twirl

Pressing any key quits Twirl and returns control to the operating system.

To exeute Twirl on actual hardware I converted twirl.com to Intel HEX format with z80pack's bin2hex tool, then transferred the twirl.hex file to the Z80-MBC2 under CP/M 3.0.

It was really rewarding to see Twirl come to life on a real Z80 computer and get a sense of its performance.

The code

Here is the full code of the CP/M port of Twirl:

; Twirling bar animation.
;
; Runs on CP/M with an ANSI terminal. Press any key to quit the program.


TPA        equ      100h
BDOS       equ      0005h
WRITESTR   equ      09h                ; Write string
WRITECHR   equ      02h                ; Write character
CONSTAT    equ      0bh                ; Console status

FRAMES     equ      8                  ; Number of animation frames


           org      TPA
            
           mvi      c, WRITESTR
           lxi      d, cls             ; Clear screen
           call     BDOS

loop:      lxi      h, anim            ; Initialize frame pointer...
           mvi      b, FRAMES          ; ...and count

loop1:     push     h
           push     b
           mvi      c, WRITESTR
           lxi      d, home            ; Go to screen home
           call     BDOS
           pop      b
           pop      h

           push     h
           push     b
           mvi      c, WRITECHR
           mov      e, m               ; Print current frame
           call     BDOS
           pop      b
           pop      h

           push     h
           push     b
           mvi      c, CONSTAT         ; Get console status
           call     BDOS
           pop      b
           pop      h
           ora      a                  ; Key pressed?
           jnz      exit               ; Yes

           inx      h                  ; Point to next frame
           dcr      b                  ; One fewer frame
           jnz      loop1

           jmp      loop

exit:      ret


cls:       db       1bh, '[2J$'        ; ANSI clear screen: ESC [ 2 J
home:      db       1bh, '[H$'         ; ANSI go to screen home: ESC [ H
anim:      db       '|/-\|/-\'         ; 8 frames

           end

The program represents the animation as the string |/-\|/-\, a sequence of ASCII characters that show the bar at various steps of the rotation.

After clearing the screen, Twirl begins the main loop loop: by initializing the frame pointer and count. An inner loop loop1: prints each animation frame, i.e. the characters of the animation sequence.

The inner loop moves the cursor to the home position and prints the current frame. Then it updates the frame pointer and count, and checks whether a key was pressed. In case of a key press the inner loop exits the program, otherwise it jumps back to the beginning of the main loop.

#Assembly #retrocomputing #Suite8080 #z80mbc2 #CPM

Discuss... Email | Reply @amoroso@oldbytes.space

I'm still troubleshooting a file transfer issue between Crostini Linux and the Z80-MBC2. Sending files from Crostini to the Z80 computer via XMODEM times out, but I figured and tested an effective workaround.

The workaround, which works only for ASCII transfers, consists in pasting a text file from the Minicom terminal emulator into an ED session on CP/M, i.e. sending the contents of the file as if they were typed in. Saving ED's buffer makes the file available on CP/M.

More specifically, this sample Minicom session shows the steps I go through for sending the file greet.hex from Crostini to the Z80-MBC2.

Pasting a text file into an ED session from Minicom on Linux to CP/M on the Z80-MBC2.

First off, it's essential to set at least a 5 ms character transmit delay in Minicom's terminal settings, otherwise the board can't keep up with the flow of data. I press the keystrokes ^A T F to execute the command Terminal settings > Character tx delay (ms). I actually changed the Minicom escape from ^A to ^Y, but in the following I'll continue with the default ^A.

Next, at the CP/M prompt I run the ED text editor for creating a new file GREET.HEX to hold the text coming from Crostini:

B>ed greet.hex

After entering insert mode with the i command, ED is ready to accept any characters typed in — or coming through the serial line connected to the terminal.

In Minicom, I proceed to invoke the Paste file command with the keystrokes ^A Y and select greet.hex on the Crostini file system. One by one, the characters of the file appear in ED's buffer. When Minicom completes pasting greet.hex, in ED I execute the commands #w to save the full text and e to exit the editing session.

The file is now available on CP/M. For example, with the standard tool LOAD I can convert GREET.HEX in Intel HEX format to an executable .COM program:

B>load greet.hex

FIRST ADDRESS 0100
LAST  ADDRESS 0121
BYTES READ    0022
RECORDS WRITTEN 01

Finally, the greet.com hello world demo is ready for execution on CP/M:

B>greet
Greetings from Suite8080

This workaround is slower than XMODEM transfers, but still acceptable and practical.

Pasting text files lets me indirectly send arbitrary binary files to CP/M. Executable programs can be converted to HEX format. Other binary, non-excutable files need uuencoding or processing with similar text-encodings.

#z80mbc2 #sbc #CPM

Discuss... Email | Reply @amoroso@oldbytes.space

It's been over a week since I received the Z80-MBC2 Z80 single-board computer, so I got a chance to spent some time exploring and playing with it. Although I shared some usage updates, it's time for some notes on how the board is working, its value and potential, and the issues I'm facing.

I wish to thank the board's developer and the retailer I bought it from, who clarified some features and details.

Hardware

The Z80-MBC2 comes with two additional small cards (a microSD reader and a real-time clock unit) and a USB serial adapter to plug into the main board. It was easy even for someone with no hardware skills like me, but I had to check some product photos and seek help to figure how to match the connectors.

Here is the board with all the parts plugged in.

Z80-MBC2 Z80 single-board computer.

What surpised me about the Z80-MBC2 is its heft compared with the small size. It weighs almost as much as a smartphone, as those old-fashioned chips pack a lot of stuff.

At 10x10 cm, the Z80-MBC2 is compact and fits well next to my Chromebox as this photo shows. Via the USB serial cable, long enough for my setup, I plug the unit into the Chromebox and access it via the Minicom terminal emulator.

Z80-MBC2 Z80 computer board connected to an ASUS Chromebox 3.

I haven't perceived any significant warming of the board after prolonged use. The readings of the built-in temperature sensor usually stick around 32-33° C.

Software

The Z80-MBC2 is a great kit aimed at hobbysts and electronic enthusiasts, but no mnual is available. There's little documentation on how to operate the product and what it can do.

However, some background on computer technology, programming languages, and 1980s 8-bit systems make it easy to learn by experimenting and interacting with the board. The Z80-MBC2 project site, as well as the site of the predecessor Z80-MBC, are useful sources on the features and capabilities of the product.

The firmware comes with lots of software and tools, see this screenshot of the boot menu. There are programming language interpreters like on 1980s microcomputers, such as BASIC and Forth, and a number of operating systems like CP/M 2.2 and 3.0.

Boot menu of the Z80M-MBC2 single-board computer in a Minicom Linux session over a serial USB connection.

The firmware provides an option for uploading an executable file in Intel HEX format. For example, this allows experimenting with software designed to run on the bare metal such as resident monitors or other low-level code.

Value and potential

I bought a professionally assembled and tested Z80-MBC2 unit. The main value of this solution is the product is pretty much plug and play.

It comes with everything needed to start using the board. In particular, the latest version of the firmware, which fixes some I/O issues, and the USB serial adapter. All I have to do is plug the board's USB connector into a port of my Chromebox.

The board is perfect for running my Assembly code on actual hardware.

The Z80-MBC2 is also an interactive history of computing lab, a way of feeling first-hand the performance and latency of early 8-bit microcomputers and I/O. I actually experienced that kind of performance back in the day but lost touch with it long ago.

Issues

I love the Z80-MBC2 but an issue is limiting what I can do with it: XMODEM file transfers from Crostini Linux to the board time out. Given XMODEM is the most effective way of sending code and programs to the board, this is a major inconvenience.

I'm troubleshooting the issue with the help of comp.os.cpm. The Z80-MBC2 developer reassured me it's likely not a firmware problem, as versions earlier than the one I have didn't fully support XMODEM.

Meanwhile, I'm looking for workarounds shouldn't I be able to devise a fix.

For example, I could paste a file from the terminal emulator to a text editor running on the board. Another less practical option would be to copy the files on the microSD card, the mass storage device of the Z80 system.

#z80mbc2 #sbc #CPM

Discuss... Email | Reply @amoroso@oldbytes.space

In the Crostini Linux Minicom terminal emulation session of this screenshot, a hello world Intel 8080 Assembly program run under CP/M on the Z80-MBC2 Z80 homebrew computer, printing the string Greetings from Suite8080 to the console.

Screenshot of a Crostini Linux Minicom session showing a hello world Assembly demo running under CP/M on a Z80-MBC2 Z80 computer.

It may not seem like much, but it's a personal achievement I'm proud of.

The demo program comes with Suite8080, a suite of Intel 8080 Assembly cross-development tools I'm writing in Python. I created the demo, assembled it with my own assembler, and run it on actual hardware. Just a few months ago I didn't think I could do this.

Running the demo also helped me put together and test a cross-development toolchain based on Suite8080. For example, I learnt how to transfer files via XMODEM from Crostini to the Z80 board.

I can't wait to use the toolchain to develop more code for the Z80-MBC2.

#Suite8080 #z80mbc2 #sbc #CPM

Discuss... Email | Reply @amoroso@oldbytes.space

The Z80-MBC2 board, a Z80 homebrew computer I ordered, finally arrived and I connected it via serial USB to my i7 ASUS Chromebox 3, hoping to control the board from a terminal emulator.

I got a professionally assembled and tested Z80-MBC2 unit and the developer confirmed I hooked it up correctly, so I'm confident the hardware is working. All the right leds are on, as shows this photo of the board connected to the Chromebox at right (the “Z80 inside” logo alone is worth the board).

Z80-MBC2 Z80 computer board connected to an ASUS Chromebox 3.

However, the Chromebox doesn't recognize the board neither under Crostini, nor Android, nor chromeOS.

In Crostini, the output of lsusb doesn't list the board:

Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

The output of usb-devices doesn't list it either:

T:  Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=480 MxCh= 8
D:  Ver= 2.00 Cls=09(hub  ) Sub=00 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=1d6b ProdID=0002 Rev=05.10
S:  Manufacturer=Linux 5.10.110-15808-ge5740beba59b xhci-hcd
S:  Product=xHCI Host Controller
S:  SerialNumber=0000:00:0c.0
C:  #Ifs=