mirror of
https://github.com/micropython/micropython.git
synced 2026-01-05 03:30:14 +01:00
rp2: Add new port to Raspberry Pi RP2 microcontroller.
This commit adds a new port "rp2" which targets the new Raspberry Pi RP2040 microcontroller. The build system uses pure cmake (with a small Makefile wrapper for convenience). The USB driver is TinyUSB, and there is a machine module with most of the standard classes implemented. Some examples are provided in the examples/rp2/ directory. Work done in collaboration with Graham Sanderson. Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
294
ports/rp2/modules/rp2.py
Normal file
294
ports/rp2/modules/rp2.py
Normal file
@@ -0,0 +1,294 @@
|
||||
# rp2 module: uses C code from _rp2, plus asm_pio decorator implemented in Python.
|
||||
# MIT license; Copyright (c) 2020-2021 Damien P. George
|
||||
|
||||
from _rp2 import *
|
||||
from micropython import const
|
||||
|
||||
_PROG_DATA = const(0)
|
||||
_PROG_OFFSET_PIO0 = const(1)
|
||||
_PROG_OFFSET_PIO1 = const(2)
|
||||
_PROG_EXECCTRL = const(3)
|
||||
_PROG_SHIFTCTRL = const(4)
|
||||
_PROG_OUT_PINS = const(5)
|
||||
_PROG_SET_PINS = const(6)
|
||||
_PROG_SIDESET_PINS = const(7)
|
||||
_PROG_MAX_FIELDS = const(8)
|
||||
|
||||
|
||||
class PIOASMError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class PIOASMEmit:
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
out_init=None,
|
||||
set_init=None,
|
||||
sideset_init=None,
|
||||
in_shiftdir=0,
|
||||
out_shiftdir=0,
|
||||
autopush=False,
|
||||
autopull=False,
|
||||
push_thresh=32,
|
||||
pull_thresh=32
|
||||
):
|
||||
from array import array
|
||||
|
||||
self.labels = {}
|
||||
execctrl = 0
|
||||
shiftctrl = (
|
||||
(pull_thresh & 0x1F) << 25
|
||||
| (push_thresh & 0x1F) << 20
|
||||
| out_shiftdir << 19
|
||||
| in_shiftdir << 18
|
||||
| autopull << 17
|
||||
| autopush << 16
|
||||
)
|
||||
self.prog = [array("H"), -1, -1, execctrl, shiftctrl, out_init, set_init, sideset_init]
|
||||
|
||||
self.wrap_used = False
|
||||
|
||||
if sideset_init is None:
|
||||
self.sideset_count = 0
|
||||
elif isinstance(sideset_init, int):
|
||||
self.sideset_count = 1
|
||||
else:
|
||||
self.sideset_count = len(sideset_init)
|
||||
|
||||
def start_pass(self, pass_):
|
||||
if pass_ == 1:
|
||||
if not self.wrap_used and self.num_instr:
|
||||
self.wrap()
|
||||
self.delay_max = 31
|
||||
if self.sideset_count:
|
||||
self.sideset_opt = self.num_sideset != self.num_instr
|
||||
if self.sideset_opt:
|
||||
self.prog[_PROG_EXECCTRL] |= 1 << 30
|
||||
self.sideset_count += 1
|
||||
self.delay_max >>= self.sideset_count
|
||||
self.pass_ = pass_
|
||||
self.num_instr = 0
|
||||
self.num_sideset = 0
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.delay(key)
|
||||
|
||||
def delay(self, delay):
|
||||
if self.pass_ > 0:
|
||||
if delay > self.delay_max:
|
||||
raise PIOASMError("delay too large")
|
||||
self.prog[_PROG_DATA][-1] |= delay << 8
|
||||
return self
|
||||
|
||||
def side(self, value):
|
||||
self.num_sideset += 1
|
||||
if self.pass_ > 0:
|
||||
set_bit = 13 - self.sideset_count
|
||||
self.prog[_PROG_DATA][-1] |= self.sideset_opt << 12 | value << set_bit
|
||||
return self
|
||||
|
||||
def wrap_target(self):
|
||||
self.prog[_PROG_EXECCTRL] |= self.num_instr << 7
|
||||
|
||||
def wrap(self):
|
||||
assert self.num_instr
|
||||
self.prog[_PROG_EXECCTRL] |= (self.num_instr - 1) << 12
|
||||
self.wrap_used = True
|
||||
|
||||
def label(self, label):
|
||||
if self.pass_ == 0:
|
||||
if label in self.labels:
|
||||
raise PIOASMError("duplicate label {}".format(label))
|
||||
self.labels[label] = self.num_instr
|
||||
|
||||
def word(self, instr, label=None):
|
||||
self.num_instr += 1
|
||||
if self.pass_ > 0:
|
||||
if label is None:
|
||||
label = 0
|
||||
else:
|
||||
if not label in self.labels:
|
||||
raise PIOASMError("unknown label {}".format(label))
|
||||
label = self.labels[label]
|
||||
self.prog[_PROG_DATA].append(instr | label)
|
||||
return self
|
||||
|
||||
def nop(self):
|
||||
return self.word(0xA042)
|
||||
|
||||
def jmp(self, cond, label=None):
|
||||
if label is None:
|
||||
label = cond
|
||||
cond = 0 # always
|
||||
return self.word(0x0000 | cond << 5, label)
|
||||
|
||||
def wait(self, polarity, src, index):
|
||||
if src == 6:
|
||||
src = 1 # "pin"
|
||||
elif src != 0:
|
||||
src = 2 # "irq"
|
||||
return self.word(0x2000 | polarity << 7 | src << 5 | index)
|
||||
|
||||
def in_(self, src, data):
|
||||
if not 0 < data <= 32:
|
||||
raise PIOASMError("invalid bit count {}".format(data))
|
||||
return self.word(0x4000 | src << 5 | data & 0x1F)
|
||||
|
||||
def out(self, dest, data):
|
||||
if dest == 8:
|
||||
dest = 7 # exec
|
||||
if not 0 < data <= 32:
|
||||
raise PIOASMError("invalid bit count {}".format(data))
|
||||
return self.word(0x6000 | dest << 5 | data & 0x1F)
|
||||
|
||||
def push(self, value=0, value2=0):
|
||||
value |= value2
|
||||
if not value & 1:
|
||||
value |= 0x20 # block by default
|
||||
return self.word(0x8000 | (value & 0x60))
|
||||
|
||||
def pull(self, value=0, value2=0):
|
||||
value |= value2
|
||||
if not value & 1:
|
||||
value |= 0x20 # block by default
|
||||
return self.word(0x8080 | (value & 0x60))
|
||||
|
||||
def mov(self, dest, src):
|
||||
if dest == 8:
|
||||
dest = 4 # exec
|
||||
return self.word(0xA000 | dest << 5 | src)
|
||||
|
||||
def irq(self, mod, index=None):
|
||||
if index is None:
|
||||
index = mod
|
||||
mod = 0 # no modifiers
|
||||
return self.word(0xC000 | (mod & 0x60) | index)
|
||||
|
||||
def set(self, dest, data):
|
||||
return self.word(0xE000 | dest << 5 | data)
|
||||
|
||||
|
||||
_pio_funcs = {
|
||||
# source constants for wait
|
||||
"gpio": 0,
|
||||
# "pin": see below, translated to 1
|
||||
# "irq": see below function, translated to 2
|
||||
# source/dest constants for in_, out, mov, set
|
||||
"pins": 0,
|
||||
"x": 1,
|
||||
"y": 2,
|
||||
"null": 3,
|
||||
"pindirs": 4,
|
||||
"pc": 5,
|
||||
"status": 5,
|
||||
"isr": 6,
|
||||
"osr": 7,
|
||||
"exec": 8, # translated to 4 for mov, 7 for out
|
||||
# operation functions for mov's src
|
||||
"invert": lambda x: x | 0x08,
|
||||
"reverse": lambda x: x | 0x10,
|
||||
# jmp condition constants
|
||||
"not_x": 1,
|
||||
"x_dec": 2,
|
||||
"not_y": 3,
|
||||
"y_dec": 4,
|
||||
"x_not_y": 5,
|
||||
"pin": 6,
|
||||
"not_osre": 7,
|
||||
# constants for push, pull
|
||||
"noblock": 0x01,
|
||||
"block": 0x21,
|
||||
"iffull": 0x40,
|
||||
"ifempty": 0x40,
|
||||
# constants and modifiers for irq
|
||||
# "noblock": see above
|
||||
# "block": see above
|
||||
"clear": 0x40,
|
||||
"rel": lambda x: x | 0x10,
|
||||
# functions
|
||||
"wrap_target": None,
|
||||
"wrap": None,
|
||||
"label": None,
|
||||
"word": None,
|
||||
"nop": None,
|
||||
"jmp": None,
|
||||
"wait": None,
|
||||
"in_": None,
|
||||
"out": None,
|
||||
"push": None,
|
||||
"pull": None,
|
||||
"mov": None,
|
||||
"irq": None,
|
||||
"set": None,
|
||||
}
|
||||
|
||||
|
||||
def asm_pio(**kw):
|
||||
emit = PIOASMEmit(**kw)
|
||||
|
||||
def dec(f):
|
||||
nonlocal emit
|
||||
|
||||
gl = _pio_funcs
|
||||
gl["wrap_target"] = emit.wrap_target
|
||||
gl["wrap"] = emit.wrap
|
||||
gl["label"] = emit.label
|
||||
gl["word"] = emit.word
|
||||
gl["nop"] = emit.nop
|
||||
gl["jmp"] = emit.jmp
|
||||
gl["wait"] = emit.wait
|
||||
gl["in_"] = emit.in_
|
||||
gl["out"] = emit.out
|
||||
gl["push"] = emit.push
|
||||
gl["pull"] = emit.pull
|
||||
gl["mov"] = emit.mov
|
||||
gl["irq"] = emit.irq
|
||||
gl["set"] = emit.set
|
||||
|
||||
old_gl = f.__globals__.copy()
|
||||
f.__globals__.clear()
|
||||
f.__globals__.update(gl)
|
||||
|
||||
emit.start_pass(0)
|
||||
f()
|
||||
|
||||
emit.start_pass(1)
|
||||
f()
|
||||
|
||||
f.__globals__.clear()
|
||||
f.__globals__.update(old_gl)
|
||||
|
||||
return emit.prog
|
||||
|
||||
return dec
|
||||
|
||||
|
||||
# sideset_count is inclusive of enable bit
|
||||
def asm_pio_encode(instr, sideset_count):
|
||||
emit = PIOASMEmit()
|
||||
emit.delay_max = 31
|
||||
emit.sideset_count = sideset_count
|
||||
if emit.sideset_count:
|
||||
emit.delay_max >>= emit.sideset_count
|
||||
emit.pass_ = 1
|
||||
emit.num_instr = 0
|
||||
emit.num_sideset = 0
|
||||
|
||||
gl = _pio_funcs
|
||||
gl["nop"] = emit.nop
|
||||
# gl["jmp"] = emit.jmp currently not supported
|
||||
gl["wait"] = emit.wait
|
||||
gl["in_"] = emit.in_
|
||||
gl["out"] = emit.out
|
||||
gl["push"] = emit.push
|
||||
gl["pull"] = emit.pull
|
||||
gl["mov"] = emit.mov
|
||||
gl["irq"] = emit.irq
|
||||
gl["set"] = emit.set
|
||||
|
||||
exec(instr, gl)
|
||||
|
||||
if len(emit.prog[_PROG_DATA]) != 1:
|
||||
raise PIOASMError("expecting exactly 1 instruction")
|
||||
return emit.prog[_PROG_DATA][0]
|
||||
Reference in New Issue
Block a user