Time based disk reads
This commit is contained in:
parent
a27ab17766
commit
e14b26f876
|
@ -126,13 +126,16 @@ func (c *cardDisk2) assign(a *Apple2, slot int) {
|
||||||
c.cardBase.assign(a, slot)
|
c.cardBase.assign(a, slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Q6: shift/load
|
||||||
|
// Q7: read/write
|
||||||
|
|
||||||
func (c *cardDisk2) softSwitchQ6Q7(index uint8, in uint8) uint8 {
|
func (c *cardDisk2) softSwitchQ6Q7(index uint8, in uint8) uint8 {
|
||||||
switch index {
|
switch index {
|
||||||
case 0xC: // Q6L
|
case 0xC: // Q6L
|
||||||
c.q6 = false
|
c.q6 = false
|
||||||
case 0xD: // Q6H
|
case 0xD: // Q6H
|
||||||
c.q6 = true
|
c.q6 = true
|
||||||
case 0xE: // Q/L
|
case 0xE: // Q7L
|
||||||
c.q7 = false
|
c.q7 = false
|
||||||
case 0xF: // Q7H
|
case 0xF: // Q7H
|
||||||
c.q7 = true
|
c.q7 = true
|
||||||
|
@ -151,13 +154,13 @@ func (c *cardDisk2) processQ6Q7(in uint8) {
|
||||||
if d.diskette == nil {
|
if d.diskette == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !c.q6 {
|
if !c.q6 { // shift
|
||||||
if !c.q7 { // Q6L-Q7L: Read
|
if !c.q7 { // Q6L-Q7L: Read
|
||||||
c.dataLatch = d.diskette.read(d.tracksStep, c.a.cpu.GetCycles())
|
c.dataLatch = d.diskette.read(d.tracksStep, c.a.cpu.GetCycles())
|
||||||
} else { // Q6L-Q7H: Write the dataLatch value to disk. Shift data out
|
} else { // Q6L-Q7H: Write the dataLatch value to disk. Shift data out
|
||||||
d.diskette.write(d.tracksStep, c.dataLatch, c.a.cpu.GetCycles())
|
d.diskette.write(d.tracksStep, c.dataLatch, c.a.cpu.GetCycles())
|
||||||
}
|
}
|
||||||
} else {
|
} else { // load
|
||||||
if !c.q7 { // Q6H-Q7L: Sense write protect / prewrite state
|
if !c.q7 { // Q6H-Q7L: Sense write protect / prewrite state
|
||||||
// Bit 7 of the control status register means write protected
|
// Bit 7 of the control status register means write protected
|
||||||
c.dataLatch = 0 // Never write protected
|
c.dataLatch = 0 // Never write protected
|
||||||
|
|
|
@ -20,28 +20,58 @@ const (
|
||||||
nibImageSize = numberOfTracks * nibBytesPerTrack
|
nibImageSize = numberOfTracks * nibBytesPerTrack
|
||||||
dskImageSize = numberOfTracks * numberOfSectors * bytesPerSector
|
dskImageSize = numberOfTracks * numberOfSectors * bytesPerSector
|
||||||
defaultVolumeTag = 254
|
defaultVolumeTag = 254
|
||||||
|
cyclesPerBit = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
type diskette16sector struct {
|
type diskette16sector struct {
|
||||||
track [numberOfTracks][]byte
|
track [numberOfTracks][]byte
|
||||||
position int
|
timeBased bool
|
||||||
|
// Not time based implementation
|
||||||
|
position int // For not time based implemenation
|
||||||
|
// Time based implementation, expermiental
|
||||||
|
cycleOn uint64 // Cycle when the disk was last turned on
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *diskette16sector) powerOn(_ uint64) {
|
func (d *diskette16sector) powerOn(cycle uint64) {
|
||||||
// Not needed
|
d.cycleOn = cycle
|
||||||
}
|
}
|
||||||
func (d *diskette16sector) powerOff(_ uint64) {
|
func (d *diskette16sector) powerOff(_ uint64) {
|
||||||
// Not needed
|
// Not needed
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *diskette16sector) read(quarterTrack int, _ uint64) uint8 {
|
func (d *diskette16sector) getBitPositionInTrack(cycle uint64) int {
|
||||||
track := quarterTrack / stepsPerTrack
|
// Calculate how long the disk has been spinning. We move one bit every 4 cycles.
|
||||||
value := d.track[track][d.position]
|
// In this implementation we don't take into account hot long the motor takes to be at full speed.
|
||||||
|
cycles := cycle - d.cycleOn
|
||||||
|
position := cycles / cyclesPerBit
|
||||||
|
return int(position % (8 * nibBytesPerTrack)) // Ignore full turns
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *diskette16sector) read(quarterTrack int, cycle uint64) uint8 {
|
||||||
|
track := d.track[quarterTrack/stepsPerTrack]
|
||||||
|
if d.timeBased {
|
||||||
|
bitPosition := d.getBitPositionInTrack(cycle)
|
||||||
|
bytePosition := bitPosition / 8
|
||||||
|
shift := uint(bitPosition % 8)
|
||||||
|
if shift == 1 {
|
||||||
|
// We continue having the previous data for a little longer
|
||||||
|
shift = 0
|
||||||
|
}
|
||||||
|
value := track[bytePosition]
|
||||||
|
value >>= shift
|
||||||
|
//fmt.Printf("%v, %v, %v, %x\n", bitPosition, shift, bytePosition, uint8(data))
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
value := track[d.position]
|
||||||
d.position = (d.position + 1) % nibBytesPerTrack
|
d.position = (d.position + 1) % nibBytesPerTrack
|
||||||
|
//fmt.Printf("%v, %v, %v, %x\n", 0, 0, d.position, uint8(value))
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *diskette16sector) write(quarterTrack int, value uint8, _ uint64) {
|
func (d *diskette16sector) write(quarterTrack int, value uint8, _ uint64) {
|
||||||
|
if d.timeBased {
|
||||||
|
panic("Write not implmented on time based disk implementation")
|
||||||
|
}
|
||||||
track := quarterTrack / stepsPerTrack
|
track := quarterTrack / stepsPerTrack
|
||||||
d.track[track][d.position] = value
|
d.track[track][d.position] = value
|
||||||
d.position = (d.position + 1) % nibBytesPerTrack
|
d.position = (d.position + 1) % nibBytesPerTrack
|
||||||
|
@ -50,6 +80,9 @@ func (d *diskette16sector) write(quarterTrack int, value uint8, _ uint64) {
|
||||||
func loadDisquette(filename string) (*diskette16sector, error) {
|
func loadDisquette(filename string) (*diskette16sector, error) {
|
||||||
var d diskette16sector
|
var d diskette16sector
|
||||||
|
|
||||||
|
// Experimental
|
||||||
|
d.timeBased = true
|
||||||
|
|
||||||
data, err := loadResource(filename)
|
data, err := loadResource(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
Loading…
Reference in New Issue