https://github.com/Ivsucram/ivsemu/issues/47
This commit is contained in:
Marcus Vinicius de Carvalho 2021-07-30 15:42:05 +08:00
parent 03b943eeca
commit e6f494aea3
6 changed files with 80 additions and 79 deletions

View File

@ -13,7 +13,7 @@ pub fn run() {
); );
let sdl_context = sdl2::init().unwrap(); let sdl_context = sdl2::init().unwrap();
let mut display = Display::init(&sdl_context, cpu.get_display_scale()); let mut display = Display::init(&sdl_context);
let mut event_pump = sdl_context.event_pump().unwrap(); let mut event_pump = sdl_context.event_pump().unwrap();
'runner: loop { 'runner: loop {
@ -68,7 +68,7 @@ pub fn run() {
cpu.fetch(); cpu.fetch();
cpu.decode(); cpu.decode();
if cpu.should_redraw { if cpu.should_redraw {
display.draw(&cpu.get_display_buffer()); display.draw(&cpu.get_frame_buffer());
cpu.should_redraw = false; cpu.should_redraw = false;
} }
} }

View File

@ -1,7 +1,7 @@
pub mod cpu; pub mod cpu;
mod clock; mod clock;
mod display_buffer; mod frame_buffer;
mod keypad; mod keypad;
mod opcodes; mod opcodes;
mod ram; mod ram;

View File

