Эх сурвалжийг харах

gw write: New specifier --precomp=

"type={mfm,fm,gcr}" (default MFM)
"c=p" (precompensate cyls >= c by p nanoseconds)
Keir Fraser 4 жил өмнө
parent
commit
ea5beebfd2

+ 40 - 2
scripts/greaseweazle/tools/write.py

@@ -12,7 +12,7 @@ description = "Write a disk from the specified image file."
 import sys
 
 from greaseweazle.tools import util
-from greaseweazle import error
+from greaseweazle import error, track
 from greaseweazle import usb as USB
 
 # Read and parse the image file.
@@ -60,6 +60,8 @@ def write_from_image(usb, args, image):
             usb.erase_track(drive.ticks_per_rev * 1.1)
             continue
 
+        if args.precomp is not None:
+            track.precomp = args.precomp.track_precomp(cyl)
         flux = track.flux_for_writeout()
 
         # @factor adjusts flux times for speed variations between the
@@ -118,6 +120,37 @@ def write_from_image(usb, args, image):
         print(s)
 
 
+class PrecompSpec:
+    def __str__(self):
+        s = "Precomp %s" % track.Precomp.TYPESTRING[self.type]
+        for e in self.list:
+            s += ", %d-:%dns" % e
+        return s
+
+    def track_precomp(self, cyl):
+        for c,s in reversed(self.list):
+            if cyl >= c:
+                return track.Precomp(self.type, s)
+        return None
+
+    def importspec(self, spec):
+        self.list = []
+        self.type = track.Precomp.MFM
+        for x in spec.split(':'):
+            k,v = x.split('=')
+            if k == 'type':
+                self.type = track.Precomp.TYPESTRING.index(v.upper())
+            else:
+                self.list.append((int(k), int(v)))
+        self.list.sort()
+
+    def __init__(self, spec):
+        try:
+            self.importspec(spec)
+        except:
+            raise ValueError
+        
+
 def main(argv):
 
     parser = util.ArgumentParser(usage='%(prog)s [options] file')
@@ -130,6 +163,8 @@ def main(argv):
                         help="erase empty tracks (default: skip)")
     parser.add_argument("--no-verify", action="store_true",
                         help="disable verify")
+    parser.add_argument("--precomp", type=PrecompSpec,
+                        help="write precompensation")
     parser.add_argument("file", help="input filename")
     parser.description = description
     parser.prog += ' ' + argv[1]
@@ -142,7 +177,10 @@ def main(argv):
         if args.tracks is not None:
             tracks.update_from_trackspec(args.tracks.trackspec)
         args.tracks = tracks
-        print("Writing %s" % (args.tracks))
+        s = str(args.tracks)
+        if args.precomp is not None:
+            s += "; %s" % args.precomp
+        print("Writing %s" % s)
         util.with_drive_selected(write_from_image, usb, args, image)
     except USB.CmdError as error:
         print("Command Failed: %s" % error)

+ 37 - 0
scripts/greaseweazle/track.py

@@ -11,6 +11,38 @@ from bitarray import bitarray
 from greaseweazle.flux import WriteoutFlux
 from greaseweazle import optimised
 
+# Precompensation to apply to a MasterTrack for writeout.
+class Precomp:
+    MFM = 0
+    FM  = 1
+    GCR = 2
+    TYPESTRING = [ 'MFM', 'FM', 'GCR' ]
+    def __str__(self):
+        return "Precomp: %s, %dns" % (Precomp.TYPESTRING[self.type], self.ns)
+    def __init__(self, type, ns):
+        self.type = type
+        self.ns = ns
+    def apply(self, bits, bit_ticks, scale):
+        t = self.ns * scale
+        if self.type == Precomp.MFM:
+            for i in bits.itersearch(bitarray('10100', endian='big')):
+                bit_ticks[i+2] -= t
+                bit_ticks[i+3] += t
+            for i in bits.itersearch(bitarray('00101', endian='big')):
+                bit_ticks[i+2] += t
+                bit_ticks[i+3] -= t
+        # This is primarily for GCR and FM which permit adjacent 1s (and
+        # have correspondingly slower bit times). However it may be useful
+        # for illegal MFM sequences too, especially on Amiga (custom syncwords,
+        # 4us-bitcell tracks). Normal MFM should not trigger these patterns.
+        for i in bits.itersearch(bitarray('110', endian='big')):
+            bit_ticks[i+1] -= t
+            bit_ticks[i+2] += t
+        for i in bits.itersearch(bitarray('011', endian='big')):
+            bit_ticks[i+1] += t
+            bit_ticks[i+2] -= t
+
+
 # A pristine representation of a track, from a codec and/or a perfect image.
 class MasterTrack:
 
@@ -33,6 +65,7 @@ class MasterTrack:
         self.bit_ticks = bit_ticks
         self.splice = splice
         self.weak = weak
+        self.precomp = None
 
     def __str__(self):
         s = "\nMaster Track: splice @ %d\n" % self.splice
@@ -142,6 +175,10 @@ class MasterTrack:
                 pos -= 32
                 bits[pos:pos+32] = fill_pattern
 
+        if for_writeout and self.precomp is not None:
+            self.precomp.apply(bits, bit_ticks,
+                               ticks_to_index / (self.time_per_rev*1e9))
+
         # Convert the stretched track data into flux.
         bit_ticks_i = iter(bit_ticks)
         flux_list = []