From 18e54f4a444f1d9e5a055f62509b32e01c369ca6 Mon Sep 17 00:00:00 2001 From: transistor Date: Mon, 20 Dec 2021 20:11:43 -0800 Subject: [PATCH] Added line-based hscroll and fixed an hscroll bug The hscroll table was multiplying by 2 (because scroll a and b values are next to each other) but it should have multiplied by 4 because each value is also 2 bytes and the array is of u8. I added hscroll by-line support by using a different function for the line scroll vs the cell or whole screen scrolling. There are still a bunch of glitches in scroll b's scroll values that I need to fix --- src/peripherals/genesis/ym7101.rs | 76 ++++++++++++++++++++++++------- todo.txt | 16 ++++++- 2 files changed, 73 insertions(+), 19 deletions(-) diff --git a/src/peripherals/genesis/ym7101.rs b/src/peripherals/genesis/ym7101.rs index 4c9d49c..2a0c09c 100644 --- a/src/peripherals/genesis/ym7101.rs +++ b/src/peripherals/genesis/ym7101.rs @@ -313,15 +313,15 @@ impl Ym7101State { (((rgb & 0xF00) as u32) >> 4) | (((rgb & 0x0F0) as u32) << 8) | (((rgb & 0x00F) as u32) << 20) } - pub fn get_pattern_iter<'a>(&'a self, pattern_name: u16) -> PatternIterator<'a> { + pub fn get_pattern_iter<'a>(&'a self, pattern_name: u16, line: i8) -> PatternIterator<'a> { let pattern_addr = (pattern_name & 0x07FF) << 5; let pattern_palette = ((pattern_name & 0x6000) >> 13) as u8; let h_rev = (pattern_name & 0x0800) != 0; let v_rev = (pattern_name & 0x1000) != 0; - PatternIterator::new(&self, pattern_addr as u32, pattern_palette, h_rev, v_rev) + PatternIterator::new(&self, pattern_addr as u32, pattern_palette, h_rev, v_rev, line) } - pub fn get_hscroll(&self, hcell: usize) -> (u32, u32) { + pub fn get_hscroll(&self, hcell: usize, column: usize) -> (u32, u32) { let base_addr = match self.mode_3 & MODE3_BF_H_SCROLL_MODE { 0 => self.hscroll_addr, 2 => self.hscroll_addr + (hcell << 4), @@ -329,8 +329,9 @@ impl Ym7101State { _ => panic!("Unsupported horizontal scroll mode"), }; - let scroll_a = read_beu16(&self.vram[base_addr..]) as u32 & 0x3FF; - let scroll_b = read_beu16(&self.vram[base_addr + 2..]) as u32 & 0x3FF; + let scroll_addr = base_addr + (column * 2 * 2); + let scroll_a = read_beu16(&self.vram[scroll_addr..]) as u32 & 0x3FF; + let scroll_b = read_beu16(&self.vram[scroll_addr + 2..]) as u32 & 0x3FF; (scroll_a, scroll_b) } @@ -367,10 +368,15 @@ impl Ym7101State { pub fn draw_pattern(&mut self, frame: &mut Frame, pattern: u16, pixel_x: u32, pixel_y: u32) { - let iter = self.get_pattern_iter(pattern); + let iter = self.get_pattern_iter(pattern, 0); frame.blit(pixel_x, pixel_y, iter, 8, 8); } + pub fn draw_pattern_line(&mut self, frame: &mut Frame, pattern: u16, pixel_x: u32, pixel_y: u32, line: i8) { + let iter = self.get_pattern_iter(pattern, line); + frame.blit(pixel_x, pixel_y, iter, 8, 1); + } + pub fn draw_frame(&mut self, frame: &mut Frame) { self.draw_background(frame); self.draw_scrolls(frame); @@ -383,25 +389,61 @@ impl Ym7101State { frame.clear(bg_colour); } + #[inline(always)] pub fn draw_scrolls(&mut self, frame: &mut Frame) { - let (scroll_h, scroll_v) = self.scroll_size; - let (cells_h, cells_v) = self.screen_size; - - if scroll_h == 0 || scroll_v == 0 { - return; + if (self.mode_3 & MODE3_BF_H_SCROLL_MODE) != 3 { + self.draw_scrolls_cell(frame); + } else { + self.draw_scrolls_line(frame); } + } + + pub fn draw_scrolls_cell(&mut self, frame: &mut Frame) { + let (cells_h, cells_v) = self.screen_size; for cell_y in 0..cells_v { let (vscrolling_a, vscrolling_b) = self.get_vscroll(cell_y); for cell_x in 0..cells_h { - let (hscrolling_a, hscrolling_b) = self.get_hscroll(cell_x); + let (hscrolling_a, hscrolling_b) = self.get_hscroll(cell_x, 0); let pattern_b = self.get_scroll_b_pattern(cell_x, cell_y, hscrolling_b as usize, vscrolling_b as usize); let pattern_a = self.get_scroll_a_pattern(cell_x, cell_y, hscrolling_a as usize, vscrolling_a as usize); //if (pattern_b & 0x8000) != 0 && (pattern_a & 0x8000) == 0 { - self.draw_pattern(frame, pattern_b, (cell_x << 3) as u32, (cell_y << 3) as u32); - self.draw_pattern(frame, pattern_a, (cell_x << 3) as u32, (cell_y << 3) as u32); + self.draw_pattern(frame, pattern_b, (cell_x << 3) as u32, (cell_y << 3) as u32 - (vscrolling_b % 8)); + self.draw_pattern(frame, pattern_a, (cell_x << 3) as u32, (cell_y << 3) as u32 - (vscrolling_b % 8)); + } + } + } + + pub fn draw_scrolls_line(&mut self, frame: &mut Frame) { + let (cells_h, cells_v) = self.screen_size; + + for cell_y in 0..cells_v { + let (vscrolling_a, vscrolling_b) = self.get_vscroll(cell_y); + for cell_x in 0..cells_h { + let (hscrolling_a, hscrolling_b) = self.get_hscroll(cell_x, 0); + + let pattern_b = self.get_scroll_b_pattern(cell_x, cell_y, hscrolling_b as usize, vscrolling_b as usize); + + for line in 0..8 { + let (_, offset_b) = self.get_hscroll(cell_x, line as usize); + self.draw_pattern_line(frame, pattern_b, (cell_x << 3) as u32 + (offset_b % 8), (cell_y << 3) as u32 + line as u32 - (vscrolling_b % 8), line); + } + } + } + + for cell_y in 0..cells_v { + let (vscrolling_a, vscrolling_b) = self.get_vscroll(cell_y); + for cell_x in 0..cells_h { + let (hscrolling_a, hscrolling_b) = self.get_hscroll(cell_x, 0); + + let pattern_a = self.get_scroll_a_pattern(cell_x, cell_y, hscrolling_a as usize, vscrolling_a as usize); + + for line in 0..8 { + let (offset_a, _) = self.get_hscroll(cell_x, line as usize); + self.draw_pattern_line(frame, pattern_a, (cell_x << 3) as u32 + (offset_a % 8), (cell_y << 3) as u32 + line as u32 - (vscrolling_a % 8), line); + } } } } @@ -462,7 +504,7 @@ impl Ym7101State { let (h, v) = (if !h_rev { ih } else { size_h - 1 - ih }, if !v_rev { iv } else { size_v - 1 - iv }); let (x, y) = (h_pos + ih * 8, v_pos + iv * 8); if x > 128 && x < pos_limit_h && y > 128 && y < pos_limit_v { - let iter = self.get_pattern_iter(((pattern_name & 0x07FF) + (h * size_v) + v) | (pattern_name & 0xF800)); + let iter = self.get_pattern_iter(((pattern_name & 0x07FF) + (h * size_v) + v) | (pattern_name & 0xF800), 0); frame.blit(x as u32 - 128, y as u32 - 128, iter, 8, 8); } @@ -493,14 +535,14 @@ pub struct PatternIterator<'a> { } impl<'a> PatternIterator<'a> { - pub fn new(state: &'a Ym7101State, start: u32, palette: u8, h_rev: bool, v_rev: bool) -> Self { + pub fn new(state: &'a Ym7101State, start: u32, palette: u8, h_rev: bool, v_rev: bool, line: i8) -> Self { Self { state, palette, base: start as usize, h_rev, v_rev, - line: 0, + line, col: 0, second: false, } diff --git a/todo.txt b/todo.txt index 8d4de69..3e0b15f 100644 --- a/todo.txt +++ b/todo.txt @@ -1,5 +1,17 @@ -* when a MOVE's targets are both ARegDec, the 2 extra clocks can be combined (-2 clocks in this one case) +* there is possibly a cpu bug in causing the acceleration in sonic 2 to be very slow. Speeding up the CPU makes it playably fast, but I think it's still + incorrect, in that the top speed is faster than it should be, but the acceleration is correct... +* for the speed problem, I've actually noticed the level vint is only called every ~33_200_000 ns which is twice as long as it should be, so maybe there's + a vint problem, maybe even a toggle trigger that should be a one-shot +* there is definitely something related to interrupts; 2 interrupts occur in between each call to Vint_Level (ie. Vint_Level only runs every 2 frames (33.2ms) instead + of every frame (16.6 ms), which perfectly explains the slowdown without it being related to an instruction implementation error... but why is this happening? + Maybe it's because the clock advances too much and first interrupt doesn't complete, or maybe there's a problem with interrupts and masking... + It does appear to do I/O with the VDP between te interrupts so it doesn't seem to be just waiting around + +* for the line based hscroll, you need to add that extra cell cycle... +* there is still some kind of hscroll glitch, and it seems to entirely be caused by the horizontal scroll offset value. I could be calculating or adding/moding + it incorrectly somewhere somehow, or the data in the hscroll table could be incorrect due to the cpu impl +* go through the testcases and make sure they are decoded correctly @@ -40,6 +52,7 @@ Audio: Debugger: + * i need a way to debug only the cpu and not the coprocessor, but that's tricky without a way to id or compare Transmutables * how can you improve the debugger? * the command line definitely needs to be fixed so it prints the prompt correctly * debugger could maybe even allows arrows left/right for editing, and up/down for history @@ -66,7 +79,6 @@ Macintosh: 68000: - * add instruction timing to M68k * check all instructions in the docs * unimplemented: BFFFO, BFINS, CHK, ILLEGAL, NBCD, NEGX, RTR, RTD