Reputation: 16117
I am playing with cliffordwolf/picorv32 and am having some problem understanding the following snippet in picosoc
(link to source):
SB_IO #(
.PIN_TYPE(6'b 1010_01),
.PULLUP(1'b 0)
) flash_io_buf [3:0] (
.PACKAGE_PIN({flash_io3, flash_io2, flash_io1, flash_io0}),
.OUTPUT_ENABLE({flash_io3_oe, flash_io2_oe, flash_io1_oe, flash_io0_oe}),
.D_OUT_0({flash_io3_do, flash_io2_do, flash_io1_do, flash_io0_do}),
.D_IN_0({flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di})
);
I have found a graphic description for the SB_IO
primitive in Lattice iCE40 technology library documentation, but I still cannot understand its purpose because it's too complex for me to interpret. There is another question about the primitive, after reading which I would assume it creates some kind of bidirectional connection, but I failed to understand how that is related to making the output pin "tristated".
I would appreciate a high-level description of the effect of the SB_IO
cell under this particular configuration. Which pin is connected to which pin? Which are inputs and which are outputs? What is the purpose of instantiating this cell?
Upvotes: 2
Views: 3925
Reputation: 469
This is my interpretation of the diagram in the documenatation (set means 1'b1
/ high / True):
SB_IO.PIN_TYPE[5:0]
config parameter by each bit index (left to right):
5: Set if OUTPUT_ENABLE
input signal used (use inout
for PACKAGE_PIN
)
4: depends on 5:
OUTPUT_ENABLE
is registered to posedge OUTPUT_CLK
, else the enable is direct (unregistered).PACKAGE_PIN
is output
else input
3: Whether D_OUT_0
is a direct(unregistered) output else it's registered DDR along with D_OUT_1
2: depends on 3:
D_OUT_0
/1 DDR clock phase on output latch:
D_OUT_O
register loads on posedge .OUTPUT_CLK
, but is output on negedge (during clock low), vice versa for D_OUT_1
. If clear, then D_OUT_O
is output during clock high, and D_OUT_1
is output during clock low.1: D_IN_0
input is latched with LATCH_INPUT_VALUE
signal
0: D_IN_0
input is direct else registered with .INPUT_CLK
,
with no effect if input latch enabled.
note D_IN_1
input is always registered to negedge INPUT_CLK
,
yet may be ignored for a posedge registered SDR input mode.
D_OUT_1
has no effect unless [3]==0, however,
there is no SDR registered output mode!
output reg
.also note D_OUT_1
is unable to be set on posedge clock,
meaning if you need to set it from posedge domain, then
all output may need to be one register later.
[3]
may help with this.6'b1010_01
is thus a direct (unregistered) inout
pin.
6'b0010_01
is a plain input pin
6'b0110_01
is a plain output pin
you rarely see those last two, because yosys will automatically infer them with sensible default settings, and can even infer the first, usually, so long as the assign packagepin = enablesig? outputsig : 1'bz;
line is in the top level module.
.PULLUP(1'b1)
is desired, this enables the weak-high pullup resistor on that pin.finally, PIN_TYPE
maps into configuration bits, you can't wire dynamic signals to them, you just choose them as constant to be set at compile-time.
This sort of 'direct use of a primitive' is pretty common for parts of FPGA's which can't easily be 'inferred' from the verilog design behaviour, and which usually vary between FPGA architectures (fpga 'families' if you like).
Yosys treats these like 'black boxes', but you can load a verilog definition so that you can simulate how they behave.
Trivia: the 'SB_' on the front almost certainly meant 'Silicon Blue', who originally designed the ice40 architecture, before being bought up and incorporated into Lattice. You can still find some ice40 chips with the SiliconBlue logo on them.
Upvotes: 1
Reputation: 604
I found the following comments for the module parameters, which might go some way to explaining how to use SB_IO
:
SB_IO #(
.PIN_TYPE (6'b 1010_01),
.PULLUP (HIGH)
) ram_d_io [15:0] ( // Name of the cell. Must be unique
.PACKAGE_PIN (ram_d_inout [15:0]), // Name of the module parameter
.OUTPUT_ENABLE (~data_bus_we), // Line that controls whether `ram_d_inout` is high-Z or driven
.D_OUT_0 (data_bus_w [15:0]), // Line that determines level when `ram_d_inout` is driven
.D_IN_0 (data_bus_r [15:0]) // Line that is driven by `ram_d_inout` when high-Z
);
Upvotes: 1
Reputation: 1186
This instance was used because at the time Yosys didn't support tristates in Verilog well enough, it does now but in general tristate support in FPGA toolchains isn't always trusted.
It could be replaced with the following generic Verilog, repeated 4 times from 0 to 4.
assign flash_io0 = flash_io0_oe ? flash_io0_do : 1'bz;
assign flash_io0_di = flash_io0;
Upvotes: 5