diff --git a/python-scripts/dsp_dma.py b/python-scripts/dsp_dma.py new file mode 100755 index 0000000..502e74c --- /dev/null +++ b/python-scripts/dsp_dma.py @@ -0,0 +1,461 @@ +#!/usr/bin/env python3 + +# This resets the GP DSP and attempts to do DMA transfers + +from xboxpy import * + +import random +import sys +import time +import struct + + + + +BUFFER_TO_DSP = False +DSP_TO_BUFFER = True + +BUFFER_OUT_FIFO0 = 0x0 +BUFFER_OUT_FIFO1 = 0x1 +BUFFER_OUT_FIFO2 = 0x2 +BUFFER_OUT_FIFO3 = 0x3 +BUFFER_SCRATCH_CIRCULAR = 0xE +BUFFER_SCRATCH = 0xF + +FORMAT_8_BIT = 0x0 +FORMAT_16_BIT = 0x1 +FORMAT_24_BIT_MSB = 0x2 +FORMAT_32_BIT = 0x3 +FORMAT_24_BIT_LSB = 0x6 + +FLAGS_UNK0 = (1 << 0) +FLAGS_UNK4 = (1 << 4) +FLAGS_UNK9 = (1 << 9) + +DSP_MEMORY_X = 0x0 +DSP_MEMORY_Y = 0x1800 +DSP_MEMORY_P = 0x2800 + + +scratch_page_base = 0 +fifo_page_base = 0 + + +def dsp_write(base, address, data): + # Write code to PMEM (normally you can just use write() but we don't support that for apu MMIO yet.. boo!) + for i in range(0, len(data) // 4): + word = int.from_bytes(data[i*4:i*4+4], byteorder='little', signed=False) & 0xFFFFFF + apu.write_u32(base + (address + i)*4, word) + +def dsp_read_scratch(address, size): + global scratch_page_base + return read(scratch_page_base + address, size) + +def dsp_write_scratch(address, data): + global scratch_page_base + write(scratch_page_base + address, data) + +def dsp_read_fifo(address, size): + global fifo_page_base + return read(fifo_page_base + address, size) + +def dsp_write_fifo(address, data): + global fifo_page_base + write(fifo_page_base + address, data) + +def dsp_write_dma_command_block(address, next_block, is_eol, transfer_direction, buffer, sample_format, sample_count, dsp_address, buffer_offset, buffer_base, buffer_limit, control_flags, step): + + w0 = next_block & 0x3FFF + if is_eol: + w0 |= 1 << 14 + + w1 = 0 + if transfer_direction: + w1 |= 1 << 1 + w1 |= buffer << 5 + w1 |= sample_format << 10 + w1 |= control_flags + + #FIXME: Turn into a parameter + # This is how many samples the read (?) cursor advances + w1 |= step << 14 + + w2 = sample_count + + w3 = dsp_address + + w4 = buffer_offset + + w5 = buffer_base + + w6 = buffer_limit + + data = struct.pack(" buffer) +# next-block 0x0 (eol) +# control 0x0059d2: unk0:0, unk4:1 buf 0xe (scratch-circular?) unk9:0 format 0x6 (24 bit lsb) step 0x1 +# count 0x20 +# dsp-offset 0x1460 (x:$1460) +# buffer-offset 0x0 (+ buffer-base 0xa800 = 0xa800) +# buffer-size 0x800 + + +dsp_write_dma_command_block(0x100, 0x107, False, # address / next / eol + DSP_TO_BUFFER, # direction + BUFFER_SCRATCH, # buffer + FORMAT_16_BIT, 0x2 << 4 | 0x1, # sample-format / sample-count + DSP_MEMORY_X + 0x600, # dsp-offset + 0x100, # buffer-offset + 0x0, 0x0, # buffer-base / buffer-size + FLAGS_UNK0, # control flags + 0x12) # step + +if False: + dsp_write_dma_command_block(0x107, 0x10E, False, # address / next / eol + BUFFER_TO_DSP, # direction + BUFFER_SCRATCH, # buffer + FORMAT_16_BIT, 0x5, # sample-format / sample-count + DSP_MEMORY_X + 0x700, # dsp-offset + 0x200, # buffer-offset + 0x0, 0x0, # buffer-base / buffer-size + FLAGS_UNK0 | FLAGS_UNK9, # control flags + 0x20) # step + +#dsp dma block 0x0 (dsp -> buffer) +# next-block 0x0 (eol) +# control 0x080403: +# unk0 1 +# buffer-offset-writeback 0 +# buffer 0x0 (fifo0) +# unk9 0 +# sample-format 0x1 (16 bit) +# dsp-step 0x20 +# sample-count 0x201 +# dsp-offset 0xc00 (x:$c00) +# buffer-offset 0xc000 (+ buffer-base 0x0 = 0xc000) +# buffer-size 0x1 + +#FIXME: What is this used for? +#apu.write_u32(NV_PAPU_FEMAXGPSGE, page_count - 1) + +# Unsure how these affect everything +NV_PAPU_GPGET = 0x3FF00 +NV_PAPU_GPPUT = 0x3FF04 +apu.write_u32(NV_PAPU_GPGET, 0) +apu.write_u32(NV_PAPU_GPPUT, 0) + +# Configure a FIFO + +# Output FIFO0-FIFO3; 0x10 step +NV_PAPU_GPOFBASE0 = 0x3024 +NV_PAPU_GPOFEND0 = 0x3028 +NV_PAPU_GPOFCUR0 = 0x302C +for i in range(4): + apu.write_u32(NV_PAPU_GPOFBASE0 + i * 0x10, 0x200) + apu.write_u32(NV_PAPU_GPOFEND0 + i * 0x10, 0x300) + apu.write_u32(NV_PAPU_GPOFCUR0 + i * 0x10, 0x300 + i * 4) # absolute, so must be between base and end + print("0x%X" % apu.read_u32(NV_PAPU_GPOFCUR0 + i * 0x10)) + +# Input FIFO0-FIFO1; 0x10 step +NV_PAPU_GPIFBASE0 = 0x3064 +NV_PAPU_GPIFEND0 = 0x3068 +NV_PAPU_GPIFCUR0 = 0x306C +for i in range(2): + apu.write_u32(NV_PAPU_GPIFBASE0 + i * 0x10, 0x0) + apu.write_u32(NV_PAPU_GPIFEND0 + i * 0x10, 0x1000) + apu.write_u32(NV_PAPU_GPIFCUR0 + i * 0x10, 0x200 + i * 4) # absolute, so must be between base and end + + +dsp_write_dma_command_block(0x107, 0x10E, False, # address / next / eol + BUFFER_TO_DSP, # direction + BUFFER_SCRATCH, # buffer + FORMAT_16_BIT, 0x11, # sample-format / sample-count + DSP_MEMORY_X + 0x700, # dsp-offset + 0x200, # buffer-offset + 0xF00BAA, 0xF00BAA, # buffer-base / buffer-size + FLAGS_UNK0 | FLAGS_UNK4, # control flags + 2) # step + + + + +dsp_write_dma_command_block(0x10E, 0, True, # address / next / eol + DSP_TO_BUFFER, # direction + BUFFER_SCRATCH_CIRCULAR, # buffer + FORMAT_24_BIT_LSB, 0x1, # sample-format / sample-count + DSP_MEMORY_X + 0x800, # dsp-offset + 0x0, # buffer-offset + 0x400, 0x100, # buffer-base / buffer-size + 0, # control flags + 1) # step + +# Write a pattern to X memory at 0x200 (DMA source) +#dsp_write(NV_PAPU_GPXMEM, 0x200, bytes(range(40))) +for i in range(40): + apu.write_u32(NV_PAPU_GPXMEM + (0x700 + i) * 4, 1 + i) + apu.write_u32(NV_PAPU_GPXMEM + (0x800 + i) * 4, 1 + i) + +# Write a pattern to scratch memory (DMA destination) +dsp_write_fifo(0x1F0, [0xFF] * 80) +dsp_write_scratch(0x1F0, [0xFF] * 80) +dsp_write_scratch(0x2F0, [0xFF] * 80) + +# Place marker in YMEM +apu.write_u32(NV_PAPU_GPYMEM + 0, 0x000000) +assert(apu.read_u32(NV_PAPU_GPYMEM + 0) != 0x1337) + +def group_memory(address, size, group_size, gap_size, accessor): + s = "" + i = 0 + for x in accessor(address, size): + if i == 0 and group_size > 0: + s += " " + s += "%02X" % x + i += 1 + if i >= group_size and group_size > 0: + s += " " + i = -gap_size + return s.strip() + +def print_scratch(address, size, group_size, gap_size): + print("s: " + group_memory(address, size, group_size, gap_size, dsp_read_scratch)) + +def print_fifo(address, size, group_size, gap_size): + print("f: " + group_memory(address, size, group_size, gap_size, dsp_read_fifo)) + +def print_x(address, count, silent = False): + words = [] + for i in range(count): + words += ["%06X" % apu.read_u32(NV_PAPU_GPXMEM + (address + i) * 4)] + if not silent: + print("%s" % words) + return str(words) + +def print_dma_block(address): + x = print_x(address, 7, silent = True) + print("dma x:$%x: %s" % (address, x)) + +# Check input data +old = print_dma_block(0x107) +print_fifo(0x200, 40, 0, 0) +print_scratch(0x300, 40, 0, 0) + +# Start DSP +dsp_start() + +# Wait for results +while apu.read_u32(NV_PAPU_GPYMEM + 0) != 0x1337: + pass + +# Signal success +print("Finished") + +# Check output data +new = print_dma_block(0x107) +print_fifo(0x1F0, 40, 0, 0) +print_scratch(0x200, 40, 0, 0) +print_scratch(0x300, 40, 0, 0) +print_x(0x700, 10) + +assert(new == old) + +