19 Commits

Author SHA1 Message Date
e430a62c35 Kernel documentation. Still need to do thread.rs 2023-05-14 23:51:15 +02:00
2f38edee70 Module description 2023-05-10 08:02:25 +02:00
c60aaa1aae Documentation for the simulator 2023-05-09 22:02:22 +02:00
28200ebc04 small fix in mmu.rs documentation 2023-05-09 19:18:40 +02:00
692c3bfa03 Documentation for mem_cmp.rs and mmu.rs modules 2023-05-09 19:15:56 +02:00
d35314bead Added missing current_thread assignment in test_lock_multiple 2023-05-05 00:30:06 +02:00
7b7d48c775 Try to fix double free 2023-05-05 00:30:06 +02:00
9dec9b041a Update userlib/sys.s 2023-05-05 00:30:06 +02:00
9bd0ef02aa Fix join not working on join.c 2023-05-05 00:30:06 +02:00
c6f5818059 try to implement join 2023-05-05 00:30:06 +02:00
31f1e760e9 Fixed lock_release behaviour when multiple users of given lock 2023-05-05 00:30:06 +02:00
f6195a9da0 Updated thread_manager module documentation 2023-05-05 00:30:06 +02:00
5393c6e3f2 test lock for multiple threads
Signed-off-by: Rémi Rativel <remi.rativel@etudiant.univ-rennes1.fr>
2023-05-05 00:30:06 +02:00
ff921117f7 Using direct link to git hosted logo for documentation 2023-04-21 14:55:07 +02:00
ce4c7230f9 📝 Updated utility mod documentation 2023-04-21 14:50:55 +02:00
33cbe77175 Fixed logo now showing up in doc 2023-04-21 14:46:06 +02:00
052b950ca0 📝 Updated cfg.rs documentation 2023-04-21 14:42:07 +02:00
f06f14354a Added project logo to doc 2023-04-21 14:29:00 +02:00
8732a6f0b7 Added build.rs script
- Executes make all
 - Moves the project logo to the documentation folder
2023-04-21 14:28:30 +02:00
27 changed files with 374 additions and 412 deletions

View File

@ -1,13 +1,6 @@
TOPDIR=. TOPDIR=.
include $(TOPDIR)/Makefile.config include $(TOPDIR)/Makefile.config
#
# Demo vars
#
FLAGS=--offline -r --
CARGO=RUSTFLAGS=-Awarnings cargo run ${FLAGS}
all: dumps user_lib instruction_tests syscall all: dumps user_lib instruction_tests syscall
# #
@ -35,21 +28,4 @@ clean:
$(MAKE) clean -C userlib/ $(MAKE) clean -C userlib/
$(MAKE) clean -C test/ $(MAKE) clean -C test/
$(RM) -rf $(TOPDIR)/target $(RM) -rf $(TOPDIR)/target
#
# Demo targets
#
halt: syscall
${CARGO} -x ./target/guac/halt.guac -d3
pc: syscall
${CARGO} -x ./target/guac/producteur_consommateur.guac -d2
matmult: syscall
${CARGO} -x ./target/guac/matmult.guac -d2
lr: syscall
${CARGO} -x ./target/guac/lecteur_redacteur.guac -d2
prints: syscall
${CARGO} -x ./target/guac/prints.guac -d2

12
build.rs Normal file
View File

@ -0,0 +1,12 @@
//! Build script for BurritOS.
//!
//! Moves files from the assets folder to the target directory
//! and runs `make all`.
use std::process::Command;
fn main() {
let mut make_all = Command::new("make");
make_all.arg("all");
println!("{:?}", make_all.output().unwrap());
}

View File

@ -2,7 +2,7 @@
# BurritOS configuration file # BurritOS configuration file
################################################## ##################################################
NumPhysPages = 40000000 NumPhysPages = 400
UserStackSize = 4096 UserStackSize = 4096
MaxFileNameSize = 256 MaxFileNameSize = 256
NumDirEntries = 30 NumDirEntries = 30

View File

