iCEstick + yosys - using the Global Set/Reset (GSR) - fpga

This is probably more of an iCEstick question than a yosys one, but asking here since I'm using the Icestorm tool chain.
I want to specify startup behavior of my design, which various places on the internet seem to agree is related to the typically named rst signal. It wasn't obvious to me where such a signal comes from, so I dug into the powerup sequence. Current understanding is from Figure 2 in this document.
After CDONE is pulled high by the device, all of the internal registers have been reset, to some initial value. Now, I've found plenty of lattice documents about how each type of flip-flop or hard IP receives a reset signal and does something with its internal state, but I still don't quite understand how I specify what those states are (or even just know what they are so I can use them).
For example, if I wanted to bring an LED high for 1 second after powerup (and only after powerup) I would want to start a counter after this reset signal (whatever it is) disables.
Poking around the ice40 family data sheet and the Lattice site, I found this document about using the Global Set/Reset signal. I confirmed this GSR is mentioned in the family data sheet, referenced on page 2-3 under "Clock/Control Distribution Network". It seems that a global reset signal is usable by one of the global buffers GBUF[0-7] and can be routed (up to 4 of them) to all LUTs with the global/high-fanout distribution network.
This seems like exactly what I was after, I but I can't find any other info about how to use this in my designs. The document on using the GSR states that you can instantiate a native GSR component like this:
GSR GSR_INST (.GSR (<global reset sig>));
but I can't tell whether this is just for simulation. Am I completely going in the wrong direction here or just missing something? I'm very inexperienced with FPGAs and hardware, so its entirely possible my entire approach is flawed.

I'm not sure if that GSR document actually is about iCE40. The Lattice iCEcube tool interestingly accepts instances of GSR cells, but it seems to simply treat them as constant zero drivers. There is also no simulation model for the GSR cell type in the iCE40 sim library and no description of it in the iCE40 tech library documentation provided by Lattice.
Furthermore, I have built the following two designs with the lattice tools, and besides the timestamp in the "comment field" of the generated bit-stream file, the generated bit-streams are identical! (This test was performed with Lattice LSE as synthesis tool, not Synplify. I had problems getting Synplify to run on my machine for some reason and gave up trying to do so over a year ago..)
This is the first test design I've used:
module top (
input clk,
output rst,
output reg val
);
always #(posedge clk, posedge rst)
if (rst)
val = 1;
else
val = 0;
GSR GSR_INST (.GSR (rst));
endmodule
And this is the second test design:
module top (
input clk,
output rst,
output val
);
assign val = 0, rst = 0;
endmodule
Given this results I think it is safe to say that the lattice tools simply ignore GSR cells in iCE40 designs. (Maybe for compatibility with their other FPGA families?)
So how does one generate a rst signal then? For example, the following is a simple reset generator that asserts (pulls low) resetn for the first 15 cycles:
input clk;
...
wire resetn;
reg [3:0] rststate = 0;
assign resetn = &rststate;
always #(posedge clk) rststate <= rststate + !resetn;
(The IceStorm flow does support arbitrary initialization values for registers, whereas the lattice tools ignore the initialization value and simply initialize all FFs to zero. So if you want your designs to be portable between the tools, it is recommended to only initialize regs to zero.)
If you are using a PLL, then it is custom to use the PLL LOCK output to drive the resetn signal. Unfortunately the "iCE40 sysCLOCK PLL Design and Usage Guide" does not state if the generated LOCK signal is already synchronous to the generated clock, so it would be a good idea to synchronize it to the clock to avoid problems with metastability:
wire clk, resetn, PLL_LOCKED;
reg [3:0] PLL_LOCKED_BUF;
...
SB_PLL40_PAD #( ... ) PLL_INST (
...
.PLLOUTGLOBAL(clk),
.LOCK(PLL_LOCKED)
);
always #(posedge clk)
PLL_LOCKED_BUF <= {PLL_LOCKED_BUF, PLL_LOCKED};
assign resetn = PLL_LOCKED_BUF[3];
Regarding usage of global nets: You can explicitly route the resetn signal via a global net (using the SB_GB primitive), but using the IceStorm flow, arachne-pnr will automatically route a set/reset signal (when used by more than just a few FFs) over a global net, if a global net is available.

Related

Simple flag in VHDL [Error 10820]

