1#![allow(
32 clippy::cast_possible_truncation,
33 clippy::cast_possible_wrap,
34 clippy::cast_sign_loss,
35 clippy::cast_lossless,
36 clippy::doc_markdown,
37 clippy::similar_names,
38 clippy::unreadable_literal,
39 clippy::struct_excessive_bools,
40 clippy::missing_const_for_fn,
41 clippy::verbose_bit_mask,
42 clippy::if_not_else
43)]
44
45use alloc::boxed::Box;
46use alloc::vec;
47use alloc::vec::Vec;
48
49use rustysnes_savestate::{SaveReader, SaveStateError, SaveWriter};
50
51pub struct GsuMem<'a> {
57 pub rom: &'a [u8],
59 pub rom_mask: u32,
61 pub ram: &'a mut [u8],
63 pub ram_mask: u32,
65}
66
67impl GsuMem<'_> {
68 #[must_use]
70 fn read(&self, address: u32) -> u8 {
71 if address & 0xc0_0000 == 0x00_0000 {
72 let off = (((address & 0x3f_0000) >> 1) | (address & 0x7fff)) & self.rom_mask;
74 return self.rom.get(off as usize).copied().unwrap_or(0);
75 }
76 if address & 0xe0_0000 == 0x40_0000 {
77 let off = address & self.rom_mask;
79 return self.rom.get(off as usize).copied().unwrap_or(0);
80 }
81 if address & 0xfe_0000 == 0x70_0000 {
82 let off = address & self.ram_mask;
84 return self.ram.get(off as usize).copied().unwrap_or(0);
85 }
86 0
87 }
88
89 fn write(&mut self, address: u32, data: u8) {
91 if address & 0xfe_0000 == 0x70_0000 {
92 let off = (address & self.ram_mask) as usize;
93 if let Some(slot) = self.ram.get_mut(off) {
94 *slot = data;
95 }
96 }
97 }
98}
99
100const SFR_Z: u16 = 1 << 1;
104const SFR_CY: u16 = 1 << 2;
106const SFR_S: u16 = 1 << 3;
108const SFR_OV: u16 = 1 << 4;
110const SFR_G: u16 = 1 << 5;
112const SFR_R: u16 = 1 << 6;
114const SFR_ALT1: u16 = 1 << 8;
116const SFR_ALT2: u16 = 1 << 9;
118const SFR_B: u16 = 1 << 12;
120const SFR_IRQ: u16 = 1 << 15;
122const SFR_READ_MASK: u16 = 0x9f7e;
124
125#[derive(Clone, Copy)]
127struct PixelCache {
128 offset: u16,
130 bitpend: u8,
132 data: [u8; 8],
134}
135
136impl PixelCache {
137 const fn empty() -> Self {
138 Self {
139 offset: !0,
140 bitpend: 0,
141 data: [0; 8],
142 }
143 }
144}
145
146pub struct Gsu {
151 r: [u16; 16],
153 r14_mod: bool,
155 r15_mod: bool,
157 sfr: u16,
159 sreg: usize,
161 dreg: usize,
163 pipeline: u8,
165 pbr: u8,
167 rombr: u8,
169 rambr: bool,
171 cbr: u16,
173 scbr: u8,
175 scmr_ht: u8,
177 scmr_ron: bool,
179 scmr_ran: bool,
181 scmr_md: u8,
183 colr: u8,
185 por_obj: bool,
187 por_freezehigh: bool,
188 por_highnibble: bool,
189 por_dither: bool,
190 por_transparent: bool,
191 bramr: bool,
193 vcr: u8,
195 cfgr_irq: bool,
197 cfgr_ms0: bool,
199 clsr: bool,
201 romcl: u32,
203 romdr: u8,
205 ramcl: u32,
207 ramar: u16,
209 ramdr: u8,
211 ramaddr: u16,
213 cache_buffer: Box<[u8; 512]>,
215 cache_valid: [bool; 32],
217 pixelcache: [PixelCache; 2],
219 clocks: u64,
221 instructions: u64,
223 pending_clocks: Vec<u32>,
227 pending_idx: usize,
229 owed: u32,
238}
239
240impl Clone for Gsu {
241 fn clone(&self) -> Self {
242 Self {
243 cache_buffer: self.cache_buffer.clone(),
244 pending_clocks: self.pending_clocks.clone(),
245 ..*self
246 }
247 }
248}
249
250impl core::fmt::Debug for Gsu {
251 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
252 f.debug_struct("Gsu")
253 .field("go", &self.go())
254 .field("pbr", &self.pbr)
255 .field("r15", &self.r[15])
256 .field("instructions", &self.instructions)
257 .finish_non_exhaustive()
258 }
259}
260
261impl Default for Gsu {
262 fn default() -> Self {
263 Self::new()
264 }
265}
266
267impl Gsu {
268 #[must_use]
274 pub fn new() -> Self {
275 Self {
276 r: [0; 16],
277 r14_mod: false,
278 r15_mod: false,
279 sfr: 0,
280 sreg: 0,
281 dreg: 0,
282 pbr: 0,
283 rombr: 0,
284 rambr: false,
285 cbr: 0,
286 scbr: 0,
287 scmr_ht: 0,
288 scmr_ron: false,
289 scmr_ran: false,
290 scmr_md: 0,
291 colr: 0,
292 por_obj: false,
293 por_freezehigh: false,
294 por_highnibble: false,
295 por_dither: false,
296 por_transparent: false,
297 bramr: false,
298 vcr: 0x04,
299 cfgr_irq: false,
300 cfgr_ms0: false,
301 clsr: false,
302 romcl: 0,
303 romdr: 0,
304 ramcl: 0,
305 ramar: 0,
306 ramdr: 0,
307 ramaddr: 0,
308 pipeline: 0x01, cache_buffer: vec![0u8; 512].into_boxed_slice().try_into().unwrap(),
310 cache_valid: [false; 32],
311 pixelcache: [PixelCache::empty(); 2],
312 clocks: 0,
313 instructions: 0,
314 pending_clocks: Vec::new(),
315 pending_idx: 0,
316 owed: 0,
317 }
318 }
319
320 #[must_use]
322 pub const fn go(&self) -> bool {
323 self.sfr & SFR_G != 0
324 }
325
326 #[must_use]
328 pub const fn owns_rom(&self) -> bool {
329 self.go() && self.scmr_ron
330 }
331
332 #[must_use]
334 pub const fn owns_ram(&self) -> bool {
335 self.go() && self.scmr_ran
336 }
337
338 #[must_use]
340 pub const fn irq_pending(&self) -> bool {
341 self.sfr & SFR_IRQ != 0
342 }
343
344 #[must_use]
346 pub const fn instructions(&self) -> u64 {
347 self.instructions
348 }
349
350 #[must_use]
352 pub const fn clocks(&self) -> u64 {
353 self.clocks
354 }
355
356 #[inline]
359 const fn flag(&self, mask: u16) -> bool {
360 self.sfr & mask != 0
361 }
362
363 #[inline]
364 fn set_flag(&mut self, mask: u16, value: bool) {
365 if value {
366 self.sfr |= mask;
367 } else {
368 self.sfr &= !mask;
369 }
370 }
371
372 #[inline]
374 const fn alt1(&self) -> bool {
375 self.flag(SFR_ALT1)
376 }
377 #[inline]
378 const fn alt2(&self) -> bool {
379 self.flag(SFR_ALT2)
380 }
381
382 #[inline]
385 fn write_r(&mut self, n: usize, val: u16) {
386 self.r[n] = val;
387 match n {
388 14 => self.r14_mod = true,
389 15 => self.r15_mod = true,
390 _ => {}
391 }
392 }
393
394 #[inline]
396 const fn sr(&self) -> u16 {
397 self.r[self.sreg]
398 }
399
400 #[inline]
402 fn set_dr(&mut self, val: u16) {
403 let d = self.dreg;
404 self.write_r(d, val);
405 }
406
407 #[inline]
409 fn reset_prefix(&mut self) {
410 self.sfr &= !(SFR_B | SFR_ALT1 | SFR_ALT2);
411 self.sreg = 0;
412 self.dreg = 0;
413 }
414
415 #[must_use]
421 pub const fn registers(&self) -> [u16; 16] {
422 self.r
423 }
424
425 #[must_use]
427 pub const fn sfr(&self) -> u16 {
428 self.sfr
429 }
430
431 #[must_use]
433 pub const fn pbr(&self) -> u8 {
434 self.pbr
435 }
436
437 pub fn step_one(&mut self, mem: &mut GsuMem) -> u32 {
452 loop {
453 if self.pending_idx < self.pending_clocks.len() {
454 let clocks = self.pending_clocks[self.pending_idx];
455 self.pending_idx += 1;
456 if self.pending_idx == self.pending_clocks.len() {
457 self.pending_clocks.clear();
458 self.pending_idx = 0;
459 }
460 if clocks > 0 {
461 return clocks;
462 }
463 continue;
464 }
465 if !self.go() {
466 return 0;
467 }
468 self.main_step(mem);
469 }
470 }
471
472 pub fn tick(&mut self, mem: &mut GsuMem) {
485 if self.owed > 0 {
486 self.owed -= 1;
487 return;
488 }
489 let clocks = self.step_one(mem);
490 if clocks > 0 {
491 self.owed = clocks - 1;
492 }
493 }
494
495 pub fn run_until_stopped(&mut self, mem: &mut GsuMem) {
503 const MAX_INSTRUCTIONS: u64 = 8_000_000;
506 let start = self.instructions;
507 while self.go() && self.instructions - start < MAX_INSTRUCTIONS {
508 self.main_step(mem);
509 }
510 self.pending_clocks.clear();
513 self.pending_idx = 0;
514 }
515
516 fn main_step(&mut self, mem: &mut GsuMem) {
518 let opcode = self.peekpipe(mem);
519 self.instructions = self.instructions.wrapping_add(1);
520 self.execute(opcode, mem);
521
522 if self.r14_mod {
523 self.r14_mod = false;
524 self.update_rom_buffer();
525 }
526 if self.r15_mod {
527 self.r15_mod = false;
528 } else {
529 self.r[15] = self.r[15].wrapping_add(1);
530 }
531 }
532
533 fn step(&mut self, clocks: u32, mem: &mut GsuMem) {
538 if self.romcl != 0 {
539 self.romcl -= clocks.min(self.romcl);
540 if self.romcl == 0 {
541 self.set_flag(SFR_R, false);
542 self.romdr = mem.read((u32::from(self.rombr) << 16) + u32::from(self.r[14]));
543 }
544 }
545 if self.ramcl != 0 {
546 self.ramcl -= clocks.min(self.ramcl);
547 if self.ramcl == 0 {
548 let addr = 0x70_0000 + (u32::from(self.rambr) << 16) + u32::from(self.ramar);
549 mem.write(addr, self.ramdr);
550 }
551 }
552 self.clocks = self.clocks.wrapping_add(u64::from(clocks));
553 self.pending_clocks.push(clocks);
562 }
563
564 #[inline]
566 const fn access_latency(&self) -> u32 {
567 if self.clsr { 5 } else { 6 }
568 }
569
570 fn sync_rom_buffer(&mut self, mem: &mut GsuMem) {
571 if self.romcl != 0 {
572 self.step(self.romcl, mem);
573 }
574 }
575
576 fn read_rom_buffer(&mut self, mem: &mut GsuMem) -> u8 {
577 self.sync_rom_buffer(mem);
578 self.romdr
579 }
580
581 fn update_rom_buffer(&mut self) {
582 self.set_flag(SFR_R, true);
583 self.romcl = self.access_latency();
584 }
585
586 fn sync_ram_buffer(&mut self, mem: &mut GsuMem) {
587 if self.ramcl != 0 {
588 self.step(self.ramcl, mem);
589 }
590 }
591
592 fn read_ram_buffer(&mut self, mem: &mut GsuMem, address: u16) -> u8 {
593 self.sync_ram_buffer(mem);
594 mem.read(0x70_0000 + (u32::from(self.rambr) << 16) + u32::from(address))
595 }
596
597 fn write_ram_buffer(&mut self, mem: &mut GsuMem, address: u16, data: u8) {
598 self.sync_ram_buffer(mem);
599 self.ramcl = self.access_latency();
600 self.ramar = address;
601 self.ramdr = data;
602 }
603
604 fn read_opcode(&mut self, address: u16, mem: &mut GsuMem) -> u8 {
607 let offset = address.wrapping_sub(self.cbr);
608 if offset < 512 {
609 let line = (offset >> 4) as usize;
610 if !self.cache_valid[line] {
611 let dp0 = (offset & 0xfff0) as usize;
612 let sp0 = (u32::from(self.pbr) << 16)
613 + u32::from(self.cbr.wrapping_add(dp0 as u16) & 0xfff0);
614 for i in 0..16 {
615 self.step(self.access_latency(), mem);
616 self.cache_buffer[dp0 + i] = mem.read(sp0 + i as u32);
617 }
618 self.cache_valid[line] = true;
619 } else {
620 self.step(if self.clsr { 1 } else { 2 }, mem);
621 }
622 return self.cache_buffer[offset as usize];
623 }
624
625 if self.pbr <= 0x5f {
626 self.sync_rom_buffer(mem);
627 } else {
628 self.sync_ram_buffer(mem);
629 }
630 self.step(self.access_latency(), mem);
631 mem.read((u32::from(self.pbr) << 16) | u32::from(address))
632 }
633
634 fn peekpipe(&mut self, mem: &mut GsuMem) -> u8 {
636 let result = self.pipeline;
637 self.pipeline = self.read_opcode(self.r[15], mem);
638 self.r15_mod = false;
639 result
640 }
641
642 fn pipe(&mut self, mem: &mut GsuMem) -> u8 {
644 let result = self.pipeline;
645 self.r[15] = self.r[15].wrapping_add(1);
646 self.pipeline = self.read_opcode(self.r[15], mem);
647 self.r15_mod = false;
648 result
649 }
650
651 fn flush_cache(&mut self) {
652 self.cache_valid = [false; 32];
653 }
654
655 fn read_cache(&self, address: u16) -> u8 {
657 self.cache_buffer[(address.wrapping_add(self.cbr) & 511) as usize]
658 }
659
660 fn write_cache(&mut self, address: u16, data: u8) {
661 let a = address.wrapping_add(self.cbr) & 511;
662 self.cache_buffer[a as usize] = data;
663 if a & 15 == 15 {
664 self.cache_valid[(a >> 4) as usize] = true;
665 }
666 }
667
668 const fn color(&self, source: u8) -> u8 {
672 if self.por_highnibble {
673 return (self.colr & 0xf0) | (source >> 4);
674 }
675 if self.por_freezehigh {
676 return (self.colr & 0xf0) | (source & 0x0f);
677 }
678 source
679 }
680
681 fn rpix(&mut self, x: u8, y: u8, mem: &mut GsuMem) -> u8 {
683 let pc1 = self.pixelcache[1];
686 self.flush_pixel_cache_into(pc1, mem);
687 self.pixelcache[1].bitpend = 0;
688 let pc0 = self.pixelcache[0];
689 self.flush_pixel_cache_into(pc0, mem);
690 self.pixelcache[0].bitpend = 0;
691
692 let bpp = Self::bpp(self.scmr_md);
693 let addr = self.char_address(x, y, bpp);
694 let mut data = 0u8;
695 let xi = (x & 7) ^ 7;
696 for n in 0..bpp {
697 let byte = ((n >> 1) << 4) + (n & 1);
698 self.step(if self.clsr { 5 } else { 6 }, mem);
699 data |= ((mem.read(addr + byte) >> xi) & 1) << n;
700 }
701 data
702 }
703
704 const fn bpp(md: u8) -> u32 {
706 (2 << (md - (md >> 1))) as u32
707 }
708
709 fn char_address(&self, x: u8, y: u8, bpp: u32) -> u32 {
712 let x = u32::from(x);
713 let y = u32::from(y);
714 let cn = match if self.por_obj { 3 } else { self.scmr_ht } {
715 0 => ((x & 0xf8) << 1) + ((y & 0xf8) >> 3),
716 1 => ((x & 0xf8) << 1) + ((x & 0xf8) >> 1) + ((y & 0xf8) >> 3),
717 2 => ((x & 0xf8) << 1) + (x & 0xf8) + ((y & 0xf8) >> 3),
718 _ => ((y & 0x80) << 2) + ((x & 0x80) << 1) + ((y & 0x78) << 1) + ((x & 0x78) >> 3),
719 };
720 0x70_0000 + (cn * (bpp << 3)) + (u32::from(self.scbr) << 10) + ((y & 0x07) * 2)
721 }
722
723 fn flush_pixel_cache_into(&mut self, cache: PixelCache, mem: &mut GsuMem) {
726 if cache.bitpend == 0 {
727 return;
728 }
729 let x = (cache.offset << 3) as u8;
730 let y = (cache.offset >> 5) as u8;
731 let bpp = Self::bpp(self.scmr_md);
732 let addr = self.char_address(x, y, bpp);
733
734 for n in 0..bpp {
735 let byte = ((n >> 1) << 4) + (n & 1);
736 let mut data = 0u8;
737 for col in 0..8 {
738 data |= ((cache.data[col] >> n) & 1) << col;
739 }
740 if cache.bitpend != 0xff {
741 self.step(if self.clsr { 5 } else { 6 }, mem);
742 data &= cache.bitpend;
743 data |= mem.read(addr + byte) & !cache.bitpend;
744 }
745 self.step(if self.clsr { 5 } else { 6 }, mem);
746 mem.write(addr + byte, data);
747 }
748 }
749
750 pub fn read_register(&mut self, address: u16) -> u8 {
754 let address = 0x3000 | (address & 0x1ff);
755 if (0x3100..=0x32ff).contains(&address) {
756 return self.read_cache(address - 0x3100);
757 }
758 if (0x3000..=0x301f).contains(&address) {
759 let r = self.r[(address >> 1 & 15) as usize];
760 return (r >> ((address & 1) << 3)) as u8;
761 }
762 match address {
763 0x3030 => self.sfr as u8,
764 0x3031 => {
765 let r = (self.sfr & SFR_READ_MASK) >> 8;
766 self.set_flag(SFR_IRQ, false);
767 r as u8
768 }
769 0x3034 => self.pbr,
770 0x3036 => self.rombr,
771 0x303b => self.vcr,
772 0x303c => u8::from(self.rambr),
773 0x303e => self.cbr as u8,
774 0x303f => (self.cbr >> 8) as u8,
775 _ => 0,
776 }
777 }
778
779 #[must_use]
782 pub fn write_register(&mut self, address: u16, data: u8) -> bool {
783 let address = 0x3000 | (address & 0x1ff);
784 let was_go = self.go();
785
786 if (0x3100..=0x32ff).contains(&address) {
787 self.write_cache(address - 0x3100, data);
788 return false;
789 }
790 if (0x3000..=0x301f).contains(&address) {
791 let n = (address >> 1 & 15) as usize;
792 if address & 1 == 0 {
793 self.r[n] = (self.r[n] & 0xff00) | u16::from(data);
794 } else {
795 self.r[n] = (u16::from(data) << 8) | (self.r[n] & 0x00ff);
796 }
797 if n == 14 {
798 self.update_rom_buffer();
799 }
800 if address == 0x301f {
801 self.set_flag(SFR_G, true);
802 }
803 return !was_go && self.go();
804 }
805
806 match address {
807 0x3030 => {
808 let g = self.go();
809 self.sfr = (self.sfr & 0xff00) | u16::from(data);
810 if g && !self.go() {
811 self.cbr = 0;
812 self.flush_cache();
813 }
814 }
815 0x3031 => self.sfr = (u16::from(data) << 8) | (self.sfr & 0x00ff),
816 0x3033 => self.bramr = data & 0x01 != 0,
817 0x3034 => {
818 self.pbr = data & 0x7f;
819 self.flush_cache();
820 }
821 0x3037 => {
822 self.cfgr_irq = data & 0x80 != 0;
823 self.cfgr_ms0 = data & 0x20 != 0;
824 }
825 0x3038 => self.scbr = data,
826 0x3039 => self.clsr = data & 0x01 != 0,
827 0x303a => self.set_scmr(data),
828 _ => {}
829 }
830 !was_go && self.go()
831 }
832
833 fn set_scmr(&mut self, data: u8) {
835 self.scmr_ht = (u8::from(data & 0x20 != 0) << 1) | u8::from(data & 0x04 != 0);
836 self.scmr_ron = data & 0x10 != 0;
837 self.scmr_ran = data & 0x08 != 0;
838 self.scmr_md = data & 0x03;
839 }
840
841 #[allow(clippy::too_many_lines)]
844 fn execute(&mut self, opcode: u8, mem: &mut GsuMem) {
845 let n = (opcode & 0x0f) as usize;
846 match opcode {
847 0x00 => self.i_stop(),
848 0x01 => self.reset_prefix(), 0x02 => self.i_cache(), 0x03 => self.i_lsr(), 0x04 => self.i_rol(), 0x05 => self.i_branch(true, mem), 0x06 => self.i_branch(self.flag(SFR_S) == self.flag(SFR_OV), mem), 0x07 => self.i_branch(self.flag(SFR_S) != self.flag(SFR_OV), mem),
855 0x08 => self.i_branch(!self.flag(SFR_Z), mem), 0x09 => self.i_branch(self.flag(SFR_Z), mem), 0x0a => self.i_branch(!self.flag(SFR_S), mem), 0x0b => self.i_branch(self.flag(SFR_S), mem), 0x0c => self.i_branch(!self.flag(SFR_CY), mem), 0x0d => self.i_branch(self.flag(SFR_CY), mem), 0x0e => self.i_branch(!self.flag(SFR_OV), mem), 0x0f => self.i_branch(self.flag(SFR_OV), mem), 0x10..=0x1f => self.i_to_move(n), 0x20..=0x2f => self.i_with(n), 0x30..=0x3b => self.i_store(n, mem), 0x3c => self.i_loop(), 0x3d => self.i_alt1(),
868 0x3e => self.i_alt2(),
869 0x3f => self.i_alt3(),
870 0x40..=0x4b => self.i_load(n, mem), 0x4c => self.i_plot_rpix(mem), 0x4d => self.i_swap(), 0x4e => self.i_color_cmode(), 0x4f => self.i_not(), 0x50..=0x5f => self.i_add_adc(n, mem), 0x60..=0x6f => self.i_sub_sbc_cmp(n, mem), 0x70 => self.i_merge(), 0x71..=0x7f => self.i_and_bic(n, mem), 0x80..=0x8f => self.i_mult_umult(n, mem), 0x90 => self.i_sbk(mem), 0x91..=0x94 => self.i_link(n), 0x95 => self.i_sex(), 0x96 => self.i_asr_div2(), 0x97 => self.i_ror(), 0x98..=0x9d => self.i_jmp_ljmp(n), 0x9e => self.i_lob(), 0x9f => self.i_fmult_lmult(mem), 0xa0..=0xaf => self.i_ibt_lms_sms(n, mem), 0xb0..=0xbf => self.i_from_moves(n), 0xc0 => self.i_hib(), 0xc1..=0xcf => self.i_or_xor(n, mem), 0xd0..=0xde => self.i_inc(n), 0xdf => self.i_getc_ramb_romb(mem), 0xe0..=0xee => self.i_dec(n), 0xef => self.i_getb(mem), 0xf0..=0xff => self.i_iwt_lm_sm(n, mem), }
898 }
899
900 fn set_sz_from(&mut self, value: u16) {
901 self.set_flag(SFR_S, value & 0x8000 != 0);
902 self.set_flag(SFR_Z, value == 0);
903 }
904
905 fn i_stop(&mut self) {
907 if !self.cfgr_irq {
908 self.set_flag(SFR_IRQ, true);
909 }
910 self.set_flag(SFR_G, false);
911 self.pipeline = 0x01;
912 self.reset_prefix();
913 }
914
915 fn i_cache(&mut self) {
917 if self.cbr != (self.r[15] & 0xfff0) {
918 self.cbr = self.r[15] & 0xfff0;
919 self.flush_cache();
920 }
921 self.reset_prefix();
922 }
923
924 fn i_lsr(&mut self) {
926 self.set_flag(SFR_CY, self.sr() & 1 != 0);
927 let r = self.sr() >> 1;
928 self.set_dr(r);
929 self.set_sz_from(r);
930 self.reset_prefix();
931 }
932
933 fn i_rol(&mut self) {
935 let carry = self.sr() & 0x8000 != 0;
936 let r = (self.sr() << 1) | u16::from(self.flag(SFR_CY));
937 self.set_dr(r);
938 self.set_flag(SFR_S, r & 0x8000 != 0);
939 self.set_flag(SFR_CY, carry);
940 self.set_flag(SFR_Z, r == 0);
941 self.reset_prefix();
942 }
943
944 fn i_branch(&mut self, take: bool, mem: &mut GsuMem) {
946 let displacement = self.pipe(mem) as i8;
947 if take {
948 self.r[15] = self.r[15].wrapping_add(displacement as u16);
949 self.r15_mod = true;
950 }
951 }
952
953 fn i_to_move(&mut self, n: usize) {
955 if !self.flag(SFR_B) {
956 self.dreg = n;
957 } else {
958 let v = self.sr();
959 self.write_r(n, v);
960 self.reset_prefix();
961 }
962 }
963
964 fn i_with(&mut self, n: usize) {
966 self.sreg = n;
967 self.dreg = n;
968 self.set_flag(SFR_B, true);
969 }
970
971 fn i_store(&mut self, n: usize, mem: &mut GsuMem) {
973 self.ramaddr = self.r[n];
974 let s = self.sr();
975 self.write_ram_buffer(mem, self.ramaddr, s as u8);
976 if !self.alt1() {
977 self.write_ram_buffer(mem, self.ramaddr ^ 1, (s >> 8) as u8);
978 }
979 self.reset_prefix();
980 }
981
982 fn i_loop(&mut self) {
984 self.r[12] = self.r[12].wrapping_sub(1);
985 self.set_flag(SFR_S, self.r[12] & 0x8000 != 0);
986 self.set_flag(SFR_Z, self.r[12] == 0);
987 if !self.flag(SFR_Z) {
988 self.r[15] = self.r[13];
989 self.r15_mod = true;
990 }
991 self.reset_prefix();
992 }
993
994 fn i_alt1(&mut self) {
996 self.set_flag(SFR_B, false);
997 self.set_flag(SFR_ALT1, true);
998 }
999 fn i_alt2(&mut self) {
1000 self.set_flag(SFR_B, false);
1001 self.set_flag(SFR_ALT2, true);
1002 }
1003 fn i_alt3(&mut self) {
1004 self.set_flag(SFR_B, false);
1005 self.set_flag(SFR_ALT1, true);
1006 self.set_flag(SFR_ALT2, true);
1007 }
1008
1009 fn i_load(&mut self, n: usize, mem: &mut GsuMem) {
1011 self.ramaddr = self.r[n];
1012 let mut v = u16::from(self.read_ram_buffer(mem, self.ramaddr));
1013 if !self.alt1() {
1014 v |= u16::from(self.read_ram_buffer(mem, self.ramaddr ^ 1)) << 8;
1015 }
1016 self.set_dr(v);
1017 self.reset_prefix();
1018 }
1019
1020 fn i_plot_rpix(&mut self, mem: &mut GsuMem) {
1022 if !self.alt1() {
1023 self.plot(self.r[1] as u8, self.r[2] as u8, mem);
1024 self.r[1] = self.r[1].wrapping_add(1);
1025 } else {
1026 let v = u16::from(self.rpix(self.r[1] as u8, self.r[2] as u8, mem));
1027 self.set_dr(v);
1028 self.set_sz_from(v);
1029 }
1030 self.reset_prefix();
1031 }
1032
1033 fn plot(&mut self, x: u8, y: u8, mem: &mut GsuMem) {
1036 if !self.por_transparent {
1037 let transparent = if self.scmr_md == 3 {
1038 if self.por_freezehigh {
1039 self.colr & 0x0f == 0
1040 } else {
1041 self.colr == 0
1042 }
1043 } else {
1044 self.colr & 0x0f == 0
1045 };
1046 if transparent {
1047 return;
1048 }
1049 }
1050
1051 let mut color = self.colr;
1052 if self.por_dither && self.scmr_md != 3 {
1053 if (x ^ y) & 1 != 0 {
1054 color >>= 4;
1055 }
1056 color &= 0x0f;
1057 }
1058
1059 let offset = (u16::from(y) << 5) + (u16::from(x) >> 3);
1060 if offset != self.pixelcache[0].offset {
1061 let evicted = self.pixelcache[1];
1062 self.flush_pixel_cache_into(evicted, mem);
1063 self.pixelcache[1] = self.pixelcache[0];
1064 self.pixelcache[0].bitpend = 0;
1065 self.pixelcache[0].offset = offset;
1066 }
1067
1068 let xi = ((x & 7) ^ 7) as usize;
1069 self.pixelcache[0].data[xi] = color;
1070 self.pixelcache[0].bitpend |= 1 << xi;
1071 if self.pixelcache[0].bitpend == 0xff {
1072 let evicted = self.pixelcache[1];
1073 self.flush_pixel_cache_into(evicted, mem);
1074 self.pixelcache[1] = self.pixelcache[0];
1075 self.pixelcache[0].bitpend = 0;
1076 }
1077 }
1078
1079 fn i_swap(&mut self) {
1081 let r = (self.sr() >> 8) | (self.sr() << 8);
1082 self.set_dr(r);
1083 self.set_sz_from(r);
1084 self.reset_prefix();
1085 }
1086
1087 fn i_color_cmode(&mut self) {
1089 if self.alt1() {
1090 self.set_por(self.sr() as u8);
1091 } else {
1092 self.colr = self.color(self.sr() as u8);
1093 }
1094 self.reset_prefix();
1095 }
1096
1097 fn set_por(&mut self, data: u8) {
1099 self.por_obj = data & 0x10 != 0;
1100 self.por_freezehigh = data & 0x08 != 0;
1101 self.por_highnibble = data & 0x04 != 0;
1102 self.por_dither = data & 0x02 != 0;
1103 self.por_transparent = data & 0x01 != 0;
1104 }
1105
1106 fn i_not(&mut self) {
1108 let r = !self.sr();
1109 self.set_dr(r);
1110 self.set_sz_from(r);
1111 self.reset_prefix();
1112 }
1113
1114 fn i_add_adc(&mut self, n: usize, _mem: &mut GsuMem) {
1116 let operand: i32 = if self.alt2() {
1117 n as i32
1118 } else {
1119 i32::from(self.r[n])
1120 };
1121 let sr = i32::from(self.sr());
1122 let carry = if self.alt1() {
1123 i32::from(self.flag(SFR_CY))
1124 } else {
1125 0
1126 };
1127 let r = sr + operand + carry;
1128 self.set_flag(SFR_OV, !(sr ^ operand) & (operand ^ r) & 0x8000 != 0);
1129 self.set_flag(SFR_S, r & 0x8000 != 0);
1130 self.set_flag(SFR_CY, r >= 0x10000);
1131 self.set_flag(SFR_Z, (r as u16) == 0);
1132 self.set_dr(r as u16);
1133 self.reset_prefix();
1134 }
1135
1136 fn i_sub_sbc_cmp(&mut self, n: usize, _mem: &mut GsuMem) {
1138 let operand: i32 = if !self.alt2() || self.alt1() {
1139 i32::from(self.r[n])
1140 } else {
1141 n as i32
1142 };
1143 let sr = i32::from(self.sr());
1144 let borrow = if !self.alt2() && self.alt1() {
1145 i32::from(!self.flag(SFR_CY))
1146 } else {
1147 0
1148 };
1149 let r = sr - operand - borrow;
1150 self.set_flag(SFR_OV, (sr ^ operand) & (sr ^ r) & 0x8000 != 0);
1151 self.set_flag(SFR_S, r & 0x8000 != 0);
1152 self.set_flag(SFR_CY, r >= 0);
1153 self.set_flag(SFR_Z, (r as u16) == 0);
1154 if !self.alt2() || !self.alt1() {
1155 self.set_dr(r as u16);
1156 }
1157 self.reset_prefix();
1158 }
1159
1160 fn i_merge(&mut self) {
1162 let r = (self.r[7] & 0xff00) | (self.r[8] >> 8);
1163 self.set_dr(r);
1164 self.set_flag(SFR_OV, r & 0xc0c0 != 0);
1165 self.set_flag(SFR_S, r & 0x8080 != 0);
1166 self.set_flag(SFR_CY, r & 0xe0e0 != 0);
1167 self.set_flag(SFR_Z, r & 0xf0f0 != 0);
1168 self.reset_prefix();
1169 }
1170
1171 fn i_and_bic(&mut self, n: usize, _mem: &mut GsuMem) {
1173 let operand = if self.alt2() { n as u16 } else { self.r[n] };
1174 let operand = if self.alt1() { !operand } else { operand };
1175 let r = self.sr() & operand;
1176 self.set_dr(r);
1177 self.set_sz_from(r);
1178 self.reset_prefix();
1179 }
1180
1181 fn i_mult_umult(&mut self, n: usize, mem: &mut GsuMem) {
1183 let operand = if self.alt2() { n as u16 } else { self.r[n] };
1184 let r = if self.alt1() {
1185 u16::from(self.sr() as u8).wrapping_mul(u16::from(operand as u8))
1186 } else {
1187 ((self.sr() as i8 as i16).wrapping_mul(operand as i8 as i16)) as u16
1188 };
1189 self.set_dr(r);
1190 self.set_sz_from(r);
1191 self.reset_prefix();
1192 if !self.cfgr_ms0 {
1193 self.step(if self.clsr { 1 } else { 2 }, mem);
1194 }
1195 }
1196
1197 fn i_sbk(&mut self, mem: &mut GsuMem) {
1199 let s = self.sr();
1200 self.write_ram_buffer(mem, self.ramaddr, s as u8);
1201 self.write_ram_buffer(mem, self.ramaddr ^ 1, (s >> 8) as u8);
1202 self.reset_prefix();
1203 }
1204
1205 fn i_link(&mut self, n: usize) {
1207 self.r[11] = self.r[15].wrapping_add(n as u16);
1208 self.reset_prefix();
1209 }
1210
1211 fn i_sex(&mut self) {
1213 let r = (self.sr() as i8 as i16) as u16;
1214 self.set_dr(r);
1215 self.set_sz_from(r);
1216 self.reset_prefix();
1217 }
1218
1219 fn i_asr_div2(&mut self) {
1221 self.set_flag(SFR_CY, self.sr() & 1 != 0);
1225 let correction = if self.alt1() {
1226 (i32::from(self.sr()) + 1) >> 16
1227 } else {
1228 0
1229 };
1230 let r = ((i32::from(self.sr() as i16) >> 1) + correction) as u16;
1231 self.set_dr(r);
1232 self.set_sz_from(r);
1233 self.reset_prefix();
1234 }
1235
1236 fn i_ror(&mut self) {
1238 let carry = self.sr() & 1 != 0;
1239 let r = (u16::from(self.flag(SFR_CY)) << 15) | (self.sr() >> 1);
1240 self.set_dr(r);
1241 self.set_flag(SFR_S, r & 0x8000 != 0);
1242 self.set_flag(SFR_CY, carry);
1243 self.set_flag(SFR_Z, r == 0);
1244 self.reset_prefix();
1245 }
1246
1247 fn i_jmp_ljmp(&mut self, n: usize) {
1249 if !self.alt1() {
1250 self.r[15] = self.r[n];
1251 self.r15_mod = true;
1252 } else {
1253 self.pbr = (self.r[n] & 0x7f) as u8;
1254 self.r[15] = self.sr();
1255 self.r15_mod = true;
1256 self.cbr = self.r[15] & 0xfff0;
1257 self.flush_cache();
1258 }
1259 self.reset_prefix();
1260 }
1261
1262 fn i_lob(&mut self) {
1264 let r = self.sr() & 0xff;
1265 self.set_dr(r);
1266 self.set_flag(SFR_S, r & 0x80 != 0);
1267 self.set_flag(SFR_Z, r == 0);
1268 self.reset_prefix();
1269 }
1270
1271 fn i_fmult_lmult(&mut self, mem: &mut GsuMem) {
1273 let result = ((self.sr() as i16 as i32) * (self.r[6] as i16 as i32)) as u32;
1274 if self.alt1() {
1275 self.r[4] = result as u16;
1276 }
1277 let r = (result >> 16) as u16;
1278 self.set_dr(r);
1279 self.set_flag(SFR_S, r & 0x8000 != 0);
1280 self.set_flag(SFR_CY, result & 0x8000 != 0);
1281 self.set_flag(SFR_Z, r == 0);
1282 self.reset_prefix();
1283 let mul = if self.cfgr_ms0 { 3 } else { 7 };
1284 self.step(mul * if self.clsr { 1 } else { 2 }, mem);
1285 }
1286
1287 fn i_ibt_lms_sms(&mut self, n: usize, mem: &mut GsuMem) {
1289 if self.alt1() {
1290 self.ramaddr = u16::from(self.pipe(mem)) << 1;
1291 let lo = u16::from(self.read_ram_buffer(mem, self.ramaddr));
1292 let hi = u16::from(self.read_ram_buffer(mem, self.ramaddr ^ 1)) << 8;
1293 self.write_r(n, hi | lo);
1294 } else if self.alt2() {
1295 self.ramaddr = u16::from(self.pipe(mem)) << 1;
1296 let v = self.r[n];
1297 self.write_ram_buffer(mem, self.ramaddr, v as u8);
1298 self.write_ram_buffer(mem, self.ramaddr ^ 1, (v >> 8) as u8);
1299 } else {
1300 let imm = (self.pipe(mem) as i8 as i16) as u16;
1301 self.write_r(n, imm);
1302 }
1303 self.reset_prefix();
1304 }
1305
1306 fn i_from_moves(&mut self, n: usize) {
1308 if !self.flag(SFR_B) {
1309 self.sreg = n;
1310 } else {
1311 let v = self.r[n];
1312 self.set_dr(v);
1313 self.set_flag(SFR_OV, v & 0x80 != 0);
1314 self.set_flag(SFR_S, v & 0x8000 != 0);
1315 self.set_flag(SFR_Z, v == 0);
1316 self.reset_prefix();
1317 }
1318 }
1319
1320 fn i_hib(&mut self) {
1322 let r = self.sr() >> 8;
1323 self.set_dr(r);
1324 self.set_flag(SFR_S, r & 0x80 != 0);
1325 self.set_flag(SFR_Z, r == 0);
1326 self.reset_prefix();
1327 }
1328
1329 fn i_or_xor(&mut self, n: usize, _mem: &mut GsuMem) {
1331 let operand = if self.alt2() { n as u16 } else { self.r[n] };
1332 let r = if self.alt1() {
1333 self.sr() ^ operand
1334 } else {
1335 self.sr() | operand
1336 };
1337 self.set_dr(r);
1338 self.set_sz_from(r);
1339 self.reset_prefix();
1340 }
1341
1342 fn i_inc(&mut self, n: usize) {
1344 let v = self.r[n].wrapping_add(1);
1345 self.write_r(n, v);
1346 self.set_sz_from(v);
1347 self.reset_prefix();
1348 }
1349
1350 fn i_getc_ramb_romb(&mut self, mem: &mut GsuMem) {
1352 if !self.alt2() {
1353 let c = self.read_rom_buffer(mem);
1354 self.colr = self.color(c);
1355 } else if !self.alt1() {
1356 self.sync_ram_buffer(mem);
1357 self.rambr = self.sr() & 0x01 != 0;
1358 } else {
1359 self.sync_rom_buffer(mem);
1360 self.rombr = (self.sr() & 0x7f) as u8;
1361 }
1362 self.reset_prefix();
1363 }
1364
1365 fn i_dec(&mut self, n: usize) {
1367 let v = self.r[n].wrapping_sub(1);
1368 self.write_r(n, v);
1369 self.set_sz_from(v);
1370 self.reset_prefix();
1371 }
1372
1373 fn i_getb(&mut self, mem: &mut GsuMem) {
1375 let rb = u16::from(self.read_rom_buffer(mem));
1376 let mode = (u8::from(self.alt2()) << 1) | u8::from(self.alt1());
1377 let r = match mode {
1378 0 => rb,
1379 1 => (rb << 8) | (self.sr() & 0xff),
1380 2 => (self.sr() & 0xff00) | rb,
1381 _ => (rb as u8 as i8 as i16) as u16,
1382 };
1383 self.set_dr(r);
1384 self.reset_prefix();
1385 }
1386
1387 fn i_iwt_lm_sm(&mut self, n: usize, mem: &mut GsuMem) {
1389 if self.alt1() {
1390 let mut addr = u16::from(self.pipe(mem));
1391 addr |= u16::from(self.pipe(mem)) << 8;
1392 self.ramaddr = addr;
1393 let lo = u16::from(self.read_ram_buffer(mem, addr));
1394 let hi = u16::from(self.read_ram_buffer(mem, addr ^ 1)) << 8;
1395 self.write_r(n, hi | lo);
1396 } else if self.alt2() {
1397 let mut addr = u16::from(self.pipe(mem));
1398 addr |= u16::from(self.pipe(mem)) << 8;
1399 self.ramaddr = addr;
1400 let v = self.r[n];
1401 self.write_ram_buffer(mem, addr, v as u8);
1402 self.write_ram_buffer(mem, addr ^ 1, (v >> 8) as u8);
1403 } else {
1404 let lo = u16::from(self.pipe(mem));
1405 let hi = u16::from(self.pipe(mem)) << 8;
1406 self.write_r(n, hi | lo);
1407 }
1408 self.reset_prefix();
1409 }
1410
1411 const MAX_SAVED_PENDING_CLOCKS: usize = 64;
1416
1417 pub fn save_state(&self, w: &mut SaveWriter) {
1426 w.section(*b"GSU0", |s| {
1427 for ® in &self.r {
1428 s.write_u16(reg);
1429 }
1430 s.write_bool(self.r14_mod);
1431 s.write_bool(self.r15_mod);
1432 s.write_u16(self.sfr);
1433 #[allow(clippy::cast_possible_truncation)] s.write_u8(self.sreg as u8);
1435 #[allow(clippy::cast_possible_truncation)]
1436 s.write_u8(self.dreg as u8);
1437 s.write_u8(self.pipeline);
1438 s.write_u8(self.pbr);
1439 s.write_u8(self.rombr);
1440 s.write_bool(self.rambr);
1441 s.write_u16(self.cbr);
1442 s.write_u8(self.scbr);
1443 s.write_u8(self.scmr_ht);
1444 s.write_bool(self.scmr_ron);
1445 s.write_bool(self.scmr_ran);
1446 s.write_u8(self.scmr_md);
1447 s.write_u8(self.colr);
1448 s.write_bool(self.por_obj);
1449 s.write_bool(self.por_freezehigh);
1450 s.write_bool(self.por_highnibble);
1451 s.write_bool(self.por_dither);
1452 s.write_bool(self.por_transparent);
1453 s.write_bool(self.bramr);
1454 s.write_u8(self.vcr);
1455 s.write_bool(self.cfgr_irq);
1456 s.write_bool(self.cfgr_ms0);
1457 s.write_bool(self.clsr);
1458 s.write_u32(self.romcl);
1459 s.write_u8(self.romdr);
1460 s.write_u32(self.ramcl);
1461 s.write_u16(self.ramar);
1462 s.write_u8(self.ramdr);
1463 s.write_u16(self.ramaddr);
1464 s.write_bytes(&*self.cache_buffer);
1465 for &valid in &self.cache_valid {
1466 s.write_bool(valid);
1467 }
1468 for pc in &self.pixelcache {
1469 s.write_u16(pc.offset);
1470 s.write_u8(pc.bitpend);
1471 s.write_bytes(&pc.data);
1472 }
1473 s.write_u64(self.clocks);
1474 s.write_u64(self.instructions);
1475 #[allow(clippy::cast_possible_truncation)] s.write_u32(self.pending_clocks.len() as u32);
1477 for &c in &self.pending_clocks {
1478 s.write_u32(c);
1479 }
1480 #[allow(clippy::cast_possible_truncation)] s.write_u32(self.pending_idx as u32);
1482 s.write_u32(self.owed);
1483 });
1484 }
1485
1486 pub fn load_state(&mut self, r: &mut SaveReader) -> Result<(), SaveStateError> {
1495 let mut s = r.expect_section(*b"GSU0")?;
1496 for reg in &mut self.r {
1497 *reg = s.read_u16()?;
1498 }
1499 self.r14_mod = s.read_bool()?;
1500 self.r15_mod = s.read_bool()?;
1501 self.sfr = s.read_u16()?;
1502 self.sreg = usize::from(s.read_u8()? & 0xF);
1503 self.dreg = usize::from(s.read_u8()? & 0xF);
1504 self.pipeline = s.read_u8()?;
1505 self.pbr = s.read_u8()? & 0x7F;
1509 self.rombr = s.read_u8()? & 0x7F;
1510 self.rambr = s.read_bool()?;
1511 self.cbr = s.read_u16()? & 0xFFF0;
1512 self.scbr = s.read_u8()?;
1513 self.scmr_ht = s.read_u8()? & 0x03;
1514 self.scmr_ron = s.read_bool()?;
1515 self.scmr_ran = s.read_bool()?;
1516 self.scmr_md = s.read_u8()? & 0x03;
1517 self.colr = s.read_u8()?;
1518 self.por_obj = s.read_bool()?;
1519 self.por_freezehigh = s.read_bool()?;
1520 self.por_highnibble = s.read_bool()?;
1521 self.por_dither = s.read_bool()?;
1522 self.por_transparent = s.read_bool()?;
1523 self.bramr = s.read_bool()?;
1524 self.vcr = s.read_u8()?;
1525 self.cfgr_irq = s.read_bool()?;
1526 self.cfgr_ms0 = s.read_bool()?;
1527 self.clsr = s.read_bool()?;
1528 self.romcl = s.read_u32()?;
1529 self.romdr = s.read_u8()?;
1530 self.ramcl = s.read_u32()?;
1531 self.ramar = s.read_u16()?;
1532 self.ramdr = s.read_u8()?;
1533 self.ramaddr = s.read_u16()?;
1534 self.cache_buffer.copy_from_slice(s.read_bytes(512)?);
1535 for valid in &mut self.cache_valid {
1536 *valid = s.read_bool()?;
1537 }
1538 for pc in &mut self.pixelcache {
1539 pc.offset = s.read_u16()?;
1540 pc.bitpend = s.read_u8()?;
1541 pc.data.copy_from_slice(s.read_bytes(8)?);
1542 }
1543 self.clocks = s.read_u64()?;
1544 self.instructions = s.read_u64()?;
1545 let pending_len = s.read_u32()? as usize;
1546 if pending_len > Self::MAX_SAVED_PENDING_CLOCKS {
1547 return Err(SaveStateError::Invalid(alloc::format!(
1548 "GSU pending_clocks length {pending_len} exceeds the sane bound of {}",
1549 Self::MAX_SAVED_PENDING_CLOCKS
1550 )));
1551 }
1552 self.pending_clocks.clear();
1553 for _ in 0..pending_len {
1554 self.pending_clocks.push(s.read_u32()?);
1555 }
1556 let pending_idx = s.read_u32()? as usize;
1557 if pending_idx > self.pending_clocks.len() {
1558 return Err(SaveStateError::Invalid(alloc::format!(
1559 "GSU pending_idx {pending_idx} exceeds the restored queue length {}",
1560 self.pending_clocks.len()
1561 )));
1562 }
1563 self.pending_idx = pending_idx;
1564 self.owed = s.read_u32()?;
1565 if s.remaining() != 0 {
1566 return Err(SaveStateError::Invalid(alloc::format!(
1567 "GSU0 section has {} trailing byte(s)",
1568 s.remaining()
1569 )));
1570 }
1571 Ok(())
1572 }
1573}
1574
1575#[cfg(test)]
1576mod tests {
1577 use super::*;
1578
1579 fn pending_len_offset(bytes: &[u8]) -> usize {
1584 let mut r = SaveReader::new(bytes);
1585 let mut s = r.expect_section(*b"GSU0").unwrap();
1586 for _ in 0..16 {
1587 s.read_u16().unwrap(); }
1589 s.read_bool().unwrap(); s.read_bool().unwrap(); s.read_u16().unwrap(); s.read_u8().unwrap(); s.read_u8().unwrap(); s.read_u8().unwrap(); s.read_u8().unwrap(); s.read_u8().unwrap(); s.read_bool().unwrap(); s.read_u16().unwrap(); s.read_u8().unwrap(); s.read_u8().unwrap(); s.read_bool().unwrap(); s.read_bool().unwrap(); s.read_u8().unwrap(); s.read_u8().unwrap(); for _ in 0..5 {
1606 s.read_bool().unwrap(); }
1608 s.read_bool().unwrap(); s.read_u8().unwrap(); s.read_bool().unwrap(); s.read_bool().unwrap(); s.read_bool().unwrap(); s.read_u32().unwrap(); s.read_u8().unwrap(); s.read_u32().unwrap(); s.read_u16().unwrap(); s.read_u8().unwrap(); s.read_u16().unwrap(); s.read_bytes(512).unwrap(); for _ in 0..32 {
1621 s.read_bool().unwrap(); }
1623 for _ in 0..2 {
1624 s.read_u16().unwrap(); s.read_u8().unwrap(); s.read_bytes(8).unwrap(); }
1628 s.read_u64().unwrap(); s.read_u64().unwrap(); bytes.len() - s.remaining()
1631 }
1632
1633 #[test]
1634 fn oversized_pending_clocks_length_is_rejected_not_trusted() {
1635 let gsu = Gsu::new();
1636 let mut w = SaveWriter::new();
1637 gsu.save_state(&mut w);
1638 let mut bytes = w.into_bytes();
1639
1640 let offset = pending_len_offset(&bytes);
1641 bytes[offset..offset + 4].copy_from_slice(&1000u32.to_le_bytes());
1646
1647 let mut fresh = Gsu::new();
1648 let mut r = SaveReader::new(&bytes);
1649 assert!(matches!(
1650 fresh.load_state(&mut r),
1651 Err(SaveStateError::Invalid(_))
1652 ));
1653 }
1654
1655 #[test]
1656 fn pending_idx_beyond_the_restored_queue_is_rejected_not_trusted() {
1657 let gsu = Gsu::new();
1658 let mut w = SaveWriter::new();
1659 gsu.save_state(&mut w);
1660 let mut bytes = w.into_bytes();
1661
1662 let len_offset = pending_len_offset(&bytes);
1665 let idx_offset = len_offset + 4;
1666 bytes[idx_offset..idx_offset + 4].copy_from_slice(&1u32.to_le_bytes());
1667
1668 let mut fresh = Gsu::new();
1669 let mut r = SaveReader::new(&bytes);
1670 assert!(matches!(
1671 fresh.load_state(&mut r),
1672 Err(SaveStateError::Invalid(_))
1673 ));
1674 }
1675}