From 5d6af61531c05a2e9b07fe4ae6be3407dac1016c Mon Sep 17 00:00:00 2001 From: transistor Date: Wed, 29 Dec 2021 10:54:43 -0800 Subject: [PATCH] Incomplete addition of shadow/highlight mode for Genesis --- src/peripherals/genesis/ym7101.rs | 39 ++++++++++++++++++++----------- todo.txt | 15 ++++++++---- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/peripherals/genesis/ym7101.rs b/src/peripherals/genesis/ym7101.rs index 06676a7..c652fca 100644 --- a/src/peripherals/genesis/ym7101.rs +++ b/src/peripherals/genesis/ym7101.rs @@ -59,7 +59,7 @@ const MODE3_BF_V_SCROLL_MODE: u8 = 0x04; const MODE3_BF_H_SCROLL_MODE: u8 = 0x03; const MODE4_BF_H_CELL_MODE: u8 = 0x01; -//const MODE4_BF_SHADOW_HIGHLIGHT: u8 = 0x08; +const MODE4_BF_SHADOW_HIGHLIGHT: u8 = 0x08; @@ -81,6 +81,13 @@ pub enum TargetType { Vsram, } +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum ColourMode { + Normal, + Shadow, + Highlight, +} + pub struct Ym7101State { pub status: u16, pub vram: [u8; 0x10000], @@ -305,12 +312,18 @@ impl Ym7101State { (self.mode_3 & MODE3_BF_EXTERNAL_INTERRUPT) != 0 } - pub fn get_palette_colour(&self, palette: u8, colour: u8) -> u32 { + pub fn get_palette_colour(&self, palette: u8, colour: u8, mode: ColourMode) -> u32 { if colour == 0 { return 0xFFFFFFFF; } + let shift_enabled = (self.mode_4 & MODE4_BF_SHADOW_HIGHLIGHT) != 0; let rgb = read_beu16(&self.cram[(((palette * 16) + colour) * 2) as usize..]); - (((rgb & 0xF00) as u32) >> 4) | (((rgb & 0x0F0) as u32) << 8) | (((rgb & 0x00F) as u32) << 20) + if !shift_enabled || mode == ColourMode::Normal { + (((rgb & 0xF00) as u32) >> 4) | (((rgb & 0x0F0) as u32) << 8) | (((rgb & 0x00F) as u32) << 20) + } else { + let offset = if mode == ColourMode::Highlight { 0x808080 } else { 0x00 }; + (((rgb & 0xF00) as u32) >> 5) | (((rgb & 0x0F0) as u32) << 7) | (((rgb & 0x00F) as u32) << 19) | offset + } } pub fn get_pattern_iter<'a>(&'a self, pattern_name: u16, line: i8) -> PatternIterator<'a> { @@ -318,7 +331,8 @@ impl Ym7101State { 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, line) + let mode = if (pattern_name & 0x8000) != 0 { ColourMode::Shadow } else { ColourMode::Normal }; + PatternIterator::new(&self, pattern_addr as u32, pattern_palette, mode, h_rev, v_rev, line) } pub fn get_hscroll(&self, hcell: usize, line: usize) -> (u32, u32) { @@ -385,7 +399,7 @@ impl Ym7101State { } pub fn draw_background(&mut self, frame: &mut Frame) { - let bg_colour = self.get_palette_colour((self.background & 0x30) >> 4, self.background & 0x0f); + let bg_colour = self.get_palette_colour((self.background & 0x30) >> 4, self.background & 0x0f, ColourMode::Normal); frame.clear(bg_colour); } @@ -421,19 +435,14 @@ impl Ym7101State { for cell_y in 0..cells_v { for line in 0..8 { - let (_, hscrolling_b) = self.get_hscroll(cell_y, line as usize); + let (hscrolling_a, hscrolling_b) = self.get_hscroll(cell_y, line as usize); for cell_x in 0..cells_h { let (_, vscrolling_b) = self.get_vscroll(cell_x); let pattern_b = self.get_scroll_b_pattern(cell_x, cell_y, hscrolling_b as usize, vscrolling_b as usize); self.draw_pattern_line(frame, pattern_b, (cell_x << 3) as u32 + (hscrolling_b % 8), (cell_y << 3) as u32 + line as u32 - (vscrolling_b % 8), line); } - } - } - for cell_y in 0..cells_v { - for line in 0..8 { - let (hscrolling_a, _) = self.get_hscroll(cell_y, line as usize); for cell_x in 0..cells_h { let (vscrolling_a, _) = self.get_vscroll(cell_x); @@ -524,6 +533,7 @@ fn decode_scroll_size(size: u8) -> usize { pub struct PatternIterator<'a> { state: &'a Ym7101State, palette: u8, + mode: ColourMode, base: usize, h_rev: bool, v_rev: bool, @@ -533,10 +543,11 @@ pub struct PatternIterator<'a> { } impl<'a> PatternIterator<'a> { - pub fn new(state: &'a Ym7101State, start: u32, palette: u8, h_rev: bool, v_rev: bool, line: i8) -> Self { + pub fn new(state: &'a Ym7101State, start: u32, palette: u8, mode: ColourMode, h_rev: bool, v_rev: bool, line: i8) -> Self { Self { state, palette, + mode, base: start as usize, h_rev, v_rev, @@ -553,9 +564,9 @@ impl<'a> Iterator for PatternIterator<'a> { fn next(&mut self) -> Option { let offset = self.base + (if !self.v_rev { self.line } else { 7 - self.line }) as usize * 4 + (if !self.h_rev { self.col } else { 3 - self.col }) as usize; let value = if (!self.h_rev && !self.second) || (self.h_rev && self.second) { - self.state.get_palette_colour(self.palette, self.state.vram[offset] >> 4) + self.state.get_palette_colour(self.palette, self.state.vram[offset] >> 4, self.mode) } else { - self.state.get_palette_colour(self.palette, self.state.vram[offset] & 0x0f) + self.state.get_palette_colour(self.palette, self.state.vram[offset] & 0x0f, self.mode) }; if !self.second { diff --git a/todo.txt b/todo.txt index ceb6ece..1bb85ae 100644 --- a/todo.txt +++ b/todo.txt @@ -1,15 +1,14 @@ +* you need to refactor the ym7101 stuff +* can you make vram/cram/vsram be Addressables that can be accessed the same way? Would this add too much overhead? +* you can directly use a MemoryBlock, and separate out the dma + * there is an issue with Mortal Kombat 2 where it will crash randomly at the start of a fight. The code is actually swapping stacks a bunch of times, and at some point, the stack is corrupted or something and it `rts`s to the wrong address... * go through the testcases.rs file and make sure they were decoded correctly * should you rename devices.rs traits.rs? -* add command line arguments to speed up or slow down either the frame rate limiter or the simulated time per frame - -* can you make the connections between things (like memory adapters), be expressed in a way that's more similar to the electrical design? - like specifying that address pins 10-7 should be ignored/unconnected, pin 11 will connect to "chip select", etc -* should you add a unique ID to devices, such that they can be indexed, and their step functions can reset the next_run count and run them immediately Audio: @@ -33,6 +32,10 @@ Audio: System/Traits: + * can you make the connections between things (like memory adapters), be expressed in a way that's more similar to the electrical design? + like specifying that address pins 10-7 should be ignored/unconnected, pin 11 will connect to "chip select", etc + * should you add a unique ID to devices, such that they can be indexed, and their step functions can reset the next_run count and run them immediately + * should you simulate bus arbitration? * interrupts could be done in a better way * need a better way of handling disparate reads/writes to I/O spaces, rather than having multiple devices or having a massive chunk of address space allocated, continuously @@ -47,6 +50,7 @@ Debugger: * add a way to delete a watcher * can you improve how the watcher implementation in the Bus works, instead of setting a flag and then checking it every cycle, pass in the System to Addressable?? * can you use the breakpoint address parser in other commands? + * get stack tracing working again, but can you do it with just data? * 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 @@ -61,6 +65,7 @@ Genesis/Mega Drive: * in some games the controller doesn't seem to work at all (Earthworm Jim, and Mortal Kombat) * refactor ym7101 into multiple files perhaps. You can separate the DMA stuff, the address/interfacing parts, and the graphics state * colours are still broken in Sonic1 + * sonic3 needs some kind of nvram to run * implement sn76489 and ym2612 for audio * the 68000/Z80 bank switching is probably buggy, and there's that other banking stuff in the 0xC00000 range, which isn't implemented at all