mirror of
https://github.com/JetSetIlly/Gopher2600.git
synced 2024-05-20 13:48:02 -04:00
more flexible yield information
This commit is contained in:
parent
123a96cd09
commit
81f4a83490
|
@ -22,7 +22,7 @@ import (
|
|||
// YieldState records the most recent yield.
|
||||
type YieldState struct {
|
||||
InstructionPC uint32
|
||||
Reason mapper.YieldReason
|
||||
Reason mapper.CoProcYieldType
|
||||
LocalVariables []*SourceVariableLocal
|
||||
}
|
||||
|
||||
|
@ -32,15 +32,15 @@ func (y *YieldState) Cmp(w *YieldState) bool {
|
|||
}
|
||||
|
||||
// OnYield implements the mapper.CartCoProcDeveloper interface.
|
||||
func (dev *Developer) OnYield(instructionPC uint32, currentPC uint32, reason mapper.YieldReason) {
|
||||
func (dev *Developer) OnYield(instructionPC uint32, currentPC uint32, yield mapper.CoProcYield) {
|
||||
// do nothing if yield reason is YieldSyncWithVCS
|
||||
//
|
||||
// yielding for this reason is likely to be followed by another yield
|
||||
// very soon after so there is no point gathering this information
|
||||
if reason == mapper.YieldSyncWithVCS {
|
||||
if yield.Type == mapper.YieldSyncWithVCS {
|
||||
dev.BorrowYieldState(func(yld *YieldState) {
|
||||
yld.InstructionPC = instructionPC
|
||||
yld.Reason = reason
|
||||
yld.Reason = yield.Type
|
||||
yld.LocalVariables = yld.LocalVariables[:0]
|
||||
})
|
||||
|
||||
|
@ -64,7 +64,7 @@ func (dev *Developer) OnYield(instructionPC uint32, currentPC uint32, reason map
|
|||
}
|
||||
|
||||
// log a bug for any of these reasons
|
||||
switch reason {
|
||||
switch yield.Type {
|
||||
case mapper.YieldMemoryAccessError:
|
||||
fallthrough
|
||||
case mapper.YieldExecutionError:
|
||||
|
@ -127,7 +127,7 @@ func (dev *Developer) OnYield(instructionPC uint32, currentPC uint32, reason map
|
|||
|
||||
dev.BorrowYieldState(func(yld *YieldState) {
|
||||
yld.InstructionPC = instructionPC
|
||||
yld.Reason = reason
|
||||
yld.Reason = yield.Type
|
||||
|
||||
// clear list of local variables from previous yield
|
||||
yld.LocalVariables = yld.LocalVariables[:0]
|
||||
|
|
|
@ -858,14 +858,14 @@ func (dbg *Debugger) StartInPlayMode(filename string) error {
|
|||
}
|
||||
|
||||
// CartYield implements the mapper.CartYieldHook interface.
|
||||
func (dbg *Debugger) CartYield(reason mapper.YieldReason) bool {
|
||||
func (dbg *Debugger) CartYield(yield mapper.CoProcYieldType) bool {
|
||||
// if the emulator wants to quit we need to return true to instruct the
|
||||
// cartridge to return to the main loop immediately
|
||||
if !dbg.running {
|
||||
return true
|
||||
}
|
||||
|
||||
switch reason {
|
||||
switch yield {
|
||||
case mapper.YieldProgramEnded:
|
||||
// expected reason for CDF and DPC+ cartridges
|
||||
return false
|
||||
|
|
|
@ -599,7 +599,8 @@ func (dbg *Debugger) handleInterrupt(inputter terminal.Input) {
|
|||
_, err = inputter.TermRead(confirm,
|
||||
terminal.Prompt{
|
||||
Content: "really quit (y/n) ",
|
||||
Type: terminal.PromptTypeConfirm},
|
||||
Type: terminal.PromptTypeConfirm,
|
||||
},
|
||||
dbg.events)
|
||||
|
||||
if err != nil {
|
||||
|
|
|
@ -21,59 +21,48 @@ import (
|
|||
|
||||
"github.com/jetsetilly/gopher2600/debugger/terminal"
|
||||
"github.com/jetsetilly/gopher2600/disassembly"
|
||||
"github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper"
|
||||
)
|
||||
|
||||
func (dbg *Debugger) buildPrompt() terminal.Prompt {
|
||||
content := strings.Builder{}
|
||||
s := strings.Builder{}
|
||||
|
||||
// to keep things simple for now, only the idle coprocessor state will
|
||||
// result in a detailed 6507 prompt. the other states are better served
|
||||
// (for now) by a descriptive prompt without any disassembly
|
||||
//
|
||||
// TODO: better prompts for non-idle coprocessor states
|
||||
switch dbg.vcs.Mem.Cart.CoProcState() {
|
||||
case mapper.CoProcNOPFeed:
|
||||
content.WriteString(fmt.Sprintf("$%04x (NOP feed)", dbg.vcs.CPU.PC.Address()))
|
||||
case mapper.CoProcStrongARMFeed:
|
||||
content.WriteString(fmt.Sprintf("$%04x (StrongARM feed)", dbg.vcs.CPU.PC.Address()))
|
||||
case mapper.CoProcParallel:
|
||||
content.WriteString(fmt.Sprintf("$%04x (parallel)", dbg.vcs.CPU.PC.Address()))
|
||||
case mapper.CoProcIdle:
|
||||
var e *disassembly.Entry
|
||||
var e *disassembly.Entry
|
||||
|
||||
// decide which address value to use
|
||||
if dbg.vcs.CPU.LastResult.Final || dbg.vcs.CPU.HasReset() {
|
||||
e = dbg.Disasm.GetEntryByAddress(dbg.vcs.CPU.PC.Address())
|
||||
} else {
|
||||
// if we're in the middle of an instruction then use the addresss in
|
||||
// lastResult. in these instances we want the prompt to report the
|
||||
// instruction that the CPU is working on, not the next one to be
|
||||
// stepped into.
|
||||
e = dbg.liveDisasmEntry
|
||||
}
|
||||
// decide which address value to use
|
||||
if dbg.vcs.CPU.LastResult.Final || dbg.vcs.CPU.HasReset() {
|
||||
e = dbg.Disasm.GetEntryByAddress(dbg.vcs.CPU.PC.Address())
|
||||
} else {
|
||||
// if we're in the middle of an instruction then use the addresss in
|
||||
// lastResult. in these instances we want the prompt to report the
|
||||
// instruction that the CPU is working on, not the next one to be
|
||||
// stepped into.
|
||||
e = dbg.liveDisasmEntry
|
||||
}
|
||||
|
||||
// build prompt based on how confident we are of the contents of the
|
||||
// disassembly entry. starting with the condition of no disassembly at all
|
||||
if e == nil {
|
||||
content.WriteString(fmt.Sprintf("$%04x", dbg.vcs.CPU.PC.Address()))
|
||||
} else if e.Level == disassembly.EntryLevelUnmappable {
|
||||
content.WriteString(e.Address)
|
||||
} else {
|
||||
// this is the ideal path. the address is in the disassembly and we've
|
||||
// decoded it already
|
||||
content.WriteString(fmt.Sprintf("%s %s", e.Address, e.Operator))
|
||||
// build prompt based on how confident we are of the contents of the
|
||||
// disassembly entry. starting with the condition of no disassembly at all
|
||||
if e == nil {
|
||||
s.WriteString(fmt.Sprintf("$%04x", dbg.vcs.CPU.PC.Address()))
|
||||
} else if e.Level == disassembly.EntryLevelUnmappable {
|
||||
s.WriteString(e.Address)
|
||||
} else {
|
||||
// this is the ideal path. the address is in the disassembly and we've
|
||||
// decoded it already
|
||||
s.WriteString(fmt.Sprintf("%s %s", e.Address, e.Operator))
|
||||
|
||||
if e.Operand.String() != "" {
|
||||
content.WriteString(fmt.Sprintf(" %s", e.Operand))
|
||||
}
|
||||
if e.Operand.String() != "" {
|
||||
s.WriteString(fmt.Sprintf(" %s", e.Operand))
|
||||
}
|
||||
}
|
||||
|
||||
p := terminal.Prompt{
|
||||
Content: content.String(),
|
||||
Content: s.String(),
|
||||
Recording: dbg.scriptScribe.IsActive(),
|
||||
CPURdy: dbg.vcs.CPU.RdyFlg,
|
||||
}
|
||||
|
||||
if coproc := dbg.vcs.Mem.Cart.GetCoProc(); coproc != nil {
|
||||
state := coproc.CoProcExecutionState()
|
||||
p.Yield = state.Yield
|
||||
}
|
||||
|
||||
// LastResult final is false on CPU reset so we must check for that also
|
||||
|
|
|
@ -133,7 +133,7 @@ func (ct *ColorTerminal) TermRead(input []byte, prompt terminal.Prompt, events *
|
|||
inputLen = 0
|
||||
cursorPos = 0
|
||||
ct.EasyTerm.TermPrint("\r")
|
||||
ct.EasyTerm.TermPrint(ansi.CursorMove(len(prompt.Content)))
|
||||
ct.EasyTerm.TermPrint(ansi.CursorMove(len(prompt.String())))
|
||||
} else {
|
||||
// there is no input so return UserInterrupt error
|
||||
ct.EasyTerm.TermPrint("\r\n")
|
||||
|
|
|
@ -15,17 +15,21 @@
|
|||
|
||||
package terminal
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper"
|
||||
)
|
||||
|
||||
// Prompt specifies the prompt text and the prompt style. For CPUStep
|
||||
// and VideoStep prompt types thre is some additional information that
|
||||
// can be used to decorate the prompt.
|
||||
type Prompt struct {
|
||||
Content string
|
||||
Type PromptType
|
||||
Type PromptType
|
||||
|
||||
Content string
|
||||
Yield mapper.CoProcYield
|
||||
|
||||
// valid for PromptTypeCPUStep and PromptTypeVideoStep
|
||||
CPURdy bool
|
||||
Recording bool
|
||||
}
|
||||
|
||||
|
@ -36,6 +40,7 @@ type PromptType int
|
|||
const (
|
||||
PromptTypeCPUStep PromptType = iota
|
||||
PromptTypeVideoStep
|
||||
PromptTypeCartYield
|
||||
PromptTypeConfirm
|
||||
)
|
||||
|
||||
|
@ -54,17 +59,15 @@ func (p Prompt) String() string {
|
|||
}
|
||||
s.WriteString(" ")
|
||||
s.WriteString(p.Content)
|
||||
|
||||
s.WriteString(" ]")
|
||||
|
||||
if !p.CPURdy {
|
||||
s.WriteString(" !")
|
||||
}
|
||||
|
||||
if p.Type == PromptTypeCPUStep {
|
||||
switch p.Type {
|
||||
case PromptTypeCPUStep:
|
||||
s.WriteString(" >> ")
|
||||
} else {
|
||||
case PromptTypeVideoStep:
|
||||
s.WriteString(" > ")
|
||||
case PromptTypeCartYield:
|
||||
s.WriteString(" . ")
|
||||
}
|
||||
|
||||
return s.String()
|
||||
|
|
|
@ -623,7 +623,7 @@ func (scr *screen) reflectionColor(ref *reflection.ReflectedVideoStep) color.RGB
|
|||
return reflectionColors[reflection.AudioPhase1]
|
||||
}
|
||||
case reflection.OverlayLabels[reflection.OverlayCoproc]:
|
||||
switch ref.CoProcState {
|
||||
switch ref.CoProcSync {
|
||||
case mapper.CoProcIdle:
|
||||
return reflectionColors[reflection.CoProcInactive]
|
||||
case mapper.CoProcNOPFeed:
|
||||
|
|
|
@ -312,7 +312,7 @@ func (win *winCoProcPerformance) draw() {
|
|||
}
|
||||
|
||||
func (win *winCoProcPerformance) drawFrameStats() {
|
||||
accumulate := func(s mapper.CoProcState) int {
|
||||
accumulate := func(s mapper.CoProcSynchronisation) int {
|
||||
switch s {
|
||||
case mapper.CoProcIdle:
|
||||
case mapper.CoProcNOPFeed:
|
||||
|
@ -354,18 +354,18 @@ func (win *winCoProcPerformance) drawFrameStats() {
|
|||
|
||||
switch win.kernelFocus {
|
||||
case developer.KernelAny:
|
||||
clockCount += float32(accumulate(r.CoProcState))
|
||||
clockCount += float32(accumulate(r.CoProcSync))
|
||||
case developer.KernelScreen:
|
||||
if sl >= win.img.screen.crit.frameInfo.VisibleTop && sl <= win.img.screen.crit.frameInfo.VisibleBottom {
|
||||
clockCount += float32(accumulate(r.CoProcState))
|
||||
clockCount += float32(accumulate(r.CoProcSync))
|
||||
}
|
||||
case developer.KernelVBLANK:
|
||||
if sl < win.img.screen.crit.frameInfo.VisibleTop {
|
||||
clockCount += float32(accumulate(r.CoProcState))
|
||||
clockCount += float32(accumulate(r.CoProcSync))
|
||||
}
|
||||
case developer.KernelOverscan:
|
||||
if sl > win.img.screen.crit.frameInfo.VisibleBottom {
|
||||
clockCount += float32(accumulate(r.CoProcState))
|
||||
clockCount += float32(accumulate(r.CoProcSync))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -734,7 +734,7 @@ func (win *winDbgScr) drawReflectionTooltip() {
|
|||
}
|
||||
case reflection.OverlayLabels[reflection.OverlayCoproc]:
|
||||
imguiSeparator()
|
||||
switch ref.CoProcState {
|
||||
switch ref.CoProcSync {
|
||||
case mapper.CoProcIdle:
|
||||
imgui.Text(fmt.Sprintf("%s is idle", win.img.lz.Cart.CoProcID))
|
||||
case mapper.CoProcNOPFeed:
|
||||
|
|
|
@ -184,6 +184,13 @@ func (win *winTerm) debuggerDraw() bool {
|
|||
}
|
||||
} else {
|
||||
imgui.Text(win.prompt.Content)
|
||||
if !win.prompt.Yield.Type.Normal() {
|
||||
imgui.SameLine()
|
||||
imgui.Text(win.prompt.Yield.Type.String())
|
||||
if win.prompt.Yield.Detail != nil {
|
||||
imguiTooltipSimple(win.prompt.Yield.Detail.Error(), true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// chevron indicator
|
||||
|
|
|
@ -36,11 +36,6 @@ type Ace struct {
|
|||
// the hook that handles cartridge yields
|
||||
yieldHook mapper.CartYieldHook
|
||||
|
||||
// parallelARM is true whenever the address bus is not a cartridge address (ie.
|
||||
// a TIA or RIOT address). this means that the arm is running unhindered
|
||||
// and will not have yielded for that colour clock
|
||||
parallelARM bool
|
||||
|
||||
// armState is a copy of the ARM's state at the moment of the most recent
|
||||
// Snapshot. it's used only suring a Plumb() operation
|
||||
armState *arm.ARMState
|
||||
|
@ -154,15 +149,15 @@ func (cart *Ace) Patch(_ int, _ uint8) error {
|
|||
|
||||
func (cart *Ace) runARM() {
|
||||
// call arm once and then check for yield conditions
|
||||
yld, _ := cart.arm.Run()
|
||||
cart.mem.yield, _ = cart.arm.Run()
|
||||
|
||||
// keep calling runArm() for as long as program does not need to sync with the VCS...
|
||||
for yld != mapper.YieldSyncWithVCS {
|
||||
for cart.mem.yield.Type != mapper.YieldSyncWithVCS {
|
||||
// ... or if the yield hook says to return to the VCS immedtiately
|
||||
if cart.yieldHook.CartYield(yld) {
|
||||
if cart.yieldHook.CartYield(cart.mem.yield.Type) {
|
||||
return
|
||||
}
|
||||
yld, _ = cart.arm.Run()
|
||||
cart.mem.yield, _ = cart.arm.Run()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,7 +165,7 @@ func (cart *Ace) runARM() {
|
|||
func (cart *Ace) AccessPassive(addr uint16, data uint8) {
|
||||
// if memory access is not a cartridge address (ie. a TIA or RIOT address)
|
||||
// then the ARM is running in parallel (ie. no synchronisation)
|
||||
cart.parallelARM = (addr&memorymap.OriginCart != memorymap.OriginCart)
|
||||
cart.mem.parallelARM = (addr&memorymap.OriginCart != memorymap.OriginCart)
|
||||
|
||||
// start profiling before the run sequence
|
||||
if cart.dev != nil {
|
||||
|
@ -247,12 +242,18 @@ func (cart *Ace) ExecutableOrigin() uint32 {
|
|||
return cart.mem.flashARMOrigin
|
||||
}
|
||||
|
||||
// CoProcState implements the mapper.CartCoProc interface.
|
||||
func (cart *Ace) CoProcState() mapper.CoProcState {
|
||||
if cart.parallelARM {
|
||||
return mapper.CoProcParallel
|
||||
// CoProcExecutionState implements the mapper.CartCoProc interface.
|
||||
func (cart *Ace) CoProcExecutionState() mapper.CoProcExecutionState {
|
||||
if cart.mem.parallelARM {
|
||||
return mapper.CoProcExecutionState{
|
||||
Sync: mapper.CoProcParallel,
|
||||
Yield: cart.mem.yield,
|
||||
}
|
||||
}
|
||||
return mapper.CoProcExecutionState{
|
||||
Sync: mapper.CoProcStrongARMFeed,
|
||||
Yield: cart.mem.yield,
|
||||
}
|
||||
return mapper.CoProcStrongARMFeed
|
||||
}
|
||||
|
||||
// CoProcRegister implements the mapper.CartCoProc interface.
|
||||
|
|
|
@ -82,6 +82,14 @@ type aceMemory struct {
|
|||
flashARMMemtop uint32
|
||||
|
||||
arm interruptARM
|
||||
|
||||
// parallelARM is true whenever the address bus is not a cartridge address (ie.
|
||||
// a TIA or RIOT address). this means that the arm is running unhindered
|
||||
// and will not have yielded for that colour clock
|
||||
parallelARM bool
|
||||
|
||||
// most recent yield from the coprocessor
|
||||
yield mapper.CoProcYield
|
||||
}
|
||||
|
||||
const (
|
||||
|
|
|
@ -110,7 +110,7 @@ type ARMState struct {
|
|||
interrupt bool
|
||||
|
||||
// the yield reason explains the reason for why the ARM execution ended
|
||||
yieldReason mapper.YieldReason
|
||||
yield mapper.CoProcYield
|
||||
|
||||
// for clarity both the interrupt and yieldReason fields should be set at
|
||||
// the same time wher possible
|
||||
|
@ -590,7 +590,13 @@ func (arm *ARM) SetInitialRegisters(args ...uint32) error {
|
|||
// previous execution ran to completion (ie. was uninterrupted).
|
||||
//
|
||||
// Returns the yield reason, the number of ARM cycles consumed.
|
||||
func (arm *ARM) Run() (mapper.YieldReason, float32) {
|
||||
func (arm *ARM) Run() (mapper.CoProcYield, float32) {
|
||||
if arm.dev != nil {
|
||||
defer func() {
|
||||
arm.dev.OnYield(arm.state.instructionPC, arm.state.registers[rPC], arm.state.yield)
|
||||
}()
|
||||
}
|
||||
|
||||
if !arm.state.interrupt {
|
||||
arm.resetRegisters()
|
||||
}
|
||||
|
@ -598,7 +604,7 @@ func (arm *ARM) Run() (mapper.YieldReason, float32) {
|
|||
// reset cycles count
|
||||
arm.state.cyclesTotal = 0
|
||||
|
||||
// arm.staten.prefetchCycle reset in reset() function. we don't want to change
|
||||
// arm.state.prefetchCycle reset in reset() function. we don't want to change
|
||||
// the value if we're resuming from a yield
|
||||
|
||||
// reset continue flag and error conditions
|
||||
|
@ -618,12 +624,10 @@ func (arm *ARM) Run() (mapper.YieldReason, float32) {
|
|||
if err != nil {
|
||||
logger.Logf("ARM7", err.Error())
|
||||
|
||||
// returing early so we must call OnYield here
|
||||
if arm.dev != nil {
|
||||
arm.dev.OnYield(arm.state.instructionPC, arm.state.registers[rPC], arm.state.yieldReason)
|
||||
}
|
||||
arm.state.yield.Type = mapper.YieldMemoryAccessError
|
||||
arm.state.yield.Detail = err
|
||||
|
||||
return mapper.YieldMemoryAccessError, 0
|
||||
return arm.state.yield, 0
|
||||
}
|
||||
|
||||
// fill pipeline cannot happen immediately after resetRegisters()
|
||||
|
@ -633,7 +637,8 @@ func (arm *ARM) Run() (mapper.YieldReason, float32) {
|
|||
|
||||
// default to an uninterrupted state and a sync with VCS yield reason
|
||||
arm.state.interrupt = false
|
||||
arm.state.yieldReason = mapper.YieldSyncWithVCS
|
||||
arm.state.yield.Type = mapper.YieldSyncWithVCS
|
||||
arm.state.yield.Detail = nil
|
||||
|
||||
return arm.run()
|
||||
}
|
||||
|
@ -680,7 +685,7 @@ func (arm *ARM) BreakpointsEnable(enable bool) {
|
|||
arm.breakpointsEnabled = enable
|
||||
}
|
||||
|
||||
func (arm *ARM) run() (mapper.YieldReason, float32) {
|
||||
func (arm *ARM) run() (mapper.CoProcYield, float32) {
|
||||
select {
|
||||
case <-arm.prefsPulse.C:
|
||||
arm.updatePrefs()
|
||||
|
@ -905,7 +910,9 @@ func (arm *ARM) run() (mapper.YieldReason, float32) {
|
|||
}
|
||||
|
||||
if arm.abortOnStackCollision && arm.breakpointsEnabled {
|
||||
return mapper.YieldMemoryAccessError, 0
|
||||
arm.state.interrupt = true
|
||||
arm.state.yield.Type = mapper.YieldMemoryAccessError
|
||||
arm.state.yield.Detail = err
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -924,16 +931,16 @@ func (arm *ARM) run() (mapper.YieldReason, float32) {
|
|||
|
||||
logger.Logf("ARM7: memory error", arm.disasmVerbose(entry))
|
||||
}
|
||||
if arm.abortOnIllegalMem && arm.breakpointsEnabled {
|
||||
arm.state.interrupt = true
|
||||
arm.state.yield.Type = mapper.YieldMemoryAccessError
|
||||
arm.state.yield.Detail = arm.memoryError
|
||||
}
|
||||
|
||||
// we need to reset the memory error instances so that we don't end
|
||||
// up printing the same message over and over
|
||||
arm.memoryError = nil
|
||||
arm.memoryErrorDev = nil
|
||||
|
||||
if arm.abortOnIllegalMem && arm.breakpointsEnabled {
|
||||
arm.state.interrupt = true
|
||||
arm.state.yieldReason = mapper.YieldMemoryAccessError
|
||||
}
|
||||
}
|
||||
|
||||
// handle execution errors
|
||||
|
@ -942,7 +949,8 @@ func (arm *ARM) run() (mapper.YieldReason, float32) {
|
|||
|
||||
if arm.breakpointsEnabled {
|
||||
arm.state.interrupt = true
|
||||
arm.state.yieldReason = mapper.YieldExecutionError
|
||||
arm.state.yield.Type = mapper.YieldExecutionError
|
||||
arm.state.yield.Detail = arm.executionError
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -952,7 +960,8 @@ func (arm *ARM) run() (mapper.YieldReason, float32) {
|
|||
if arm.dev != nil && arm.breakpointsEnabled && !arm.state.function32bitDecoding {
|
||||
if arm.dev.CheckBreakpoint(arm.state.instructionPC) {
|
||||
arm.state.interrupt = true
|
||||
arm.state.yieldReason = mapper.YieldBreakpoint
|
||||
arm.state.yield.Type = mapper.YieldBreakpoint
|
||||
arm.state.yield.Detail = fmt.Errorf("%08x", arm.state.instructionPC)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -965,12 +974,7 @@ func (arm *ARM) run() (mapper.YieldReason, float32) {
|
|||
}
|
||||
}
|
||||
|
||||
// update yield information
|
||||
if arm.dev != nil {
|
||||
arm.dev.OnYield(arm.state.instructionPC, arm.state.registers[rPC], arm.state.yieldReason)
|
||||
}
|
||||
|
||||
return arm.state.yieldReason, arm.state.cyclesTotal
|
||||
return arm.state.yield, arm.state.cyclesTotal
|
||||
}
|
||||
|
||||
func (arm *ARM) stepARM7TDMI(opcode uint16, memIdx int) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package arm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/bits"
|
||||
|
||||
|
@ -919,7 +920,8 @@ func (arm *ARM) decodeThumbHiRegisterOps(opcode uint16) *DisasmEntry {
|
|||
// cannot switch to ARM mode in the ARMv7-M architecture
|
||||
arm.continueExecution = false
|
||||
arm.state.interrupt = true
|
||||
arm.state.yieldReason = mapper.YieldUndefinedBehaviour
|
||||
arm.state.yield.Type = mapper.YieldUndefinedBehaviour
|
||||
arm.state.yield.Detail = errors.New("cannot switch to ARM mode in ARMv7-M architecture")
|
||||
}
|
||||
arm.state.registers[rPC] = (target + 2) & 0xfffffffe
|
||||
} else {
|
||||
|
@ -929,7 +931,8 @@ func (arm *ARM) decodeThumbHiRegisterOps(opcode uint16) *DisasmEntry {
|
|||
// cannot switch to ARM mode in the ARMv7-M architecture
|
||||
arm.continueExecution = false
|
||||
arm.state.interrupt = true
|
||||
arm.state.yieldReason = mapper.YieldUndefinedBehaviour
|
||||
arm.state.yield.Type = mapper.YieldUndefinedBehaviour
|
||||
arm.state.yield.Detail = errors.New("cannot switch to ARM mode in ARMv7-M architecture")
|
||||
}
|
||||
arm.state.registers[rPC] = (target + 2) & 0xfffffffe
|
||||
}
|
||||
|
@ -996,7 +999,8 @@ func (arm *ARM) decodeThumbHiRegisterOps(opcode uint16) *DisasmEntry {
|
|||
if !res.InterruptServiced {
|
||||
arm.continueExecution = false
|
||||
arm.state.interrupt = false
|
||||
arm.state.yieldReason = mapper.YieldProgramEnded
|
||||
arm.state.yield.Type = mapper.YieldProgramEnded
|
||||
arm.state.yield.Detail = nil
|
||||
// "7.6 Data Operations" in "ARM7TDMI-S Technical Reference Manual r4p3"
|
||||
// - interrupted
|
||||
return nil
|
||||
|
|
|
@ -149,7 +149,8 @@ func (arm *ARM) decodeThumb2Miscellaneous(opcode uint16) decodeFunction {
|
|||
return func(_ uint16) *DisasmEntry {
|
||||
arm.continueExecution = false
|
||||
arm.state.interrupt = true
|
||||
arm.state.yieldReason = mapper.YieldSyncWithVCS
|
||||
arm.state.yield.Type = mapper.YieldSyncWithVCS
|
||||
arm.state.yield.Detail = nil
|
||||
return nil
|
||||
}
|
||||
} else if opcode&0xff00 == 0xba00 {
|
||||
|
|
|
@ -533,12 +533,15 @@ func (cart *Cartridge) SetYieldHook(hook mapper.CartYieldHook) {
|
|||
}
|
||||
}
|
||||
|
||||
// CoProcState implements the mapper.CartCoProc interface.
|
||||
func (cart *Cartridge) CoProcState() mapper.CoProcState {
|
||||
// CoProcExecutionState implements the mapper.CartCoProc interface
|
||||
//
|
||||
// If cartridge does not have a coprocessor then an empty instance of
|
||||
// mapper.CoProcExecutionState is returned
|
||||
func (cart *Cartridge) CoProcExecutionState() mapper.CoProcExecutionState {
|
||||
if cart.hasCoProc {
|
||||
return cart.coproc.CoProcState()
|
||||
return cart.coproc.CoProcExecutionState()
|
||||
}
|
||||
return mapper.CoProcIdle
|
||||
return mapper.CoProcExecutionState{}
|
||||
}
|
||||
|
||||
// BusStuff implements the mapper.CartBusStuff interface.
|
||||
|
|
|
@ -379,15 +379,15 @@ func (cart *cdf) AccessVolatile(addr uint16, data uint8, poke bool) error {
|
|||
}
|
||||
|
||||
// call runArm() once and then check for yield conditions
|
||||
yld := cart.runArm()
|
||||
cart.state.yield = cart.runArm()
|
||||
|
||||
// keep calling runArm() for as long as program has not ended...
|
||||
for yld != mapper.YieldProgramEnded {
|
||||
for cart.state.yield.Type != mapper.YieldProgramEnded {
|
||||
// ... or if the yield hook says to return to the VCS immediately
|
||||
if cart.yieldHook.CartYield(yld) {
|
||||
if cart.yieldHook.CartYield(cart.state.yield.Type) {
|
||||
break // for loop
|
||||
}
|
||||
yld = cart.runArm()
|
||||
cart.state.yield = cart.runArm()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -664,12 +664,18 @@ func (cart *cdf) HotLoad(data []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// CoProcState implements the mapper.CartCoProc interface.
|
||||
func (cart *cdf) CoProcState() mapper.CoProcState {
|
||||
// CoProcExecutionState implements the mapper.CartCoProc interface.
|
||||
func (cart *cdf) CoProcExecutionState() mapper.CoProcExecutionState {
|
||||
if cart.state.callfn.IsActive() {
|
||||
return mapper.CoProcNOPFeed
|
||||
return mapper.CoProcExecutionState{
|
||||
Sync: mapper.CoProcNOPFeed,
|
||||
Yield: cart.state.yield,
|
||||
}
|
||||
}
|
||||
return mapper.CoProcExecutionState{
|
||||
Sync: mapper.CoProcIdle,
|
||||
Yield: cart.state.yield,
|
||||
}
|
||||
return mapper.CoProcIdle
|
||||
}
|
||||
|
||||
// CoProcRegister implements the mapper.CartCoProc interface.
|
||||
|
@ -715,7 +721,7 @@ func (cart *cdf) SetYieldHook(hook mapper.CartYieldHook) {
|
|||
cart.yieldHook = hook
|
||||
}
|
||||
|
||||
func (cart *cdf) runArm() mapper.YieldReason {
|
||||
func (cart *cdf) runArm() mapper.CoProcYield {
|
||||
yld, cycles := cart.arm.Run()
|
||||
|
||||
cart.state.callfn.Accumulate(cycles)
|
||||
|
|
|
@ -15,7 +15,10 @@
|
|||
|
||||
package cdf
|
||||
|
||||
import "github.com/jetsetilly/gopher2600/hardware/memory/cartridge/arm/callfn"
|
||||
import (
|
||||
"github.com/jetsetilly/gopher2600/hardware/memory/cartridge/arm/callfn"
|
||||
"github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper"
|
||||
)
|
||||
|
||||
type State struct {
|
||||
// currently selected bank
|
||||
|
@ -42,6 +45,9 @@ type State struct {
|
|||
|
||||
// the callfn process is stateful
|
||||
callfn callfn.CallFn
|
||||
|
||||
// most recent yield from the coprocessor
|
||||
yield mapper.CoProcYield
|
||||
}
|
||||
|
||||
// initialise should be called as soon as convenient.
|
||||
|
|
|
@ -507,15 +507,15 @@ func (cart *dpcPlus) AccessVolatile(addr uint16, data uint8, poke bool) error {
|
|||
cart.dev.StartProfiling()
|
||||
}
|
||||
|
||||
yld := cart.runArm()
|
||||
cart.state.yield = cart.runArm()
|
||||
|
||||
// keep calling runArm() for as long as program has not ended...
|
||||
for yld != mapper.YieldProgramEnded {
|
||||
for cart.state.yield.Type != mapper.YieldProgramEnded {
|
||||
// ... or if the yield hook says to return to the VCS immediately
|
||||
if cart.yieldHook.CartYield(yld) {
|
||||
if cart.yieldHook.CartYield(cart.state.yield.Type) {
|
||||
break // for loop
|
||||
}
|
||||
yld = cart.runArm()
|
||||
cart.state.yield = cart.runArm()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -917,12 +917,18 @@ func (cart *dpcPlus) ARMinterrupt(addr uint32, val1 uint32, val2 uint32) (arm.AR
|
|||
return arm.ARMinterruptReturn{}, nil
|
||||
}
|
||||
|
||||
// CoProcState implements the mapper.CartCoProc interface.
|
||||
func (cart *dpcPlus) CoProcState() mapper.CoProcState {
|
||||
// CoProcExecutionState implements the mapper.CartCoProc interface.
|
||||
func (cart *dpcPlus) CoProcExecutionState() mapper.CoProcExecutionState {
|
||||
if cart.state.callfn.IsActive() {
|
||||
return mapper.CoProcNOPFeed
|
||||
return mapper.CoProcExecutionState{
|
||||
Sync: mapper.CoProcNOPFeed,
|
||||
Yield: cart.state.yield,
|
||||
}
|
||||
}
|
||||
return mapper.CoProcExecutionState{
|
||||
Sync: mapper.CoProcIdle,
|
||||
Yield: cart.state.yield,
|
||||
}
|
||||
return mapper.CoProcIdle
|
||||
}
|
||||
|
||||
// CoProcRegister implements the mapper.CartCoProc interface.
|
||||
|
@ -968,7 +974,7 @@ func (cart *dpcPlus) SetYieldHook(hook mapper.CartYieldHook) {
|
|||
cart.yieldHook = hook
|
||||
}
|
||||
|
||||
func (cart *dpcPlus) runArm() mapper.YieldReason {
|
||||
func (cart *dpcPlus) runArm() mapper.CoProcYield {
|
||||
yld, cycles := cart.arm.Run()
|
||||
cart.state.callfn.Accumulate(cycles)
|
||||
return yld
|
||||
|
|
|
@ -17,6 +17,7 @@ package dpcplus
|
|||
|
||||
import (
|
||||
"github.com/jetsetilly/gopher2600/hardware/memory/cartridge/arm/callfn"
|
||||
"github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper"
|
||||
"github.com/jetsetilly/gopher2600/random"
|
||||
)
|
||||
|
||||
|
@ -42,6 +43,9 @@ type State struct {
|
|||
|
||||
// the callfn process is stateful
|
||||
callfn callfn.CallFn
|
||||
|
||||
// most recent yield from the coprocessor
|
||||
yield mapper.CoProcYield
|
||||
}
|
||||
|
||||
func newDPCPlusState() *State {
|
||||
|
|
|
@ -43,11 +43,6 @@ type Elf struct {
|
|||
// the hook that handles cartridge yields
|
||||
yieldHook mapper.CartYieldHook
|
||||
|
||||
// parallelARM is true whenever the address bus is not a cartridge address (ie.
|
||||
// a TIA or RIOT address). this means that the arm is running unhindered
|
||||
// and will not have yielded for that colour clock
|
||||
parallelARM bool
|
||||
|
||||
// armState is a copy of the ARM's state at the moment of the most recent
|
||||
// Snapshot. it's used only suring a Plumb() operation
|
||||
armState *arm.ARMState
|
||||
|
@ -258,15 +253,15 @@ func (cart *Elf) runARM() {
|
|||
}
|
||||
|
||||
// call arm once and then check for yield conditions
|
||||
yld, _ := cart.arm.Run()
|
||||
cart.mem.yield, _ = cart.arm.Run()
|
||||
|
||||
// keep calling runArm() for as long as program does not need to sync with the VCS...
|
||||
for yld != mapper.YieldSyncWithVCS {
|
||||
for cart.mem.yield.Type != mapper.YieldSyncWithVCS {
|
||||
// ... or if the yield hook says to return to the VCS immediately
|
||||
if cart.yieldHook.CartYield(yld) {
|
||||
if cart.yieldHook.CartYield(cart.mem.yield.Type) {
|
||||
return
|
||||
}
|
||||
yld, _ = cart.arm.Run()
|
||||
cart.mem.yield, _ = cart.arm.Run()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,7 +300,7 @@ func (cart *Elf) runStrongarm(addr uint16, data uint8) bool {
|
|||
func (cart *Elf) AccessPassive(addr uint16, data uint8) {
|
||||
// if memory access is not a cartridge address (ie. a TIA or RIOT address)
|
||||
// then the ARM is running in parallel (ie. no synchronisation)
|
||||
cart.parallelARM = (addr&memorymap.OriginCart != memorymap.OriginCart)
|
||||
cart.mem.parallelARM = (addr&memorymap.OriginCart != memorymap.OriginCart)
|
||||
|
||||
// if address is the reset address then trigger the reset procedure
|
||||
if (addr&memorymap.CartridgeBits)|memorymap.OriginCart == (cpubus.Reset&memorymap.CartridgeBits)|memorymap.OriginCart {
|
||||
|
@ -405,12 +400,18 @@ func (cart *Elf) ELFSection(name string) ([]uint8, uint32, bool) {
|
|||
return nil, 0, false
|
||||
}
|
||||
|
||||
// CoProcState implements the mapper.CartCoProc interface.
|
||||
func (cart *Elf) CoProcState() mapper.CoProcState {
|
||||
if cart.parallelARM {
|
||||
return mapper.CoProcParallel
|
||||
// CoProcExecutionState implements the mapper.CartCoProc interface.
|
||||
func (cart *Elf) CoProcExecutionState() mapper.CoProcExecutionState {
|
||||
if cart.mem.parallelARM {
|
||||
return mapper.CoProcExecutionState{
|
||||
Sync: mapper.CoProcParallel,
|
||||
Yield: cart.mem.yield,
|
||||
}
|
||||
}
|
||||
return mapper.CoProcExecutionState{
|
||||
Sync: mapper.CoProcStrongARMFeed,
|
||||
Yield: cart.mem.yield,
|
||||
}
|
||||
return mapper.CoProcStrongARMFeed
|
||||
}
|
||||
|
||||
// CoProcRegister implements the mapper.CartCoProc interface.
|
||||
|
@ -455,3 +456,23 @@ func (cart *Elf) BreakpointsEnable(enable bool) {
|
|||
func (cart *Elf) SetYieldHook(hook mapper.CartYieldHook) {
|
||||
cart.yieldHook = hook
|
||||
}
|
||||
|
||||
// GetStatic implements the mapper.CartStaticBus interface.
|
||||
func (cart *Elf) GetStatic() mapper.CartStatic {
|
||||
return cart.mem.Snapshot()
|
||||
}
|
||||
|
||||
// StaticWrite implements the mapper.CartStaticBus interface.
|
||||
func (cart *Elf) PutStatic(segment string, idx int, data uint8) bool {
|
||||
mem, ok := cart.mem.Reference(segment)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if idx >= len(mem) {
|
||||
return false
|
||||
}
|
||||
mem[idx] = data
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -123,6 +123,14 @@ type elfMemory struct {
|
|||
// args is a special memory area that is used for the arguments passed to
|
||||
// the main function on startup
|
||||
args []byte
|
||||
|
||||
// parallelARM is true whenever the address bus is not a cartridge address (ie.
|
||||
// a TIA or RIOT address). this means that the arm is running unhindered
|
||||
// and will not have yielded for that colour clock
|
||||
parallelARM bool
|
||||
|
||||
// most recent yield from the coprocessor
|
||||
yield mapper.CoProcYield
|
||||
}
|
||||
|
||||
func newElfMemory(ef *elf.File) (*elfMemory, error) {
|
||||
|
@ -674,23 +682,3 @@ func (m *elfMemory) Read32bit(addr uint32) (uint32, bool) {
|
|||
uint32((*mem)[addr+2])<<16 |
|
||||
uint32((*mem)[addr+3])<<24, true
|
||||
}
|
||||
|
||||
// GetStatic implements the mapper.CartStaticBus interface.
|
||||
func (cart *Elf) GetStatic() mapper.CartStatic {
|
||||
return cart.mem.Snapshot()
|
||||
}
|
||||
|
||||
// StaticWrite implements the mapper.CartStaticBus interface.
|
||||
func (cart *Elf) PutStatic(segment string, idx int, data uint8) bool {
|
||||
mem, ok := cart.mem.Reference(segment)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if idx >= len(mem) {
|
||||
return false
|
||||
}
|
||||
mem[idx] = data
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -19,16 +19,35 @@ import (
|
|||
"fmt"
|
||||
)
|
||||
|
||||
// CoProcState is used to describe the state of the coprocessor. We can think
|
||||
// of these values as descriptions of the synchronisation state between the
|
||||
// coprocessor and the VCS.
|
||||
type CoProcState int
|
||||
// CoProcExecutionState details the current condition of the coprocessor's execution
|
||||
type CoProcExecutionState struct {
|
||||
Sync CoProcSynchronisation
|
||||
Yield CoProcYield
|
||||
}
|
||||
|
||||
// List of valid CoProcState values. A mapper will probably not employ all of
|
||||
// these states depending on the synchronisation strategy.
|
||||
// CoProcSynchronisation is used to describe the VCS synchronisation state of
|
||||
// the coprocessor
|
||||
type CoProcSynchronisation int
|
||||
|
||||
func (s CoProcSynchronisation) String() string {
|
||||
switch s {
|
||||
case CoProcIdle:
|
||||
return "idle"
|
||||
case CoProcNOPFeed:
|
||||
return "nop feed"
|
||||
case CoProcStrongARMFeed:
|
||||
return "strongarm feed"
|
||||
case CoProcParallel:
|
||||
return "parallel"
|
||||
}
|
||||
panic("unknown CoProcSynchronisation")
|
||||
}
|
||||
|
||||
// List of valid CoProcSynchronisation values.
|
||||
//
|
||||
// In reality the state will alternate between Idle-and-NOPFeed and
|
||||
// StronARMFeed-and-Parallel.
|
||||
// A mapper will probably not employ all of these states depending on the
|
||||
// synchronisation strategy. In reality the state will alternate between
|
||||
// Idle-and-NOPFeed and StronARMFeed-and-Parallel.
|
||||
//
|
||||
// Other synchronisation strategies may need the addition of additional states
|
||||
// or a different mechanism altogether.
|
||||
|
@ -36,7 +55,7 @@ const (
|
|||
// the idle state means that the coprocessor is not interacting with the
|
||||
// VCS at that moment. the coprocessor might be running but it is waiting
|
||||
// to be instructed by the VCS program
|
||||
CoProcIdle CoProcState = iota
|
||||
CoProcIdle CoProcSynchronisation = iota
|
||||
|
||||
// a NOP feed describes the state where a cartridge mapper is waiting for
|
||||
// the coprocessor to finish processing. in the meantime, the cartridge is
|
||||
|
@ -56,21 +75,21 @@ const (
|
|||
// coprocessor has reached a breakpoint or some other yield point (eg.
|
||||
// undefined behaviour)
|
||||
type CartYieldHook interface {
|
||||
// CartYield returns true if the YieldReason cannot be handled without
|
||||
// CartYield returns true if the yield type cannot be handled without
|
||||
// breaking into a debugging loop
|
||||
//
|
||||
// CartYield will return true if the cartridge mapper should cancel
|
||||
// CartYield will also return true if the cartridge mapper should cancel
|
||||
// coprocessing immediately
|
||||
//
|
||||
// all other yield reasons will return false
|
||||
CartYield(YieldReason) bool
|
||||
CartYield(CoProcYieldType) bool
|
||||
}
|
||||
|
||||
// StubCartYieldHook is a stub implementation for the CartYieldHook interface.
|
||||
type StubCartYieldHook struct{}
|
||||
|
||||
// CartYield is a stub implementation for the CartYieldHook interface.
|
||||
func (_ StubCartYieldHook) CartYield(_ YieldReason) bool {
|
||||
func (_ StubCartYieldHook) CartYield(_ CoProcYieldType) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -84,7 +103,7 @@ type CartCoProc interface {
|
|||
SetDeveloper(CartCoProcDeveloper)
|
||||
|
||||
// the state of the coprocessor
|
||||
CoProcState() CoProcState
|
||||
CoProcExecutionState() CoProcExecutionState
|
||||
|
||||
// breakpoint control of coprocessor
|
||||
BreakpointsEnable(bool)
|
||||
|
@ -168,42 +187,74 @@ type CartCoProcDeveloper interface {
|
|||
|
||||
// OnYield is called whenever the ARM yields to the VCS. It communicates the PC of the most
|
||||
// recent instruction, the current PC (as it is now), and the reason for the yield
|
||||
OnYield(instructionPC uint32, currentPC uint32, reason YieldReason)
|
||||
OnYield(instructionPC uint32, currentPC uint32, reason CoProcYield)
|
||||
}
|
||||
|
||||
// YieldReason specifies the reason for a yield
|
||||
type YieldReason string
|
||||
// CoProcYield describes a coprocessor yield state
|
||||
type CoProcYield struct {
|
||||
Type CoProcYieldType
|
||||
Detail error
|
||||
}
|
||||
|
||||
// List of YieldReason values
|
||||
// CoProcYieldType specifies the type of yield. This is a broad categorisation
|
||||
type CoProcYieldType int
|
||||
|
||||
func (t CoProcYieldType) String() string {
|
||||
switch t {
|
||||
case YieldProgramEnded:
|
||||
return "ended"
|
||||
case YieldSyncWithVCS:
|
||||
return "sync"
|
||||
case YieldBreakpoint:
|
||||
return "break"
|
||||
case YieldUndefinedBehaviour:
|
||||
return "undefined behaviour"
|
||||
case YieldUnimplementedFeature:
|
||||
return "unimplement feature"
|
||||
case YieldMemoryAccessError:
|
||||
return "memory error"
|
||||
case YieldExecutionError:
|
||||
return "execution error"
|
||||
}
|
||||
panic("unknown CoProcYieldType")
|
||||
}
|
||||
|
||||
// Normal returns true if yield type is expected during normal operation of the
|
||||
// coprocessor
|
||||
func (t CoProcYieldType) Normal() bool {
|
||||
return t == YieldProgramEnded || t == YieldSyncWithVCS
|
||||
}
|
||||
|
||||
// List of CoProcYieldType values
|
||||
const (
|
||||
// the coprocessor has yielded because the program has ended. in this instance the
|
||||
// CoProcessor is not considered to be in a "yielded" state and can be modified
|
||||
//
|
||||
// Expected YieldReason for CDF and DPC+ type ROMs
|
||||
YieldProgramEnded YieldReason = "Program Ended"
|
||||
YieldProgramEnded CoProcYieldType = iota
|
||||
|
||||
// the coprocessor has reached a synchronisation point in the program. it
|
||||
// must wait for the VCS before continuing
|
||||
//
|
||||
// Expected YieldReason for ACE and ELF type ROMs
|
||||
YieldSyncWithVCS YieldReason = "Sync With VCS"
|
||||
YieldSyncWithVCS
|
||||
|
||||
// a user supplied breakpoint has been encountered
|
||||
YieldBreakpoint YieldReason = "Breakpoint"
|
||||
YieldBreakpoint
|
||||
|
||||
// the program has triggered undefined behaviour in the coprocessor
|
||||
YieldUndefinedBehaviour YieldReason = "Undefined Behaviour"
|
||||
YieldUndefinedBehaviour
|
||||
|
||||
// the program has triggered an unimplemented feature in the coprocessor
|
||||
YieldUnimplementedFeature YieldReason = "Unimplemented Feature"
|
||||
YieldUnimplementedFeature
|
||||
|
||||
// the program has tried to access memory illegally. details will have been
|
||||
// communicated by the IllegalAccess() function of the CartCoProcDeveloper
|
||||
// interface
|
||||
YieldMemoryAccessError YieldReason = "Memory Access Error"
|
||||
YieldMemoryAccessError
|
||||
|
||||
// execution error indicates that something has gone very wrong
|
||||
YieldExecutionError YieldReason = "Execution Error"
|
||||
YieldExecutionError
|
||||
)
|
||||
|
||||
// CartCoProcDisasmSummary represents a summary of a coprocessor execution.
|
||||
|
|
|
@ -39,8 +39,8 @@ const (
|
|||
|
||||
// for graphical purposes we only distinguish between active and inactive
|
||||
// coprocessor states. the underlying states as defined in the mapper
|
||||
// package (mapper.CoProcState) are used to decided whether the coproc is
|
||||
// active or inactive
|
||||
// package (mapper.CoProcSynchronisation) are used to decided whether the
|
||||
// coproc is active or inactive
|
||||
CoProcInactive
|
||||
CoProcActive
|
||||
)
|
||||
|
|
|
@ -59,7 +59,7 @@ type ReflectedVideoStep struct {
|
|||
VideoElement video.Element
|
||||
WSYNC bool
|
||||
IsRAM bool
|
||||
CoProcState mapper.CoProcState
|
||||
CoProcSync mapper.CoProcSynchronisation
|
||||
IsHblank bool
|
||||
RSYNCalign bool
|
||||
RSYNCreset bool
|
||||
|
|
|
@ -100,7 +100,7 @@ func (ref *Reflector) Step(bank mapper.BankInfo) error {
|
|||
h[0].Signal = sig
|
||||
h[0].Collision = *ref.vcs.TIA.Video.Collisions
|
||||
h[0].IsHblank = ref.vcs.TIA.Hblank
|
||||
h[0].CoProcState = ref.vcs.Mem.Cart.CoProcState()
|
||||
h[0].CoProcSync = ref.vcs.Mem.Cart.CoProcExecutionState().Sync
|
||||
|
||||
if ref.vcs.TIA.Hmove.Future.IsActive() {
|
||||
h[0].Hmove.Delay = true
|
||||
|
|
Loading…
Reference in a new issue