I want to design a IIC sniffer in VHDL and I struggle at a very basic point.
To keep it "sequential" I want to set a flag after every part that will be executed by an entity.
Now I want to set a Flag on the START condition (SCL = HIGH & RISING_EDGE on SDA)
This flag should be resetted on the STOP condition (SCL = HIGH & FALLING_EDGE on SDA) and when I push a reset button.
I now have the problem that I can not get the flag to be set by the START and resetted by the STOP command.
How should I approach to get a flag for this period?
entity scltest is
port( scl, sda: in std_logic;
scled, sdaled, flag: out std_logic
);
end scltest;
architecture test of scltest is
begin
scled <= scl;
sdaled <= sda;
process(sda)
begin
if (scl = '1' AND rising_edge(sda)) then
flag <= '1';
else
if (scl = '1' AND falling_edge(sda)) then
flag <= '0';
end if;
end if;
end process;
end test;
This code does not work because:
"Error (10820): Netlist error at scltest.vhd(18): can't infer register for flag because its behavior depends on the edges of multiple distinct clocks"
I do understand why it won't work but I can't think of a design that will work which gives me the same function.
Thank you in advance.
Your basic idea seems to be that you want to do all your logic with the bus clock. However, your design shouldn't depend entirely on the bus clocks -- especially since I²C is so slow.
You'll want to have a running system that can do other tasks (like USB, USART...) to report to your host system (PC, SoC...) about the state of the I²C bus.
Towards that end, you'll need to sample both SCL and SDA and have a core clocked by your system clock perform the actual anaylsis of rising/fallig edges, bus states etc. That way, all your logic will be synchronous to your system clock.
Depending on your development board, example designs might exist that already have the host side ready and you would only need to "plug" your module in the right place. A good starting point IMHO1 would be one of Digilent's Spartan boards as the host side code is freely available with tools and a programming API.
1 I'm not affiliated with Digilent in any way.

How can I write sequential component with case

Below code is not compiling. How can I modify it to make it works? Thank you.
case S is
when '0' =>
U1: hi port map (x,y,z);
when others =>
U2: hey port map (x,y,z);
end case;
Without the rest of the code there will be some guessing, but you have probably used case outside a process, thus the "illegal concurrent statement" message, since case is a statement that can only be used in a process. However, component instantiation with port map (x,y,z) is a concurrent statement, thus can only be used outside a process.
VHDL is not a programming language, but a Hardware Description Language (the HDL part of VHDL), thus when writing VHDL code, think of it like describing a electrical circuit, and in this the parts are fixed, but the signal values can vary over time.
So, instantiate the components outside a process with port map (x,y,z) and control the signal values from processes, other components, ports, etc.
As you are instantiating components, you are not within a process, hence you cannot use sequential programming constructs.
You can however use if ... generate which selectively generates hardware, on the value of S as long as S is a generic or constant. (If you could input a signal to if ... generate, that would require hardware to appear or disappear when the signal value changed ... not gonna happen!)
Note that if ... generate has no "elsif" or "else" options, so you have to express your example in a slightly more awkward fashion:
gen_S_0 : if S = '0' generate
U1: hi port map (x,y,z);
end generate;
gen_S_others: if S /= '0' generate
U2: hey port map (x,y,z);
end generate;

VHDL - same bitstream, two boards -> inout issue

