use std::io::*;
use std::sync::mpsc;
use std::sync::mpsc::Receiver;
use std::sync::mpsc::TryRecvError;
use std::thread;
use std::time::Duration;
use iz80::Cpu;
use iz80::Machine;
use iz80::TimedRunner;
static TINY_BASIC: &[u8] = include_bytes!("rom/tinybasic2dms.bin");
const MHZ: f64 = 4.0;
fn main() {
let mut machine = VilleMachine::new();
let mut cpu = Cpu::new();
let mut timed_runner = TimedRunner::new();
timed_runner.set_mhz(&cpu, MHZ, 1000);
let mut stdout = stdout();
let stdin_channel = spawn_stdin_channel();
let mut in_char_waiting = false;
let code = TINY_BASIC;
for (i, e) in code.iter().enumerate() {
machine.poke(i as u16, *e);
}
cpu.registers().set_pc(0x0000);
machine.in_values[3] = 1;
loop {
timed_runner.execute(&mut cpu, &mut machine);
if let Some(port) = machine.out_port {
match port {
2 => {
print!("{}", machine.out_value as char);
stdout.flush().unwrap();
},
3 => {},
_ => panic!("BDOS command not implemented")
}
machine.out_port = None;
}
if let Some(port) = machine.in_port {
match port {
2 => {
in_char_waiting = false;
},
3 => {},
_ => panic!("BDOS command not implemented")
}
machine.in_port = None;
if MHZ == 0.0 {
thread::sleep(Duration::from_millis(1));
}
}
if !in_char_waiting {
match stdin_channel.try_recv() {
Ok(key) => {
machine.in_values[2] = key;
in_char_waiting = true;
machine.in_values[3] = 3; },
Err(TryRecvError::Empty) => {
machine.in_values[3] = 1; },
Err(TryRecvError::Disconnected) => {},
}
}
}
}
fn spawn_stdin_channel() -> Receiver<u8> {
let (tx, rx) = mpsc::channel::<u8>();
thread::spawn(move || loop {
let mut buffer = String::new();
stdin().read_line(&mut buffer).unwrap();
for mut c in buffer.bytes() {
if c == 10 {c = 13};
tx.send(c).unwrap();
}
});
rx
}
struct VilleMachine {
mem: [u8; 65536],
in_values: [u8; 256],
in_port: Option<u8>,
out_port: Option<u8>,
out_value: u8
}
impl VilleMachine {
pub fn new() -> VilleMachine {
VilleMachine {
mem: [0; 65536],
in_values: [0; 256],
out_port: None,
out_value: 0,
in_port: None
}
}
}
impl Machine for VilleMachine {
fn peek(&self, address: u16) -> u8 {
self.mem[address as usize]
}
fn poke(&mut self, address: u16, value: u8) {
self.mem[address as usize] = value;
}
fn port_in(&mut self, address: u16) -> u8 {
let value = self.in_values[address as u8 as usize];
if value != 1 {
}
self.in_port = Some(address as u8);
value
}
fn port_out(&mut self, address: u16, value: u8) {
self.out_port = Some(address as u8);
self.out_value = value;
}
}