Pārlūkot izejas kodu

Suport read/write Amiga HD ADF files

Keir Fraser 3 gadi atpakaļ
vecāks
revīzija
d7b926f895

+ 27 - 15
scripts/greaseweazle/codec/amiga/amigados.py

@@ -21,13 +21,12 @@ bad_sector = b'-=[BAD SECTOR]=-' * 32
 
 class AmigaDOS:
 
-    DDSEC = 11
+    time_per_rev = 0.2
 
-    def __init__(self, tracknr, nsec=DDSEC):
-        self.tracknr = tracknr
-        self.nsec = nsec
-        self.sector = [None] * nsec
-        self.map = [None] * nsec
+    def __init__(self, cyl, head):
+        self.tracknr = cyl*2 + head
+        self.sector = [None] * self.nsec
+        self.map = [None] * self.nsec
 
     def summary_string(self):
         nsec, nbad = self.nsec, self.nr_missing()
@@ -60,9 +59,13 @@ class AmigaDOS:
         return tdat
 
     def set_adf_track(self, tdat):
+        totsize = self.nsec * 512
+        if len(tdat) < totsize:
+            tdat += bytes(totsize - len(tdat))
         self.map = list(range(self.nsec))
         for sec in self.map:
             self.sector[sec] = bytes(16), tdat[sec*512:(sec+1)*512]
+        return totsize
 
     def flux_for_writeout(self, *args, **kwargs):
         return self.raw_track().flux_for_writeout(args, kwargs)
@@ -72,7 +75,7 @@ class AmigaDOS:
 
 
     def decode_raw(self, track):
-        raw = RawTrack(clock = 2e-6, data = track)
+        raw = RawTrack(clock = self.clock, data = track)
         bits, _ = raw.get_all_data()
 
         for offs in bits.itersearch(sync):
@@ -128,7 +131,7 @@ class AmigaDOS:
             t += encode(bytes(2))
 
         # Add the pre-index gap.
