rigless 0.2.1

Virtual hardware-in-the-loop runtime: run unmodified firmware on an emulated MCU with every peripheral, chip model and unit of virtual time in Rust, and a CPU core of its own that translates the firmware's instructions to host code
Documentation
// Copyright (c) 2026 Rigless Labs.
// SPDX-License-Identifier: MIT OR Apache-2.0
//! The fields and codes the model reads, by channel, from the advanced timer's generated table.
//!
//! Every field here sits at the same bits in every layout that has it, which the tests of
//! [`super::family`] hold. The advanced timer's table is the one the others are subsets of, so it names
//! them all. Three fields are split in two by ST, "for compatibility reasons": the output compare mode,
//! the slave mode and the trigger selection. A [`Split`] reads and writes the pair as one value.
//!
//! The codes are those of RM0433 rev 9 section 38.4: `SMS` and `TS` of 38.4.3, `CMS` of 38.4.1, `MMS` and
//! `MMS2` of 38.4.2, `CCxS` of 38.4.7, `OCxM` of 38.4.8, `LOCK` of 38.4.20. The per-channel tables follow
//! the registers they come from: the capture/compare mode registers 1 to 3 of 38.4.7 to 38.4.10 and
//! 38.4.23, `CCER` of 38.4.11, `SR`, `DIER`, `EGR` of 38.4.5, 38.4.4 and 38.4.6, and the idle levels of
//! `CR2`. The idle levels and the complementary enables are the advanced timer's three complementary
//! channels'. Channels 5 and 6 have no input stage, no request and no interrupt of their own.

use crate::soc::FieldSpec;
use crate::soc::stm32h743::generated::tim1::{
    ccer, ccmr1_input, ccmr1_output, ccmr2_input, ccmr2_output, ccmr3_output, cr2, dier, egr, smcr,
    sr,
};

pub(super) const CHANNEL_COUNT: u8 = 6;
pub(super) const CHANNELS: usize = CHANNEL_COUNT as usize;
pub(super) const BYTE: u64 = 0xFF;
// 38.3.6
pub(super) const INPUTS: usize = 4;

#[derive(Debug, Clone, Copy)]
pub(super) struct Split {
    low: &'static FieldSpec,
    high: &'static FieldSpec,
}

impl Split {
    pub(super) const fn new(low: &'static FieldSpec, high: &'static FieldSpec) -> Self {
        Self { low, high }
    }

    pub(super) const fn get(&self, register_value: u64) -> u64 {
        self.low.get(register_value) | (self.high.get(register_value) << self.low.width)
    }

    pub(super) const fn set(&self, register_value: u64, value: u64) -> u64 {
        let low_mask = (1u64 << self.low.width) - 1;
        self.high.set(
            self.low.set(register_value, value & low_mask),
            value >> self.low.width,
        )
    }

    pub(super) const fn mask(&self) -> u64 {
        self.low.mask() | self.high.mask()
    }
}

// 38.4.3
pub(super) const SMS: Split = Split::new(smcr::SMS, smcr::SMS_3);
// 38.4.3
pub(super) const TS: Split = Split::new(smcr::TS, smcr::TS_4_3);

pub(super) const SMS_DISABLED: u64 = 0b0000;
pub(super) const SMS_ENCODER_1: u64 = 0b0001;
pub(super) const SMS_ENCODER_2: u64 = 0b0010;
pub(super) const SMS_ENCODER_3: u64 = 0b0011;
pub(super) const SMS_RESET: u64 = 0b0100;
pub(super) const SMS_GATED: u64 = 0b0101;
pub(super) const SMS_TRIGGER: u64 = 0b0110;
pub(super) const SMS_EXTERNAL_CLOCK_1: u64 = 0b0111;
pub(super) const SMS_COMBINED: u64 = 0b1000;
pub(super) const TS_LAST_LOW_INTERNAL: u64 = 0b00011;
pub(super) const TS_TI1_EDGES: u64 = 0b00100;
pub(super) const TS_TI1FP1: u64 = 0b00101;
pub(super) const TS_TI2FP2: u64 = 0b00110;
pub(super) const TS_ETRF: u64 = 0b00111;
pub(super) const TS_FIRST_HIGH_INTERNAL: u64 = 0b01000;
pub(super) const TS_LAST_INTERNAL: u64 = 0b01100;
pub(super) const TS_RESERVED: u64 = 0b01101;
pub(super) const CMS_EDGE_ALIGNED: u64 = 0b00;
pub(super) const CMS_FLAGS_DOWN: u64 = 0b01;
pub(super) const CMS_FLAGS_UP: u64 = 0b10;
pub(super) const MMS_RESET: u64 = 0b000;
pub(super) const MMS_ENABLE: u64 = 0b001;
pub(super) const MMS_UPDATE: u64 = 0b010;
pub(super) const MMS_COMPARE_PULSE: u64 = 0b011;
pub(super) const MMS_FIRST_REFERENCE: u64 = 0b100;
pub(super) const MMS2_FIRST_REFERENCE: u64 = 0b0100;
pub(super) const MMS2_LAST_REFERENCE: u64 = 0b1001;
pub(super) const MMS2_OC4_EDGES: u64 = 0b1010;
pub(super) const MMS2_OC6_EDGES: u64 = 0b1011;
pub(super) const MMS2_OC4_OR_OC6_RISING: u64 = 0b1100;
pub(super) const MMS2_OC4_RISING_OC6_FALLING: u64 = 0b1101;
pub(super) const MMS2_OC5_OR_OC6_RISING: u64 = 0b1110;
pub(super) const MMS2_OC5_RISING_OC6_FALLING: u64 = 0b1111;
pub(super) const CCS_OUTPUT: u64 = 0b00;
pub(super) const CCS_OWN_INPUT: u64 = 0b01;
pub(super) const CCS_OTHER_INPUT: u64 = 0b10;
pub(super) const CCS_TRC: u64 = 0b11;
pub(super) const OCM_FROZEN: u64 = 0b0000;
pub(super) const OCM_ACTIVE_ON_MATCH: u64 = 0b0001;
pub(super) const OCM_INACTIVE_ON_MATCH: u64 = 0b0010;
pub(super) const OCM_TOGGLE: u64 = 0b0011;
pub(super) const OCM_FORCE_INACTIVE: u64 = 0b0100;
pub(super) const OCM_FORCE_ACTIVE: u64 = 0b0101;
pub(super) const OCM_PWM_1: u64 = 0b0110;
pub(super) const OCM_PWM_2: u64 = 0b0111;
pub(super) const OCM_RETRIGGERABLE_1: u64 = 0b1000;
pub(super) const OCM_RETRIGGERABLE_2: u64 = 0b1001;
pub(super) const OCM_COMBINED_1: u64 = 0b1100;
pub(super) const OCM_COMBINED_2: u64 = 0b1101;
pub(super) const OCM_ASYMMETRIC_1: u64 = 0b1110;
pub(super) const OCM_ASYMMETRIC_2: u64 = 0b1111;
pub(super) const LOCK_LEVEL_1: u64 = 1;
pub(super) const LOCK_LEVEL_2: u64 = 2;
pub(super) const LOCK_LEVEL_3: u64 = 3;

