Begin to rework player operation generation

This commit is contained in:
kris 2022-07-02 10:05:21 +01:00
parent 695ddb2c10
commit efb66e03d8
3 changed files with 580 additions and 726 deletions

View File

@ -5,6 +5,23 @@ from typing import Iterable, List, Tuple
import opcodes_6502 import opcodes_6502
def audio_opcodes() -> Iterable[Tuple[opcodes_6502.Opcode]]:
# These two basic sequences let us chain together STA $C030 with any number
# >= 10 of intervening cycles (except 11). We don't need to explicitly
# include 6 or more cycles of NOP because those can be obtained by chaining
# together JMP (WDATA) to itself
#
# XXX support 11 cycles explicitly?
yield tuple(
[nop for nop in opcodes_6502.nops(4)] + [
opcodes_6502.STA_C030, opcodes_6502.JMP_WDATA])
yield tuple(
[nop for nop in opcodes_6502.nops(4)] + [
opcodes_6502.Opcode(3, 2, "STA zpdummy"),
opcodes_6502.STA_C030, opcodes_6502.JMP_WDATA])
def duty_cycle_range(): def duty_cycle_range():
cycles = [] cycles = []
for i in range(4, 42): for i in range(4, 42):
@ -172,11 +189,9 @@ def _duty_cycles(duty_cycles):
for c in sorted(list(res.keys())): for c in sorted(list(res.keys())):
pair = sorted(res[c], reverse=False)[0][1:] pair = sorted(res[c], reverse=False)[0][1:]
cycles.append(pair) cycles.append(pair)
print(c, pair) # print(c, pair)
print(len(cycles)) return sorted(cycles)
return sorted(cycles, key=lambda p: p[0] + p[1])
EOF_DUTY_CYCLES = _duty_cycles(duty_cycle_range()) EOF_DUTY_CYCLES = _duty_cycles(duty_cycle_range())
@ -315,25 +330,7 @@ def _make_end_of_frame_voltages2(cycles) -> numpy.ndarray:
return numpy.array(c, dtype=numpy.float32) return numpy.array(c, dtype=numpy.float32)
def audio_opcodes() -> Iterable[opcodes_6502.Opcode]:
# These two basic sequences let us chain together STA $C030 with any number
# >= 10 of intervening cycles (except 11). We don't need to explicitly
# include 6 or more cycles of NOP because those can be obtained by chaining
# together JMP (WDATA) to itself
#
# XXX support 11 cycles explicitly?
yield tuple(
[nop for nop in opcodes_6502.nops(4)] + [
opcodes_6502.STA_C030, opcodes_6502.JMP_WDATA])
yield tuple(
[nop for nop in opcodes_6502.nops(4)] + [
opcodes_6502.Opcode(3, 2, "STA zpdummy"),
opcodes_6502.STA_C030, opcodes_6502.JMP_WDATA])
def generate_player( def generate_player(
player_ops: Iterable[opcodes_6502.Opcode],
opcode_filename: str, opcode_filename: str,
player_stage1_filename: str, player_stage1_filename: str,
player_stage2_filename: str player_stage2_filename: str
@ -344,9 +341,12 @@ def generate_player(
unique_entrypoints = {} unique_entrypoints = {}
toggles = {} toggles = {}
# Write out page 3 operations
with open(player_stage1_filename, "w+") as f: with open(player_stage1_filename, "w+") as f:
for i, ops in enumerate(player_ops): # Audio operations
for i, ops in enumerate(audio_opcodes()):
player_op = [] player_op = []
# Generate unique entrypoints
for j, op in enumerate(ops): for j, op in enumerate(ops):
op_suffix_toggles = opcodes_6502.toggles(ops[j:]) op_suffix_toggles = opcodes_6502.toggles(ops[j:])
if op_suffix_toggles not in seen_op_suffix_toggles: if op_suffix_toggles not in seen_op_suffix_toggles:
@ -371,7 +371,9 @@ def generate_player(
num_bytes += player_op_len num_bytes += player_op_len
f.write("\n") f.write("\n")
# stage 1 EOF trampoline operations
duty_cycle_first = sorted(list(set(dc[0] for dc in EOF_DUTY_CYCLES))) duty_cycle_first = sorted(list(set(dc[0] for dc in EOF_DUTY_CYCLES)))
stage_1_offsets = {}
for eof_stage1_cycles in duty_cycle_first: for eof_stage1_cycles in duty_cycle_first:
eof_stage1_ops = EOF_TRAMPOLINE_STAGE1[eof_stage1_cycles] eof_stage1_ops = EOF_TRAMPOLINE_STAGE1[eof_stage1_cycles]
if not eof_stage1_ops: if not eof_stage1_ops:
@ -382,10 +384,12 @@ def generate_player(
f.write("\n") f.write("\n")
num_bytes += opcodes_6502.total_bytes(eof_stage1_ops) num_bytes += opcodes_6502.total_bytes(eof_stage1_ops)
stage_1_offsets[eof_stage1_cycles] = num_bytes
f.write("; %d entrypoints, %d bytes\n" % ( f.write("; %d entrypoints, %d bytes\n" % (
len(unique_entrypoints), num_bytes)) len(unique_entrypoints), num_bytes))
# Write out stage 2 EOF trampoline operations
with open(player_stage2_filename, "w+") as f: with open(player_stage2_filename, "w+") as f:
for eof_stage1_cycles in duty_cycle_first: for eof_stage1_cycles in duty_cycle_first:
@ -404,9 +408,10 @@ def generate_player(
opcodes_6502.STA_C030, opcodes_6502.padding(b - 4)] opcodes_6502.STA_C030, opcodes_6502.padding(b - 4)]
) )
stage_3_ops = [ stage_3_ops = [
opcodes_6502.Literal("eof_stage_3_%d_%d:" % (a, b), indent=0) opcodes_6502.Literal(
] + list(opcodes_6502.interleave_opcodes( "eof_stage_3_%d_%d:" % (a, b), indent=0)
stage_3_tick_ops, EOF_STAGE_3_BASE)) ] + list(opcodes_6502.interleave_opcodes(
stage_3_tick_ops, EOF_STAGE_3_BASE))
for op in stage_3_ops: for op in stage_3_ops:
f.write("%s\n" % str(op)) f.write("%s\n" % str(op))
f.write("\n") f.write("\n")
@ -423,32 +428,56 @@ def generate_player(
# eof_trampoline_7_stage3_page: # eof_trampoline_7_stage3_page:
# ; ... # ; ...
with open(opcode_filename, "w") as f: with open(opcode_filename, "w") as f:
f.write("import enum\nimport numpy\n\n\n") f.write("""
f.write("class Opcode(enum.Enum):\n") import numpy
class PlayerOp:
def __init__(self, byte: int):
self.byte = byte
class PlayerOps:
""")
for o in unique_entrypoints.keys(): for o in unique_entrypoints.keys():
f.write(" TICK_%02x = 0x%02x\n" % (o, o)) f.write(" TICK_%02x = PlayerOp(0x%02x)\n" % (o, o))
f.write(" EXIT = 0x%02x\n" % num_bytes) # XXX EXIT operation
# f.write(" END_OF_FRAME = 0x%02x\n" % (num_bytes + 3)) # f.write(" EXIT = PlayerOp(0x%02x)\n" % num_bytes)
for i, _ in enumerate(EOF_DUTY_CYCLES): f.write("\n")
eof_stage1_names = []
for first in duty_cycle_first:
eof_stage1_name = "END_OF_FRAME_%d_STAGE1" % first
eof_stage1_names.append(eof_stage1_name)
f.write( f.write(
" END_OF_FRAME_%d = 0x%02x\n" % (i, num_bytes + 4 + i)) " %s = PlayerOp(0x%02x)\n" % (
f.write("\n\nVOLTAGE_SCHEDULE = {\n") eof_stage1_name, stage_1_offsets[first]))
for o, v in unique_entrypoints.items(): f.write("\n")
eof_stage2_names = []
for first, second in EOF_DUTY_CYCLES:
eof_stage2_name = "END_OF_FRAME_%d_%d_STAGE2_3" % (first, second)
eof_stage2_names.append(eof_stage2_name)
f.write( f.write(
" Opcode.TICK_%02x: numpy.array(%s, dtype=numpy.float32)," " %s = PlayerOp(0x%02x)\n" % (eof_stage2_name,
"\n" % (o, v)) EOF_TRAMPOLINE_STAGE3_PAGE_OFFSETS[
for i, skip_cycles in enumerate(EOF_DUTY_CYCLES): first, second][1]))
f.write(" Opcode.END_OF_FRAME_%d: numpy.array([%s], " f.write("\n")
"dtype=numpy.float32), # %s\n" % (i, ", ".join(
str(f) for f in _make_end_of_frame_voltages2( # f.write("\n\nVOLTAGE_SCHEDULE = {\n")
skip_cycles)), skip_cycles)) # for o, v in unique_entrypoints.items():
f.write("}\n") # f.write(
# # " Opcode.TICK_%02x: numpy.array(%s, dtype=numpy.float32),"
# "\n" % (o, v))
# for i, skip_cycles in enumerate(EOF_DUTY_CYCLES):
# f.write(" Opcode.END_OF_FRAME_%d: numpy.array([%s], "
# "dtype=numpy.float32), # %s\n" % (i, ", ".join(
# str(f) for f in _make_end_of_frame_voltages2(
# skip_cycles)), skip_cycles))
# f.write("}\n")
# f.write("\n\nTOGGLES = {\n") # f.write("\n\nTOGGLES = {\n")
# for o, v in toggles.items(): # for o, v in toggles.items():
# f.write( # f.write(
@ -456,16 +485,19 @@ def generate_player(
# ) # )
# f.write("}\n") # f.write("}\n")
# #
f.write("\n\nEOF_OPCODES = (\n") f.write("\nEOF_STAGE_1_OPS = (\n")
for i in range(len(EOF_DUTY_CYCLES)): for n in eof_stage1_names:
f.write(" Opcode.END_OF_FRAME_%d,\n" % i) f.write(" PlayerOps.%s,\n" % n)
f.write(")\n")
f.write("\n\nEOF_STAGE_2_3_OPS = (\n")
for n in eof_stage2_names:
f.write(" PlayerOps.%s,\n" % n)
f.write(")\n") f.write(")\n")
def main(): def main():
player_ops = audio_opcodes()
generate_player( generate_player(
player_ops,
opcode_filename="opcodes_generated.py", opcode_filename="opcodes_generated.py",
player_stage1_filename="player/player_generated.s", player_stage1_filename="player/player_generated.s",
player_stage2_filename="player/player_stage2_generated.s" player_stage2_filename="player/player_stage2_generated.s"

View File

@ -4,6 +4,8 @@ import opcodes_generated
import numpy import numpy
from typing import Dict, List, Tuple, Iterable from typing import Dict, List, Tuple, Iterable
# #
# def _make_end_of_frame_voltages(bits) -> numpy.ndarray: # def _make_end_of_frame_voltages(bits) -> numpy.ndarray:
# """Voltage sequence for end-of-frame TCP processing.""" # """Voltage sequence for end-of-frame TCP processing."""
@ -23,6 +25,8 @@ from typing import Dict, List, Tuple, Iterable
Opcode = opcodes_generated.Opcode Opcode = opcodes_generated.Opcode
# TOGGLES = opcodes_generated.TOGGLES # TOGGLES = opcodes_generated.TOGGLES
_VOLTAGE_SCHEDULE = opcodes_generated.VOLTAGE_SCHEDULE _VOLTAGE_SCHEDULE = opcodes_generated.VOLTAGE_SCHEDULE
# _VOLTAGE_SCHEDULE[Opcode.END_OF_FRAME], TOGGLES[Opcode.END_OF_FRAME] = ( # _VOLTAGE_SCHEDULE[Opcode.END_OF_FRAME], TOGGLES[Opcode.END_OF_FRAME] = (
# _make_end_of_frame_voltages()) # _make_end_of_frame_voltages())

File diff suppressed because it is too large Load Diff