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"
cmdList = "LIST"
cmdMemMap = "MEMMAP"
cmdReflect = "REFLECT"
cmdMissile = "MISSILE"
cmdOnHalt = "ONHALT"
cmdOnStep = "ONSTEP"
@ -89,7 +88,6 @@ var commandTemplate = []string{
cmdLast + " (DEFN|BYTECODE)",
cmdList + " [BREAKS|TRAPS|WATCHES|ALL]",
cmdMemMap,
cmdReflect + " (ON|OFF)",
cmdMissile + " (0|1)",
cmdOnHalt + " (OFF|ON|%S {%S})",
cmdOnStep + " (OFF|ON|%S {%S})",
@ -642,28 +640,6 @@ func (dbg *Debugger) enactCommand(tokens *commandline.Tokens, interactive bool)
case cmdMemMap:
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:
fallthrough
@ -1135,10 +1111,6 @@ func (dbg *Debugger) enactCommand(tokens *commandline.Tokens, interactive bool)
}
}
case "OVERLAY":
if !dbg.relfectMonitor.IsActive() {
return doNothing, errors.New(errors.ReflectionNotRunning)
}
action, _ := tokens.Get()
action = strings.ToUpper(action)
switch action {

View file

@ -147,7 +147,6 @@ func NewDebugger(tv television.Television, scr gui.GUI, term terminal.Terminal)
// set up reflection monitor
dbg.relfectMonitor = reflection.NewMonitor(dbg.vcs, dbg.scr)
dbg.relfectMonitor.Activate(true)
// set up breakpoints/traps
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
// timeout is necessary. a matter of milliseconds should be sufficient
case <-time.After(1 * time.Millisecond):
case <-time.After(10 * time.Millisecond):
empty = true
}
}

View file

@ -33,12 +33,6 @@ func (dbg *Debugger) guiEventHandler(event gui.Event) error {
err = dbg.scr.SetFeature(gui.ReqToggleAltColors)
case "2":
// 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)
case "=":

View file

@ -18,7 +18,6 @@ var help = map[string]string{
cmdLast: "Prints the result of the last cpu/video cycle",
cmdList: "List current entries for BREAKS and TRAPS",
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",
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)",

View file

@ -43,8 +43,6 @@ type Monitor struct {
groupMissile0 addressMonitor
groupMissile1 addressMonitor
groupBall addressMonitor
active bool
}
// 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
}
// 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
// emulation/system
func (mon *Monitor) Check() error {
// silently return if monitor is not active
if !mon.IsActive() {
return nil
}
if err := mon.checkWSYNC(); err != nil {
return err
}

View file

@ -12,10 +12,11 @@ import (
type target interface {
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{}
// 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
}

View file

@ -20,13 +20,12 @@ const (
DisassemblyError = "error debugging disassembly: %v"
// debugger
ParserError = "parser error: %v: %v (char %d)" // first placeholder is the command definition
ValidationError = "%v for %v"
InvalidTarget = "invalid target (%v)"
CommandError = "%v"
TerminalError = "%v"
GUIEventError = "%v"
ReflectionNotRunning = "reflection process is not running"
ParserError = "parser error: %v: %v (char %d)" // first placeholder is the command definition
ValidationError = "%v for %v"
InvalidTarget = "invalid target (%v)"
CommandError = "%v"
TerminalError = "%v"
GUIEventError = "%v"
// dissassembly
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) {
// !!TODO: test page faults
// !!TODO: test backwards branching
var origin uint16
mem.Clear()
_ = mc.Reset()
@ -416,6 +413,57 @@ func testBranching(t *testing.T, mc *cpu.CPU, mem *mockMem) {
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) {
var origin uint16
mem.Clear()
@ -597,6 +645,8 @@ func TestCPU(t *testing.T) {
testPostIndexedIndirect(t, mc, mem)
testStorageInstructions(t, mc, mem)
testBranching(t, mc, mem)
testBranchingBackwards(t, mc, mem)
testBranchingPageFaults(t, mc, mem)
testJumps(t, mc, mem)
testComparisonInstructions(t, mc, mem)
testSubroutineInstructions(t, mc, mem)

View file

@ -21,6 +21,11 @@ func (pc ProgramCounter) String() string {
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
func (pc ProgramCounter) FormatValue(val interface{}) string {
return fmt.Sprintf("%#04x", val)

View file

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

View file

@ -22,7 +22,7 @@ func EquateRegisters(t *testing.T, value, expectedValue interface{}) {
case int:
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:
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:
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: