izapple2/storage/disketteWoz.go

101 lines
2.8 KiB
Go
Raw Normal View History

package storage
2019-12-15 23:36:34 +00:00
2019-12-22 13:15:19 +00:00
import (
"errors"
"math/rand"
)
2019-12-21 13:21:12 +00:00
/*
See:
https://applesaucefdc.com/woz/
*/
2019-12-21 10:16:07 +00:00
type disketteWoz struct {
2021-05-09 17:48:54 +00:00
data *FileWoz
2019-12-21 10:16:07 +00:00
cycleOn uint64 // Cycle when the disk was last turned on
turning bool
2019-12-15 23:36:34 +00:00
2021-05-09 17:48:54 +00:00
latch uint8
position uint32
positionMax uint32 // As tracks may have different lengths position is related of positionMax of the las track
cycle uint64
2019-12-15 23:36:34 +00:00
2019-12-21 13:21:12 +00:00
mc3470Buffer uint8 // Four bit buffer to detect weak bits and to add latency
2019-12-21 10:16:07 +00:00
visibleLatch uint8
visibleLatchCountDown int8 // The visible latch stores a valid latch reading for 2 bit timings
2019-12-15 23:36:34 +00:00
}
2021-05-09 17:48:54 +00:00
func newDisquetteWoz(f *FileWoz) (*disketteWoz, error) {
2019-12-22 13:15:19 +00:00
// Discard not supported features
2021-05-09 17:48:54 +00:00
if f.Info.DiskType != 1 {
2019-12-22 13:15:19 +00:00
return nil, errors.New("Only 5.25 disks are supported")
}
2021-05-09 17:48:54 +00:00
if f.Info.BootSectorFormat == 2 { // Info not available in WOZ 1.0
2019-12-22 13:15:19 +00:00
return nil, errors.New("Woz 13 sector disks are not supported")
}
var d disketteWoz
d.data = f
return &d, nil
}
func (d *disketteWoz) PowerOn(cycle uint64) {
2019-12-21 10:16:07 +00:00
d.turning = true
d.cycleOn = cycle
2019-12-15 23:36:34 +00:00
}
func (d *disketteWoz) PowerOff(_ uint64) {
2019-12-21 10:16:07 +00:00
d.turning = false
2019-12-15 23:36:34 +00:00
}
func (d *disketteWoz) Read(quarterTrack int, cycle uint64) uint8 {
2019-12-21 10:16:07 +00:00
// Count cycles to know how many bits have been read
cycles := cycle - d.cycle
deltaBits := cycles / cyclesPerBit // TODO: Use Woz optimal bit timing
// Process bits from woz
// TODO: avoid processing too many bits if delta is big
for i := uint64(0); i < deltaBits; i++ {
2019-12-21 13:21:12 +00:00
// Get next bit taking into account the MC3470 latency and weak bits
2021-07-01 16:15:49 +00:00
var fluxBit bool
2021-05-09 17:48:54 +00:00
fluxBit, d.position, d.positionMax = d.data.GetNextBitAndPosition(d.position, d.positionMax, quarterTrack)
2021-07-01 16:15:49 +00:00
d.mc3470Buffer = (d.mc3470Buffer << 1) & 0x0f
if fluxBit {
d.mc3470Buffer++
}
2019-12-21 13:21:12 +00:00
bit := (d.mc3470Buffer >> 1) & 0x1 // Use the previous to last bit to add latency
if d.mc3470Buffer == 0 && rand.Intn(100) < 3 {
2020-10-14 19:54:51 +00:00
// Four consecutive zeros. It'a a fake bit.
2019-12-21 13:21:12 +00:00
// Output a random value. 70% zero, 30% one
bit = 1
}
2019-12-21 10:16:07 +00:00
d.latch = (d.latch << 1) + bit
if d.latch >= 0x80 {
// Valid byte, store value a bit longer and clear the internal latch
//fmt.Printf("Valid 0x%.2x\n", d.latch)
d.visibleLatch = d.latch
d.visibleLatchCountDown = 1
d.latch = 0
} else if d.visibleLatchCountDown > 0 {
// Continue showing the valid byte
d.visibleLatchCountDown--
} else {
// The valid byte is lost, show the internal latch
d.visibleLatch = d.latch
}
}
2019-12-15 23:36:34 +00:00
2019-12-21 10:16:07 +00:00
//fmt.Printf("Visible: 0x%.2x, latch: 0x%.2x, bits: %v, cycles: %v\n", d.visibleLatch, d.latch, deltaBits, cycle-d.cycle)
2019-12-15 23:36:34 +00:00
2019-12-21 10:16:07 +00:00
// Update the internal last cycle without losing the remainder not processed
d.cycle += deltaBits * cyclesPerBit
2019-12-15 23:36:34 +00:00
2019-12-21 10:16:07 +00:00
return d.visibleLatch
2019-12-15 23:36:34 +00:00
}
func (d *disketteWoz) Write(quarterTrack int, value uint8, _ uint64) {
2019-12-21 10:16:07 +00:00
panic("Write not implemented on woz disk implementation")
}