Compare commits
No commits in common. "main" and "fix-strings" have entirely different histories.
main
...
fix-string
26
Makefile
26
Makefile
@ -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
|
||||||
#
|
#
|
||||||
@ -29,27 +22,10 @@ syscall: user_lib
|
|||||||
$(MAKE) build -C test/syscall_tests/
|
$(MAKE) build -C test/syscall_tests/
|
||||||
$(RM) test/syscall_tests/*.o
|
$(RM) test/syscall_tests/*.o
|
||||||
mkdir -p ${TOPDIR}/target/guac/
|
mkdir -p ${TOPDIR}/target/guac/
|
||||||
find . -name '*.guac' -exec mv {} ${TOPDIR}/target/guac/ 2> /dev/null \;
|
find . -name '*.guac' -exec mv {} ${TOPDIR}/target/guac/ \;
|
||||||
|
|
||||||
clean:
|
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
|
|
||||||
|
|
||||||
lock: syscall
|
|
||||||
${CARGO} -x ./target/guac/lock.guac -d2
|
|
||||||
|
|
||||||
prints: syscall
|
|
||||||
${CARGO} -x ./target/guac/prints.guac -d2
|
|
||||||
|
70
README.md
70
README.md
@ -6,76 +6,6 @@ BurritOS (BurritOS Using Rust Really Improves The Operating System) is an educat
|
|||||||
|
|
||||||
Based on [NachOS](https://homes.cs.washington.edu/~tom/nachos/) (Copyright (c) 1992-1993 The Regents of the University of California. All rights reserved.)
|
Based on [NachOS](https://homes.cs.washington.edu/~tom/nachos/) (Copyright (c) 1992-1993 The Regents of the University of California. All rights reserved.)
|
||||||
|
|
||||||
## Progress overview
|
|
||||||
|
|
||||||
![Progress overview](./assets/progress_overview.png)
|
|
||||||
|
|
||||||
Currently, the BurritOS project simulator contains a RISC-V processing unit supporting all 47 base instructions plus multiplication and 32bit floating point operations. RAM and the interrupt controller are also integrated. Both the memory management unit and the Disk are written but not tested nor integrated yet.
|
|
||||||
|
|
||||||
On the kernel side, synchronization primitives and scheduling logic are all implemented except for Conditions.
|
|
||||||
|
|
||||||
## Build instructions
|
|
||||||
|
|
||||||
To build in release mode:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ cargo build -r
|
|
||||||
```
|
|
||||||
|
|
||||||
To build in development mode:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ cargo build
|
|
||||||
```
|
|
||||||
|
|
||||||
The generated executable can then be found in the `./target` directory.
|
|
||||||
|
|
||||||
## Running BurritOS
|
|
||||||
|
|
||||||
*In the following examples, BurritOS is started by directly invoking its executable. However, replacing this direct invocation by `cargo run -- <PARAMETERS>` would garner the same result.*
|
|
||||||
|
|
||||||
As it stands, BurritOS does not include a virtual console nor a shell for dynamic user interaction. Thus, programs need to be manually loaded into the system memory. To perform this operation:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ ./burritos --executable <PATH>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Help
|
|
||||||
|
|
||||||
BurritOS provides a succinct manual. To display this manual:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ ./burritos --help
|
|
||||||
```
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
Documentation for all components of the BurritOS project can be generated using the following command:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ cargo doc
|
|
||||||
```
|
|
||||||
|
|
||||||
The generated web documentation can be found in the `./target/doc` directory.
|
|
||||||
|
|
||||||
## Tests
|
|
||||||
|
|
||||||
BurritOS is unit tested using the cargo provided testing framework. However, some tests, most notably the Machine tests, require access to a few files **which need to be generated first**.
|
|
||||||
|
|
||||||
To generate test files:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ make all
|
|
||||||
```
|
|
||||||
|
|
||||||
Afterwards, tests can be run with:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ cargo test
|
|
||||||
```
|
|
||||||
|
|
||||||
All make artifacts can be found in the `./target` directory.
|
|
||||||
|
|
||||||
## Authors
|
## Authors
|
||||||
|
|
||||||
Amaury Brodu, Abdelmajid El Bahri, François Autin, Quentin Legot, Baptiste Meauze, Gabriel Moysan, Rémi Rativel, Samy Solhi
|
Amaury Brodu, Abdelmajid El Bahri, François Autin, Quentin Legot, Baptiste Meauze, Gabriel Moysan, Rémi Rativel, Samy Solhi
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 100 KiB |
12
build.rs
12
build.rs
@ -1,12 +0,0 @@
|
|||||||
//! 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());
|
|
||||||
}
|
|
@ -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
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
//! # 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;
|
||||||
@ -143,8 +138,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!(),
|
||||||
@ -188,7 +182,7 @@ fn syscall(machine: &mut Machine, system: &mut System) -> Result<MachineOk, Mach
|
|||||||
SC_LOCK_CREATE => sc_lock_create(machine, system),
|
SC_LOCK_CREATE => sc_lock_create(machine, system),
|
||||||
SC_LOCK_DESTROY => sc_lock_destroy(machine, system),
|
SC_LOCK_DESTROY => sc_lock_destroy(machine, system),
|
||||||
SC_LOCK_ACQUIRE => sc_lock_acquire(machine, system),
|
SC_LOCK_ACQUIRE => sc_lock_acquire(machine, system),
|
||||||
SC_LOCK_RELEASE => sc_lock_release(machine, system),
|
SC_LOCK_RELEASE => todo!(),
|
||||||
SC_COND_CREATE => todo!(),
|
SC_COND_CREATE => todo!(),
|
||||||
SC_COND_DESTROY => todo!(),
|
SC_COND_DESTROY => todo!(),
|
||||||
SC_COND_WAIT => todo!(),
|
SC_COND_WAIT => todo!(),
|
||||||
@ -288,16 +282,13 @@ 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)
|
||||||
} else {
|
} else {
|
||||||
return Err("Process owner of current thread is none")?;
|
return Err("Process owner of current thread is none")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sc_join(machine: &mut Machine, system: &mut System) -> Result<MachineOk, MachineError> {
|
fn sc_join(machine: &mut Machine, system: &mut System) -> Result<MachineOk, MachineError> {
|
||||||
@ -362,18 +353,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
|
||||||
|
@ -1,11 +1,3 @@
|
|||||||
//! # 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 {
|
||||||
|
@ -1,9 +1,3 @@
|
|||||||
//! # 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;
|
||||||
|
@ -1,11 +1,3 @@
|
|||||||
//! # 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;
|
||||||
@ -14,21 +6,20 @@ 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 simultaneous Semaphore
|
/// Counter of simultanous Semaphore
|
||||||
pub counter:i32,
|
pub counter:i32,
|
||||||
/// QUeue of Semaphore waiting to be executed
|
/// QUeue of Semaphore waiting to be exucated
|
||||||
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
|
||||||
@ -58,7 +49,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 initially free
|
/// The lock is initialy free
|
||||||
///
|
///
|
||||||
/// ### Parameters
|
/// ### Parameters
|
||||||
/// - **thread_manager** Thread manager which managing threads
|
/// - **thread_manager** Thread manager which managing threads
|
||||||
@ -81,7 +72,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 = Some(match thread_manager.get_g_current_thread() {
|
self.owner = Option::Some(match thread_manager.get_g_current_thread() {
|
||||||
Some(th) => {
|
Some(th) => {
|
||||||
Rc::clone(&th)
|
Rc::clone(&th)
|
||||||
},
|
},
|
||||||
@ -137,14 +128,8 @@ impl Lock {
|
|||||||
machine.interrupt.set_status(old_status);
|
machine.interrupt.set_status(old_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Say if the lock is held by the current thread
|
/// True if the current thread holds this lock.
|
||||||
/// 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) =>
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
//! # 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};
|
||||||
|
@ -118,11 +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
|
||||||
/// Temporary field, to be removed when virtual memory will be available to use.
|
|
||||||
///
|
|
||||||
/// A value to know where the next starting thread should have its stack pointer
|
|
||||||
sp_max: u64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ThreadManager {
|
impl ThreadManager {
|
||||||
@ -134,24 +130,23 @@ 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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mark `thread` as ready, but not necessarily running yet.
|
/// Mark a thread as aready, but not necessarily running yet.
|
||||||
///
|
///
|
||||||
/// Put it in the ready list, for later scheduling onto the CPU.
|
/// Put it in the ready list, for later scheduling onto the CPU.
|
||||||
///
|
///
|
||||||
/// ## Pamameter
|
/// ## Pamameter
|
||||||
///
|
///
|
||||||
/// **thread** is the thread to be put on the ready list
|
/// **thread** is the thread to be put on the read list
|
||||||
pub fn ready_to_run(&mut self, thread: ThreadRef) {
|
pub fn ready_to_run(&mut self, thread: ThreadRef) {
|
||||||
self.ready_list.push(thread);
|
self.ready_list.push(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the next thread to be scheduled onto the CPU.
|
/// Return the next thread to be scheduled onto the CPU.
|
||||||
/// If there are no ready threads, return `Option::None`
|
/// If there are no ready threads, return Option::None
|
||||||
///
|
///
|
||||||
/// Thread is removed from the ready list.
|
/// Thread is removed from the ready list.
|
||||||
///
|
///
|
||||||
@ -160,12 +155,12 @@ impl ThreadManager {
|
|||||||
self.ready_list.pop()
|
self.ready_list.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dispatch the CPU to `next_thread`. Save the state of the old thread
|
/// Dispatch the CPU to next_thread. Save the state of the old thread
|
||||||
/// and load the state of the new thread.
|
/// and load the state of the new thread.
|
||||||
///
|
///
|
||||||
/// We assume the state of the previously running thread has already been changed from running to blocked or ready.
|
/// We assume the state of the previously running thread has already been changed from running to blocked or ready.
|
||||||
///
|
///
|
||||||
/// Variable `g_current_thread` become next_thread
|
/// Global variable g_current_thread become next_thread
|
||||||
///
|
///
|
||||||
/// ## Parameter
|
/// ## Parameter
|
||||||
///
|
///
|
||||||
@ -190,14 +185,6 @@ impl ThreadManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Start a thread, attaching it to a process
|
/// Start a thread, attaching it to a process
|
||||||
///
|
|
||||||
/// ## Parameter
|
|
||||||
///
|
|
||||||
/// **thread** thread to start
|
|
||||||
/// **owner** process owner of thread (after the execution of this method)
|
|
||||||
/// **func_pc** pc the thread
|
|
||||||
/// **sp_loc** stack pointer of the thread, to remove (or move) when mmu will be completed
|
|
||||||
/// **argument** value to be place on register[10]
|
|
||||||
pub fn start_thread(&mut self, thread: ThreadRef, owner: Rc<RefCell<Process>>, func_pc: u64, sp_loc: u64, argument: i64) {
|
pub fn start_thread(&mut self, thread: ThreadRef, owner: Rc<RefCell<Process>>, func_pc: u64, sp_loc: u64, argument: i64) {
|
||||||
self.debug(format!("starting thread \"{}\"", thread.borrow().get_name()));
|
self.debug(format!("starting thread \"{}\"", thread.borrow().get_name()));
|
||||||
|
|
||||||
@ -212,11 +199,6 @@ impl ThreadManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Wait for another thread to finish its execution
|
/// Wait for another thread to finish its execution
|
||||||
///
|
|
||||||
/// If the thread you want to wait doesn't exist (isn't alive), execution will resume.
|
|
||||||
/// Otherwise, CPU is dispatch to next alive thread if any.
|
|
||||||
///
|
|
||||||
/// When the thread you want to join finish, it place the waiting thread (self) in ready list
|
|
||||||
pub fn thread_join(&mut self, machine: &mut Machine, waiter: ThreadRef, waiting_for: ThreadRef) {
|
pub fn thread_join(&mut self, machine: &mut Machine, waiter: ThreadRef, waiting_for: ThreadRef) {
|
||||||
let waiting_for = Rc::clone(&waiting_for);
|
let waiting_for = Rc::clone(&waiting_for);
|
||||||
if self.get_g_alive().contains(&waiting_for) {
|
if self.get_g_alive().contains(&waiting_for) {
|
||||||
@ -227,19 +209,10 @@ impl ThreadManager {
|
|||||||
|
|
||||||
/// Relinquish the CPU if any other thread is runnable.
|
/// Relinquish the CPU if any other thread is runnable.
|
||||||
///
|
///
|
||||||
/// If so, put the current thread at the end of the ready list, so it'll be re-scheduled in the future.
|
/// Cannot use yield as a function name -> reserved name in rust
|
||||||
///
|
|
||||||
/// **Returns** immediately if there's no other thread ready or return when the current thread has been switched.
|
|
||||||
///
|
|
||||||
/// Interruptions are disabled during the process, so all the process of looking for a next thread and switching to it is atomic,
|
|
||||||
/// and is place at its old status at the end of the method.
|
|
||||||
///
|
|
||||||
/// Cannot use `yield` as a function name -> reserved name in rust
|
|
||||||
///
|
///
|
||||||
/// ## Parameters
|
/// ## Parameters
|
||||||
///
|
///
|
||||||
/// **machine** RISC-V simulator
|
|
||||||
/// **thread** current thread to be relinquish
|
|
||||||
/// **is_ready** true if **thread** should be readded to ready_to_run list, false otherwise. Typically false when joining per example
|
/// **is_ready** true if **thread** should be readded to ready_to_run list, false otherwise. Typically false when joining per example
|
||||||
pub fn thread_yield(&mut self, machine: &mut Machine, thread: ThreadRef, is_ready: bool) {
|
pub fn thread_yield(&mut self, machine: &mut Machine, thread: ThreadRef, is_ready: bool) {
|
||||||
let old_status = machine.interrupt.set_status(crate::simulator::interrupt::InterruptStatus::InterruptOff);
|
let old_status = machine.interrupt.set_status(crate::simulator::interrupt::InterruptStatus::InterruptOff);
|
||||||
@ -256,16 +229,7 @@ impl ThreadManager {
|
|||||||
machine.interrupt.set_status(old_status);
|
machine.interrupt.set_status(old_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Put the thread to sleep and relinquish the processor because the current thread is blocked (Semaphore, Lock, Condition) or because it finished its execution
|
/// Put the thread to sleep and relinquish the processor
|
||||||
///
|
|
||||||
/// Another thread will eventually wake it up and put it back to ready list after it has been unblocked.
|
|
||||||
///
|
|
||||||
/// Behavior now: At the moment, disk isn't fully develop and not integrated to burritos, so if there's no ready thread, then we stop the OS.
|
|
||||||
///
|
|
||||||
/// Behaviour in the future: If there are no threads on the ready list, that means there is no thread to run,
|
|
||||||
/// we assume this is because at least one thread is waiting for I/O [`interrupt`](crate::simulator::interrupt::Interrupt) (the only reason a new thread can become ready at this point).
|
|
||||||
///
|
|
||||||
/// We also assume interruption are already disabled, becuase it's called from a synchronization routine for interrupt should be disabled.
|
|
||||||
pub fn thread_sleep(&mut self, machine: &mut Machine, thread: ThreadRef) {
|
pub fn thread_sleep(&mut self, machine: &mut Machine, thread: ThreadRef) {
|
||||||
debug_assert_eq!(Option::Some(Rc::clone(&thread)), self.g_current_thread);
|
debug_assert_eq!(Option::Some(Rc::clone(&thread)), self.g_current_thread);
|
||||||
debug_assert_eq!(machine.interrupt.get_status(), InterruptStatus::InterruptOff);
|
debug_assert_eq!(machine.interrupt.get_status(), InterruptStatus::InterruptOff);
|
||||||
@ -275,27 +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) {
|
||||||
/// Called by the thread itself when it finish its execution ([`Exit`](super::exception::SC_EXIT) exception).
|
|
||||||
///
|
|
||||||
/// We remove the thread from the alive list, and rustc deallocate the thread itself(behaviour different than Nachos)
|
|
||||||
///
|
|
||||||
/// Interruption are disabled to assume atomicity.
|
|
||||||
pub fn thread_finish(&mut self, machine: &mut Machine, thread: ThreadRef, exit_code: i64) {
|
|
||||||
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));
|
||||||
@ -305,8 +259,6 @@ impl ThreadManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Save the CPU state of a user program on a context switch.
|
/// Save the CPU state of a user program on a context switch.
|
||||||
///
|
|
||||||
/// Save PC and registers
|
|
||||||
pub fn thread_save_processor_state(&mut self, machine: &mut Machine, thread: ThreadRef) {
|
pub fn thread_save_processor_state(&mut self, machine: &mut Machine, thread: ThreadRef) {
|
||||||
let mut t = thread.borrow_mut();
|
let mut t = thread.borrow_mut();
|
||||||
for i in 0..NUM_INT_REGS {
|
for i in 0..NUM_INT_REGS {
|
||||||
@ -319,8 +271,6 @@ impl ThreadManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Restore the CPU state of a user program on a context switch.
|
/// Restore the CPU state of a user program on a context switch.
|
||||||
///
|
|
||||||
/// Restore PC and registers
|
|
||||||
pub fn thread_restore_processor_state(&self, machine: &mut Machine, thread: ThreadRef) {
|
pub fn thread_restore_processor_state(&self, machine: &mut Machine, thread: ThreadRef) {
|
||||||
let t: Ref<_> = thread.borrow();
|
let t: Ref<_> = thread.borrow();
|
||||||
for i in 0..NUM_INT_REGS {
|
for i in 0..NUM_INT_REGS {
|
||||||
@ -415,9 +365,7 @@ impl ThreadManager {
|
|||||||
Ok(MachineOk::Ok)
|
Ok(MachineOk::Ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Release lock hold by current thread and wake up a waiter if necessary, placing it on ready list, this thread now hold the lock.
|
/// Wake up a waiter if necessary, or release it if no thread is waiting.
|
||||||
///
|
|
||||||
/// If no thread is waiting for the lock, the lock is released
|
|
||||||
pub fn lock_release(&mut self, id: i32, machine: &mut Machine) -> Result<MachineOk, MachineError> {
|
pub fn lock_release(&mut self, id: i32, machine: &mut Machine) -> Result<MachineOk, MachineError> {
|
||||||
let old_status = machine.interrupt.set_status(InterruptStatus::InterruptOff);
|
let old_status = machine.interrupt.set_status(InterruptStatus::InterruptOff);
|
||||||
let current_thread = match self.get_g_current_thread() {
|
let current_thread = match self.get_g_current_thread() {
|
||||||
@ -448,12 +396,12 @@ impl ThreadManager {
|
|||||||
Ok(MachineOk::Ok)
|
Ok(MachineOk::Ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return currently running thread
|
/// Currently running thread
|
||||||
pub fn get_g_current_thread(&mut self) -> &Option<ThreadRef> {
|
pub fn get_g_current_thread(&mut self) -> &Option<ThreadRef> {
|
||||||
&self.g_current_thread
|
&self.g_current_thread
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return list of alive threads
|
/// List of alive threads
|
||||||
pub fn get_g_alive(&mut self) -> &mut List<ThreadRef> {
|
pub fn get_g_alive(&mut self) -> &mut List<ThreadRef> {
|
||||||
&mut self.g_alive
|
&mut self.g_alive
|
||||||
}
|
}
|
||||||
@ -475,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)]
|
||||||
|
11
src/main.rs
11
src/main.rs
@ -1,7 +1,4 @@
|
|||||||
#![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)]
|
||||||
|
|
||||||
@ -10,8 +7,10 @@
|
|||||||
//! 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};
|
||||||
@ -56,9 +55,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));
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,38 +1,17 @@
|
|||||||
//! # 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;
|
||||||
@ -46,7 +25,6 @@ impl Interrupt {
|
|||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interupt getter
|
|
||||||
pub fn get_status(&self) -> InterruptStatus {
|
pub fn get_status(&self) -> InterruptStatus {
|
||||||
self.level
|
self.level
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,9 @@
|
|||||||
//! # 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 [ELF file Header](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header) for more informations
|
/// see <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
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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))?
|
||||||
}
|
}
|
||||||
|
@ -1,37 +1,20 @@
|
|||||||
//! # Memory Comparator
|
///! FILE.TXT FORMAT Representing machine memory memory
|
||||||
//!
|
/// - PC
|
||||||
//! This module contains a MemChecker.
|
/// - SP
|
||||||
//!
|
/// - Section_1
|
||||||
//! It's used to compare state memory obtained after a dump memory from NachOS and BurritOS.
|
/// - Section_2
|
||||||
//!
|
/// - ...
|
||||||
//! This module is used exclusively for testing the instruction simulator.
|
/// - Section_n
|
||||||
//!
|
///
|
||||||
//! Basic usage:
|
/// Each section is divided in 3 parts, on two lines of text
|
||||||
//!
|
/// 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
|
||||||
@ -43,7 +26,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
|
||||||
@ -53,23 +36,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(§ion.addr, 16).unwrap_or_default();
|
let addr = usize::from_str_radix(§ion.addr, 16).unwrap_or_default();
|
||||||
let len = usize::from_str_radix(§ion.len, 16).unwrap_or_default();
|
let len = usize::from_str_radix(§ion.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
|
||||||
@ -93,7 +68,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
|
||||||
@ -119,7 +94,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
|
||||||
@ -151,12 +126,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(§ion_f));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -194,7 +169,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -260,12 +235,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(§ion_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);
|
||||||
}
|
}
|
||||||
|
@ -1,38 +1,18 @@
|
|||||||
//! # 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>{
|
||||||
/// Reference to a page table
|
/* Un MMU possède une seule référence vers une table des pages à un instant donné
|
||||||
|
* 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,
|
||||||
|
@ -1,12 +1,3 @@
|
|||||||
//! 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;
|
||||||
@ -223,7 +214,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;
|
||||||
|
@ -1,35 +1,23 @@
|
|||||||
//! # Translation Table
|
//Nombre maximum de correspondances dans une table des pages
|
||||||
//!
|
//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
|
|
||||||
/// An iteration of type TranslationTable should be possesses by an oject of type Process
|
/* Une table de correspondance propre à un processus
|
||||||
|
* Une variable de type TranslationTable devra etre possédée par un objet de type Process
|
||||||
|
*/
|
||||||
pub struct TranslationTable{
|
pub struct TranslationTable{
|
||||||
/// Table size <=> nb of possible translation
|
//capacité de cette table <=> nombre de correspondances possibles
|
||||||
|
//A voir si cette donnée doit etre immuable
|
||||||
pub maxNumPages : u64,
|
pub maxNumPages : u64,
|
||||||
|
|
||||||
///The table *Vec impemente Index Trait*
|
//la table en question
|
||||||
|
//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();
|
||||||
|
@ -93,35 +93,24 @@ 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
|
/// 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())
|
||||||
.filter(|l| !l.is_empty() && !l.starts_with('#'))
|
.filter(|l| !l.is_empty() && !l.starts_with("#"))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts user settings into setting map
|
|
||||||
/// Adds a <K, V> pair to a [`Settings`] 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 = str::parse::<u64>(setting).unwrap_or(0);
|
let setting = u64::from_str_radix(setting, 10).unwrap_or(0);
|
||||||
settings_map.insert(key, setting);
|
settings_map.insert(key, setting);
|
||||||
settings_map
|
settings_map
|
||||||
}
|
}
|
@ -1,6 +1,3 @@
|
|||||||
//! 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;
|
@ -17,13 +17,9 @@ 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>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
PROGRAMS = halt.guac prints.guac producteur_consommateur.guac lock.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
|
||||||
|
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
#include "userlib/syscall.h"
|
|
||||||
#include "userlib/libnachos.h"
|
|
||||||
|
|
||||||
LockId mutex;
|
|
||||||
int glob_int = 0;
|
|
||||||
|
|
||||||
void increment(void){
|
|
||||||
LockAcquire(mutex);
|
|
||||||
glob_int++;
|
|
||||||
LockRelease(mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void counter(int n){
|
|
||||||
for (int i = 0; i < 50; i++){
|
|
||||||
increment();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void){
|
|
||||||
mutex = LockCreate("Lock_debug");
|
|
||||||
|
|
||||||
ThreadId th1 = threadCreate("Thread1", (VoidNoArgFunctionPtr) counter);
|
|
||||||
ThreadId th2 = threadCreate("Thread2",(VoidNoArgFunctionPtr) counter);
|
|
||||||
|
|
||||||
Join(th1);
|
|
||||||
Join(th2);
|
|
||||||
Exit(glob_int);
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
@ -2,53 +2,9 @@
|
|||||||
#include "userlib/libnachos.h"
|
#include "userlib/libnachos.h"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
n_printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
|
n_printf("Hello World 1");
|
||||||
n_printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&##BBGGGPPGGGBB##&@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
|
n_printf("Hello World 2");
|
||||||
n_printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&#G5J?!~^::............::^~!?J5G#&@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
|
n_printf("Hello World 3");
|
||||||
n_printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@&B5?!^:....:^^~!!7777??7777!!~~^::...:^!JPB&@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
|
n_printf("Hello World 4");
|
||||||
n_printf("@@@@@@@@@@@@@@@@@@@@@@@@@B57^....^~!?JJYYY5555555555555555Y5PGP57~::..:^75B@@@@@@@@@@@@@@@@@@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@@@@@@@@@@@@@@&G?~. .:~7?JY55555YYYYYYYYYYYYYYYYY5PB##BPY???7!~^:..:~JG&@@@@@@@@@@@@@@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@@@@@@@@@@@@BJ~. .^!?Y5555YYYYYYYYYYYYYYYYYYYY5PB##B5J?77???????7!~^:.:~JB@@@@@@@@@@@@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@@@@@@@@@&P!. .^!JY55YYYYYYYYYYYYYYYYYYYYYY5PB##B5J?77??????????????7~^:.:!P&@@@@@@@@@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@@@@@@@&Y^..:~?Y55YYYYYYYYYYYYYYYYYYYYYY5PB##B5J?77????????????????????7~:.:~5&@@@@@@@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@@@@@&5^..:!J55YYYYYYYYYYYYYYYYYYYYYY5PB##B5J?77?????????????????????????7~^::~5@@@@@@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@@@@G~..:!Y55YYYYYYYYYYYYYYYYYYYYY5PB##B5J?77??????????????????????????????7~:::!B@@@@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@@&J...~J55YYYYYYYYYYYYYYYYYYYY5PB##B5J?77??????????????????????????????777?Y57:::J&@@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@#!..:7Y5YYYYYYYYYYYYYYYYYYY5PB##B5J?77??????????????????????????????777?YPB##G?^::7#@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@G^..^J5YYYYYYYYYYYYYYYYYY5PB##B5J?77??????????????????????????????777?YPB##GP5Y5J~::~B@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@G^..^Y5YYYYYYYYYYYYYYYY5PB##B5J?77??????????????????????????????777?YPB##GP55Y5555Y~::^B@@@@@@\n");
|
|
||||||
n_printf("@@@@@B^..^Y5YYYYYYYYYYYYYY5PB##B5J?77??????????????????????????????777?YPB##GP5YYYY555555Y~::~B@@@@@\n");
|
|
||||||
n_printf("@@@@&!..^J5YYYYYYYYYYYY5PB##B5J?77??????????????????????????????777?YPB#BGPYYYYYY555555555Y~::7&@@@@\n");
|
|
||||||
n_printf("@@@@J..:?5YYYYYYYYYY5PB##B5J?77??????????????????????????????777?YPB#BG5YYYYYYY55YY55555555J^::Y@@@@\n");
|
|
||||||
n_printf("@@@B:..~5YYYYYYYY5PB##G5J?77??????????????????????????????777?YPB#BG5YYYYYYYY5YYY55555555555!::^#@@@\n");
|
|
||||||
n_printf("@@@?..:JYYYYYY5PB##G5J?77??????????????????????????????777?YPB#BG5YYYYYYYYYYYYY55YY555555555Y^::J@@@\n");
|
|
||||||
n_printf("@@&^..~YYYY5PB##G5J?77??????????????????????????????777?YPB#BG5YYYYYYYYYYYYYYYYYY5555Y5555555!::~&@@\n");
|
|
||||||
n_printf("@@G:..7Y5PB##G5J?77??????????????????????????????777?YPB#BG5YJYYYYYYYYYYYYYYYYY55YYY555555555?::^B@@\n");
|
|
||||||
n_printf("@@5:..YB##G5J?77??????????????????????????????777?YPB#BG5JJJYYYJYYYYYYYYYYYYYY5YY5555Y5555555J:^^P@@\n");
|
|
||||||
n_printf("@@5:..PB5J?77??????????????????????????????777?YGB#BG5JJJYYJYYYYYYYYYYYYYYYYYYY55Y55555555555J:^^5@@\n");
|
|
||||||
n_printf("@@5:..7?77??????????????????????????????777?YPB#BG5JJJJJJJJYYYYYYYYYYYYYYYYYYY5YY5Y5555555555J:^^P@@\n");
|
|
||||||
n_printf("@@G:..~??????????????????????????????777?YGB#BPYJJJJJJJJJJJYYYYYYYYYYYYYYYYYYYY5YY55555555555?:^^B@@\n");
|
|
||||||
n_printf("@@&^..^???????????????????????????777?YGB#BPYJ?JJJJJJJJJJJYYJYYYYYYYYYYYYYYYYY5YY5Y5555555555!^:~@@@\n");
|
|
||||||
n_printf("@@@?.::7???????????????????????777?YGB#BPYJ???JJJJJJJJJJJJJYYYYYYYYYYYYYYYYYYYYYYY5555555555Y^^:J@@@\n");
|
|
||||||
n_printf("@@@#:..^????????????????????777?YG##BPYJ????JJJJJJJJJJJJJJYJJYYYYYYYYYYYYYYYYY5YYYY555555555!^^^#@@@\n");
|
|
||||||
n_printf("@@@@J.::!????????????????777?YG##BPY???????JJJJJJJJJJJJJJJJYYYYYYYYYYYYYYYYYY5YYY5555555555J^^:Y@@@@\n");
|
|
||||||
n_printf("@@@@&!..:7????????????777?YGB#BPJ????????????JJJJJJJJJJJJYYJJYYYYYYYYYYYYYYYYYY55YY5555555Y~::7&@@@@\n");
|
|
||||||
n_printf("@@@@@B^.:^7????????777?YGB#BPJ?7???????????JJJ?JJJJJJJJJJJJYYYYJYYYYYYYYYYYYYYYYY5555Y555Y~^:~B@@@@@\n");
|
|
||||||
n_printf("@@@@@@G^.:^7????777?YGB#BPJ?7????????????????JJJJJJJJJJJJYYJJYYYYYYYYYYYYYYYYYY55YYY5555Y~::~B@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@B^.:^7?77?YGB#BPJ?77??7?????????????JJJ?JJJJJJJJJJJJYYYYJYYYYYYYYYYYYYYYYY5555Y5J~::~B@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@#!..:!YG##BPJ?77?????????????????????JJJJJJJJJJJJYYJYYYYYYYYYYYYYYYYYYY55YYY55?^::7#@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@@&J:.:7PPY?77???7????7??????????????JJ?JJJJJJJJJJJJYYYYJYYYYYYYYYYYYYY5YY555J!^:^Y&@@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@@@@G!..:~7?????????????????????????JJJJJJJJJJJJJJYYJYYYYYYYYYYYYYYYYYYY555Y7^::7G@@@@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@@@@@@5~..:~7????????????????????????JJJJJJJJJJJJJJJYJYYYYYYYYYYYYYYYYY5YY7^::~5@@@@@@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@@@@@@@&Y~..:~7?????????????????????JJJJJJJJJJJJJJJJYYYYYYYYYYYYYYYYY5YJ!^::!5&@@@@@@@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@@@@@@@@@&P!:.:^~7???????????????????JJJJJJJJJJJJJJJJJYYYYYYYYYYYYYYJ7~::^7P&@@@@@@@@@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@@@@@@@@@@@@BJ~:.:^~77??????????????JJ?JJJJJJJJJJJJJYYYYYYYYYYYYYJ7~^::!YB@@@@@@@@@@@@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@@@@@@@@@@@@@@&GJ~:.::~!!7????????????JJJJJJJJJJJJJYJJYYYYYYJ?7!^::^!JG&@@@@@@@@@@@@@@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@@@@@@@@@@@@@@@@@@B5?~::::^~~!7????JJJJJJJJJJJJYYJJJJJJ?77!~^::^~?5B@@@@@@@@@@@@@@@@@@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@&BPJ7~^:::::^~~~!!77777777!!!~~^^::::^~7JPB&@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&#G5Y?7!~^^::::::::::::^~~!7JYPG#&@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&&##BGGGGGGGBB##&&@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
|
|
||||||
n_printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
|
|
||||||
Shutdown();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user