Kernel: Simple monitor program for Z80 and Z180, useful for inspecting
authorWill Sowerbutts <will@sowerbutts.com>
Sat, 17 Jan 2015 12:15:24 +0000 (12:15 +0000)
committerWill Sowerbutts <will@sowerbutts.com>
Sat, 17 Jan 2015 12:15:24 +0000 (12:15 +0000)
machine state.

Platform must provide an "inchar" routine which waits for a character on
the console and returns it in A.

This patch also implements the monitor on the p112 and n8vem-mark4
platforms.

Kernel/lib/monitor-z80.s [new file with mode: 0644]
Kernel/platform-n8vem-mark4/Makefile
Kernel/platform-n8vem-mark4/fuzix.lnk
Kernel/platform-n8vem-mark4/kernel.def
Kernel/platform-n8vem-mark4/mark4.s
Kernel/platform-n8vem-mark4/monitor.s [new file with mode: 0644]
Kernel/platform-p112/Makefile
Kernel/platform-p112/fuzix.lnk
Kernel/platform-p112/kernel.def
Kernel/platform-p112/monitor.s [new file with mode: 0644]
Kernel/platform-p112/p112.s

diff --git a/Kernel/lib/monitor-z80.s b/Kernel/lib/monitor-z80.s
new file mode 100644 (file)
index 0000000..75fa047
--- /dev/null
@@ -0,0 +1,286 @@
+; 2015-01-15 William R Sowerbutts
+; A simple Z80 monitor program, mainly useful for inspecting machine state
+;
+; Based on the the socz80 ROM monitor program, and the UZI-180 monitor
+; program, itself based on YM.MAC and M580 monitor.
+;
+; Commands:
+;   D arg1 [arg2]  - display memory at address arg1 (to arg2)
+;   I arg1         - input from port address arg1
+;   O arg1 arg2    - output arg2 to port address arg1
+
+                .module monitor-z80
+                .z80
+
+                ; exported symbols
+                .globl _trap_monitor
+
+                ; imported symbols
+                .globl inchar
+                .globl outchar
+                .globl outcharhex
+                .globl outhl
+                .globl outnewline
+                .globl outstring
+
+                .area _COMMONMEM
+
+; expect to arrive here with return PC on stack
+_trap_monitor:  di                      ; turn off pesky interrupts
+                ld hl, #0
+                add hl, sp              ; save SP
+                pop bc                  ; save PC
+                ld sp, #monitor_stack
+                push bc                 ; orig PC
+                ex de,hl                ; orig SP -> DE
+                ld hl, #entrystr1
+                call outstring
+                ex de,hl                ; orig SP -> HL
+                call outhl
+                ld hl, #entrystr2
+                call outstring
+                pop hl
+                call outhl
+monitor_loop:   call outnewline
+                ld hl, #prompt
+                call outstring
+                ld hl, #linebuffer
+                ld b, #(linebuffer_end-linebuffer) ; length
+                call instring
+                call outnewline
+                call parse_args
+                ld hl, #monitor_loop
+                push hl ; return address
+                ld hl,(arg1)
+                ld de,(arg2)
+                ;ld bc,(arg3)
+                ld a, (linebuffer)
+                cp #'D'
+                jr z, dump
+                cp #'I'
+                jp z, inport
+                cp #'O'
+                jp z, outport
+badinput:       ld a, #'?'
+                jp outchar  ; ret back to monitor_loop
+
+parse_args:     ld hl, #0
+                ld (arg1), hl
+                ld (arg2), hl
+                ;ld (arg3), hl
+                ld de, #linebuffer+1
+                call gethex
+                ld (arg1), hl
+                ld (arg2), hl
+                ret c
+                call gethex
+                ld (arg2), hl
+                ret c
+                ;call gethex
+                ;ld (arg3), hl
+                ;ret c
+                ; more?!
+                jr badinput
+
+; D addr1,addr2
+; Dump region addr1...addr2
+
+dump:           call    out_addr
+                push    hl
+dmph:           ld      a,(hl)
+                call    outbyte
+                call    hl_eq_de
+                jr      z,enddmp
+                inc     hl
+                ld      a,l
+                and     #0x0F
+                jr      nz,dmph
+                pop     hl
+                call    dumpl
+                jr      dump
+enddmp:         pop     hl
+dumpl:          ld      a,#'|'
+                call outchar
+                ld      a,#' '
+                call outchar
+dumpln:         ld      a,(hl)
+                cp      #0x20
+                jr      c,outdot
+                cp      #0x7f
+                jr      c,char
+outdot:         ld      a,#'.'
+char:           call    outchar
+                call    hl_eq_de
+                ret     z
+                inc     hl
+                ld      a,l
+                and     #0x0F
+                jr      nz,dumpln
+                ret
+
+hl_eq_de:       ld      a,h
+                cp      d
+                ret     nz
+                ld      a,l
+                cp      e
+                ret
+
+; I port
+; Input from port
+
+inport:         push hl
+                ld      a,l
+                call    outcharhex
+                ld      a,#'='
+                call    outchar
+                pop hl
+                ld      c,l
+                ld      b,h
+                in      a,(c)
+                call    outcharhex
+                ret
+
+; O port,byte
+; Output to port
+
+outport:        ld      c,l
+                ld      b,h
+                ld      a,e
+                out     (c),a
+                ret
+
+out_addr:       call    outnewline
+                call    outhl
+                ld      a,#':'
+                call    outchar
+                ld      a,#' '
+                jp      outchar
+
+outbyte:        call    outcharhex
+                ld      a,#' '
+                jp      outchar
+
+;cmd_debug:
+;                ld hl, (arg1)
+;                call outhl
+;                call outnewline
+;                ld hl, (arg2)
+;                call outhl
+;                call outnewline
+;                ld hl, (arg3)
+;                call outhl
+;                call outnewline
+;                jp monitor_loop
+
+
+; parse 16-bit hex number at (DE) into HL
+; return with carry flag set if end of string
+gethex:         ld      hl,#0
+ghskip:         ld      a,(de)
+                cp      #' '
+                jr      nz, gh1
+                inc     de
+                jr      ghskip
+gh1:            ld      a,(de)
+                inc     de
+                or      a
+                jp      z,aend
+                cp      #','
+                ret     z
+                cp      #' '
+                ret     z
+                sub     #'0'
+                jp      m,badinput
+                cp      #10
+                jp      m,dig
+                cp      #0x11
+                jp      m,badinput
+                cp      #0x17
+                jp      p,badinput
+                sub     #7
+dig:            ld      c,a
+                ld      b,#0
+                add     hl,hl
+                add     hl,hl
+                add     hl,hl
+                add     hl,hl
+                jp      c,badinput
+                add     hl,bc
+                jp      gh1
+aend:           scf
+                ret
+
+; instring (from socz80, added buffer length checking, added case conversion)
+; reads a string from terminal to memory. HL=buffer address, B=buffer length.
+; Returns length of string (excluding 0 terminator) in C
+instring:       ld c, #0        ; we use C to remember our string length
+instringloop:   call inchar
+                ; test for cr/lf
+                cp #0x0d
+                jr z, cr
+                cp #0x0a
+                jr z, cr
+                ; test for backspace
+                cp #0x08
+                jr z, backspace
+                cp #0x7f
+                jr z, backspace
+                ; test for non-printing characters
+                cp #0x20 ; < 0x20?
+                jp c, instringloop 
+                cp #0x7e ; > 0x7e?
+                jp nc, instringloop
+                cp #'a'
+                jr c, storechar
+                cp #'z'+1
+                jr nc, storechar
+                and #0x5f ; uppercase: characters from a-z are now A-Z
+storechar:      ; store the character in the buffer
+                ld (hl), a
+                inc hl
+                inc c
+                call outchar ; echo back the character typed
+                ; test buffer length
+                ld a, c
+                sub b
+                jr nz, instringloop ; space remains - next character
+                ld a, #7
+                call outchar ; ring the bell
+                ; buffer full - fall through to backspace
+backspace:      ld a, c
+                cp #0
+                jr z, instringloop ; cannot backspace past the start
+                dec hl
+                dec c
+                ld a, #0x08 ; move back
+                call outchar
+                ld a, #0x20 ; print space
+                call outchar
+                ld a, #0x08 ; move back again
+                call outchar
+                jr instringloop
+cr:             ld a, #0
+                ld (hl), a
+                ret
+
+
+; strings
+entrystr1:      .ascii "monitor: SP="
+                .db 0
+entrystr2:      .ascii ", PC="
+                .db 0
+prompt:         .ascii ":( "
+                .db 0
+
+; arguments
+arg1:           .ds 2
+arg2:           .ds 2
+;arg3:           .ds 2
+
+; input buffer
+linebuffer:     .ds 20
+linebuffer_end:
+
+; stack
+                .ds 40
+monitor_stack:
index 84942f9..bfde7f2 100644 (file)
@@ -1,6 +1,6 @@
 CSRCS += devices.c main.c devtty.c devsdspi.c
 DSRCS = ../dev/devide.c ../dev/devsd.c ../dev/mbr.c ../dev/blkdev.c ../dev/ds1302.c
