Z80 Input/Output
Ports
Console
0x10 - 0x14Character
port 0x10- In
- Reads a Terminal line one character at a time, pausing when no input is buffered. Pressing Enter ends the line with newline 0x0A. Using a Screen, Keyboard or Mouse port in drawing mode, other than a display-mode command, switches character input to the Screen for the rest of the run. Click the Screen to focus it before typing. Each read then takes one keystroke; Enter still returns 0x0A. Typed characters are echoed at the text cursor while in drawing mode.
- Out
- Prints the byte as a Latin-1 character to the Terminal and, in drawing mode, at the Screen’s text cursor. 0x0A prints a newline. At the bottom, text scrolls the whole Screen up one cell row, graphics included. In TRS-80 mode output goes only to the Terminal.
.org 0x8000
ld hl, msg
loop: ld a, (hl)
or a
jr z, done
out (0x10), a
inc hl
jr loop
done: halt
msg: .asciz "Hello!", 10 ; 10 is the newline: strings keep \n literally- prints
Hello!
Unsigned number
port 0x11- In
- Reads a line, parses it as a decimal number and returns its low byte. Stops the program with an error when the line is not a number.
- Out
- Prints the byte as an unsigned decimal number, 0 to 255.
.org 0x8000
in a, (0x11) ; ask for a number
add a, a ; double it
out (0x11), a ; print it
halt- input
21- prints
42
Signed number
port 0x12- In
- Same as the unsigned number port.
- Out
- Prints the byte as a signed decimal number, -128 to 127.
.org 0x8000
ld a, 5
sub 10
out (0x12), a
halt- prints
-5
Hexadecimal
port 0x13- In
- Reads a line, parses it as a hexadecimal number (
0x,$prefix orhsuffix accepted) and returns its low byte. - Out
- Prints the byte as two upper case hexadecimal digits.
.org 0x8000
ld a, 255
out (0x13), a
halt- prints
FF
16 bit number
port 0x14- In
- Same as the unsigned number port.
- Out
- Prints the 16 bit number made of the high byte of the port address (register B when using
out (c),r) and the byte written, as an unsigned decimal number.
.org 0x8000
ld hl, 1000
ld b, h ; high byte goes on the address bus
ld c, 0x14 ; port number
out (c), l ; prints HL
halt- prints
1000
Screen
0x20 - 0x2AScreen commands
Pixel
command 0Line
command 1Line to
command 2Move to
command 3Rectangle
command 4Rectangle outline
command 5Ellipse
command 6Ellipse outline
command 7Flood fill
command 8Clear
command 9Resize
command 10Buffering on
command 11Buffering off
command 12Present
command 13Mode cells
command 14Mode drawing
command 15The TRS-80 display
Colors
- black
0x00 - blue
0x03 - green
0x1C - cyan
0x1F - red
0xE0 - magenta
0xE3 - yellow
0xFC - white
0xFF - orange
0xF0 - gray
0x92 - dark gray
0x49
Pictures in Files
Pen color
port 0x20- In
- The current pen color, back in 3-3-2.
- Out
- Sets the color of pixels, lines, outlines and text, as one 3-3-2 byte (
RRRGGGBB).
.org 0x8000
ld a, 0xE0 ; 111 000 00: pure red
out (0x20), a ; pen color
ld a, 100
out (0x23), a ; X
ld a, 50
out (0x24), a ; Y
xor a ; command 0: pixel
out (0x27), a
halt- shows
- one red pixel at (100, 50).
Fill color
port 0x21- In
- The current fill color, back in 3-3-2.
- Out
- Sets the color the inside of a filled shape, a flood fill and a clear use, as one 3-3-2 byte.
.org 0x8000
ld a, 0x1C ; 000 111 00: pure green
out (0x21), a ; fill color
ld a, 0xFF
out (0x20), a ; white pen for the outline
ld a, 20
out (0x23), a
out (0x24), a ; from (20, 20)
ld a, 80
out (0x25), a
out (0x26), a ; to (80, 80), right and bottom excluded
ld a, 4 ; command 4: filled rectangle
out (0x27), a
halt- shows
- a green square with a white outline, 60 by 60 pixels, at (20, 20).
Pen width
port 0x22- In
- The current pen width.
- Out
- Sets how many pixels wide lines and outlines are, at least 1. A width of 0 is read as 1.
.org 0x8000
ld a, 5
out (0x22), a ; five pixels wide
ld a, 10
out (0x23), a
out (0x24), a ; from (10, 10)
ld a, 200
out (0x25), a
ld a, 150
out (0x26), a ; to (200, 150)
ld a, 1 ; command 1: line
out (0x27), a
halt- shows
- a thick white diagonal line across the Screen.
X
port 0x23- In
- The byte last written.
- Out
- The first X coordinate: the pixel, the start of a line, the left edge of a shape, the width of a resize.
.org 0x8000
ld a, 128
out (0x23), a
ld a, 96
out (0x24), a ; (128, 96), the middle of the default Screen
ld a, 3 ; command 3: move to
out (0x27), a
ld a, 200
out (0x23), a
ld a, 20
out (0x24), a
ld a, 2 ; command 2: line to
out (0x27), a
halt- shows
- a line from the middle of the Screen to (200, 20).
Y
port 0x24- In
- The byte last written.
- Out
- The first Y coordinate, the companion of the X port, and the height of a resize.
X2
port 0x25- In
- The byte last written.
- Out
- The second X coordinate: the end of a line, the right edge of a shape. Unused by the one-point commands.
Y2
port 0x26- In
- The byte last written.
- Out
- The second Y coordinate, the companion of the X2 port.
Command
port 0x27- In
- The number of the last command run, 0 before the first one.
- Out
- Runs one drawing operation on the coordinates, colors and pen width already set. The commands are listed above.
.org 0x8000
ld a, 0x03 ; 000 000 11: pure blue
out (0x21), a ; fill color
ld a, 9 ; command 9: clear to the fill color
out (0x27), a
ld a, 0xFC ; 111 111 00: yellow
out (0x21), a
ld a, 60
out (0x23), a
ld a, 40
out (0x24), a
ld a, 196
out (0x25), a
ld a, 152
out (0x26), a
ld a, 6 ; command 6: filled ellipse
out (0x27), a
halt- shows
- a yellow ellipse with a white outline on a blue Screen.
Pixel color
port 0x28- In
- The color of the pixel at (X, Y) as a 3-3-2 byte, read from the image being drawn on — the off-screen one while double buffering. Outside the Screen it reads as the background color.
- Out
- Ignored: the pixel is drawn with command 0, in the pen color.
.org 0x8000
ld a, 0xE0
out (0x20), a ; red pen
ld a, 8
out (0x23), a
out (0x24), a ; (8, 8)
xor a ; command 0: pixel
out (0x27), a
in a, (0x28) ; read the color back
out (0x13), a ; print it as hexadecimal
halt- prints
E0
Text cursor column
port 0x29- In
- The column the text cursor is on.
- Out
- Moves the text cursor to a column, in 8 by 8 character cells: 0 to 31 on the default Screen. Out of range values are clamped.
.org 0x8000
ld a, 12
out (0x29), a ; column 12
ld a, 8
out (0x2A), a ; row 8
ld hl, msg
loop: ld a, (hl)
or a
jr z, done
out (0x10), a ; the character port draws at the cursor
inc hl
jr loop
done: halt
msg: .asciz "HELLO"- prints
HELLO- shows
- the same text on the Screen, at the eighth row.
Text cursor row
port 0x2A- In
- The row the text cursor is on.
- Out
- Moves the text cursor to a row, in 8 by 8 character cells: 0 to 23 on the default Screen. Out of range values are clamped.
Keyboard
0x30 - 0x33Typed input available
port 0x30- In
- 1 when a character typed on the focused Screen is waiting to be read from the character port, else 0. During a testcase it answers for the scripted input instead, so a program that polls before reading works in both.
- Out
- Ignored.
.org 0x8000
wait: in a, (0x30) ; anything typed?
or a
jr z, wait ; poll until there is
in a, (0x10) ; take the character
out (0x10), a ; print it
halt- input
hi- shows
- the first character typed on the Screen, echoed back. Click the Screen first: that is where the keys go.
Key state
port 0x31- In
- 1 while the key whose code is in B is held down, else 0. This is how a game reads WASD or the arrows: it never consumes anything, and a key held over several reads answers 1 every time.
- Out
- Ignored.
.org 0x8000
ld c, 0x31 ; the key state port
ld b, 0x27 ; the right arrow
wait: in a, (c)
or a
jr z, wait ; poll until it is held
ld a, 'R'
out (0x10), a
halt- shows
- an R printed once the right arrow is held down on the focused Screen.
Last key pressed
port 0x32- In
- The code of the last key pressed on the Screen, 0 before the first press. It persists, so a program that polls slowly still sees the key.
- Out
- Ignored.
.org 0x8000
loop: in a, (0x32) ; the last key pressed
or a
jr z, loop
out (0x13), a ; print its code in hexadecimal
halt- shows
- the code of the first key pressed on the focused Screen, in hexadecimal.
Last key released
port 0x33- In
- The code of the last key released, 0 before the first release. With the last-pressed port it is the pair EASy68K’s task 19 answers with.
- Out
- Ignored.
Mouse
0x40 - 0x43Mouse views
Mouse X
port 0x40- In
- The X of the view selected by B (0 current, 1 last release, 2 last press), in logical Screen pixels from the left edge, independently of how the panel is zoomed.
- Out
- Ignored.
.org 0x8000
ld c, 0x42 ; the buttons port
ld b, 0 ; view 0: the current state
wait: in a, (c)
and 1 ; the left button
jr z, wait
ld c, 0x40
in a, (c) ; X
out (0x11), a
ld a, ','
out (0x10), a
ld c, 0x41
in a, (c) ; Y
out (0x11), a
halt- shows
- the pointer position printed as "x,y" as soon as the left button is held over the Screen.
Mouse Y
port 0x41- In
- The Y of the view selected by B, in logical Screen pixels from the top edge.
- Out
- Ignored.
Mouse buttons
port 0x42- In
- The buttons and modifiers of the view selected by B: bit 0 left, bit 1 right, bit 2 middle, bit 3 the double-click flag (only in the last-press view), bit 4 Shift, bit 5 Alt, bit 6 Ctrl.
- Out
- Ignored.
Mouse event count
port 0x43- In
- For the current view, how many mouse events have happened, as a byte that wraps around; for the two snapshot views, the count at the moment of the snapshot, 0 when it has not happened yet. Comparing it with the previous read is how a program tells a new click from the one it already handled.
- Out
- Ignored.
Program time
0x50 - 0x52Wait
port 0x50- In
- Waits B hundredths of a second, then answers 0. In a testcase the wait completes at once and advances the virtual clock by the requested duration.
- Out
- Ignored.
.org 0x8000
ld c, 0x50
ld b, 25 ; a quarter of a second
in a, (c)
ld a, '!'
out (0x10), a
halt- prints
!
Frame sync
port 0x51- In
- Waits for the next animation frame, then answers 0. One read per frame is how an animation runs at the display’s own pace instead of as fast as the host can go; with double buffering, present the frame first and sync afterwards. In a testcase the wait completes at once and advances the virtual clock.
- Out
- Ignored.
.org 0x8000
ld b, 10 ; ten frames
loop: push bc
in a, (0x51) ; wait for the next frame
ld a, '.'
out (0x10), a
pop bc
djnz loop
halt- prints
..........
Elapsed time
port 0x52- In
- One byte of the number of hundredths of a second since the run started, selected by B: 0 the lowest byte, 3 the highest. This is elapsed time, not a calendar clock. A testcase reads a virtual clock that starts at zero and only moves when the program waits, so a test is reproducible.
- Out
- Ignored.
.org 0x8000
ld c, 0x50
ld b, 10 ; wait a tenth of a second
in a, (c)
ld c, 0x52
ld b, 0 ; the lowest byte of the elapsed hundredths
in a, (c)
out (0x11), a
halt- shows
- the hundredths of a second the program has been running, about 10.
Audio
0x60 - 0x64Sound
Play a note
port 0x60- In
- Returns 0xFF; this port only accepts writes.
- Out
- Writing a pitch starts a note and continues immediately, so notes can overlap. Pitch runs from 0 to 127: 60 is middle C, 62 is D, 64 is E, and each step is one semitone. The note uses the instrument, volume, and duration last set through the other audio ports. A pitch of 128 or more becomes 60, as in MARS service 31. The first note or MIDI-file request after opening or reloading the editor page waits while the browser loads the sound bank, the collection of instrument sounds; later runs share it.
.org 0x8000
ld a, 60 ; C
out (0x60), a
ld a, 64 ; E, sounding with it
out (0x60), a
ld a, 67 ; G: a C major chord
out (0x60), a
halt- shows
- No text output; plays a C major chord on the piano for one second, continuing after the program ends.
Play a note and wait
port 0x61- In
- Read with
in r,(c)and the pitch in B to play a note using the instrument, volume, and duration already set. Waits for the requested duration, then returns 0, like MARS service 33. A sequence of these reads can play a melody. Muting or stopping the audible note does not shorten the wait. Testcases are silent; the wait completes immediately and advances the virtual clock by the duration. - Out
- Ignored.
.org 0x8000
ld b, 0
ld a, 150 ; 150 ms per note
ld c, 0x64
out (c), a
ld c, 0x61
ld b, 60 ; C
in a, (c)
ld b, 64 ; then E
in a, (c)
ld b, 67 ; then G
in a, (c)
ld a, '!'
out (0x10), a
halt- prints
!
Instrument
port 0x62- In
- Returns 0xFF; this port only accepts writes.
- Out
- Selects the instrument sound for later notes from the General MIDI list, numbered from 0 to 127: 0 is acoustic grand piano, 40 violin, 56 trumpet, and 73 flute. Values of 128 or more select 0 (piano), as in MARS. Every run starts at 0 (piano).
.org 0x8000
ld a, 40 ; violin
out (0x62), a
ld a, 69 ; A above middle C
out (0x60), a
halt- shows
- No text output; plays an A on the violin for one second.
Volume
port 0x63- In
- Returns 0xFF; this port only accepts writes.
- Out
- Sets the volume for later notes, from 0 (silent) to 127 (loudest). Values of 128 or more become 100, the MARS default. Every run starts at 100.
.org 0x8000
ld a, 30 ; quietly
out (0x63), a
ld a, 60
out (0x60), a
halt- shows
- No text output; plays a quiet middle C.
Duration
port 0x64- In
- Returns 0xFF; this port only accepts writes.
- Out
- Sets the duration for later notes in milliseconds. Use
out (c),rwith C = 0x64: B supplies the high byte and the written register supplies the low byte, giving a duration up to 65,535 milliseconds. Every run starts at 1000 milliseconds, the MARS default.
.org 0x8000
ld b, 0x07 ; 0x07D0 = 2000 ms
ld a, 0xd0
ld c, 0x64
out (c), a
ld a, 48 ; a low C for two seconds
out (0x60), a
halt- shows
- No text output; plays a low C for two seconds.
Sound chip
0xA0 - 0xA2Select a Sound chip register
port 0xA0- In
- Returns 0xFF; this port only accepts writes.
- Out
- Selects the register, 0 to 15, that the next writes to SOUND_CHIP_WRITE (0xA1) and reads from SOUND_CHIP_READ (0xA2) reach; it stays selected until the next write here. Registers 14 and 15 are the chip’s two I/O ports, which the MSX wires to its joysticks: nothing is attached here, so they read 0xFF and writes to them are ignored. A number of 16 or more selects nothing, as on the chip.
.org 0x8000
ld a, 0 ; register 0: channel A's period, low byte
out (0xa0), a
ld a, 254 ; 254 is 440 Hz
out (0xa1), a
ld a, 1 ; register 1: the period's high four bits
out (0xa0), a
xor a
out (0xa1), a
ld a, 7 ; register 7: the mixer
out (0xa0), a
ld a, 0xbe ; only channel A's tone on
out (0xa1), a
ld a, 8 ; register 8: channel A's volume
out (0xa0), a
ld a, 15 ; the loudest
out (0xa1), a
ld c, 0x50
ld b, 100 ; let it sound for a second
in a, (c)
halt- shows
- No text output; plays a square wave at 440 Hz for a second, which stops when the program ends.
Write a Sound chip register
port 0xA1- In
- Returns 0xFF; this port only accepts writes.
- Out
- Writes the selected register. Each keeps only its own bits: four of a tone period’s high register, five of the noise period and of a volume, four of the envelope shape. Writing the envelope shape, register 13, restarts the envelope, even with the shape it already has; this retriggers all channels following the shared envelope.
.org 0x8000
ld hl, chord ; pairs of a register and its value
ld b, 10 ; ten of them
next: ld a, (hl)
out (0xa0), a
inc hl
ld a, (hl)
out (0xa1), a
inc hl
djnz next
ld c, 0x50
ld b, 200 ; two seconds
in a, (c)
halt
chord: .byte 0, 0xac, 1, 1 ; A: period 428, middle C
.byte 2, 0x53, 3, 1 ; B: period 339, E
.byte 4, 0x1d, 5, 1 ; C: period 285, G
.byte 7, 0xb8 ; the three tones on, no noise
.byte 8, 12, 9, 12 ; volumes of A and B
.byte 10, 12 ; and of C- shows
- No text output; plays a C major chord on the three channels for two seconds.
Read a Sound chip register
port 0xA2- In
- Returns the selected register as the chip holds it: what was last written, less the bits the register does not keep. Registers 14 and 15, and a number of 16 or more, read 0xFF.
- Out
- Ignored.
.org 0x8000
ld a, 1 ; channel A's period, high bits
out (0xa0), a
ld a, 0xff
out (0xa1), a
in a, (0xa2) ; the register keeps four bits
out (0x11), a
halt- prints
15