mirror of
https://github.com/JetSetIlly/Gopher2600.git
synced 2025-04-02 11:02:17 -04:00
pressing CTRL+SHIFT allows the user to bring a window to the front by typing in the window title. as soon as the entered string is unique the window is selected a search preview is shown in the menu bar while the CTRL+SHIFT combination is held down
320 lines
9 KiB
Go
320 lines
9 KiB
Go
// This file is part of Gopher2600.
|
|
//
|
|
// Gopher2600 is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Gopher2600 is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Gopher2600. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
package sdlimgui
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/inkyblackness/imgui-go/v4"
|
|
"github.com/jetsetilly/gopher2600/hardware/memory/memorymap"
|
|
"github.com/jetsetilly/gopher2600/hardware/tia/phaseclock"
|
|
)
|
|
|
|
const win6507PinoutID = "6507 Pinout"
|
|
|
|
type win6507Pinout struct {
|
|
debuggerWin
|
|
|
|
img *SdlImgui
|
|
|
|
busInfoHeight float32
|
|
|
|
// Vec4 colors for address and data bus. used as the basis for the
|
|
// packed colors and for styling text
|
|
addressBus imgui.Vec4
|
|
addressBusOff imgui.Vec4
|
|
dataBus imgui.Vec4
|
|
dataBusOff imgui.Vec4
|
|
|
|
// packed colours are used for the drawlist primitives used to create the
|
|
// pinout image
|
|
body imgui.PackedColor
|
|
bodyOutline imgui.PackedColor
|
|
pinOn imgui.PackedColor
|
|
pinOff imgui.PackedColor
|
|
addressPinOn imgui.PackedColor
|
|
addressPinOff imgui.PackedColor
|
|
dataPinOn imgui.PackedColor
|
|
dataPinOff imgui.PackedColor
|
|
rdyPinOn imgui.PackedColor
|
|
rdyPinOff imgui.PackedColor
|
|
}
|
|
|
|
func newWin6507Pinout(img *SdlImgui) (window, error) {
|
|
win := &win6507Pinout{
|
|
img: img,
|
|
}
|
|
|
|
win.addressBus = imgui.Vec4{0.3, 0.8, 0.8, 1.0}
|
|
win.addressBusOff = imgui.Vec4{0.3, 0.8, 0.8, 0.5}
|
|
win.dataBus = imgui.Vec4{0.8, 0.8, 0.3, 1.0}
|
|
win.dataBusOff = imgui.Vec4{0.8, 0.8, 0.3, 0.5}
|
|
|
|
win.body = imgui.PackedColorFromVec4(imgui.Vec4{0.1, 0.1, 0.1, 1.0})
|
|
win.bodyOutline = imgui.PackedColorFromVec4(imgui.Vec4{1.0, 1.0, 1.0, 0.8})
|
|
win.pinOn = imgui.PackedColorFromVec4(imgui.Vec4{0.8, 0.8, 0.8, 1.0})
|
|
win.pinOff = imgui.PackedColorFromVec4(imgui.Vec4{0.8, 0.8, 0.8, 0.5})
|
|
win.addressPinOn = imgui.PackedColorFromVec4(win.addressBus)
|
|
win.addressPinOff = imgui.PackedColorFromVec4(win.addressBusOff)
|
|
win.dataPinOn = imgui.PackedColorFromVec4(win.dataBus)
|
|
win.dataPinOff = imgui.PackedColorFromVec4(win.dataBusOff)
|
|
win.rdyPinOn = imgui.PackedColorFromVec4(win.img.cols.True)
|
|
win.rdyPinOff = imgui.PackedColorFromVec4(win.img.cols.False)
|
|
|
|
return win, nil
|
|
}
|
|
|
|
func (win *win6507Pinout) init() {
|
|
}
|
|
|
|
func (win *win6507Pinout) id() string {
|
|
return win6507PinoutID
|
|
}
|
|
|
|
func (win *win6507Pinout) debuggerDraw() bool {
|
|
if !win.debuggerOpen {
|
|
return false
|
|
}
|
|
|
|
imgui.SetNextWindowPosV(imgui.Vec2{756, 117}, imgui.ConditionFirstUseEver, imgui.Vec2{0, 0})
|
|
imgui.SetNextWindowSizeV(imgui.Vec2{326, 338}, imgui.ConditionFirstUseEver)
|
|
imgui.SetNextWindowSizeConstraints(imgui.Vec2{326, 338}, imgui.Vec2{529, 593})
|
|
|
|
if imgui.BeginV(win.debuggerID(win.id()), &win.debuggerOpen, imgui.WindowFlagsNone) {
|
|
win.draw()
|
|
}
|
|
|
|
win.debuggerGeom.update()
|
|
imgui.End()
|
|
|
|
return true
|
|
}
|
|
|
|
func (win *win6507Pinout) draw() {
|
|
avail := imgui.ContentRegionAvail()
|
|
avail.Y -= win.busInfoHeight
|
|
p := imgui.CursorScreenPos()
|
|
|
|
// size and positioning
|
|
chipDim := imgui.Vec2{X: avail.X * 0.5, Y: avail.Y * 0.9}
|
|
chipPos := imgui.Vec2{X: p.X + avail.X*0.5 - chipDim.X*0.5, Y: p.Y + avail.Y*0.5 - chipDim.Y*0.5}
|
|
|
|
if imgui.BeginChildV("pinout", avail, false, imgui.WindowFlagsNone) {
|
|
dl := imgui.WindowDrawList()
|
|
imgui.PushFont(win.img.glsl.fonts.diagram)
|
|
|
|
const lineThick = 2.0
|
|
|
|
// main body
|
|
dl.AddRectFilledV(chipPos, imgui.Vec2{chipPos.X + chipDim.X, chipPos.Y + chipDim.Y},
|
|
win.body, 0, imgui.DrawCornerFlagsAll)
|
|
|
|
// pins
|
|
pinSpacing := chipDim.Y / 14
|
|
pinSize := pinSpacing / 2
|
|
pinTextAdj := (pinSize - imgui.TextLineHeight()) / 2
|
|
|
|
// address/data values (for convenience)
|
|
addressBus := win.img.lz.Bus.AddressBus
|
|
dataBus := win.img.lz.Bus.DataBus
|
|
|
|
// left pins
|
|
pinX := chipPos.X - pinSize
|
|
for i := 0; i < 14; i++ {
|
|
col := win.pinOff
|
|
label := ""
|
|
switch i {
|
|
case 0:
|
|
// RES
|
|
if !win.img.lz.CPU.HasReset {
|
|
col = win.pinOn
|
|
}
|
|
label = "RES"
|
|
case 1:
|
|
// Vss
|
|
col = win.pinOn
|
|
label = "Vss"
|
|
case 2:
|
|
// RDY
|
|
if win.img.lz.CPU.RdyFlg {
|
|
col = win.rdyPinOn
|
|
} else {
|
|
col = win.rdyPinOff
|
|
}
|
|
label = "RDY"
|
|
case 3:
|
|
// Vcc
|
|
col = win.pinOn
|
|
label = "Vcc"
|
|
default:
|
|
// address pins
|
|
m := uint16(0x01 << (i - 4))
|
|
if addressBus&m == m {
|
|
col = win.addressPinOn
|
|
} else {
|
|
col = win.addressPinOff
|
|
}
|
|
label = fmt.Sprintf("A%d", i-4)
|
|
}
|
|
|
|
pinY := chipPos.Y + pinSize*0.5 + (float32(i) * pinSpacing)
|
|
pinPos := imgui.Vec2{pinX, pinY}
|
|
dl.AddRectFilledV(pinPos, imgui.Vec2{pinPos.X + pinSize, pinPos.Y + pinSize},
|
|
col, 0, imgui.DrawCornerFlagsNone)
|
|
|
|
textPos := imgui.Vec2{X: chipPos.X + lineThick + chipDim.X*0.025, Y: pinPos.Y + pinTextAdj}
|
|
dl.AddText(textPos, col, label)
|
|
}
|
|
|
|
pinX = chipPos.X + chipDim.X
|
|
for i := 0; i < 14; i++ {
|
|
col := win.pinOff
|
|
label := ""
|
|
switch i {
|
|
case 0:
|
|
switch win.img.lz.Phaseclock.LastPClk {
|
|
case phaseclock.RisingPhi2:
|
|
col = win.pinOn
|
|
case phaseclock.FallingPhi2:
|
|
col = win.pinOn
|
|
}
|
|
label = "φ2"
|
|
case 1:
|
|
switch win.img.lz.Phaseclock.LastPClk {
|
|
case phaseclock.RisingPhi1:
|
|
col = win.pinOn
|
|
case phaseclock.FallingPhi1:
|
|
col = win.pinOn
|
|
}
|
|
label = "φ1"
|
|
case 2:
|
|
// R/W
|
|
if win.img.lz.Bus.LastCPUWrite {
|
|
col = win.pinOn
|
|
}
|
|
label = "R/W"
|
|
default:
|
|
if i > 10 {
|
|
// address pins
|
|
m := uint16(0x01 << (23 - i))
|
|
if addressBus&m == m {
|
|
col = win.addressPinOn
|
|
} else {
|
|
col = win.addressPinOff
|
|
}
|
|
label = fmt.Sprintf("A%d", (23 - i))
|
|
} else {
|
|
// data pins
|
|
m := uint16(0x01 << (i - 3))
|
|
if uint16(dataBus)&m == m {
|
|
col = win.dataPinOn
|
|
} else {
|
|
col = win.dataPinOff
|
|
}
|
|
label = fmt.Sprintf("D%d", i-3)
|
|
}
|
|
}
|
|
|
|
pinY := chipPos.Y + pinSize*0.5 + (float32(i) * pinSpacing)
|
|
pinPos := imgui.Vec2{pinX, pinY}
|
|
dl.AddRectFilledV(pinPos, imgui.Vec2{pinPos.X + pinSize, pinPos.Y + pinSize},
|
|
col, 0, imgui.DrawCornerFlagsNone)
|
|
|
|
textPos := imgui.Vec2{X: chipPos.X + chipDim.X + lineThick*2 - imguiGetFrameDim(label).X, Y: pinPos.Y + pinTextAdj}
|
|
dl.AddText(textPos, col, label)
|
|
}
|
|
|
|
// main chip body (outline)
|
|
dl.AddRectV(chipPos, imgui.Vec2{chipPos.X + chipDim.X, chipPos.Y + chipDim.Y},
|
|
win.bodyOutline, 0, imgui.DrawCornerFlagsAll, lineThick)
|
|
|
|
imgui.PopFont()
|
|
imgui.EndChild()
|
|
}
|
|
|
|
// bus information
|
|
win.busInfoHeight = imguiMeasureHeight(func() {
|
|
if imgui.CollapsingHeaderV("Bus", imgui.TreeNodeFlagsDefaultOpen) {
|
|
if imgui.BeginTableV("trackerHeader", 4, imgui.TableFlagsBordersInnerV|imgui.TableFlagsSizingFixedFit, imgui.Vec2{}, 0) {
|
|
// weight the column widths
|
|
width := imgui.ContentRegionAvail().X
|
|
imgui.TableSetupColumnV("", imgui.TableColumnFlagsNone, width*0.23, 0)
|
|
imgui.TableSetupColumnV("", imgui.TableColumnFlagsNone, width*0.30, 1)
|
|
imgui.TableSetupColumnV("", imgui.TableColumnFlagsNone, width*0.15, 2)
|
|
imgui.TableSetupColumnV("", imgui.TableColumnFlagsNone, width*0.32, 3)
|
|
|
|
imgui.TableNextRow()
|
|
imgui.TableNextColumn()
|
|
imguiColorLabelSimple("Address", win.addressBus)
|
|
|
|
imgui.TableNextColumn()
|
|
imgui.PushStyleColor(imgui.StyleColorText, win.addressBus)
|
|
imgui.Text(fmt.Sprintf("%013b", win.img.lz.Bus.AddressBus&0x1fff))
|
|
imgui.PopStyleColor()
|
|
|
|
imgui.TableNextColumn()
|
|
imgui.Text(fmt.Sprintf("%#04x", win.img.lz.Bus.AddressBus&0x1fff))
|
|
|
|
imgui.TableNextColumn()
|
|
_, area := memorymap.MapAddress(win.img.lz.Bus.AddressBus, !win.img.lz.Bus.LastCPUWrite)
|
|
imgui.Text(area.String())
|
|
|
|
imgui.TableNextRow()
|
|
imgui.TableNextColumn()
|
|
imguiColorLabelSimple("Data", win.dataBus)
|
|
|
|
imgui.TableNextColumn()
|
|
if win.img.lz.Bus.DataBusDriven != 0xff {
|
|
p := imgui.CursorScreenPos()
|
|
s1 := strings.Builder{}
|
|
s2 := strings.Builder{}
|
|
for i := 7; i >= 0; i-- {
|
|
if (win.img.lz.Bus.DataBusDriven>>i)&0x01 == 0x01 {
|
|
s1.WriteString(fmt.Sprintf("%d", (win.img.lz.Bus.DataBus>>i)&0x01))
|
|
s2.WriteRune(' ')
|
|
} else {
|
|
s1.WriteRune(' ')
|
|
s2.WriteString(fmt.Sprintf("%d", (win.img.lz.Bus.DataBus>>i)&0x01))
|
|
}
|
|
}
|
|
imgui.PushStyleColor(imgui.StyleColorText, win.dataBus)
|
|
imgui.Text(s1.String())
|
|
imgui.SetCursorScreenPos(p)
|
|
imgui.PushStyleColor(imgui.StyleColorText, win.dataBusOff)
|
|
imgui.Text(s2.String())
|
|
imgui.PopStyleColorV(2)
|
|
} else {
|
|
imgui.PushStyleColor(imgui.StyleColorText, win.dataBus)
|
|
imgui.Text(fmt.Sprintf("%08b", win.img.lz.Bus.DataBus))
|
|
imgui.PopStyleColor()
|
|
}
|
|
|
|
imgui.TableNextColumn()
|
|
imgui.Text(fmt.Sprintf("%#02x", win.img.lz.Bus.DataBus))
|
|
|
|
imgui.TableNextColumn()
|
|
if win.img.lz.Bus.LastCPUWrite {
|
|
imgui.Text("Writing")
|
|
} else {
|
|
imgui.Text("Reading")
|
|
}
|
|
|
|
imgui.EndTable()
|
|
}
|
|
}
|
|
})
|
|
}
|