IBM logo mostly working with slight graphical error
This commit is contained in:
parent
bd8f7ed1a4
commit
aaccc26abf
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1 +1,3 @@
|
|||
/target
|
||||
/IBMLogo.ch8
|
||||
/.idea
|
||||
|
|
2829
Cargo.lock
generated
Normal file
2829
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -4,3 +4,9 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5.28", features = ["derive"] }
|
||||
clap_derive = "4.5.28"
|
||||
pixels = "0.15.0"
|
||||
tao = "0.31.1"
|
||||
tracing = "0.1.41"
|
||||
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
|
307
src/main.rs
307
src/main.rs
|
@ -1,3 +1,306 @@
|
|||
fn main() {
|
||||
println!("Hello, world!");
|
||||
use std::path::PathBuf;
|
||||
use clap::Parser;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::num::NonZeroU32;
|
||||
use std::rc::Rc;
|
||||
use pixels::{Error, Pixels, SurfaceTexture};
|
||||
use tao::{
|
||||
event::{Event, KeyEvent, WindowEvent},
|
||||
event_loop::{ControlFlow, EventLoop},
|
||||
window::WindowBuilder,
|
||||
keyboard::KeyCode,
|
||||
};
|
||||
use tao::dpi::LogicalSize;
|
||||
use tracing::{info, error};
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||
use std::sync::Arc;
|
||||
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
struct Args {
|
||||
#[arg(short, long)]
|
||||
file: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Chip8 {
|
||||
display: [u64; 32],
|
||||
index_register: u16,
|
||||
registers: [u8; 16],
|
||||
sound_timer: u8,
|
||||
delay_timer: u8,
|
||||
ram: [u8; 4096],
|
||||
pc: u16,
|
||||
stack: [u8; 64],
|
||||
stack_pointer: u8,
|
||||
}
|
||||
|
||||
impl Chip8 {
|
||||
fn new() -> Self {
|
||||
Chip8 {
|
||||
display: [0;32],
|
||||
index_register: 0,
|
||||
registers: [0;16],
|
||||
sound_timer: 0,
|
||||
delay_timer: 0,
|
||||
ram: [0; 4096],
|
||||
pc: 0x200,
|
||||
stack: [0; 64],
|
||||
stack_pointer: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_font(mut self) -> Self {
|
||||
font_initialiser(&mut self.ram);
|
||||
self
|
||||
}
|
||||
|
||||
fn load_file(mut self, file: PathBuf) -> Self {
|
||||
file_reader(&mut self.ram, file);
|
||||
self
|
||||
}
|
||||
|
||||
fn draw(self, frame: &mut [u8], dimensions: (u32, u32)) -> Self {
|
||||
for(i, pixel) in frame.chunks_exact_mut(4).enumerate() {
|
||||
let x = i % dimensions.0 as usize;
|
||||
let y = i / dimensions.0 as usize;
|
||||
|
||||
let sx = (x * 64) / dimensions.0 as usize;
|
||||
let sy = (y * 32) / dimensions.1 as usize;
|
||||
|
||||
let rgba = if get_bit(self.display[sy], sx as u8) {
|
||||
[0xff, 0xff, 0xff, 0xff]
|
||||
} else {
|
||||
[0x00, 0x00, 0x00, 0xff]
|
||||
};
|
||||
|
||||
pixel.copy_from_slice(&rgba);
|
||||
}
|
||||
info!("done");
|
||||
self
|
||||
}
|
||||
|
||||
fn update(&mut self, instructions: u32) -> Self {
|
||||
for i in 0..instructions {
|
||||
let pointer = self.pc as usize;
|
||||
let opcodes: [u8; 4] = [
|
||||
((self.ram[pointer] & 240) / 16),
|
||||
(self.ram[pointer] & 15),
|
||||
((self.ram[pointer + 1] & 240) /16),
|
||||
(self.ram[pointer + 1] & 15)
|
||||
];
|
||||
self.pc += 2;
|
||||
//info!("{:?}",opcodes);
|
||||
match opcodes[0] {
|
||||
0x00 => {
|
||||
match opcodes[1] {
|
||||
0x00 => {
|
||||
match opcodes[2] {
|
||||
0x0e => {
|
||||
match opcodes[3] {
|
||||
0x00 => {
|
||||
self.clear_screen();
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
0x01 => {
|
||||
let position = (opcodes[1] as u16) << 8 | (opcodes[2] as u16) << 4 | opcodes[3] as u16;
|
||||
self.pc = position;
|
||||
},
|
||||
0x02 => {
|
||||
|
||||
},
|
||||
0x03 => {
|
||||
|
||||
},
|
||||
0x04 => {
|
||||
|
||||
},
|
||||
0x05 => {
|
||||
|
||||
},
|
||||
0x06 => {
|
||||
self.registers[opcodes[1] as usize] = opcodes[2] << 4 | opcodes[3];
|
||||
},
|
||||
0x07 => {
|
||||
let value = (opcodes[2] << 4 | opcodes[3]) as u16;
|
||||
self.registers[opcodes[1] as usize] = (((self.registers[opcodes[1] as usize] as u16) + value) & 255) as u8;
|
||||
},
|
||||
0x08 => {
|
||||
|
||||
},
|
||||
0x09 => {
|
||||
|
||||
},
|
||||
0x0a => {
|
||||
self.index_register = (opcodes[1] as u16) << 8 | (opcodes[2] as u16) << 4 | (opcodes[3] as u16);
|
||||
},
|
||||
0x0b => {
|
||||
|
||||
},
|
||||
0x0c => {
|
||||
|
||||
},
|
||||
0x0d => {
|
||||
let x = self.registers[opcodes[1] as usize] % 64;
|
||||
let y = self.registers[opcodes[2] as usize] % 32;
|
||||
self.registers[0x0f] = 0;
|
||||
for n in 0..opcodes[3] {
|
||||
let spritedata = self.ram[self.index_register as usize + n as usize];
|
||||
for i in 0..7 {
|
||||
let bit = get_bit_u8(spritedata, i);
|
||||
self.display[(y + n) as usize] = self.display[(y + n) as usize] ^ ((bit as u64) << (x + i));
|
||||
}
|
||||
}
|
||||
},
|
||||
0x0e => {
|
||||
|
||||
},
|
||||
0x0f => {
|
||||
|
||||
},
|
||||
_ => {
|
||||
error!("out of scope opcode");
|
||||
}
|
||||
}
|
||||
}
|
||||
//info!("{:?}",self.display);
|
||||
*self
|
||||
}
|
||||
|
||||
fn clear_screen(mut self) -> Self {
|
||||
self.display = [0;32];
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
tracing_subscriber::registry()
|
||||
.with(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| "INFO=debug".into()),
|
||||
)
|
||||
.with(tracing_subscriber::fmt::layer())
|
||||
.init();
|
||||
|
||||
let args = Args::parse();
|
||||
let mut chip8 = Chip8::new().insert_font().load_file(args.file);
|
||||
|
||||
println!("ram: {:?}", chip8.ram);
|
||||
|
||||
let event_loop = EventLoop::new();
|
||||
|
||||
let window = { let window = WindowBuilder::new()
|
||||
.with_title("Chip8 Emulator")
|
||||
.with_inner_size(LogicalSize::new(320, 240))
|
||||
.with_min_inner_size(LogicalSize::new(320, 240))
|
||||
.build(&event_loop)
|
||||
.unwrap();
|
||||
Arc::new(window)
|
||||
};
|
||||
|
||||
let mut pixels = {
|
||||
let window_size = window.inner_size();
|
||||
let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, Arc::clone(&window));
|
||||
Pixels::new(window_size.width, window_size.height, surface_texture).unwrap()
|
||||
};
|
||||
|
||||
let test: u64 = 1;
|
||||
info!("{}", get_bit(test, 0));
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
match event {
|
||||
Event::WindowEvent {event, ..} => match event {
|
||||
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
||||
WindowEvent::Resized(size) => {
|
||||
if let Err(e) = pixels.resize_surface(size.width, size.height) {
|
||||
error!("pixels.resize_surface");
|
||||
*control_flow = ControlFlow::Exit;
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
},
|
||||
Event::MainEventsCleared => {
|
||||
info!(chip8.pc);
|
||||
chip8.update(40);
|
||||
info!(chip8.pc);
|
||||
window.request_redraw();
|
||||
}
|
||||
Event::RedrawRequested(_) => {
|
||||
chip8.draw(pixels.frame_mut(), (window.inner_size().width, window.inner_size().height));
|
||||
if let Err(err) = pixels.render() {
|
||||
error!("pixels.render");
|
||||
*control_flow = ControlFlow::Exit;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
fn file_reader(ram: &mut [u8; 4096], file: PathBuf) {
|
||||
let mut file = File::open(file).unwrap();
|
||||
let mut file_contents:Vec<u8> = Vec::new();
|
||||
file.read_to_end(&mut file_contents).unwrap();
|
||||
for i in 0..file_contents.len() {
|
||||
ram[i + 0x200] = file_contents[i];
|
||||
}
|
||||
}
|
||||
|
||||
fn font_initialiser(ram: &mut [u8; 4096]) {
|
||||
let font: [u8; 80] = [
|
||||
0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
|
||||
0x20, 0x60, 0x20, 0x20, 0x70, // 1
|
||||
0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
|
||||
0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
|
||||
0x90, 0x90, 0xF0, 0x10, 0x10, // 4
|
||||
0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
|
||||
0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
|
||||
0xF0, 0x10, 0x20, 0x40, 0x40, // 7
|
||||
0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
|
||||
0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
|
||||
0xF0, 0x90, 0xF0, 0x90, 0x90, // A
|
||||
0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
|
||||
0xF0, 0x80, 0x80, 0x80, 0xF0, // C
|
||||
0xE0, 0x90, 0x90, 0x90, 0xE0, // D
|
||||
0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
|
||||
0xF0, 0x80, 0xF0, 0x80, 0x80 // F
|
||||
];
|
||||
|
||||
for i in 0..80 {
|
||||
ram[i + 0x050] = font[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn get_bit(num: u64, bit: u8) -> bool {
|
||||
//info!(bit);
|
||||
if bit <= 63 {
|
||||
let mask: u64 = 1 << bit;
|
||||
let bitvalue = ((num & mask)) != 0;
|
||||
bitvalue
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn get_bit_u8(num: u8, bit: u8) -> bool {
|
||||
if bit <= 8 {
|
||||
let mask: u8 = 128 >> bit;
|
||||
let bitvalue = (num & mask) != 0;
|
||||
bitvalue
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user