diff --git a/.gitignore b/.gitignore
index 2c6ddfd..6559e83 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,3 +16,4 @@ bundles
dist
**/*.egg-info
.vscode
+.venv
diff --git a/README.rst b/README.rst
index 9b83f08..96dcbc8 100644
--- a/README.rst
+++ b/README.rst
@@ -32,8 +32,6 @@ This is easily achieved by downloading
Installing from PyPI
=====================
-.. note:: This library is not available on PyPI yet. Install documentation is included
- as a standard element. Stay tuned for PyPI availability!
On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally `from
PyPI `_. To install for current user:
diff --git a/adafruit_pioasm.py b/adafruit_pioasm.py
index 266d962..263e986 100644
--- a/adafruit_pioasm.py
+++ b/adafruit_pioasm.py
@@ -115,7 +115,12 @@ class Program: # pylint: disable=too-few-public-methods
raise SyntaxError(f"Invalid jmp target {repr(target)}")
if len(instruction) > 2:
- assembled[-1] |= CONDITIONS.index(instruction[1]) << 5
+ try:
+ assembled[-1] |= CONDITIONS.index(instruction[1]) << 5
+ except ValueError as exc:
+ raise ValueError(
+ f"Invalid jmp condition '{instruction[1]}'"
+ ) from exc
elif instruction[0] == "wait":
# instr delay p sr index
@@ -163,7 +168,10 @@ class Program: # pylint: disable=too-few-public-methods
source = instruction[-1]
source_split = mov_splitter(source)
if len(source_split) == 1:
- assembled[-1] |= MOV_SOURCES.index(source)
+ try:
+ assembled[-1] |= MOV_SOURCES.index(source)
+ except ValueError as exc:
+ raise ValueError(f"Invalid mov source '{source}'") from exc
else:
assembled[-1] |= MOV_SOURCES.index(source_split[1])
if source[:1] == "!":
@@ -195,7 +203,10 @@ class Program: # pylint: disable=too-few-public-methods
elif instruction[0] == "set":
# instr delay dst data
assembled.append(0b111_00000_000_00000)
- assembled[-1] |= SET_DESTINATIONS.index(instruction[1]) << 5
+ try:
+ assembled[-1] |= SET_DESTINATIONS.index(instruction[1]) << 5
+ except ValueError as exc:
+ raise ValueError(f"Invalid set destination '{instruction[1]}'") from exc
value = int(instruction[-1])
if not 0 <= value <= 31:
raise RuntimeError("Set value out of range")
diff --git a/docs/index.rst b/docs/index.rst
index ed5921d..96d9e30 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -24,6 +24,7 @@ Table of Contents
:caption: Tutorials
Getting Started with Raspberry Pi Pico and CircuitPython
+ An Introduction to RP2040 PIO with CircuitPython
.. toctree::
:caption: Related Products
diff --git a/tests/testpioasm.py b/tests/testpioasm.py
index 684702a..0069b0e 100644
--- a/tests/testpioasm.py
+++ b/tests/testpioasm.py
@@ -18,7 +18,7 @@ def nice_opcode(o):
return o[:3] + "_" + o[3:8] + "_" + o[8:]
-class TestNop(unittest.TestCase):
+class AssembleChecks(unittest.TestCase):
def assertAssemblesTo(self, source, expected):
actual = adafruit_pioasm.assemble(source)
expected_bin = [nice_opcode(x) for x in expected]
@@ -29,13 +29,18 @@ class TestNop(unittest.TestCase):
f"Assembling {source!r}: Expected {expected_bin}, got {actual_bin}",
)
- def assertAssemblyFails(self, source):
- self.assertRaises(RuntimeError, adafruit_pioasm.assemble, source)
+ def assertAssemblyFails(self, source, match=None, errtype=RuntimeError):
+ if match:
+ self.assertRaisesRegex(errtype, match, adafruit_pioasm.assemble, source)
+ else:
+ self.assertRaises(errtype, adafruit_pioasm.assemble, source)
def assertPioKwargs(self, source, **kw):
program = adafruit_pioasm.Program(source)
self.assertEqual(kw, program.pio_kwargs)
+
+class TestNop(AssembleChecks):
def testNonsense(self):
self.assertAssemblyFails("nope")
@@ -64,6 +69,12 @@ class TestNop(unittest.TestCase):
".side_set 1 opt\nnop side 0 [7]", [0b101_10111_010_00_010]
)
+ def testSet(self):
+ # non happy path
+ self.assertAssemblyFails(
+ "set isr, 1", match="Invalid set destination 'isr'", errtype=ValueError
+ )
+
def testJmp(self):
self.assertAssemblesTo("l:\njmp l", [0b000_00000_000_00000])
self.assertAssemblesTo("l:\njmp 7", [0b000_00000_000_00111])
@@ -75,6 +86,10 @@ class TestNop(unittest.TestCase):
self.assertAssemblesTo("jmp x!=y, l\nl:", [0b000_00000_101_00001])
self.assertAssemblesTo("jmp pin, l\nl:", [0b000_00000_110_00001])
self.assertAssemblesTo("jmp !osre, l\nl:", [0b000_00000_111_00001])
+ # non happy path
+ self.assertAssemblyFails(
+ "jmp x--., l\nl:", match="Invalid jmp condition 'x--.'", errtype=ValueError
+ )
def testWait(self):
self.assertAssemblesTo("wait 0 gpio 0", [0b001_00000_0_00_00000])
@@ -99,3 +114,23 @@ class TestNop(unittest.TestCase):
self.assertPioKwargs("", sideset_count=0, sideset_enable=False)
self.assertPioKwargs(".side_set 1", sideset_count=1, sideset_enable=False)
self.assertPioKwargs(".side_set 3 opt", sideset_count=3, sideset_enable=True)
+
+
+class TestMov(AssembleChecks):
+ def testMovNonHappy(self):
+ # non happy path
+ self.assertAssemblyFails(
+ "mov x, blah", match="Invalid mov source 'blah'", errtype=ValueError
+ )
+
+ def testMovInvert(self):
+ # test moving and inverting
+ self.assertAssemblesTo("mov x, ~ x", [0b101_00000_001_01_001])
+ self.assertAssemblesTo("mov x, ~ x", [0b101_00000_001_01_001])
+ self.assertAssemblesTo("mov x, ~x", [0b101_00000_001_01_001])
+ self.assertAssemblesTo("mov x, !x", [0b101_00000_001_01_001])
+
+ def testMovReverse(self):
+ # test moving and reversing bits
+ self.assertAssemblesTo("mov x, :: x", [0b101_00000_001_10_001])
+ self.assertAssemblesTo("mov x, ::x", [0b101_00000_001_10_001])