izapple2/softSwitches2.go

188 lines
6.4 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
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) {
2019-10-20 22:00:42 +00:00
io.addSoftSwitchRW(0x00, keySoftSwitch, "KEYBOARD") // Keyboard
io.addSoftSwitchRW(0x10, strobeKeyboardSoftSwitch, "AKD") // Keyboard Strobe
io.addSoftSwitchR(0x20, notImplementedSoftSwitchR, "TAPEOUT") // Cassette Output
io.addSoftSwitchR(0x30, speakerSoftSwitch, "SPEAKER") // Speaker
io.addSoftSwitchR(0x40, notImplementedSoftSwitchR, "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.
2019-10-20 22:00:42 +00:00
io.addSoftSwitchRW(0x50, getSoftSwitch(ioFlagText, false), "TEXTOFF")
io.addSoftSwitchRW(0x51, getSoftSwitch(ioFlagText, true), "TEXTON")
io.addSoftSwitchRW(0x52, getSoftSwitch(ioFlagMixed, false), "MIXEDOFF")
io.addSoftSwitchRW(0x53, getSoftSwitch(ioFlagMixed, true), "MIXEDON")
io.addSoftSwitchRW(0x54, getSoftSwitch(ioFlagSecondPage, false), "PAGE2OFF")
io.addSoftSwitchRW(0x55, getSoftSwitch(ioFlagSecondPage, true), "PAGE2ON")
io.addSoftSwitchRW(0x56, getSoftSwitch(ioFlagHiRes, false), "HIRESOFF")
io.addSoftSwitchRW(0x57, getSoftSwitch(ioFlagHiRes, true), "HIRESON")
2019-10-20 22:00:42 +00:00
io.addSoftSwitchRW(0x58, getSoftSwitch(ioFlagAnnunciator0, false), "ANN0OFF")
io.addSoftSwitchRW(0x59, getSoftSwitch(ioFlagAnnunciator0, true), "ANN0ON")
io.addSoftSwitchRW(0x5a, getSoftSwitch(ioFlagAnnunciator1, false), "ANN1OFF")
io.addSoftSwitchRW(0x5b, getSoftSwitch(ioFlagAnnunciator1, true), "ANN1ON")
io.addSoftSwitchRW(0x5c, getSoftSwitch(ioFlagAnnunciator2, false), "ANN2OFF")
io.addSoftSwitchRW(0x5d, getSoftSwitch(ioFlagAnnunciator2, true), "ANN2ON")
io.addSoftSwitchRW(0x5e, getSoftSwitch(ioFlagAnnunciator3, false), "ANN3OFF")
io.addSoftSwitchRW(0x5f, getSoftSwitch(ioFlagAnnunciator3, true), "ANN3ON")
2019-02-24 14:05:50 +00:00
2019-10-20 22:00:42 +00:00
io.addSoftSwitchR(0x60, notImplementedSoftSwitchR, "CASSETTE") // Cassette Input
io.addSoftSwitchR(0x61, getButtonSoftSwitch(0), "PB0")
io.addSoftSwitchR(0x62, getButtonSoftSwitch(1), "PB1")
io.addSoftSwitchR(0x63, getButtonSoftSwitch(2), "PB2")
io.addSoftSwitchR(0x64, getPaddleSoftSwitch(0), "PDL0")
io.addSoftSwitchR(0x65, getPaddleSoftSwitch(1), "PDL1")
io.addSoftSwitchR(0x66, getPaddleSoftSwitch(2), "PDL2")
io.addSoftSwitchR(0x67, getPaddleSoftSwitch(3), "PDL3")
// The previous 8 softswitches are repeated
2019-10-20 22:00:42 +00:00
io.addSoftSwitchR(0x68, notImplementedSoftSwitchR, "CASSETTE") // Cassette Input
io.addSoftSwitchR(0x69, getButtonSoftSwitch(0), "PB0")
io.addSoftSwitchR(0x6A, getButtonSoftSwitch(1), "PB1")
io.addSoftSwitchR(0x6B, getButtonSoftSwitch(2), "PB2")
io.addSoftSwitchR(0x6C, getPaddleSoftSwitch(0), "PDL0")
io.addSoftSwitchR(0x6D, getPaddleSoftSwitch(1), "PDL1")
io.addSoftSwitchR(0x6E, getPaddleSoftSwitch(2), "PDL2")
io.addSoftSwitchR(0x6F, getPaddleSoftSwitch(3), "PDL3")
2019-08-05 22:37:27 +00:00
2019-10-20 22:00:42 +00:00
io.addSoftSwitchR(0x70, strobePaddlesSoftSwitch, "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
}
func notImplementedSoftSwitchR(io *ioC0Page) 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
}
func notImplementedSoftSwitchW(*ioC0Page, uint8) {
}
2019-11-11 21:58:42 +00:00
func setStatusSoftSwitch(ioFlag uint8) softSwitchW {
return func(io *ioC0Page, value uint8) {
io.softSwitchesData[ioFlag] = value
}
}
func getStatusSoftSwitch(ioFlag uint8) softSwitchR {
return func(io *ioC0Page) uint8 {
2019-02-24 14:05:50 +00:00
return io.softSwitchesData[ioFlag]
}
}
func getSoftSwitch(ioFlag uint8, isSet bool) softSwitchR {
return func(io *ioC0Page) uint8 {
2019-02-24 14:05:50 +00:00
if isSet {
io.softSwitchesData[ioFlag] = ssOn
} else {
io.softSwitchesData[ioFlag] = ssOff
}
return 0
}
}
2019-08-05 22:37:27 +00:00
func speakerSoftSwitch(io *ioC0Page) uint8 {
2019-05-09 22:09:15 +00:00
if io.speaker != nil {
io.speaker.Click(io.apple2.cpu.GetCycles())
}
return 0
}
2019-08-05 22:37:27 +00:00
func keySoftSwitch(io *ioC0Page) uint8 {
strobed := (io.softSwitchesData[ioDataKeyboard] & (1 << 7)) == 0
2019-04-14 10:54:11 +00:00
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
}
}
value := io.softSwitchesData[ioDataKeyboard]
//fmt.Printf("Key $%02x, %v\n", value, strobed)
return value
2019-02-24 14:05:50 +00:00
}
func strobeKeyboardSoftSwitch(io *ioC0Page) uint8 {
result := io.softSwitchesData[ioDataKeyboard]
//fmt.Printf("Strobe $%02x\n", result)
io.softSwitchesData[ioDataKeyboard] &^= 1 << 7
2019-02-24 14:05:50 +00:00
return result
}
2019-08-05 22:37:27 +00:00
func getButtonSoftSwitch(i int) softSwitchR {
return func(io *ioC0Page) uint8 {
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
func getPaddleSoftSwitch(i int) softSwitchR {
return func(io *ioC0Page) uint8 {
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
}
}
func strobePaddlesSoftSwitch(io *ioC0Page) uint8 {
// On the real machine this discharges the capacitors.
io.paddlesStrobeCycle = io.apple2.cpu.GetCycles()
return 0
}