///! 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 } 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 = 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
, } 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>, pc: &mut usize, sp: &mut usize) -> Vec{ 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 { 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
= 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 = vec![0u8, 255u8, 10u8, 160u8, 165u8]; assert_eq!(section.content, expected_vec); } }