mirror of
https://github.com/robmcmullen/atrcopy.git
synced 2024-12-02 00:51:41 +00:00
Added -s command to use pyatasm to assemble MAC/65 source and place it in a file in the disk image
This commit is contained in:
parent
3e77cb86bc
commit
07cdb05ba2
@ -90,27 +90,32 @@ def extract_files(image, files):
|
|||||||
with open(name, "wb") as fh:
|
with open(name, "wb") as fh:
|
||||||
fh.write(data)
|
fh.write(data)
|
||||||
|
|
||||||
def add_files(image, files):
|
def save_file(image, name, filetype, data):
|
||||||
filetype = options.filetype
|
|
||||||
if not filetype:
|
|
||||||
filetype = image.default_filetype
|
|
||||||
changed = False
|
|
||||||
for name in files:
|
|
||||||
try:
|
try:
|
||||||
dirent = image.find_dirent(name)
|
dirent = image.find_dirent(name)
|
||||||
if options.force:
|
if options.force:
|
||||||
image.delete_file(name)
|
image.delete_file(name)
|
||||||
else:
|
else:
|
||||||
print "skipping %s, use -f to overwrite" % (name)
|
print "skipping %s, use -f to overwrite" % (name)
|
||||||
continue
|
return False
|
||||||
except FileNotFound:
|
except FileNotFound:
|
||||||
pass
|
pass
|
||||||
print "copying %s to %s" % (name, image)
|
print "copying %s to %s" % (name, image)
|
||||||
if not options.dry_run:
|
if not options.dry_run:
|
||||||
|
image.write_file(name, filetype, data)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def add_files(image, files):
|
||||||
|
filetype = options.filetype
|
||||||
|
if not filetype:
|
||||||
|
filetype = image.default_filetype
|
||||||
|
changed = False
|
||||||
|
for name in files:
|
||||||
with open(name, "rb") as fh:
|
with open(name, "rb") as fh:
|
||||||
data = fh.read()
|
data = fh.read()
|
||||||
image.write_file(name, filetype, data)
|
changed = save_file(image, name, filetype, data)
|
||||||
changed = True
|
|
||||||
if changed:
|
if changed:
|
||||||
image.save()
|
image.save()
|
||||||
|
|
||||||
@ -135,6 +140,32 @@ def list_files(image, files):
|
|||||||
if not files or dirent.filename in files:
|
if not files or dirent.filename in files:
|
||||||
print dirent
|
print dirent
|
||||||
|
|
||||||
|
def assemble(image, files):
|
||||||
|
try:
|
||||||
|
import pyatasm
|
||||||
|
except ImportError:
|
||||||
|
raise AtrError("Please install pyatasm to compile code.")
|
||||||
|
changed = False
|
||||||
|
segments = []
|
||||||
|
print files
|
||||||
|
for name in files:
|
||||||
|
try:
|
||||||
|
asm = pyatasm.Assemble(name)
|
||||||
|
except SyntaxError, e:
|
||||||
|
raise AtrError("Assembly error: %s" % e.msg)
|
||||||
|
for first, last, object_code in asm.segments:
|
||||||
|
print "%04x - %04x, size=%04x" % (first, last, len(object_code))
|
||||||
|
rawdata = SegmentData(object_code)
|
||||||
|
s = DefaultSegment(rawdata, first, name)
|
||||||
|
segments.append(s)
|
||||||
|
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)
|
||||||
|
changed = save_file(image, options.output, filetype, file_data)
|
||||||
|
if changed:
|
||||||
|
image.save()
|
||||||
|
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
import sys
|
import sys
|
||||||
@ -152,12 +183,15 @@ def run():
|
|||||||
parser.add_argument("--xex", action="store_true", default=False, help="add .xex extension")
|
parser.add_argument("--xex", action="store_true", default=False, help="add .xex extension")
|
||||||
parser.add_argument("-f", "--force", action="store_true", default=False, help="force operation, allowing file overwrites and operation on non-standard disk images")
|
parser.add_argument("-f", "--force", action="store_true", default=False, help="force operation, allowing file overwrites and operation on non-standard disk images")
|
||||||
parser.add_argument("files", metavar="IMAGE", nargs="+", help="a disk image file [or a list of them]")
|
parser.add_argument("files", metavar="IMAGE", nargs="+", help="a disk image file [or a list of them]")
|
||||||
parser.add_argument("-s", "--segments", action="store_true", default=False, help="display segments")
|
parser.add_argument("-g", "--segments", action="store_true", default=False, help="display segments")
|
||||||
parser.add_argument("-x", "-e", "--extract", action="store_true", default=False, help="extract named files")
|
parser.add_argument("-x", "-e", "--extract", action="store_true", default=False, help="extract named files")
|
||||||
parser.add_argument("-a", "--add", action="store_true", default=False, help="add files to image")
|
parser.add_argument("-a", "--add", action="store_true", default=False, help="add files to image")
|
||||||
parser.add_argument("-r", "--remove", action="store_true", default=False, help="remove named files from image")
|
parser.add_argument("-r", "--remove", action="store_true", default=False, help="remove named files from image")
|
||||||
parser.add_argument("-t", "--filetype", action="store", default="", help="file type metadata for writing to disk images that require it")
|
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("-o", "--output", action="store", default="", help="output file name for those commands that need it")
|
||||||
options, extra_args = parser.parse_known_args()
|
options, extra_args = parser.parse_known_args()
|
||||||
|
print options, extra_args
|
||||||
|
|
||||||
# Turn off debug messages by default
|
# Turn off debug messages by default
|
||||||
logging.basicConfig(level=logging.WARNING)
|
logging.basicConfig(level=logging.WARNING)
|
||||||
@ -186,5 +220,7 @@ def run():
|
|||||||
extract_files(parser.image, file_list)
|
extract_files(parser.image, file_list)
|
||||||
elif options.remove:
|
elif options.remove:
|
||||||
remove_files(parser.image, file_list)
|
remove_files(parser.image, file_list)
|
||||||
|
elif options.asm:
|
||||||
|
assemble(parser.image, options.asm[0])
|
||||||
else:
|
else:
|
||||||
list_files(parser.image, file_list)
|
list_files(parser.image, file_list)
|
||||||
|
@ -2,7 +2,7 @@ import numpy as np
|
|||||||
|
|
||||||
from errors import *
|
from errors import *
|
||||||
from diskimages import DiskImageBase, BaseHeader
|
from diskimages import DiskImageBase, BaseHeader
|
||||||
from segments import EmptySegment, ObjSegment, RawSectorsSegment, DefaultSegment, SegmentSaver, get_style_bits
|
from segments import SegmentData, EmptySegment, ObjSegment, RawSectorsSegment, DefaultSegment, SegmentSaver, get_style_bits
|
||||||
from utils import *
|
from utils import *
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
@ -616,6 +616,9 @@ class AtariDosDiskImage(DiskImageBase):
|
|||||||
log.debug("%s not a binary file; skipping segment generation" % str(segment))
|
log.debug("%s not a binary file; skipping segment generation" % str(segment))
|
||||||
return segments_out
|
return segments_out
|
||||||
|
|
||||||
|
def create_executable_file_image(self, segments,run_addr=None):
|
||||||
|
return get_xex(segments, run_addr), "XEX"
|
||||||
|
|
||||||
|
|
||||||
class BootDiskImage(AtariDosDiskImage):
|
class BootDiskImage(AtariDosDiskImage):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@ -645,10 +648,21 @@ class BootDiskImage(AtariDosDiskImage):
|
|||||||
raise InvalidDiskImage("Bad boot load address")
|
raise InvalidDiskImage("Bad boot load address")
|
||||||
|
|
||||||
|
|
||||||
def get_xex(segments, runaddr):
|
def get_xex(segments, runaddr=None):
|
||||||
total = 2
|
total = 2
|
||||||
|
runad = False
|
||||||
for s in segments:
|
for s in segments:
|
||||||
total += 4 + len(s)
|
total += 4 + len(s)
|
||||||
|
if s.start_addr == 0x2e0:
|
||||||
|
runad = True
|
||||||
|
if not runad:
|
||||||
|
words = np.empty([1], dtype='<u2')
|
||||||
|
if not runaddr:
|
||||||
|
runaddr = segments[0].start_addr
|
||||||
|
words[0] = runaddr
|
||||||
|
r = SegmentData(words.view(dtype=np.uint8))
|
||||||
|
s = DefaultSegment(r, 0x2e0)
|
||||||
|
segments[0:0] = [s]
|
||||||
total += 6
|
total += 6
|
||||||
bytes = np.zeros([total], dtype=np.uint8)
|
bytes = np.zeros([total], dtype=np.uint8)
|
||||||
bytes[0:2] = 0xff # FFFF header
|
bytes[0:2] = 0xff # FFFF header
|
||||||
@ -660,10 +674,6 @@ def get_xex(segments, runaddr):
|
|||||||
i += 4
|
i += 4
|
||||||
bytes[i:i + len(s)] = s[:]
|
bytes[i:i + len(s)] = s[:]
|
||||||
i += len(s)
|
i += len(s)
|
||||||
words = bytes[i:i+6].view(dtype='<u2')
|
|
||||||
words[0] = 0x2e0
|
|
||||||
words[1] = 0x2e1
|
|
||||||
words[2] = runaddr
|
|
||||||
return bytes
|
return bytes
|
||||||
|
|
||||||
def add_atr_header(bytes):
|
def add_atr_header(bytes):
|
||||||
|
@ -301,6 +301,9 @@ class DiskImageBase(object):
|
|||||||
segments.append(segment)
|
segments.append(segment)
|
||||||
return segments
|
return segments
|
||||||
|
|
||||||
|
def create_executable_file_image(self, segments):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
# file writing methods
|
# file writing methods
|
||||||
|
|
||||||
def begin_transaction(self):
|
def begin_transaction(self):
|
||||||
|
@ -537,6 +537,28 @@ class Dos33DiskImage(DiskImageBase):
|
|||||||
segment = EmptySegment(self.rawdata, name=dirent.filename)
|
segment = EmptySegment(self.rawdata, name=dirent.filename)
|
||||||
return segment
|
return segment
|
||||||
|
|
||||||
|
def create_executable_file_image(self, segments):
|
||||||
|
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)
|
||||||
|
size = last - origin
|
||||||
|
image = np.zeros([size + 4], dtype=np.uint8)
|
||||||
|
words = image[0:4].view(dtype="<u2") # always little endian
|
||||||
|
words[0] = origin
|
||||||
|
words[1] = size
|
||||||
|
for s in segments:
|
||||||
|
index = s.start_addr - origin + 4
|
||||||
|
print "setting data for %04x - %04x at %04x" % (s.start_addr, s.start_addr + len(s), index)
|
||||||
|
image[index:index + len(s)] = s.data
|
||||||
|
return image, 'B'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ProdosHeader(Dos33Header):
|
class ProdosHeader(Dos33Header):
|
||||||
file_format = "ProDOS"
|
file_format = "ProDOS"
|
||||||
|
Loading…
Reference in New Issue
Block a user