1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
 * File: header.rs
 * Project: cpu
 * Created Date: 02/05/2022
 * Author: Shun Suzuki
 * -----
 * Last Modified: 19/05/2023
 * Modified By: Shun Suzuki (suzuki@hapis.k.u-tokyo.ac.jp)
 * -----
 * Copyright (c) 2022-2023 Shun Suzuki. All rights reserved.
 *
 */

use crate::{cpu::CPUControlFlags, fpga::FPGAControlFlags};

pub const MSG_CLEAR: u8 = 0x00;
pub const MSG_RD_CPU_VERSION: u8 = 0x01;
pub const MSG_RD_FPGA_VERSION: u8 = 0x03;
pub const MSG_RD_FPGA_FUNCTION: u8 = 0x04;
pub const MSG_BEGIN: u8 = 0x05;
pub const MSG_END: u8 = 0xF0;
pub const MSG_RD_CPU_VERSION_MINOR: u8 = 0xF1;
pub const MSG_RD_FPGA_VERSION_MINOR: u8 = 0xF2;
pub const MSG_SERVER_CLOSE: u8 = 0xFD;
pub const MSG_SIMULATOR_CLOSE: u8 = 0xFE;
pub const MSG_SIMULATOR_INIT: u8 = 0xFF;

pub const MOD_HEADER_INITIAL_DATA_SIZE: usize = 120;
pub const MOD_HEADER_SUBSEQUENT_DATA_SIZE: usize = 124;

#[derive(Clone, Copy)]
#[repr(C)]
pub struct GlobalHeader {
    pub msg_id: u8,
    pub fpga_flag: FPGAControlFlags,
    pub cpu_flag: CPUControlFlags,
    pub size: u8,
    pub data: [u8; 124],
}

#[repr(C)]
pub struct ModInitial {
    pub freq_div: u32,
    pub data: [u8; MOD_HEADER_INITIAL_DATA_SIZE],
}

#[repr(C)]
pub struct ModSubsequent {
    pub data: [u8; MOD_HEADER_SUBSEQUENT_DATA_SIZE],
}

#[repr(C)]
pub struct SilencerHeader {
    _cycle: u16,
    pub step: u16,
    _unused: [u8; 120],
}

impl GlobalHeader {
    pub fn new() -> Self {
        Self {
            msg_id: 0,
            fpga_flag: FPGAControlFlags::NONE,
            cpu_flag: CPUControlFlags::NONE,
            size: 0,
            data: [0x00; 124],
        }
    }

    pub fn mod_initial(&self) -> &ModInitial {
        unsafe { std::mem::transmute(&self.data) }
    }

    pub fn mod_initial_mut(&mut self) -> &mut ModInitial {
        unsafe { std::mem::transmute(&mut self.data) }
    }

    pub fn mod_subsequent(&self) -> &ModSubsequent {
        unsafe { std::mem::transmute(&self.data) }
    }

    pub fn mod_subsequent_mut(&mut self) -> &mut ModSubsequent {
        unsafe { std::mem::transmute(&mut self.data) }
    }

    pub fn silencer(&self) -> &SilencerHeader {
        unsafe { std::mem::transmute(&self.data) }
    }

    pub fn silencer_mut(&mut self) -> &mut SilencerHeader {
        unsafe { std::mem::transmute(&mut self.data) }
    }
}

impl Default for GlobalHeader {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use std::mem::size_of;

    use super::*;

    #[test]
    fn mod_header_initial() {
        assert_eq!(size_of::<ModInitial>(), 124);

        let header = ModInitial {
            freq_div: 0x01234567,
            data: (0..MOD_HEADER_INITIAL_DATA_SIZE)
                .map(|i| i as u8)
                .collect::<Vec<_>>()
                .try_into()
                .unwrap(),
        };

        let mut buf = vec![0x00; 124];
        unsafe {
            std::ptr::copy_nonoverlapping(&header as *const _ as *const u8, buf.as_mut_ptr(), 124);
        }
        assert_eq!(buf[0], 0x67);
        assert_eq!(buf[1], 0x45);
        assert_eq!(buf[2], 0x23);
        assert_eq!(buf[3], 0x01);
        for i in 0..MOD_HEADER_INITIAL_DATA_SIZE {
            assert_eq!(buf[4 + i], i as u8);
        }
    }

    #[test]
    fn mod_header_subsequent() {
        assert_eq!(size_of::<ModSubsequent>(), 124);
    }

    #[test]
    fn silencer_header() {
        assert_eq!(size_of::<SilencerHeader>(), 124);

        let header = SilencerHeader {
            _cycle: 0,
            step: 0x4567,
            _unused: [0x00; 120],
        };

        let mut buf = vec![0x00; 124];
        unsafe {
            std::ptr::copy_nonoverlapping(&header as *const _ as *const u8, buf.as_mut_ptr(), 124);
        }
        assert_eq!(buf[2], 0x67);
        assert_eq!(buf[3], 0x45);
    }

    #[test]
    fn global_header() {
        assert_eq!(size_of::<GlobalHeader>(), 128);

        let header = GlobalHeader {
            msg_id: 0x01,
            fpga_flag: FPGAControlFlags::FORCE_FAN,
            cpu_flag: CPUControlFlags::CONFIG_SYNC,
            size: 0x02,
            data: (0..124)
                .map(|i| i as u8)
                .collect::<Vec<_>>()
                .try_into()
                .unwrap(),
        };

        let mut buf = vec![0x00; 128];
        unsafe {
            std::ptr::copy_nonoverlapping(&header as *const _ as *const u8, buf.as_mut_ptr(), 128);
        }
        assert_eq!(buf[0], 0x01);
        assert_eq!(buf[1], 1 << 4);
        assert_eq!(buf[2], 1 << 2);
        assert_eq!(buf[3], 0x02);
        for i in 0..124 {
            assert_eq!(buf[4 + i], i as u8);
        }
    }
}