-
Notifications
You must be signed in to change notification settings - Fork 14
Monitor User Guide
The AVR firmware contains a built-in monitor program to allow control of the Z80. When the AVR starts up, it presents a z80ctrl> prompt. The following commands are provided:
- Dump, disassemble, or fill memory (
dump,disasm,fill) - List files on the SD card (
dir) - Load and save Intel HEX files (
loadhex,savehex) - Mount, unmount, and boot from disk images (
mount,unmount,sboot,dboot) - Set breakpoints and watchpoints, and debug a program (
break,watch,debug,step) - Start the Z80 running from any address (
run) - Clear the screen (
cls) - List available commands (
help)
Load hello world program from a Intel hex file.
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
Show a hex dump of the program. 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 ................
Disassemble the program. 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
Enable watches on bus activity and opcode fetches and then display 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 [start] [end] watch off to disable type watch off to disable all
Enable breaks on IO writes and display status:
z80ctrl>break iowr z80ctrl>break break status: memrd: disabled memwr: disabled iord: disabled iowr: 0000-00ff opfetch: disabled
usage: break [start] [end] break off to disable type break off to disable all
Debug the program. Bus watch 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. After the entire instruction and its operands has been fetched, the disassembled instruction is displayed, along with the start address.
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 were run to execute a single instruction. We can continue stepping through a few more instructions.
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, so only instructions are still being watched. Now if we single-step, it only shows the 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. If 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>
Watch this [YouTube video](https://www.youtube.com/watch?v=5hJ0k5ZuQRE) for a demo of the monitor software.