mirror of https://github.com/Ivsucram/ivsemu.git
commit
25d228c440
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
pub mod cpu;
|
||||
|
||||
mod clock;
|
||||
mod display_buffer;
|
||||
mod frame_buffer;
|
||||
mod keypad;
|
||||
mod opcodes;
|
||||
mod ram;
|
||||
|
|
|
@ -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;
|
||||
|
@ -10,16 +10,16 @@ use sdl2::keyboard::Keycode;
|
|||
use rand::Rng;
|
||||
|
||||
pub struct CPU {
|
||||
stack: Vec<usize>, // Function Stack
|
||||
dt: Clock, // Delay Timer
|
||||
st: Clock, // Sound Timer
|
||||
clock: Clock, // CPU Clock
|
||||
regs: Registers, // Registers
|
||||
ram: RAM, // RAM
|
||||
keypad: Keypad, // Keypad
|
||||
db: DisplayBuffer, // Display Buffer
|
||||
op: OpCodes, // Operation Code,
|
||||
pub should_redraw: bool, // Boolean indicating Display Buffer update
|
||||
stack: Vec<usize>, // Function Stack
|
||||
dt: Clock, // Delay Timer
|
||||
st: Clock, // Sound Timer
|
||||
clock: Clock, // CPU Clock
|
||||
regs: Registers, // Registers
|
||||
ram: RAM, // RAM
|
||||
keypad: Keypad, // Keypad
|
||||
frame_buffer: FrameBuffer, // Frame Buffer
|
||||
op: OpCodes, // Operation Code,
|
||||
pub should_redraw: bool, // Boolean indicating Display Buffer update
|
||||
}
|
||||
|
||||
impl CPU {
|
||||
|
@ -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 });
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
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: Color,
|
||||
on_color: Color,
|
||||
}
|
||||
|
||||
impl FrameBuffer {
|
||||
pub fn new() -> FrameBuffer {
|
||||
FrameBuffer {
|
||||
frame_buffer: [0; WIDTH * HEIGHT * PITCH_BYTES],
|
||||
toggle_buffer: [[false; HEIGHT]; WIDTH],
|
||||
off_color: Color::RGBA(0, 0, 0, 255),
|
||||
on_color: Color::RGBA(255, 255, 255, 255),
|
||||
}
|
||||
}
|
||||
|
||||
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.color_to_array(&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: Color = if self.toggle_buffer[x][y] { self.on_color } else { self.off_color };
|
||||
for i in offset..(offset + PITCH_BYTES) { self.frame_buffer[i] = self.color_to_array(&color)[i - offset]; }
|
||||
}
|
||||
|
||||
fn color_to_array(&self, color: &Color) -> [u8; PITCH_BYTES] {
|
||||
[color.r, color.g, color.b, color.a]
|
||||
}
|
||||
}
|
|
@ -1,56 +1,35 @@
|
|||
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
|
||||
const PITCH: usize = WIDTH * PITCH_BYTES;
|
||||
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
|
||||
|
||||
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],
|
||||
canvas: canvas
|
||||
}
|
||||
}
|
||||
|
||||
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]; }
|
||||
}
|
||||
}
|
||||
|
||||
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, WIDTH * PITCH_BYTES).unwrap();
|
||||
self.canvas.copy(&texture, None, None).unwrap();
|
||||
self.canvas.present();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue