rp2: Add StateMachine.may_exec

and also sanity-check the init instructions, thanks to the newly
factored-out checker.

Closes: #8221
This commit is contained in:
Jeff Epler 2023-07-27 11:39:40 -05:00
parent a27a5aa00d
commit 5780d9a3d2
No known key found for this signature in database
GPG Key ID: D5BF15AB975AB4DE
10 changed files with 167 additions and 139 deletions

View File

@ -251,6 +251,22 @@ msgstr ""
msgid "%q=%q" msgid "%q=%q"
msgstr "" msgstr ""
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
msgid "%q[%u] shifts in more bits than pin count"
msgstr ""
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
msgid "%q[%u] shifts out more bits than pin count"
msgstr ""
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
msgid "%q[%u] uses extra pin"
msgstr ""
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
msgid "%q[%u] waits on input outside of count"
msgstr ""
#: ports/espressif/common-hal/espidf/__init__.c #: ports/espressif/common-hal/espidf/__init__.c
#, c-format #, c-format
msgid "%s error 0x%x" msgid "%s error 0x%x"
@ -1161,26 +1177,6 @@ msgstr ""
msgid "Input/output error" msgid "Input/output error"
msgstr "" msgstr ""
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
#, c-format
msgid "Instruction %d shifts in more bits than pin count"
msgstr ""
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
#, c-format
msgid "Instruction %d shifts out more bits than pin count"
msgstr ""
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
#, c-format
msgid "Instruction %d uses extra pin"
msgstr ""
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
#, c-format
msgid "Instruction %d waits on input outside of count"
msgstr ""
#: ports/nrf/common-hal/_bleio/__init__.c #: ports/nrf/common-hal/_bleio/__init__.c
msgid "Insufficient authentication" msgid "Insufficient authentication"
msgstr "" msgstr ""
@ -1352,38 +1348,31 @@ msgid "Mismatched swap flag"
msgstr "" msgstr ""
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
#, c-format msgid "Missing first_in_pin. %q[%u] reads pin(s)"
msgid "Missing first_in_pin. Instruction %d reads pin(s)"
msgstr "" msgstr ""
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
#, c-format msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)"
msgid "Missing first_in_pin. Instruction %d shifts in from pin(s)"
msgstr "" msgstr ""
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
#, c-format msgid "Missing first_in_pin. %q[%u] waits based on pin"
msgid "Missing first_in_pin. Instruction %d waits based on pin"
msgstr "" msgstr ""
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
#, c-format msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)"
msgid "Missing first_out_pin. Instruction %d shifts out to pin(s)"
msgstr "" msgstr ""
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
#, c-format msgid "Missing first_out_pin. %q[%u] writes pin(s)"
msgid "Missing first_out_pin. Instruction %d writes pin(s)"
msgstr "" msgstr ""
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
#, c-format msgid "Missing first_set_pin. %q[%u] sets pin(s)"
msgid "Missing first_set_pin. Instruction %d sets pin(s)"
msgstr "" msgstr ""
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
#, c-format msgid "Missing jmp_pin. %q[%u] jumps on pin"
msgid "Missing jmp_pin. Instruction %d jumps on pin"
msgstr "" msgstr ""
#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c #: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c
@ -1825,7 +1814,8 @@ msgstr ""
#: shared-bindings/_bleio/__init__.c #: shared-bindings/_bleio/__init__.c
#: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/memorymonitor/AllocationSize.c
#: shared-bindings/pulseio/PulseIn.c shared-module/displayio/Bitmap.c #: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c
#: shared-module/displayio/Bitmap.c
msgid "Read-only" msgid "Read-only"
msgstr "" msgstr ""
@ -4021,7 +4011,7 @@ msgstr ""
msgid "sosfilt requires iterable arguments" msgid "sosfilt requires iterable arguments"
msgstr "" msgstr ""
#: shared-bindings/bitmaptools/__init__.c shared-bindings/displayio/Bitmap.c #: shared-bindings/bitmaptools/__init__.c
msgid "source palette too large" msgid "source palette too large"
msgstr "" msgstr ""

View File

