Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Random RAM #158

Merged
merged 7 commits into from
Oct 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions pyboy/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def valid_file_path(path):
parser.add_argument("ROM", type=valid_file_path, help="Path to a Game Boy compatible ROM file")
parser.add_argument("-b", "--bootrom", type=valid_file_path, help="Path to a boot-ROM file")
parser.add_argument("--profiling", action="store_true", help="Enable opcode profiling (internal use)")
parser.add_argument("--randomize-ram", action="store_true", help="Randomize Game Boy RAM on startup")
parser.add_argument(
"--log-level",
default="INFO",
Expand Down
9 changes: 8 additions & 1 deletion pyboy/core/lcd.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from array import array
from ctypes import c_void_p
from random import getrandbits

from pyboy.utils import color_code

Expand All @@ -22,7 +23,7 @@


class LCD:
def __init__(self):
def __init__(self, randomize=False):
self.VRAM = array("B", [0] * VIDEO_RAM)
self.OAM = array("B", [0] * OBJECT_ATTRIBUTE_MEMORY)

Expand All @@ -39,6 +40,12 @@ def __init__(self):
self.WY = 0x00
self.WX = 0x00

if randomize:
for i in range(VIDEO_RAM):
self.VRAM[i] = getrandbits(8)
for i in range(OBJECT_ATTRIBUTE_MEMORY):
self.OAM[i] = getrandbits(8)

def save_state(self, f):
for n in range(VIDEO_RAM):
f.write(self.VRAM[n])
Expand Down
7 changes: 4 additions & 3 deletions pyboy/core/mb.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@


class Motherboard:
def __init__(self, gamerom_file, bootrom_file, color_palette, disable_renderer, sound_enabled, profiling=False):
def __init__(self, gamerom_file, bootrom_file, color_palette, disable_renderer, sound_enabled, randomize=False,
profiling=False):
if bootrom_file is not None:
logger.info("Boot-ROM file provided")

Expand All @@ -27,9 +28,9 @@ def __init__(self, gamerom_file, bootrom_file, color_palette, disable_renderer,
self.interaction = interaction.Interaction()
self.cartridge = cartridge.load_cartridge(gamerom_file)
self.bootrom = bootrom.BootROM(bootrom_file)
self.ram = ram.RAM(random=False)
self.ram = ram.RAM(randomize=randomize)
self.cpu = cpu.CPU(self, profiling)
self.lcd = lcd.LCD()
self.lcd = lcd.LCD(randomize=randomize)
self.renderer = lcd.Renderer(color_palette)
self.disable_renderer = disable_renderer
self.sound_enabled = sound_enabled
Expand Down
30 changes: 19 additions & 11 deletions pyboy/core/ram.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
# GitHub: https://github.com/Baekalfen/PyBoy
#

import array
from array import array
from random import getrandbits

# MEMORY SIZES
INTERNAL_RAM0 = 8 * 1024 # 8KB
INTERNAL_RAM0 = 8 * 1024 # 8KiB
NON_IO_INTERNAL_RAM0 = 0x60
IO_PORTS = 0x4C
NON_IO_INTERNAL_RAM1 = 0x34
Expand All @@ -15,16 +16,23 @@


class RAM:
def __init__(self, random=False):
if random: # NOTE: In real life, the RAM is scrambled with random data on boot.
raise Exception("Random RAM not implemented")
def __init__(self, randomize=False):
self.internal_ram0 = array("B", [0] * (INTERNAL_RAM0))
self.non_io_internal_ram0 = array("B", [0] * (NON_IO_INTERNAL_RAM0))
self.io_ports = array("B", [0] * (IO_PORTS))
self.internal_ram1 = array("B", [0] * (INTERNAL_RAM1))
self.non_io_internal_ram1 = array("B", [0] * (NON_IO_INTERNAL_RAM1))
self.interrupt_register = array("B", [0] * (INTERRUPT_ENABLE_REGISTER))

self.internal_ram0 = array.array("B", [0] * (INTERNAL_RAM0))
self.non_io_internal_ram0 = array.array("B", [0] * (NON_IO_INTERNAL_RAM0))
self.io_ports = array.array("B", [0] * (IO_PORTS))
self.internal_ram1 = array.array("B", [0] * (INTERNAL_RAM1))
self.non_io_internal_ram1 = array.array("B", [0] * (NON_IO_INTERNAL_RAM1))
self.interrupt_register = array.array("B", [0] * (INTERRUPT_ENABLE_REGISTER))
if randomize:
for i in range(INTERNAL_RAM0):
self.internal_ram0[i] = getrandbits(8)
for i in range(NON_IO_INTERNAL_RAM0):
self.non_io_internal_ram0[i] = getrandbits(8)
for i in range(INTERNAL_RAM1):
self.internal_ram1[i] = getrandbits(8)
for i in range(NON_IO_INTERNAL_RAM1):
self.non_io_internal_ram1[i] = getrandbits(8)

def save_state(self, f):
for n in range(INTERNAL_RAM0):
Expand Down
4 changes: 3 additions & 1 deletion pyboy/pyboy.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@

class PyBoy:
def __init__(
self, gamerom_file, *, bootrom_file=None, profiling=False, disable_renderer=False, sound=False, **kwargs
self, gamerom_file, *, bootrom_file=None, profiling=False, disable_renderer=False, sound=False,
randomize=False, **kwargs
):
"""
PyBoy is loadable as an object in Python. This means, it can be initialized from another script, and be
Expand Down Expand Up @@ -70,6 +71,7 @@ def __init__(
kwargs["color_palette"],
disable_renderer,
sound,
randomize=randomize,
profiling=profiling,
)

Expand Down
22 changes: 22 additions & 0 deletions tests/test_basics.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,25 @@ def test_tilemaps():
assert isinstance(wdw_tilemap[0, 0], Tile)

pyboy.stop(save=False)


def test_randomize_ram():
pyboy = PyBoy(default_rom) # randomize=False, by default
# RAM banks should all be 0 by default
assert not any([pyboy.get_memory_value(x) for x in range(0x8000, 0xA000)]), "VRAM not zeroed"
assert not any([pyboy.get_memory_value(x) for x in range(0xC000, 0xE000)]), "Internal RAM 0 not zeroed"
assert not any([pyboy.get_memory_value(x) for x in range(0xFE00, 0xFEA0)]), "OAM not zeroed"
assert not any([pyboy.get_memory_value(x) for x in range(0xFEA0, 0xFF00)]), "Non-IO internal RAM 0 not zeroed"
assert not any([pyboy.get_memory_value(x) for x in range(0xFF4C, 0xFF80)]), "Non-IO internal RAM 1 not zeroed"
assert not any([pyboy.get_memory_value(x) for x in range(0xFF80, 0xFFFF)]), "Internal RAM 1 not zeroed"
pyboy.stop(save=False)

pyboy = PyBoy(default_rom, randomize=True)
# RAM banks should have nonzero values now
assert any([pyboy.get_memory_value(x) for x in range(0x8000, 0xA000)]), "VRAM not randomized"
assert any([pyboy.get_memory_value(x) for x in range(0xC000, 0xE000)]), "Internal RAM 0 not randomized"
assert any([pyboy.get_memory_value(x) for x in range(0xFE00, 0xFEA0)]), "OAM not randomized"
assert any([pyboy.get_memory_value(x) for x in range(0xFEA0, 0xFF00)]), "Non-IO internal RAM 0 not randomized"
assert any([pyboy.get_memory_value(x) for x in range(0xFF4C, 0xFF80)]), "Non-IO internal RAM 1 not randomized"
assert any([pyboy.get_memory_value(x) for x in range(0xFF80, 0xFFFF)]), "Internal RAM 1 not randomized"
pyboy.stop(save=False)
7 changes: 5 additions & 2 deletions tests/test_replay.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ def replay(
rewind=False,
bootrom_file=utils.boot_rom,
overwrite=RESET_REPLAYS,
gif_hash=None
gif_hash=None,
randomize=False
):
with open(replay, "rb") as f:
recorded_input, b64_romhash, b64_state = json.loads(zlib.decompress(f.read()).decode("ascii"))
Expand All @@ -86,6 +87,7 @@ def replay(
bootrom_file=bootrom_file,
disable_input=True,
rewind=rewind,
randomize=randomize,
record_input=(RESET_REPLAYS and window in ["SDL2", "headless", "OpenGL"])
)
pyboy.set_emulation_speed(0)
Expand Down Expand Up @@ -187,7 +189,8 @@ def test_supermarioland_gif():
"tests/replays/supermarioland_gif.replay",
record_gif=(122, 644),
gif_destination="README/3.gif",
gif_hash="15aVUmwtTq38E3SB91moQLYSTZVWuTNTUmzYVSgTg38="
gif_hash="15aVUmwtTq38E3SB91moQLYSTZVWuTNTUmzYVSgTg38=",
randomize=True
)


Expand Down