Added rom image conversion to atari cart images
This commit is contained in:
parent
a2831c0edf
commit
50488fc2e5
|
@ -19,7 +19,7 @@ from .dos33 import Dos33DiskImage
|
|||
from .kboot import KBootImage, add_xexboot_header
|
||||
from .segments import SegmentData, SegmentSaver, DefaultSegment, EmptySegment, ObjSegment, RawSectorsSegment, SegmentedFileSegment, user_bit_mask, match_bit_mask, comment_bit_mask, data_style, selected_bit_mask, diff_bit_mask, not_user_bit_mask, interleave_segments, SegmentList, get_style_mask, get_style_bits
|
||||
from .spartados import SpartaDosDiskImage
|
||||
from .cartridge import A8CartHeader, AtariCartImage
|
||||
from .cartridge import A8CartHeader, AtariCartImage, RomImage
|
||||
from .parsers import SegmentParser, DefaultSegmentParser, guess_parser_for_mime, guess_parser_for_system, guess_container, iter_parsers, iter_known_segment_parsers, mime_parse_order, parsers_for_filename
|
||||
from .magic import guess_detail_for_mime
|
||||
from .utils import to_numpy, text_to_int
|
||||
|
|
|
@ -119,6 +119,7 @@ class A8CartHeader:
|
|||
('checksum', '>u4'),
|
||||
('unused','>u4')
|
||||
])
|
||||
nominal_length = format.itemsize
|
||||
file_format = "Cart"
|
||||
|
||||
def __init__(self, bytes=None, create=False):
|
||||
|
@ -138,7 +139,7 @@ class A8CartHeader:
|
|||
self.main_origin = 0
|
||||
self.possible_types = set()
|
||||
if create:
|
||||
self.header_offset = 16
|
||||
self.header_offset = self.nominal_length
|
||||
self.check_size(0)
|
||||
if bytes is None:
|
||||
return
|
||||
|
@ -149,7 +150,7 @@ class A8CartHeader:
|
|||
raise errors.InvalidCartHeader
|
||||
self.cart_type = int(values[1])
|
||||
self.crc = int(values[2])
|
||||
self.header_offset = 16
|
||||
self.header_offset = self.nominal_length
|
||||
self.set_type(self.cart_type)
|
||||
else:
|
||||
raise errors.InvalidCartHeader
|
||||
|
@ -160,8 +161,15 @@ class A8CartHeader:
|
|||
def __len__(self):
|
||||
return self.header_offset
|
||||
|
||||
@property
|
||||
def valid(self):
|
||||
return self.cart_type != -1
|
||||
|
||||
def calc_crc_from_data(self, data):
|
||||
self.crc = 0
|
||||
|
||||
def to_array(self):
|
||||
raw = np.zeros([16], dtype=np.uint8)
|
||||
raw = np.zeros([self.nominal_length], dtype=np.uint8)
|
||||
values = raw.view(dtype=self.format)[0]
|
||||
values[0] = b'CART'
|
||||
values[1] = self.cart_type
|
||||
|
@ -189,7 +197,7 @@ class A8CartHeader:
|
|||
def check_size(self, size):
|
||||
self.possible_types = set()
|
||||
k, r = divmod(size, 1024)
|
||||
if r == 0 or r == 16:
|
||||
if r == 0 or r == self.nominal_length:
|
||||
for i, t in enumerate(known_cart_types):
|
||||
valid_size = t[0]
|
||||
if k == valid_size:
|
||||
|
@ -205,7 +213,7 @@ class BaseAtariCartImage(DiskImageBase):
|
|||
try:
|
||||
self.header = A8CartHeader(data)
|
||||
except errors.InvalidCartHeader:
|
||||
raise errors.InvalidDiskImage("Missing cart header")
|
||||
self.header = A8CartHeader()
|
||||
|
||||
def strict_check(self):
|
||||
raise NotImplementedError
|
||||
|
@ -217,10 +225,10 @@ class BaseAtariCartImage(DiskImageBase):
|
|||
self.header.set_type(self.cart_type)
|
||||
|
||||
def check_size(self):
|
||||
if self.header is None:
|
||||
if not self.header.valid:
|
||||
return
|
||||
k, rem = divmod((len(self) - len(self.header)), 1024)
|
||||
c = get_cart(self.cart_type)
|
||||
c = get_cart(self.header.cart_type)
|
||||
log.debug("checking type=%d, k=%d, rem=%d for %s, %s" % (self.cart_type, k, rem, c[1], c[2]))
|
||||
if rem > 0:
|
||||
raise errors.InvalidDiskImage("Cart not multiple of 1K")
|
||||
|
@ -252,13 +260,31 @@ class BaseAtariCartImage(DiskImageBase):
|
|||
segments.append(s)
|
||||
return segments
|
||||
|
||||
def create_emulator_boot_segment(self):
|
||||
print(self.segments)
|
||||
h = self.header
|
||||
k, rem = divmod(len(self), 1024)
|
||||
if rem == 0:
|
||||
h.calc_crc_from_data(self.bytes)
|
||||
data_with_header = np.empty(len(self) + h.nominal_length, dtype=np.uint8)
|
||||
data_with_header[0:h.nominal_length] = h.to_array()
|
||||
data_with_header[h.nominal_length:] = self.bytes
|
||||
r = SegmentData(data_with_header)
|
||||
else:
|
||||
r = self.rawdata
|
||||
s = ObjSegment(r, 0, 0, self.header.main_origin, name="Cart image")
|
||||
return s
|
||||
|
||||
|
||||
class AtariCartImage(BaseAtariCartImage):
|
||||
def __init__(self, rawdata, cart_type, filename=""):
|
||||
c = get_cart(cart_type)
|
||||
self.cart_type = cart_type
|
||||
DiskImageBase.__init__(self, rawdata, filename)
|
||||
|
||||
def strict_check(self):
|
||||
if not self.header.valid:
|
||||
raise errors.InvalidDiskImage("Missing cart header")
|
||||
if self.header.cart_type != self.cart_type:
|
||||
raise errors.InvalidDiskImage("Cart type doesn't match type defined in header")
|
||||
|
||||
|
@ -267,12 +293,14 @@ class Atari8bitCartImage(BaseAtariCartImage):
|
|||
def strict_check(self):
|
||||
if "5200" in self.header.cart_name:
|
||||
raise errors.InvalidDiskImage("5200 Carts don't work in the home computers.")
|
||||
AtariCartImage.strict_check(self)
|
||||
|
||||
|
||||
class Atari5200CartImage(BaseAtariCartImage):
|
||||
def strict_check(self):
|
||||
if "5200" not in self.header.cart_name:
|
||||
raise errors.InvalidDiskImage("Home computer carts don't work in the 5200.")
|
||||
AtariCartImage.strict_check(self)
|
||||
|
||||
|
||||
def add_cart_header(bytes):
|
||||
|
|
|
@ -3,8 +3,8 @@ from __future__ import division
|
|||
from builtins import object
|
||||
from mock import *
|
||||
|
||||
from atrcopy import AtariCartImage, SegmentData
|
||||
from atrcopy import errors
|
||||
from atrcopy import AtariCartImage, SegmentData, RomImage, errors
|
||||
from atrcopy.cartridge import known_cart_types
|
||||
|
||||
|
||||
class TestAtariCart:
|
||||
|
@ -17,26 +17,24 @@ class TestAtariCart:
|
|||
data[4:8].view(">u4")[0] = cart_type
|
||||
return data
|
||||
|
||||
def test_unbanked(self):
|
||||
carts = [
|
||||
@pytest.mark.parametrize("k_size,cart_type", [
|
||||
(8, 1),
|
||||
(16, 2),
|
||||
(8, 21),
|
||||
(2, 57),
|
||||
(4, 58),
|
||||
(4, 59),
|
||||
]
|
||||
for k_size, cart_type in carts:
|
||||
data = self.get_cart(k_size, cart_type)
|
||||
rawdata = SegmentData(data)
|
||||
image = AtariCartImage(rawdata, cart_type)
|
||||
image.parse_segments()
|
||||
assert len(image.segments) == 2
|
||||
assert len(image.segments[0]) == 16
|
||||
assert len(image.segments[1]) == k_size * 1024
|
||||
])
|
||||
def test_unbanked(self, k_size, cart_type):
|
||||
data = self.get_cart(k_size, cart_type)
|
||||
rawdata = SegmentData(data)
|
||||
image = AtariCartImage(rawdata, cart_type)
|
||||
image.parse_segments()
|
||||
assert len(image.segments) == 2
|
||||
assert len(image.segments[0]) == 16
|
||||
assert len(image.segments[1]) == k_size * 1024
|
||||
|
||||
def test_banked(self):
|
||||
carts = [
|
||||
@pytest.mark.parametrize("k_size,main_size,banked_size,cart_type", [
|
||||
(32, 8, 8, 12),
|
||||
(64, 8, 8, 13),
|
||||
(64, 8, 8, 67),
|
||||
|
@ -44,16 +42,16 @@ class TestAtariCart:
|
|||
(256, 8, 8, 23),
|
||||
(512, 8, 8, 24),
|
||||
(1024, 8, 8, 25),
|
||||
]
|
||||
for k_size, main_size, banked_size, cart_type in carts:
|
||||
data = self.get_cart(k_size, cart_type)
|
||||
rawdata = SegmentData(data)
|
||||
image = AtariCartImage(rawdata, cart_type)
|
||||
image.parse_segments()
|
||||
assert len(image.segments) == 1 + 1 + (k_size - main_size) //banked_size
|
||||
assert len(image.segments[0]) == 16
|
||||
assert len(image.segments[1]) == main_size * 1024
|
||||
assert len(image.segments[2]) == banked_size * 1024
|
||||
])
|
||||
def test_banked(self, k_size, main_size, banked_size, cart_type):
|
||||
data = self.get_cart(k_size, cart_type)
|
||||
rawdata = SegmentData(data)
|
||||
image = AtariCartImage(rawdata, cart_type)
|
||||
image.parse_segments()
|
||||
assert len(image.segments) == 1 + 1 + (k_size - main_size) //banked_size
|
||||
assert len(image.segments[0]) == 16
|
||||
assert len(image.segments[1]) == main_size * 1024
|
||||
assert len(image.segments[2]) == banked_size * 1024
|
||||
|
||||
def test_bad(self):
|
||||
k_size = 32
|
||||
|
@ -74,9 +72,55 @@ class TestAtariCart:
|
|||
image = AtariCartImage(rawdata, 1337)
|
||||
|
||||
|
||||
class TestRomCart:
|
||||
def setup(self):
|
||||
pass
|
||||
|
||||
def get_rom(self, k_size):
|
||||
data = np.zeros((k_size * 1024), dtype=np.uint8)
|
||||
return data
|
||||
|
||||
@pytest.mark.parametrize("k_size", [1, 2, 4, 8, 16, 32, 64])
|
||||
def test_typical_rom_sizes(self, k_size):
|
||||
data = self.get_rom(k_size)
|
||||
rawdata = SegmentData(data)
|
||||
rom_image = RomImage(rawdata)
|
||||
rom_image.strict_check()
|
||||
rom_image.parse_segments()
|
||||
assert len(rom_image.segments) == 1
|
||||
assert len(rom_image.segments[0]) == k_size * 1024
|
||||
|
||||
@pytest.mark.parametrize("k_size", [1, 2, 4, 8, 16, 32, 64])
|
||||
def test_invalid_rom_sizes(self, k_size):
|
||||
data = np.zeros((k_size * 1024) + 17, dtype=np.uint8)
|
||||
rawdata = SegmentData(data)
|
||||
with pytest.raises(errors.InvalidDiskImage):
|
||||
rom_image = RomImage(rawdata)
|
||||
|
||||
@pytest.mark.parametrize("cart", known_cart_types)
|
||||
def test_conversion_to_atari_cart(self, cart):
|
||||
cart_type = cart[0]
|
||||
name = cart[1]
|
||||
k_size = cart[2]
|
||||
if "Bounty" in name:
|
||||
return
|
||||
data = self.get_rom(k_size)
|
||||
rawdata = SegmentData(data)
|
||||
rom_image = RomImage(rawdata)
|
||||
rom_image.strict_check()
|
||||
rom_image.parse_segments()
|
||||
new_cart_image = AtariCartImage(rawdata, cart_type)
|
||||
new_cart_image.relaxed_check()
|
||||
new_cart_image.parse_segments()
|
||||
assert new_cart_image.header.valid
|
||||
s = new_cart_image.create_emulator_boot_segment()
|
||||
assert len(s) == len(rawdata) + new_cart_image.header.nominal_length
|
||||
assert s[0:4].tobytes() == b'CART'
|
||||
assert s[4:8].view(dtype=">u4") == cart_type
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from atrcopy.parsers import mime_parse_order
|
||||
print("\n".join(mime_parse_order))
|
||||
|
||||
t = TestAtariCart()
|
||||
|
|
Loading…
Reference in New Issue