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
/// Abstraction of the device hosting the Z80 CPU
/// 
/// The device hosting the CPU has to provide implementations
/// of the memory and port access. A simple implementation is
/// provided with PlainMachine
pub trait Machine {
    /// Returns the memory contents in [address]
    fn peek(&self, address: u16) -> u8;

    /// Sets the memory content to [value] in [address]
    fn poke(&mut self, address: u16, value: u8);

    /// Returns the memory contents in [address] as word
    fn peek16(&self, address: u16) -> u16 {
        self.peek(address) as u16
        + ((self.peek(address.wrapping_add(1)) as u16) << 8)
    }

    /// Sets the memory content to the word [value] in [address]
    fn poke16(&mut self, address: u16, value: u16) {
        self.poke(address, value as u8 );
        self.poke(address.wrapping_add(1), (value >> 8) as u8);
    }

    /// Port in, from the device to the CPU. Returns the port value
    /// in the hosting device.
    fn port_in(&mut self, address: u16) -> u8;
    /// Port out, from the CPU to the device. Sets a port value on
    /// the hosting device.
    fn port_out(&mut self, address: u16, value: u8);
}

/// A simple Machine implementation
/// 
/// A minimum implementation of Machine. It uses two arrays of 65536 bytes to back the peeks and
/// pokes to memory and the ins and outs of ports.
pub struct PlainMachine {
    mem: [u8; 65536],
    io: [u8; 65536]
}

impl PlainMachine {
    /// Returns a new PlainMachine instance
    pub fn new() -> PlainMachine {
        PlainMachine {
            mem: [0; 65536],
            io: [0; 65536]
        }
    }
}

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

impl Machine for PlainMachine {
    fn peek(&self, address: u16) -> u8 {
        self.mem[address as usize]
    }
    fn poke(&mut self, address: u16, value: u8) {
        self.mem[address as usize] = value;
    }

    fn port_in(&mut self, address: u16) -> u8 {
        self.io[address as usize]
    }
    fn port_out(&mut self, address: u16, value: u8) {
        self.io[address as usize] = value;
    }
}



#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn set_get_byte() {
        let mut m = PlainMachine::new();
        const A:u16 = 0x2345;
        const V:u8 = 0xa0;

        m.poke(A, V);
        assert_eq!(V, m.peek(A));
    }
}