From 330cd0a335f64417755f6e07566e5c0456dd7662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Vi=C3=B6l?= Date: Sun, 20 Dec 2020 22:56:27 +0100 Subject: [PATCH 1/5] Merge I128/Ixx and U128/Uxx variants --- decoder/src/lib.rs | 70 ++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/decoder/src/lib.rs b/decoder/src/lib.rs index 8f38fd393..076f2d3aa 100644 --- a/decoder/src/lib.rs +++ b/decoder/src/lib.rs @@ -332,11 +332,9 @@ enum Arg<'t> { Bool(Arc), F32(f32), /// U8, U16, U24 and U32 - Uxx(u64), - U128(u128), + Uxx(u128), /// I8, I16, I24 and I32 - Ixx(i64), - I128(i128), + Ixx(i128), /// Str Str(String), /// Interned string @@ -697,7 +695,7 @@ impl<'t, 'b> Decoder<'t, 'b> { match ¶m.ty { Type::U8 => { let data = self.bytes.read_u8()?; - args.push(Arg::Uxx(data as u64)); + args.push(Arg::Uxx(data as u128)); } Type::Bool => { @@ -739,61 +737,61 @@ impl<'t, 'b> Decoder<'t, 'b> { } Type::I16 => { let data = self.bytes.read_i16::()?; - args.push(Arg::Ixx(data as i64)); + args.push(Arg::Ixx(data as i128)); } Type::I32 => { let data = self.bytes.read_i32::()?; - args.push(Arg::Ixx(data as i64)); + args.push(Arg::Ixx(data as i128)); } Type::I64 => { let data = self.bytes.read_i64::()?; - args.push(Arg::Ixx(data as i64)); + args.push(Arg::Ixx(data as i128)); } Type::I128 => { let data = self.bytes.read_i128::()?; - args.push(Arg::I128(data)); + args.push(Arg::Ixx(data)); } Type::I8 => { let data = self.bytes.read_i8()?; - args.push(Arg::Ixx(data as i64)); + args.push(Arg::Ixx(data as i128)); } Type::Isize => { // Signed isize is encoded in zigzag-encoding. let unsigned = read_leb128(&mut self.bytes)?; - args.push(Arg::Ixx(zigzag_decode(unsigned))) + args.push(Arg::Ixx(zigzag_decode(unsigned) as i128)) } Type::U16 => { let data = self.bytes.read_u16::()?; - args.push(Arg::Uxx(data as u64)); + args.push(Arg::Uxx(data as u128)); } Type::U24 => { let data_low = self.bytes.read_u8()?; let data_high = self.bytes.read_u16::()?; - let data = data_low as u64 | (data_high as u64) << 8; - args.push(Arg::Uxx(data as u64)); + let data = data_low as u128 | (data_high as u128) << 8; + args.push(Arg::Uxx(data as u128)); } Type::U32 => { let data = self.bytes.read_u32::()?; - args.push(Arg::Uxx(data as u64)); + args.push(Arg::Uxx(data as u128)); } Type::U64 => { let data = self.bytes.read_u64::()?; - args.push(Arg::Uxx(data as u64)); + args.push(Arg::Uxx(data as u128)); } Type::U128 => { let data = self.bytes.read_u128::()?; - args.push(Arg::U128(data)); + args.push(Arg::Uxx(data as u128)); } Type::Usize => { let unsigned = read_leb128(&mut self.bytes)?; - args.push(Arg::Uxx(unsigned)) + args.push(Arg::Uxx(unsigned as u128)) } Type::F32 => { let data = self.bytes.read_u32::()?; args.push(Arg::F32(f32::from_bits(data))); } Type::BitField(range) => { - let mut data: u64; + let mut data: u128; let lowest_byte = range.start / 8; // -1 because `range` is range-exclusive let highest_byte = (range.end - 1) / 8; @@ -801,16 +799,16 @@ impl<'t, 'b> Decoder<'t, 'b> { match size_after_truncation { 1 => { - data = self.bytes.read_u8()? as u64; + data = self.bytes.read_u8()? as u128; } 2 => { - data = self.bytes.read_u16::()? as u64; + data = self.bytes.read_u16::()? as u128; } 3 => { - data = self.bytes.read_u24::()? as u64; + data = self.bytes.read_u24::()? as u128; } 4 => { - data = self.bytes.read_u32::()? as u64; + data = self.bytes.read_u32::()? as u128; } _ => { unreachable!(); @@ -1009,7 +1007,7 @@ fn format_args_real( Arg::Uxx(x) => { match param.ty { Type::BitField(range) => { - let left_zeroes = mem::size_of::() * 8 - range.end as usize; + let left_zeroes = mem::size_of::() * 8 - range.end as usize; let right_zeroes = left_zeroes + range.start as usize; // isolate the desired bitfields let bitfields = (*x << left_zeroes) >> right_zeroes; @@ -1018,9 +1016,7 @@ fn format_args_real( _ => format_u128(*x as u128, hint, &mut buf)?, } } - Arg::U128(x) => format_u128(*x, hint, &mut buf)?, Arg::Ixx(x) => format_i128(*x as i128, hint, &mut buf)?, - Arg::I128(x) => format_i128(*x, hint, &mut buf)?, Arg::Str(x) => format_str(x, hint, &mut buf)?, Arg::IStr(x) => format_str(x, hint, &mut buf)?, Arg::Format { format, args } => buf.push_str(&format_args(format, args, hint)), @@ -1167,17 +1163,17 @@ mod tests { format: FMT, timestamp: 2, args: vec![ - Arg::Uxx(42), // u8 - Arg::Uxx(u16::max_value().into()), // u16 - Arg::Uxx(0x10000), // u24 - Arg::Uxx(u32::max_value().into()), // u32 - Arg::Uxx(u64::max_value().into()), // u64 - Arg::U128(u128::max_value().into()), - Arg::Ixx(-1), // i8 - Arg::Ixx(-1), // i16 - Arg::Ixx(-1), // i32 - Arg::Ixx(-1), // i64 - Arg::I128(-1), // i128 + Arg::Uxx(42), // u8 + Arg::Uxx(u16::max_value().into()), // u16 + Arg::Uxx(0x10000), // u24 + Arg::Uxx(u32::max_value().into()), // u32 + Arg::Uxx(u64::max_value().into()), // u64 + Arg::Uxx(u128::max_value().into()), // u128 + Arg::Ixx(-1), // i8 + Arg::Ixx(-1), // i16 + Arg::Ixx(-1), // i32 + Arg::Ixx(-1), // i64 + Arg::Ixx(-1), // i128 ], }, bytes.len(), From 957c4253aa11d32f9edbbc7b20a6ceba1834a926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Vi=C3=B6l?= Date: Mon, 21 Dec 2020 23:50:18 +0100 Subject: [PATCH 2/5] Fix maximum bitfields range Range is exclusive. To match the MSB 32 for `range.end` has to be allowed. --- parser/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/parser/src/lib.rs b/parser/src/lib.rs index a27633106..7c642e495 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -127,7 +127,7 @@ fn parse_range(mut s: &str) -> Option<(Range, usize /* consumed */)> { return None; } - if start >= 32 || end >= 32 { + if start >= 32 || end > 32 { return None; } @@ -887,9 +887,9 @@ mod tests { // start > end assert!(parse("{=1..0}", ParserMode::Strict).is_err()); // out of 32-bit range - assert!(parse("{=0..32}", ParserMode::Strict).is_err()); + assert!(parse("{=0..33}", ParserMode::Strict).is_err()); // just inside 32-bit range - assert!(parse("{=0..31}", ParserMode::Strict).is_ok()); + assert!(parse("{=0..32}", ParserMode::Strict).is_ok()); // missing parts assert!(parse("{=0..4", ParserMode::Strict).is_err()); From 4b276f7c299bb94faa749d0fd1b1a7e491bed461 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Vi=C3=B6l?= Date: Sun, 20 Dec 2020 22:57:31 +0100 Subject: [PATCH 3/5] bitfields: Lift 32-bit range limit --- decoder/src/lib.rs | 31 +++++++++++++++++++++++++++++++ firmware/qemu/src/bin/log.rs | 9 +++++++++ macros/src/lib.rs | 7 +++++++ parser/src/lib.rs | 12 +++++++----- src/export.rs | 31 +++++++++++++++++++++++++++++++ 5 files changed, 85 insertions(+), 5 deletions(-) diff --git a/decoder/src/lib.rs b/decoder/src/lib.rs index 076f2d3aa..a0b593b0d 100644 --- a/decoder/src/lib.rs +++ b/decoder/src/lib.rs @@ -810,6 +810,12 @@ impl<'t, 'b> Decoder<'t, 'b> { 4 => { data = self.bytes.read_u32::()? as u128; } + 5..=8 => { + data = self.bytes.read_u64::()? as u128; + } + 9..=16 => { + data = self.bytes.read_u128::()? as u128; + } _ => { unreachable!(); } @@ -1604,6 +1610,31 @@ mod tests { ); } + #[test] + fn bitfields_u128() { + let bytes = [ + 0, // index + 2, // timestamp + 0b1110_0101, // 120..127 + 0b1110_0101, // 112..119 + 0b0000_0000, // 104..111 + 0b0000_0000, // 96..103 + 0b0000_0000, // 88..95 + 0b0000_0000, // 80..87 + 0b0000_0000, // 72..79 + 0b0000_0000, // 64..71 + 0b0000_0000, // 56..63 + 0b0000_0000, // 48..55 + 0b0000_0000, // 40..47 + 0b0000_0000, // 32..39 + 0b0000_0000, // 24..31 + 0b0000_0000, // 16..23 + 0b0000_0000, // 8..15 + 0b0000_0000, // 0..7 + ]; + decode_and_expect("x: {0=119..124:b}", &bytes, "0.000002 INFO x: 0b1011"); + } + #[test] fn slice() { let bytes = [ diff --git a/firmware/qemu/src/bin/log.rs b/firmware/qemu/src/bin/log.rs index 40edfb5e6..565cf12ea 100644 --- a/firmware/qemu/src/bin/log.rs +++ b/firmware/qemu/src/bin/log.rs @@ -52,6 +52,15 @@ fn main() -> ! { ); defmt::info!("usize: 0 = {=usize}, MAX = {=usize}", 0, usize::max_value()); defmt::info!("bitfields {0=0..3} {0=5..7}", 0b0110_0011_1101_0110u16); + defmt::info!( + "bitfields \ + {0=120..128:x} \ + {0=112..120:b} \ + {0=80..88} \ + {0=48..64:x} \ + {=8..48:x}", + 0x9784_89AE_FF0C_5900_3432_6865_6C6C_6F00u128 + ); defmt::trace!("log trace"); defmt::debug!("log debug"); diff --git a/macros/src/lib.rs b/macros/src/lib.rs index eed8b8aa5..d1f6ad56e 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -1175,6 +1175,13 @@ impl Codegen { 4 => { exprs.push(quote!(_fmt_.u32(&defmt::export::truncate((*#arg) >> (#lowest_byte * 8))))); } + 5..=8 => { + exprs.push(quote!(_fmt_.u64(&defmt::export::truncate((*#arg) >> (#lowest_byte * 8))))); + } + 9..=16 => { + exprs.push(quote!(_fmt_.u128(&defmt::export::truncate((*#arg) >> (#lowest_byte * 8))))); + } + _ => unreachable!(), } } diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 7c642e495..7077aded9 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -127,7 +127,7 @@ fn parse_range(mut s: &str) -> Option<(Range, usize /* consumed */)> { return None; } - if start >= 32 || end > 32 { + if start >= 128 || end > 128 { return None; } @@ -886,10 +886,12 @@ mod tests { assert!(parse("{=0..0}", ParserMode::Strict).is_err()); // start > end assert!(parse("{=1..0}", ParserMode::Strict).is_err()); - // out of 32-bit range - assert!(parse("{=0..33}", ParserMode::Strict).is_err()); - // just inside 32-bit range - assert!(parse("{=0..32}", ParserMode::Strict).is_ok()); + // out of 128-bit range + assert!(parse("{=0..129}", ParserMode::Strict).is_err()); + assert!(parse("{=128..128}", ParserMode::Strict).is_err()); + // just inside 128-bit range + assert!(parse("{=0..128}", ParserMode::Strict).is_ok()); + assert!(parse("{=127..128}", ParserMode::Strict).is_ok()); // missing parts assert!(parse("{=0..4", ParserMode::Strict).is_err()); diff --git a/src/export.rs b/src/export.rs index b3ede26dc..af8658354 100644 --- a/src/export.rs +++ b/src/export.rs @@ -104,6 +104,12 @@ mod sealed { } } + impl Truncate for u128 { + fn truncate(self) -> u8 { + self as u8 + } + } + // needed so we can call truncate() without having to check whether truncation is necessary first impl Truncate for u16 { fn truncate(self) -> u16 { @@ -123,6 +129,12 @@ mod sealed { } } + impl Truncate for u128 { + fn truncate(self) -> u16 { + self as u16 + } + } + // needed so we can call truncate() without having to check whether truncation is necessary first impl Truncate for u32 { fn truncate(self) -> u32 { @@ -136,6 +148,12 @@ mod sealed { } } + impl Truncate for u128 { + fn truncate(self) -> u32 { + self as u32 + } + } + // needed so we can call truncate() without having to check whether truncation is necessary first impl Truncate for u64 { fn truncate(self) -> u64 { @@ -143,6 +161,19 @@ mod sealed { } } + impl Truncate for u128 { + fn truncate(self) -> u64 { + self as u64 + } + } + + // needed so we can call truncate() without having to check whether truncation is necessary first + impl Truncate for u128 { + fn truncate(self) -> u128 { + self + } + } + #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct NoneError; From 015690d0131ff829379abff93b2d29b84568119a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Vi=C3=B6l?= Date: Mon, 21 Dec 2020 22:27:35 +0100 Subject: [PATCH 4/5] Support ascii formatting for bitfields --- decoder/src/lib.rs | 13 ++++++++++++- firmware/qemu/src/bin/hints.out | 2 +- firmware/qemu/src/bin/hints.release.out | 2 +- firmware/qemu/src/bin/log.out | 3 ++- firmware/qemu/src/bin/log.release.out | 3 ++- firmware/qemu/src/bin/log.rs | 20 ++++++++++---------- 6 files changed, 28 insertions(+), 15 deletions(-) diff --git a/decoder/src/lib.rs b/decoder/src/lib.rs index a0b593b0d..e030a0cfb 100644 --- a/decoder/src/lib.rs +++ b/decoder/src/lib.rs @@ -1017,7 +1017,18 @@ fn format_args_real( let right_zeroes = left_zeroes + range.start as usize; // isolate the desired bitfields let bitfields = (*x << left_zeroes) >> right_zeroes; - format_u128(bitfields as u128, hint, &mut buf)?; + + if let Some(DisplayHint::Ascii) = hint { + let bstr = bitfields + .to_be_bytes() + .iter() + .skip(right_zeroes / 8) + .copied() + .collect::>(); + format_bytes(&bstr, hint, &mut buf)? + } else { + format_u128(bitfields as u128, hint, &mut buf)?; + } } _ => format_u128(*x as u128, hint, &mut buf)?, } diff --git a/firmware/qemu/src/bin/hints.out b/firmware/qemu/src/bin/hints.out index 8a6e68b33..8a0c13f11 100644 --- a/firmware/qemu/src/bin/hints.out +++ b/firmware/qemu/src/bin/hints.out @@ -40,5 +40,5 @@ 0.000039 INFO hex 0xa 0.000040 INFO HEX 0xA 0.000041 INFO binary 0b1010 -0.000042 INFO ASCII 10 +0.000042 INFO ASCII b"\n" 0.000043 INFO Debug 10 diff --git a/firmware/qemu/src/bin/hints.release.out b/firmware/qemu/src/bin/hints.release.out index 8a6e68b33..8a0c13f11 100644 --- a/firmware/qemu/src/bin/hints.release.out +++ b/firmware/qemu/src/bin/hints.release.out @@ -40,5 +40,5 @@ 0.000039 INFO hex 0xa 0.000040 INFO HEX 0xA 0.000041 INFO binary 0b1010 -0.000042 INFO ASCII 10 +0.000042 INFO ASCII b"\n" 0.000043 INFO Debug 10 diff --git a/firmware/qemu/src/bin/log.out b/firmware/qemu/src/bin/log.out index 08fd07cde..1c2f4130c 100644 --- a/firmware/qemu/src/bin/log.out +++ b/firmware/qemu/src/bin/log.out @@ -104,4 +104,5 @@ 0.000103 INFO EnumLarge::A051 0.000104 INFO EnumLarge::A269 0.000105 INFO S { x: "hi" } -0.000106 INFO QEMU test finished! +0.000106 INFO bitfields 0x97 0b10000100 12 b"42" b"hello" +0.000107 INFO QEMU test finished! diff --git a/firmware/qemu/src/bin/log.release.out b/firmware/qemu/src/bin/log.release.out index 0206c8ac1..fe1e029fe 100644 --- a/firmware/qemu/src/bin/log.release.out +++ b/firmware/qemu/src/bin/log.release.out @@ -102,4 +102,5 @@ 0.000101 INFO EnumLarge::A051 0.000102 INFO EnumLarge::A269 0.000103 INFO S { x: "hi" } -0.000104 INFO QEMU test finished! +0.000104 INFO bitfields 0x97 0b10000100 12 b"42" b"hello" +0.000105 INFO QEMU test finished! diff --git a/firmware/qemu/src/bin/log.rs b/firmware/qemu/src/bin/log.rs index 565cf12ea..866b44d87 100644 --- a/firmware/qemu/src/bin/log.rs +++ b/firmware/qemu/src/bin/log.rs @@ -52,16 +52,6 @@ fn main() -> ! { ); defmt::info!("usize: 0 = {=usize}, MAX = {=usize}", 0, usize::max_value()); defmt::info!("bitfields {0=0..3} {0=5..7}", 0b0110_0011_1101_0110u16); - defmt::info!( - "bitfields \ - {0=120..128:x} \ - {0=112..120:b} \ - {0=80..88} \ - {0=48..64:x} \ - {=8..48:x}", - 0x9784_89AE_FF0C_5900_3432_6865_6C6C_6F00u128 - ); - defmt::trace!("log trace"); defmt::debug!("log debug"); defmt::info!("log info"); @@ -548,6 +538,16 @@ fn main() -> ! { defmt::info!("{:?}", S { x: "hi" }); } + defmt::info!( + "bitfields \ + {0=120..128:x} \ + {0=112..120:b} \ + {0=80..88} \ + {0=48..64:a} \ + {=8..48:a}", + 0x9784_89AE_FF0C_5900_3432_6865_6C6C_6F00u128 + ); + defmt::info!("QEMU test finished!"); loop { From a270f5c7d7df39a9e072a60e36354c8240864401 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Vi=C3=B6l?= Date: Mon, 21 Dec 2020 22:30:07 +0100 Subject: [PATCH 5/5] Fix clippy lint #[clippy(warn::or_fun_call)] --- macros/src/symbol.rs | 2 +- parser/src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/macros/src/symbol.rs b/macros/src/symbol.rs index 0040eb277..99591e35f 100644 --- a/macros/src/symbol.rs +++ b/macros/src/symbol.rs @@ -31,7 +31,7 @@ impl<'a> Symbol<'a> { pub fn new(tag: &'a str, data: &'a str) -> Self { Self { // `CARGO_PKG_NAME` is set to the invoking package's name. - package: env::var("CARGO_PKG_NAME").unwrap_or("".to_string()), + package: env::var("CARGO_PKG_NAME").unwrap_or_else(|_| "".to_string()), disambiguator: { // We want a deterministic, but unique-per-macro-invocation identifier. For that we // hash the call site `Span`'s debug representation, which contains a counter that diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 7077aded9..a4191bb89 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -169,7 +169,7 @@ fn parse_param(mut input: &str, mode: ParserMode) -> Result Result