@ -1,5 +1,5 @@
use super::clock::Clock; use super::clock::Clock;
use super::display_buffer::{DisplayBuffer, DISPLAY_HEIGHT, DISPLAY_WIDTH}; use super::frame_buffer::{FrameBuffer, HEIGHT, WIDTH, PITCH_BYTES};
use super::keypad::Keypad; use super::keypad::Keypad;
use super::opcodes::OpCodes; use super::opcodes::OpCodes;
use super::ram::RAM; use super::ram::RAM;
@ -10,16 +10,16 @@ use sdl2::keyboard::Keycode;
use rand::Rng; use rand::Rng;
pub struct CPU { pub struct CPU {
stack: Vec<usize>, // Function Stack stack: Vec<usize>, // Function Stack
dt: Clock, // Delay Timer dt: Clock, // Delay Timer
st: Clock, // Sound Timer st: Clock, // Sound Timer
clock: Clock, // CPU Clock clock: Clock, // CPU Clock
regs: Registers, // Registers regs: Registers, // Registers
ram: RAM, // RAM ram: RAM, // RAM
keypad: Keypad, // Keypad keypad: Keypad, // Keypad
db: DisplayBuffer, // Display Buffer frame_buffer: FrameBuffer, // Frame Buffer
op: OpCodes, // Operation Code, op: OpCodes, // Operation Code,
pub should_redraw: bool, // Boolean indicating Display Buffer update pub should_redraw: bool, // Boolean indicating Display Buffer update
} }
impl CPU { impl CPU {
@ -35,7 +35,7 @@ impl CPU {
regs: Registers::new(), regs: Registers::new(),
ram: ram, ram: ram,
keypad: Keypad::new(), keypad: Keypad::new(),
db: DisplayBuffer::new(10), frame_buffer: FrameBuffer::new(),
op: OpCodes::new(0000), op: OpCodes::new(0000),
should_redraw: false, should_redraw: false,
} }
@ -211,17 +211,13 @@ impl CPU {
self.ram.load_rom(rom); self.ram.load_rom(rom);
} }
pub fn get_display_scale(&self) -> u32 { pub fn get_frame_buffer(&self) -> [u8; WIDTH * HEIGHT * PITCH_BYTES] {
self.db.scale self.frame_buffer.frame_buffer
}
pub fn get_display_buffer(&self) -> [[bool; DISPLAY_HEIGHT]; DISPLAY_WIDTH] {
self.db.db
} }
} }
fn op_00e0(cpu: &mut CPU) { fn op_00e0(cpu: &mut CPU) {
cpu.db.clear(); cpu.frame_buffer.clear();
} }
fn op_1nnn(cpu: &mut CPU) { fn op_1nnn(cpu: &mut CPU) {
@ -349,26 +345,27 @@ fn op_cxnn(cpu: &mut CPU) {
fn op_dxyn(cpu: &mut CPU) { fn op_dxyn(cpu: &mut CPU) {
let mut vf: bool = false; let mut vf: bool = false;
let value = cpu.op.n as usize; let value = cpu.op.n as usize;
let ori_x = cpu.regs.get(cpu.op.x) as usize % DISPLAY_WIDTH; let ori_x = cpu.regs.get(cpu.op.x) as usize % WIDTH;
let ori_y = cpu.regs.get(cpu.op.y) as usize % DISPLAY_HEIGHT; let ori_y = cpu.regs.get(cpu.op.y) as usize % HEIGHT;
for row in 0..value { for row in 0..value {
let y = ori_y + row; let y = ori_y + row;
if y >= DISPLAY_HEIGHT { if y >= HEIGHT {
break; break;
} }
let sprite = cpu.ram.read8(cpu.regs.i + row); let sprite = cpu.ram.read8(cpu.regs.i + row);
for pixel_position in 0..8 { for pixel_position in 0..8 {
let x = ori_x + pixel_position; let x = ori_x + pixel_position;
if x >= DISPLAY_WIDTH { if x >= WIDTH {
break; break;
} }
let memory_pixel: bool = (sprite & (1 << (7 - pixel_position))) > 0; let memory_pixel: bool = (sprite & (1 << (7 - pixel_position))) > 0;
let display_pixel: bool = cpu.db.db[x][y]; let frame_pixel: bool = cpu.frame_buffer.toggle_buffer[x][y];
cpu.db.db[x][y] = memory_pixel ^ display_pixel; cpu.frame_buffer.toggle_buffer[x][y] = memory_pixel ^ frame_pixel;
vf = (memory_pixel && display_pixel) || vf; cpu.frame_buffer.update_frame_buffer(x, y);
vf = (memory_pixel && frame_pixel) || vf;
} }
} }
cpu.regs.set(0xF, if vf { 1 } else { 0 }); cpu.regs.set(0xF, if vf { 1 } else { 0 });

View File

@ -1,20 +0,0 @@
pub const DISPLAY_WIDTH: usize = 64;
pub const DISPLAY_HEIGHT: usize = 32;
pub struct DisplayBuffer {
pub db: [[bool; DISPLAY_HEIGHT]; DISPLAY_WIDTH],
pub scale: u32,
}
impl DisplayBuffer {
pub fn new(scale: u32) -> DisplayBuffer {
DisplayBuffer {
db: [[false; DISPLAY_HEIGHT]; DISPLAY_WIDTH],
scale: scale,
}
}
pub fn clear(&mut self) {
self.db = [[false; DISPLAY_HEIGHT]; DISPLAY_WIDTH];
}
}

View File

@ -0,0 +1,44 @@
use sdl2::pixels::Color;
use crate::chip_8::display;
pub const WIDTH: usize = display::WIDTH;
pub const HEIGHT: usize = display::HEIGHT;
pub const PITCH_BYTES: usize = display::PITCH_BYTES;
pub struct FrameBuffer {
pub frame_buffer: [u8; WIDTH * HEIGHT * PITCH_BYTES],
pub toggle_buffer: [[bool; HEIGHT]; WIDTH],
off_color: [u8; PITCH_BYTES],
on_color: [u8; PITCH_BYTES],
}
impl FrameBuffer {
pub fn new() -> FrameBuffer {
let off_color = Color::RGBA(0, 0, 0, 255);
let on_color = Color::RGBA(255, 255, 255, 255);
FrameBuffer {
frame_buffer: [0; WIDTH * HEIGHT * PITCH_BYTES],
toggle_buffer: [[false; HEIGHT]; WIDTH],
off_color: [off_color.r, off_color.g, off_color.b, off_color.a],
on_color: [on_color.r, on_color.g, on_color.b, on_color.a],
}
}
pub fn clear(&mut self) {
for (x, col) in self.toggle_buffer.iter().enumerate() {
for (y, _) in col.iter().enumerate() {
let offset = x * PITCH_BYTES + y * WIDTH * PITCH_BYTES;
for i in offset..(offset + PITCH_BYTES) { self.frame_buffer[i] = self.off_color[i - offset]; }
}
}
self.toggle_buffer = [[false; HEIGHT]; WIDTH];
}
pub fn update_frame_buffer(&mut self, x: usize, y: usize) {
let offset = x * PITCH_BYTES + y * WIDTH * PITCH_BYTES;
let color: &[u8; PITCH_BYTES] = if self.toggle_buffer[x][y] { &self.on_color } else { &self.off_color };
for i in offset..(offset + PITCH_BYTES) { self.frame_buffer[i] = color[i - offset]; }
}
}

View File

@ -1,56 +1,36 @@
use sdl2::pixels::Color;
use sdl2::pixels::PixelFormatEnum; use sdl2::pixels::PixelFormatEnum;
use sdl2::render::Canvas; use sdl2::render::Canvas;
use sdl2::video::Window; use sdl2::video::Window;
const WIDTH: usize = 64; pub const WIDTH: usize = 64;
const HEIGHT: usize = 32; pub const HEIGHT: usize = 32;
const PITCH_BYTES: usize = std::mem::size_of::<u32>(); // 4 bytes: R G B A, from colors pub const PITCH_BYTES: usize = std::mem::size_of::<u32>(); // 4 bytes: R G B A, from colors
const PITCH: usize = WIDTH * PITCH_BYTES; const PITCH: usize = WIDTH * PITCH_BYTES;
pub struct Display { pub struct Display {
canvas: Canvas<Window>, canvas: Canvas<Window>
off_color: [u8; PITCH_BYTES],
on_color: [u8; PITCH_BYTES],
} }
impl Display { impl Display {
pub fn init(sdl_context: &sdl2::Sdl, scale: u32) -> Display { pub fn init(sdl_context: &sdl2::Sdl) -> Display {
let scale = 10;
let canvas = sdl_context.video().unwrap() let canvas = sdl_context.video().unwrap()
.window("Chip-8", WIDTH as u32 * scale, HEIGHT as u32 * scale) .window("Chip-8", WIDTH as u32 * scale, HEIGHT as u32 * scale)
.resizable().position_centered().build().unwrap() .resizable().position_centered().build().unwrap()
.into_canvas().build().unwrap(); .into_canvas().build().unwrap();
let off_color = Color::RGBA(0, 0, 0, 255);
let on_color = Color::RGBA(255, 255, 255, 255);
Display { Display {
canvas: canvas, canvas: canvas
off_color: [off_color.r, off_color.g, off_color.b, off_color.a],
on_color: [on_color.r, on_color.g, on_color.b, on_color.a],
} }
} }
pub fn draw(self: &mut Display, buffer: &[[bool; HEIGHT]; WIDTH]) { pub fn draw(self: &mut Display, frame_buffer: &[u8; HEIGHT * WIDTH * PITCH_BYTES]) {
self.apply_texture(buffer);
self.canvas.present();
}
fn apply_texture(&mut self, buffer: &[[bool; HEIGHT]; WIDTH]) {
let mut framebuffer: [u8; HEIGHT * PITCH] = [0; HEIGHT * PITCH];
for (x, col) in buffer.iter().enumerate() {
for (y, pixel) in col.iter().enumerate() {
let offset = x * PITCH_BYTES + y * PITCH;
let color: &[u8; PITCH_BYTES] = if *pixel { &self.on_color } else { &self.off_color };
for i in offset..(offset + PITCH_BYTES) { framebuffer[i] = color[i - offset]; }
}
}
let texture_creator = self.canvas.texture_creator(); let texture_creator = self.canvas.texture_creator();
let mut texture = texture_creator let mut texture = texture_creator
.create_texture_streaming(PixelFormatEnum::RGBA32, WIDTH as u32, HEIGHT as u32) .create_texture_streaming(PixelFormatEnum::RGBA32, WIDTH as u32, HEIGHT as u32)
.unwrap(); .unwrap();
texture.update(None, &framebuffer, PITCH).unwrap(); texture.update(None, frame_buffer, PITCH).unwrap();
self.canvas.copy(&texture, None, None).unwrap(); self.canvas.copy(&texture, None, None).unwrap();
self.canvas.present();
} }
} }