diff --git a/idasm/loadptp.py b/idasm/loadptp.py index 8949d69..f0e8aef 100755 --- a/idasm/loadptp.py +++ b/idasm/loadptp.py @@ -2,27 +2,31 @@ # coding: utf-8 """ -Test the format of an imlac binary file. +Load a PTP file handling various formats. Usage: - import guess_format - format = guess_format.guess('test.ptp') - if format: + import loadptp + result = loadptp.load('test.ptp') + if result: + (format, memory, start, initial_ac) = result print('test.ptp is %s format' % format) else: print('UNKNOWN FORMAT') """ -from __future__ import (absolute_import, division, print_function, unicode_literals) +#from __future__ import (absolute_import, division, print_function, unicode_literals) import struct +# size of the Imlace memory +MemSize = 04000 + # size of block loader LoaderSize = 0100 # True if debug code is active -Debug = False +Debug = True def debug(msg): @@ -109,32 +113,46 @@ def skipzeros(ptp_data, index): return None -def read_blockloader(ptp_data, index): +def read_blockloader(ptp_data, index, memory=None): """Skip over the block loader. ptp_data array of PTP data index index of next byte to read in 'ptp_data' + memory memory object to be populated with the loader code + (if None, we aren't interested in the loader code) Returns None if off the end of the tape data, else the index of the next byte to read from 'ptp_data'. """ + if memory is None: + memory = {} + + address = MemSize - LoaderSize numwords = LoaderSize while numwords > 0: result = get_word(ptp_data, index) if result is None: return None (data, index) = result - numwords = numwords - 1 + memory[address] = data + address += 1 + numwords -= 1 return index -def c8lds_handler(ptp_data): +def c8lds_handler(ptp_data, memory, loader=False, body=False): """Sees if the PTP data follows the format in "Loading the PDS-1" document. ptp_data array of PTP data + memory memory object to be populated with body code + loader True if we put loader code into memory + body True if we put body code into memory - Return True if data is 'c8lds', else False. + Returns None if PTP not recognized as 'c8lds'. + Returns a tuple (None, None) if recognized. This tuple is really + (start, initialAC) but this format PTP file doesn't cater to those values. + Note that the 'memory' may have been populated in either case. Characterized as 'c8lds' meaning an 8bit data word [C]ount, then a [L]oad address, then [D]ata words followed by a check[S]um. @@ -165,33 +183,43 @@ def c8lds_handler(ptp_data): index = 0 + if memory is None: + memory = {} + # skip initial zero leader index = skipzeros(ptp_data, index) if index is None: # empty tape debug('c8lds: No leader?') - return False + return None + + if loader: + index = read_blockloader(ptp_data, index, memory=memory) + else: + unused_mem = {} + index = read_blockloader(ptp_data, index, memory=unused_mem) - index = read_blockloader(ptp_data, index) if index is None: # short block loader? debug('c8lds: Short leader?') - return False + return None # now read data blocks + if not body: + memory = {} # save body code into unused memory while True: index = skipzeros(ptp_data, index) if index is None: # empty tape debug('c8lds: EOT looking for block?') - return False + return None # get data word count result = get_byte(ptp_data, index) if result is None: # premature end of tape? debug('c8lds: EOT at start of block?') - return False + return None (count, index) = result debug('c8lds: word count=%03o' % count) @@ -200,12 +228,12 @@ def c8lds_handler(ptp_data): if result is None: # premature end of tape? debug('c8lds: EOT getting load address?') - return False + return None (address, index) = result debug('c8lds: load address=%06o' % address) if address == 0177777: # it's an End-Of-Tape block! - break + return (None, None) # read data words, store in memory and calculate checksum checksum = 0 @@ -214,8 +242,10 @@ def c8lds_handler(ptp_data): if result is None: # premature end of tape? debug('c8lds: EOT getting data word?') - return False + return None (data, index) = result + memory[address] = data + debug('c8lds: data word=%06o' % data) address += 1 checksum += data @@ -229,18 +259,16 @@ def c8lds_handler(ptp_data): if result is None: # premature end of tape? debug('c8lds: EOT getting checksum?') - return False + return None (ptp_checksum, index) = result if ptp_checksum != checksum: # bad checksum debug('c8lds: Bad checksum? Read %06o, expected %06o.' % (ptp_checksum, checksum)) - return False + return None - # only read one block - break - - # passed all checks, so it's c8lds format - return True + # we shouldn't get here + debug('c8lds: Badly formed PTP file') + return None def lc16sd_add_csum(csum, word): """Add 'csum' and 'word', return new checksum.""" @@ -248,12 +276,21 @@ def lc16sd_add_csum(csum, word): result = (csum + word) & 0xffff return result -def lc16sd_handler(ptp_data): +def lc16sd_handler(ptp_data, memory, loader=False, body=False): """Decides if PTP data is in 'lc16sd' format. ptp_data array of PTP data + memory memory object to be populated with body code + loader True if we put loader code into memory + body True if we put body code into memory - Returns True if in 'lc16sd' format, else False. + Returns None if PTP not recognized as 'lc16sd'. + Returns a tuple (start, initialAC) if recognized. + Note that the 'memory' may have been populated in either case. + + Returns False if the PTP is not recognized as 'lc16sd'. + Returns True if in 'lc16sd' format, else False. Note that the 'memory' may + have been populated in either case. Characterized as 'lc16sd' meaning [L]oad address, then a 16bit data word [C]ount, then a 16bit check[S]um, followed by one or more [D]ata words. @@ -279,21 +316,28 @@ def lc16sd_handler(ptp_data): if index is None: # empty tape debug('lc16sd: No leader?') - return False + return None + + if loader: + index = read_blockloader(ptp_data, index, memory=memory) + else: + unused_mem = {} + index = read_blockloader(ptp_data, index, memory=unused_mem) - index = read_blockloader(ptp_data, index) if index is None: # short block loader? debug('lc16sd: Short blockloader?') - return False + return None # now read data blocks + if not body: + memory = {} while True: # get this block load address result = get_word(ptp_data, index) if result is None: debug('lc16sd: EOT getting load address?') - return False # premature end of tape? + return None # premature end of tape? (address, index) = result # if block load address has high bit set, we are finished if address & 0x8000: @@ -303,8 +347,10 @@ def lc16sd_handler(ptp_data): result = get_word(ptp_data, index) if result is None: debug('lc16sd: EOT getting AC value for autostart?') - return False # premature end of tape? - return True + return None # premature end of tape? + (initAC, index) = result + return (address & 0x3fff, initAC) + return (None, None) # read data block, calculating checksum csum = address # start checksum with base address @@ -312,7 +358,7 @@ def lc16sd_handler(ptp_data): result = get_word(ptp_data, index) if result is None: debug('lc16sd: EOT getting word count?') - return False # premature end of tape? + return None # premature end of tape? (count, index) = result neg_count = pyword(count) debug('lc16sd: count=%06o, neg_count=%d' % (count, neg_count)) @@ -321,32 +367,32 @@ def lc16sd_handler(ptp_data): result = get_word(ptp_data, index) if result is None: debug('lc16sd: EOT getting checksum?') - return False # premature end of tape? + return None # premature end of tape? (csum_word, index) = result debug('lc16sd: csum_word=%06o' % csum_word) old_csum = csum csum = lc16sd_add_csum(csum, csum_word) + # read body code, updating memory while neg_count < 0: result = get_word(ptp_data, index) if result is None: debug('lc16sd: EOT getting data word?') - return False # premature end of tape? + return None # premature end of tape? (word, index) = result debug('lc16sd: data word=%06o' % word) old_csum = csum csum = lc16sd_add_csum(csum, word) + memory[address] = word address += 1 neg_count += 1 if csum != 0: debug('lc16sd: Bad checksum, sum is %06o, expected 0?' % csum) - return False # bad block checksum + return None # bad block checksum - # only read one block - break - - # no errors, so it's c16sd - return True + # on a well-formed 'lc16sd' file we shouldn't get here + debug('lc16sd: Badly formed file') + return None # list of recognized loaders and handlers Loaders = [ @@ -354,17 +400,22 @@ Loaders = [ ('lc16sd', lc16sd_handler), ] -def guess_format(filename): - """Figure out the format of a PTP file. +def load(filename, loader=False, body=False): + """Load a PTP file into a memory object after figuring out its format. filename path of the PTP file to inspect + loader True if the blockloader code is to be loaded + body True if the body code is to be loaded - Returns None if there was a problem, else returns a 'loader' string - identifying the loader, which is the first element of the 'Loaders' - tuples above. + Returns None if there was a problem, else returns a tuple + (loader, memory, start, initial_ac) + where the 'loader' string identifies the loader, + 'memory' is a memory object holding the loaded code, + 'start' is the start addres, if any + 'initial_ac' is the initial contents of AC """ - # get entirety of PTP file into memory + # get all of PTP file into memory data = None try: with open(filename, 'rb') as handle: @@ -383,17 +434,18 @@ def guess_format(filename): # try loaders in order for (name, loader) in Loaders: try: - result = loader(ptp_data) + memory = {} + result = loader(ptp_data, memory, loader=loader, body=body) + debug('%s: result=%s' % (name, str(result))) except IndexError: - result = False - if result: - print('%14s: %s' % (name, filename)) - return name + result = None + if result is not None: + (start_addr, initial_ac) = result + return (name, memory, start_addr, initial_ac) - # if we get here, no loader was successful - print('NOT RECOGNIZED: %s' % filename) return None + if __name__ == '__main__': import sys @@ -404,10 +456,22 @@ if __name__ == '__main__': print('*'*60) print(msg) print('*'*60) - print('Usage: guess_format ') + print('Usage: loadptp ') sys.exit(10) if len(sys.argv) < 2: usage() for filename in sys.argv[1:]: - guess_format(filename) + result = load(filename, loader=True, body=True) + debug('top: result=%s' % str(result)) + if result is not None: + (loader, memory, start, initial_ac) = result + start_str = '' + if start: + start_str = ', start address is %06o' % start + initial_ac_str = '' + if initial_ac: + initial_ac_str = ', initial AC is %06o' % initial_ac + print('%14s: %s%s%s' % (loader, filename, start_str, initial_ac_str)) + else: + print('UNRECOGNIZED: %s' % filename)