-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.rs
134 lines (111 loc) · 3.74 KB
/
main.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// this is the character / text mode implementation
extern crate ncurses;
use ncurses::*;
use core::time;
use crossbeam_channel::*;
use std::thread;
use rust6502::address_bus::*;
use rust6502::mc6821::*;
use rust6502::memory::*;
use rust6502::mos6502::*;
struct ConsoleTerminal {
pub rx_input: Receiver<u8>,
}
impl ConsoleTerminal {
pub fn new(rx_output: Receiver<u8>) -> ConsoleTerminal {
initscr();
noecho();
addstr("Apple1 console - hit Ctrl-C to quit\n\n");
let (tx_input, rx_input) = unbounded();
thread::spawn(move || loop {
tx_input.send(getch() as u8).unwrap();
});
thread::spawn(move || loop {
match rx_output.try_recv() {
Ok(b) => {
let c = (b & !0x80).to_ascii_uppercase() as u8;
match c {
0x0A | 0x0D => {
addch('\n' as chtype);
}
_ => {
addch(c as chtype);
}
}
refresh();
}
Err(_) => {
thread::sleep(time::Duration::from_millis(100));
}
}
});
ConsoleTerminal { rx_input }
}
pub fn check_input(&self) -> Result<u8, TryRecvError> {
self.rx_input.try_recv()
}
}
fn main() {
let mut address_bus = AddressBus::new(0x100);
let mut mem = Memory::new(0, 4 * 1024);
if address_bus.add_component(0, mem.len(), &mut (mem)).is_err() {
panic!("add_component for RAM failed");
}
let mut pia = MC6821::new();
// channel from PIA to terminal (PIA=tx, terminal=rx)
let (tx_apple_output, rx_apple_output): (Sender<u8>, Receiver<u8>) = unbounded();
pia.set_output_channel_b(tx_apple_output);
let terminal = ConsoleTerminal::new(rx_apple_output);
// channel from keyboard to PIA (keyboard=tx, PIA=rx)
let (tx_apple_input, rx_apple_input): (Sender<InputSignal>, Receiver<InputSignal>) =
unbounded();
pia.set_input_channel(rx_apple_input);
let check_input = || -> bool {
let mut stop = false;
if let Ok(mut c) = terminal.check_input() {
match c {
0x03 => stop = true, // ^c
0x0A => c = 0x0D,
_ => {}
};
tx_apple_input.send(InputSignal::CA1(Signal::Fall)).unwrap();
tx_apple_input
.send(InputSignal::IRA(c.to_ascii_uppercase() as u8 | 0x80))
.unwrap();
tx_apple_input.send(InputSignal::CA1(Signal::Rise)).unwrap();
tx_apple_input.send(InputSignal::CA1(Signal::Fall)).unwrap();
}
stop
};
if address_bus
.add_component(0xD000, 0x100, &mut (pia))
.is_err()
{
panic!("add_component PIA failed");
}
let mut rom_monitor = Memory::load_rom(0xFF00, "./roms/Apple1_HexMonitor.bin".to_string());
if address_bus
.add_component(0xFF00, rom_monitor.len(), &mut (rom_monitor))
.is_err()
{
panic!("add_component for ROM failed");
}
let mut rom_basic = Memory::load_rom(0xE000, "./roms/Apple1_Basic.bin".to_string());
if address_bus
.add_component(0xE000, rom_basic.len(), &mut (rom_basic))
.is_err()
{
panic!("add_component for ROM failed");
}
let mut cpu = Cpu::new(CpuRegisters::default(), &mut address_bus);
cpu.reset();
cpu.wait_for_system_reset_cycles();
// main emulation loop
loop {
// check input from the terminal and send to PIA
check_input();
// processor cycle
cpu.cycle(false);
thread::sleep(time::Duration::from_micros(100));
}
}