From 841fe434e711fe8d2b000ec751f92707fc5a6db4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Izaguirre?= Date: Sun, 15 Sep 2024 23:21:59 +0200 Subject: [PATCH] Trace BDOS calls in CP/M --- README.md | 1 + cardVidex.go | 2 +- cardZ80Softcard.go | 2 +- doc/usage.txt | 1 + traceBuilder.go | 5 +++ traceCpm.go | 81 ++++++++++++++++++++++++++++++++++++++++++++++ traceCpm65.go | 12 +++---- 7 files changed, 96 insertions(+), 8 deletions(-) create mode 100644 traceCpm.go diff --git a/README.md b/README.md index 5c5f6655..1b1ae2f9 100644 --- a/README.md +++ b/README.md @@ -261,6 +261,7 @@ The available cards are: z80softcard: Microsoft Z80 SoftCard to run CP/M The available tracers are: + cpm: Trace CPM BDOS calls cpm65: Trace CPM65 BDOS calls cpu: Trace CPU execution mli: Trace ProDOS MLI calls diff --git a/cardVidex.go b/cardVidex.go index 097b428e..d328fc71 100644 --- a/cardVidex.go +++ b/cardVidex.go @@ -142,7 +142,7 @@ func (c *CardVidex) buildImage(light color.Color) *image.RGBA { img.Set(1, 1, color.White) return img } - ms := time.Now().Nanosecond() / (1000 * 1000) // Host time, used for the cursoR blink + ms := time.Now().Nanosecond() / (1000 * 1000) // Host time, used for the cursor blink size := image.Rect(0, 0, width, height) img := image.NewRGBA(size) diff --git a/cardZ80Softcard.go b/cardZ80Softcard.go index 5746441d..ff42d31c 100644 --- a/cardZ80Softcard.go +++ b/cardZ80Softcard.go @@ -79,7 +79,7 @@ func (c *CardZ80SoftCard) runDMACycle() { fmt.Printf("Z80 PC: $%04X, A: $%02X, B: $%02X, C: $%02X, D: $%02X, E: $%02X, HL: $%04X\n", c.cpu.States.PC, c.cpu.States.AF.Hi, c.cpu.States.BC.Hi, c.cpu.States.BC.Lo, c.cpu.States.DE.Hi, c.cpu.States.DE.Lo, - c.cpu.States.HL) + c.cpu.States.HL.U16()) } c.cpu.Step() } diff --git a/doc/usage.txt b/doc/usage.txt index f6e97fd1..a7318a84 100644 --- a/doc/usage.txt +++ b/doc/usage.txt @@ -81,6 +81,7 @@ The available cards are: z80softcard: Microsoft Z80 SoftCard to run CP/M The available tracers are: + cpm: Trace CPM BDOS calls cpm65: Trace CPM65 BDOS calls cpu: Trace CPU execution mli: Trace ProDOS MLI calls diff --git a/traceBuilder.go b/traceBuilder.go index cb20319a..f562e49e 100644 --- a/traceBuilder.go +++ b/traceBuilder.go @@ -77,6 +77,11 @@ func getTracerFactory() map[string]*traceBuilder { description: "Trace CPM65 BDOS calls", executionTracer: newTraceCpm65(false), } + tracerFactory["cpm"] = &traceBuilder{ + name: "cpm", + description: "Trace CPM BDOS calls", + executionTracer: newTraceCpm(false), + } return tracerFactory } diff --git a/traceCpm.go b/traceCpm.go new file mode 100644 index 00000000..c69eaf50 --- /dev/null +++ b/traceCpm.go @@ -0,0 +1,81 @@ +package izapple2 + +import ( + "fmt" +) + +/* + See: + https://github.com/davidgiven/cpm65 +*/ + +type traceCpm struct { + a *Apple2 + skipConsole bool +} + +const ( + cpmBdosEntrypoint uint16 = 0x0005 +) + +func newTraceCpm(skipConsole bool) *traceCpm { + var t traceCpm + t.skipConsole = skipConsole + return &t +} + +func (t *traceCpm) connect(a *Apple2) { + t.a = a +} + +func (t *traceCpm) inspect() { + if !t.a.dmaActive { + return // The 6502 is not running + } + + softCard, ok := t.a.cards[t.a.dmaSlot].(*CardZ80SoftCard) + if !ok { + return // The DMA slot is not a Z80 SoftCard + } + + pc := softCard.cpu.PC + + if pc == cpmBdosEntrypoint { + command := softCard.cpu.BC.Lo + switch command { + case 2: // C_WRITE + if !t.skipConsole { + ch := softCard.cpu.DE.Lo + fmt.Printf("CPM BDOS call %s from $%04x with \"%c\"\n", + bdosCodeToName(command), pc, ch) + } + default: + fmt.Printf("CPM BDOS call %s\n", bdosCodeToName(command)) + } + } +} + +func bdosCodeToName(code uint8) string { + if code < uint8(len(bdosCommandNames)) { + return fmt.Sprintf("%02v-%s", code, bdosCommandNames[code]) + } + return fmt.Sprintf("%02v-UNKNOWN", code) +} + +var bdosCommandNames = []string{ + // 0 + "P_TERMCPM", "C_READ", "C_WRITE", "A_READ", "A_WRITE", + "L_WRITE", "C_RAWIO", "A_STATIN", "A_STATOUT", "C_WRITESTR", + // 10 + "C_READSTR", "C_STAT", "S_BDOSVER", "DRV_ALLRESET", "DRV_SET", + "F_OPEN", "F_CLOSE", "F_SFIRST", "F_SNEXT", "F_DELETE", + // 20 + "F_READ", "F_WRITE", "F_MAKE", "F_RENAME", "DRV_LOGINVEC", + "DRV_GET", "F_DMAOFF", "DRV_ALLOCVEC", "DRV_SETRO", "DRV_ROVEC", + // 30 + "F_ATTRIB", "DRV_DPB", "F_USERNUM", "F_READRAND", "F_WRITERAND", + "F_SIZE", "F_RANDREC", "DRV_RESET", "*", "", + // 40 + "F_WRITEZ", "", "", "", "", + "F_ERRMODE", "", "", "", "", +} diff --git a/traceCpm65.go b/traceCpm65.go index 7fa71bc1..825c4ba0 100644 --- a/traceCpm65.go +++ b/traceCpm65.go @@ -40,15 +40,15 @@ func (t *traceCpm65) inspect() { switch regY { case 2: // CONSOLE_OUTPUT if !t.skipConsole { - fmt.Printf("CPM65 BDOS call $%02x:%s from $%04x with \"%c\"\n", regY, bdosCodeToName(regY), pc, regA) + fmt.Printf("CPM65 BDOS call $%02x:%s from $%04x with \"%c\"\n", regY, bdos65CodeToName(regY), pc, regA) } case 9: // WRITE_STRING if !t.skipConsole { - text := t.getCpmString(param) - fmt.Printf("CPM65 BDOS call $%02x:%s from $%04x with \"%s\"\n", regY, bdosCodeToName(regY), pc, text) + text := t.getCpm65String(param) + fmt.Printf("CPM65 BDOS call $%02x:%s from $%04x with \"%s\"\n", regY, bdos65CodeToName(regY), pc, text) } default: - fmt.Printf("CPM65 BDOS call $%02x:%s from $%04x\n", regY, bdosCodeToName(regY), pc) + fmt.Printf("CPM65 BDOS call $%02x:%s from $%04x\n", regY, bdos65CodeToName(regY), pc) } } } @@ -99,14 +99,14 @@ var cpm65BdosNames = []string{ "GETTPA", // 42 } -func bdosCodeToName(code uint8) string { +func bdos65CodeToName(code uint8) string { if code < uint8(len(cpm65BdosNames)) { return cpm65BdosNames[code] } return fmt.Sprintf("BDOS_%d", code) } -func (t *traceCpm65) getCpmString(address uint16) string { +func (t *traceCpm65) getCpm65String(address uint16) string { s := "" for { ch := t.a.mmu.Peek(address)