Initial commit
This commit is contained in:
commit
ceb62d2c53
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
||||
83
.vscode/launch.json
vendored
Normal file
83
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug unit tests in library 'trevors_chip8_toy'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"test",
|
||||
"--no-run",
|
||||
"--lib",
|
||||
"--package=trevors_chip8_toy"
|
||||
],
|
||||
"filter": {
|
||||
"name": "trevors_chip8_toy",
|
||||
"kind": "lib"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug executable 'trevors_chip8_toy'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--bin=trevors_chip8_toy",
|
||||
"--package=trevors_chip8_toy"
|
||||
],
|
||||
"filter": {
|
||||
"name": "trevors_chip8_toy",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug unit tests in executable 'trevors_chip8_toy'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"test",
|
||||
"--no-run",
|
||||
"--bin=trevors_chip8_toy",
|
||||
"--package=trevors_chip8_toy"
|
||||
],
|
||||
"filter": {
|
||||
"name": "trevors_chip8_toy",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug unit tests in library 'trevors_chip8_core'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"test",
|
||||
"--no-run",
|
||||
"--lib",
|
||||
"--package=trevors_chip8_core"
|
||||
],
|
||||
"filter": {
|
||||
"name": "trevors_chip8_core",
|
||||
"kind": "lib"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
||||
2166
Cargo.lock
generated
Normal file
2166
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
3
Cargo.toml
Normal file
3
Cargo.toml
Normal file
@ -0,0 +1,3 @@
|
||||
[workspace]
|
||||
members = ["chip8_toy","chip8_core"]
|
||||
resolver = "2"
|
||||
9
chip8_core/Cargo.toml
Normal file
9
chip8_core/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "trevors_chip8_core"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bitmask = "0.5.0"
|
||||
|
||||
[lib]
|
||||
21
chip8_core/src/chip8_constants.rs
Normal file
21
chip8_core/src/chip8_constants.rs
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
pub const CHIP8_MEMORY_SIZE: u16 = 0x1000;
|
||||
pub const CHIP8_MEMORY_SIZE_USIZE: usize = 0x1000;
|
||||
|
||||
pub const FONT_0: [u8; 5] = [0xF0, 0x90, 0x90, 0x90, 0xF0];
|
||||
pub const FONT_1: [u8; 5] = [0x20, 0x60, 0x20, 0x20, 0x70];
|
||||
pub const FONT_2: [u8; 5] = [0xF0, 0x10, 0xF0, 0x80, 0xF0];
|
||||
pub const FONT_3: [u8; 5] = [0xF0, 0x10, 0xF0, 0x10, 0xF0];
|
||||
pub const FONT_4: [u8; 5] = [0x90, 0x90, 0xF0, 0x10, 0x10];
|
||||
pub const FONT_5: [u8; 5] = [0xF0, 0x80, 0xF0, 0x10, 0xF0];
|
||||
pub const FONT_6: [u8; 5] = [0xF0, 0x80, 0xF0, 0x90, 0xF0];
|
||||
pub const FONT_7: [u8; 5] = [0xF0, 0x10, 0x20, 0x40, 0x40];
|
||||
pub const FONT_8: [u8; 5] = [0xF0, 0x90, 0xF0, 0x90, 0xF0];
|
||||
pub const FONT_9: [u8; 5] = [0xF0, 0x90, 0xF0, 0x10, 0xF0];
|
||||
pub const FONT_A: [u8; 5] = [0xF0, 0x90, 0xF0, 0x90, 0x90];
|
||||
pub const FONT_B: [u8; 5] = [0xE0, 0x90, 0xE0, 0x90, 0xE0];
|
||||
pub const FONT_C: [u8; 5] = [0xF0, 0x80, 0x80, 0x80, 0xF0];
|
||||
pub const FONT_D: [u8; 5] = [0xE0, 0x90, 0x90, 0x90, 0xE0];
|
||||
pub const FONT_E: [u8; 5] = [0xF0, 0x80, 0xF0, 0x80, 0xF0];
|
||||
pub const FONT_F: [u8; 5] = [0xF0, 0x80, 0xf0, 0x80, 0x80];
|
||||
|
||||
195
chip8_core/src/chip8_mnemonics.rs
Normal file
195
chip8_core/src/chip8_mnemonics.rs
Normal file
@ -0,0 +1,195 @@
|
||||
use bitmask::bitmask;
|
||||
|
||||
use crate::{chip8_constants::CHIP8_MEMORY_SIZE, parts::Display::Chip8Display};
|
||||
|
||||
enum Chip8StartOffset {
|
||||
STANDARD,
|
||||
ETI600,
|
||||
OTHER,
|
||||
}
|
||||
|
||||
struct Chip8Registers {
|
||||
V: [u8; 16],
|
||||
I: u16,
|
||||
DelayTimer: u16,
|
||||
SoundTimer: u16,
|
||||
StackPointer: u8,
|
||||
ProgramCounter: u16,
|
||||
}
|
||||
|
||||
impl Default for Chip8Registers {
|
||||
fn default() -> Self {
|
||||
Chip8Registers {
|
||||
DelayTimer: 60,
|
||||
V: [
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
],
|
||||
I: 0x00,
|
||||
SoundTimer: 60,
|
||||
StackPointer: 255,
|
||||
ProgramCounter: 0x200,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Chip8Instruction {
|
||||
SYS(u16),
|
||||
CLS,
|
||||
RET,
|
||||
JMP(u16),
|
||||
CALL(u16),
|
||||
SNEQ(u8, u16),
|
||||
SNNE(u8, u8),
|
||||
SNRE(u8, u8),
|
||||
STOR(u8, u16),
|
||||
ADD(u8, u16),
|
||||
MOV(u8, u8),
|
||||
OR(u8, u8),
|
||||
AND(u8, u8),
|
||||
XOR(u8, u8),
|
||||
ADC(u8, u8),
|
||||
SBC(u8, u8),
|
||||
RSR(u8, u8),
|
||||
LSR(u8, u8),
|
||||
SNE(u8, u8),
|
||||
STO(i16),
|
||||
JMPI(u16),
|
||||
RND(u8, u8),
|
||||
SETD(u8),
|
||||
SETT(u8),
|
||||
BCD(u8),
|
||||
}
|
||||
|
||||
enum Chip8Keys {
|
||||
KEY0,
|
||||
KEY1,
|
||||
KEY2,
|
||||
KEY3,
|
||||
KEY4,
|
||||
KEY5,
|
||||
KEY6,
|
||||
KEY7,
|
||||
KEY8,
|
||||
KEY9,
|
||||
KEYA,
|
||||
KEYB,
|
||||
KEYC,
|
||||
KEYD,
|
||||
KEYE,
|
||||
KEYF,
|
||||
}
|
||||
|
||||
pub fn display_video_memory(system_memory: [u8; CHIP8_MEMORY_SIZE as usize]) {
|
||||
// Assumes memory addresses from
|
||||
}
|
||||
|
||||
const ZERO: u16 = 0b0000000000000000;
|
||||
const BOTTOM_BYTE: u16 = 0b0000000011111111;
|
||||
const TOP_BYTE: u16 = 0b1111111100000000;
|
||||
const NIBBLE0: u16 = 0b1111000000000000;
|
||||
const NIBBLE1: u16 = 0b0000111100000000;
|
||||
const NIBBLE2: u16 = 0b0000000011110000;
|
||||
const NIBBLE3: u16 = 0b0000000000001111;
|
||||
const NIBBLE0_BALANCE: u16 = 0x0FFF;
|
||||
const PMSK_0000: i16 = 0x0000;
|
||||
const PMSK_00X0: i16 = 0x00F0;
|
||||
const PMSK_0X00: i16 = 0x0F00;
|
||||
const PMSK_0XXX: i16 = 0x0FFF;
|
||||
|
||||
// AND against the possible operand to find which one we have
|
||||
bitmask! {
|
||||
mask Chip8Instructions: u16 where flags Chip8InstructionFlags {
|
||||
SYS = 0x00,
|
||||
CLR = 0b0000000011100000,
|
||||
RTS = 0b0000000011101110,
|
||||
JUMP = 0b0001000000000000,
|
||||
CALL = 0b0010000000000000,
|
||||
SKE = 0b0011000000000000,
|
||||
SKNE = 0b0100000000000000,
|
||||
SKRE = 0b0101000000000000,
|
||||
LOAD = 0b0110000000000000,
|
||||
ADD = 0b0111000000000000,
|
||||
MOVE = 0b1000000000000000,
|
||||
OR = 0b1000000000000001,
|
||||
AND = 0b1000000000000010,
|
||||
XOR = 0b1000000000000011,
|
||||
ADDR = 0b1000000000000100,
|
||||
SUB = 0b1000000000000101,
|
||||
SHR = 0b1000000000000110,
|
||||
SHL = 0b1000000000001110,
|
||||
SKRNE = 0b1001000000000000,
|
||||
LOADI = 0b1010000000000000,
|
||||
JUMPI = 0b1011000000000000,
|
||||
RAND = 0b1100000000000000,
|
||||
DRAW = 0b1101000000000000,
|
||||
SKPR = 0b1110000000001110,
|
||||
SKUP = 0b1111000010100001,
|
||||
MOVED = 0b1111000000000111,
|
||||
KEYD = 0b1111000000001010,
|
||||
LOADD = 0b1111000000010101,
|
||||
LOADS = 0b1111000000011000,
|
||||
ADDI = 0b1111000000011110,
|
||||
LDSPR = 0b1111000000101001,
|
||||
BCD = 0b1111000000110011,
|
||||
STOR = 0b1111000001010101,
|
||||
MEMCPY = 0b1111000001100101
|
||||
}
|
||||
}
|
||||
|
||||
enum Chip8Asm {
|
||||
SYS(u16),
|
||||
CLR(),
|
||||
RTS(),
|
||||
JUMP(u16),
|
||||
CALL(u16),
|
||||
SKE(u8, u8),
|
||||
SKNE(u8, u8),
|
||||
SKRE(u8, u8),
|
||||
LOAD(u8, u8),
|
||||
ADD(u8, u8),
|
||||
MOVE(u8, u8),
|
||||
OR(u8, u8),
|
||||
AND(u8, u8),
|
||||
XOR(u8, u8),
|
||||
ADDR(u8, u8),
|
||||
SUB(u8, u8),
|
||||
SHR(u8, u8),
|
||||
SHL(u8, u8),
|
||||
SKRNE(u8, u8),
|
||||
LOADI(u16),
|
||||
JUMPI(u16),
|
||||
RAND(u8, u8),
|
||||
DRAW(u8, u8, u8),
|
||||
SKPR(u8),
|
||||
SKUP(u8),
|
||||
MOVED(u8),
|
||||
KEYD(u8),
|
||||
LOADD(u8),
|
||||
LOADS(u8),
|
||||
ADDI(u8),
|
||||
LDSPR(u8),
|
||||
BCD(u8),
|
||||
STOR(u8),
|
||||
READ(u8),
|
||||
}
|
||||
|
||||
struct Chip8Cpu {}
|
||||
|
||||
struct Chip8System {
|
||||
registers: Chip8Registers,
|
||||
screen: Chip8Display,
|
||||
}
|
||||
|
||||
impl Chip8System {
|
||||
pub fn tick(self: Self) {
|
||||
println!(" Ticking Chip8System");
|
||||
|
||||
// Fetch...
|
||||
// ...Decode...
|
||||
// ...Execute
|
||||
|
||||
// self.registers.tick();
|
||||
self.screen.tick();
|
||||
}
|
||||
}
|
||||
8
chip8_core/src/lib.rs
Normal file
8
chip8_core/src/lib.rs
Normal file
@ -0,0 +1,8 @@
|
||||
pub mod chip8_mnemonics;
|
||||
pub mod chip8_constants;
|
||||
|
||||
pub mod parts {
|
||||
pub mod CPU;
|
||||
pub mod Display;
|
||||
pub mod Keyboard;
|
||||
}
|
||||
449
chip8_core/src/parts/CPU.rs
Normal file
449
chip8_core/src/parts/CPU.rs
Normal file
@ -0,0 +1,449 @@
|
||||
struct Chip8Registers {
|
||||
|
||||
}
|
||||
|
||||
|
||||
impl Chip8Registers {
|
||||
pub fn tick(self: &Self) {
|
||||
println!("Ticking Registers");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct Chip8InstructionParameter {
|
||||
mask: u16
|
||||
}
|
||||
|
||||
struct Chip8Instruction {
|
||||
id: String,
|
||||
mask: u16,
|
||||
pattern: u16,
|
||||
arguments: Vec<Chip8InstructionParameter>,
|
||||
description: Box<str>
|
||||
}
|
||||
|
||||
pub fn fill_chip8_instructions() {
|
||||
let full_instruction_set = vec![
|
||||
Chip8Instruction {
|
||||
id: "SYS".to_string(),
|
||||
mask: 0x00,
|
||||
pattern: 0x00,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0FFF
|
||||
}
|
||||
],
|
||||
description: "Execute method at address referenced by parameter".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "CLR".to_string(),
|
||||
mask: 0x00E0,
|
||||
pattern: 0x00E0,
|
||||
arguments: vec![],
|
||||
description: "Clear the Screen".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "RET".to_string(),
|
||||
mask: 0x00EE,
|
||||
pattern: 0x00EE,
|
||||
arguments: vec![],
|
||||
description: "Return from Subroutine".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "JMP".to_string(),
|
||||
mask: 0x1FFF,
|
||||
pattern: 0x1000,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0fff
|
||||
}
|
||||
],
|
||||
description: "Jump to specified location".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "SEQ".to_string(),
|
||||
mask: 0x3FFF,
|
||||
pattern: 0x3000,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
},
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x00ff
|
||||
}
|
||||
],
|
||||
description: "Skip next instruction if Register does equal parameter".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "SNE".to_string(),
|
||||
mask: 0x4FFF,
|
||||
pattern: 0x4000,
|
||||
arguments: vec! [
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
},
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x00ff
|
||||
}
|
||||
],
|
||||
description: "Skip next instruction if Register doesn't equal parameter".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "SREQ".to_string(),
|
||||
mask: 0x5FF0,
|
||||
pattern: 0x5000,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
},
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x00f0
|
||||
}
|
||||
],
|
||||
description: "TBD".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "STO".to_string(),
|
||||
mask: 0x6FFF,
|
||||
pattern: 0x6000,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
},
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x00ff
|
||||
}
|
||||
],
|
||||
description: "Store value into register".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "ADD".to_string(),
|
||||
mask: 0x7FFF,
|
||||
pattern: 0x7000,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
},
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x00ff
|
||||
}
|
||||
],
|
||||
description: "TBD".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "CPY".to_string(),
|
||||
mask: 0x8FF0,
|
||||
pattern: 0x8000,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
},
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x00f0
|
||||
}
|
||||
],
|
||||
description: "TBD".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "OR".to_string(),
|
||||
mask: 0x8FF1,
|
||||
pattern: 0x8001,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
},
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x00f0
|
||||
}
|
||||
],
|
||||
description: "Logical OR of registers placing result in first register".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "AND".to_string(),
|
||||
mask: 0x8FF2,
|
||||
pattern: 0x8002,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
},
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x00f0
|
||||
}
|
||||
],
|
||||
description: "Logical AND of registers placing result in first register".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "XOR".to_string(),
|
||||
mask: 0x8FF3,
|
||||
pattern: 0x8003,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
},
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x00f0
|
||||
}
|
||||
],
|
||||
description: "Logical XOR of registers placing result in first register".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "ADC".to_string(),
|
||||
mask: 0x8FF4,
|
||||
pattern: 0x8004,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
},
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x00f0
|
||||
}
|
||||
],
|
||||
description: "Add 2 Registers with carry flag".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "SUBC".to_string(),
|
||||
mask: 0x8FF5,
|
||||
pattern: 0x8005,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
},
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x00f0
|
||||
}
|
||||
],
|
||||
description: "Subtract 2 Registers with carry flag".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "RSR".to_string(),
|
||||
mask: 0x8FF6,
|
||||
pattern: 0x8006,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
},
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x00f0
|
||||
}
|
||||
],
|
||||
description: "Register Shifted Right".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "SUBC".to_string(),
|
||||
mask: 0x8FF7,
|
||||
pattern: 0x8007,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
},
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x00f0
|
||||
}
|
||||
],
|
||||
description: "Subtract 2 Regiters with Carry".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "RSL".to_string(),
|
||||
mask: 0x8FFE,
|
||||
pattern: 0x800E,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
},
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x00f0
|
||||
}
|
||||
],
|
||||
description: "Register Shifted Left".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "SRNE".to_string(),
|
||||
mask: 0x9FF0,
|
||||
pattern: 0x9000,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
},
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x00f0
|
||||
}
|
||||
],
|
||||
description: "Skip next instruction if registers not equal".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "LDI".to_string(),
|
||||
mask: 0xAFFF,
|
||||
pattern: 0xA000,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0fff
|
||||
}
|
||||
],
|
||||
description: "Load Data from Memory Address".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "JMPI".to_string(),
|
||||
mask: 0xBFFF,
|
||||
pattern: 0xB000,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0fff
|
||||
}
|
||||
],
|
||||
description: "Jump to Memory Address".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "RNG".to_string(),
|
||||
mask: 0xCFFF,
|
||||
pattern: 0xC000,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
},
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x00ff
|
||||
}
|
||||
],
|
||||
description: "Random number Generator".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "SPR".to_string(),
|
||||
mask: 0xDFFF,
|
||||
pattern: 0xD000,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
},
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x00f0
|
||||
},
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x000f
|
||||
}
|
||||
|
||||
],
|
||||
description: "TBD".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "JNK".to_string(),
|
||||
mask: 0xEF9E,
|
||||
pattern: 0xE09E,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
}
|
||||
],
|
||||
description: "Jump over next instruction if Key Pressed".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "JKP".to_string(),
|
||||
mask: 0xEFA1,
|
||||
pattern: 0xE0A1,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
}
|
||||
],
|
||||
description: "Jump over next instruction if Key Not Pressed".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "SDT".to_string(),
|
||||
mask: 0xFF07,
|
||||
pattern: 0xF007,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0F00
|
||||
}
|
||||
],
|
||||
description: "TBD".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "WKP".to_string(),
|
||||
mask: 0xFF0A,
|
||||
pattern: 0xF00A,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
}
|
||||
],
|
||||
description: "TBD".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "LDT".to_string(),
|
||||
mask: 0xFF15,
|
||||
pattern: 0xF015,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
}
|
||||
],
|
||||
description: "TBD".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "LST".to_string(),
|
||||
mask: 0xFF18,
|
||||
pattern: 0xF018,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
}
|
||||
],
|
||||
description: "TBD".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "ADDI".to_string(),
|
||||
mask: 0xFF1E,
|
||||
pattern: 0xF01E,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
}
|
||||
],
|
||||
description: "TBD".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "SETI".to_string(),
|
||||
mask: 0xFF29,
|
||||
pattern: 0xF029,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
}
|
||||
],
|
||||
description: "TBD".into()
|
||||
},
|
||||
Chip8Instruction{
|
||||
id: "BCD".to_string(),
|
||||
mask: 0xFF33,
|
||||
pattern: 0xF033,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
}
|
||||
],
|
||||
description: "Binary Coded Decimal of register".into()
|
||||
},
|
||||
Chip8Instruction{
|
||||
id: "MSTO".to_string(),
|
||||
mask: 0xFF55,
|
||||
pattern: 0xF055,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
}
|
||||
],
|
||||
description: "TBD".into()
|
||||
},
|
||||
Chip8Instruction {
|
||||
id: "MLOAD".to_string(),
|
||||
mask: 0xFF65,
|
||||
pattern: 0xF065,
|
||||
arguments: vec![
|
||||
Chip8InstructionParameter {
|
||||
mask: 0x0f00
|
||||
}
|
||||
],
|
||||
description: "TBD".into()
|
||||
}
|
||||
];
|
||||
}
|
||||
28
chip8_core/src/parts/Display.rs
Normal file
28
chip8_core/src/parts/Display.rs
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
pub struct Chip8Display {
|
||||
// 64w x 32h
|
||||
pub memory: [bool; 512],
|
||||
}
|
||||
|
||||
impl Chip8Display {
|
||||
pub fn tick(self: &Self) {
|
||||
println!("Ticking the display");
|
||||
|
||||
}
|
||||
|
||||
pub fn render_chip8_display(to_render: Chip8Display) {
|
||||
// 32 rows...
|
||||
for index_row in 0..=32 {
|
||||
// ...64 columns
|
||||
for index_col in 0..=64 {
|
||||
let offset = (index_row * 64) + index_col;
|
||||
if (to_render.memory[offset]) {
|
||||
print!("*")
|
||||
} else {
|
||||
print!(" ")
|
||||
};
|
||||
}
|
||||
println!("");
|
||||
}
|
||||
}
|
||||
}
|
||||
82
chip8_core/src/parts/Keyboard.rs
Normal file
82
chip8_core/src/parts/Keyboard.rs
Normal file
@ -0,0 +1,82 @@
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Chip8Keyboard {
|
||||
keys_state: [bool; 16]
|
||||
}
|
||||
|
||||
impl Default for Chip8Keyboard {
|
||||
fn default() -> Self {
|
||||
Self { keys_state: [
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
false, false, false, false,
|
||||
false, false, false, false
|
||||
] }
|
||||
}
|
||||
}
|
||||
|
||||
impl Chip8Keyboard {
|
||||
|
||||
fn display_keyboard_key(self: Self, key_id: u8) {
|
||||
let filler = if self.is_pressed(key_id) { "*" } else { " " };
|
||||
print!("{}{}{}", filler, key_id, filler)
|
||||
}
|
||||
|
||||
fn display_keyboard_horizontal_line(self: Self, row_values: [u8; 4]) {
|
||||
print!("|");
|
||||
for current in row_values {
|
||||
self.clone().display_keyboard_key(current);
|
||||
print!("|");
|
||||
}
|
||||
println!();
|
||||
}
|
||||
|
||||
fn display_keyboard_seperator_line(self: Self) {
|
||||
println!("+---+---+---+---+");
|
||||
|
||||
}
|
||||
|
||||
pub fn display_keyboard(self: Self) {
|
||||
self.clone().display_keyboard_seperator_line();
|
||||
self.clone().display_keyboard_horizontal_line(
|
||||
[1,2,3,0xC]
|
||||
);
|
||||
println!("+---+---+---+---+");
|
||||
println!("| 4 | 5 | 6 | D |");
|
||||
println!("+---+---+---+---+");
|
||||
println!("| 7 | 8 | 9 | E |");
|
||||
println!("+---+---+---+---+");
|
||||
println!("| A | 0 | B | F |");
|
||||
println!("+---+---+---+---+");
|
||||
}
|
||||
|
||||
pub fn press_key(self: &mut Self, key_id: u8) {
|
||||
self.keys_state[key_id as usize] = true;
|
||||
}
|
||||
|
||||
pub fn release_key(self: &mut Self, key_id: u8) {
|
||||
self.keys_state[key_id as usize] = false;
|
||||
}
|
||||
|
||||
pub fn is_pressed(self: Self, key_id: u8) -> bool {
|
||||
self.keys_state[key_id as usize]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn smoke_test() {
|
||||
assert_eq!(true, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_keyboard_display_works() {
|
||||
let basic_keyboard = Chip8Keyboard::default();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
7
chip8_toy/Cargo.lock
generated
Normal file
7
chip8_toy/Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "trevors_chip8_toy"
|
||||
version = "0.1.0"
|
||||
17
chip8_toy/Cargo.toml
Normal file
17
chip8_toy/Cargo.toml
Normal file
@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "trevors_chip8_toy"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
trevors_chip8_core = { path = "../chip8_core" }
|
||||
easy-imgui-sys = { version = "=0.6.0" }
|
||||
easy-imgui = { version = "=0.6.0" }
|
||||
easy-imgui-renderer = { version = "=0.6.0" }
|
||||
easy-imgui-window = { version = "0.6.0" }
|
||||
log ="0.4"
|
||||
glutin = "0.32"
|
||||
glutin-winit = { version = "0.5", optional = true }
|
||||
raw-window-handle = "0.6"
|
||||
arboard = { version = "3", optional = true, default-features = false }
|
||||
winit = { version = "0.30", features = ["x11", "mint"] }
|
||||
79
chip8_toy/src/gui/display.rs
Normal file
79
chip8_toy/src/gui/display.rs
Normal file
@ -0,0 +1,79 @@
|
||||
use easy_imgui::{Ui, UiBuilder};
|
||||
use easy_imgui_window::{MainWindow, MainWindowWithRenderer};
|
||||
use winit::{application::ApplicationHandler, event_loop::ActiveEventLoop, window::{Window, WindowAttributes}};
|
||||
|
||||
|
||||
pub struct Chip8Display {
|
||||
pub window: MainWindowWithRenderer,
|
||||
}
|
||||
|
||||
impl Chip8Display {
|
||||
pub fn new(event_loop: &ActiveEventLoop) -> Chip8Display {
|
||||
Chip8Display { window: MainWindowWithRenderer::new(
|
||||
MainWindow::new::<()>(&event_loop, Window::default_attributes().with_title("Chip8 Display")).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render<M>(ui: &Ui<M>) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
impl UiBuilder for Chip8AppHandler {
|
||||
fn do_ui(&mut self, ui: &Ui<Self>) {
|
||||
|
||||
ui.text("This is where the Chip8 UI Goes");
|
||||
ui.text("Controls for Start/Stop/Load/Run Maybe?");
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Chip8AppHandler {
|
||||
pub windows: Vec<MainWindowWithRenderer>,
|
||||
// pub display: Chip8Display
|
||||
}
|
||||
|
||||
impl ApplicationHandler for Chip8AppHandler {
|
||||
fn suspended(&mut self, _event_loop: &ActiveEventLoop) {
|
||||
self.windows.clear();
|
||||
}
|
||||
|
||||
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||
self.windows.push(Chip8Display::new(event_loop).window);
|
||||
}
|
||||
|
||||
fn window_event(
|
||||
&mut self,
|
||||
event_loop: &ActiveEventLoop,
|
||||
window_id: winit::window::WindowId,
|
||||
event: winit::event::WindowEvent,
|
||||
) {
|
||||
for window in &mut self.windows {
|
||||
if window.main_window().window().id() != window_id {
|
||||
continue;
|
||||
}
|
||||
let res = window.window_event(
|
||||
&mut self,
|
||||
&event,
|
||||
easy_imgui_window::EventFlags::empty(),
|
||||
);
|
||||
if res.window_closed {
|
||||
event_loop.exit();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
fn new_events(&mut self, _event_loop: &ActiveEventLoop, _cause: winit::event::StartCause) {
|
||||
for window in &mut self.windows {
|
||||
window.new_events();
|
||||
}
|
||||
}
|
||||
fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {
|
||||
for window in &mut self.windows {
|
||||
window.about_to_wait();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
3
chip8_toy/src/lib.rs
Normal file
3
chip8_toy/src/lib.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub mod gui {
|
||||
pub mod display;
|
||||
}
|
||||
94
chip8_toy/src/main.rs
Normal file
94
chip8_toy/src/main.rs
Normal file
@ -0,0 +1,94 @@
|
||||
use easy_imgui_window::{
|
||||
easy_imgui as imgui,
|
||||
easy_imgui_renderer::Renderer,
|
||||
winit::{
|
||||
event_loop::{ActiveEventLoop, EventLoop},
|
||||
window::Window,
|
||||
},
|
||||
MainWindow, MainWindowWithRenderer,
|
||||
};
|
||||
use trevors_chip8_toy::gui::display::{Chip8App, Chip8AppHandler};
|
||||
use std::rc::Rc;
|
||||
|
||||
fn main() {
|
||||
let event_loop = EventLoop::new().unwrap();
|
||||
|
||||
let mut main = Chip8AppHandler {
|
||||
windows: vec![],
|
||||
app: Chip8App,
|
||||
};
|
||||
|
||||
event_loop.run_app(&mut main).unwrap();
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct AppHandler {
|
||||
windows: Vec<MainWindowWithRenderer>,
|
||||
app: App,
|
||||
}
|
||||
|
||||
impl winit::application::ApplicationHandler for AppHandler {
|
||||
fn suspended(&mut self, _event_loop: &ActiveEventLoop) {
|
||||
self.windows.clear();
|
||||
}
|
||||
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||
let wattr_1 = Window::default_attributes().with_title("Example #1");
|
||||
let main_window_1 = MainWindow::new::<()>(&event_loop, wattr_1).unwrap();
|
||||
let mut window_1 = MainWindowWithRenderer::new(main_window_1);
|
||||
|
||||
let wattr_2 = Window::default_attributes().with_title("Example #2");
|
||||
let main_window_2 = MainWindow::new::<()>(&event_loop, wattr_2).unwrap();
|
||||
// The GL context can be reused, but the imgui context cannot
|
||||
let mut renderer_2 = Renderer::new(Rc::clone(window_1.renderer().gl_context())).unwrap();
|
||||
renderer_2.set_background_color(Some(imgui::Color::GREEN));
|
||||
let window_2 = MainWindowWithRenderer::new_with_renderer(main_window_2, renderer_2);
|
||||
|
||||
self.windows.push(window_1);
|
||||
self.windows.push(window_2);
|
||||
}
|
||||
fn window_event(
|
||||
&mut self,
|
||||
event_loop: &ActiveEventLoop,
|
||||
window_id: winit::window::WindowId,
|
||||
event: winit::event::WindowEvent,
|
||||
) {
|
||||
for window in &mut self.windows {
|
||||
if window.main_window().window().id() != window_id {
|
||||
continue;
|
||||
}
|
||||
let res = window.window_event(
|
||||
&mut self.app,
|
||||
&event,
|
||||
easy_imgui_window::EventFlags::empty(),
|
||||
);
|
||||
if res.window_closed {
|
||||
event_loop.exit();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
fn new_events(&mut self, _event_loop: &ActiveEventLoop, _cause: winit::event::StartCause) {
|
||||
for window in &mut self.windows {
|
||||
window.new_events();
|
||||
}
|
||||
}
|
||||
fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {
|
||||
for window in &mut self.windows {
|
||||
window.about_to_wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct App;
|
||||
|
||||
impl imgui::UiBuilder for App {
|
||||
fn do_ui(&mut self, ui: &imgui::Ui<Self>) {
|
||||
#[cfg(feature = "docking")]
|
||||
{
|
||||
ui.dock_space_over_viewport(0, imgui::DockNodeFlags::None);
|
||||
}
|
||||
|
||||
ui.show_demo_window(None);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user