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 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();
'runner: loop {
@ -68,7 +68,7 @@ pub fn run() {
cpu.fetch();
cpu.decode();
if cpu.should_redraw {
display.draw(&cpu.get_display_buffer());
display.draw(&cpu.get_frame_buffer());
cpu.should_redraw = false;
}
}

View File

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

View File

@ -1,5 +1,5 @@
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::opcodes::OpCodes;
use super::ram::RAM;
@ -17,7 +17,7 @@ pub struct CPU {
regs: Registers, // Registers
ram: RAM, // RAM
keypad: Keypad, // Keypad
db: DisplayBuffer, // Display Buffer
frame_buffer: FrameBuffer, // Frame Buffer
op: OpCodes, // Operation Code,
pub should_redraw: bool, // Boolean indicating Display Buffer update
}
@ -35,7 +35,7 @@ impl CPU {
regs: Registers::new(),
ram: ram,
keypad: Keypad::new(),
db: DisplayBuffer::new(10),
frame_buffer: FrameBuffer::new(),
op: OpCodes::new(0000),
should_redraw: false,
}
@ -211,17 +211,13 @@ impl CPU {
self.ram.load_rom(rom);
}
pub fn get_display_scale(&self) -> u32 {
self.db.scale
}
pub fn get_display_buffer(&self) -> [[bool; DISPLAY_HEIGHT]; DISPLAY_WIDTH] {
self.db.db
pub fn get_frame_buffer(&self) -> [u8; WIDTH * HEIGHT * PITCH_BYTES] {
self.frame_buffer.frame_buffer
}
}
fn op_00e0(cpu: &mut CPU) {
cpu.db.clear();
cpu.frame_buffer.clear();
}
fn op_1nnn(cpu: &mut CPU) {
@ -349,26 +345,27 @@ fn op_cxnn(cpu: &mut CPU) {
fn op_dxyn(cpu: &mut CPU) {
let mut vf: bool = false;
let value = cpu.op.n as usize;
let ori_x = cpu.regs.get(cpu.op.x) as usize % DISPLAY_WIDTH;
let ori_y = cpu.regs.get(cpu.op.y) as usize % DISPLAY_HEIGHT;
let ori_x = cpu.regs.get(cpu.op.x) as usize % WIDTH;
let ori_y = cpu.regs.get(cpu.op.y) as usize % HEIGHT;
for row in 0..value {
let y = ori_y + row;
if y >= DISPLAY_HEIGHT {
if y >= HEIGHT {
break;
}
let sprite = cpu.ram.read8(cpu.regs.i + row);
for pixel_position in 0..8 {
let x = ori_x + pixel_position;
if x >= DISPLAY_WIDTH {
if x >= WIDTH {
break;
}
let memory_pixel: bool = (sprite & (1 << (7 - pixel_position))) > 0;
let display_pixel: bool = cpu.db.db[x][y];
cpu.db.db[x][y] = memory_pixel ^ display_pixel;
vf = (memory_pixel && display_pixel) || vf;
let frame_pixel: bool = cpu.frame_buffer.toggle_buffer[x][y];
cpu.frame_buffer.toggle_buffer[x][y] = memory_pixel ^ frame_pixel;
cpu.frame_buffer.update_frame_buffer(x, y);
vf = (memory_pixel && frame_pixel) || vf;
}
}
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::render::Canvas;
use sdl2::video::Window;
const WIDTH: usize = 64;
const HEIGHT: usize = 32;
const PITCH_BYTES: usize = std::mem::size_of::<u32>(); // 4 bytes: R G B A, from colors
pub const WIDTH: usize = 64;
pub const HEIGHT: usize = 32;
pub const PITCH_BYTES: usize = std::mem::size_of::<u32>(); // 4 bytes: R G B A, from colors
const PITCH: usize = WIDTH * PITCH_BYTES;
pub struct Display {
canvas: Canvas<Window>,
off_color: [u8; PITCH_BYTES],
on_color: [u8; PITCH_BYTES],
canvas: Canvas<Window>
}
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()
.window("Chip-8", WIDTH as u32 * scale, HEIGHT as u32 * scale)
.resizable().position_centered().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 {
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]) {
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]; }
canvas: canvas
}
}
pub fn draw(self: &mut Display, frame_buffer: &[u8; HEIGHT * WIDTH * PITCH_BYTES]) {
let texture_creator = self.canvas.texture_creator();
let mut texture = texture_creator
.create_texture_streaming(PixelFormatEnum::RGBA32, WIDTH as u32, HEIGHT as u32)
.unwrap();
texture.update(None, &framebuffer, PITCH).unwrap();
texture.update(None, frame_buffer, PITCH).unwrap();
self.canvas.copy(&texture, None, None).unwrap();
self.canvas.present();
}
}