mirror of
https://github.com/ivanizag/izapple2.git
synced 2024-12-22 09:30:19 +00:00
Apple IIe rom boots with all the ROM shadowing in place.
This commit is contained in:
parent
d2c897f7ea
commit
645c37049f
@ -8,6 +8,15 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Uses the console standard input and output to interface with the machine.
|
||||||
|
Input is buffered until the next CR. This avoids working in place, a line
|
||||||
|
for input is added at the end.
|
||||||
|
Outut is done in place using ANSI escape sequences.
|
||||||
|
|
||||||
|
Those tricks do not work with the Apple2e ROM
|
||||||
|
*/
|
||||||
|
|
||||||
type ansiConsoleFrontend struct {
|
type ansiConsoleFrontend struct {
|
||||||
keyChannel chan uint8
|
keyChannel chan uint8
|
||||||
extraLineFeeds chan int
|
extraLineFeeds chan int
|
||||||
@ -100,6 +109,7 @@ func (fe *ansiConsoleFrontend) textModeGoRoutine(tp *textPages) {
|
|||||||
func textMemoryByteToString(value uint8) string {
|
func textMemoryByteToString(value uint8) string {
|
||||||
// See https://en.wikipedia.org/wiki/Apple_II_character_set
|
// See https://en.wikipedia.org/wiki/Apple_II_character_set
|
||||||
// Only ascii from 0x20 to 0x5F is visible
|
// Only ascii from 0x20 to 0x5F is visible
|
||||||
|
// Does not support the new lowercase characters in the Apple2e
|
||||||
topBits := value >> 6
|
topBits := value >> 6
|
||||||
isInverse := topBits == 0
|
isInverse := topBits == 0
|
||||||
isFlash := topBits == 1
|
isFlash := topBits == 1
|
||||||
|
@ -21,8 +21,14 @@ type keyboardProvider interface {
|
|||||||
// 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
|
||||||
|
|
||||||
|
const (
|
||||||
|
ssOn uint8 = 0x80
|
||||||
|
ssOff uint8 = 0x00
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ioDataKeyboard uint8 = 0x10
|
ioDataKeyboard uint8 = 0x10
|
||||||
|
|
||||||
ioFlagGraphics uint8 = 0x50
|
ioFlagGraphics uint8 = 0x50
|
||||||
ioFlagMixed uint8 = 0x52
|
ioFlagMixed uint8 = 0x52
|
||||||
ioFlagSecondPage uint8 = 0x54
|
ioFlagSecondPage uint8 = 0x54
|
||||||
@ -31,10 +37,19 @@ const (
|
|||||||
ioFlagAnnunciator1 uint8 = 0x5a
|
ioFlagAnnunciator1 uint8 = 0x5a
|
||||||
ioFlagAnnunciator2 uint8 = 0x5c
|
ioFlagAnnunciator2 uint8 = 0x5c
|
||||||
ioFlagAnnunciator3 uint8 = 0x5e
|
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
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *ioC0Page) isSoftSwitchExtActive(ioFlag uint8) bool {
|
func (p *ioC0Page) isSoftSwitchExtActive(ioFlag uint8) bool {
|
||||||
return (p.softSwitchesData[ioFlag] & 0x08) == 0x80
|
return (p.softSwitchesData[ioFlag] & ssOn) == ssOn
|
||||||
}
|
}
|
||||||
|
|
||||||
func newIoC0Page(mmu *memoryManager) *ioC0Page {
|
func newIoC0Page(mmu *memoryManager) *ioC0Page {
|
||||||
@ -44,7 +59,12 @@ func newIoC0Page(mmu *memoryManager) *ioC0Page {
|
|||||||
|
|
||||||
ss[0x00] = getKeySoftSwitch // Keyboard
|
ss[0x00] = getKeySoftSwitch // Keyboard
|
||||||
ss[0x10] = strobeKeyboardSoftSwitch // Keyboard Strobe
|
ss[0x10] = strobeKeyboardSoftSwitch // Keyboard Strobe
|
||||||
|
ss[0x20] = notImplementedSoftSwitch // Cassette Output
|
||||||
ss[0x30] = notImplementedSoftSwitch // Speaker
|
ss[0x30] = notImplementedSoftSwitch // Speaker
|
||||||
|
ss[0x40] = notImplementedSoftSwitch // Game connector Strobe
|
||||||
|
// Note: Some sources indicate that all these cover 16 positions
|
||||||
|
// for read and write. But the Apple2e take over some of them, with
|
||||||
|
// the prevention on acting only on writes.
|
||||||
|
|
||||||
ss[0x50] = getSoftSwitch(ioFlagGraphics, false)
|
ss[0x50] = getSoftSwitch(ioFlagGraphics, false)
|
||||||
ss[0x51] = getSoftSwitch(ioFlagGraphics, true)
|
ss[0x51] = getSoftSwitch(ioFlagGraphics, true)
|
||||||
@ -63,6 +83,24 @@ func newIoC0Page(mmu *memoryManager) *ioC0Page {
|
|||||||
ss[0x5e] = getSoftSwitch(ioFlagAnnunciator3, false)
|
ss[0x5e] = getSoftSwitch(ioFlagAnnunciator3, false)
|
||||||
ss[0x5f] = getSoftSwitch(ioFlagAnnunciator3, true)
|
ss[0x5f] = getSoftSwitch(ioFlagAnnunciator3, true)
|
||||||
|
|
||||||
|
ss[0x60] = notImplementedSoftSwitch // Cassetter Input
|
||||||
|
ss[0x61] = getStatusSoftSwitch(ioFlagButton0)
|
||||||
|
ss[0x62] = getStatusSoftSwitch(ioFlagButton1)
|
||||||
|
ss[0x63] = getStatusSoftSwitch(ioFlagButton2)
|
||||||
|
ss[0x64] = getStatusSoftSwitch(ioDataPaddle0)
|
||||||
|
ss[0x65] = getStatusSoftSwitch(ioDataPaddle1)
|
||||||
|
ss[0x66] = getStatusSoftSwitch(ioDataPaddle2)
|
||||||
|
ss[0x67] = getStatusSoftSwitch(ioDataPaddle3)
|
||||||
|
ss[0x68] = ss[0x60]
|
||||||
|
ss[0x69] = ss[0x61]
|
||||||
|
ss[0x6A] = ss[0x62]
|
||||||
|
ss[0x6B] = ss[0x63]
|
||||||
|
ss[0x6C] = ss[0x64]
|
||||||
|
ss[0x6D] = ss[0x65]
|
||||||
|
ss[0x6E] = ss[0x66]
|
||||||
|
ss[0x6F] = ss[0x67]
|
||||||
|
ss[0x70] = notImplementedSoftSwitch // Game controllers reset
|
||||||
|
|
||||||
return &p
|
return &p
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,8 +119,8 @@ func (p *ioC0Page) Poke(address uint8, value uint8) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *ioC0Page) access(address uint8, isWrite bool, value uint8) uint8 {
|
func (p *ioC0Page) access(address uint8, isWrite bool, value uint8) uint8 {
|
||||||
// The second hals of the pages is reserved for slots
|
// The second half of the pages is reserved for slots
|
||||||
if address >= 0x80 {
|
if address >= 0x90 {
|
||||||
// TODO reserved slots data
|
// TODO reserved slots data
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@ -95,12 +133,18 @@ func (p *ioC0Page) access(address uint8, isWrite bool, value uint8) uint8 {
|
|||||||
return ss(p, isWrite, value)
|
return ss(p, isWrite, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getStatusSoftSwitch(ioFlag uint8) softSwitch {
|
||||||
|
return func(io *ioC0Page, isWrite bool, value uint8) uint8 {
|
||||||
|
return io.softSwitchesData[ioFlag]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func getSoftSwitch(ioFlag uint8, isSet bool) softSwitch {
|
func getSoftSwitch(ioFlag uint8, isSet bool) softSwitch {
|
||||||
return func(io *ioC0Page, isWrite bool, value uint8) uint8 {
|
return func(io *ioC0Page, isWrite bool, value uint8) uint8 {
|
||||||
if isSet {
|
if isSet {
|
||||||
io.softSwitchesData[ioFlag] = 0x80
|
io.softSwitchesData[ioFlag] = ssOn
|
||||||
} else {
|
} else {
|
||||||
io.softSwitchesData[ioFlag] = 0
|
io.softSwitchesData[ioFlag] = ssOff
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
package apple2
|
package apple2
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
// memoryPage is a data page of 256 bytes
|
// memoryPage is a data page of 256 bytes
|
||||||
type memoryPage interface {
|
type memoryPage interface {
|
||||||
Peek(uint8) uint8
|
Peek(uint8) uint8
|
||||||
@ -32,6 +27,6 @@ func (m *pagedMemory) Poke(address uint16, value uint8) {
|
|||||||
|
|
||||||
// SetPage assigns a MemoryPage implementation on the page given
|
// SetPage assigns a MemoryPage implementation on the page given
|
||||||
func (m *pagedMemory) SetPage(index uint8, page memoryPage) {
|
func (m *pagedMemory) SetPage(index uint8, page memoryPage) {
|
||||||
fmt.Printf("Assigning page 0x%02x type %s\n", index, reflect.TypeOf(page))
|
//fmt.Printf("Assigning page 0x%02x type %s\n", index, reflect.TypeOf(page))
|
||||||
m.data[index] = page
|
m.data[index] = page
|
||||||
}
|
}
|
||||||
|
@ -1,45 +1,46 @@
|
|||||||
package apple2
|
package apple2
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ioFlagIntCxRom uint8 = 0x15
|
ioFlagIntCxRom uint8 = 0x15
|
||||||
ioFlagSlotC3Rom uint8 = 0x17
|
ioFlagSlotC3Rom uint8 = 0x17
|
||||||
|
ioFlag80Store uint8 = 0x18
|
||||||
|
ioFlag80Col uint8 = 0x1F
|
||||||
)
|
)
|
||||||
|
|
||||||
func addApple2ESoftSwitches(mmu *memoryManager) {
|
func addApple2ESoftSwitches(mmu *memoryManager) {
|
||||||
ss := &mmu.ioPage.softSwitches
|
ss := &mmu.ioPage.softSwitches
|
||||||
ss[0x06] = getSoftSwitchExt(ioFlagIntCxRom, 0x00, softSwitchIntCxRomOff)
|
|
||||||
ss[0x07] = getSoftSwitchExt(ioFlagIntCxRom, 0x80, softSwitchIntCxRomOn)
|
|
||||||
ss[0x15] = getStatusSoftSwitchExt(ioFlagIntCxRom)
|
|
||||||
|
|
||||||
ss[0x0A] = getSoftSwitchExt(ioFlagSlotC3Rom, 0x00, softSwitchSlotC3RomOff)
|
ss[0x00] = getSoftSwitchExt(ioFlag80Store, ssOff, nil)
|
||||||
ss[0x0B] = getSoftSwitchExt(ioFlagSlotC3Rom, 0x80, softSwitchSlotC3RomOn)
|
ss[0x01] = getSoftSwitchExt(ioFlag80Store, ssOn, nil)
|
||||||
ss[0x17] = getStatusSoftSwitchExt(ioFlagSlotC3Rom)
|
ss[0x06] = getSoftSwitchExt(ioFlagIntCxRom, ssOff, softSwitchIntCxRomOff)
|
||||||
|
ss[0x07] = getSoftSwitchExt(ioFlagIntCxRom, ssOn, softSwitchIntCxRomOn)
|
||||||
ss[0x1c] = getStatusSoftSwitchExt(ioFlagSecondPage)
|
ss[0x0A] = getSoftSwitchExt(ioFlagSlotC3Rom, ssOff, softSwitchSlotC3RomOff)
|
||||||
|
ss[0x0B] = getSoftSwitchExt(ioFlagSlotC3Rom, ssOn, softSwitchSlotC3RomOn)
|
||||||
|
ss[0x0C] = getSoftSwitchExt(ioFlag80Col, ssOff, nil)
|
||||||
|
ss[0x0D] = getSoftSwitchExt(ioFlag80Col, ssOn, nil)
|
||||||
|
|
||||||
|
ss[0x15] = getStatusSoftSwitch(ioFlagIntCxRom)
|
||||||
|
ss[0x17] = getStatusSoftSwitch(ioFlagSlotC3Rom)
|
||||||
|
ss[0x18] = getStatusSoftSwitch(ioFlag80Store)
|
||||||
|
ss[0x1C] = getStatusSoftSwitch(ioFlagSecondPage)
|
||||||
|
ss[0x1F] = getStatusSoftSwitch(ioFlag80Col)
|
||||||
}
|
}
|
||||||
|
|
||||||
type softSwitchExtAction func(io *ioC0Page)
|
type softSwitchExtAction func(io *ioC0Page)
|
||||||
|
|
||||||
func getStatusSoftSwitchExt(ioFlag uint8) softSwitch {
|
|
||||||
return func(io *ioC0Page, isWrite bool, value uint8) uint8 {
|
|
||||||
return io.softSwitchesData[ioFlag]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSoftSwitchExt(ioFlag uint8, dstValue uint8, action softSwitchExtAction) softSwitch {
|
func getSoftSwitchExt(ioFlag uint8, dstValue uint8, action softSwitchExtAction) softSwitch {
|
||||||
return func(io *ioC0Page, isWrite bool, value uint8) uint8 {
|
return func(io *ioC0Page, isWrite bool, value uint8) uint8 {
|
||||||
fmt.Printf("Softswitch 0x%02x %v %v\n", ioFlag, isWrite, dstValue)
|
//fmt.Printf("Softswitch 0x%02x %v %v\n", ioFlag, isWrite, dstValue)
|
||||||
if !isWrite {
|
if !isWrite {
|
||||||
return 0 // Ignore reads
|
return 0 // New Apple2e softswitches ignore reads
|
||||||
}
|
}
|
||||||
currentValue := io.softSwitchesData[ioFlag]
|
currentValue := io.softSwitchesData[ioFlag]
|
||||||
if currentValue == dstValue {
|
if currentValue == dstValue {
|
||||||
return 0 // Already switched, ignore
|
return 0 // Already switched, ignore
|
||||||
}
|
}
|
||||||
|
if action != nil {
|
||||||
action(io)
|
action(io)
|
||||||
|
}
|
||||||
io.softSwitchesData[ioFlag] = value
|
io.softSwitchesData[ioFlag] = value
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@ -53,7 +54,7 @@ func softSwitchIntCxRomOn(io *ioC0Page) {
|
|||||||
|
|
||||||
func softSwitchIntCxRomOff(io *ioC0Page) {
|
func softSwitchIntCxRomOff(io *ioC0Page) {
|
||||||
// TODO restore all the ROM from the slot for 0xc1 to 0xc7
|
// TODO restore all the ROM from the slot for 0xc1 to 0xc7
|
||||||
for i := 1; i <= 16; i++ {
|
for i := 1; i < 16; i++ {
|
||||||
io.mmu.activeMemory.SetPage(uint8(0xc0+i), &io.mmu.unassignedExpansionROM[i])
|
io.mmu.activeMemory.SetPage(uint8(0xc0+i), &io.mmu.unassignedExpansionROM[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user