rom.rsannotatedrom.rssource78 lines · 2.1 KB · raw
1pub fn mirror_to_next_power_of_two(rom: &mut Vec<u8>) {
2    if rom.is_empty() {
3        log::error!("Cannot mirror empty ROM");
4        return;
5    }
6
7    let ones_count = rom.len().count_ones();
8    if ones_count == 1 {
9        // ROM size is already a power of two
10        return;
11    }
12
13    let trailing_zeroes = rom.len().trailing_zeros();
14    let source_len = 1 << trailing_zeroes;
15    let source_mask = source_len - 1;
16
17    let remaining_rom_len = rom.len() & !source_len;
18    let copy_len = (1 << (remaining_rom_len.trailing_zeros())) - source_len;
19
20    log::debug!(
21        "ROM len is {}; duplicating last {source_len} bytes of ROM to last {copy_len} bytes",
22        rom.len()
23    );
24
25    let base_addr = rom.len() & !source_len;
26    for i in 0..copy_len {
27        rom.push(rom[base_addr + (i & source_mask)]);
28    }
29
30    // Recurse in case there are more than 2 ROM chips (e.g. fan translated version of Daikaijuu
31    // Monogatari II which is 5.5MB)
32    mirror_to_next_power_of_two(rom);
33}
34
35#[cfg(test)]
36mod tests {
37    use super::*;
38    use std::array;
39
40    fn new_vec<const LEN: usize>() -> Vec<u8> {
41        Vec::from(array::from_fn::<u8, LEN, _>(|i| i as u8))
42    }
43
44    #[test]
45    fn mirror_empty_rom() {
46        let mut rom = vec![];
47        mirror_to_next_power_of_two(&mut rom);
48        assert_eq!(rom, vec![]);
49    }
50
51    #[test]
52    fn mirror_power_of_two() {
53        let mut rom = new_vec::<8>();
54        mirror_to_next_power_of_two(&mut rom);
55        assert_eq!(rom, vec![0, 1, 2, 3, 4, 5, 6, 7]);
56    }
57
58    #[test]
59    fn mirror_6_to_8() {
60        let mut rom = new_vec::<6>();
61        mirror_to_next_power_of_two(&mut rom);
62        assert_eq!(rom, vec![0, 1, 2, 3, 4, 5, 4, 5]);
63    }
64
65    #[test]
66    fn mirror_5_to_8() {
67        let mut rom = new_vec::<5>();
68        mirror_to_next_power_of_two(&mut rom);
69        assert_eq!(rom, vec![0, 1, 2, 3, 4, 4, 4, 4]);
70    }
71
72    #[test]
73    fn mirror_11_to_16() {
74        let mut rom = new_vec::<11>();
75        mirror_to_next_power_of_two(&mut rom);
76        assert_eq!(rom, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 8, 9, 10, 10]);
77    }
78}