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='