CPM-65 preconfigured model and better CPM-65 BIOS and BDOS tracing

This commit is contained in:
Ivan Izaguirre
2024-10-18 23:59:51 +02:00
parent 83f72fe8cb
commit e8a44a8af8
7 changed files with 81 additions and 7 deletions

View File

@@ -233,6 +233,7 @@ The available pre-configured models are:
basis108: Basis 108
cpm: Apple ][+ with CP/M
cpm3: Apple //e with CP/M 3.0
cpm65: Apple //e with CPM-65
dos32: Apple ][ with 13 sectors disk adapter and DOS 3.2x
swyft: swyft
@@ -263,7 +264,8 @@ The available cards are:
The available tracers are:
cpm: Trace CPM BDOS calls
cpm65: Trace CPM65 BDOS calls
cpm65: Trace CPM65 BDOS calls skipping terminal IO
cpm65full: Trace CPM65 BDOS calls
cpu: Trace CPU execution
mli: Trace ProDOS MLI calls
mos: Trace MOS calls with Applecorn skipping terminal IO

3
configs/cpm65.cfg Normal file
View File

@@ -0,0 +1,3 @@
name: Apple //e with CPM-65
parent: 2enh
s6: diskii,disk1=<internal>/cpm65.po

16
doc/cpm65.md Normal file
View File

@@ -0,0 +1,16 @@
# CPM-65
CPM-65 is a native port of Digital Research's seminal 1977 operating system CP/M to the 6502. See https://github.com/davidgiven/cpm65
It runs on an Apple IIe with 80 columns.
To run use the preconfigured model `cpm65`.
Usefull commands:
- `ìzapple -model cpm65` : To run the preconfigured setup
- `izapple apple2e.po`: To use the disk apple2e.po to run any release from [cpm65 releases](https://github.com/davidgiven/cpm65/releases/tag/dev)
- `ìzapple -model cpm65 -trace cpm65` : To trace the BDOS calls, skipping the console related calls
- `ìzapple -model cpm65 -trace cpm65full` : To trace all the BDOS calls.
Todo:
- The address for the BIOS and BDOS entrypoints is hardwired. It should be extracted somehow from the running memory.

View File

@@ -53,6 +53,7 @@ The available pre-configured models are:
basis108: Basis 108
cpm: Apple ][+ with CP/M
cpm3: Apple //e with CP/M 3.0
cpm65: Apple //e with CPM-65
dos32: Apple ][ with 13 sectors disk adapter and DOS 3.2x
swyft: swyft
@@ -83,7 +84,8 @@ The available cards are:
The available tracers are:
cpm: Trace CPM BDOS calls
cpm65: Trace CPM65 BDOS calls
cpm65: Trace CPM65 BDOS calls skipping terminal IO
cpm65full: Trace CPM65 BDOS calls
cpu: Trace CPU execution
mli: Trace ProDOS MLI calls
mos: Trace MOS calls with Applecorn skipping terminal IO

Binary file not shown.

View File

@@ -74,9 +74,19 @@ func getTracerFactory() map[string]*traceBuilder {
}
tracerFactory["cpm65"] = &traceBuilder{
name: "cpm65",
description: "Trace CPM65 BDOS calls skipping terminal IO",
executionTracer: newTraceCpm65(true),
}
tracerFactory["cpm65full"] = &traceBuilder{
name: "cpm65full",
description: "Trace CPM65 BDOS calls",
executionTracer: newTraceCpm65(false),
}
tracerFactory["cpm"] = &traceBuilder{
name: "cpm",
description: "Trace CPM BDOS calls skipping terminal IO",
executionTracer: newTraceCpm(true),
}
tracerFactory["cpm"] = &traceBuilder{
name: "cpm",
description: "Trace CPM BDOS calls",
@@ -109,6 +119,8 @@ func setupTracers(a *Apple2, paramString string) error {
if builder.executionTracer != nil {
a.addTracer(builder.executionTracer)
}
fmt.Printf("Tracer %s enabled\n", builder.name)
}
return nil
}

View File

@@ -15,7 +15,8 @@ type traceCpm65 struct {
}
const (
cpm65BdosEntrypoint uint16 = 0x0804 // start-3, not really sure about this
cpm65BdosEntrypoint uint16 = 0xeb8f // TODO: find the correct address dinamically
cpm65BiosEntrypoint uint16 = 0xfdce // TODO: find the correct address dinamically
)
func newTraceCpm65(skipConsole bool) *traceCpm65 {
@@ -40,15 +41,26 @@ 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, bdos65CodeToName(regY), pc, regA)
fmt.Printf("CPM65 BDOS call %02v:%s with \"%c\"\n", regY, bdos65CodeToName(regY), regA)
}
case 9: // WRITE_STRING
if !t.skipConsole {
text := t.getCpm65String(param)
fmt.Printf("CPM65 BDOS call $%02x:%s from $%04x with \"%s\"\n", regY, bdos65CodeToName(regY), pc, text)
fmt.Printf("CPM65 BDOS call %02v:%s with \"%s\"\n", regY, bdos65CodeToName(regY), text)
}
default:
fmt.Printf("CPM65 BDOS call $%02x:%s from $%04x\n", regY, bdos65CodeToName(regY), pc)
fmt.Printf("CPM65 BDOS call %02v:%s($%04x)\n", regY, bdos65CodeToName(regY), param)
}
}
if pc == cpm65BiosEntrypoint {
regA, regX, regY, _ := t.a.cpu.GetAXYP()
param := uint16(regX)<<8 | uint16(regA)
if regY > 2 /*CONOUT*/ || !t.skipConsole {
switch regY {
default:
fmt.Printf("CPM65 BIOS call %02v:%s($%04x)\n", regY, bios65CodeToName(regY), param)
}
}
}
}
@@ -97,6 +109,26 @@ var cpm65BdosNames = []string{
"WRITE_RANDOM_FILLED", // 40
"GETZP", // 41
"GETTPA", // 42
"PARSE_FILENAME", // 43
}
var cpm65BiosNames = []string{
"CONST", // 0
"CONIN", // 1
"CONOUT", // 2
"SELDSK", // 3
"SETSEC", // 4
"SETDMA", // 5
"READ", // 6
"WRITE", // 7
"RELOCATE", // 8
"GETTPA", // 9
"SETTPA", // 10
"GETZP", // 11
"SETZP", // 12
"SETBANK", // 13
"ADDDRV", // 14
"FINDDRV", // 15
}
func bdos65CodeToName(code uint8) string {
@@ -106,11 +138,18 @@ func bdos65CodeToName(code uint8) string {
return fmt.Sprintf("BDOS_%d", code)
}
func bios65CodeToName(code uint8) string {
if code < uint8(len(cpm65BiosNames)) {
return cpm65BiosNames[code]
}
return fmt.Sprintf("BIOS_%d", code)
}
func (t *traceCpm65) getCpm65String(address uint16) string {
s := ""
for {
ch := t.a.mmu.Peek(address)
if ch == '$' {
if ch == '$' || ch == 0 {
break
}
s += string(ch)