mirror of
https://github.com/JetSetIlly/Gopher2600.git
synced 2025-04-02 11:02:17 -04:00
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:
parent
b509143549
commit
f39d1d33e3
12 changed files with 71 additions and 71 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 "=":
|
||||||
|
|
|
@ -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)",
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Add table
Reference in a new issue