-ASRCS = crt0.s z180.s commonmem.s mark4.s ds1302-mark4.s
+ASRCS = crt0.s z180.s commonmem.s mark4.s ds1302-mark4.s monitor.s
 
 AOBJS = $(ASRCS:.s=.rel)
 COBJS = $(CSRCS:.c=.rel)
index dcce185..37a10c9 100644 (file)
@@ -39,4 +39,5 @@ platform-n8vem-mark4/mbr.rel
 platform-n8vem-mark4/blkdev.rel
 platform-n8vem-mark4/ds1302.rel
 platform-n8vem-mark4/ds1302-mark4.rel
+platform-n8vem-mark4/monitor.rel
 -e
index cabb2a9..96be477 100644 (file)
@@ -13,4 +13,5 @@ Z180_IO_BASE                .equ 0x40
 MARK4_IO_BASE               .equ 0x80
 
 ; No standard clock speed for the Mark IV board, but this is a common choice.
+USE_FANCY_MONITOR           .equ 1            ; disabling this saves around approx 0.5KB
 CPU_CLOCK_KHZ               .equ 36864        ; 18.432MHz * 2
index f10b51e..7043e8d 100644 (file)
@@ -7,10 +7,9 @@
         ; exported symbols
         .globl init_early
         .globl init_hardware
