izapple2/softSwitches2.go

200 lines
6.9 KiB
Go
Raw Normal View History

2020-10-03 21:38:26 +00:00
package izapple2
2019-02-24 14:05:50 +00:00
const (
ioDataKeyboard uint8 = 0x10
2019-04-26 16:08:30 +00:00
ioFlagText uint8 = 0x50
2019-02-24 14:05:50 +00:00
ioFlagMixed uint8 = 0x52
ioFlagSecondPage uint8 = 0x54
ioFlagHiRes uint8 = 0x56
ioFlagAnnunciator0 uint8 = 0x58
2019-02-24 14:05:50 +00:00
ioFlagAnnunciator1 uint8 = 0x5a
ioFlagAnnunciator2 uint8 = 0x5c
ioFlagAnnunciator3 uint8 = 0x5e
2021-08-05 19:12:52 +00:00
//ioDataCassette uint8 = 0x60
//ioFlagButton0 uint8 = 0x61
//ioFlagButton1 uint8 = 0x62
//ioFlagButton2 uint8 = 0x63
//ioDataPaddle0 uint8 = 0x64
//ioDataPaddle1 uint8 = 0x65
//ioDataPaddle2 uint8 = 0x66
//ioDataPaddle3 uint8 = 0x67
// Not real softSwitches. Using the numbers to store the flags somewhere.
ioFlagRGBCardActive uint8 = 0x7d
ioFlag1RGBCard uint8 = 0x7e
ioFlag2RGBCard uint8 = 0x7f
2019-02-24 14:05:50 +00:00
)
func addApple2SoftSwitches(io *ioC0Page) {
2022-08-05 17:43:17 +00:00
io.addSoftSwitchRW(0x00, buildKeySoftSwitch(io), "KEYBOARD") // Keyboard
io.addSoftSwitchRW(0x10, buildStrobeKeyboardSoftSwitch(io), "AKD") // Keyboard Strobe
io.addSoftSwitchR(0x20, buildNotImplementedSoftSwitchR(io), "TAPEOUT") // Cassette Output
io.addSoftSwitchRW(0x30, buildSpeakerSoftSwitch(io), "SPEAKER") // Speaker
io.addSoftSwitchR(0x40, buildNotImplementedSoftSwitchR(io), "STROBE") // Game connector Strobe
2019-02-24 14:05:50 +00:00
// Note: Some sources indicate that all these cover 16 positions
// for read and write. But the Apple2e takes over some of them, with
2019-02-24 14:05:50 +00:00
// the prevention on acting only on writes.
2022-08-05 17:43:17 +00:00
io.addSoftSwitchRW(0x50, getSoftSwitch(io, ioFlagText, false), "TEXTOFF")
io.addSoftSwitchRW(0x51, getSoftSwitch(io, ioFlagText, true), "TEXTON")
io.addSoftSwitchRW(0x52, getSoftSwitch(io, ioFlagMixed, false), "MIXEDOFF")
io.addSoftSwitchRW(0x53, getSoftSwitch(io, ioFlagMixed, true), "MIXEDON")
io.addSoftSwitchRW(0x54, getSoftSwitch(io, ioFlagSecondPage, false), "PAGE2OFF")
io.addSoftSwitchRW(0x55, getSoftSwitch(io, ioFlagSecondPage, true), "PAGE2ON")
io.addSoftSwitchRW(0x56, getSoftSwitch(io, ioFlagHiRes, false), "HIRESOFF")
io.addSoftSwitchRW(0x57, getSoftSwitch(io, ioFlagHiRes, true), "HIRESON")
io.addSoftSwitchRW(0x58, getSoftSwitch(io, ioFlagAnnunciator0, false), "ANN0OFF")
io.addSoftSwitchRW(0x59, getSoftSwitch(io, ioFlagAnnunciator0, true), "ANN0ON")
io.addSoftSwitchRW(0x5a, getSoftSwitch(io, ioFlagAnnunciator1, false), "ANN1OFF")
io.addSoftSwitchRW(0x5b, getSoftSwitch(io, ioFlagAnnunciator1, true), "ANN1ON")
io.addSoftSwitchRW(0x5c, getSoftSwitch(io, ioFlagAnnunciator2, false), "ANN2OFF")
io.addSoftSwitchRW(0x5d, getSoftSwitch(io, ioFlagAnnunciator2, true), "ANN2ON")
io.addSoftSwitchRW(0x5e, getSoftSwitch(io, ioFlagAnnunciator3, false), "ANN3OFF")
io.addSoftSwitchRW(0x5f, getSoftSwitch(io, ioFlagAnnunciator3, true), "ANN3ON")
io.addSoftSwitchR(0x60, buildNotImplementedSoftSwitchR(io), "CASSETTE") // Cassette Input
io.addSoftSwitchR(0x61, buildButtonSoftSwitch(io, 0), "PB0")
io.addSoftSwitchR(0x62, buildButtonSoftSwitch(io, 1), "PB1")
io.addSoftSwitchR(0x63, buildButtonSoftSwitch(io, 2), "PB2")
io.addSoftSwitchR(0x64, buildPaddleSoftSwitch(io, 0), "PDL0")
io.addSoftSwitchR(0x65, buildPaddleSoftSwitch(io, 1), "PDL1")
io.addSoftSwitchR(0x66, buildPaddleSoftSwitch(io, 2), "PDL2")
io.addSoftSwitchR(0x67, buildPaddleSoftSwitch(io, 3), "PDL3")
// The previous 8 softswitches are repeated
2022-08-05 17:43:17 +00:00
io.addSoftSwitchR(0x68, buildNotImplementedSoftSwitchR(io), "CASSETTE") // Cassette Input
io.addSoftSwitchR(0x69, buildButtonSoftSwitch(io, 0), "PB0")
io.addSoftSwitchR(0x6A, buildButtonSoftSwitch(io, 1), "PB1")
io.addSoftSwitchR(0x6B, buildButtonSoftSwitch(io, 2), "PB2")
io.addSoftSwitchR(0x6C, buildPaddleSoftSwitch(io, 0), "PDL0")
io.addSoftSwitchR(0x6D, buildPaddleSoftSwitch(io, 1), "PDL1")
io.addSoftSwitchR(0x6E, buildPaddleSoftSwitch(io, 2), "PDL2")
io.addSoftSwitchR(0x6F, buildPaddleSoftSwitch(io, 3), "PDL3")
2019-08-05 22:37:27 +00:00
2022-08-05 17:43:17 +00:00
io.addSoftSwitchR(0x70, buildStrobePaddlesSoftSwitch(io), "RESETPDL") // Game controllers reset
// For RGB screen modes. Default to NTSC artifacts
io.softSwitchesData[ioFlag1RGBCard] = ssOn
io.softSwitchesData[ioFlag2RGBCard] = ssOn
2019-02-24 14:05:50 +00:00
}
2022-08-05 17:43:17 +00:00
func buildNotImplementedSoftSwitchR(io *ioC0Page) softSwitchR {
return func() uint8 {
// Return random info. Some games (Serpentine) used CASSETTE and get stuck if not changing.
return uint8(io.apple2.cpu.GetCycles())
}
2019-02-24 14:05:50 +00:00
}
2022-08-05 17:43:17 +00:00
func buildNotImplementedSoftSwitchW(io *ioC0Page) softSwitchW {
return func(uint8) {
// Do nothing
}
}
2022-08-05 17:43:17 +00:00
func setStatusSoftSwitch(io *ioC0Page, ioFlag uint8) softSwitchW {
return func(value uint8) {
2019-11-11 21:58:42 +00:00
io.softSwitchesData[ioFlag] = value
}
}
2022-08-05 17:43:17 +00:00
func getStatusSoftSwitch(io *ioC0Page, ioFlag uint8) softSwitchR {
return func() uint8 {
2019-02-24 14:05:50 +00:00
return io.softSwitchesData[ioFlag]
}
}
2022-08-05 17:43:17 +00:00
func getSoftSwitch(io *ioC0Page, ioFlag uint8, isSet bool) softSwitchR {
return func() uint8 {
2019-02-24 14:05:50 +00:00
if isSet {
io.softSwitchesData[ioFlag] = ssOn
} else {
io.softSwitchesData[ioFlag] = ssOff
}
return 0
}
}
2022-08-05 17:43:17 +00:00
func buildSpeakerSoftSwitch(io *ioC0Page) softSwitchR {
return func() uint8 {
if io.speaker != nil {
io.speaker.Click(io.apple2.cpu.GetCycles())
}
return 0
2019-05-09 22:09:15 +00:00
}
}
2022-08-05 17:43:17 +00:00
func buildKeySoftSwitch(io *ioC0Page) softSwitchR {
return func() uint8 {
strobed := (io.softSwitchesData[ioDataKeyboard] & (1 << 7)) == 0
if io.keyboard != nil {
if key, ok := io.keyboard.GetKey(strobed); ok {
io.softSwitchesData[ioDataKeyboard] = key + (1 << 7)
}
2019-02-24 14:05:50 +00:00
}
2022-08-05 17:43:17 +00:00
value := io.softSwitchesData[ioDataKeyboard]
//fmt.Printf("Key $%02x, %v\n", value, strobed)
return value
2019-02-24 14:05:50 +00:00
}
}
2022-08-05 17:43:17 +00:00
func buildStrobeKeyboardSoftSwitch(io *ioC0Page) softSwitchR {
return func() uint8 {
result := io.softSwitchesData[ioDataKeyboard]
//fmt.Printf("Strobe $%02x\n", result)
io.softSwitchesData[ioDataKeyboard] &^= 1 << 7
return result
}
2019-02-24 14:05:50 +00:00
}
2019-08-05 22:37:27 +00:00
2022-08-05 17:43:17 +00:00
func buildButtonSoftSwitch(io *ioC0Page, i int) softSwitchR {
return func() uint8 {
2019-08-05 22:37:27 +00:00
if io.joysticks != nil && io.joysticks.ReadButton(i) {
return 128
}
return 0
}
}
/*
Paddle values are calculated by the time taken by a current going
through the paddle variable resistor to charge a capacitor.
2019-08-05 22:37:27 +00:00
The capacitor is discharged via the strobe softswitch. The result is
how many times a 11 cycles loop runs before the capacitor reaches
2019-08-05 22:37:27 +00:00
the voltage threshold.
See: http://www.1000bit.it/support/manuali/apple/technotes/aiie/tn.aiie.06.html
*/
const paddleToCyclesFactor = 11
2022-08-05 17:43:17 +00:00
func buildPaddleSoftSwitch(io *ioC0Page, i int) softSwitchR {
return func() uint8 {
2019-08-05 22:37:27 +00:00
if io.joysticks == nil {
return 255 // Capacitors never discharge if there is not joystick
}
reading, hasData := io.joysticks.ReadPaddle(i)
if !hasData {
return 255 // Capacitors never discharge if there is not joystick
2019-08-05 22:37:27 +00:00
}
cyclesNeeded := uint64(reading) * paddleToCyclesFactor
cyclesElapsed := io.apple2.cpu.GetCycles() - io.paddlesStrobeCycle
if cyclesElapsed < cyclesNeeded {
// The capacitor is not charged yet
return 128
}
return 0
2019-08-05 22:37:27 +00:00
}
}
2022-08-05 17:43:17 +00:00
func buildStrobePaddlesSoftSwitch(io *ioC0Page) softSwitchR {
return func() uint8 {
// On the real machine this discharges the capacitors.
io.paddlesStrobeCycle = io.apple2.cpu.GetCycles()
return 0
}
2019-08-05 22:37:27 +00:00
}