rom.rsannotatedrom.rssource133 lines · 3.1 KB · raw
1#![allow(clippy::needless_range_loop)]
2
3use std::sync::LazyLock;
4
5const PI: f64 = std::f64::consts::PI;
6
7type Cx4Rom = [u32; 1024];
8
9pub fn read(address: u32) -> u32 {
10    static ROM: LazyLock<Box<Cx4Rom>> = LazyLock::new(|| {
11        let mut rom: Box<Cx4Rom> = vec![0; 1024].into_boxed_slice().try_into().unwrap();
12
13        populate_div(&mut rom);
14        populate_sqrt(&mut rom);
15        populate_sin(&mut rom);
16        populate_asin(&mut rom);
17        populate_tan(&mut rom);
18        populate_cos(&mut rom);
19
20        rom
21    });
22
23    ROM[(address & 0x3FF) as usize]
24}
25
26fn populate_div(rom: &mut Cx4Rom) {
27    // Division by 0 produces $FFFFFF (overflow)
28    rom[0] = 0xFFFFFF;
29
30    for i in 0x001..0x100 {
31        rom[i as usize] = 0x800000 / i;
32    }
33}
34
35fn populate_sqrt(rom: &mut Cx4Rom) {
36    for i in 0x100..0x200 {
37        let input = i - 0x100;
38        let scaled_sqrt = f64::from(0x100000) * (input as f64).sqrt();
39        rom[i] = (scaled_sqrt as u32) & 0xFFFFFF;
40    }
41}
42
43fn populate_sin(rom: &mut Cx4Rom) {
44    for i in 0x200..0x280 {
45        let input = i - 0x200;
46        let scaled_sin = f64::from(0x1000000) * (input as f64 / 256.0 * PI).sin();
47        rom[i] = (scaled_sin as u32) & 0xFFFFFF;
48    }
49}
50
51fn populate_asin(rom: &mut Cx4Rom) {
52    for i in 0x280..0x300 {
53        let input = i - 0x280;
54        let scaled_asin = f64::from(0x800000) / (PI / 2.0) * (input as f64 / 128.0).asin();
55        rom[i] = (scaled_asin as u32) & 0xFFFFFF;
56    }
57}
58
59fn populate_tan(rom: &mut Cx4Rom) {
60    for i in 0x300..0x380 {
61        let input = i - 0x300;
62        let scaled_tan = f64::from(0x10000) * (input as f64 / 256.0 * PI).tan();
63        rom[i] = (scaled_tan as u32) & 0xFFFFFF;
64    }
65
66    // tan(pi / 4) is defined as 1; without this the value will be ~0.9999999
67    rom[0x340] = 0x010000;
68}
69
70fn populate_cos(rom: &mut Cx4Rom) {
71    // cos(0) produces $FFFFFF (overflow)
72    rom[0x380] = 0xFFFFFF;
73
74    for i in 0x381..0x400 {
75        let input = i - 0x380;
76        let scaled_cos = f64::from(0x1000000) * (input as f64 / 256.0 * PI).cos();
77        rom[i] = (scaled_cos as u32) & 0xFFFFFF;
78    }
79}
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84
85    #[test]
86    fn div() {
87        assert_eq!(read(0x000), 0xFFFFFF);
88        assert_eq!(read(0x0FF), 0x008080);
89    }
90
91    #[test]
92    fn sqrt() {
93        assert_eq!(read(0x100), 0x000000);
94        assert_eq!(read(0x1FF), 0xFF7FDF);
95    }
96
97    #[test]
98    fn sin() {
99        assert_eq!(read(0x200), 0x000000);
100        assert_eq!(read(0x27F), 0xFFFB10);
101    }
102
103    #[test]
104    fn asin() {
105        assert_eq!(read(0x280), 0x000000);
106        assert_eq!(read(0x2FF), 0x75CEB4);
107    }
108
109    #[test]
110    fn tan() {
111        assert_eq!(read(0x300), 0x000000);
112        assert_eq!(read(0x37F), 0x517BB5);
113    }
114
115    #[test]
116    fn cos() {
117        assert_eq!(read(0x380), 0xFFFFFF);
118        assert_eq!(read(0x3FF), 0x03243A);
119    }
120
121    #[test]
122    fn sum() {
123        let mut sum = 0;
124        for i in 0..0x400 {
125            let value = read(i);
126            sum += value & 0xFF;
127            sum += (value >> 8) & 0xFF;
128            sum += (value >> 16) & 0xFF;
129        }
130
131        assert_eq!(sum, 0x054336);
132    }
133}