Skip to content

Commit

Permalink
JSON support + p-word injection
Browse files Browse the repository at this point in the history
  • Loading branch information
JayFoxRox committed Jan 6, 2019
1 parent 6be498b commit a628f2c
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 44 deletions.
187 changes: 143 additions & 44 deletions python-scripts/dsp_instruction_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,23 @@

from xboxpy import *

import json
import sys
import time

reserved_words = 0x20

def get_word(s):
#FIXME: Assert type is string or int
s = str(s)
s = s.strip()
s = s.replace('$', '0x')
s = s.lower()
if s[0:2] == "0x":
return int(s[2:], 16)
else:
return int(s, 10)

def dsp_stop():
# Reset GP and GP DSP
apu.write_u32(NV_PAPU_GPRST, 0)
Expand Down Expand Up @@ -72,19 +86,20 @@ def dsp_homebrew(tests):
print("Generating DSP code")
code = ""

# We reserve some program words (jump targets, as magic for p-word injection)
code += "nop\n" * reserved_words

# Setup memory registers
#FIXME: Do this before every writeback / address outputs directly
code += "\n; Memory register setup\n\n"
code += "move #$100, R0\n"
code += "move #1, N0\n"
code += "movec #$FFFF, M0\n"
code += "move #$100, R1\n"
code += "move #1, N1\n"
code += "movec #$FFFF, M1\n"
code += "movec #$FFFF, M7\n"
code += "move #$100, R7\n"
code += "move #1, N7\n"
code += "nop\n"

# Generate each test
r0 = 0x100 #FIXME: X:0 seems to be used during DSP reset?!
n0 = 1
r7 = 0x100 #FIXME: X:0 seems to be used during DSP reset?!
n7 = 1
for t in tests:
i = t[0]
p = t[1]
Expand All @@ -96,27 +111,62 @@ def dsp_homebrew(tests):
# - Replace 'a' by ('a2', 'a1', 'a0')
# - Replace 'b' by ('b2', 'b1', 'b0')

control_regs = [
"vba", "sr", "omr", "sp", "ssh", "ssl", "la", "lc",
"m0", "m1", "m2", "m3", "m4", "m5", "m6", "m7",
]

# Add any register which would cause trouble
forbidden_regs = [
"ssh", # Crash in XQEMU (possibly bug in a56?)
"vba", # Caused error in a56
"m7", "r7", "n7" # Used for input/output addressing
]

# Input
for k, v in i.items():
#FIXME: Check for special registers like SR etc.

if k == 'sr':
code += "movec x:(R0)+N0, %s\n" % (k)
else:
code += "move x:(R0)+N0, %s\n" % (k)
apu.write_u32(NV_PAPU_GPXMEM + r0*4, v)
r0 += n0
if k.find(':') != -1:
print("Memory %s unsupported in setter" % k)
space, colon, address = k.partition(':')
address = get_word(address)

for w in v:
print("Would have set %s:$%X to 0x%06X" % (space, address, w))
address += 1

# Processing
code += p + "\n"
elif k.lower() in forbidden_regs:
print("Register %s forbidden in setter" % k)
else:
if k.lower() in control_regs:
code += "movec x:(R7)+N7, %s\n" % (k)
else:
code += "move x:(R7)+N7, %s\n" % (k)
apu.write_u32(NV_PAPU_GPXMEM + r7*4, v)
r7 += n7
code += "nop\n" # Avoid hazards

# Processing, while avoiding the mix any of the surrounding instructions
code += "nop\n"
code += p[0] + "\n"
code += "nop\n"

# Setup memory registers for output
code += "movec #$FFFF, M7\n"
code += "move #$100, R7\n"
code += "move #1, N7\n"
code += "nop\n"

# Output
for k in o:

if k == 'sr':
code += "movec %s, y:(R1)+N1\n" % (k)
if k.lower() in forbidden_regs:
print("Register %s forbidden in getter" % k)
code += "move a0, y:(R7)+N7\n" # Used to advance R7
elif k.lower() in control_regs:
code += "movec %s, y:(R7)+N7\n" % (k)
else:
code += "move %s, y:(R1)+N1\n" % (k)
code += "move %s, y:(R7)+N7\n" % (k)

# Mark results as ready and stick in a loop
code += "\n; Result marker\n\n"
Expand All @@ -130,10 +180,17 @@ def dsp_homebrew(tests):
data = dsp.assemble(code)
data = dsp.from24(data)