-        tlen = 101376 * (self.nsec//11)
+        tlen = (int((self.time_per_rev / self.clock)) + 31) & ~31
         t += bytes(tlen//8-len(t))
 
         track = MasterTrack(
@@ -142,10 +145,25 @@ class AmigaDOS:
     def verify_track(self, flux):
         cyl = self.tracknr // 2
         head = self.tracknr & 1
-        readback_track = decode_track(cyl, head, flux)
+        readback_track = self.decode_track(cyl, head, flux)
         return (readback_track.nr_missing() == 0
                 and self.sector == readback_track.sector)
 
+    @classmethod
+    def decode_track(cls, cyl, head, track):
+        ados = cls(cyl, head)
+        ados.decode_raw(track)
+        return ados
+
+
+class AmigaDOS_DD(AmigaDOS):
+    nsec = 11
+    clock = 14/7093790
+
+class AmigaDOS_HD(AmigaDOS):
+    nsec = 22
+    clock = AmigaDOS_DD.clock / 2
+
 
 def mfm_encode(dat):
     y = 0
@@ -178,12 +196,6 @@ def checksum(dat):
     return (csum ^ (csum>>1)) & 0x55555555
 
 
-def decode_track(cyl, head, track):
-    ados = AmigaDOS(cyl*2 + head)
-    ados.decode_raw(track)
-    return ados
-
-
 # Local variables:
 # python-indent: 4
 # End:

+ 15 - 16
scripts/greaseweazle/codec/formats.py

@@ -8,19 +8,29 @@
 from greaseweazle.tools import util
 
 class Format:
+    adf_compatible = False
     img_compatible = False
     default_trackset = 'c=0-79:h=0-1'
     max_trackset = 'c=0-81:h=0-1'
     def __init__(self):
         self.default_tracks = util.TrackSet(self.default_trackset)
         self.max_tracks = util.TrackSet(self.max_trackset)
+        self.decode_track = self.fmt.decode_track
 
-class Format_Amiga_AmigaDOS(Format):
+class Format_Amiga_AmigaDOS_DD(Format):
+    adf_compatible = True
     def __init__(self):
         import greaseweazle.codec.amiga.amigados as m
-        self.fmt = m.AmigaDOS
+        self.fmt = m.AmigaDOS_DD
+        self.default_revs = m.default_revs
+        super().__init__()
+    
+class Format_Amiga_AmigaDOS_HD(Format):
+    adf_compatible = True
+    def __init__(self):
+        import greaseweazle.codec.amiga.amigados as m
+        self.fmt = m.AmigaDOS_HD
         self.default_revs = m.default_revs
-        self.decode_track = m.decode_track
         super().__init__()
     
 class Format_IBM_180(Format):
@@ -31,7 +41,6 @@ class Format_IBM_180(Format):
         import greaseweazle.codec.ibm.mfm as m
         self.fmt = m.IBM_MFM_720
         self.default_revs = m.default_revs
-        self.decode_track = self.fmt.decode_track
         super().__init__()
     
 class Format_IBM_360(Format):
@@ -42,7 +51,6 @@ class Format_IBM_360(Format):
         import greaseweazle.codec.ibm.mfm as m
         self.fmt = m.IBM_MFM_720
         self.default_revs = m.default_revs
-        self.decode_track = self.fmt.decode_track
         super().__init__()
     
 class Format_IBM_720(Format):
@@ -51,7 +59,6 @@ class Format_IBM_720(Format):
         import greaseweazle.codec.ibm.mfm as m
         self.fmt = m.IBM_MFM_720
         self.default_revs = m.default_revs
-        self.decode_track = self.fmt.decode_track
         super().__init__()
     
 class Format_IBM_800(Format):
@@ -60,7 +67,6 @@ class Format_IBM_800(Format):
         import greaseweazle.codec.ibm.mfm as m
         self.fmt = m.IBM_MFM_800
         self.default_revs = m.default_revs
-        self.decode_track = self.fmt.decode_track
         super().__init__()
     
 class Format_IBM_1440(Format):
@@ -69,7 +75,6 @@ class Format_IBM_1440(Format):
         import greaseweazle.codec.ibm.mfm as m
         self.fmt = m.IBM_MFM_1440
         self.default_revs = m.default_revs
-        self.decode_track = self.fmt.decode_track
         super().__init__()
 
 class Format_IBM_1200(Format):
@@ -78,7 +83,6 @@ class Format_IBM_1200(Format):
         import greaseweazle.codec.ibm.mfm as m
         self.fmt = m.IBM_MFM_1200
         self.default_revs = m.default_revs
-        self.decode_track = self.fmt.decode_track
         super().__init__()
 
 class Format_AtariST_360(Format):
@@ -89,7 +93,6 @@ class Format_AtariST_360(Format):
         import greaseweazle.codec.ibm.mfm as m
         self.fmt = m.AtariST_SS_9SPT
         self.default_revs = m.default_revs
-        self.decode_track = self.fmt.decode_track
         super().__init__()
     
 class Format_AtariST_400(Format):
@@ -100,7 +103,6 @@ class Format_AtariST_400(Format):
         import greaseweazle.codec.ibm.mfm as m
         self.fmt = m.AtariST_10SPT
         self.default_revs = m.default_revs
-        self.decode_track = self.fmt.decode_track
         super().__init__()
     
 class Format_AtariST_440(Format):
@@ -111,7 +113,6 @@ class Format_AtariST_440(Format):
         import greaseweazle.codec.ibm.mfm as m
         self.fmt = m.AtariST_11SPT
         self.default_revs = m.default_revs
-        self.decode_track = self.fmt.decode_track
         super().__init__()
     
 class Format_AtariST_720(Format):
@@ -120,7 +121,6 @@ class Format_AtariST_720(Format):
         import greaseweazle.codec.ibm.mfm as m
         self.fmt = m.AtariST_DS_9SPT
         self.default_revs = m.default_revs
-        self.decode_track = self.fmt.decode_track
         super().__init__()
     
 class Format_AtariST_800(Format):
@@ -129,7 +129,6 @@ class Format_AtariST_800(Format):
         import greaseweazle.codec.ibm.mfm as m
         self.fmt = m.AtariST_10SPT
         self.default_revs = m.default_revs
-        self.decode_track = self.fmt.decode_track
         super().__init__()
     
 class Format_AtariST_880(Format):
@@ -138,12 +137,12 @@ class Format_AtariST_880(Format):
         import greaseweazle.codec.ibm.mfm as m
         self.fmt = m.AtariST_11SPT
         self.default_revs = m.default_revs
-        self.decode_track = self.fmt.decode_track
         super().__init__()
     
     
 formats = {
-    'amiga.amigados': Format_Amiga_AmigaDOS,
+    'amiga.amigados': Format_Amiga_AmigaDOS_DD,
+    'amiga.amigados_hd': Format_Amiga_AmigaDOS_HD,
     'ibm.180': Format_IBM_180,
     'ibm.360': Format_IBM_360,
     'ibm.720': Format_IBM_720,

+ 32 - 17
scripts/greaseweazle/image/adf.py

@@ -9,39 +9,54 @@ from greaseweazle import error
 import greaseweazle.codec.amiga.amigados as amigados
 from .image import Image
 
+from greaseweazle.codec import formats
+
 class ADF(Image):
 
     default_format = 'amiga.amigados'
 
-    def __init__(self):
-        self.sec_per_track = 11
+    def __init__(self, name, fmt):
         self.to_track = dict()
+        error.check(fmt is not None and fmt.adf_compatible, """\
+ADF image requires compatible format specifier
+Compatible formats:\n%s"""
+                    % formats.print_formats(lambda k, v: v.adf_compatible))
+        self.filename = name
+        self.fmt = fmt
 
 
     @classmethod
-    def from_file(cls, name):
+    def from_file(cls, name, fmt):
 
         with open(name, "rb") as f:
             dat = f.read()
 
-        adf = cls()
-
-        nsec = adf.sec_per_track
-        error.check((len(dat) % (2*nsec*512)) == 0, "Bad ADF image")
-        ncyl = len(dat) // (2*nsec*512)
-        if ncyl > 90:
-            ncyl //= 2
-            nsec *= 2
-            adf.sec_per_track = nsec
+        adf = cls(name, fmt)
 
-        for tnr in range(ncyl*2):
-            ados = amigados.AmigaDOS(tracknr=tnr, nsec=nsec)
-            ados.set_adf_track(dat[tnr*nsec*512:(tnr+1)*nsec*512])
+        while True:
+            nsec = fmt.fmt.nsec
+            error.check((len(dat) % (2*nsec*512)) == 0, "Bad ADF image length")
+            ncyl = len(dat) // (2*nsec*512)
+            if ncyl < 90:
+                break
+            error.check(nsec == 11, "Bad ADF image length")
+            fmt = adf.fmt = formats.Format_Amiga_AmigaDOS_HD()
+
+        pos = 0
+        for t in fmt.max_tracks:
+            tnr = t.cyl*2 + t.head
+            ados = fmt.fmt(t.cyl, t.head)
+            pos += ados.set_adf_track(dat[pos:])
             adf.to_track[tnr] = ados
 
         return adf
 
 
+    @classmethod
+    def to_file(cls, name, fmt=None):
+        return cls(name, fmt)
+
+
     def get_track(self, cyl, side):
         tnr = cyl * 2 + side
         if not tnr in self.to_track:
@@ -66,13 +81,13 @@ class ADF(Image):
                 tdat += t.get_adf_track()
             elif tnr < 160:
                 # Pad empty/damaged tracks.
-                tdat += amigados.bad_sector * self.sec_per_track
+                tdat += amigados.bad_sector * self.fmt.fmt.nsec
             else:
                 # Do not extend past 160 tracks unless there is data.
                 break
 
         if ntracks < 160:
-            tdat += amigados.bad_sector * self.sec_per_track * (160 - ntracks)
+            tdat += amigados.bad_sector * self.fmt.fmt.nsec * (160 - ntracks)
 
         return tdat
 

+ 2 - 2
scripts/greaseweazle/image/img.py

@@ -9,7 +9,7 @@ from greaseweazle import error
 from greaseweazle.codec.ibm import mfm
 from .image import Image
 
-import greaseweazle.codec.formats
+from greaseweazle.codec import formats
 
 class IMG(Image):
 
@@ -20,7 +20,7 @@ class IMG(Image):
         error.check(fmt is not None and fmt.img_compatible, """\
 Sector image requires compatible format specifier
 Compatible formats:\n%s"""
-                    % greaseweazle.codec.formats.print_formats(
+                    % formats.print_formats(
                         lambda k, v: v.img_compatible))
         self.filename = name
         self.fmt = fmt

+ 7 - 5
scripts/greaseweazle/tools/write.py

@@ -17,12 +17,11 @@ from greaseweazle import usb as USB
 from greaseweazle.codec import formats
 
 # Read and parse the image file.
-def open_image(args):
-    cls = util.get_image_class(args.file)
+def open_image(args, image_class):
     try:
-        image = cls.from_file(args.file)
+        image = image_class.from_file(args.file)
     except TypeError:
-        image = cls.from_file(args.file, args.fmt_cls)
+        image = image_class.from_file(args.file, args.fmt_cls)
     return image
 
 # write_from_image:
@@ -171,6 +170,9 @@ def main(argv):
     args = parser.parse_args(argv[2:])
 
     try:
+        image_class = util.get_image_class(args.file)
+        if not args.format and hasattr(image_class, 'default_format'):
+            args.format = image_class.default_format
         def_tracks, args.fmt_cls = None, None
         if args.format:
             try:
@@ -187,7 +189,7 @@ Known formats:\n%s"""
             def_tracks.update_from_trackspec(args.tracks.trackspec)
         args.tracks = def_tracks
         usb = util.usb_open(args.device)
-        image = open_image(args)
+        image = open_image(args, image_class)
         s = str(args.tracks)
         if args.precomp is not None:
             s += "; %s" % args.precomp