mirror of
https://github.com/ivanizag/izapple2.git
synced 2024-12-22 09:30:19 +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
|
// 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 := newCardDisk2(diskRomFile)
|
||||||
d.cardBase.insert(a, 6)
|
d.cardBase.insert(a, 6)
|
||||||
|
|
||||||
|
if diskImage != "" {
|
||||||
|
d.drive[0].loadDisk(diskImage)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run starts the Apple2 emulation
|
// Run starts the Apple2 emulation
|
||||||
|
@ -2,7 +2,6 @@ package apple2
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -10,14 +9,29 @@ import (
|
|||||||
https://applesaucefdc.com/woz/reference2/
|
https://applesaucefdc.com/woz/reference2/
|
||||||
Good explanation of the softswitches and the phases:
|
Good explanation of the softswitches and the phases:
|
||||||
http://yesterbits.com/media/pubs/AppleOrchard/articles/disk-ii-part-1-1983-apr.pdf
|
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 {
|
type cardDisk2 struct {
|
||||||
cardBase
|
cardBase
|
||||||
phases [4]bool
|
selected int // Only 0 and 1 supported
|
||||||
power [2]bool
|
drive [2]cardDisk2Drive
|
||||||
selected int // Only 0 and 1 supported
|
}
|
||||||
writeMode bool
|
|
||||||
|
type cardDisk2Drive struct {
|
||||||
|
isLoaded bool
|
||||||
|
currentPhase int
|
||||||
|
power bool
|
||||||
|
writeMode bool
|
||||||
|
halfTrack int
|
||||||
|
position int
|
||||||
|
data *[]uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
// type softSwitchR func(io *ioC0Page) uint8
|
// type softSwitchR func(io *ioC0Page) uint8
|
||||||
@ -27,73 +41,103 @@ func newCardDisk2(filename string) *cardDisk2 {
|
|||||||
c.rom = loadCardRom(filename)
|
c.rom = loadCardRom(filename)
|
||||||
|
|
||||||
// Phase control soft switches
|
// 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++ {
|
for i := 0; i < 4; i++ {
|
||||||
c.ssr[i<<1] = func(_ *ioC0Page) uint8 {
|
func(phase int) {
|
||||||
fmt.Printf("DISKII: Phase %v off\n", i)
|
c.ssr[phase<<1] = func(_ *ioC0Page) uint8 {
|
||||||
return 0
|
//fmt.Printf("DISKII: Phase %v off\n", phase)
|
||||||
}
|
return 0
|
||||||
c.ssr[(i<<1)+1] = func(_ *ioC0Page) uint8 {
|
}
|
||||||
fmt.Printf("DISKII: Phase %v on\n", i)
|
c.ssr[(phase<<1)+1] = func(_ *ioC0Page) uint8 {
|
||||||
return 0
|
//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
|
// Other soft switches
|
||||||
c.ssr[0x8] = func(_ *ioC0Page) uint8 {
|
c.ssr[0x8] = func(_ *ioC0Page) uint8 {
|
||||||
c.power[c.selected] = false
|
c.drive[c.selected].power = false
|
||||||
fmt.Printf("DISKII: Disk %v is off\n", c.selected)
|
//fmt.Printf("DISKII: Disk %v is off\n", c.selected)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
c.ssr[0x9] = func(_ *ioC0Page) uint8 {
|
c.ssr[0x9] = func(_ *ioC0Page) uint8 {
|
||||||
c.power[c.selected] = true
|
c.drive[c.selected].power = true
|
||||||
fmt.Printf("DISKII: Disk %v is on\n", c.selected)
|
//fmt.Printf("DISKII: Disk %v is on\n", c.selected)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
c.ssr[0xA] = func(_ *ioC0Page) uint8 {
|
c.ssr[0xA] = func(_ *ioC0Page) uint8 {
|
||||||
c.selected = 0
|
c.selected = 0
|
||||||
fmt.Printf("DISKII: Disk %v selected\n", c.selected)
|
//fmt.Printf("DISKII: Disk %v selected\n", c.selected)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
c.ssr[0xB] = func(_ *ioC0Page) uint8 {
|
c.ssr[0xB] = func(_ *ioC0Page) uint8 {
|
||||||
c.selected = 1
|
c.selected = 1
|
||||||
fmt.Printf("DISKII: Disk %v selected\n", c.selected)
|
//fmt.Printf("DISKII: Disk %v selected\n", c.selected)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
var i uint8
|
|
||||||
// Q6L
|
// Q6L
|
||||||
c.ssr[0xC] = func(_ *ioC0Page) uint8 {
|
c.ssr[0xC] = func(_ *ioC0Page) uint8 {
|
||||||
fmt.Printf("DISKII: Reading\n")
|
//fmt.Printf("DISKII: Reading\n")
|
||||||
i++
|
drive := &c.drive[c.selected]
|
||||||
return i
|
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) {
|
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
|
// Q6H
|
||||||
c.ssr[0xD] = func(_ *ioC0Page) uint8 {
|
c.ssr[0xD] = func(_ *ioC0Page) uint8 {
|
||||||
c.writeMode = false
|
c.drive[c.selected].writeMode = false
|
||||||
fmt.Printf("DISKII: Sense write protection\n")
|
//fmt.Printf("DISKII: Sense write protection\n")
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Q7L
|
// Q7L
|
||||||
c.ssr[0xE] = func(_ *ioC0Page) uint8 {
|
c.ssr[0xE] = func(_ *ioC0Page) uint8 {
|
||||||
c.writeMode = false
|
c.drive[c.selected].writeMode = false
|
||||||
fmt.Printf("DISKII: Set read mode\n")
|
//fmt.Printf("DISKII: Set read mode\n")
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Q7H
|
// Q7H
|
||||||
c.ssr[0xF] = func(_ *ioC0Page) uint8 {
|
c.ssr[0xF] = func(_ *ioC0Page) uint8 {
|
||||||
c.writeMode = true
|
c.drive[c.selected].writeMode = true
|
||||||
fmt.Printf("DISKII: Set write mode\n")
|
//fmt.Printf("DISKII: Set write mode\n")
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
// TODO: missing C, D, E, and F
|
|
||||||
|
|
||||||
return &c
|
return &c
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,3 +175,28 @@ func loadCardRom(filename string) []memoryPage {
|
|||||||
|
|
||||||
return memPages
|
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)
|
//fmt.Printf("Peek on $C0%02x ", address)
|
||||||
ss := p.softSwitchesR[address]
|
ss := p.softSwitchesR[address]
|
||||||
if ss == nil {
|
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)
|
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)
|
//fmt.Printf("Poke on $C0%02x with %02x ", address, value)
|
||||||
ss := p.softSwitchesW[address]
|
ss := p.softSwitchesW[address]
|
||||||
if ss == nil {
|
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)
|
ss(p, value)
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
package apple2
|
package apple2
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
type unassignedPage struct {
|
type unassignedPage struct {
|
||||||
page uint8
|
page uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
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 0xdd
|
return 0xdd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *unassignedPage) Poke(address uint8, value uint8) {
|
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)
|
//panic(address)
|
||||||
}
|
}
|
||||||
|
7
main.go
7
main.go
@ -6,10 +6,11 @@ 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"
|
disk2RomFile := "apple2/romdumps/DISK2.rom"
|
||||||
|
diskImage := "../dos33.nib"
|
||||||
|
|
||||||
log := true
|
log := false
|
||||||
a := apple2.NewApple2(romFile)
|
a := apple2.NewApple2(romFile)
|
||||||
//a.AddDisk2(disk2RomFile)
|
a.AddDisk2(disk2RomFile, diskImage)
|
||||||
a.Run(log)
|
a.Run(log)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user