diff --git a/README.md b/README.md index 0839661..75b0ec0 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ Portable emulator of an Apple II+ or //e. Written in Go. - ProDOS MLI calls - Apple Pascal BIOS calls - Smartport commands + - BBC MOS calls when using [Applecorn](https://github.com/bobbimanners/) - Other features: - Sound - Joystick support. Up to two joysticks or four paddles @@ -227,6 +228,10 @@ Only valid on SDL mode use the sequencer based Disk II card -thunderClockCardSlot int slot for the ThunderClock Plus card. -1 for none (default 4) + -traceBBC + trace BBC MOS API calls used with Applecorn, skip console I/O calls + -traceBBCFull + trace BBC MOS API calls used with Applecorn -traceCpu dump to the console the CPU execution. Use F11 to toggle. -traceHD diff --git a/apple2main.go b/apple2main.go index 21cbfd1..0855425 100644 --- a/apple2main.go +++ b/apple2main.go @@ -142,6 +142,14 @@ func MainApple() *Apple2 { "sequencer", false, "use the sequencer based Disk II card") + traceBBC := flag.Bool( + "traceBBC", + false, + "trace BBC MOS API calls used with Applecorn, skip console I/O calls") + traceBBCFull := flag.Bool( + "traceBBCFull", + false, + "trace BBC MOS API calls used with Applecorn") flag.Parse() @@ -170,6 +178,12 @@ func MainApple() *Apple2 { if *tracePascal { a.addTracer(newTracePascal(a)) } + if *traceBBC { + a.addTracer(newTraceApplecorn(a, false)) + } + if *traceBBCFull { + a.addTracer(newTraceApplecorn(a, true)) + } var charGenMap charColumnMap initialCharGenPage := 0 diff --git a/core6502/execute.go b/core6502/execute.go index cdceb55..c787ccd 100644 --- a/core6502/execute.go +++ b/core6502/execute.go @@ -127,11 +127,16 @@ func (s *State) GetPCAndSP() (uint16, uint8) { return s.reg.getPC(), s.reg.getSP() } -// GetCarryAndAcc returns the value of te carry flag and the accumulator. Used to trace MLI calls +// GetCarryAndAcc returns the value of the carry flag and the accumulator. Used to trace MLI calls func (s *State) GetCarryAndAcc() (bool, uint8) { return s.reg.getFlag(flagC), s.reg.getA() } +// GetAXY returns the value of the A, X and Y registers +func (s *State) GetAXY() (uint8, uint8, uint8) { + return s.reg.getA(), s.reg.getX(), s.reg.getY() +} + // Save saves the CPU state (registers and cycle counter) func (s *State) Save(w io.Writer) error { err := binary.Write(w, binary.BigEndian, s.cycles) diff --git a/traceApplecorn.go b/traceApplecorn.go new file mode 100644 index 0000000..b1139a1 --- /dev/null +++ b/traceApplecorn.go @@ -0,0 +1,107 @@ +package izapple2 + +import "fmt" + +/* + See: + https://github.com/bobbimanners/Applecorn + http://beebwiki.mdfs.net/Category:MOS_API + http://beebwiki.mdfs.net/OSBYTEs + http://mdfs.net/Docs/Comp/BBC/Osbyte00 + +*/ + +type traceApplecorn struct { + a *Apple2 + skipConsole bool + osbyteNames [256]string +} + +const ( + applecornMosVec uint16 = 0xffb9 // Start of the MOS entry points +) + +func newTraceApplecorn(a *Apple2, skipConsole bool) *traceApplecorn { + var t traceApplecorn + t.a = a + t.skipConsole = skipConsole + t.osbyteNames[0x7c] = "clear escape condition" + t.osbyteNames[0x7d] = "set escape condition" + t.osbyteNames[0x7e] = "ack detection of ESC" + t.osbyteNames[0x81] = "Read key with time lim" + t.osbyteNames[0x82] = "read high order address" + t.osbyteNames[0x83] = "read bottom of user mem" + t.osbyteNames[0x84] = "read top of user mem" + t.osbyteNames[0x85] = "top user mem for mode" + t.osbyteNames[0x86] = "read cursor pos" + t.osbyteNames[0xDA] = "clear VDU queue" + + return &t +} + +func (t *traceApplecorn) inspect() { + pc, _ := t.a.cpu.GetPCAndSP() + if pc >= applecornMosVec { + regA, regX, regY := t.a.cpu.GetAXY() + s := "" + + if !t.skipConsole { + switch pc { + case 0xffe0: + s = fmt.Sprintf("OSNEWL()") + case 0xffc8: + ch := "" + if regA >= 0x20 && regA < 0x7f { + ch = string(regA) + } + s = fmt.Sprintf("OSNWRCH(A=%02x, '%v')", regA, ch) + case 0xffcb: + s = fmt.Sprintf("OSNRDCH()") + case 0xffe7: + s = fmt.Sprintf("OSRDCH()") + case 0xffee: + ch := "" + if regA >= 0x20 && regA < 0x7f { + ch = string(regA) + } + s = fmt.Sprintf("OSWRCH(A=%02x, '%v')", regA, ch) + } + + } + + switch pc { + case 0xffb9: + s = "OSDRM(?)" + case 0xffbf: + s = "OSEVEN(?)" + case 0xffc2: + s = "OSINIT(?)" + case 0xffc5: + s = "OSREAD(?)" + case 0xffce: + s = "OSFIND(?)" + case 0xffd1: + s = "OSGBPB(?)" + case 0xffd4: + s = "OSBPUT(?)" + case 0xffd7: + s = "OSBGET(?)" + case 0xffda: + s = "OSARGS(?)" + case 0xffdd: + s = "OSFILE(?)" + case 0xffe3: + s = "OSASCI(?)" + case 0xfff1: + s = fmt.Sprintf("OSWORD(A=%02x,XY=%04x)", regA, uint16(regX)<<8+uint16(regY)) + case 0xfff4: + s = fmt.Sprintf("OSBYTE('%s';A=%02x,X=%02x,Y=%02x)", t.osbyteNames[regA], regA, regX, regY) + case 0xfff7: + s = "OSCLI(?)" + } + + if s != "" { + fmt.Printf("BBC MOS call to $%04x %s\n", pc, s) + } + } +}