2020-08-13 21:08:50 +00:00
|
|
|
import enum
|
|
|
|
import functools
|
|
|
|
import numpy
|
|
|
|
from typing import Dict, List, Tuple, Iterable
|
|
|
|
|
|
|
|
|
2020-08-16 22:15:30 +00:00
|
|
|
# TODO: support 6502 cycle counts as well
|
2020-08-24 20:27:24 +00:00
|
|
|
#
|
|
|
|
# class Opcode(enum.Enum):
|
|
|
|
# """Audio player opcodes representing atomic units of audio playback work."""
|
|
|
|
# TICK_17 = 0x00
|
|
|
|
# TICK_15 = 0x01
|
|
|
|
# TICK_13 = 0x02
|
|
|
|
# TICK_14 = 0x0a
|
|
|
|
# TICK_12 = 0x0b
|
|
|
|
# TICK_10 = 0x0c
|
|
|
|
# NOTICK_6 = 0x0f
|
|
|
|
#
|
|
|
|
# EXIT = 0x12
|
|
|
|
# SLOWPATH = 0x22
|
|
|
|
#
|
|
|
|
# # XXX not yet diminishing returns, add more?
|
|
|
|
# # TODO: incremental quality from each of these
|
|
|
|
# TICK_TICK_TICK_TICK_TICK = 0x77
|
|
|
|
# TICK_TICK_TICK_TICK = 0x7a
|
|
|
|
# TICK_TICK_TICK = 0x7d
|
|
|
|
# TICK_TICK = 0x80
|
|
|
|
# INC_INC_INC_INC_INC = 0x89
|
|
|
|
# INC_INC_INC_INC = 0x8c
|
|
|
|
# INC_INC_INC = 0x8f
|
|
|
|
# INC_INC = 0x92
|
|
|
|
# INC = 0x95
|
|
|
|
# STAX_STAX_STAX_STAX_STAX = 0x9b
|
|
|
|
# STAX_STAX_STAX_STAX = 0x9e
|
|
|
|
# STAX_STAX_STAX = 0xa1
|
|
|
|
# STAX_STAX = 0xa4
|
|
|
|
# STAX = 0xa7
|
|
|
|
# INCX_INCX_INCX_INCX_INCX = 0xad
|
|
|
|
# INCX_INCX_INCX_INCX = 0xb0
|
|
|
|
# INCX_INCX_INCX = 0xb3
|
|
|
|
# INCX_INCX = 0xb6
|
|
|
|
# INCX = 0xb9
|
2020-08-13 21:08:50 +00:00
|
|
|
class Opcode(enum.Enum):
|
2020-08-24 20:27:24 +00:00
|
|
|
TICK_01 = 0x01
|
|
|
|
TICK_02 = 0x02
|
|
|
|
TICK_03 = 0x03
|
|
|
|
TICK_04 = 0x04
|
|
|
|
TICK_05 = 0x05
|
|
|
|
TICK_08 = 0x08
|
|
|
|
TICK_09 = 0x09
|
|
|
|
TICK_0a = 0x0a
|
|
|
|
TICK_0b = 0x0b
|
|
|
|
TICK_0c = 0x0c
|
|
|
|
TICK_0e = 0x0e
|
|
|
|
TICK_12 = 0x12
|
|
|
|
TICK_13 = 0x13
|
|
|
|
TICK_14 = 0x14
|
|
|
|
TICK_17 = 0x17
|
|
|
|
TICK_1b = 0x1b
|
|
|
|
TICK_1c = 0x1c
|
|
|
|
TICK_1d = 0x1d
|
|
|
|
TICK_20 = 0x20
|
|
|
|
TICK_24 = 0x24
|
|
|
|
TICK_25 = 0x25
|
|
|
|
TICK_27 = 0x27
|
|
|
|
TICK_2e = 0x2e
|
|
|
|
TICK_2f = 0x2f
|
|
|
|
TICK_32 = 0x32
|
|
|
|
TICK_36 = 0x36
|
|
|
|
TICK_37 = 0x37
|
|
|
|
TICK_3a = 0x3a
|
|
|
|
TICK_3e = 0x3e
|
|
|
|
TICK_40 = 0x40
|
|
|
|
TICK_47 = 0x47
|
|
|
|
TICK_49 = 0x49
|
|
|
|
TICK_50 = 0x50
|
|
|
|
TICK_53 = 0x53
|
|
|
|
TICK_5a = 0x5a
|
|
|
|
TICK_5d = 0x5d
|
|
|
|
TICK_65 = 0x65
|
|
|
|
TICK_70 = 0x70
|
|
|
|
TICK_79 = 0x79
|
|
|
|
TICK_82 = 0x82
|
|
|
|
TICK_8b = 0x8b
|
|
|
|
TICK_94 = 0x94
|
|
|
|
EXIT = 0xfe
|
|
|
|
SLOWPATH = 0xff
|
2020-08-16 22:15:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
def make_tick_voltages(length) -> numpy.ndarray:
|
|
|
|
"""Voltage sequence for a NOP; ...; STA $C030; JMP (WDATA)."""
|
2020-08-13 21:08:50 +00:00
|
|
|
c = numpy.full(length, 1.0, dtype=numpy.float32)
|
2020-08-16 22:15:30 +00:00
|
|
|
for i in range(length - 7, length): # TODO: 6502
|
2020-08-13 21:08:50 +00:00
|
|
|
c[i] = -1.0
|
|
|
|
return c
|
|
|
|
|
|
|
|
|
2020-08-16 22:15:30 +00:00
|
|
|
def make_notick_voltages(length) -> numpy.ndarray:
|
|
|
|
"""Voltage sequence for a NOP; ...; JMP (WDATA)."""
|
2020-08-13 21:08:50 +00:00
|
|
|
return numpy.full(length, 1.0, dtype=numpy.float32)
|
|
|
|
|
|
|
|
|
2020-08-16 22:15:30 +00:00
|
|
|
def make_slowpath_voltages() -> numpy.ndarray:
|
|
|
|
"""Voltage sequence for slowpath TCP processing."""
|
2020-08-24 20:27:24 +00:00
|
|
|
length = 14 * 10 + 10 # TODO: 6502
|
2020-08-13 21:08:50 +00:00
|
|
|
c = numpy.full(length, 1.0, dtype=numpy.float32)
|
|
|
|
voltage_high = True
|
2020-08-24 20:27:24 +00:00
|
|
|
for i in range(15):
|
2020-08-13 21:08:50 +00:00
|
|
|
voltage_high = not voltage_high
|
2020-08-24 20:27:24 +00:00
|
|
|
for j in range(3 + 10 * i, min(length, 3 + 10 * (i + 1))):
|
2020-08-13 21:08:50 +00:00
|
|
|
c[j] = 1.0 if voltage_high else -1.0
|
|
|
|
return c
|
|
|
|
|
2020-08-24 20:27:24 +00:00
|
|
|
# exp3
|
|
|
|
|
|
|
|
class Opcode(enum.Enum):
|
|
|
|
TICK_00 = 0x00
|
|
|
|
TICK_01 = 0x01
|
|
|
|
TICK_02 = 0x02
|
|
|
|
TICK_03 = 0x03
|
|
|
|
TICK_04 = 0x04
|
|
|
|
TICK_05 = 0x05
|
|
|
|
TICK_08 = 0x08
|
|
|
|
TICK_09 = 0x09
|
|
|
|
TICK_0a = 0x0a
|
|
|
|
TICK_0b = 0x0b
|
|
|
|
TICK_11 = 0x11
|
|
|
|
TICK_12 = 0x12
|
|
|
|
TICK_13 = 0x13
|
|
|
|
TICK_1a = 0x1a
|
|
|
|
TICK_1b = 0x1b
|
|
|
|
TICK_23 = 0x23
|
|
|
|
TICK_2c = 0x2c
|
|
|
|
TICK_2d = 0x2d
|
|
|
|
TICK_2e = 0x2e
|
|
|
|
TICK_34 = 0x34
|
|
|
|
TICK_35 = 0x35
|
|
|
|
TICK_36 = 0x36
|
|
|
|
TICK_3c = 0x3c
|
|
|
|
TICK_3d = 0x3d
|
|
|
|
TICK_46 = 0x46
|
|
|
|
TICK_47 = 0x47
|
|
|
|
TICK_4e = 0x4e
|
|
|
|
TICK_4f = 0x4f
|
|
|
|
TICK_56 = 0x56
|
|
|
|
TICK_60 = 0x60
|
|
|
|
TICK_6a = 0x6a
|
|
|
|
TICK_72 = 0x72
|
|
|
|
TICK_7a = 0x7a
|
|
|
|
TICK_7b = 0x7b
|
|
|
|
TICK_81 = 0x81
|
|
|
|
TICK_8a = 0x8a
|
|
|
|
TICK_93 = 0x93
|
|
|
|
TICK_9c = 0x9c
|
|
|
|
TICK_a5 = 0xa5
|
|
|
|
TICK_ae = 0xae
|
|
|
|
EXIT = 0xb5
|
|
|
|
SLOWPATH = 0xb8
|
2020-08-13 21:08:50 +00:00
|
|
|
|
2020-08-16 22:15:30 +00:00
|
|
|
VOLTAGE_SCHEDULE = {
|
2020-08-24 20:27:24 +00:00
|
|
|
Opcode.TICK_00: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_01: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_02: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_03: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_04: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_05: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_08: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_09: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_0a: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_0b: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_11: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_12: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_13: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_1a: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_1b: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_23: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_2c: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_2d: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_2e: numpy.array((1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_34: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_35: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_36: numpy.array((1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_3c: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_3d: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_46: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_47: numpy.array((1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_4e: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_4f: numpy.array((1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_56: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_60: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_6a: numpy.array((1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_72: numpy.array((1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_7a: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_7b: numpy.array((1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_81: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_8a: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_93: numpy.array((1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_9c: numpy.array((1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_a5: numpy.array((1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
Opcode.TICK_ae: numpy.array((1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
2020-08-16 22:15:30 +00:00
|
|
|
Opcode.SLOWPATH: make_slowpath_voltages(),
|
2020-08-24 20:27:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#
|
|
|
|
# class Opcode(enum.Enum):
|
|
|
|
# TICK_00 = 0x00
|
|
|
|
# TICK_01 = 0x01
|
|
|
|
# TICK_02 = 0x02
|
|
|
|
# TICK_03 = 0x03
|
|
|
|
# TICK_04 = 0x04
|
|
|
|
# TICK_05 = 0x05
|
|
|
|
# TICK_08 = 0x08
|
|
|
|
# TICK_09 = 0x09
|
|
|
|
# TICK_0a = 0x0a
|
|
|
|
# TICK_0b = 0x0b
|
|
|
|
# TICK_0c = 0x0c
|
|
|
|
# TICK_11 = 0x11
|
|
|
|
# TICK_12 = 0x12
|
|
|
|
# TICK_13 = 0x13
|
|
|
|
# TICK_14 = 0x14
|
|
|
|
# TICK_1a = 0x1a
|
|
|
|
# TICK_1b = 0x1b
|
|
|
|
# TICK_1c = 0x1c
|
|
|
|
# TICK_23 = 0x23
|
|
|
|
# TICK_24 = 0x24
|
|
|
|
# TICK_25 = 0x25
|
|
|
|
# TICK_2d = 0x2d
|
|
|
|
# TICK_2e = 0x2e
|
|
|
|
# TICK_2f = 0x2f
|
|
|
|
# TICK_37 = 0x37
|
|
|
|
# TICK_38 = 0x38
|
|
|
|
# TICK_40 = 0x40
|
|
|
|
# TICK_41 = 0x41
|
|
|
|
# TICK_4a = 0x4a
|
|
|
|
# TICK_4b = 0x4b
|
|
|
|
# TICK_54 = 0x54
|
|
|
|
# TICK_5d = 0x5d
|
|
|
|
# TICK_67 = 0x67
|
|
|
|
# TICK_71 = 0x71
|
|
|
|
# TICK_72 = 0x72
|
|
|
|
# TICK_7b = 0x7b
|
|
|
|
# TICK_85 = 0x85
|
|
|
|
# TICK_8f = 0x8f
|
|
|
|
# TICK_9a = 0x9a
|
|
|
|
# TICK_a5 = 0xa5
|
|
|
|
# TICK_b0 = 0xb0
|
|
|
|
# EXIT = 0xba
|
|
|
|
# SLOWPATH = 0xbd
|
|
|
|
#
|
|
|
|
# VOLTAGE_SCHEDULE = {
|
|
|
|
# Opcode.TICK_00: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_01: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_02: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_03: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_04: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_05: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_08: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_09: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_0a: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_0b: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_0c: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_11: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_12: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_13: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_14: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_1a: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_1b: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_1c: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_23: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_24: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_25: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_2d: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_2e: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_2f: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_37: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_38: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_40: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_41: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_4a: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_4b: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_54: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_5d: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_67: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_71: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_72: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_7b: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_85: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_8f: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_9a: numpy.array((1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_a5: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.TICK_b0: numpy.array((1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0), dtype=numpy.float32),
|
|
|
|
# Opcode.SLOWPATH: make_slowpath_voltages(),
|
|
|
|
# }
|
2020-08-13 21:08:50 +00:00
|
|
|
|
|
|
|
def cycle_length(op: Opcode) -> int:
|
2020-08-16 22:15:30 +00:00
|
|
|
"""Returns the 65C02 cycle length of a player opcode."""
|
|
|
|
return len(VOLTAGE_SCHEDULE[op])
|
2020-08-13 21:08:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
class _Opcodes:
|
2020-08-16 22:15:30 +00:00
|
|
|
"""Container for immutable Iterable[Opcode], to improve hash performance."""
|
|
|
|
|
2020-08-13 21:08:50 +00:00
|
|
|
def __init__(self, opcodes: Iterable[Opcode]):
|
|
|
|
self.opcodes = tuple(opcodes)
|
|
|
|
self._hash = hash(self.opcodes)
|
|
|
|
|
|
|
|
def __hash__(self):
|
|
|
|
return self._hash
|
|
|
|
|
2020-08-16 22:15:30 +00:00
|
|
|
|
2020-08-13 21:08:50 +00:00
|
|
|
# Guarantees each Tuple[Opcode] has a unique _Opcodes representation
|
2020-08-16 22:15:30 +00:00
|
|
|
_OPCODES_SINGLETON = {}
|
2020-08-13 21:08:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
@functools.lru_cache(None)
|
|
|
|
def Opcodes(opcodes: Tuple[Opcode]):
|
2020-08-16 22:15:30 +00:00
|
|
|
"""Returns unique _Opcodes representation for Tuple[Opcode]."""
|
|
|
|
return _OPCODES_SINGLETON.setdefault(opcodes, _Opcodes(opcodes))
|
2020-08-13 21:08:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
@functools.lru_cache(None)
|
|
|
|
def opcode_choices(frame_offset: int) -> List[Opcode]:
|
2020-08-16 22:15:30 +00:00
|
|
|
"""Returns sorted list of valid opcodes for given frame offset.
|
|
|
|
|
|
|
|
Sorted by decreasing cycle length, so that if two opcodes produce equally
|
|
|
|
good results, we'll pick the one with the longest cycle count to reduce the
|
|
|
|
stream bitrate.
|
|
|
|
"""
|
2020-08-13 21:08:50 +00:00
|
|
|
if frame_offset == 2047:
|
|
|
|
return [Opcode.SLOWPATH]
|
|
|
|
|
2020-08-16 22:15:30 +00:00
|
|
|
opcodes = set(VOLTAGE_SCHEDULE.keys()) - {Opcode.SLOWPATH}
|
2020-08-13 21:08:50 +00:00
|
|
|
return sorted(list(opcodes), key=cycle_length, reverse=True)
|
|
|
|
|
|
|
|
|
2020-08-16 22:15:30 +00:00
|
|
|
@functools.lru_cache(None)
|
|
|
|
def opcode_lookahead(
|
|
|
|
frame_offset: int,
|
|
|
|
lookahead_cycles: int) -> Tuple[_Opcodes]:
|
|
|
|
"""Computes all valid sequences of opcodes spanning lookahead_cycles."""
|
|
|
|
|
|
|
|
return tuple(Opcodes(ops) for ops in
|
|
|
|
_opcode_lookahead(frame_offset, lookahead_cycles))
|
|
|
|
|
|
|
|
|
2020-08-13 21:08:50 +00:00
|
|
|
@functools.lru_cache(None)
|
|
|
|
def _opcode_lookahead(
|
|
|
|
frame_offset: int,
|
|
|
|
lookahead_cycles: int) -> Tuple[Tuple[Opcode]]:
|
2020-08-16 22:15:30 +00:00
|
|
|
"""Recursively enumerates all valid opcode sequences."""
|
|
|
|
|
2020-08-13 21:08:50 +00:00
|
|
|
ch = opcode_choices(frame_offset)
|
|
|
|
ops = []
|
|
|
|
for op in ch:
|
|
|
|
if cycle_length(op) >= lookahead_cycles:
|
|
|
|
ops.append((op,))
|
|
|
|
else:
|
|
|
|
for res in _opcode_lookahead((frame_offset + 1) % 2048,
|
2020-08-16 22:15:30 +00:00
|
|
|
lookahead_cycles - cycle_length(op)):
|
2020-08-13 21:08:50 +00:00
|
|
|
ops.append((op,) + res)
|
2020-08-16 22:15:30 +00:00
|
|
|
return tuple(ops) # TODO: fix return type
|
2020-08-13 21:08:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Cycles:
|
2020-08-16 22:15:30 +00:00
|
|
|
"""Container for immutable Tuple[float], to improve hash performance."""
|
|
|
|
|
2020-08-13 21:08:50 +00:00
|
|
|
def __init__(self, cycles: Tuple[float]):
|
|
|
|
self.cycles = cycles
|
|
|
|
self._hash = hash(cycles)
|
|
|
|
|
|
|
|
def __hash__(self):
|
|
|
|
return self._hash
|
|
|
|
|
|
|
|
|
2020-08-16 22:15:30 +00:00
|
|
|
# Guarantees each Tuple[float] has a unique Cycles representation
|
|
|
|
_CYCLES_SINGLETON = {}
|
|
|
|
|
|
|
|
|
2020-08-13 21:08:50 +00:00
|
|
|
@functools.lru_cache(None)
|
|
|
|
def cycle_lookahead(
|
|
|
|
opcodes: _Opcodes,
|
|
|
|
lookahead_cycles: int
|
|
|
|
) -> Cycles:
|
2020-08-16 22:15:30 +00:00
|
|
|
"""Computes the applied voltage effects of a sequence of opcodes.
|
|
|
|
|
|
|
|
i.e. produces the sequence of applied voltage changes that will result
|
|
|
|
from executing these opcodes, limited to the next lookahead_cycles.
|
|
|
|
"""
|
2020-08-13 21:08:50 +00:00
|
|
|
cycles = []
|
|
|
|
for op in opcodes.opcodes:
|
2020-08-16 22:15:30 +00:00
|
|
|
cycles.extend(VOLTAGE_SCHEDULE[op])
|
2020-08-13 21:08:50 +00:00
|
|
|
trunc_cycles = tuple(cycles[:lookahead_cycles])
|
2020-08-16 22:15:30 +00:00
|
|
|
return _CYCLES_SINGLETON.setdefault(trunc_cycles, Cycles(trunc_cycles))
|
2020-08-13 21:08:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
@functools.lru_cache(None)
|
2020-08-24 20:27:24 +00:00
|
|
|
def candidate_opcodes(frame_offset:int, lookahead_cycles: int
|
2020-08-13 21:08:50 +00:00
|
|
|
) -> Tuple[List[_Opcodes], numpy.ndarray]:
|
2020-08-16 22:15:30 +00:00
|
|
|
"""Deduplicate a tuple of opcode sequences that are equivalent.
|
|
|
|
|
|
|
|
For each opcode sequence whose effect is the same when truncated to
|
|
|
|
lookahead_cycles, retains the first such opcode sequence.
|
|
|
|
"""
|
2020-08-24 20:27:24 +00:00
|
|
|
opcodes = opcode_lookahead(frame_offset, lookahead_cycles)
|
2020-08-13 21:08:50 +00:00
|
|
|
seen_cycles = set()
|
|
|
|
pruned_opcodes = []
|
|
|
|
pruned_cycles = []
|
|
|
|
for ops in opcodes:
|
|
|
|
cycles = cycle_lookahead(ops, lookahead_cycles)
|
|
|
|
if cycles in seen_cycles:
|
|
|
|
continue
|
|
|
|
seen_cycles.add(cycles)
|
|
|
|
pruned_opcodes.append(ops)
|
|
|
|
pruned_cycles.append(cycles.cycles)
|
|
|
|
|
2020-08-24 20:27:24 +00:00
|
|
|
return pruned_opcodes, numpy.array(pruned_cycles, dtype=numpy.float32)
|