diff --git a/atrcopy/__init__.py b/atrcopy/__init__.py index a41da22..cb5d34c 100644 --- a/atrcopy/__init__.py +++ b/atrcopy/__init__.py @@ -1,6 +1,9 @@ __version__ = "4.0.0" +import sys + import logging +log = logging.getLogger(__name__) try: import numpy as np @@ -143,7 +146,7 @@ def list_files(image, files): print dirent.extra_metadata(image) -def assemble(image, source_files, data_files): +def assemble(image, source_files, data_files, run_addr=""): if source_files: try: import pyatasm @@ -156,15 +159,17 @@ def assemble(image, source_files, data_files): asm = pyatasm.Assemble(name) except SyntaxError, e: raise AtrError("Assembly error: %s" % e.msg) + log.debug("Assembled %s into:" % name) for first, last, object_code in asm.segments: s = segments.add_segment(object_code, first) - print s.name + log.debug(" %s" % s.name) for name in data_files: if "@" not in name: raise AtrError("Data files must include a load address specified with the @ char") name, addr = name.rsplit("@", 1) first = text_to_int(addr) - subset = slice(0, -1) + log.debug("Adding data file %s at $%04x" % (name, first)) + subset = slice(0, sys.maxint) if "[" in name and "]" in name: name, slicetext = name.rsplit("[", 1) if ":" in slicetext: @@ -183,11 +188,17 @@ def assemble(image, source_files, data_files): with open(name, 'rb') as fh: data = fh.read()[subset] s = segments.add_segment(data, first) - print s.name + log.debug("read data for %s" % s.name) if options.verbose: for s in segments: print "%s - %04x)" % (str(s)[:-1], s.start_addr + len(s)) - file_data, filetype = image.create_executable_file_image(segments) + if run_addr: + try: + run_addr = text_to_int(run_addr) + except ValueError: + run_addr = None + + file_data, filetype = image.create_executable_file_image(segments, run_addr) changed = save_file(image, options.output, filetype, file_data) if changed: image.save() @@ -216,6 +227,7 @@ def run(): parser.add_argument("-t", "--filetype", action="store", default="", help="file type metadata for writing to disk images that require it") parser.add_argument("-s", "--asm", nargs="+", action="append", help="source file(s) to assemble using pyatasm (requires -o to specify filename stored on disk image)") parser.add_argument("-b", "--bytes", nargs="+", action="append", help="data file(s) to add to assembly, specify as file@addr (requires -o to specify filename stored on disk image)") + parser.add_argument("--run-addr", "--brun", action="store", default="", help="run address of binary file if not the first byte of the first segment") parser.add_argument("-o", "--output", action="store", default="", help="output file name for those commands that need it") parser.add_argument("-f", "--force", action="store_true", default=False, help="force operation, allowing file overwrites or attempt operation on non-standard disk images") parser.add_argument("--all", action="store_true", default=False, help="operate on all files on disk image") @@ -276,7 +288,7 @@ def run(): elif options.asm or options.bytes: asm = options.asm[0] if options.asm else [] datafiles = options.bytes[0] if options.bytes else [] - assemble(parser.image, asm, datafiles) + assemble(parser.image, asm, datafiles, options.run_addr) else: list_files(parser.image, file_list) diff --git a/atrcopy/ataridos.py b/atrcopy/ataridos.py index 58ce777..047478d 100644 --- a/atrcopy/ataridos.py +++ b/atrcopy/ataridos.py @@ -649,7 +649,7 @@ class AtariDosDiskImage(DiskImageBase): log.debug("%s not a binary file; skipping segment generation" % str(segment)) return segments_out - def create_executable_file_image(self, segments,run_addr=None): + def create_executable_file_image(self, segments, run_addr=None): return get_xex(segments, run_addr), "XEX" diff --git a/atrcopy/dos33.py b/atrcopy/dos33.py index 01d2d17..fffbb36 100644 --- a/atrcopy/dos33.py +++ b/atrcopy/dos33.py @@ -3,7 +3,7 @@ import numpy as np from errors import * from diskimages import BaseHeader, DiskImageBase from utils import Directory, VTOC, WriteableSector, BaseSectorList, Dirent -from segments import DefaultSegment, EmptySegment, ObjSegment, RawTrackSectorSegment, SegmentSaver, get_style_bits +from segments import DefaultSegment, EmptySegment, ObjSegment, RawTrackSectorSegment, SegmentSaver, get_style_bits, SegmentData import logging log = logging.getLogger(__name__) @@ -586,21 +586,33 @@ class Dos33DiskImage(DiskImageBase): segment = EmptySegment(self.rawdata, name=dirent.filename) return segment - def create_executable_file_image(self, segments): + def create_executable_file_image(self, segments, run_addr=None): + # Apple 2 executables get executed at the first address loaded. If the + # run_addr is not the first byte of the combined data, have to create a + # new 3-byte segment with a "JMP run_addr" to go at the beginning origin = 100000000 last = -1 + for s in segments: origin = min(origin, s.start_addr) last = max(last, s.start_addr + len(s)) - print "contiguous bytes needed: %04x - %04x" % (origin, last) + log.debug("contiguous bytes needed: %04x - %04x" % (origin, last)) + if run_addr and run_addr != origin: + origin -= 3 + hi, lo = divmod(run_addr, 256) + raw = SegmentData([0x4c, lo, hi]) + all_segments = [DefaultSegment(raw, start_addr=origin)] + all_segments.extend(segments) + else: + all_segments = segments size = last - origin image = np.zeros([size + 4], dtype=np.uint8) words = image[0:4].view(dtype="