@ -1,9 +1,14 @@
//! # Exceprions
//!
//! This module Enum the constant values of the exceptions.
//! They are used to stop the system to execute some opperation
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use crate::{simulator::{machine::{ExceptionType, Machine}, error::{MachineOk, MachineError}}}; use crate::{simulator::{machine::{ExceptionType, Machine}, error::{MachineOk, MachineError}}};
use crate::kernel::synch::{Lock, Semaphore}; use crate::kernel::synch::{Lock, Semaphore};
use super::{system::System, thread::Thread}; use super::{system::{System, self}, thread::Thread};
/// The halt system call. Stops Burritos. /// The halt system call. Stops Burritos.
pub const SC_SHUTDOWN: u8 = 0; pub const SC_SHUTDOWN: u8 = 0;
@ -138,8 +143,7 @@ fn syscall(machine: &mut Machine, system: &mut System) -> Result<MachineOk, Mach
Some(th) => th.clone(), Some(th) => th.clone(),
None => Err("Current thread is None")? None => Err("Current thread is None")?
}; };
let code = machine.read_int_register(10); system.get_thread_manager().thread_finish(machine, th);
system.get_thread_manager().thread_finish(machine, th, code);
Ok(MachineOk::Ok) Ok(MachineOk::Ok)
}, },
SC_EXEC => todo!(), SC_EXEC => todo!(),
@ -155,17 +159,13 @@ fn syscall(machine: &mut Machine, system: &mut System) -> Result<MachineOk, Mach
let f = machine.read_int_register(12); let f = machine.read_int_register(12);
// load buffer // load buffer
let mut buffer = String::new(); let mut buffer = "".to_string();
let mut val: [u8; 4] = [0; 4];
for (j, elem) in val.iter_mut().enumerate() {
*elem = machine.read_memory(1, address as usize + j) as u8;
}
for i in 0..size { for i in 0..size {
buffer.push((machine.read_memory(1, (address + i) as usize)) as u8 as char); buffer.push((machine.read_memory(1, (address + i) as usize)) as u8 as char);
} }
if f as u8 == CONSOLE_OUTPUT { if f as u8 == CONSOLE_OUTPUT {
print!("{}", buffer); // todo replace with console driver in the future println!("{}", buffer); // todo replace with console driver in the future
Ok(MachineOk::Ok) Ok(MachineOk::Ok)
} else { } else {
Err("SC_WRITE to file is not yet implemented")? Err("SC_WRITE to file is not yet implemented")?
@ -283,9 +283,7 @@ fn sc_new_thread(machine: &mut Machine, system: &mut System) -> Result<MachineOk
}; };
let current_thread = current_thread.borrow_mut(); let current_thread = current_thread.borrow_mut();
if let Some(process) = current_thread.get_process_owner() { if let Some(process) = current_thread.get_process_owner() {
let sp_max = system.get_thread_manager().get_sp_max() + machine.user_stack_size; system.get_thread_manager().start_thread(n_thread, Rc::clone(&process), func as u64, current_thread.thread_context.int_registers[2] as u64 + machine.page_size, args);
system.get_thread_manager().set_sp_max(sp_max);
system.get_thread_manager().start_thread(n_thread, Rc::clone(&process), func as u64, sp_max, args);
// TODO changé la valeur de sp quand on supportera les addresses virtuels // TODO changé la valeur de sp quand on supportera les addresses virtuels
machine.write_int_register(10, tid as i64); machine.write_int_register(10, tid as i64);
Ok(MachineOk::Ok) Ok(MachineOk::Ok)
@ -356,18 +354,9 @@ mod test {
let mut machine = Machine::new(true, get_debug_configuration()); let mut machine = Machine::new(true, get_debug_configuration());
machine.write_int_register(17, SC_SHUTDOWN as i64); // Set type to shutdown machine.write_int_register(17, SC_SHUTDOWN as i64); // Set type to shutdown
// let ecall = Instruction::new(0b000000000000_00000_000_00000_1110011); // let ecall = Instruction::new(0b000000000000_00000_000_00000_1110011);
let insts: [u8; 4] = 0b000000000000_00000_000_00000_1110011_u32.to_le_bytes();
machine.write_memory(1, 0, insts[0] as u64); machine.write_memory(4, 0, 0b000000000000_00000_000_00000_1110011); // ecall
machine.write_memory(1, 1, insts[1] as u64); machine.write_memory(4, 4, 0b000000001010_00000_000_00001_0010011); // r1 <- 10
machine.write_memory(1, 2, insts[2] as u64);
machine.write_memory(1, 3, insts[3] as u64); // ecall
// machine.write_memory(4, 0, 0b000000000000_00000_000_00000_1110011_u64.to_be()); // ecall
let insts: [u8; 4] = 0b000000001010_00000_000_00001_0010011_u32.to_le_bytes();
machine.write_memory(1, 4, insts[0] as u64);
machine.write_memory(1, 5, insts[1] as u64);
machine.write_memory(1, 6, insts[2] as u64);
machine.write_memory(1, 7, insts[3] as u64); // r1 <- 10
// machine.write_memory(4, 4, 0b000000001010_00000_000_00001_0010011_u64.to_be()); // r1 <- 10
let mut system = System::new(true); let mut system = System::new(true);
machine.run(&mut system); machine.run(&mut system);
// If the machine was stopped with no error, the shutdown worked // If the machine was stopped with no error, the shutdown worked

View File

@ -1,3 +1,11 @@
//! # Error Code
//!
//! This module enumerate the possibles error code who could get in a function
//!
//! **Basic Usage:*
//!
//! Result<YourSuccessStruct, **ErrorCode**
#![allow(unused, clippy::missing_docs_in_private_items)] #![allow(unused, clippy::missing_docs_in_private_items)]
/// Error enum, use it with Result<YourSucessStruct, **ErrorCode**> /// Error enum, use it with Result<YourSucessStruct, **ErrorCode**>
pub enum ErrorCode { pub enum ErrorCode {

View File

@ -1,3 +1,9 @@
//! # Kernel
//!
//! This module contains all the tool required for the kernel to work.
//!
//! Currently it contains the scheduling and synchroisation tools, but it will contains the tools
//! required Memory gestion, Files gestion and peripheral pilots.
pub mod process; pub mod process;
pub mod thread; pub mod thread;
pub mod mgerror; pub mod mgerror;

View File

@ -1,3 +1,11 @@
//! # Synchronisation
//!
//! This module contains some scheduling and synchronisation utilities:
//! - **Semaphore**
//! - **Lock**
//!
//! Conditions aren't implemented currently
use crate::utility::list::List; use crate::utility::list::List;
use crate::kernel::thread::Thread; use crate::kernel::thread::Thread;
use crate::simulator::interrupt::InterruptStatus::InterruptOff; use crate::simulator::interrupt::InterruptStatus::InterruptOff;
@ -6,20 +14,21 @@ use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use super::thread_manager::ThreadManager; use super::thread_manager::ThreadManager;
/// Structure of a Semaphore used for synchronisation /// Structure of a Semaphore used for synchronisation.
/// It use a counter to determine the number of thread that can be executed simultaneously.
#[derive(PartialEq)] #[derive(PartialEq)]
pub struct Semaphore { pub struct Semaphore {
/// Counter of simultanous Semaphore /// Counter of simultaneous Semaphore
pub counter:i32, pub counter:i32,
/// QUeue of Semaphore waiting to be exucated /// QUeue of Semaphore waiting to be executed
pub waiting_queue:List<Rc<RefCell<Thread>>>, pub waiting_queue:List<Rc<RefCell<Thread>>>,
} }
impl Semaphore { impl Semaphore {
/// Initializes a semaphore, so that it can be used for synchronization. /// Initializes a semaphore, so that it can be used for synchronization.
/// ///
/// ### Parameters /// ### Parameters
/// - *counter* initial value of counter /// - *counter* initial value of counter
@ -49,7 +58,7 @@ pub struct Lock {
impl Lock { impl Lock {
/// Initialize a Lock, so that it can be used for synchronization. /// Initialize a Lock, so that it can be used for synchronization.
/// The lock is initialy free /// The lock is initially free
/// ///
/// ### Parameters /// ### Parameters
/// - **thread_manager** Thread manager which managing threads /// - **thread_manager** Thread manager which managing threads
@ -72,7 +81,7 @@ impl Lock {
let old_status = machine.interrupt.set_status(InterruptOff); let old_status = machine.interrupt.set_status(InterruptOff);
if self.free { if self.free {
self.free = false; self.free = false;
self.owner = Option::Some(match thread_manager.get_g_current_thread() { self.owner = Some(match thread_manager.get_g_current_thread() {
Some(th) => { Some(th) => {
Rc::clone(&th) Rc::clone(&th)
}, },
@ -128,8 +137,14 @@ impl Lock {
machine.interrupt.set_status(old_status); machine.interrupt.set_status(old_status);
} }
/// True if the current thread holds this lock. /// Say if the lock is held by the current thread
/// Useful for checking in Release, and in Condition operations below. /// Useful for checking in Release, and in Condition operations below.
/// ### Parameters
/// - **self** The current lock
/// - **thread-manager** The thread manager present in the system
/// ### Return
/// True if the current thread holds this lock.
pub fn held_by_current_thread(&mut self, thread_manager: &mut ThreadManager) -> bool { pub fn held_by_current_thread(&mut self, thread_manager: &mut ThreadManager) -> bool {
match &self.owner { match &self.owner {
Some(x) => Some(x) =>

View File

@ -1,3 +1,6 @@
//! # Thread
//!
//!
use std::{rc::Rc, cell::RefCell}; use std::{rc::Rc, cell::RefCell};
use super::{process::Process, thread_manager::ThreadRef}; use super::{process::Process, thread_manager::ThreadRef};

View File

@ -118,8 +118,7 @@ pub struct ThreadManager {
/// List of objects created by the thread manager (such as Locks and Semaphores) /// List of objects created by the thread manager (such as Locks and Semaphores)
obj_addrs: ObjAddr, obj_addrs: ObjAddr,
/// If true, enables debug mode /// If true, enables debug mode
debug: bool, debug: bool
sp_max: u64,
} }
impl ThreadManager { impl ThreadManager {
@ -131,8 +130,7 @@ impl ThreadManager {
g_alive: List::default(), g_alive: List::default(),
ready_list: List::default(), ready_list: List::default(),
obj_addrs: ObjAddr::init(), obj_addrs: ObjAddr::init(),
debug, debug
sp_max: 0
} }
} }
@ -241,21 +239,17 @@ impl ThreadManager {
while next_thread.is_none() { while next_thread.is_none() {
eprintln!("Nobody to run => idle"); eprintln!("Nobody to run => idle");
machine.interrupt.idle(); machine.interrupt.idle();
if let Some(t) = self.find_next_to_run() { next_thread = self.find_next_to_run();
next_thread = Some(t);
} else {
panic!("Couldn't find next thread to run.\nShutting down...");
}
} }
self.switch_to(machine, Rc::clone(&next_thread.unwrap())); self.switch_to(machine, Rc::clone(&next_thread.unwrap()));
} }
/// Finish the execution of the thread and prepare its deallocation /// Finish the execution of the thread and prepare its deallocation
pub fn thread_finish(&mut self, machine: &mut Machine, thread: ThreadRef, exit_code: i64) { pub fn thread_finish(&mut self, machine: &mut Machine, thread: ThreadRef) {
let old_status = machine.interrupt.set_status(InterruptStatus::InterruptOff); let old_status = machine.interrupt.set_status(InterruptStatus::InterruptOff);
assert!(self.g_alive.remove(Rc::clone(&thread))); assert!(self.g_alive.remove(Rc::clone(&thread)));
self.debug(format!("Finishing thread {} with code {}", thread.borrow().get_name(), exit_code)); self.debug(format!("Finishing thread {}", thread.borrow().get_name()));
// g_objets_addrs->removeObject(self.thread) // a ajouté plus tard // g_objets_addrs->removeObject(self.thread) // a ajouté plus tard
for (_, el) in thread.borrow().join_thread.iter().enumerate() { for (_, el) in thread.borrow().join_thread.iter().enumerate() {
self.ready_to_run(Rc::clone(&el)); self.ready_to_run(Rc::clone(&el));
@ -429,14 +423,6 @@ impl ThreadManager {
} }
} }
pub fn get_sp_max(&self) -> u64 {
self.sp_max
}
pub fn set_sp_max(&mut self, sp_max: u64) {
self.sp_max = sp_max;
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -1,4 +1,7 @@
#![doc(
html_logo_url = "https://gitlab.istic.univ-rennes1.fr/simpleos/burritos/-/raw/main/assets/logo/logo.svg",
html_favicon_url = "https://gitlab.istic.univ-rennes1.fr/simpleos/burritos/-/raw/main/assets/logo/logo.svg")
]
#![warn(missing_docs)] #![warn(missing_docs)]
#![warn(clippy::missing_docs_in_private_items)] #![warn(clippy::missing_docs_in_private_items)]
@ -7,10 +10,8 @@
//! Burritos is an educational operating system written in Rust //! Burritos is an educational operating system written in Rust
//! running on RISC-V emulator. //! running on RISC-V emulator.
/// Contain hardware simulated part of the machine
mod simulator; mod simulator;
mod kernel; mod kernel;
/// module containing useful tools which can be use in most part of the OS to ease the development of the OS
pub mod utility; pub mod utility;
use std::{rc::Rc, cell::RefCell}; use std::{rc::Rc, cell::RefCell};
@ -55,10 +56,7 @@ fn main() {
let owner1 = Process { num_thread: 0 }; let owner1 = Process { num_thread: 0 };
let owner1 = Rc::new(RefCell::new(owner1)); let owner1 = Rc::new(RefCell::new(owner1));
let sp_max = ptr + machine.user_stack_size; system.get_thread_manager().start_thread(Rc::clone(&thread_exec), owner1, loader.elf_header.entrypoint, ptr + machine.page_size, -1);
system.get_thread_manager().set_sp_max(sp_max);
system.get_thread_manager().start_thread(Rc::clone(&thread_exec), owner1, loader.elf_header.entrypoint, sp_max, -1);
let to_run = system.get_thread_manager().find_next_to_run().unwrap(); let to_run = system.get_thread_manager().find_next_to_run().unwrap();
system.get_thread_manager().switch_to(&mut machine, Rc::clone(&to_run)); system.get_thread_manager().switch_to(&mut machine, Rc::clone(&to_run));

View File

@ -349,11 +349,11 @@ mod test {
#[test] #[test]
fn test_op() { fn test_op() {
let sub = Instruction::new(0b0100000_10000_10001_000_11100_0110011_u64.to_le()); let sub = Instruction::new(0b0100000_10000_10001_000_11100_0110011);
let add = Instruction::new(0b0000000_10000_10001_000_11100_0110011_u64.to_le()); let add = Instruction::new(0b0000000_10000_10001_000_11100_0110011);
let xor = Instruction::new(0b0000000_10000_10001_100_11100_0110011_u64.to_le()); let xor = Instruction::new(0b0000000_10000_10001_100_11100_0110011);
let slr = Instruction::new(0b0000000_10000_10001_101_11100_0110011_u64.to_le()); let slr = Instruction::new(0b0000000_10000_10001_101_11100_0110011);
let sra = Instruction::new(0b0100000_10000_10001_101_11100_0110011_u64.to_le()); let sra = Instruction::new(0b0100000_10000_10001_101_11100_0110011);
assert_eq!("sub\tt3,a7,a6", instruction_debug(&sub, 0)); assert_eq!("sub\tt3,a7,a6", instruction_debug(&sub, 0));
assert_eq!("xor\tt3,a7,a6", instruction_debug(&xor, 0)); assert_eq!("xor\tt3,a7,a6", instruction_debug(&xor, 0));
@ -365,13 +365,13 @@ mod test {
#[test] #[test]
fn test_opi() { fn test_opi() {
let addi = Instruction::new(0b0000000000_10001_000_11100_0010011_u64.to_le()); let addi = Instruction::new(0b0000000000_10001_000_11100_0010011);
let slli = Instruction::new(0b0000000000_10001_001_11100_0010011_u64.to_le()); let slli = Instruction::new(0b0000000000_10001_001_11100_0010011);
let slti = Instruction::new(0b0000000000_10001_010_11100_0010011_u64.to_le()); let slti = Instruction::new(0b0000000000_10001_010_11100_0010011);
let sltiu = Instruction::new(0b0000000000_10001_011_11100_0010011_u64.to_le()); let sltiu = Instruction::new(0b0000000000_10001_011_11100_0010011);
let xori = Instruction::new(0b_0000000000010001_100_11100_0010011_u64.to_le()); let xori = Instruction::new(0b_0000000000010001_100_11100_0010011);
let ori = Instruction::new(0b00000000000_10001_110_11100_0010011_u64.to_le()); let ori = Instruction::new(0b00000000000_10001_110_11100_0010011);
let andi = Instruction::new(0b000000000000_10001_111_11100_0010011_u64.to_le()); let andi = Instruction::new(0b000000000000_10001_111_11100_0010011);
assert_eq!("andi\tt3,a7,0", instruction_debug(&andi, 0)); assert_eq!("andi\tt3,a7,0", instruction_debug(&andi, 0));
assert_eq!("addi\tt3,a7,0", instruction_debug(&addi, 0)); assert_eq!("addi\tt3,a7,0", instruction_debug(&addi, 0));
assert_eq!("slli\tt3,a7,0", instruction_debug(&slli, 0)); assert_eq!("slli\tt3,a7,0", instruction_debug(&slli, 0));
@ -383,8 +383,8 @@ mod test {
#[test] #[test]
fn test_lui() { fn test_lui() {
let lui = Instruction::new(0b01110001000011111000_11100_0110111_u64.to_le()); let lui = Instruction::new(0b01110001000011111000_11100_0110111);
let lui_negatif = Instruction::new(0b11110001000011111000_11100_0110111_u64.to_le()); let lui_negatif = Instruction::new(0b11110001000011111000_11100_0110111);
assert_eq!("lui\tt3,710f8000", instruction_debug(&lui, 0)); assert_eq!("lui\tt3,710f8000", instruction_debug(&lui, 0));
assert_eq!("lui\tt3,f10f8000", instruction_debug(&lui_negatif, 0)); assert_eq!("lui\tt3,f10f8000", instruction_debug(&lui_negatif, 0));
} }
@ -392,13 +392,13 @@ mod test {
#[test] #[test]
fn test_ld() { fn test_ld() {
// imm rs1 f3 rd opcode // imm rs1 f3 rd opcode
let lb = Instruction::new(0b010111110000_10001_000_11100_0000011_u64.to_le()); let lb = Instruction::new(0b010111110000_10001_000_11100_0000011);
let lh = Instruction::new(0b010111110000_10001_001_11100_0000011_u64.to_le()); let lh = Instruction::new(0b010111110000_10001_001_11100_0000011);
let lw = Instruction::new(0b010111110000_10001_010_11100_0000011_u64.to_le()); let lw = Instruction::new(0b010111110000_10001_010_11100_0000011);
let lbu = Instruction::new(0b010111110000_10001_100_11100_0000011_u64.to_le()); let lbu = Instruction::new(0b010111110000_10001_100_11100_0000011);
let lhu = Instruction::new(0b010111110000_10001_101_11100_0000011_u64.to_le()); let lhu = Instruction::new(0b010111110000_10001_101_11100_0000011);
let ld = Instruction::new(0b010111110000_10001_011_11100_0000011_u64.to_le()); let ld = Instruction::new(0b010111110000_10001_011_11100_0000011);
let lwu = Instruction::new(0b010111110000_10001_110_11100_0000011_u64.to_le()); let lwu = Instruction::new(0b010111110000_10001_110_11100_0000011);
assert_eq!("lb\tt3,1520(a7)", instruction_debug(&lb, 0)); assert_eq!("lb\tt3,1520(a7)", instruction_debug(&lb, 0));
assert_eq!("lh\tt3,1520(a7)", instruction_debug(&lh, 0)); assert_eq!("lh\tt3,1520(a7)", instruction_debug(&lh, 0));
@ -411,10 +411,10 @@ mod test {
#[test] #[test]
fn test_opw() { fn test_opw() {
let addw: Instruction = Instruction::new(0b0000000_10000_10001_000_11100_0111011_u64.to_le()); let addw: Instruction = Instruction::new(0b0000000_10000_10001_000_11100_0111011);
let sllw: Instruction = Instruction::new(0b0000000_10000_10001_001_11100_0111011_u64.to_le()); let sllw: Instruction = Instruction::new(0b0000000_10000_10001_001_11100_0111011);
let srlw: Instruction = Instruction::new(0b0000000_10000_10001_101_11100_0111011_u64.to_le()); let srlw: Instruction = Instruction::new(0b0000000_10000_10001_101_11100_0111011);
let sraw: Instruction = Instruction::new(0b0100000_10000_10001_101_11100_0111011_u64.to_le()); let sraw: Instruction = Instruction::new(0b0100000_10000_10001_101_11100_0111011);
assert_eq!("addw\tt3,a7,a6", instruction_debug(&addw, 0)); assert_eq!("addw\tt3,a7,a6", instruction_debug(&addw, 0));
assert_eq!("sllw\tt3,a7,a6", instruction_debug(&sllw, 0)); assert_eq!("sllw\tt3,a7,a6", instruction_debug(&sllw, 0));
@ -424,9 +424,9 @@ mod test {
#[test] #[test]
fn test_opwi() { fn test_opwi() {
let addiw: Instruction =Instruction::new(0b000000000000_10001_000_11100_0011011_u64.to_le()); let addiw: Instruction =Instruction::new(0b000000000000_10001_000_11100_0011011);
let slliw: Instruction = Instruction::new(0b0000000_10000_10001_001_11100_0011011_u64.to_le()); let slliw: Instruction = Instruction::new(0b0000000_10000_10001_001_11100_0011011);
let srai: Instruction = Instruction::new(0b010000010001_10001_101_11100_0010011_u64.to_le()); let srai: Instruction = Instruction::new(0b010000010001_10001_101_11100_0010011);
assert_eq!("addiw\tt3,a7,0x0", instruction_debug(&addiw, 0)); assert_eq!("addiw\tt3,a7,0x0", instruction_debug(&addiw, 0));
assert_eq!("slliw\tt3,a7,0x10", instruction_debug(&slliw, 0)); assert_eq!("slliw\tt3,a7,0x10", instruction_debug(&slliw, 0));
assert_eq!("srai\tt3,a7,17", instruction_debug(&srai, 0)); assert_eq!("srai\tt3,a7,17", instruction_debug(&srai, 0));
@ -435,13 +435,13 @@ mod test {
#[test] #[test]
fn test_br() { fn test_br() {
let beq: Instruction = Instruction::new(0b0000000_10000_10001_000_00000_1100011_u64.to_le()); let beq: Instruction = Instruction::new(0b0000000_10000_10001_000_00000_1100011);
let bne: Instruction = Instruction::new(0b0000000_10000_10001_001_00000_1100011_u64.to_le()); let bne: Instruction = Instruction::new(0b0000000_10000_10001_001_00000_1100011);
let blt: Instruction = Instruction::new(0b0000000_10000_10001_100_00000_1100011_u64.to_le()); let blt: Instruction = Instruction::new(0b0000000_10000_10001_100_00000_1100011);
let bge: Instruction = Instruction::new(0b0000000_10000_10001_101_00000_1100011_u64.to_le()); let bge: Instruction = Instruction::new(0b0000000_10000_10001_101_00000_1100011);
let bge2: Instruction = Instruction::new(0x00f75863_u64.to_le()); let bge2: Instruction = Instruction::new(0x00f75863);
let bltu: Instruction = Instruction::new(0b0000000_10000_10001_110_00000_1100011_u64.to_le()); let bltu: Instruction = Instruction::new(0b0000000_10000_10001_110_00000_1100011);
let bgeu: Instruction = Instruction::new(0b0000000_10000_10001_111_00000_1100011_u64.to_le()); let bgeu: Instruction = Instruction::new(0b0000000_10000_10001_111_00000_1100011);
assert_eq!("blt\ta7,a6,0", instruction_debug(&blt, 0)); assert_eq!("blt\ta7,a6,0", instruction_debug(&blt, 0));
assert_eq!("bge\ta7,a6,0", instruction_debug(&bge, 0)); assert_eq!("bge\ta7,a6,0", instruction_debug(&bge, 0));
assert_eq!("bge\ta4,a5,104d4", instruction_debug(&bge2, 0x104c4)); assert_eq!("bge\ta4,a5,104d4", instruction_debug(&bge2, 0x104c4));
@ -461,72 +461,72 @@ mod test {
a = a + b; a = a + b;
b = a - b; b = a - b;
*/ */
assert_eq!("addi sp,sp,-32", instruction_debug(&Instruction::new(0xfe010113_u64.to_le()), 0)); assert_eq!("addi sp,sp,-32", instruction_debug(&Instruction::new(0xfe010113), 0));
assert_eq!("sd s0,24(sp)", instruction_debug(&Instruction::new(0x00813c23_u64.to_le()), 0)); assert_eq!("sd s0,24(sp)", instruction_debug(&Instruction::new(0x00813c23), 0));
assert_eq!("addi s0,sp,32", instruction_debug(&Instruction::new(0x02010413_u64.to_le()), 0)); assert_eq!("addi s0,sp,32", instruction_debug(&Instruction::new(0x02010413), 0));
assert_eq!("sw zero,-20(s0)", instruction_debug(&Instruction::new(0xfe042623_u64.to_le()), 0)); assert_eq!("sw zero,-20(s0)", instruction_debug(&Instruction::new(0xfe042623), 0));
assert_eq!("addi a5,zero,5", instruction_debug(&Instruction::new(0x00500793_u64.to_le()), 0)); assert_eq!("addi a5,zero,5", instruction_debug(&Instruction::new(0x00500793), 0));
assert_eq!("sw a5,-24(s0)", instruction_debug(&Instruction::new(0xfef42423_u64.to_le()), 0)); assert_eq!("sw a5,-24(s0)", instruction_debug(&Instruction::new(0xfef42423), 0));
assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783_u64.to_le()), 0)); assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783), 0));
assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623_u64.to_le()), 0)); assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623), 0));
assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783_u64.to_le()), 0)); assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783), 0));
assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713_u64.to_le()), 0)); assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713), 0));
assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783_u64.to_le()), 0)); assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783), 0));
assert_eq!("mulw a5,a4,a5", instruction_debug(&Instruction::new(0x02f707bb_u64.to_le()), 0)); assert_eq!("mulw a5,a4,a5", instruction_debug(&Instruction::new(0x02f707bb), 0));
assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623_u64.to_le()), 0)); assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623), 0));
assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783_u64.to_le()), 0)); assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783), 0));
assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713_u64.to_le()), 0)); assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713), 0));
assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783_u64.to_le()), 0)); assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783), 0));
assert_eq!("addw a5,a4,a5", instruction_debug(&Instruction::new(0x00f707bb_u64.to_le()), 0)); assert_eq!("addw a5,a4,a5", instruction_debug(&Instruction::new(0x00f707bb), 0));
assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623_u64.to_le()), 0)); assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623), 0));
assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783_u64.to_le()), 0)); assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783), 0));
assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713_u64.to_le()), 0)); assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713), 0));
assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783_u64.to_le()), 0)); assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783), 0));
assert_eq!("subw a5,a4,a5", instruction_debug(&Instruction::new(0x40f707bb_u64.to_le()), 0)); assert_eq!("subw a5,a4,a5", instruction_debug(&Instruction::new(0x40f707bb), 0));
assert_eq!("sw a5,-24(s0)", instruction_debug(&Instruction::new(0xfef42423_u64.to_le()), 0)); assert_eq!("sw a5,-24(s0)", instruction_debug(&Instruction::new(0xfef42423), 0));
assert_eq!("addi a5,zero,0", instruction_debug(&Instruction::new(0x00000793_u64.to_le()), 0)); assert_eq!("addi a5,zero,0", instruction_debug(&Instruction::new(0x00000793), 0));
assert_eq!("addi a0,a5,0", instruction_debug(&Instruction::new(0x00078513_u64.to_le()), 0)); assert_eq!("addi a0,a5,0", instruction_debug(&Instruction::new(0x00078513), 0));
assert_eq!("ld s0,24(sp)", instruction_debug(&Instruction::new(0x01813403_u64.to_le()), 0)); assert_eq!("ld s0,24(sp)", instruction_debug(&Instruction::new(0x01813403), 0));
assert_eq!("addi sp,sp,32", instruction_debug(&Instruction::new(0x02010113_u64.to_le()), 0)); assert_eq!("addi sp,sp,32", instruction_debug(&Instruction::new(0x02010113), 0));
assert_eq!("jalr zero,0(ra)", instruction_debug(&Instruction::new(0x00008067_u64.to_le()), 0)); assert_eq!("jalr zero,0(ra)", instruction_debug(&Instruction::new(0x00008067), 0));
} }
#[test] #[test]
fn test_fibo() { fn test_fibo() {
assert_eq!("jal zero,10504", instruction_debug(&Instruction::new(0x0500006f_u64.to_le()), 0x104b4)); assert_eq!("jal zero,10504", instruction_debug(&Instruction::new(0x0500006f), 0x104b4));
assert_eq!("blt a4,a5,104b8", instruction_debug(&Instruction::new(0xfaf740e3_u64.to_le()), 0x10518)); assert_eq!("blt a4,a5,104b8", instruction_debug(&Instruction::new(0xfaf740e3), 0x10518));
} }
#[test] #[test]
fn test_mul_prog() { fn test_mul_prog() {
assert_eq!("addi sp,sp,-32", instruction_debug(&Instruction::new(0xfe010113_u64.to_le()), 0)); assert_eq!("addi sp,sp,-32", instruction_debug(&Instruction::new(0xfe010113), 0));
assert_eq!("sd s0,24(sp)", instruction_debug(&Instruction::new(0x00813c23_u64.to_le()), 0)); assert_eq!("sd s0,24(sp)", instruction_debug(&Instruction::new(0x00813c23), 0));
assert_eq!("addi s0,sp,32", instruction_debug(&Instruction::new(0x02010413_u64.to_le()), 0)); assert_eq!("addi s0,sp,32", instruction_debug(&Instruction::new(0x02010413), 0));
assert_eq!("addi a5,zero,5", instruction_debug(&Instruction::new(0x00500793_u64.to_le()), 0)); assert_eq!("addi a5,zero,5", instruction_debug(&Instruction::new(0x00500793), 0));
assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623_u64.to_le()), 0)); assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623), 0));
assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783_u64.to_le()), 0)); assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783), 0));
assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713_u64.to_le()), 0)); assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713), 0));
assert_eq!("addi a5,a4,0", instruction_debug(&Instruction::new(0x00070793_u64.to_le()), 0)); assert_eq!("addi a5,a4,0", instruction_debug(&Instruction::new(0x00070793), 0));
assert_eq!("slliw a5,a5,0x2", instruction_debug(&Instruction::new(0x0027979b_u64.to_le()), 0)); assert_eq!("slliw a5,a5,0x2", instruction_debug(&Instruction::new(0x0027979b), 0));
assert_eq!("addw a5,a5,a4", instruction_debug(&Instruction::new(0x00e787bb_u64.to_le()), 0)); assert_eq!("addw a5,a5,a4", instruction_debug(&Instruction::new(0x00e787bb), 0));
assert_eq!("sw a5,-24(s0)", instruction_debug(&Instruction::new(0xfef42423_u64.to_le()), 0)); assert_eq!("sw a5,-24(s0)", instruction_debug(&Instruction::new(0xfef42423), 0));
assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783_u64.to_le()), 0)); assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783), 0));
assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713_u64.to_le()), 0)); assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713), 0));
assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783_u64.to_le()), 0)); assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783), 0));
assert_eq!("mulw a5,a4,a5", instruction_debug(&Instruction::new(0x02f707bb_u64.to_le()), 0)); assert_eq!("mulw a5,a4,a5", instruction_debug(&Instruction::new(0x02f707bb), 0));
assert_eq!("sw a5,-28(s0)", instruction_debug(&Instruction::new(0xfef42223_u64.to_le()), 0)); assert_eq!("sw a5,-28(s0)", instruction_debug(&Instruction::new(0xfef42223), 0));
assert_eq!("lw a5,-28(s0)", instruction_debug(&Instruction::new(0xfe442783_u64.to_le()), 0)); assert_eq!("lw a5,-28(s0)", instruction_debug(&Instruction::new(0xfe442783), 0));
assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713_u64.to_le()), 0)); assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713), 0));
assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783_u64.to_le()), 0)); assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783), 0));
assert_eq!("divw a5,a4,a5", instruction_debug(&Instruction::new(0x02f747bb_u64.to_le()), 0)); assert_eq!("divw a5,a4,a5", instruction_debug(&Instruction::new(0x02f747bb), 0));
assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623_u64.to_le()), 0)); assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623), 0));
assert_eq!("addi a5,zero,0", instruction_debug(&Instruction::new(0x00000793_u64.to_le()), 0)); assert_eq!("addi a5,zero,0", instruction_debug(&Instruction::new(0x00000793), 0));
assert_eq!("addi a0,a5,0", instruction_debug(&Instruction::new(0x00078513_u64.to_le()), 0)); assert_eq!("addi a0,a5,0", instruction_debug(&Instruction::new(0x00078513), 0));
assert_eq!("ld s0,24(sp)", instruction_debug(&Instruction::new(0x01813403_u64.to_le()), 0)); assert_eq!("ld s0,24(sp)", instruction_debug(&Instruction::new(0x01813403), 0));
assert_eq!("addi sp,sp,32", instruction_debug(&Instruction::new(0x02010113_u64.to_le()), 0)); assert_eq!("addi sp,sp,32", instruction_debug(&Instruction::new(0x02010113), 0));
assert_eq!("jalr zero,0(ra)", instruction_debug(&Instruction::new(0x00008067_u64.to_le()), 0)); assert_eq!("jalr zero,0(ra)", instruction_debug(&Instruction::new(0x00008067), 0));
} }
} }

