diff --git a/README.rst b/README.rst index b7ae53a..67e7577 100644 --- a/README.rst +++ b/README.rst @@ -55,6 +55,11 @@ To install in a virtual environment in your current project: source .venv/bin/activate pip3 install adafruit-circuitpython-pioasm +CircuitPython Extensions +======================== + +* ``.fifo auto``: By default, CircuitPython joins the TX and RX fifos if a PIO program only receives or transmits. The ``.fifo auto`` directive makes this explicit. + Usage Example ============= diff --git a/adafruit_pioasm.py b/adafruit_pioasm.py index fa5a529..ad29fcb 100644 --- a/adafruit_pioasm.py +++ b/adafruit_pioasm.py @@ -29,10 +29,20 @@ IN_SOURCES = ["pins", "x", "y", "null", None, None, "isr", "osr"] OUT_DESTINATIONS = ["pins", "x", "y", "null", "pindirs", "pc", "isr", "exec"] WAIT_SOURCES = ["gpio", "pin", "irq", None] -MOV_DESTINATIONS = ["pins", "x", "y", None, "exec", "pc", "isr", "osr"] +MOV_DESTINATIONS_V0 = ["pins", "x", "y", None, "exec", "pc", "isr", "osr"] +MOV_DESTINATIONS_V1 = ["pins", "x", "y", "pindirs", "exec", "pc", "isr", "osr"] MOV_SOURCES = ["pins", "x", "y", "null", None, "status", "isr", "osr"] MOV_OPS = [None, "~", "::", None] SET_DESTINATIONS = ["pins", "x", "y", None, "pindirs", None, None, None] +FIFO_TYPES = { + "auto": 0, + "txrx": 0, + "tx": 0, + "rx": 0, + "txput": 1, + "txget": 1, + "putget": 1, +} class Program: # pylint: disable=too-few-public-methods @@ -58,18 +68,65 @@ def __init__(self, text_program: str, *, build_debuginfo: bool = False) -> None: wrap = None wrap_target = None offset = -1 + pio_version = 0 + fifo_type = "auto" + mov_status_type = None + mov_status_n = None + in_count = None + in_shift_right = None + auto_push = None + push_threshold = None + out_count = None + out_shift_right = None + auto_pull = None + pull_threshold = None + set_count = None + + def require_before_instruction(): + if len(instructions) != 0: + raise RuntimeError(f"{words[0]} must be before first instruction") + + def require_version(required_version, instruction): + if pio_version < required_version: + raise RuntimeError( + f"{instruction} requires .pio_version {required_version}" + ) + + def int_in_range(arg, low, high, what, radix=0): + result = int(arg, radix) + if low <= result < high: + return result + raise RuntimeError( + f"{what} must be at least {low} and less than {high}, got {result}" + ) + + def parse_rxfifo_brackets(arg, fifo_dir): + require_version(1, line) + if ( # pylint: disable=consider-using-in + fifo_type != "putget" and fifo_type != fifo_dir + ): + raise RuntimeError( + f"FIFO must be configured for '{fifo_dir}' or 'putget' for {line}" + ) + if arg.endswith("[y]"): + return 0b1000 + return int_in_range(arg[7:-1], 0, 8, "rxfifo index") + for i, line in enumerate(text_program.split("\n")): - line = line.strip() + line = line.split(";")[0].strip() if not line: continue - if ";" in line: - line = line.split(";")[0].strip() + words = line.split() if line.startswith(".program"): if program_name: raise RuntimeError("Multiple programs not supported") program_name = line.split()[1] + elif line.startswith(".pio_version"): + require_before_instruction() + pio_version = int_in_range(words[1], 0, 2, ".pio_version") elif line.startswith(".origin"): - offset = int(line.split()[1], 0) + require_before_instruction() + offset = int_in_range(words[1], 0, 32, ".origin") elif line.startswith(".wrap_target"): wrap_target = len(instructions) elif line.startswith(".wrap"): @@ -79,6 +136,87 @@ def __init__(self, text_program: str, *, build_debuginfo: bool = False) -> None: elif line.startswith(".side_set"): sideset_count = int(line.split()[1], 0) sideset_enable = "opt" in line + elif line.startswith(".fifo"): + require_before_instruction() + fifo_type = line.split()[1] + required_version = FIFO_TYPES.get(fifo_type) + if required_version is None: + raise RuntimeError(f"Invalid fifo type {fifo_type}") + require_version(required_version, line) + elif line.startswith(".mov_status"): + require_before_instruction() + required_version = 0 + mov_status_n = 0 + mov_status_type = words[1] + if words[1] in ("txfifo", "rxfifo"): + if words[2] != "<": + raise RuntimeError(f"Invalid {line}") + mov_status_n = int_in_range(words[3], 0, 32, words[1]) + elif words[1] == "irq": + required_version = 1 + idx = 2 + if words[idx] == "next": + mov_status_n = 0x10 + idx += 1 + elif words[idx] == "prev": + mov_status_n = 0x8 + idx += 1 + else: + mov_status_n = 0 + if words[idx] != "set": + raise RuntimeError(f"Invalid {line})") + mov_status_n |= int_in_range(words[idx + 1], 0, 8, "mov_status irq") + require_version(required_version, line) + elif words[0] == ".out": + require_before_instruction() + out_count = int_in_range(words[1], 1, 33, ".out count") + auto_pull = False + + idx = 2 + if idx < len(words) and words[idx] == "left": + out_shift_right = False + idx += 1 + elif idx < len(words) and words[idx] == "right": + out_shift_right = True + idx += 1 + + if idx < len(words) and words[idx] == "auto": + auto_pull = True + idx += 1 + + if idx < len(words): + pull_threshold = int_in_range(words[idx], 1, 33, ".out threshold") + idx += 1 + + elif words[0] == ".in": + require_before_instruction() + in_count = int_in_range( + words[1], 32 if pio_version == 0 else 1, 33, ".in count" + ) + auto_push = False + + idx = 2 + if idx < len(words) and words[idx] == "left": + in_shift_right = False + idx += 1 + elif idx < len(words) and words[idx] == "right": + in_shift_right = True + idx += 1 + + if idx < len(words) and words[idx] == "auto": + auto_push = True + idx += 1 + + if idx < len(words): + push_threshold = int_in_range(words[idx], 1, 33, ".in threshold") + idx += 1 + + elif words[0] == ".set": + require_before_instruction() + set_count = int_in_range( + words[1], 5 if pio_version == 0 else 1, 6, ".set count" + ) + elif line.endswith(":"): label = line[:-1] if label in labels: @@ -89,12 +227,21 @@ def __init__(self, text_program: str, *, build_debuginfo: bool = False) -> None: instructions.append(line) linemap.append(i) + if pio_version >= 1: + mov_destinations = MOV_DESTINATIONS_V1 + else: + mov_destinations = MOV_DESTINATIONS_V0 + max_delay = 2 ** (5 - sideset_count - sideset_enable) - 1 assembled = [] - for line in instructions: + for line in instructions: # pylint: disable=too-many-nested-blocks instruction = splitter(line.strip()) delay = 0 - if len(instruction) > 1 and instruction[-1].endswith("]"): # Delay + if ( + len(instruction) > 1 + and instruction[-1].startswith("[") + and instruction[-1].endswith("]") + ): # Delay delay = int(instruction[-1].strip("[]"), 0) if delay < 0: raise RuntimeError("Delay negative:", delay) @@ -138,16 +285,46 @@ def __init__(self, text_program: str, *, build_debuginfo: bool = False) -> None: # instr delay p sr index assembled.append(0b001_00000_0_00_00000) polarity = int(instruction[1], 0) + source = instruction[2] if not 0 <= polarity <= 1: raise RuntimeError("Invalid polarity") assembled[-1] |= polarity << 7 - assembled[-1] |= WAIT_SOURCES.index(instruction[2]) << 5 - num = int(instruction[3], 0) - if not 0 <= num <= 31: - raise RuntimeError("Wait num out of range") - assembled[-1] |= num - if instruction[-1] == "rel": - assembled[-1] |= 0x10 # Set the high bit of the irq value + if instruction[2] == "jmppin": + require_version(1, "wait jmppin") + num = 0 + if len(instruction) > 3: + if len(instruction) < 5 or instruction[3] != "+": + raise RuntimeError("invalid wait jmppin") + num = int_in_range(instruction[4], 0, 4, "wait jmppin offset") + assembled[-1] |= num + assembled[-1] |= 0b11 << 5 # JMPPIN wait source + else: + idx = 3 + assembled[-1] |= WAIT_SOURCES.index(instruction[2]) << 5 + if source == "irq": + if instruction[idx] == "next": + require_version(1, "wait irq next") + assembled[-1] |= 0b11000 + idx += 1 + elif instruction[idx] == "prev": + require_version(1, "wait irq prev") + assembled[-1] |= 0b01000 + idx += 1 + + limit = 8 + # The flag index is decoded in the same way as the IRQ + # index field, decoding down from the two MSBs + if instruction[-1] == "rel": + if assembled[-1] & 0b11000: + raise RuntimeError("cannot use next/prev with rel") + assembled[-1] |= 0b10000 + else: + limit = 32 + num = int_in_range( + instruction[idx], 0, limit, "wait {instruction[2]}" + ) + assembled[-1] |= num + elif instruction[0] == "in": # instr delay src count assembled.append(0b010_00000_000_00000) @@ -185,43 +362,72 @@ def __init__(self, text_program: str, *, build_debuginfo: bool = False) -> None: assembled[-1] |= 0x40 elif instruction[0] == "mov": # instr delay dst op src - assembled.append(0b101_00000_000_00_000) - assembled[-1] |= MOV_DESTINATIONS.index(instruction[1]) << 5 - source = instruction[-1] - source_split = mov_splitter(source) - if len(source_split) == 1: - try: - assembled[-1] |= MOV_SOURCES.index(source) - except ValueError as exc: - raise ValueError(f"Invalid mov source '{source}'") from exc + if instruction[1].startswith("rxfifo["): # mov rxfifo[], isr + assembled.append(0b100_00000_0001_1_000) + if instruction[2] != "isr": + raise ValueError("mov rxfifo[] source must be isr") + assembled[-1] ^= parse_rxfifo_brackets(instruction[1], "txput") + elif instruction[2].startswith("rxfifo["): # mov osr, rxfifo[] + assembled.append(0b100_00000_1001_1_000) + if instruction[1] != "osr": + raise ValueError("mov ,rxfifo[] target must be osr") + assembled[-1] ^= parse_rxfifo_brackets(instruction[2], "txget") else: - assembled[-1] |= MOV_SOURCES.index(source_split[1]) - if source[:1] == "!": - assembled[-1] |= 0x08 - elif source[:1] == "~": - assembled[-1] |= 0x08 - elif source[:2] == "::": - assembled[-1] |= 0x10 + assembled.append(0b101_00000_000_00_000) + assembled[-1] |= mov_destinations.index(instruction[1]) << 5 + source = instruction[-1] + source_split = mov_splitter(source) + if len(source_split) == 1: + try: + assembled[-1] |= MOV_SOURCES.index(source) + except ValueError as exc: + raise ValueError(f"Invalid mov source '{source}'") from exc else: - raise RuntimeError("Invalid mov operator:", source[:1]) - if len(instruction) > 3: - assembled[-1] |= MOV_OPS.index(instruction[-2]) << 3 + assembled[-1] |= MOV_SOURCES.index(source_split[1]) + if source[:1] == "!": + assembled[-1] |= 0x08 + elif source[:1] == "~": + assembled[-1] |= 0x08 + elif source[:2] == "::": + assembled[-1] |= 0x10 + else: + raise RuntimeError("Invalid mov operator:", source[:1]) + if len(instruction) > 3: + assembled[-1] |= MOV_OPS.index(instruction[-2]) << 3 elif instruction[0] == "irq": - # instr delay z c w index + # instr delay z c w tp/idx assembled.append(0b110_00000_0_0_0_00000) + + irq_type = 0 + idx = 1 + if instruction[idx] == "wait": + assembled[-1] |= 0x20 + idx += 1 + elif instruction[idx] == "clear": + assembled[-1] |= 0x40 + idx += 1 + + if instruction[idx] == "prev": + irq_type = 1 + require_version(1, "irq prev") + idx += 1 + elif instruction[idx] == "next": + irq_type = 3 + require_version(1, "irq next") + idx += 1 + if instruction[-1] == "rel": - assembled[-1] |= 0x10 # Set the high bit of the irq value + if irq_type != 0: + raise RuntimeError("cannot use next/prev with rel") + irq_type = 2 instruction.pop() - num = int(instruction[-1], 0) - if not 0 <= num <= 7: - raise RuntimeError("Interrupt index out of range") + + assembled[-1] |= irq_type << 3 + + num = int_in_range(instruction[idx], 0, 8, "irq index") assembled[-1] |= num - if len(instruction) == 3: # after rel has been removed - if instruction[1] == "wait": - assembled[-1] |= 0x20 - elif instruction[1] == "clear": - assembled[-1] |= 0x40 - # All other values are the default of set without waiting + instruction.pop() + elif instruction[0] == "set": # instr delay dst data assembled.append(0b111_00000_000_00000) @@ -247,6 +453,9 @@ def __init__(self, text_program: str, *, build_debuginfo: bool = False) -> None: if offset != -1: self.pio_kwargs["offset"] = offset + if pio_version != 0: + self.pio_kwargs["pio_version"] = pio_version + if sideset_count != 0: self.pio_kwargs["sideset_pin_count"] = sideset_count @@ -255,10 +464,51 @@ def __init__(self, text_program: str, *, build_debuginfo: bool = False) -> None: if wrap_target is not None: self.pio_kwargs["wrap_target"] = wrap_target + if fifo_type != "auto": + self.pio_kwargs["fifo_type"] = fifo_type + + if mov_status_type is not None: + self.pio_kwargs["mov_status_type"] = mov_status_type + self.pio_kwargs["mov_status_n"] = mov_status_n + + if set_count is not None: + self.pio_kwargs["set_pin_count"] = set_count + + if out_count not in (None, 32): + self.pio_kwargs["out_pin_count"] = out_count + + if out_shift_right is not None: + self.pio_kwargs["out_shift_right"] = out_shift_right + + if auto_pull is not None: + self.pio_kwargs["auto_pull"] = auto_pull + + if pull_threshold is not None: + self.pio_kwargs["pull_threshold"] = pull_threshold + + if in_count not in (None, 32): + self.pio_kwargs["in_pin_count"] = in_count + + if in_shift_right is not None: + self.pio_kwargs["in_shift_right"] = in_shift_right + + if auto_push is not None: + self.pio_kwargs["auto_push"] = auto_push + + if push_threshold is not None: + self.pio_kwargs["push_threshold"] = push_threshold + self.assembled = array.array("H", assembled) self.debuginfo = (linemap, text_program) if build_debuginfo else None + @classmethod + def from_file(cls, filename: str, **kwargs) -> "Program": + """Assemble a PIO program in a file""" + with open(filename, "r", encoding="utf-8") as i: + program = i.read() + return cls(program, **kwargs) + def print_c_program(self, name: str, qualifier: str = "const") -> None: """Print the program into a C program snippet""" if self.debuginfo is None: diff --git a/examples/pioasm_rp2350_fifo.py b/examples/pioasm_rp2350_fifo.py new file mode 100644 index 0000000..f6dda86 --- /dev/null +++ b/examples/pioasm_rp2350_fifo.py @@ -0,0 +1,84 @@ +# SPDX-FileCopyrightText: 2024 Jeff Epler, written for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +"""A PIO demo that uses the FIFO in random access mode + +Random access mode is a new feature of the PIO peripheral of the RP2350. +This demo is not compatible with the original RP2040 or Raspberry Pi +Pico. + +Wiring: + * LED with current limiting resistor on GP25 (Pico 2 standard location) + +The LED will blink in several patterns depending on the values loaded in the 'rxfifo' registers +""" + +import array +import time +import board +import rp2pio +import adafruit_pioasm + +program = adafruit_pioasm.Program( + """ + .pio_version 1 + .set 1 + .fifo txget + + ; LED on time taken from rxfifo[0] + mov osr, rxfifo[0] + mov x, osr + + set pins, 1 +xloop1: + jmp x--, xloop1 + + ; LED off time taken from rxfifo[1] + mov osr, rxfifo[1] + mov x, osr + + set pins, 0 +xloop2: + jmp x--, xloop2 + """ +) + + +def assign_uint32s(ar, off, *args): + """Assign multiple 32-bit registers within an AddressRange""" + vv = b"".join(v.to_bytes(4, "little") for v in args) + ar[off : off + 4 * len(args)] = vv + + +print(program.pio_kwargs) +sm = rp2pio.StateMachine( + program.assembled, + first_set_pin=board.GP25, + frequency=10_000_000, + **program.pio_kwargs, +) +fifo = sm.rxfifo + +# Set non-zero register entries & re-start the state machine at its offset. +# this is needed because the default register value could represent a very long delay +fifo[0:4] = b"\1\0\0\0" +fifo[4:8] = b"\1\0\0\0" +sm.run(array.array("H", [sm.offset])) + +while True: + # equal blinks + assign_uint32s(fifo, 0, 2000000, 2000000) + time.sleep(1) + + # small on time + assign_uint32s(fifo, 0, 1000000, 3000000) + time.sleep(1) + + # small off time + assign_uint32s(fifo, 0, 3000000, 1000000) + time.sleep(1) + + # slower blinks + assign_uint32s(fifo, 0, 3000000, 3000000) + time.sleep(1) diff --git a/tests/all_pio_instructions.py b/tests/all_pio_instructions.py new file mode 100644 index 0000000..bd341ca --- /dev/null +++ b/tests/all_pio_instructions.py @@ -0,0 +1,1240 @@ +# SPDX-FileCopyrightText: 2024 Jeff Epler, written for Adafruit Industries +# +# SPDX-License-Identifier: MIT +# pylint: disable=too-many-lines +# fmt: off + +all_instruction = { + 0: 'jmp 0', + 32: 'jmp !x 0', + 64: 'jmp x-- 0', + 96: 'jmp !y 0', + 128: 'jmp y-- 0', + 160: 'jmp x!=y 0', + 192: 'jmp pin 0', + 224: 'jmp !osre 0', + 1: 'jmp 1', + 33: 'jmp !x 1', + 65: 'jmp x-- 1', + 97: 'jmp !y 1', + 129: 'jmp y-- 1', + 161: 'jmp x!=y 1', + 193: 'jmp pin 1', + 225: 'jmp !osre 1', + 2: 'jmp 2', + 34: 'jmp !x 2', + 66: 'jmp x-- 2', + 98: 'jmp !y 2', + 130: 'jmp y-- 2', + 162: 'jmp x!=y 2', + 194: 'jmp pin 2', + 226: 'jmp !osre 2', + 3: 'jmp 3', + 35: 'jmp !x 3', + 67: 'jmp x-- 3', + 99: 'jmp !y 3', + 131: 'jmp y-- 3', + 163: 'jmp x!=y 3', + 195: 'jmp pin 3', + 227: 'jmp !osre 3', + 4: 'jmp 4', + 36: 'jmp !x 4', + 68: 'jmp x-- 4', + 100: 'jmp !y 4', + 132: 'jmp y-- 4', + 164: 'jmp x!=y 4', + 196: 'jmp pin 4', + 228: 'jmp !osre 4', + 5: 'jmp 5', + 37: 'jmp !x 5', + 69: 'jmp x-- 5', + 101: 'jmp !y 5', + 133: 'jmp y-- 5', + 165: 'jmp x!=y 5', + 197: 'jmp pin 5', + 229: 'jmp !osre 5', + 6: 'jmp 6', + 38: 'jmp !x 6', + 70: 'jmp x-- 6', + 102: 'jmp !y 6', + 134: 'jmp y-- 6', + 166: 'jmp x!=y 6', + 198: 'jmp pin 6', + 230: 'jmp !osre 6', + 7: 'jmp 7', + 39: 'jmp !x 7', + 71: 'jmp x-- 7', + 103: 'jmp !y 7', + 135: 'jmp y-- 7', + 167: 'jmp x!=y 7', + 199: 'jmp pin 7', + 231: 'jmp !osre 7', + 8: 'jmp 8', + 40: 'jmp !x 8', + 72: 'jmp x-- 8', + 104: 'jmp !y 8', + 136: 'jmp y-- 8', + 168: 'jmp x!=y 8', + 200: 'jmp pin 8', + 232: 'jmp !osre 8', + 9: 'jmp 9', + 41: 'jmp !x 9', + 73: 'jmp x-- 9', + 105: 'jmp !y 9', + 137: 'jmp y-- 9', + 169: 'jmp x!=y 9', + 201: 'jmp pin 9', + 233: 'jmp !osre 9', + 10: 'jmp 10', + 42: 'jmp !x 10', + 74: 'jmp x-- 10', + 106: 'jmp !y 10', + 138: 'jmp y-- 10', + 170: 'jmp x!=y 10', + 202: 'jmp pin 10', + 234: 'jmp !osre 10', + 11: 'jmp 11', + 43: 'jmp !x 11', + 75: 'jmp x-- 11', + 107: 'jmp !y 11', + 139: 'jmp y-- 11', + 171: 'jmp x!=y 11', + 203: 'jmp pin 11', + 235: 'jmp !osre 11', + 12: 'jmp 12', + 44: 'jmp !x 12', + 76: 'jmp x-- 12', + 108: 'jmp !y 12', + 140: 'jmp y-- 12', + 172: 'jmp x!=y 12', + 204: 'jmp pin 12', + 236: 'jmp !osre 12', + 13: 'jmp 13', + 45: 'jmp !x 13', + 77: 'jmp x-- 13', + 109: 'jmp !y 13', + 141: 'jmp y-- 13', + 173: 'jmp x!=y 13', + 205: 'jmp pin 13', + 237: 'jmp !osre 13', + 14: 'jmp 14', + 46: 'jmp !x 14', + 78: 'jmp x-- 14', + 110: 'jmp !y 14', + 142: 'jmp y-- 14', + 174: 'jmp x!=y 14', + 206: 'jmp pin 14', + 238: 'jmp !osre 14', + 15: 'jmp 15', + 47: 'jmp !x 15', + 79: 'jmp x-- 15', + 111: 'jmp !y 15', + 143: 'jmp y-- 15', + 175: 'jmp x!=y 15', + 207: 'jmp pin 15', + 239: 'jmp !osre 15', + 16: 'jmp 16', + 48: 'jmp !x 16', + 80: 'jmp x-- 16', + 112: 'jmp !y 16', + 144: 'jmp y-- 16', + 176: 'jmp x!=y 16', + 208: 'jmp pin 16', + 240: 'jmp !osre 16', + 17: 'jmp 17', + 49: 'jmp !x 17', + 81: 'jmp x-- 17', + 113: 'jmp !y 17', + 145: 'jmp y-- 17', + 177: 'jmp x!=y 17', + 209: 'jmp pin 17', + 241: 'jmp !osre 17', + 18: 'jmp 18', + 50: 'jmp !x 18', + 82: 'jmp x-- 18', + 114: 'jmp !y 18', + 146: 'jmp y-- 18', + 178: 'jmp x!=y 18', + 210: 'jmp pin 18', + 242: 'jmp !osre 18', + 19: 'jmp 19', + 51: 'jmp !x 19', + 83: 'jmp x-- 19', + 115: 'jmp !y 19', + 147: 'jmp y-- 19', + 179: 'jmp x!=y 19', + 211: 'jmp pin 19', + 243: 'jmp !osre 19', + 20: 'jmp 20', + 52: 'jmp !x 20', + 84: 'jmp x-- 20', + 116: 'jmp !y 20', + 148: 'jmp y-- 20', + 180: 'jmp x!=y 20', + 212: 'jmp pin 20', + 244: 'jmp !osre 20', + 21: 'jmp 21', + 53: 'jmp !x 21', + 85: 'jmp x-- 21', + 117: 'jmp !y 21', + 149: 'jmp y-- 21', + 181: 'jmp x!=y 21', + 213: 'jmp pin 21', + 245: 'jmp !osre 21', + 22: 'jmp 22', + 54: 'jmp !x 22', + 86: 'jmp x-- 22', + 118: 'jmp !y 22', + 150: 'jmp y-- 22', + 182: 'jmp x!=y 22', + 214: 'jmp pin 22', + 246: 'jmp !osre 22', + 23: 'jmp 23', + 55: 'jmp !x 23', + 87: 'jmp x-- 23', + 119: 'jmp !y 23', + 151: 'jmp y-- 23', + 183: 'jmp x!=y 23', + 215: 'jmp pin 23', + 247: 'jmp !osre 23', + 24: 'jmp 24', + 56: 'jmp !x 24', + 88: 'jmp x-- 24', + 120: 'jmp !y 24', + 152: 'jmp y-- 24', + 184: 'jmp x!=y 24', + 216: 'jmp pin 24', + 248: 'jmp !osre 24', + 25: 'jmp 25', + 57: 'jmp !x 25', + 89: 'jmp x-- 25', + 121: 'jmp !y 25', + 153: 'jmp y-- 25', + 185: 'jmp x!=y 25', + 217: 'jmp pin 25', + 249: 'jmp !osre 25', + 26: 'jmp 26', + 58: 'jmp !x 26', + 90: 'jmp x-- 26', + 122: 'jmp !y 26', + 154: 'jmp y-- 26', + 186: 'jmp x!=y 26', + 218: 'jmp pin 26', + 250: 'jmp !osre 26', + 27: 'jmp 27', + 59: 'jmp !x 27', + 91: 'jmp x-- 27', + 123: 'jmp !y 27', + 155: 'jmp y-- 27', + 187: 'jmp x!=y 27', + 219: 'jmp pin 27', + 251: 'jmp !osre 27', + 28: 'jmp 28', + 60: 'jmp !x 28', + 92: 'jmp x-- 28', + 124: 'jmp !y 28', + 156: 'jmp y-- 28', + 188: 'jmp x!=y 28', + 220: 'jmp pin 28', + 252: 'jmp !osre 28', + 29: 'jmp 29', + 61: 'jmp !x 29', + 93: 'jmp x-- 29', + 125: 'jmp !y 29', + 157: 'jmp y-- 29', + 189: 'jmp x!=y 29', + 221: 'jmp pin 29', + 253: 'jmp !osre 29', + 30: 'jmp 30', + 62: 'jmp !x 30', + 94: 'jmp x-- 30', + 126: 'jmp !y 30', + 158: 'jmp y-- 30', + 190: 'jmp x!=y 30', + 222: 'jmp pin 30', + 254: 'jmp !osre 30', + 31: 'jmp 31', + 63: 'jmp !x 31', + 95: 'jmp x-- 31', + 127: 'jmp !y 31', + 159: 'jmp y-- 31', + 191: 'jmp x!=y 31', + 223: 'jmp pin 31', + 255: 'jmp !osre 31', + 8288: 'wait 0 jmppin', + 8192: 'wait 0 gpio 0', + 8193: 'wait 0 gpio 1', + 8194: 'wait 0 gpio 2', + 8195: 'wait 0 gpio 3', + 8196: 'wait 0 gpio 4', + 8197: 'wait 0 gpio 5', + 8198: 'wait 0 gpio 6', + 8199: 'wait 0 gpio 7', + 8200: 'wait 0 gpio 8', + 8201: 'wait 0 gpio 9', + 8202: 'wait 0 gpio 10', + 8203: 'wait 0 gpio 11', + 8204: 'wait 0 gpio 12', + 8205: 'wait 0 gpio 13', + 8206: 'wait 0 gpio 14', + 8207: 'wait 0 gpio 15', + 8208: 'wait 0 gpio 16', + 8209: 'wait 0 gpio 17', + 8210: 'wait 0 gpio 18', + 8211: 'wait 0 gpio 19', + 8212: 'wait 0 gpio 20', + 8213: 'wait 0 gpio 21', + 8214: 'wait 0 gpio 22', + 8215: 'wait 0 gpio 23', + 8216: 'wait 0 gpio 24', + 8217: 'wait 0 gpio 25', + 8218: 'wait 0 gpio 26', + 8219: 'wait 0 gpio 27', + 8220: 'wait 0 gpio 28', + 8221: 'wait 0 gpio 29', + 8222: 'wait 0 gpio 30', + 8223: 'wait 0 gpio 31', + 8224: 'wait 0 pin 0', + 8225: 'wait 0 pin 1', + 8226: 'wait 0 pin 2', + 8227: 'wait 0 pin 3', + 8228: 'wait 0 pin 4', + 8229: 'wait 0 pin 5', + 8230: 'wait 0 pin 6', + 8231: 'wait 0 pin 7', + 8232: 'wait 0 pin 8', + 8233: 'wait 0 pin 9', + 8234: 'wait 0 pin 10', + 8235: 'wait 0 pin 11', + 8236: 'wait 0 pin 12', + 8237: 'wait 0 pin 13', + 8238: 'wait 0 pin 14', + 8239: 'wait 0 pin 15', + 8240: 'wait 0 pin 16', + 8241: 'wait 0 pin 17', + 8242: 'wait 0 pin 18', + 8243: 'wait 0 pin 19', + 8244: 'wait 0 pin 20', + 8245: 'wait 0 pin 21', + 8246: 'wait 0 pin 22', + 8247: 'wait 0 pin 23', + 8248: 'wait 0 pin 24', + 8249: 'wait 0 pin 25', + 8250: 'wait 0 pin 26', + 8251: 'wait 0 pin 27', + 8252: 'wait 0 pin 28', + 8253: 'wait 0 pin 29', + 8254: 'wait 0 pin 30', + 8255: 'wait 0 pin 31', + 8272: 'wait 0 irq 0 rel', + 8264: 'wait 0 irq prev 0', + 8280: 'wait 0 irq next 0', + 8273: 'wait 0 irq 1 rel', + 8265: 'wait 0 irq prev 1', + 8281: 'wait 0 irq next 1', + 8274: 'wait 0 irq 2 rel', + 8266: 'wait 0 irq prev 2', + 8282: 'wait 0 irq next 2', + 8275: 'wait 0 irq 3 rel', + 8267: 'wait 0 irq prev 3', + 8283: 'wait 0 irq next 3', + 8276: 'wait 0 irq 4 rel', + 8268: 'wait 0 irq prev 4', + 8284: 'wait 0 irq next 4', + 8277: 'wait 0 irq 5 rel', + 8269: 'wait 0 irq prev 5', + 8285: 'wait 0 irq next 5', + 8278: 'wait 0 irq 6 rel', + 8270: 'wait 0 irq prev 6', + 8286: 'wait 0 irq next 6', + 8279: 'wait 0 irq 7 rel', + 8271: 'wait 0 irq prev 7', + 8287: 'wait 0 irq next 7', + 8289: 'wait 0 jmppin + 1', + 8290: 'wait 0 jmppin + 2', + 8291: 'wait 0 jmppin + 3', + 8416: 'wait 1 jmppin', + 8320: 'wait 1 gpio 0', + 8321: 'wait 1 gpio 1', + 8322: 'wait 1 gpio 2', + 8323: 'wait 1 gpio 3', + 8324: 'wait 1 gpio 4', + 8325: 'wait 1 gpio 5', + 8326: 'wait 1 gpio 6', + 8327: 'wait 1 gpio 7', + 8328: 'wait 1 gpio 8', + 8329: 'wait 1 gpio 9', + 8330: 'wait 1 gpio 10', + 8331: 'wait 1 gpio 11', + 8332: 'wait 1 gpio 12', + 8333: 'wait 1 gpio 13', + 8334: 'wait 1 gpio 14', + 8335: 'wait 1 gpio 15', + 8336: 'wait 1 gpio 16', + 8337: 'wait 1 gpio 17', + 8338: 'wait 1 gpio 18', + 8339: 'wait 1 gpio 19', + 8340: 'wait 1 gpio 20', + 8341: 'wait 1 gpio 21', + 8342: 'wait 1 gpio 22', + 8343: 'wait 1 gpio 23', + 8344: 'wait 1 gpio 24', + 8345: 'wait 1 gpio 25', + 8346: 'wait 1 gpio 26', + 8347: 'wait 1 gpio 27', + 8348: 'wait 1 gpio 28', + 8349: 'wait 1 gpio 29', + 8350: 'wait 1 gpio 30', + 8351: 'wait 1 gpio 31', + 8352: 'wait 1 pin 0', + 8353: 'wait 1 pin 1', + 8354: 'wait 1 pin 2', + 8355: 'wait 1 pin 3', + 8356: 'wait 1 pin 4', + 8357: 'wait 1 pin 5', + 8358: 'wait 1 pin 6', + 8359: 'wait 1 pin 7', + 8360: 'wait 1 pin 8', + 8361: 'wait 1 pin 9', + 8362: 'wait 1 pin 10', + 8363: 'wait 1 pin 11', + 8364: 'wait 1 pin 12', + 8365: 'wait 1 pin 13', + 8366: 'wait 1 pin 14', + 8367: 'wait 1 pin 15', + 8368: 'wait 1 pin 16', + 8369: 'wait 1 pin 17', + 8370: 'wait 1 pin 18', + 8371: 'wait 1 pin 19', + 8372: 'wait 1 pin 20', + 8373: 'wait 1 pin 21', + 8374: 'wait 1 pin 22', + 8375: 'wait 1 pin 23', + 8376: 'wait 1 pin 24', + 8377: 'wait 1 pin 25', + 8378: 'wait 1 pin 26', + 8379: 'wait 1 pin 27', + 8380: 'wait 1 pin 28', + 8381: 'wait 1 pin 29', + 8382: 'wait 1 pin 30', + 8383: 'wait 1 pin 31', + 8400: 'wait 1 irq 0 rel', + 8392: 'wait 1 irq prev 0', + 8408: 'wait 1 irq next 0', + 8401: 'wait 1 irq 1 rel', + 8393: 'wait 1 irq prev 1', + 8409: 'wait 1 irq next 1', + 8402: 'wait 1 irq 2 rel', + 8394: 'wait 1 irq prev 2', + 8410: 'wait 1 irq next 2', + 8403: 'wait 1 irq 3 rel', + 8395: 'wait 1 irq prev 3', + 8411: 'wait 1 irq next 3', + 8404: 'wait 1 irq 4 rel', + 8396: 'wait 1 irq prev 4', + 8412: 'wait 1 irq next 4', + 8405: 'wait 1 irq 5 rel', + 8397: 'wait 1 irq prev 5', + 8413: 'wait 1 irq next 5', + 8406: 'wait 1 irq 6 rel', + 8398: 'wait 1 irq prev 6', + 8414: 'wait 1 irq next 6', + 8407: 'wait 1 irq 7 rel', + 8399: 'wait 1 irq prev 7', + 8415: 'wait 1 irq next 7', + 8417: 'wait 1 jmppin + 1', + 8418: 'wait 1 jmppin + 2', + 8419: 'wait 1 jmppin + 3', + 16385: 'in pins 1', + 16386: 'in pins 2', + 16387: 'in pins 3', + 16388: 'in pins 4', + 16389: 'in pins 5', + 16390: 'in pins 6', + 16391: 'in pins 7', + 16392: 'in pins 8', + 16393: 'in pins 9', + 16394: 'in pins 10', + 16395: 'in pins 11', + 16396: 'in pins 12', + 16397: 'in pins 13', + 16398: 'in pins 14', + 16399: 'in pins 15', + 16400: 'in pins 16', + 16401: 'in pins 17', + 16402: 'in pins 18', + 16403: 'in pins 19', + 16404: 'in pins 20', + 16405: 'in pins 21', + 16406: 'in pins 22', + 16407: 'in pins 23', + 16408: 'in pins 24', + 16409: 'in pins 25', + 16410: 'in pins 26', + 16411: 'in pins 27', + 16412: 'in pins 28', + 16413: 'in pins 29', + 16414: 'in pins 30', + 16415: 'in pins 31', + 16384: 'in pins 32', + 16417: 'in x 1', + 16418: 'in x 2', + 16419: 'in x 3', + 16420: 'in x 4', + 16421: 'in x 5', + 16422: 'in x 6', + 16423: 'in x 7', + 16424: 'in x 8', + 16425: 'in x 9', + 16426: 'in x 10', + 16427: 'in x 11', + 16428: 'in x 12', + 16429: 'in x 13', + 16430: 'in x 14', + 16431: 'in x 15', + 16432: 'in x 16', + 16433: 'in x 17', + 16434: 'in x 18', + 16435: 'in x 19', + 16436: 'in x 20', + 16437: 'in x 21', + 16438: 'in x 22', + 16439: 'in x 23', + 16440: 'in x 24', + 16441: 'in x 25', + 16442: 'in x 26', + 16443: 'in x 27', + 16444: 'in x 28', + 16445: 'in x 29', + 16446: 'in x 30', + 16447: 'in x 31', + 16416: 'in x 32', + 16449: 'in y 1', + 16450: 'in y 2', + 16451: 'in y 3', + 16452: 'in y 4', + 16453: 'in y 5', + 16454: 'in y 6', + 16455: 'in y 7', + 16456: 'in y 8', + 16457: 'in y 9', + 16458: 'in y 10', + 16459: 'in y 11', + 16460: 'in y 12', + 16461: 'in y 13', + 16462: 'in y 14', + 16463: 'in y 15', + 16464: 'in y 16', + 16465: 'in y 17', + 16466: 'in y 18', + 16467: 'in y 19', + 16468: 'in y 20', + 16469: 'in y 21', + 16470: 'in y 22', + 16471: 'in y 23', + 16472: 'in y 24', + 16473: 'in y 25', + 16474: 'in y 26', + 16475: 'in y 27', + 16476: 'in y 28', + 16477: 'in y 29', + 16478: 'in y 30', + 16479: 'in y 31', + 16448: 'in y 32', + 16481: 'in null 1', + 16482: 'in null 2', + 16483: 'in null 3', + 16484: 'in null 4', + 16485: 'in null 5', + 16486: 'in null 6', + 16487: 'in null 7', + 16488: 'in null 8', + 16489: 'in null 9', + 16490: 'in null 10', + 16491: 'in null 11', + 16492: 'in null 12', + 16493: 'in null 13', + 16494: 'in null 14', + 16495: 'in null 15', + 16496: 'in null 16', + 16497: 'in null 17', + 16498: 'in null 18', + 16499: 'in null 19', + 16500: 'in null 20', + 16501: 'in null 21', + 16502: 'in null 22', + 16503: 'in null 23', + 16504: 'in null 24', + 16505: 'in null 25', + 16506: 'in null 26', + 16507: 'in null 27', + 16508: 'in null 28', + 16509: 'in null 29', + 16510: 'in null 30', + 16511: 'in null 31', + 16480: 'in null 32', + 16577: 'in isr 1', + 16578: 'in isr 2', + 16579: 'in isr 3', + 16580: 'in isr 4', + 16581: 'in isr 5', + 16582: 'in isr 6', + 16583: 'in isr 7', + 16584: 'in isr 8', + 16585: 'in isr 9', + 16586: 'in isr 10', + 16587: 'in isr 11', + 16588: 'in isr 12', + 16589: 'in isr 13', + 16590: 'in isr 14', + 16591: 'in isr 15', + 16592: 'in isr 16', + 16593: 'in isr 17', + 16594: 'in isr 18', + 16595: 'in isr 19', + 16596: 'in isr 20', + 16597: 'in isr 21', + 16598: 'in isr 22', + 16599: 'in isr 23', + 16600: 'in isr 24', + 16601: 'in isr 25', + 16602: 'in isr 26', + 16603: 'in isr 27', + 16604: 'in isr 28', + 16605: 'in isr 29', + 16606: 'in isr 30', + 16607: 'in isr 31', + 16576: 'in isr 32', + 16609: 'in osr 1', + 16610: 'in osr 2', + 16611: 'in osr 3', + 16612: 'in osr 4', + 16613: 'in osr 5', + 16614: 'in osr 6', + 16615: 'in osr 7', + 16616: 'in osr 8', + 16617: 'in osr 9', + 16618: 'in osr 10', + 16619: 'in osr 11', + 16620: 'in osr 12', + 16621: 'in osr 13', + 16622: 'in osr 14', + 16623: 'in osr 15', + 16624: 'in osr 16', + 16625: 'in osr 17', + 16626: 'in osr 18', + 16627: 'in osr 19', + 16628: 'in osr 20', + 16629: 'in osr 21', + 16630: 'in osr 22', + 16631: 'in osr 23', + 16632: 'in osr 24', + 16633: 'in osr 25', + 16634: 'in osr 26', + 16635: 'in osr 27', + 16636: 'in osr 28', + 16637: 'in osr 29', + 16638: 'in osr 30', + 16639: 'in osr 31', + 16608: 'in osr 32', + 24577: 'out pins 1', + 24578: 'out pins 2', + 24579: 'out pins 3', + 24580: 'out pins 4', + 24581: 'out pins 5', + 24582: 'out pins 6', + 24583: 'out pins 7', + 24584: 'out pins 8', + 24585: 'out pins 9', + 24586: 'out pins 10', + 24587: 'out pins 11', + 24588: 'out pins 12', + 24589: 'out pins 13', + 24590: 'out pins 14', + 24591: 'out pins 15', + 24592: 'out pins 16', + 24593: 'out pins 17', + 24594: 'out pins 18', + 24595: 'out pins 19', + 24596: 'out pins 20', + 24597: 'out pins 21', + 24598: 'out pins 22', + 24599: 'out pins 23', + 24600: 'out pins 24', + 24601: 'out pins 25', + 24602: 'out pins 26', + 24603: 'out pins 27', + 24604: 'out pins 28', + 24605: 'out pins 29', + 24606: 'out pins 30', + 24607: 'out pins 31', + 24576: 'out pins 32', + 24609: 'out x 1', + 24610: 'out x 2', + 24611: 'out x 3', + 24612: 'out x 4', + 24613: 'out x 5', + 24614: 'out x 6', + 24615: 'out x 7', + 24616: 'out x 8', + 24617: 'out x 9', + 24618: 'out x 10', + 24619: 'out x 11', + 24620: 'out x 12', + 24621: 'out x 13', + 24622: 'out x 14', + 24623: 'out x 15', + 24624: 'out x 16', + 24625: 'out x 17', + 24626: 'out x 18', + 24627: 'out x 19', + 24628: 'out x 20', + 24629: 'out x 21', + 24630: 'out x 22', + 24631: 'out x 23', + 24632: 'out x 24', + 24633: 'out x 25', + 24634: 'out x 26', + 24635: 'out x 27', + 24636: 'out x 28', + 24637: 'out x 29', + 24638: 'out x 30', + 24639: 'out x 31', + 24608: 'out x 32', + 24641: 'out y 1', + 24642: 'out y 2', + 24643: 'out y 3', + 24644: 'out y 4', + 24645: 'out y 5', + 24646: 'out y 6', + 24647: 'out y 7', + 24648: 'out y 8', + 24649: 'out y 9', + 24650: 'out y 10', + 24651: 'out y 11', + 24652: 'out y 12', + 24653: 'out y 13', + 24654: 'out y 14', + 24655: 'out y 15', + 24656: 'out y 16', + 24657: 'out y 17', + 24658: 'out y 18', + 24659: 'out y 19', + 24660: 'out y 20', + 24661: 'out y 21', + 24662: 'out y 22', + 24663: 'out y 23', + 24664: 'out y 24', + 24665: 'out y 25', + 24666: 'out y 26', + 24667: 'out y 27', + 24668: 'out y 28', + 24669: 'out y 29', + 24670: 'out y 30', + 24671: 'out y 31', + 24640: 'out y 32', + 24673: 'out null 1', + 24674: 'out null 2', + 24675: 'out null 3', + 24676: 'out null 4', + 24677: 'out null 5', + 24678: 'out null 6', + 24679: 'out null 7', + 24680: 'out null 8', + 24681: 'out null 9', + 24682: 'out null 10', + 24683: 'out null 11', + 24684: 'out null 12', + 24685: 'out null 13', + 24686: 'out null 14', + 24687: 'out null 15', + 24688: 'out null 16', + 24689: 'out null 17', + 24690: 'out null 18', + 24691: 'out null 19', + 24692: 'out null 20', + 24693: 'out null 21', + 24694: 'out null 22', + 24695: 'out null 23', + 24696: 'out null 24', + 24697: 'out null 25', + 24698: 'out null 26', + 24699: 'out null 27', + 24700: 'out null 28', + 24701: 'out null 29', + 24702: 'out null 30', + 24703: 'out null 31', + 24672: 'out null 32', + 24705: 'out pindirs 1', + 24706: 'out pindirs 2', + 24707: 'out pindirs 3', + 24708: 'out pindirs 4', + 24709: 'out pindirs 5', + 24710: 'out pindirs 6', + 24711: 'out pindirs 7', + 24712: 'out pindirs 8', + 24713: 'out pindirs 9', + 24714: 'out pindirs 10', + 24715: 'out pindirs 11', + 24716: 'out pindirs 12', + 24717: 'out pindirs 13', + 24718: 'out pindirs 14', + 24719: 'out pindirs 15', + 24720: 'out pindirs 16', + 24721: 'out pindirs 17', + 24722: 'out pindirs 18', + 24723: 'out pindirs 19', + 24724: 'out pindirs 20', + 24725: 'out pindirs 21', + 24726: 'out pindirs 22', + 24727: 'out pindirs 23', + 24728: 'out pindirs 24', + 24729: 'out pindirs 25', + 24730: 'out pindirs 26', + 24731: 'out pindirs 27', + 24732: 'out pindirs 28', + 24733: 'out pindirs 29', + 24734: 'out pindirs 30', + 24735: 'out pindirs 31', + 24704: 'out pindirs 32', + 24737: 'out pc 1', + 24738: 'out pc 2', + 24739: 'out pc 3', + 24740: 'out pc 4', + 24741: 'out pc 5', + 24742: 'out pc 6', + 24743: 'out pc 7', + 24744: 'out pc 8', + 24745: 'out pc 9', + 24746: 'out pc 10', + 24747: 'out pc 11', + 24748: 'out pc 12', + 24749: 'out pc 13', + 24750: 'out pc 14', + 24751: 'out pc 15', + 24752: 'out pc 16', + 24753: 'out pc 17', + 24754: 'out pc 18', + 24755: 'out pc 19', + 24756: 'out pc 20', + 24757: 'out pc 21', + 24758: 'out pc 22', + 24759: 'out pc 23', + 24760: 'out pc 24', + 24761: 'out pc 25', + 24762: 'out pc 26', + 24763: 'out pc 27', + 24764: 'out pc 28', + 24765: 'out pc 29', + 24766: 'out pc 30', + 24767: 'out pc 31', + 24736: 'out pc 32', + 24769: 'out isr 1', + 24770: 'out isr 2', + 24771: 'out isr 3', + 24772: 'out isr 4', + 24773: 'out isr 5', + 24774: 'out isr 6', + 24775: 'out isr 7', + 24776: 'out isr 8', + 24777: 'out isr 9', + 24778: 'out isr 10', + 24779: 'out isr 11', + 24780: 'out isr 12', + 24781: 'out isr 13', + 24782: 'out isr 14', + 24783: 'out isr 15', + 24784: 'out isr 16', + 24785: 'out isr 17', + 24786: 'out isr 18', + 24787: 'out isr 19', + 24788: 'out isr 20', + 24789: 'out isr 21', + 24790: 'out isr 22', + 24791: 'out isr 23', + 24792: 'out isr 24', + 24793: 'out isr 25', + 24794: 'out isr 26', + 24795: 'out isr 27', + 24796: 'out isr 28', + 24797: 'out isr 29', + 24798: 'out isr 30', + 24799: 'out isr 31', + 24768: 'out isr 32', + 24801: 'out exec 1', + 24802: 'out exec 2', + 24803: 'out exec 3', + 24804: 'out exec 4', + 24805: 'out exec 5', + 24806: 'out exec 6', + 24807: 'out exec 7', + 24808: 'out exec 8', + 24809: 'out exec 9', + 24810: 'out exec 10', + 24811: 'out exec 11', + 24812: 'out exec 12', + 24813: 'out exec 13', + 24814: 'out exec 14', + 24815: 'out exec 15', + 24816: 'out exec 16', + 24817: 'out exec 17', + 24818: 'out exec 18', + 24819: 'out exec 19', + 24820: 'out exec 20', + 24821: 'out exec 21', + 24822: 'out exec 22', + 24823: 'out exec 23', + 24824: 'out exec 24', + 24825: 'out exec 25', + 24826: 'out exec 26', + 24827: 'out exec 27', + 24828: 'out exec 28', + 24829: 'out exec 29', + 24830: 'out exec 30', + 24831: 'out exec 31', + 24800: 'out exec 32', + 32800: ('push', {'fifo': 'txrx'}), + 32864: ('push iffull block', {'fifo': 'txrx'}), + 32832: ('push iffull noblock', {'fifo': 'txrx'}), + 32928: ('pull', {'fifo': 'txrx'}), + 32992: ('pull ifempty block', {'fifo': 'txrx'}), + 32960: ('pull ifempty noblock', {'fifo': 'txrx'}), + 40960: 'mov pins pins', + 40968: 'mov pins ~pins', + 40976: 'mov pins ::pins', + 40961: 'mov pins x', + 40969: 'mov pins ~x', + 40977: 'mov pins ::x', + 40962: 'mov pins y', + 40970: 'mov pins ~y', + 40978: 'mov pins ::y', + 40963: 'mov pins null', + 40971: 'mov pins ~null', + 40979: 'mov pins ::null', + 40965: 'mov pins status', + 40973: 'mov pins ~status', + 40981: 'mov pins ::status', + 40966: 'mov pins isr', + 40974: 'mov pins ~isr', + 40982: 'mov pins ::isr', + 40967: 'mov pins osr', + 40975: 'mov pins ~osr', + 40983: 'mov pins ::osr', + 40992: 'mov x pins', + 41000: 'mov x ~pins', + 41008: 'mov x ::pins', + 40993: 'mov x x', + 41001: 'mov x ~x', + 41009: 'mov x ::x', + 40994: 'mov x y', + 41002: 'mov x ~y', + 41010: 'mov x ::y', + 40995: 'mov x null', + 41003: 'mov x ~null', + 41011: 'mov x ::null', + 40997: 'mov x status', + 41005: 'mov x ~status', + 41013: 'mov x ::status', + 40998: 'mov x isr', + 41006: 'mov x ~isr', + 41014: 'mov x ::isr', + 40999: 'mov x osr', + 41007: 'mov x ~osr', + 41015: 'mov x ::osr', + 41024: 'mov y pins', + 41032: 'mov y ~pins', + 41040: 'mov y ::pins', + 41025: 'mov y x', + 41033: 'mov y ~x', + 41041: 'mov y ::x', + 41026: 'mov y y', + 41034: 'mov y ~y', + 41042: 'mov y ::y', + 41027: 'mov y null', + 41035: 'mov y ~null', + 41043: 'mov y ::null', + 41029: 'mov y status', + 41037: 'mov y ~status', + 41045: 'mov y ::status', + 41030: 'mov y isr', + 41038: 'mov y ~isr', + 41046: 'mov y ::isr', + 41031: 'mov y osr', + 41039: 'mov y ~osr', + 41047: 'mov y ::osr', + 41056: 'mov pindirs pins', + 41064: 'mov pindirs ~pins', + 41072: 'mov pindirs ::pins', + 41057: 'mov pindirs x', + 41065: 'mov pindirs ~x', + 41073: 'mov pindirs ::x', + 41058: 'mov pindirs y', + 41066: 'mov pindirs ~y', + 41074: 'mov pindirs ::y', + 41059: 'mov pindirs null', + 41067: 'mov pindirs ~null', + 41075: 'mov pindirs ::null', + 41061: 'mov pindirs status', + 41069: 'mov pindirs ~status', + 41077: 'mov pindirs ::status', + 41062: 'mov pindirs isr', + 41070: 'mov pindirs ~isr', + 41078: 'mov pindirs ::isr', + 41063: 'mov pindirs osr', + 41071: 'mov pindirs ~osr', + 41079: 'mov pindirs ::osr', + 41088: 'mov exec pins', + 41096: 'mov exec ~pins', + 41104: 'mov exec ::pins', + 41089: 'mov exec x', + 41097: 'mov exec ~x', + 41105: 'mov exec ::x', + 41090: 'mov exec y', + 41098: 'mov exec ~y', + 41106: 'mov exec ::y', + 41091: 'mov exec null', + 41099: 'mov exec ~null', + 41107: 'mov exec ::null', + 41093: 'mov exec status', + 41101: 'mov exec ~status', + 41109: 'mov exec ::status', + 41094: 'mov exec isr', + 41102: 'mov exec ~isr', + 41110: 'mov exec ::isr', + 41095: 'mov exec osr', + 41103: 'mov exec ~osr', + 41111: 'mov exec ::osr', + 41120: 'mov pc pins', + 41128: 'mov pc ~pins', + 41136: 'mov pc ::pins', + 41121: 'mov pc x', + 41129: 'mov pc ~x', + 41137: 'mov pc ::x', + 41122: 'mov pc y', + 41130: 'mov pc ~y', + 41138: 'mov pc ::y', + 41123: 'mov pc null', + 41131: 'mov pc ~null', + 41139: 'mov pc ::null', + 41125: 'mov pc status', + 41133: 'mov pc ~status', + 41141: 'mov pc ::status', + 41126: 'mov pc isr', + 41134: 'mov pc ~isr', + 41142: 'mov pc ::isr', + 41127: 'mov pc osr', + 41135: 'mov pc ~osr', + 41143: 'mov pc ::osr', + 41152: 'mov isr pins', + 41160: 'mov isr ~pins', + 41168: 'mov isr ::pins', + 41153: 'mov isr x', + 41161: 'mov isr ~x', + 41169: 'mov isr ::x', + 41154: 'mov isr y', + 41162: 'mov isr ~y', + 41170: 'mov isr ::y', + 41155: 'mov isr null', + 41163: 'mov isr ~null', + 41171: 'mov isr ::null', + 41157: 'mov isr status', + 41165: 'mov isr ~status', + 41173: 'mov isr ::status', + 41158: 'mov isr isr', + 41166: 'mov isr ~isr', + 41174: 'mov isr ::isr', + 41159: 'mov isr osr', + 41167: 'mov isr ~osr', + 41175: 'mov isr ::osr', + 41184: 'mov osr pins', + 41192: 'mov osr ~pins', + 41200: 'mov osr ::pins', + 41185: 'mov osr x', + 41193: 'mov osr ~x', + 41201: 'mov osr ::x', + 41186: 'mov osr y', + 41194: 'mov osr ~y', + 41202: 'mov osr ::y', + 41187: 'mov osr null', + 41195: 'mov osr ~null', + 41203: 'mov osr ::null', + 41189: 'mov osr status', + 41197: 'mov osr ~status', + 41205: 'mov osr ::status', + 41190: 'mov osr isr', + 41198: 'mov osr ~isr', + 41206: 'mov osr ::isr', + 41191: 'mov osr osr', + 41199: 'mov osr ~osr', + 41207: 'mov osr ::osr', + 32792: 'mov rxfifo[0], isr', + 32920: 'mov osr, rxfifo[0]', + 32793: 'mov rxfifo[1], isr', + 32921: 'mov osr, rxfifo[1]', + 32794: 'mov rxfifo[2], isr', + 32922: 'mov osr, rxfifo[2]', + 32795: 'mov rxfifo[3], isr', + 32923: 'mov osr, rxfifo[3]', + 32784: 'mov rxfifo[y], isr', + 32912: 'mov osr, rxfifo[y]', + 49152: 'irq 0', + 49168: 'irq 0 rel', + 49160: 'irq prev 0', + 49176: 'irq next 0', + 49153: 'irq 1', + 49169: 'irq 1 rel', + 49161: 'irq prev 1', + 49177: 'irq next 1', + 49154: 'irq 2', + 49170: 'irq 2 rel', + 49162: 'irq prev 2', + 49178: 'irq next 2', + 49155: 'irq 3', + 49171: 'irq 3 rel', + 49163: 'irq prev 3', + 49179: 'irq next 3', + 49156: 'irq 4', + 49172: 'irq 4 rel', + 49164: 'irq prev 4', + 49180: 'irq next 4', + 49157: 'irq 5', + 49173: 'irq 5 rel', + 49165: 'irq prev 5', + 49181: 'irq next 5', + 49158: 'irq 6', + 49174: 'irq 6 rel', + 49166: 'irq prev 6', + 49182: 'irq next 6', + 49159: 'irq 7', + 49175: 'irq 7 rel', + 49167: 'irq prev 7', + 49183: 'irq next 7', + 57344: 'set pins 0', + 57345: 'set pins 1', + 57346: 'set pins 2', + 57347: 'set pins 3', + 57348: 'set pins 4', + 57349: 'set pins 5', + 57350: 'set pins 6', + 57351: 'set pins 7', + 57352: 'set pins 8', + 57353: 'set pins 9', + 57354: 'set pins 10', + 57355: 'set pins 11', + 57356: 'set pins 12', + 57357: 'set pins 13', + 57358: 'set pins 14', + 57359: 'set pins 15', + 57360: 'set pins 16', + 57361: 'set pins 17', + 57362: 'set pins 18', + 57363: 'set pins 19', + 57364: 'set pins 20', + 57365: 'set pins 21', + 57366: 'set pins 22', + 57367: 'set pins 23', + 57368: 'set pins 24', + 57369: 'set pins 25', + 57370: 'set pins 26', + 57371: 'set pins 27', + 57372: 'set pins 28', + 57373: 'set pins 29', + 57374: 'set pins 30', + 57375: 'set pins 31', + 57376: 'set x 0', + 57377: 'set x 1', + 57378: 'set x 2', + 57379: 'set x 3', + 57380: 'set x 4', + 57381: 'set x 5', + 57382: 'set x 6', + 57383: 'set x 7', + 57384: 'set x 8', + 57385: 'set x 9', + 57386: 'set x 10', + 57387: 'set x 11', + 57388: 'set x 12', + 57389: 'set x 13', + 57390: 'set x 14', + 57391: 'set x 15', + 57392: 'set x 16', + 57393: 'set x 17', + 57394: 'set x 18', + 57395: 'set x 19', + 57396: 'set x 20', + 57397: 'set x 21', + 57398: 'set x 22', + 57399: 'set x 23', + 57400: 'set x 24', + 57401: 'set x 25', + 57402: 'set x 26', + 57403: 'set x 27', + 57404: 'set x 28', + 57405: 'set x 29', + 57406: 'set x 30', + 57407: 'set x 31', + 57408: 'set y 0', + 57409: 'set y 1', + 57410: 'set y 2', + 57411: 'set y 3', + 57412: 'set y 4', + 57413: 'set y 5', + 57414: 'set y 6', + 57415: 'set y 7', + 57416: 'set y 8', + 57417: 'set y 9', + 57418: 'set y 10', + 57419: 'set y 11', + 57420: 'set y 12', + 57421: 'set y 13', + 57422: 'set y 14', + 57423: 'set y 15', + 57424: 'set y 16', + 57425: 'set y 17', + 57426: 'set y 18', + 57427: 'set y 19', + 57428: 'set y 20', + 57429: 'set y 21', + 57430: 'set y 22', + 57431: 'set y 23', + 57432: 'set y 24', + 57433: 'set y 25', + 57434: 'set y 26', + 57435: 'set y 27', + 57436: 'set y 28', + 57437: 'set y 29', + 57438: 'set y 30', + 57439: 'set y 31', + 57472: 'set pindirs 0', + 57473: 'set pindirs 1', + 57474: 'set pindirs 2', + 57475: 'set pindirs 3', + 57476: 'set pindirs 4', + 57477: 'set pindirs 5', + 57478: 'set pindirs 6', + 57479: 'set pindirs 7', + 57480: 'set pindirs 8', + 57481: 'set pindirs 9', + 57482: 'set pindirs 10', + 57483: 'set pindirs 11', + 57484: 'set pindirs 12', + 57485: 'set pindirs 13', + 57486: 'set pindirs 14', + 57487: 'set pindirs 15', + 57488: 'set pindirs 16', + 57489: 'set pindirs 17', + 57490: 'set pindirs 18', + 57491: 'set pindirs 19', + 57492: 'set pindirs 20', + 57493: 'set pindirs 21', + 57494: 'set pindirs 22', + 57495: 'set pindirs 23', + 57496: 'set pindirs 24', + 57497: 'set pindirs 25', + 57498: 'set pindirs 26', + 57499: 'set pindirs 27', + 57500: 'set pindirs 28', + 57501: 'set pindirs 29', + 57502: 'set pindirs 30', + 57503: 'set pindirs 31', +} diff --git a/tests/pytest_helpers.py b/tests/pytest_helpers.py index 72ac7cf..8425a5b 100644 --- a/tests/pytest_helpers.py +++ b/tests/pytest_helpers.py @@ -45,4 +45,6 @@ def assert_assembly_fails( def assert_pio_kwargs(source: str, **kw: Any) -> None: program = adafruit_pioasm.Program(source) - assert kw == program.pio_kwargs + assert ( + kw == program.pio_kwargs + ), f"Assembling {source!r}: Expected {kw}, got {program.pio_kwargs}" diff --git a/tests/test_all.py b/tests/test_all.py new file mode 100644 index 0000000..5d0d094 --- /dev/null +++ b/tests/test_all.py @@ -0,0 +1,31 @@ +# SPDX-FileCopyrightText: 2024 Jeff Epler, written for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import pytest +from pytest_helpers import assert_assembles_to + +import all_pio_instructions + + +def _assert_one(expected, instruction_in, fifo="putget"): + program = f""" + .program all_pio + .pio_version 1 + .fifo {fifo} + {instruction_in} + """ + assert_assembles_to(program, [expected]) + + +def assert_one(expected, instruction_in): + if isinstance(instruction_in, str): + return _assert_one(expected, instruction_in) + return _assert_one(expected, instruction_in[0], **instruction_in[1]) + + +@pytest.mark.parametrize("arg", all_pio_instructions.all_instruction.items()) +def test_all(arg): + expected = arg[0] + instruction = arg[1] + assert_one(expected, instruction) diff --git a/tests/test_pseudo.py b/tests/test_pseudo.py index 66d93c2..1bf89f8 100644 --- a/tests/test_pseudo.py +++ b/tests/test_pseudo.py @@ -6,8 +6,9 @@ Tests pseudo-ops """ -from pytest_helpers import assert_pio_kwargs +from pytest_helpers import assert_pio_kwargs, assert_assembly_fails def test_offset() -> None: assert_pio_kwargs(".origin 7", offset=7, sideset_enable=False) + assert_assembly_fails("nop\n.origin 7") diff --git a/tests/test_version.py b/tests/test_version.py new file mode 100644 index 0000000..d2aa57f --- /dev/null +++ b/tests/test_version.py @@ -0,0 +1,146 @@ +# SPDX-FileCopyrightText: 2024 Jeff Epler, written for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +Tests version dependent instructions +""" + +from pytest_helpers import assert_pio_kwargs, assert_assembly_fails, assert_assembles_to + + +def test_version() -> None: + assert_pio_kwargs(".pio_version 0", sideset_enable=0) + assert_pio_kwargs(".pio_version 1", pio_version=1, sideset_enable=0) + assert_assembly_fails(".pio_version muffin", errtype=ValueError) + assert_assembly_fails(".pio_version -1") + + +def test_fifo() -> None: + assert_pio_kwargs(".fifo txrx", sideset_enable=0, fifo_type="txrx") + assert_pio_kwargs(".fifo auto", sideset_enable=0) + assert_assembly_fails(".fifo txput") + assert_pio_kwargs( + ".pio_version 1\n.fifo txput", + pio_version=1, + sideset_enable=0, + fifo_type="txput", + ) + + +def test_mov_status() -> None: + assert_pio_kwargs( + ".mov_status txfifo < 5", + sideset_enable=0, + mov_status_type="txfifo", + mov_status_n=5, + ) + assert_pio_kwargs( + ".mov_status rxfifo < 8", + sideset_enable=0, + mov_status_type="rxfifo", + mov_status_n=8, + ) + assert_assembly_fails(".mov_status rxfifo < -1") + assert_assembly_fails(".mov_status rxfifo < 33") + assert_assembly_fails(".mov_status irq next set 3") + assert_pio_kwargs( + ".pio_version 1\n.mov_status irq prev set 3", + pio_version=1, + sideset_enable=0, + mov_status_type="irq", + mov_status_n=3 | 0x8, + ) + assert_pio_kwargs( + ".pio_version 1\n.mov_status irq next set 3", + pio_version=1, + sideset_enable=0, + mov_status_type="irq", + mov_status_n=3 | 0x10, + ) + assert_pio_kwargs( + ".pio_version 1\n.mov_status irq set 3", + pio_version=1, + sideset_enable=0, + mov_status_type="irq", + mov_status_n=3, + ) + assert_assembly_fails(".pio_version 1\n.mov_status irq prev set 9") + + +def test_dot_in() -> None: + assert_pio_kwargs( + ".in 32 left auto 11", + sideset_enable=0, + auto_push=True, + push_threshold=11, + in_shift_right=False, + ) + assert_assembly_fails(".in 16") + assert_pio_kwargs( + ".pio_version 1\n.in 16 right", + pio_version=1, + sideset_enable=0, + in_pin_count=16, + auto_push=False, + in_shift_right=True, + ) + + +def test_dot_out() -> None: + assert_pio_kwargs( + ".out 32 left auto 11", + sideset_enable=0, + auto_pull=True, + pull_threshold=11, + out_shift_right=False, + ) + assert_pio_kwargs( + ".out 16 right", + sideset_enable=0, + out_pin_count=16, + auto_pull=False, + out_shift_right=True, + ) + + +def test_dot_set() -> None: + assert_pio_kwargs(".set 5", sideset_enable=0, set_pin_count=5) + assert_assembly_fails(".set 16") + assert_assembly_fails(".pio_version 1\n.set 16") + assert_assembly_fails(".set 3") + assert_pio_kwargs( + ".pio_version 1\n.set 3 right", pio_version=1, sideset_enable=0, set_pin_count=3 + ) + + +def test_irq_v1() -> None: + assert_assembly_fails("irq next 7") + assert_assembly_fails(".pio_version 1\nirq next 7 rel") + assert_assembles_to(".pio_version 1\nirq next 5", [0b110_00000_0_0_0_11_101]) + assert_assembles_to(".pio_version 1\nirq wait prev 1", [0b110_00000_0_0_1_01_001]) + + +def test_mov_v1() -> None: + assert_assembly_fails("mov osr, rxfifo[y]") + assert_assembly_fails(".pio_version 1\nmov osr, rxfifo[y]") + prefix = ".pio_version 1\n.fifo putget\n" + assert_assembly_fails(prefix + "mov osr, rxfifo[8]") + assert_assembles_to(prefix + "mov rxfifo[y], isr", [0b100_00000_0001_0_000]) + assert_assembles_to(prefix + "mov osr, rxfifo[1]", [0b100_00000_1001_1_001]) + + assert_assembly_fails("mov pindirs, null", errtype=ValueError) + assert_assembles_to(prefix + "mov pindirs, null", [0b101_00000_01100011]) + + +def test_wait_v1() -> None: + assert_assembly_fails("wait 0 jmppin") + assert_assembly_fails("wait 0 irq next 5") + prefix = ".pio_version 1\n" + assert_assembly_fails(prefix + "wait 0 jmppin +") + assert_assembly_fails(prefix + "wait 0 jmppin + 7") + assert_assembles_to(prefix + "wait 0 jmppin + 3", [0b001_00000_0_11_00011]) + assert_assembles_to(prefix + "wait 1 jmppin", [0b001_00000_1_11_00000]) + + assert_assembles_to(prefix + "wait 0 irq next 5", [0b001_00000_0_10_11_101]) + assert_assembles_to(prefix + "wait 1 irq prev 4", [0b001_00000_1_10_01_100]) diff --git a/tools/make_all.py b/tools/make_all.py new file mode 100644 index 0000000..e71cb97 --- /dev/null +++ b/tools/make_all.py @@ -0,0 +1,135 @@ +# SPDX-FileCopyrightText: 2024 Jeff Epler, written for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +Generate test cases for adafruit_pioasm, with expected results from sdk pioasm +""" + +# pylint: disable=missing-function-docstring + +import re +from subprocess import check_output + +PIOASM = ( + "/home/jepler/src/circuitpython/ports/raspberrypi/sdk/tools/pioasm/build/pioasm" +) + + +def assemble_one_instruction(instruction_in): + if isinstance(instruction_in, str): + return _assemble_one_instruction(instruction_in) + return _assemble_one_instruction(instruction_in[0], **instruction_in[1]) + + +def _assemble_one_instruction(instruction_in, fifo="putget"): + nops = "\n".join("nop" for _ in range(31)) + program = f""" + .program all_pio + .pio_version 1 + .fifo {fifo} + {instruction_in} + {nops} + """ + output = check_output( + [PIOASM, "/dev/stdin", "/dev/stdout"], input=program, encoding="utf-8" + ) + return int(re.search("0x[0-9a-f]{4}", output).group(0), 16) + + +def all_jmp(): + for i in range(32): + yield f"jmp {i}" + for cond in "!x", "x--", "!y", "y--", "x!=y", "pin", "!osre": + yield f"jmp {cond} {i}" + + +def all_wait(): + for polarity in range(2): + yield f"wait {polarity} jmppin" + for source in "gpio", "pin": + for i in range(32): + yield f"wait {polarity} {source} {i}" + for i in range(8): + yield f"wait {polarity} irq {i} rel" + for what in "prev", "next": + yield f"wait {polarity} irq {what} {i}" + for i in range(1, 4): + yield f"wait {polarity} jmppin + {i}" + + +def all_in(): + for source in "pins", "x", "y", "null", "isr", "osr": + for bit_count in range(1, 33): + yield f"in {source} {bit_count}" + + +def all_out(): + for dest in "pins", "x", "y", "null", "pindirs", "pc", "isr", "exec": + for bit_count in range(1, 33): + yield f"out {dest} {bit_count}" + + +def all_push(): + yield "push", {"fifo": "txrx"} + yield "push iffull block", {"fifo": "txrx"} + yield "push iffull noblock", {"fifo": "txrx"} + + +def all_pull(): + yield "pull", {"fifo": "txrx"} + yield "pull ifempty block", {"fifo": "txrx"} + yield "pull ifempty noblock", {"fifo": "txrx"} + + +def all_mov(): + for dest in ("pins", "x", "y", "pindirs", "exec", "pc", "isr", "osr"): + for source in ("pins", "x", "y", "null", "status", "isr", "osr"): + for operator in "", "~", "::": + yield f"mov {dest} {operator}{source}" + for where in 0, 1, 2, 3, "y": + yield f"mov rxfifo[{where}], isr" + yield f"mov osr, rxfifo[{where}]" + + +def all_irq(): + for i in range(8): + yield f"irq {i}" + yield f"irq {i} rel" + for what in "prev", "next": + yield f"irq {what} {i}" + + +def all_set(): + for dest in ("pins", "x", "y", "pindirs"): + for i in range(32): + yield f"set {dest} {i}" + + +def all_instructions(): + yield from all_jmp() + yield from all_wait() + yield from all_in() + yield from all_out() + yield from all_push() + yield from all_pull() + yield from all_mov() + yield from all_irq() + yield from all_set() + + +if __name__ == "__main__": + print( + """\ +# SPDX-FileCopyrightText: 2024 Jeff Epler, written for Adafruit Industries +# +# SPDX-License-Identifier: MIT +# pylint: disable=too-many-lines +# fmt: off +""" + ) + print("all_instruction = {") + for instr in all_instructions(): + assembled = assemble_one_instruction(instr) + print(f" {assembled}: {instr!r},") + print("}")