Skip to content

Commit

Permalink
Naming refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
abaire authored and mborgerson committed Feb 24, 2022
1 parent aac78f5 commit 2b9e90f
Show file tree
Hide file tree
Showing 11 changed files with 575 additions and 382 deletions.
19 changes: 19 additions & 0 deletions AbortFlag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""Provides a simple pass-by-reference wrapped flag."""

# pylint: disable=invalid-name


class AbortFlag:
"""Indicates whether the trace should be aborted"""

def __init__(self):
self.abort_now = False

def abort(self):
"""Sets the abort flag."""
self.abort_now = True

@property
def should_abort(self):
"""Queries the abort flag."""
return self.abort_now
42 changes: 42 additions & 0 deletions ExchangeU32.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""Manages the exchange_u32.asm patch."""

# pylint: disable=consider-using-f-string
# pylint: disable=too-few-public-methods
# pylint: disable=invalid-name

import struct
from Xbox import Xbox
import XboxHelper


class _ExchangeU32:
"""Manages the exchange_u32.asm patch."""

def __init__(self, verbose=True):
self.exchange_u32_addr = 0
self.verbose = verbose

def _install_kicker(self, xbox: Xbox):
with open("exchange_u32", "rb") as patch_file:
data = patch_file.read()

self.exchange_u32_addr = XboxHelper.load_binary(xbox, data)
if self.verbose:
print("exchange_u32 installed at 0x%08X" % self.exchange_u32_addr)

def call(self, xbox: Xbox, address: int, value: int) -> int:
"""Calls the kicker with the given argument."""
if not self.exchange_u32_addr:
self._install_kicker(xbox)

return xbox.call(self.exchange_u32_addr, struct.pack("<LL", value, address))[
"eax"
]


_instance = _ExchangeU32()


def exchange_u32(xbox: Xbox, address: int, value: int) -> int:
"""Exchanges `value` with the value at `address`, returning the original value."""
return _instance.call(xbox, address, value)
44 changes: 44 additions & 0 deletions HTMLLog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""Manages the HTML log file."""

# pylint: disable=consider-using-f-string
# pylint: disable=invalid-name
# pylint: disable=line-too-long

import atexit


class HTMLLog:
"""Manages the HTML log file."""

def __init__(self, path):
self.path = path

with open(path, "w", encoding="utf8") as logfile:
logfile.write(
"<html><head>"
"<style>"
"body { font-family: sans-serif; background:#333; color: #ccc } "
"img { border: 1px solid #FFF; } "
"td, tr, table { background: #444; padding: 10px; border:1px solid #888; border-collapse: collapse; }"
"</style></head><body><table>\n"
)

self.log(["<b>#</b>", "<b>Opcode / Method</b>", "..."])
atexit.register(self._close_tags)

def _close_tags(self):
with open(self.path, "a", encoding="utf8") as logfile:
logfile.write("</table></body></html>")

def log(self, values):
"""Append the given values to the HTML log."""
with open(self.path, "a", encoding="utf8") as logfile:
logfile.write("<tr>")
for val in values:
logfile.write("<td>%s</td>" % val)
logfile.write("</tr>\n")

def print_log(self, message):
"""Print the given string and append it to the HTML log."""
print(message)
self.log([message])
48 changes: 39 additions & 9 deletions KickFIFO.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,68 @@
# pylint: disable=too-few-public-methods

import struct
from Xbox import Xbox
import XboxHelper


class _KickFIFO:
"""Manages the kick_fifo.asm patch."""

# The kick worked and the pushbuffer is empty.
STATE_OK = 0x1337C0DE

# The kick worked, but the command timed out waiting for the pushbuffer to become
# empty
STATE_BUSY = 0x32555359

# xbox.DMA_PUSH_ADDR != `expected_push`
STATE_INVALID_READ_PUSH_ADDR = 0xBAD0000

# xbox.DMA_PUSH_ADDR changed during the course of the kick
STATE_INVALID_PUSH_MODIFIED_IN_CALL = 0xBADBAD

def __init__(self, verbose=True):
self.kick_fifo_addr = None
self.method_addr = None
self.verbose = verbose

def _install_kicker(self, xbox):
if self.kick_fifo_addr is not None:
if self.method_addr is not None:
return

with open("kick_fifo", "rb") as patch_file:
data = patch_file.read()

self.kick_fifo_addr = XboxHelper.load_binary(xbox, data)
self.method_addr = XboxHelper.load_binary(xbox, data)
if self.verbose:
print("kick_fifo installed at 0x%08X" % self.kick_fifo_addr)
print("kick_fifo installed at 0x%08X" % self.method_addr)

def call(self, xbox, expected_put):
def call(self, xbox: Xbox, expected_push: int):
"""Calls the kicker with the given argument."""
self._install_kicker(xbox)
eax = xbox.call(self.kick_fifo_addr, struct.pack("<L", expected_put))["eax"]
assert eax != 0xBADBAD
return eax == 0x1337C0DE

# Allow a handful of retries if the push buffer does not become empty during a
# kick
for _ in range(100):
eax = xbox.call(self.method_addr, struct.pack("<L", expected_push))["eax"]
if eax == self.STATE_INVALID_READ_PUSH_ADDR:
real_push_addr = xbox.read_u32(XboxHelper.DMA_PUSH_ADDR)
print(
"WARNING: real DMA_PUSH_ADDR 0x%X != expected address 0x%X. Aborting"
% (real_push_addr, expected_push)
)
return False
if eax == self.STATE_INVALID_PUSH_MODIFIED_IN_CALL:
raise Exception("DMA_PUSH_ADDR modified during kick_fifo call")
if eax == self.STATE_OK:
return True

print("WARNING: timed out waiting for pushbuffer to become empty.")
return False


_kicker = _KickFIFO()


def kick(xbox, expected_put):
def kick(xbox: Xbox, expected_put: int):
"""Calls the kicker with the given argument. Returns true if successful."""
return _kicker.call(xbox, expected_put)
46 changes: 46 additions & 0 deletions NV2ALog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""Manages the nv2a log file."""

# pylint: disable=invalid-name
# pylint: disable=consider-using-f-string

Nv2aLogMethodDetails = False


class NV2ALog:
"""Manages the nv2a log file."""

def __init__(self, path):
self.path = path

with open(self.path, "w", encoding="utf8") as logfile:
logfile.write("xemu style NV2A log from nv2a-trace.py")

def log(self, message):
"""Append the given string to the nv2a log."""
with open(self.path, "a", encoding="utf8") as logfile:
logfile.write(message)

def log_method(self, method_info, data, pre_info, post_info):
"""Append a line describing the given pgraph call to the nv2a log."""
with open(self.path, "a", encoding="utf8") as logfile:
logfile.write(
"nv2a: pgraph method (%d): 0x%x -> 0x%x (0x%x)\n"
% (
method_info["subchannel"],
method_info["object"],
method_info["method"],
data,
)
)

if Nv2aLogMethodDetails:
logfile.write("Method info:\n")
logfile.write("Address: 0x%X\n" % method_info["address"])
logfile.write("Method: 0x%X\n" % method_info["method"])
logfile.write("Nonincreasing: %d\n" % method_info["nonincreasing"])
logfile.write("Subchannel: 0x%X\n" % method_info["subchannel"])
logfile.write("data:\n")
logfile.write(str(data))
logfile.write("\n\n")
logfile.write("pre_info: %s\n" % pre_info)
logfile.write("post_info: %s\n" % post_info)
Loading

0 comments on commit 2b9e90f

Please sign in to comment.