This code works in simulation but not in reality, please help

F

FranzH

Hello,

I have difficulies with the following code. It translates, I can make
a programing file, download it to the chip but the result is not as it
is in simulation and I don't understand why:

The following process sends out bytes by using the PicoBlaze UART
sender macro. The plan is to wait until "SEND_A_BYTE_NOW" gets '1'
and then send out the byte in "BYTE_TO_SEND_NOW". PBCLK is a 50 MHz
clock.

SERIALSENDER: process (PBCLK)
begin
if (rising_edge(PBCLK)) then
if (UART_STATE = B"00") then
write_to_uart <= '0';
if (SEND_A_BYTE_NOW = '1') then
UART_STATE <= B"01";
end if;
elsif (UART_STATE = B"01") then
out_port <= BYTE_TO_SEND_NOW;
write_to_uart <= '0';
UART_STATE <= B"10";
elsif (UART_STATE = B"10") then
write_to_uart <= '1';
UART_STATE <= B"00";
end if;
end if;
end process;

The sending itself work fine, but the wrong data seems to get sent.
The following process controls what is sent:

SEND: process (write_to_uart, BUSVAL)
begin
if (BUSVAL /= BUFBUS) then
if (tx_half_full = '0' AND SEND_A_BYTE_NOW = '0') then
SEND_A_BYTE_NOW <= '1';
BYTE_TO_SEND_NOW <= BYTE_TO_SEND_NOW + '1';
end if;
BUFBUS <= BUSVAL;
elsif (rising_edge(write_to_uart)) then
SEND_A_BYTE_NOW <= '0';
end if;
end process;

I want it to work like this: Each time "write_to_uart" gets '1', I
know that a byte was written to the UART send buffer. So I reset
"SEND_A_BYTE_NOW" to '0' such that the next byte only gets
sent if this goes back to '1'.

I want to send out a byte under the following conditions:
1. BUSVAL has changed
2. tx_half_full = '0'
3. SEND_A_BYTE_NOW is not already '1'

Then I want to send out a value that is the last value sent + 1

It simulates fine, but when I listen to the serial port of the real
device, the bytes don't come out in consecutive order. I would
expect:

1,2,3,4,5,6,7 and what I really get is 30, 45, 96, AE, B4 etc ....

I have a few questions:

* It this code above bad design ?
* Why does it work fine in simulation, but not on the real device ?
* Why does BYTE_TO_SEND_NOW get increased multiple times on the real
device and only once in simulation ?

Please help me. I am a VHDL beginner and don't know where to start
searching.

Thanks !
F.
 
R

Russell

Hello,

I have difficulies with the following code. It translates, I can make
a programing file, download it to the chip but the result is not as it
is in simulation and I don't understand why:

The following process sends out bytes by using the PicoBlaze UART
sender macro. The plan is to wait until "SEND_A_BYTE_NOW" gets '1'
and then send out the byte in "BYTE_TO_SEND_NOW". PBCLK is a 50 MHz
clock.

SERIALSENDER: process (PBCLK)
begin
if (rising_edge(PBCLK)) then
if (UART_STATE = B"00") then
write_to_uart <= '0';
if (SEND_A_BYTE_NOW = '1') then
UART_STATE <= B"01";
end if;
elsif (UART_STATE = B"01") then
out_port <= BYTE_TO_SEND_NOW;
write_to_uart <= '0';
UART_STATE <= B"10";
elsif (UART_STATE = B"10") then
write_to_uart <= '1';
UART_STATE <= B"00";
end if;
end if;
end process;

The sending itself work fine, but the wrong data seems to get sent.
The following process controls what is sent:

SEND: process (write_to_uart, BUSVAL)
begin
if (BUSVAL /= BUFBUS) then
if (tx_half_full = '0' AND SEND_A_BYTE_NOW = '0') then
SEND_A_BYTE_NOW <= '1';
BYTE_TO_SEND_NOW <= BYTE_TO_SEND_NOW + '1';
end if;
BUFBUS <= BUSVAL;
elsif (rising_edge(write_to_uart)) then
SEND_A_BYTE_NOW <= '0';
end if;
end process;

