Added Apple BSAVE file parser

* added object file parsing into assembled files
* updated docs
This commit is contained in:
Rob McMullen 2017-05-06 16:49:42 -07:00
parent e91c14d1f9
commit e06a82e611
4 changed files with 113 additions and 32 deletions

View File

@ -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 <http://www.numpy.org/>`_ 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 <https://pypi.python.org/pypi/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<https://github.com/cc65/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
-------------------

View File

@ -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:

View File

@ -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='<u2')
s[pos:pos + 4] = get_style_bits(data=True)
data = b[pos + 4:pos + 4 + count]
if len(data) == count:
name = "BSAVE data" % start
else:
name = "Incomplete data: expected %04x, loaded %04x" % (count, len(data))
self.segments.append(ObjSegment(r[pos + 4:pos + 4 + count], pos, pos + 4, start, start + len(data), name))
else:
self.segments.append(ObjSegment(r[pos:pos + 4], 0, 0, 0, len(b[pos:pos + 4]), "Short Segment Header"))
class ProdosHeader(Dos33Header):
file_format = "ProDOS"

View File

@ -6,7 +6,7 @@ from ataridos import AtariDosDiskImage, BootDiskImage, AtariDosFile, XexContaine
from spartados import SpartaDosDiskImage
from cartridge import AtariCartImage, get_known_carts
from mame import MameZipImage
from dos33 import Dos33DiskImage, ProdosDiskImage
from dos33 import Dos33DiskImage, ProdosDiskImage, Dos33BinFile
from errors import *
import logging
@ -130,6 +130,11 @@ class Dos33SegmentParser(SegmentParser):
image_type = Dos33DiskImage
class Dos33BinSegmentParser(SegmentParser):
menu_name = "BIN (Apple ][ executable)"
image_type = Dos33BinFile
class ProdosSegmentParser(SegmentParser):
menu_name = "ProDOS Disk Image"
image_type = ProdosDiskImage
@ -187,6 +192,9 @@ mime_parsers = {
Dos33SegmentParser,
ProdosSegmentParser,
],
"application/vnd.apple2.bin": [
Dos33BinSegmentParser,
],
}
mime_parse_order = [
@ -196,6 +204,7 @@ mime_parse_order = [
"application/vnd.atari8bit.5200_cart",
"application/vnd.mame_rom",
"application/vnd.apple2.dsk",
"application/vnd.apple2.bin",
]
pretty_mime = {
@ -205,6 +214,7 @@ pretty_mime = {
"application/vnd.atari8bit.5200_cart":"Atari 5200 Cartridge",
"application/vnd.mame_rom": "MAME",
"application/vnd.apple2.dsk": "Apple ][ Disk Image",
"application/vnd.apple2.bin": "Apple ][ Binary",
}
grouped_carts = get_known_carts()