diff --git a/apple2/ansiConsoleFrontend.go b/apple2/ansiConsoleFrontend.go index b37817c..1b0b780 100644 --- a/apple2/ansiConsoleFrontend.go +++ b/apple2/ansiConsoleFrontend.go @@ -102,7 +102,7 @@ func (fe *ansiConsoleFrontend) textModeGoRoutine() { // See "Understand the Apple II", page 5-10 // http://www.applelogic.org/files/UNDERSTANDINGTHEAII.pdf - isAltText := fe.apple2.isApple2e && fe.apple2.ioPage.isSoftSwitchExtActive(ioFlagAltChar) + isAltText := fe.apple2.isApple2e && fe.apple2.io.isSoftSwitchExtActive(ioFlagAltChar) var i, j, h, c uint8 // Top, middle and botton screen for i = 0; i < 120; i = i + 40 { diff --git a/apple2/apple2.go b/apple2/apple2.go index 21702ed..26e4a3d 100644 --- a/apple2/apple2.go +++ b/apple2/apple2.go @@ -6,12 +6,14 @@ import ( "os" ) +// Apple2 represents all the components and state of the emulated machine type Apple2 struct { cpu *core6502.State mmu *memoryManager + io *ioC0Page + cards []cardBase isApple2e bool - ioPage *ioC0Page // 0xc000 to 0xc080 - activeSlot int // Slot that has the addressing 0xc800 to 0ccfff + activeSlot int // Slot that has the addressing 0xc800 to 0ccfff } // NewApple2 instantiates an apple2 @@ -23,17 +25,26 @@ func NewApple2(romFile string) *Apple2 { a.mmu.resetPaging() // Set the io in 0xc000 - a.ioPage = newIoC0Page(&a) - a.mmu.setPage(0xc0, a.ioPage) + a.io = newIoC0Page(&a) + a.mmu.setPage(0xc0, a.io) return &a } +// AddDisk2 insterts a DiskII controller on slot 6 +func (a *Apple2) AddDisk2(diskRomFile string) { + d := newCardDisk2(diskRomFile) + d.cardBase.insert(a, 6) +} + +// Run starts the Apple2 emulation func (a *Apple2) Run(log bool) { // Init frontend fe := newAnsiConsoleFrontend(a) - a.ioPage.setKeyboardProvider(fe) - go fe.textModeGoRoutine() + a.io.setKeyboardProvider(fe) + if !log { + go fe.textModeGoRoutine() + } // Start the processor a.cpu.Reset() diff --git a/apple2/cardBase.go b/apple2/cardBase.go new file mode 100644 index 0000000..4227168 --- /dev/null +++ b/apple2/cardBase.go @@ -0,0 +1,20 @@ +package apple2 + +type cardBase struct { + rom []memoryPage + slot int + ssr [16]softSwitchR + ssw [16]softSwitchW +} + +func (c *cardBase) insert(a *Apple2, slot int) { + c.slot = slot + if slot != 0 && c.rom[0] != nil { + a.mmu.setPage(uint8(0xC0+slot), c.rom[0]) + } + + for i := 0; i < 0x10; i++ { + a.io.addSoftSwitchR(uint8(0xC80+slot*0x10+i), c.ssr[i]) + a.io.addSoftSwitchW(uint8(0xC80+slot*0x10+i), c.ssw[i]) + } +} diff --git a/apple2/cardDisk2.go b/apple2/cardDisk2.go index 47efa54..7dd4e30 100644 --- a/apple2/cardDisk2.go +++ b/apple2/cardDisk2.go @@ -1,13 +1,100 @@ package apple2 -type disk2 struct { - mmu *memoryManager - slot int +import ( + "bufio" + "fmt" + "os" +) + +/* +https://applesaucefdc.com/woz/reference2/ +Good explanation of the softswitches and the phases: +http://yesterbits.com/media/pubs/AppleOrchard/articles/disk-ii-part-1-1983-apr.pdf +*/ + +type cardDisk2 struct { + cardBase + phases [4]bool + power [2]bool + selected int // Only 0 and 1 supported } -func insertCardDisk2(mmu *memoryManager, slot int) disk2 { - var c disk2 - c.mmu = mmu - c.slot = slot - return c +// type softSwitchR func(io *ioC0Page) uint8 + +func newCardDisk2(filename string) *cardDisk2 { + var c cardDisk2 + c.rom = loadCardRom(filename) + + // Phase control soft switches + for i := 0; i < 4; i++ { + c.ssr[i<<1] = func(_ *ioC0Page) uint8 { + fmt.Printf("DISKII: Phase %v off\n", i) + return 0 + } + c.ssr[(i<<1)+1] = func(_ *ioC0Page) uint8 { + fmt.Printf("DISKII: Phase %v on\n", i) + return 0 + } + } + + // Other soft switches + c.ssr[0x8] = func(_ *ioC0Page) uint8 { + c.power[c.selected] = false + fmt.Printf("DISKII: Disk %v is off\n", c.selected) + return 0 + } + c.ssr[0x9] = func(_ *ioC0Page) uint8 { + c.power[c.selected] = true + fmt.Printf("DISKII: Disk %v is on\n", c.selected) + return 0 + } + c.ssr[0xA] = func(_ *ioC0Page) uint8 { + c.selected = 0 + fmt.Printf("DISKII: Disk %v selected\n", c.selected) + return 0 + } + c.ssr[0xB] = func(_ *ioC0Page) uint8 { + c.selected = 1 + fmt.Printf("DISKII: Disk %v selected\n", c.selected) + return 0 + } + + // TODO: missing C, D, E, and F + + return &c +} + +func loadCardRom(filename string) []memoryPage { + f, err := os.Open(filename) + if err != nil { + panic(err) + } + defer f.Close() + + stats, statsErr := f.Stat() + if statsErr != nil { + panic(err) + } + + size := stats.Size() + bytes := make([]byte, size) + buf := bufio.NewReader(f) + buf.Read(bytes) + + pages := size / 256 + if (size % 256) > 0 { + pages++ + } + + rom := make([]romPage, pages) + for i := int64(0); i < size; i++ { + rom[i>>8].burn(uint8(i), bytes[i]) + } + + memPages := make([]memoryPage, pages) + for i := range rom { + memPages[i] = &rom[i] + } + + return memPages } diff --git a/apple2/expansionCard.go b/apple2/expansionCard.go deleted file mode 100644 index b070629..0000000 --- a/apple2/expansionCard.go +++ /dev/null @@ -1,78 +0,0 @@ -package apple2 - -import ( - "bufio" - "os" -) - -type expansionSlots struct { - mmu *memoryManager - cards [7]expansionCard -} - -type expansionCard interface { - insert(es *expansionSlots, slot int) cardBase - activateRom() -} - -type cardBase struct { - es *expansionSlots - rom []romPage - slot int - softSwitchesR [16]softSwitchR - softSwitchesW [16]softSwitchW -} - -/* -https://applesaucefdc.com/woz/reference2/ -http://yesterbits.com/media/pubs/AppleOrchard/articles/disk-ii-part-1-1983-apr.pdf -*/ - -type cardDisk2 struct { - cardBase -} - -func newCardDisk2(filename string) *cardDisk2 { - var c cardDisk2 - c.rom = loadCardRom(filename) - return &c -} - -func (c *cardBase) insert(es *expansionSlots, slot int) { - c.es = es - c.slot = slot - if c.rom != nil { - //rom = c.rom[0] - } - -} - -func loadCardRom(filename string) []romPage { - f, err := os.Open(filename) - if err != nil { - panic(err) - } - defer f.Close() - - stats, statsErr := f.Stat() - if statsErr != nil { - panic(err) - } - - size := stats.Size() - bytes := make([]byte, size) - buf := bufio.NewReader(f) - buf.Read(bytes) - - pages := size / 256 - if (size % 256) > 0 { - pages++ - } - - rom := make([]romPage, pages) - for i := int64(0); i < size; i++ { - rom[i>>8].burn(uint8(i), bytes[i]) - } - - return rom -} diff --git a/apple2/ioC0Page.go b/apple2/ioC0Page.go index cc25f34..189a050 100644 --- a/apple2/ioC0Page.go +++ b/apple2/ioC0Page.go @@ -5,8 +5,8 @@ import ( ) type ioC0Page struct { - softSwitchesR [128]softSwitchR - softSwitchesW [128]softSwitchW + softSwitchesR [256]softSwitchR + softSwitchesW [256]softSwitchW softSwitchesData [128]uint8 keyboard keyboardProvider apple2 *Apple2 diff --git a/apple2/memoryManager.go b/apple2/memoryManager.go index f0645b6..d1fda95 100644 --- a/apple2/memoryManager.go +++ b/apple2/memoryManager.go @@ -55,7 +55,7 @@ func (mmu *memoryManager) setPage(index uint8, page memoryPage) { // When 0xcfff is accessed the card expansion rom is unassigned func (mmu *memoryManager) resetSlotExpansionRoms() { - if mmu.apple2.ioPage.isSoftSwitchExtActive(ioFlagIntCxRom) { + if mmu.apple2.io.isSoftSwitchExtActive(ioFlagIntCxRom) { // Ignore if the Apple2 shadow ROM is active return } diff --git a/apple2/unassignedPage.go b/apple2/unassignedPage.go index 6142807..8cc5a4b 100644 --- a/apple2/unassignedPage.go +++ b/apple2/unassignedPage.go @@ -9,7 +9,7 @@ type unassignedPage struct { func (p *unassignedPage) Peek(address uint8) uint8 { fmt.Printf("Read on address 0x%02x%02x\n", p.page, address) //panic(address) - return 0xcc + return 0xdd } func (p *unassignedPage) Poke(address uint8, value uint8) { diff --git a/main.go b/main.go index 8d57540..5881963 100644 --- a/main.go +++ b/main.go @@ -6,8 +6,10 @@ func main() { //romFile := "apple2/romdumps/Apple2.rom" romFile := "apple2/romdumps/Apple2_Plus.rom" //romFile := "apple2/romdumps/Apple2e.rom" + disk2RomFile := "apple2/romdumps/DISK2.rom" - log := false + log := true a := apple2.NewApple2(romFile) + a.AddDisk2(disk2RomFile) a.Run(log) }