mirror of https://github.com/Ivsucram/ivsemu.git
commit
25d228c440
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -17,7 +17,7 @@ pub struct CPU {
|
||||||
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
|
||||||
}
|
}
|
||||||
|
@ -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 });
|
||||||
|
|
|
@ -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::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;
|
|
||||||
|
|
||||||
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]) {
|
|
||||||
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 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, WIDTH * PITCH_BYTES).unwrap();
|
||||||
self.canvas.copy(&texture, None, None).unwrap();
|
self.canvas.copy(&texture, None, None).unwrap();
|
||||||
|
self.canvas.present();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue