This commit is contained in:
Jeff Epler 2024-09-18 16:52:34 -05:00 committed by GitHub
commit cd0f6ece6c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 1940 additions and 46 deletions

View file

@ -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
=============

View file

@ -29,10 +29,20 @@ CONDITIONS = ["", "!x", "x--", "!y", "y--", "x!=y", "pin", "!osre"]
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 @@ class Program: # pylint: disable=too-few-public-methods
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 @@ class Program: # pylint: disable=too-few-public-methods
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 @@ class Program: # pylint: disable=too-few-public-methods
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 @@ class Program: # pylint: disable=too-few-public-methods
# 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")
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":
assembled[-1] |= 0x10 # Set the high bit of the irq value
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,8 +362,19 @@ class Program: # pylint: disable=too-few-public-methods
assembled[-1] |= 0x40
elif instruction[0] == "mov":
# instr delay dst op src
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.append(0b101_00000_000_00_000)
assembled[-1] |= MOV_DESTINATIONS.index(instruction[1]) << 5
assembled[-1] |= mov_destinations.index(instruction[1]) << 5
source = instruction[-1]
source_split = mov_splitter(source)
if len(source_split) == 1:
@ -207,21 +395,39 @@ class Program: # pylint: disable=too-few-public-methods
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)
if instruction[-1] == "rel":
assembled[-1] |= 0x10 # Set the high bit of the irq value
instruction.pop()
num = int(instruction[-1], 0)
if not 0 <= num <= 7:
raise RuntimeError("Interrupt index out of range")
assembled[-1] |= num
if len(instruction) == 3: # after rel has been removed
if instruction[1] == "wait":
irq_type = 0
idx = 1
if instruction[idx] == "wait":
assembled[-1] |= 0x20
elif instruction[1] == "clear":
idx += 1
elif instruction[idx] == "clear":
assembled[-1] |= 0x40
# All other values are the default of set without waiting
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":
if irq_type != 0:
raise RuntimeError("cannot use next/prev with rel")
irq_type = 2
instruction.pop()
assembled[-1] |= irq_type << 3
num = int_in_range(instruction[idx], 0, 8, "irq index")
assembled[-1] |= num
instruction.pop()
elif instruction[0] == "set":
# instr delay dst data
assembled.append(0b111_00000_000_00000)
@ -247,6 +453,9 @@ class Program: # pylint: disable=too-few-public-methods
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 @@ class Program: # pylint: disable=too-few-public-methods
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:

View file

@ -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)

File diff suppressed because it is too large Load diff

View file

@ -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}"

31
tests/test_all.py Normal file
View file

@ -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)

View file

@ -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")

146
tests/test_version.py Normal file
View file

@ -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])

135
tools/make_all.py Normal file
View file

@ -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("}")