o debugger

- removed REFLECT ON/OFF system
    - the performance hit is not that great

o cpu
    - added backward branching test
    - added branching page fault test

o debugger_test
    - increased timeout for rcvOutput()
This commit is contained in:
steve 2019-12-28 11:18:01 +00:00
parent b509143549
commit f39d1d33e3
12 changed files with 71 additions and 71 deletions

View file

@ -40,7 +40,6 @@ const (
cmdLast = "LAST" cmdLast = "LAST"
cmdList = "LIST" cmdList = "LIST"
cmdMemMap = "MEMMAP" cmdMemMap = "MEMMAP"
cmdReflect = "REFLECT"
cmdMissile = "MISSILE" cmdMissile = "MISSILE"
cmdOnHalt = "ONHALT" cmdOnHalt = "ONHALT"
cmdOnStep = "ONSTEP" cmdOnStep = "ONSTEP"
@ -89,7 +88,6 @@ var commandTemplate = []string{
cmdLast + " (DEFN|BYTECODE)", cmdLast + " (DEFN|BYTECODE)",
cmdList + " [BREAKS|TRAPS|WATCHES|ALL]", cmdList + " [BREAKS|TRAPS|WATCHES|ALL]",
cmdMemMap, cmdMemMap,
cmdReflect + " (ON|OFF)",
cmdMissile + " (0|1)", cmdMissile + " (0|1)",
cmdOnHalt + " (OFF|ON|%S {%S})", cmdOnHalt + " (OFF|ON|%S {%S})",
cmdOnStep + " (OFF|ON|%S {%S})", cmdOnStep + " (OFF|ON|%S {%S})",
@ -642,28 +640,6 @@ func (dbg *Debugger) enactCommand(tokens *commandline.Tokens, interactive bool)
case cmdMemMap: case cmdMemMap:
dbg.print(terminal.StyleInstrument, "%v", memorymap.Summary()) dbg.print(terminal.StyleInstrument, "%v", memorymap.Summary())
case cmdReflect:
option, _ := tokens.Get()
switch strings.ToUpper(option) {
case "OFF":
err := dbg.scr.SetFeature(gui.ReqSetOverlay, false)
if err != nil {
dbg.print(terminal.StyleError, err.Error())
}
dbg.relfectMonitor.Activate(false)
case "ON":
err := dbg.scr.SetFeature(gui.ReqSetOverlay, true)
if err != nil {
dbg.print(terminal.StyleError, err.Error())
}
dbg.relfectMonitor.Activate(true)
}
if dbg.relfectMonitor.IsActive() {
dbg.print(terminal.StyleEmulatorInfo, "reflection: ON")
} else {
dbg.print(terminal.StyleEmulatorInfo, "reflection: OFF")
}
case cmdExit: case cmdExit:
fallthrough fallthrough
@ -1135,10 +1111,6 @@ func (dbg *Debugger) enactCommand(tokens *commandline.Tokens, interactive bool)
} }
} }
case "OVERLAY": case "OVERLAY":
if !dbg.relfectMonitor.IsActive() {
return doNothing, errors.New(errors.ReflectionNotRunning)
}
action, _ := tokens.Get() action, _ := tokens.Get()
action = strings.ToUpper(action) action = strings.ToUpper(action)
switch action { switch action {

View file

@ -147,7 +147,6 @@ func NewDebugger(tv television.Television, scr gui.GUI, term terminal.Terminal)
// set up reflection monitor // set up reflection monitor
dbg.relfectMonitor = reflection.NewMonitor(dbg.vcs, dbg.scr) dbg.relfectMonitor = reflection.NewMonitor(dbg.vcs, dbg.scr)
dbg.relfectMonitor.Activate(true)
// set up breakpoints/traps // set up breakpoints/traps
dbg.breakpoints = newBreakpoints(dbg) dbg.breakpoints = newBreakpoints(dbg)

View file

@ -120,7 +120,7 @@ func (trm *mockTerm) rcvOutput() {
// the amount of output sent by the debugger is unpredictable so a // the amount of output sent by the debugger is unpredictable so a
// timeout is necessary. a matter of milliseconds should be sufficient // timeout is necessary. a matter of milliseconds should be sufficient
case <-time.After(1 * time.Millisecond): case <-time.After(10 * time.Millisecond):
empty = true empty = true
} }
} }

View file

