diff --git a/README.rst b/README.rst index 8da1d72..913a42a 100644 --- a/README.rst +++ b/README.rst @@ -7,6 +7,11 @@ images. Prerequisites ------------- +``atrcopy`` 4.0 introduces a new command line argument structure based on +subcommands, much like ``git`` uses ``git pull``, ``git clone``, ``git +branch``, etc. Upgrading to 4.0 will require modification of scripts that use +``atrcopy`` 3.x-style command line arguments. + Starting with ``atrcopy`` 2.0, `numpy `_ is required. It will be automatically installed when installing ``atrcopy`` with:: @@ -118,7 +123,8 @@ abbreviated as shown here:: happened -Help for available options for each command is available using:: +Help for available options for each command is available without specifying a +disk image, using a command line like:: atrcopy COMMAND --help @@ -178,9 +184,10 @@ Extract all files:: extracting File #4 (.2.u.*) 162 COPY32 COM 056 -> COPY32.COM extracting File #5 (.2.u.*) 218 DISKFIX COM 057 -> DISKFIX.COM -Extract all, renaming to lower case on the host file system:: +Extract all, using the abbreviated commandn and renaming to lower case on the +host file system:: - $ atrcopy DOS_25.ATR extract --all -l + $ atrcopy DOS_25.ATR x --all -l DOS_25.ATR: ATR Disk Image (size=133120 (1040x128b), crc=0 flags=0 unused=0) Atari DOS Format: 1010 usable sectors (739 free), 6 files extracting File #0 (.2.u.*) 004 DOS SYS 037 -> dos.sys extracting File #1 (.2.u.*) 041 DUP SYS 042 -> dup.sys @@ -242,31 +249,6 @@ The simple assembler included in ``atrcopy`` can create binary programs by connecting binary data together in a single file and specifying a start address so it can be executed by the system's binary run command. -The following command links together a hires image loaded at 2000 hex (the -first hires screen) and code at 6000 hex (that was assembled using an external -program, in this case the assembler from the cc65 project) and sets a start -address of 6000 hex. (Note that all the addresses are implicitly hex values.) -Because the Apple ][ binary format is limited to a single contiguous block of -data with a start address of the first byte of data loaded, ``atrcopy`` will fill -the gaps between any segments that aren't contiguous with zeros. If the start -address is not the first byte of the first specified segment, a mini-segment -will be included at the beginning that jumps to the specified ``brun`` address -(shown here as the segment from 1ffd - 2000). Note the gap between 4000 and -6000 hex will be filled with zeros:: - - $ atrcopy game.dsk create dos33autobrun - using dos33autobrun template: Apple ][ DOS 3.3 (140K) standard RWTS, HGR, BRUN a file named AUTOBRUN - created game.dsk: DOS 3.3 Disk Image (size=143360 (560x256b) - File #0 ( A) 002 HELLO 003 001 - - $ atrcopy game.dsk asm -b title.bin@2000 game[4:]@6000 --brun 6000 -f -o AUTOBRUN - game.dsk: DOS 3.3 Disk Image (size=143360 (560x256b) - setting data for $1ffd - $2000 at index $0004 - setting data for $2000 - $4000 at index $0007 - setting data for $6000 - $6ef3 at index $4007 - total file size: $4efa (20218) bytes - copying AUTOBRUN to game.dsk - It is also possible to assemble text files that use the MAC/65 syntax, because support for `pyatasm `_ is built-in (but optional). MAC/65 is a macro assembler originally designed for the Atari 8-bit @@ -274,6 +256,44 @@ machines but since it produces 6502 code it can be used to compile for any machine that uses the 6502: Apple, Commodore, etc. +Creating DOS 3.3 Binaries +~~~~~~~~~~~~~~~~~~~~~~~~~ + +For this example, the goal is to produce a single binary file that combines a +hi-res image ``title.bin`` loaded at 2000 hex (the first hi-res screen) and +code at 6000 hex from the binary file ``game``, with a start address of 6000 +hex. + +The binary file ``game`` was assembled using the assembler from the +`cc65`_ project, using the command:: + + cl65 -t apple2 --cpu 6502 --start-addr 0x6000 -o game game.s + +Because the Apple ][ binary format is limited to a single contiguous block of +data with a start address of the first byte of data loaded, ``atrcopy`` will +fill the gaps between any segments that aren't contiguous with zeros. If the +start address is not the first byte of the first specified segment, a small +segment will be included at the beginning that jumps to the specified ``brun`` +address (shown here as the segment from 1ffd - 2000). Note the gap between 4000 +and 6000 hex will be filled with zeros:: + + $ atrcopy game.dsk create dos33autobrun + using dos33autobrun template: + Apple ][ DOS 3.3 (140K) disk image for binary program development: HELLO sets + fullscreen HGR and calls BRUN on user-supplied AUTOBRUN binary file + created game.dsk: DOS 3.3 Disk Image (size=143360 (560x256b) + File #0 ( A) 002 HELLO 003 001 + + $ atrcopy game.dsk asm -d title.bin@2000 -b game --brun 6000 -f -o AUTOBRUN + game.dsk: DOS 3.3 Disk Image (size=143360 (560x256b) + adding BSAVE data $6000-$6ef3 ($0ef3 @ $0004) from game + setting data for $1ffd - $2000 at index $0004 + setting data for $2000 - $4000 at index $0007 + setting data for $6000 - $6ef3 at index $4007 + total file size: $4efa (20218) bytes + copying AUTOBRUN to game.dsk + + Example on Mac OS X ------------------- diff --git a/atrcopy/__init__.py b/atrcopy/__init__.py index 06a7d76..0f16f75 100644 --- a/atrcopy/__init__.py +++ b/atrcopy/__init__.py @@ -175,7 +175,7 @@ def crc_files(image, files): print("%s: %08x" % (dirent.filename, crc)) -def assemble(image, source_files, data_files, run_addr=""): +def assemble(image, source_files, data_files, obj_files, run_addr=""): if source_files: try: import pyatasm @@ -218,6 +218,13 @@ def assemble(image, source_files, data_files, run_addr=""): data = fh.read()[subset] s = segments.add_segment(data, first) log.debug("read data for %s" % s.name) + for name in obj_files: + parser = find_diskimage(name) + if parser and parser.image: + for s in parser.segments: + if s.start_addr > 0: + print "adding %s from %s" % (s, name) + segments.add_segment(s.data, s.start_addr) if options.verbose: for s in segments: print "%s - %04x)" % (str(s)[:-1], s.start_addr + len(s)) @@ -418,7 +425,8 @@ def run(): assembly_parser = subparsers.add_parser(command, help="Create a new binary file in the disk image", aliases=command_aliases[command]) assembly_parser.add_argument("-f", "--force", action="store_true", default=False, help="allow file overwrites in the disk image") assembly_parser.add_argument("-s", "--asm", nargs="*", action="append", help="source file(s) to assemble using pyatasm") - assembly_parser.add_argument("-d","-b", "--data", nargs="*", action="append", help="binary data file(s) to add to assembly, specify as file@addr. Only a portion of the file may be included; specify the subset using standard python slice notation: file[subset]@addr") + assembly_parser.add_argument("-d","--data", nargs="*", action="append", help="binary data file(s) to add to assembly, specify as file@addr. Only a portion of the file may be included; specify the subset using standard python slice notation: file[subset]@addr") + assembly_parser.add_argument("-b", "--obj", "--bload", nargs="*", action="append", help="binary file(s) to add to assembly, either executables or labeled memory dumps (e.g. BSAVE on Apple ][), parsing each file's binary segments to add to the resulting disk image at the load address for each segment") assembly_parser.add_argument("-r", "--run-addr", "--brun", action="store", default="", help="run address of binary file if not the first byte of the first segment") assembly_parser.add_argument("-o", "--output", action="store", default="", required=True, help="output file name in disk image") @@ -522,7 +530,8 @@ def run(): elif command == "assemble": asm = options.asm[0] if options.asm else [] data = options.data[0] if options.data else [] - assemble(parser.image, asm, data, options.run_addr) + obj = options.obj[0] if options.obj else [] + assemble(parser.image, asm, data, obj, options.run_addr) elif command == "segments": print "\n".join([str(a) for a in parser.segments]) else: diff --git a/atrcopy/dos33.py b/atrcopy/dos33.py index 0de329f..6282536 100644 --- a/atrcopy/dos33.py +++ b/atrcopy/dos33.py @@ -625,6 +625,48 @@ class Dos33DiskImage(DiskImageBase): return image, 'B' +class Dos33BinFile(object): + """Parse a binary chunk into segments according to the DOS 3.3 binary + dump format + """ + + def __init__(self, rawdata): + self.rawdata = rawdata + self.size = len(rawdata) + self.segments = [] + self.files = [] + + def __str__(self): + return "\n".join(str(s) for s in self.segments) + "\n" + + def strict_check(self): + pass + + def relaxed_check(self): + pass + + def parse_segments(self): + r = self.rawdata + b = r.get_data() + s = r.get_style() + pos = 0 + style_pos = 0 + first = True + log.debug("Initial parsing: size=%d" % self.size) + if len(b[pos:pos + 4]) == 4: + start, count = b[pos:pos + 4].view(dtype='