First changes for disk support
This commit is contained in:
parent
5b186f9b15
commit
84f45d9f99
|
@ -102,7 +102,7 @@ func (fe *ansiConsoleFrontend) textModeGoRoutine() {
|
||||||
|
|
||||||
// See "Understand the Apple II", page 5-10
|
// See "Understand the Apple II", page 5-10
|
||||||
// http://www.applelogic.org/files/UNDERSTANDINGTHEAII.pdf
|
// 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
|
var i, j, h, c uint8
|
||||||
// Top, middle and botton screen
|
// Top, middle and botton screen
|
||||||
for i = 0; i < 120; i = i + 40 {
|
for i = 0; i < 120; i = i + 40 {
|
||||||
|
|
|
@ -6,12 +6,14 @@ import (
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Apple2 represents all the components and state of the emulated machine
|
||||||
type Apple2 struct {
|
type Apple2 struct {
|
||||||
cpu *core6502.State
|
cpu *core6502.State
|
||||||
mmu *memoryManager
|
mmu *memoryManager
|
||||||
|
io *ioC0Page
|
||||||
|
cards []cardBase
|
||||||
isApple2e bool
|
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
|
// NewApple2 instantiates an apple2
|
||||||
|
@ -23,17 +25,26 @@ func NewApple2(romFile string) *Apple2 {
|
||||||
a.mmu.resetPaging()
|
a.mmu.resetPaging()
|
||||||
|
|
||||||
// Set the io in 0xc000
|
// Set the io in 0xc000
|
||||||
a.ioPage = newIoC0Page(&a)
|
a.io = newIoC0Page(&a)
|
||||||
a.mmu.setPage(0xc0, a.ioPage)
|
a.mmu.setPage(0xc0, a.io)
|
||||||
|
|
||||||
return &a
|
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) {
|
func (a *Apple2) Run(log bool) {
|
||||||
// Init frontend
|
// Init frontend
|
||||||
fe := newAnsiConsoleFrontend(a)
|
fe := newAnsiConsoleFrontend(a)
|
||||||
a.ioPage.setKeyboardProvider(fe)
|
a.io.setKeyboardProvider(fe)
|
||||||
go fe.textModeGoRoutine()
|
if !log {
|
||||||
|
go fe.textModeGoRoutine()
|
||||||
|
}
|
||||||
|
|
||||||
// Start the processor
|
// Start the processor
|
||||||
a.cpu.Reset()
|
a.cpu.Reset()
|
||||||
|
|
|
@ -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])
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,100 @@
|
||||||
package apple2
|
package apple2
|
||||||
|
|
||||||
type disk2 struct {
|
import (
|
||||||
mmu *memoryManager
|
"bufio"
|
||||||
slot int
|
"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 {
|
// type softSwitchR func(io *ioC0Page) uint8
|
||||||
var c disk2
|
|
||||||
c.mmu = mmu
|
func newCardDisk2(filename string) *cardDisk2 {
|
||||||
c.slot = slot
|
var c cardDisk2
|
||||||
return c
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type ioC0Page struct {
|
type ioC0Page struct {
|
||||||
softSwitchesR [128]softSwitchR
|
softSwitchesR [256]softSwitchR
|
||||||
softSwitchesW [128]softSwitchW
|
softSwitchesW [256]softSwitchW
|
||||||
softSwitchesData [128]uint8
|
softSwitchesData [128]uint8
|
||||||
keyboard keyboardProvider
|
keyboard keyboardProvider
|
||||||
apple2 *Apple2
|
apple2 *Apple2
|
||||||
|
|
|
@ -55,7 +55,7 @@ func (mmu *memoryManager) setPage(index uint8, page memoryPage) {
|
||||||
|
|
||||||
// When 0xcfff is accessed the card expansion rom is unassigned
|
// When 0xcfff is accessed the card expansion rom is unassigned
|
||||||
func (mmu *memoryManager) resetSlotExpansionRoms() {
|
func (mmu *memoryManager) resetSlotExpansionRoms() {
|
||||||
if mmu.apple2.ioPage.isSoftSwitchExtActive(ioFlagIntCxRom) {
|
if mmu.apple2.io.isSoftSwitchExtActive(ioFlagIntCxRom) {
|
||||||
// Ignore if the Apple2 shadow ROM is active
|
// Ignore if the Apple2 shadow ROM is active
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ type unassignedPage struct {
|
||||||
func (p *unassignedPage) Peek(address uint8) uint8 {
|
func (p *unassignedPage) Peek(address uint8) uint8 {
|
||||||
fmt.Printf("Read on address 0x%02x%02x\n", p.page, address)
|
fmt.Printf("Read on address 0x%02x%02x\n", p.page, address)
|
||||||
//panic(address)
|
//panic(address)
|
||||||
return 0xcc
|
return 0xdd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *unassignedPage) Poke(address uint8, value uint8) {
|
func (p *unassignedPage) Poke(address uint8, value uint8) {
|
||||||
|
|
4
main.go
4
main.go
|
@ -6,8 +6,10 @@ func main() {
|
||||||
//romFile := "apple2/romdumps/Apple2.rom"
|
//romFile := "apple2/romdumps/Apple2.rom"
|
||||||
romFile := "apple2/romdumps/Apple2_Plus.rom"
|
romFile := "apple2/romdumps/Apple2_Plus.rom"
|
||||||
//romFile := "apple2/romdumps/Apple2e.rom"
|
//romFile := "apple2/romdumps/Apple2e.rom"
|
||||||
|
disk2RomFile := "apple2/romdumps/DISK2.rom"
|
||||||
|
|
||||||
log := false
|
log := true
|
||||||
a := apple2.NewApple2(romFile)
|
a := apple2.NewApple2(romFile)
|
||||||
|
a.AddDisk2(disk2RomFile)
|
||||||
a.Run(log)
|
a.Run(log)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue