use std::collections::HashMap;
use consortium_cfg::components::address::{Address, ApAddress};
use consortium_cfg::components::bella::{BellA, HardwareDoorbell};
use consortium_cfg::components::ipc_shm::{
Channel, DoorbellMeta, DoorbellRingerSide, DoorbellSource, ShuHan, Transceiver,
initialize_instances,
};
use consortium_cfg::components::irq::InterruptLine;
use consortium_cfg::components::region::Region;
use consortium_cfg_common::config::{Codec, McoreName, VisibleCore};
use consortium_cfg_common::database::{HardwareDoorbellPeripheralType, MemoryRegionType};
use proc_macro2::TokenStream;
use quote::format_ident;
fn stmts(tokens: TokenStream) -> String {
let wrapped: TokenStream = quote::quote! { fn _generated() { #tokens } };
consortium_cfg::render(wrapped).expect("generated code should parse as Rust")
}
fn expr(tokens: TokenStream) -> String {
let wrapped: TokenStream = quote::quote! { fn _generated() { let _ = #tokens; } };
consortium_cfg::render(wrapped).expect("generated code should parse as Rust")
}
fn items(tokens: TokenStream) -> String {
consortium_cfg::render(tokens).expect("generated code should parse as Rust")
}
fn cm33() -> VisibleCore {
VisibleCore::Mcore(McoreName::Cm33)
}
fn cm7() -> VisibleCore {
VisibleCore::Mcore(McoreName::Cm7)
}
fn shared_address(mmap_id: usize, cp_addr: u32) -> Address {
Address {
ap: ApAddress { uio_id: 0, mmap_id },
cp: HashMap::from([(cm33(), cp_addr)]),
}
}
fn transceiver() -> Transceiver {
Transceiver {
name: "ping".to_string(),
doorbell_address: shared_address(2, 0x4400_0000),
mtu: 256,
codec: Codec::Postcard,
region: Region {
r#type: MemoryRegionType::Sram,
cache: false,
address: shared_address(1, 0x3400_0000),
length: 0x8000,
},
channel_primary: (
VisibleCore::Ap,
Channel {
doorbell_chan: 0,
ack_chan: None,
type_name: "Ping".to_string(),
buffer_name: "ping_tx_buf".to_string(),
},
),
channel_secondary: (
cm33(),
Channel {
doorbell_chan: 1,
ack_chan: None,
type_name: "Pong".to_string(),
buffer_name: "ping_rx_buf".to_string(),
},
),
doorbell: DoorbellMeta {
r#type: HardwareDoorbellPeripheralType::Ipcc,
id: Some(1),
},
doorbell_window: (DoorbellRingerSide::Primary, DoorbellRingerSide::Secondary),
}
}
#[test]
fn transceiver_primary_side_binds_uio_notifier() {
let uio = format_ident!("uio");
let tokens = transceiver().build_field_init(
VisibleCore::Ap,
&uio,
DoorbellSource::Uio,
"::consortium_hal_stm32mp2",
);
insta::assert_snapshot!(expr(tokens));
}
#[test]
fn transceiver_secondary_side_uses_controller_addresses() {
let uio = format_ident!("uio");
let tokens = transceiver().build_field_init(
cm33(),
&uio,
DoorbellSource::Owned(format_ident!("__db_ipcc1")),
"::consortium_hal_stm32mp2",
);
insta::assert_snapshot!(expr(tokens));
}
#[test]
fn region_initialize_uncached_ap() {
let uio = format_ident!("uio");
let tokens = transceiver().region.initialize(VisibleCore::Ap, &uio);
insta::assert_snapshot!(expr(tokens));
}
#[test]
fn bella_nvic_enable_for_controller_core() {
let mut bella = BellA {
bells: vec![
HardwareDoorbell {
name: "ipcc1".to_string(),
address: shared_address(0, 0),
r#type: HardwareDoorbellPeripheralType::Ipcc,
id: Some(1),
channels: vec![0],
irq: HashMap::from([(cm33(), InterruptLine::new(171))]),
side: HashMap::from([(cm33(), DoorbellRingerSide::Secondary)]),
},
HardwareDoorbell {
name: "ipcc2".to_string(),
address: shared_address(0, 0),
r#type: HardwareDoorbellPeripheralType::Ipcc,
id: Some(2),
channels: vec![1],
irq: HashMap::from([(cm33(), InterruptLine::new(175))]),
side: HashMap::from([(cm33(), DoorbellRingerSide::Secondary)]),
},
],
};
let map = consortium_cfg::chipmap::load("stm32mp257fai3", "cm33").expect("bundled cm33 map");
assert!(map.has_pac_interrupts());
bella.resolve_variants(|_, number| map.irq_by_number(number).map(|irq| irq.name.clone()));
let tokens = bella
.nvic_enable(&cm33(), "::consortium_hal_stm32mp2")
.expect("controller core has irqs");
insta::assert_snapshot!(stmts(tokens));
}
fn pong() -> Transceiver {
Transceiver {
name: "pong".to_string(),
doorbell_address: Address {
ap: ApAddress {
uio_id: 2,
mmap_id: 0,
},
cp: HashMap::from([(cm7(), 0x4500_0000)]),
},
mtu: 512,
codec: Codec::Rkyv,
region: Region {
r#type: MemoryRegionType::Sram,
cache: false,
address: Address {
ap: ApAddress {
uio_id: 0,
mmap_id: 1,
},
cp: HashMap::from([(cm7(), 0x3404_0000)]),
},
length: 0x4000,
},
channel_primary: (
VisibleCore::Ap,
Channel {
doorbell_chan: 2,
ack_chan: None,
type_name: "Telemetry".to_string(),
buffer_name: "pong_tx_buf".to_string(),
},
),
channel_secondary: (
cm7(),
Channel {
doorbell_chan: 3,
ack_chan: None,
type_name: "Command".to_string(),
buffer_name: "pong_rx_buf".to_string(),
},
),
doorbell: DoorbellMeta {
r#type: HardwareDoorbellPeripheralType::Ipcc,
id: Some(2),
},
doorbell_window: (DoorbellRingerSide::Primary, DoorbellRingerSide::Secondary),
}
}
fn shuhan() -> ShuHan {
ShuHan::new(vec![transceiver(), pong()])
}
#[test]
fn shuhan_ap_side_emits_full_endpoint_struct() {
let uio = format_ident!("uio");
let ty_crate: syn::Path = syn::parse_str("::shared").unwrap();
let tokens = initialize_instances(
&shuhan(),
VisibleCore::Ap,
&uio,
&ty_crate,
"::consortium_hal_stm32mp2",
&[],
);
insta::assert_snapshot!(items(tokens));
}
#[test]
fn shuhan_controller_side_emits_single_endpoint_struct() {
let uio = format_ident!("uio");
let ty_crate: syn::Path = syn::parse_str("::shared").unwrap();
let tokens = initialize_instances(
&ShuHan::new(vec![transceiver()]),
cm33(),
&uio,
&ty_crate,
"::consortium_hal_stm32mp2",
&["IPCC1".to_string()],
);
insta::assert_snapshot!(items(tokens));
}