mirror of
https://github.com/ivanizag/izapple2.git
synced 2024-12-21 18:29:45 +00:00
Boots DOS 3.3 using nib format
This commit is contained in:
parent
6babe07ea6
commit
cc45403b43
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
7
main.go
7
main.go
@ -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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user