cleaned up instructions, using termion now but is kinda broken, might switch back to crossterm

This commit is contained in:
2024-07-04 13:04:13 -04:00
parent ac4619406d
commit fb4fae430b
9 changed files with 2789 additions and 2045 deletions
+104 -111
View File
@@ -1,9 +1,8 @@
use crate::instructions::{get_instruction, Instruction};
use crate::memory::{MemHandle, MemoryReader, MemoryWriter};
use crate::types::{Byte, Word};
use std::fmt::Display;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread::{sleep, LocalKey};
use std::thread::sleep;
use std::time::Duration;
use anyhow::Result;
@@ -58,30 +57,18 @@ impl CpuReceiver {
}
}
pub struct CpuState {
pub a: Byte, // Accumulator Register
pub x: Byte, // X Register
pub y: Byte, // Y Register
pub pc: Word, // Program Counter
pub s: Byte, // Stack Pointer
pub p: Byte, // Status Register
pub irq: bool,
pub nmi: bool,
}
// #[derive(Clone)]
pub struct Cpu {
pub a: Byte, // Accumulator Register
pub x: Byte, // X Register
pub y: Byte, // Y Register
pub pc: Word, // Program Counter
pub s: Byte, // Stack Pointer
pub p: Byte, // Status Register
pub a: u8, // Accumulator Register
pub x: u8, // X Register
pub y: u8, // Y Register
pub pc: u16, // Program Counter
pub s: u8, // Stack Pointer
pub p: u8, // Status Register
pub irq: bool,
pub nmi: bool,
pub memory: MemHandle,
pub pending_cycles: usize,
receiver: CpuReceiver,
receiver: Option<CpuReceiver>,
stopped: bool,
// cycle_count: usize,
// state_tx: Sender<CpuState>,
@@ -94,18 +81,18 @@ impl Display for Cpu {
}
impl MemoryReader for Cpu {
fn read(&self, address: Word) -> Byte {
fn read(&self, address: u16) -> u8 {
self.memory.read(address)
}
}
impl MemoryWriter for Cpu {
fn write(&self, address: Word, data: Byte) {
fn write(&self, address: u16, data: u8) {
self.memory.write(address, data);
}
}
impl Cpu {
pub fn new(memory: MemHandle, receiver: CpuReceiver) -> Self {
pub fn new(memory: MemHandle) -> Self {
// pub fn new(memory: MemHandle) -> Self {
Cpu {
a: 0x00,
@@ -116,7 +103,7 @@ impl Cpu {
p: 0b0010_0100,
irq: false,
nmi: false,
receiver,
receiver: None,
memory,
stopped: false,
pending_cycles: 0,
@@ -124,78 +111,78 @@ impl Cpu {
// state_tx,
}
}
pub fn with_receiver(mut self, receiver: CpuReceiver) -> Self {
self.receiver = Some(receiver);
self
}
pub fn new_with_control(memory: MemHandle) -> (Self, CpuController) {
let (tx, rx) = channel::<CpuControl>();
let controller = CpuController(tx);
let receiver = CpuReceiver(rx);
let cpu = Cpu::new(memory, receiver);
let cpu = Cpu::new(memory).with_receiver(receiver);
(cpu, controller)
}
pub fn reset(&mut self) -> Result<()> {
let reset_vector_pointer = self.read_word(0xFFFC)?;
pub fn reset(&mut self) {
let reset_vector_pointer = self.read_word(0xFFFC);
self.pc = reset_vector_pointer;
self.pending_cycles = 0;
Ok(())
}
pub fn read_word(&self, address: Word) -> Result<Word> {
pub fn read_word(&self, address: u16) -> u16 {
let low_byte = self.read(address);
let high_byte = self.read(address + 0x1);
Ok((high_byte as u16) << 8 | (low_byte as u16))
let high_byte = self.read(address.wrapping_add(0x1));
(high_byte as u16) << 8 | (low_byte as u16)
}
fn stack_addr(&self) -> Word {
fn stack_addr(&self) -> u16 {
// Dunno if this is necessary, i just don't like adding the 0x0100 every time
0x0100 + self.s as u16
}
pub fn push_stack(&mut self, data: Byte) -> Result<()> {
pub fn push_stack(&mut self, data: u8) {
self.s = self.s.wrapping_sub(0x1);
self.write(self.stack_addr(), data);
Ok(())
}
pub fn push_stack_word(&mut self, address: Word) -> Result<()> {
pub fn push_stack_word(&mut self, address: u16) {
self.s = self.s.wrapping_sub(0x1);
self.write(self.stack_addr(), address.to_le_bytes()[1]); // Upper byte first
self.s = self.s.wrapping_sub(0x1);
self.write(self.stack_addr(), address.to_le_bytes()[0]); // Lower byte second
Ok(())
}
pub fn pop_stack(&mut self) -> Result<Byte> {
pub fn pop_stack(&mut self) -> u8 {
let byte = self.read(self.stack_addr());
self.s = self.s.wrapping_add(0x1);
Ok(byte)
byte
}
pub fn pop_stack_word(&mut self) -> Result<Word> {
let low_byte = self.pop_stack()?;
let high_byte = self.pop_stack()?;
let word = ((high_byte as Word) << 8) + low_byte as u16;
Ok(word)
pub fn pop_stack_word(&mut self) -> u16 {
let low_byte = self.pop_stack();
let high_byte = self.pop_stack();
((high_byte as u16) << 8) + low_byte as u16
}
pub fn set_flag(&mut self, flag: StatusFlag, value: bool) {
self.p &= !(flag as Byte);
self.p &= !(flag as u8);
if value {
self.p |= flag as Byte
self.p |= flag as u8
}
}
pub fn get_flag(&self, flag: StatusFlag) -> bool {
(self.p & flag as Byte) > 0
(self.p & flag as u8) > 0
}
pub fn is_negative(&self, value: Byte) -> bool {
pub fn is_negative(&self, value: u8) -> bool {
value & 0b1000_0000 == 0b1000_0000
}
pub fn execute(&mut self) {
self.cycle();
while self.pending_cycles != 0 {
self.cycle();
}
}
// pub fn execute(&mut self) {
// self.cycle();
// while self.pending_cycles != 0 {
// self.cycle();
// }
// }
pub fn wait_for_interrupt(&self) {
unimplemented!()
@@ -203,36 +190,41 @@ impl Cpu {
pub fn interrupt(&mut self) {
self.irq = false;
self.push_stack_word(self.pc).unwrap();
self.push_stack(self.p).unwrap();
self.push_stack_word(self.pc);
self.push_stack(self.p);
self.set_flag(StatusFlag::IrqDisable, true);
self.pc = self.read_word(0xFFFE).unwrap();
self.pc = self.read_word(0xFFFE);
}
fn receive_control(&mut self) {
let control = match self.receiver.0.try_recv() {
Ok(control) => control,
Err(_error) => return, // most of the time we won't have any impending control
// messages, just return if that's the case
};
match control {
CpuControl::Nmi => self.nmi = true,
CpuControl::Irq => self.irq = true,
CpuControl::Stop => self.stopped = true,
CpuControl::Resume => self.stopped = false,
CpuControl::Data => {} // self
// .state_tx
// .send(CpuState {
// a: self.a.clone(), // Accumulator Register
// x: self.x.clone(), // X Register
// y: self.y.clone(), // Y Register
// pc: self.pc.clone(), // Program Counter
// s: self.s.clone(), // Stack Pointer
// p: self.p.clone(), // Status Register
// irq: self.irq.clone(),
// nmi: self.nmi.clone(),
// })
// .unwrap(),
match &self.receiver {
Some(receiver) => {
let control = match receiver.0.try_recv() {
Ok(control) => control,
Err(_error) => return, // most of the time we won't have any impending control
// messages, just return if that's the case
};
match control {
CpuControl::Nmi => self.nmi = true,
CpuControl::Irq => self.irq = true,
CpuControl::Stop => self.stopped = true,
CpuControl::Resume => self.stopped = false,
CpuControl::Data => {} // self
// .state_tx
// .send(CpuState {
// a: self.a.clone(), // Accumulator Register
// x: self.x.clone(), // X Register
// y: self.y.clone(), // Y Register
// pc: self.pc.clone(), // Program Counter
// s: self.s.clone(), // Stack Pointer
// p: self.p.clone(), // Status Register
// irq: self.irq.clone(),
// nmi: self.nmi.clone(),
// })
// .unwrap(),
}
}
None => {}
}
}
@@ -251,37 +243,38 @@ impl Cpu {
}
let opcode = self.read(self.pc);
let instruction = get_instruction(opcode);
match instruction {
Instruction::Valid(valid_instruction) => {
// println!("a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", a = self.a, x = self.x, y = self.y, pc = self.pc, s = self.s, p = self.p, irq = self.irq, nmi = self.nmi);
// println!(
// "Instruction: {:?}, {:#04x}",
// valid_instruction.opcode, opcode
// );
// println!("");
self.pc += 1;
match valid_instruction.opcode.call(self) {
Ok(_) => {
self.pending_cycles += valid_instruction.cycles as usize;
}
Err(_) => {
println!("An IncompatibleAddrMode was used at address {:#06x} for instruction {:?}", self.pc, valid_instruction);
}
};
}
Instruction::Invalid(invalid_instruction) => match invalid_instruction.opcode {
0x02 => {
// println!("a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", a = self.a, x = self.x, y = self.y, pc = self.pc, s = self.s, p = self.p, irq = self.irq.try_recv().unwrap_or_default(), nmi = self.nmi);
&self.memory.dump();
}
_ => {
println!(
"An invalid instruction with opcode {:#04x} was called at address {:#06x}",
invalid_instruction.opcode, self.pc
);
}
},
}
instruction.call(self);
// match instruction {
// Instruction::Valid(valid_instruction) => {
// // println!("a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", a = self.a, x = self.x, y = self.y, pc = self.pc, s = self.s, p = self.p, irq = self.irq, nmi = self.nmi);
// // println!(
// // "Instruction: {:?}, {:#04x}",
// // valid_instruction.opcode, opcode
// // );
// // println!("");
// self.pc += 1;
// match valid_instruction.opcode.call(self) {
// Ok(_) => {
// self.pending_cycles += valid_instruction.cycles as usize;
// }
// Err(_) => {
// println!("An IncompatibleAddrMode was used at address {:#06x} for instruction {:?}", self.pc, valid_instruction);
// }
// };
// }
// Instruction::Invalid(invalid_instruction) => match invalid_instruction.opcode {
// 0x02 => {
// // println!("a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", a = self.a, x = self.x, y = self.y, pc = self.pc, s = self.s, p = self.p, irq = self.irq.try_recv().unwrap_or_default(), nmi = self.nmi);
// let _ = &self.memory.dump();
// }
// _ => {
// println!(
// "An invalid instruction with opcode {:#04x} was called at address {:#06x}",
// invalid_instruction.opcode, self.pc
// );
// }
// },
// }
// self.cycle_count += 1;
}
pub fn stop(&mut self) {
+2150 -1529
View File
File diff suppressed because it is too large Load Diff
+460 -121
View File
@@ -1,5 +1,10 @@
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use minifb::{InputCallback, Key};
use std::io::{self, stdin, Read};
// use minifb::{InputCallback, Key};
use termion::{
event::Key,
input::{Keys, TermRead},
};
use crate::memory::{MemHandle, MemoryWriter};
@@ -7,74 +12,405 @@ pub struct Keyboard {
memory: MemHandle,
}
struct PlainKeys<R> {
iter: Keys<R>,
}
impl<R: Read> Iterator for PlainKeys<R> {
type Item = Result<char, io::Error>;
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.iter.next() {
Some(Ok(key)) => match key {
Key::Ctrl(char) => return Some(Ok(char)),
Key::Alt(char) => return Some(Ok(char)),
Key::Char('A') => return Some(Ok('a')),
Key::Char('B') => return Some(Ok('b')),
Key::Char('C') => return Some(Ok('c')),
Key::Char('D') => return Some(Ok('d')),
Key::Char('E') => return Some(Ok('e')),
Key::Char('F') => return Some(Ok('f')),
Key::Char('G') => return Some(Ok('g')),
Key::Char('H') => return Some(Ok('h')),
Key::Char('I') => return Some(Ok('i')),
Key::Char('J') => return Some(Ok('j')),
Key::Char('K') => return Some(Ok('k')),
Key::Char('L') => return Some(Ok('l')),
Key::Char('M') => return Some(Ok('m')),
Key::Char('N') => return Some(Ok('n')),
Key::Char('O') => return Some(Ok('o')),
Key::Char('P') => return Some(Ok('p')),
Key::Char('Q') => return Some(Ok('q')),
Key::Char('R') => return Some(Ok('r')),
Key::Char('S') => return Some(Ok('s')),
Key::Char('T') => return Some(Ok('t')),
Key::Char('U') => return Some(Ok('u')),
Key::Char('V') => return Some(Ok('v')),
Key::Char('W') => return Some(Ok('w')),
Key::Char('X') => return Some(Ok('x')),
Key::Char('Y') => return Some(Ok('y')),
Key::Char('Z') => return Some(Ok('z')),
Key::Char('!') => return Some(Ok('1')),
Key::Char('@') => return Some(Ok('2')),
Key::Char('#') => return Some(Ok('3')),
Key::Char('$') => return Some(Ok('4')),
Key::Char('%') => return Some(Ok('5')),
Key::Char('^') => return Some(Ok('6')),
Key::Char('&') => return Some(Ok('7')),
Key::Char('*') => return Some(Ok('8')),
Key::Char('(') => return Some(Ok('9')),
Key::Char(')') => return Some(Ok('0')),
Key::Char('~') => return Some(Ok('`')),
Key::Char('_') => return Some(Ok('-')),
Key::Char('+') => return Some(Ok('=')),
Key::Char('|') => return Some(Ok('\\')),
Key::Char('}') => return Some(Ok(']')),
Key::Char('{') => return Some(Ok('[')),
Key::Char('"') => return Some(Ok('\'')),
Key::Char(':') => return Some(Ok(';')),
Key::Char('?') => return Some(Ok('/')),
Key::Char('>') => return Some(Ok('.')),
Key::Char('<') => return Some(Ok(',')),
Key::Char(char) => return Some(Ok(char)),
_ => continue,
},
Some(Err(e)) => return Some(Err(e)),
None => return None,
}
}
}
}
#[derive(Clone, Copy, Debug, Ord, Eq, PartialEq, PartialOrd)]
enum ControlKey {
Alt,
Shift,
Ctrl,
Left,
Right,
Up,
Down,
Esc,
Enter,
Home,
End,
Tab,
Backspace,
Delete,
Insert,
PageDown,
PageUp,
}
struct ControlKeys<R> {
iter: Keys<R>,
extra: Option<ControlKey>,
}
impl<R: Read> Iterator for ControlKeys<R> {
type Item = Result<ControlKey, io::Error>;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(key) = self.extra {
return Some(Ok(key));
}
match self.iter.next() {
Some(Ok(key)) => match key {
Key::Ctrl(char) => match char {
'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' | '!' | '@' | '#' | '$' | '%' | '^' | '&' | '*' | '(' | ')'
| '~' | '_' | '+' | '|' | '}' | '{' | '"' | ':' | '?' | '>' | '<' => {
self.extra = Some(ControlKey::Shift);
return Some(Ok(ControlKey::Ctrl));
}
_ => return Some(Ok(ControlKey::Ctrl)),
},
Key::CtrlUp => {
self.extra = Some(ControlKey::Ctrl);
return Some(Ok(ControlKey::Up));
}
Key::CtrlDown => {
self.extra = Some(ControlKey::Ctrl);
return Some(Ok(ControlKey::Down));
}
Key::CtrlRight => {
self.extra = Some(ControlKey::Ctrl);
return Some(Ok(ControlKey::Right));
}
Key::CtrlLeft => {
self.extra = Some(ControlKey::Ctrl);
return Some(Ok(ControlKey::Left));
}
Key::CtrlEnd => {
self.extra = Some(ControlKey::Ctrl);
return Some(Ok(ControlKey::End));
}
Key::CtrlHome => {
self.extra = Some(ControlKey::Ctrl);
return Some(Ok(ControlKey::Home));
}
Key::Alt(char) => match char {
'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' | '!' | '@' | '#' | '$' | '%' | '^' | '&' | '*' | '(' | ')'
| '~' | '_' | '+' | '|' | '}' | '{' | '"' | ':' | '?' | '>' | '<' => {
self.extra = Some(ControlKey::Shift);
return Some(Ok(ControlKey::Alt));
}
_ => return Some(Ok(ControlKey::Alt)),
},
Key::AltUp => {
self.extra = Some(ControlKey::Alt);
return Some(Ok(ControlKey::Up));
}
Key::AltDown => {
self.extra = Some(ControlKey::Alt);
return Some(Ok(ControlKey::Down));
}
Key::AltRight => {
self.extra = Some(ControlKey::Alt);
return Some(Ok(ControlKey::Right));
}
Key::AltLeft => {
self.extra = Some(ControlKey::Alt);
return Some(Ok(ControlKey::Left));
}
Key::Char('A')
| Key::Char('B')
| Key::Char('C')
| Key::Char('D')
| Key::Char('E')
| Key::Char('F')
| Key::Char('G')
| Key::Char('H')
| Key::Char('I')
| Key::Char('J')
| Key::Char('K')
| Key::Char('L')
| Key::Char('M')
| Key::Char('N')
| Key::Char('O')
| Key::Char('P')
| Key::Char('Q')
| Key::Char('R')
| Key::Char('S')
| Key::Char('T')
| Key::Char('U')
| Key::Char('V')
| Key::Char('W')
| Key::Char('X')
| Key::Char('Y')
| Key::Char('Z')
| Key::Char('!')
| Key::Char('@')
| Key::Char('#')
| Key::Char('$')
| Key::Char('%')
| Key::Char('^')
| Key::Char('&')
| Key::Char('*')
| Key::Char('(')
| Key::Char(')')
| Key::Char('~')
| Key::Char('_')
| Key::Char('+')
| Key::Char('|')
| Key::Char('}')
| Key::Char('{')
| Key::Char('"')
| Key::Char(':')
| Key::Char('?')
| Key::Char('>')
| Key::Char('<') => return Some(Ok(ControlKey::Shift)),
Key::ShiftUp => {
self.extra = Some(ControlKey::Shift);
return Some(Ok(ControlKey::Up));
}
Key::ShiftDown => {
self.extra = Some(ControlKey::Shift);
return Some(Ok(ControlKey::Down));
}
Key::ShiftRight => {
self.extra = Some(ControlKey::Shift);
return Some(Ok(ControlKey::Right));
}
Key::ShiftLeft => {
self.extra = Some(ControlKey::Shift);
return Some(Ok(ControlKey::Left));
}
Key::Backspace => return Some(Ok(ControlKey::Backspace)),
Key::Up => return Some(Ok(ControlKey::Up)),
Key::Down => return Some(Ok(ControlKey::Down)),
Key::Right => return Some(Ok(ControlKey::Right)),
Key::Left => return Some(Ok(ControlKey::Left)),
Key::Home => return Some(Ok(ControlKey::Home)),
Key::End => return Some(Ok(ControlKey::End)),
Key::PageUp => return Some(Ok(ControlKey::PageUp)),
Key::PageDown => return Some(Ok(ControlKey::PageDown)),
Key::Insert => return Some(Ok(ControlKey::Insert)),
Key::Delete => return Some(Ok(ControlKey::Delete)),
_ => continue,
},
Some(Err(e)) => return Some(Err(e)),
None => return None,
}
}
}
}
trait GetKeys {
fn get_plain(self) -> PlainKeys<Self>
where
Self: Sized;
fn get_modifiers(self) -> ControlKeys<Self>
where
Self: Sized;
}
impl<R: Read + TermRead> GetKeys for R {
fn get_plain(self) -> PlainKeys<Self>
where
Self: Sized,
{
PlainKeys { iter: self.keys() }
}
fn get_modifiers(self) -> ControlKeys<Self>
where
Self: Sized,
{
ControlKeys {
iter: self.keys(),
extra: None,
}
}
}
impl Keyboard {
pub fn new(memory: MemHandle) -> Self {
Self { memory }
}
pub fn read_keys(&self, key: KeyEvent) {
pub fn clear_keys(&self) {
self.memory.write(0x4400, 0x00);
self.memory.write(0x4401, 0x00);
self.memory.write(0x4402, 0x00);
self.memory.write(0x4403, 0x00);
self.memory.write(0x4404, 0x00);
self.memory.write(0x4405, 0x00);
}
// pub fn read_keys(&self, key: KeyEvent) {
pub fn read_keys(&self) {
let mut row0 = 0;
let mut row1 = 0;
let mut row2 = 0;
let mut row3 = 0;
let mut row4 = 0;
let mut row5 = 0;
match key.modifiers {
KeyModifiers::SHIFT => row2 ^= 0b1000_0000,
KeyModifiers::CONTROL => row3 ^= 0b1000_0000,
KeyModifiers::ALT => row4 ^= 0b1000_0000,
KeyModifiers::META => row5 ^= 0b1000_0000,
KeyModifiers::SUPER => row5 ^= 0b0010_0000,
_ => {}
};
match key.code {
KeyCode::Esc => row0 ^= 0b1000_0000,
KeyCode::Char('w') => row0 ^= 0b0100_0000,
KeyCode::Char('e') => row0 ^= 0b0010_0000,
KeyCode::Char('r') => row0 ^= 0b0001_0000,
KeyCode::Char('t') => row0 ^= 0b0000_1000,
KeyCode::Char('u') => row0 ^= 0b0000_0100,
KeyCode::Char('o') => row0 ^= 0b0000_0010,
KeyCode::Backspace => row0 ^= 0b0000_0001,
KeyCode::Tab => row1 ^= 0b1000_0000,
KeyCode::Char('q') => row1 ^= 0b0100_0000,
KeyCode::Char('s') => row1 ^= 0b0010_0000,
KeyCode::Char('g') => row1 ^= 0b0001_0000,
KeyCode::Char('y') => row1 ^= 0b0000_1000,
KeyCode::Char('i') => row1 ^= 0b0000_0100,
KeyCode::Char('p') => row1 ^= 0b0000_0010,
KeyCode::Enter => row1 ^= 0b0000_0001,
KeyCode::Char('d') => row2 ^= 0b0100_0000,
KeyCode::Char('v') => row2 ^= 0b0010_0000,
KeyCode::Char('h') => row2 ^= 0b0001_0000,
KeyCode::Char('k') => row2 ^= 0b0000_1000,
KeyCode::Char('\'') => row2 ^= 0b0000_0100,
KeyCode::Char('/') => row2 ^= 0b0000_0010,
KeyCode::Char('a') => row2 ^= 0b0000_0001,
KeyCode::Char('z') => row3 ^= 0b0100_0000,
KeyCode::Char('f') => row3 ^= 0b0010_0000,
KeyCode::Char('b') => row3 ^= 0b0001_0000,
KeyCode::Char('j') => row3 ^= 0b0000_1000,
KeyCode::Char('l') => row3 ^= 0b0000_0100,
KeyCode::Char('2') => row3 ^= 0b0000_0010,
KeyCode::Char('4') => row3 ^= 0b0000_0001,
KeyCode::Char('x') => row4 ^= 0b0100_0000,
KeyCode::Char('c') => row4 ^= 0b0010_0000,
KeyCode::Char('n') => row4 ^= 0b0001_0000,
KeyCode::Char('m') => row4 ^= 0b0000_1000,
KeyCode::Char(',') => row4 ^= 0b0000_0100,
KeyCode::Char('1') => row4 ^= 0b0000_0010,
KeyCode::Char('3') => row4 ^= 0b0000_0001,
KeyCode::Char(' ') => row5 ^= 0b0100_0000,
_ => {
row0 = 0;
row1 = 0;
row2 = 0;
row3 = 0;
row4 = 0;
row5 = 0;
let modifiers = termion::async_stdin().get_modifiers();
for m in modifiers {
match m.unwrap() {
ControlKey::Shift => row2 ^= 0b1000_0000,
ControlKey::Ctrl => row3 ^= 0b1000_0000,
ControlKey::Alt => row4 ^= 0b1000_0000,
ControlKey::Esc => row0 ^= 0b1000_0000,
ControlKey::Backspace => row0 ^= 0b0000_0001,
ControlKey::Tab => row1 ^= 0b1000_0000,
ControlKey::Enter => row1 ^= 0b0000_0001,
_ => {}
}
};
}
let keys = termion::async_stdin().get_plain();
for k in keys {
match k.unwrap() {
'w' => row0 ^= 0b0100_0000,
'e' => row0 ^= 0b0010_0000,
'r' => row0 ^= 0b0001_0000,
't' => row0 ^= 0b0000_1000,
'u' => row0 ^= 0b0000_0100,
'o' => row0 ^= 0b0000_0010,
'q' => row1 ^= 0b0100_0000,
's' => row1 ^= 0b0010_0000,
'g' => row1 ^= 0b0001_0000,
'y' => row1 ^= 0b0000_1000,
'i' => row1 ^= 0b0000_0100,
'p' => row1 ^= 0b0000_0010,
'd' => row2 ^= 0b0100_0000,
'v' => row2 ^= 0b0010_0000,
'h' => row2 ^= 0b0001_0000,
'k' => row2 ^= 0b0000_1000,
'\\' => row2 ^= 0b0000_0100,
'/' => row2 ^= 0b0000_0010,
'a' => row2 ^= 0b0000_0001,
'z' => row3 ^= 0b0100_0000,
'f' => row3 ^= 0b0010_0000,
'b' => row3 ^= 0b0001_0000,
'j' => row3 ^= 0b0000_1000,
'l' => row3 ^= 0b0000_0100,
'2' => row3 ^= 0b0000_0010,
'4' => row3 ^= 0b0000_0001,
'x' => row4 ^= 0b0100_0000,
'c' => row4 ^= 0b0010_0000,
'n' => row4 ^= 0b0001_0000,
'm' => row4 ^= 0b0000_1000,
',' => row4 ^= 0b0000_0100,
'1' => row4 ^= 0b0000_0010,
'3' => row4 ^= 0b0000_0001,
' ' => row5 ^= 0b0100_0000,
_ => {}
}
}
// match key.code {
// KeyCode::Esc => row0 ^= 0b1000_0000,
// KeyCode::Char('w') => row0 ^= 0b0100_0000,
// KeyCode::Char('e') => row0 ^= 0b0010_0000,
// KeyCode::Char('r') => row0 ^= 0b0001_0000,
// KeyCode::Char('t') => row0 ^= 0b0000_1000,
// KeyCode::Char('u') => row0 ^= 0b0000_0100,
// KeyCode::Char('o') => row0 ^= 0b0000_0010,
// KeyCode::Backspace => row0 ^= 0b0000_0001,
// KeyCode::Tab => row1 ^= 0b1000_0000,
// KeyCode::Char('q') => row1 ^= 0b0100_0000,
// KeyCode::Char('s') => row1 ^= 0b0010_0000,
// KeyCode::Char('g') => row1 ^= 0b0001_0000,
// KeyCode::Char('y') => row1 ^= 0b0000_1000,
// KeyCode::Char('i') => row1 ^= 0b0000_0100,
// KeyCode::Char('p') => row1 ^= 0b0000_0010,
// KeyCode::Enter => row1 ^= 0b0000_0001,
// KeyCode::Char('d') => row2 ^= 0b0100_0000,
// KeyCode::Char('v') => row2 ^= 0b0010_0000,
// KeyCode::Char('h') => row2 ^= 0b0001_0000,
// KeyCode::Char('k') => row2 ^= 0b0000_1000,
// KeyCode::Char('\'') => row2 ^= 0b0000_0100,
// KeyCode::Char('/') => row2 ^= 0b0000_0010,
// KeyCode::Char('a') => row2 ^= 0b0000_0001,
// KeyCode::Char('z') => row3 ^= 0b0100_0000,
// KeyCode::Char('f') => row3 ^= 0b0010_0000,
// KeyCode::Char('b') => row3 ^= 0b0001_0000,
// KeyCode::Char('j') => row3 ^= 0b0000_1000,
// KeyCode::Char('l') => row3 ^= 0b0000_0100,
// KeyCode::Char('2') => row3 ^= 0b0000_0010,
// KeyCode::Char('4') => row3 ^= 0b0000_0001,
// KeyCode::Char('x') => row4 ^= 0b0100_0000,
// KeyCode::Char('c') => row4 ^= 0b0010_0000,
// KeyCode::Char('n') => row4 ^= 0b0001_0000,
// KeyCode::Char('m') => row4 ^= 0b0000_1000,
// KeyCode::Char(',') => row4 ^= 0b0000_0100,
// KeyCode::Char('1') => row4 ^= 0b0000_0010,
// KeyCode::Char('3') => row4 ^= 0b0000_0001,
// KeyCode::Char(' ') => row5 ^= 0b0100_0000,
// _ => {
// row0 = 0;
// row1 = 0;
// row2 = 0;
// row3 = 0;
// row4 = 0;
// row5 = 0;
// }
// };
self.memory.write(0x4400, row0);
self.memory.write(0x4401, row1);
@@ -87,72 +423,75 @@ impl Keyboard {
impl MemoryWriter for Keyboard {
fn write(&self, address: u16, data: u8) {
if data != 0x00 {
println!("wrote {:02x} to address {:04x}", data, address);
}
self.memory.write(address, data);
}
}
impl InputCallback for Keyboard {
fn add_char(&mut self, _uni_char: u32) {}
fn set_key_state(&mut self, key: Key, _state: bool) {
let mut row0 = 0;
let mut row1 = 0;
let mut row2 = 0;
let mut row3 = 0;
let mut row4 = 0;
let mut row5 = 0;
// impl InputCallback for Keyboard {
// fn add_char(&mut self, _uni_char: u32) {}
// fn set_key_state(&mut self, key: Key, _state: bool) {
// let mut row0 = 0;
// let mut row1 = 0;
// let mut row2 = 0;
// let mut row3 = 0;
// let mut row4 = 0;
// let mut row5 = 0;
match key {
Key::Escape => row0 ^= 0b1000_0000,
Key::W => row0 ^= 0b0100_0000,
Key::E => row0 ^= 0b0010_0000,
Key::R => row0 ^= 0b0001_0000,
Key::T => row0 ^= 0b0000_1000,
Key::U => row0 ^= 0b0000_0100,
Key::O => row0 ^= 0b0000_0010,
Key::Backspace => row0 ^= 0b0000_0001,
Key::Tab => row1 ^= 0b1000_0000,
Key::Q => row1 ^= 0b0100_0000,
Key::S => row1 ^= 0b0010_0000,
Key::G => row1 ^= 0b0001_0000,
Key::Y => row1 ^= 0b0000_1000,
Key::I => row1 ^= 0b0000_0100,
Key::P => row1 ^= 0b0000_0010,
Key::Enter => row1 ^= 0b0000_0001,
Key::LeftShift | Key::RightShift => row2 ^= 0b1000_0000,
Key::D => row2 ^= 0b0100_0000,
Key::V => row2 ^= 0b0010_0000,
Key::H => row2 ^= 0b0001_0000,
Key::K => row2 ^= 0b0000_1000,
Key::Apostrophe => row2 ^= 0b0000_0100,
Key::Slash => row2 ^= 0b0000_0010,
Key::A => row2 ^= 0b0000_0001,
Key::LeftCtrl | Key::RightCtrl => row3 ^= 0b1000_0000,
Key::Z => row3 ^= 0b0100_0000,
Key::F => row3 ^= 0b0010_0000,
Key::B => row3 ^= 0b0001_0000,
Key::J => row3 ^= 0b0000_1000,
Key::L => row3 ^= 0b0000_0100,
Key::Key2 => row3 ^= 0b0000_0010,
Key::Key4 => row3 ^= 0b0000_0001,
Key::LeftAlt | Key::RightAlt => row4 ^= 0b1000_0000,
Key::X => row4 ^= 0b0100_0000,
Key::C => row4 ^= 0b0010_0000,
Key::N => row4 ^= 0b0001_0000,
Key::M => row4 ^= 0b0000_1000,
Key::Comma => row4 ^= 0b0000_0100,
Key::Key1 => row4 ^= 0b0000_0010,
Key::Key3 => row4 ^= 0b0000_0001,
Key::LeftSuper => row5 ^= 0b1000_0000,
Key::Space => row5 ^= 0b0100_0000,
Key::RightSuper => row5 ^= 0b0010_0000,
_ => {}
};
// match key {
// Key::Escape => row0 ^= 0b1000_0000,
// Key::W => row0 ^= 0b0100_0000,
// Key::E => row0 ^= 0b0010_0000,
// Key::R => row0 ^= 0b0001_0000,
// Key::T => row0 ^= 0b0000_1000,
// Key::U => row0 ^= 0b0000_0100,
// Key::O => row0 ^= 0b0000_0010,
// Key::Backspace => row0 ^= 0b0000_0001,
// Key::Tab => row1 ^= 0b1000_0000,
// Key::Q => row1 ^= 0b0100_0000,
// Key::S => row1 ^= 0b0010_0000,
// Key::G => row1 ^= 0b0001_0000,
// Key::Y => row1 ^= 0b0000_1000,
// Key::I => row1 ^= 0b0000_0100,
// Key::P => row1 ^= 0b0000_0010,
// Key::Enter => row1 ^= 0b0000_0001,
// Key::LeftShift | Key::RightShift => row2 ^= 0b1000_0000,
// Key::D => row2 ^= 0b0100_0000,
// Key::V => row2 ^= 0b0010_0000,
// Key::H => row2 ^= 0b0001_0000,
// Key::K => row2 ^= 0b0000_1000,
// Key::Apostrophe => row2 ^= 0b0000_0100,
// Key::Slash => row2 ^= 0b0000_0010,
// Key::A => row2 ^= 0b0000_0001,
// Key::LeftCtrl | Key::RightCtrl => row3 ^= 0b1000_0000,
// Key::Z => row3 ^= 0b0100_0000,
// Key::F => row3 ^= 0b0010_0000,
// Key::B => row3 ^= 0b0001_0000,
// Key::J => row3 ^= 0b0000_1000,
// Key::L => row3 ^= 0b0000_0100,
// Key::Key2 => row3 ^= 0b0000_0010,
// Key::Key4 => row3 ^= 0b0000_0001,
// Key::LeftAlt | Key::RightAlt => row4 ^= 0b1000_0000,
// Key::X => row4 ^= 0b0100_0000,
// Key::C => row4 ^= 0b0010_0000,
// Key::N => row4 ^= 0b0001_0000,
// Key::M => row4 ^= 0b0000_1000,
// Key::Comma => row4 ^= 0b0000_0100,
// Key::Key1 => row4 ^= 0b0000_0010,
// Key::Key3 => row4 ^= 0b0000_0001,
// Key::LeftSuper => row5 ^= 0b1000_0000,
// Key::Space => row5 ^= 0b0100_0000,
// Key::RightSuper => row5 ^= 0b0010_0000,
// _ => {}
// };
self.memory.write(0x4400, row0);
self.memory.write(0x4401, row1);
self.memory.write(0x4402, row2);
self.memory.write(0x4403, row3);
self.memory.write(0x4404, row4);
self.memory.write(0x4405, row5);
}
}
// self.memory.write(0x4400, row0);
// self.memory.write(0x4401, row1);
// self.memory.write(0x4402, row2);
// self.memory.write(0x4403, row3);
// self.memory.write(0x4404, row4);
// self.memory.write(0x4405, row5);
// }
// }
+26 -57
View File
@@ -10,64 +10,36 @@ mod video;
use crate::cpu::Cpu;
use crate::keyboard::Keyboard;
use crate::memory::Mem;
use crate::video::{Screen, TerminalRenderer};
use crate::video::Screen;
use cli::get_input;
use crossterm::execute;
use crossterm::terminal::{size, Clear, ClearType, SetSize};
// use cpu::CpuController;
use memory::MemHandle;
use minifb::{Scale, ScaleMode, Window, WindowOptions};
use std::io::{stdout, Result};
use std::io::{stdin, stdout, Result};
use std::thread::{self, sleep};
use std::time::Duration;
use termion::event::Key;
use termion::input::TermRead;
use termion::raw::IntoRawMode;
// use termion::raw::IntoRawMode;
use crossterm::{
cursor,
event::{self, KeyCode, KeyEventKind},
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use std::io::Write;
// For when we want to leave the terminal again :sigh:
//
// thread::spawn(move || {
// let mut screen = Crtc::new(
// screen_memory,
// config.char_rom.as_ref(),
// CpuController::new(screen_cpu_tx),
// window_tx,
// );
// screen.run();
// });
// let mut window = Window::new(
// "ʕ·ᴥ·ʔ-☆",
// 512,
// 380,
// WindowOptions {
// resize: true,
// borderless: true,
// title: true,
// transparency: false,
// scale: Scale::X2,
// scale_mode: ScaleMode::AspectRatioStretch,
// topmost: false,
// none: true,
// },
// )
// .unwrap();
use termion::{self, clear, cursor, screen};
fn main() -> Result<()> {
let mut stdout = stdout();
let (cols, rows) = size()?;
let mut stdout = stdout().into_raw_mode().unwrap();
// let (cols, rows) = size()?;
let config = get_input();
let mut memory = Mem::new();
let _ = memory.load_rom(&config.rom);
execute!(stdout, SetSize(64, 29), cursor::Hide, EnterAlternateScreen)?;
enable_raw_mode()?;
write!(stdout, "{}{}", cursor::Hide, screen::ToAlternateScreen)?;
// execute!(stdout, SetSize(64, 29), cursor::Hide, EnterAlternateScreen)?;
// enable_raw_mode()?;
let shared_memory = MemHandle::new(memory);
let screen_memory = shared_memory.clone();
@@ -86,24 +58,21 @@ fn main() -> Result<()> {
let mut screen = Screen::new(&config, cpu_controller, screen_memory);
loop {
sleep(Duration::from_millis(16));
keyboard.clear_keys(); // nasty hack until i can figure out a good way of clearing keyboard
// memory when no keys are pressed
screen.draw();
// if event::poll(std::time::Duration::from_millis(16))? {
if let event::Event::Key(key) = event::read()? {
keyboard.read_keys(key);
if key.kind == KeyEventKind::Press && key.code == KeyCode::Char('q') {
break;
keyboard.read_keys();
for key in stdin().keys() {
match key.unwrap() {
Key::Char('q') => {
write!(stdout, "{}", clear::All)?;
return Ok(());
}
_ => {}
}
// }
}
// }
sleep(Duration::from_millis(16));
}
execute!(
stdout,
LeaveAlternateScreen,
SetSize(cols, rows),
Clear(ClearType::Purge)
)?;
disable_raw_mode()?;
Ok(())
}
+1 -1
View File
@@ -30,7 +30,7 @@ cleardisplay:
main:
; jsr read_keys
; lda key_buffer
lda $4402
lda $4400
sta $6000
jmp main
+11 -26
View File
@@ -1,10 +1,9 @@
use crossterm::{
cursor::{MoveTo, RestorePosition, SavePosition},
execute, queue,
style::{Color, PrintStyledContent, Stylize},
};
use minifb::{Scale, ScaleMode, Window, WindowOptions};
use serde::{Deserialize, Serialize};
use termion::{
color::{self, Bg, Color, Fg},
cursor::Goto,
};
use crate::{
cli::Config,
@@ -16,6 +15,8 @@ use std::{
fs::File,
io::{self, Read, Write},
path::Path,
process::exit,
time::Instant,
};
const FG_COLOR: u32 = 0xFFCC00;
@@ -150,40 +151,24 @@ const ASCII_LOOPUP: [&str; 256] = [
// impl Renderer for TerminalRenderer<'_> {
impl Renderer for TerminalRenderer {
fn render(&mut self) {
// let now = Instant::now();
let mut stdout = io::stdout();
let _ = execute!(stdout, SavePosition);
let mut i = 0;
for char_row in 0..29 {
for char_col in 0..64 {
let ascii = self.read(0x6000 + i);
i += 1;
let char = ASCII_LOOPUP[ascii as usize];
let _ = queue!(
let _ = write!(
// FG_COLOR = 0xFFCC00
// BG_COLOR = 0x110500
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
})
)
"{}{}{}{char}",
Goto(char_col + 1, char_row + 1),
Fg(color::Rgb(0xFF, 0xCC, 0x00)),
Bg(color::Rgb(0x11, 0x05, 0x00))
);
}
}
let _ = stdout.flush();
let _ = execute!(stdout, RestorePosition);
// let elapsed = now.elapsed();
// println!("{elapsed:?}");
// exit(0);
}
}