I really should be using branches for diff experiments, but we can display in the terminal now!

This commit is contained in:
august kline 2024-06-23 13:23:29 -04:00
parent f9198cd0b1
commit 229b8b450d
10 changed files with 1967 additions and 2298 deletions

701
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -8,10 +8,18 @@ edition = "2021"
[dependencies] [dependencies]
anyhow = "1.0.81" anyhow = "1.0.81"
bdf = "0.6.0" bdf = "0.6.0"
bitvec = "1.0.1"
clap = { version = "4.5.4", features = ["derive"] } clap = { version = "4.5.4", features = ["derive"] }
criterion = "0.4"
crossterm = "0.27.0" crossterm = "0.27.0"
minifb = "0.25.0" minifb = "0.25.0"
ratatui = "0.26.3" ratatui = "0.26.3"
serde = { version = "1.0.197", features = ["serde_derive", "derive"] } serde = { version = "1.0.197", features = ["serde_derive", "derive"] }
toml = "0.8.12" toml = "0.8.12"
[dev-dependencies]
criterion = {version = "0.4", features = ["html_reports"]}
[[bench]]
name = "benchmark"
path = "src/benches/benchmark.rs"
harness = false

View File

@ -1,3 +1,3 @@
char_rom = "./src/roms/cozette.rom" char_rom = "./src/roms/cozette.rom"
rom = "./src/roms/test.rom" rom = "./src/roms/george.rom"

View File

