Porting a twirling bar demo to CP/M

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@fosstodon.org