View File

@ -1,17 +1,38 @@
//! # Interrupt
//!
//! This module contains an interrupt Handler.
//! The methodes one_trick and idle aren't implemented for now
/// # Interrupt
///
/// Interrupt Handler
#[derive(PartialEq)] #[derive(PartialEq)]
pub struct Interrupt { pub struct Interrupt {
/// Current Status
level: InterruptStatus level: InterruptStatus
} }
impl Interrupt { impl Interrupt {
/// Interrupt constructor
///
/// ### Return
/// Interrupt with status Off
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
level: InterruptStatus::InterruptOff level: InterruptStatus::InterruptOff
} }
} }
/// Interrupt setter
/// Change the value of the Interrupt
///
/// ### Parameters
/// - **self** the interupt handler
/// - **new_status** the new status value
///
/// ### return
/// The previus status
pub fn set_status(&mut self, new_status: InterruptStatus) -> InterruptStatus { pub fn set_status(&mut self, new_status: InterruptStatus) -> InterruptStatus {
let old = self.level; let old = self.level;
self.level = new_status; self.level = new_status;
@ -25,6 +46,7 @@ impl Interrupt {
todo!(); todo!();
} }
/// Interupt getter
pub fn get_status(&self) -> InterruptStatus { pub fn get_status(&self) -> InterruptStatus {
self.level self.level
} }

View File

@ -1,9 +1,25 @@
//! # Loader
//!
//! This module contains a loader for file section.
//! Following the common standard file format for executable files
//! [ELF (Executable and Linkable Format)](https://en.wikipedia.org/wiki/Executable_and_Linkable_Forma)
//!
//! It's used to charge a programme into the machine from a binary file (.guac files)
//!
//! Basic usage:
//!
//! ```
//! let args = Args::parse();
//! let mut machine = Machine::new(args.debug & 1 != 0, read_settings().unwrap());
//! let (loader, ptr) = loader::Loader::new(args.executable.as_str(), &mut machine, 0).expect("An error occured while parsing the program");
//! ```
use crate::Machine; use crate::Machine;
use std::fs; use std::fs;
use std::io::Read; use std::io::Read;
/// The elf header defines principes aspects of the binary files, it's place at the start of the file /// The elf header defines principes aspects of the binary files, it's place at the start of the file
/// see <https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header> for more informations /// see [ELF file Header](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header) for more informations
pub struct ElfHeader { pub struct ElfHeader {
/// Defines whether the file is big or little endian /// Defines whether the file is big or little endian
/// true correspond to big endian, false otherwise /// true correspond to big endian, false otherwise
@ -463,12 +479,7 @@ impl Loader {
buf[k] = self.bytes.get(section.image_offset as usize + j + k).copied().ok_or(LoaderError::ParsingError(format!("index 0x{:x} is out of bound because list have a size of 0x{:x} (image offset 0x{:x}, j 0x{:x}, k 0x{:x})", section.image_offset as usize + j + k, self.bytes.len(), section.image_offset, j, k)))?; buf[k] = self.bytes.get(section.image_offset as usize + j + k).copied().ok_or(LoaderError::ParsingError(format!("index 0x{:x} is out of bound because list have a size of 0x{:x} (image offset 0x{:x}, j 0x{:x}, k 0x{:x})", section.image_offset as usize + j + k, self.bytes.len(), section.image_offset, j, k)))?;
} }
} }
machine.write_memory(4, start_index + section.virt_addr as usize + j, u32::from_le_bytes(buf) as u64);
machine.write_memory(1, start_index + section.virt_addr as usize + j, buf[0] as u64);
machine.write_memory(1, start_index + section.virt_addr as usize + j + 1, buf[1] as u64);
machine.write_memory(1, start_index + section.virt_addr as usize + j + 2, buf[2] as u64);
machine.write_memory(1, start_index + section.virt_addr as usize + j + 3, buf[3] as u64);
} }
} }
} }

