mirror of
https://github.com/KrisKennaway/ii-sound.git
synced 2024-06-02 01:41:30 +00:00
Begin to rework player operation generation
This commit is contained in:
parent
695ddb2c10
commit
efb66e03d8
|
@ -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"
|
||||||
|
|
|
@ -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())
|
||||||
|
|
||||||
|
|
1164
opcodes_generated.py
1164
opcodes_generated.py
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user