1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
// See LICENSE for license details.
/** Wrappers for ready-valid (Decoupled) interfaces and associated circuit generators using them.
*/
package Chisel
/** An I/O Bundle with simple handshaking using valid and ready signals for data 'bits'*/
class DecoupledIO[+T <: Data](gen: T) extends Bundle
{
val ready = Bool(INPUT)
val valid = Bool(OUTPUT)
val bits = gen.cloneType.asOutput
def fire(dummy: Int = 0): Bool = ready && valid
override def cloneType: this.type = new DecoupledIO(gen).asInstanceOf[this.type]
}
/** Adds a ready-valid handshaking protocol to any interface.
* The standard used is that the consumer uses the flipped interface.
*/
object Decoupled {
def apply[T <: Data](gen: T): DecoupledIO[T] = new DecoupledIO(gen)
}
/** An I/O bundle for enqueuing data with valid/ready handshaking */
class EnqIO[T <: Data](gen: T) extends DecoupledIO(gen)
{
def enq(dat: T): T = { valid := Bool(true); bits := dat; dat }
valid := Bool(false)
for (io <- bits.flatten)
io := UInt(0)
override def cloneType: this.type = { new EnqIO(gen).asInstanceOf[this.type]; }
}
/** An I/O bundle for dequeuing data with valid/ready handshaking */
class DeqIO[T <: Data](gen: T) extends DecoupledIO(gen)
{
flip()
ready := Bool(false)
def deq(b: Boolean = false): T = { ready := Bool(true); bits }
override def cloneType: this.type = { new DeqIO(gen).asInstanceOf[this.type]; }
}
/** An I/O bundle for dequeuing data with valid/ready handshaking */
class DecoupledIOC[+T <: Data](gen: T) extends Bundle
{
val ready = Bool(INPUT)
val valid = Bool(OUTPUT)
val bits = gen.cloneType.asOutput
}
/** An I/O Bundle for Queues
* @param gen The type of data to queue
* @param entries The max number of entries in the queue */
class QueueIO[T <: Data](gen: T, entries: Int) extends Bundle
{
/** I/O to enqueue data, is [[Chisel.DecoupledIO]] flipped */
val enq = Decoupled(gen.cloneType).flip
/** I/O to enqueue data, is [[Chisel.DecoupledIO]]*/
val deq = Decoupled(gen.cloneType)
/** The current amount of data in the queue */
val count = UInt(OUTPUT, log2Up(entries + 1))
}
/** A hardware module implementing a Queue
* @param gen The type of data to queue
* @param entries The max number of entries in the queue
* @param pipe True if a single entry queue can run at full throughput (like a pipeline). The ''ready'' signals are
* combinationally coupled.
* @param flow True if the inputs can be consumed on the same cycle (the inputs "flow" through the queue immediately).
* The ''valid'' signals are coupled.
*
* Example usage:
* {{{ val q = new Queue(UInt(), 16)
* q.io.enq <> producer.io.out
* consumer.io.in <> q.io.deq }}}
*/
class Queue[T <: Data](gen: T, val entries: Int,
pipe: Boolean = false,
flow: Boolean = false,
_reset: Bool = null) extends Module(_reset=_reset)
{
val io = new QueueIO(gen, entries)
val ram = Mem(gen, entries)
val enq_ptr = Counter(entries)
val deq_ptr = Counter(entries)
val maybe_full = Reg(init=Bool(false))
val ptr_match = enq_ptr.value === deq_ptr.value
val empty = ptr_match && !maybe_full
val full = ptr_match && maybe_full
val maybe_flow = Bool(flow) && empty
val do_flow = maybe_flow && io.deq.ready
val do_enq = io.enq.ready && io.enq.valid && !do_flow
val do_deq = io.deq.ready && io.deq.valid && !do_flow
when (do_enq) {
ram(enq_ptr.value) := io.enq.bits
enq_ptr.inc()
}
when (do_deq) {
deq_ptr.inc()
}
when (do_enq != do_deq) {
maybe_full := do_enq
}
io.deq.valid := !empty || Bool(flow) && io.enq.valid
io.enq.ready := !full || Bool(pipe) && io.deq.ready
io.deq.bits := Mux(maybe_flow, io.enq.bits, ram(deq_ptr.value))
val ptr_diff = enq_ptr.value - deq_ptr.value
if (isPow2(entries)) {
io.count := Cat(maybe_full && ptr_match, ptr_diff)
} else {
io.count := Mux(ptr_match,
Mux(maybe_full,
UInt(entries), UInt(0)),
Mux(deq_ptr.value > enq_ptr.value,
UInt(entries) + ptr_diff, ptr_diff))
}
}
/** Generic hardware queue. Required parameter entries controls
the depth of the queues. The width of the queue is determined
from the inputs.
Example usage:
{{{ val q = Queue(Decoupled(UInt()), 16)
q.io.enq <> producer.io.out
consumer.io.in <> q.io.deq }}}
*/
object Queue
{
def apply[T <: Data](enq: DecoupledIO[T], entries: Int = 2, pipe: Boolean = false): DecoupledIO[T] = {
val q = Module(new Queue(enq.bits.cloneType, entries, pipe))
q.io.enq.valid := enq.valid // not using <> so that override is allowed
q.io.enq.bits := enq.bits
enq.ready := q.io.enq.ready
q.io.deq
}
}
|