I wanted to ask if it is possible to use an inout pin as inout and normal out? The two behaviours should be switched through a MUX. The reason for this weird looking implementation is that I have two boards and I want to use the same bitstream. On one board, the same pin is connected to a LED through GPIO and on the other it goes to my I2C bus connection. The software tries to detect the I2C and if successful it sets a register. If not, it clears it.
LED_or_SDA : inout std_logic; -- port definition
process (register)
begin
if ( register = '1') then -- software sets this register
LED_or_SDA <= I2C_SDA; -- here I want to use it as inout
else
LED_or_SDA <= gpio_reg; -- here I want to use it as normal out
end if;
end process;
This implementation throws the error "bidirect pad net is driving non-buffer primitives" during translate. Is there a solution for this?
No, you can't. A mux is not a switch, it is a logic function. The line
LED_or_SDA <= I2C_SDA;
strongly drives LED_or_SDA from I2C_SDA. It does not connect the two nets in a way that allows bidirectional data flow.
You'll need to separate the two directions:
I2C_SDA_in <= LED_or_SDA;
LED_or_SDA <= gpio_reg WHEN (register = '1') ELSE
'0' WHEN (I2C_SDA_out = '0') ELSE
'Z';
Most I2C logic blocks have separate data in and out signals anyway, right up until the external interface, where you'll find a tri-state buffer expressed in much the same way as the code I gave you. You'll simply need to make the input and output data separate ports on your I2C block.
Unfortunately, the weak drive state of the internal signal likely isn't accessible to internal logic, so these won't work:
LED_or_SDA <= gpio_reg WHEN (register = '1') ELSE
I2C_SDA_out;
LED_or_SDA <= gpio_reg WHEN (register = '1') ELSE
'Z' WHEN (I2C_SDA_out = 'Z') ELSE
I2C_SDA_out;
The VHDL compiler actually is keeping track of a tri-state control signal, and propagating that through port statements until it hits the external pin and connects it to the real (hardware) tri-state buffer. But in most compilers you can't access that control signal for your own logic.
Guessing from your error message I assume that we are talking about a Xilinx System, e.g. around a Microblaze - if that's not the case, please update your question and also specify the exact GPIO core you're using.
Often these GPIO blocks already contain the IO-Buffer macro by default. This IOBUF is located next to a physical pin and can not drive any other signals on the FPGA. Hence the GPIO block is intended to be used on the top level of the chip and be directly connected to a pin. However, there usually is a way to also access the signals before the IOBUF: E.g. in Xilinx Platform Studio on the tab "Ports" you should have a choice to use also GPIO_IO (after buffer), GPIO_IO_I (pure input), GPIO_IO_O (pure output), GPIO_IO_T (tristate) or similar.
Yes, the trick is to treat it always as a tristate buffer, and control the output based on the state of register
-- define a tristate pin the usual way.
LED_or_SDA <= LED_or_SDA_out when LED_or_SDA_tristate = '0' else 'Z';
LED_or_SDA_in <= LED_or_SDA
-- then control the data onto it, and the tristate control line
LED_or_SDA_tristate <= '0' when register = '0' else ICD_SDA;
LED_or_SDA_out <= gpio_reg when register = '0' else '0';

difference between using reset logic vs initial values on signals

Let's say I have a signal, I can either assign a initial value of zero OR I can set it to zero upon RESET. I've seen my co-workers using the two method interchangeably. I just want to see others opinion on this.
Example (using initial value):
architecture arch of xxx is
signal flag : STD_LOGIC := 0;
begin
process (clk) begin
if rising_edge(clk) then
-- do something
end if;
end process;
end arch;
Example (using reset value):
architecture arch of xxx is
signal flag : STD_LOGIC;
begin
process (clk,rst) begin
if (rst = '1') then
flag <= '0';
elsif rising_edge(clk) then
-- do something
end if;
end process;
end arch;
If possible, use a dedicated reset signal, for several reasons:
Designs using complex clock generation may require that a module is held idle
(reset) until the clock is stable. Using initial values with an unstable but
running clock may change the initial value from the expected.
A module that interfaces to other or external modules may get protocol
violations on an interface during startup, and to avoid wrong operation or
hangup due to protocol violations, it may be required to hold the module in
reset until the protocol operation is well defined in the interface.
Restart of the entire system, or part of the system, is possible by asserting
reset, instead of having to reload the entire FPGA, which takes much longer
time, and may be more complicated if it requires CPU interaction.
Some FPGA technologies, for example Altera partial reconfiguration, does not
support initial values for the modules used in partial reconfiguration.
Reuse of modules is therefore easier if only reset is used.
Simulation of different start/restart conditions is easier when it is
possible to apply reset, and continue the same simulation sequence. If
initial value is used, then the entire simulation must be restarted.
Apply reset to as few flip-flops as possible, for the resource reasons that Russell
points out. Also, applying it to only the required flip-flop, makes it easier
to catch bugs and oversights in the design during simulation, since unknown X
values may then appear. The reset should be asynchronous, since most FPGA and
ASIC technologies have flip-flops with dedicated reset input, and the reset
will then not slow down the timing of the synchronous design part, by insertion of logic to apply a reset value. The slow down can be seen in for example Altera Cyclone V, where logic is inserted in the data path due to the synchronous reset through a MLABCELL, as shown in the data path timing report here:
A flip-flop using asynchronous reset does not have this extra delay in the data path, as can be seen in figure through this link.
The process for flip-flops with reset should be written with the reset part as:
process (clk, rst) begin
if rising_edge(clk) then
-- Flip-flops updated at clock
end if;
if (rst = '1') then
-- Flip-flops reset
end if;
end process;
This coding style makes it possible to apply reset to only some of the
flip-flops updated at the rising clock, while the remaining flip-flops are
implemented without reset.
The combined if-then-elsif-end if in question code, actually specified that
the state is held during reset for flip-flops that are not reset, since the
rising_edge(clk) part of the if does then not take effect. This is
probably not the intended implementation.
For proper timing, the reset signal (rst) should be synchronized to the clock
(clk), at least for deassertion (1 to 0), so recovery and removal time are not violated.
'Value after FPGA configuration' vs 'Value after reset'
The initial value will be the value the signal will get after the FPGA configuration.
The value affected in case of a reset will be... the value the signal will get in case the reset signal is asserted :-)
About the signal value after FPGA configuration
From Xilinx "Large FPGA Methodology Guide" page 31 :
FPGA devices have dedicated global set/reset signals (GSR). At the end of device
configuration, the GSR is automatically asserted to initialize all registers to the initial state specified in the HDL code.
Every register is at a known state at the end of configuration. You do not need to code a global reset for the sole purpose of initializing the device.
Of course, you need to trust the FPGA you use about this initial value. People often prefer to have a reset on control signals to ensure this out of configuration initial value, even if this is normaly not required...
To reset or not to reset
Maybe you need a reset for specific other reasons :
coding rules that enforce this
the necessity to set this signal back to a known value without having to reconfigure the FPGA
If you need this reset, it will probably be asserted when the FPGA go out of configuration, and the initial value will then be useless, so it is probably better to not use it.
Hope this helps.
I'm of the opinion that you should not reset any signals that do not need it. Only things like state machines or counters should be reset. Adding resets to everything means that the tools will have to add routing resources to hook up all of these resets. So for example I almost never reset any signal that just holds data, or some enable signal that will only be active for one clock cycle anyway.
Regarding initialization, I initialize every register that I infer. This can be easily checked by looking at a modelsim waveform. Red = Bad. This takes no additional resources to achieve, but it ensures that the FPGA starts up in a known-condition.