@ -33,12 +33,6 @@ func (dbg *Debugger) guiEventHandler(event gui.Event) error {
err = dbg.scr.SetFeature(gui.ReqToggleAltColors) err = dbg.scr.SetFeature(gui.ReqToggleAltColors)
case "2": case "2":
// toggle overlay // toggle overlay
// !!TODO: handle error if reflection is not being processed
// if !dbg.reflectProcess {
// return errors.New(errors.ReflectionNotRunning)
// }
err = dbg.scr.SetFeature(gui.ReqToggleOverlay) err = dbg.scr.SetFeature(gui.ReqToggleOverlay)
case "=": case "=":

View file

@ -18,7 +18,6 @@ var help = map[string]string{
cmdLast: "Prints the result of the last cpu/video cycle", cmdLast: "Prints the result of the last cpu/video cycle",
cmdList: "List current entries for BREAKS and TRAPS", cmdList: "List current entries for BREAKS and TRAPS",
cmdMemMap: "Display high-level VCS memory map", cmdMemMap: "Display high-level VCS memory map",
cmdReflect: "Turn reflection on/off. this will slow down the debugger.",
cmdMissile: "Display the current state of the missile 0/1 sprite", cmdMissile: "Display the current state of the missile 0/1 sprite",
cmdOnHalt: "Commands to run whenever emulation is halted (separate commands with comma)", cmdOnHalt: "Commands to run whenever emulation is halted (separate commands with comma)",
cmdOnStep: "Commands to run whenever emulation steps forward an cpu/video cycle (separate commands with comma)", cmdOnStep: "Commands to run whenever emulation steps forward an cpu/video cycle (separate commands with comma)",

View file

@ -43,8 +43,6 @@ type Monitor struct {
groupMissile0 addressMonitor groupMissile0 addressMonitor
groupMissile1 addressMonitor groupMissile1 addressMonitor
groupBall addressMonitor groupBall addressMonitor
active bool
} }
// NewMonitor is the preferred method of initialisation for the Monitor type // NewMonitor is the preferred method of initialisation for the Monitor type
@ -84,24 +82,9 @@ func NewMonitor(vcs *hardware.VCS, renderer gui.MetaPixelRenderer) *Monitor {
return mon return mon
} }
// Activate the reflection monitor
func (mon *Monitor) Activate(active bool) {
mon.active = active
}
// IsActive returns whether reflection monitor is currently active
func (mon *Monitor) IsActive() bool {
return mon.active
}
// Check should be called every video cycle to record the current state of the // Check should be called every video cycle to record the current state of the
// emulation/system // emulation/system
func (mon *Monitor) Check() error { func (mon *Monitor) Check() error {
// silently return if monitor is not active
if !mon.IsActive() {
return nil
}
if err := mon.checkWSYNC(); err != nil { if err := mon.checkWSYNC(); err != nil {
return err return err
} }

View file

@ -12,10 +12,11 @@ import (
type target interface { type target interface {
Label() string Label() string
// the current value of the target // the current value of the target. should return a value of type int or
// bool.
CurrentValue() interface{} CurrentValue() interface{}
// format an arbitrary value using suitable formatting method of the target // format an arbitrary value using suitable formatting method for the target
FormatValue(val interface{}) string FormatValue(val interface{}) string
} }

View file

@ -20,13 +20,12 @@ const (
DisassemblyError = "error debugging disassembly: %v" DisassemblyError = "error debugging disassembly: %v"
// debugger // debugger
ParserError = "parser error: %v: %v (char %d)" // first placeholder is the command definition ParserError = "parser error: %v: %v (char %d)" // first placeholder is the command definition
ValidationError = "%v for %v" ValidationError = "%v for %v"
InvalidTarget = "invalid target (%v)" InvalidTarget = "invalid target (%v)"
CommandError = "%v" CommandError = "%v"
TerminalError = "%v" TerminalError = "%v"
GUIEventError = "%v" GUIEventError = "%v"
ReflectionNotRunning = "reflection process is not running"
// dissassembly // dissassembly
DisasmError = "disassembly error: %v" DisasmError = "disassembly error: %v"

View file

@ -349,9 +349,6 @@ func testStorageInstructions(t *testing.T, mc *cpu.CPU, mem *mockMem) {
} }
func testBranching(t *testing.T, mc *cpu.CPU, mem *mockMem) { func testBranching(t *testing.T, mc *cpu.CPU, mem *mockMem) {
// !!TODO: test page faults
// !!TODO: test backwards branching
var origin uint16 var origin uint16
mem.Clear() mem.Clear()
_ = mc.Reset() _ = mc.Reset()
@ -416,6 +413,57 @@ func testBranching(t *testing.T, mc *cpu.CPU, mem *mockMem) {
rtest.EquateRegisters(t, mc.PC, 0x12) rtest.EquateRegisters(t, mc.PC, 0x12)
} }
func testBranchingBackwards(t *testing.T, mc *cpu.CPU, mem *mockMem) {
var origin uint16
mem.Clear()
_ = mc.Reset()
mem.Clear()
_ = mc.Reset()
origin = 0x20
mc.LoadPC(0x20)
// BPL backwards
_ = mem.putInstructions(origin, 0x10, 0xfd)
step(t, mc) // BPL $FF
rtest.EquateRegisters(t, mc.PC, 0x1f)
// BVS backwards
origin = 0x20
mc.LoadPC(0x20)
mc.Status.Overflow = true
_ = mem.putInstructions(origin, 0x70, 0xfd)
step(t, mc) // BVS $FF
rtest.EquateRegisters(t, mc.PC, 0x1f)
}
func testBranchingPageFaults(t *testing.T, mc *cpu.CPU, mem *mockMem) {
var origin uint16
mem.Clear()
_ = mc.Reset()
// BNE backwards - with PC wrap (causing a page fault)
origin = 0x20
mc.LoadPC(0x20)
mc.Status.Zero = false
_ = mem.putInstructions(origin, 0xd0, 0x80)
step(t, mc) // BNE $F0
rtest.EquateRegisters(t, mc.PC, 0xffa2)
// pagefault flag should be set
if !mc.LastResult.PageFault {
t.Errorf("expected pagefault on branch")
}
// number of cycles should be 4 instead of 2
// +1 for failed branch test (causing PC to jump)
// +1 for page fault
if mc.LastResult.ActualCycles != 4 {
t.Errorf("expected pagefault on branch")
}
}
func testJumps(t *testing.T, mc *cpu.CPU, mem *mockMem) { func testJumps(t *testing.T, mc *cpu.CPU, mem *mockMem) {
var origin uint16 var origin uint16
mem.Clear() mem.Clear()
@ -597,6 +645,8 @@ func TestCPU(t *testing.T) {
testPostIndexedIndirect(t, mc, mem) testPostIndexedIndirect(t, mc, mem)
testStorageInstructions(t, mc, mem) testStorageInstructions(t, mc, mem)
testBranching(t, mc, mem) testBranching(t, mc, mem)
testBranchingBackwards(t, mc, mem)
testBranchingPageFaults(t, mc, mem)
testJumps(t, mc, mem) testJumps(t, mc, mem)
testComparisonInstructions(t, mc, mem) testComparisonInstructions(t, mc, mem)
testSubroutineInstructions(t, mc, mem) testSubroutineInstructions(t, mc, mem)

View file

@ -21,6 +21,11 @@ func (pc ProgramCounter) String() string {
return fmt.Sprintf("%#04x", pc.value) return fmt.Sprintf("%#04x", pc.value)
} }
// Value returns the current value of the register
func (pc ProgramCounter) Value() uint16 {
return pc.value
}
// FormatValue formats an arbitary value to look like a PC value // FormatValue formats an arbitary value to look like a PC value
func (pc ProgramCounter) FormatValue(val interface{}) string { func (pc ProgramCounter) FormatValue(val interface{}) string {
return fmt.Sprintf("%#04x", val) return fmt.Sprintf("%#04x", val)

View file

@ -4,8 +4,6 @@ import (
"strings" "strings"
) )
// !!TODO: Status register N,V,Z flag bug
// StatusRegister is the special purpose register that stores the flags of the CPU // StatusRegister is the special purpose register that stores the flags of the CPU
type StatusRegister struct { type StatusRegister struct {
Sign bool Sign bool

View file

@ -22,7 +22,7 @@ func EquateRegisters(t *testing.T, value, expectedValue interface{}) {
case int: case int:
if int(value.Value()) != expectedValue { if int(value.Value()) != expectedValue {
t.Errorf("unexpected Register value (%d wanted %d)", value.Value(), expectedValue) t.Errorf("unexpected Register value (%#02x wanted %#02x)", value.Value(), expectedValue)
} }
} }
@ -33,7 +33,7 @@ func EquateRegisters(t *testing.T, value, expectedValue interface{}) {
case int: case int:
if int(value.Address()) != expectedValue { if int(value.Address()) != expectedValue {
t.Errorf("unexpected ProgramCounter value (%d wanted %d)", value, expectedValue) t.Errorf("unexpected ProgramCounter value (%#04x wanted %#04x)", value.Value(), expectedValue)
} }
} }
@ -44,7 +44,7 @@ func EquateRegisters(t *testing.T, value, expectedValue interface{}) {
case int: case int:
if int(value.Value()) != expectedValue { if int(value.Value()) != expectedValue {
t.Errorf("unexpected StatusRegister value (%d wanted %d)", value.Value(), expectedValue) t.Errorf("unexpected StatusRegister value (%#02x wanted %#02x)", value.Value(), expectedValue)
} }
case string: case string: