operator-keyword #direction #chisel
#оператор-ключевое слово #направление #chisel
Вопрос:
В 2.6 chiseltest из учебных пособий chisel-bootcamp есть пример создания очереди с использованием Decoupled
интерфейса:
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)
действительно сбивает меня с толку, поскольку я проверяю <>
operator класса DecoupledIO
в chisel-api и получаю определение: «Соедините эти данные с этими данными двунаправленно и поэлементно». что означает out
, Queue(in, entries)
что возврат and должен быть двунаправленным. Тем не менее, я нашел 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)
}
}
которые возвращаются q.io.deq
TransitName
методом и 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.deq
, что он не перевернут DecoupledIO
и имеет то же направление интерфейса out
. Итак, я действительно хочу знать, как <>
это работает в out <> Queue(in, entries)
?
Ответ №1:
Decoupled(data)
добавьте протокол квитирования в пакет данных, указанный в параметрах. Если вы объявите этот сигнал, например :
val dec_data = IO(Decoupled(chiselTypeOf(data)))
dec_data
объект будет иметь 2 значения квитирования ( 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
к другому пакету DecoupledIO, вы не можете использовать :=
operator для всего пакета, потому что это однонаправленный operator .
Вы должны выполнять соединение по значению :
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
С помощью bulk connector <>
вы можете избежать этой болезненной связи с :
dec_data_sink <> dec_data
Chisel автоматически соединит правильные сигналы вместе.
Для получения дополнительной документации о соединениях bulks и несвязанном интерфейсе см. Документацию здесь .
Комментарии:
1. но я имею в виду, что я нашел
out <> Queue(in, entries)
в примере с очередьюQueue
‘return, которыйq.io.deq
имеет то же направление,out
но не похож на ваш пример,dec_data
иdec_data_sink
получил другое направление —dec_data
развязано иdec_data_sink
перевернуто развязано
Ответ №2:
Хорошо, я проверяю 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
Я обнаружил, что есть просто входы, соединяющие входы, и выходы, соединяющие выходы между Queue
и QueueModule
. Насколько я понимаю, существует создание экземпляра Queue
модуля в QueueModule
, so QueueModule
и Queue
сопоставление родительских / дочерних модулей, а <>
оператор массового подключения соединяет интерфейсы того же пола, что и документация
Итак, я понимаю, что я проигнорировал 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
родительским / дочерним модулям.