Disabled generate gives compile error in Modelsim...

S

Stef

Guest
[This is a repost. Posted this to comp.lang.vhdl a few days ago, but no
replies. So maybe nobody knows the answer, it was a malformed question
or there are no readers in that group. So a repost (with a little
clarification, I hope) with the comp.arch.fpga added at least resolves
the last option. ;-)]


It has been a while since I used VHDL so I am a little rusty. Did not
much use the generate statement in the past either. And now I have the
problem that I have (been given) a VHDL model that has a conditional
generate in it. And this does not work as I expected. In the model, the
purpose of the conditional is that there is a clock source that cannot be
simulated, so an alternative is simulated. I have reproduced the problem
in the minimal example below.

If I declare \'sigio\' as \'inout\', as below and as I got the model, then when
I simulate it, the signals in the simulation remain \'U\'. So somehow the
\'gentest\' model drives the \'sigio\' signal although the generic
\'this_is_a_simulation\' has been set to true.

If I declare \'sigio\' as \'in\' (change the comment line in the port), I get a
compilation error in Modelsim on driving the type \'in\' \'sigio\' signal. When
I then just comment out the \'rtlblk\' generate, the model simulates as
expected.

Can this be made to work as expected (simulation/clocksource model switch
without changing the code)? Unfortunately I cannot get information from the
original creator of this construct and I don\'t know if it ever worked.


-------- gentest.vhd ------------
library ieee;
use ieee.std_logic_1164.all;

entity gentest is
generic(
this_is_a_simulation : boolean := true
);
port(
-- sigio : in std_logic; -- Compile error
sigio : inout std_logic; -- Original line
sigout : out std_logic
);
end entity gentest;

architecture behav of gentest is
begin

-- If I comment out this generate, the compile error with sigio as
-- \'in\' disappears.
-- But should this section not be ignored if \'this_is_a_simulation\'
-- is set to false?
rtlblk : if this_is_a_simulation = false generate
sigio <= \'1\';
sigout <= \'1\';
end generate;

simblk : if this_is_a_simulation = true generate
sigout <= sigio;
end generate;

end architecture behav;


-------- tb_gentest.vhd ------------
library ieee;
use ieee.std_logic_1164.all;

entity tb_gentest is
end entity tb_gentest;

architecture behav of tb_gentest is
signal clk : std_logic;
signal sigout : std_logic;
begin

gentest_inst : entity work.gentest
generic map(
this_is_a_simulation => true
)
port map(
sigio => clk,
sigout => sigout
);

process
begin
clk <= \'0\';
wait for 10ns;
clk <= \'1\';
wait for 10ns;
end process;

end architecture behav;


--
Stef

The world is no nursery.
- Sigmund Freud
 
On Friday, December 9, 2022 at 6:20:14 AM UTC-5, Stef wrote:
<snip>
> If I declare \'sigio\' as \'inout\', as below and as I got the model, then when I simulate it, the signals in the simulation remain \'U\'. So somehow the \'gentest\' model drives the \'sigio\' signal although the generic \'this_is_a_simulation\' has been set to true.

When you declared sigio as inout, you\'re saying that there will be a driver for this signal. But in your testbench you\'ve connected sigio to the signal clk, and you have a process that drives clk. Regardless of how if this_is_a_simulation is set there will be problems.
* if this_is_a_simulation = true then sigio will get set to \'1\'. But since clk is also driving the signal to either a \'0\' or \'1\', half the time the two drivers will be in conflict. When clk happens to be set to \'1\' is the only time that you will get a \'1\'. The other half of the time you\'ll have a \'1\' and a \'0\' being driven...resulting in unknown
* if this_is_a_simulation = false then the gentest entity will say that there is a driver for \'sigio\', but since the architecture doesn\'t actually drive the signal, sigio will be unknown and will always override the \'0\' and \'1\' that clk is being set to. The result of that condition is an unknown, all of the time.

You could work around the problem for \"if this_is_a_simulation = false\" by changing the entity to give a default of \'Z\' like this: \"sigio : inout std_logic := \'Z\'; -- Original line\". Now sigio will have a driver of \'Z\' at t=0 and \'clk\' will always be able to override the \'Z\' with a \'0\' or \'1\'.

> I then just comment out the \'rtlblk\' generate, the model simulates as expected.

Not sure what you mean with \"as expected\". This design is fatally flawed by having two drivers both trying to drive the same signal at the same time. I have no idea what you\'re trying to do inside gentest with sigio in the first place. Either sigio should be of type \'in\' and the \"sigio <= 1\'\" statement should be removed OR if it really is meant to be of type \'inout\', then you should only be driving sigio when nothing on the outside (i.e. the testbench signal clk) is actively driving it to \'0\' or \'1\'. During that time clk should be driven to \'Z\' in the testbench. I have no idea how you expect gentest to know this based on the posted code. Generally, when there are multiple potential drivers of a signal, there is also another signal that tells both sides who has control. Check how something like an 74xx244 IC works. There is an OE input signal that tells the IC when it should actively drive the signal low or high and when it should tri-state the outputs.

Kevin Jennings
 
On 2022-12-11 KJ wrote in comp.lang.vhdl:
On Friday, December 9, 2022 at 6:20:14 AM UTC-5, Stef wrote:
snip
If I declare \'sigio\' as \'inout\', as below and as I got the model, then when I simulate it, the signals in the simulation remain \'U\'. So somehow the \'gentest\' model drives the \'sigio\' signal although the generic \'this_is_a_simulation\' has been set to true.

When you declared sigio as inout, you\'re saying that there will be a driver for this signal. But in your testbench you\'ve connected sigio to the signal clk, and you have a process that drives clk. Regardless of how if this_is_a_simulation is set there will be problems.

Okay, just the fact that the signal is declared as inout is a problem
already.

* if this_is_a_simulation = true then sigio will get set to \'1\'. But since clk is also driving the signal to either a \'0\' or \'1\', half the time the two drivers will be in conflict. When clk happens to be set to \'1\' is the only time that you will get a \'1\'. The other half of the time you\'ll have a \'1\' and a \'0\' being driven...resulting in unknown
* if this_is_a_simulation = false then the gentest entity will say that there is a driver for \'sigio\', but since the architecture doesn\'t actually drive the signal, sigio will be unknown and will always override the \'0\' and \'1\' that clk is being set to. The result of that condition is an unknown, all of the time.

You could work around the problem for \"if this_is_a_simulation = false\" by changing the entity to give a default of \'Z\' like this: \"sigio : inout std_logic := \'Z\'; -- Original line\". Now sigio will have a driver of \'Z\' at t=0 and \'clk\' will always be able to override the \'Z\' with a \'0\' or \'1\'.

In the examples I tried to reduce the problem down to a small model and
I may have simpified it too much. In the \"if this_is_a_simulation =
false\" situation, the sigio in gentest.vhd is connected to the clock
pin of an instantiated PLL block and according to the code I inherited,
this pin is an inout signal (you would expect an in, but it is inout).

I then just comment out the \'rtlblk\' generate, the model simulates as expected.

Not sure what you mean with \"as expected\". This design is fatally flawed by having two drivers both trying to drive the same signal at the same time. I have no idea what you\'re trying to do inside gentest with sigio in the first place. Either sigio should be of type \'in\' and the \"sigio <= 1\'\" statement should be removed OR if it really is meant to be of type \'inout\', then you should only be driving sigio when nothing on the outside (i.e. the testbench signal clk) is actively driving it to \'0\' or \'1\'. During that time clk should be driven to \'Z\' in the testbench. I have no idea how you expect gentest to know this based on the posted code. Generally, when there are multiple potential drivers of a signal, there is also another signal that tells both sides who has control. Check how something like an 74xx244 IC works. There is an OE input signal that tells the IC when it should actively drive the signal low or high and when it should tri-state the outputs.

What I \"expect\" is that I can simulate the
model (this_is_a_simulation = true) with the testbench
driving the clk signal. And that by setting this_is_a_simulation
to false, I can generate the logic for the real FPGA, where clk is
connected to an IO pin and must for some reason be inout.

I now solve this by commenting in/out a block of code. This works, but
is error prone. Luckily forgetting to uncomment the PLL block is easily
spotted as it results in a fast run with an empty FPGA as a result. ;-)

As I said before, I got this code with this construct and could not get
is to work and I do not know if it ever worked.

I expected the problem to be in the \"if condition generate\" part of the
code. But of I understand you correctly, the problem already is in
declaring the signal as inout.

