Merge remote-tracking branch 'origin/main' into program-object
This commit is contained in:
commit
666f4ef2c9
5 changed files with 54 additions and 8 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -16,3 +16,4 @@ bundles
|
||||||
dist
|
dist
|
||||||
**/*.egg-info
|
**/*.egg-info
|
||||||
.vscode
|
.vscode
|
||||||
|
.venv
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,6 @@ This is easily achieved by downloading
|
||||||
|
|
||||||
Installing from PyPI
|
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
|
On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally `from
|
||||||
PyPI <https://pypi.org/project/adafruit-circuitpython-pioasm/>`_. To install for current user:
|
PyPI <https://pypi.org/project/adafruit-circuitpython-pioasm/>`_. To install for current user:
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,12 @@ class Program: # pylint: disable=too-few-public-methods
|
||||||
raise SyntaxError(f"Invalid jmp target {repr(target)}")
|
raise SyntaxError(f"Invalid jmp target {repr(target)}")
|
||||||
|
|
||||||
if len(instruction) > 2:
|
if len(instruction) > 2:
|
||||||
|
try:
|
||||||
assembled[-1] |= CONDITIONS.index(instruction[1]) << 5
|
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":
|
elif instruction[0] == "wait":
|
||||||
# instr delay p sr index
|
# instr delay p sr index
|
||||||
|
|
@ -163,7 +168,10 @@ class Program: # pylint: disable=too-few-public-methods
|
||||||
source = instruction[-1]
|
source = instruction[-1]
|
||||||
source_split = mov_splitter(source)
|
source_split = mov_splitter(source)
|
||||||
if len(source_split) == 1:
|
if len(source_split) == 1:
|
||||||
|
try:
|
||||||
assembled[-1] |= MOV_SOURCES.index(source)
|
assembled[-1] |= MOV_SOURCES.index(source)
|
||||||
|
except ValueError as exc:
|
||||||
|
raise ValueError(f"Invalid mov source '{source}'") from exc
|
||||||
else:
|
else:
|
||||||
assembled[-1] |= MOV_SOURCES.index(source_split[1])
|
assembled[-1] |= MOV_SOURCES.index(source_split[1])
|
||||||
if source[:1] == "!":
|
if source[:1] == "!":
|
||||||
|
|
@ -195,7 +203,10 @@ class Program: # pylint: disable=too-few-public-methods
|
||||||
elif instruction[0] == "set":
|
elif instruction[0] == "set":
|
||||||
# instr delay dst data
|
# instr delay dst data
|
||||||
assembled.append(0b111_00000_000_00000)
|
assembled.append(0b111_00000_000_00000)
|
||||||
|
try:
|
||||||
assembled[-1] |= SET_DESTINATIONS.index(instruction[1]) << 5
|
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])
|
value = int(instruction[-1])
|
||||||
if not 0 <= value <= 31:
|
if not 0 <= value <= 31:
|
||||||
raise RuntimeError("Set value out of range")
|
raise RuntimeError("Set value out of range")
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ Table of Contents
|
||||||
:caption: Tutorials
|
:caption: Tutorials
|
||||||
|
|
||||||
Getting Started with Raspberry Pi Pico and CircuitPython <https://learn.adafruit.com/getting-started-with-raspberry-pi-pico-circuitpython>
|
Getting Started with Raspberry Pi Pico and CircuitPython <https://learn.adafruit.com/getting-started-with-raspberry-pi-pico-circuitpython>
|
||||||
|
An Introduction to RP2040 PIO with CircuitPython <https://learn.adafruit.com/intro-to-rp2040-pio-with-circuitpython>
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:caption: Related Products
|
:caption: Related Products
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ def nice_opcode(o):
|
||||||
return o[:3] + "_" + o[3:8] + "_" + o[8:]
|
return o[:3] + "_" + o[3:8] + "_" + o[8:]
|
||||||
|
|
||||||
|
|
||||||
class TestNop(unittest.TestCase):
|
class AssembleChecks(unittest.TestCase):
|
||||||
def assertAssemblesTo(self, source, expected):
|
def assertAssemblesTo(self, source, expected):
|
||||||
actual = adafruit_pioasm.assemble(source)
|
actual = adafruit_pioasm.assemble(source)
|
||||||
expected_bin = [nice_opcode(x) for x in expected]
|
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}",
|
f"Assembling {source!r}: Expected {expected_bin}, got {actual_bin}",
|
||||||
)
|
)
|
||||||
|
|
||||||
def assertAssemblyFails(self, source):
|
def assertAssemblyFails(self, source, match=None, errtype=RuntimeError):
|
||||||
self.assertRaises(RuntimeError, adafruit_pioasm.assemble, source)
|
if match:
|
||||||
|
self.assertRaisesRegex(errtype, match, adafruit_pioasm.assemble, source)
|
||||||
|
else:
|
||||||
|
self.assertRaises(errtype, adafruit_pioasm.assemble, source)
|
||||||
|
|
||||||
def assertPioKwargs(self, source, **kw):
|
def assertPioKwargs(self, source, **kw):
|
||||||
program = adafruit_pioasm.Program(source)
|
program = adafruit_pioasm.Program(source)
|
||||||
self.assertEqual(kw, program.pio_kwargs)
|
self.assertEqual(kw, program.pio_kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class TestNop(AssembleChecks):
|
||||||
def testNonsense(self):
|
def testNonsense(self):
|
||||||
self.assertAssemblyFails("nope")
|
self.assertAssemblyFails("nope")
|
||||||
|
|
||||||
|
|
@ -64,6 +69,12 @@ class TestNop(unittest.TestCase):
|
||||||
".side_set 1 opt\nnop side 0 [7]", [0b101_10111_010_00_010]
|
".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):
|
def testJmp(self):
|
||||||
self.assertAssemblesTo("l:\njmp l", [0b000_00000_000_00000])
|
self.assertAssemblesTo("l:\njmp l", [0b000_00000_000_00000])
|
||||||
self.assertAssemblesTo("l:\njmp 7", [0b000_00000_000_00111])
|
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 x!=y, l\nl:", [0b000_00000_101_00001])
|
||||||
self.assertAssemblesTo("jmp pin, l\nl:", [0b000_00000_110_00001])
|
self.assertAssemblesTo("jmp pin, l\nl:", [0b000_00000_110_00001])
|
||||||
self.assertAssemblesTo("jmp !osre, l\nl:", [0b000_00000_111_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):
|
def testWait(self):
|
||||||
self.assertAssemblesTo("wait 0 gpio 0", [0b001_00000_0_00_00000])
|
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("", sideset_count=0, sideset_enable=False)
|
||||||
self.assertPioKwargs(".side_set 1", sideset_count=1, 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)
|
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])
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue