1#![allow(
19 clippy::doc_markdown,
20 clippy::struct_excessive_bools,
21 clippy::cast_possible_truncation,
22 clippy::cast_possible_wrap,
23 clippy::cast_sign_loss,
24 clippy::similar_names,
25 clippy::missing_const_for_fn
30)]
31
32use alloc::boxed::Box;
33
34use rustysnes_savestate::{SaveReader, SaveStateError, SaveWriter};
35
36pub trait Hg51bBus {
42 fn is_rom(&self, address: u32) -> bool;
44 fn is_ram(&self, address: u32) -> bool;
46 fn read(&mut self, address: u32) -> u8;
48 fn write(&mut self, address: u32, data: u8);
50}
51
52#[derive(Debug, Clone, Copy, Default)]
53struct Registers {
54 pb: u16, pc: u8, n: bool, z: bool, c: bool, v: bool, i: bool, a: u32, p: u16, mul: u64, mdr: u32, rom: u32, ram: u32, mar: u32, dpr: u32, gpr: [u32; 16],
70}
71
72#[derive(Debug, Clone, Copy, Default)]
73struct CacheState {
74 enable: bool,
75 page: bool,
76 lock: [bool; 2],
77 address: [u32; 2],
78 base: u32,
79 pb: u16,
80 pc: u8,
81}
82
83#[derive(Debug, Clone, Copy, Default)]
84struct DmaState {
85 enable: bool,
86 source: u32,
87 target: u32,
88 length: u16,
89}
90
91#[derive(Debug, Clone, Copy, Default)]
92struct BusState {
93 enable: bool,
94 reading: bool,
95 writing: bool,
96 pending: u32,
97 address: u32,
98}
99
100#[derive(Debug, Clone, Copy, Default)]
101struct Wait {
102 rom: u32,
103 ram: u32,
104}
105
106#[derive(Debug, Clone, Copy, Default)]
107struct Suspend {
108 enable: bool,
109 duration: u32,
110}
111
112#[derive(Debug, Clone, Copy)]
113struct Io {
114 lock: bool,
115 halt: bool, irq: bool, rom_mapping: bool,
118 vector: [u8; 32],
119 wait: Wait,
120 suspend: Suspend,
121 cache: CacheState,
122 dma: DmaState,
123 bus: BusState,
124}
125
126impl Default for Io {
127 fn default() -> Self {
128 Self {
129 lock: false,
130 halt: true,
131 irq: false,
132 rom_mapping: true,
133 vector: [0; 32],
134 wait: Wait::default(),
135 suspend: Suspend::default(),
136 cache: CacheState::default(),
137 dma: DmaState::default(),
138 bus: BusState::default(),
139 }
140 }
141}
142
143pub struct Hg51b {
150 r: Registers,
151 io: Io,
152 program_ram: Box<[[u16; 256]; 2]>,
153 data_rom: Box<[u32; 1024]>,
154 data_ram: Box<[u8; 3072]>,
155 stack: [u32; 8],
156 data_rom_loaded: bool,
157 instructions_run: u64,
159}
160
161const RUN_CAP: u64 = 20_000_000;
164
165impl core::fmt::Debug for Hg51b {
166 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
167 f.debug_struct("Hg51b")
168 .field("halted", &self.io.halt)
169 .field("data_rom_loaded", &self.data_rom_loaded)
170 .field("pb", &self.r.pb)
171 .field("pc", &self.r.pc)
172 .field("instructions_run", &self.instructions_run)
173 .finish_non_exhaustive()
174 }
175}
176
177impl Default for Hg51b {
178 fn default() -> Self {
179 Self::new()
180 }
181}
182
183impl Hg51b {
184 #[must_use]
187 pub fn new() -> Self {
188 Self {
189 r: Registers::default(),
190 io: Io::default(),
191 program_ram: Box::new([[0u16; 256]; 2]),
192 data_rom: Box::new([0u32; 1024]),
193 data_ram: Box::new([0u8; 3072]),
194 stack: [0; 8],
195 data_rom_loaded: false,
196 instructions_run: 0,
197 }
198 }
199
200 pub fn load_data_rom(&mut self, bytes: &[u8]) -> bool {
203 if bytes.len() < self.data_rom.len() * 3 {
204 return false;
205 }
206 for (i, word) in self.data_rom.iter_mut().enumerate() {
207 let o = i * 3;
208 *word =
209 u32::from(bytes[o]) | u32::from(bytes[o + 1]) << 8 | u32::from(bytes[o + 2]) << 16;
210 }
211 self.data_rom_loaded = true;
212 true
213 }
214
215 #[must_use]
217 pub const fn data_rom_loaded(&self) -> bool {
218 self.data_rom_loaded
219 }
220
221 #[must_use]
223 pub const fn instructions_run(&self) -> u64 {
224 self.instructions_run
225 }
226
227 #[must_use]
232 pub fn read_dram(&self, offset: u32) -> u8 {
233 let a = Self::fold_dram(offset);
234 if a >= 0xC00 {
235 0
236 } else {
237 self.data_ram[a as usize]
238 }
239 }
240
241 pub fn write_dram(&mut self, offset: u32, data: u8) {
243 let a = Self::fold_dram(offset);
244 if a < 0xC00 {
245 self.data_ram[a as usize] = data;
246 }
247 }
248
249 const fn fold_dram(offset: u32) -> u32 {
250 let a = offset & 0xFFF;
251 if a >= 0xC00 { a - 0x400 } else { a }
252 }
253
254 #[must_use]
258 pub fn read_io(&mut self, local: u32) -> u8 {
259 match local {
260 0x7F40 => byte(self.io.dma.source, 0),
261 0x7F41 => byte(self.io.dma.source, 1),
262 0x7F42 => byte(self.io.dma.source, 2),
263 0x7F43 => (self.io.dma.length & 0xFF) as u8,
264 0x7F44 => (self.io.dma.length >> 8) as u8,
265 0x7F45 => byte(self.io.dma.target, 0),
266 0x7F46 => byte(self.io.dma.target, 1),
267 0x7F47 => byte(self.io.dma.target, 2),
268 0x7F48 => u8::from(self.io.cache.page),
269 0x7F49 => byte(self.io.cache.base, 0),
270 0x7F4A => byte(self.io.cache.base, 1),
271 0x7F4B => byte(self.io.cache.base, 2),
272 0x7F4C => u8::from(self.io.cache.lock[0]) | (u8::from(self.io.cache.lock[1]) << 1),
273 0x7F4D => (self.io.cache.pb & 0xFF) as u8,
274 0x7F4E => (self.io.cache.pb >> 8) as u8,
275 0x7F4F => self.io.cache.pc,
276 0x7F50 => (self.io.wait.ram as u8) | ((self.io.wait.rom as u8) << 4),
277 0x7F51 => u8::from(self.io.irq),
278 0x7F52 => u8::from(self.io.rom_mapping),
279 0x7F53 | 0x7F54 | 0x7F55 | 0x7F56 | 0x7F57 | 0x7F59 | 0x7F5B | 0x7F5C | 0x7F5D
280 | 0x7F5E | 0x7F5F => {
281 u8::from(self.io.suspend.enable)
282 | (u8::from(self.r.i) << 1)
283 | (u8::from(self.running()) << 6)
284 | (u8::from(self.busy()) << 7)
285 }
286 0x7F60..=0x7F7F => self.io.vector[(local & 0x1F) as usize],
287 0x7F80..=0x7FAF | 0x7FC0..=0x7FEF => {
288 let a = local & 0x3F;
289 byte(self.r.gpr[(a / 3) as usize], (a % 3) as u8)
290 }
291 _ => 0,
292 }
293 }
294
295 pub fn write_io(&mut self, local: u32, data: u8, bus: &mut impl Hg51bBus) {
298 match local {
299 0x7F40 => set_byte(&mut self.io.dma.source, 0, data),
300 0x7F41 => set_byte(&mut self.io.dma.source, 1, data),
301 0x7F42 => set_byte(&mut self.io.dma.source, 2, data),
302 0x7F43 => self.io.dma.length = (self.io.dma.length & 0xFF00) | u16::from(data),
303 0x7F44 => self.io.dma.length = (self.io.dma.length & 0x00FF) | (u16::from(data) << 8),
304 0x7F45 => set_byte(&mut self.io.dma.target, 0, data),
305 0x7F46 => set_byte(&mut self.io.dma.target, 1, data),
306 0x7F47 => {
307 set_byte(&mut self.io.dma.target, 2, data);
308 if self.io.halt {
309 self.io.dma.enable = true;
310 self.run_until_halt(bus);
311 }
312 }
313 0x7F48 => {
314 self.io.cache.page = data & 1 != 0;
315 if self.io.halt {
316 self.io.cache.enable = true;
317 self.run_until_halt(bus);
318 }
319 }
320 0x7F49 => set_byte(&mut self.io.cache.base, 0, data),
321 0x7F4A => set_byte(&mut self.io.cache.base, 1, data),
322 0x7F4B => set_byte(&mut self.io.cache.base, 2, data),
323 0x7F4C => {
324 self.io.cache.lock[0] = data & 1 != 0;
325 self.io.cache.lock[1] = data & 2 != 0;
326 }
327 0x7F4D => self.io.cache.pb = (self.io.cache.pb & 0xFF00) | u16::from(data),
328 0x7F4E => {
329 self.io.cache.pb = (self.io.cache.pb & 0x00FF) | (u16::from(data & 0x7F) << 8);
330 }
331 0x7F4F => {
332 self.io.cache.pc = data;
333 if self.io.halt {
334 self.io.halt = false;
335 self.r.pb = self.io.cache.pb;
336 self.r.pc = self.io.cache.pc;
337 self.run_until_halt(bus);
338 }
339 }
340 0x7F50 => {
341 self.io.wait.ram = u32::from(data & 7);
342 self.io.wait.rom = u32::from((data >> 4) & 7);
343 }
344 0x7F51 => self.io.irq = data & 1 != 0,
345 0x7F52 => self.io.rom_mapping = data & 1 != 0,
346 0x7F53 => {
347 self.io.lock = false;
348 self.io.halt = true;
349 }
350 0x7F55 => {
351 self.io.suspend.enable = true;
352 self.io.suspend.duration = 0;
353 }
354 0x7F56 => {
355 self.io.suspend.enable = true;
356 self.io.suspend.duration = 32;
357 }
358 0x7F57 => {
359 self.io.suspend.enable = true;
360 self.io.suspend.duration = 64;
361 }
362 0x7F58 => {
363 self.io.suspend.enable = true;
364 self.io.suspend.duration = 96;
365 }
366 0x7F59 => {
367 self.io.suspend.enable = true;
368 self.io.suspend.duration = 128;
369 }
370 0x7F5A => {
371 self.io.suspend.enable = true;
372 self.io.suspend.duration = 160;
373 }
374 0x7F5B => {
375 self.io.suspend.enable = true;
376 self.io.suspend.duration = 192;
377 }
378 0x7F5C => {
379 self.io.suspend.enable = true;
380 self.io.suspend.duration = 224;
381 }
382 0x7F5D => self.io.suspend.enable = false,
383 0x7F5E => self.r.i = false,
384 0x7F60..=0x7F7F => self.io.vector[(local & 0x1F) as usize] = data,
385 0x7F80..=0x7FAF | 0x7FC0..=0x7FEF => {
386 let a = local & 0x3F;
387 set_byte(&mut self.r.gpr[(a / 3) as usize], (a % 3) as u8, data);
388 }
389 _ => {}
390 }
391 }
392
393 #[must_use]
395 pub const fn running(&self) -> bool {
396 self.io.cache.enable || self.io.dma.enable || self.io.bus.pending > 0 || !self.io.halt
397 }
398
399 #[must_use]
401 pub const fn busy(&self) -> bool {
402 self.io.cache.enable || self.io.dma.enable || self.io.bus.pending > 0
403 }
404
405 #[must_use]
408 pub const fn irq_pending(&self) -> bool {
409 self.r.i
410 }
411
412 pub fn run_until_halt(&mut self, bus: &mut impl Hg51bBus) {
415 if !self.data_rom_loaded {
416 return;
417 }
418 let mut n = 0u64;
419 while (self.io.lock
425 || self.io.suspend.enable
426 || self.io.cache.enable
427 || self.io.dma.enable
428 || !self.io.halt)
429 && n < RUN_CAP
430 {
431 self.main(bus);
432 n += 1;
433 self.instructions_run += 1;
434 }
435 }
436
437 fn main(&mut self, bus: &mut impl Hg51bBus) {
438 if self.io.lock {
439 return self.step(1);
440 }
441 if self.io.suspend.enable {
442 return self.suspend();
443 }
444 if self.io.cache.enable {
445 self.cache(bus);
446 return;
447 }
448 if self.io.dma.enable {
449 return self.dma(bus);
450 }
451 if self.io.halt {
452 return self.step(1);
453 }
454 self.execute(bus);
455 }
456
457 fn step(&mut self, clocks: u32) {
458 if !self.io.bus.enable {
459 return;
460 }
461 if self.io.bus.pending > clocks {
462 self.io.bus.pending -= clocks;
463 } else {
464 self.io.bus.enable = false;
465 self.io.bus.pending = 0;
466 }
467 }
468
469 fn finish_bus_access(&mut self, bus: &mut impl Hg51bBus) {
473 if self.io.bus.enable && self.io.bus.pending == 0 {
474 self.io.bus.enable = false;
475 if self.io.bus.reading {
476 self.io.bus.reading = false;
477 self.r.mdr = u32::from(bus.read(self.io.bus.address));
478 }
479 if self.io.bus.writing {
480 self.io.bus.writing = false;
481 bus.write(self.io.bus.address, self.r.mdr as u8);
482 }
483 }
484 }
485
486 fn wait(&self, address: u32, bus: &impl Hg51bBus) -> u32 {
487 if bus.is_rom(address) {
488 return 1 + self.io.wait.rom;
489 }
490 if bus.is_ram(address) {
491 return 1 + self.io.wait.ram;
492 }
493 1
494 }
495
496 fn execute(&mut self, bus: &mut impl Hg51bBus) {
497 if !self.cache(bus) {
498 self.io.halt = true;
499 return;
500 }
501 let opcode = self.program_ram[usize::from(self.io.cache.page)][usize::from(self.r.pc)];
502 self.advance(bus);
503 self.step(1);
504 self.dispatch(opcode, bus);
505 }
506
507 fn advance(&mut self, bus: &mut impl Hg51bBus) {
508 let (pc, overflow) = self.r.pc.overflowing_add(1);
509 self.r.pc = pc;
510 if overflow {
511 if self.io.cache.page {
512 self.io.halt = true;
513 return;
514 }
515 self.io.cache.page = true;
516 if self.io.cache.lock[usize::from(self.io.cache.page)] {
517 self.io.halt = true;
518 return;
519 }
520 self.r.pb = self.r.p;
521 if !self.cache(bus) {
522 self.io.halt = true;
523 }
524 }
525 }
526
527 fn suspend(&mut self) {
528 if self.io.suspend.duration == 0 {
529 self.step(1);
530 return;
531 }
532 self.step(self.io.suspend.duration);
533 self.io.suspend.duration = 0;
534 self.io.suspend.enable = false;
535 }
536
537 fn cache(&mut self, bus: &mut impl Hg51bBus) -> bool {
540 let address = self.io.cache.base.wrapping_add(u32::from(self.r.pb) * 512);
541 if self.io.cache.address[usize::from(self.io.cache.page)] == address {
542 self.io.cache.enable = false;
543 return true;
544 }
545 self.io.cache.page = !self.io.cache.page;
546 if self.io.cache.address[usize::from(self.io.cache.page)] == address {
547 self.io.cache.enable = false;
548 return true;
549 }
550 if self.io.cache.lock[usize::from(self.io.cache.page)] {
551 self.io.cache.page = !self.io.cache.page;
552 }
553 if self.io.cache.lock[usize::from(self.io.cache.page)] {
554 self.io.cache.enable = false;
555 return false;
556 }
557
558 self.io.cache.address[usize::from(self.io.cache.page)] = address;
559 let mut a = address;
560 for offset in 0..256usize {
561 self.step(self.wait(a, bus));
562 let lo = bus.read(a);
563 a = a.wrapping_add(1);
564 let hi = bus.read(a);
565 a = a.wrapping_add(1);
566 self.program_ram[usize::from(self.io.cache.page)][offset] =
567 u16::from(lo) | (u16::from(hi) << 8);
568 }
569 self.io.cache.enable = false;
570 true
571 }
572
573 fn dma(&mut self, bus: &mut impl Hg51bBus) {
574 for offset in 0..u32::from(self.io.dma.length) {
575 let source = self.io.dma.source.wrapping_add(offset) & 0xFF_FFFF;
576 let target = self.io.dma.target.wrapping_add(offset) & 0xFF_FFFF;
577 if bus.is_rom(source) && bus.is_rom(target) {
578 self.io.lock = true;
579 return;
580 }
581 if bus.is_ram(source) && bus.is_ram(target) {
582 self.io.lock = true;
583 return;
584 }
585 self.step(self.wait(source, bus));
586 let data = bus.read(source);
587 self.step(self.wait(target, bus));
588 bus.write(target, data);
589 }
590 self.io.dma.enable = false;
591 }
592
593 fn read_register(&mut self, address: u16, bus: &mut impl Hg51bBus) -> u32 {
596 let v = match address {
597 0x01 => (self.r.mul >> 24) as u32 & 0xFF_FFFF,
598 0x02 => self.r.mul as u32 & 0xFF_FFFF,
599 0x03 => self.r.mdr,
600 0x08 => self.r.rom,
601 0x0C => self.r.ram,
602 0x13 => self.r.mar,
603 0x1C => self.r.dpr,
604 0x20 => u32::from(self.r.pc),
605 0x28 => u32::from(self.r.p),
606 0x2E => {
607 self.io.bus.enable = true;
608 self.io.bus.reading = true;
609 self.io.bus.pending = 1 + self.io.wait.rom;
610 self.io.bus.address = self.r.mar;
611 self.finish_bus_access(bus);
612 0
613 }
614 0x2F => {
615 self.io.bus.enable = true;
616 self.io.bus.reading = true;
617 self.io.bus.pending = 1 + self.io.wait.ram;
618 self.io.bus.address = self.r.mar;
619 self.finish_bus_access(bus);
620 0
621 }
622 0x51 => 0xFF_FFFF,
624 0x52 => 0x00_FF00,
625 0x53 => 0xFF_0000,
626 0x54 => 0x00_FFFF,
627 0x55 => 0xFF_FF00,
628 0x56 => 0x80_0000,
629 0x57 => 0x7F_FFFF,
630 0x58 => 0x00_8000,
631 0x59 => 0x00_7FFF,
632 0x5A => 0xFF_7FFF,
633 0x5B => 0xFF_FF7F,
634 0x5C => 0x01_0000,
635 0x5D => 0xFE_FFFF,
636 0x5E => 0x00_0100,
637 0x5F => 0x00_FEFF,
638 0x60..=0x7F => self.r.gpr[usize::from(address & 0xF)],
639 _ => 0,
640 };
641 v & 0xFF_FFFF
642 }
643
644 fn write_register(&mut self, address: u16, data: u32, bus: &mut impl Hg51bBus) {
645 let data = data & 0xFF_FFFF;
646 match address {
647 0x01 => self.r.mul = (self.r.mul & 0x00_FF_FF_FF) | (u64::from(data) << 24),
648 0x02 => self.r.mul = (self.r.mul & 0xFF_FF_FF_00_00_00) | u64::from(data),
649 0x03 => self.r.mdr = data,
650 0x08 => self.r.rom = data,
651 0x0C => self.r.ram = data,
652 0x13 => self.r.mar = data,
653 0x1C => self.r.dpr = data,
654 0x20 => self.r.pc = data as u8,
655 0x28 => self.r.p = data as u16 & 0x7FFF,
656 0x2E => {
657 self.io.bus.enable = true;
658 self.io.bus.writing = true;
659 self.io.bus.pending = 1 + self.io.wait.rom;
660 self.io.bus.address = self.r.mar;
661 self.finish_bus_access(bus);
662 }
663 0x2F => {
664 self.io.bus.enable = true;
665 self.io.bus.writing = true;
666 self.io.bus.pending = 1 + self.io.wait.ram;
667 self.io.bus.address = self.r.mar;
668 self.finish_bus_access(bus);
669 }
670 0x60..=0x7F => self.r.gpr[usize::from(address & 0xF)] = data,
671 _ => {}
672 }
673 }
674
675 pub fn save_state(&self, w: &mut SaveWriter) {
682 w.section(*b"HG51", |s| {
683 s.write_u16(self.r.pb);
684 s.write_u8(self.r.pc);
685 s.write_bool(self.r.n);
686 s.write_bool(self.r.z);
687 s.write_bool(self.r.c);
688 s.write_bool(self.r.v);
689 s.write_bool(self.r.i);
690 s.write_u32(self.r.a);
691 s.write_u16(self.r.p);
692 s.write_u64(self.r.mul);
693 s.write_u32(self.r.mdr);
694 s.write_u32(self.r.rom);
695 s.write_u32(self.r.ram);
696 s.write_u32(self.r.mar);
697 s.write_u32(self.r.dpr);
698 for &g in &self.r.gpr {
699 s.write_u32(g);
700 }
701 s.write_bool(self.io.lock);
702 s.write_bool(self.io.halt);
703 s.write_bool(self.io.irq);
704 s.write_bool(self.io.rom_mapping);
705 s.write_bytes(&self.io.vector);
706 s.write_u32(self.io.wait.rom);
707 s.write_u32(self.io.wait.ram);
708 s.write_bool(self.io.suspend.enable);
709 s.write_u32(self.io.suspend.duration);
710 s.write_bool(self.io.cache.enable);
711 s.write_bool(self.io.cache.page);
712 s.write_bool(self.io.cache.lock[0]);
713 s.write_bool(self.io.cache.lock[1]);
714 s.write_u32(self.io.cache.address[0]);
715 s.write_u32(self.io.cache.address[1]);
716 s.write_u32(self.io.cache.base);
717 s.write_u16(self.io.cache.pb);
718 s.write_u8(self.io.cache.pc);
719 s.write_bool(self.io.dma.enable);
720 s.write_u32(self.io.dma.source);
721 s.write_u32(self.io.dma.target);
722 s.write_u16(self.io.dma.length);
723 s.write_bool(self.io.bus.enable);
724 s.write_bool(self.io.bus.reading);
725 s.write_bool(self.io.bus.writing);
726 s.write_u32(self.io.bus.pending);
727 s.write_u32(self.io.bus.address);
728 for page in self.program_ram.iter() {
729 for &word in page {
730 s.write_u16(word);
731 }
732 }
733 for &byte in self.data_ram.iter() {
734 s.write_u8(byte);
735 }
736 for &word in &self.stack {
737 s.write_u32(word);
738 }
739 });
740 }
741
742 pub fn load_state(&mut self, r: &mut SaveReader) -> Result<(), SaveStateError> {
756 let mut s = r.expect_section(*b"HG51")?;
757 self.r.pb = s.read_u16()? & 0x7FFF;
758 self.r.pc = s.read_u8()?;
759 self.r.n = s.read_bool()?;
760 self.r.z = s.read_bool()?;
761 self.r.c = s.read_bool()?;
762 self.r.v = s.read_bool()?;
763 self.r.i = s.read_bool()?;
764 self.r.a = s.read_u32()? & 0xFF_FFFF;
765 self.r.p = s.read_u16()? & 0x7FFF;
766 self.r.mul = s.read_u64()? & 0xFF_FF_FF_FF_FF_FF;
767 self.r.mdr = s.read_u32()? & 0xFF_FFFF;
768 self.r.rom = s.read_u32()? & 0xFF_FFFF;
769 self.r.ram = s.read_u32()? & 0xFF_FFFF;
770 self.r.mar = s.read_u32()? & 0xFF_FFFF;
771 self.r.dpr = s.read_u32()? & 0xFF_FFFF;
772 for g in &mut self.r.gpr {
773 *g = s.read_u32()? & 0xFF_FFFF;
774 }
775 self.io.lock = s.read_bool()?;
776 self.io.halt = s.read_bool()?;
777 self.io.irq = s.read_bool()?;
778 self.io.rom_mapping = s.read_bool()?;
779 self.io.vector.copy_from_slice(s.read_bytes(32)?);
780 self.io.wait.rom = s.read_u32()? & 7;
781 self.io.wait.ram = s.read_u32()? & 7;
782 self.io.suspend.enable = s.read_bool()?;
783 self.io.suspend.duration = s.read_u32()?;
784 self.io.cache.enable = s.read_bool()?;
785 self.io.cache.page = s.read_bool()?;
786 self.io.cache.lock[0] = s.read_bool()?;
787 self.io.cache.lock[1] = s.read_bool()?;
788 self.io.cache.address[0] = s.read_u32()?;
789 self.io.cache.address[1] = s.read_u32()?;
790 self.io.cache.base = s.read_u32()?;
791 self.io.cache.pb = s.read_u16()? & 0x7FFF;
792 self.io.cache.pc = s.read_u8()?;
793 self.io.dma.enable = s.read_bool()?;
794 self.io.dma.source = s.read_u32()?;
795 self.io.dma.target = s.read_u32()?;
796 self.io.dma.length = s.read_u16()?;
797 self.io.bus.enable = s.read_bool()?;
798 self.io.bus.reading = s.read_bool()?;
799 self.io.bus.writing = s.read_bool()?;
800 self.io.bus.pending = s.read_u32()?;
801 self.io.bus.address = s.read_u32()?;
802 for page in self.program_ram.iter_mut() {
803 for word in page.iter_mut() {
804 *word = s.read_u16()?;
805 }
806 }
807 for byte in self.data_ram.iter_mut() {
808 *byte = s.read_u8()?;
809 }
810 for word in &mut self.stack {
811 *word = s.read_u32()?;
812 }
813 if s.remaining() != 0 {
814 return Err(SaveStateError::Invalid(alloc::format!(
815 "HG51 section has {} trailing byte(s)",
816 s.remaining()
817 )));
818 }
819 Ok(())
820 }
821}
822
823const fn byte(v: u32, i: u8) -> u8 {
824 (v >> (i * 8)) as u8
825}
826
827fn set_byte(v: &mut u32, i: u8, data: u8) {
828 let shift = i * 8;
829 *v = (*v & !(0xFF << shift)) | (u32::from(data) << shift);
830}
831
832include!("hg51b_instructions.rs");