use onerom_config::chip::ChipType;
use onerom_config::hw::Board;
use onerom_metadata::{
BitModes, GPIO_NONE, GpioOverride, OneromAlgAddrConfig, OneromAlgConfig, OneromAlgDataConfig,
OneromAlgDmaConfig, OneromAlgOverrideConfig,
};
use crate::image::CsConfig;
use crate::v2::cs_overrides::encode_override;
use super::addr_layout::AddrLayout;
use super::alg_cs::build_alg_cs;
use super::alg_preference::{
AddrAlgPreference, CombinedAlgPreference, CsAlgPreference, DataAlgPreference, DmaAlgPreference,
};
use super::cs_data_layout::CsDataLayout;
use super::cs_overrides::{
build_cs_overrides, build_gpio_x_overrides, build_unused_addr_overrides,
};
use super::gpio_pull_config::build_gpio_pull_config;
use super::slot_context::SlotContext;
pub const DEFAULT_CLKDIV_INT: u16 = 1;
pub const DEFAULT_CLKDIV_FRAC: u8 = 0;
const ALG_DATA0_NUM_DELAY_CYCLES_8_BIT: u8 = 2;
const ALG_DATA1_NUM_DELAY_CYCLES_16_BIT: u8 = 4;
pub fn bit_mode_for(chip_type: ChipType, board: Board) -> BitModes {
if board.pin_byte() != GPIO_NONE && chip_type.supports_bit_mode(16) {
BitModes::BitMode16
} else {
BitModes::BitMode8
}
}
pub fn build_alg_data(
layout: &CsDataLayout,
board: Board,
bit_mode: BitModes,
force_16_bit: bool,
) -> OneromAlgDataConfig {
match bit_mode {
BitModes::BitMode8 => OneromAlgDataConfig::AlgData0 {
clkdiv_int: DEFAULT_CLKDIV_INT,
clkdiv_frac: DEFAULT_CLKDIV_FRAC,
gpio_base: layout.gpio_base,
base_data_pin: layout.base_data_pin,
word_size: 8,
},
BitModes::BitMode16 if force_16_bit => OneromAlgDataConfig::AlgData0 {
clkdiv_int: DEFAULT_CLKDIV_INT,
clkdiv_frac: DEFAULT_CLKDIV_FRAC,
gpio_base: layout.gpio_base,
base_data_pin: layout.base_data_pin,
word_size: 16,
},
BitModes::BitMode16 => {
let byte_pin = board.pin_byte() - layout.gpio_base;
let a_minus_1_pin =
layout.data_pin_gpios[layout.num_data_pins as usize - 1] - layout.gpio_base;
OneromAlgDataConfig::AlgData1 {
clkdiv_int: DEFAULT_CLKDIV_INT,
clkdiv_frac: DEFAULT_CLKDIV_FRAC,
gpio_base: layout.gpio_base,
base_data_pin: layout.base_data_pin,
word_size: 16,
byte_pin,
a_minus_1_pin,
}
}
}
}
pub fn build_alg_addr(layout: &AddrLayout, alg_data: &OneromAlgDataConfig) -> OneromAlgAddrConfig {
let (num_delay_cycles, num_rom_table_bits) = match alg_data {
OneromAlgDataConfig::AlgData0 { word_size, .. } => (
ALG_DATA0_NUM_DELAY_CYCLES_8_BIT,
if *word_size == 8u8 {
layout.num_addr_pins
} else {
layout.num_addr_pins + 1
},
),
OneromAlgDataConfig::AlgData1 { .. } => {
(ALG_DATA1_NUM_DELAY_CYCLES_16_BIT, layout.num_addr_pins + 1)
}
};
let pio_base: u8 = if layout.gpio_base < 16 { 0 } else { 16 };
let base_addr_pin = layout.gpio_base - pio_base;
OneromAlgAddrConfig::AlgAddr0 {
clkdiv_int: DEFAULT_CLKDIV_INT,
clkdiv_frac: DEFAULT_CLKDIV_FRAC,
gpio_base: pio_base,
num_delay_cycles,
base_addr_pin,
num_addr_pins: layout.num_addr_pins,
num_rom_table_bits,
}
}
pub fn build_alg_dma(bit_mode: BitModes) -> OneromAlgDmaConfig {
OneromAlgDmaConfig::AlgDma0 {
bit_mode,
continuous: 1,
}
}
pub fn combined_alg_preference(alg: &OneromAlgConfig) -> CombinedAlgPreference {
(
CsAlgPreference::from(&alg.alg_cs),
AddrAlgPreference::from(&alg.alg_addr),
DataAlgPreference::from(&alg.alg_data),
DmaAlgPreference::from(&alg.alg_dma),
)
}
#[allow(clippy::too_many_arguments)]
pub fn build_alg_config(
ctx: &SlotContext,
addr_layout: &AddrLayout,
cs_data_layout: &CsDataLayout,
secondary_cs_configs: &[CsConfig],
) -> OneromAlgConfig {
let board = ctx.board;
let set_type = ctx.set_type;
let bit_mode = ctx.bit_mode;
let force_16_bit = ctx.force_16_bit;
let num_chips = ctx.chip_types.len();
let cs_config = &ctx.cs_config;
let alg_data = build_alg_data(cs_data_layout, board, bit_mode, force_16_bit);
let alg_addr = build_alg_addr(addr_layout, &alg_data);
let alg_cs = build_alg_cs(cs_data_layout, set_type, &alg_data);
let alg_dma = build_alg_dma(bit_mode);
let mut overrides =
build_cs_overrides(cs_data_layout, set_type, cs_config, secondary_cs_configs);
if let OneromAlgDataConfig::AlgData1 { byte_pin, .. } = &alg_data {
let abs_gpio = byte_pin + cs_data_layout.gpio_base;
overrides.push(encode_override(abs_gpio, GpioOverride::GpioOverInvert));
}
overrides.extend(build_gpio_x_overrides(
addr_layout,
set_type,
num_chips,
board,
));
overrides.extend(build_unused_addr_overrides(
addr_layout,
cs_data_layout,
&alg_data,
));
let gpio_override_config = if overrides.is_empty() {
None
} else {
Some(OneromAlgOverrideConfig { params: overrides })
};
let gpio_pull_config = build_gpio_pull_config(addr_layout, set_type, num_chips, board);
OneromAlgConfig {
alg_cs,
alg_addr,
alg_data,
alg_dma,
gpio_pull_config,
gpio_override_config,
}
}
#[cfg(test)]
mod tests {
use super::super::addr_layout::derive_addr_layout;
use super::super::alg_preference::{
AddrAlgPreference, CombinedAlgPreference, CsAlgPreference, DataAlgPreference,
DmaAlgPreference,
};
use super::super::cs_data_layout::derive_cs_data_layout;
use super::super::slot_context::SlotContext;
use super::*;
use crate::image::{ChipSetType, CsConfig, CsLogic};
use onerom_metadata::OneromAlgCsConfig;
#[test]
fn fire24a_2364_single() {
let addr_layout = AddrLayout {
gpio_base: 0,
num_addr_pins: 16,
x1_gpio: None,
x2_gpio: None,
addr_pin_gpios: alloc::vec![7, 6, 5, 4, 3, 2, 1, 0, 10, 11, 14, 15, 12],
excess_addr_pin_gpios: alloc::vec![],
};
let cs_data_layout = CsDataLayout {
gpio_base: 0,
base_data_pin: 16,
num_data_pins: 8,
data_pin_gpios: alloc::vec![16, 17, 18, 19, 20, 21, 22, 23],
base_cs_pin: 13,
num_cs_pins: 1,
cs_ignore_index: None,
select_lines: alloc::vec![super::super::cs_data_layout::SelectLine {
role: super::super::cs_data_layout::SelectRole::Cs1,
gpio: 13,
}],
commoned_lines: alloc::vec![],
alg_cs2: None,
};
let alg_data = build_alg_data(&cs_data_layout, Board::Fire24A, BitModes::BitMode8, false);
assert_eq!(
alg_data,
OneromAlgDataConfig::AlgData0 {
clkdiv_int: 1,
clkdiv_frac: 0,
gpio_base: 0,
base_data_pin: 16,
word_size: 8,
}
);
let alg_addr = build_alg_addr(&addr_layout, &alg_data);
assert_eq!(
alg_addr,
OneromAlgAddrConfig::AlgAddr0 {
clkdiv_int: 1,
clkdiv_frac: 0,
gpio_base: 0,
num_delay_cycles: 2,
base_addr_pin: 0,
num_addr_pins: 16,
num_rom_table_bits: 16,
}
);
let alg_dma = build_alg_dma(BitModes::BitMode8);
assert_eq!(
alg_dma,
OneromAlgDmaConfig::AlgDma0 {
bit_mode: BitModes::BitMode8,
continuous: 1,
}
);
}
#[test]
fn fire24a_2364_single_full_config() {
let cs_config = CsConfig::new(Some(CsLogic::ActiveLow), None, None);
let ctx = SlotContext {
board: Board::Fire24A,
set_type: ChipSetType::Single,
chip_types: alloc::vec![ChipType::Chip2364],
cs_config,
bit_mode: bit_mode_for(ChipType::Chip2364, Board::Fire24A),
pin_offset: 0,
force_16_bit: false,
multi_cs_config: None,
};
assert_eq!(ctx.bit_mode, BitModes::BitMode8);
let addr_layout = derive_addr_layout(&ctx).expect("addr layout derivation should succeed");
let cs_data_layout = derive_cs_data_layout(&ctx, Some(&addr_layout))
.expect("cs/data layout derivation should succeed");
let config = build_alg_config(&ctx, &addr_layout, &cs_data_layout, &[]);
assert_eq!(
config,
OneromAlgConfig {
alg_cs: OneromAlgCsConfig::AlgCs0 {
clkdiv_int: 1,
clkdiv_frac: 0,
gpio_base: 0,
base_cs_pin: 13,
num_cs_pins: 1,
base_data_pin: 16,
num_data_pins: 8,
cs_active_delay: 0,
cs_inactive_delay: 0,
serve_cs_low_0: 0,
byte_pin: GPIO_NONE,
first_rom_cs_base: 13,
first_rom_num_cs_pins: 1,
},
alg_addr: OneromAlgAddrConfig::AlgAddr0 {
clkdiv_int: 1,
clkdiv_frac: 0,
gpio_base: 0,
num_delay_cycles: 2,
base_addr_pin: 0,
num_addr_pins: 16,
num_rom_table_bits: 16,
},
alg_data: OneromAlgDataConfig::AlgData0 {
clkdiv_int: 1,
clkdiv_frac: 0,
gpio_base: 0,
base_data_pin: 16,
word_size: 8,
},
alg_dma: OneromAlgDmaConfig::AlgDma0 {
bit_mode: BitModes::BitMode8,
continuous: 1,
},
gpio_pull_config: None,
gpio_override_config: Some(OneromAlgOverrideConfig {
params: alloc::vec![
encode_override(8, GpioOverride::GpioOverLow),
encode_override(9, GpioOverride::GpioOverLow),
],
}),
}
);
}
#[test]
fn fire24a_2364_banked_2chip_has_x_override() {
let cs_config = CsConfig::new(Some(CsLogic::ActiveLow), None, None);
let ctx = SlotContext {
board: Board::Fire24A,
set_type: ChipSetType::Banked,
chip_types: alloc::vec![ChipType::Chip2364, ChipType::Chip2364],
cs_config,
bit_mode: bit_mode_for(ChipType::Chip2364, Board::Fire24A),
pin_offset: 0,
force_16_bit: false,
multi_cs_config: None,
};
let addr_layout = derive_addr_layout(&ctx).expect("addr layout derivation should succeed");
let cs_data_layout = derive_cs_data_layout(&ctx, Some(&addr_layout))
.expect("cs/data layout derivation should succeed");
let config = build_alg_config(&ctx, &addr_layout, &cs_data_layout, &[]);
let ov = config
.gpio_override_config
.expect("banked on x_jumper_pull=0 board must have gpio_override_config");
assert_eq!(
ov.params.len(),
2,
"2-chip banked: X1 invert + X2 unused-low"
);
let x1_gpio = addr_layout
.x1_gpio
.expect("banked addr_layout must have x1_gpio");
assert_eq!(ov.params[0] >> 6, 1, "entry 0 must be GpioOverInvert type");
assert_eq!(
ov.params[0] & 0x3F,
x1_gpio,
"override GPIO must match addr_layout.x1_gpio"
);
assert_eq!(ov.params[1] >> 6, 2, "entry 1 must be GpioOverLow type");
assert_eq!(ov.params[1] & 0x3F, 8, "unused-low GPIO must be X2 (GPIO8)");
}
#[test]
fn fire28a_23ql384_single_full_config_alg_cs2() {
let cs_config = CsConfig::new(Some(CsLogic::ActiveLow), None, None);
let ctx = SlotContext {
board: Board::Fire28A,
set_type: ChipSetType::Single,
chip_types: alloc::vec![ChipType::Chip23QL384],
cs_config,
bit_mode: bit_mode_for(ChipType::Chip23QL384, Board::Fire28A),
pin_offset: 0,
force_16_bit: false,
multi_cs_config: None,
};
assert_eq!(ctx.bit_mode, BitModes::BitMode8);
let addr_layout = derive_addr_layout(&ctx).expect("addr layout derivation should succeed");
let cs_data_layout = derive_cs_data_layout(&ctx, Some(&addr_layout))
.expect("cs/data layout derivation should succeed");
let config = build_alg_config(&ctx, &addr_layout, &cs_data_layout, &[]);
assert_eq!(
config.alg_dma,
OneromAlgDmaConfig::AlgDma0 {
bit_mode: BitModes::BitMode8,
continuous: 1
}
);
match &config.alg_cs {
OneromAlgCsConfig::AlgCs2 {
clkdiv_int: _,
clkdiv_frac: _,
gpio_base: _,
base_cs_pin: _,
num_cs_pins: _,
base_data_pin: _,
num_data_pins: _,
cs_active_delay: _,
cs_inactive_delay: _,
base_qualifier_pin,
num_qualifier_pins,
qualifier_inactive_pattern,
} => {
assert_eq!(*num_qualifier_pins, 2);
assert_eq!(*qualifier_inactive_pattern, 0b11);
assert!(
*base_qualifier_pin < 32,
"base_qualifier_pin {base_qualifier_pin} out of PIO window"
);
}
other => panic!("expected AlgCs2 for 23QL384, got {other:?}"),
}
}
#[test]
fn fire40a_27c400_bitmode16_algdata1() {
let cs_data_layout = CsDataLayout {
gpio_base: 0,
base_data_pin: 0,
num_data_pins: 16,
data_pin_gpios: alloc::vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
base_cs_pin: 17,
num_cs_pins: 1,
cs_ignore_index: None,
select_lines: alloc::vec![super::super::cs_data_layout::SelectLine {
role: super::super::cs_data_layout::SelectRole::Ce,
gpio: 17,
}],
commoned_lines: alloc::vec![],
alg_cs2: None,
};
let addr_layout = AddrLayout {
gpio_base: 19,
num_addr_pins: 18,
x1_gpio: None,
x2_gpio: None,
addr_pin_gpios: alloc::vec![
36, 35, 34, 33, 32, 31, 30, 29, 27, 26, 25, 24, 23, 22, 21, 20, 19, 28
],
excess_addr_pin_gpios: alloc::vec![],
};
let alg_data = build_alg_data(&cs_data_layout, Board::Fire40A, BitModes::BitMode16, false);
assert_eq!(
alg_data,
OneromAlgDataConfig::AlgData1 {
clkdiv_int: 1,
clkdiv_frac: 0,
gpio_base: 0,
base_data_pin: 0,
word_size: 16,
byte_pin: 18,
a_minus_1_pin: 15,
}
);
let alg_addr = build_alg_addr(&addr_layout, &alg_data);
assert_eq!(
alg_addr,
OneromAlgAddrConfig::AlgAddr0 {
clkdiv_int: 1,
clkdiv_frac: 0,
gpio_base: 16,
num_delay_cycles: 4,
base_addr_pin: 3,
num_addr_pins: 18,
num_rom_table_bits: 19,
}
);
let alg_dma = build_alg_dma(BitModes::BitMode16);
assert_eq!(
alg_dma,
OneromAlgDmaConfig::AlgDma0 {
bit_mode: BitModes::BitMode16,
continuous: 1,
}
);
}
#[test]
fn fire40a_27c400_force_16bit_algdata0() {
let cs_data_layout = CsDataLayout {
gpio_base: 0,
base_data_pin: 0,
num_data_pins: 16,
data_pin_gpios: alloc::vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
base_cs_pin: 17,
num_cs_pins: 1,
cs_ignore_index: None,
select_lines: alloc::vec![super::super::cs_data_layout::SelectLine {
role: super::super::cs_data_layout::SelectRole::Ce,
gpio: 17,
}],
commoned_lines: alloc::vec![],
alg_cs2: None,
};
let addr_layout = AddrLayout {
gpio_base: 19,
num_addr_pins: 18,
x1_gpio: None,
x2_gpio: None,
addr_pin_gpios: alloc::vec![
36, 35, 34, 33, 32, 31, 30, 29, 27, 26, 25, 24, 23, 22, 21, 20, 19, 28
],
excess_addr_pin_gpios: alloc::vec![],
};
let alg_data = build_alg_data(&cs_data_layout, Board::Fire40A, BitModes::BitMode16, true);
assert_eq!(
alg_data,
OneromAlgDataConfig::AlgData0 {
clkdiv_int: 1,
clkdiv_frac: 0,
gpio_base: 0,
base_data_pin: 0,
word_size: 16,
}
);
let alg_addr = build_alg_addr(&addr_layout, &alg_data);
assert_eq!(
alg_addr,
OneromAlgAddrConfig::AlgAddr0 {
clkdiv_int: 1,
clkdiv_frac: 0,
gpio_base: 16,
num_delay_cycles: 2,
base_addr_pin: 3,
num_addr_pins: 18,
num_rom_table_bits: 19,
}
);
let alg_dma = build_alg_dma(BitModes::BitMode16);
assert_eq!(
alg_dma,
OneromAlgDmaConfig::AlgDma0 {
bit_mode: BitModes::BitMode16,
continuous: 1,
}
);
}
#[test]
fn combined_alg_preference_fire24a_2364() {
let cs_config = CsConfig::new(Some(CsLogic::ActiveLow), None, None);
let ctx = SlotContext {
board: Board::Fire24A,
set_type: ChipSetType::Single,
chip_types: alloc::vec![ChipType::Chip2364],
cs_config,
bit_mode: bit_mode_for(ChipType::Chip2364, Board::Fire24A),
pin_offset: 0,
force_16_bit: false,
multi_cs_config: None,
};
let addr_layout = derive_addr_layout(&ctx).expect("addr layout should succeed");
let cs_data_layout =
derive_cs_data_layout(&ctx, Some(&addr_layout)).expect("cs layout should succeed");
let config = build_alg_config(&ctx, &addr_layout, &cs_data_layout, &[]);
let pref: CombinedAlgPreference = combined_alg_preference(&config);
assert_eq!(
pref,
(
CsAlgPreference::AlgCs0,
AddrAlgPreference::AlgAddr0,
DataAlgPreference::AlgData0,
DmaAlgPreference::AlgDma0,
)
);
}
}