I/O in Z80 Assembly

RunCPM provides access to Arduino I/O capabilities through CP/M's BDOS (Basic Disk Operating System) interface. By loading the C register with a function number and a call to address 5, additional functionality that has been added to the system can be accessed. 

For these functions, the number of the pin being used is placed in the D register and the value to write (when appropriate) is placed in E. For read functions, the result is returned as noted.

 PinMode

LD C, 220
LD D, pin_number
LD E, mode ;(0 = INPUT, 1 = OUTPUT, 2 = INPUT_PULLUP)
CALL 5 

DigitalRead

LD C, 221 LD D, pin_number CALL 5 Returns result in A (0 = LOW, 1 = HIGH).

DigitalWrite

LD C, 222 LD D, pin_number LD E, value ;(0 = LOW, 1 = HIGH) CALL 5

AnalogRead

LD C, 223 LD D, pin_number CALL 5

Returns result in HL (0 - 1023).

AnalogWrite (i.e. PWM)

LD C, 224 LD D, pin_number LD E, value (0-255) CALL 5

Turning on a LED

Using the above PinMode and DigitalWrite calls, it's easy to write some code to turn on a LED connected to, for example, pin D8.  Use ED (the editor) to enter the following into the file LED.ASM. You could do this on your workstation directly on the SD card since ED is a beast from another time and, quite possibly, another dimension. 

; Turn on a LED wired to pin 8
org 100h    ;start address
mvi c, 220  ;pinmode
mvi d, 8    ;digital pin number
mvi e, 1    ;value (0 = low, 1 = high)
push d      ;save arguments
call 5      ;call BDOS
pop d       ;restore arguments
mvi c, 222  ;digital write
call 5      ;call BDOS
ret         ;exit to CP/M

Then use the ASM command to assemble it:

A>asm led
CP/M ASSEMBLER - VER 2.0
0111
000H USE FACTOR
END OF ASSEMBLY

RunCPM Version 3.7 (CP/M 2.2 60K)

This produces several files. LED.PRN is a text file containing your assembly language program along with the machine code it assembles to. Each line has 3 columns: address, machine code, and assembly language.

A>type led.prn


0100          org 100h
0100 0EDC     mvi c,220
0102 1608     mvi d,8
0104 1E01     mvi e, 1
0106 D5       push d
0107 CD0500   call 5
010A D1       pop d
010B 0EDE     mvi c, 222
010D CD0500   call 5
0110 C9       ret

There is also now a LED.HEX file. We can use the LOAD command/program to convert it into LED.COM which can be executed.

A> load led

FIRST ADDRESS 0100
LAST ADDRESS  0110
BYTES READ    0011
RECORDS WRITTEN 01

Now it can executed:

A>led

which will turn on the LED connected to pin D8.

So now we can read and write digital and analog I/O from Z80 assembly language code that's running on a Z80 emulated on the Grand Central. That seems pretty round-about.

While that's true, the point is to be able to play around with Z80 assembly language (and CP/M in this case) without having to find or build an actual Z80 system (although that can be its own kind of fun).

This guide was first published on Jan 29, 2019. It was last updated on Jan 29, 2019. This page (I/O in Z80 Assembly) was last updated on May 20, 2019.