mirror of
https://github.com/a2-4am/passport.py.git
synced 2024-06-26 05:29:35 +00:00
various speed improvements
This commit is contained in:
parent
47b9b27a4c
commit
dd8761c7c5
|
@ -2,6 +2,7 @@ from passport.loggers import *
|
||||||
from passport.rwts import *
|
from passport.rwts import *
|
||||||
from passport.patchers import *
|
from passport.patchers import *
|
||||||
from passport.strings import *
|
from passport.strings import *
|
||||||
|
from passport.constants import *
|
||||||
from passport.util import *
|
from passport.util import *
|
||||||
from passport import wozardry
|
from passport import wozardry
|
||||||
import bitarray
|
import bitarray
|
||||||
|
@ -165,32 +166,16 @@ class BasePassportProcessor: # base class
|
||||||
|
|
||||||
def IDDiversi(self, t00s00):
|
def IDDiversi(self, t00s00):
|
||||||
"""returns True if T00S00 is Diversi-DOS bootloader, or False otherwise"""
|
"""returns True if T00S00 is Diversi-DOS bootloader, or False otherwise"""
|
||||||
return find.at(0xF1, t00s00,
|
return find.at(0xF1, t00s00, kIDDiversiDOSBootloader)
|
||||||
b'\xB3\xA3\xA0\xD2\xCF\xD2\xD2\xC5'
|
|
||||||
b'\x8D\x87\x8D')
|
|
||||||
|
|
||||||
def IDProDOS(self, t00s00):
|
def IDProDOS(self, t00s00):
|
||||||
"""returns True if T00S00 is ProDOS bootloader, or False otherwise"""
|
"""returns True if T00S00 is ProDOS bootloader, or False otherwise"""
|
||||||
return find.at(0x00, t00s00,
|
return find.at(0x00, t00s00, kIDProDOSBootloader)
|
||||||
b'\x01'
|
|
||||||
b'\x38'
|
|
||||||
b'\xB0\x03'
|
|
||||||
b'\x4C')
|
|
||||||
|
|
||||||
def IDPascal(self, t00s00):
|
def IDPascal(self, t00s00):
|
||||||
"""returns True if T00S00 is Pascal bootloader, or False otherwise"""
|
"""returns True if T00S00 is Pascal bootloader, or False otherwise"""
|
||||||
if find.wild_at(0x00, t00s00,
|
return find.wild_at(0x00, t00s00, kIDPascalBootloader1) or \
|
||||||
b'\x01'
|
find.at(0x00, t00s00, kIDPascalBootloader2)
|
||||||
b'\xE0\x60'
|
|
||||||
b'\xF0\x03'
|
|
||||||
b'\x4C' + find.WILDCARD + b'\x08'):
|
|
||||||
return True
|
|
||||||
return find.at(0x00, t00s00,
|
|
||||||
b'\x01'
|
|
||||||
b'\xE0\x70'
|
|
||||||
b'\xB0\x04'
|
|
||||||
b'\xE0\x40'
|
|
||||||
b'\xB0')
|
|
||||||
|
|
||||||
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"""
|
||||||
|
@ -683,30 +668,23 @@ class BasePassportProcessor: # base class
|
||||||
# .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))
|
self.g.logger.debug("Seeking to track %s" % hex(self.g.track))
|
||||||
try_again = True
|
|
||||||
tried_reseek = False
|
tried_reseek = False
|
||||||
while try_again:
|
while True:
|
||||||
try_again = False
|
|
||||||
physical_sectors = self.rwts.decode_track(self.tracks[physical_track_num], logical_track_num, self.burn)
|
physical_sectors = self.rwts.decode_track(self.tracks[physical_track_num], logical_track_num, self.burn)
|
||||||
if len(physical_sectors) == self.rwts.sectors_per_track:
|
if self.rwts.enough(logical_track_num, physical_sectors):
|
||||||
# TODO this is bad, we should just ask the RWTS object if we decoded enough sectors,
|
break
|
||||||
# so that SunburstRWTS can override the logic on track 0x11
|
|
||||||
continue
|
|
||||||
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
|
||||||
try_again = True
|
|
||||||
continue
|
continue
|
||||||
self.g.logger.debug("found %d sectors" % len(physical_sectors))
|
self.g.logger.debug("found %d sectors" % len(physical_sectors))
|
||||||
if self.rwts.__class__ is SunburstRWTS and logical_track_num == 0x11:
|
|
||||||
# TODO this is bad, see above
|
|
||||||
continue
|
|
||||||
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
|
||||||
continue
|
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("fatal220f")
|
self.g.logger.PrintByID("fatal220f")
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
|
@ -716,11 +694,9 @@ class BasePassportProcessor: # base class
|
||||||
self.g.logger.PrintByID("switch", {"sector":0x0F}) # TODO find exact sector
|
self.g.logger.PrintByID("switch", {"sector":0x0F}) # TODO find exact sector
|
||||||
self.rwts = UniversalRWTS(self.g)
|
self.rwts = UniversalRWTS(self.g)
|
||||||
self.g.tried_univ = True
|
self.g.tried_univ = True
|
||||||
try_again = 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)
|
||||||
try_again = True
|
|
||||||
continue
|
continue
|
||||||
self.g.logger.PrintByID("fail")
|
self.g.logger.PrintByID("fail")
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -10,30 +10,29 @@ class A2RImage:
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
self.tracks = collections.OrderedDict()
|
self.tracks = collections.OrderedDict()
|
||||||
self.a2r_image = a2rchery.A2RReader(filename, stream)
|
self.a2r_image = a2rchery.A2RReader(filename, stream)
|
||||||
|
self.speed = 0
|
||||||
|
|
||||||
def to_bits(self, flux_record):
|
def to_bits(self, flux_record):
|
||||||
"""|flux_record| is a dictionary of 'capture_type', 'data_length', 'tick_count', and 'data'"""
|
"""|flux_record| is a dictionary of 'capture_type', 'data_length', 'tick_count', and 'data'"""
|
||||||
bits = bitarray.bitarray()
|
bits = bitarray.bitarray()
|
||||||
estimated_track_length = 0
|
|
||||||
if not flux_record or flux_record["capture_type"] != a2rchery.kCaptureTiming:
|
if not flux_record or flux_record["capture_type"] != a2rchery.kCaptureTiming:
|
||||||
return bits, estimated_track_length, 0
|
return bits
|
||||||
ticks = 0
|
fluxxen = flux_record["data"][1:]
|
||||||
flux_total = 0
|
if not self.speed:
|
||||||
fluxxen = flux_record["data"]
|
speeds = [(len([1 for i in fluxxen[:8192] if i%t==0]), t) for t in range(0x1e,0x23)]
|
||||||
speeds = [(len([1 for i in fluxxen if i%t==0]), t) for t in range(0x1c,0x25)]
|
speeds.sort()
|
||||||
speeds.sort()
|
self.speed = speeds[-1][1]
|
||||||
speed = speeds[-1][1]
|
speed = self.speed
|
||||||
for flux_value in fluxxen[1:]:
|
flux_total = flux_start = -speed//2
|
||||||
ticks += flux_value
|
for flux_value in fluxxen:
|
||||||
if not estimated_track_length and ticks > flux_record["tick_count"]:
|
|
||||||
estimated_track_length = len(bits)
|
|
||||||
flux_total += flux_value
|
flux_total += flux_value
|
||||||
if flux_value == 0xFF:
|
if flux_value == 0xFF:
|
||||||
continue
|
continue
|
||||||
bits.extend([0] * ((flux_total - speed//2) // speed))
|
if flux_total >= speed:
|
||||||
bits.append(1)
|
bits.extend("0" * (flux_total // speed))
|
||||||
flux_total = 0
|
bits.extend("1")
|
||||||
return bits, estimated_track_length, speed
|
flux_total = flux_start
|
||||||
|
return bits
|
||||||
|
|
||||||
def seek(self, track_num):
|
def seek(self, track_num):
|
||||||
if type(track_num) != float:
|
if type(track_num) != float:
|
||||||
|
@ -48,16 +47,20 @@ class A2RImage:
|
||||||
# (if the caller determines that they're not good, it will call reseek()
|
# (if the caller determines that they're not good, it will call reseek()
|
||||||
# which is smarter but takes longer)
|
# which is smarter but takes longer)
|
||||||
bits = bitarray.bitarray()
|
bits = bitarray.bitarray()
|
||||||
for flux_record in self.a2r_image.flux.get(location, [{}])[:1]:
|
if location in self.a2r_image.flux:
|
||||||
bits, track_length, speed = self.to_bits(flux_record)
|
bits = self.to_bits(self.a2r_image.flux[location][0])
|
||||||
self.tracks[location] = Track(bits, len(bits))
|
self.tracks[location] = Track(bits, len(bits))
|
||||||
return self.tracks[location]
|
return self.tracks[location]
|
||||||
|
|
||||||
def reseek(self, track_num):
|
def reseek(self, track_num):
|
||||||
location = int(track_num * 4)
|
location = int(track_num * 4)
|
||||||
all_bits = bitarray.bitarray()
|
# reset cached speed so we'll recalculate it
|
||||||
for flux_record in self.a2r_image.flux.get(location, [{}]):
|
self.speed = 0
|
||||||
bits, track_length, speed = self.to_bits(flux_record)
|
# read the rest of the flux records and concatenate them on the end
|
||||||
all_bits.extend(bits)
|
# of the existing bitstream (this assumes you've called seek() before
|
||||||
|
# on this track)
|
||||||
|
all_bits = self.tracks[location].bits
|
||||||
|
for flux_record in self.a2r_image.flux[location][1:]:
|
||||||
|
all_bits.extend(self.to_bits(flux_record))
|
||||||
self.tracks[location] = Track(all_bits, len(all_bits))
|
self.tracks[location] = Track(all_bits, len(all_bits))
|
||||||
return self.tracks[location]
|
return self.tracks[location]
|
||||||
|
|
22
passport/constants.py
Normal file
22
passport/constants.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
from passport.util import *
|
||||||
|
|
||||||
|
kIDDiversiDOSBootloader = bytes.fromhex("B3 A3 A0 D2 CF D2 D2 C5 8D 87 8D")
|
||||||
|
|
||||||
|
kIDProDOSBootloader = bytes.fromhex(
|
||||||
|
"01"
|
||||||
|
"38" # SEC
|
||||||
|
"B0 03" # BCS +3
|
||||||
|
"4C") # JMP
|
||||||
|
|
||||||
|
kIDPascalBootloader1 = bytes.fromhex(
|
||||||
|
"01"
|
||||||
|
"E0 60" # CPX #$60
|
||||||
|
"F0 03" # BEQ +3
|
||||||
|
"4C" + find.WILDSTR + "08") # JMP $08**
|
||||||
|
|
||||||
|
kIDPascalBootloader2 = bytes.fromhex(
|
||||||
|
"01"
|
||||||
|
"E0 70" # CPX #$70
|
||||||
|
"B0 04" # BCS +4
|
||||||
|
"E0 40" # CPX #$40
|
||||||
|
"B0") # BCS
|
|
@ -204,6 +204,9 @@ class RWTS:
|
||||||
break
|
break
|
||||||
return sectors
|
return sectors
|
||||||
|
|
||||||
|
def enough(self, logical_track_num, physical_sectors):
|
||||||
|
return len(physical_sectors) == self.sectors_per_track
|
||||||
|
|
||||||
from .universal import *
|
from .universal import *
|
||||||
from .dos33 import *
|
from .dos33 import *
|
||||||
from .sunburst import *
|
from .sunburst import *
|
||||||
|
|
|
@ -16,7 +16,17 @@ class SunburstRWTS(DOS33RWTS):
|
||||||
self.data_prologue[1],
|
self.data_prologue[1],
|
||||||
self.data_prologue_third_nibble_by_track[logical_track_num])
|
self.data_prologue_third_nibble_by_track[logical_track_num])
|
||||||
DOS33RWTS.seek(self, logical_track_num)
|
DOS33RWTS.seek(self, logical_track_num)
|
||||||
|
if logical_track_num == 0x11:
|
||||||
|
self.sector_order = (0x00, 0x07, 0x08, 0x06, 0x0D, 0x05, 0x0C, 0x04, 0x0B, 0x03, 0x0A, 0x02, 0x09, 0x01, 0x08, 0x0F)
|
||||||
|
else:
|
||||||
|
self.sector_order = self.kDefaultSectorOrder16
|
||||||
|
|
||||||
if logical_track_num >= 0x11:
|
if logical_track_num >= 0x11:
|
||||||
return logical_track_num + 0.5
|
return logical_track_num + 0.5
|
||||||
else:
|
else:
|
||||||
return float(logical_track_num)
|
return float(logical_track_num)
|
||||||
|
|
||||||
|
def enough(self, logical_track_num, physical_sectors):
|
||||||
|
if logical_track_num == 0x11:
|
||||||
|
return len(physical_sectors) >= 14
|
||||||
|
return DOS33RWTS.enough(self, logical_track_num, physical_sectors)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
__date__ = "2019-02-01"
|
__date__ = "2019-02-02"
|
||||||
|
|
||||||
STRINGS = {
|
STRINGS = {
|
||||||
"header": "Passport.py by 4am (" + __date__ + ")\n", # max 32 characters
|
"header": "Passport.py by 4am (" + __date__ + ")\n", # max 32 characters
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
WILDCARD = b'\x97'
|
WILDCARD = b'\x97'
|
||||||
|
WILDSTR = "97"
|
||||||
|
|
||||||
def wild(source_bytes, search_bytes):
|
def wild(source_bytes, search_bytes):
|
||||||
"""Search source_bytes (bytes object) for the first instance of search_bytes (bytes_object). search_bytes may contain WILDCARD, which matches any single byte (like "." in a regular expression). Returns index of first match, or -1 if no matches."""
|
"""Search source_bytes (bytes object) for the first instance of search_bytes (bytes_object). search_bytes may contain WILDCARD, which matches any single byte (like "." in a regular expression). Returns index of first match, or -1 if no matches."""
|
||||||
|
|
Loading…
Reference in New Issue
Block a user