better handling of mid-track transition to built-in RWTS

This commit is contained in:
4am 2019-02-02 11:50:34 -05:00
parent dd8761c7c5
commit 5b411eb582
2 changed files with 205 additions and 113 deletions

View File

@ -162,6 +162,7 @@ class BasePassportProcessor: # base class
self.g.logger.PrintByID("sync") self.g.logger.PrintByID("sync")
return True return True
# TODO IsUnformatted nibble test and other tests # TODO IsUnformatted nibble test and other tests
# (still need these for disks like Crime Wave and Thunder Bombs)
return False return False
def IDDiversi(self, t00s00): def IDDiversi(self, t00s00):
@ -179,103 +180,32 @@ class BasePassportProcessor: # base class
def IDDavidDOS(self, t00s00): def IDDavidDOS(self, t00s00):
"""returns True if T00S00 is David-DOS II bootloader, or False otherwise""" """returns True if T00S00 is David-DOS II bootloader, or False otherwise"""
if not find.at(0x01, t00s00, return find.at(0x01, t00s00, kIDDavidDOS1) and \
b'\xA5\x27' find.wild_at(0x4A, t00s00, kIDDavidDOS2)
b'\xC9\x09'
b'\xD0\x17'):
return False
return find.wild_at(0x4A, t00s00,
b'\xA2' + find.WILDCARD + \
b'\xBD' + find.WILDCARD + b'\x08' + \
b'\x9D' + find.WILDCARD + b'\x04' + \
b'\xCA'
b'\x10\xF7')
def IDDatasoft(self, t00s00): def IDDatasoft(self, t00s00):
"""returns True if T00S00 is encrypted Datasoft bootloader, or False otherwise""" """returns True if T00S00 is encrypted Datasoft bootloader, or False otherwise"""
return find.at(0x00, t00s00, return find.at(0x00, t00s00, kIDDatasoft)
b'\x01\x4C\x7E\x08\x04\x8A\x0C\xB8'
b'\x00\x56\x10\x7A\x00\x00\x1A\x16'
b'\x12\x0E\x0A\x06\x53\x18\x9A\x02'
b'\x10\x1B\x02\x10\x4D\x56\x15\x0B'
b'\xBF\x14\x14\x54\x54\x54\x92\x81'
b'\x1B\x10\x10\x41\x06\x73\x0A\x10'
b'\x33\x4E\x00\x73\x12\x10\x33\x7C'
b'\x00\x11\x20\xE3\x49\x50\x73\x1A'
b'\x10\x41\x00\x23\x80\x5B\x0A\x10'
b'\x0B\x4E\x9D\x0A\x10\x9D\x0C\x10'
b'\x60\x1E\x53\x10\x90\x53\xBC\x90'
b'\x53\x00\x90\xD8\x52\x00\xD8\x7C'
b'\x00\x53\x80\x0B\x06\x41\x00\x09'
b'\x04\x45\x0C\x63\x04\x90\x94\xD0'
b'\xD4\x23\x04\x91\xA1\xEB\xCD\x06'
b'\x95\xA1\xE1\x98\x97\x86')
def IDMicrograms(self, t00s00): def IDMicrograms(self, t00s00):
"""returns True if T00S00 is Micrograms bootloader, or False otherwise""" """returns True if T00S00 is Micrograms bootloader, or False otherwise"""
if not find.at(0x01, t00s00, return find.at(0x01, t00s00, kIDMicrograms1) and \
b'\xA5\x27' find.at(0x42, t00s00, kIDMicrograms2)
b'\xC9\x09'
b'\xD0\x12'
b'\xA9\xC6'
b'\x85\x3F'):
return False
return find.at(0x42, t00s00, b'\x4C\x00')
def IDQuickDOS(self, t00s00): def IDQuickDOS(self, t00s00):
"""returns True if T00S00 is Quick-DOS bootloader, or False otherwise""" """returns True if T00S00 is Quick-DOS bootloader, or False otherwise"""
return find.at(0x01, t00s00, return find.at(0x01, t00s00, kIDQuickDOS)
b'\xA5\x27'
b'\xC9\x09'
b'\xD0\x27'
b'\x78'
b'\xAD\x83\xC0')
def IDRDOS(self, t00s00): def IDRDOS(self, t00s00):
"""returns True if T00S00 is Quick-DOS bootloader, or False otherwise""" """returns True if T00S00 is Quick-DOS bootloader, or False otherwise"""
return find.at(0x00, t00s00, return find.at(0x00, t00s00, kIDRDOS)
b'\x01'
b'\xA9\x60'
b'\x8D\x01\x08'
b'\xA2\x00'
b'\xA0\x1F'
b'\xB9\x00\x08'
b'\x49')
def IDDOS33(self, t00s00): def IDDOS33(self, t00s00):
"""returns True if T00S00 is DOS bootloader or some variation """returns True if T00S00 is DOS bootloader or some variation
that can be safely boot traced, or False otherwise""" that can be safely boot traced, or False otherwise"""
# Code at $0801 must be standard (with one exception) # Code at $0801 must be standard (with one exception)
if not find.wild_at(0x00, t00s00, if not find.wild_at(0x00, t00s00, kIDDOS33a):
b'\x01' return False
b'\xA5\x27'
b'\xC9\x09'
b'\xD0\x18'
b'\xA5\x2B'
b'\x4A'
b'\x4A'
b'\x4A'
b'\x4A'
b'\x09\xC0'
b'\x85\x3F'
b'\xA9\x5C'
b'\x85\x3E'
b'\x18'
b'\xAD\xFE\x08'
b'\x6D\xFF\x08' + \
find.WILDCARD + find.WILDCARD + find.WILDCARD + \
b'\xAE\xFF\x08'
b'\x30\x15'
b'\xBD\x4D\x08'
b'\x85\x3D'
b'\xCE\xFF\x08'
b'\xAD\xFE\x08'
b'\x85\x27'
b'\xCE\xFE\x08'
b'\xA6\x2B'
b'\x6C\x3E\x00'
b'\xEE\xFE\x08'
b'\xEE\xFE\x08'): return False
# DOS 3.3 has JSR $FE89 / JSR $FE93 / JSR $FB2F # DOS 3.3 has JSR $FE89 / JSR $FE93 / JSR $FB2F
# some Sierra have STA $C050 / STA $C057 / STA $C055 instead # some Sierra have STA $C050 / STA $C057 / STA $C055 instead
# with the unpleasant side-effect of showing text-mode garbage # with the unpleasant side-effect of showing text-mode garbage
@ -661,43 +591,53 @@ class BasePassportProcessor: # base class
# main loop - loop through disk from track $22 down to track $00 # main loop - loop through disk from track $22 down to track $00
for logical_track_num in range(0x22, -1, -1): for logical_track_num in range(0x22, -1, -1):
self.g.track = logical_track_num # for display purposes only self.g.track = logical_track_num # for display purposes only
self.g.logger.debug("Seeking to track %s" % hex(self.g.track))
# distinguish between logical and physical track numbers to deal with # distinguish between logical and physical track numbers to deal with
# disks like Sunburst that store logical track 0x11+ on physical track 0x11.5+ # disks like Sunburst that store logical track 0x11+ on physical track 0x11.5+
physical_track_num = self.rwts.seek(logical_track_num) physical_track_num = self.rwts.seek(logical_track_num)
# self.tracks must be indexed by physical track number so we can write out # self.tracks must be indexed by physical track number so we can write out
# .woz files correctly # .woz files correctly
self.tracks[physical_track_num] = self.g.disk_image.seek(physical_track_num) self.tracks[physical_track_num] = self.g.disk_image.seek(physical_track_num)
self.g.logger.debug("Seeking to track %s" % hex(self.g.track))
tried_reseek = False tried_reseek = False
physical_sectors = OrderedDict()
while True: while True:
physical_sectors = self.rwts.decode_track(self.tracks[physical_track_num], logical_track_num, self.burn) physical_sectors.update(self.rwts.decode_track(self.tracks[physical_track_num], logical_track_num, self.burn))
if self.rwts.enough(logical_track_num, physical_sectors): if self.rwts.enough(logical_track_num, physical_sectors):
break break
if supports_reseek and not tried_reseek: if supports_reseek and not tried_reseek:
self.tracks[physical_track_num] = self.g.disk_image.reseek(physical_track_num) self.tracks[physical_track_num] = self.g.disk_image.reseek(physical_track_num)
self.g.logger.debug("Reseeking to track %s" % hex(self.g.track)) self.g.logger.debug("Reseeking to track %s" % hex(self.g.track))
tried_reseek = True tried_reseek = True
continue continue
self.g.logger.debug("found %d sectors" % len(physical_sectors)) self.g.logger.debug("found %d sectors" % len(physical_sectors))
if (0x0F not in physical_sectors) and self.SkipTrack(logical_track_num, self.tracks[physical_track_num]): if (0x0F not in physical_sectors) and self.SkipTrack(logical_track_num, self.tracks[physical_track_num]):
physical_sectors = None physical_sectors = None
break break
if self.g.tried_univ: if self.g.tried_univ:
if logical_track_num == 0x22 and (0x0F not in physical_sectors): if logical_track_num == 0x22 and (0x0F not in physical_sectors):
self.g.logger.PrintByID("fail") self.g.logger.PrintByID("fail")
self.g.logger.PrintByID("fatal220f") self.g.logger.PrintByID("fatal220f")
return False return False
else: else:
# TODO wrong in case where we switch mid-track. transition_sector = 0x0F
# Need to save the sectors that worked with the original RWTS if physical_sectors:
# then append the ones that worked with the universal RWTS temp_logical_sectors = self.rwts.reorder_to_logical_sectors(physical_sectors)
self.g.logger.PrintByID("switch", {"sector":0x0F}) # TODO find exact sector transition_sector = min(temp_logical_sectors.keys())
self.g.logger.PrintByID("switch", {"sector":transition_sector})
self.rwts = UniversalRWTS(self.g) self.rwts = UniversalRWTS(self.g)
self.g.tried_univ = True self.g.tried_univ = True
continue continue
if logical_track_num == 0 and type(self.rwts) != UniversalRWTSIgnoreEpilogues: if logical_track_num == 0 and type(self.rwts) != UniversalRWTSIgnoreEpilogues:
self.rwts = UniversalRWTSIgnoreEpilogues(self.g) self.rwts = UniversalRWTSIgnoreEpilogues(self.g)
continue continue
self.g.logger.PrintByID("fail") self.g.logger.PrintByID("fail")
return False return False
self.save_track(physical_track_num, logical_track_num, physical_sectors) self.save_track(physical_track_num, logical_track_num, physical_sectors)
@ -711,37 +651,14 @@ class BasePassportProcessor: # base class
class Verify(BasePassportProcessor): class Verify(BasePassportProcessor):
def AnalyzeT00(self, logical_sectors): def AnalyzeT00(self, logical_sectors):
self.g.is_boot1 = find.at(0x00, logical_sectors[1], self.g.is_boot1 = find.at(0x00, logical_sectors[1], kIDBoot1)
b'\x8E\xE9\xB7\x8E\xF7\xB7\xA9\x01' self.g.is_master = find.at(0x00, logical_sectors[1], kIDMaster)
b'\x8D\xF8\xB7\x8D\xEA\xB7\xAD\xE0' self.g.is_rwts = find.wild_at(0x00, logical_sectors[7], kIDRWTS)
b'\xB7\x8D\xE1\xB7\xA9\x02\x8D\xEC'
b'\xB7\xA9\x04\x8D\xED\xB7\xAC\xE7'
b'\xB7\x88\x8C\xF1\xB7\xA9\x01\x8D'
b'\xF4\xB7\x8A\x4A\x4A\x4A\x4A\xAA'
b'\xA9\x00\x9D\xF8\x04\x9D\x78\x04')
self.g.is_master = find.at(0x00, logical_sectors[1],
b'\x8E\xE9\x37\x8E\xF7\x37\xA9\x01'
b'\x8D\xF8\x37\x8D\xEA\x37\xAD\xE0'
b'\x37\x8D\xE1\x37\xA9\x02\x8D\xEC'
b'\x37\xA9\x04\x8D\xED\x37\xAC\xE7'
b'\x37\x88\x8C\xF1\x37\xA9\x01\x8D'
b'\xF4\x37\x8A\x4A\x4A\x4A\x4A\xAA'
b'\xA9\x00\x9D\xF8\x04\x9D\x78\x04')
self.g.is_rwts = find.wild_at(0x00, logical_sectors[7],
b'\x84\x48\x85\x49\xA0\x02\x8C' + find.WILDCARD + \
find.WILDCARD + b'\xA0\x04\x8C' + find.WILDCARD + find.WILDCARD + b'\xA0\x01' + \
b'\xB1\x48\xAA\xA0\x0F\xD1\x48\xF0'
b'\x1B\x8A\x48\xB1\x48\xAA\x68\x48'
b'\x91\x48\xBD\x8E\xC0\xA0\x08\xBD'
b'\x8C\xC0\xDD\x8C\xC0\xD0\xF6\x88'
b'\xD0\xF8\x68\xAA\xBD\x8E\xC0\xBD'
b'\x8C\xC0\xA0\x08\xBD\x8C\xC0\x48')
def save_track(self, physical_track_num, logical_track_num, physical_sectors): def save_track(self, physical_track_num, logical_track_num, physical_sectors):
if not physical_sectors: return {} if not physical_sectors: return {}
logical_sectors = self.rwts.reorder_to_logical_sectors(physical_sectors) logical_sectors = self.rwts.reorder_to_logical_sectors(physical_sectors)
should_run_patchers = (len(physical_sectors) == 16) # TODO if self.rwts.enough(logical_track_num, physical_sectors):
if should_run_patchers:
# patchers operate on logical tracks # patchers operate on logical tracks
if logical_track_num == 0: if logical_track_num == 0:
# set additional globals for patchers to use # set additional globals for patchers to use

