-
Notifications
You must be signed in to change notification settings - Fork 14
Monitor User Guide
When the monitor starts up, it displays the version and then prompts for input with z80ctrl>.
z80ctrl 0.9 by J.B. Langston
type help to list available commands
z80ctrl>
We can type help to get a list of available commands. Each command is shown followed by a short description.
z80ctrl>help
available commands:
altmon run altmon 8080 monitor
bus display low-level bus status
break set breakpoints
c shorthand to continue debugging
cls clear screen
dboot boot disk using Altair disk bootloader
debug debug code at address
dir shows directory listing
disasm disassembles memory location
dump dump memory in hex and ascii
fill fill memory with byte
help list available commands
loadhex load intel hex file to memory
mount mount a disk image
run execute code at address
reset reset the processor, with optional vector
savehex save intel hex file from memory
sboot boot disk using SIMH bootloader
s shorthand for step
step step processor N cycles
unmount unmount a disk image
watch set watch points
z80ctrl>
Any command that requires options will display its usage if you try to run it without any options.
z80ctrl>mount
usage: mount <drive #> <filename>
The dir command will list the files available on the SD card. Directories are indicated by a trailing /. We can list the files within a directory by passing the directory name to the dir command.
z80ctrl>dir
SYSTEM~1/ SCMON.HEX HELLO.HEX CPM2S.DSK Z80OPS.HEX
CPM2D.DSK SIMH/ DBL/
8 item(s)
z80ctrl>dir dbl
CPM1-24K.DSK CPM1-48K.DSK CPM2-48K.DSK CPM2-56K.DSK CPM2-63K.DSK
CPM2B24K.DSK CPM2B63K.DSK GAMES.DSK KERMIT.DSK SUPERC~1.DSK
SYSDEV.DSK SYSGEN.DSK WORDSTAR.DSK ZORK.DSK BASCOM.DSK
BASGAMES.DSK BDSC.DSK
17 item(s)
z80ctrl>
z80ctrl supports loading and saving memory to and from Intel hex files. The load process prints out a message for each line in the hex file showing how many bytes were loaded and to what address. At the end of the process, the total number of bytes loaded is displayed.
z80ctrl>loadhex hello.hex
loading from hello.hex
loaded 0x10 bytes to 0x0100
loaded 0x10 bytes to 0x0110
loaded 0x0D bytes to 0x0120
loaded 0x002D bytes total
Once the program is loaded, it can be run.
z80ctrl>run 100
hello, world
This program has a halt instruction at the end, which stops the Z80 processor and returns control to the monitor.
z80ctrl is compatible with unmodified CP/M disk images from the SIMH project and the Altair Clone project. Disks are mounted by giving a drive number followed by the file to mount on that drive. z80ctrl supports up to 26 drives (0-25), which correspond to drive letters A-Z in CP/M. However, depending on the CP/M BIOS, it may not support more than several drives.
The disk image mounted in drive A: (0) can be booted from. There are two bootloaders: one for SIMH disk images (sboot), and one for DBL disk images used by the Altair Clone project (dboot). Disk images must be booted using the appropriate bootloader.
We will mount a CP/M 2.2 disk image from the SIMH project on A: and a secondary disk with some games on drive B:, then boot CP/M.
z80ctrl>mount 0 simh/cpm2.dsk
z80ctrl>mount 1 simh/games.dsk
z80ctrl>sboot
64K CP/M Version 2.2 (SIMH ALTAIR 8800, BIOS V1.27, 2 HD, 02-May-2009)
A>
We can list the files on the drive, and run one of the programs:
A>dir
A: ASM COM : BDOS MAC : SYSCPM2 SUB : BOOT MAC
A: SYSCPM2Z SUB : CBIOSX MAC : CCP MAC : CCPZ MAC
A: CCPZ TXT : CFGCCP LIB : CFGCCPZ LIB : COPY COM
A: CPU COM : CPU MAC : CREF80 COM : DDT COM
A: DDTZ COM : MOVER MAC : DO COM : DSKBOOT MAC
A: DUMP COM : ED COM : ELIZA BAS : EX MAC
A: EX SUB : EX8080 COM : EXZ80ALL COM : EXZ80DOC COM
A: FORMAT COM : GO COM : HALT COM : PRELIM MAC
A: HDSKBOOT MAC : L80 COM : LADDER COM : LADDER DAT
A: LIB80 COM : LOAD COM : LS COM : LU COM
A: M80 COM : MBASIC COM : MC SUB : MCC SUB
A: MCCL SUB : OTHELLO COM : PIP COM : EC8080 LIB
A: PRELIM COM : ECZ80ALL LIB : RSETSIMH COM : RSETSIMH MAC
A: ECZ80DOC LIB : SID COM : BOOT COM : STAT COM
A: SUBMIT COM : SURVEY COM : SURVEY MAC : SPEED COM
A: SYSCOPY COM : URL COM : TIMER COM : TIMER MAC
A: UNCR COM : UNERA COM : UNERA MAC : USQ COM
A: W COM : WM COM : WM HLP : WORM COM
A: XSUB COM : ZAP COM : ZSID COM : ZTRAN4 COM
A: BOOTGEN COM : DIF COM : HDIR COM : R COM
A: SHOWSEC COM : XFORMAT COM
A>survey
*** System Survey (June 82) ***
Drive A: 746K bytes in 103 files with 246K bytes remaining
Memory map:
0 8 16 24 32 40 48 56 64
| | | | | | | | |
TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTCCCBBBB
T=TPA C=CPM B=BIOS or unassigned R=ROM or bad
BIOS at F203 iobyte E5 drive 00 BDOS at E406
65535 Bytes RAM 0 Bytes ROM 58374 Bytes in TPA
0 Bytes Empty 65535 Total Active Bytes
Active I/O ports:
08 09 0A
10 11
5 Ports active
A>
Now we can switch to the B: drive and look at the files on the second disk we mounted.
B>dir
B: ADVT DAT : ADVDDIA SAV : ADVDDOM SAV : ADVI DAT
B: ADVI PTR : ADVT PTR : ADV COM : CATCHUM COM
B: CREDITS : QT ASM : QTERMR PAT : QTERMW PAT
B: README 1ST : CATCHUM DAT : ROGUE COM : WORTE TXT
B: ROGUE DOC : ROGUE NOT : SCREEN 001 : SCREEN 002
B: SCREEN 003 : SCREEN 004 : SCREEN 005 : SCREEN 006
B: SCREEN 007 : SCREEN 008 : SCREEN 009 : SCREEN 010
B: SCREEN 011 : SCREEN 012 : SCREEN 013 : SCREEN 014
B: SCREEN 015 : SCREEN 016 : SCREEN 017 : SCREEN 018
B: SCREEN 019 : SCREEN 020 : SCREEN 021 : SCREEN 022
B: SCREEN 023 : SCREEN 024 : SCREEN 025 : SCREEN 026
B: SCREEN 027 : SCREEN 028 : SCREEN 029 : SCREEN 030
B: SCREEN 031 : SCREEN 032 : SCREEN 033 : SCREEN 034
B: SCREEN 035 : SCREEN 036 : SCREEN 037 : SCREEN 038
B: SCREEN 039 : SCREEN 040 : SCREEN 041 : SCREEN 042
B: SCREEN 043 : SCREEN 044 : SCREEN 045 : SCREEN 046
B: SCREEN 047 : SCREEN 048 : SCREEN 049 : SCREEN 050
B: WANDERER COM : WANDERER DOC : LADDER COM : LADDER DAT
B: WORM COM
If we attempt to access a drive that has not been mounted, we will get a Bad Sector error:
B>c:
Bdos Err On C: Bad Sector
We can halt CP/M using the halt button on the z80ctrl board. The z80ctrl> prompt is displayed again. Now, we will mount and run some disks using the Altair Disk Boot Loader format.
z80ctrl>mount 0 dbl/cpm2b63k.dsk
z80ctrl>mount 1 dbl/zork.dsk
z80ctrl>dboot
63K CP/M 2.2b v2.0
For Altair 8" Floppy
A>dir
A: L80 COM : LADDER COM : ED COM : ASM COM
A: DUMP COM : XSUB COM : PCGET COM : LS COM
A: SUBMIT COM : LOAD COM : SURVEY COM : VIEW COM
A: LADDER DAT : LUNAR BAS : M80 COM : MAC COM
A: MBASIC COM : PIP COM : STAT COM : DDT COM
A: IOBYTE TXT : NSWP COM : SYSGEN COM : AFORMAT COM
A: MOVCPM8 COM : OTHELLO COM : STARTRK BAS : TICTAK BAS
A: WM COM : WM HLP : CRC COM : PCPUT COM
A: ACOPY COM : STARINS BAS : DOWNLOAD COM
A>b:
B>dir
B: ZORK1 COM : ZORK1 DAT : ZORK2 DAT : ZORK3 DAT
B: ZORK2 COM : ZORK3 COM
B>zork1
ZORK I: The Great Underground Empire
Copyright (c) 1981, 1982, 1983 Infocom, Inc. All rights
reserved.
ZORK is a registered trademark of Infocom, Inc.
Revision 88 / Serial number 840726
West of House
You are standing in an open field west of a white house, with
a boarded front door.
There is a small mailbox here.
>
If we try to boot a disk image with the wrong boot loader, it will hang. We can get back to the z80ctrl> prompt by pressing the halt button on the board.
z80ctrl>mount 0 dbl/cpm2b63k.dsk
z80ctrl>sboot
Sometimes before a debugging session, it's helpful to clear out memory. We can do this with the fill command, and then use dump to confirm that it was cleared.
z80ctrl>fill 0 ffff 0
z80ctrl>dump 100
0100 01ff
0100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Now we can reload the hello world program and show another hex dump of the program starting at address 100 and see the bytes that were loaded in. ASCII is shown to the right. You can see the "hello, world" string that the program displays. Dots are used for non-printable characters.
z80ctrl>dump 100
0100 01ff
0100: 31 FF FF 21 1E 01 CD 0A 01 76 7E A7 C8 CD 13 01 1..!.....v~.....
0110: 23 18 F7 F5 DB 10 CB 4F 28 FA F1 D3 11 C9 68 65 #......O(.....he
0120: 6C 6C 6F 2C 20 77 6F 72 6C 64 0D 0A 00 00 00 00 llo, world......
0130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Now we can disassemble the program from memory. The disassembler output shows the hex address (4 digits), followed by the hex bytes of the instruction (2 digits per byte), then the ASCII representation of those bytes. Again dots are used for non-printable characters. Starting at address 011e, the program ends and the string data begins. The disassembler has now way of knowing this is not code, but the ASCII output helps you recognize that it's a string.
z80ctrl>disasm 100 130
0100 31 ff ff 1.. LD SP,FFFFH
0103 21 1e 01 !.. LD HL,011EH
0106 cd 0a 01 ... CALL 010AH
0109 76 v HALT
010a 7e ~ LD A,(HL)
010b a7 . AND A
010c c8 . RET Z
010d cd 13 01 ... CALL 0113H
0110 23 # INC HL
0111 18 f7 .. JR -9
0113 f5 . PUSH AF
0114 db 10 .. IN A,(10H)
0116 cb 4f .O BIT 1,A
0118 28 fa (. JR Z,-6
011a f1 . POP AF
011b d3 11 .. OUT (11H),A
011d c9 . RET
011e 68 h LD L,B
011f 65 e LD H,L
0120 6c l LD L,H
0121 6c l LD L,H
0122 6f o LD L,A
0123 2c , INC L
0124 20 77 w JR NZ,119
0126 6f o LD L,A
0127 72 r LD (HL),D
0128 6c l LD L,H
0129 64 d LD H,H
012a 0d . DEC C
012b 0a . LD A,(BC)
012c 00 . NOP
012d 00 . NOP
012e 00 . NOP
012f 00 . NOP
0130 00 . NOP
Now we enable watches on bus activity and opcode fetches and then display the watch status. If no address is specified, the entire address range is used.
z80ctrl>watch bus
z80ctrl>watch opfetch
z80ctrl>watch
watch status:
bus: 0000-ffff
memrd: disabled
memwr: disabled
iord: disabled
iowr: disabled
opfetch: 0000-ffff
usage:
watch <type> [start] [end]
watch <type> off to disable type
watch off to disable all
We also enable breaks on IO writes and display the status to confirm:
z80ctrl>break iowr
z80ctrl>break
break status:
memrd: disabled
memwr: disabled
iord: disabled
iowr: 0000-00ff
opfetch: disabled
usage:
break <type> [start] [end]
break <type> off to disable type
break off to disable all
Now we will debug the program starting at address 100. The bus watch we enabled shows the bus status for every T cycle. The values of the address and data bus are shown, then the status of the control lines: rd/wr/rfsh (read, write refresh) mem/io (memory or IO request), m1 (start of a machine cycle), and so on.
Because we also enabled watches on opfetch, each instruction is disassembled in real time as it is executed by the Z80. The mnemonic and operands are displayed after the full instruction and its operands have been fetched. In front of the mnemonic, the starting address of the instruction is displayed.
z80ctrl>debug 100
ff17 00 rd mem
ff17 01
0000 01 m1
0000 c3 rd mem m1
0000 c3 rfsh
0000 c3 rfsh mem
0001 c3
0001 00 rd mem
0001 00 rd mem
0002 01
0002 01 rd mem
0002 01 rd mem
0100 01 m1
0000 JP 0100H
0100 31 1 rd mem m1
0001 31 1 rfsh
0001 31 1 rfsh mem
0101 31 1
0101 ff rd mem
0101 ff rd mem
0102 ff
0102 ff rd mem
0102 ff rd mem
0103 ff m1
0100 LD SP,FFFFH
0103 21 ! rd mem m1
0002 21 ! rfsh
0002 21 ! rfsh mem
0104 21 !
0104 1e rd mem
0104 1e rd mem
0105 1f
0105 01 rd mem
0105 01 rd mem
0106 01 m1
0103 LD HL,011EH
0106 cd rd mem m1
0003 cd rfsh
0003 cd rfsh mem
0107 cd
0107 0a rd mem
0107 0a rd mem
0108 0b
0108 01 rd mem
0108 01 rd mem
0108 01
0106 CALL 010AH
fffe 01
fffe 01 mem
fffe 01 wr mem
fffd 01
fffd 09 mem
fffd 09 wr mem
010a 09 m1
010a 7e ~ rd mem m1
0004 7f rfsh
010a LD A,(HL)
0004 7f rfsh mem
011e 7f
011e 68 h rd mem
011e 68 h rd mem
010b 69 i m1
010b a7 rd mem m1
0005 a7 rfsh
010b AND A
0005 a7 rfsh mem
010c a7 m1
010c c8 rd mem m1
0006 c9 rfsh
010c RET Z
0006 c9 rfsh mem
0006 c9
010d c9 m1
010d cd rd mem m1
0007 cd rfsh
0007 cd rfsh mem
010e cd
010e 13 rd mem
010e 13 rd mem
010f 13
010f 01 rd mem
010f 01 rd mem
010f 01
010d CALL 0113H
fffc 01
fffc 01 mem
fffc 01 wr mem
fffb 01
fffb 10 mem
fffb 10 wr mem
0113 11 m1
0113 f5 rd mem m1
0008 f5 rfsh
0113 PUSH AF
0008 f5 rfsh mem
0008 f5
fffa f5
fffa 68 h mem
fffa 68 h wr mem
fff9 69 i
fff9 38 8 mem
fff9 38 8 wr mem
0114 39 9 m1
0114 db rd mem m1
0009 db rfsh
0009 db rfsh mem
0115 db
0115 10 rd mem
0115 10 rd mem
6810 11
0114 IN A,(10H)
6810 02
0116 02 m1
0116 cb rd mem m1
000a cb rfsh
000a cb rfsh mem
0117 cb m1
0117 4f O rd mem m1
000b 4f O rfsh
0116 BIT 1,A
000b 4f O rfsh mem
0118 4f O m1
0118 28 ( rd mem m1
000c 2a * rfsh
000c 2a * rfsh mem
0119 2a *
0119 fa rd mem
0119 fa rd mem
011a fa m1
0118 JR Z,-6
011a f1 rd mem m1
000d f3 rfsh
011a POP AF
000d f3 rfsh mem
fff9 f3
fff9 38 8 rd mem
fff9 38 8 rd mem
fffa 3a :
fffa 68 h rd mem
fffa 68 h rd mem
011b 6a j m1
011b d3 rd mem m1
000e d3 rfsh
000e d3 rfsh mem
011c d3
011c 11 rd mem
011c 11 rd mem
6811 13
011b OUT (11H),A
h 6811 68 h
Once the first IO write is encountered (outputting the h in hello, world), the breakpoint activates and execution stops. Now we can single step instructions:
z80ctrl>s
ff2d 00 busack
fffb 00
fffb 10 rd mem
fffb 10 rd mem
fffc 10
fffc 01 rd mem
fffc 01 rd mem
0110 01 m1
0110 23 # rd mem m1
0010 23 # rfsh
0110 INC HL
You can see that only enough bus cycles were run to execute a single instruction. We can continue stepping through a few more instructions, one at a time.
z80ctrl>s
0010 00 rfsh mem
0010 00
0010 00
0111 00 m1
0111 18 rd mem m1
0011 18 rfsh
0011 18 rfsh mem
0112 18
0112 f7 rd mem
0112 f7 rd mem
0112 f7
0111 JR -9
z80ctrl>s
0112 00
0112 00
0112 00
0112 00
010a 00 m1
010a 7e ~ rd mem m1
0012 7e ~ rfsh
010a LD A,(HL)
z80ctrl>s
0012 00 rfsh mem
011f 00
011f 65 e rd mem
011f 65 e rd mem
010b 65 e m1
010b a7 rd mem m1
0013 a7 rfsh
010b AND A
We can now continue, and the program will run until the next breakpoint is encountered.
z80ctrl>c
0013 00 rfsh mem
010c 00 m1
010c c8 rd mem m1
0014 c8 rfsh
010c RET Z
0014 c8 rfsh mem
0014 c8
010d c8 m1
010d cd rd mem m1
0015 cd rfsh
0015 cd rfsh mem
010e cd
010e 13 rd mem
010e 13 rd mem
010f 13
010f 01 rd mem
010f 01 rd mem
010f 01
010d CALL 0113H
fffc 01
fffc 01 mem
fffc 01 wr mem
fffb 01
fffb 10 mem
fffb 10 wr mem
0113 10 m1
0113 f5 rd mem m1
0016 f5 rfsh
0113 PUSH AF
0016 f5 rfsh mem
0016 f5
fffa f5
fffa 65 e mem
fffa 65 e wr mem
fff9 65 e
fff9 34 4 mem
fff9 34 4 wr mem
0114 34 4 m1
0114 db rd mem m1
0017 db rfsh
0017 db rfsh mem
0115 db
0115 10 rd mem
0115 10 rd mem
6510 10
0114 IN A,(10H)
6510 02
0116 02 m1
0116 cb rd mem m1
0018 cb rfsh
0018 cb rfsh mem
0117 cb m1
0117 4f O rd mem m1
0019 4f O rfsh
0116 BIT 1,A
0019 4f O rfsh mem
0118 4f O m1
0118 28 ( rd mem m1
001a 2a * rfsh
001a 2a * rfsh mem
0119 2a *
0119 fa rd mem
0119 fa rd mem
011a fa m1
0118 JR Z,-6
011a f1 rd mem m1
001b f3 rfsh
011a POP AF
001b f3 rfsh mem
fff9 f3
fff9 34 4 rd mem
fff9 34 4 rd mem
fffa 36 6
fffa 65 e rd mem
fffa 65 e rd mem
011b 67 g m1
011b d3 rd mem m1
001c d3 rfsh
001c d3 rfsh mem
011c d3
011c 11 rd mem
011c 11 rd mem
6511 13
011b OUT (11H),A
e 6511 65 e
Once again it stops at an IO write (the e in hello world). We'll single step through a few more instructions, then continue.
z80ctrl>s
ff2d 00 busack
fffb 00
fffb 10 rd mem
fffb 10 rd mem
fffc 10
fffc 01 rd mem
fffc 01 rd mem
0110 01 m1
0110 23 # rd mem m1
0010 23 # rfsh
0110 INC HL
z80ctrl>s
0010 00 rfsh mem
0010 00
0010 00
0111 00 m1
0111 18 rd mem m1
0011 18 rfsh
0011 18 rfsh mem
0112 18
0112 f7 rd mem
0112 f7 rd mem
0112 f7
0111 JR -9
z80ctrl>s
0112 00
0112 00
0112 00
0112 00
010a 00 m1
010a 7e ~ rd mem m1
0012 7e ~ rfsh
010a LD A,(HL)
z80ctrl>s
0012 00 rfsh mem
011f 00
011f 65 e rd mem
011f 65 e rd mem
010b 65 e m1
010b a7 rd mem m1
0013 a7 rfsh
010b AND A
z80ctrl>c
0013 00 rfsh mem
010c 00 m1
010c c8 rd mem m1
0014 c8 rfsh
010c RET Z
0014 c8 rfsh mem
0014 c8
010d c8 m1
010d cd rd mem m1
0015 cd rfsh
0015 cd rfsh mem
010e cd
010e 13 rd mem
010e 13 rd mem
010f 13
010f 01 rd mem
010f 01 rd mem
010f 01
010d CALL 0113H
fffc 01
fffc 01 mem
fffc 01 wr mem
fffb 01
fffb 10 mem
fffb 10 wr mem
0113 10 m1
0113 f5 rd mem m1
0016 f5 rfsh
0113 PUSH AF
0016 f5 rfsh mem
0016 f5
fffa f5
fffa 65 e mem
fffa 65 e wr mem
fff9 65 e
fff9 34 4 mem
fff9 34 4 wr mem
0114 34 4 m1
0114 db rd mem m1
0017 db rfsh
0017 db rfsh mem
0115 db
0115 10 rd mem
0115 10 rd mem
6510 10
0114 IN A,(10H)
6510 02
0116 02 m1
0116 cb rd mem m1
0018 cb rfsh
0018 cb rfsh mem
0117 cb m1
0117 4f O rd mem m1
0019 4f O rfsh
0116 BIT 1,A
0019 4f O rfsh mem
0118 4f O m1
0118 28 ( rd mem m1
001a 2a * rfsh
001a 2a * rfsh mem
0119 2a *
0119 fa rd mem
0119 fa rd mem
011a fa m1
0118 JR Z,-6
011a f1 rd mem m1
001b f3 rfsh
011a POP AF
001b f3 rfsh mem
fff9 f3
fff9 34 4 rd mem
fff9 34 4 rd mem
fffa 36 6
fffa 65 e rd mem
fffa 65 e rd mem
011b 67 g m1
011b d3 rd mem m1
001c d3 rfsh
001c d3 rfsh mem
011c d3
011c 11 rd mem
011c 11 rd mem
6511 13
011b OUT (11H),A
e 6511 65 e
Now we'll disable bus watching, but instruction execution is still being watched. Now if we single-step, it only outputsthe instruction and the address it started with. The bus cycles used to fetch the instruction are not shown.
z80ctrl>watch bus off
z80ctrl>s
011d RET
z80ctrl>s
0110 INC HL
z80ctrl>s
0111 JR -9
z80ctrl>s
010a LD A,(HL)
z80ctrl>s
010b AND A
z80ctrl>s
010c RET Z
Continuing, we can see all the instructions that execute for a single iteration of the loop that outputs each character.
z80ctrl>c
010d CALL 0113H
0113 PUSH AF
0114 IN A,(10H)
0116 BIT 1,A
0118 JR Z,-6
011a POP AF
011b OUT (11H),A
lz80ctrl>c
011d RET
0110 INC HL
0111 JR -9
010a LD A,(HL)
010b AND A
010c RET Z
010d CALL 0113H
0113 PUSH AF
0114 IN A,(10H)
0116 BIT 1,A
0118 JR Z,-6
011a POP AF
011b OUT (11H),A
We stopped again on an IO write, which is outputting the second l in hello world. When we're finished debugging, we can run the program, and it will continue running at full speed from the location where execution was stopped. Breakpoints and watches are ignored while running at full speed. The program finishes printing out "o, world". Once the program finishes, it executes a HALT instruction, which stops the Z80 and automatically returns control to the monitor.
lz80ctrl>run
o, world
z80ctrl>
I have also made YouTube video demonstrating the monitor software.