use wasm_bindgen::prelude::*;
use wasm_bindgen::JsValue;
use web_sys::Window;
use crate::bus::{UART_BASE, UART_SIZE};
use crate::cpu::BYTE;
use crate::exception::Exception;
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
}
pub const UART_IRQ: u64 = 10;
pub const UART_RHR: u64 = UART_BASE + 0;
pub const UART_THR: u64 = UART_BASE + 0;
pub const UART_IER: u64 = UART_BASE + 1;
pub const UART_FCR: u64 = UART_BASE + 2;
pub const UART_ISR: u64 = UART_BASE + 2;
pub const UART_LCR: u64 = UART_BASE + 3;
pub const UART_LSR: u64 = UART_BASE + 5;
fn get_input(window: &Window) -> u8 {
let document = window.document().expect("failed to get a document object");
let buffer = document
.get_element_by_id("inputBuffer")
.expect("failed to get an element by `inputBuffer` id");
match buffer.first_child() {
Some(span) => {
buffer
.remove_child(&span)
.expect("faled to remove a first child");
let text = span.text_content().expect("failed to get a text content");
let byte: u8 = text.parse().expect("failed to parse a text to byte");
byte
}
None => 0,
}
}
pub struct Uart {
uart: [u8; UART_SIZE as usize],
clock: u64,
not_null: bool,
window: web_sys::Window,
}
impl Uart {
pub fn new() -> Self {
let mut uart = [0; UART_SIZE as usize];
uart[(UART_ISR - UART_BASE) as usize] |= 1;
uart[(UART_LSR - UART_BASE) as usize] |= 1 << 5;
Self {
uart,
clock: 0,
not_null: false,
window: web_sys::window().expect("failed to get a global window object"),
}
}
pub fn is_interrupting(&mut self) -> bool {
self.clock += 1;
if self.clock > 500000 || self.not_null {
self.clock = 0;
let b = get_input(&self.window);
if b == 0 {
self.not_null = false;
return false;
}
self.uart[0] = b;
self.uart[(UART_LSR - UART_BASE) as usize] |= 1;
self.not_null = true;
return true;
}
false
}
pub fn read(&mut self, index: u64, size: u8) -> Result<u64, Exception> {
if size != BYTE {
return Err(Exception::LoadAccessFault);
}
match index {
UART_RHR => {
self.uart[(UART_LSR - UART_BASE) as usize] &= !1;
Ok(self.uart[(index - UART_BASE) as usize] as u64)
}
_ => Ok(self.uart[(index - UART_BASE) as usize] as u64),
}
}
pub fn write(&mut self, index: u64, value: u8, size: u8) -> Result<(), Exception> {
if size != BYTE {
return Err(Exception::StoreAMOAccessFault);
}
match index {
UART_THR => {
self.window
.post_message(&JsValue::from(value), "*")
.expect("failed to post message");
}
_ => {
self.uart[(index - UART_BASE) as usize] = value;
}
}
Ok(())
}
}