+        .globl inchar
         .globl outchar
-        .globl outcharhex
         .globl platform_interrupt_all
-        .globl _trap_monitor
 
         ; imported symbols
         .globl z180_init_hardware
@@ -75,26 +74,14 @@ ocloop: in0 a, (ASCI_STAT0)
         pop bc
         ret
 
-platform_interrupt_all:
+; inchar: Wait for character on UART, return in A
+; destroys: AF
+inchar:
+        in0 a, (ASCI_STAT0)
+        rlca
+        jr nc, inchar
+        in0 a, (ASCI_RDR0)
         ret
 
-_trap_monitor:
-        di
-        call outnewline
-        pop hl
-        call outhl
-        call outnewline
-        pop hl
-        call outhl
-        call outnewline
-        pop hl
-        call outhl
-        call outnewline
-        pop hl
-        call outhl
-        call outnewline
-        pop hl
-        call outhl
-        call outnewline
-        halt
-        jr _trap_monitor
+platform_interrupt_all:
+        ret
diff --git a/Kernel/platform-n8vem-mark4/monitor.s b/Kernel/platform-n8vem-mark4/monitor.s
new file mode 100644 (file)
index 0000000..656d650
--- /dev/null
@@ -0,0 +1,24 @@
+; 2015-01-17 William R Sowerbutts
+                .module monitor
+                .include "kernel.def"
+
+.ifne USE_FANCY_MONITOR
+                .include "../lib/monitor-z80.s"
+.else
+                .globl outchar
+                .globl outnewline
+                .globl outhl
+                .globl _trap_monitor
+
+                ; micro monitor -
+                ; just dumps a few words from the stack
+_trap_monitor:  di
+                call outnewline
+                ld b, #50
+stacknext:      pop hl
+                call outhl
+                ld a, #' '
+                call outchar
+                djnz stacknext
+                halt
+.endif
index 9f195fd..03e7656 100644 (file)
@@ -1,6 +1,6 @@
 CSRCS += devices.c main.c devtty.c
 DSRCS = ../dev/blkdev.c ../dev/devide.c ../dev/mbr.c ../dev/ds1302.c