I want it to work like this: Each time "write_to_uart" gets '1', I
know that a byte was written to the UART send buffer. So I reset
"SEND_A_BYTE_NOW" to '0' such that the next byte only gets
sent if this goes back to '1'.

I want to send out a byte under the following conditions:
1. BUSVAL has changed
2. tx_half_full = '0'
3. SEND_A_BYTE_NOW is not already '1'

Then I want to send out a value that is the last value sent + 1

It simulates fine, but when I listen to the serial port of the real
device, the bytes don't come out in consecutive order. I would
expect:

1,2,3,4,5,6,7 and what I really get is 30, 45, 96, AE, B4 etc ....

I have a few questions:

* It this code above bad design ?
* Why does it work fine in simulation, but not on the real device ?
* Why does BYTE_TO_SEND_NOW get increased multiple times on the real
device and only once in simulation ?

Please help me. I am a VHDL beginner and don't know where to start
searching.

Thanks !
F.
chack that:
1)you haven't reversed your bits - does your simulation send the same
orderthat the serial port sends (I made this mistake before ) -- I
think it is LSB first
2) do you translate the character sent to ascii first? wow is it
defined -- if you send me your code maybe I can look further - Russell
 
F

FranzH

chack that:
1)you haven't reversed your bits - does your simulation send the same
orderthat the serial port sends (I made this mistake before ) -- I
think it is LSB first

Hm ... I use the PicoBlaze Macro. It receives the input parallel so I
thought I don't need to worry about bit order. In addition, if I just
send bytes, then it works normally. Only if I put it together in the
way I posted, then things start to get strange. I am sure the sender
part of PicoBlaze should work fine. There must be something I am
missing in the interaction of the two processes that I posted.

2) do you translate the character sent to ascii first? wow is it
defined

I do not send ASCII, I just send out binary values. They should start
from 0 and get higher each time the bus changes.

Thanks
F.
 
P

Pieter Hulshoff

FranzH said:
SEND: process (write_to_uart, BUSVAL)
begin
if (BUSVAL /= BUFBUS) then
if (tx_half_full = '0' AND SEND_A_BYTE_NOW = '0') then
SEND_A_BYTE_NOW <= '1';
BYTE_TO_SEND_NOW <= BYTE_TO_SEND_NOW + '1';
end if;
BUFBUS <= BUSVAL;
elsif (rising_edge(write_to_uart)) then
SEND_A_BYTE_NOW <= '0';
end if;
end process;

This can never work. You are using a combinatorial process to change the value
of BUFBUS while using that same BUFBUS to check on what to do in the process.
Within the simulator, this will cause a 1 delta cycle time during which your
BYTE_TO_SEND_NOW counter is incremented and SEND_A_BYTE_NOW is set to 1. Now try
to think of what this should look like in hardware...

Kind regards,

Pieter Hulshoff
 
F

FranzH

This can never work. You are using a combinatorial process to change the value
of BUFBUS while using that same BUFBUS to check on what to do in the process.
Within the simulator, this will cause a 1 delta cycle time during which your
BYTE_TO_SEND_NOW counter is incremented and SEND_A_BYTE_NOW is set to 1. Now try
to think of what this should look like in hardware...

Kind regards,

Pieter Hulshoff

Thanks very much Pieter. I am a complete newbie in VHDL. I have great
difficulty to see what can be synthesized and what can not be
synthesized. I also don't know much about what the synthesis tool will
make out of my code. Can you point me to some book or tutorial where I
can learn what VHDL constructs will be synthesizable and what will not
work ? Or is this all a question of experience and I have to learn it
the hard way ? It is very confusing for me that a synthesis tool does
not create an error if it can not synthesize something. I hope this
doesn't sound too stupid :)

