diff --git a/crates/cpu/src/next_pc.rs b/crates/cpu/src/next_pc.rs index 3ac1cf0..7be530b 100644 --- a/crates/cpu/src/next_pc.rs +++ b/crates/cpu/src/next_pc.rs @@ -2899,11 +2899,11 @@ impl ResetSteps for BranchTargetBuffer { struct Queue { data: ArrayType, /// inclusive - head: UIntInRangeType, Capacity>, + start: UIntInRangeType, Capacity>, /// exclusive - tail: UIntInRangeType, Capacity>, + end: UIntInRangeType, Capacity>, /// used to disambiguate between a full and an empty queue - eq_head_tail_means_full: Bool, + eq_start_end_means_full: Bool, } impl Queue { @@ -2923,37 +2923,36 @@ impl Queue { (pos + self.capacity() - 1) % self.capacity() } fn is_empty(this: &SimValue) -> bool { - this.head == this.tail && !*this.eq_head_tail_means_full + this.start == this.end && !*this.eq_start_end_means_full } fn is_full(this: &SimValue) -> bool { - this.head == this.tail && *this.eq_head_tail_means_full + this.start == this.end && *this.eq_start_end_means_full } fn len(this: &SimValue) -> usize { let capacity = this.ty().capacity(); if Self::is_full(this) { capacity } else { - (*this.tail + capacity - *this.head) % capacity + (*this.end + capacity - *this.start) % capacity } } fn space_left(this: &SimValue) -> usize { this.ty().capacity() - Self::len(this) } fn clear(this: &mut SimValue) { - *this.head = 0; - *this.tail = 0; - *this.eq_head_tail_means_full = false; + *this.start = 0; + *this.end = 0; + *this.eq_start_end_means_full = false; } fn try_push(this: &mut SimValue, value: impl ToSimValueWithType) -> Result<(), ()> { if Self::is_full(this) { Err(()) } else { - let head = *this.head; - let head = this.ty().next_pos(head); - *this.head = head; - *this.eq_head_tail_means_full = true; - let data = &mut this.data[head]; - *data = value.to_sim_value_with_type(data.ty()); + let end = *this.end; + *this.end = this.ty().next_pos(end); + *this.eq_start_end_means_full = true; + let data = &mut this.data[end]; + *data = dbg!(value.to_sim_value_with_type(data.ty())); Ok(()) } } @@ -2961,11 +2960,10 @@ impl Queue { if Self::is_empty(this) { None } else { - let head = *this.head; - let data = this.data[head].clone(); - let head = this.ty().prev_pos(head); - *this.head = head; - *this.eq_head_tail_means_full = false; + let end = this.ty().prev_pos(*this.end); + *this.end = end; + let data = this.data[end].clone(); + *this.eq_start_end_means_full = false; Some(data) } } @@ -2973,22 +2971,23 @@ impl Queue { if Self::is_empty(this) { None } else { - Some(this.data[*this.tail].clone()) + Some(this.data[*this.start].clone()) } } fn peek_iter( this: &SimValue, ) -> impl Clone + DoubleEndedIterator> + ExactSizeIterator { - (0..Self::len(this)).map(|nth| this.data[this.ty().nth_pos_after(*this.tail, nth)].clone()) + (0..Self::len(this)) + .map(|nth| dbg!(this.data[this.ty().nth_pos_after(*this.start, nth)].clone())) } fn pop(this: &mut SimValue) -> Option> { if Self::is_empty(this) { None } else { - let tail = *this.tail; - let data = this.data[tail].clone(); - *this.tail = this.ty().next_pos(tail); - *this.eq_head_tail_means_full = false; + let start = *this.start; + *this.start = this.ty().next_pos(start); + let data = this.data[start].clone(); + *this.eq_start_end_means_full = false; Some(data) } } @@ -2999,9 +2998,9 @@ impl SimValueDefault for Queue fn sim_value_default(self) -> SimValue { let Self { data, - head, - tail, - eq_head_tail_means_full: _, + start, + end, + eq_start_end_means_full: _, } = self; #[hdl(sim)] Queue:: { @@ -3009,9 +3008,9 @@ impl SimValueDefault for Queue data.element().sim_value_default(), Capacity::from_usize(data.len()), ), - head: 0usize.to_sim_value_with_type(head), - tail: 0usize.to_sim_value_with_type(tail), - eq_head_tail_means_full: false, + start: 0usize.to_sim_value_with_type(start), + end: 0usize.to_sim_value_with_type(end), + eq_start_end_means_full: false, } } } @@ -3022,13 +3021,13 @@ impl ResetSteps for Queue { #[hdl(sim)] let Queue:: { data, - head, - tail, - eq_head_tail_means_full, + start, + end, + eq_start_end_means_full, } = this; - **head = 0; - **tail = 0; - **eq_head_tail_means_full = false; + **start = 0; + **end = 0; + **eq_start_end_means_full = false; ResetSteps::reset_step(data, step) } } @@ -4141,3 +4140,52 @@ pub fn next_pc(config: PhantomConst) { }, ); } + +#[cfg(test)] +mod tests { + use super::*; + use std::collections::VecDeque; + + #[test] + fn test_queue() { + let mut queue: SimValue, ConstUsize<8>>> = Queue::TYPE.sim_value_default(); + let mut reference_queue = VecDeque::new(); + let mut tested_full = false; + let mut tested_empty = false; + for i in 0..0x1000u32 { + let expected_full = reference_queue.len() >= queue.ty().capacity(); + let full = Queue::is_full(&queue); + assert_eq!(expected_full, full, "{queue:?}"); + let expected_empty = reference_queue.is_empty(); + let empty = Queue::is_empty(&queue); + assert_eq!(expected_empty, empty, "{queue:?}"); + tested_full |= full; + if tested_full { + tested_empty |= empty; + } + let rand = i + .wrapping_mul(0xED5E3831) // a random prime + .rotate_left(16) + .wrapping_mul(0x2287F1BD) // a random prime + .rotate_left(16); + if ((rand >> 8) & 1) == 0 { + let popped = Queue::pop(&mut queue).map(|v| v.as_int()); + let expected_popped = reference_queue.pop_front(); + dbg!(expected_popped); + assert_eq!(popped, expected_popped); + } else if !full { + let push_value = rand as u8; + dbg!(push_value); + Queue::try_push(&mut queue, push_value).expect("known to be not full"); + reference_queue.push_back(push_value); + } + dbg!(&queue); + dbg!(&reference_queue); + let queue_contents = Vec::from_iter(Queue::peek_iter(&queue).map(|v| v.as_int())); + let reference_queue_contents = Vec::from_iter(reference_queue.iter().copied()); + assert_eq!(queue_contents, reference_queue_contents); + } + assert!(tested_full); + assert!(tested_empty); + } +}