pub(super) const CC_S: [&FieldSpec; INPUTS] = [
    ccmr1_output::CC1S,
    ccmr1_output::CC2S,
    ccmr2_output::CC3S,
    ccmr2_output::CC4S,
];
pub(super) const IC_PSC: [&FieldSpec; INPUTS] = [
    ccmr1_input::IC1PSC,
    ccmr1_input::IC2PSC,
    ccmr2_input::IC3PSC,
    ccmr2_input::IC4PSC,
];
pub(super) const IC_F: [&FieldSpec; INPUTS] = [
    ccmr1_input::IC1F,
    ccmr1_input::IC2F,
    ccmr2_input::IC3F,
    ccmr2_input::IC4F,
];
pub(super) const OC_FE: [&FieldSpec; CHANNELS] = [
    ccmr1_output::OC1FE,
    ccmr1_output::OC2FE,
    ccmr2_output::OC3FE,
    ccmr2_output::OC4FE,
    ccmr3_output::OC5FE,
    ccmr3_output::OC6FE,
];
pub(super) const OC_PE: [&FieldSpec; CHANNELS] = [
    ccmr1_output::OC1PE,
    ccmr1_output::OC2PE,
    ccmr2_output::OC3PE,
    ccmr2_output::OC4PE,
    ccmr3_output::OC5PE,
    ccmr3_output::OC6PE,
];
pub(super) const OC_CE: [&FieldSpec; CHANNELS] = [
    ccmr1_output::OC1CE,
    ccmr1_output::OC2CE,
    ccmr2_output::OC3CE,
    ccmr2_output::OC4CE,
    ccmr3_output::OC5CE,
    ccmr3_output::OC6CE,
];
pub(super) const OC_M: [Split; CHANNELS] = [
    Split::new(ccmr1_output::OC1M, ccmr1_output::OC1M_3),
    Split::new(ccmr1_output::OC2M, ccmr1_output::OC2M_3),
    Split::new(ccmr2_output::OC3M, ccmr2_output::OC3M_3),
    Split::new(ccmr2_output::OC4M, ccmr2_output::OC4M_4),
    Split::new(ccmr3_output::OC5M, ccmr3_output::OC5M3),
    Split::new(ccmr3_output::OC6M, ccmr3_output::OC6M3),
];
pub(super) const CC_E: [&FieldSpec; CHANNELS] = [
    ccer::CC1E,
    ccer::CC2E,
    ccer::CC3E,
    ccer::CC4E,
    ccer::CC5E,
    ccer::CC6E,
];
pub(super) const CC_P: [&FieldSpec; CHANNELS] = [
    ccer::CC1P,
    ccer::CC2P,
    ccer::CC3P,
    ccer::CC4P,
    ccer::CC5P,
    ccer::CC6P,
];
pub(super) const CC_NP: [&FieldSpec; INPUTS] = [ccer::CC1NP, ccer::CC2NP, ccer::CC3NP, ccer::CC4NP];
pub(super) const CC_NE: [&FieldSpec; 3] = [ccer::CC1NE, ccer::CC2NE, ccer::CC3NE];
pub(super) const CC_IF: [&FieldSpec; CHANNELS] = [
    sr::CC1IF,
    sr::CC2IF,
    sr::CC3IF,
    sr::CC4IF,
    sr::CC5IF,
    sr::CC6IF,
];
pub(super) const CC_OF: [&FieldSpec; INPUTS] = [sr::CC1OF, sr::CC2OF, sr::CC3OF, sr::CC4OF];
pub(super) const CC_DE: [&FieldSpec; INPUTS] = [dier::CC1DE, dier::CC2DE, dier::CC3DE, dier::CC4DE];
pub(super) const CC_G: [&FieldSpec; INPUTS] = [egr::CC1G, egr::CC2G, egr::CC3G, egr::CC4G];
pub(super) const OIS: [&FieldSpec; CHANNELS] = [
    cr2::OIS1,
    cr2::OIS2,
    cr2::OIS3,
    cr2::OIS4,
    cr2::OIS5,
    cr2::OIS6,
];
pub(super) const OIS_N: [&FieldSpec; 3] = [cr2::OIS1N, cr2::OIS2N, cr2::OIS3N];