How to effectively utilize a VHDL module?

There's a few questions in here, so bear with me, and thanks for taking the time to read this...
I recently wrote an SPI master, and have fully simulated it to make sure it works as expected.
From here I'd like to use it in another design where I've already got a 7 segment display component set up to take the value received from an ADC on the SPI bus, however I think I've confused myself with things at this point.
I need to send a pulse with other parameters to the SPI master to initiate a transfer, and wait on a busy signal to be de-asserted before I can send anything else. I'm not really sure how best way to implement the SPI master within the new design.
Would I use it in the design as a component? is there a better way?
If it has to be a component, is there any way I can set it up to directly output from that component to pins rather than me having to map to new inputs/outputs in the top level design?
For example, I have SCLK, MOSI, MISO, and CS; Can I not just have them output directly rather than having to be mapped through the top level? Seems like it'd simplify the top level and make it less clunky.
Also, would it be possible to set up a function to just say "Send this data over SPI and then return what's received"?
I'm still getting my head around how to put these things together so help/examples would be greatly appreciated. It seems like all the examples/tutorials available are based on things like using two half-adders, logic gates, etc. which only help to a point when they're so simple.
edit: Entity of my SPI Master
entity SPI_master is
generic(data_width: integer := 8;
clock_select: integer := 0);
port(SCLK: out std_logic;
MOSI: out std_logic;
MISO: in std_logic;
CS: out std_logic;
Mclk_in: in std_logic;
RST: in std_logic;
CPOL: in std_logic;
CPHA: in integer;
send_packet: in std_logic;
busy: out std_logic;
Tx_data: in std_logic_vector(data_width-1 downto 0);
Rx_data: out std_logic_vector(data_width-1 downto 0));
end SPI_master;
Your entity looks reasonable, though better names or comments on CPOL,CPHA would be useful!
Partial answers :
1) You CAN use it in your design as a component, but as previously mentioned, direct entity instantiation is simpler and less verbose.
2) No you can't directly output from deep in the hierarchy, and even if you could it would be a terrible idea!
Are you familiar with "Design Patterns" from C++, Ada or Java programming? If so, think of your top level design as the "Facade" pattern.
It's the only thing the external world needs to know about your design. And it will often be written as structural HDL, instantiating your other entities, and making interconnections between sub-units and connections to external ports.
There are ways to reduce the pain of these interconnections, especially across multiple layers of hierarchy, but ultimately you must break out the SPI signals to individual pins on the top level design, so that they can be connected to the correct wires on the PCB!
3) would it be possible to set up a function to just say "Send this data over SPI and then return what's received" ... not a function, no.
But certainly you can introduce a hardware wrapper to provide the rest of your design with a simple view of a complex task. For example, (assuming "send_packet" is asserted to write a byte on SPI, and "busy" goes high until the write is complete) you can create an entity taking an array of bytes and a "start" signal as inputs. Its architecture contains a process to count the bytes, outputting each in turn to SPI and waiting while "busy", and it can signal to its "caller" when done.

Resources