@ -1,6 +1,7 @@
use crate::instructions::{get_instruction, Instruction}; use crate::instructions::{get_instruction, Instruction};
use crate::memory::{MemHandle, MemoryReader, MemoryWriter}; use crate::memory::{MemHandle, MemoryReader, MemoryWriter};
use crate::types::{Byte, Word}; use crate::types::{Byte, Word};
use std::fmt::Display;
use std::sync::mpsc::{Receiver, Sender}; use std::sync::mpsc::{Receiver, Sender};
use std::thread::sleep; use std::thread::sleep;
use std::time::Duration; use std::time::Duration;
@ -68,6 +69,7 @@ pub struct CpuState {
pub nmi: bool, pub nmi: bool,
} }
// #[derive(Clone)]
pub struct Cpu { pub struct Cpu {
pub a: Byte, // Accumulator Register pub a: Byte, // Accumulator Register
pub x: Byte, // X Register pub x: Byte, // X Register
@ -81,8 +83,14 @@ pub struct Cpu {
pub pending_cycles: usize, pub pending_cycles: usize,
receiver: CpuReceiver, receiver: CpuReceiver,
stopped: bool, stopped: bool,
cycle_count: usize, // cycle_count: usize,
state_tx: Sender<CpuState>, // state_tx: Sender<CpuState>,
}
impl Display for Cpu {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{},{}", self.a, self.x)
}
} }
impl MemoryReader for Cpu { impl MemoryReader for Cpu {
@ -97,7 +105,8 @@ impl MemoryWriter for Cpu {
} }
impl Cpu { impl Cpu {
pub fn new(memory: MemHandle, receiver: CpuReceiver, state_tx: Sender<CpuState>) -> Self { pub fn new(memory: MemHandle, receiver: CpuReceiver) -> Self {
// pub fn new(memory: MemHandle) -> Self {
Cpu { Cpu {
a: 0x00, a: 0x00,
x: 0x00, x: 0x00,
@ -111,8 +120,8 @@ impl Cpu {
memory, memory,
stopped: false, stopped: false,
pending_cycles: 0, pending_cycles: 0,
cycle_count: 0, // cycle_count: 0,
state_tx, // state_tx,
} }
} }
pub fn reset(&mut self) -> Result<()> { pub fn reset(&mut self) -> Result<()> {
@ -121,15 +130,6 @@ impl Cpu {
self.pending_cycles = 0; self.pending_cycles = 0;
Ok(()) Ok(())
} }
// pub fn read(&self, address: Word) -> Result<Byte> {
// let memory = match self.memory.lock() {
// Ok(read) => read,
// Err(_) => {
// bail!("Couldn't acquire lock on memory in cpu thread")
// }
// };
// Ok(memory.read(address))
// }
pub fn read_word(&self, address: Word) -> Result<Word> { pub fn read_word(&self, address: Word) -> Result<Word> {
let low_byte = self.read(address); let low_byte = self.read(address);
let high_byte = self.read(address + 0x1); let high_byte = self.read(address + 0x1);
@ -209,24 +209,24 @@ impl Cpu {
CpuControl::Irq => self.irq = true, CpuControl::Irq => self.irq = true,
CpuControl::Stop => self.stopped = true, CpuControl::Stop => self.stopped = true,
CpuControl::Resume => self.stopped = false, CpuControl::Resume => self.stopped = false,
CpuControl::Data => self CpuControl::Data => {} // self
.state_tx // .state_tx
.send(CpuState { // .send(CpuState {
a: self.a.clone(), // Accumulator Register // a: self.a.clone(), // Accumulator Register
x: self.x.clone(), // X Register // x: self.x.clone(), // X Register
y: self.y.clone(), // Y Register // y: self.y.clone(), // Y Register
pc: self.pc.clone(), // Program Counter // pc: self.pc.clone(), // Program Counter
s: self.s.clone(), // Stack Pointer // s: self.s.clone(), // Stack Pointer
p: self.p.clone(), // Status Register // p: self.p.clone(), // Status Register
irq: self.irq.clone(), // irq: self.irq.clone(),
nmi: self.nmi.clone(), // nmi: self.nmi.clone(),
}) // })
.unwrap(), // .unwrap(),
} }
} }
pub fn cycle(&mut self) { pub fn cycle(&mut self) {
self.receive_control(); // self.receive_control();
if self.stopped { if self.stopped {
return; return;
} }
@ -239,13 +239,6 @@ impl Cpu {
self.interrupt(); self.interrupt();
} }
let opcode = self.read(self.pc); let opcode = self.read(self.pc);
// let opcode = match self.read(&self.memory, self.pc) {
// Ok(byte) => byte,
// Err(_) => {
// println!("Failed to read from memory at address {:#06x}!", self.pc);
// return;
// }
// };
let instruction = get_instruction(opcode); let instruction = get_instruction(opcode);
match instruction { match instruction {
Instruction::Valid(valid_instruction) => { Instruction::Valid(valid_instruction) => {
@ -278,7 +271,8 @@ impl Cpu {
} }
}, },
} }
self.cycle_count += 1; // self.cycle_count += 1;
sleep(Duration::from_nanos(100));
} }
pub fn stop(&mut self) { pub fn stop(&mut self) {
self.stopped = true; self.stopped = true;

View File

@ -7,259 +7,259 @@
# column #2 is the Unicode (in hex as 0xXXXX) # column #2 is the Unicode (in hex as 0xXXXX)
# column #3 the Unicode name (follows a comment sign, '#') # column #3 the Unicode name (follows a comment sign, '#')
0x00 0x00 # 0x00 0x00 #
0x01 0x2591 # 0x01 0x2591 #
0x02 0x2592 # 0x02 0x2592 #
0x03 0x2593 # ʔ 0x03 0x2593 #
0x04 0x2661 # White heart 0x04 0x2661 #
0x05 0x2665 # Black heart 0x05 0x2665 #
0x06 0x2B50 # White star 0x06 0x2B50 #
0x07 0x272D # Black star 0x07 0x272D #
0x08 0xF005 # Alternate Black Star 0x08 0xF005 #
0x09 0x2726 # Black four pointed star 0x09 0x2726 #
0x0a 0x2728 # Sparkles 0x0a 0x2728 #
0x0b 0x2640 # Female Sign 0x0b 0x2640 #
0x0c 0x2642 # Male Sign 0x0c 0x2642 #
0x0d 0x26A2 # Doubled female sign 0x0d 0x26A2 #
0x0E 0x26A3 # Doubled male sign 0x0E 0x26A3 #
0x0F 0x26A5 # Male and Female sign0x000E 0x0F 0x26A5 #
0x10 0x2669 # Quarter Note 0x10 0x2669 #
0x11 0x266A # Eighth note 0x11 0x266A #
0x12 0x266B # Beamed eighth notes 0x12 0x266B #
0x13 0x266C # Beamed sixteenth notes 0x13 0x266C #
0x14 0xFC5D # 0x14 0xFC5D #
0x15 0xF026 # 0x15 0xF026 #
0x16 0xF027 # 0x16 0xF027 #
0x17 0xF028 # 0x17 0xF028 #
0x18 0xFA7E # 0x18 0xFA7E #
0x19 0xFA7F # 0x19 0xFA7F # 奔
0x1A 0xFA80 # 0x1A 0xFA80 #
0x1B 0xFC5C # 0x1B 0xFC5C #
0x1C 0xFC5B # 0x1C 0xFC5B #
0x1D 0xF0AC # 0x1D 0xF0AC #
0x1E 0xF04B # 0x1E 0xF04B #
0x1F 0xF04D # 0x1F 0xF04D #
0x20 0x0020 # SPACE 0x20 0x0020 #
0x21 0x0021 # EXCLAMATION MARK 0x21 0x0021 # !
0x22 0x0022 # QUOTATION MARK 0x22 0x0022 # "
0x23 0x0023 # NUMBER SIGN 0x23 0x0023 # #
0x24 0x0024 # DOLLAR SIGN 0x24 0x0024 # $
0x25 0x0025 # PERCENT SIGN 0x25 0x0025 # %
0x26 0x0026 # AMPERSAND 0x26 0x0026 # &
0x27 0x0027 # APOSTROPHE 0x27 0x0027 # '
0x28 0x0028 # LEFT PARENTHESIS 0x28 0x0028 # (
0x29 0x0029 # RIGHT PARENTHESIS 0x29 0x0029 # )
0x2A 0x002A # ASTERISK 0x2A 0x002A # *
0x2B 0x002B # PLUS SIGN 0x2B 0x002B # +
0x2C 0x002C # COMMA 0x2C 0x002C # ,
0x2D 0x002D # HYPHEN-MINUS 0x2D 0x002D # -
0x2E 0x002E # FULL STOP 0x2E 0x002E # .
0x2F 0x002F # SOLIDUS 0x2F 0x002F # /
0x30 0x0030 # DIGIT ZERO 0x30 0x0030 # 0
0x31 0x0031 # DIGIT ONE 0x31 0x0031 # 1
0x32 0x0032 # DIGIT TWO 0x32 0x0032 # 2
0x33 0x0033 # DIGIT THREE 0x33 0x0033 # 3
0x34 0x0034 # DIGIT FOUR 0x34 0x0034 # 4
0x35 0x0035 # DIGIT FIVE 0x35 0x0035 # 5
0x36 0x0036 # DIGIT SIX 0x36 0x0036 # 6
0x37 0x0037 # DIGIT SEVEN 0x37 0x0037 # 7
0x38 0x0038 # DIGIT EIGHT 0x38 0x0038 # 8
0x39 0x0039 # DIGIT NINE 0x39 0x0039 # 9
0x3A 0x003A # COLON 0x3A 0x003A # :
0x3B 0x003B # SEMICOLON 0x3B 0x003B # ;
0x3C 0x003C # LESS-THAN SIGN 0x3C 0x003C # <
0x3D 0x003D # EQUALS SIGN 0x3D 0x003D # =
0x3E 0x003E # GREATER-THAN SIGN 0x3E 0x003E # >
0x3F 0x003F # QUESTION MARK 0x3F 0x003F # ?
0x40 0x0040 # COMMERCIAL AT 0x40 0x0040 # @
0x41 0x0041 # LATIN CAPITAL LETTER A 0x41 0x0041 # A
0x42 0x0042 # LATIN CAPITAL LETTER B 0x42 0x0042 # B
0x43 0x0043 # LATIN CAPITAL LETTER C 0x43 0x0043 # C
0x44 0x0044 # LATIN CAPITAL LETTER D 0x44 0x0044 # D
0x45 0x0045 # LATIN CAPITAL LETTER E 0x45 0x0045 # E
0x46 0x0046 # LATIN CAPITAL LETTER F 0x46 0x0046 # F
0x47 0x0047 # LATIN CAPITAL LETTER G 0x47 0x0047 # G
0x48 0x0048 # LATIN CAPITAL LETTER H 0x48 0x0048 # H
0x49 0x0049 # LATIN CAPITAL LETTER I 0x49 0x0049 # I
0x4A 0x004A # LATIN CAPITAL LETTER J 0x4A 0x004A # J
0x4B 0x004B # LATIN CAPITAL LETTER K 0x4B 0x004B # K
0x4C 0x004C # LATIN CAPITAL LETTER L 0x4C 0x004C # L
0x4D 0x004D # LATIN CAPITAL LETTER M 0x4D 0x004D # M
0x4E 0x004E # LATIN CAPITAL LETTER N 0x4E 0x004E # N
0x4F 0x004F # LATIN CAPITAL LETTER O 0x4F 0x004F # O
0x50 0x0050 # LATIN CAPITAL LETTER P 0x50 0x0050 # P
0x51 0x0051 # LATIN CAPITAL LETTER Q 0x51 0x0051 # Q
0x52 0x0052 # LATIN CAPITAL LETTER R 0x52 0x0052 # R
0x53 0x0053 # LATIN CAPITAL LETTER S 0x53 0x0053 # S
0x54 0x0054 # LATIN CAPITAL LETTER T 0x54 0x0054 # T
0x55 0x0055 # LATIN CAPITAL LETTER U 0x55 0x0055 # U
0x56 0x0056 # LATIN CAPITAL LETTER V 0x56 0x0056 # V
0x57 0x0057 # LATIN CAPITAL LETTER W 0x57 0x0057 # W
0x58 0x0058 # LATIN CAPITAL LETTER X 0x58 0x0058 # X
0x59 0x0059 # LATIN CAPITAL LETTER Y 0x59 0x0059 # Y
0x5A 0x005A # LATIN CAPITAL LETTER Z 0x5A 0x005A # Z
0x5B 0x005B # LEFT SQUARE BRACKET 0x5B 0x005B # [
0x5C 0x005C # REVERSE SOLIDUS 0x5C 0x005C # \
0x5D 0x005D # RIGHT SQUARE BRACKET 0x5D 0x005D # ]
0x5E 0x005E # CIRCUMFLEX ACCENT 0x5E 0x005E # ^
0x5F 0x005F # LOW LINE 0x5F 0x005F # _
0x60 0x0060 # GRAVE ACCENT 0x60 0x0060 # `
0x61 0x0061 # LATIN SMALL LETTER A 0x61 0x0061 # a
0x62 0x0062 # LATIN SMALL LETTER B 0x62 0x0062 # b
0x63 0x0063 # LATIN SMALL LETTER C 0x63 0x0063 # c
0x64 0x0064 # LATIN SMALL LETTER D 0x64 0x0064 # d
0x65 0x0065 # LATIN SMALL LETTER E 0x65 0x0065 # e
0x66 0x0066 # LATIN SMALL LETTER F 0x66 0x0066 # f
0x67 0x0067 # LATIN SMALL LETTER G 0x67 0x0067 # g
0x68 0x0068 # LATIN SMALL LETTER H 0x68 0x0068 # h
0x69 0x0069 # LATIN SMALL LETTER I 0x69 0x0069 # i
0x6A 0x006A # LATIN SMALL LETTER J 0x6A 0x006A # j
0x6B 0x006B # LATIN SMALL LETTER K 0x6B 0x006B # k
0x6C 0x006C # LATIN SMALL LETTER L 0x6C 0x006C # l
0x6D 0x006D # LATIN SMALL LETTER M 0x6D 0x006D # m
0x6E 0x006E # LATIN SMALL LETTER N 0x6E 0x006E # n
0x6F 0x006F # LATIN SMALL LETTER O 0x6F 0x006F # o
0x70 0x0070 # LATIN SMALL LETTER P 0x70 0x0070 # p
0x71 0x0071 # LATIN SMALL LETTER Q 0x71 0x0071 # q
0x72 0x0072 # LATIN SMALL LETTER R 0x72 0x0072 # r
0x73 0x0073 # LATIN SMALL LETTER S 0x73 0x0073 # s
0x74 0x0074 # LATIN SMALL LETTER T 0x74 0x0074 # t
0x75 0x0075 # LATIN SMALL LETTER U 0x75 0x0075 # u
0x76 0x0076 # LATIN SMALL LETTER V 0x76 0x0076 # v
0x77 0x0077 # LATIN SMALL LETTER W 0x77 0x0077 # w
0x78 0x0078 # LATIN SMALL LETTER X 0x78 0x0078 # x
0x79 0x0079 # LATIN SMALL LETTER Y 0x79 0x0079 # y
0x7A 0x007A # LATIN SMALL LETTER Z 0x7A 0x007A # z
0x7B 0x007B # LEFT CURLY BRACKET 0x7B 0x007B # {
0x7C 0x007C # VERTICAL LINE 0x7C 0x007C # |
0x7D 0x007D # RIGHT CURLY BRACKET 0x7D 0x007D # }
0x7E 0x007E # TILDE 0x7E 0x007E # ~
0x7F 0x2500 # Box Drawings light horizontal 0x7F 0x2500 #
0x80 0x2502 # Box drawings light vertical 0x80 0x2502 #
0x81 0x250C # Box drawing light down and right 0x81 0x250C #
0x82 0x2514 # Box drawing light up and right 0x82 0x2514 #
0x83 0x251C # Box drawings light vertical and right 0x83 0x251C #
0x84 0x2524 # 0x84 0x2524 #
0x85 0x252C # 0x85 0x252C #
0x86 0x2534 # 0x86 0x2534 #
0x87 0x253C # 0x87 0x253C #
0x88 0x256D # 0x88 0x256D #
0x89 0x256E # 0x89 0x256E #
0x8A 0x256F # 0x8A 0x256F #
0x8B 0x2570 # 0x8B 0x2570 #
0x8C 0x2571 # 0x8C 0x2571 #
0x8D 0x2572 # 0x8D 0x2572 #
0x8E 0x2573 # 0x8E 0x2573 #
0x8F 0x2550 # 0x8F 0x2550 #
0x90 0x2551 # 0x90 0x2551 #
0x91 0x2554 # 0x91 0x2554 #
0x92 0x2557 # 0x92 0x2557 #
0x93 0x255a # 0x93 0x255a #
0x94 0x255D # 0x94 0x255D #
0x95 0x2560 # 0x95 0x2560 #
0x96 0x2563 # 0x96 0x2563 #
0x97 0x2566 # 0x97 0x2566 #
0x98 0x2569 # 0x98 0x2569 #
0x99 0x256C # 0x99 0x256C #
0x9A 0xF04E # 0x9A 0xF04E #
0x9B 0xF050 # 0x9B 0xF050 #
0x9C 0xF051 # 0x9C 0xF051 #
0x9D 0xF052 # 0x9D 0xF052 #
0x9E 0xF048 # 0x9E 0xF048 #
0x9F 0xE0B0 # 0x9F 0xE0B0 #
0xA0 0xE0B2 # 0xA0 0xE0B2 #
0xA1 0xE0B4 # 0xA1 0xE0B4 #
0xA2 0xE0B6 # 0xA2 0xE0B6 #
0xA3 0xE0B8 # 0xA3 0xE0B8 #
0xA4 0xE0BA # 0xA4 0xE0BA #
0xA5 0xE0BC # 0xA5 0xE0BC #
0xA6 0xE0BE # 0xA6 0xE0BE #
0xA7 0x2581 # 0xA7 0x2581 #
0xA8 0x2582 # 0xA8 0x2582 #
0xA9 0x2583 # 0xA9 0x2583 #
0xAA 0x2584 # 0xAA 0x2584 #
0xAB 0x2585 # 0xAB 0x2585 #
0xAC 0x2586 # 0xAC 0x2586 #
0xAD 0x2587 # 0xAD 0x2587 #
0xAE 0x2588 # 0xAE 0x2588 #
0xAF 0x2589 # 0xAF 0x2589 #
0xB0 0x258A # 0xB0 0x258A #
0xB1 0x258B # 0xB1 0x258B #
0xB2 0x258C # 0xB2 0x258C #
0xB3 0x258D # 0xB3 0x258D #
0xB4 0x258E # 0xB4 0x258E #
0xB5 0x258F # 0xB5 0x258F #
0xB6 0x0295 # 0xB6 0x0295 # ʕ
0xB7 0x00B7 # 0xB7 0x00B7 # ·
0xB8 0x1D25 # 0xB8 0x1D25 #
0xB9 0x0294 0xB9 0x0294 # ʔ
0xBA 0x2596 0xBA 0x2596 # ▖
0xBB 0x2597 0xBB 0x2597 # ▗
0xBC 0x2598 0xBC 0x2598 # ▘
0xBD 0x2599 0xBD 0x2599 # ▙
0xBE 0x259A 0xBE 0x259A # ▚
0xBF 0x259B 0xBF 0x259B # ▛
0xC0 0x259C 0xC0 0x259C # ▜
0xC1 0x259D 0xC1 0x259D # ▝
0xC2 0x259E 0xC2 0x259E # ▞
0xC3 0x259F 0xC3 0x259F # ▟
0xC4 0x2190 0xC4 0x2190 # ←
0xC5 0x2191 0xC5 0x2191 # ↑
0xC6 0x2192 0xC6 0x2192 # →
0xC7 0x2193 0xC7 0x2193 # ↓
0xC8 0x2B60 0xC8 0x2B60 # ⭠
0xC9 0x2B61 0xC9 0x2B61 # ⭡
0xCA 0x2B62 0xCA 0x2B62 # ⭢
0xCB 0x2B63 0xCB 0x2B63 # ⭣
0xCC 0x2B80 0xCC 0x2B80 # ⮀
0xCD 0x2B81 0xCD 0x2B81 # ⮁
0xCE 0x2B82 0xCE 0x2B82 # ⮂
0xCF 0x2B83 0xCF 0x2B83 # ⮃
0xD0 0xF049 0xD0 0xF049 # 
0xD1 0xF04A 0xD1 0xF04A # 
0xD2 0x23F3 0xD2 0x23F3 # ⏳
0xD3 0xF07B 0xD3 0xF07B # 
0xD4 0xF07C 0xD4 0xF07C # 
0xD5 0xF114 0xD5 0xF114 # 
0xD6 0xF115 0xD6 0xF115 # 
0xD7 0xF250 0xD7 0xF250 # 
0xD8 0xF251 0xD8 0xF251 # 
0xD9 0xF253 0xD9 0xF253 # 
0xDA 0xF254 0xDA 0xF254 # 
0xDB 0xF461 0xDB 0xF461 # 
0xDC 0xF016 0xDC 0xF016 # 
0xDD 0xF401 0xDD 0xF401 # 
0xDE 0x1F52E 0xDE 0x1F52E # 🔮
0xDF 0xF2DB 0xDF 0xF2DB # 
0xE0 0xF008 0xE0 0xF008 # 
0xE1 0x25C7 0xE1 0x25C7 # ◇
0xE2 0x25C8 0xE2 0x25C8 # ◈
0xE3 0x1F311 0xE3 0x1F311 # 🌑
0xE4 0x1F312 0xE4 0x1F312 # 🌒
0xE5 0x1F313 0xE5 0x1F313 # 🌓
0xE6 0x1F314 0xE6 0x1F314 # 🌔
0xE7 0x1F315 0xE7 0x1F315 # 🌕
0xE8 0x1F316 0xE8 0x1F316 # 🌖
0xE9 0x1F317 0xE9 0x1F317 # 🌗
0xEA 0x1F318 0xEA 0x1F318 # 🌘
0xEB 0xF04C 0xEB 0xF04C # 
0xEC 0x2714 0xEC 0x2714 # ✔
0xED 0x2718 0xED 0x2718 # ✘
0xEE 0x25C6 0xEE 0x25C6 # ◆
0xEF 0xF15D 0xEF 0xF15D # 
0xF0 0xF15E 0xF0 0xF15E # 
0xF1 0xF071 0xF1 0xF071 # 
0xF2 0xF449 0xF2 0xF449 # 
0xF3 0xF529 0xF3 0xF529 # 
0xF4 0xF658 0xF4 0xF658 # 
0xF5 0xF659 # 0xF5 0xF659 #
0xF6 0x1f381 # Space 0xF6 0x1f381 # 🎁
0xF7 0xf05a # Space 0xF7 0xf05a #
0xF8 0xf06a # Space 0xF8 0xf06a #
0xF9 0xf834 # Space 0xF9 0xf834 #
0xFA 0xf835 # Space 0xFA 0xf835 #
0xFB 0x2690 # Space 0xFB 0x2690 #
0xFC 0x2691 # Space 0xFC 0x2691 #
0xFD 0xf8d7 # Space 0xFD 0xf8d7 #
0xFE 0xf0e7 # Space 0xFE 0xf0e7 #
0xFF 0xf7d9 # Space 0xFF 0xf7d9 #

File diff suppressed because it is too large Load Diff

View File

@ -12,12 +12,16 @@ mod video;
use crate::cpu::Cpu; use crate::cpu::Cpu;
use crate::keyboard::Keyboard; use crate::keyboard::Keyboard;
use crate::memory::Mem; use crate::memory::Mem;
use crate::video::Crtc; use crate::video::{Screen, TerminalRenderer};
use cpu::{CpuController, CpuReceiver}; use cpu::{CpuController, CpuReceiver};
use crossterm::cursor::Hide;
use crossterm::execute;
use crossterm::terminal::{size, Clear, ClearType, SetSize};
// use cpu::CpuController;
use memory::MemHandle; use memory::MemHandle;
// use clap::Parser; // use clap::Parser;
use minifb::{Scale, ScaleMode, Window, WindowOptions}; // use minifb::{Scale, ScaleMode, Window, WindowOptions};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ use std::{
@ -30,13 +34,12 @@ use std::{
}; };
use crossterm::{ use crossterm::{
cursor,
event::{self, KeyCode, KeyEventKind}, event::{self, KeyCode, KeyEventKind},
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
ExecutableCommand, // ExecutableCommand,
}; };
use ratatui::prelude::{CrosstermBackend, Terminal};
// use toml::Table; // use toml::Table;
//#[derive(Parser)] //#[derive(Parser)]
@ -53,10 +56,10 @@ struct Config {
} }
fn main() -> Result<()> { fn main() -> Result<()> {
stdout().execute(EnterAlternateScreen)?; let mut stdout = stdout();
let (cols, rows) = size()?;
execute!(stdout, SetSize(64, 29), cursor::Hide, EnterAlternateScreen)?;
enable_raw_mode()?; enable_raw_mode()?;
let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
terminal.clear()?;
let config: Config = match File::open("./config.toml") { let config: Config = match File::open("./config.toml") {
Ok(mut file) => { Ok(mut file) => {
@ -86,50 +89,60 @@ fn main() -> Result<()> {
let keyboard_memory = shared_memory.clone(); let keyboard_memory = shared_memory.clone();
let (cpu_tx, cpu_rx) = mpsc::channel(); let (cpu_tx, cpu_rx) = mpsc::channel();
let (state_tx, state_rx) = mpsc::channel(); // let (state_tx, state_rx) = mpsc::channel();
let screen_cpu_tx = cpu_tx.clone(); let screen_cpu_tx = cpu_tx.clone();
let (window_tx, window_rx) = mpsc::channel(); // let (window_tx, window_rx) = mpsc::channel();
thread::spawn(move || { // thread::spawn(move || {
let mut screen = Crtc::new( // let mut screen = Crtc::new(
screen_memory, // screen_memory,
config.char_rom.as_ref(), // config.char_rom.as_ref(),
CpuController::new(screen_cpu_tx), // CpuController::new(screen_cpu_tx),
window_tx, // window_tx,
); // );
screen.run(); // screen.run();
}); // });
let mut window = Window::new( // let mut window = Window::new(
"ʕ·ᴥ·ʔ-☆", // "ʕ·ᴥ·ʔ-☆",
512, // 512,
380, // 380,
WindowOptions { // WindowOptions {
resize: true, // resize: true,
borderless: true, // borderless: true,
title: true, // title: true,
transparency: false, // transparency: false,
scale: Scale::X2, // scale: Scale::X2,
scale_mode: ScaleMode::AspectRatioStretch, // scale_mode: ScaleMode::AspectRatioStretch,
topmost: false, // topmost: false,
none: true, // none: true,
}, // },
) // )
.unwrap(); // .unwrap();
window.set_input_callback(Box::new(Keyboard::new(keyboard_memory))); // window.set_input_callback(Box::new(Keyboard::new(keyboard_memory)));
let mut cpu = Cpu::new(cpu_memory, CpuReceiver::new(cpu_rx), state_tx); let mut cpu = Cpu::new(cpu_memory, CpuReceiver::new(cpu_rx));
let mut tui = tui::App::new( // let mut cpu = Cpu::new(cpu_memory);
CpuController::new(cpu_tx.clone()), // let mut tui = tui::App::new(
shared_memory.clone(), // CpuController::new(cpu_tx.clone()),
state_rx, // shared_memory.clone(),
); // state_rx,
// );
thread::spawn(move || { thread::spawn(move || {
cpu.reset().unwrap(); cpu.reset().unwrap();
cpu.memory.write(0x4400, 0b0000_0100);
cpu.execute() cpu.execute()
}); });
let stdout_lock = stdout.lock();
let renderer = TerminalRenderer::new(screen_memory, stdout_lock);
let mut screen = Screen::new(CpuController::new(cpu_tx.clone()), renderer);
// thread::spawn(move || {
// screen.run();
// });
loop { loop {
if event::poll(std::time::Duration::from_millis(16))? { if event::poll(std::time::Duration::from_millis(16))? {
if let event::Event::Key(key) = event::read()? { if let event::Event::Key(key) = event::read()? {
@ -138,11 +151,17 @@ fn main() -> Result<()> {
} }
} }
} }
let buffer = window_rx.recv().unwrap(); // let buffer = window_rx.recv().unwrap();
window.update_with_buffer(&buffer, 512, 380).unwrap(); screen.draw()
tui.update(&mut terminal)?; // tui.update(&mut terminal)?;
} }
stdout().execute(LeaveAlternateScreen)?;
execute!(
stdout,
LeaveAlternateScreen,
SetSize(cols, rows),
Clear(ClearType::Purge)
)?;
disable_raw_mode()?; disable_raw_mode()?;
Ok(()) Ok(())
} }

View File

@ -53,12 +53,18 @@ pub struct Mem {
pub data: Vec<u8>, pub data: Vec<u8>,
} }
impl Mem { impl Default for Mem {
pub fn new() -> Self { fn default() -> Self {
Self { Self {
data: vec![0; u16::MAX as usize + 1], data: vec![0; u16::MAX as usize + 1],
} }
} }
}
impl Mem {
pub fn new() -> Self {
Mem::default()
}
pub fn dump(&self, path: PathBuf) -> io::Result<()> { pub fn dump(&self, path: PathBuf) -> io::Result<()> {
let mut outfile = File::create(path)?; let mut outfile = File::create(path)?;
outfile.write_all(&self.data)?; outfile.write_all(&self.data)?;

894
src/opcodes.in Normal file
View File

@ -0,0 +1,894 @@
vec![
Instruction::Valid(ValidInstruction {
opcode: Opcode::BRK(AddressingMode::Implied),
cycles: 7,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ORA(AddressingMode::ZeroPageIndexedIndirect),
cycles: 6,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0x02 }),
Instruction::Invalid(InvalidInstruction { opcode: 0x03 }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::TSB(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ORA(AddressingMode::ZeroPage),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ASL(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::RMB0(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::PHP(AddressingMode::Stack),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ORA(AddressingMode::Immediate),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ASL(AddressingMode::Accumulator),
cycles: 2,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0x0b }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::TSB(AddressingMode::AbsoluteA),
cycles: 6,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ORA(AddressingMode::AbsoluteA),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ASL(AddressingMode::AbsoluteA),
cycles: 6,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BBR0(AddressingMode::ProgramCounterRelativeTest),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BPL(AddressingMode::ProgramCounterRelative),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ORA(AddressingMode::AbsoluteIndexedWithY),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ORA(AddressingMode::ZeroPageIndirect),
cycles: 5,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0x13 }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::TRB(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ORA(AddressingMode::ZeroPageIndexedWithX),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ASL(AddressingMode::ZeroPageIndexedWithX),
cycles: 6,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::RMB1(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::CLC(AddressingMode::Implied),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ORA(AddressingMode::AbsoluteIndexedWithY),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::INC(AddressingMode::Accumulator),
cycles: 2,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0x1b }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::TRB(AddressingMode::AbsoluteA),
cycles: 6,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ORA(AddressingMode::AbsoluteIndexedWithX),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ASL(AddressingMode::AbsoluteIndexedWithX),
cycles: 7,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BBR1(AddressingMode::ProgramCounterRelativeTest),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::JSR(AddressingMode::AbsoluteA),
cycles: 6,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::AND(AddressingMode::ZeroPageIndexedIndirect),
cycles: 6,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0x22 }),
Instruction::Invalid(InvalidInstruction { opcode: 0x23 }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BIT(AddressingMode::ZeroPage),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::AND(AddressingMode::ZeroPage),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ROL(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::RMB2(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::PLP(AddressingMode::Stack),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::AND(AddressingMode::Immediate),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ROL(AddressingMode::Accumulator),
cycles: 2,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0x2b }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BIT(AddressingMode::AbsoluteA),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::AND(AddressingMode::AbsoluteA),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ROL(AddressingMode::AbsoluteA),
cycles: 6,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BBR2(AddressingMode::ProgramCounterRelativeTest),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BMI(AddressingMode::ProgramCounterRelative),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::AND(AddressingMode::ZeroPageIndirectIndexedWithY),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::AND(AddressingMode::ZeroPageIndirect),
cycles: 5,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0x33 }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BIT(AddressingMode::ZeroPageIndexedWithX),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::AND(AddressingMode::ZeroPageIndexedWithX),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ROL(AddressingMode::ZeroPageIndexedWithX),
cycles: 6,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::RMB3(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::SEC(AddressingMode::Implied),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::AND(AddressingMode::AbsoluteIndexedWithY),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::DEC(AddressingMode::Accumulator),
cycles: 2,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0x3b }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BIT(AddressingMode::AbsoluteIndexedWithX),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::AND(AddressingMode::AbsoluteIndexedWithX),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ROL(AddressingMode::AbsoluteIndexedWithX),
cycles: 7,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BBR3(AddressingMode::ProgramCounterRelativeTest),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::RTI(AddressingMode::Implied),
cycles: 6,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::EOR(AddressingMode::ZeroPageIndexedIndirect),
cycles: 6,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0x42 }),
Instruction::Invalid(InvalidInstruction { opcode: 0x43 }),
Instruction::Invalid(InvalidInstruction { opcode: 0x44 }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::EOR(AddressingMode::ZeroPage),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LSR(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::RMB4(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::PHA(AddressingMode::Stack),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::EOR(AddressingMode::Immediate),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LSR(AddressingMode::Accumulator),
cycles: 2,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0x4b }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::JMP(AddressingMode::AbsoluteA),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::EOR(AddressingMode::AbsoluteA),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LSR(AddressingMode::AbsoluteA),
cycles: 6,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BBR4(AddressingMode::ProgramCounterRelativeTest),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BVC(AddressingMode::ProgramCounterRelative),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::EOR(AddressingMode::ZeroPageIndirectIndexedWithY),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::EOR(AddressingMode::ZeroPageIndirect),
cycles: 5,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0x53 }),
Instruction::Invalid(InvalidInstruction { opcode: 0x54 }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::EOR(AddressingMode::ZeroPageIndexedWithX),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LSR(AddressingMode::ZeroPageIndexedWithX),
cycles: 6,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::RMB5(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::CLI(AddressingMode::Implied),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::EOR(AddressingMode::AbsoluteIndexedWithY),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::PHY(AddressingMode::Stack),
cycles: 3,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0x5b }),
Instruction::Invalid(InvalidInstruction { opcode: 0x5c }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::EOR(AddressingMode::AbsoluteIndexedWithX),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LSR(AddressingMode::AbsoluteIndexedWithX),
cycles: 7,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BBR5(AddressingMode::ProgramCounterRelativeTest),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::RTS(AddressingMode::Stack),
cycles: 6,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ADC(AddressingMode::ZeroPageIndexedIndirect),
cycles: 6,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0x62 }),
Instruction::Invalid(InvalidInstruction { opcode: 0x63 }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::STZ(AddressingMode::ZeroPage),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ADC(AddressingMode::ZeroPage),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ROR(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::RMB6(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::PLA(AddressingMode::Stack),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ADC(AddressingMode::Immediate),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ROR(AddressingMode::Accumulator),
cycles: 2,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0x6b }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::JMP(AddressingMode::AbsoluteIndirect),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ADC(AddressingMode::AbsoluteA),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ROR(AddressingMode::AbsoluteA),
cycles: 6,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BBR6(AddressingMode::ProgramCounterRelativeTest),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BVS(AddressingMode::ProgramCounterRelative),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ADC(AddressingMode::ZeroPageIndirectIndexedWithY),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ADC(AddressingMode::ZeroPageIndirect),
cycles: 5,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0x73 }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::STZ(AddressingMode::ZeroPageIndexedWithX),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ADC(AddressingMode::ZeroPageIndexedWithX),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ROR(AddressingMode::ZeroPageIndexedWithX),
cycles: 6,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::RMB7(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::SEI(AddressingMode::Implied),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ADC(AddressingMode::AbsoluteIndexedWithY),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::PLY(AddressingMode::Stack),
cycles: 4,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0x7b }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::JMP(AddressingMode::AbsoluteIndexedIndirect),
cycles: 6,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ADC(AddressingMode::AbsoluteIndexedWithX),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::ROR(AddressingMode::AbsoluteIndexedWithX),
cycles: 7,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BBR7(AddressingMode::ProgramCounterRelativeTest),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BRA(AddressingMode::ProgramCounterRelative),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::STA(AddressingMode::ZeroPageIndexedIndirect),
cycles: 6,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0x82 }),
Instruction::Invalid(InvalidInstruction { opcode: 0x83 }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::STY(AddressingMode::ZeroPage),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::STA(AddressingMode::ZeroPage),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::STX(AddressingMode::ZeroPage),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::SMB0(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::DEY(AddressingMode::Implied),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BIT(AddressingMode::Immediate),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::TXA(AddressingMode::Implied),
cycles: 2,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0x8b }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::STY(AddressingMode::AbsoluteA),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::STA(AddressingMode::AbsoluteA),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::STX(AddressingMode::AbsoluteA),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BBS0(AddressingMode::ProgramCounterRelativeTest),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BCC(AddressingMode::ProgramCounterRelative),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::STA(AddressingMode::ZeroPageIndirectIndexedWithY),
cycles: 6,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::STA(AddressingMode::ZeroPageIndirect),
cycles: 5,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0x93 }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::STY(AddressingMode::ZeroPageIndexedWithX),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::STA(AddressingMode::ZeroPageIndexedWithX),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::STX(AddressingMode::ZeroPageIndexedWithY),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::SMB1(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::TYA(AddressingMode::Implied),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::STA(AddressingMode::AbsoluteIndexedWithY),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::TXS(AddressingMode::Implied),
cycles: 2,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0x9b }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::STZ(AddressingMode::AbsoluteA),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::STA(AddressingMode::AbsoluteIndexedWithX),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::STZ(AddressingMode::AbsoluteIndexedWithX),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BBS1(AddressingMode::ProgramCounterRelativeTest),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LDY(AddressingMode::Immediate),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LDA(AddressingMode::ZeroPageIndexedIndirect),
cycles: 6,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LDX(AddressingMode::Immediate),
cycles: 2,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0xa3 }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LDY(AddressingMode::ZeroPage),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LDA(AddressingMode::ZeroPage),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LDX(AddressingMode::ZeroPage),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::SMB2(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::TAY(AddressingMode::Implied),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LDA(AddressingMode::Immediate),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::TAX(AddressingMode::Implied),
cycles: 2,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0xab }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LDY(AddressingMode::AbsoluteA),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LDA(AddressingMode::AbsoluteA),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LDX(AddressingMode::AbsoluteA),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BBS2(AddressingMode::ProgramCounterRelativeTest),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BCS(AddressingMode::ProgramCounterRelative),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LDA(AddressingMode::ZeroPageIndirectIndexedWithY),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LDA(AddressingMode::ZeroPageIndirect),
cycles: 5, // Unsure, see https://cx16.dk/65c02/reference.html#LDA
}),
Instruction::Invalid(InvalidInstruction { opcode: 0xb3 }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LDY(AddressingMode::ZeroPageIndexedWithX),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LDA(AddressingMode::ZeroPageIndexedWithX),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LDX(AddressingMode::ZeroPageIndexedWithY),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::SMB3(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::CLV(AddressingMode::Implied),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LDA(AddressingMode::AbsoluteIndexedWithY),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::TSX(AddressingMode::Implied),
cycles: 2,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0xbb }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LDY(AddressingMode::AbsoluteIndexedWithX),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LDA(AddressingMode::AbsoluteIndexedWithX),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::LDX(AddressingMode::AbsoluteIndexedWithY),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BBS3(AddressingMode::ProgramCounterRelativeTest),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::CPY(AddressingMode::Immediate),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::CMP(AddressingMode::ZeroPageIndexedIndirect),
cycles: 6,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0xc2 }),
Instruction::Invalid(InvalidInstruction { opcode: 0xc3 }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::CPY(AddressingMode::ZeroPage),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::CMP(AddressingMode::ZeroPage),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::DEC(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::SMB4(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::INY(AddressingMode::Implied),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::CMP(AddressingMode::Immediate),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::DEX(AddressingMode::Implied),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::WAI(AddressingMode::Implied),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::CPY(AddressingMode::AbsoluteA),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::CMP(AddressingMode::AbsoluteA),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::DEC(AddressingMode::AbsoluteA),
cycles: 6,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BBS4(AddressingMode::ProgramCounterRelativeTest),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BNE(AddressingMode::ProgramCounterRelative),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::CMP(AddressingMode::ZeroPageIndirectIndexedWithY),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::CMP(AddressingMode::ZeroPageIndirect),
cycles: 5, // Unsure, look here: https://cx16.dk/65c02/reference.html#CMP
}),
Instruction::Invalid(InvalidInstruction { opcode: 0xd3 }),
Instruction::Invalid(InvalidInstruction { opcode: 0xd4 }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::CMP(AddressingMode::ZeroPageIndexedWithX),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::DEC(AddressingMode::ZeroPageIndexedWithX),
cycles: 6,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::SMB5(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::CLD(AddressingMode::Implied),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::CMP(AddressingMode::AbsoluteIndexedWithY),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::PHX(AddressingMode::Stack),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::STP(AddressingMode::Implied),
cycles: 3,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0xdc }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::CMP(AddressingMode::AbsoluteIndexedWithX),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::DEC(AddressingMode::AbsoluteIndexedWithX),
cycles: 7,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BBS5(AddressingMode::ProgramCounterRelativeTest),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::CPX(AddressingMode::Immediate),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::SBC(AddressingMode::ZeroPageIndexedIndirect),
cycles: 6,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0xe2 }),
Instruction::Invalid(InvalidInstruction { opcode: 0xe3 }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::CPX(AddressingMode::ZeroPage),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::SBC(AddressingMode::ZeroPage),
cycles: 3,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::INC(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::SMB6(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::INX(AddressingMode::Implied),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::SBC(AddressingMode::Immediate),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::NOP(AddressingMode::Implied),
cycles: 2,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0xeb }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::CPX(AddressingMode::AbsoluteA),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::SBC(AddressingMode::AbsoluteA),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::INC(AddressingMode::AbsoluteA),
cycles: 6,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BBS6(AddressingMode::ProgramCounterRelativeTest),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BEQ(AddressingMode::ProgramCounterRelative),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::SBC(AddressingMode::ZeroPageIndirectIndexedWithY),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::SBC(AddressingMode::ZeroPageIndirect),
cycles: 5,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0xf3 }),
Instruction::Invalid(InvalidInstruction { opcode: 0xf4 }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::SBC(AddressingMode::ZeroPageIndexedWithX),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::INC(AddressingMode::ZeroPageIndexedWithX),
cycles: 6,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::SMB7(AddressingMode::ZeroPage),
cycles: 5,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::SED(AddressingMode::Implied),
cycles: 2,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::SBC(AddressingMode::AbsoluteIndexedWithY),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::PLX(AddressingMode::Stack),
cycles: 4,
}),
Instruction::Invalid(InvalidInstruction { opcode: 0xfb }),
Instruction::Invalid(InvalidInstruction { opcode: 0xfc }),
Instruction::Valid(ValidInstruction {
opcode: Opcode::SBC(AddressingMode::AbsoluteIndexedWithX),
cycles: 4,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::INC(AddressingMode::AbsoluteIndexedWithX),
cycles: 7,
}),
Instruction::Valid(ValidInstruction {
opcode: Opcode::BBS7(AddressingMode::ProgramCounterRelativeTest),
cycles: 4,
}),
]

View File

@ -1,9 +1,22 @@
use crossterm::{
cursor::{MoveTo, SavePosition},
execute, queue,
style::{Color, PrintStyledContent, Stylize},
};
use crate::{ use crate::{
cpu::CpuController, cpu::CpuController,
memory::{MemHandle, MemoryReader}, memory::{self, MemHandle, MemoryReader},
types::{Byte, Word}, types::{Byte, Word},
}; };
use std::{fs::File, io::Read, path::Path, sync::mpsc::Sender, thread::sleep, time::Duration}; use std::{
fs::File,
io::{Read, Stdout, StdoutLock, Write},
path::Path,
sync::mpsc::Sender,
thread::sleep,
time::Duration,
};
const FG_COLOR: u32 = 0xFFCC00; const FG_COLOR: u32 = 0xFFCC00;
const BG_COLOR: u32 = 0x110500; const BG_COLOR: u32 = 0x110500;
@ -27,44 +40,37 @@ where
} }
} }
pub struct Crtc { trait Renderer {
memory: MemHandle, fn render(&mut self) {}
buffer: Vec<u32>, }
pub struct WindowRenderer {
char_rom: Vec<u8>, char_rom: Vec<u8>,
cpu_controller: CpuController,
window: Sender<Vec<u32>>, window: Sender<Vec<u32>>,
memory: MemHandle,
} }
impl MemoryReader for Crtc { impl WindowRenderer {
fn read(&self, address: Word) -> Byte { pub fn new<P>(memory: MemHandle, char_rom: Option<P>, window: Sender<Vec<u32>>) -> Self
self.memory.read(address)
}
}
impl Crtc {
pub fn new<P>(
memory: MemHandle,
char_rom: Option<P>,
cpu_controller: CpuController,
window: Sender<Vec<u32>>,
) -> Self
where where
P: AsRef<Path>, P: AsRef<Path>,
{ {
let char_rom = get_char_bin(char_rom); let char_rom = get_char_bin(char_rom);
Self { Self {
memory, memory,
buffer: vec![0; 512 * 380],
window, window,
char_rom, char_rom,
cpu_controller,
} }
} }
fn draw(&mut self) { }
impl Renderer for WindowRenderer {
fn render(&mut self) {
// the rest of this function is arcane wizardry // the rest of this function is arcane wizardry
// based on the specifics of george's weird // based on the specifics of george's weird
// display and characters... don't fuck around w it // display and characters... don't fuck around w it
let mut i = 0; let mut i = 0;
let mut buffer = vec![0; 512 * 380];
for char_row in 0..29 { for char_row in 0..29 {
for char_col in 0..64 { for char_col in 0..64 {
let ascii = self.memory.read(0x6000 + i); let ascii = self.memory.read(0x6000 + i);
@ -75,23 +81,114 @@ impl Crtc {
let buffer_index = let buffer_index =
((char_row) * 13 + (row)) * 512 + (char_col * 8 + bit_index); ((char_row) * 13 + (row)) * 512 + (char_col * 8 + bit_index);
if (byte << bit_index) & 0x80 == 0x80 { if (byte << bit_index) & 0x80 == 0x80 {
self.buffer[buffer_index] = FG_COLOR; buffer[buffer_index] = FG_COLOR;
} else { } else {
self.buffer[buffer_index] = BG_COLOR; buffer[buffer_index] = BG_COLOR;
} }
} }
} }
} }
let _ = self.window.send(buffer.clone());
} }
}
}
let buffer = self.buffer.to_owned(); impl MemoryReader for WindowRenderer {
fn read(&self, address: Word) -> Byte {
self.memory.read(address)
}
}
let _ = self.window.send(buffer); pub struct TerminalRenderer<'a> {
memory: MemHandle,
// stdout: Stdout,
stdout: StdoutLock<'a>,
}
impl<'a> TerminalRenderer<'a> {
pub fn new(memory: MemHandle, stdout: StdoutLock<'a>) -> Self {
Self { memory, stdout }
}
}
impl MemoryReader for TerminalRenderer<'_> {
fn read(&self, address: Word) -> Byte {
self.memory.read(address)
}
}
static ASCII_LOOPUP: [&str; 256] = [
" ", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "奔", "", "", "", "", "", "", " ", "!", "\"", "#",
"$", "%", "&", "\'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6",
"7", "8", "9", ":", ";", "<", "=", ">", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I",
"J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\",
"]", "^", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
"p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "ʕ", "·", "", "ʔ", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "🔮", "", "",
"", "", "🌑", "🌒", "🌓", "🌔", "🌕", "🌖", "🌗", "🌘", "", "", "", "", "", "", "",
"", "", "", "", "🎁", "", "", "", "", "", "", "", "", "",
];
impl Renderer for TerminalRenderer<'_> {
fn render(&mut self) {
let _ = execute!(self.stdout, SavePosition);
let mut i = 0;
for char_row in 0..29 {
for char_col in 0..64 {
let ascii = self.memory.read(0x6000 + i);
i += 1;
let char = ASCII_LOOPUP[ascii as usize];
let _ = queue!(
// FG_COLOR = 0xFFCC00
// BG_COLOR = 0x110500
self.stdout,
MoveTo(char_col, char_row),
PrintStyledContent(
char.with(Color::Rgb {
r: 0xFF,
g: 0xCC,
b: 0x00
})
.on(Color::Rgb {
r: 0x11,
g: 0x05,
b: 0x00
})
)
);
}
}
let _ = self.stdout.flush();
}
}
pub struct Screen<'a> {
cpu_controller: CpuController,
// renderer: Box<dyn Renderer>,
renderer: TerminalRenderer<'a>,
}
impl<'a> Screen<'a> {
// pub fn new(cpu_controller: CpuController, renderer: Box<dyn Renderer>) -> Self {
pub fn new(cpu_controller: CpuController, renderer: TerminalRenderer<'a>) -> Self {
Self {
cpu_controller,
renderer,
}
}
pub fn draw(&mut self) {
self.renderer.render();
} }
pub fn run(&mut self) { pub fn run(&mut self) {
loop { loop {
let _ = self.cpu_controller.irq(); self.cpu_controller.irq();
sleep(Duration::from_millis(16)); sleep(Duration::from_millis(16));
self.draw(); self.draw();
} }