F.
 
P

Pieter Hulshoff

FranzH said:
Thanks very much Pieter. I am a complete newbie in VHDL. I have great
difficulty to see what can be synthesized and what can not be
synthesized. I also don't know much about what the synthesis tool will
make out of my code. Can you point me to some book or tutorial where I
can learn what VHDL constructs will be synthesizable and what will not
work ? Or is this all a question of experience and I have to learn it
the hard way ? It is very confusing for me that a synthesis tool does
not create an error if it can not synthesize something. I hope this
doesn't sound too stupid :)

I can't think of a good book on that off the top of my head, but usually it
helps if you just draw a little hardware schematic of what you think you are
designing. If you see a combinatorial loopback anywhere (as you have created
here) you may want to think long and hard about if that's truly what you had in
mind.

Drawing things also helps prevent timing problems due to long paths. As a little
example, consider the schematic and timing implications of the two following
functionally identical processes:

cnt := cnt + 1;
IF cnt = 5 THEN
cnt := 0;
END IF;

cnt <= cnt + 1;
IF cnt = 4 THEN
cnt <= 0;
END IF;

The first process increments first, then uses the incremented result to clear
the counter. The second uses the counter value in the flip-flops to do the
check. The second process will therefore probably function at a higher clock
frequency than the first one.

Regards,

Pieter
 
T

Thomas Stanka

This can never work. You are using a combinatorial process to change the value
of BUFBUS while using that same BUFBUS to check on what to do in the process.
Within the simulator, this will cause a 1 delta cycle time during which your
BYTE_TO_SEND_NOW counter is incremented and SEND_A_BYTE_NOW is set to 1. Now try
to think of what this should look like in hardware...

Actually this is not the problem with this sensibility list (the
sensibility list prevents the 1 delta).
The problem arises due do the usage of a nonstandard clocked process
which can't be exactly synthesised.
A clocked process shall be:
process (clock, Reset) -- no signal else, naming doesn't matter, reset
optional (but recommended)
if reset = <static signal> then
all_registers <= <static value>
elsif rising_edge(clock) then
some_reg <= any_value
if (synch_reset|enable|whatever)....
other_reg <= any_value
end if
.......
end if
end process

Every other clocked process tends to fit in no real hardware.
Your HW can't re-wire your reset during runtime to set a register to a
nonstatic value during asynch reset (unless you do reconfiguration in
some fpgas). And whatever HW your tool generate when accepting the
code above, it won't be reliabel the HW you expected or you see in
simulation. It wouldn't even be the same functionality when changing
the synthesis tool.

bye Thomas
 
P

Pieter Hulshoff

Thomas said:
Actually this is not the problem with this sensibility list (the
sensibility list prevents the 1 delta).

Even with BUSVAL added to the sensitivity list it would not have made a
difference, since the next time the process is called BUFBUS = BUSVAL. Most
synthesis tools would give at most a warning about forgetting BUSVAL in the
sensitivity list here.

Personally I prefer the following code style:

PROCESS
BEGIN
WAIT UNTIL clk = '1';
<code>
IF reset = '1' THEN
<resets>
END IF;
END PROCESS;

Regards,

Pieter
 
F

FranzH

Actually this is not the problem with this sensibility list (the
sensibility list prevents the 1 delta).
The problem arises due do the usage of a nonstandard clocked process
which can't be exactly synthesised.

So I will try to stick to the "standard". I would be very interested
in some book or pdf about all existing "standards". It is very hard
for a beginner to know what is standard and what is not. The VHDL book
I have is great but puts little emphasis on synthesis. Or are there so
few standards that this can't fill a book ?
Every other clocked process tends to fit in no real hardware.
Your HW can't re-wire your reset during runtime to set a register to a
nonstatic value during asynch reset (unless you do reconfiguration in
some fpgas). And whatever HW your tool generate when accepting the
code above, it won't be reliabel the HW you expected or you see in
simulation. It wouldn't even be the same functionality when changing
the synthesis tool.

Thanks very much Thomas, I think I know much better now what I am
allowed to do with regard to my processes. Still for a programmer like
me, it is confusing that something that doesn't work does not create
some kind of error. Of course it is hard for the synthesis tool to
guess what I wanted to model :)

F.
 
F

FranzH

Even with BUSVAL added to the sensitivity list it would not have made a
difference, since the next time the process is called BUFBUS = BUSVAL. Most
synthesis tools would give at most a warning about forgetting BUSVAL in the
sensitivity list here.

Sorry I don't understand. BUSVAL is in the sensitivity list. I had
expected that if BUSVAL changes and is different from the last
value, then my reset path should be entered.

Actually I had the following hardware in mind:

A comparator that compares a register with the current value on the
bus. The output is used as reset condition for the process. In
addition, this reset signal is used to update the register which is
used for BUS comparison.

The statements in the reset path should only be "executed" under the
condition that tx_half_full = '0' AND SEND_A_BYTE_NOW = '0

Well I will try to write this down in a more "standard" way. hope it
won't be too difficult ...

Thanks again
F.
 
P

Pieter Hulshoff

FranzH said:
Sorry I don't understand. BUSVAL is in the sensitivity list. I had
expected that if BUSVAL changes and is different from the last
value, then my reset path should be entered.

My apologies: I meant BUFBUS in stead of BUSVAL. Since BUFBUS is used in the
compare, it should be in the sensitivity list (which is what any synthesizer
should tell you). What you want is clear, and it works fine in the simulator. In
hardware however you have created a combinatorial loop: depending on the value
of BUFBUS compared to BUFVAL, BUFBUS is updated.
Actually I had the following hardware in mind:

A comparator that compares a register with the current value on the
bus. The output is used as reset condition for the process. In
addition, this reset signal is used to update the register which is
used for BUS comparison.

The statements in the reset path should only be "executed" under the
condition that tx_half_full = '0' AND SEND_A_BYTE_NOW = '0

As said: the problem here is that you are describing a combinatorial loop: a
loop within your hardware connections without a flop-flop in between. What is
stopping you from making it a fully synchronous process by the way? Like:
SEND: process is
begin
wait until write_to_uart = '1';
bufbus <= busval;
send_a_byte_now <= '0';
if busval /= bufbus and tx_half_full = '0' and SEND_A_BYTE_NOW = '0' then
send_a_byte_now <= '1';
byte_to_send_now <= byte_to_send_now + '1';
end if;
end process SEND;

Kind regards,

Pieter
 
T

Thomas Stanka

Even with BUSVAL added to the sensitivity list it would not have made a
difference, since the next time the process is called BUFBUS = BUSVAL. Most
synthesis tools would give at most a warning about forgetting BUSVAL in the
sensitivity list here.

As write_to_uart is used as clock (rising_edge) some tools assume a
sequential process. You can't use rising_edge in a combinatorical
process.
Personally I prefer the following code style:
BEGIN
WAIT UNTIL clk = '1'; [..]
END PROCESS;

Which is ok, if you don't like asynchronous resets. I wouldn't use
this style because I fear that some tools didn't come along with this
style. In fact most code requirements are requirements to have a code
that fits to a broad varity of tools. It doesn't help, if XST accepts
your code, if you need to target an Altera device or Xilinx stops Xst
due to any reason.

bye Thomas
 
K

KJ

Personally I prefer the following code style:

PROCESS
BEGIN
WAIT UNTIL clk = '1';
KJ: wait until rising_edge(clk) -- this is probably what you want
<code>
IF reset = '1' THEN
<resets>
END IF;
END PROCESS;

Regards,
The above code though won't work if the user wants an async reset
though since the process will be stopped at the 'wait until...'
statement until the clock starts going so what you have is not really
a replacement for Thomas' code.

KJ
 
T

Thomas Stanka