View File

@ -1,5 +1,94 @@
from passport.util import * from passport.util import *
kIDBoot1 = bytes.fromhex(
"8E E9 B7"
"8E F7 B7"
"A9 01"
"8D F8 B7"
"8D EA B7"
"AD E0 B7"
"8D E1 B7"
"A9 02"
"8D EC B7"
"A9 04"
"8D ED B7"
"AC E7 B7"
"88"
"8C F1 B7"
"A9 01"
"8D F4 B7"
"8A"
"4A"
"4A"
"4A"
"4A"
"AA"
"A9 00"
"9D F8 04"
"9D 78 04")
kIDMaster = bytes.fromhex(
"8E E9 37"
"8E F7 37"
"A9 01"
"8D F8 37"
"8D EA 37"
"AD E0 37"
"8D E1 37"
"A9 02"
"8D EC 37"
"A9 04"
"8D ED 37"
"AC E7 37"
"88"
"8C F1 37"
"A9 01"
"8D F4 37"
"8A"
"4A"
"4A"
"4A"
"4A"
"AA"
"A9 00"
"9D F8 04"
"9D 78 04")
kIDRWTS = bytes.fromhex(
"84 48"
"85 49"
"A0 02"
"8C" + find.WILDSTR + find.WILDSTR + \
"A0 04"
"8C" + find.WILDSTR + find.WILDSTR + \
"A0 01"
"B1 48"
"AA"
"A0 0F"
"D1 48"
"F0 1B"
"8A"
"48"
"B1 48"
"AA"
"68"
"48"
"91 48"
"BD 8E C0"
"A0 08"
"BD 8C C0"
"DD 8C C0"
"D0 F6"
"88"
"D0 F8"
"68"
"AA"
"BD 8E C0"
"BD 8C C0"
"A0 08"
"BD 8C C0"
"48")
kIDDiversiDOSBootloader = bytes.fromhex("B3 A3 A0 D2 CF D2 D2 C5 8D 87 8D") kIDDiversiDOSBootloader = bytes.fromhex("B3 A3 A0 D2 CF D2 D2 C5 8D 87 8D")
kIDProDOSBootloader = bytes.fromhex( kIDProDOSBootloader = bytes.fromhex(
@ -20,3 +109,89 @@ kIDPascalBootloader2 = bytes.fromhex(
"B0 04" # BCS +4 "B0 04" # BCS +4
"E0 40" # CPX #$40 "E0 40" # CPX #$40
"B0") # BCS "B0") # BCS
kIDDavidDOS1 = bytes.fromhex(
"A5 27"
"C9 09"
"D0 17")
kIDDavidDOS2 = bytes.fromhex(
"A2" + find.WILDSTR + \
"BD" + find.WILDSTR + " 08" + \
"9D" + find.WILDSTR + " 04" + \
"CA"
"10 F7")
kIDDatasoft = bytes.fromhex(
"01 4C 7E 08 04 8A 0C B8"
"00 56 10 7A 00 00 1A 16"
"12 0E 0A 06 53 18 9A 02"
"10 1B 02 10 4D 56 15 0B"
"BF 14 14 54 54 54 92 81"
"1B 10 10 41 06 73 0A 10"
"33 4E 00 73 12 10 33 7C"
"00 11 20 E3 49 50 73 1A"
"10 41 00 23 80 5B 0A 10"
"0B 4E 9D 0A 10 9D 0C 10"
"60 1E 53 10 90 53 BC 90"
"53 00 90 D8 52 00 D8 7C"
"00 53 80 0B 06 41 00 09"
"04 45 0C 63 04 90 94 D0"
"D4 23 04 91 A1 EB CD 06"
"95 A1 E1 98 97 86")
kIDMicrograms1 = bytes.fromhex(
"A5 27"
"C9 09"
"D0 12"
"A9 C6"
"85 3F")
kIDMicrograms2 = bytes.fromhex("4C 00")
kIDQuickDOS = bytes.fromhex(
"A5 27"
"C9 09"
"D0 27"
"78"
"AD 83 C0")
kIDRDOS = bytes.fromhex(
"01"
"A9 60"
"8D 01 08"
"A2 00"
"A0 1F"
"B9 00 08"
"49")
kIDDOS33a = bytes.fromhex(
"01"
"A5 27"
"C9 09"
"D0 18"
"A5 2B"
"4A"
"4A"
"4A"
"4A"
"09 C0"
"85 3F"
"A9 5C"
"85 3E"
"18"
"AD FE 08"
"6D FF 08" + \
find.WILDSTR + find.WILDSTR + find.WILDSTR + \
"AE FF 08"
"30 15"
"BD 4D 08"
"85 3D"
"CE FF 08"
"AD FE 08"
"85 27"
"CE FE 08"
"A6 2B"
"6C 3E 00"
"EE FE 08"
"EE FE 08")