But what should a compiler do with a conditional generate block that is
off? Should it be completely ignored or should it still be tested for
validity?

Say we have an entity with this port:

port( signal_in : in std_logic );

And then somewhere in the architecture we have this:

testblock : if false generate
signal_in <= \'1\';
end generate;

Should the compiler ignore driving a input signal or should it give an
error although testblock is \"off\"?


--
Stef

Walk softly and carry a BFG-9000.
 
On Monday, December 12, 2022 at 4:26:46 AM UTC-5, Stef wrote:
On 2022-12-11 KJ wrote in comp.lang.vhdl:
On Friday, December 9, 2022 at 6:20:14 AM UTC-5, Stef wrote:

In the examples I tried to reduce the problem down to a small model and
I may have simpified it too much. In the \"if this_is_a_simulation =
false\" situation, the sigio in gentest.vhd is connected to the clock
pin of an instantiated PLL block and according to the code I inherited,
this pin is an inout signal (you would expect an in, but it is inout).

This doesn\'t make any sense. Is gentest connected to an input or an output of the PLL block? Whichever it is, gentest should be the opposite. This is pretty basic, you connect inputs to outputs and vice versa. You don\'t connect outputs together, you don\'t connect inputs. Pretty simple.

Not sure what you mean with \"as expected\". This design is fatally flawed by having two drivers both trying to drive the same signal at the same time. I have no idea what you\'re trying to do inside gentest with sigio in the first place. Either sigio should be of type \'in\' and the \"sigio <= 1\'\" statement should be removed OR if it really is meant to be of type \'inout\', then you should only be driving sigio when nothing on the outside (i.e. the testbench signal clk) is actively driving it to \'0\' or \'1\'. During that time clk should be driven to \'Z\' in the testbench. I have no idea how you expect gentest to know this based on the posted code. Generally, when there are multiple potential drivers of a signal, there is also another signal that tells both sides who has control. Check how something like an 74xx244 IC works. There is an OE input signal that tells the IC when it should actively drive the signal low or high and when it should tri-state the outputs.

What I \"expect\" is that I can simulate the
model (this_is_a_simulation = true) with the testbench
driving the clk signal. And that by setting this_is_a_simulation
to false, I can generate the logic for the real FPGA, where clk is
connected to an IO pin and must for some reason be inout.

This doesn\'t make much sense either. You shouldn\'t be changing logic to do simulation. The whole point of simulation is to have a model of the real system. If you are making logic changes \"for simulation\", you are most likely making a mistake that you will then have to figure out.

I now solve this by commenting in/out a block of code. This works, but
is error prone. Luckily forgetting to uncomment the PLL block is easily
spotted as it results in a fast run with an empty FPGA as a result. ;-)

Error prone is a polite way to put it. Of no value at all would be another..

As I said before, I got this code with this construct and could not get
is to work and I do not know if it ever worked.

That\'s why you run the simulator...to find out what\'s wrong. But you don\'t start by connecting outputs together.

I expected the problem to be in the \"if condition generate\" part of the
code. But of I understand you correctly, the problem already is in
declaring the signal as inout.

The problem is that you are thinking that a real design would connect two outputs together. It has nothing to do with VHDL at all.

But what should a compiler do with a conditional generate block that is
off? Should it be completely ignored or should it still be tested for
validity?

The compiler already did the right thing.

Say we have an entity with this port:

port( signal_in : in std_logic );

And then somewhere in the architecture we have this:

testblock : if false generate
signal_in <= \'1\';
end generate;

Should the compiler ignore driving a input signal or should it give an
error although testblock is \"off\"?

As long as the syntax is correct (and your signal assignment to signal_in is), there is no error for the compiler to report. What error do you think should be reported? The compiler does not report on design errors such as connecting two outputs together as you did. Instead it shows you the results of that design error which is that the resulting output is undefined.

If you want the compiler itself to help you out some more, change all your usages of \'std_logic\' to \'std_ulogic\' in gentest as well as the testbench. Then the compilation will fail because signals of type \'std_ulogic\' can have only one driver. You won\'t even be able to start the simulation until you fix the error. Use of std_ulogic rather than std_logic finds the design errors that you are creating right at compile time and gives you all the information about where the problem is located in the code. Using std_logic only in situations where their truly can be multiple drivers such as some shared bus like the data bus between a processor and memory. In all other cases, use std_ulogic. FPGAs do not support multiple driver designs for any internal signal.

Kevin Jennings
 
On 2022-12-14 KJ wrote in comp.lang.vhdl:
On Monday, December 12, 2022 at 4:26:46 AM UTC-5, Stef wrote:
On 2022-12-11 KJ wrote in comp.lang.vhdl:
On Friday, December 9, 2022 at 6:20:14 AM UTC-5, Stef wrote:

In the examples I tried to reduce the problem down to a small model and
I may have simpified it too much. In the \"if this_is_a_simulation =
false\" situation, the sigio in gentest.vhd is connected to the clock
pin of an instantiated PLL block and according to the code I inherited,
this pin is an inout signal (you would expect an in, but it is inout).

This doesn\'t make any sense. Is gentest connected to an input or an output of the PLL block? Whichever it is, gentest should be the opposite. This is pretty basic, you connect inputs to outputs and vice versa. You don\'t connect outputs together, you don\'t connect inputs. Pretty simple.

In the design I inherited the PLL pin is a package pin and declared as
inout. Why this was done, I do not know. So two inouts are connected
together. And yes, I am aware that you don\'t connect outputs or inputs
together (I am and electronics engineer). I will see if it can be changed
to an input to get rid of this problem.

Not sure what you mean with \"as expected\". This design is fatally flawed by having two drivers both trying to drive the same signal at the same time. I have no idea what you\'re trying to do inside gentest with sigio in the first place. Either sigio should be of type \'in\' and the \"sigio <= 1\'\" statement should be removed OR if it really is meant to be of type \'inout\', then you should only be driving sigio when nothing on the outside (i.e. the testbench signal clk) is actively driving it to \'0\' or \'1\'. During that time clk should be driven to \'Z\' in the testbench. I have no idea how you expect gentest to know this based on the posted code. Generally, when there are multiple potential drivers of a signal, there is also another signal that tells both sides who has control. Check how something like an 74xx244 IC works. There is an OE input signal that tells the IC when it should actively drive the signal low or high and when it should tri-state the outputs.

What I \"expect\" is that I can simulate the
model (this_is_a_simulation = true) with the testbench
driving the clk signal. And that by setting this_is_a_simulation
to false, I can generate the logic for the real FPGA, where clk is
connected to an IO pin and must for some reason be inout.


This doesn\'t make much sense either. You shouldn\'t be changing logic to do simulation. The whole point of simulation is to have a model of the real system. If you are making logic changes \"for simulation\", you are most likely making a mistake that you will then have to figure out.

Aparently the PLL could not be simulated, so the clock came directly
from the test bench. So some switch between testbench and pll clock must
be made between simulation and hardware generation. Probably not the
best solution, as you say. But this is how I got it. And I try to
understand why they did this before changing everything.

I now solve this by commenting in/out a block of code. This works, but
is error prone. Luckily forgetting to uncomment the PLL block is easily
spotted as it results in a fast run with an empty FPGA as a result. ;-)


Error prone is a polite way to put it. Of no value at all would be another.
I would not say that, only the clock source is changed from PLL\'ed input
to direct input (at the intended PLL frequency).

As I said before, I got this code with this construct and could not get
is to work and I do not know if it ever worked.


That\'s why you run the simulator...to find out what\'s wrong. But you don\'t start by connecting outputs together.

I expected the problem to be in the \"if condition generate\" part of the
code. But of I understand you correctly, the problem already is in
declaring the signal as inout.


The problem is that you are thinking that a real design would connect two outputs together. It has nothing to do with VHDL at all.

No I do not think that, what makes you believe I do?

But what should a compiler do with a conditional generate block that is
off? Should it be completely ignored or should it still be tested for
validity?


The compiler already did the right thing.

Say we have an entity with this port:

port( signal_in : in std_logic );

And then somewhere in the architecture we have this:

testblock : if false generate
signal_in <= \'1\';
end generate;

Should the compiler ignore driving a input signal or should it give an
error although testblock is \"off\"?


As long as the syntax is correct (and your signal assignment to signal_in is), there is no error for the compiler to report. What error do you think should be reported? The compiler does not report on design errors such as connecting two outputs together as you did. Instead it shows you the results of that design error which is that the resulting output is undefined.

The syntax in itself is correct, but assigning a value to an input is
not. So I would not expect an error on that code, as do you, I read in
the above. However when I compile this in Modelsim:

rtlblk : if this_is_a_simulation = false generate
sigio <= \'1\';
sigout <= \'1\';
end generate;

With this_is_a_simulation set to true and sigio declared as in, I get
the following error

-- Compiling architecture behav of gentest
** Error: ../gentest.vhd(19): Cannot drive signal \'sigio\' of mode IN.

This is not what I expect, why is the assignment not ignored?

This is the core of my original question. What is the expected behaviour
when such generate blocks are disabled and contain incorrect code?

> If you want the compiler itself to help you out some more, change all your usages of \'std_logic\' to \'std_ulogic\' in gentest as well as the testbench. Then the compilation will fail because signals of type \'std_ulogic\' can have only one driver. You won\'t even be able to start the simulation until you fix the error. Use of std_ulogic rather than std_logic finds the design errors that you are creating right at compile time and gives you all the information about where the problem is located in the code. Using std_logic only in situations where their truly can be multiple drivers such as some shared bus like the data bus between a processor and memory. In all other cases, use std_ulogic. FPGAs do not support multiple driver designs for any internal signal.

No, FPGAa don\'t have internal tri-state signals. Changing to std_ulogic
sounds like a good idea. Is this what you normally use for internal logic?

--
Stef

Two wrongs are only the beginning.
-- Kohn
 
On Wednesday, December 14, 2022 at 7:08:35 AM UTC-5, Stef wrote:
On 2022-12-14 KJ wrote in comp.lang.vhdl:
On Monday, December 12, 2022 at 4:26:46 AM UTC-5, Stef wrote:
On 2022-12-11 KJ wrote in comp.lang.vhdl:
On Friday, December 9, 2022 at 6:20:14 AM UTC-5, Stef wrote:


This doesn\'t make any sense. Is gentest connected to an input or an output of the PLL block? Whichever it is, gentest should be the opposite. This is pretty basic, you connect inputs to outputs and vice versa. You don\'t connect outputs together, you don\'t connect inputs. Pretty simple.

In the design I inherited the PLL pin is a package pin and declared as
inout. Why this was done, I do not know. So two inouts are connected
together. And yes, I am aware that you don\'t connect outputs or inputs
together (I am and electronics engineer). I will see if it can be changed
to an input to get rid of this problem.

The place to look is in the documentation for the PLL, not in the VHDL code.. If the PLL documentation says that there are times when the pin is driven externally and other times that it is producing an output then it should be described in VHDL as an inout. I doubt that to actually be the case based on what you\'ve described so far. However, if it is truly a bi-directional signal, then that same PLL documentation will also describe the conditions under which the PLL uses the pin as an input and the times it is an output. VHDL is a description of hardware, it is not the place one should go to as the definition of how the signal works.

If the documentation says the pin is an output, then it is. If the VHDL says it is an inout, the VHDL is not correctly describing the PLL which means the VHDL is wrong and should be corrected.

Aparently the PLL could not be simulated, so the clock came directly
from the test bench. So some switch between testbench and pll clock must
be made between simulation and hardware generation. Probably not the
best solution, as you say. But this is how I got it. And I try to
understand why they did this before changing everything.

Not wanting to make changes before understanding is a good approach. But now I think we\'re finally getting to the nuts and bolts of the problem you\'re actually looking at which is that there is no simulation model for the PLL, correct? What you should then be doing is creating an if/generate around the PLL itself, not in some separate entity which is how it appears that you are currently doing it.

So in the FPGA design there is someplace where you are instantiating a component that is the PLL. All FPGA PLLs will have an input clock and produce output clocks and will have multiple parameters to configure it. The instantiation then will look something like this...

MyPll : ThePll(InputClock, OutputClock, ...);

So, if you really don\'t have a simulation model for the PLL you would modify this single instantiation to be the following. Note that what is being switched between based on this_is_a_simulation will be in the same entity/architecture. What you originally posted had the process that generated the clock in one entity (the testbench). You don\'t really show where the instantiation of the PLL is located, but I\'m assuming it is in gentest which I\'m guessing is the FPGA design. Regardless though, this is how you structure things in the VHDL code that are to be \'switched\' out based on some simulation parameter. The thing that is receiving the PLL\'s OutputClock signal is not modified at all. In particular, there is no need to add code to drive some sigio signal under some conditions.

Also note that for the simulation part, I\'ve simply copied the code you posted from the testbench just renaming the \'clk\' signal to be the same name as the clock signal output from the PLL. PLLs also tend to have an output that says when the PLL has locked on to the input and the output clock is now valid. If you\'re using such a signal (or other PLL output signals), you would connect them to the PLL component in the rtlblk for the MyPll but then also generate logic in the simblk to create that output. Maybe it\'s something like \"locked <= \'0\', \'1\' after 1 us;\"

simblk : if this_is_a_simulation = true generate
process
begin
OutputClock <= \'0\';
wait for 10ns;
OutputClock <= \'1\';
wait for 10ns;
end process;
-- Add code for any other PLL outputs that you\'re using here

Having said all that, you might want to double check your FPGA tools. Typically there is a simulation model of the PLL. In that case you wouldn\'t make any changes to the source code of the FPGA design as described above. Instead all you need to do is add the simulation model VHDL file to the simulation project. That would be the best approach since it gets you the correct simulation model as opposed to something that is cobbled together. Which software are you using to build the FPGA design? I know Altera (now Intel) does create PLL simulation models. Haven\'t used any others in quite a while.

The problem is that you are thinking that a real design would connect two outputs together. It has nothing to do with VHDL at all.

No I do not think that, what makes you believe I do?

Because you added code in gentest to explicitly drive a signal that is already being driven by the testbench.

The syntax in itself is correct, but assigning a value to an input is
not. So I would not expect an error on that code, as do you, I read in
the above. However when I compile this in Modelsim:
rtlblk : if this_is_a_simulation = false generate
sigio <= \'1\';
sigout <= \'1\';
end generate;
With this_is_a_simulation set to true and sigio declared as in, I get
the following error

-- Compiling architecture behav of gentest
** Error: ../gentest.vhd(19): Cannot drive signal \'sigio\' of mode IN.

This is not what I expect, why is the assignment not ignored?

Because a VHDL generate statement is not like a C pre-processor where it ignores entire blocks of code. For example, in C you can have the following which will compile just fine and not produce any problems

#if false
alkljdfljk
#endif

The equivalent in VHDL would be
MyGenerate : if false
alkljdfljk
end generate

VHDL will flag \'alkljdfljk\' as an error because it analyzes all of the code, even if the conditions imply that the code will never be used. In your case, the error was that you tried to assign a value to an input.

You may choose to see this as \"Why the heck are you complaining about code that will not be used?\" or choose to see it as making sure that all of the code, whether it will be used or not, is valid code. In this case, it may be trivial, but consider if you had several if/generate statements controlled by various parameters. Would you really want to have to compile all of the possible parameter settings in order to know that every possible combination of parameters compiles correctly? What VHDL is doing is validating that every possible if/generate will in fact compile correctly with a single compile.

This is the core of my original question. What is the expected behaviour
when such generate blocks are disabled and contain incorrect code?

I think I\'ve answered the question here. Hopefully that is the case. If not, chime back in.

If you want the compiler itself to help you out some more, change all your usages of \'std_logic\' to \'std_ulogic\' in gentest as well as the testbench. Then the compilation will fail because signals of type \'std_ulogic\' can have only one driver. You won\'t even be able to start the simulation until you fix the error. Use of std_ulogic rather than std_logic finds the design errors that you are creating right at compile time and gives you all the information about where the problem is located in the code. Using std_logic only in situations where their truly can be multiple drivers such as some shared bus like the data bus between a processor and memory. In all other cases, use std_ulogic. FPGAs do not support multiple driver designs for any internal signal.
No, FPGAa don\'t have internal tri-state signals. Changing to std_ulogic
sounds like a good idea. Is this what you normally use for internal logic?

Yes, I use std_ulogic for all signals, testbench and design, that have a single driver in \'real life\'. Bi-directional interfaces, such as that to an external memory, are the only std_logic signals.

Kevin Jennings
 
On 2022-12-17 KJ wrote in comp.lang.vhdl:
On Wednesday, December 14, 2022 at 7:08:35 AM UTC-5, Stef wrote:
On 2022-12-14 KJ wrote in comp.lang.vhdl:
On Monday, December 12, 2022 at 4:26:46 AM UTC-5, Stef wrote:
On 2022-12-11 KJ wrote in comp.lang.vhdl:
On Friday, December 9, 2022 at 6:20:14 AM UTC-5, Stef wrote:


This doesn\'t make any sense. Is gentest connected to an input or an output of the PLL block? Whichever it is, gentest should be the opposite. This is pretty basic, you connect inputs to outputs and vice versa. You don\'t connect outputs together, you don\'t connect inputs. Pretty simple.

In the design I inherited the PLL pin is a package pin and declared as
inout. Why this was done, I do not know. So two inouts are connected
together. And yes, I am aware that you don\'t connect outputs or inputs
together (I am and electronics engineer). I will see if it can be changed
to an input to get rid of this problem.

The place to look is in the documentation for the PLL, not in the VHDL code. If the PLL documentation says that there are times when the pin is driven externally and other times that it is producing an output then it should be described in VHDL as an inout. I doubt that to actually be the case based on what you\'ve described so far. However, if it is truly a bi-directional signal, then that same PLL documentation will also describe the conditions under which the PLL uses the pin as an input and the times it is an output. VHDL is a description of hardware, it is not the place one should go to as the definition of how the signal works.

If the documentation says the pin is an output, then it is. If the VHDL says it is an inout, the VHDL is not correctly describing the PLL which means the VHDL is wrong and should be corrected.

That was my initial thought as well, but the documentation is not very
clear on this subject:
PACKAGEPIN: PLL REFERENCE CLOCK pin that serves as the input to the
SB_PLL40_PAD primitive.

\"serves as an input\" is not saying explicitely that it is an \'in\'. Could
be.

The part is a Lattice iCE40 and the pll entity is created by the PLL
configurator in the iCEcube2 tool. If I re-do the configuration, I get
the exact same PLL entity, with the \'inout\' PACKAGEPIN as input clock to
the PLL.

Aparently the PLL could not be simulated, so the clock came directly
from the test bench. So some switch between testbench and pll clock must
be made between simulation and hardware generation. Probably not the
best solution, as you say. But this is how I got it. And I try to
understand why they did this before changing everything.

Not wanting to make changes before understanding is a good approach. But now I think we\'re finally getting to the nuts and bolts of the problem you\'re actually looking at which is that there is no simulation model for the PLL, correct? What you should then be doing is creating an if/generate around the PLL itself, not in some separate entity which is how it appears that you are currently doing it.

I have not searched for a simulation model. I was first trying to get
the package I got to work, and that does not include the PLL model.

The iCEcube2 tool creates a wrapper entity for the PLL and this wrapper
entity was instantiated in the top level. The if/generate was indeed in
the top level, acting on the wrapper, not on the PLL itself.

So in the FPGA design there is someplace where you are instantiating a component that is the PLL. All FPGA PLLs will have an input clock and produce output clocks and will have multiple parameters to configure it. The instantiation then will look something like this...

MyPll : ThePll(InputClock, OutputClock, ...);

So, if you really don\'t have a simulation model for the PLL you would modify this single instantiation to be the following. Note that what is being switched between based on this_is_a_simulation will be in the same entity/architecture. What you originally posted had the process that generated the clock in one entity (the testbench). You don\'t really show where the instantiation of the PLL is located, but I\'m assuming it is in gentest which I\'m guessing is the FPGA design. Regardless though, this is how you structure things in the VHDL code that are to be \'switched\' out based on some simulation parameter. The thing that is receiving the PLL\'s OutputClock signal is not modified at all. In particular, there is no need to add code to drive some sigio signal under some conditions.

Yes, the simulated clock is generated in the testbench and connected to
the input that in real life is the input for the PLL input clock.

in gentest, the PLL is in \'rtlblk\' with its output connected to sigout.
In simulation the external clock is assigned directly to sigout in
\'simblk\'.


Also note that for the simulation part, I\'ve simply copied the code you posted from the testbench just renaming the \'clk\' signal to be the same name as the clock signal output from the PLL. PLLs also tend to have an output that says when the PLL has locked on to the input and the output clock is now valid. If you\'re using such a signal (or other PLL output signals), you would connect them to the PLL component in the rtlblk for the MyPll but then also generate logic in the simblk to create that output. Maybe it\'s something like \"locked <= \'0\', \'1\' after 1 us;\"