@ -100,6 +100,10 @@
//| :param int frequency: the target clock frequency of the state machine. Actual may be less. Use 0 for system clock speed. //| :param int frequency: the target clock frequency of the state machine. Actual may be less. Use 0 for system clock speed.
//| :param ReadableBuffer init: a program to run once at start up. This is run after program //| :param ReadableBuffer init: a program to run once at start up. This is run after program
//| is started so instructions may be intermingled //| is started so instructions may be intermingled
//| :param ReadableBuffer may_exec: Instructions that may be executed via `StateMachine.exec` calls.
//| Some elements of the `StateMachine`'s configuration are inferred from the instructions used;
//| for instance, if there is no ``in`` or ``push`` instruction, then the `StateMachine` is configured without a receive FIFO.
//| In this case, passing a ``may_exec`` program containing an ``in`` instruction such as ``in x``, a receive FIFO will be configured.
//| :param ~microcontroller.Pin first_out_pin: the first pin to use with the OUT instruction //| :param ~microcontroller.Pin first_out_pin: the first pin to use with the OUT instruction
//| :param int out_pin_count: the count of consecutive pins to use with OUT starting at first_out_pin //| :param int out_pin_count: the count of consecutive pins to use with OUT starting at first_out_pin
//| :param int initial_out_pin_state: the initial output value for out pins starting at first_out_pin //| :param int initial_out_pin_state: the initial output value for out pins starting at first_out_pin
@ -152,7 +156,7 @@
STATIC mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { STATIC mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
rp2pio_statemachine_obj_t *self = m_new_obj(rp2pio_statemachine_obj_t); rp2pio_statemachine_obj_t *self = m_new_obj(rp2pio_statemachine_obj_t);
self->base.type = &rp2pio_statemachine_type; self->base.type = &rp2pio_statemachine_type;
enum { ARG_program, ARG_frequency, ARG_init, enum { ARG_program, ARG_frequency, ARG_init, ARG_may_exec,
ARG_first_out_pin, ARG_out_pin_count, ARG_initial_out_pin_state, ARG_initial_out_pin_direction, ARG_first_out_pin, ARG_out_pin_count, ARG_initial_out_pin_state, ARG_initial_out_pin_direction,
ARG_first_in_pin, ARG_in_pin_count, ARG_first_in_pin, ARG_in_pin_count,
ARG_pull_in_pin_up, ARG_pull_in_pin_down, ARG_pull_in_pin_up, ARG_pull_in_pin_down,
@ -171,6 +175,7 @@ STATIC mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n
{ MP_QSTR_program, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_program, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_frequency, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_frequency, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_init, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_init, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_may_exec, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_first_out_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_first_out_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_out_pin_count, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, { MP_QSTR_out_pin_count, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
@ -220,6 +225,10 @@ STATIC mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n
init_bufinfo.len = 0; init_bufinfo.len = 0;
mp_get_buffer(args[ARG_init].u_obj, &init_bufinfo, MP_BUFFER_READ); mp_get_buffer(args[ARG_init].u_obj, &init_bufinfo, MP_BUFFER_READ);
mp_buffer_info_t may_exec_bufinfo;
may_exec_bufinfo.len = 0;
mp_get_buffer(args[ARG_may_exec].u_obj, &may_exec_bufinfo, MP_BUFFER_READ);
// We don't validate pin in use here because we may be ok sharing them within a PIO. // We don't validate pin in use here because we may be ok sharing them within a PIO.
const mcu_pin_obj_t *first_out_pin = const mcu_pin_obj_t *first_out_pin =
validate_obj_is_pin_or_none(args[ARG_first_out_pin].u_obj, MP_QSTR_first_out_pin); validate_obj_is_pin_or_none(args[ARG_first_out_pin].u_obj, MP_QSTR_first_out_pin);
@ -264,6 +273,7 @@ STATIC mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n
bufinfo.buf, bufinfo.len / 2, bufinfo.buf, bufinfo.len / 2,
args[ARG_frequency].u_int, args[ARG_frequency].u_int,
init_bufinfo.buf, init_bufinfo.len / 2, init_bufinfo.buf, init_bufinfo.len / 2,
may_exec_bufinfo.buf, bufinfo.len / 2,
first_out_pin, out_pin_count, args[ARG_initial_out_pin_state].u_int, args[ARG_initial_out_pin_direction].u_int, first_out_pin, out_pin_count, args[ARG_initial_out_pin_state].u_int, args[ARG_initial_out_pin_direction].u_int,
first_in_pin, in_pin_count, args[ARG_pull_in_pin_up].u_int, args[ARG_pull_in_pin_down].u_int, first_in_pin, in_pin_count, args[ARG_pull_in_pin_up].u_int, args[ARG_pull_in_pin_down].u_int,
first_set_pin, set_pin_count, args[ARG_initial_set_pin_state].u_int, args[ARG_initial_set_pin_direction].u_int, first_set_pin, set_pin_count, args[ARG_initial_set_pin_state].u_int, args[ARG_initial_set_pin_direction].u_int,

View File

@ -41,6 +41,7 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
const uint16_t *program, size_t program_len, const uint16_t *program, size_t program_len,
size_t frequency, size_t frequency,
const uint16_t *init, size_t init_len, const uint16_t *init, size_t init_len,
const uint16_t *may_exec, size_t may_exec_len,
const mcu_pin_obj_t *first_out_pin, uint8_t out_pin_count, uint32_t initial_out_pin_state, uint32_t initial_out_pin_direction, const mcu_pin_obj_t *first_out_pin, uint8_t out_pin_count, uint32_t initial_out_pin_state, uint32_t initial_out_pin_direction,
const mcu_pin_obj_t *first_in_pin, uint8_t in_pin_count, uint32_t pull_pin_up, uint32_t pull_pin_down, const mcu_pin_obj_t *first_in_pin, uint8_t in_pin_count, uint32_t pull_pin_up, uint32_t pull_pin_down,
const mcu_pin_obj_t *first_set_pin, uint8_t set_pin_count, uint32_t initial_set_pin_state, uint32_t initial_set_pin_direction, const mcu_pin_obj_t *first_set_pin, uint8_t set_pin_count, uint32_t initial_set_pin_state, uint32_t initial_set_pin_direction,

View File

@ -121,7 +121,8 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self,
&self->state_machine, &self->state_machine,
program, program_len, program, program_len,
44100 * 32 * 6, // Clock at 44.1 khz to warm the DAC up. 44100 * 32 * 6, // Clock at 44.1 khz to warm the DAC up.
NULL, 0, NULL, 0, // init
NULL, 0, // may_exec
data, 1, 0, 0xffffffff, // out pin data, 1, 0, 0xffffffff, // out pin
NULL, 0, // in pins NULL, 0, // in pins
0, 0, // in pulls 0, 0, // in pulls

View File

@ -66,6 +66,7 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t *self,
pdmin, MP_ARRAY_SIZE(pdmin), pdmin, MP_ARRAY_SIZE(pdmin),
sample_rate * 32 * 2, // Frequency based on sample rate sample_rate * 32 * 2, // Frequency based on sample rate
NULL, 0, NULL, 0,
NULL, 0, // may_exec
NULL, 1, 0, 0xffffffff, // out pin NULL, 1, 0, 0xffffffff, // out pin
data_pin, 1, // in pins data_pin, 1, // in pins
0, 0, // in pulls 0, 0, // in pulls

View File

@ -102,6 +102,7 @@ void common_hal_imagecapture_parallelimagecapture_construct(imagecapture_paralle
imagecapture_code, MP_ARRAY_SIZE(imagecapture_code), imagecapture_code, MP_ARRAY_SIZE(imagecapture_code),
common_hal_mcu_processor_get_frequency(), // full speed (4 instructions per loop -> max pclk 30MHz @ 120MHz) common_hal_mcu_processor_get_frequency(), // full speed (4 instructions per loop -> max pclk 30MHz @ 120MHz)
0, 0, // init 0, 0, // init
NULL, 0, // may_exec
NULL, 0, 0, 0, // out pins NULL, 0, 0, 0, // out pins
pin_from_number(data_pins[0]), data_count, // in pins pin_from_number(data_pins[0]), data_count, // in pins
0, 0, // in pulls 0, 0, // in pulls

View File

@ -98,6 +98,7 @@ void common_hal_paralleldisplay_parallelbus_construct(paralleldisplay_parallelbu
parallel_program, MP_ARRAY_SIZE(parallel_program), parallel_program, MP_ARRAY_SIZE(parallel_program),
frequency * 2, // frequency multiplied by 2 as 2 PIO instructions frequency * 2, // frequency multiplied by 2 as 2 PIO instructions
NULL, 0, // init NULL, 0, // init
NULL, 0, // may_exec
data0, 8, 0, 255, // first out pin, # out pins data0, 8, 0, 255, // first out pin, # out pins
NULL, 0, 0, 0, // first in pin, # in pins NULL, 0, 0, 0, // first in pin, # in pins
NULL, 0, 0, 0, // first set pin NULL, 0, 0, 0, // first set pin

View File

@ -61,6 +61,7 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t *self,
pulsein_program, MP_ARRAY_SIZE(pulsein_program), pulsein_program, MP_ARRAY_SIZE(pulsein_program),
1000000, // frequency 1000000, // frequency
NULL, 0, // init, init_len NULL, 0, // init, init_len
NULL, 0, // may_exec
NULL, 0, 0, 0, // first out pin, # out pins, initial_out_pin_state NULL, 0, 0, 0, // first out pin, # out pins, initial_out_pin_state
pin, 1, 0, 0, // first in pin, # in pins pin, 1, 0, 0, // first in pin, # in pins
NULL, 0, 0, 0, // first set pin NULL, 0, 0, 0, // first set pin

View File

@ -81,6 +81,7 @@ void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencode
encoder, MP_ARRAY_SIZE(encoder), encoder, MP_ARRAY_SIZE(encoder),
1000000, 1000000,
encoder_init, MP_ARRAY_SIZE(encoder_init), // init encoder_init, MP_ARRAY_SIZE(encoder_init), // init
NULL, 0, // may_exec
NULL, 0, 0, 0, // out pin NULL, 0, 0, 0, // out pin
pins[0], 2, // in pins pins[0], 2, // in pins
3, 0, // in pulls 3, 0, // in pulls

View File

@ -387,10 +387,115 @@ static uint32_t mask_and_rotate(const mcu_pin_obj_t *first_pin, uint32_t bit_cou
return value << shift | value >> (32 - shift); return value << shift | value >> (32 - shift);
} }
typedef struct {
uint32_t pins_we_use, in_pin_count, out_pin_count;
bool has_jmp_pin, auto_push, auto_pull, has_in_pin, has_out_pin, has_set_pin;
bool tx_fifo, rx_fifo, in_loaded, out_loaded, in_used, out_used;
} introspect_t;
static void consider_instruction(introspect_t *state, uint16_t full_instruction, qstr what, size_t i) {
uint16_t instruction = full_instruction & 0xe000;
if (instruction == 0x8000) {
if ((full_instruction & 0xe080) == pio_instr_bits_push) {
state->rx_fifo = true;
state->in_loaded = true;
} else { // pull otherwise.
state->tx_fifo = true;
state->out_loaded = true;
}
}
if (instruction == pio_instr_bits_jmp) {
uint16_t condition = (full_instruction & 0x00e0) >> 5;
if ((condition == 0x6) && !state->has_jmp_pin) {
mp_raise_ValueError_varg(translate("Missing jmp_pin. %q[%u] jumps on pin"), what, i);
}
}
if (instruction == pio_instr_bits_wait) {
uint16_t wait_source = (full_instruction & 0x0060) >> 5;
uint16_t wait_index = full_instruction & 0x001f;
if (wait_source == 0 && (state->pins_we_use & (1 << wait_index)) == 0) { // GPIO
mp_raise_ValueError_varg(translate("%q[%u] uses extra pin"), i);
}
if (wait_source == 1) { // Input pin
if (state->has_in_pin) {
mp_raise_ValueError_varg(translate("Missing first_in_pin. %q[%u] waits based on pin"), what, i);
}
if (wait_index >= state->in_pin_count) {
mp_raise_ValueError_varg(translate("%q[%u] waits on input outside of count"), what, i);
}
}
}
if (instruction == pio_instr_bits_in) {
uint16_t source = (full_instruction & 0x00e0) >> 5;
uint16_t bit_count = full_instruction & 0x001f;
if (source == 0) {
if (!state->has_in_pin) {
mp_raise_ValueError_varg(translate("Missing first_in_pin. %q[%u] shifts in from pin(s)"), i);
}
if (bit_count > state->in_pin_count) {
mp_raise_ValueError_varg(translate("%q[%u] shifts in more bits than pin count"), i);
}
}
if (state->auto_push) {
state->in_loaded = true;
state->rx_fifo = true;
}
state->in_used = true;
}
if (instruction == pio_instr_bits_out) {
uint16_t bit_count = full_instruction & 0x001f;
uint16_t destination = (full_instruction & 0x00e0) >> 5;
// Check for pins or pindirs destination.
if (destination == 0x0 || destination == 0x4) {
if (!state->has_out_pin) {
mp_raise_ValueError_varg(translate("Missing first_out_pin. %q[%u] shifts out to pin(s)"), i);
}
if (bit_count > state->out_pin_count) {
mp_raise_ValueError_varg(translate("%q[%u] shifts out more bits than pin count"), i);
}
}
if (state->auto_pull) {
state->out_loaded = true;
state->tx_fifo = true;
}
state->out_used = true;
}
if (instruction == pio_instr_bits_set) {
uint16_t destination = (full_instruction & 0x00e0) >> 5;
// Check for pins or pindirs destination.
if ((destination == 0x00 || destination == 0x4) && !state->has_set_pin) {
mp_raise_ValueError_varg(translate("Missing first_set_pin. %q[%u] sets pin(s)"), i);
}
}
if (instruction == pio_instr_bits_mov) {
uint16_t source = full_instruction & 0x0007;
uint16_t destination = (full_instruction & 0x00e0) >> 5;
// Check for pins or pindirs destination.
if (destination == 0x0 && !state->has_out_pin) {
mp_raise_ValueError_varg(translate("Missing first_out_pin. %q[%u] writes pin(s)"), i);
}
if (source == 0x0 && !state->has_out_pin) {
mp_raise_ValueError_varg(translate("Missing first_in_pin. %q[%u] reads pin(s)"), i);
}
if (destination == 0x6) {
state->in_loaded = true;
} else if (destination == 0x7) {
state->out_loaded = true;
}
}
}
static void consider_program(introspect_t *state, const uint16_t *program, size_t program_len, qstr what) {
for (size_t i = 0; i < program_len; i++) {
consider_instruction(state, program[i], what, i);
}
}
void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
const uint16_t *program, size_t program_len, const uint16_t *program, size_t program_len,
size_t frequency, size_t frequency,
const uint16_t *init, size_t init_len, const uint16_t *init, size_t init_len,
const uint16_t *may_exec, size_t may_exec_len,
const mcu_pin_obj_t *first_out_pin, uint8_t out_pin_count, uint32_t initial_out_pin_state, uint32_t initial_out_pin_direction, const mcu_pin_obj_t *first_out_pin, uint8_t out_pin_count, uint32_t initial_out_pin_state, uint32_t initial_out_pin_direction,
const mcu_pin_obj_t *first_in_pin, uint8_t in_pin_count, const mcu_pin_obj_t *first_in_pin, uint8_t in_pin_count,
uint32_t pull_pin_up, uint32_t pull_pin_down, uint32_t pull_pin_up, uint32_t pull_pin_down,
@ -415,109 +520,25 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
pins_we_use |= _check_pins_free(jmp_pin, 1, exclusive_pin_use); pins_we_use |= _check_pins_free(jmp_pin, 1, exclusive_pin_use);
// Look through the program to see what we reference and make sure it was provided. // Look through the program to see what we reference and make sure it was provided.
bool tx_fifo = false; introspect_t state = {
bool rx_fifo = false; .pins_we_use = pins_we_use,
bool in_loaded = false; // can be loaded in other ways besides the fifo .has_jmp_pin = jmp_pin != NULL,
bool out_loaded = false; .has_in_pin = first_in_pin != NULL,
bool in_used = false; .has_out_pin = first_out_pin != NULL,
bool out_used = false; .has_set_pin = first_set_pin != NULL,
for (size_t i = 0; i < program_len; i++) { .in_pin_count = in_pin_count,
uint16_t full_instruction = program[i]; .out_pin_count = out_pin_count,
uint16_t instruction = full_instruction & 0xe000; .auto_pull = auto_pull,
if (instruction == 0x8000) { .auto_push = auto_push,
if ((full_instruction & 0xe080) == pio_instr_bits_push) { };
rx_fifo = true; consider_program(&state, program, program_len, MP_QSTR_program);
in_loaded = true; consider_program(&state, init, init_len, MP_QSTR_init);
} else { // pull otherwise. consider_program(&state, may_exec, may_exec_len, MP_QSTR_may_exec);
tx_fifo = true;
out_loaded = true;
}
}
if (instruction == pio_instr_bits_jmp) {
uint16_t condition = (full_instruction & 0x00e0) >> 5;
if ((condition == 0x6) && (jmp_pin == NULL)) {
mp_raise_ValueError_varg(translate("Missing jmp_pin. Instruction %d jumps on pin"), i);
}
}
if (instruction == pio_instr_bits_wait) {
uint16_t wait_source = (full_instruction & 0x0060) >> 5;
uint16_t wait_index = full_instruction & 0x001f;
if (wait_source == 0 && (pins_we_use & (1 << wait_index)) == 0) { // GPIO
mp_raise_ValueError_varg(translate("Instruction %d uses extra pin"), i);
}
if (wait_source == 1) { // Input pin
if (first_in_pin == NULL) {
mp_raise_ValueError_varg(translate("Missing first_in_pin. Instruction %d waits based on pin"), i);
}
if (wait_index >= in_pin_count) {
mp_raise_ValueError_varg(translate("Instruction %d waits on input outside of count"), i);
}
}
}
if (instruction == pio_instr_bits_in) {
uint16_t source = (full_instruction & 0x00e0) >> 5;
uint16_t bit_count = full_instruction & 0x001f;
if (source == 0) {
if (first_in_pin == NULL) {
mp_raise_ValueError_varg(translate("Missing first_in_pin. Instruction %d shifts in from pin(s)"), i);
}
if (bit_count > in_pin_count) {
mp_raise_ValueError_varg(translate("Instruction %d shifts in more bits than pin count"), i);
}
}
if (auto_push) {
in_loaded = true;
rx_fifo = true;
}
in_used = true;
}
if (instruction == pio_instr_bits_out) {
uint16_t bit_count = full_instruction & 0x001f;
uint16_t destination = (full_instruction & 0x00e0) >> 5;
// Check for pins or pindirs destination.
if (destination == 0x0 || destination == 0x4) {
if (first_out_pin == NULL) {
mp_raise_ValueError_varg(translate("Missing first_out_pin. Instruction %d shifts out to pin(s)"), i);
}
if (bit_count > out_pin_count) {
mp_raise_ValueError_varg(translate("Instruction %d shifts out more bits than pin count"), i);
}
}
if (auto_pull) {
out_loaded = true;
tx_fifo = true;
}
out_used = true;
}
if (instruction == pio_instr_bits_set) {
uint16_t destination = (full_instruction & 0x00e0) >> 5;
// Check for pins or pindirs destination.
if ((destination == 0x00 || destination == 0x4) && first_set_pin == NULL) {
mp_raise_ValueError_varg(translate("Missing first_set_pin. Instruction %d sets pin(s)"), i);
}
}
if (instruction == pio_instr_bits_mov) {
uint16_t source = full_instruction & 0x0007;
uint16_t destination = (full_instruction & 0x00e0) >> 5;
// Check for pins or pindirs destination.
if (destination == 0x0 && first_out_pin == NULL) {
mp_raise_ValueError_varg(translate("Missing first_out_pin. Instruction %d writes pin(s)"), i);
}
if (source == 0x0 && first_in_pin == NULL) {
mp_raise_ValueError_varg(translate("Missing first_in_pin. Instruction %d reads pin(s)"), i);
}
if (destination == 0x6) {
in_loaded = true;
} else if (destination == 0x7) {
out_loaded = true;
}
}
}
if (!in_loaded && in_used) { if (!state.in_loaded && state.in_used) {
mp_raise_ValueError_varg(translate("Program does IN without loading ISR")); mp_raise_ValueError_varg(translate("Program does IN without loading ISR"));
} }
if (!out_loaded && out_used) { if (!state.out_loaded && state.out_used) {
mp_raise_ValueError_varg(translate("Program does OUT without loading OSR")); mp_raise_ValueError_varg(translate("Program does OUT without loading OSR"));
} }
@ -570,7 +591,7 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
first_sideset_pin, sideset_pin_count, first_sideset_pin, sideset_pin_count,
initial_pin_state, initial_pin_direction, initial_pin_state, initial_pin_direction,
jmp_pin, jmp_pin,
pins_we_use, tx_fifo, rx_fifo, pins_we_use, state.tx_fifo, state.rx_fifo,
auto_pull, pull_threshold, out_shift_right, auto_pull, pull_threshold, out_shift_right,
wait_for_txstall, wait_for_txstall,
auto_push, push_threshold, in_shift_right, auto_push, push_threshold, in_shift_right,