I'm generating Verilog from Chisel 3 source code and mapping the Verilog's top module ports to FPGA pins by using an UCF file.
I have a set of inout pins in my design (SDRAM data pins), which on the Chisel side have to be expressed as separate input and output ports. The problem is, I can't (AFAIK) then map the Verilog input ports and output ports to the same FPGA pin (if I were directly writing Verilog those would be a single inout signal, so that wouldn't be an issue) and I don't know of anyway to coerce Chisel 3 to produce a single Verilog inout port from two input/output Chisel ports.
How is this usually solved in Chisel (3)?
We are working on some level of support for Verilog inout in Chisel 3, but until that API is fully fleshed out you should write a Verilog wrapper that converts from from inout to an input, output, and some direction.
For example, say I have some Verilog with an inout pin that can be used to set or read from some register:
module Inout(
input clock,
input write,
inout [31:0] data
);
reg [31:0] value;
assign data = (write) ? 32'dz : value;
always @(posedge clock) begin
if (write)
value <= data;
else
value <= value;
end
endmodule
With a simple wrapper, I can expose a different interface that does not use inout:
module InoutWrapper(
input clock,
input write,
input [31:0] dataIn,
output [31:0] dataOut
);
wire [31:0] bus;
assign bus = (write)? dataIn : 32'dz;
assign dataOut = bus;
Inout mod (
.clock(clock),
.write(write),
.data(bus)
);
endmodule
This wrapper interface can be used in a Chisel design as a BlackBox:
class InoutWrapper extends BlackBox {
val io = IO(new Bundle {
val clock = Input(Clock())
val write = Input(Bool())
val dataIn = Input(UInt(32.W))
val dataOut = Output(UInt(32.W))
})
}
And here's a bonus simple sanity test to show that it works:
class InoutTester extends BasicTester {
val mod = Module(new InoutWrapper)
val (cycle, done) = Counter(true.B, 4)
when (done) { stop(); stop() }
mod.io.clock := this.clock // BlackBoxes require explicit clock assignment
mod.io.write := false.B // default assignments
mod.io.dataIn := "hdeadbeef".U
when (cycle === 1.U) {
mod.io.write := true.B
mod.io.dataIn := 123.U
}
when (cycle === 2.U) {
assert(mod.io.dataOut === 123.U)
}
}
If the inout port is at the top of the design, you can create a similar kind of wrapper for the top of your design.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With