diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 955d22e6a..505c4716a 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -37,6 +37,7 @@ Aylon Chaim Porat Bartłomiej Chmiel Benjamin Collier Brian Li +Bryan Murdock Cameron Kirk Cameron Waite Chih-Mao Chen diff --git a/include/verilated_types.h b/include/verilated_types.h index a48b99c4c..f6040d611 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -741,8 +741,14 @@ public: // Return slice q[lsb:msb] VlQueue slice(int32_t lsb, int32_t msb) const { VlQueue out; + if (VL_UNLIKELY(lsb > msb)) return out; + if (VL_UNLIKELY(lsb == msb)) { + if (lsb >= 0 && lsb < m_deque.size()) { + out.push_back(m_deque[lsb]); + } + return out; + } if (VL_UNLIKELY(lsb < 0)) lsb = 0; - if (VL_UNLIKELY(lsb >= m_deque.size())) lsb = m_deque.size() - 1; if (VL_UNLIKELY(msb >= m_deque.size())) msb = m_deque.size() - 1; for (int32_t i = lsb; i <= msb; ++i) out.push_back(m_deque[i]); return out; diff --git a/test_regress/t/t_queue_slice.v b/test_regress/t/t_queue_slice.v index cae6faf09..810247518 100644 --- a/test_regress/t/t_queue_slice.v +++ b/test_regress/t/t_queue_slice.v @@ -56,18 +56,100 @@ module t; `checks(v, "ins2"); `checkp(q, "'{\"ins0\", \"q\", \"ins2\", \"c\", \"d\", \"e\", \"f\"}"); - // Slicing - q = '{"q", "b", "c", "d", "e", "f"}; - q = q[-1:0]; - `checkp(q, "'{\"q\"}"); + // Slicing. + + // The simple cases: q = '{"q", "b", "c", "d", "e", "f"}; q = q[2:3]; `checkp(q, "'{\"c\", \"d\"}"); q = '{"q", "b", "c", "d", "e", "f"}; q = q[3:$]; `checkp(q, "'{\"d\", \"e\", \"f\"}"); + + // These are all the special cases straight from the LRM. We + // repeat tests for queues with size 1 specially because they are + // tricky. + + // If a > b, then Q[a:b] yields the empty queue {}. + q = '{"q", "b", "c", "d", "e", "f"}; + q = q[4:0]; + `checkp(q, "'{}"); + // FIX! + q = '{"q", "b", "c", "d", "e", "f"}; + q = q[$:0]; + `checkp(q, "'{}"); + q = '{"q"}; + q = q[1:0]; + `checkp(q, "'{}"); + // Or another way of writing the above (this case is specifically + // described under section 7.10.4, Updating a queue using + // assignment) + q = '{"q"}; + q = q[1:$]; + `checkp(q, "'{}"); + + + // Q[ n : n ] yields a queue with one item, the one at position n + q = '{"q", "b", "c", "d", "e", "f"}; + q = q[1:1]; + `checkp(q, "'{\"b\"}"); + q = '{"q", "b", "c", "d", "e", "f"}; q = q[$:$]; `checkp(q, "'{\"f\"}"); + q = '{"q"}; + q = q[0:0]; + `checkp(q, "'{\"q\"}"); + // FIX! + q = '{"q"}; + q = q[0:$]; + `checkp(q, "'{\"q\"}"); + // FIX! + q = '{"q"}; + q = q[$:$]; + `checkp(q, "'{\"q\"}"); + + // If n lies outside Q's range (n < 0 or n > $), then Q[n:n] + // yields the empty queue {} + q = '{"q", "b", "c", "d", "e", "f"}; + q = q[7:7]; + `checkp(q, "'{}"); + q = '{"q"}; + q = q[7:7]; + `checkp(q, "'{}"); + + // Skipping until verilator gets X/Z support: If either a or b are + // 4-state expressions containing X or Z values, it yields the + // empty queue {} + + // Q[ a : b ] where a < 0 is the same as Q[ 0 : b ] + q = '{"q", "b", "c", "d", "e", "f"}; + q = q[-1:0]; + `checkp(q, "'{\"q\"}"); + q = '{"q"}; + q = q[-1:0]; + `checkp(q, "'{\"q\"}"); + + // Q[ a : b ] where b > $ is the same as Q[ a : $ ] + q = '{"q", "b", "c", "d", "e", "f"}; + q = q[3:7]; + `checkp(q, "'{\"d\", \"e\", \"f\"}"); + q = '{"q"}; + q = q[0:3]; + `checkp(q, "'{\"q\"}"); + + // There isn't actually a clear statement in the LRM for when a > + // $ and b > $, but in the same section as all the above rules it + // says, "An invalid index value (i.e., a 4-state expression whose + // value has one or more x or z bits, or a value that lies outside + // 0...$) shall cause a read operation to return the value + // appropriate for a nonexistent array entry of the queue’s + // element type (as described in Table 7-1 in 7.4.6)" + q = '{"q", "b", "c", "d", "e", "f"}; + q = q[6:8]; + `checkp(q, "'{}"); + q = '{"q"}; + q = q[6:8]; + `checkp(q, "'{}"); // Similar using implied notation q = '{"f"};