248 lines
7.3 KiB
Rust
248 lines
7.3 KiB
Rust
///! 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 crate::Machine;
|
|
|
|
/// File section
|
|
pub struct SectionFormat{
|
|
/// Memory address of the section
|
|
addr: String,
|
|
/// The size of data in bytes
|
|
len: String,
|
|
/// The data itself in Hexadecimal format
|
|
content: String,
|
|
}
|
|
|
|
/// # Memory section
|
|
///
|
|
/// Representation of a section of memory from BurritOS or NachOS
|
|
pub struct Section{
|
|
/// Memory address of the section
|
|
addr: usize,
|
|
/// The size of data in bytes
|
|
len: usize,
|
|
/// The data itself in Hexadecimal format
|
|
content: Vec<u8>
|
|
}
|
|
|
|
impl Section {
|
|
|
|
/// Creates a memory section from a SectionFormat
|
|
fn from(section: &SectionFormat) -> Section {
|
|
let addr = usize::from_str_radix(§ion.addr, 10).unwrap_or_default();
|
|
let len = usize::from_str_radix(§ion.len, 10).unwrap_or_default();
|
|
let content: Vec<u8> = section.content.as_bytes().chunks(2).map(|x| {
|
|
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
|
|
fn print_section(s: &Section){
|
|
println!("ADDR :: {:x}\nLEN :: {:x}\nCONTENT :: {:?}", s.addr, s.len, s.content);
|
|
}
|
|
}
|
|
|
|
|
|
/// # Representation of the state of machine memory
|
|
///
|
|
/// Could represent memory at any point in time, before, during, or after execution.
|
|
/// The memory is split into sections.
|
|
pub struct MemChecker {
|
|
/// Value of the program counter
|
|
pc: usize,
|
|
/// Value of the stack pointer
|
|
sp: usize,
|
|
/// Sections
|
|
sections: Vec<Section>,
|
|
}
|
|
|
|
|
|
impl MemChecker{
|
|
|
|
///Translate lines of a file in e Vector of String
|
|
///We need this method to parse the memory we received
|
|
///
|
|
/// ### Parameters
|
|
///
|
|
/// - **Lines** The file to parse
|
|
///
|
|
/// ### Return
|
|
/// - A vector of String where each line of the file os an element of the vector
|
|
fn vect_from_lines(lines: &mut Lines<BufReader<fs::File>>, pc: &mut usize, sp: &mut usize) -> Vec<String>{
|
|
let mut vector = Vec::new();
|
|
for (_,line) in lines.enumerate() {
|
|
vector.push(line.unwrap());
|
|
}
|
|
let size = vector.len();
|
|
*pc = usize::from_str_radix(vector.get(size - 2).expect("0"), 16).unwrap_or_default();
|
|
*sp = usize::from_str_radix(vector.get(size - 1).expect("0"), 16).unwrap_or_default();
|
|
vector
|
|
}
|
|
|
|
/// Fill a mem checker from a file (here the mock memory)
|
|
/// Extract the values of pc, sp and sections
|
|
///
|
|
/// ### Parameter
|
|
/// -**path** addr to the file
|
|
///
|
|
/// ### Return
|
|
/// Mem-checker filled
|
|
pub fn from(path: &str) -> Result<MemChecker, Error> {
|
|
|
|
let file = fs::File::open(path)?;
|
|
|
|
let reader = BufReader::new(file);
|
|
let mut lines = reader.lines();
|
|
|
|
let mut pc: usize = 0;
|
|
let mut sp: usize = 0;
|
|
let vector = MemChecker::vect_from_lines(&mut lines, &mut pc, &mut sp);
|
|
|
|
let mut sections: Vec<Section> = Vec::new();
|
|
let mut tmp_addr_str: String = String::new();
|
|
let mut tmp_len_str: String = String::new();
|
|
|
|
let default = String::new();
|
|
for i in 0..vector.len()-2 {
|
|
let current_line = vector.get(i).unwrap_or(&default);
|
|
|
|
//Lecture des sections
|
|
if i % 2 == 0 {
|
|
//lecture ligne ADDR LEN
|
|
let next_word_index = current_line.find(' ').unwrap();
|
|
tmp_addr_str = String::from(¤t_line[0..next_word_index]);
|
|
tmp_len_str = String::from(¤t_line[next_word_index+1..]);
|
|
}
|
|
else {
|
|
//lecture ligne CONTENT
|
|
let section_f = SectionFormat{
|
|
addr: tmp_addr_str.clone(),
|
|
len: tmp_len_str.clone(),
|
|
content: current_line.clone().replace(' ', ""),
|
|
};
|
|
sections.push(Section::from(§ion_f));
|
|
}
|
|
|
|
}
|
|
|
|
Ok(MemChecker{pc, sp, sections})
|
|
}
|
|
|
|
|
|
/// Print the content of a Mem_Checker
|
|
///
|
|
/// ### Parameter
|
|
///
|
|
/// - **m_c** Contains the data we want to print
|
|
pub fn print_mem_checker(m_c: &MemChecker){
|
|
println!("PC :: {:x}", m_c.pc);
|
|
println!("SP :: {:x}", m_c.sp);
|
|
|
|
for(i,s) in m_c.sections.iter().enumerate() {
|
|
println!("\nSection {}\n", i);
|
|
Section::print_section(s);
|
|
}
|
|
|
|
}
|
|
|
|
/// Fill a machine's memory from a Mem Chacker
|
|
///
|
|
/// ### Parameters
|
|
///
|
|
/// - **m_c** contains the data
|
|
/// - **machine** contains the memry to fill
|
|
pub fn fill_memory_from_mem_checker(m_c: &MemChecker, machine: &mut Machine){
|
|
|
|
machine.sp = m_c.sp;
|
|
machine.int_reg.set_reg(2, m_c.sp as i64);
|
|
machine.pc = m_c.pc as u64;
|
|
|
|
for section in m_c.sections.iter() {
|
|
for (i,b) in section.content.iter().enumerate() {
|
|
machine.main_memory[section.addr/8 + i] = *b;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// For debug
|
|
fn compare_print_m_c_machine(m_c: &MemChecker, machine: &mut Machine){
|
|
MemChecker::print_mem_checker(m_c);
|
|
for section in m_c.sections.iter() {
|
|
print!("\n\n");
|
|
println!("Content addr : {}", section.addr);
|
|
println!("Content len (number of bytes) : {}", section.len);
|
|
for i in 0..section.len {
|
|
println!("mem[{}] = {}", section.addr + i, machine.main_memory[section.addr + i]);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/// Compare sections of a memChecker and a machine memory
|
|
///
|
|
/// ### Parameters
|
|
///
|
|
/// - **m_c** contains section of the memory checker
|
|
/// - **machine** contains the main memory
|
|
pub fn compare_machine_memory(m_c: &MemChecker, machine: &Machine) -> bool {
|
|
m_c.sections.iter().map(|section| {
|
|
(0..section.len).into_iter().all(|i| machine.main_memory[section.addr + i] == section.content[i])
|
|
}).all(|e| e)
|
|
}
|
|
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_fill_memory(){
|
|
let m_c = MemChecker::from("test/machine/memory.txt").unwrap();
|
|
let mut machine = Machine::init_machine();
|
|
MemChecker::fill_memory_from_mem_checker(&m_c, &mut machine);
|
|
MemChecker::compare_print_m_c_machine(&m_c, &mut machine);
|
|
}
|
|
|
|
#[test]
|
|
fn test_enum_start_at_zero(){
|
|
let v = vec![1,2,3];
|
|
|
|
for (i,val) in v.iter().enumerate() {
|
|
println!("i = {} :: v[i] = {}", i, val);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_create_mem_checker(){
|
|
let m_c = MemChecker::from("test/machine/memory.txt").unwrap();
|
|
MemChecker::print_mem_checker(&m_c);
|
|
}
|
|
|
|
#[test]
|
|
fn test_create_section_content(){
|
|
let section_format = SectionFormat{
|
|
addr: "0".to_string(),
|
|
len: "0".to_string(),
|
|
content: "00FF0AA0A5".to_string(),
|
|
};
|
|
let section = Section::from(§ion_format);
|
|
let expected_vec: Vec<u8> = vec![0u8, 255u8, 10u8, 160u8, 165u8];
|
|
assert_eq!(section.content, expected_vec);
|
|
}
|
|
|
|
}
|