View File

@ -96,7 +96,6 @@ pub struct Machine {
//creer une struct cfg(configuration) qui s'initialise avec valeur dans un fichier cfg //creer une struct cfg(configuration) qui s'initialise avec valeur dans un fichier cfg
num_phy_page: u64, num_phy_page: u64,
pub page_size: u64, pub page_size: u64,
pub user_stack_size: u64,
/// Current machine status /// Current machine status
pub status: MachineStatus pub status: MachineStatus
} }
@ -116,8 +115,7 @@ impl Machine {
let num_phy_page = *settings.get(&MachineSettingKey::NumPhysPages).unwrap(); let num_phy_page = *settings.get(&MachineSettingKey::NumPhysPages).unwrap();
let page_size = *settings.get(&MachineSettingKey::PageSize).unwrap(); let page_size = *settings.get(&MachineSettingKey::PageSize).unwrap();
let user_stack_size = *settings.get(&MachineSettingKey::UserStackSize).unwrap(); let mem_size = (page_size*num_phy_page*100_000) as usize;
let mem_size = (page_size*num_phy_page) as usize;
Machine { Machine {
debug, debug,
@ -131,8 +129,7 @@ impl Machine {
registers_trace : String::from(""), registers_trace : String::from(""),
status: MachineStatus::SystemMode, status: MachineStatus::SystemMode,
num_phy_page, num_phy_page,
page_size, page_size
user_stack_size
} }
} }
@ -287,7 +284,7 @@ impl Machine {
*elem = self.main_memory[self.pc as usize + i]; *elem = self.main_memory[self.pc as usize + i];
} }
let val = u32::from_le_bytes(val) as u64; let val = u32::from_be_bytes(val) as u64;
let inst : Instruction = Instruction::new(val); let inst : Instruction = Instruction::new(val);
if self.debug { if self.debug {
self.print_status(); self.print_status();
@ -428,10 +425,10 @@ impl Machine {
RISCV_OPI_XORI => compute(&core::ops::BitXor::bitxor, rs1, imm12), RISCV_OPI_XORI => compute(&core::ops::BitXor::bitxor, rs1, imm12),
RISCV_OPI_ORI => compute(&core::ops::BitOr::bitor, rs1, imm12), RISCV_OPI_ORI => compute(&core::ops::BitOr::bitor, rs1, imm12),
RISCV_OPI_ANDI => compute(&core::ops::BitAnd::bitand, rs1, imm12), RISCV_OPI_ANDI => compute(&core::ops::BitAnd::bitand, rs1, imm12),
RISCV_OPI_SLLI => compute(&core::ops::Shl::shl, rs1, shamt), RISCV_OPI_SLLI => compute(&core::ops::Shl::shl, rs1, imm12),
RISCV_OPI_SRI => if inst.funct7_smaller == RISCV_OPI_SRI_SRLI { RISCV_OPI_SRI => if inst.funct7_smaller == RISCV_OPI_SRI_SRLI {
compute(&|a, b| { (a >> b) & self.shiftmask[inst.shamt as usize] as i64 }, rs1, shamt) compute(&|a, b| { (a >> b) & self.shiftmask[inst.shamt as usize] as i64 }, rs1, shamt)
} else { // SRAI } else {
compute(&core::ops::Shr::shr, rs1, shamt) compute(&core::ops::Shr::shr, rs1, shamt)
} }
_ => Err(format!("Unreachable in opi_instruction match! Instruction was {:?}", inst))? _ => Err(format!("Unreachable in opi_instruction match! Instruction was {:?}", inst))?
@ -504,8 +501,8 @@ impl Machine {
let local_data = self.int_reg.get_reg(inst.rs1); let local_data = self.int_reg.get_reg(inst.rs1);
let result = match inst.funct3 { let result = match inst.funct3 {
RISCV_OPIW_ADDIW => local_data + inst.imm12_I_signed as i64, RISCV_OPIW_ADDIW => local_data + inst.imm12_I_signed as i64,
RISCV_OPIW_SLLIW => local_data << inst.rs2, RISCV_OPIW_SLLIW => local_data << inst.shamt,
RISCV_OPIW_SRW => (local_data >> inst.rs2) & if inst.funct7 == RISCV_OPIW_SRW_SRLIW { self.shiftmask[32 + inst.rs2 as usize] as i64 } else { 1 }, RISCV_OPIW_SRW => (local_data >> inst.shamt) & if inst.funct7 == RISCV_OPIW_SRW_SRLIW { self.shiftmask[32 + inst.shamt as usize] as i64 } else { 1 },
_ => Err(format!("Unreachable in op_instruction match! Instruction was {:?}", inst))? _ => Err(format!("Unreachable in op_instruction match! Instruction was {:?}", inst))?
}; };
self.int_reg.set_reg(inst.rd, result); self.int_reg.set_reg(inst.rd, result);
@ -522,7 +519,7 @@ impl Machine {
// Match case for multiplication operations (in standard extension RV32M) // Match case for multiplication operations (in standard extension RV32M)
match inst.funct3 { match inst.funct3 {
RISCV_OPW_M_MULW => self.int_reg.set_reg(inst.rd, (local_data_a * local_data_b) & 0xffffffff), RISCV_OPW_M_MULW => self.int_reg.set_reg(inst.rd, local_data_a * local_data_b),
RISCV_OPW_M_DIVW => self.int_reg.set_reg(inst.rd, local_data_a / local_data_b), RISCV_OPW_M_DIVW => self.int_reg.set_reg(inst.rd, local_data_a / local_data_b),
RISCV_OPW_M_DIVUW => self.int_reg.set_reg(inst.rd, local_data_a_unsigned / local_data_b_unsigned), RISCV_OPW_M_DIVUW => self.int_reg.set_reg(inst.rd, local_data_a_unsigned / local_data_b_unsigned),
RISCV_OPW_M_REMW => self.int_reg.set_reg(inst.rd, local_data_a % local_data_b), RISCV_OPW_M_REMW => self.int_reg.set_reg(inst.rd, local_data_a % local_data_b),
@ -541,9 +538,9 @@ impl Machine {
}, },
RISCV_OPW_SLLW => self.int_reg.set_reg(inst.rd, local_dataa << (local_datab & 0x1f)), RISCV_OPW_SLLW => self.int_reg.set_reg(inst.rd, local_dataa << (local_datab & 0x1f)),
RISCV_OPW_SRW => if inst.funct7 == RISCV_OPW_SRW_SRLW { RISCV_OPW_SRW => if inst.funct7 == RISCV_OPW_SRW_SRLW {
self.int_reg.set_reg(inst.rd, local_dataa >> (local_datab /* & 0x1f */) & self.shiftmask[32 + local_datab as usize] as i64) self.int_reg.set_reg(inst.rd, local_dataa >> (local_datab & 0x1f) & self.shiftmask[32 + local_datab as usize] as i64)
} else { // SRAW } else { // SRAW
self.int_reg.set_reg(inst.rd, local_dataa >> (local_datab /* & 0x1f */)) self.int_reg.set_reg(inst.rd, local_dataa >> (local_datab & 0x1f))
}, },
_ => Err(format!("Unreachable in opw_instruction match! Instruction was {:?}", inst))? _ => Err(format!("Unreachable in opw_instruction match! Instruction was {:?}", inst))?
} }

View File

@ -1,20 +1,37 @@
///! FILE.TXT FORMAT Representing machine memory memory //! # Memory Comparator
/// - PC //!
/// - SP //! This module contains a MemChecker.
/// - Section_1 //!
/// - Section_2 //! It's used to compare state memory obtained after a dump memory from NachOS and BurritOS.
/// - ... //!
/// - Section_n //! This module is used exclusively for testing the instruction simulator.
/// //!
/// Each section is divided in 3 parts, on two lines of text //! Basic usage:
/// addr SPACE len //!
/// content //! ```
//! let mut m = Machine::new(true, get_debug_configuration());
//! let mut MemChecker = mem_cmp::MemChecker::from(get_full_path!("memory", expr));
//! mem_cmp::MemChecker::fill_memory_from_mem_checker(&MemChecker, &mut m);
//! ```
//!
//!
//! ! FILE.TXT FORMAT Representing machine memory memory
//! - PC
//! - SP
//! - Section_1
//! - Section_2
//! - ...
//! - Section_n
//!
//! Each section is divided in 3 parts, on two lines of text
//! addr SPACE len
//! content
use std::{fs, io::{BufRead, BufReader, Lines, Error}}; use std::{fs, io::{BufRead, BufReader, Lines, Error}};
use crate::Machine; use crate::Machine;
/// File section /// File section
pub struct SectionFormat { pub struct SectionFormat{
/// Memory address of the section /// Memory address of the section
addr: String, addr: String,
/// The size of data in bytes /// The size of data in bytes
@ -26,7 +43,7 @@ pub struct SectionFormat {
/// # Memory section /// # Memory section
/// ///
/// Representation of a section of memory from BurritOS or NachOS /// Representation of a section of memory from BurritOS or NachOS
pub struct Section { pub struct Section{
/// Memory address of the section /// Memory address of the section
addr: usize, addr: usize,
/// The size of data in bytes /// The size of data in bytes
@ -36,23 +53,15 @@ pub struct Section {
} }
impl Section { impl Section {
/// Creates a memory section from a SectionFormat /// Creates a memory section from a SectionFormat
fn from(section: &mut SectionFormat) -> Section { fn from(section: &SectionFormat) -> Section {
let addr = usize::from_str_radix(&section.addr, 16).unwrap_or_default(); let addr = usize::from_str_radix(&section.addr, 16).unwrap_or_default();
let len = usize::from_str_radix(&section.len, 16).unwrap_or_default(); let len = usize::from_str_radix(&section.len, 16).unwrap_or_default();
let content: Vec<u8>; let content: Vec<u8> = section.content.as_bytes().chunks(2).map(|x| {
unsafe { u8::from_str_radix(std::str::from_utf8(x).unwrap_or_default(), 16).unwrap_or_default()
content = section.content.as_bytes_mut() }).collect();
.chunks_mut(4).map( Section{addr, len, content}
|x| {
x.reverse();
u8::from_str_radix(
std::str::from_utf8(x).unwrap_or_default(), 16
).unwrap_or_default()
}
).collect();
}
Section { addr, len, content }
} }
/// Pretty prints a memory section /// Pretty prints a memory section
@ -76,7 +85,7 @@ pub struct MemChecker {
} }
impl MemChecker { impl MemChecker{
///Translate lines of a file in e Vector of String ///Translate lines of a file in e Vector of String
///We need this method to parse the memory we received ///We need this method to parse the memory we received
@ -102,7 +111,7 @@ impl MemChecker {
/// Extract the values of pc, sp and sections /// Extract the values of pc, sp and sections
/// ///
/// ### Parameter /// ### Parameter
/// -**path** addr to the file /// - **path** addr to the file
/// ///
/// ### Return /// ### Return
/// Mem-checker filled /// Mem-checker filled
@ -134,12 +143,12 @@ impl MemChecker {
} }
else { else {
//lecture ligne CONTENT //lecture ligne CONTENT
let mut section_f = SectionFormat { let section_f = SectionFormat{
addr: tmp_addr_str.clone(), addr: tmp_addr_str.clone(),
len: tmp_len_str.clone(), len: tmp_len_str.clone(),
content: current_line.clone().replace(' ', ""), content: current_line.clone().replace(' ', ""),
}; };
sections.push(Section::from(&mut section_f)); sections.push(Section::from(&section_f));
} }
} }
@ -177,7 +186,7 @@ impl MemChecker {
machine.pc = m_c.pc as u64; machine.pc = m_c.pc as u64;
for section in m_c.sections.iter() { for section in m_c.sections.iter() {
for (i, b) in section.content.iter().enumerate() { for (i,b) in section.content.iter().enumerate() {
machine.main_memory[section.addr + i] = *b; machine.main_memory[section.addr + i] = *b;
} }
} }
@ -243,12 +252,12 @@ mod tests {
#[test] #[test]
fn test_create_section_content(){ fn test_create_section_content(){
let mut section_format = SectionFormat{ let section_format = SectionFormat{
addr: "0".to_string(), addr: "0".to_string(),
len: "0".to_string(), len: "0".to_string(),
content: "00FF0AA0A5".to_string(), content: "00FF0AA0A5".to_string(),
}; };
let section = Section::from(&mut section_format); let section = Section::from(&section_format);
let expected_vec: Vec<u8> = vec![0u8, 255u8, 10u8, 160u8, 165u8]; let expected_vec: Vec<u8> = vec![0u8, 255u8, 10u8, 160u8, 165u8];
assert_eq!(section.content, expected_vec); assert_eq!(section.content, expected_vec);
} }

View File

@ -1,18 +1,38 @@
//! # MMU
//!
//! This module contains a MMU implementation
//!
//! This part isn't tested nor integrated to BurritOS because of the lack of pagination implementation
//!
//!
use crate::simulator::translationtable::*; use crate::simulator::translationtable::*;
use crate::simulator::machine::*; use crate::simulator::machine::*;
/// # Memory Management Unit
/// An MMU possesses a single reference to a translation table
/// This table is associated to the current process
pub struct MMU <'a>{ pub struct MMU <'a>{
/* Un MMU possède une seule référence vers une table des pages à un instant donné /// Reference to a page table
* Cette table est associée au processus courant
* Cette référence peut etre mise a jour par exemple lors d'un switchTo
*/
translationTable : Option<&'a mut TranslationTable>, translationTable : Option<&'a mut TranslationTable>,
/// The number of physique pages
numPhyPages : u64, numPhyPages : u64,
/// Size of each page
pageSize : u64 pageSize : u64
} }
impl <'a>MMU <'_>{ impl <'a>MMU <'_>{
/// Create a MMU with a None reference for the translation table
///
/// ### Parameters
///
/// - **numPhyPages** the number of physique pages
/// - **pageSize** the size of a page
///
/// ### Return
///
/// MMU with None reference and the value for the number of physical pages and pae size associated
fn create(numPhyPages: u64, pageSize: u64) -> MMU <'a>{ fn create(numPhyPages: u64, pageSize: u64) -> MMU <'a>{
MMU { MMU {
translationTable : None, translationTable : None,

View File

@ -1,3 +1,12 @@
//! This module implement an Instruction simulator
//! with all the simulated hardware requested to run the Machine :
//! - **MMU**
//! - **Processor**
//! - **RAM**
//! - **Interruption Controler**
//!
//! The disk, the console and the serial coupler aren't implmented for now
//!
pub mod machine; pub mod machine;
pub mod error; pub mod error;
pub mod instruction; pub mod instruction;
@ -214,7 +223,7 @@ pub mod global {
/// ///
/// Shift left logical immediate /// Shift left logical immediate
/// ///
/// `SLLI rd, rs1, shamt` => `rd <- rs1 << shamt` /// `SLLI rd, rs1, shamt` => `rd <- rs1 >> shamt`
pub const RISCV_OPI_SLLI: u8 = 0x1; pub const RISCV_OPI_SLLI: u8 = 0x1;
/// Shift right immediate, may be SRAI or SRLI /// Shift right immediate, may be SRAI or SRLI
pub const RISCV_OPI_SRI: u8 = 0x5; pub const RISCV_OPI_SRI: u8 = 0x5;

View File

@ -1,23 +1,35 @@
//Nombre maximum de correspondances dans une table des pages //! # Translation Table
//Cette donnée devra a terme etre recupérée depuis un fichier de configuration //!
//! This module implement a trnslation table used for fot the MMU Emulator
//!
//! This part isn't tested nor integrated to BurritOS,
//! but will be useful in the futur when the pagination will be implemented.
//!
//! It contains:
//! - all the setters and getters for translation table
//! - modificaters of table values
/// Maximum number in a Page Table
/// For a futur evolution of program, this value should be load from a configuration file
const MaxVirtPages : u64 = 200000; const MaxVirtPages : u64 = 200000;
/// Translation Table corresponding to a process
/* Une table de correspondance propre à un processus /// An iteration of type TranslationTable should be possesses by an oject of type Process
* Une variable de type TranslationTable devra etre possédée par un objet de type Process
*/
pub struct TranslationTable{ pub struct TranslationTable{
//capacité de cette table <=> nombre de correspondances possibles /// Table size <=> nb of possible translation
//A voir si cette donnée doit etre immuable
pub maxNumPages : u64, pub maxNumPages : u64,
//la table en question ///The table *Vec impemente Index Trait*
//Vec implemente le trait Index, donc un bon choix
pub pageTable : Vec<PageTableEntry> pub pageTable : Vec<PageTableEntry>
} }
impl TranslationTable { impl TranslationTable {
/// TranslationTable constructor
///
/// ### Return
/// TranslationTable with an empty Vector
pub fn create() -> TranslationTable { pub fn create() -> TranslationTable {
let mut tmp_vec : Vec<PageTableEntry> = Vec::new(); let mut tmp_vec : Vec<PageTableEntry> = Vec::new();

View File

@ -93,17 +93,17 @@ pub fn read_settings() -> Result<Settings, Error> {
} }
/// Returns a mock configuration for Machine unit testing /// Returns a mock configuration for Machine unit testing
///
/// FIXME: Does not cover the whole configuration yet
pub fn get_debug_configuration() -> Settings { pub fn get_debug_configuration() -> Settings {
let mut settings_map = Settings::new(); let mut settings_map = Settings::new();
settings_map.insert(MachineSettingKey::PageSize, 2048); settings_map.insert(MachineSettingKey::PageSize, 128);
settings_map.insert(MachineSettingKey::NumPhysPages, 8192); settings_map.insert(MachineSettingKey::NumPhysPages, 400);
settings_map.insert(MachineSettingKey::UserStackSize, 4096);
settings_map settings_map
} }
/// Removes comments and empty lines /// Filters out empty lines and comments from the reader `BufReader`.
///
/// Returns a [`Vec<String>`], each entry containing a valid
/// line from the input file.
fn filter_garbage<R: std::io::Read>(reader: BufReader<R>) -> Vec<String> { fn filter_garbage<R: std::io::Read>(reader: BufReader<R>) -> Vec<String> {
reader.lines() reader.lines()
.map(|l| l.unwrap()) .map(|l| l.unwrap())
@ -111,11 +111,12 @@ fn filter_garbage<R: std::io::Read>(reader: BufReader<R>) -> Vec<String> {
.collect() .collect()
} }
/// Adds a <K, V> pair to a [`Settings`] map.
/// Inserts user settings into setting map ///
/// Returns the updated [`Settings`].
fn update_settings_map(mut settings_map: Settings, key: &str, setting: &str) -> Settings { fn update_settings_map(mut settings_map: Settings, key: &str, setting: &str) -> Settings {
let key = MachineSettingKey::from(key); let key = MachineSettingKey::from(key);
let setting = setting.parse::<u64>().unwrap_or(0); let setting = str::parse::<u64>(setting).unwrap_or(0);
settings_map.insert(key, setting); settings_map.insert(key, setting);
settings_map settings_map
} }

View File

@ -1,3 +1,6 @@
//! This module contains data type definitions used in other parts the BurritOS
//! They are separated from the rest of the operating system so as to promote
//! reusability and to separate data constructs proper from state and actions.
pub mod list; pub mod list;
pub mod objaddr; pub mod objaddr;
pub mod cfg; pub mod cfg;

View File

@ -17,9 +17,13 @@ use crate::kernel::{synch::{ Semaphore, Lock }, thread::Thread};
/// calls. /// calls.
#[derive(PartialEq)] #[derive(PartialEq)]
pub struct ObjAddr { pub struct ObjAddr {
/// Id of the last added object
last_id: i32, last_id: i32,
/// List of [Semaphore] added in this struct. Each is keyed with a unique i32 id.
semaphores: HashMap<i32, Semaphore>, semaphores: HashMap<i32, Semaphore>,
/// List of [Lock] added in this struct. Each is keyed with a unique i32 id.
locks: HashMap<i32, Lock>, locks: HashMap<i32, Lock>,
/// List of threads known by this instance of ObjAddr (useful for managing lock ownership)
threads: HashMap<i32, Rc<RefCell<Thread>>>, threads: HashMap<i32, Rc<RefCell<Thread>>>,
} }

View File

@ -1,13 +1,15 @@
int main() { int main() {
int x = 0; int x = 0;
int y = 1; int y = 1;
if (x > y) { while (x <= y) {
x += 1; if (x > y) {
} x += 1;
if (x == y) { } else if (x == y) {
x += y; x += y;
} } else if (x < y) {
if (x < y) { y += 1;
y += 1; } else {
return 0;
}
} }
} }

View File

@ -1,4 +1,4 @@
PROGRAMS = halt.guac prints.guac producteur_consommateur.guac lecteur_redacteur.guac join.guac matmult.guac PROGRAMS = halt.guac prints.guac producteur_consommateur.guac join.guac
TOPDIR = ../.. TOPDIR = ../..
include $(TOPDIR)/Makefile.rules include $(TOPDIR)/Makefile.rules

View File

@ -1,60 +0,0 @@
#include "userlib/syscall.h"
#include "userlib/libnachos.h"
SemId red;
SemId mutex;
SemId util;
int nblect = 0;
int nbWrite = 0;
void lecteur() {
while(1) {
P(red);
P(mutex);
if (nblect == 0) {
V(util);
}
nblect++;
V(mutex);
V(red);
n_printf("Lecture de l'information \n");
if(nbWrite == 10)
return;
P(mutex);
nblect--;
if(nblect == 0) {
V(util);
}
V(mutex);
}
Exit(nblect);
}
void redacteur() {
while(1) {
P(red);
P(util);
V(red);
n_printf((char*)"Ecriture de l'information\n");
nbWrite++;
if(nbWrite == 10)
return;
V(util);
}
Exit(nbWrite);
}
int main() {
red = SemCreate((char*)"redacteur", 1);
mutex = SemCreate((char*)"mutex lecteur redacteur", 1);
util = SemCreate((char*)"Mutex util lecteur redacteur", 1);
ThreadId lecteurTh = threadCreate((char*)"Lecteur", (VoidNoArgFunctionPtr) lecteur);
ThreadId lecteur1 = threadCreate((char*)"Lecteur", (VoidNoArgFunctionPtr) lecteur);
ThreadId lecteur2 = threadCreate((char*)"Lecteur", (VoidNoArgFunctionPtr) lecteur);
ThreadId redacteurTh = threadCreate((char*)"redacteur", (VoidNoArgFunctionPtr) redacteur);
Join(lecteurTh);
Join(lecteur1);
Join(lecteur2);
Join(redacteurTh);
return 0;
}

View File

@ -1,60 +0,0 @@
/* matmult.c
* Test program to do matrix multiplication on large arrays.
*
* Intended to stress virtual memory system.
*
* Ideally, we could read the matrices off of the file system,
* and store the result back to the file system!
*
* -----------------------------------------------------
* This file is part of the Nachos-RiscV distribution
* Copyright (c) 2022 University of Rennes 1.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details
* (see see <http://www.gnu.org/licenses/>).
* -----------------------------------------------------
*/
#include "userlib/syscall.h"
#define Dim 10 /* sum total of the arrays doesn't fit in
* physical memory
*/
/* The matrices to be filled-in and multiplied */
int A[Dim][Dim];
int B[Dim][Dim];
int C[Dim][Dim];
int
main()
{
int i, j, k;
Write("Start matmult\n",14,CONSOLE_OUTPUT);
for (i = 0; i < Dim; i++) /* first initialize the matrices */
for (j = 0; j < Dim; j++) {
A[i][j] = i;
B[i][j] = j;
C[i][j] = 0;
}
for (i = 0; i < Dim; i++) /* then multiply them together */
for (j = 0; j < Dim; j++)
for (k = 0; k < Dim; k++)
C[i][j] += A[i][k] * B[k][j];
Exit(C[Dim-1][Dim-1]); /* and then we're done */
return 0;
}

View File

@ -2,10 +2,9 @@
#include "userlib/libnachos.h" #include "userlib/libnachos.h"
int main() { int main() {
n_printf("Hello World 1\n"); n_printf("Hello World 1");
n_printf("Hello World 2\n"); n_printf("Hello World 2");
n_printf("Hello World 3\n"); n_printf("Hello World 3");
n_printf("Hello World 4\n"); n_printf("Hello World 4");
Shutdown();
return 0; return 0;
} }

View File

@ -9,32 +9,9 @@ int tab[3];
SemId svide; SemId svide;
SemId splein; SemId splein;
void producteur() { void producteur();
for(int i = 0; i < 10; i++)
{
n_printf("batir une information\n");
P(svide);
iplein = (iplein + 1) % N;
// n_printf("communique une information : %d\n", i);
tab[iplein] = i;
V(splein);
}
}
void consommateur() { void consommateur();
int sum = 0;
for(int i = 0; i < 10; i++)
{
P(splein);
ivide = (ivide +1) % N;
n_printf("recevoir une information\n");
int info = tab[ivide];
V(svide);
sum += info;
// n_printf("exploiter l'information : %d\n", info);
}
Exit(sum);
}
int main() { int main() {
svide = SemCreate("producteur", N); svide = SemCreate("producteur", N);
@ -43,6 +20,29 @@ int main() {
ThreadId consommateurTh = threadCreate("consommateur", consommateur); ThreadId consommateurTh = threadCreate("consommateur", consommateur);
Join(producteurTh); Join(producteurTh);
Join(consommateurTh); Join(consommateurTh);
Shutdown();
return 0; return 0;
} }
void producteur() {
for(int i = 0; i < 10; i++)
{
n_printf("batir une information\n");
P(svide);
iplein = (iplein + 1) % N;
n_printf("communique une information : %d\n", i);
tab[iplein] = i;
V(splein);
}
}
void consommateur() {
for(int i = 0; i < 10; i++)
{
P(splein);
ivide = (ivide +1) % N;
n_printf("recevoir une information\n");
int info = tab[ivide];
V(svide);
n_printf("exploiter l'information : %d\n", info);
}
}