Skip to main content

maurice_lib/hardware/
machine.rs

1use crate::hardware::keyboard::Keyboard;
2
3use crate::hardware::k7::K7;
4use crate::hardware::memory::Memory;
5use crate::hardware::screen::Screen;
6use crate::hardware::sound::Sound;
7use crate::hardware::M6809::{unassemble, M6809};
8use crate::int;
9use crate::raw_image::RawImage;
10use chrono::{DateTime, Local};
11use log::{debug, info};
12
13pub struct Machine {
14    // Emulation Objects
15    pub(crate) mem: Memory,
16    pub(crate) micro: M6809,
17    pub(crate) screen: Screen,
18    sound: Sound,
19    pub(crate) keyboard: Keyboard,
20    pub(crate) irq: bool,
21    pub(crate) last_time: DateTime<Local>,
22    pub(crate) running: bool,
23    #[cfg(target_arch = "wasm32")]
24    waiting: web_time::Instant,
25    #[cfg(target_arch = "wasm32")]
26    sleeptime: u128,
27}
28
29impl Default for Machine {
30    fn default() -> Self {
31        info!("Machine created");
32        let screen = Screen::new(get_ratio());
33        info!("Machine created");
34        let mut mem = Memory::default();
35        info!("Memory created");
36        mem.reset();
37        let micro = M6809::new(&mem);
38        info!("CPU created");
39        Self {
40            mem,
41            micro,
42            screen,
43            sound: Sound::new(),
44            keyboard: Keyboard::default(),
45            last_time: Local::now(),
46            irq: false,
47            running: true,
48            #[cfg(target_arch = "wasm32")]
49            waiting: web_time::Instant::now(),
50            #[cfg(target_arch = "wasm32")]
51            sleeptime: 0,
52        }
53    }
54}
55
56impl Machine {
57    pub fn run_loop(&mut self) -> Option<RawImage> {
58        #[cfg(debug_assertions)]
59        debug!("run_loop");
60        if self.running {
61            self.run();
62            self.screen.paint(&mut self.mem);
63            let raw_image = self.screen.get_pixels();
64            Some(raw_image)
65        } else {
66            None
67        }
68    }
69
70    #[cfg(not(target_family = "wasm"))]
71    pub(crate) fn run(&mut self) {
72        self.full_speed();
73        self.synchronize();
74    }
75
76    #[cfg(target_arch = "wasm32")]
77    pub(crate) fn run(&mut self) {
78        if self.waiting.elapsed().as_millis() > self.sleeptime {
79            self.full_speed();
80            self.synchronize();
81        }
82    }
83
84    // the emulator main loop
85    fn full_speed(&mut self) {
86        // let cl;
87
88        // Mise a jour du crayon optique a partir des donnée de la souris souris
89        self.mem.light_pen_clic = self.screen.mouse_clic;
90        self.mem.light_pen_x = self.screen.mouse_x;
91        self.mem.light_pen_y = self.screen.mouse_y;
92
93        self.mem.set(0xA7E7, 0x00);
94        self.mem.GA3 = 0x00;
95        /* 3.9 ms haut �cran (+0.3 irq)*/
96        if self.irq {
97            self.irq = false;
98            self.micro
99                .FetchUntil(3800, &mut self.mem, &mut self.screen, &mut self.sound);
100        } else {
101            self.micro
102                .FetchUntil(4100, &mut self.mem, &mut self.screen, &mut self.sound);
103        }
104
105        /* 13ms fenetre */
106        self.mem.set(0xA7E7, 0x80);
107        self.mem.GA3 = 0x80;
108        self.micro
109            .FetchUntil(13100, &mut self.mem, &mut self.screen, &mut self.sound);
110
111        self.mem.set(0xA7E7, 0x00);
112        self.mem.GA3 = 0x00;
113        self.micro
114            .FetchUntil(2800, &mut self.mem, &mut self.screen, &mut self.sound);
115
116        if (self.mem.CRB & 0x01) == 0x01 {
117            self.irq = true;
118            /* Positionne le bit 7 de CRB */
119            self.mem.CRB |= 0x80;
120            self.mem.set(0xA7C3, self.mem.CRB);
121            let cc = self.micro.readCC();
122            if (cc & 0x10) == 0 {
123                self.micro.IRQ(&mut self.mem);
124            }
125            /* 300 cycles sous interrupt */
126            self.micro
127                .FetchUntil(300, &mut self.mem, &mut self.screen, &mut self.sound);
128            self.mem.CRB &= 0x7F;
129            self.mem.set(0xA7C3, self.mem.CRB);
130        }
131    }
132
133    fn synchronize(&mut self) {
134        let real_time_millis: i64 =
135            Local::now().timestamp_millis() - self.last_time.timestamp_millis();
136
137        let sleep_millis: i64 = 20i64 - real_time_millis - 1;
138        if sleep_millis < 0 {
139            self.last_time = Local::now();
140            return;
141        }
142
143        #[cfg(target_arch = "wasm32")]
144        {
145            self.sleeptime = sleep_millis as u128;
146            self.waiting = web_time::Instant::now();
147        }
148
149        #[cfg(not(target_family = "wasm"))]
150        std::thread::sleep(std::time::Duration::from_millis(sleep_millis as u64));
151        self.last_time = Local::now();
152    }
153
154    pub fn set_k7(&mut self, k7: K7) {
155        info!("Machine::set_k7_data()");
156        self.mem.set_k7(k7);
157    }
158
159    pub(crate) fn rewind_k7(&mut self) {
160        info!("Machine::rewind_k7()");
161        self.mem.rewind_k7();
162    }
163
164    pub(crate) fn stop(&mut self) {
165        info!("Machine::stop()");
166        self.running = false;
167    }
168
169    pub(crate) fn start(&mut self) {
170        info!("Machine::start()");
171        self.running = true;
172    }
173
174    // soft reset method ("reinit prog" button on original MO5)
175    pub(crate) fn reset_soft(&mut self) {
176        info!("Machine::reset_soft()");
177        self.running = false;
178        self.micro.reset(&self.mem);
179        self.running = true;
180    }
181
182    // hard reset (match off and on)
183    pub(crate) fn reset_hard(&mut self) {
184        info!("Machine::reset_hard()");
185        self.running = false;
186        for i in 0x2000..0x3000 {
187            self.mem.set(i, 0);
188        }
189        self.micro.reset(&self.mem);
190        self.running = true;
191    }
192
193    pub(crate) fn dump_registers(&mut self) -> String {
194        self.micro.print_state()
195    }
196
197    pub(crate) fn unassemble_from_pc(&self, nblines: int, mem: &Memory) -> String {
198        unassemble(self.micro.PC, nblines, mem)
199    }
200}
201
202fn get_ratio() -> usize {
203    crate::hardware::screen::DEFAULT_PIXEL_SIZE
204}