fix next_pc::Queue and add test
This commit is contained in:
parent
cbd52c60a8
commit
f39f40ce1f
1 changed files with 86 additions and 38 deletions
|
|
@ -2899,11 +2899,11 @@ impl ResetSteps for BranchTargetBuffer {
|
||||||
struct Queue<T, Capacity: Size> {
|
struct Queue<T, Capacity: Size> {
|
||||||
data: ArrayType<T, Capacity>,
|
data: ArrayType<T, Capacity>,
|
||||||
/// inclusive
|
/// inclusive
|
||||||
head: UIntInRangeType<ConstUsize<0>, Capacity>,
|
start: UIntInRangeType<ConstUsize<0>, Capacity>,
|
||||||
/// exclusive
|
/// exclusive
|
||||||
tail: UIntInRangeType<ConstUsize<0>, Capacity>,
|
end: UIntInRangeType<ConstUsize<0>, Capacity>,
|
||||||
/// used to disambiguate between a full and an empty queue
|
/// used to disambiguate between a full and an empty queue
|
||||||
eq_head_tail_means_full: Bool,
|
eq_start_end_means_full: Bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Type, Capacity: Size> Queue<T, Capacity> {
|
impl<T: Type, Capacity: Size> Queue<T, Capacity> {
|
||||||
|
|
@ -2923,37 +2923,36 @@ impl<T: Type, Capacity: Size> Queue<T, Capacity> {
|
||||||
(pos + self.capacity() - 1) % self.capacity()
|
(pos + self.capacity() - 1) % self.capacity()
|
||||||
}
|
}
|
||||||
fn is_empty(this: &SimValue<Self>) -> bool {
|
fn is_empty(this: &SimValue<Self>) -> 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<Self>) -> bool {
|
fn is_full(this: &SimValue<Self>) -> 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<Self>) -> usize {
|
fn len(this: &SimValue<Self>) -> usize {
|
||||||
let capacity = this.ty().capacity();
|
let capacity = this.ty().capacity();
|
||||||
if Self::is_full(this) {
|
if Self::is_full(this) {
|
||||||
capacity
|
capacity
|
||||||
} else {
|
} else {
|
||||||
(*this.tail + capacity - *this.head) % capacity
|
(*this.end + capacity - *this.start) % capacity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn space_left(this: &SimValue<Self>) -> usize {
|
fn space_left(this: &SimValue<Self>) -> usize {
|
||||||
this.ty().capacity() - Self::len(this)
|
this.ty().capacity() - Self::len(this)
|
||||||
}
|
}
|
||||||
fn clear(this: &mut SimValue<Self>) {
|
fn clear(this: &mut SimValue<Self>) {
|
||||||
*this.head = 0;
|
*this.start = 0;
|
||||||
*this.tail = 0;
|
*this.end = 0;
|
||||||
*this.eq_head_tail_means_full = false;
|
*this.eq_start_end_means_full = false;
|
||||||
}
|
}
|
||||||
fn try_push(this: &mut SimValue<Self>, value: impl ToSimValueWithType<T>) -> Result<(), ()> {
|
fn try_push(this: &mut SimValue<Self>, value: impl ToSimValueWithType<T>) -> Result<(), ()> {
|
||||||
if Self::is_full(this) {
|
if Self::is_full(this) {
|
||||||
Err(())
|
Err(())
|
||||||
} else {
|
} else {
|
||||||
let head = *this.head;
|
let end = *this.end;
|
||||||
let head = this.ty().next_pos(head);
|
*this.end = this.ty().next_pos(end);
|
||||||
*this.head = head;
|
*this.eq_start_end_means_full = true;
|
||||||
*this.eq_head_tail_means_full = true;
|
let data = &mut this.data[end];
|
||||||
let data = &mut this.data[head];
|
*data = dbg!(value.to_sim_value_with_type(data.ty()));
|
||||||
*data = value.to_sim_value_with_type(data.ty());
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2961,11 +2960,10 @@ impl<T: Type, Capacity: Size> Queue<T, Capacity> {
|
||||||
if Self::is_empty(this) {
|
if Self::is_empty(this) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let head = *this.head;
|
let end = this.ty().prev_pos(*this.end);
|
||||||
let data = this.data[head].clone();
|
*this.end = end;
|
||||||
let head = this.ty().prev_pos(head);
|
let data = this.data[end].clone();
|
||||||
*this.head = head;
|
*this.eq_start_end_means_full = false;
|
||||||
*this.eq_head_tail_means_full = false;
|
|
||||||
Some(data)
|
Some(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2973,22 +2971,23 @@ impl<T: Type, Capacity: Size> Queue<T, Capacity> {
|
||||||
if Self::is_empty(this) {
|
if Self::is_empty(this) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(this.data[*this.tail].clone())
|
Some(this.data[*this.start].clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn peek_iter(
|
fn peek_iter(
|
||||||
this: &SimValue<Self>,
|
this: &SimValue<Self>,
|
||||||
) -> impl Clone + DoubleEndedIterator<Item = SimValue<T>> + ExactSizeIterator {
|
) -> impl Clone + DoubleEndedIterator<Item = SimValue<T>> + 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<Self>) -> Option<SimValue<T>> {
|
fn pop(this: &mut SimValue<Self>) -> Option<SimValue<T>> {
|
||||||
if Self::is_empty(this) {
|
if Self::is_empty(this) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let tail = *this.tail;
|
let start = *this.start;
|
||||||
let data = this.data[tail].clone();
|
*this.start = this.ty().next_pos(start);
|
||||||
*this.tail = this.ty().next_pos(tail);
|
let data = this.data[start].clone();
|
||||||
*this.eq_head_tail_means_full = false;
|
*this.eq_start_end_means_full = false;
|
||||||
Some(data)
|
Some(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2999,9 +2998,9 @@ impl<T: SimValueDefault, Capacity: Size> SimValueDefault for Queue<T, Capacity>
|
||||||
fn sim_value_default(self) -> SimValue<Self> {
|
fn sim_value_default(self) -> SimValue<Self> {
|
||||||
let Self {
|
let Self {
|
||||||
data,
|
data,
|
||||||
head,
|
start,
|
||||||
tail,
|
end,
|
||||||
eq_head_tail_means_full: _,
|
eq_start_end_means_full: _,
|
||||||
} = self;
|
} = self;
|
||||||
#[hdl(sim)]
|
#[hdl(sim)]
|
||||||
Queue::<T, Capacity> {
|
Queue::<T, Capacity> {
|
||||||
|
|
@ -3009,9 +3008,9 @@ impl<T: SimValueDefault, Capacity: Size> SimValueDefault for Queue<T, Capacity>
|
||||||
data.element().sim_value_default(),
|
data.element().sim_value_default(),
|
||||||
Capacity::from_usize(data.len()),
|
Capacity::from_usize(data.len()),
|
||||||
),
|
),
|
||||||
head: 0usize.to_sim_value_with_type(head),
|
start: 0usize.to_sim_value_with_type(start),
|
||||||
tail: 0usize.to_sim_value_with_type(tail),
|
end: 0usize.to_sim_value_with_type(end),
|
||||||
eq_head_tail_means_full: false,
|
eq_start_end_means_full: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3022,13 +3021,13 @@ impl<T: SimValueDefault, Capacity: Size> ResetSteps for Queue<T, Capacity> {
|
||||||
#[hdl(sim)]
|
#[hdl(sim)]
|
||||||
let Queue::<T, Capacity> {
|
let Queue::<T, Capacity> {
|
||||||
data,
|
data,
|
||||||
head,
|
start,
|
||||||
tail,
|
end,
|
||||||
eq_head_tail_means_full,
|
eq_start_end_means_full,
|
||||||
} = this;
|
} = this;
|
||||||
**head = 0;
|
**start = 0;
|
||||||
**tail = 0;
|
**end = 0;
|
||||||
**eq_head_tail_means_full = false;
|
**eq_start_end_means_full = false;
|
||||||
ResetSteps::reset_step(data, step)
|
ResetSteps::reset_step(data, step)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4141,3 +4140,52 @@ pub fn next_pc(config: PhantomConst<CpuConfig>) {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_queue() {
|
||||||
|
let mut queue: SimValue<Queue<UInt<8>, 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue