VIP inspection tooling #4
			
				
			
		
		
		
	| 
						 | 
					@ -39,11 +39,12 @@ impl MemoryClient {
 | 
				
			||||||
        MemoryView { region }
 | 
					        MemoryView { region }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn write<T: bytemuck::NoUninit>(&self, sim: SimId, address: u32, data: &T) {
 | 
					    pub fn write<T: MemoryValue>(&self, sim: SimId, address: u32, data: &T) {
 | 
				
			||||||
        let data = bytemuck::bytes_of(data).to_vec();
 | 
					        let mut buffer = vec![];
 | 
				
			||||||
 | 
					        data.to_bytes(&mut buffer);
 | 
				
			||||||
        let (tx, _) = oneshot::channel();
 | 
					        let (tx, _) = oneshot::channel();
 | 
				
			||||||
        self.client
 | 
					        self.client
 | 
				
			||||||
            .send_command(EmulatorCommand::WriteMemory(sim, address, data, tx));
 | 
					            .send_command(EmulatorCommand::WriteMemory(sim, address, buffer, tx));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -74,17 +75,87 @@ pub struct MemoryRef<'a> {
 | 
				
			||||||
    inner: RwLockReadGuard<'a, BoxBytes>,
 | 
					    inner: RwLockReadGuard<'a, BoxBytes>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl MemoryRef<'_> {
 | 
					pub trait MemoryValue {
 | 
				
			||||||
    pub fn read<T: bytemuck::AnyBitPattern>(&self, index: usize) -> T {
 | 
					    fn from_bytes(bytes: &[u8]) -> Self;
 | 
				
			||||||
        let from = index * size_of::<T>();
 | 
					    fn to_bytes(&self, buffer: &mut Vec<u8>);
 | 
				
			||||||
        let to = from + size_of::<T>();
 | 
					 | 
				
			||||||
        *bytemuck::from_bytes(&self.inner[from..to])
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn range<T: bytemuck::AnyBitPattern>(&self, start: usize, count: usize) -> &[T] {
 | 
					macro_rules! primitive_memory_value_impl {
 | 
				
			||||||
 | 
					    ($T:ty, $L: expr) => {
 | 
				
			||||||
 | 
					        impl MemoryValue for $T {
 | 
				
			||||||
 | 
					            #[inline]
 | 
				
			||||||
 | 
					            fn from_bytes(bytes: &[u8]) -> Self {
 | 
				
			||||||
 | 
					                let bytes: [u8; std::mem::size_of::<$T>()] = std::array::from_fn(|i| bytes[i]);
 | 
				
			||||||
 | 
					                <$T>::from_le_bytes(bytes)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            #[inline]
 | 
				
			||||||
 | 
					            fn to_bytes(&self, buffer: &mut Vec<u8>) {
 | 
				
			||||||
 | 
					                buffer.extend_from_slice(&self.to_le_bytes())
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					primitive_memory_value_impl!(u8, 1);
 | 
				
			||||||
 | 
					primitive_memory_value_impl!(u16, 2);
 | 
				
			||||||
 | 
					primitive_memory_value_impl!(u32, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<const N: usize, T: MemoryValue> MemoryValue for [T; N] {
 | 
				
			||||||
 | 
					    #[inline]
 | 
				
			||||||
 | 
					    fn from_bytes(bytes: &[u8]) -> Self {
 | 
				
			||||||
 | 
					        std::array::from_fn(|i| {
 | 
				
			||||||
 | 
					            T::from_bytes(&bytes[i * std::mem::size_of::<T>()..(i + 1) * std::mem::size_of::<T>()])
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[inline]
 | 
				
			||||||
 | 
					    fn to_bytes(&self, buffer: &mut Vec<u8>) {
 | 
				
			||||||
 | 
					        for item in self {
 | 
				
			||||||
 | 
					            item.to_bytes(buffer);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct MemoryIter<'a, T> {
 | 
				
			||||||
 | 
					    bytes: &'a [u8],
 | 
				
			||||||
 | 
					    index: usize,
 | 
				
			||||||
 | 
					    _phantom: std::marker::PhantomData<T>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a, T> MemoryIter<'a, T> {
 | 
				
			||||||
 | 
					    fn new(bytes: &'a [u8]) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            bytes,
 | 
				
			||||||
 | 
					            index: 0,
 | 
				
			||||||
 | 
					            _phantom: std::marker::PhantomData,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T: MemoryValue> Iterator for MemoryIter<'_, T> {
 | 
				
			||||||
 | 
					    type Item = T;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[inline]
 | 
				
			||||||
 | 
					    fn next(&mut self) -> Option<Self::Item> {
 | 
				
			||||||
 | 
					        if self.index >= self.bytes.len() {
 | 
				
			||||||
 | 
					            return None;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let bytes = &self.bytes[self.index..self.index + std::mem::size_of::<T>()];
 | 
				
			||||||
 | 
					        self.index += std::mem::size_of::<T>();
 | 
				
			||||||
 | 
					        Some(T::from_bytes(bytes))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl MemoryRef<'_> {
 | 
				
			||||||
 | 
					    pub fn read<T: MemoryValue>(&self, index: usize) -> T {
 | 
				
			||||||
 | 
					        let from = index * size_of::<T>();
 | 
				
			||||||
 | 
					        let to = from + size_of::<T>();
 | 
				
			||||||
 | 
					        T::from_bytes(&self.inner[from..to])
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn range<T: MemoryValue>(&self, start: usize, count: usize) -> MemoryIter<T> {
 | 
				
			||||||
        let from = start * size_of::<T>();
 | 
					        let from = start * size_of::<T>();
 | 
				
			||||||
        let to = from + (count * size_of::<T>());
 | 
					        let to = from + (count * size_of::<T>());
 | 
				
			||||||
        bytemuck::cast_slice(&self.inner[from..to])
 | 
					        MemoryIter::new(&self.inner[from..to])
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -239,30 +239,26 @@ impl BgMapRenderer {
 | 
				
			||||||
        let brightness = self.brightness.borrow();
 | 
					        let brightness = self.brightness.borrow();
 | 
				
			||||||
        let palettes = self.palettes.borrow();
 | 
					        let palettes = self.palettes.borrow();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let brts = brightness.range::<u8>(0, 8);
 | 
					        let brts = brightness.read::<[u8; 8]>(0);
 | 
				
			||||||
        let colors = if generic_palette {
 | 
					        let colors = if generic_palette {
 | 
				
			||||||
            [utils::generic_palette(Color32::RED); 4]
 | 
					            [utils::generic_palette(Color32::RED); 4]
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            [0, 2, 4, 6].map(|i| utils::parse_palette(palettes.read(i), brts, Color32::RED))
 | 
					            [0, 2, 4, 6].map(|i| utils::parse_palette(palettes.read(i), &brts, Color32::RED))
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (i, cell) in bgmaps
 | 
					        for (i, cell) in bgmaps.range::<u16>(bgmap_index * 4096, 4096).enumerate() {
 | 
				
			||||||
            .range::<u16>(bgmap_index * 4096, 4096)
 | 
					 | 
				
			||||||
            .iter()
 | 
					 | 
				
			||||||
            .enumerate()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            let CellData {
 | 
					            let CellData {
 | 
				
			||||||
                char_index,
 | 
					                char_index,
 | 
				
			||||||
                vflip,
 | 
					                vflip,
 | 
				
			||||||
                hflip,
 | 
					                hflip,
 | 
				
			||||||
                palette_index,
 | 
					                palette_index,
 | 
				
			||||||
            } = CellData::parse(*cell);
 | 
					            } = CellData::parse(cell);
 | 
				
			||||||
            let char = chardata.range::<u16>(char_index * 8, 8);
 | 
					            let char = chardata.read::<[u16; 8]>(char_index);
 | 
				
			||||||
            let palette = &colors[palette_index];
 | 
					            let palette = &colors[palette_index];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for row in 0..8 {
 | 
					            for row in 0..8 {
 | 
				
			||||||
                let y = row + (i / 64) * 8;
 | 
					                let y = row + (i / 64) * 8;
 | 
				
			||||||
                for (col, pixel) in utils::read_char_row(char, hflip, vflip, row).enumerate() {
 | 
					                for (col, pixel) in utils::read_char_row(&char, hflip, vflip, row).enumerate() {
 | 
				
			||||||
                    let x = col + (i % 64) * 8;
 | 
					                    let x = col + (i % 64) * 8;
 | 
				
			||||||
                    image.write((x, y), palette[pixel as usize]);
 | 
					                    image.write((x, y), palette[pixel as usize]);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
| 
						 | 
					@ -276,7 +272,7 @@ impl BgMapRenderer {
 | 
				
			||||||
        let brightness = self.brightness.borrow();
 | 
					        let brightness = self.brightness.borrow();
 | 
				
			||||||
        let palettes = self.palettes.borrow();
 | 
					        let palettes = self.palettes.borrow();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let brts = brightness.range::<u8>(0, 8);
 | 
					        let brts = brightness.read::<[u8; 8]>(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let cell = bgmaps.read::<u16>(index);
 | 
					        let cell = bgmaps.read::<u16>(index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -286,15 +282,15 @@ impl BgMapRenderer {
 | 
				
			||||||
            hflip,
 | 
					            hflip,
 | 
				
			||||||
            palette_index,
 | 
					            palette_index,
 | 
				
			||||||
        } = CellData::parse(cell);
 | 
					        } = CellData::parse(cell);
 | 
				
			||||||
        let char = chardata.range::<u16>(char_index * 8, 8);
 | 
					        let char = chardata.read::<[u16; 8]>(char_index);
 | 
				
			||||||
        let palette = if generic_palette {
 | 
					        let palette = if generic_palette {
 | 
				
			||||||
            utils::generic_palette(Color32::RED)
 | 
					            utils::generic_palette(Color32::RED)
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            utils::parse_palette(palettes.read(palette_index * 2), brts, Color32::RED)
 | 
					            utils::parse_palette(palettes.read(palette_index * 2), &brts, Color32::RED)
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for row in 0..8 {
 | 
					        for row in 0..8 {
 | 
				
			||||||
            for (col, pixel) in utils::read_char_row(char, hflip, vflip, row).enumerate() {
 | 
					            for (col, pixel) in utils::read_char_row(&char, hflip, vflip, row).enumerate() {
 | 
				
			||||||
                image.write((col, row), palette[pixel as usize]);
 | 
					                image.write((col, row), palette[pixel as usize]);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -221,8 +221,8 @@ impl CharacterDataWindow {
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        let palette = self.palettes.borrow().read(offset);
 | 
					        let palette = self.palettes.borrow().read(offset);
 | 
				
			||||||
        let brightnesses = self.brightness.borrow();
 | 
					        let brightnesses = self.brightness.borrow();
 | 
				
			||||||
        let brts = brightnesses.range(0, 8);
 | 
					        let brts = brightnesses.read(0);
 | 
				
			||||||
        utils::parse_palette(palette, brts, Color32::RED)
 | 
					        utils::parse_palette(palette, &brts, Color32::RED)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn show_chardata(&mut self, ui: &mut Ui) {
 | 
					    fn show_chardata(&mut self, ui: &mut Ui) {
 | 
				
			||||||
| 
						 | 
					@ -321,7 +321,7 @@ impl CharDataRenderer {
 | 
				
			||||||
        let palette = self.load_palette(palette);
 | 
					        let palette = self.load_palette(palette);
 | 
				
			||||||
        let chardata = self.chardata.borrow();
 | 
					        let chardata = self.chardata.borrow();
 | 
				
			||||||
        let character = chardata.range::<u16>(index * 8, 8);
 | 
					        let character = chardata.range::<u16>(index * 8, 8);
 | 
				
			||||||
        for (row, pixels) in character.iter().enumerate() {
 | 
					        for (row, pixels) in character.enumerate() {
 | 
				
			||||||
            for col in 0..8 {
 | 
					            for col in 0..8 {
 | 
				
			||||||
                let char = (pixels >> (col * 2)) & 0x03;
 | 
					                let char = (pixels >> (col * 2)) & 0x03;
 | 
				
			||||||
                image.write((col, row), palette[char as usize]);
 | 
					                image.write((col, row), palette[char as usize]);
 | 
				
			||||||
| 
						 | 
					@ -332,7 +332,7 @@ impl CharDataRenderer {
 | 
				
			||||||
    fn render_character_data(&self, image: &mut VramImage, palette: VramPalette) {
 | 
					    fn render_character_data(&self, image: &mut VramImage, palette: VramPalette) {
 | 
				
			||||||
        let palette = self.load_palette(palette);
 | 
					        let palette = self.load_palette(palette);
 | 
				
			||||||
        let chardata = self.chardata.borrow();
 | 
					        let chardata = self.chardata.borrow();
 | 
				
			||||||
        for (row, pixels) in chardata.range::<u16>(0, 8 * 2048).iter().enumerate() {
 | 
					        for (row, pixels) in chardata.range::<u16>(0, 8 * 2048).enumerate() {
 | 
				
			||||||
            let char_index = row / 8;
 | 
					            let char_index = row / 8;
 | 
				
			||||||
            let row_index = row % 8;
 | 
					            let row_index = row % 8;
 | 
				
			||||||
            let x = (char_index % 16) * 8;
 | 
					            let x = (char_index % 16) * 8;
 | 
				
			||||||
| 
						 | 
					@ -350,7 +350,7 @@ impl CharDataRenderer {
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        let palette = self.palettes.borrow().read(offset);
 | 
					        let palette = self.palettes.borrow().read(offset);
 | 
				
			||||||
        let brightnesses = self.brightness.borrow();
 | 
					        let brightnesses = self.brightness.borrow();
 | 
				
			||||||
        let brts = brightnesses.range(0, 8);
 | 
					        let brts = brightnesses.read(0);
 | 
				
			||||||
        utils::parse_palette(palette, brts, Color32::RED)
 | 
					        utils::parse_palette(palette, &brts, Color32::RED)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -282,7 +282,7 @@ impl ObjectRenderer {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let brts = brightness.range::<u8>(0, 8);
 | 
					        let brts = brightness.read::<[u8; 8]>(0);
 | 
				
			||||||
        let (x, y) = if use_pos {
 | 
					        let (x, y) = if use_pos {
 | 
				
			||||||
            let x = match eye {
 | 
					            let x = match eye {
 | 
				
			||||||
                Eye::Left => obj.x - obj.parallax,
 | 
					                Eye::Left => obj.x - obj.parallax,
 | 
				
			||||||
| 
						 | 
					@ -298,11 +298,11 @@ impl ObjectRenderer {
 | 
				
			||||||
            Eye::Right => params.right_color,
 | 
					            Eye::Right => params.right_color,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let char = chardata.range::<u16>(obj.data.char_index * 8, 8);
 | 
					        let char = chardata.read::<[u16; 8]>(obj.data.char_index);
 | 
				
			||||||
        let palette = if params.generic_palette {
 | 
					        let palette = if params.generic_palette {
 | 
				
			||||||
            utils::generic_palette(color)
 | 
					            utils::generic_palette(color)
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            utils::parse_palette(palettes.read(8 + obj.data.palette_index * 2), brts, color)
 | 
					            utils::parse_palette(palettes.read(8 + obj.data.palette_index * 2), &brts, color)
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for row in 0..8 {
 | 
					        for row in 0..8 {
 | 
				
			||||||
| 
						 | 
					@ -311,7 +311,7 @@ impl ObjectRenderer {
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            for (col, pixel) in
 | 
					            for (col, pixel) in
 | 
				
			||||||
                utils::read_char_row(char, obj.data.hflip, obj.data.vflip, row).enumerate()
 | 
					                utils::read_char_row(&char, obj.data.hflip, obj.data.vflip, row).enumerate()
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                let real_x = x + col as i16;
 | 
					                let real_x = x + col as i16;
 | 
				
			||||||
                if !(0..384).contains(&real_x) {
 | 
					                if !(0..384).contains(&real_x) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,7 @@ pub fn generic_palette(color: Color32) -> [Color32; 4] {
 | 
				
			||||||
    GENERIC_PALETTE.map(|brt| shade(brt, color))
 | 
					    GENERIC_PALETTE.map(|brt| shade(brt, color))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn parse_palette(palette: u8, brts: &[u8], color: Color32) -> [Color32; 4] {
 | 
					pub fn parse_palette(palette: u8, brts: &[u8; 8], color: Color32) -> [Color32; 4] {
 | 
				
			||||||
    let shades = [
 | 
					    let shades = [
 | 
				
			||||||
        Color32::BLACK,
 | 
					        Color32::BLACK,
 | 
				
			||||||
        shade(brts[0], color),
 | 
					        shade(brts[0], color),
 | 
				
			||||||
| 
						 | 
					@ -117,7 +117,7 @@ impl CellData {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn read_char_row(
 | 
					pub fn read_char_row(
 | 
				
			||||||
    char: &[u16],
 | 
					    char: &[u16; 8],
 | 
				
			||||||
    hflip: bool,
 | 
					    hflip: bool,
 | 
				
			||||||
    vflip: bool,
 | 
					    vflip: bool,
 | 
				
			||||||
    row: usize,
 | 
					    row: usize,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue