From e4dea5c7b948bfa05ecf4d52ab06d62c970f9fca Mon Sep 17 00:00:00 2001 From: JetSetIlly Date: Tue, 15 Oct 2024 22:53:49 +0100 Subject: [PATCH] reverted SignalAttributes to a struct profiling shows that the performance penalty is no longer that great. the struct is preferable because the code is clearer --- bots/chess/videochess.go | 7 ++-- bots/spacejockey/spacejockey.go | 7 ++-- comparison/comparison.go | 9 ++--- comparison/driver.go | 9 ++--- coprocessor/developer/profiling.go | 5 +-- digest/audio.go | 7 ++-- digest/video.go | 5 +-- gui/sdlaudio/audio.go | 6 +-- gui/sdlimgui/screen.go | 9 ++--- gui/sdlimgui/win_dbgscr.go | 4 +- gui/sdlimgui/win_dbgscr_paint.go | 11 +++--- gui/sdlimgui/win_oscilloscope.go | 6 +-- hardware/television/resizer.go | 9 ++--- hardware/television/signal/signal.go | 53 +++++++++----------------- hardware/television/simple.go | 11 +++--- hardware/television/television.go | 19 ++++++---- hardware/television/vblank.go | 10 ++--- hardware/tia/tia.go | 57 ++++++++++------------------ reflection/reflector.go | 9 ++--- thumbnailer/anim.go | 9 ++--- thumbnailer/image.go | 5 +-- wavwriter/wav.go | 6 +-- 22 files changed, 109 insertions(+), 164 deletions(-) diff --git a/bots/chess/videochess.go b/bots/chess/videochess.go index 1309accae..9f1d25efd 100644 --- a/bots/chess/videochess.go +++ b/bots/chess/videochess.go @@ -88,7 +88,7 @@ const audioSilence = 15 func (o *observer) SetAudio(sig []signal.SignalAttributes) error { for _, s := range sig { - if uint8((s&signal.AudioChannel0)>>signal.AudioChannel0Shift) != audioSilence { + if s.AudioChannel0 != audioSilence { select { case o.audioFeedback <- true: default: @@ -132,11 +132,10 @@ func (obs *observer) SetPixels(sig []signal.SignalAttributes, last int) error { for i := range sig { // handle VBLANK by setting pixels to black - if sig[i]&signal.VBlank == signal.VBlank { + if sig[i].VBlank { col = color.RGBA{R: 0, G: 0, B: 0} } else { - px := signal.ColorSignal((sig[i] & signal.Color) >> signal.ColorShift) - col = obs.frameInfo.Spec.GetColor(px) + col = obs.frameInfo.Spec.GetColor(sig[i].Color) } // small cap improves performance, see https://golang.org/issue/27857 diff --git a/bots/spacejockey/spacejockey.go b/bots/spacejockey/spacejockey.go index 87412b04c..815ede508 100644 --- a/bots/spacejockey/spacejockey.go +++ b/bots/spacejockey/spacejockey.go @@ -57,7 +57,7 @@ const audioSilence = 15 func (o *observer) SetAudio(sig []signal.SignalAttributes) error { for _, s := range sig { - if uint8((s&signal.AudioChannel0)>>signal.AudioChannel0Shift) != audioSilence { + if s.AudioChannel0 != audioSilence { select { case o.audioFeedback <- true: default: @@ -101,11 +101,10 @@ func (obs *observer) SetPixels(sig []signal.SignalAttributes, last int) error { for i := range sig { // handle VBLANK by setting pixels to black - if sig[i]&signal.VBlank == signal.VBlank { + if sig[i].VBlank { col = color.RGBA{R: 0, G: 0, B: 0} } else { - px := signal.ColorSignal((sig[i] & signal.Color) >> signal.ColorShift) - col = obs.frameInfo.Spec.GetColor(px) + col = obs.frameInfo.Spec.GetColor(sig[i].Color) } // small cap improves performance, see https://golang.org/issue/27857 diff --git a/comparison/comparison.go b/comparison/comparison.go index 14f6ac2e7..8ff76824a 100644 --- a/comparison/comparison.go +++ b/comparison/comparison.go @@ -354,11 +354,10 @@ func (cmp *Comparison) SetPixels(sig []signal.SignalAttributes, last int) error for i := range sig { // handle VBLANK by setting pixels to black - if sig[i]&signal.VBlank == signal.VBlank { + if sig[i].VBlank { col = color.RGBA{R: 0, G: 0, B: 0} } else { - px := signal.ColorSignal((sig[i] & signal.Color) >> signal.ColorShift) - col = cmp.frameInfo.Spec.GetColor(px) + col = cmp.frameInfo.Spec.GetColor(sig[i].Color) } // small cap improves performance, see https://golang.org/issue/27857 @@ -407,9 +406,7 @@ func (cmp *Comparison) EndRendering() error { // SetAudio implements the television.AudioMixer interface. func (cmp *Comparison) SetAudio(sig []signal.SignalAttributes) error { for _, s := range sig { - v0 := uint8((s & signal.AudioChannel0) >> signal.AudioChannel0Shift) - v1 := uint8((s & signal.AudioChannel1) >> signal.AudioChannel1Shift) - cmp.audio = append(cmp.audio, v0, v1) + cmp.audio = append(cmp.audio, s.AudioChannel0, s.AudioChannel1) } return nil } diff --git a/comparison/driver.go b/comparison/driver.go index e6d85e099..d75571808 100644 --- a/comparison/driver.go +++ b/comparison/driver.go @@ -110,11 +110,10 @@ func (drv *driver) SetPixels(sig []signal.SignalAttributes, last int) error { for i := range sig { // handle VBLANK by setting pixels to black - if sig[i]&signal.VBlank == signal.VBlank { + if sig[i].VBlank { col = color.RGBA{R: 0, G: 0, B: 0} } else { - px := signal.ColorSignal((sig[i] & signal.Color) >> signal.ColorShift) - col = drv.frameInfo.Spec.GetColor(px) + col = drv.frameInfo.Spec.GetColor(sig[i].Color) } // small cap improves performance, see https://golang.org/issue/27857 @@ -156,9 +155,7 @@ func (drv *driver) SetAudio(sig []signal.SignalAttributes) error { idx = 1 } for _, s := range sig { - v0 := uint8((s & signal.AudioChannel0) >> signal.AudioChannel0Shift) - v1 := uint8((s & signal.AudioChannel1) >> signal.AudioChannel1Shift) - drv.audio[idx] = append(drv.audio[idx], v0, v1) + drv.audio[idx] = append(drv.audio[idx], s.AudioChannel0, s.AudioChannel1) } return nil } diff --git a/coprocessor/developer/profiling.go b/coprocessor/developer/profiling.go index 5a750fc30..680bf5b55 100644 --- a/coprocessor/developer/profiling.go +++ b/coprocessor/developer/profiling.go @@ -20,7 +20,6 @@ import ( "github.com/jetsetilly/gopher2600/coprocessor" "github.com/jetsetilly/gopher2600/coprocessor/developer/profiling" - "github.com/jetsetilly/gopher2600/hardware/television/signal" ) // Profiling implements the coprocessor.CartCoProcDeveloper interface. @@ -186,13 +185,13 @@ func (dev *Developer) ProcessProfiling() { if frameInfo.Stable { if coords.Scanline == frameInfo.VisibleTop { - if dev.tv.GetLastSignal()&signal.VBlank == signal.VBlank { + if dev.tv.GetLastSignal().VBlank { accumulate(profiling.FocusVBLANK) } else { accumulate(profiling.FocusScreen) } } else if coords.Scanline == frameInfo.VisibleBottom { - if dev.tv.GetLastSignal()&signal.VBlank == signal.VBlank { + if dev.tv.GetLastSignal().VBlank { accumulate(profiling.FocusOverscan) } else { accumulate(profiling.FocusScreen) diff --git a/digest/audio.go b/digest/audio.go index 932238433..36edd3101 100644 --- a/digest/audio.go +++ b/digest/audio.go @@ -76,16 +76,15 @@ func (dig *Audio) ResetDigest() { func (dig *Audio) SetAudio(sig []signal.SignalAttributes) error { for _, s := range sig { // ignore invalid signals - if s == signal.NoSignal { + if s.Index == signal.NoSignal { continue } // ignore signals with no audio update - if s&signal.AudioUpdate != signal.AudioUpdate { + if !s.AudioUpdate { continue } - - dig.buffer[dig.bufferCt] = uint8((s & signal.AudioChannel0) >> signal.AudioChannel0Shift) + dig.buffer[dig.bufferCt] = s.AudioChannel0 dig.bufferCt++ if dig.bufferCt >= audioBufferLength { diff --git a/digest/video.go b/digest/video.go index d8278a023..f3b9fc424 100644 --- a/digest/video.go +++ b/digest/video.go @@ -109,13 +109,12 @@ func (dig *Video) SetPixels(sig []signal.SignalAttributes, _ int) error { for _, s := range sig { // ignore invalid signals - if s == signal.NoSignal { + if s.Index == signal.NoSignal { continue } // ignore VBLANK and extract the color signal in all situations - px := signal.ColorSignal((s & signal.Color) >> signal.ColorShift) - col := dig.spec.GetColor(px) + col := dig.spec.GetColor(s.Color) // setting every pixel regardless of vblank value p := dig.pixels[offset : offset+3 : offset+3] diff --git a/gui/sdlaudio/audio.go b/gui/sdlaudio/audio.go index c34dcd846..a540d35fe 100644 --- a/gui/sdlaudio/audio.go +++ b/gui/sdlaudio/audio.go @@ -123,12 +123,12 @@ func (aud *Audio) MoreAudio() bool { // SetAudio implements the protocol.AudioMixer interface. func (aud *Audio) SetAudio(sig []signal.SignalAttributes) error { for _, s := range sig { - if s&signal.AudioUpdate != signal.AudioUpdate { + if !s.AudioUpdate { continue } - v0 := uint8((s & signal.AudioChannel0) >> signal.AudioChannel0Shift) - v1 := uint8((s & signal.AudioChannel1) >> signal.AudioChannel1Shift) + v0 := s.AudioChannel0 + v1 := s.AudioChannel1 aud.stereoCh0Buffer = aud.stereoCh0Buffer[1:] aud.stereoCh0Buffer = append(aud.stereoCh0Buffer, v0) diff --git a/gui/sdlimgui/screen.go b/gui/sdlimgui/screen.go index f743473c1..4c7e6e021 100644 --- a/gui/sdlimgui/screen.go +++ b/gui/sdlimgui/screen.go @@ -489,11 +489,10 @@ func (scr *screen) SetPixels(sig []signal.SignalAttributes, last int) error { } // handle VBLANK by setting pixels to black - if sig[i]&signal.VBlank == signal.VBlank { + if sig[i].VBlank { col = color.RGBA{R: 0, G: 0, B: 0} } else { - px := signal.ColorSignal((sig[i] & signal.Color) >> signal.ColorShift) - col = scr.crit.frameInfo.Spec.GetColor(px) + col = scr.crit.frameInfo.Spec.GetColor(sig[i].Color) } // small cap improves performance, see https://golang.org/issue/27857 @@ -571,10 +570,10 @@ func (scr *screen) plotOverlay() { func (scr *screen) reflectionColor(ref *reflection.ReflectedVideoStep) color.RGBA { switch scr.crit.overlay { case reflection.OverlayLabels[reflection.OverlayVBLANK_VSYNC]: - if ref.Signal&signal.VBlank == signal.VBlank { + if ref.Signal.VBlank { return reflectionColors[reflection.VBLANK] } - if ref.Signal&signal.VSync == signal.VSync { + if ref.Signal.VSync { return reflectionColors[reflection.VSYNC] } case reflection.OverlayLabels[reflection.OverlayWSYNC]: diff --git a/gui/sdlimgui/win_dbgscr.go b/gui/sdlimgui/win_dbgscr.go index 31028b361..ce0a6fd51 100644 --- a/gui/sdlimgui/win_dbgscr.go +++ b/gui/sdlimgui/win_dbgscr.go @@ -635,8 +635,8 @@ func (win *winDbgScr) drawReflectionTooltip() { // pixel swatch. using black swatch if pixel is HBLANKed or VBLANKed _, _, pal, _ := win.img.imguiTVPalette() - px := signal.ColorSignal((ref.Signal & signal.Color) >> signal.ColorShift) - if (ref.IsHblank || ref.Signal&signal.VBlank == signal.VBlank || px == signal.VideoBlack) && !win.elements { + px := ref.Signal.Color + if (ref.IsHblank || ref.Signal.VBlank || px == signal.VideoBlack) && !win.elements { imguiColorLabelSimple("No color signal", pal[0]) } else { // not using GetColor() function. arguably we should but we've diff --git a/gui/sdlimgui/win_dbgscr_paint.go b/gui/sdlimgui/win_dbgscr_paint.go index 0819b4bf1..022436054 100644 --- a/gui/sdlimgui/win_dbgscr_paint.go +++ b/gui/sdlimgui/win_dbgscr_paint.go @@ -38,7 +38,7 @@ func (win *winDbgScr) paintDragAndDrop() { ff := floodFill{ win: win, - from: uint8((ref.Signal&signal.Color)>>signal.ColorShift) & 0xfe, + from: uint8(ref.Signal.Color) & 0xfe, to: payload[0] & 0xfe, } @@ -79,18 +79,17 @@ type floodFill struct { func (ff *floodFill) build(target floodFillTarget) { ref := ff.startingReflection[target.offset] - if ref.Signal&signal.VBlank == signal.VBlank { + if ref.Signal.VBlank { return } - px := uint8((ref.Signal&signal.Color)>>signal.ColorShift) & 0xfe + px := uint8(ref.Signal.Color) & 0xfe if px != ff.from { return } ff.targets = append(ff.targets, target) - ref.Signal &= ^signal.Color - ref.Signal |= signal.SignalAttributes(ff.to) << signal.ColorShift + ref.Signal.Color = signal.ColorSignal(ff.to) ff.startingReflection[target.offset] = ref // down @@ -134,7 +133,7 @@ func (ff *floodFill) resolve(offsetIdx int) { ff.win.img.dbg.PushFunctionImmediate(func() { target := ff.targets[offsetIdx] ref := ff.win.scr.crit.reflection[target.offset] - px := uint8((ref.Signal&signal.Color)>>signal.ColorShift) & 0xfe + px := uint8(ref.Signal.Color) & 0xfe if px != ff.from { ff.resolve(offsetIdx + 1) return diff --git a/gui/sdlimgui/win_oscilloscope.go b/gui/sdlimgui/win_oscilloscope.go index 33fdc4960..53cc23077 100644 --- a/gui/sdlimgui/win_oscilloscope.go +++ b/gui/sdlimgui/win_oscilloscope.go @@ -145,12 +145,12 @@ func (win *winOscilloscope) drawTVLabel(label string) { // SetAudio implements protocol.AudioMixer. func (win *winOscilloscope) SetAudio(sig []signal.SignalAttributes) error { for _, s := range sig { - if s&signal.AudioUpdate != signal.AudioUpdate { + if !s.AudioUpdate { continue } - v0 := uint8((s & signal.AudioChannel0) >> signal.AudioChannel0Shift) - v1 := uint8((s & signal.AudioChannel1) >> signal.AudioChannel1Shift) + v0 := s.AudioChannel0 + v1 := s.AudioChannel1 m := mix.Mono(v0, v1) s0, s1 := mix.Stereo(v0, v1) diff --git a/hardware/television/resizer.go b/hardware/television/resizer.go index 055df7a3c..cda269c5d 100644 --- a/hardware/television/resizer.go +++ b/hardware/television/resizer.go @@ -156,10 +156,10 @@ func (rz *Resizer) examine(state *State, sig signal.SignalAttributes) { // some ROMs never set VBLANK but we still want to do our best and frame the // screen nicely. this flag controls whether we use vblank top/bottom values // or "black" top/bottom values - rz.usingVBLANK = rz.usingVBLANK || sig&signal.VBlank == signal.VBlank + rz.usingVBLANK = rz.usingVBLANK || sig.VBlank // if VBLANK is off then update the top/bottom values note - if sig&signal.VBlank != signal.VBlank { + if !sig.VBlank { if state.frameInfo.Stable { if state.scanline < rz.vblankTop && state.scanline >= state.frameInfo.Spec.ExtendedVisibleTop { @@ -197,9 +197,8 @@ func (rz *Resizer) examine(state *State, sig signal.SignalAttributes) { // some ROMs never set VBLANK. for these cases we also record the extent of // non-black pixels. these values are using in the commit() function in the // event that usingVBLANK is false. - if state.clock > specification.ClksHBlank && sig&signal.VBlank != signal.VBlank { - px := signal.ColorSignal((sig & signal.Color) >> signal.ColorShift) - col := state.frameInfo.Spec.GetColor(px) + if state.clock > specification.ClksHBlank && !sig.VBlank { + col := state.frameInfo.Spec.GetColor(sig.Color) if col.R != 0x00 || col.G != 0x00 || col.B != 0x00 { if state.frameInfo.Stable { if state.scanline < rz.blackTop && diff --git a/hardware/television/signal/signal.go b/hardware/television/signal/signal.go index d87cc2dcf..c9cfeb047 100644 --- a/hardware/television/signal/signal.go +++ b/hardware/television/signal/signal.go @@ -27,51 +27,34 @@ type ColorSignal uint8 // VideoBlack is the ColorSignal value that indicates no pixel is being output. const VideoBlack ColorSignal = 0xff -// SignalAttributes represents the data sent to the television. -type SignalAttributes uint64 - -// List of bit masks to be used to with the SignalAttribute type. -const ( - VSync SignalAttributes = 0b0000000000000000000000000000000000000000000001 - VBlank SignalAttributes = 0b0000000000000000000000000000000000000000000010 - CBurst SignalAttributes = 0b0000000000000000000000000000000000000000000100 - HSync SignalAttributes = 0b0000000000000000000000000000000000000000001000 - AudioUpdate SignalAttributes = 0b0000000000000000000000000000000000000000010000 - AudioChannel0 SignalAttributes = 0b0000000000000000000000000000000001111111100000 // 8 bits - AudioChannel1 SignalAttributes = 0b0000000000000000000000000111111110000000000000 // 8 bits - Color SignalAttributes = 0b0000000000000000011111111000000000000000000000 // 8 bits - - // Index is additional information relating to the position of the signal - // in relation to the top left of the screen. It can mostly be ignored but - // it is useful for synchronisation between the television and reflection - // packages. - Index SignalAttributes = 0b1111111111111111100000000000000000000000000000 // 17 bits -) +// Index value to indicate that the signal is invalid +const NoSignal = -1 -// List of shift amounts to be used to access the corresponding bits in a -// SignalAttributes value. -const ( - AudioChannel0Shift = 5 - AudioChannel1Shift = 13 - ColorShift = 21 - IndexShift = 29 -) - -// NoSignal is the null value of the SignalAttributes type. -const NoSignal = Index +// SignalAttributes represents the data sent to the television. +type SignalAttributes struct { + Index int + VSync bool + VBlank bool + CBurst bool + HSync bool + AudioUpdate bool + AudioChannel0 uint8 + AudioChannel1 uint8 + Color ColorSignal +} func (a SignalAttributes) String() string { s := strings.Builder{} - if a&VSync == VSync { + if a.VSync { s.WriteString("VSYNC ") } - if a&VBlank == VBlank { + if a.VBlank { s.WriteString("VBLANK ") } - if a&CBurst == CBurst { + if a.CBurst { s.WriteString("CBURST ") } - if a&HSync == HSync { + if a.HSync { s.WriteString("HSYNC ") } return s.String() diff --git a/hardware/television/simple.go b/hardware/television/simple.go index d3416a51a..d26ed6ac0 100644 --- a/hardware/television/simple.go +++ b/hardware/television/simple.go @@ -99,8 +99,8 @@ func (tv *Television) signalSimple(sig signal.SignalAttributes) { } // check for change of VSYNC signal - if sig&signal.VSync != tv.state.lastSignal&signal.VSync { - if sig&signal.VSync == signal.VSync { + if sig.VSync != tv.state.lastSignal.VSync { + if sig.VSync { // VSYNC has started tv.simple.vsyncActive = true tv.simple.vsyncScanlines = 0 @@ -134,7 +134,7 @@ func (tv *Television) signalSimple(sig signal.SignalAttributes) { // is to enable the RSYNC smooth scrolling trick to be displayed correctly. // // https://atariage.com/forums/topic/224946-smooth-scrolling-playfield-i-think-ive-done-it - if sig&signal.HSync == signal.HSync && tv.state.lastSignal&signal.HSync != signal.HSync { + if sig.HSync && !tv.state.lastSignal.HSync { if tv.state.clock < 13 || tv.state.clock > 22 { tv.state.clock = 16 } @@ -157,8 +157,7 @@ func (tv *Television) signalSimple(sig signal.SignalAttributes) { } // augment television signal before storing and sending to pixel renderers - sig &= ^signal.Index - sig |= signal.SignalAttributes(tv.currentSignalIdx << signal.IndexShift) + sig.Index = tv.currentSignalIdx // write the signal into the correct index of the signals array. tv.signals[tv.currentSignalIdx] = sig @@ -239,7 +238,7 @@ func (tv *Television) newFrameSimple(fromVsync bool) error { // nullify unused signals at end of frame for i := tv.currentSignalIdx; i < len(tv.signals); i++ { - tv.signals[i] = signal.NoSignal + tv.signals[i].Index = signal.NoSignal } // set pending pixels diff --git a/hardware/television/television.go b/hardware/television/television.go index 9ed357a74..6a7684813 100644 --- a/hardware/television/television.go +++ b/hardware/television/television.go @@ -288,10 +288,14 @@ func (tv *Television) Reset(keepFrameNum bool) error { tv.state.stableFrames = 0 tv.state.vsync.reset() tv.state.fromVSYNC = false - tv.state.lastSignal = signal.NoSignal + tv.state.lastSignal = signal.SignalAttributes{ + Index: signal.NoSignal, + } for i := range tv.signals { - tv.signals[i] = signal.NoSignal + tv.signals[i] = signal.SignalAttributes{ + Index: signal.NoSignal, + } } tv.currentSignalIdx = 0 tv.firstSignalIdx = 0 @@ -484,8 +488,8 @@ func (tv *Television) Signal(sig signal.SignalAttributes) { func (tv *Television) signalFull(sig signal.SignalAttributes) { // check for change of VSYNC signal - if sig&signal.VSync != tv.state.lastSignal&signal.VSync { - if sig&signal.VSync == signal.VSync { + if sig.VSync != tv.state.lastSignal.VSync { + if sig.VSync { // VSYNC has started tv.state.vsync.active = true tv.state.vsync.activeScanlineCount = 0 @@ -652,7 +656,7 @@ func (tv *Television) signalFull(sig signal.SignalAttributes) { // is to enable the RSYNC smooth scrolling trick to be displayed correctly. // // https://atariage.com/forums/topic/224946-smooth-scrolling-playfield-i-think-ive-done-it - if sig&signal.HSync == signal.HSync && tv.state.lastSignal&signal.HSync != signal.HSync { + if sig.HSync && !tv.state.lastSignal.HSync { if tv.state.clock < 13 || tv.state.clock > 22 { tv.state.clock = 16 } @@ -675,8 +679,7 @@ func (tv *Television) signalFull(sig signal.SignalAttributes) { } // augment television signal before storing and sending to pixel renderers - sig &= ^signal.Index - sig |= signal.SignalAttributes(tv.currentSignalIdx << signal.IndexShift) + sig.Index = tv.currentSignalIdx // write the signal into the correct index of the signals array. tv.signals[tv.currentSignalIdx] = sig @@ -842,7 +845,7 @@ func (tv *Television) newFrame() error { // nullify unused signals at end of frame for i := tv.currentSignalIdx; i < len(tv.signals); i++ { - tv.signals[i] = signal.NoSignal + tv.signals[i].Index = signal.NoSignal } // set pending pixels diff --git a/hardware/television/vblank.go b/hardware/television/vblank.go index 998ede115..8b72518c8 100644 --- a/hardware/television/vblank.go +++ b/hardware/television/vblank.go @@ -42,26 +42,24 @@ func (b *vblankBounds) reset() { } func (b *vblankBounds) examine(sig signal.SignalAttributes, scanline int) { - vblank := sig&signal.VBlank == signal.VBlank - switch b.phase { case phaseTop: - if b.vblank && !vblank { + if b.vblank && !sig.VBlank { b.top = scanline b.phase = phaseMiddle } case phaseMiddle: - if !b.vblank && vblank { + if !b.vblank && sig.VBlank { b.bottom = scanline b.phase = phaseBottom } case phaseBottom: - if b.vblank && !vblank { + if b.vblank && !sig.VBlank { b.phase = phaseMiddle } } - b.vblank = vblank + b.vblank = sig.VBlank } func (b *vblankBounds) commit(state *State) bool { diff --git a/hardware/tia/tia.go b/hardware/tia/tia.go index 0a9cae286..e211af9bb 100644 --- a/hardware/tia/tia.go +++ b/hardware/tia/tia.go @@ -181,10 +181,7 @@ func (tia *TIA) Plumb(env *environment.Environment, tv TV, mem chipbus.Memory, r func (tia *TIA) Update(data chipbus.ChangedRegister) bool { switch data.Register { case cpubus.VSYNC: - tia.sig &= ^signal.VSync - if data.Value&0x02 == 0x02 { - tia.sig |= signal.VSync - } + tia.sig.VSync = data.Value&0x02 == 0x02 return false case cpubus.VBLANK: @@ -316,10 +313,7 @@ func (tia *TIA) resolveDelayedEvents() { // actual vblank signal tia.futureVblank.Tick(func(v uint8) { tia.pendingEvents-- - tia.sig &= ^signal.VBlank - if v&0x02 == 0x02 { - tia.sig |= signal.VBlank - } + tia.sig.VBlank = v&0x02 == 0x02 }) tia.futureRsyncAlign.Tick(func(v uint8) { @@ -358,11 +352,10 @@ func (tia *TIA) resolveDelayedEvents() { case hsyncEventSHB: tia.newScanline() case hsyncEventRHS: - tia.sig &= ^signal.HSync - tia.sig &= ^signal.CBurst - tia.sig |= signal.CBurst + tia.sig.HSync = false + tia.sig.CBurst = true case hsyncEventRCB: - tia.sig &= ^signal.CBurst + tia.sig.CBurst = false case hsyncEventRHB: tia.Hblank = false case hsyncEventLRHB: @@ -464,8 +457,7 @@ func (tia *TIA) Step(reg chipbus.ChangedRegister, ct int) { // this. not clear if this is the case. // // !!TODO: check accuracy of HSync timing - tia.sig &= ^signal.HSync - tia.sig |= signal.HSync + tia.sig.HSync = true case 8: // [RHS] // reset HSYNC @@ -576,11 +568,9 @@ func (tia *TIA) Step(reg chipbus.ChangedRegister, ct int) { // historic reasons (to do with how we handle debug colours) we leave // it up to PixelRenderer implementations to switch to VideoBlack on // VBLANK. - tia.sig &= ^signal.Color - tia.sig |= signal.SignalAttributes(signal.VideoBlack) << signal.ColorShift + tia.sig.Color = signal.VideoBlack } else { - tia.sig &= ^signal.Color - tia.sig |= signal.SignalAttributes(tia.Video.PixelColor) << signal.ColorShift + tia.sig.Color = signal.ColorSignal(tia.Video.PixelColor) } // late memory resolution @@ -602,14 +592,11 @@ func (tia *TIA) Step(reg chipbus.ChangedRegister, ct int) { // mix audio and copy values to television signal if ct == 3 && tia.Audio.Step() { - tia.sig &= ^signal.AudioUpdate - tia.sig |= signal.AudioUpdate - tia.sig &= ^signal.AudioChannel0 - tia.sig |= signal.SignalAttributes(tia.Audio.Vol0) << signal.AudioChannel0Shift - tia.sig &= ^signal.AudioChannel1 - tia.sig |= signal.SignalAttributes(tia.Audio.Vol1) << signal.AudioChannel1Shift + tia.sig.AudioUpdate = true + tia.sig.AudioChannel0 = tia.Audio.Vol0 + tia.sig.AudioChannel1 = tia.Audio.Vol1 } else { - tia.sig &= ^signal.AudioUpdate + tia.sig.AudioUpdate = false } // send signal to television @@ -697,8 +684,7 @@ func (tia *TIA) QuickStep(ct int) { // this. not clear if this is the case. // // !!TODO: check accuracy of HSync timing - tia.sig &= ^signal.HSync - tia.sig |= signal.HSync + tia.sig.HSync = true case 8: // [RHS] // reset HSYNC @@ -769,23 +755,18 @@ func (tia *TIA) QuickStep(ct int) { // historic reasons (to do with how we handle debug colours) we leave // it up to PixelRenderer implementations to switch to VideoBlack on // VBLANK. - tia.sig &= ^signal.Color - tia.sig |= signal.SignalAttributes(signal.VideoBlack) << signal.ColorShift + tia.sig.Color = signal.VideoBlack } else { - tia.sig &= ^signal.Color - tia.sig |= signal.SignalAttributes(tia.Video.PixelColor) << signal.ColorShift + tia.sig.Color = signal.ColorSignal(tia.Video.PixelColor) } // mix audio and copy values to television signal if ct == 3 && tia.Audio.Step() { - tia.sig &= ^signal.AudioUpdate - tia.sig |= signal.AudioUpdate - tia.sig &= ^signal.AudioChannel0 - tia.sig |= signal.SignalAttributes(tia.Audio.Vol0) << signal.AudioChannel0Shift - tia.sig &= ^signal.AudioChannel1 - tia.sig |= signal.SignalAttributes(tia.Audio.Vol1) << signal.AudioChannel1Shift + tia.sig.AudioUpdate = true + tia.sig.AudioChannel0 = tia.Audio.Vol0 + tia.sig.AudioChannel1 = tia.Audio.Vol1 } else { - tia.sig &= ^signal.AudioUpdate + tia.sig.AudioUpdate = false } // send signal to television diff --git a/reflection/reflector.go b/reflection/reflector.go index a18fabbd3..ae17ce151 100644 --- a/reflection/reflector.go +++ b/reflection/reflector.go @@ -88,12 +88,11 @@ func (ref *Reflector) Step(bank mapper.BankInfo) error { // at the time of writng, this can sometimes happen if the VCS has been // reset but the emulator loop has not been unwound. The newly reset TV // will return an invalid signal leading to an index that is too large - if sig == signal.NoSignal { + if sig.Index == signal.NoSignal { return nil } - idx := int((sig & signal.Index) >> signal.IndexShift) - h := ref.history[idx : idx+1] + h := ref.history[sig.Index : sig.Index+1] h[0].CPU = ref.vcs.CPU.LastResult h[0].WSYNC = !ref.vcs.CPU.RdyFlg @@ -114,10 +113,10 @@ func (ref *Reflector) Step(bank mapper.BankInfo) error { // nullify entries at the head of the array that do not have a // corresponding signal. we do this because the first index of a signal // after a NewFrame might be different that the previous frame - for i := ref.lastIdx; i < idx-1; i++ { + for i := ref.lastIdx; i < sig.Index-1; i++ { ref.history[i] = ReflectedVideoStep{} } - ref.lastIdx = idx + ref.lastIdx = sig.Index return nil } diff --git a/thumbnailer/anim.go b/thumbnailer/anim.go index daa739a7b..b58c21655 100644 --- a/thumbnailer/anim.go +++ b/thumbnailer/anim.go @@ -328,15 +328,12 @@ func (thmb *Anim) SetPixels(sig []signal.SignalAttributes, last int) error { var offset int for i := range sig { - // note vblank signal for later - vblank := sig[i]&signal.VBlank == signal.VBlank // handle VBLANK by setting pixels to black - if vblank { + if sig[i].VBlank { col = color.RGBA{R: 0, G: 0, B: 0} } else { - px := signal.ColorSignal((sig[i] & signal.Color) >> signal.ColorShift) - col = thmb.frameInfo.Spec.GetColor(px) + col = thmb.frameInfo.Spec.GetColor(sig[i].Color) } // small cap improves performance, see https://golang.org/issue/27857 @@ -344,7 +341,7 @@ func (thmb *Anim) SetPixels(sig []signal.SignalAttributes, last int) error { offset += 4 // monitor pixels - if thmb.monitorActive && !vblank && i%specification.ClksScanline > specification.ClksHBlank { + if thmb.monitorActive && !sig[i].VBlank && i%specification.ClksScanline > specification.ClksHBlank { monitorPixels++ if s[0] != col.R || s[1] != col.G || s[2] != col.B { monitorChanges = true diff --git a/thumbnailer/image.go b/thumbnailer/image.go index 89d69fff9..4871f8e18 100644 --- a/thumbnailer/image.go +++ b/thumbnailer/image.go @@ -211,11 +211,10 @@ func (thmb *Image) SetPixels(sig []signal.SignalAttributes, last int) error { for i := range sig { // handle VBLANK by setting pixels to black - if sig[i]&signal.VBlank == signal.VBlank { + if sig[i].VBlank { col = color.RGBA{R: 0, G: 0, B: 0} } else { - px := signal.ColorSignal((sig[i] & signal.Color) >> signal.ColorShift) - col = thmb.frameInfo.Spec.GetColor(px) + col = thmb.frameInfo.Spec.GetColor(sig[i].Color) } // small cap improves performance, see https://golang.org/issue/27857 diff --git a/wavwriter/wav.go b/wavwriter/wav.go index 351f30098..8071ecd05 100644 --- a/wavwriter/wav.go +++ b/wavwriter/wav.go @@ -46,12 +46,12 @@ func NewWavWriter(filename string) (*WavWriter, error) { // SetAudio implements the television.AudioMixer interface. func (aw *WavWriter) SetAudio(sig []signal.SignalAttributes) error { for _, s := range sig { - if s&signal.AudioUpdate != signal.AudioUpdate { + if s.AudioUpdate { continue } - v0 := uint8((s & signal.AudioChannel0) >> signal.AudioChannel0Shift) - v1 := uint8((s & signal.AudioChannel1) >> signal.AudioChannel1Shift) + v0 := s.AudioChannel0 + v1 := s.AudioChannel1 m := mix.Mono(v0, v1) aw.buffer = append(aw.buffer, m)