mirror of
https://github.com/ivanizag/izapple2.git
synced 2024-06-14 02:29:29 +00:00
Mouse support with Apple Mouse Card
This commit is contained in:
parent
8b50ae1500
commit
55ca1df967
|
@ -30,6 +30,7 @@ Portable emulator of an Apple II+ or //e. Written in Go.
|
||||||
- Bootable Smartport / ProDOS card
|
- Bootable Smartport / ProDOS card
|
||||||
- VidHd, limited to the ROM signature and SHR as used by Total Replay, only for //e models with 128Kb
|
- VidHd, limited to the ROM signature and SHR as used by Total Replay, only for //e models with 128Kb
|
||||||
- FASTChip, limited to what Total Replay needs to set and clear fast mode
|
- FASTChip, limited to what Total Replay needs to set and clear fast mode
|
||||||
|
- Mouse Card, emulates the entry points, not the softswitches. Experimental.
|
||||||
- Host console card. Maps the host STDIN and STDOUT to PR# and IN#
|
- Host console card. Maps the host STDIN and STDOUT to PR# and IN#
|
||||||
|
|
||||||
- Graphic modes:
|
- Graphic modes:
|
||||||
|
@ -55,6 +56,7 @@ Portable emulator of an Apple II+ or //e. Written in Go.
|
||||||
- Other features:
|
- Other features:
|
||||||
- Sound
|
- Sound
|
||||||
- Joystick support. Up to two joysticks or four paddles
|
- Joystick support. Up to two joysticks or four paddles
|
||||||
|
- Mouse support. No mouse capture needed
|
||||||
- Adjustable speed
|
- Adjustable speed
|
||||||
- Fast disk mode to set max speed while using the disks
|
- Fast disk mode to set max speed while using the disks
|
||||||
- Single file executable with embedded ROMs and DOS 3.3
|
- Single file executable with embedded ROMs and DOS 3.3
|
||||||
|
@ -69,7 +71,7 @@ By default the following configuration is launched:
|
||||||
- Memory Expansion card with 1Gb in slot 1
|
- Memory Expansion card with 1Gb in slot 1
|
||||||
- VidHD card (SHR support) in slot 2
|
- VidHD card (SHR support) in slot 2
|
||||||
- FASTChip Accelerator card in slot 3
|
- FASTChip Accelerator card in slot 3
|
||||||
- ThunderClock Plus card in slot 4
|
- Mouse card in slot 4
|
||||||
- SmartPort card with 1 device in slot 5 (if an image is provided with -disk35)
|
- SmartPort card with 1 device in slot 5 (if an image is provided with -disk35)
|
||||||
- DiskII controller card in slot 6
|
- DiskII controller card in slot 6
|
||||||
- SmartPort card with 1 device in slot 7 (if an image is provided with -hd)
|
- SmartPort card with 1 device in slot 7 (if an image is provided with -hd)
|
||||||
|
@ -199,6 +201,8 @@ Only valid on SDL mode
|
||||||
cpu speed in Mhz, use 0 for full speed. Use F5 to toggle. (default 1.0227142857142857)
|
cpu speed in Mhz, use 0 for full speed. Use F5 to toggle. (default 1.0227142857142857)
|
||||||
-model string
|
-model string
|
||||||
set base model. Models available 2plus, 2e, 2enh, base64a (default "2enh")
|
set base model. Models available 2plus, 2e, 2enh, base64a (default "2enh")
|
||||||
|
-mouseCardSlot int
|
||||||
|
slot for the Mouse card. -1 for none (default 4)
|
||||||
-nsc int
|
-nsc int
|
||||||
add a DS1216 No-Slot-Clock on the main ROM (use 0) or a slot ROM. -1 for none (default -1)
|
add a DS1216 No-Slot-Clock on the main ROM (use 0) or a slot ROM. -1 for none (default -1)
|
||||||
-panicSS
|
-panicSS
|
||||||
|
|
|
@ -153,6 +153,11 @@ func (a *Apple2) AddThunderClockPlusCard(slot int) {
|
||||||
a.insertCard(NewCardThunderClockPlus(), slot)
|
a.insertCard(NewCardThunderClockPlus(), slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddMouseCard inserts a Mouse card
|
||||||
|
func (a *Apple2) AddMouseCard(slot int) {
|
||||||
|
a.insertCard(NewCardMouse(), slot)
|
||||||
|
}
|
||||||
|
|
||||||
// AddRGBCard inserts an RBG option to the Apple IIe 80 col 64KB card
|
// AddRGBCard inserts an RBG option to the Apple IIe 80 col 64KB card
|
||||||
func (a *Apple2) AddRGBCard() {
|
func (a *Apple2) AddRGBCard() {
|
||||||
setupRGBCard(a)
|
setupRGBCard(a)
|
||||||
|
@ -212,3 +217,8 @@ func (a *Apple2) SetSpeakerProvider(s SpeakerProvider) {
|
||||||
func (a *Apple2) SetJoysticksProvider(j JoysticksProvider) {
|
func (a *Apple2) SetJoysticksProvider(j JoysticksProvider) {
|
||||||
a.io.setJoysticksProvider(j)
|
a.io.setJoysticksProvider(j)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetMouseProvider attaches an external joysticks provider
|
||||||
|
func (a *Apple2) SetMouseProvider(m MouseProvider) {
|
||||||
|
a.io.setMouseProvider(m)
|
||||||
|
}
|
||||||
|
|
|
@ -73,12 +73,16 @@ func MainApple() *Apple2 {
|
||||||
"memory to use with RAMWorks card, 0 for no card, max is 16384")
|
"memory to use with RAMWorks card, 0 for no card, max is 16384")
|
||||||
thunderClockCardSlot := flag.Int(
|
thunderClockCardSlot := flag.Int(
|
||||||
"thunderClockCardSlot",
|
"thunderClockCardSlot",
|
||||||
4,
|
-1,
|
||||||
"slot for the ThunderClock Plus card. -1 for none")
|
"slot for the ThunderClock Plus card. -1 for none")
|
||||||
consoleCardSlot := flag.Int(
|
consoleCardSlot := flag.Int(
|
||||||
"consoleCardSlot",
|
"consoleCardSlot",
|
||||||
-1,
|
-1,
|
||||||
"slot for the host console card. -1 for none")
|
"slot for the host console card. -1 for none")
|
||||||
|
mouseCardSlot := flag.Int(
|
||||||
|
"mouseCardSlot",
|
||||||
|
4,
|
||||||
|
"slot for the Mouse card. -1 for none")
|
||||||
nsc := flag.Int(
|
nsc := flag.Int(
|
||||||
"nsc",
|
"nsc",
|
||||||
-1,
|
-1,
|
||||||
|
@ -247,6 +251,9 @@ func MainApple() *Apple2 {
|
||||||
if *consoleCardSlot >= 0 {
|
if *consoleCardSlot >= 0 {
|
||||||
a.AddCardInOut(*consoleCardSlot)
|
a.AddCardInOut(*consoleCardSlot)
|
||||||
}
|
}
|
||||||
|
if *mouseCardSlot > 0 {
|
||||||
|
a.AddMouseCard(*mouseCardSlot)
|
||||||
|
}
|
||||||
|
|
||||||
if *smartPortImage != "" {
|
if *smartPortImage != "" {
|
||||||
err := a.AddSmartPortDisk(5, *smartPortImage, *traceHD)
|
err := a.AddSmartPortDisk(5, *smartPortImage, *traceHD)
|
||||||
|
|
|
@ -194,7 +194,7 @@ func (c *CardHardDisk) status(unit uint8, dest uint16) uint8 {
|
||||||
c.a.mmu.Poke(dest+2, 0x00)
|
c.a.mmu.Poke(dest+2, 0x00)
|
||||||
c.a.mmu.Poke(dest+3, 0x00) // Unknown manufacturer
|
c.a.mmu.Poke(dest+3, 0x00) // Unknown manufacturer
|
||||||
c.a.mmu.Poke(dest+4, 0x01)
|
c.a.mmu.Poke(dest+4, 0x01)
|
||||||
c.a.mmu.Poke(dest+5, 0x00) // Versión 1.0 final
|
c.a.mmu.Poke(dest+5, 0x00) // Version 1.0 final
|
||||||
c.a.mmu.Poke(dest+6, 0x00)
|
c.a.mmu.Poke(dest+6, 0x00)
|
||||||
c.a.mmu.Poke(dest+7, 0x00) // Reserved
|
c.a.mmu.Poke(dest+7, 0x00) // Reserved
|
||||||
|
|
||||||
|
|
60
cardInOut.go
60
cardInOut.go
|
@ -58,6 +58,12 @@ func (c *CardInOut) assign(a *Apple2, slot int) {
|
||||||
|
|
||||||
}, "INOUTW")
|
}, "INOUTW")
|
||||||
|
|
||||||
|
data := buildBaseInOutRom(slot)
|
||||||
|
c.romCsxx = newMemoryRangeROM(0xC200, data[:], "InOUt card")
|
||||||
|
c.cardBase.assign(a, slot)
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildBaseInOutRom(slot int) []uint8 {
|
||||||
data := [256]uint8{
|
data := [256]uint8{
|
||||||
// Register
|
// Register
|
||||||
0x4c, 0x40, 0xc2, 0, 0, 0, 0, 0,
|
0x4c, 0x40, 0xc2, 0, 0, 0, 0, 0,
|
||||||
|
@ -67,21 +73,20 @@ func (c *CardInOut) assign(a *Apple2, slot int) {
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
|
||||||
0x48, 0xA5, 0x38, 0xD0, 0x12, 0xA9, 0xC2, 0xC5,
|
0x48, 0xA5, 0x38, 0xD0, 0x11, 0xA9, 0xC2, 0xC5,
|
||||||
0x39, 0xD0, 0x0C, 0xAD, 0x50, 0x00, 0x85, 0x38,
|
0x39, 0xD0, 0x0B, 0xAD, 0x4F, 0x85, 0x38, 0x68,
|
||||||
0x68, 0x91, 0x28, 0xAD, 0xA0, 0xC0, 0x60, 0x68,
|
|
||||||
0x8D, 0xA1, 0xC0, 0x60,
|
|
||||||
}
|
|
||||||
|
|
||||||
c.romCsxx = newMemoryRangeROM(0xC200, data[:], "InOUt card")
|
0x91, 0x28, 0xAD, 0xA0, 0xC0, 0x60, 0x68, 0x8D,
|
||||||
|
0xA1, 0xC0, 0x60,
|
||||||
|
}
|
||||||
|
|
||||||
// Fix slot dependant addresses
|
// Fix slot dependant addresses
|
||||||
data[0x02] = uint8(0xc0 + slot)
|
data[0x02] = uint8(0xc0 + slot)
|
||||||
data[0x46] = uint8(0xc0 + slot)
|
data[0x46] = uint8(0xc0 + slot)
|
||||||
data[0x54] = uint8(0x80 + slot<<4)
|
data[0x53] = uint8(0x80 + slot<<4)
|
||||||
data[0x59] = uint8(0x81 + slot<<4)
|
data[0x58] = uint8(0x81 + slot<<4)
|
||||||
|
|
||||||
c.cardBase.assign(a, slot)
|
return data[:]
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -109,7 +114,7 @@ src:
|
||||||
CMP *KSWH
|
CMP *KSWH
|
||||||
BNE PREntry
|
BNE PREntry
|
||||||
FixKSWL:
|
FixKSWL:
|
||||||
LDA <INEntry
|
LDA #<INEntry
|
||||||
STA *KSWL
|
STA *KSWL
|
||||||
INEntry:
|
INEntry:
|
||||||
PLA
|
PLA
|
||||||
|
@ -138,22 +143,21 @@ pass 2
|
||||||
C240 SKIPHE
|
C240 SKIPHE
|
||||||
C240 PHA 48
|
C240 PHA 48
|
||||||
C241 LDA *KSWL A5 38
|
C241 LDA *KSWL A5 38
|
||||||
C243 BNE PRENTR D0 12
|
C243 BNE PRENTR D0 11
|
||||||
C245 LDA #$C2 A9 C2
|
C245 LDA #$C2 A9 C2
|
||||||
C247 CMP *KSWH C5 39
|
C247 CMP *KSWH C5 39
|
||||||
C249 BNE PRENTR D0 0C
|
C249 BNE PRENTR D0 0B
|
||||||
C24B FIXKSW
|
C24B LDA #<INENTR A9 4F
|
||||||
C24B LDA <INENTR AD 50 00
|
C24D STA *KSWL 85 38
|
||||||
C24E STA *KSWL 85 38
|
C24F INENTR
|
||||||
C250 INENTR
|
C24F PLA 68
|
||||||
C250 PLA 68
|
C250 STA (BASL),Y 91 28
|
||||||
C251 STA (BASL),Y 91 28
|
C252 LDA $C0A0 AD A0 C0
|
||||||
C253 LDA $C0A0 AD A0 C0
|
C255 RTS 60
|
||||||
C256 RTS 60
|
C256 PRENTR
|
||||||
C257 PRENTR
|
C256 PLA 68
|
||||||
C257 PLA 68
|
C257 STA $C0A1 8D A1 C0
|
||||||
C258 STA $C0A1 8D A1 C0
|
C25A RTS 60
|
||||||
C25B RTS 60
|
|
||||||
|
|
||||||
done.
|
done.
|
||||||
|
|
||||||
|
@ -161,8 +165,8 @@ Object Code:
|
||||||
c200:
|
c200:
|
||||||
4C 40 C2
|
4C 40 C2
|
||||||
c240:
|
c240:
|
||||||
48 A5 38 D0 12
|
48 A5 38 D0 11
|
||||||
A9 C2 C5 39 D0 0C AD 50
|
A9 C2 C5 39 D0 0B A9 4F
|
||||||
00 85 38 68 91 28 AD A0
|
85 38 68 91 28 AD A0 C0
|
||||||
C0 60 68 8D A1 C0 60
|
60 68 8D A1 C0 60
|
||||||
*/
|
*/
|
||||||
|
|
247
cardMouse.go
Normal file
247
cardMouse.go
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
package izapple2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Mouse card implementation. Does not emulate a real card, only the behaviour. Idea taken
|
||||||
|
from aiie (https://hackaday.io/project/19925-aiie-an-embedded-apple-e-emulator/log/188017-entry-23-here-mousie-mousie-mousie)
|
||||||
|
|
||||||
|
See:
|
||||||
|
https://www.apple.asimov.net/documentation/hardware/io/AppleMouse%20II%20User%27s%20Manual.pdf
|
||||||
|
https://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Interface%20Cards/Digitizers/Apple%20Mouse%20Interface%20Card/Documentation/Apple%20II%20Mouse%20Technical%20Notes.pdf
|
||||||
|
|
||||||
|
The management of IN# and PR# is copied from cardInOut
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// CardMouse represents a SmartPort card
|
||||||
|
type CardMouse struct {
|
||||||
|
cardBase
|
||||||
|
|
||||||
|
lastX, lastY uint16
|
||||||
|
lastPressed bool
|
||||||
|
|
||||||
|
minX, minY, maxX, maxY uint16
|
||||||
|
mode uint8
|
||||||
|
|
||||||
|
iIn int
|
||||||
|
i int
|
||||||
|
|
||||||
|
trace bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCardMouse creates a new SmartPort card
|
||||||
|
func NewCardMouse() *CardMouse {
|
||||||
|
var c CardMouse
|
||||||
|
c.name = "Mouse Card"
|
||||||
|
c.trace = true
|
||||||
|
c.maxX = 0x3ff
|
||||||
|
c.maxY = 0x3ff
|
||||||
|
//c.loadRomFromResource("<internal>//Apple Mouse Interface Card ROM - 342-0270-C.bin")
|
||||||
|
return &c
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
mouseXLo = uint16(0x478)
|
||||||
|
mouseYLo = uint16(0x4f8)
|
||||||
|
mouseXHi = uint16(0x578)
|
||||||
|
mouseYHi = uint16(0x5f8)
|
||||||
|
mouseStatus = uint16(0x778)
|
||||||
|
mouseMode = uint16(0x7f8)
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
mouseModeEnabled = uint8(1)
|
||||||
|
mouseModeIntMoveEnabled = uint8(2)
|
||||||
|
mouseModeIntButtonEnabled = uint8(4)
|
||||||
|
mouseModeIntVBlankEnabled = uint8(4)
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *CardMouse) set(field uint16, value uint8) {
|
||||||
|
c.a.mmu.Poke(field+uint16(c.slot), value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CardMouse) get(field uint16) uint8 {
|
||||||
|
return c.a.mmu.Peek(field /*+ uint16(c.slot)*/)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CardMouse) setMode(mode uint8) {
|
||||||
|
c.mode = mode
|
||||||
|
enabled := mode&mouseModeEnabled == 1
|
||||||
|
moveInts := mode&mouseModeIntMoveEnabled == 1
|
||||||
|
buttonInts := mode&mouseModeIntButtonEnabled == 1
|
||||||
|
vBlankInts := mode&mouseModeIntVBlankEnabled == 1
|
||||||
|
if c.trace {
|
||||||
|
fmt.Printf("[cardMouse] Mode set to 0x%02x. Enabled %v. Interrups: move=%v, button=%v, vblank=%v.\n",
|
||||||
|
mode, enabled, moveInts, buttonInts, vBlankInts)
|
||||||
|
}
|
||||||
|
if moveInts || buttonInts || vBlankInts {
|
||||||
|
panic("Mouse interrupts not implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mouseReponse = "10,10,+4\n"
|
||||||
|
|
||||||
|
func (c *CardMouse) assign(a *Apple2, slot int) {
|
||||||
|
c.addCardSoftSwitchR(0, func(*ioC0Page) uint8 {
|
||||||
|
// TODO
|
||||||
|
value := uint8(mouseReponse[c.i])
|
||||||
|
c.i = (c.i + 1) % len(mouseReponse)
|
||||||
|
value += 0x80
|
||||||
|
if value&0x7f == 10 {
|
||||||
|
value = 13 + 0x80
|
||||||
|
}
|
||||||
|
if c.trace {
|
||||||
|
fmt.Printf("[cardMouse] Read access to softswith 0x%x for slot %v, value %x.\n", 0, slot, value)
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}, "MOUSEOUT")
|
||||||
|
|
||||||
|
c.addCardSoftSwitchW(1, func(_ *ioC0Page, value uint8) {
|
||||||
|
if c.trace {
|
||||||
|
fmt.Printf("[cardMouse] Write access to softswith 0x%x for slot %v, value 0x%x: %v, %v.\n", 1, slot, value, value&0x7f, string(value&0x7f))
|
||||||
|
}
|
||||||
|
if c.iIn == 0 {
|
||||||
|
// We care only about the first byte
|
||||||
|
c.setMode(value & 0x0f)
|
||||||
|
}
|
||||||
|
c.iIn++
|
||||||
|
if value == 13 {
|
||||||
|
c.iIn = 0 // Ready for the next command
|
||||||
|
}
|
||||||
|
}, "MOUSEIN")
|
||||||
|
|
||||||
|
c.addCardSoftSwitchW(2, func(_ *ioC0Page, value uint8) {
|
||||||
|
if c.trace {
|
||||||
|
fmt.Printf("[cardMouse] SetMouse(0x%02v)\n", value)
|
||||||
|
}
|
||||||
|
c.setMode(value & 0x0f)
|
||||||
|
}, "SETMOUSE")
|
||||||
|
|
||||||
|
c.addCardSoftSwitchW(3, func(_ *ioC0Page, value uint8) {
|
||||||
|
if c.trace {
|
||||||
|
fmt.Printf("[cardMouse] ServeMouse(0x%02v)\n", value)
|
||||||
|
}
|
||||||
|
}, "SERVEMOUSE")
|
||||||
|
|
||||||
|
c.addCardSoftSwitchW(4, func(_ *ioC0Page, value uint8) {
|
||||||
|
if c.mode&mouseModeEnabled == 1 {
|
||||||
|
x, y, pressed := a.io.mouse.ReadMouse()
|
||||||
|
|
||||||
|
xTrans := uint16(uint64(c.maxX-c.minX) * uint64(x) / 65536)
|
||||||
|
yTrans := uint16(uint64(c.maxY-c.minY) * uint64(y) / 65536)
|
||||||
|
|
||||||
|
status := uint8(0)
|
||||||
|
if pressed {
|
||||||
|
status |= 1 << 7
|
||||||
|
}
|
||||||
|
if c.lastPressed {
|
||||||
|
status |= 1 << 6
|
||||||
|
}
|
||||||
|
if (xTrans != c.lastX) || (yTrans != c.lastY) {
|
||||||
|
status |= 1 << 5
|
||||||
|
}
|
||||||
|
|
||||||
|
c.set(mouseXHi, uint8(xTrans>>8))
|
||||||
|
c.set(mouseYHi, uint8(yTrans>>8))
|
||||||
|
c.set(mouseXLo, uint8(xTrans))
|
||||||
|
c.set(mouseYLo, uint8(yTrans))
|
||||||
|
c.set(mouseStatus, status)
|
||||||
|
c.set(mouseMode, c.mode)
|
||||||
|
if c.trace && ((status&(1<<5) != 0) || (pressed != c.lastPressed)) {
|
||||||
|
fmt.Printf("[cardMouse] ReadMouse(): x: %v, y: %v, pressed: %v\n",
|
||||||
|
xTrans, yTrans, pressed)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.lastX = xTrans
|
||||||
|
c.lastY = yTrans
|
||||||
|
c.lastPressed = pressed
|
||||||
|
}
|
||||||
|
}, "READMOUSE")
|
||||||
|
|
||||||
|
c.addCardSoftSwitchW(5, func(_ *ioC0Page, value uint8) {
|
||||||
|
if c.trace {
|
||||||
|
fmt.Printf("[cardMouse] ClearMouse()\n")
|
||||||
|
}
|
||||||
|
c.set(mouseXHi, 0)
|
||||||
|
c.set(mouseYHi, 0)
|
||||||
|
c.set(mouseXLo, 0)
|
||||||
|
c.set(mouseYLo, 0)
|
||||||
|
}, "CLEARMOUSE")
|
||||||
|
c.addCardSoftSwitchW(6, func(_ *ioC0Page, value uint8) {
|
||||||
|
if c.trace {
|
||||||
|
fmt.Printf("[cardMouse] PosMouse(0x%02v)\n", value)
|
||||||
|
}
|
||||||
|
}, "POSMOUSE")
|
||||||
|
|
||||||
|
c.addCardSoftSwitchW(7, func(_ *ioC0Page, value uint8) {
|
||||||
|
if c.trace {
|
||||||
|
fmt.Printf("[cardMouse] ClampMouse(%v)\n", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if value == 0 {
|
||||||
|
//c.a.cpu.SetTrace(false)
|
||||||
|
c.minX = uint16(c.get(mouseXLo)) + uint16(c.get(mouseXHi))<<8
|
||||||
|
c.maxX = uint16(c.get(mouseYLo)) + uint16(c.get(mouseYHi))<<8
|
||||||
|
} else if value == 1 {
|
||||||
|
//c.a.cpu.SetTrace(true)
|
||||||
|
c.minY = uint16(c.get(mouseXLo)) + uint16(c.get(mouseXHi))<<8
|
||||||
|
c.maxY = uint16(c.get(mouseYLo)) + uint16(c.get(mouseYHi))<<8
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.trace {
|
||||||
|
fmt.Printf("[cardMouse] Current bounds: X[%v-%v], Y[%v-%v],\n", c.minX, c.maxX, c.minY, c.maxY)
|
||||||
|
}
|
||||||
|
}, "CLAMPMOUSE")
|
||||||
|
|
||||||
|
c.addCardSoftSwitchW(8, func(_ *ioC0Page, value uint8) {
|
||||||
|
if c.trace {
|
||||||
|
fmt.Printf("[cardMouse] HomeMouse(0x%02x)\n", value)
|
||||||
|
}
|
||||||
|
}, "HOMEMOUSE")
|
||||||
|
|
||||||
|
c.addCardSoftSwitchW(0xc, func(_ *ioC0Page, value uint8) {
|
||||||
|
if c.trace {
|
||||||
|
fmt.Printf("[cardMouse] InitMouse()\n")
|
||||||
|
}
|
||||||
|
c.minX = 0
|
||||||
|
c.minY = 0
|
||||||
|
c.maxX = 0x3ff
|
||||||
|
c.maxY = 0x3ff
|
||||||
|
c.mode = 0
|
||||||
|
}, "INITMOUSE")
|
||||||
|
|
||||||
|
c.addCardSoftSwitchW(8, func(_ *ioC0Page, value uint8) {
|
||||||
|
if c.trace {
|
||||||
|
fmt.Printf("[cardMouse] TimeData(%v)\n", value)
|
||||||
|
}
|
||||||
|
}, "TIMEDATEMOUSE")
|
||||||
|
|
||||||
|
data := buildBaseInOutRom(slot)
|
||||||
|
c.romCsxx = newMemoryRangeROM(0xC200, data[:], "Mouse card")
|
||||||
|
|
||||||
|
// Identification as a mouse card
|
||||||
|
// From Technical Note Misc #8, "Pascal 1.1 Firmware Protocol ID Bytes":
|
||||||
|
data[0x05] = 0x38
|
||||||
|
data[0x07] = 0x18
|
||||||
|
data[0x0b] = 0x01
|
||||||
|
data[0x0c] = 0x20
|
||||||
|
// From "AppleMouse // User's Manual", Appendix B:
|
||||||
|
//data[0x0c] = 0x20
|
||||||
|
data[0xfb] = 0xd6
|
||||||
|
|
||||||
|
// Set 8 entrypoints to sofstwitches 2 to 1f
|
||||||
|
for i := uint8(0); i < 14; i++ {
|
||||||
|
base := 0x60 + 0x05*i
|
||||||
|
data[0x12+i] = base
|
||||||
|
data[base+0] = 0x8D // STA $C0x2
|
||||||
|
data[base+1] = 0x82 + i + uint8(slot<<4)
|
||||||
|
data[base+2] = 0xC0
|
||||||
|
data[base+3] = 0x18 // CLC ;no error
|
||||||
|
data[base+4] = 0x60 // RTS
|
||||||
|
}
|
||||||
|
|
||||||
|
c.cardBase.assign(a, slot)
|
||||||
|
}
|
|
@ -47,6 +47,9 @@ func sdlRun(a *izapple2.Apple2) {
|
||||||
j := newSDLJoysticks(true)
|
j := newSDLJoysticks(true)
|
||||||
a.SetJoysticksProvider(j)
|
a.SetJoysticksProvider(j)
|
||||||
|
|
||||||
|
m := newSDLMouse()
|
||||||
|
a.SetMouseProvider(m)
|
||||||
|
|
||||||
go a.Run()
|
go a.Run()
|
||||||
|
|
||||||
paused := false
|
paused := false
|
||||||
|
@ -69,8 +72,10 @@ func sdlRun(a *izapple2.Apple2) {
|
||||||
case *sdl.MouseMotionEvent:
|
case *sdl.MouseMotionEvent:
|
||||||
w, h := window.GetSize()
|
w, h := window.GetSize()
|
||||||
j.putMouseMotionEvent(t, w, h)
|
j.putMouseMotionEvent(t, w, h)
|
||||||
|
m.putMouseMotionEvent(t, w, h)
|
||||||
case *sdl.MouseButtonEvent:
|
case *sdl.MouseButtonEvent:
|
||||||
j.putMouseButtonEvent(t)
|
j.putMouseButtonEvent(t)
|
||||||
|
m.putMouseButtonEvent(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
33
frontend/a2sdl/sdlMouse.go
Normal file
33
frontend/a2sdl/sdlMouse.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
|
)
|
||||||
|
|
||||||
|
type sdlMouse struct {
|
||||||
|
x uint16
|
||||||
|
y uint16
|
||||||
|
pressed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSDLMouse() *sdlMouse {
|
||||||
|
var m sdlMouse
|
||||||
|
return &m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *sdlMouse) putMouseMotionEvent(e *sdl.MouseMotionEvent, width int32, height int32) {
|
||||||
|
m.x = uint16(65536 * e.X / width)
|
||||||
|
m.y = uint16(65536 * e.Y / height)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *sdlMouse) putMouseButtonEvent(e *sdl.MouseButtonEvent) {
|
||||||
|
if e.Button == 1 { // BUTTTON_LEFT
|
||||||
|
m.pressed = e.State == sdl.PRESSED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *sdlMouse) ReadMouse() (x uint16, y uint16, pressed bool) {
|
||||||
|
return m.x, m.y, m.pressed
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: SDL_WarpMouseInWindow
|
12
ioC0Page.go
12
ioC0Page.go
|
@ -14,6 +14,7 @@ type ioC0Page struct {
|
||||||
speaker SpeakerProvider
|
speaker SpeakerProvider
|
||||||
paddlesStrobeCycle uint64
|
paddlesStrobeCycle uint64
|
||||||
joysticks JoysticksProvider
|
joysticks JoysticksProvider
|
||||||
|
mouse MouseProvider
|
||||||
apple2 *Apple2
|
apple2 *Apple2
|
||||||
trace bool
|
trace bool
|
||||||
traceRegistrations bool
|
traceRegistrations bool
|
||||||
|
@ -29,12 +30,17 @@ type SpeakerProvider interface {
|
||||||
Click(cycle uint64)
|
Click(cycle uint64)
|
||||||
}
|
}
|
||||||
|
|
||||||
// JoysticksProvider declares de the joysticks
|
// JoysticksProvider abstracts the joysticks
|
||||||
type JoysticksProvider interface {
|
type JoysticksProvider interface {
|
||||||
ReadButton(i int) bool
|
ReadButton(i int) bool
|
||||||
ReadPaddle(i int) (uint8, bool)
|
ReadPaddle(i int) (uint8, bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MouseProvider abstracts the mouse
|
||||||
|
type MouseProvider interface {
|
||||||
|
ReadMouse() (x uint16, y uint16, pressed bool)
|
||||||
|
}
|
||||||
|
|
||||||
// See https://www.kreativekorp.com/miscpages/a2info/iomemory.shtml
|
// See https://www.kreativekorp.com/miscpages/a2info/iomemory.shtml
|
||||||
// See https://stason.org/TULARC/pc/apple2/programmer/004-I-d-like-to-do-some-serious-Apple-II-programming-Whe.html
|
// See https://stason.org/TULARC/pc/apple2/programmer/004-I-d-like-to-do-some-serious-Apple-II-programming-Whe.html
|
||||||
|
|
||||||
|
@ -100,6 +106,10 @@ func (p *ioC0Page) setJoysticksProvider(j JoysticksProvider) {
|
||||||
p.joysticks = j
|
p.joysticks = j
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *ioC0Page) setMouseProvider(m MouseProvider) {
|
||||||
|
p.mouse = m
|
||||||
|
}
|
||||||
|
|
||||||
func (p *ioC0Page) peek(address uint16) uint8 {
|
func (p *ioC0Page) peek(address uint16) uint8 {
|
||||||
pageAddress := uint8(address)
|
pageAddress := uint8(address)
|
||||||
ss := p.softSwitchesR[pageAddress]
|
ss := p.softSwitchesR[pageAddress]
|
||||||
|
|
|
@ -216,7 +216,12 @@ func (mmu *memoryManager) Peek(address uint16) uint8 {
|
||||||
if mh == nil {
|
if mh == nil {
|
||||||
return 0xf4 // Or some random number
|
return 0xf4 // Or some random number
|
||||||
}
|
}
|
||||||
return mh.peek(address)
|
value := mh.peek(address)
|
||||||
|
//if address >= 0xc400 && address < 0xc500 {
|
||||||
|
// fmt.Printf("[MMU] Peek at %04x: %02x\n", address, value)
|
||||||
|
//}
|
||||||
|
|
||||||
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
// Peek returns the data on the given address optimized for more local requests
|
// Peek returns the data on the given address optimized for more local requests
|
||||||
|
@ -237,7 +242,13 @@ func (mmu *memoryManager) PeekCode(address uint16) uint8 {
|
||||||
if mh == nil {
|
if mh == nil {
|
||||||
return 0xf4 // Or some random number
|
return 0xf4 // Or some random number
|
||||||
}
|
}
|
||||||
return mh.peek(address)
|
|
||||||
|
value := mh.peek(address)
|
||||||
|
//if address >= 0xc400 && address < 0xc500 {
|
||||||
|
// fmt.Printf("[MMU] PeekCode at %04x: %02x\n", address, value)
|
||||||
|
//}
|
||||||
|
|
||||||
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
// Poke sets the data at the given address
|
// Poke sets the data at the given address
|
||||||
|
@ -246,6 +257,10 @@ func (mmu *memoryManager) Poke(address uint16, value uint8) {
|
||||||
if mh != nil {
|
if mh != nil {
|
||||||
mh.poke(address, value)
|
mh.poke(address, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//if address >= 0x0036 && address <= 0x0039 {
|
||||||
|
// fmt.Printf("[MMU] Poke at %04x: %02x\n", address, value)
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Memory initialization
|
// Memory initialization
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user