diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9b8e47f..8e08a40 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,4 +16,5 @@ jobs: toolchain: stable - run: cargo clippy --all-targets --all-features -- -D warnings - run: cargo test --workspace + - run: cargo test --workspace -F rp2350 - run: cargo fmt -- --check diff --git a/Cargo.toml b/Cargo.toml index c566515..8ee7295 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,9 @@ repository = "https://github.com/rp-rs/pio-rs" [workspace] members = ["pio-proc", "pio-parser"] +[features] +rp2350 = ["pio-proc/rp2350", "pio-parser/rp2350"] + [dependencies] arrayvec = { version = "0.7", default-features = false } paste = "1.0" diff --git a/pio-parser/Cargo.toml b/pio-parser/Cargo.toml index f65fe77..7e287a4 100644 --- a/pio-parser/Cargo.toml +++ b/pio-parser/Cargo.toml @@ -8,12 +8,16 @@ description = "Raspberry Silicon PIO asm parser" license = "MIT" repository = "https://github.com/rp-rs/pio-rs" +[features] +default = ["rp2350"] +rp2350 = ["pio/rp2350"] + [dependencies] -lalrpop-util = { version = "0.19.6", features = ["lexer"] } +lalrpop-util = { version = "0.21.0", features = ["lexer"] } pio = { path = "..", version = "0.2.1" } [build-dependencies] -lalrpop = "0.19.6" +lalrpop = "0.21.0" # This is only here to work around https://github.com/lalrpop/lalrpop/issues/750 # It should be removed once that workaround is no longer needed. regex-syntax = { version = "0.6", default-features = false, features = ["unicode"] } diff --git a/pio-parser/build.rs b/pio-parser/build.rs index ca5c283..578b82a 100644 --- a/pio-parser/build.rs +++ b/pio-parser/build.rs @@ -1,3 +1,12 @@ fn main() { - lalrpop::process_root().unwrap(); + #[cfg(not(feature = "rp2350"))] + lalrpop::Configuration::new() + .set_out_dir(std::env::var("OUT_DIR").unwrap()) + .process_file("src/rp2040.lalrpop") + .unwrap(); + #[cfg(feature = "rp2350")] + lalrpop::Configuration::new() + .set_out_dir(std::env::var("OUT_DIR").unwrap()) + .process_file("src/rp2350.lalrpop") + .unwrap(); } diff --git a/pio-parser/src/lib.rs b/pio-parser/src/lib.rs index b8e2ffb..ac09bdd 100644 --- a/pio-parser/src/lib.rs +++ b/pio-parser/src/lib.rs @@ -8,12 +8,18 @@ use pio::{ MovSource, OutDestination, ProgramWithDefines, SetDestination, WaitSource, }; +#[cfg(feature = "rp2350")] +use pio::MovRxIndex; + use std::collections::HashMap; mod parser { #![allow(clippy::all)] #![allow(unused)] - include!(concat!(env!("OUT_DIR"), "/pio.rs")); + #[cfg(not(feature = "rp2350"))] + include!(concat!(env!("OUT_DIR"), "/src/rp2040.rs")); + #[cfg(feature = "rp2350")] + include!(concat!(env!("OUT_DIR"), "/src/rp2350.rs")); } #[derive(Debug)] @@ -86,6 +92,92 @@ impl<'i> ParsedInstruction<'i> { } } +#[derive(Clone, Copy, Debug)] +pub(crate) enum ParsedMovDestination { + PINS, + X, + Y, + #[cfg(feature = "rp2350")] + PINDIRS, + EXEC, + PC, + ISR, + OSR, + RXFIFOY, + RXFIFO0, + RXFIFO1, + RXFIFO2, + RXFIFO3, +} + +#[derive(Debug)] +enum MovDestInternal { + Mov(MovDestination), + Fifo(MovRxIndex), +} + +impl From for MovDestInternal { + fn from(value: ParsedMovDestination) -> Self { + match value { + ParsedMovDestination::PINS => MovDestInternal::Mov(MovDestination::PINS), + ParsedMovDestination::X => MovDestInternal::Mov(MovDestination::X), + ParsedMovDestination::Y => MovDestInternal::Mov(MovDestination::Y), + #[cfg(feature = "rp2350")] + ParsedMovDestination::PINDIRS => MovDestInternal::Mov(MovDestination::PINDIRS), + ParsedMovDestination::EXEC => MovDestInternal::Mov(MovDestination::EXEC), + ParsedMovDestination::PC => MovDestInternal::Mov(MovDestination::PC), + ParsedMovDestination::ISR => MovDestInternal::Mov(MovDestination::ISR), + ParsedMovDestination::OSR => MovDestInternal::Mov(MovDestination::OSR), + ParsedMovDestination::RXFIFOY => MovDestInternal::Fifo(MovRxIndex::RXFIFOY), + ParsedMovDestination::RXFIFO0 => MovDestInternal::Fifo(MovRxIndex::RXFIFO0), + ParsedMovDestination::RXFIFO1 => MovDestInternal::Fifo(MovRxIndex::RXFIFO1), + ParsedMovDestination::RXFIFO2 => MovDestInternal::Fifo(MovRxIndex::RXFIFO2), + ParsedMovDestination::RXFIFO3 => MovDestInternal::Fifo(MovRxIndex::RXFIFO3), + } + } +} + +#[derive(Clone, Copy, Debug)] +pub(crate) enum ParsedMovSource { + PINS, + X, + Y, + NULL, + STATUS, + ISR, + OSR, + RXFIFOY, + RXFIFO0, + RXFIFO1, + RXFIFO2, + RXFIFO3, +} + +#[derive(Debug)] +enum MovSrcInternal { + Mov(MovSource), + Fifo(MovRxIndex), +} + +impl From for MovSrcInternal { + fn from(value: ParsedMovSource) -> Self { + match value { + ParsedMovSource::PINS => MovSrcInternal::Mov(MovSource::PINS), + ParsedMovSource::X => MovSrcInternal::Mov(MovSource::X), + ParsedMovSource::Y => MovSrcInternal::Mov(MovSource::Y), + ParsedMovSource::NULL => MovSrcInternal::Mov(MovSource::NULL), + ParsedMovSource::STATUS => MovSrcInternal::Mov(MovSource::STATUS), + ParsedMovSource::ISR => MovSrcInternal::Mov(MovSource::ISR), + ParsedMovSource::OSR => MovSrcInternal::Mov(MovSource::OSR), + ParsedMovSource::RXFIFOY => MovSrcInternal::Fifo(MovRxIndex::RXFIFOY), + ParsedMovSource::RXFIFO0 => MovSrcInternal::Fifo(MovRxIndex::RXFIFO0), + ParsedMovSource::RXFIFO1 => MovSrcInternal::Fifo(MovRxIndex::RXFIFO1), + ParsedMovSource::RXFIFO2 => MovSrcInternal::Fifo(MovRxIndex::RXFIFO2), + ParsedMovSource::RXFIFO3 => MovSrcInternal::Fifo(MovRxIndex::RXFIFO3), + } + } +} + #[derive(Debug)] pub(crate) enum ParsedOperands<'input> { JMP { @@ -115,9 +207,9 @@ pub(crate) enum ParsedOperands<'input> { block: bool, }, MOV { - destination: MovDestination, + destination: ParsedMovDestination, op: MovOperation, - source: MovSource, + source: ParsedMovSource, }, IRQ { clear: bool, @@ -172,11 +264,24 @@ impl<'i> ParsedOperands<'i> { destination, op, source, - } => InstructionOperands::MOV { - destination: *destination, - op: *op, - source: *source, - }, + } => { + let source_internal = (*source).into(); + let dest_internal = (*destination).into(); + match (source_internal, dest_internal) { + (MovSrcInternal::Mov(MovSource::ISR), MovDestInternal::Fifo(index)) => { + InstructionOperands::MOVTORX { index } + } + (MovSrcInternal::Fifo(index), MovDestInternal::Mov(MovDestination::OSR)) => { + InstructionOperands::MOVTORX { index } + } + (MovSrcInternal::Mov(s), MovDestInternal::Mov(d)) => InstructionOperands::MOV { + destination: d, + op: *op, + source: s, + }, + (d, s) => panic!("Illegal Mov src/dest combination: {:?} {:?}", d, s), + } + } ParsedOperands::IRQ { clear, wait, @@ -426,6 +531,42 @@ fn test() { ); } +#[test] +#[cfg(feature = "rp2350")] +fn test_rp2350() { + let p = Parser::<32>::parse_program( + " + label: + mov osr, rxfifo0 + mov rxfifo1, isr + mov pins, isr + mov osr, x + jmp label + ", + ) + .unwrap(); + + assert_eq!( + &p.program.code[..], + &[ + // LABEL: + 0b100_00000_1001_1_000, // MOV OSR, RXFIFO0 + 0b100_00000_0001_1_001, // MOV RXFIFO1, ISR + 0b101_00000_000_00_110, // MOV PINS, ISR + 0b101_00000_111_00_001, // MOV OSR, X + 0b000_00000_000_00000, // JMP LABEL + ] + ); + assert_eq!(p.program.origin, None); + assert_eq!( + p.program.wrap, + pio::Wrap { + source: 4, + target: 0, + } + ); +} + #[test] fn test_side_set() { let p = Parser::<32>::parse_program( diff --git a/pio-parser/src/pio.lalrpop b/pio-parser/src/rp2040.lalrpop similarity index 100% rename from pio-parser/src/pio.lalrpop rename to pio-parser/src/rp2040.lalrpop diff --git a/pio-parser/src/rp2350.lalrpop b/pio-parser/src/rp2350.lalrpop new file mode 100644 index 0000000..66b1f67 --- /dev/null +++ b/pio-parser/src/rp2350.lalrpop @@ -0,0 +1,334 @@ +// https://github.com/raspberrypi/pico-sdk/blob/master/tools/pioasm/parser.yy + +use std::str::FromStr; +use ::pio::{ + JmpCondition, + WaitSource, + InSource, + OutDestination, + MovDestination, + MovOperation, + MovSource, + SetDestination, +}; +use crate::{ + Line, + Value, + ParsedDirective, + ParsedInstruction, + ParsedOperands, + ParsedMovSource, + ParsedMovDestination, +}; + +grammar(); + +match { + r"[\t\f\v ]" => {}, // ignore whitespace + r"(\r?\n)?(;|//)[^\n\r]*" => {}, // ignore `;` and `//` comments + r"\r?\n" => NEWLINE, + r"% c-sdk \{[^%]*%}" => {}, // ignore `% c-sdk { ... }` + r"\.lang_opt [^\n\r]*" => LANG_OPT, // lex `.lang_opt` directives + + // As per the rp2040 datasheet, + // "instruction names, keywords and directives are case insensitive" + r"(?i)nop" => "nop", + r"(?i)jmp" => "jmp", + r"(?i)wait" => "wait", + r"(?i)in" => "in", + r"(?i)out" => "out", + r"(?i)push" => "push", + r"(?i)pull" => "pull", + r"(?i)mov" => "mov", + r"(?i)irq" => "irq", + r"(?i)set" => "set", + r"(?i)x" => "x", + r"(?i)y" => "y", + r"(?i)pins" => "pins", + r"(?i)pin" => "pin", + r"(?i)gpio" => "gpio", + r"(?i)null" => "null", + r"(?i)isr" => "isr", + r"(?i)osr" => "osr", + r"(?i)pc" => "pc", + r"(?i)exec" => "exec", + r"(?i)pindirs" => "pindirs", + r"(?i)block" => "block", + r"(?i)noblock" => "noblock", + r"(?i)status" => "status", + r"(?i)nowait" => "nowait", + r"(?i)clear" => "clear", + r"(?i)public" => "public", + r"(?i)IfFull" => "iffull", + r"(?i)IfEmpty" => "ifempty", + r"(?i)side" => "side", + r"(?i)osre" => "osre", + r"(?i)\.define" => ".define", + r"(?i)\.program" => ".program", + r"(?i)\.origin" => ".origin", + r"(?i)\.side_set" => ".side_set", + r"(?i)\.wrap_target" => ".wrap_target", + r"(?i)\.wrap" => ".wrap", + r"(?i)\.lang_opt" => ".lang_opt", + r"(?i)\.word" => ".word", +} else { + _ +} + +// for parsing a .pio file +pub(crate) File = NEWLINE* <(DefineDirective NEWLINE+)*> ; + +ProgramWithDirective = ".program" NEWLINE ; + +// for parsing macro input +pub(crate) Program = NEWLINE* ; + +Line: Line<'input> = { + NEWLINE+ => Line::Directive(d), + ":" NEWLINE+ => Line::Label { + public: p.is_some(), + name: s, + }, + NEWLINE+ => Line::Instruction(i), +}; + +Directive: ParsedDirective<'input> = { + DefineDirective, + ".origin" => ParsedDirective::Origin(v), + ".side_set" => ParsedDirective::SideSet { + value: v, + opt: o.is_some(), + pindirs: p.is_some(), + }, + ".wrap_target" => ParsedDirective::WrapTarget, + ".wrap" => ParsedDirective::Wrap, + => ParsedDirective::LangOpt(l), +}; + +DefineDirective: ParsedDirective<'input> = ".define" => ParsedDirective::Define { + public: p.is_some(), + name: s, + value: e, +}; + +Instruction: ParsedInstruction<'input> = { + => ParsedInstruction { + operands: o, + side_set: Some(s), + delay: d, + }, + => ParsedInstruction { + operands: o, + side_set: Some(s), + delay: d, + }, + => ParsedInstruction { + operands: o, + side_set: Some(s), + delay: Value::I32(0), + }, + => ParsedInstruction { + operands: o, + side_set: None, + delay: d, + }, + => ParsedInstruction { + operands: o, + side_set: None, + delay: Value::I32(0), + }, +}; + +BaseInstruction: ParsedOperands<'input> = { + "nop" => ParsedOperands::MOV { + destination: ParsedMovDestination::Y, + op: MovOperation::None, + source: ParsedMovSource::Y, + }, + "jmp" ","? => ParsedOperands::JMP { + condition: match c { + Some(c) => c, + None => JmpCondition::Always, + }, + address: e, + }, + "wait" ","? => ParsedOperands::WAIT { + polarity: p, + source: s, + index: i, + relative: r.is_some(), + }, + "in" ","? => ParsedOperands::IN { + source: s, + bit_count: b, + }, + "out" ","? => ParsedOperands::OUT { + destination: d, + bit_count: b, + }, + "push" => ParsedOperands::PUSH { + if_full: i.is_some(), + block: match b { + Some(b) => b, + None => true, + }, + }, + "pull" => ParsedOperands::PULL { + if_empty: i.is_some(), + block: match b { + Some(b) => b, + None => true, + }, + }, + "mov" ","? => ParsedOperands::MOV { + destination: d, + op: match o { + Some(o) => o, + None => MovOperation::None, + }, + source: s, + }, + "irq" => ParsedOperands::IRQ { + clear: match m { + Some(m) => m.0, + None => false, + }, + wait: match m { + Some(m) => m.1, + None => false, + }, + index: v, + relative: r.is_some(), + }, + "set" ","? => ParsedOperands::SET { + destination: d, + data: v, + }, +}; + +JmpCondition: JmpCondition = { + "!" "x" => JmpCondition::XIsZero, + "x" "--" => JmpCondition::XDecNonZero, + "!" "y" => JmpCondition::YIsZero, + "y" "--" => JmpCondition::YDecNonZero, + "x" "!=" "y" => JmpCondition::XNotEqualY, + "pin" => JmpCondition::PinHigh, + "!" "osre" => JmpCondition::OutputShiftRegisterNotEmpty, +}; + +WaitSource: WaitSource = { + "gpio" => WaitSource::GPIO, + "pin" => WaitSource::PIN, + "irq" => WaitSource::IRQ, +}; + +InSource: InSource = { + "pins" => InSource::PINS, + "x" => InSource::X, + "y" => InSource::Y, + "null" => InSource::NULL, + "isr" => InSource::ISR, + "osr" => InSource::OSR, +}; + +OutDestination: OutDestination = { + "pins" => OutDestination::PINS, + "x" => OutDestination::X, + "y" => OutDestination::Y, + "null" => OutDestination::NULL, + "pindirs" => OutDestination::PINDIRS, + "pc" => OutDestination::PC, + "isr" => OutDestination::ISR, + "exec" => OutDestination::EXEC, +}; + +ShouldBlock: bool = { + "block" => true, + "noblock" => false, +}; + +ParsedMovDestination: ParsedMovDestination = { + "pins" => ParsedMovDestination::PINS, + "x" => ParsedMovDestination::X, + "y" => ParsedMovDestination::Y, + "pindirs" => ParsedMovDestination::PINDIRS, + "exec" => ParsedMovDestination::EXEC, + "pc" => ParsedMovDestination::PC, + "isr" => ParsedMovDestination::ISR, + "osr" => ParsedMovDestination::OSR, + "rxfifoy" => ParsedMovDestination::RXFIFOY, + "rxfifo0" => ParsedMovDestination::RXFIFO0, + "rxfifo1" => ParsedMovDestination::RXFIFO1, + "rxfifo2" => ParsedMovDestination::RXFIFO2, + "rxfifo3" => ParsedMovDestination::RXFIFO3, +}; + +MovOperation: MovOperation = { + "!" => MovOperation::Invert, + "~" => MovOperation::Invert, + "::" => MovOperation::BitReverse, +}; + +ParsedMovSource: ParsedMovSource = { + "pins" => ParsedMovSource::PINS, + "x" => ParsedMovSource::X, + "y" => ParsedMovSource::Y, + "null" => ParsedMovSource::NULL, + "status" => ParsedMovSource::STATUS, + "isr" => ParsedMovSource::ISR, + "osr" => ParsedMovSource::OSR, + "rxfifoy" => ParsedMovSource::RXFIFOY, + "rxfifo0" => ParsedMovSource::RXFIFO0, + "rxfifo1" => ParsedMovSource::RXFIFO1, + "rxfifo2" => ParsedMovSource::RXFIFO2, + "rxfifo3" => ParsedMovSource::RXFIFO3, +}; + +IrqModifier: (bool, bool) = { + "set" => (false, false), + "nowait" => (false, false), + "wait" => (false, true), + "clear" => (true, false), +}; + +SetDestination: SetDestination = { + "pins" => SetDestination::PINS, + "x" => SetDestination::X, + "y" => SetDestination::Y, + "pindirs" => SetDestination::PINDIRS, +}; + +SideSet: Value<'input> = "side" => v; +Delay: Value<'input> = "[" "]" => e; + +Value: Value<'input> = { + Int, + => Value::Symbol(s), + "(" ")" => e, +}; + +Expression: Value<'input> = { + "+" => Value::Add(Box::new(a), Box::new(b)), + "-" => Value::Sub(Box::new(a), Box::new(b)), + ExprNotAdd, +}; + +ExprNotAdd: Value<'input> = { + "*" => Value::Mul(Box::new(a), Box::new(b)), + "/" => Value::Div(Box::new(a), Box::new(b)), + ExprNotMul, +}; + +ExprNotMul: Value<'input> = { + "-" => Value::Neg(Box::new(v)), + "::" => Value::Rev(Box::new(v)), + Value, +}; + +Symbol = r"(\p{ID_Start}|_)\p{ID_Continue}*"; + +Int: Value<'input> = { + => Value::I32(i32::from_str(s).unwrap()), + => Value::I32(i32::from_str_radix(&s[2..], 2).unwrap()), + => Value::I32(i32::from_str_radix(&s[2..], 16).unwrap()), +}; diff --git a/pio-proc/Cargo.toml b/pio-proc/Cargo.toml index 1cad892..b5dd59f 100644 --- a/pio-proc/Cargo.toml +++ b/pio-proc/Cargo.toml @@ -8,6 +8,9 @@ license = "MIT" repository = "https://github.com/rp-rs/pio-rs" description = "proc-macro for assembling PIO code in a Rust program at compile time" +[features] +rp2350 = ["pio-parser/rp2350"] + [lib] proc-macro = true @@ -19,7 +22,4 @@ quote = "1.0" codespan-reporting = "0.11" pio = { path = "..", version = "0.2.0" } pio-parser = { path = "../pio-parser", version = "0.2.0" } -lalrpop-util = "0.19.6" -# This is only here to work around https://github.com/lalrpop/lalrpop/issues/750 -# It should be removed once that workaround is no longer needed. -regex-syntax = { version = "0.6", default-features = false, features = ["unicode"] } +lalrpop-util = "0.21.0" diff --git a/pio-proc/src/lib.rs b/pio-proc/src/lib.rs index 327469d..4895a56 100644 --- a/pio-proc/src/lib.rs +++ b/pio-proc/src/lib.rs @@ -402,7 +402,7 @@ fn parse_error(error: &pio_parser::ParseError, program_source: &str) -> proc_mac ParseError::InvalidToken { location } => { (*location..*location, vec!["invalid token".to_string()]) } - ParseError::UnrecognizedEOF { location, expected } => ( + ParseError::UnrecognizedEof { location, expected } => ( *location..*location, vec![ "unrecognized eof".to_string(), diff --git a/src/lib.rs b/src/lib.rs index b06e260..1515090 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,7 +74,8 @@ pub enum WaitSource { GPIO = 0b00, PIN = 0b01, IRQ = 0b10, - // RESERVED = 0b11, + #[cfg(feature = "rp2350")] + JMPPIN = 0b11, } #[repr(u8)] @@ -109,7 +110,8 @@ pub enum MovDestination { PINS = 0b000, X = 0b001, Y = 0b010, - // RESERVED = 0b011, + #[cfg(feature = "rp2350")] + PINDIRS = 0b011, EXEC = 0b100, PC = 0b101, ISR = 0b110, @@ -138,6 +140,17 @@ pub enum MovSource { OSR = 0b111, } +#[repr(u8)] +#[derive(Debug, Clone, Copy, TryFromPrimitive)] +#[cfg(feature = "rp2350")] +pub enum MovRxIndex { + RXFIFOY = 0b0000, + RXFIFO0 = 0b1000, + RXFIFO1 = 0b1001, + RXFIFO2 = 0b1010, + RXFIFO3 = 0b1011, +} + #[repr(u8)] #[derive(Debug, Clone, Copy, TryFromPrimitive)] pub enum SetDestination { @@ -186,10 +199,19 @@ pub enum InstructionOperands { op: MovOperation, source: MovSource, }, + #[cfg(feature = "rp2350")] + MOVTORX { + index: MovRxIndex, + }, + #[cfg(feature = "rp2350")] + MOVFROMRX { + index: MovRxIndex, + }, IRQ { clear: bool, wait: bool, index: u8, + // TODO: irq index mode, support interrupting next/prev sm relative: bool, }, SET { @@ -208,6 +230,10 @@ impl InstructionOperands { InstructionOperands::PUSH { .. } => 0b100, InstructionOperands::PULL { .. } => 0b100, InstructionOperands::MOV { .. } => 0b101, + #[cfg(feature = "rp2350")] + InstructionOperands::MOVTORX { .. } => 0b100, + #[cfg(feature = "rp2350")] + InstructionOperands::MOVFROMRX { .. } => 0b100, InstructionOperands::IRQ { .. } => 0b110, InstructionOperands::SET { .. } => 0b111, } @@ -259,6 +285,10 @@ impl InstructionOperands { op, source, } => (*destination as u8, (*op as u8) << 3 | (*source as u8)), + #[cfg(feature = "rp2350")] + InstructionOperands::MOVTORX { index } => (0, 1 << 4 | *index as u8), + #[cfg(feature = "rp2350")] + InstructionOperands::MOVFROMRX { index } => (0b100, 1 << 4 | *index as u8), InstructionOperands::IRQ { clear, wait, @@ -299,6 +329,7 @@ impl InstructionOperands { let discrim = instruction >> 13; let o0 = ((instruction >> 5) & 0b111) as u8; let o1 = (instruction & 0b11111) as u8; + match discrim { 0b000 => JmpCondition::try_from(o0) .ok() @@ -335,20 +366,48 @@ impl InstructionOperands { }) } 0b100 => { - let if_flag = o0 & 0b010 != 0; - let block = o0 & 0b001 != 0; - if o1 != 0 { - None - } else if o0 & 0b100 == 0 { - Some(InstructionOperands::PUSH { - if_full: if_flag, - block, - }) - } else { - Some(InstructionOperands::PULL { - if_empty: if_flag, - block, - }) + let p_o0 = ((instruction >> 4) & 0b1111) as u8; + + let if_flag = p_o0 & 0b0100 != 0; + let block = p_o0 & 0b0010 != 0; + + #[cfg(not(feature = "rp2350"))] + { + if p_o0 & 0b1001 == 0b1000 { + Some(InstructionOperands::PULL { + if_empty: if_flag, + block, + }) + } else if p_o0 & 0b1001 == 0b0000 { + Some(InstructionOperands::PUSH { + if_full: if_flag, + block, + }) + } else { + None + } + } + + #[cfg(feature = "rp2350")] + { + let index = MovRxIndex::try_from((instruction & 0b1111) as u8); + if p_o0 & 0b1001 == 0b1000 { + Some(InstructionOperands::PULL { + if_empty: if_flag, + block, + }) + } else if p_o0 & 0b1001 == 0b0000 { + Some(InstructionOperands::PUSH { + if_full: if_flag, + block, + }) + } else if p_o0 == 0b1001 { + Some(InstructionOperands::MOVFROMRX { index: index.ok()? }) + } else if p_o0 == 0b0001 { + Some(InstructionOperands::MOVTORX { index: index.ok()? }) + } else { + None + } } } 0b101 => match ( @@ -743,6 +802,26 @@ impl Assembler { } ); + #[cfg(feature = "rp2350")] + instr!( + /// Emit a `mov to rx` instruction. + mov_to_rx(self, index: MovRxIndex) { + InstructionOperands::MOVTORX { + index + } + } + ); + + #[cfg(feature = "rp2350")] + instr!( + /// Emit a `mov from rx` instruction. + mov_from_rx(self, index: MovRxIndex) { + InstructionOperands::MOVFROMRX { + index + } + } + ); + instr!( /// Emit an `irq` instruction using `clear` and `wait` with `index` which may be `relative`. irq(self, clear: bool, wait: bool, index: u8, relative: bool) { @@ -1035,6 +1114,18 @@ instr_test!(irq(false, true, 0b111, true), 0b110_00000_001_10111); instr_test!(set(SetDestination::Y, 10), 0b111_00000_010_01010); +#[cfg(feature = "rp2350")] +#[cfg(test)] +mod rp2350_test { + use super::*; + + instr_test!(mov_to_rx(MovRxIndex::RXFIFO3), 0b100_00000_0001_1011); + instr_test!(mov_to_rx(MovRxIndex::RXFIFOY), 0b100_00000_0001_0000); + + instr_test!(mov_from_rx(MovRxIndex::RXFIFO3), 0b100_00000_1001_1011); + instr_test!(mov_from_rx(MovRxIndex::RXFIFOY), 0b100_00000_1001_0000); +} + /// This block ensures that README.md is checked when `cargo test` is run. #[cfg(doctest)] mod test_readme {