Synthesisable TristateSignal

Hi,

Can somebody explain how to use TristateSignal’s and create verilog that can be synthesised?

If I understand the documentation correctly, this needs to be done like this:
(BUS is the “bus”, io1 and io2 are two signals driving the bus).

(in main)

BUS = TristateSignal(intbv(0)[1:])

toVerilog(top, clk, systemreset, BUS)

(in top)

io1 = BUS.driver()
io2 = BUS.driver()

io1.next = 0
io2.next = None

However, looking at the generated verilog code, I have this:

module top (
clk,
systemreset,
BUS
);

(…)

output [0:0] BUS;
wire [0:0] BUS;
reg [0:0] io2;
reg [0:0] io1;

(…)

assign BUS = io1;
assign BUS = io2;

And this does not synthesise "(“net has multiple drivers”) according arachne-pnr.

So how do you write this myhdl code that is does synthethise.

As far as I understand this, a “TriStateSignal” is in essence a combinatory logic-block that produces the correct output, based on the input of the “driver” modules.
So am I correct to assume that, when you convert this into verilog, you still need to implement that block yourself in verilog ?
Or am I missing something here?

F.Y.I.
The actual use of this code is to learn how to access the SRAM module on an olimex ice40HX8K-EVK board where two modules (the top block to program the SRAM and a “vga” block that reads the SRAM) need to access the databus and addressbus of the memory.

Kristoff

Maybe this: https://gist.github.com/josyb/c816d585e12ae397627b will help?

Regards,

Josy

Josy,

Thanks for helping out.

The example you mention only has one single driver. My module has a tristatebuffer (in the actual module I want to implement, an addressbus of a SRAM module) that has two drivers.

If you read Tristate and bidirectional signals, ot mentions this:

User interface
class TristateSignal(val, [delay=0])

(…)
The current value of a tristate is determined by resolving the values from its drivers. When exactly one driver value is different from None, that is the resolved value; otherwise it is None. When more than one driver value is different from None, a contention warning is issued.

As mentioned, the verilog convertor just translates this to two "reg"s that are assigned to a one wire (the bus). When you simulate this using a verilog simulator, this does indeed behave as mentioned, … but the synthesiser has a different idea about it.
(or is this arachne-pnr that does work correctly?)

Kristoff

Kristoff,

It is difficult to guess your intentions from the few snippets you provide.
Now I must humbly confess that I never use MyHDL tristates; I use the Vendor’s primitives or a VHDL construct in the top level VHDL file. A bit of old school/class …
I don’t do Verilog (probably never will), so I can’t say anything meaningful about synthesising it. I think I would agree with the synthesiser complaining about BUS being assigned twice, though.
I don’t understand why you need tristates to access external memory, either. Maybe I’ll understand when reading the complete MyHDL code of your program.

Regards,
Josy

Hi Josy,

From what I understand TriStateSignals, there are two usecases for these structures:

  • “inout”: read and write data from/to a bidirectional pin (like in the example you provided)
  • to drive a pin from two (or more) inputs.

I agree, for the 2nd use, if you just need to select one of two input-signals to drive one output, you usually use a 2-1 mux. But -looking the description of the TriStateSignal on the myhdl website- it did look like you could mimic this behaviour with a TriStateSignal. (and one less pin)

The documentation of the TriStateSignal describes the truthtable as follows:

IN1 IN2 OUT
Z 0 0
Z 1 1
0 Z 0
1 Z 1

So by setting either one or the other IN signal (buffer signals) to None (“Z”), you should be able to mimic the behaviour of a mux, … with one less pin.

The thing is, if you simulate this (using myhdl itself or iverilog), this works as expected. But -as said earlier- the synthetiser seams to have a different view on this. :frowning:

So my question: am I using these TriStateSignals wrongly or is the synthetiser to blame?

BTW. I use verilog as this runs on a ice40-board for which I can use “project icestorm” tools (an open-source FPGA-flow for lattice ice40 FPGAs).

Kristoff

Kristoff,

Simulation and Synthesis don’t have to agree, i.o.w. what you can synthesise will simulate but what you can simulate doesn’t necessarily synthesise.

