From 0c8569358097f3df6f1bc7a570217d818af69160 Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 9 Feb 2024 15:41:59 -0500 Subject: [PATCH] Start using communicator to update memory --- src/agent/datapath_communicator.rs | 2 +- src/agent/messages.rs | 2 +- src/bin/main.rs | 147 ++++++++++++++++------------ src/emulation_core/datapath.rs | 2 +- src/emulation_core/mips/datapath.rs | 4 +- src/emulation_core/mips/memory.rs | 92 ++++++++--------- src/ui/hex_editor/component.rs | 26 +++++ static/assembly_examples/data.asm | 2 + 8 files changed, 159 insertions(+), 118 deletions(-) diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index c1f5def1e..c5a9249e2 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -109,7 +109,7 @@ impl DatapathCommunicator { /// Copies the contents of `data` to the emulator core's memory at `ptr`. Copies until either the end of `data` or /// the end of the emulaot core's memory. - pub fn set_memory(&self, ptr: usize, data: Vec) { + pub fn set_memory(&self, ptr: u64, data: u32) { self.send_message(Command::SetMemory(ptr, data)); } diff --git a/src/agent/messages.rs b/src/agent/messages.rs index b92c23208..f0c381f2a 100644 --- a/src/agent/messages.rs +++ b/src/agent/messages.rs @@ -11,7 +11,7 @@ pub enum Command { Initialize(usize, Vec), SetExecuteSpeed(u32), SetRegister(String, u64), - SetMemory(usize, Vec), + SetMemory(u64, u32), Execute, ExecuteInstruction, ExecuteStage, diff --git a/src/bin/main.rs b/src/bin/main.rs index 6def0765f..03e525f9e 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -10,7 +10,7 @@ use monaco::{ MarkerSeverity, } }; -use swim::ui::{footer::component::FooterTabState, swim_editor::component::EditorTabState}; +use swim::{emulation_core::{architectures::AvailableDatapaths, mips::instruction::get_string_version}, ui::{footer::component::FooterTabState, hex_editor::component::{parse_hexdump, UpdatedLine}, swim_editor::component::EditorTabState}}; use swim::parser::parser_structs_and_enums::ProgramInfo; use std::rc::Rc; use swim::agent::datapath_communicator::DatapathCommunicator; @@ -298,10 +298,13 @@ fn app(props: &AppProps) -> Html { let trigger = use_force_update(); let communicator = props.communicator; + let datapath_state = datapath_state.clone(); use_callback( move |_, _| { - let mut datapath = datapath.borrow_mut(); + let datapath = datapath.borrow_mut(); + + let communicator = communicator.clone(); let text_model = text_model.clone(); let program_info_ref = Rc::clone(&program_info_ref); @@ -311,78 +314,100 @@ fn app(props: &AppProps) -> Html { let current_memory_text_model_value = memory_text_model.get_value(); - match datapath.memory.parse_hexdump(¤t_memory_text_model_value) { + match parse_hexdump(¤t_memory_text_model_value) { Ok(instructions) => { - // Memory parsed with no errors - match datapath.memory.store_hexdump(instructions) { - Ok(changed_lines) => { - // Memory updated successfully - let program_info = program_info_ref.borrow().clone(); - let mut lines_beyond_counter = program_info.address_to_line_number.len(); - let mut curr_value = text_model.get_value().to_owned(); - let mut add_new_lines = false; - for line in changed_lines { - // Check if we're updating or appending instruction - if line.line_number < program_info.address_to_line_number.len() { - let updated_line = program_info.address_to_line_number[line.line_number] as f64 + 1.0; - let curr_model = text_model.as_ref(); - - // Get the current line's contents in the code editor - let line_to_replace = curr_model.get_line_content(updated_line); - // Create the range to replace - let mut start_line_column = 0.0; - let end_line_column = line_to_replace.len() as f64 + 2.0; - for (i, c) in line_to_replace.chars().enumerate() { - if c.is_alphanumeric() { - start_line_column = i as f64 + 1.0; - break; - } - } - let edit_range = monaco::sys::Range::new(updated_line, start_line_column, updated_line, end_line_column); - let before_cursor_state = monaco::sys::Selection::new(updated_line, start_line_column, updated_line,end_line_column); - // Create the edit operation using the range and new text - let edit_operations: monaco::sys::editor::IIdentifiedSingleEditOperation = Object::new().unchecked_into(); - edit_operations.set_range(&edit_range); - edit_operations.set_text(Some(&line.text)); - // Append it to JavaScript Array - let edit_operations_array = js_sys::Array::new(); - edit_operations_array.push(&edit_operations); - let before_cursor_state_array = js_sys::Array::new(); - before_cursor_state_array.push(&before_cursor_state); - // Do the edit! - curr_model.push_edit_operations(&before_cursor_state_array, &edit_operations_array, None); - } else if line.line_number == lines_beyond_counter { - // Append instruction - if !add_new_lines { - // If we've added new lines already, - // start adding new lines by getting a copy of the current text model to append to - add_new_lines = true; - curr_value = text_model.get_value(); - } - curr_value.push_str("\n"); - curr_value.push_str(&line.text); - lines_beyond_counter += 1; + + let mut changed_lines: Vec = vec![]; + for (i, data) in instructions.iter().enumerate() { + let address = i as u64; + // change string version based on architecture + let string_version = match datapath_state.current_architecture { + AvailableDatapaths::MIPS => { + match get_string_version(*data) { + Ok(string) => string, + Err(string) => string, } + }, + AvailableDatapaths::RISCV => { + String::from("") } - if add_new_lines { - text_model.set_value(&curr_value); + }; + + let curr_word = match datapath.memory.load_word(address * 4) { + Ok(data) => data, + Err(e) => { + debug!("{:?}", e); + 0 } + }; + if curr_word != *data { + debug!("address: {:?}", address * 4); + log::debug!("curr word: {}, new word: {}", curr_word, data); + changed_lines.push(UpdatedLine::new(string_version, i)); - }, - Err(err) => { - debug!("Error: {}", err) + communicator.set_memory(address * 4, *data); } - }; - () + } + // Memory updated successfully + let program_info = program_info_ref.borrow().clone(); + let mut lines_beyond_counter = program_info.address_to_line_number.len(); + let mut curr_value = text_model.get_value().to_owned(); + let mut add_new_lines = false; + for line in changed_lines { + // Check if we're updating or appending instruction + if line.line_number < program_info.address_to_line_number.len() { + let updated_line = program_info.address_to_line_number[line.line_number] as f64 + 1.0; + let curr_model = text_model.as_ref(); + + // Get the current line's contents in the code editor + let line_to_replace = curr_model.get_line_content(updated_line); + // Create the range to replace + let mut start_line_column = 0.0; + let end_line_column = line_to_replace.len() as f64 + 2.0; + for (i, c) in line_to_replace.chars().enumerate() { + if c.is_alphanumeric() { + start_line_column = i as f64 + 1.0; + break; + } + } + let edit_range = monaco::sys::Range::new(updated_line, start_line_column, updated_line, end_line_column); + let before_cursor_state = monaco::sys::Selection::new(updated_line, start_line_column, updated_line,end_line_column); + // Create the edit operation using the range and new text + let edit_operations: monaco::sys::editor::IIdentifiedSingleEditOperation = Object::new().unchecked_into(); + edit_operations.set_range(&edit_range); + edit_operations.set_text(Some(&line.text)); + // Append it to JavaScript Array + let edit_operations_array = js_sys::Array::new(); + edit_operations_array.push(&edit_operations); + let before_cursor_state_array = js_sys::Array::new(); + before_cursor_state_array.push(&before_cursor_state); + // Do the edit! + curr_model.push_edit_operations(&before_cursor_state_array, &edit_operations_array, None); + } else if line.line_number == lines_beyond_counter { + // Append instruction + if !add_new_lines { + // If we've added new lines already, + // start adding new lines by getting a copy of the current text model to append to + add_new_lines = true; + curr_value = text_model.get_value(); + } + curr_value.push_str("\n"); + curr_value.push_str(&line.text); + lines_beyond_counter += 1; + } + } + if add_new_lines { + text_model.set_value(&curr_value); + } }, Err(err) => { debug!("Error updating memory: {}", err) } } - let hexdump = &datapath.memory.generate_formatted_hex(); + let hexdump = datapath.memory.generate_formatted_hex(); - memory_text_model.set_value(hexdump); + memory_text_model.set_value(&hexdump); // Update the parsed info for text and data segment views let (program_info, _) = parser(text_model.get_value()); diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index 4529ab819..106e8495b 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -55,7 +55,7 @@ pub trait Datapath { /// Retrieve all memory as-is. fn get_memory(&self) -> &Memory; - fn set_memory(&mut self, ptr: usize, data: Vec); + fn set_memory(&mut self, ptr: u64, data: u32); /// Returns if the datapath is in a "halted" or "stopped" state. This may /// be true in the case where an error had occurred previously. diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index bd6b18585..d9848ae3b 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -287,8 +287,8 @@ impl Datapath for MipsDatapath { &self.memory } - fn set_memory(&mut self, _ptr: usize, _data: Vec) { - todo!() + fn set_memory(&mut self, _ptr: u64, _data: u32) { + self.memory.store_word(_ptr, _data); } fn is_halted(&self) -> bool { diff --git a/src/emulation_core/mips/memory.rs b/src/emulation_core/mips/memory.rs index 5b4217a60..42a317aab 100644 --- a/src/emulation_core/mips/memory.rs +++ b/src/emulation_core/mips/memory.rs @@ -12,20 +12,20 @@ pub struct Memory { pub memory: Vec, } -#[derive(Clone, Debug, PartialEq)] -pub struct UpdatedLine { - pub text: String, - pub line_number: usize -} - -impl UpdatedLine { - pub fn new(text: String, line_number: usize) -> Self { - UpdatedLine { - text, - line_number - } - } -} +// #[derive(Clone, Debug, PartialEq)] +// pub struct UpdatedLine { +// pub text: String, +// pub line_number: usize +// } + +// impl UpdatedLine { +// pub fn new(text: String, line_number: usize) -> Self { +// UpdatedLine { +// text, +// line_number +// } +// } +// } impl Default for Memory { fn default() -> Self { @@ -128,44 +128,32 @@ impl Memory { Ok(result) } - pub fn parse_hexdump(&mut self, input: &str) -> Result, String> { - let mut words = Vec::new(); - for line in input.lines() { - let parts: Vec<&str> = line.split('\t').collect(); - for &part in &parts[2..6] { - let data = u32::from_str_radix(part, 16).map_err(|e| e.to_string())?; - words.push(data); - } - } - Ok(words) - } - - // Returns instructions that were updated with their string versions and line numbers - pub fn store_hexdump(&mut self, instructions: Vec) -> Result, String> { - let mut changed_lines: Vec = vec![]; - for (i, data) in instructions.iter().enumerate() { - let address = i as u64; - let line = match get_string_version(*data) { - Ok(string) => string, - Err(string) => string, - }; - let curr_word = match self.load_word(address * 4) { - Ok(data) => data, - Err(e) => { - debug!("{:?}", e); - 0 - } - }; - if curr_word != *data { - changed_lines.push(UpdatedLine::new(line, i)); - self.store_word(address * 4, *data)? - } - } - - Ok(changed_lines) - } - - pub fn generate_formatted_hex(&mut self) -> String { + // // Returns instructions that were updated with their string versions and line numbers + // pub fn store_hexdump(&mut self, instructions: Vec) -> Result, String> { + // let mut changed_lines: Vec = vec![]; + // for (i, data) in instructions.iter().enumerate() { + // let address = i as u64; + // let line = match get_string_version(*data) { + // Ok(string) => string, + // Err(string) => string, + // }; + // let curr_word = match self.load_word(address * 4) { + // Ok(data) => data, + // Err(e) => { + // debug!("{:?}", e); + // 0 + // } + // }; + // if curr_word != *data { + // changed_lines.push(UpdatedLine::new(line, i)); + // self.store_word(address * 4, *data)? + // } + // } + + // Ok(changed_lines) + // } + + pub fn generate_formatted_hex(&self) -> String { let iterator = MemoryIter::new(&self); let mut string: String = "".to_string(); diff --git a/src/ui/hex_editor/component.rs b/src/ui/hex_editor/component.rs index 819eb7574..0bbc72f26 100644 --- a/src/ui/hex_editor/component.rs +++ b/src/ui/hex_editor/component.rs @@ -33,6 +33,20 @@ pub struct HexEditorProps { pub instruction_num: UseStateHandle, } +#[derive(Clone, Debug, PartialEq)] +pub struct UpdatedLine { + pub text: String, + pub line_number: usize +} +impl UpdatedLine { + pub fn new(text: String, line_number: usize) -> Self { + UpdatedLine { + text, + line_number + } + } +} + #[function_component(HexEditor)] pub fn hex_editor(props: &HexEditorProps) -> Html { let editor_link = CodeEditorLink::new(); @@ -204,3 +218,15 @@ fn get_options() -> IStandaloneEditorConstructionOptions { options } + +pub fn parse_hexdump(input: &str) -> Result, String> { + let mut words = Vec::new(); + for line in input.lines() { + let parts: Vec<&str> = line.split('\t').collect(); + for &part in &parts[2..6] { + let data = u32::from_str_radix(part, 16).map_err(|e| e.to_string())?; + words.push(data); + } + } + Ok(words) +} \ No newline at end of file diff --git a/static/assembly_examples/data.asm b/static/assembly_examples/data.asm index c89613710..4f2ad3957 100644 --- a/static/assembly_examples/data.asm +++ b/static/assembly_examples/data.asm @@ -1,5 +1,7 @@ .text addi $t0, $zero, 300 +addi $t1, $zero, 340 +addi $t2, $zero, 380 syscall .data a_secret: .ascii "hi"