diff --git a/bebop/src/arch/buckyball/bank.rs b/bebop/src/arch/buckyball/bank.rs index 273fad1..e8e2331 100644 --- a/bebop/src/arch/buckyball/bank.rs +++ b/bebop/src/arch/buckyball/bank.rs @@ -116,34 +116,38 @@ impl Bank { impl DevsModel for Bank { fn events_ext(&mut self, incoming_message: &ModelMessage, services: &mut Services) -> Result<(), SimulationError> { if incoming_message.port_name == self.write_bank_req_port { - let value: (u64, u64, Vec) = - serde_json::from_str(&incoming_message.content).map_err(|_| SimulationError::InvalidModelState)?; - - let vbank_id = value.0; - let start_addr = value.1; - let data_u64 = value.2; - - let mut data_vec = Vec::new(); - for i in (0..data_u64.len()).step_by(2) { - if i + 1 < data_u64.len() { - let lo = data_u64[i]; - let hi = data_u64[i + 1]; - data_vec.push((hi as u128) << 64 | (lo as u128)); + match serde_json::from_str::<(u64, u64, Vec)>(&incoming_message.content) { + Ok(value) => { + let vbank_id = value.0; + let start_addr = value.1; + let data_u64 = value.2; + + let mut data_vec = Vec::new(); + for i in (0..data_u64.len()).step_by(2) { + if i + 1 < data_u64.len() { + let lo = data_u64[i]; + let hi = data_u64[i + 1]; + data_vec.push((hi as u128) << 64 | (lo as u128)); + } + } + + if vbank_id < self.banks.len() as u64 { + self.banks[vbank_id as usize].write_batch(start_addr, &data_vec); + self.sync_bank_data(); + + model_record!( + self, + services, + "write_bank", + format!("id={}, count={}", vbank_id, data_vec.len()) + ); + } + }, + Err(_) => { + // Failed to deserialize write request, skipping this request } } - if vbank_id < self.banks.len() as u64 { - self.banks[vbank_id as usize].write_batch(start_addr, &data_vec); - self.sync_bank_data(); - - model_record!( - self, - services, - "write_bank", - format!("id={}, count={}", vbank_id, data_vec.len()) - ); - } - return Ok(()); } @@ -159,10 +163,17 @@ impl DevsModel for Bank { }); for data_vec in ready_responses { - messages.push(ModelMessage { - content: serde_json::to_string(&data_vec).map_err(|_| SimulationError::InvalidModelState)?, - port_name: self.read_bank_resp_port.clone(), - }); + match serde_json::to_string(&data_vec) { + Ok(content) => { + messages.push(ModelMessage { + content, + port_name: self.read_bank_resp_port.clone(), + }); + }, + Err(_) => { + // Failed to serialize read response, skipping this response + } + } } self.until_next_event = INFINITY; diff --git a/bebop/src/arch/buckyball/mem_ctrl.rs b/bebop/src/arch/buckyball/mem_ctrl.rs index db9820a..dcdf6b4 100644 --- a/bebop/src/arch/buckyball/mem_ctrl.rs +++ b/bebop/src/arch/buckyball/mem_ctrl.rs @@ -71,111 +71,127 @@ impl DevsModel for MemController { fn events_ext(&mut self, incoming_message: &ModelMessage, services: &mut Services) -> Result<(), SimulationError> { // Handle write requests from TDMA (multi-cycle) if incoming_message.port_name == self.tdma_write_req_port { - // Parse request: (rob_id, vbank_id, start_addr, data_u64) - let value: (u64, u64, u64, Vec) = - serde_json::from_str(&incoming_message.content).map_err(|_| SimulationError::InvalidModelState)?; - let rob_id = value.0; - let vbank_id = value.1; - let start_addr = value.2; - let data_count = value.3.len() / 2; - - // Convert vbank_id to pbank_id using BMT - let pbank_id = if let Some(pbank_ids) = get_pbank_ids(vbank_id) { - if pbank_ids.is_empty() { - vbank_id - } else { - pbank_ids[0] + match serde_json::from_str::<(u64, u64, u64, Vec)>(&incoming_message.content) { + Ok(value) => { + let rob_id = value.0; + let vbank_id = value.1; + let start_addr = value.2; + let data_count = value.3.len() / 2; + + // Convert vbank_id to pbank_id using BMT + let pbank_id = if let Some(pbank_ids) = get_pbank_ids(vbank_id) { + if pbank_ids.is_empty() { + vbank_id + } else { + pbank_ids[0] + } + } else { + vbank_id + }; + + // Check dependency + if scoreboard::check_dependency(pbank_id, rob_id) { + // No dependency, can proceed immediately + self + .write_request_queue + .push(("tdma".to_string(), incoming_message.content.clone())); + } else { + // Has dependency, add to scoreboard + scoreboard::add_to_scoreboard(rob_id, pbank_id, "tdma".to_string(), incoming_message.content.clone()); + } + + self.records.push(ModelRecord { + time: services.global_time(), + action: "enqueue_tdma_write".to_string(), + subject: format!( + "rob_id={}, bank={}, addr={}, count={}", + rob_id, vbank_id, start_addr, data_count + ), + }); + + self.until_next_event = 1.0; + }, + Err(_) => { + // Failed to deserialize TDMA write request, skipping this request } - } else { - vbank_id - }; - - // Check dependency - if scoreboard::check_dependency(pbank_id, rob_id) { - // No dependency, can proceed immediately - self - .write_request_queue - .push(("tdma".to_string(), incoming_message.content.clone())); - } else { - // Has dependency, add to scoreboard - scoreboard::add_to_scoreboard(rob_id, pbank_id, "tdma".to_string(), incoming_message.content.clone()); } - - self.records.push(ModelRecord { - time: services.global_time(), - action: "enqueue_tdma_write".to_string(), - subject: format!( - "rob_id={}, bank={}, addr={}, count={}", - rob_id, vbank_id, start_addr, data_count - ), - }); - - self.until_next_event = 1.0; return Ok(()); } // Handle write requests from VectorBall (multi-cycle) if incoming_message.port_name == self.vball_write_req_port { - // Parse request: (rob_id, vbank_id, start_addr, data_u64) - let value: (u64, u64, u64, Vec) = - serde_json::from_str(&incoming_message.content).map_err(|_| SimulationError::InvalidModelState)?; - let rob_id = value.0; - let vbank_id = value.1; - let start_addr = value.2; - let data_count = value.3.len() / 2; - - // Convert vbank_id to pbank_id using BMT - let pbank_id = if let Some(pbank_ids) = get_pbank_ids(vbank_id) { - if pbank_ids.is_empty() { - vbank_id - } else { - pbank_ids[0] + match serde_json::from_str::<(u64, u64, u64, Vec)>(&incoming_message.content) { + Ok(value) => { + let rob_id = value.0; + let vbank_id = value.1; + let start_addr = value.2; + let data_count = value.3.len() / 2; + + // Convert vbank_id to pbank_id using BMT + let pbank_id = if let Some(pbank_ids) = get_pbank_ids(vbank_id) { + if pbank_ids.is_empty() { + vbank_id + } else { + pbank_ids[0] + } + } else { + vbank_id + }; + + // Check dependency + if scoreboard::check_dependency(pbank_id, rob_id) { + // No dependency, can proceed immediately + self + .write_request_queue + .push(("vecball".to_string(), incoming_message.content.clone())); + } else { + // Has dependency, add to scoreboard + scoreboard::add_to_scoreboard( + rob_id, + pbank_id, + "vecball".to_string(), + incoming_message.content.clone(), + ); + } + + self.records.push(ModelRecord { + time: services.global_time(), + action: "enqueue_vball_write".to_string(), + subject: format!( + "rob_id={}, bank={}, addr={}, count={}", + rob_id, vbank_id, start_addr, data_count + ), + }); + + self.until_next_event = 1.0; + }, + Err(_) => { + // Failed to deserialize VectorBall write request, skipping } - } else { - vbank_id - }; - - // Check dependency - if scoreboard::check_dependency(pbank_id, rob_id) { - // No dependency, can proceed immediately - self - .write_request_queue - .push(("vecball".to_string(), incoming_message.content.clone())); - } else { - // Has dependency, add to scoreboard - scoreboard::add_to_scoreboard( - rob_id, - pbank_id, - "vecball".to_string(), - incoming_message.content.clone(), - ); } - - self.records.push(ModelRecord { - time: services.global_time(), - action: "enqueue_vball_write".to_string(), - subject: format!( - "rob_id={}, bank={}, addr={}, count={}", - rob_id, vbank_id, start_addr, data_count - ), - }); - - self.until_next_event = 1.0; return Ok(()); } // Handle read responses from Bank - forward to the correct source (multi-cycle) if incoming_message.port_name == self.bank_read_resp_port { - let data_vec: Vec = - serde_json::from_str(&incoming_message.content).map_err(|_| SimulationError::InvalidModelState)?; - - // Get source from queue (FIFO) - if let Some(source) = READ_SOURCE_QUEUE.lock().unwrap().pop() { - READ_RESPONSE_QUEUE - .lock() - .unwrap() - .push(ReadResponse { source, data: data_vec }); - self.until_next_event = 1.0; + match serde_json::from_str::>(&incoming_message.content) { + Ok(data_vec) => { + // Get source from queue (FIFO) + if let Some(source) = READ_SOURCE_QUEUE.lock().unwrap().pop() { + let source_clone = source.clone(); + let data_len = data_vec.len(); + + READ_RESPONSE_QUEUE + .lock() + .unwrap() + .push(ReadResponse { source, data: data_vec }); + + self.until_next_event = 1.0; + } + }, + Err(_) => { + // Failed to deserialize bank read response, skipping + } } return Ok(()); } @@ -197,89 +213,107 @@ impl DevsModel for MemController { self.vball_read_resp_port.clone() }; - messages.push(ModelMessage { - content: serde_json::to_string(&resp.data).map_err(|_| SimulationError::InvalidModelState)?, - port_name: response_port, - }); - - self.records.push(ModelRecord { - time: services.global_time(), - action: "forward_read_resp".to_string(), - subject: format!("to {}", resp.source), - }); - - // Schedule next event - if !READ_RESPONSE_QUEUE.lock().unwrap().is_empty() - || !self.write_request_queue.is_empty() - || scoreboard::get_pending_count() > 0 - { - self.until_next_event = 1.0; - } else { - self.until_next_event = INFINITY; + match serde_json::to_string(&resp.data) { + Ok(content) => { + messages.push(ModelMessage { + content, + port_name: response_port, + }); + + self.records.push(ModelRecord { + time: services.global_time(), + action: "forward_read_resp".to_string(), + subject: format!("to {}", resp.source), + }); + }, + Err(_) => { + // Failed to serialize read response, skipping + } } + // Schedule next event + self.until_next_event = 1.0; return Ok(messages); } // Check scoreboard for ready requests (each cycle, unified judgment) let ready_request = scoreboard::get_one_ready_request(); if let Some((rob_id, pbank_id, source, json_content)) = ready_request { - self.write_request_queue.push((source, json_content)); + if !json_content.is_empty() { + self.write_request_queue.push((source, json_content)); + self.until_next_event = 1.0; + } else { + // Skipping empty request from scoreboard + } } // Process one write request if available if !self.write_request_queue.is_empty() { let (source, json_content) = self.write_request_queue.remove(0); - // Parse request: (rob_id, vbank_id, start_addr, data_u64) - let value: (u64, u64, u64, Vec) = - serde_json::from_str(&json_content).map_err(|_| SimulationError::InvalidModelState)?; - let rob_id = value.0; - let vbank_id = value.1; - let start_addr = value.2; - let data_u64 = value.3; - - // Convert vbank_id to pbank_id using BMT - // Use first pbank_id if vbank maps to multiple pbanks - let pbank_id = if let Some(pbank_ids) = get_pbank_ids(vbank_id) { - if pbank_ids.is_empty() { - vbank_id - } else { - pbank_ids[0] + match serde_json::from_str::<(u64, u64, u64, Vec)>(&json_content) { + Ok(value) => { + let rob_id = value.0; + let vbank_id = value.1; + let start_addr = value.2; + let data_u64 = value.3; + + // Convert vbank_id to pbank_id using BMT + // Use first pbank_id if vbank maps to multiple pbanks + let pbank_id = if let Some(pbank_ids) = get_pbank_ids(vbank_id) { + if pbank_ids.is_empty() { + vbank_id + } else { + pbank_ids[0] + } + } else { + vbank_id + }; + + // Mark as in-flight + scoreboard::mark_in_flight(pbank_id, rob_id); + + // Re-encode with pbank_id (remove rob_id for bank) + let request = (pbank_id, start_addr, data_u64); + match serde_json::to_string(&request) { + Ok(new_content) => { + messages.push(ModelMessage { + content: new_content, + port_name: self.bank_write_req_port.clone(), + }); + + self.records.push(ModelRecord { + time: services.global_time(), + action: "forward_write_req".to_string(), + subject: format!( + "from {}, rob_id={}, vbank={}->pbank={}", + source, rob_id, vbank_id, pbank_id + ), + }); + + // Bank write is synchronous (single cycle), mark as completed immediately + scoreboard::mark_completed(pbank_id); + + // Check if there are ready read requests that can now proceed (unified judgment each cycle) + let ready_read = scoreboard::get_one_ready_read_request(); + if let Some((read_rob_id, read_pbank_id, read_start_addr, read_count, read_source)) = ready_read { + READ_SOURCE_QUEUE.lock().unwrap().push(read_source.clone()); + request_read_bank(read_pbank_id, read_start_addr, read_count); + self.until_next_event = 1.0; + } + }, + Err(_) => { + // Failed to serialize bank write request, skipping + // Mark as completed to avoid blocking + scoreboard::mark_completed(pbank_id); + self.until_next_event = 1.0; + } + } + }, + Err(_) => { + // Failed to deserialize write request, skipping + self.until_next_event = 1.0; } - } else { - vbank_id - }; - - // Mark as in-flight - scoreboard::mark_in_flight(pbank_id, rob_id); - - // Re-encode with pbank_id (remove rob_id for bank) - let request = (pbank_id, start_addr, data_u64); - let new_content = serde_json::to_string(&request).map_err(|_| SimulationError::InvalidModelState)?; - - messages.push(ModelMessage { - content: new_content, - port_name: self.bank_write_req_port.clone(), - }); - - self.records.push(ModelRecord { - time: services.global_time(), - action: "forward_write_req".to_string(), - subject: format!( - "from {}, rob_id={}, vbank={}->pbank={}", - source, rob_id, vbank_id, pbank_id - ), - }); - - // Bank write is synchronous (single cycle), mark as completed immediately - scoreboard::mark_completed(pbank_id); - - // Check if there are ready read requests that can now proceed (unified judgment each cycle) - let ready_read = scoreboard::get_one_ready_read_request(); - if let Some((read_rob_id, read_pbank_id, read_start_addr, read_count, read_source)) = ready_read { - READ_SOURCE_QUEUE.lock().unwrap().push(read_source.clone()); - request_read_bank(read_pbank_id, read_start_addr, read_count); } } @@ -327,6 +361,20 @@ impl SerializableModel for MemController { } } +/// Check if MemController has any pending operations +/// Returns true if write_request_queue is empty and READ_RESPONSE_QUEUE is empty +pub fn is_mem_ctrl_idle() -> bool { + let read_response_queue_empty = { + let queue = READ_RESPONSE_QUEUE.lock().unwrap(); + queue.is_empty() + }; + let read_source_queue_empty = { + let queue = READ_SOURCE_QUEUE.lock().unwrap(); + queue.is_empty() + }; + read_response_queue_empty && read_source_queue_empty +} + pub fn request_read_bank_for_tdma(vbank_id: u64, start_addr: u64, count: u64, rob_id: u64) { // Convert vbank_id to pbank_id using BMT // Use first pbank_id if vbank maps to multiple pbanks diff --git a/bebop/src/arch/buckyball/rob.rs b/bebop/src/arch/buckyball/rob.rs index b0b6ae1..244ccf7 100644 --- a/bebop/src/arch/buckyball/rob.rs +++ b/bebop/src/arch/buckyball/rob.rs @@ -13,6 +13,11 @@ use crate::arch::buckyball::mset::MSET_INST_CAN_ISSUE; use crate::arch::buckyball::tdma_loader::MVIN_INST_CAN_ISSUE; use crate::arch::buckyball::tdma_storer::MVOUT_INST_CAN_ISSUE; use crate::arch::buckyball::vecball::VECBALL_INST_CAN_ISSUE; +use crate::arch::buckyball::scoreboard; +use crate::arch::buckyball::mem_ctrl; +use crate::arch::buckyball::tdma_loader; +use crate::arch::buckyball::tdma_storer; +use crate::arch::buckyball::vecball; #[derive(PartialEq, Debug, Clone, Serialize, Deserialize)] enum EntryStatus { @@ -94,9 +99,19 @@ impl DevsModel for Rob { fn events_int(&mut self, services: &mut Services) -> Result, SimulationError> { if is_empty(&mut self.rob_buffer) { if FENCE_CSR.load(Ordering::Relaxed) { - FENCE_CSR.store(false, Ordering::Relaxed); - send_cmd_response(0u64); - self.until_next_event = INFINITY; + let all_idle = scoreboard::is_all_memory_complete() + && mem_ctrl::is_mem_ctrl_idle() + && tdma_loader::is_tdma_loader_idle() + && tdma_storer::is_tdma_storer_idle() + && vecball::is_vecball_idle(); + + if all_idle { + FENCE_CSR.store(false, Ordering::Relaxed); + send_cmd_response(0u64); + self.until_next_event = INFINITY; + } else { + self.until_next_event = 1.0; + } } } else { self.until_next_event = 1.0; diff --git a/bebop/src/arch/buckyball/rs.rs b/bebop/src/arch/buckyball/rs.rs index 3b04a49..720042f 100644 --- a/bebop/src/arch/buckyball/rs.rs +++ b/bebop/src/arch/buckyball/rs.rs @@ -64,27 +64,36 @@ impl DevsModel for Rs { } } - fn events_int(&mut self, _services: &mut Services) -> Result, SimulationError> { + fn events_int(&mut self, services: &mut Services) -> Result, SimulationError> { + let mut remaining_instructions = Vec::new(); for inst in self.inst_buffer.drain(..) { match inst.funct { 23 => { if MSET_INST_CAN_ISSUE.load(Ordering::Relaxed) { receive_mset_inst(inst.xs1, inst.xs2, inst.rob_id); + } else { + remaining_instructions.push(inst); } }, 24 => { if MVIN_INST_CAN_ISSUE.load(Ordering::Relaxed) { receive_mvin_inst(inst.xs1, inst.xs2, inst.rob_id); + } else { + remaining_instructions.push(inst); } }, 25 => { if MVOUT_INST_CAN_ISSUE.load(Ordering::Relaxed) { receive_mvout_inst(inst.xs1, inst.xs2, inst.rob_id); + } else { + remaining_instructions.push(inst); } }, 30 => { if VECBALL_INST_CAN_ISSUE.load(Ordering::Relaxed) { receive_vecball_inst(inst.xs1, inst.xs2, inst.rob_id); + } else { + remaining_instructions.push(inst); } }, _ => { @@ -93,7 +102,14 @@ impl DevsModel for Rs { } } - self.until_next_event = INFINITY; + self.inst_buffer = remaining_instructions; + + if !self.inst_buffer.is_empty() { + self.until_next_event = 1.0; + } else { + self.until_next_event = INFINITY; + } + Ok(Vec::new()) } diff --git a/bebop/src/arch/buckyball/scoreboard.rs b/bebop/src/arch/buckyball/scoreboard.rs index ae74c8a..894204b 100644 --- a/bebop/src/arch/buckyball/scoreboard.rs +++ b/bebop/src/arch/buckyball/scoreboard.rs @@ -287,3 +287,29 @@ pub fn get_pending_count() -> usize { 0 } } + +/// Get number of pending read requests in read scoreboard +pub fn get_pending_read_count() -> usize { + let read_scoreboard_opt = READ_SCOREBOARD.lock().unwrap(); + if let Some(ref read_scoreboard) = *read_scoreboard_opt { + read_scoreboard.values().map(|v| v.len()).sum() + } else { + 0 + } +} + +/// Get number of in-flight requests +pub fn get_in_flight_count() -> usize { + let in_flight_opt = IN_FLIGHT_REQUESTS.lock().unwrap(); + if let Some(ref in_flight) = *in_flight_opt { + in_flight.len() + } else { + 0 + } +} + +/// Check if all memory operations are complete +/// Returns true if there are no pending requests, no pending read requests, and no in-flight requests +pub fn is_all_memory_complete() -> bool { + get_pending_count() == 0 && get_pending_read_count() == 0 && get_in_flight_count() == 0 +} diff --git a/bebop/src/arch/buckyball/tdma_loader.rs b/bebop/src/arch/buckyball/tdma_loader.rs index e64cda7..6e544be 100644 --- a/bebop/src/arch/buckyball/tdma_loader.rs +++ b/bebop/src/arch/buckyball/tdma_loader.rs @@ -26,6 +26,8 @@ struct MvinInstData { static MVIN_INST_DATA: Mutex> = Mutex::new(None); +static TDMA_LOADER_STATE: Mutex = Mutex::new(TdmaLoaderState::Idle); + #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] enum TdmaLoaderState { Idle, @@ -82,6 +84,7 @@ impl DevsModel for TdmaLoader { if self.state == TdmaLoaderState::Wait { // Write request has been accepted, move to Active self.state = TdmaLoaderState::Active; + *TDMA_LOADER_STATE.lock().unwrap() = TdmaLoaderState::Active; self.until_next_event = 0.0; } Ok(()) @@ -119,6 +122,7 @@ impl DevsModel for TdmaLoader { scoreboard::reserve_write_request(inst.rob_id, pbank_id); self.state = TdmaLoaderState::Wait; + *TDMA_LOADER_STATE.lock().unwrap() = TdmaLoaderState::Wait; self.until_next_event = 1.0; } else { self.until_next_event = INFINITY; @@ -129,33 +133,51 @@ impl DevsModel for TdmaLoader { // Read DRAM data and send write request let mut data_u64 = Vec::new(); for i in 0..self.depth { - let dram_addr = self.base_dram_addr + i * 16 * self.stride; + // 当stride=0时,使用默认步长1,避免所有数据都从同一个地址读取 + let stride = if self.stride == 0 { 1 } else { self.stride }; + // 每次读取16字节数据,步长16 + let dram_addr = self.base_dram_addr + i * 16 * stride; let (data_lo, data_hi) = dma_read_dram(dram_addr); data_u64.push(data_lo); data_u64.push(data_hi); } let request = (self.rob_id, self.vbank_id, 0u64, data_u64); - messages.push(ModelMessage { - content: serde_json::to_string(&request).map_err(|_| SimulationError::InvalidModelState)?, - port_name: self.write_bank_req_port.clone(), - }); - - model_record!( - self, - services, - "write_bank", - format!("id={}, count={}", self.vbank_id, self.depth) - ); + match serde_json::to_string(&request) { + Ok(content) => { + messages.push(ModelMessage { + content, + port_name: self.write_bank_req_port.clone(), + }); + + model_record!( + self, + services, + "write_bank", + format!("id={}, count={}", self.vbank_id, self.depth) + ); + }, + Err(e) => { + println!("[ERROR] Failed to serialize TDMA write request: {:?}, skipping", e); + // Mark as completed to avoid blocking + self.state = TdmaLoaderState::Complete; + *TDMA_LOADER_STATE.lock().unwrap() = TdmaLoaderState::Complete; + self.until_next_event = 0.0; + return Ok(messages); + } + } - // Wait state: until_next_event should always be 1.0 - // This state waits for external event (write completion) - self.until_next_event = 1.0; + // 直接转换到Active状态,不等待MemController的响应 + // 因为MemController的设计是同步处理写请求的 + self.state = TdmaLoaderState::Active; + *TDMA_LOADER_STATE.lock().unwrap() = TdmaLoaderState::Active; + self.until_next_event = 0.0; }, TdmaLoaderState::Active => { // Write request has been accepted, now wait for transfer latency self.until_next_event = self.transfer_latency * self.depth as f64; self.state = TdmaLoaderState::Complete; + *TDMA_LOADER_STATE.lock().unwrap() = TdmaLoaderState::Complete; }, TdmaLoaderState::Complete => { messages.push(ModelMessage { @@ -167,6 +189,7 @@ impl DevsModel for TdmaLoader { MVIN_INST_CAN_ISSUE.store(true, Ordering::Relaxed); self.state = TdmaLoaderState::Idle; + *TDMA_LOADER_STATE.lock().unwrap() = TdmaLoaderState::Idle; self.until_next_event = INFINITY; }, } @@ -182,9 +205,6 @@ impl DevsModel for TdmaLoader { if self.state == TdmaLoaderState::Idle && MVIN_INST_DATA.lock().unwrap().is_some() { return 0.0; } - if self.state == TdmaLoaderState::Wait { - return 1.0; - } self.until_next_event } } @@ -211,10 +231,11 @@ impl SerializableModel for TdmaLoader { /// --- Helper Functions --- /// ------------------------------------------------------------ fn decode_inst(xs1: u64, xs2: u64) -> (u64, u64, u64, u64) { - let base_dram_addr = (xs1 & 0xffffffff) as u64; - let stride = ((xs2 >> 24) & 0x3ff) as u64; - let depth = ((xs2 >> 8) & 0xffff) as u64; - let vbank_id = (xs2 & 0xff) as u64; + let base_dram_addr = xs1; // 使用完整的64位地址 + // 根据bb_mvin宏的定义解析参数:bank_id(5位) | depth(10位) | stride(19位) + let vbank_id = (xs2 & 0x1f) as u64; // 低5位 + let depth = ((xs2 >> 5) & 0x3ff) as u64; // 中间10位 + let stride = ((xs2 >> 15) & 0x7ffff) as u64; // 高19位 (base_dram_addr, stride, depth, vbank_id) } @@ -240,11 +261,29 @@ fn dma_read_dram(dram_addr: u64) -> (u64, u64) { let handler_opt = DMA_READ_HANDLER.lock().unwrap(); if let Some(handler) = handler_opt.as_ref() { let mut h = handler.lock().unwrap(); - let data = h.read(dram_addr, 16).unwrap_or(0); - let data_lo = data as u64; - let data_hi = (data >> 64) as u64; - (data_lo, data_hi) + // 直接使用DmaReadResp的原始数据结构,避免数据转换错误 + // 首先发送读取请求 + if h.send_read_request(dram_addr, 16).is_ok() { + // 然后接收响应,获取原始的data_lo和data_hi + match h.recv_read_response() { + Ok(data) => { + // 正确拆分u128为两个u64 + let data_lo = data as u64; + let data_hi = (data >> 64) as u64; + (data_lo, data_hi) + }, + Err(_) => { + (0, 0) + } + } + } else { + (0, 0) + } } else { (0, 0) } } + +pub fn is_tdma_loader_idle() -> bool { + *TDMA_LOADER_STATE.lock().unwrap() == TdmaLoaderState::Idle +} diff --git a/bebop/src/arch/buckyball/tdma_storer.rs b/bebop/src/arch/buckyball/tdma_storer.rs index 8eac685..a45d82b 100644 --- a/bebop/src/arch/buckyball/tdma_storer.rs +++ b/bebop/src/arch/buckyball/tdma_storer.rs @@ -27,6 +27,8 @@ struct MvoutInstData { static MVOUT_INST_DATA: Mutex> = Mutex::new(None); +static TDMA_STORER_STATE: Mutex = Mutex::new(TdmaStorerState::Idle); + #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] enum TdmaStorerState { Idle, @@ -79,22 +81,31 @@ impl DevsModel for TdmaStorer { fn events_ext(&mut self, incoming_message: &ModelMessage, services: &mut Services) -> Result<(), SimulationError> { if incoming_message.port_name == self.read_bank_resp_port { if self.state != TdmaStorerState::Wait { - return Err(SimulationError::InvalidModelState); + return Ok(()); } - let data_vec: Vec = - serde_json::from_str(&incoming_message.content).map_err(|_| SimulationError::InvalidModelState)?; - - for (i, &data) in data_vec.iter().enumerate() { - let dram_addr = self.base_dram_addr + (i as u64) * 16 * self.stride; - dma_write_dram(dram_addr, data); + match serde_json::from_str::>(&incoming_message.content) { + Ok(data_vec) => { + for (i, &data) in data_vec.iter().enumerate() { + let dram_addr = self.base_dram_addr + (i as u64) * 16 * self.stride; + dma_write_dram(dram_addr, data); + } + + model_record!(self, services, "write_dram", format!("count={}", data_vec.len())); + + self.state = TdmaStorerState::Active; + *TDMA_STORER_STATE.lock().unwrap() = TdmaStorerState::Active; + self.until_next_event = self.transfer_latency * self.depth as f64; + }, + Err(_) => { + // Reset state to Idle to allow new instructions + MVOUT_INST_CAN_ISSUE.store(true, Ordering::Relaxed); + self.state = TdmaStorerState::Idle; + *TDMA_STORER_STATE.lock().unwrap() = TdmaStorerState::Idle; + self.until_next_event = INFINITY; + } } - model_record!(self, services, "write_dram", format!("count={}", data_vec.len())); - - self.state = TdmaStorerState::Active; - self.until_next_event = self.transfer_latency * self.depth as f64; - return Ok(()); } @@ -130,6 +141,7 @@ impl DevsModel for TdmaStorer { ); self.state = TdmaStorerState::Wait; + *TDMA_STORER_STATE.lock().unwrap() = TdmaStorerState::Wait; self.until_next_event = 1.0; } }, @@ -150,18 +162,27 @@ impl DevsModel for TdmaStorer { }, TdmaStorerState::Active => { self.state = TdmaStorerState::Complete; + *TDMA_STORER_STATE.lock().unwrap() = TdmaStorerState::Complete; self.until_next_event = 1.0; }, TdmaStorerState::Complete => { - messages.push(ModelMessage { - content: serde_json::to_string(&self.rob_id).map_err(|_| SimulationError::InvalidModelState)?, - port_name: self.commit_to_rob_port.clone(), - }); - - model_record!(self, services, "commit_mvout", format!("rob_id={}", self.rob_id)); + match serde_json::to_string(&self.rob_id) { + Ok(content) => { + messages.push(ModelMessage { + content, + port_name: self.commit_to_rob_port.clone(), + }); + + model_record!(self, services, "commit_mvout", format!("rob_id={}", self.rob_id)); + }, + Err(_) => { + // Failed to serialize commit message, skipping + } + } MVOUT_INST_CAN_ISSUE.store(true, Ordering::Relaxed); self.state = TdmaStorerState::Idle; + *TDMA_STORER_STATE.lock().unwrap() = TdmaStorerState::Idle; self.until_next_event = INFINITY; }, } @@ -206,10 +227,11 @@ impl SerializableModel for TdmaStorer { /// --- Helper Functions --- /// ------------------------------------------------------------ fn decode_inst(xs1: u64, xs2: u64) -> (u64, u64, u64, u64) { - let base_dram_addr = (xs1 & 0xffffffff) as u64; - let stride = ((xs2 >> 24) & 0x3ff) as u64; - let depth = ((xs2 >> 8) & 0xffff) as u64; - let vbank_id = (xs2 & 0xff) as u64; + let base_dram_addr = xs1; // 使用完整的64位地址 + // 根据bb_mvin宏的定义解析参数:bank_id(5位) | depth(10位) | stride(19位) + let vbank_id = (xs2 & 0x1f) as u64; // 低5位 + let depth = ((xs2 >> 5) & 0x3ff) as u64; // 中间10位 + let stride = ((xs2 >> 15) & 0x7ffff) as u64; // 高19位 (base_dram_addr, stride, depth, vbank_id) } @@ -242,3 +264,7 @@ fn dma_write_dram(dram_addr: u64, data: u128) { let _ = h.write(dram_addr, data, 16); } } + +pub fn is_tdma_storer_idle() -> bool { + *TDMA_STORER_STATE.lock().unwrap() == TdmaStorerState::Idle +} diff --git a/bebop/src/arch/buckyball/vecball.rs b/bebop/src/arch/buckyball/vecball.rs index 99a8710..7b884a3 100644 --- a/bebop/src/arch/buckyball/vecball.rs +++ b/bebop/src/arch/buckyball/vecball.rs @@ -22,6 +22,8 @@ struct VecballInstData { static VECBALL_INST_DATA: Mutex> = Mutex::new(None); +static VECBALL_STATE: Mutex = Mutex::new(VecBallState::Idle); + // VectorBall states for matrix multiplication pipeline #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] enum VecBallState { @@ -118,6 +120,7 @@ impl DevsModel for VectorBall { // Now request operand 2 self.state = VecBallState::WaitOp2; + *VECBALL_STATE.lock().unwrap() = VecBallState::WaitOp2; self.until_next_event = 1.0; }, VecBallState::WaitOp2 => { @@ -132,6 +135,7 @@ impl DevsModel for VectorBall { // Start computing self.state = VecBallState::Computing; + *VECBALL_STATE.lock().unwrap() = VecBallState::Computing; self.until_next_event = self.compute_latency; }, _ => {}, @@ -160,6 +164,7 @@ impl DevsModel for VectorBall { // Start by requesting operand 1 (all 16 elements at once) self.state = VecBallState::WaitOp1; + *VECBALL_STATE.lock().unwrap() = VecBallState::WaitOp1; self.until_next_event = 1.0; self.records.push(ModelRecord { @@ -242,6 +247,7 @@ impl DevsModel for VectorBall { // Move to wait for write response self.state = VecBallState::WaitWriteResp; + *VECBALL_STATE.lock().unwrap() = VecBallState::WaitWriteResp; self.until_next_event = self.write_latency; }, VecBallState::WaitWriteResp => { @@ -267,6 +273,7 @@ impl DevsModel for VectorBall { }); self.state = VecBallState::Idle; + *VECBALL_STATE.lock().unwrap() = VecBallState::Idle; self.until_next_event = 1.0; VECBALL_INST_CAN_ISSUE.store(true, Ordering::Relaxed); } @@ -341,3 +348,7 @@ pub fn receive_vecball_inst(xs1: u64, xs2: u64, rob_id: u64) { // Mark as busy VECBALL_INST_CAN_ISSUE.store(false, Ordering::Relaxed); } + +pub fn is_vecball_idle() -> bool { + *VECBALL_STATE.lock().unwrap() == VecBallState::Idle +} diff --git a/host/gem5/install-gem5.sh b/host/gem5/install-gem5.sh index cd395b6..d775932 100755 --- a/host/gem5/install-gem5.sh +++ b/host/gem5/install-gem5.sh @@ -25,7 +25,7 @@ pip install scons cd ${GEM5_ROOT} # We dont need this step now # Apply the patch to gem5 -# git apply ${SCRIPT_DIR}/bebop.patch +git apply ${SCRIPT_DIR}/bebop.patch # We need to update the patch in this way if we make changes to gem5 # git add -A && git diff --cached > ../bebop.patch