use std::rc::Rc; use crate::simulator::{machine::{ExceptionType, Machine}, error::{MachineOk, MachineError}}; use super::system::System; pub const SC_SHUTDOWN: u8 = 0; pub const SC_EXIT: u8 = 1; pub const SC_EXEC: u8 = 2; pub const SC_JOIN: u8 = 3; pub const SC_CREATE: u8 = 4; pub const SC_OPEN: u8 = 5; pub const SC_READ: u8 = 6; pub const SC_WRITE: u8 = 7; pub const SC_SEEK: u8 = 8; pub const SC_CLOSE: u8 = 9; pub const SC_NEW_THREAD: u8 = 10; pub const SC_YIELD: u8 = 11; pub const SC_PERROR: u8 = 12; pub const SC_P: u8 = 13; pub const SC_V: u8 = 14; pub const SC_SEM_CREATE: u8 = 15 ; pub const SC_SEM_DESTROY: u8 = 16; pub const SC_LOCK_CREATE: u8 = 17 ; pub const SC_LOCK_DESTROY: u8 = 18 ; pub const SC_LOCK_ACQUIRE: u8 = 19 ; pub const SC_LOCK_RELEASE: u8 = 20 ; pub const SC_COND_CREATE: u8 = 21 ; pub const SC_COND_DESTROY: u8 = 22 ; pub const SC_COND_WAIT: u8 = 23 ; pub const SC_COND_SIGNAL: u8 = 24; pub const SC_COND_BROADCAST: u8 = 25; pub const SC_TTY_SEND: u8 = 26; pub const SC_TTY_RECEIVE: u8 = 27; pub const SC_MKDIR: u8 = 28; pub const SC_RMDIR: u8 = 29; pub const SC_REMOVE: u8 = 30; pub const SC_FSLIST: u8 = 31; pub const SC_SYS_TIME: u8 = 32 ; pub const SC_MMAP: u8 = 33; pub const SC_DEBUG: u8 = 34; pub const CONSOLE_OUTPUT: u8 = 1; // todo : returns new types, not just machine errors and machine ok pub fn call(exception: ExceptionType, machine: &mut Machine, system: &mut System) -> Result { match exception { ExceptionType::NoException => todo!(), ExceptionType::SyscallException => syscall(machine, system), ExceptionType::PagefaultException => todo!(), ExceptionType::ReadOnlyException => todo!(), ExceptionType::BusErrorException => todo!(), ExceptionType::AddressErrorException => todo!(), ExceptionType::OverflowException => todo!(), ExceptionType::IllegalInstrException => todo!(), ExceptionType::NumExceptionTypes => todo!(), } } fn syscall(machine: &mut Machine, system: &mut System) -> Result { let call_type = machine.read_int_register(17) as u8; match call_type { SC_SHUTDOWN => Ok(MachineOk::Shutdown), SC_EXIT => { match &system.get_thread_manager().g_current_thread { Some(th) => { let th = Rc::clone(th); system.get_thread_manager().thread_finish(machine, th); Ok(MachineOk::Ok) }, None => { Err("Current thread is None".into()) } } }, SC_EXEC => todo!(), SC_JOIN => todo!(), SC_CREATE => todo!(), SC_OPEN => todo!(), SC_READ => todo!(), SC_WRITE => { let address = machine.read_int_register(10); let size = machine.read_int_register(11); // openfileid or 1 (console) let f = machine.read_int_register(12); // load buffer let mut buffer = "".to_string(); for i in 0..size { buffer.push((machine.read_memory(1, (address + i) as usize)) as u8 as char); } if f as u8 == CONSOLE_OUTPUT { println!("{}", buffer); // todo replace with console driver in the future } else { todo!("SC_WRITE to file is not yet implemented") } Ok(MachineOk::Ok) }, SC_SEEK => todo!(), SC_CLOSE => todo!(), SC_NEW_THREAD => todo!(), SC_YIELD => todo!(), SC_PERROR => todo!(), SC_P => todo!(), SC_V => todo!(), SC_SEM_CREATE => todo!(), SC_SEM_DESTROY => todo!(), SC_LOCK_CREATE => todo!(), SC_LOCK_DESTROY => todo!(), SC_LOCK_ACQUIRE => todo!(), SC_LOCK_RELEASE => todo!(), SC_COND_CREATE => todo!(), SC_COND_DESTROY => todo!(), SC_COND_WAIT => todo!(), SC_COND_SIGNAL => todo!(), SC_COND_BROADCAST => todo!(), SC_TTY_SEND => todo!(), SC_TTY_RECEIVE => todo!(), SC_MKDIR => todo!(), SC_RMDIR => todo!(), SC_REMOVE => todo!(), SC_FSLIST => todo!(), SC_SYS_TIME => todo!(), SC_MMAP => todo!(), SC_DEBUG => todo!(), _ => todo!() } } #[cfg(test)] mod test { use crate::kernel::exception::{SC_SHUTDOWN, SC_WRITE}; use crate::kernel::system::System; use crate::simulator::instruction::Instruction; use crate::simulator::machine::Machine; #[test] fn test_sc_shutdown() { let mut machine = Machine::init_machine(); machine.write_int_register(17, SC_SHUTDOWN as i64); // Set type to shutdown let ecall = Instruction::new(0b000000000000_00000_000_00000_1110011); machine.write_memory(4, 0, 0b000000000000_00000_000_00000_1110011); // ecall machine.write_memory(4, 4, 0b000000001010_00000_000_00001_0010011); // r1 <- 10 let mut system = System::default(); machine.run(&mut system); // If the machine was stopped with no error, the shutdown worked assert_ne!(machine.read_int_register(1), 10); // Check if the next instruction was executed } // This test print HELLO in the console #[test] #[ignore] fn test_sc_print() { let mut machine = Machine::init_machine(); let address = machine.read_int_register(10); // Write string 'HELLO' in memory machine.write_memory(1, 4000, 72); machine.write_memory(1, 4001, 69); machine.write_memory(1, 4002, 76); machine.write_memory(1, 4003, 76); machine.write_memory(1, 4004, 79); machine.write_int_register(10, 4000); // String address machine.write_int_register(11, 5); // String size machine.write_int_register(12, 1); // Console output machine.write_memory(4, 0, 0b000000000000_00000_000_00000_1110011); // ecall machine.write_int_register(17, SC_WRITE as i64); // Set type to write machine.write_memory(4, 4, 0b000000000000_00000_000_10001_0010011); // r17 <- SC_SHUTDOWN machine.write_memory(4, 8, 0b000000000000_00000_000_00000_1110011); // ecall let mut system = System::default(); machine.run(&mut system); } }