diff --git a/Cargo.toml b/Cargo.toml index 8ee7295..c566515 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,9 +11,6 @@ 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 217d6d5..b86f448 100644 --- a/pio-parser/Cargo.toml +++ b/pio-parser/Cargo.toml @@ -8,9 +8,6 @@ description = "Raspberry Silicon PIO asm parser" license = "MIT" repository = "https://github.com/rp-rs/pio-rs" -[features] -rp2350 = ["pio/rp2350"] - [dependencies] lalrpop-util = { version = "0.21.0", features = ["lexer"] } pio = { path = "..", version = "0.2.1" } diff --git a/pio-parser/build.rs b/pio-parser/build.rs index 578b82a..ca5c283 100644 --- a/pio-parser/build.rs +++ b/pio-parser/build.rs @@ -1,12 +1,3 @@ fn main() { - #[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(); + lalrpop::process_root().unwrap(); } diff --git a/pio-parser/src/lib.rs b/pio-parser/src/lib.rs index 7557f90..d9db2e2 100644 --- a/pio-parser/src/lib.rs +++ b/pio-parser/src/lib.rs @@ -4,22 +4,17 @@ #![allow(clippy::upper_case_acronyms)] use pio::{ - InSource, Instruction, InstructionOperands, JmpCondition, MovDestination, MovOperation, - MovSource, OutDestination, ProgramWithDefines, SetDestination, WaitSource, + InSource, Instruction, InstructionOperands, IrqIndexMode, JmpCondition, MovDestination, + MovOperation, MovRxIndex, MovSource, OutDestination, ProgramWithDefines, SetDestination, + WaitSource, }; -#[cfg(feature = "rp2350")] -use pio::MovRxIndex; - use std::collections::HashMap; mod parser { #![allow(clippy::all)] #![allow(unused)] - #[cfg(not(feature = "rp2350"))] - include!(concat!(env!("OUT_DIR"), "/src/rp2040.rs")); - #[cfg(feature = "rp2350")] - include!(concat!(env!("OUT_DIR"), "/src/rp2350.rs")); + include!(concat!(env!("OUT_DIR"), "/pio.rs")); } #[derive(Debug)] @@ -97,28 +92,21 @@ pub(crate) enum ParsedMovDestination { PINS, X, Y, - #[cfg(feature = "rp2350")] PINDIRS, EXEC, PC, ISR, OSR, - #[cfg(feature = "rp2350")] RXFIFOY, - #[cfg(feature = "rp2350")] RXFIFO0, - #[cfg(feature = "rp2350")] RXFIFO1, - #[cfg(feature = "rp2350")] RXFIFO2, - #[cfg(feature = "rp2350")] RXFIFO3, } #[derive(Debug)] enum MovDestInternal { Mov(MovDestination), - #[cfg(feature = "rp2350")] Fifo(MovRxIndex), } @@ -128,21 +116,15 @@ impl From for MovDestInternal { 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), - #[cfg(feature = "rp2350")] ParsedMovDestination::RXFIFOY => MovDestInternal::Fifo(MovRxIndex::RXFIFOY), - #[cfg(feature = "rp2350")] ParsedMovDestination::RXFIFO0 => MovDestInternal::Fifo(MovRxIndex::RXFIFO0), - #[cfg(feature = "rp2350")] ParsedMovDestination::RXFIFO1 => MovDestInternal::Fifo(MovRxIndex::RXFIFO1), - #[cfg(feature = "rp2350")] ParsedMovDestination::RXFIFO2 => MovDestInternal::Fifo(MovRxIndex::RXFIFO2), - #[cfg(feature = "rp2350")] ParsedMovDestination::RXFIFO3 => MovDestInternal::Fifo(MovRxIndex::RXFIFO3), } } @@ -157,22 +139,16 @@ pub(crate) enum ParsedMovSource { STATUS, ISR, OSR, - #[cfg(feature = "rp2350")] RXFIFOY, - #[cfg(feature = "rp2350")] RXFIFO0, - #[cfg(feature = "rp2350")] RXFIFO1, - #[cfg(feature = "rp2350")] RXFIFO2, - #[cfg(feature = "rp2350")] RXFIFO3, } #[derive(Debug)] enum MovSrcInternal { Mov(MovSource), - #[cfg(feature = "rp2350")] Fifo(MovRxIndex), } @@ -186,15 +162,10 @@ impl From for MovSrcInternal { ParsedMovSource::STATUS => MovSrcInternal::Mov(MovSource::STATUS), ParsedMovSource::ISR => MovSrcInternal::Mov(MovSource::ISR), ParsedMovSource::OSR => MovSrcInternal::Mov(MovSource::OSR), - #[cfg(feature = "rp2350")] ParsedMovSource::RXFIFOY => MovSrcInternal::Fifo(MovRxIndex::RXFIFOY), - #[cfg(feature = "rp2350")] ParsedMovSource::RXFIFO0 => MovSrcInternal::Fifo(MovRxIndex::RXFIFO0), - #[cfg(feature = "rp2350")] ParsedMovSource::RXFIFO1 => MovSrcInternal::Fifo(MovRxIndex::RXFIFO1), - #[cfg(feature = "rp2350")] ParsedMovSource::RXFIFO2 => MovSrcInternal::Fifo(MovRxIndex::RXFIFO2), - #[cfg(feature = "rp2350")] ParsedMovSource::RXFIFO3 => MovSrcInternal::Fifo(MovRxIndex::RXFIFO3), } } @@ -237,7 +208,7 @@ pub(crate) enum ParsedOperands<'input> { clear: bool, wait: bool, index: Value<'input>, - relative: bool, + index_mode: IrqIndexMode, }, SET { destination: SetDestination, @@ -290,11 +261,9 @@ impl<'i> ParsedOperands<'i> { let source_internal = (*source).into(); let dest_internal = (*destination).into(); match (source_internal, dest_internal) { - #[cfg(feature = "rp2350")] (MovSrcInternal::Mov(MovSource::ISR), MovDestInternal::Fifo(index)) => { InstructionOperands::MOVTORX { index } } - #[cfg(feature = "rp2350")] (MovSrcInternal::Fifo(index), MovDestInternal::Mov(MovDestination::OSR)) => { InstructionOperands::MOVFROMRX { index } } @@ -303,7 +272,6 @@ impl<'i> ParsedOperands<'i> { op: *op, source: s, }, - #[cfg(feature = "rp2350")] (d, s) => panic!("Illegal Mov src/dest combination: {:?} {:?}", d, s), } } @@ -311,12 +279,12 @@ impl<'i> ParsedOperands<'i> { clear, wait, index, - relative, + index_mode, } => InstructionOperands::IRQ { clear: *clear, wait: *wait, index: index.reify(state) as u8, - relative: *relative, + index_mode: *index_mode, }, ParsedOperands::SET { destination, data } => InstructionOperands::SET { destination: *destination, @@ -557,7 +525,6 @@ fn test() { } #[test] -#[cfg(feature = "rp2350")] fn test_rp2350() { let p = Parser::<32>::parse_program( " diff --git a/pio-parser/src/rp2350.lalrpop b/pio-parser/src/pio.lalrpop similarity index 96% rename from pio-parser/src/rp2350.lalrpop rename to pio-parser/src/pio.lalrpop index e8ce88b..a2b0c93 100644 --- a/pio-parser/src/rp2350.lalrpop +++ b/pio-parser/src/pio.lalrpop @@ -10,6 +10,7 @@ use ::pio::{ MovOperation, MovSource, SetDestination, + IrqIndexMode, }; use crate::{ Line, @@ -188,7 +189,7 @@ BaseInstruction: ParsedOperands<'input> = { }, source: s, }, - "irq" => ParsedOperands::IRQ { + "irq" => ParsedOperands::IRQ { clear: match m { Some(m) => m.0, None => false, @@ -198,7 +199,10 @@ BaseInstruction: ParsedOperands<'input> = { None => false, }, index: v, - relative: r.is_some(), + index_mode: match r { + Some(m) => m, + None => IrqIndexMode::DIRECT + } }, "set" ","? => ParsedOperands::SET { destination: d, @@ -291,6 +295,12 @@ IrqModifier: (bool, bool) = { "clear" => (true, false), }; +IrqIndexMode: IrqIndexMode = { + "prev" => IrqIndexMode::PREV, + "rel" => IrqIndexMode::REL, + "next" => IrqIndexMode::NEXT, +} + SetDestination: SetDestination = { "pins" => SetDestination::PINS, "x" => SetDestination::X, diff --git a/pio-parser/src/rp2040.lalrpop b/pio-parser/src/rp2040.lalrpop deleted file mode 100644 index 368224a..0000000 --- a/pio-parser/src/rp2040.lalrpop +++ /dev/null @@ -1,321 +0,0 @@ -// https://github.com/raspberrypi/pico-sdk/blob/master/tools/pioasm/parser.yy - -use std::str::FromStr; -use ::pio::{ - JmpCondition, - WaitSource, - InSource, - OutDestination, - MovOperation, - SetDestination, -}; -use crate::{ - Line, - Value, - ParsedDirective, - ParsedInstruction, - ParsedOperands, - ParsedMovDestination, - ParsedMovSource, -}; - -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, - "exec" => ParsedMovDestination::EXEC, - "pc" => ParsedMovDestination::PC, - "isr" => ParsedMovDestination::ISR, - "osr" => ParsedMovDestination::OSR, -}; - -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, -}; - -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 b5dd59f..4a3b02b 100644 --- a/pio-proc/Cargo.toml +++ b/pio-proc/Cargo.toml @@ -8,9 +8,6 @@ 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 diff --git a/pio-proc/src/lib.rs b/pio-proc/src/lib.rs index 4895a56..219155e 100644 --- a/pio-proc/src/lib.rs +++ b/pio-proc/src/lib.rs @@ -349,6 +349,9 @@ fn to_codegen( ) .parse() .unwrap(); + let version: proc_macro2::TokenStream = format!("::pio::PioVersion::{:?}", program.version) + .parse() + .unwrap(); let defines_struct: proc_macro2::TokenStream = format!( " struct ExpandedDefines {{ @@ -387,6 +390,7 @@ fn to_codegen( origin: #origin, wrap: #wrap, side_set: #side_set, + version: #version, }, public_defines: #defines_init, } diff --git a/src/lib.rs b/src/lib.rs index 1515090..8c20cca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,13 +42,23 @@ pub use arrayvec::ArrayVec; use core::convert::TryFrom; use num_enum::TryFromPrimitive; -/// Maximum program size of RP2040 chip, in bytes. +/// Maximum program size of RP2040 and RP235x chips, in bytes. /// /// See Chapter 3, Figure 38 for reference of the value. pub const RP2040_MAX_PROGRAM_SIZE: usize = 32; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +/// PIO version +pub enum PioVersion { + /// Pio programs compatable with the RP2040 + V0, + /// Pio programs compatable with both the RP2040 and RP235x + V1, +} + #[repr(u8)] -#[derive(Debug, Clone, Copy, TryFromPrimitive)] +#[derive(Debug, Clone, Copy, TryFromPrimitive, PartialEq, Eq)] pub enum JmpCondition { /// Always Always = 0b000, @@ -74,12 +84,11 @@ pub enum WaitSource { GPIO = 0b00, PIN = 0b01, IRQ = 0b10, - #[cfg(feature = "rp2350")] JMPPIN = 0b11, } #[repr(u8)] -#[derive(Debug, Clone, Copy, TryFromPrimitive)] +#[derive(Debug, Clone, Copy, TryFromPrimitive, PartialEq, Eq)] pub enum InSource { PINS = 0b000, X = 0b001, @@ -92,7 +101,7 @@ pub enum InSource { } #[repr(u8)] -#[derive(Debug, Clone, Copy, TryFromPrimitive)] +#[derive(Debug, Clone, Copy, TryFromPrimitive, PartialEq, Eq)] pub enum OutDestination { PINS = 0b000, X = 0b001, @@ -105,12 +114,11 @@ pub enum OutDestination { } #[repr(u8)] -#[derive(Debug, Clone, Copy, TryFromPrimitive)] +#[derive(Debug, Clone, Copy, TryFromPrimitive, PartialEq, Eq)] pub enum MovDestination { PINS = 0b000, X = 0b001, Y = 0b010, - #[cfg(feature = "rp2350")] PINDIRS = 0b011, EXEC = 0b100, PC = 0b101, @@ -119,7 +127,7 @@ pub enum MovDestination { } #[repr(u8)] -#[derive(Debug, Clone, Copy, TryFromPrimitive)] +#[derive(Debug, Clone, Copy, TryFromPrimitive, PartialEq, Eq)] pub enum MovOperation { None = 0b00, Invert = 0b01, @@ -128,7 +136,7 @@ pub enum MovOperation { } #[repr(u8)] -#[derive(Debug, Clone, Copy, TryFromPrimitive)] +#[derive(Debug, Clone, Copy, TryFromPrimitive, PartialEq, Eq)] pub enum MovSource { PINS = 0b000, X = 0b001, @@ -141,8 +149,7 @@ pub enum MovSource { } #[repr(u8)] -#[derive(Debug, Clone, Copy, TryFromPrimitive)] -#[cfg(feature = "rp2350")] +#[derive(Debug, Clone, Copy, TryFromPrimitive, PartialEq, Eq)] pub enum MovRxIndex { RXFIFOY = 0b0000, RXFIFO0 = 0b1000, @@ -152,7 +159,7 @@ pub enum MovRxIndex { } #[repr(u8)] -#[derive(Debug, Clone, Copy, TryFromPrimitive)] +#[derive(Debug, Clone, Copy, TryFromPrimitive, PartialEq, Eq)] pub enum SetDestination { PINS = 0b000, X = 0b001, @@ -164,6 +171,15 @@ pub enum SetDestination { // RESERVED = 0b111, } +#[repr(u8)] +#[derive(Debug, Clone, Copy, TryFromPrimitive, PartialEq, Eq)] +pub enum IrqIndexMode { + DIRECT = 0b00, + PREV = 0b01, + REL = 0b10, + NEXT = 0b11, +} + #[derive(Debug, Clone, Copy)] pub enum InstructionOperands { JMP { @@ -199,11 +215,9 @@ pub enum InstructionOperands { op: MovOperation, source: MovSource, }, - #[cfg(feature = "rp2350")] MOVTORX { index: MovRxIndex, }, - #[cfg(feature = "rp2350")] MOVFROMRX { index: MovRxIndex, }, @@ -211,8 +225,7 @@ pub enum InstructionOperands { clear: bool, wait: bool, index: u8, - // TODO: irq index mode, support interrupting next/prev sm - relative: bool, + index_mode: IrqIndexMode, }, SET { destination: SetDestination, @@ -230,9 +243,7 @@ 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, @@ -285,24 +296,17 @@ 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, index, - relative, - } => { - if *index > 7 { - panic!("invalid interrupt flags"); - } - ( - (*clear as u8) << 1 | (*wait as u8), - *index | (if *relative { 0b10000 } else { 0 }), - ) - } + index_mode, + } => ( + (*clear as u8) << 1 | (*wait as u8), + *index | (*index_mode as u8) << 3, + ), InstructionOperands::SET { destination, data } => { if *data > 0x1f { panic!("SET argument out of range"); @@ -371,43 +375,23 @@ impl InstructionOperands { 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 - } + 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 ( @@ -424,11 +408,12 @@ impl InstructionOperands { }, 0b110 => { if o0 & 0b100 == 0 { + let index_mode = IrqIndexMode::try_from((o1 >> 3) & 0b11); Some(InstructionOperands::IRQ { clear: o0 & 0b010 != 0, wait: o0 & 0b001 != 0, - index: o1 & 0b01111, - relative: o1 & 0b10000 != 0, + index: o1 & 0b00111, + index_mode: index_mode.ok()?, }) } else { None @@ -618,6 +603,35 @@ impl Assembler { .collect() } + /// Check the program for instructions and operands available only on the RP2350. + pub fn version(&self) -> PioVersion { + for instr in &self.instructions { + let opr = instr.operands; + match opr { + InstructionOperands::MOVFROMRX { .. } => return PioVersion::V1, + InstructionOperands::MOVTORX { .. } => return PioVersion::V1, + InstructionOperands::MOV { destination, .. } => { + if destination == MovDestination::PINDIRS { + return PioVersion::V1; + } + } + InstructionOperands::WAIT { source, .. } => { + if source == WaitSource::JMPPIN { + return PioVersion::V1; + } + } + InstructionOperands::IRQ { index_mode, .. } => { + if index_mode == IrqIndexMode::PREV || index_mode == IrqIndexMode::NEXT { + return PioVersion::V1; + } + } + _ => (), + } + } + + PioVersion::V0 + } + /// Assemble the program into [`Program`]. /// /// The program contains the instructions and side-set info set. You can directly compile into a program with @@ -625,6 +639,7 @@ impl Assembler { /// [`Program::set_wrap`]. pub fn assemble_program(self) -> Program { let side_set = self.side_set; + let version = self.version(); let code = self.assemble(); let wrap = Wrap { source: (code.len() - 1) as u8, @@ -636,6 +651,7 @@ impl Assembler { origin: None, side_set, wrap, + version, } } @@ -802,7 +818,6 @@ impl Assembler { } ); - #[cfg(feature = "rp2350")] instr!( /// Emit a `mov to rx` instruction. mov_to_rx(self, index: MovRxIndex) { @@ -812,7 +827,6 @@ impl Assembler { } ); - #[cfg(feature = "rp2350")] instr!( /// Emit a `mov from rx` instruction. mov_from_rx(self, index: MovRxIndex) { @@ -824,12 +838,12 @@ impl Assembler { 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) { + irq(self, clear: bool, wait: bool, index: u8, index_mode: IrqIndexMode) { InstructionOperands::IRQ { clear, wait, index, - relative, + index_mode } } ); @@ -891,6 +905,8 @@ pub struct Program { pub wrap: Wrap, /// Side-set info for this program. pub side_set: SideSet, + /// Pio Version required for this program. + pub version: PioVersion, } impl Program { @@ -1005,7 +1021,7 @@ fn test_assemble_program_default_wrap() { } macro_rules! instr_test { - ($name:ident ( $( $v:expr ),* ) , $expected:expr, $side_set:expr) => { + ($name:ident ( $( $v:expr ),* ) , $expected:expr, $side_set:expr, $version:expr) => { paste::paste! { #[test] fn [< test _ $name _ $expected >]() { @@ -1015,6 +1031,9 @@ macro_rules! instr_test { a.$name( $( $v ),* ); + + assert_eq!(a.version(), $version); + let instr = a.assemble()[0]; if instr != expected { panic!("assertion failure: (left == right)\nleft: {:#016b}\nright: {:#016b}", instr, expected); @@ -1029,24 +1048,42 @@ macro_rules! instr_test { } }; - ($name:ident ( $( $v:expr ),* ) , $b:expr) => { - instr_test!( $name ( $( $v ),* ), $b, SideSet::new(false, 0, false) ); + ($name:ident ( $( $v:expr ),* ) , $b:expr, $version:expr) => { + instr_test!( $name ( $( $v ),* ), $b, SideSet::new(false, 0, false), $version); }; } -instr_test!(wait(0, WaitSource::IRQ, 2, false), 0b001_00000_010_00010); -instr_test!(wait(1, WaitSource::IRQ, 7, false), 0b001_00000_110_00111); -instr_test!(wait(1, WaitSource::GPIO, 16, false), 0b001_00000_100_10000); +instr_test!( + wait(0, WaitSource::IRQ, 2, false), + 0b001_00000_010_00010, + PioVersion::V0 +); +instr_test!( + wait(1, WaitSource::IRQ, 7, false), + 0b001_00000_110_00111, + PioVersion::V0 +); +instr_test!( + wait(1, WaitSource::GPIO, 16, false), + 0b001_00000_100_10000, + PioVersion::V0 +); instr_test!( wait_with_delay(0, WaitSource::IRQ, 2, false, 30), - 0b001_11110_010_00010 + 0b001_11110_010_00010, + PioVersion::V0 ); instr_test!( wait_with_side_set(0, WaitSource::IRQ, 2, false, 0b10101), 0b001_10101_010_00010, - SideSet::new(false, 5, false) + SideSet::new(false, 5, false), + PioVersion::V0 +); +instr_test!( + wait(0, WaitSource::IRQ, 2, true), + 0b001_00000_010_10010, + PioVersion::V0 ); -instr_test!(wait(0, WaitSource::IRQ, 2, true), 0b001_00000_010_10010); #[test] #[should_panic] @@ -1056,11 +1093,19 @@ fn test_wait_relative_not_used_on_irq() { a.assemble_program(); } -instr_test!(r#in(InSource::Y, 10), 0b010_00000_010_01010); -instr_test!(r#in(InSource::Y, 32), 0b010_00000_010_00000); +instr_test!(r#in(InSource::Y, 10), 0b010_00000_010_01010, PioVersion::V0); +instr_test!(r#in(InSource::Y, 32), 0b010_00000_010_00000, PioVersion::V0); -instr_test!(out(OutDestination::Y, 10), 0b011_00000_010_01010); -instr_test!(out(OutDestination::Y, 32), 0b011_00000_010_00000); +instr_test!( + out(OutDestination::Y, 10), + 0b011_00000_010_01010, + PioVersion::V0 +); +instr_test!( + out(OutDestination::Y, 32), + 0b011_00000_010_00000, + PioVersion::V0 +); #[test] #[should_panic(expected = "bit_count must be from 1 to 32")] @@ -1094,11 +1139,11 @@ fn test_out_bit_width_exceeds_max_should_panic() { a.assemble_program(); } -instr_test!(push(true, false), 0b100_00000_010_00000); -instr_test!(push(false, true), 0b100_00000_001_00000); +instr_test!(push(true, false), 0b100_00000_010_00000, PioVersion::V0); +instr_test!(push(false, true), 0b100_00000_001_00000, PioVersion::V0); -instr_test!(pull(true, false), 0b100_00000_110_00000); -instr_test!(pull(false, true), 0b100_00000_101_00000); +instr_test!(pull(true, false), 0b100_00000_110_00000, PioVersion::V0); +instr_test!(pull(false, true), 0b100_00000_101_00000, PioVersion::V0); instr_test!( mov( @@ -1106,25 +1151,70 @@ instr_test!( MovOperation::BitReverse, MovSource::STATUS ), - 0b101_00000_010_10101 + 0b101_00000_010_10101, + PioVersion::V0 ); -instr_test!(irq(true, false, 0b11, false), 0b110_00000_010_00011); -instr_test!(irq(false, true, 0b111, true), 0b110_00000_001_10111); +instr_test!( + irq(true, false, 0b11, IrqIndexMode::DIRECT), + 0b110_00000_010_00_011, + PioVersion::V0 +); +instr_test!( + irq(false, true, 0b111, IrqIndexMode::REL), + 0b110_00000_001_10_111, + PioVersion::V0 +); +instr_test!( + irq(true, false, 0b1, IrqIndexMode::PREV), + 0b110_00000_010_01_001, + PioVersion::V1 +); +instr_test!( + irq(false, true, 0b101, IrqIndexMode::NEXT), + 0b110_00000_001_11_101, + PioVersion::V1 +); + +instr_test!( + set(SetDestination::Y, 10), + 0b111_00000_010_01010, + PioVersion::V0 +); -instr_test!(set(SetDestination::Y, 10), 0b111_00000_010_01010); +instr_test!( + mov(MovDestination::PINDIRS, MovOperation::None, MovSource::X), + 0b101_00000_0110_0001, + PioVersion::V1 +); -#[cfg(feature = "rp2350")] -#[cfg(test)] -mod rp2350_test { - use super::*; +instr_test!( + wait(0, WaitSource::JMPPIN, 0, false), + 0b001_00000_0110_0000, + PioVersion::V1 +); - 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_to_rx(MovRxIndex::RXFIFO3), + 0b100_00000_0001_1011, + PioVersion::V1 +); +instr_test!( + mov_to_rx(MovRxIndex::RXFIFOY), + 0b100_00000_0001_0000, + PioVersion::V1 +); - instr_test!(mov_from_rx(MovRxIndex::RXFIFO3), 0b100_00000_1001_1011); - instr_test!(mov_from_rx(MovRxIndex::RXFIFOY), 0b100_00000_1001_0000); -} +instr_test!( + mov_from_rx(MovRxIndex::RXFIFO3), + 0b100_00000_1001_1011, + PioVersion::V1 +); +instr_test!( + mov_from_rx(MovRxIndex::RXFIFOY), + 0b100_00000_1001_0000, + PioVersion::V1 +); /// This block ensures that README.md is checked when `cargo test` is run. #[cfg(doctest)]