# Write code to PMEM (normally you can just use write() but we don't support that for apu MMIO yet.. boo!)
# Write code to PMEM, and also inject p-words
print("Writing program to DSP")
for i in range(0, len(data) // 4):
word = int.from_bytes(data[i*4:i*4+4], byteorder='little', signed=False) & 0xFFFFFF

# Check for the magic jmp, to inject p-words
if word & 0xFFF000 == 0x0C0000:
jmp_label = word & 0xFFF
if jmp_label < reserved_words:
word = p[1][jmp_label]

apu.write_u32(NV_PAPU_GPPMEM + i*4, word)
# According to XQEMU, 0x800 * 4 bytes will be loaded from scratch to PMEM at startup.
# So just to be sure, let's also write this to the scratch..
Expand All @@ -155,8 +212,8 @@ def dsp_homebrew(tests):
# Read all results from memory
print("Reading test results")
all_results = []
r1 = 0x100
n1 = 1
r7 = 0x100
n7 = 1
for t in tests:
i = t[0]
p = t[1]
Expand All @@ -167,37 +224,79 @@ def dsp_homebrew(tests):
# Loop over all outputs
results = {}
for k in o:
results[k] = apu.read_u32(NV_PAPU_GPYMEM + r1*4)
r1 += n1
results[k] = apu.read_u32(NV_PAPU_GPYMEM + r7*4)
r7 += n7

# Add result for this test
all_results += [results]

# Remove forbidden outputs
for k in forbidden_regs:
if k in results:
del results[k]

# Return the output
return all_results


# Generate some test cases
sr = 0xC00310
inputs = (
{'a2':0x00, 'a1': 0x001000, 'a0': 0xFFFFFF, 'b1': 0x10, 'sr': sr },
{'a2':0x80, 'a1': 0x002000, 'a0': 0x000001, 'b1': 0x20, 'sr': sr },
{'a2':0xFF, 'a1': 0x003000, 'a0': 0xFFFFFF, 'b1': 0x30, 'sr': sr }
)
processing = ['asr a'] * len(inputs)
outputs = [['a2','a1','a0','b1','sr']] * len(inputs)
tests = list(zip(inputs, processing, outputs))


# Run the tests
results = dsp_homebrew(tests)
# Process all tests
for path in sys.argv[1:]:

# Print results
print("Finished:")
for r in results:
print("")
for k, v in r.items():
print("%s: 0x%X" % (k, v))


print("Processing '%s'" % path)
print("")

# Load test from file
#FIXME: Error checking
with open(path, 'rb') as f:
source = f.read()
test = json.loads(source)

# Turn all prefixed strings into words
new_input = {}
for k, v in test['input'].items():
if k.find(':') != -1:
new_input[k] = [get_word(word) for word in v]
else:
new_input[k] = get_word(v)
new_input

# Turn line-array into string
new_code = ""
inject = []
for l in test['code']:

# Check for raw p-words to inject
if l[0] == ":":
v = get_word(l[1:])
print("Unsupported program-word: 0x%06X" % v)
#FIXME: We need some syntax for parallel words?
new_code += "jmp <$%X\n" % len(inject)
inject += [v]
assert(len(inject) <= reserved_words)

else:
new_code += l + "\n"

#FIXME: This is a legacy format; this weird conversion shouldn't be necessary
# Assemble a test
tests = [(new_input, (new_code, inject), test['output'])]

# Run the tests
results = dsp_homebrew(tests)

# Print results
print("Finished:")
output_json = {}
for r in results:
print("")
for k, v in r.items():
print("%s: 0x%X" % (k, v))
output_json[k] = '0x%X' % (v)

#FIXME: Write to log
output_source = json.dumps(output_json, indent=2)
with open(path + "-out.json", 'wb') as f:
f.write(output_source.encode("utf-8"))
15 changes: 15 additions & 0 deletions python-scripts/dsp_instruction_tests/code-test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"input": {
"a2": "0x00",
"a1": "0x000000",
"a0": "0x000000"
},
"code": [
"move #$12, a2",
"move #$345678, a1",
"move #$9ABCDE, a0"
],
"output": [
"a2","a1","a0"
]
}
15 changes: 15 additions & 0 deletions python-scripts/dsp_instruction_tests/inc_a-test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"input": {
"a2": "0x00",
"a1": "0x000000",
"a0": "0x000000"
},
"code": [
":0x000008", "; inc a"
],
"output": [
"a2",
"a1",
"a0"
]
}
13 changes: 13 additions & 0 deletions python-scripts/dsp_instruction_tests/memory-test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"input": {
"x:$10": ["0xFF0012","0x123456"],
"x:$20": ["0x789ABC"]
},
"code": [
"move x:$10, x0",
"move x0, x:$20"
],
"output": [
"x0"
]
}
16 changes: 16 additions & 0 deletions python-scripts/dsp_instruction_tests/registers-test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"input": {
"a2": "0x00", "a1": "0x000000", "a0": "0x000000"
},
"code": [],
"output": [
"vba", "sr", "omr", "sp", "ssh", "ssl", "la", "lc",
"a2","a1","a0",
"b2","b1","b0",
"x0", "x1",
"y0", "y1",
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"m0", "m1", "m2", "m3", "m4", "m5", "m6", "m7",
"n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7"
]
}

0 comments on commit a628f2c

Please sign in to comment.