mirror of
https://github.com/ivanizag/izapple2.git
synced 2024-06-14 02:29:29 +00:00
Use the diskette abstraction for no cycle dependant DSK, NIB disks
This commit is contained in:
parent
9ad13ae483
commit
a27ab17766
|
@ -25,7 +25,7 @@ Portable emulator of an Apple II+ or //e. Written in Go.
|
||||||
- FASTChip, limited to what Total Replay needs to set and clear fast mode
|
- FASTChip, limited to what Total Replay needs to set and clear fast mode
|
||||||
- Graphic modes:
|
- Graphic modes:
|
||||||
- Text 40 columns
|
- Text 40 columns
|
||||||
- text 80 columns (Apple //e only)
|
- Text 80 columns (Apple //e only)
|
||||||
- Low-Resolution graphics
|
- Low-Resolution graphics
|
||||||
- Double-Width Low-Resolution graphics (Apple //e only)
|
- Double-Width Low-Resolution graphics (Apple //e only)
|
||||||
- High-Resolution graphics
|
- High-Resolution graphics
|
||||||
|
|
119
cardDisk2.go
119
cardDisk2.go
|
@ -33,9 +33,8 @@ type cardDisk2 struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type cardDisk2Drive struct {
|
type cardDisk2Drive struct {
|
||||||
diskette *diskette16sector
|
diskette diskette
|
||||||
power bool // q4, not realy used for anything
|
power bool // q4
|
||||||
position int
|
|
||||||
phases uint8 // q3, q2, q1 and q0 with q0 on the LSB. Magnets that are active on the stepper motor
|
phases uint8 // q3, q2, q1 and q0 with q0 on the LSB. Magnets that are active on the stepper motor
|
||||||
tracksStep int // Stepmotor for tracks position. 4 steps per track
|
tracksStep int // Stepmotor for tracks position. 4 steps per track
|
||||||
}
|
}
|
||||||
|
@ -43,8 +42,8 @@ type cardDisk2Drive struct {
|
||||||
type diskette interface {
|
type diskette interface {
|
||||||
powerOn(cycle uint64)
|
powerOn(cycle uint64)
|
||||||
powerOff(cycle uint64)
|
powerOff(cycle uint64)
|
||||||
read(halfTrack int, cycle uint64) uint8
|
read(quarterTrack int, cycle uint64) uint8
|
||||||
write(halfTrack int, value uint8, cycle uint64)
|
write(quarterTrack int, value uint8, cycle uint64)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -81,16 +80,24 @@ func (c *cardDisk2) assign(a *Apple2, slot int) {
|
||||||
|
|
||||||
// Q4, power switch
|
// Q4, power switch
|
||||||
c.addCardSoftSwitchR(0x8, func(_ *ioC0Page) uint8 {
|
c.addCardSoftSwitchR(0x8, func(_ *ioC0Page) uint8 {
|
||||||
if c.drive[c.selected].power {
|
drive := c.drive[c.selected]
|
||||||
c.drive[c.selected].power = false
|
if !drive.power {
|
||||||
|
drive.power = false
|
||||||
c.a.releaseFastMode()
|
c.a.releaseFastMode()
|
||||||
|
if drive.diskette != nil {
|
||||||
|
drive.diskette.powerOff(c.a.cpu.GetCycles())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return c.dataLatch
|
return c.dataLatch
|
||||||
}, "Q4DRIVEOFF")
|
}, "Q4DRIVEOFF")
|
||||||
c.addCardSoftSwitchR(0x9, func(_ *ioC0Page) uint8 {
|
c.addCardSoftSwitchR(0x9, func(_ *ioC0Page) uint8 {
|
||||||
if !c.drive[c.selected].power {
|
drive := c.drive[c.selected]
|
||||||
c.drive[c.selected].power = true
|
if !drive.power {
|
||||||
|
drive.power = true
|
||||||
c.a.requestFastMode()
|
c.a.requestFastMode()
|
||||||
|
if drive.diskette != nil {
|
||||||
|
drive.diskette.powerOn(c.a.cpu.GetCycles())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}, "")
|
}, "")
|
||||||
|
@ -119,6 +126,47 @@ func (c *cardDisk2) assign(a *Apple2, slot int) {
|
||||||
c.cardBase.assign(a, slot)
|
c.cardBase.assign(a, slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *cardDisk2) softSwitchQ6Q7(index uint8, in uint8) uint8 {
|
||||||
|
switch index {
|
||||||
|
case 0xC: // Q6L
|
||||||
|
c.q6 = false
|
||||||
|
case 0xD: // Q6H
|
||||||
|
c.q6 = true
|
||||||
|
case 0xE: // Q/L
|
||||||
|
c.q7 = false
|
||||||
|
case 0xF: // Q7H
|
||||||
|
c.q7 = true
|
||||||
|
}
|
||||||
|
|
||||||
|
c.processQ6Q7(in)
|
||||||
|
if index&1 == 0 {
|
||||||
|
// All even addresses return the last dataLatch
|
||||||
|
return c.dataLatch
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cardDisk2) processQ6Q7(in uint8) {
|
||||||
|
d := &c.drive[c.selected]
|
||||||
|
if d.diskette == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !c.q6 {
|
||||||
|
if !c.q7 { // Q6L-Q7L: Read
|
||||||
|
c.dataLatch = d.diskette.read(d.tracksStep, c.a.cpu.GetCycles())
|
||||||
|
} else { // Q6L-Q7H: Write the dataLatch value to disk. Shift data out
|
||||||
|
d.diskette.write(d.tracksStep, c.dataLatch, c.a.cpu.GetCycles())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !c.q7 { // Q6H-Q7L: Sense write protect / prewrite state
|
||||||
|
// Bit 7 of the control status register means write protected
|
||||||
|
c.dataLatch = 0 // Never write protected
|
||||||
|
} else { // Q6H-Q7H: Load data into the controller
|
||||||
|
c.dataLatch = in
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Stepper motor to position the track.
|
Stepper motor to position the track.
|
||||||
|
|
||||||
|
@ -197,50 +245,7 @@ func moveStep(phases uint8, prevStep int) int {
|
||||||
return nextStep
|
return nextStep
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cardDisk2) softSwitchQ6Q7(index uint8, in uint8) uint8 {
|
func (d *cardDisk2Drive) insertDiskette(dt diskette) {
|
||||||
switch index {
|
|
||||||
case 0xC: // Q6L
|
|
||||||
c.q6 = false
|
|
||||||
case 0xD: // Q6H
|
|
||||||
c.q6 = true
|
|
||||||
case 0xE: // Q/L
|
|
||||||
c.q7 = false
|
|
||||||
case 0xF: // Q7H
|
|
||||||
c.q7 = true
|
|
||||||
}
|
|
||||||
|
|
||||||
c.processQ6Q7(in)
|
|
||||||
if index&1 == 0 {
|
|
||||||
// All even addresses return the last dataLatch
|
|
||||||
return c.dataLatch
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cardDisk2) processQ6Q7(in uint8) {
|
|
||||||
d := &c.drive[c.selected]
|
|
||||||
if d.diskette == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !c.q6 {
|
|
||||||
if !c.q7 { // Q6L-Q7L: Read
|
|
||||||
track := d.tracksStep / stepsPerTrack
|
|
||||||
c.dataLatch, d.position = d.diskette.read(track, d.position)
|
|
||||||
} else { // Q6L-Q7H: Write the dataLatch value to disk. Shift data out
|
|
||||||
track := d.tracksStep / stepsPerTrack
|
|
||||||
d.position = d.diskette.write(track, d.position, c.dataLatch)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if !c.q7 { // Q6H-Q7L: Sense write protect / prewrite state
|
|
||||||
// Bit 7 of the control status register means write protected
|
|
||||||
c.dataLatch = 0 // Never write protected
|
|
||||||
} else { // Q6H-Q7H: Load data into the controller
|
|
||||||
c.dataLatch = in
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *cardDisk2Drive) insertDiskette(dt *diskette16sector) {
|
|
||||||
d.diskette = dt
|
d.diskette = dt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,10 +318,6 @@ func (d *cardDisk2Drive) save(w io.Writer) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = binary.Write(w, binary.BigEndian, d.position)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,9 +334,5 @@ func (d *cardDisk2Drive) load(r io.Reader) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = binary.Read(r, binary.BigEndian, &d.position)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,17 +24,27 @@ const (
|
||||||
|
|
||||||
type diskette16sector struct {
|
type diskette16sector struct {
|
||||||
track [numberOfTracks][]byte
|
track [numberOfTracks][]byte
|
||||||
|
position int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *diskette16sector) read(track int, position int) (value uint8, newPosition int) {
|
func (d *diskette16sector) powerOn(_ uint64) {
|
||||||
value = d.track[track][position]
|
// Not needed
|
||||||
newPosition = (position + 1) % nibBytesPerTrack
|
}
|
||||||
return
|
func (d *diskette16sector) powerOff(_ uint64) {
|
||||||
|
// Not needed
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *diskette16sector) write(track int, position int, value uint8) int {
|
func (d *diskette16sector) read(quarterTrack int, _ uint64) uint8 {
|
||||||
d.track[track][position] = value
|
track := quarterTrack / stepsPerTrack
|
||||||
return (position + 1) % nibBytesPerTrack
|
value := d.track[track][d.position]
|
||||||
|
d.position = (d.position + 1) % nibBytesPerTrack
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *diskette16sector) write(quarterTrack int, value uint8, _ uint64) {
|
||||||
|
track := quarterTrack / stepsPerTrack
|
||||||
|
d.track[track][d.position] = value
|
||||||
|
d.position = (d.position + 1) % nibBytesPerTrack
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadDisquette(filename string) (*diskette16sector, error) {
|
func loadDisquette(filename string) (*diskette16sector, error) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user