maurice_lib/hardware/
machine.rs1use 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 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 fn full_speed(&mut self) {
86 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 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 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 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 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 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 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}