IMO in FPGA there is only the inout case, if you want two or more submodules to drive a single pin use a mux, or gate the signals and then drive the single case tristate.

You may however have a valid case, but without a full / concise example which also fails to synthesise with other tools than arachne-pnr we can’t really tell.

Regards,
Josy

Kristoff,

I browsed around (google: VHDL resolved unresolved) and perused the IEEE Std 1364™-2005 specification to find out what I was missing …
What you are trying to do: driving the same net (wire) from multiple sources, is only used in modelling and thus will simulate, but not synthesise.

Regards,
Josy

Josy,

First of all, I am sorry for the late reply. (you know, summer :slight_smile: ).

I understand that it is possible to create myhdl code that cannot be synthesised, but in the end, something needs to be created that will work in real life.

There are structures where it is necessairy to drive a tristate signal from multiple sources, like an internal bus of a processor.
I have been trying to small simulation of a computerbus in myhdl, hget it converted to verilog and get it to synthesise, but sofar without success. Perhaps I need to write the myhdl in a certain way so it is converted to a form of verilog that is converted to the correct hardware.

But as I am not 100 % sure how this should be done in verilog, I will post the code I have later on. (I always like to do my research myself before asking questions in forums :slight_smile: ).

But already thank you very much for the help you have provided.

Cheerio! Kr. Bonne.

Kristoff,

There are no tristate signals inside an FPGA. As such no Vendor tool can synthesise them.

Regards,

Josy

Josy,

OK, but then how do you implement a bus in a softcore processor? (which
is one of the core elements of a processor, no?)

Kristoff

Kristoff,

using lots of muxes :slight_smile: And often lots of pipeline registers too :slight_smile:

Regards,

Josy

Hi Josy,

F.Y.I.

I experimented a little bit with a small design that has an internal bus to interconnect three nodes, and I got these remarks while synthesing the design (see below).

It looks like an internal tristate bus is actually converted to or-ports.


Xilinx ISE:

WARNING:Xst:2042 - Unit busunit: 8 internal tristates are replaced by logic (pull-up yes): bus<0>, bus<1>, bus<2>, bus<3>, bus<4>, bus<5>, bus<6>, bus<7>.

Altera quartus:

Warning (13046): Tri-state node(s) do not directly drive top-level pin(s)
Warning (13047): Converted the fan-out from the tri-state buffer “busunitlong:unit1|bus[0]” to the node “busunitlong:unit1|Selector9” into an OR gate File: /data/fpga_lokaal/altera/projects/busring/busunitlong.v Line: 6
(…)

arachne-pnr (project icestorm)

Mapping busring.$techmap$auto$tribuf.cc:129:run$174.$reduce_or$/usr/local/bin/…/share/yosys/techmap.v:441$477 ($reduce_or) with simplemap.

Cheerio! Kr. Bonne.

Hi Kristoff,

Both X and A flag a warning, and I am allergic to warnings.
But yes, an or may do the trick. But if you factor in the chip select circuitry you will get about the same usage as when implementing muxes?

Regards,

Josy

P.S.

looks Dutch to me?

@krbonne
Tri-state signals are useful at the IOs of the chip. I use them for I2C bus. They can also be useful with external RAM, external peripheral… These chips often have a signal bus for data out and data in.
However, I usually create a VHDL wrapper as the top level of the design. This wrapper instantiates tri-state buffers and other specific blocs.

Hi,

In my case, I needed them to access the databus of an SRAM module.

I’ve never used (VHDL / verilog) wrappers before.
Can you post a small example of what this looks like. A search on the myhdl.org webside did not return anything.

Kristoff

Josy,

The “pull-up yes” note on Xilinx is interesting!

Greeting from the Belgian coast :slight_smile:

Kristoff

Here, a wrapper is a standard VHDL module in which IOs are chip pins.
This module instantiates :

  • Vendor specific VHDL modules (for example, I2C chip configuration on a Lattice MachXO2 FPGA)
  • VHDL module(s) converted from Python.
  • Tristate buffers

@josyb we need to create a FAQ category on discourse and capture all the tri-state and different solutions on it.