Thanks very much Thomas, I think I know much better now what I am
allowed to do with regard to my processes. Still for a programmer like
me, it is confusing that something that doesn't work does not create
some kind of error. Of course it is hard for the synthesis tool

In many cases you get a warning. Which sometimes has nothing to say
and sometimes should be a fatal error instead ;). You need to learn to
inspect the warnings to see, which of them are important.
In many cases a tool couldn't know if you know what you do.

There exist a IEEE-standard for synthesised code (AFAIK support most
synthesis tools not the full standard). It is always a good option to
relay on a "conservative" subset of vhdl which could be defined as the
code supported from all major tool vendors. This subset increases each
time a major vendor closes an important gap in its tool.

I think practicing this style (and learning by failure) is one of the
most important skills for a vhdl-designer :).

bye Thomas
 
F

FranzH

As said: the problem here is that you are describing a combinatorial loop: a
loop within your hardware connections without a flop-flop in between. What is
stopping you from making it a fully synchronous process by the way? Like:
SEND: process is
begin
wait until write_to_uart = '1';
bufbus <= busval;
send_a_byte_now <= '0';
if busval /= bufbus and tx_half_full = '0' and SEND_A_BYTE_NOW = '0' then
send_a_byte_now <= '1';
byte_to_send_now <= byte_to_send_now + '1';
end if;
end process SEND;

Thanks for your suggestion. I will try to understand the difference
and try to get this to work.

I have the feeling that I should really keep away from asynchronous
descriptions. It seems to require a lot of experience to predict what
the result is in hardware and how the final circuit behaves (If it
works reliably at all). I will stick to synchronous logic until I get
more into this.

F.
 
F

FranzH

In many cases you get a warning. Which sometimes has nothing to say
and sometimes should be a fatal error instead ;). You need to learn to
inspect the warnings to see, which of them are important.
In many cases a tool couldn't know if you know what you do.

I must admit I probably didn't really scan through the 400 warnings
that I got (I don't even understand 90% of them). It is a bit like the
mails in my spam folder. I roughly scan through them - but maybe
from now on I will have a closer look. Again, as a programmer, I
probably underestimated the criticality of a warning in vhdl or during
synthesis.
I think practicing this style (and learning by failure) is one of the
most important skills for a vhdl-designer :).

Well, I had feared it would be like that ;)

F.
 
P

Pieter Hulshoff

KJ said:
KJ: wait until rising_edge(clk) -- this is probably what you want

Actually, sorry, but no, that is not what I want. Synthesis tools do not
make a difference between the two, but within my simulation I do not wish
the behavior of rising_edge.
The above code though won't work if the user wants an async reset
though since the process will be stopped at the 'wait until...'
statement until the clock starts going so what you have is not really
a replacement for Thomas' code.

That is true, but I am of the school that believes that asynchronous resets
should be avoided unless you know extremely well what you are doing, and as
FranzH already indicated: he does not.

Kind regards,

Pieter Hulshoff
 
P

Pieter Hulshoff

Thomas said:
As write_to_uart is used as clock (rising_edge) some tools assume a
sequential process. You can't use rising_edge in a combinatorical
process.

Actually, I assumed FranzH meant it to be used as a clock; that may have
been an oversight on my part.
Personally I prefer the following code style:
BEGIN
WAIT UNTIL clk = '1'; [..]
END PROCESS;

Which is ok, if you don't like asynchronous resets. I wouldn't use
this style because I fear that some tools didn't come along with this
style. In fact most code requirements are requirements to have a code
that fits to a broad varity of tools. It doesn't help, if XST accepts
your code, if you need to target an Altera device or Xilinx stops Xst
due to any reason.

True, I do not like asynchronous resets, because many people do not
understand how to avoid the dangers that asynchronous resets bring. We have
used this coding style for over 10 years now, and have not encountered any
problems with the regular tools (at least none that I'm aware of).

Kind regards,

Pieter Hulshoff
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top