simblk : if this_is_a_simulation = true generate
process
begin
OutputClock <= \'0\';
wait for 10ns;
OutputClock <= \'1\';
wait for 10ns;
end process;
-- Add code for any other PLL outputs that you\'re using here

Having said all that, you might want to double check your FPGA tools. Typically there is a simulation model of the PLL. In that case you wouldn\'t make any changes to the source code of the FPGA design as described above. Instead all you need to do is add the simulation model VHDL file to the simulation project. That would be the best approach since it gets you the correct simulation model as opposed to something that is cobbled together. Which software are you using to build the FPGA design? I know Altera (now Intel) does create PLL simulation models. Haven\'t used any others in quite a while.

It is lattice iCEcube2. I will look into this when I need to make more
extensive modifications to the device.

The problem is that you are thinking that a real design would connect two outputs together. It has nothing to do with VHDL at all.

No I do not think that, what makes you believe I do?

Because you added code in gentest to explicitly drive a signal that is already being driven by the testbench.
Ok, this is where the problem starts. I was expecting the \'rtlblk\' to be
ignored in simulation, so there would still be a single driver.

The syntax in itself is correct, but assigning a value to an input is
not. So I would not expect an error on that code, as do you, I read in
the above. However when I compile this in Modelsim:
rtlblk : if this_is_a_simulation = false generate
sigio <= \'1\';
sigout <= \'1\';
end generate;
With this_is_a_simulation set to true and sigio declared as in, I get
the following error

-- Compiling architecture behav of gentest
** Error: ../gentest.vhd(19): Cannot drive signal \'sigio\' of mode IN.

This is not what I expect, why is the assignment not ignored?

Because a VHDL generate statement is not like a C pre-processor where it ignores entire blocks of code. For example, in C you can have the following which will compile just fine and not produce any problems

#if false
alkljdfljk
#endif

As I program more C than VHDL, this was indeed what I was expecting.

The equivalent in VHDL would be
MyGenerate : if false
alkljdfljk
end generate

VHDL will flag \'alkljdfljk\' as an error because it analyzes all of the code, even if the conditions imply that the code will never be used. In your case, the error was that you tried to assign a value to an input.

In your previous answer you said, that the compiler checks validity of
the unused code anyway, but only for correct syntax.
So an error for \"alkljdfljk\", but not for \"sigio <= \'1\';\", contrary to
what I observed in Modelsim. This what confused me and that is why I
posted the exact error description.

You may choose to see this as \"Why the heck are you complaining about code that will not be used?\" or choose to see it as making sure that all of the code, whether it will be used or not, is valid code. In this case, it may be trivial, but consider if you had several if/generate statements controlled by various parameters. Would you really want to have to compile all of the possible parameter settings in order to know that every possible combination of parameters compiles correctly? What VHDL is doing is validating that every possible if/generate will in fact compile correctly with a single compile.

Okay, I think we are on the same page now. VHDL checks all code as if it
where used, even when not used.

This is the core of my original question. What is the expected behaviour
when such generate blocks are disabled and contain incorrect code?

I think I\'ve answered the question here. Hopefully that is the case. If not, chime back in.

Yes, this is answered now. And I now believe the original construct
probably never worked in the state I got it in. :-(

If you want the compiler itself to help you out some more, change all your usages of \'std_logic\' to \'std_ulogic\' in gentest as well as the testbench. Then the compilation will fail because signals of type \'std_ulogic\' can have only one driver. You won\'t even be able to start the simulation until you fix the error. Use of std_ulogic rather than std_logic finds the design errors that you are creating right at compile time and gives you all the information about where the problem is located in the code. Using std_logic only in situations where their truly can be multiple drivers such as some shared bus like the data bus between a processor and memory. In all other cases, use std_ulogic. FPGAs do not support multiple driver designs for any internal signal.
No, FPGAa don\'t have internal tri-state signals. Changing to std_ulogic
sounds like a good idea. Is this what you normally use for internal logic?

Yes, I use std_ulogic for all signals, testbench and design, that have a single driver in \'real life\'. Bi-directional interfaces, such as that to an external memory, are the only std_logic signals.

Kevin Jennings

--
Stef

What\'s the matter with the world? Why, there ain\'t but one thing wrong
with every one of us -- and that\'s \"selfishness.\"
-- The Best of Will Rogers
 

Welcome to EDABoard.com

Sponsor

Back
Top