8xy4 and 8xy5 pass.
more flag tests passing removes legacy code moves 'gemmaemu' into 'gemma' crate moves 'gemmaimgui' into its own crate update to gemma
This commit is contained in:
parent
c7c3c6aa04
commit
e176ee5638
40
Cargo.lock
generated
40
Cargo.lock
generated
@ -1646,16 +1646,7 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gemmaegui"
|
name = "gemma"
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"eframe",
|
|
||||||
"egui",
|
|
||||||
"gemmaemu",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "gemmaemu"
|
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"beep",
|
"beep",
|
||||||
@ -1674,6 +1665,35 @@ dependencies = [
|
|||||||
"winit 0.27.5",
|
"winit 0.27.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gemmaegui"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"eframe",
|
||||||
|
"egui",
|
||||||
|
"gemma",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gemmaimgui"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"beep",
|
||||||
|
"chrono",
|
||||||
|
"copypasta",
|
||||||
|
"dimensioned",
|
||||||
|
"gemma",
|
||||||
|
"glium",
|
||||||
|
"image 0.23.14",
|
||||||
|
"imgui",
|
||||||
|
"imgui-glium-renderer",
|
||||||
|
"imgui-winit-support",
|
||||||
|
"log",
|
||||||
|
"pretty_env_logger",
|
||||||
|
"rand 0.9.0-alpha.2",
|
||||||
|
"winit 0.27.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "generic-array"
|
||||||
version = "0.14.7"
|
version = "0.14.7"
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = ["gemma", "gemmaegui"]
|
members = ["gemma", "gemmaegui", "gemmaimgui" ]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "trevors_chip8_core"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
bitmask = "0.5.0"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
|
|
||||||
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];
|
|
||||||
|
|
||||||
@ -1,207 +0,0 @@
|
|||||||
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,
|
|
||||||
system_memory: [u8; 2048]
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Chip8System {
|
|
||||||
pub fn tick(mut self) {
|
|
||||||
println!(" Ticking Chip8System");
|
|
||||||
|
|
||||||
let next_instruction = self.system_memory[self.registers.ProgramCounter as usize] as u16;
|
|
||||||
println!("READ INSTRUCTION {next_instruction}");
|
|
||||||
self.registers.ProgramCounter += 0x2;
|
|
||||||
|
|
||||||
&self.delay_timer_tick();
|
|
||||||
&self.sound_timer_tick();
|
|
||||||
|
|
||||||
// self.screen.tick();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delay_timer_tick(&mut self) {
|
|
||||||
self.registers.DelayTimer = self.registers.DelayTimer - 1;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sound_timer_tick(&mut self) {
|
|
||||||
self.registers.SoundTimer = self.registers.SoundTimer - 1;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
pub mod chip8_mnemonics;
|
|
||||||
pub mod chip8_constants;
|
|
||||||
|
|
||||||
pub mod parts {
|
|
||||||
pub mod CPU;
|
|
||||||
pub mod Display;
|
|
||||||
pub mod Keyboard;
|
|
||||||
}
|
|
||||||
@ -1,461 +0,0 @@
|
|||||||
struct Chip8Registers {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl Chip8Registers {
|
|
||||||
pub fn tick(self: &Self) {
|
|
||||||
println!("Ticking Registers");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Chip8InstructionParameter {
|
|
||||||
pub mask: u16
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Chip8Instruction {
|
|
||||||
pub id: String,
|
|
||||||
pub mask: u16,
|
|
||||||
pub pattern: u16,
|
|
||||||
pub arguments: Vec<Chip8InstructionParameter>,
|
|
||||||
pub description: Box<str>
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fill_chip8_instructions() -> [Chip8Instruction; 34] {
|
|
||||||
[
|
|
||||||
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: "Add value in register 0x0f00 with value 0x00ff".into()
|
|
||||||
},
|
|
||||||
Chip8Instruction {
|
|
||||||
id: "CPY".to_string(),
|
|
||||||
mask: 0x8FF0,
|
|
||||||
pattern: 0x8000,
|
|
||||||
arguments: vec![
|
|
||||||
Chip8InstructionParameter {
|
|
||||||
mask: 0x0f00
|
|
||||||
},
|
|
||||||
Chip8InstructionParameter {
|
|
||||||
mask: 0x00f0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
description: "Copy value between Register X and Y".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: "Wait for a Key to be pressed".into()
|
|
||||||
},
|
|
||||||
Chip8Instruction {
|
|
||||||
id: "LDT".to_string(),
|
|
||||||
mask: 0xFF15,
|
|
||||||
pattern: 0xF015,
|
|
||||||
arguments: vec![
|
|
||||||
Chip8InstructionParameter {
|
|
||||||
mask: 0x0f00
|
|
||||||
}
|
|
||||||
],
|
|
||||||
description: "Load Data Timer".into()
|
|
||||||
},
|
|
||||||
Chip8Instruction {
|
|
||||||
id: "LST".to_string(),
|
|
||||||
mask: 0xFF18,
|
|
||||||
pattern: 0xF018,
|
|
||||||
arguments: vec![
|
|
||||||
Chip8InstructionParameter {
|
|
||||||
mask: 0x0f00
|
|
||||||
}
|
|
||||||
],
|
|
||||||
description: "Load Sound Timer".into()
|
|
||||||
},
|
|
||||||
Chip8Instruction {
|
|
||||||
id: "ADDI".to_string(),
|
|
||||||
mask: 0xFF1E,
|
|
||||||
pattern: 0xF01E,
|
|
||||||
arguments: vec![
|
|
||||||
Chip8InstructionParameter {
|
|
||||||
mask: 0x0f00
|
|
||||||
}
|
|
||||||
],
|
|
||||||
description: "Add register with value at I".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: "Store value in register X at offset I".into()
|
|
||||||
},
|
|
||||||
Chip8Instruction {
|
|
||||||
id: "MLOAD".to_string(),
|
|
||||||
mask: 0xFF65,
|
|
||||||
pattern: 0xF065,
|
|
||||||
arguments: vec![
|
|
||||||
Chip8InstructionParameter {
|
|
||||||
mask: 0x0f00
|
|
||||||
}
|
|
||||||
],
|
|
||||||
description: "Load value into register X at offset I".into()
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct Chip8System {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Chip8System {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
trait CpuInstruction {
|
|
||||||
fn execute(input: Chip8System) -> Chip8System;
|
|
||||||
}
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
|
|
||||||
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!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,82 +0,0 @@
|
|||||||
|
|
||||||
#[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
7
chip8_toy/Cargo.lock
generated
@ -1,7 +0,0 @@
|
|||||||
# 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"
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "trevors_chip8_toy"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
trevors_chip8_core = { path = "../chip8_core" }
|
|
||||||
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"] }
|
|
||||||
copypasta = "0.10.1"
|
|
||||||
glium = { version = "0.34.0", default-features = true }
|
|
||||||
image = "0.25.2"
|
|
||||||
imgui = { version = "0.12.0", features = ["tables-api"] }
|
|
||||||
imgui-glium-renderer = "0.12.0"
|
|
||||||
imgui-winit-support = "0.12.0"
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct App;
|
|
||||||
|
|
||||||
impl UiBuilder for App {
|
|
||||||
fn do_ui(&mut self, ui: &Ui<Self>) {
|
|
||||||
#[cfg(feature = "docking")]
|
|
||||||
{
|
|
||||||
ui.dock_space_over_viewport(0, imgui::DockNodeFlags::None);
|
|
||||||
}
|
|
||||||
ui.show_demo_window(None);
|
|
||||||
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
@ -1,69 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
pub mod app;
|
|
||||||
|
|
||||||
pub mod gui {
|
|
||||||
pub mod display;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod support;
|
|
||||||
@ -1,143 +0,0 @@
|
|||||||
use trevors_chip8_core::parts::CPU::fill_chip8_instructions;
|
|
||||||
use trevors_chip8_toy::support;
|
|
||||||
use winit::{event::WindowEvent, event_loop::EventLoop};
|
|
||||||
|
|
||||||
use imgui::*;
|
|
||||||
/*
|
|
||||||
pub fn display_instruction_table(current_index: u32, ui: &Ui<App>) -> u32 {
|
|
||||||
let to_display = fill_chip8_instructions();
|
|
||||||
let mut return_index = current_index;
|
|
||||||
let current_instruction = to_display.get(return_index as usize).unwrap();
|
|
||||||
ui.text("Instructions");
|
|
||||||
ui.set_next_item_width(100f32);
|
|
||||||
ui.with_group(|| {
|
|
||||||
ui.text(format!("{}", current_instruction.description).as_str());
|
|
||||||
if current_instruction.arguments.is_empty() {
|
|
||||||
ui.text("No Parameters");
|
|
||||||
} else {
|
|
||||||
for current_parameter in current_instruction.arguments {
|
|
||||||
ui.text(format!("{}", current_parameter.mask).as_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ui.text(format!("{:#}", current_instruction.arguments).as_str());
|
|
||||||
ui.text("This is where cool stuff happens part 2");
|
|
||||||
});
|
|
||||||
ui.same_line();
|
|
||||||
ui.with_group(|| {
|
|
||||||
for (index, current) in to_display.iter().enumerate() {
|
|
||||||
if ui
|
|
||||||
.selectable_config(current.id.clone())
|
|
||||||
.selected(index == return_index as usize)
|
|
||||||
.build()
|
|
||||||
{
|
|
||||||
return_index = index as u32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return_index
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
fn chip8_instructions(initial_index: u32, ui: &mut Ui) -> u32 {
|
|
||||||
let to_display = fill_chip8_instructions();
|
|
||||||
let mut return_index = initial_index;
|
|
||||||
let instruction_to_display = to_display.get(return_index as usize).unwrap();
|
|
||||||
let instruction_window = ui
|
|
||||||
.window("Instructions")
|
|
||||||
.size([400.0, 400.0], Condition::FirstUseEver)
|
|
||||||
.build(|| {
|
|
||||||
ui.text("This should be my current instruction example");
|
|
||||||
ui.same_line();
|
|
||||||
ui.set_next_item_width(-1.0f32);
|
|
||||||
for (index, instruction) in to_display.iter().enumerate() {
|
|
||||||
if ui
|
|
||||||
.selectable_config(instruction.id.to_string())
|
|
||||||
.selected(index as u32 == return_index)
|
|
||||||
.build()
|
|
||||||
{
|
|
||||||
return_index = index as u32;
|
|
||||||
println!("RETURN INDEX {return_index}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return_index
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let mut value = 0;
|
|
||||||
let choices = ["test test this is 1", "test test this is 2"];
|
|
||||||
|
|
||||||
let mut selected_instruction = 0;
|
|
||||||
|
|
||||||
support::simple_init(file!(), move |_, ui| {
|
|
||||||
selected_instruction = chip8_instructions(selected_instruction, ui);
|
|
||||||
|
|
||||||
ui.window("Hello world")
|
|
||||||
.size([300.0, 110.0], Condition::FirstUseEver)
|
|
||||||
.build(|| {
|
|
||||||
ui.text_wrapped("Hello world!");
|
|
||||||
if ui.button(choices[value]) {
|
|
||||||
value += 1;
|
|
||||||
value %= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
ui.button("This...is...imgui-rs!");
|
|
||||||
ui.separator();
|
|
||||||
let mouse_pos = ui.io().mouse_pos;
|
|
||||||
ui.text(format!(
|
|
||||||
"Mouse Position: ({:.1},{:.1})",
|
|
||||||
mouse_pos[0], mouse_pos[1]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
fn main() {
|
|
||||||
let event_loop = EventLoop::new().unwrap();
|
|
||||||
|
|
||||||
let mut main = AppHandler::<App>::default();
|
|
||||||
main.attributes().title = String::from("Example-420");
|
|
||||||
|
|
||||||
event_loop.run_app(&mut main).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct App {
|
|
||||||
pub selected_instruction_index: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl App {}
|
|
||||||
|
|
||||||
impl Application for App {
|
|
||||||
type UserEvent = ();
|
|
||||||
type Data = ();
|
|
||||||
fn new(_: Args<()>) -> App {
|
|
||||||
App {
|
|
||||||
selected_instruction_index: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn window_event(&mut self, args: Args<()>, _event: WindowEvent, res: EventResult) {
|
|
||||||
if res.window_closed {
|
|
||||||
args.event_loop.exit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
let x = ui.collapsing_header_config("collapsing header");
|
|
||||||
|
|
||||||
ui.with_group(|| {
|
|
||||||
self.selected_instruction_index =
|
|
||||||
display_instruction_table(self.selected_instruction_index, ui);
|
|
||||||
});
|
|
||||||
|
|
||||||
ui.show_demo_window(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
use copypasta::{ClipboardContext, ClipboardProvider};
|
|
||||||
use imgui::ClipboardBackend;
|
|
||||||
|
|
||||||
pub struct ClipboardSupport(pub ClipboardContext);
|
|
||||||
|
|
||||||
pub fn init() -> Option<ClipboardSupport> {
|
|
||||||
ClipboardContext::new().ok().map(ClipboardSupport)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ClipboardBackend for ClipboardSupport {
|
|
||||||
fn get(&mut self) -> Option<String> {
|
|
||||||
self.0.get_contents().ok()
|
|
||||||
}
|
|
||||||
fn set(&mut self, text: &str) {
|
|
||||||
// ignore errors?
|
|
||||||
let _ = self.0.set_contents(text.to_owned());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,164 +0,0 @@
|
|||||||
use glium::glutin::surface::WindowSurface;
|
|
||||||
use glium::{Display, Surface};
|
|
||||||
use imgui::{Context, FontConfig, FontGlyphRanges, FontSource, Ui};
|
|
||||||
use imgui_glium_renderer::Renderer;
|
|
||||||
use imgui_winit_support::winit::dpi::LogicalSize;
|
|
||||||
use imgui_winit_support::winit::event::{Event, WindowEvent};
|
|
||||||
use imgui_winit_support::winit::event_loop::EventLoop;
|
|
||||||
use imgui_winit_support::winit::window::WindowBuilder;
|
|
||||||
use imgui_winit_support::{HiDpiMode, WinitPlatform};
|
|
||||||
use std::path::Path;
|
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
mod clipboard;
|
|
||||||
|
|
||||||
pub const FONT_SIZE: f32 = 13.0;
|
|
||||||
|
|
||||||
#[allow(dead_code)] // annoyingly, RA yells that this is unusued
|
|
||||||
pub fn simple_init<F: FnMut(&mut bool, &mut Ui) + 'static>(title: &str, run_ui: F) {
|
|
||||||
init_with_startup(title, |_, _, _| {}, run_ui);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init_with_startup<FInit, FUi>(title: &str, mut startup: FInit, mut run_ui: FUi)
|
|
||||||
where
|
|
||||||
FInit: FnMut(&mut Context, &mut Renderer, &Display<WindowSurface>) + 'static,
|
|
||||||
FUi: FnMut(&mut bool, &mut Ui) + 'static,
|
|
||||||
{
|
|
||||||
let mut imgui = create_context();
|
|
||||||
|
|
||||||
let title = match Path::new(&title).file_name() {
|
|
||||||
Some(file_name) => file_name.to_str().unwrap(),
|
|
||||||
None => title,
|
|
||||||
};
|
|
||||||
let event_loop = EventLoop::new().expect("Failed to create EventLoop");
|
|
||||||
|
|
||||||
let builder = WindowBuilder::new()
|
|
||||||
.with_title(title)
|
|
||||||
.with_inner_size(LogicalSize::new(1024, 768));
|
|
||||||
let (window, display) = glium::backend::glutin::SimpleWindowBuilder::new()
|
|
||||||
.set_window_builder(builder)
|
|
||||||
.build(&event_loop);
|
|
||||||
let mut renderer = Renderer::init(&mut imgui, &display).expect("Failed to initialize renderer");
|
|
||||||
|
|
||||||
if let Some(backend) = clipboard::init() {
|
|
||||||
imgui.set_clipboard_backend(backend);
|
|
||||||
} else {
|
|
||||||
eprintln!("Failed to initialize clipboard");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut platform = WinitPlatform::init(&mut imgui);
|
|
||||||
{
|
|
||||||
let dpi_mode = if let Ok(factor) = std::env::var("IMGUI_EXAMPLE_FORCE_DPI_FACTOR") {
|
|
||||||
// Allow forcing of HiDPI factor for debugging purposes
|
|
||||||
match factor.parse::<f64>() {
|
|
||||||
Ok(f) => HiDpiMode::Locked(f),
|
|
||||||
Err(e) => panic!("Invalid scaling factor: {}", e),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
HiDpiMode::Default
|
|
||||||
};
|
|
||||||
|
|
||||||
platform.attach_window(imgui.io_mut(), &window, dpi_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut last_frame = Instant::now();
|
|
||||||
|
|
||||||
startup(&mut imgui, &mut renderer, &display);
|
|
||||||
|
|
||||||
event_loop
|
|
||||||
.run(move |event, window_target| match event {
|
|
||||||
Event::NewEvents(_) => {
|
|
||||||
let now = Instant::now();
|
|
||||||
imgui.io_mut().update_delta_time(now - last_frame);
|
|
||||||
last_frame = now;
|
|
||||||
}
|
|
||||||
Event::AboutToWait => {
|
|
||||||
platform
|
|
||||||
.prepare_frame(imgui.io_mut(), &window)
|
|
||||||
.expect("Failed to prepare frame");
|
|
||||||
window.request_redraw();
|
|
||||||
}
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::RedrawRequested,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
let ui = imgui.frame();
|
|
||||||
|
|
||||||
let mut run = true;
|
|
||||||
run_ui(&mut run, ui);
|
|
||||||
if !run {
|
|
||||||
window_target.exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut target = display.draw();
|
|
||||||
target.clear_color_srgb(1.0, 1.0, 1.0, 1.0);
|
|
||||||
platform.prepare_render(ui, &window);
|
|
||||||
let draw_data = imgui.render();
|
|
||||||
renderer
|
|
||||||
.render(&mut target, draw_data)
|
|
||||||
.expect("Rendering failed");
|
|
||||||
target.finish().expect("Failed to swap buffers");
|
|
||||||
}
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::Resized(new_size),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
if new_size.width > 0 && new_size.height > 0 {
|
|
||||||
display.resize((new_size.width, new_size.height));
|
|
||||||
}
|
|
||||||
platform.handle_event(imgui.io_mut(), &window, &event);
|
|
||||||
}
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::CloseRequested,
|
|
||||||
..
|
|
||||||
} => window_target.exit(),
|
|
||||||
event => {
|
|
||||||
platform.handle_event(imgui.io_mut(), &window, &event);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.expect("EventLoop error");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates the imgui context
|
|
||||||
pub fn create_context() -> imgui::Context {
|
|
||||||
let mut imgui = Context::create();
|
|
||||||
// Fixed font size. Note imgui_winit_support uses "logical
|
|
||||||
// pixels", which are physical pixels scaled by the devices
|
|
||||||
// scaling factor. Meaning, 13.0 pixels should look the same size
|
|
||||||
// on two different screens, and thus we do not need to scale this
|
|
||||||
// value (as the scaling is handled by winit)
|
|
||||||
imgui.fonts().add_font(&[
|
|
||||||
FontSource::TtfData {
|
|
||||||
data: include_bytes!("../../../resources/Roboto-Regular.ttf"),
|
|
||||||
size_pixels: FONT_SIZE,
|
|
||||||
config: Some(FontConfig {
|
|
||||||
// As imgui-glium-renderer isn't gamma-correct with
|
|
||||||
// it's font rendering, we apply an arbitrary
|
|
||||||
// multiplier to make the font a bit "heavier". With
|
|
||||||
// default imgui-glow-renderer this is unnecessary.
|
|
||||||
rasterizer_multiply: 1.5,
|
|
||||||
// Oversampling font helps improve text rendering at
|
|
||||||
// expense of larger font atlas texture.
|
|
||||||
oversample_h: 4,
|
|
||||||
oversample_v: 4,
|
|
||||||
..FontConfig::default()
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
FontSource::TtfData {
|
|
||||||
data: include_bytes!("../../../resources/mplus-1p-regular.ttf"),
|
|
||||||
size_pixels: FONT_SIZE,
|
|
||||||
config: Some(FontConfig {
|
|
||||||
// Oversampling font helps improve text rendering at
|
|
||||||
// expense of larger font atlas texture.
|
|
||||||
oversample_h: 4,
|
|
||||||
oversample_v: 4,
|
|
||||||
// Range of glyphs to rasterize
|
|
||||||
glyph_ranges: FontGlyphRanges::japanese(),
|
|
||||||
..FontConfig::default()
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
imgui.set_ini_filename(None);
|
|
||||||
|
|
||||||
imgui
|
|
||||||
}
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "gemmaemu"
|
name = "gemma"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
autobenches = true
|
autobenches = true
|
||||||
|
|||||||
@ -1,168 +0,0 @@
|
|||||||
use std::io::{stdout, Result};
|
|
||||||
/*
|
|
||||||
use emmaemu::{chip8::{computer::Chip8Computer, video::Chip8Video}, constants::{CHIP8_MEMORY_SIZE, CHIP8_REGISTER_COUNT, CHIP8_ROM_SIZE, CHIP8_VIDEO_MEMORY}};
|
|
||||||
use ratatui::{
|
|
||||||
backend::CrosstermBackend,
|
|
||||||
crossterm::{
|
|
||||||
event::{self, KeyCode, KeyEventKind},
|
|
||||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
|
||||||
ExecutableCommand,
|
|
||||||
},
|
|
||||||
layout::{Alignment, Rect},
|
|
||||||
style::{Style, Stylize},
|
|
||||||
widgets::{List, Paragraph, Widget},
|
|
||||||
Frame, Terminal,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
fn system_memory_to_text_render(data_to_dump: [u8; 2048]) -> String {
|
|
||||||
let mut to_return = String::new();
|
|
||||||
|
|
||||||
for i in 0..256 {
|
|
||||||
to_return += &format!("{:x}\t", data_to_dump[i as usize]).to_string();
|
|
||||||
|
|
||||||
if ((i + 1) % CHIP8_REGISTER_COUNT) == 0 {
|
|
||||||
to_return += "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
to_return
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dump_memory_to_console(data_to_dump: [u8; 2048]) {
|
|
||||||
println!("STARTING TO DUMP MEMORY TO CONSOLE");
|
|
||||||
println!("{}", system_memory_to_text_render(data_to_dump));
|
|
||||||
println!("DONE DUMPING!");
|
|
||||||
panic!("DONE DUMPING");
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ControlKeyboard {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Widget for ControlKeyboard {
|
|
||||||
fn render(self, area: Rect, buf: &mut ratatui::prelude::Buffer)
|
|
||||||
where
|
|
||||||
Self: Sized {
|
|
||||||
let style = Style::new();
|
|
||||||
buf.set_string(0, 0, "F1 to cycle foreground - F2 to cycle background", style)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct AppState {
|
|
||||||
pub menu_items: Vec<String>,
|
|
||||||
pub selected_menu_item: i32,
|
|
||||||
pub system: Chip8Computer,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for AppState {
|
|
||||||
fn default() -> Self {
|
|
||||||
println!("Creating new AppState");
|
|
||||||
Self {
|
|
||||||
menu_items: vec![
|
|
||||||
"Step CPU <F5>".into(),
|
|
||||||
"Reset CPU <F12>".into(),
|
|
||||||
"Item 3".into(),
|
|
||||||
],
|
|
||||||
selected_menu_item: 0,
|
|
||||||
system: Chip8Computer {
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
|
||||||
stdout().execute(EnterAlternateScreen)?;
|
|
||||||
enable_raw_mode()?;
|
|
||||||
let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
|
|
||||||
terminal.clear()?;
|
|
||||||
|
|
||||||
let app = AppState::default();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
// Draw Ui...
|
|
||||||
terminal.draw(|frame| {
|
|
||||||
frame.render_widget(app.system.memory, frame.area());
|
|
||||||
// frame.render_widget(app.control_keyboard, area);
|
|
||||||
//render_cpu_state(app.system.clone(), frame);
|
|
||||||
// render_video_state(app.system.video_memory, frame);
|
|
||||||
// render_menu_list(app.clone(), frame);
|
|
||||||
})?;
|
|
||||||
// ...handle Events.
|
|
||||||
if event::poll(std::time::Duration::from_millis(16))? {
|
|
||||||
if let event::Event::Key(key) = event::read()? {
|
|
||||||
match key.kind {
|
|
||||||
KeyEventKind::Press => match key.code {
|
|
||||||
KeyCode::F(5) => {
|
|
||||||
println!("Execute Next Instruction");
|
|
||||||
}
|
|
||||||
KeyCode::F(12) => {
|
|
||||||
println!("Resetting CPU");
|
|
||||||
}
|
|
||||||
KeyCode::Char('q') => { break; }
|
|
||||||
_ => (),
|
|
||||||
},
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// stdout().execute(LeaveAlternateScreen)?;
|
|
||||||
// disable_raw_mode()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use emmaemu::constants::{CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_WIDTH};
|
|
||||||
|
|
||||||
use crate::*;
|
|
||||||
#[test]
|
|
||||||
fn blank_screen_renders_to_text() {
|
|
||||||
let test_video = Chip8Video::default();
|
|
||||||
|
|
||||||
|
|
||||||
let blank_data: [bool; CHIP8_VIDEO_MEMORY] = [false; CHIP8_VIDEO_MEMORY];
|
|
||||||
let blank_screen = (" ".repeat(CHIP8_VIDEO_WIDTH.try_into().unwrap()) + "\n")
|
|
||||||
.repeat(CHIP8_VIDEO_HEIGHT.try_into().unwrap());
|
|
||||||
|
|
||||||
assert_eq!(Chip8Video::new(blank_data).format_as_string(), blank_screen);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn filled_screen_renders_to_text() {
|
|
||||||
let filled_data: [bool; CHIP8_VIDEO_MEMORY] = [true; CHIP8_VIDEO_MEMORY];
|
|
||||||
let filled_screen = ("*".repeat(CHIP8_VIDEO_WIDTH.try_into().unwrap()) + "\n")
|
|
||||||
.repeat(CHIP8_VIDEO_HEIGHT.try_into().unwrap());
|
|
||||||
assert_eq!(Chip8Video::new(filled_data).format_as_string(), filled_screen);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn grid_pattern_renders_to_text() {
|
|
||||||
let mut grid_data: [bool; CHIP8_VIDEO_MEMORY] = [false; CHIP8_VIDEO_MEMORY];
|
|
||||||
let mut expected_data = String::new();
|
|
||||||
for i in 0..CHIP8_VIDEO_MEMORY {
|
|
||||||
grid_data[i] = (i % 2 == 0);
|
|
||||||
if i % 2 == 0 {
|
|
||||||
grid_data[i] = true;
|
|
||||||
expected_data += "*";
|
|
||||||
} else {
|
|
||||||
grid_data[i] = false;
|
|
||||||
expected_data += " ";
|
|
||||||
}
|
|
||||||
if (i as i32 % CHIP8_VIDEO_WIDTH as i32 == CHIP8_VIDEO_WIDTH - 1) {
|
|
||||||
expected_data += "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(Chip8Video::new(grid_data).format_as_string(), expected_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
fn main() {
|
|
||||||
println!("Taxation is theft");
|
|
||||||
}
|
|
||||||
@ -1,40 +0,0 @@
|
|||||||
use ratatui::{style::Stylize, widgets::{List, Paragraph}, Frame};
|
|
||||||
|
|
||||||
use crate::{AppState, Chip8Computer, CHIP8_REGISTER_COUNT, CHIP8_VIDEO_MEMORY};
|
|
||||||
|
|
||||||
|
|
||||||
pub fn render_cpu_state(cpu_state: Chip8Computer, frame: &mut Frame) {
|
|
||||||
let mut area = frame.area();
|
|
||||||
|
|
||||||
let mut current_state: Vec<String> = vec![];
|
|
||||||
|
|
||||||
current_state.push(format!("Delay Timer {:X}", cpu_state.delay_timer));
|
|
||||||
current_state.push(format!("Sound Timer {:X}", cpu_state.sound_timer));
|
|
||||||
current_state.push(format!("PC {:X}", cpu_state.pc));
|
|
||||||
for i in 0 .. CHIP8_REGISTER_COUNT {
|
|
||||||
current_state.push(format!("V{}: {}", i, cpu_state.registers[i as usize]));
|
|
||||||
}
|
|
||||||
|
|
||||||
frame.render_widget(
|
|
||||||
List::new(current_state).blue().on_white(), area)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render_menu_list(state: AppState, frame: &mut Frame) {
|
|
||||||
let mut area = frame.area();
|
|
||||||
|
|
||||||
frame.render_widget(List::new(state.menu_items).blue().on_white(), area);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render_hello_world(frame: &mut Frame) {
|
|
||||||
let area = frame.area();
|
|
||||||
frame.render_widget(
|
|
||||||
Paragraph::new("Hello Ratatui! (press 'q' to quit)")
|
|
||||||
.white()
|
|
||||||
.on_blue(),
|
|
||||||
area,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render_video_state(video_memory: [bool; CHIP8_VIDEO_MEMORY], frame: &mut Frame) {
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,19 +1,14 @@
|
|||||||
use log::{debug, error};
|
use log::{debug};
|
||||||
use crate::chip8::delay_timer::DelayTimer;
|
use crate::chip8::delay_timer::DelayTimer;
|
||||||
use crate::chip8::instructions::Chip8CpuInstructions::XXXXERRORINSTRUCTION;
|
|
||||||
use crate::chip8::keypad::Keypad;
|
use crate::chip8::keypad::Keypad;
|
||||||
use crate::chip8::registers::Chip8Registers;
|
use crate::chip8::registers::Chip8Registers;
|
||||||
use crate::chip8::sound_timer::SoundTimer;
|
use crate::chip8::sound_timer::SoundTimer;
|
||||||
use crate::chip8::stack::Chip8Stack;
|
use crate::chip8::stack::Chip8Stack;
|
||||||
use crate::chip8::util::InstructionUtil;
|
|
||||||
use crate::constants::{CHIP8_MEMORY_SIZE, CHIP8_REGISTER_COUNT};
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
cpu_states::Chip8CpuStates, instructions::Chip8CpuInstructions, system_memory::Chip8SystemMemory, video::Chip8Video,
|
cpu_states::Chip8CpuStates, instructions::Chip8CpuInstructions, system_memory::Chip8SystemMemory, video::Chip8Video,
|
||||||
};
|
};
|
||||||
|
|
||||||
const STACK_POINTER_DEFAULT: i16 = 0x100;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Chip8Computer {
|
pub struct Chip8Computer {
|
||||||
pub memory: Chip8SystemMemory,
|
pub memory: Chip8SystemMemory,
|
||||||
@ -85,7 +80,7 @@ impl Chip8Computer {
|
|||||||
debug!("Stepping System 1 Step");
|
debug!("Stepping System 1 Step");
|
||||||
// read the next instruction
|
// read the next instruction
|
||||||
|
|
||||||
let mut working_instruction: u16 = 0b0000000000000000;
|
// let mut working_instruction: u16 = 0b0000000000000000;
|
||||||
let start_pc = self.registers.peek_pc();
|
let start_pc = self.registers.peek_pc();
|
||||||
let high_byte = (self.memory.clone().peek(start_pc) as u16).rotate_left(8);
|
let high_byte = (self.memory.clone().peek(start_pc) as u16).rotate_left(8);
|
||||||
let low_byte = self.memory.clone().peek(start_pc + 1) as u16;
|
let low_byte = self.memory.clone().peek(start_pc + 1) as u16;
|
||||||
|
|||||||
@ -1,12 +1,10 @@
|
|||||||
use std::ops::{Shl, Shr};
|
use std::ops::{BitAnd, Shl, Shr};
|
||||||
use imgui::ColorPicker3;
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use rand::random;
|
use rand::random;
|
||||||
use crate::chip8::computer::{Chip8Computer};
|
use crate::chip8::computer::{Chip8Computer};
|
||||||
use crate::chip8::cpu_states::Chip8CpuStates::WaitingForKey;
|
use crate::chip8::cpu_states::Chip8CpuStates::WaitingForKey;
|
||||||
use crate::chip8::instructions::Chip8CpuInstructions::XXXXERRORINSTRUCTION;
|
use crate::chip8::instructions::Chip8CpuInstructions::XXXXERRORINSTRUCTION;
|
||||||
use crate::chip8::util::InstructionUtil;
|
use crate::chip8::util::InstructionUtil;
|
||||||
use crate::chip8::video::Chip8Video;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
nnn or addr - A 12-bit value, the lowest 12 bits of the instruction
|
nnn or addr - A 12-bit value, the lowest 12 bits of the instruction
|
||||||
@ -137,7 +135,7 @@ impl Chip8CpuInstructions {
|
|||||||
(0x2000 | (address & 0x0FFF)) as u16
|
(0x2000 | (address & 0x0FFF)) as u16
|
||||||
}
|
}
|
||||||
Chip8CpuInstructions::SeVxByte(vx_register, byte) => {
|
Chip8CpuInstructions::SeVxByte(vx_register, byte) => {
|
||||||
(0x3000 | (vx_register << 8 | byte) as u16)
|
0x3000 | ((*vx_register as u16) << 8 | *byte as u16) as u16
|
||||||
}
|
}
|
||||||
Chip8CpuInstructions::SneVxByte(vx_register, byte) => {
|
Chip8CpuInstructions::SneVxByte(vx_register, byte) => {
|
||||||
0x4000u16 | (*vx_register as u16) << 8 | *byte as u16
|
0x4000u16 | (*vx_register as u16) << 8 | *byte as u16
|
||||||
@ -418,7 +416,7 @@ impl Chip8CpuInstructions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute(&self, mut input: &mut Chip8Computer) -> Chip8Computer {
|
pub fn execute(&self, input: &mut Chip8Computer) -> Chip8Computer {
|
||||||
let start_pc = input.registers.peek_pc();
|
let start_pc = input.registers.peek_pc();
|
||||||
input.registers.poke_pc(start_pc + 2);
|
input.registers.poke_pc(start_pc + 2);
|
||||||
let _ = match self {
|
let _ = match self {
|
||||||
@ -461,10 +459,18 @@ impl Chip8CpuInstructions {
|
|||||||
}
|
}
|
||||||
// 0x4xkk Skip next instruction if Vx != kk
|
// 0x4xkk Skip next instruction if Vx != kk
|
||||||
Chip8CpuInstructions::SneVxByte(x, byte) => {
|
Chip8CpuInstructions::SneVxByte(x, byte) => {
|
||||||
if input.registers.peek(*x as u8) != *byte as u8 {
|
// 4xkk - SNE Vx, byte
|
||||||
|
// Skip next instruction if Vx != kk.
|
||||||
|
//
|
||||||
|
// The interpreter compares register Vx to kk, and if they are not equal,
|
||||||
|
// increments the program counter by 2.
|
||||||
|
let lhs = input.registers.peek(*x);
|
||||||
|
let rhs = *byte;
|
||||||
|
|
||||||
|
if lhs != rhs {
|
||||||
input.registers.advance_pc();
|
input.registers.advance_pc();
|
||||||
}
|
}
|
||||||
debug!("SneVxByte [0x{x:1x}] [0x{byte:2x}");
|
debug!("SneVxByte [0x{x:02x}] [0x{byte:02x}");
|
||||||
}
|
}
|
||||||
// 0x5xy0 Skip next instruction if Vx == Vy
|
// 0x5xy0 Skip next instruction if Vx == Vy
|
||||||
Chip8CpuInstructions::SeVxVy(x, y) => {
|
Chip8CpuInstructions::SeVxVy(x, y) => {
|
||||||
@ -527,37 +533,54 @@ impl Chip8CpuInstructions {
|
|||||||
let lhs = input.registers.peek(*x as u8) as i16;
|
let lhs = input.registers.peek(*x as u8) as i16;
|
||||||
let rhs = input.registers.peek(*y as u8) as i16;
|
let rhs = input.registers.peek(*y as u8) as i16;
|
||||||
let working = lhs + rhs;
|
let working = lhs + rhs;
|
||||||
if working > 0xff {
|
|
||||||
input.registers.poke(0xf, 0x01);
|
|
||||||
}
|
|
||||||
input.registers.poke(*x as u8, working as u8);
|
input.registers.poke(*x as u8, working as u8);
|
||||||
|
|
||||||
|
if working >= 0x100 {
|
||||||
|
input.registers.poke(0xf, 0x01);
|
||||||
|
} else {
|
||||||
|
input.registers.poke(0x0f, 0x00);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Chip8CpuInstructions::SubVxVy(x, y) => {
|
Chip8CpuInstructions::SubVxVy(x, y) => {
|
||||||
// 8xy5 - SUB Vx, Vy
|
// 8xy5 - SUB Vx, Vy
|
||||||
// Set Vx = Vx - Vy, set VF = NOT borrow.
|
// Set Vx = Vx - Vy, set VF = NOT borrow.
|
||||||
//
|
//
|
||||||
// If Vx > Vy, then VF is set to 1, otherwise 0. Then Vy is subtracted from Vx, and the results stored in Vx.
|
// If Vx > Vy, then VF is set to 1, otherwise 0. Then Vy is subtracted from Vx, and the results stored in Vx.
|
||||||
let mut x_value: u16 = input.registers.peek(*x as u8) as u16;
|
|
||||||
let y_value = input.registers.peek(*y as u8);
|
let lhs = input.registers.peek(*x);
|
||||||
// do we borrow?
|
let rhs = input.registers.peek(*y);
|
||||||
if y_value >= x_value as u8 {
|
|
||||||
x_value += 256;
|
let mut result = 0;
|
||||||
input.registers.poke(0xf, 1);
|
|
||||||
|
let borrow_flag: u8 = if rhs > lhs {
|
||||||
|
result = (lhs as u16 + 0x100) - rhs as u16;
|
||||||
|
0
|
||||||
} else {
|
} else {
|
||||||
input.registers.poke(0xf, 0);
|
result = lhs as u16 - rhs as u16;
|
||||||
}
|
1
|
||||||
let result = (x_value - y_value as u16) as u8;
|
};
|
||||||
input.registers.poke(*x as u8, result);
|
|
||||||
|
input.registers.poke(*x as u8, result as u8);
|
||||||
|
input.registers.poke(0x0f, borrow_flag);
|
||||||
}
|
}
|
||||||
Chip8CpuInstructions::ShrVxVy(x, _) => {
|
Chip8CpuInstructions::ShrVxVy(x, _) => {
|
||||||
// 8xy6 - SHR Vx {, Vy}
|
// 8xy6 - SHR Vx {, Vy}
|
||||||
// Set Vx = Vx SHR 1.
|
// Set Vx = Vx SHR 1.
|
||||||
//
|
// SHIFT 1 Bit ---->
|
||||||
// If the least-significant bit of Vx is 1, then VF is set to 1, otherwise 0. Then Vx is divided by 2.
|
// If the least-significant bit of Vx is 1, then VF is set to 1, otherwise 0. Then Vx is divided by 2.
|
||||||
let initial_value = input.registers.peek(*x as u8);
|
let initial_value = input.registers.peek(*x as u8);
|
||||||
if 0xb1 & initial_value == 1 {
|
|
||||||
input.registers.poke(0xf, 1);
|
// overflow check
|
||||||
|
|
||||||
|
if initial_value.bitand(0b1) == 1 {
|
||||||
|
input.registers.poke(0x0f, 0x01);
|
||||||
|
} else {
|
||||||
|
input.registers.poke(0x0f, 0x00);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let rotated = initial_value >> 1;
|
||||||
|
println!("[{initial_value:80b}] / [{rotated:80b}]");
|
||||||
|
|
||||||
input.registers.poke(*x as u8, initial_value.shr(1));
|
input.registers.poke(*x as u8, initial_value.shr(1));
|
||||||
}
|
}
|
||||||
Chip8CpuInstructions::SubnVxVy(x, y) => {
|
Chip8CpuInstructions::SubnVxVy(x, y) => {
|
||||||
@ -567,14 +590,17 @@ impl Chip8CpuInstructions {
|
|||||||
// If Vy > Vx, then VF is set to 1, otherwise 0. Then Vx is subtracted from Vy, and the results stored in Vx.
|
// If Vy > Vx, then VF is set to 1, otherwise 0. Then Vx is subtracted from Vy, and the results stored in Vx.
|
||||||
let y_register = input.registers.peek(*y as u8);
|
let y_register = input.registers.peek(*y as u8);
|
||||||
let x_register = input.registers.peek(*x as u8);
|
let x_register = input.registers.peek(*x as u8);
|
||||||
let new_value = if y_register <= x_register { 1 } else { 0 };
|
let mut value_to_poke = 0;
|
||||||
let value_to_poke = if y_register <= x_register {
|
|
||||||
((y_register as u16 + 256) - x_register as u16) as u8
|
let new_value = if y_register <= x_register {
|
||||||
} else {
|
value_to_poke = (y_register as u16 + 256) - x_register as u16;
|
||||||
y_register - x_register
|
1 } else {
|
||||||
|
value_to_poke = (y_register - x_register) as u16;
|
||||||
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
input.registers.poke(0xf, new_value);
|
input.registers.poke(0xf, new_value);
|
||||||
input.registers.poke(*x as u8, value_to_poke);
|
input.registers.poke(*x as u8, value_to_poke as u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
Chip8CpuInstructions::ShlVxVy(x, _) => {
|
Chip8CpuInstructions::ShlVxVy(x, _) => {
|
||||||
@ -583,10 +609,13 @@ impl Chip8CpuInstructions {
|
|||||||
//
|
//
|
||||||
// If the most-significant bit of Vx is 1, then VF is set to 1, otherwise to 0. Then Vx is multiplied by 2.
|
// If the most-significant bit of Vx is 1, then VF is set to 1, otherwise to 0. Then Vx is multiplied by 2.
|
||||||
let initial_value = input.registers.peek(*x as u8);
|
let initial_value = input.registers.peek(*x as u8);
|
||||||
if 0x80 & initial_value == 0x80 {
|
let rotated = initial_value.shl(1);
|
||||||
input.registers.poke(0xf, 1);
|
if 0b10000000 & initial_value == 0b10000000 {
|
||||||
|
input.registers.poke(0x0f, 0x01);
|
||||||
|
} else {
|
||||||
|
input.registers.poke(0x0f, 0x00);
|
||||||
}
|
}
|
||||||
input.registers.poke(*x as u8, initial_value.shl(1));
|
input.registers.poke(*x as u8,rotated);
|
||||||
}
|
}
|
||||||
Chip8CpuInstructions::SneVxVy(vx_register, vy_register) => {
|
Chip8CpuInstructions::SneVxVy(vx_register, vy_register) => {
|
||||||
// 9xy0 - SNE Vx, Vy
|
// 9xy0 - SNE Vx, Vy
|
||||||
@ -624,7 +653,7 @@ impl Chip8CpuInstructions {
|
|||||||
// which is then ANDed with the value kk.
|
// which is then ANDed with the value kk.
|
||||||
// The results are stored in Vx.
|
// The results are stored in Vx.
|
||||||
let new_value: u8 = random();
|
let new_value: u8 = random();
|
||||||
input.registers.poke(*x as u8, (new_value & *byte as u8))
|
input.registers.poke(*x as u8, new_value & *byte as u8)
|
||||||
}
|
}
|
||||||
Chip8CpuInstructions::DrawVxVyNibble(y,x, n) => {
|
Chip8CpuInstructions::DrawVxVyNibble(y,x, n) => {
|
||||||
// Display n-byte sprite starting at memory location I at (Vx, Vy), set VF = collision.
|
// Display n-byte sprite starting at memory location I at (Vx, Vy), set VF = collision.
|
||||||
@ -762,8 +791,7 @@ impl Chip8CpuInstructions {
|
|||||||
let units = to_convert % 10;
|
let units = to_convert % 10;
|
||||||
|
|
||||||
// Convert to BCD
|
// Convert to BCD
|
||||||
let result = ((hundreds as u16) << 8) | units as u16;
|
let result = ((hundreds as u16) << 8) | units as u16 | ((tens as u16) << 4) | units as u16;
|
||||||
(tens << 4) | units;
|
|
||||||
// write them to the memory pointed to by I, I+1, and I+2
|
// write them to the memory pointed to by I, I+1, and I+2
|
||||||
let target_start_offset = input.registers.peek_i();
|
let target_start_offset = input.registers.peek_i();
|
||||||
input.memory.poke(target_start_offset, hundreds);
|
input.memory.poke(target_start_offset, hundreds);
|
||||||
@ -775,7 +803,6 @@ impl Chip8CpuInstructions {
|
|||||||
//
|
//
|
||||||
// The interpreter copies the values of registers V0 through Vx into memory,
|
// The interpreter copies the values of registers V0 through Vx into memory,
|
||||||
// starting at the address in I.
|
// starting at the address in I.
|
||||||
let num_loops = x;
|
|
||||||
let offset = input.registers.peek_i();
|
let offset = input.registers.peek_i();
|
||||||
for i in 0..=*x {
|
for i in 0..=*x {
|
||||||
input.memory.poke(offset + i as u16, input.registers.peek(i as u8));
|
input.memory.poke(offset + i as u16, input.registers.peek(i as u8));
|
||||||
@ -1461,4 +1488,65 @@ mod test {
|
|||||||
Chip8CpuInstructions::LdVxK(0x1).execute(&mut x);
|
Chip8CpuInstructions::LdVxK(0x1).execute(&mut x);
|
||||||
assert!(matches!(x.state, WaitingForKey));
|
assert!(matches!(x.state, WaitingForKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn series8xy4_corex_tests() {
|
||||||
|
/// 8xy4
|
||||||
|
/// Set Vx = Vx + Vy
|
||||||
|
/// Set VF=1 if Carry
|
||||||
|
///
|
||||||
|
|
||||||
|
// 1 + 1
|
||||||
|
let mut x = Chip8Computer::new();
|
||||||
|
x.registers.poke(0x01, 0x01);
|
||||||
|
x.registers.poke(0x02, 0x01);
|
||||||
|
Chip8CpuInstructions::AddVxVy(0x01, 0x02).execute(&mut x);
|
||||||
|
assert_eq!(x.registers.peek(0x01), 0x02);
|
||||||
|
assert_eq!(x.registers.peek(0x0f), 0x00);
|
||||||
|
|
||||||
|
// 255+1
|
||||||
|
let mut x = Chip8Computer::new();
|
||||||
|
x.registers.poke(0x01, 0xff);
|
||||||
|
x.registers.poke(0x02, 0x01);
|
||||||
|
Chip8CpuInstructions::AddVxVy(0x01, 0x02).execute(&mut x);
|
||||||
|
assert_eq!(x.registers.peek(0x01), 0x00);
|
||||||
|
assert_eq!(x.registers.peek(0x0f), 0x01);
|
||||||
|
|
||||||
|
// 128+192
|
||||||
|
let mut x = Chip8Computer::new();
|
||||||
|
x.registers.poke(0x01, 128);
|
||||||
|
x.registers.poke(0x02, 192);
|
||||||
|
Chip8CpuInstructions::AddVxVy(0x01, 0x02).execute(&mut x);
|
||||||
|
assert_eq!(x.registers.peek(0x01), 64);
|
||||||
|
assert_eq!(x.registers.peek(0x0f), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn series8xy6_corex_tests() {
|
||||||
|
// 8xy6 - SHR Vx {, Vy}
|
||||||
|
// Set Vx = Vx SHR 1.
|
||||||
|
//
|
||||||
|
// If the least-significant bit of Vx is 1, then VF is set to 1,
|
||||||
|
// otherwise 0. Then Vx is divided by 2.
|
||||||
|
let mut x = Chip8Computer::new();
|
||||||
|
// 0b10000000 -> 0b01000000
|
||||||
|
let start_value = 0b10000000;
|
||||||
|
let end_value = 0b01000000;
|
||||||
|
x.registers.poke(0x01, start_value);
|
||||||
|
Chip8CpuInstructions::ShrVxVy(0x01, 0x00).execute(&mut x);
|
||||||
|
assert_eq!(x.registers.peek(0x01), end_value);
|
||||||
|
assert_eq!(x.registers.peek(0x0f), 0);
|
||||||
|
|
||||||
|
// 0b00000001 -> 0b00000000
|
||||||
|
let start_value = 0b00000001;
|
||||||
|
let end_value = 0b00000000;
|
||||||
|
let mut x = Chip8Computer::new();
|
||||||
|
let start_value = 1;
|
||||||
|
x.registers.poke(0x01, start_value);
|
||||||
|
Chip8CpuInstructions::ShrVxVy(0x01, 0x00).execute(&mut x);
|
||||||
|
assert_eq!(x.registers.peek(0x01), end_value);
|
||||||
|
assert_eq!(x.registers.peek(0x0f), 1);
|
||||||
|
let end_value = start_value / 2;
|
||||||
|
assert_eq!(end_value, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,3 @@
|
|||||||
use imgui::Key;
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Keypad {
|
pub struct Keypad {
|
||||||
keys: [bool; 0x10],
|
keys: [bool; 0x10],
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
use log::debug;
|
|
||||||
|
|
||||||
/// Registers. numbered 1-16 publicly.
|
/// Registers. numbered 1-16 publicly.
|
||||||
/// Privately using zero base array so -1 to shift from pub to priv.
|
/// Privately using zero base array so -1 to shift from pub to priv.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
@ -7,7 +5,6 @@ pub struct Chip8Registers {
|
|||||||
registers: [u8; 16],
|
registers: [u8; 16],
|
||||||
i_register: u16,
|
i_register: u16,
|
||||||
pc: u16,
|
pc: u16,
|
||||||
sp: u16,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Chip8Registers {
|
impl Chip8Registers {
|
||||||
@ -22,7 +19,6 @@ impl Default for Chip8Registers {
|
|||||||
registers: [0x00; 16],
|
registers: [0x00; 16],
|
||||||
i_register: 0x00,
|
i_register: 0x00,
|
||||||
pc: 0x200,
|
pc: 0x200,
|
||||||
sp: 0x100,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
use std::{thread, time};
|
|
||||||
use beep::beep;
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
|||||||
@ -1,11 +1,6 @@
|
|||||||
use glium::RawUniformValue::Vec2;
|
use log::{trace};
|
||||||
use image::load;
|
|
||||||
use imgui::sys::ImColor;
|
|
||||||
use imgui::{ImColor32, Ui};
|
|
||||||
use log::{debug, trace};
|
|
||||||
use ratatui::{style::Style, widgets::Widget};
|
|
||||||
|
|
||||||
use crate::constants::{CHIP8_MEMORY_SIZE, CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_WIDTH};
|
use crate::constants::{CHIP8_MEMORY_SIZE};
|
||||||
|
|
||||||
pub const CHIP8_PROGRAM_LOAD_OFFSET: i32 = 0x200;
|
pub const CHIP8_PROGRAM_LOAD_OFFSET: i32 = 0x200;
|
||||||
pub const CHIP8FONT_0: [u8; 5] = [0xF0, 0x90, 0x90, 0x90, 0xF0];
|
pub const CHIP8FONT_0: [u8; 5] = [0xF0, 0x90, 0x90, 0x90, 0xF0];
|
||||||
@ -41,10 +36,6 @@ impl Default for Chip8SystemMemory {
|
|||||||
x
|
x
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const cell_width: i32 = 5i32;
|
|
||||||
const cell_height: i32 = 5i32;
|
|
||||||
|
|
||||||
impl Chip8SystemMemory {
|
impl Chip8SystemMemory {
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
|||||||
@ -55,7 +55,7 @@ impl InstructionUtil {
|
|||||||
|
|
||||||
// kk or byte - An 8-bit value, the lowest 8 bits of the instruction
|
// kk or byte - An 8-bit value, the lowest 8 bits of the instruction
|
||||||
pub fn read_byte_from_instruction(instruction_to_read_from: u16) -> u16 {
|
pub fn read_byte_from_instruction(instruction_to_read_from: u16) -> u16 {
|
||||||
(instruction_to_read_from & 0x00FF)
|
instruction_to_read_from & 0x00FF
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_upper_byte_lower_nibble(to_read_from: u16) -> u16 {
|
pub fn read_upper_byte_lower_nibble(to_read_from: u16) -> u16 {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use gemmaemu::chip8::computer::Chip8Computer;
|
use gemma::chip8::computer::Chip8Computer;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn smoke() { assert!(true) }
|
fn smoke() { assert!(true) }
|
||||||
@ -6,4 +6,5 @@ fn smoke() { assert!(true) }
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_rom_1_works() {
|
fn test_rom_1_works() {
|
||||||
let mut x = Chip8Computer::new();
|
let mut x = Chip8Computer::new();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,6 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
gemmaemu = { path = "../gemma" }
|
gemma = { path = "../gemma" }
|
||||||
egui = "0.29.1"
|
egui = "0.29.1"
|
||||||
eframe = "0.29.1"
|
eframe = "0.29.1"
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
use egui::Ui;
|
use egui::Ui;
|
||||||
use gemmaemu::chip8::computer::Chip8Computer;
|
use gemma::chip8::computer::Chip8Computer;
|
||||||
|
|
||||||
struct EmmaEGuiState {
|
struct EmmaEGuiState {
|
||||||
pub display_video: bool,
|
pub display_video: bool,
|
||||||
|
|||||||
20
gemmaimgui/Cargo.toml
Normal file
20
gemmaimgui/Cargo.toml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
[package]
|
||||||
|
name = "gemmaimgui"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
gemma = { path = "../gemma" }
|
||||||
|
glium = { version = "0.34.0", default-features = true }
|
||||||
|
image = "0.23"
|
||||||
|
imgui = { version ="0.12.0", features = ["tables-api"] }
|
||||||
|
imgui-glium-renderer = { version = "0.12.0" }
|
||||||
|
imgui-winit-support = { version = "0.12.0" }
|
||||||
|
winit = { version = "0.27", features = ["x11", "mint"] }
|
||||||
|
pretty_env_logger = "0.5.0"
|
||||||
|
copypasta = "0.8"
|
||||||
|
rand = "0.9.0-alpha.2"
|
||||||
|
log = "0.4.22"
|
||||||
|
beep = "0.3.0"
|
||||||
|
chrono = "0.4.38"
|
||||||
|
dimensioned = "0.8.0"
|
||||||
@ -1,19 +1,17 @@
|
|||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::fs::DirEntry;
|
use std::fs::DirEntry;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use gemmaemu::{
|
use gemma::{
|
||||||
chip8::computer::Chip8Computer,
|
chip8::computer::Chip8Computer,
|
||||||
constants::{CHIP8_MEMORY_SIZE, CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_WIDTH},
|
constants::{CHIP8_MEMORY_SIZE, CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_WIDTH},
|
||||||
};
|
};
|
||||||
use imgui::*;
|
use imgui::*;
|
||||||
use ratatui::symbols::half_block;
|
|
||||||
use sys::{ImColor, ImVec2, ImVector_ImU32};
|
use sys::{ImColor, ImVec2, ImVector_ImU32};
|
||||||
use rand::random;
|
use rand::random;
|
||||||
use gemmaemu::chip8::system_memory::Chip8SystemMemory;
|
use gemma::chip8::system_memory::Chip8SystemMemory;
|
||||||
use support::emmagui_support::EmmaGui;
|
use support::emmagui_support::EmmaGui;
|
||||||
mod support;
|
mod support;
|
||||||
|
|
||||||
|
|
||||||
struct UiState {
|
struct UiState {
|
||||||
pub show_registers: bool,
|
pub show_registers: bool,
|
||||||
pub show_memory: bool,
|
pub show_memory: bool,
|
||||||
@ -50,7 +48,7 @@ impl Default for UiState {
|
|||||||
on_colour: ImColor32::from_rgb(0xff, 0xff, 0x00),
|
on_colour: ImColor32::from_rgb(0xff, 0xff, 0x00),
|
||||||
off_colour: ImColor32::from_rgb(0x00, 0xff, 0xff),
|
off_colour: ImColor32::from_rgb(0x00, 0xff, 0xff),
|
||||||
is_running: false,
|
is_running: false,
|
||||||
frame_time: 32.0
|
frame_time: 10.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5,9 +5,9 @@ use std::thread::sleep;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use imgui::{Condition, ImColor32, Ui};
|
use imgui::{Condition, ImColor32, Ui};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use gemmaemu::chip8::computer::Chip8Computer;
|
use gemma::chip8::computer::Chip8Computer;
|
||||||
use gemmaemu::chip8::system_memory::Chip8SystemMemory;
|
use gemma::chip8::system_memory::Chip8SystemMemory;
|
||||||
use gemmaemu::constants::{CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_WIDTH};
|
use gemma::constants::{CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_WIDTH};
|
||||||
use crate::UiState;
|
use crate::UiState;
|
||||||
|
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user