Boots DOS 3.3 using nib format

This commit is contained in:
Ivan Izaguirre 2019-03-05 00:00:12 +01:00
parent 6babe07ea6
commit cc45403b43
5 changed files with 116 additions and 42 deletions

View File

@ -32,9 +32,13 @@ func NewApple2(romFile string) *Apple2 {
}
// AddDisk2 insterts a DiskII controller on slot 6
func (a *Apple2) AddDisk2(diskRomFile string) {
func (a *Apple2) AddDisk2(diskRomFile string, diskImage string) {
d := newCardDisk2(diskRomFile)
d.cardBase.insert(a, 6)
if diskImage != "" {
d.drive[0].loadDisk(diskImage)
}
}
// Run starts the Apple2 emulation

View File

@ -2,7 +2,6 @@ package apple2
import (
"bufio"
"fmt"
"os"
)
@ -10,14 +9,29 @@ import (
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
35 tracks, 16 sectors, 256 bytes
NIB: 35 tracks 6656 bytes, 232960 bytes
*/
const maxHalfTrack = 68
const bytesPerTrack = 6656
const nibImageSize = 35 * bytesPerTrack
type cardDisk2 struct {
cardBase
phases [4]bool
power [2]bool
selected int // Only 0 and 1 supported
writeMode bool
selected int // Only 0 and 1 supported
drive [2]cardDisk2Drive
}
type cardDisk2Drive struct {
isLoaded bool
currentPhase int
power bool
writeMode bool
halfTrack int
position int
data *[]uint8
}
// type softSwitchR func(io *ioC0Page) uint8
@ -27,73 +41,103 @@ func newCardDisk2(filename string) *cardDisk2 {
c.rom = loadCardRom(filename)
// Phase control soft switches
// Lazy emulation. It only checks for phases on and move the head
// up or down depending on the previous phase.
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
}
func(phase int) {
c.ssr[phase<<1] = func(_ *ioC0Page) uint8 {
//fmt.Printf("DISKII: Phase %v off\n", phase)
return 0
}
c.ssr[(phase<<1)+1] = func(_ *ioC0Page) uint8 {
//fmt.Printf("DISKII: Phase %v on\n", phase)
halfTrack := c.drive[c.selected].halfTrack
delta := (phase - c.drive[c.selected].currentPhase + 4) % 4
switch delta {
case 1: // Up
halfTrack++
case 2: // Illegal, let's say up
halfTrack++
case 3: // Down
halfTrack--
case 0: // No chamge
}
if halfTrack > maxHalfTrack {
halfTrack = maxHalfTrack
} else if halfTrack < 0 {
halfTrack = 0
}
c.drive[c.selected].halfTrack = halfTrack
c.drive[c.selected].currentPhase = phase
//fmt.Printf("DISKII: Current halftrack is %v\n", halfTrack)
return 0
}
}(i)
}
// Other soft switches
c.ssr[0x8] = func(_ *ioC0Page) uint8 {
c.power[c.selected] = false
fmt.Printf("DISKII: Disk %v is off\n", c.selected)
c.drive[c.selected].power = 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)
c.drive[c.selected].power = 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)
//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)
//fmt.Printf("DISKII: Disk %v selected\n", c.selected)
return 0
}
var i uint8
// Q6L
c.ssr[0xC] = func(_ *ioC0Page) uint8 {
fmt.Printf("DISKII: Reading\n")
i++
return i
//fmt.Printf("DISKII: Reading\n")
drive := &c.drive[c.selected]
if drive.isLoaded {
track := drive.halfTrack / 2
data := *drive.data
value := data[track*bytesPerTrack+drive.position]
//fmt.Printf("DISKII: Reading value 0x%02v from track %v, position %v\n", value, track, drive.position)
drive.position = (drive.position + 1) % bytesPerTrack
return value
} else {
return 0
}
}
c.ssw[0xC] = func(_ *ioC0Page, value uint8) {
fmt.Printf("DISKII: Writing the value 0x%02x\n", value)
//fmt.Printf("DISKII: Writing the value 0x%02x\n", value)
}
// Q6H
c.ssr[0xD] = func(_ *ioC0Page) uint8 {
c.writeMode = false
fmt.Printf("DISKII: Sense write protection\n")
c.drive[c.selected].writeMode = false
//fmt.Printf("DISKII: Sense write protection\n")
return 0
}
// Q7L
c.ssr[0xE] = func(_ *ioC0Page) uint8 {
c.writeMode = false
fmt.Printf("DISKII: Set read mode\n")
c.drive[c.selected].writeMode = false
//fmt.Printf("DISKII: Set read mode\n")
return 0
}
// Q7H
c.ssr[0xF] = func(_ *ioC0Page) uint8 {
c.writeMode = true
fmt.Printf("DISKII: Set write mode\n")
c.drive[c.selected].writeMode = true
//fmt.Printf("DISKII: Set write mode\n")
return 0
}
// TODO: missing C, D, E, and F
return &c
}
@ -131,3 +175,28 @@ func loadCardRom(filename string) []memoryPage {
return memPages
}
func (d *cardDisk2Drive) loadDisk(filename string) {
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()
if size != nibImageSize {
panic("Disk size with nib format has to be 232960 bytes")
}
bytes := make([]uint8, size)
buf := bufio.NewReader(f)
buf.Read(bytes)
d.data = &bytes
d.isLoaded = true
}

View File

@ -72,7 +72,8 @@ func (p *ioC0Page) Peek(address uint8) uint8 {
//fmt.Printf("Peek on $C0%02x ", address)
ss := p.softSwitchesR[address]
if ss == nil {
panic(fmt.Sprintf("Unknown softswitch on read to 0xC0%02x", address))
//panic(fmt.Sprintf("Unknown softswitch on read to 0xC0%02x", address))
return 0
}
return ss(p)
@ -82,7 +83,8 @@ func (p *ioC0Page) Poke(address uint8, value uint8) {
//fmt.Printf("Poke on $C0%02x with %02x ", address, value)
ss := p.softSwitchesW[address]
if ss == nil {
panic(fmt.Sprintf("Unknown softswitch on write to 0xC0%02x", address))
//panic(fmt.Sprintf("Unknown softswitch on write to 0xC0%02x", address))
return
}
ss(p, value)
}

View File

@ -1,18 +1,16 @@
package apple2
import "fmt"
type unassignedPage struct {
page 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)
return 0xdd
}
func (p *unassignedPage) Poke(address uint8, value uint8) {
fmt.Printf("Write on address 0x%02x%02x\n", p.page, address)
//fmt.Printf("Write on address 0x%02x%02x\n", p.page, address)
//panic(address)
}

View File

@ -6,10 +6,11 @@ func main() {
//romFile := "apple2/romdumps/Apple2.rom"
romFile := "apple2/romdumps/Apple2_Plus.rom"
//romFile := "apple2/romdumps/Apple2e.rom"
//disk2RomFile := "apple2/romdumps/DISK2.rom"
disk2RomFile := "apple2/romdumps/DISK2.rom"
diskImage := "../dos33.nib"
log := true
log := false
a := apple2.NewApple2(romFile)
//a.AddDisk2(disk2RomFile)
a.AddDisk2(disk2RomFile, diskImage)
a.Run(log)
}