o debugger

- DISPLAY command only opens the display if it is called without
	additional arguments.
    - for example, calling "DISPLAY DEBUGCOLORS" does not cause the
	display to appear.
This commit is contained in:
steve 2019-03-05 15:15:41 +00:00
parent 8ebc46cc6f
commit 00873d6308
10 changed files with 87 additions and 19 deletions

View file

@ -761,13 +761,15 @@ func (dbg *Debugger) parseCommand(userInput string) (bool, error) {
case KeywordDisplay:
var err error
visibility := true
action, present := tokens.Get()
if present {
action = strings.ToUpper(action)
switch action {
case "OFF":
visibility = false
err = dbg.vcs.TV.SetFeature(television.ReqSetVisibility, false)
if err != nil {
return false, err
}
case "DEBUG":
err = dbg.vcs.TV.SetFeature(television.ReqToggleDebug)
if err != nil {
@ -796,11 +798,11 @@ func (dbg *Debugger) parseCommand(userInput string) (bool, error) {
default:
return false, fmt.Errorf("unknown display action (%s)", action)
}
}
err = dbg.vcs.TV.SetFeature(television.ReqSetVisibility, visibility)
if err != nil {
return false, err
} else {
err = dbg.vcs.TV.SetFeature(television.ReqSetVisibility, true)
if err != nil {
return false, err
}
}
case KeywordMouse:

View file

@ -73,6 +73,11 @@ func (hm *hmove) isset() bool {
return hm.latch
}
// isjustset checks to see if the horiztonal movement sequence has just started
func (hm *hmove) isjustset() bool {
return hm.count == 15 && hm.phase == hm.colorClock.Phase
}
// tick returns the current hmove ripple counter and whether a tick has occurred
func (hm *hmove) tick() (int, bool) {
// if we've reached a count of -1 then no tick will ever occur

View file

@ -27,7 +27,7 @@ func newRsync(colorClock *polycounter.Polycounter) *rsync {
// MachineInfoTerse returns the RSYNC information in verbose format
func (rs rsync) MachineInfoTerse() string {
if rs.isActive() {
if rs.isactive() {
return fmt.Sprintf("RS=%d", rs.remainingCycles)
}
return "RS=-"
@ -35,7 +35,7 @@ func (rs rsync) MachineInfoTerse() string {
// MachineInfo returns the RSYNC information in verbose format
func (rs rsync) MachineInfo() string {
if rs.isActive() {
if rs.isactive() {
return fmt.Sprintf("rsync: reset in %d cycle(s)", rs.remainingCycles)
}
return "rsync: not set"
@ -46,7 +46,7 @@ func (rs rsync) String() string {
return rs.MachineInfo()
}
func (rs rsync) isActive() bool {
func (rs rsync) isactive() bool {
return rs.remainingCycles > -1
}
@ -62,6 +62,10 @@ func (rs *rsync) set() {
rs.colorClock.ResetPhase()
}
func (rs *rsync) isjustset() bool {
return rs.remainingCycles == 5
}
func (rs *rsync) tick() bool {
if rs.remainingCycles == -1 {
return false

View file

@ -182,6 +182,15 @@ func (tia *TIA) StepVideoCycle() bool {
tia.motionClock = false
}
// send metasignal information before we perform any state ticking
err := tia.tv.MetaSignal(television.MetaSignalAttributes{
Hmove: tia.Hmove.isjustset(),
Rsync: tia.rsync.isjustset(),
Wsync: tia.wsync})
if err != nil {
panic(err)
}
// set up new scanline if colorClock has ticked its way to the reset point or if
// an rsync has matured (see rsync.go commentary)
if tia.rsync.tick() {
@ -224,7 +233,7 @@ func (tia *TIA) StepVideoCycle() bool {
}
// at the end of the video cycle we want to finally signal the televison
err := tia.tv.Signal(television.SignalAttributes{
err = tia.tv.Signal(television.SignalAttributes{
VSync: tia.vsync,
VBlank: tia.vblank,
FrontPorch: frontPorch,

View file

@ -130,6 +130,7 @@ func (vd *Video) ResolveHorizMovement(count int) {
// present. it also sets the collision registers
// - it need not be called therefore during VBLANK or HBLANK
func (vd *Video) Pixel(debugColors bool) uint8 {
bgc := vd.Playfield.backgroundColor
pfu, pfc := vd.Playfield.pixel()
blu, blc := vd.Ball.pixel()
p0u, p0c := vd.Player0.pixel()
@ -138,9 +139,15 @@ func (vd *Video) Pixel(debugColors bool) uint8 {
m1u, m1c := vd.Missile1.pixel()
// override program colors with debug colors
// -- same/similar colors to those used in the Stella emulator
if debugColors {
bgc = 0x00 // black (stella uses a light grey)
blc = 0xb4 // cyan
pfc = 0x62 // purple
p0c = 0x32 // red
p1c = 0x15 // gold
p1c = 0x12 // gold
m0c = 0xf2 // orange
m1c = 0xd2 // green
}
// collisions
@ -266,7 +273,7 @@ func (vd *Video) Pixel(debugColors bool) uint8 {
}
// priority 4
return vd.Playfield.backgroundColor
return bgc
}
func createTriggerList(playerSize uint8) []int {

View file

@ -253,6 +253,11 @@ func (tv *HeadlessTV) Signal(sig SignalAttributes) error {
return tv.HookSetPixel(x, y, red, green, blue, sig.VBlank)
}
// MetaSignal recieves (and processes) additional emulator information from the emulator
func (tv *HeadlessTV) MetaSignal(MetaSignalAttributes) error {
return nil
}
// GetState returns the TVState object for the named state. television
// implementations in other packages will difficulty extending this function
// because TVStateReq does not expose its members. (although it may need to if

View file

@ -1,6 +1,6 @@
package sdltv
// callback is used to wrap functions supplied to RequestCallbackRegistration()
// callback is used to wrap functions supplied to RequestCallback()
type callback struct {
channel chan func()

View file

@ -24,8 +24,8 @@ type screen struct {
lastX int32
lastY int32
// pixels arrays are of maximum screen size - actual smalled screens are
// masked appropriately
// pixels arrays are of maximum screen size - actual smaller play screens
// are masked appropriately
pixels []byte
pixelsFade []byte
@ -54,6 +54,9 @@ type screen struct {
// stabiliser to make sure image remains solid
stb *screenStabiliser
// overlay for screen showing metasignal information
metasignals *metasignalOverlay
}
func newScreen(tv *SDLTV) (*screen, error) {
@ -112,6 +115,12 @@ func newScreen(tv *SDLTV) (*screen, error) {
// new stabiliser
scr.stb = newScreenStabiliser(scr)
// new overlay
scr.metasignals, err = newMetasignalOverlay(scr)
if err != nil {
return nil, err
}
return scr, nil
}
@ -204,6 +213,12 @@ func (scr *screen) setPixel(x, y int32, red, green, blue byte, vblank bool) erro
func (scr *screen) update(paused bool) error {
var err error
// update additional overlays
err = scr.metasignals.update()
if err != nil {
return err
}
// clear image from rendered. using a non-video-black color if screen is
// unmasked
if scr.unmasked {
@ -242,6 +257,14 @@ func (scr *screen) update(paused bool) error {
return err
}
// show debugging overlay
if scr.unmasked {
err = scr.renderer.Copy(scr.metasignals.texture, scr.srcRect, scr.destRect)
if err != nil {
return err
}
}
// add cursor if tv is paused
// - drawing last so that cursor isn't masked
if paused {
@ -291,7 +314,7 @@ func (scr *screen) update(paused bool) error {
return nil
}
func (scr *screen) swapPixels() {
func (scr *screen) clearPixels() {
// swap which pixel buffer we're using in time for next round of pixel
// plotting
swp := scr.pixels
@ -302,4 +325,7 @@ func (scr *screen) swapPixels() {
for i := 0; i < len(scr.pixels); i++ {
scr.pixels[i] = 0
}
// clear pixels in additional overlays
scr.metasignals.clearPixels()
}

View file

@ -77,9 +77,9 @@ func NewSDLTV(tvType string, scale float32) (*SDLTV, error) {
}
// register headlesstv callbacks
// leave SignalNewScanline() hook at its default
// --leave SignalNewScanline() hook at its default
tv.HookNewFrame = func() error {
defer tv.scr.swapPixels()
defer tv.scr.clearPixels()
err := tv.scr.stb.checkStableFrame()
if err != nil {
return err

View file

@ -49,6 +49,15 @@ type SignalAttributes struct {
Pixel ColorSignal
}
// MetaSignalAttributes represents any additional emulator data sent to the
// "television" (in inverted commas). not all television implementations need
// to do anything useful with this information.
type MetaSignalAttributes struct {
Hmove bool
Rsync bool
Wsync bool
}
// Television defines the operations that can be performed on the television
type Television interface {
MachineInfoTerse() string
@ -56,6 +65,7 @@ type Television interface {
Reset() error
Signal(SignalAttributes) error
MetaSignal(MetaSignalAttributes) error
GetState(StateReq) (interface{}, error)
GetMetaState(MetaStateReq) (string, error)