use crate::error::Span;
#[derive(Debug, Clone)]
pub struct DecoderDef {
pub imports: Vec<Import>,
pub config: DecoderConfig,
pub type_aliases: Vec<TypeAlias>,
pub maps: Vec<MapDef>,
pub instructions: Vec<InstructionDef>,
}
#[derive(Debug, Clone)]
pub struct Import {
pub path: String,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct DecoderConfig {
pub name: String,
pub width: u32,
pub bit_order: BitOrder,
pub endian: ByteEndian,
pub max_units: Option<u32>,
pub span: Span,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BitOrder {
Msb0,
Lsb0,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ByteEndian {
Big,
Little,
}
#[derive(Debug, Clone)]
pub struct TypeAlias {
pub name: String,
pub base_type: String,
pub wrapper_type: Option<String>,
pub transforms: Vec<Transform>,
pub display_format: Option<DisplayFormat>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Transform {
SignExtend(u32),
ZeroExtend(u32),
ShiftLeft(u32),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DisplayFormat {
SignedHex,
Hex,
}
#[derive(Debug, Clone)]
pub struct MapDef {
pub name: String,
pub params: Vec<String>,
pub entries: Vec<MapEntry>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct MapEntry {
pub keys: Vec<MapKey>,
pub output: Vec<FormatPiece>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MapKey {
Value(i64),
Wildcard,
}
#[derive(Debug, Clone)]
pub struct FormatLine {
pub guard: Option<Guard>,
pub pieces: Vec<FormatPiece>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct Guard {
pub conditions: Vec<GuardCondition>,
}
#[derive(Debug, Clone)]
pub struct GuardCondition {
pub left: GuardOperand,
pub op: CompareOp,
pub right: GuardOperand,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompareOp {
Eq,
Ne,
Lt,
Le,
Gt,
Ge,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GuardOperand {
Field(String),
Literal(i64),
Expr {
left: Box<GuardOperand>,
op: ArithOp,
right: Box<GuardOperand>,
},
}
#[derive(Debug, Clone)]
pub enum FormatPiece {
Literal(String),
FieldRef {
expr: FormatExpr,
spec: Option<String>,
},
}
#[derive(Debug, Clone)]
pub enum FormatExpr {
Field(String),
Ternary {
field: String,
if_nonzero: String,
if_zero: Option<String>,
},
Arithmetic {
left: Box<FormatExpr>,
op: ArithOp,
right: Box<FormatExpr>,
},
IntLiteral(i64),
MapCall {
map_name: String,
args: Vec<FormatExpr>,
},
BuiltinCall {
func: BuiltinFunc,
args: Vec<FormatExpr>,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ArithOp {
Add,
Sub,
Mul,
Div,
Mod,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BuiltinFunc {
RotateRight,
RotateLeft,
}
#[derive(Debug, Clone)]
pub struct InstructionDef {
pub name: String,
pub segments: Vec<Segment>,
pub format_lines: Vec<FormatLine>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub enum Segment {
Fixed {
ranges: Vec<BitRange>,
pattern: Vec<Bit>,
span: Span,
},
Field {
name: String,
field_type: FieldType,
ranges: Vec<BitRange>,
span: Span,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BitRange {
pub unit: u32,
pub start: u32,
pub end: u32,
}
impl BitRange {
pub fn new(start: u32, end: u32) -> Self {
BitRange { unit: 0, start, end }
}
pub fn new_in_unit(unit: u32, start: u32, end: u32) -> Self {
debug_assert!(start >= end, "BitRange: start ({}) must be >= end ({})", start, end);
BitRange { unit, start, end }
}
pub fn width(&self) -> u32 {
self.start - self.end + 1
}
pub fn contains_bit(&self, bit: u32) -> bool {
bit >= self.end && bit <= self.start
}
pub fn bits(&self) -> impl Iterator<Item = u32> {
let start = self.start;
let end = self.end;
(end..=start).rev()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Bit {
Zero,
One,
Wildcard,
}
#[derive(Debug, Clone)]
pub enum FieldType {
Alias(String),
Inline {
base_type: String,
transforms: Vec<Transform>,
},
}
#[derive(Debug, Clone)]
pub struct ResolvedFieldType {
pub base_type: String,
pub wrapper_type: Option<String>,
pub transforms: Vec<Transform>,
pub display_format: Option<DisplayFormat>,
}
#[derive(Debug, Clone)]
pub struct ValidatedDef {
pub imports: Vec<Import>,
pub config: DecoderConfig,
pub type_aliases: Vec<TypeAlias>,
pub maps: Vec<MapDef>,
pub instructions: Vec<ValidatedInstruction>,
}
#[derive(Debug, Clone)]
pub struct ValidatedInstruction {
pub name: String,
pub segments: Vec<Segment>,
pub resolved_fields: Vec<ResolvedField>,
pub format_lines: Vec<FormatLine>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct ResolvedField {
pub name: String,
pub ranges: Vec<BitRange>,
pub resolved_type: ResolvedFieldType,
}
impl ValidatedInstruction {
pub fn unit_count(&self) -> u32 {
self.segments
.iter()
.flat_map(|seg| match seg {
Segment::Fixed { ranges, .. } | Segment::Field { ranges, .. } => ranges.iter(),
})
.map(|range| range.unit)
.max()
.unwrap_or(0)
+ 1
}
pub fn fixed_bits(&self) -> Vec<(u32, u32, Bit)> {
let mut result = Vec::new();
for seg in &self.segments {
if let Segment::Fixed { ranges, pattern, .. } = seg {
let mut bit_idx = 0;
for range in ranges {
let range_width = range.width() as usize;
for i in 0..range_width {
if bit_idx < pattern.len() {
let bit = pattern[bit_idx];
if bit != Bit::Wildcard {
let hw_bit = range.start - i as u32;
result.push((range.unit, hw_bit, bit));
}
bit_idx += 1;
}
}
}
}
}
result
}
pub fn fixed_bit_at(&self, hw_bit: u32) -> Option<Bit> {
for seg in &self.segments {
if let Segment::Fixed { ranges, pattern, .. } = seg {
let mut bit_idx = 0;
for range in ranges {
if range.unit != 0 {
bit_idx += range.width() as usize;
continue;
}
if range.contains_bit(hw_bit) {
let offset = (range.start - hw_bit) as usize;
let idx = bit_idx + offset;
if idx < pattern.len() {
let bit = pattern[idx];
if bit == Bit::Wildcard {
return None;
}
return Some(bit);
}
}
bit_idx += range.width() as usize;
}
}
}
None
}
}