-ASRCS = crt0.s z180.s commonmem.s p112.s ds1302-p112.s
+ASRCS = crt0.s z180.s commonmem.s p112.s ds1302-p112.s monitor.s
 
 AOBJS = $(ASRCS:.s=.rel)
 COBJS = $(CSRCS:.c=.rel)
index 00fe4cf..880d89f 100644 (file)
@@ -37,4 +37,5 @@ platform-p112/blkdev.rel
 platform-p112/mbr.rel
 platform-p112/ds1302.rel
 platform-p112/ds1302-p112.rel
+platform-p112/monitor.rel
 -e
index 024c6b0..4bf522f 100644 (file)
@@ -13,4 +13,5 @@ Z80_TYPE                  .equ 2
 
 ; Believe most P112 kits shipped with 16MHz oscillators, I have tried faster 
 ; (18.432MHz) but this made the machine unstable.
+USE_FANCY_MONITOR           .equ 1            ; disabling this saves around 0.5KB
 CPU_CLOCK_KHZ               .equ 16000        ; 16MHz is the stock crystal
diff --git a/Kernel/platform-p112/monitor.s b/Kernel/platform-p112/monitor.s
new file mode 100644 (file)
index 0000000..656d650
--- /dev/null
@@ -0,0 +1,24 @@
+; 2015-01-17 William R Sowerbutts
+                .module monitor
+                .include "kernel.def"
+
+.ifne USE_FANCY_MONITOR
+                .include "../lib/monitor-z80.s"
+.else
+                .globl outchar
+                .globl outnewline
+                .globl outhl
+                .globl _trap_monitor
+
+                ; micro monitor -
+                ; just dumps a few words from the stack
+_trap_monitor:  di
+                call outnewline
+                ld b, #50
+stacknext:      pop hl
+                call outhl
+                ld a, #' '
+                call outchar
+                djnz stacknext
+                halt
+.endif
index 3af2fe6..c27ca19 100644 (file)
@@ -7,6 +7,7 @@
         ; exported symbols
         .globl init_early
         .globl init_hardware
+        .globl inchar
         .globl outchar
         .globl outstring
         .globl outcharhex
@@ -99,26 +100,13 @@ ocloop:     in0 a, (ESCC_CTRL_A)
         pop bc
         ret
 
-platform_interrupt_all:
+; inchar: Wait for character on UART, return in A
+inchar:
+        in0 a, (ESCC_CTRL_A)    ; bit 0 is "rx ready" (1=ready)
+        rrca
+        jr nc, inchar
+        in0 a, (ESCC_DATA_A)
         ret
 
-_trap_monitor:
-        di
-        call outnewline
-        pop hl
-        call outhl
-        call outnewline
-        pop hl
-        call outhl
-        call outnewline
-        pop hl
-        call outhl
-        call outnewline
-        pop hl
-        call outhl
-        call outnewline
-        pop hl
-        call outhl
-        call outnewline
-        halt
-        jr _trap_monitor
+platform_interrupt_all:
+        ret