凿子中<>操作员的方向?



在2.6 chiseltest of chisel-bootcamp教程中,有一个关于使用Decoupled接口创建Queue的例子:

case class QueueModule[T <: Data](ioType: T, entries: Int) extends MultiIOModule {
val in = IO(Flipped(Decoupled(ioType)))
val out = IO(Decoupled(ioType))
out <> Queue(in, entries)
}

最后一行<>操作符的方向out <> Queue(in, entries)对我来说真的很困惑,因为我在chise_api中检查DecoupledIO类的<>操作符,并得到定义是"将此数据连接到该数据双向和element-wise !"这意味着outQueue(in, entries)的返回必须是双向的. 然而,我找到了Queue源代码:

object Queue
{
/** Create a queue and supply a DecoupledIO containing the product. */
@chiselName
def apply[T <: Data](
enq: ReadyValidIO[T],
entries: Int = 2,
pipe: Boolean = false,
flow: Boolean = false): DecoupledIO[T] = {
if (entries == 0) {
val deq = Wire(new DecoupledIO(chiselTypeOf(enq.bits)))
deq.valid := enq.valid
deq.bits := enq.bits
enq.ready := deq.ready
deq
} else {
val q = Module(new Queue(chiselTypeOf(enq.bits), entries, pipe, flow))
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
TransitName(q.io.deq, q)
}
}

通过TransitName方法返回q.io.deq,q.io.deq定义如下:

object DeqIO {
def apply[T<:Data](gen: T): DecoupledIO[T] = Flipped(Decoupled(gen))
}
/** 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](private val gen: T, val entries: Int) extends Bundle
{ // See github.com/freechipsproject/chisel3/issues/765 for why gen is a private val and proposed replacement APIs.
/* These may look inverted, because the names (enq/deq) are from the perspective of the client,
*  but internally, the queue implementation itself sits on the other side
*  of the interface so uses the flipped instance.
*/
/** I/O to enqueue data (client is producer, and Queue object is consumer), is [[Chisel.DecoupledIO]] flipped. */
val enq = Flipped(EnqIO(gen))
/** I/O to dequeue data (client is consumer and Queue object is producer), is [[Chisel.DecoupledIO]]*/
val deq = Flipped(DeqIO(gen))
/** The current amount of data in the queue */
val count = Output(UInt(log2Ceil(entries + 1).W))
}

表示q.io.deqNo-FlippedDecoupledIO有相同的接口方向out. 所以我真的想知道<>是如何在out <> Queue(in, entries)中工作的?

Decoupled(data)添加握手协议包中给出的数据参数。如果你声明这个信号,例如:

val dec_data = IO(Decoupled(chiselTypeOf(data)))

dec_data对象将有两个不同方向的握手值(ready,valid)和一个数据值。

myvalue := dec_data.bits
value_is_valid := dec_data.valid  //boolean value in the same direction as data
dec_data.ready := sink_ready_to_receive //boolean value in the oposite data direction

如果你想将dec_data连接到另一个解耦包,你不能在整个包上使用:=运算符,因为它是单向运算符。您必须逐个值地进行连接:

val dec_data_sink = IO(Flipped(Decoupled(chiselTypeOf(data))))
dec_data_sink.bits := dec_data.bits
dec_data_sink.valid := dec_data.valid
dec_data.ready := dec_data_sink.ready
使用批量连接器<>,您可以使用以下命令避免这种痛苦的连接:
dec_data_sink <> dec_data

Chisel将自动将正确的信号连接在一起。

有关批量连接和解耦接口的更多文档,请参阅此处的文档。

好的,我检查这个例子生成的Verilog:

module Queue(
input        clock,
input        reset,
output       io_enq_ready,
input        io_enq_valid,
input  [8:0] io_enq_bits,
input        io_deq_ready,
output       io_deq_valid,
output [8:0] io_deq_bits
);
......
......
module QueueModule(
input        clock,
input        reset,
output       in_ready,
input        in_valid,
input  [8:0] in_bits,
input        out_ready,
output       out_valid,
output [8:0] out_bits
);
wire  q_clock; // @[Decoupled.scala 296:21]
wire  q_reset; // @[Decoupled.scala 296:21]
wire  q_io_enq_ready; // @[Decoupled.scala 296:21]
wire  q_io_enq_valid; // @[Decoupled.scala 296:21]
wire [8:0] q_io_enq_bits; // @[Decoupled.scala 296:21]
wire  q_io_deq_ready; // @[Decoupled.scala 296:21]
wire  q_io_deq_valid; // @[Decoupled.scala 296:21]
wire [8:0] q_io_deq_bits; // @[Decoupled.scala 296:21]
Queue q ( // @[Decoupled.scala 296:21]
.clock(q_clock),
.reset(q_reset),
.io_enq_ready(q_io_enq_ready),
.io_enq_valid(q_io_enq_valid),
.io_enq_bits(q_io_enq_bits),
.io_deq_ready(q_io_deq_ready),
.io_deq_valid(q_io_deq_valid),
.io_deq_bits(q_io_deq_bits)
);
assign in_ready = q_io_enq_ready; // @[Decoupled.scala 299:17]
assign out_valid = q_io_deq_valid; // @[cmd2.sc 4:7]
assign out_bits = q_io_deq_bits; // @[cmd2.sc 4:7]
assign q_clock = clock;
assign q_reset = reset;
assign q_io_enq_valid = in_valid; // @[Decoupled.scala 297:22]
assign q_io_enq_bits = in_bits; // @[Decoupled.scala 298:21]
assign q_io_deq_ready = out_ready; // @[cmd2.sc 4:7]
endmodule

我发现QueueQueueModule之间存在简单的输入连接输入和输出连接输出。据我所知,有一个在QueueModuleQueue模块的实例化,所以QueueModuleQueue匹配父/子模块和<>bulk-connect运算符连接的接口相同的性别文档
所以我明白,我忽略了Queue本身也是一个模块的格式示例:

case class QueueModule[T <: Data](ioType: T, entries: Int) extends MultiIOModule {
val in = IO(Flipped(Decoupled(ioType)))
val out = IO(Decoupled(ioType))
out <> Queue(in, entries)
}

QueueModule/Queue匹配到父/子模块。

最新更新