Process variable setup times and propogations

M

Matt

Guest
Reposting: Sorry for the earlier mess. The Xilinx newsgroup portal
apparently chewed my origional posting!

Greetings folks,

I am having a strange time with some code I recently wrote to implement
a UART - the code seems to be working fine now, but a problem cropped up
that is baffling me. This design is being synthesized in Xilinx ISE 5.1
and implemented into a Spartan-II XD2S50 device. I'm on something of a
learning curve with things right now so please go easy on me! :D

.............
when 10 => -- Stop Bit
BitPos := 11; -- next is holding pattern for breaks
if(FIFOhead = 3) then
FIFOhead := 0; -- wrap around
else
FIFOhead := FIFOhead + 1;
end if;

FIFO(FIFOhead)(8) <= RxD; -- stash the break bit
FIFO(FIFOhead)(7 downto 0) <= RReg; -- stash the received data
.............

The two FIFO array assignment statements at the bottom are the
predominant problem.... The object is to assign the break bit to the 9th
bit of the array of 9-bit words (indexed by the process variable
'FIFOhead'), and then assign the databyte to the lower part. As written
and synthesized, the above writes ONLY the received byte and NOT the
break bit. If the statements are exchanged, the opposite happens. In
short, only the SECOND assignment appears to be executing properly. If a
'dummy' statement is inserted, so the code looks like:

.............
end if;
FIFO(FIFOhead)(7 downto 0) <= RReg; -- DUMMY
FIFO(FIFOhead)(8) <= RxD; -- stash the break bit
FIFO(FIFOhead)(7 downto 0) <= RReg; -- stash the received data
.............

then both assignments work properly. There appears to be some amount of
latency inherent in updating the variable before it can be used as an
index, but why? And what is the proper way to detect or circumvent this
problem? This fix seems to work just fine, but I fear this problem may
explain similarly strange behavior in other sections of code.

If this IS a latency problem, how should I go about detecting these
sort of things in my design to ensure all code is relatively
bulletproof? All of the VHDL texts I have here really only cover
language theory and simulation synthesis, not things like proper timing
and floorplanning of the design into a physical device. What's the best
way to work on filling in my learning gaps in this area? Thanks in
advance for any insight!

-- Matt
 
Matt wrote:

The two FIFO array assignment statements at the bottom are the
predominant problem.... The object is to assign the break bit to the 9th
bit of the array of 9-bit words (indexed by the process variable
'FIFOhead'), and then assign the databyte to the lower part. As written
and synthesized, the above writes ONLY the received byte and NOT the
break bit. If the statements are exchanged, the opposite happens. In
short, only the SECOND assignment appears to be executing properly. If a
'dummy' statement is inserted, so the code looks like:

............
end if;
FIFO(FIFOhead)(7 downto 0) <= RReg; -- DUMMY
FIFO(FIFOhead)(8) <= RxD; -- stash the break bit
FIFO(FIFOhead)(7 downto 0) <= RReg; -- stash the received data
............

then both assignments work properly. There appears to be some amount
of latency inherent in updating the variable before it can be used as an
index, but why?

The change you show should not have made any difference.
Post the complete process. Something else is going on.

Try changing if(FIFOhead = 3) to
if(FIFOhead >= 3)


-- Mike Treseler
 
Mike Treseler wrote:

The change you show should not have made any difference. Post the complete process. Something else is going on.
Thanks for the reply, Mike - here's the whole reciever UART process I'm
currently synth'ing... I started with a basic UART design from freecores.org and
wound up rewriting a bunch of it in order to process things like break
conditions and the like, as well as adding in the small FIFO to help with
handling data flow. As written below, the UART seems to function pretty much
normally when synthesized into the chip. However, beyond the problem I
origionally mentioned (the FIFOhead not seeming to update right away) this UART
also seems to have the quirk of occasionally letting two of the same received
byte slip thru when data is constantly streaming in.

Unfortunatly this system contains two seperate clocks - one which is devided
down to run the UART at standard baud rates, and another which drives the main
chunk of the system which reads the recived bytes from the UART. It seems that
on occasion (and this is verifiable on a logic analyzer) the clocks seem to line
up such that status data is not read correctly, and the UART is somehow being
read twice in quick succession.

Do I need to include a higher-level syncronization method to ensure the two
clocks don't cause issues when inevitably lining up such that one is reading
data controlled by the other, whilst the data is in the middle of a transition?

I've played with a couple possible solutions, but nothing seems to work with
the double-reads. This seems like a nice simple recieving UART, but I'm stumped.
Any ideas?

Regards,
-- Matt

.................
entity RxUnit is
port (
Clk : in Std_Logic; -- system clock signal
Reset : in Std_Logic; -- Reset input
Enable : in Std_Logic; -- Enable input
ReadA : in Std_logic; -- Async Read Received Byte
RxD : in Std_Logic; -- RS-232 data input
RxAv : out Std_Logic; -- Byte available
DataO : out Std_Logic_Vector(7 downto 0); -- Byte received
Break : out Std_Logic; -- Break Detected
Debug : out Std_Logic); -- debug
end entity;

architecture Behaviour of RxUnit is
signal RReg : Std_Logic_Vector(7 downto 0); -- receive register
signal ReadS : Std_Logic; -- Synchronised load signal

component synchroniser is
port (
C1 : in Std_Logic; -- Asynchronous signal
C : in Std_Logic; -- Clock
O : out Std_logic);-- Synchronised signal
end component;

-- the FIFO
type FIFOarraytype is array (integer range 0 to 4) of std_logic_vector(8
downto 0);
signal FIFO:FIFOarraytype;

begin

-- Synchronise Read on Clk
SyncLoad : Synchroniser port map (ReadA, Clk, ReadS);
--Busy <= LoadS or TBufL;

-- Rx Process
RxProc : process(Clk,Reset,Enable,RxD,ReadS)
variable BitPos : INTEGER range 0 to 11; -- Position of the bit in the frame
variable SampleCnt : INTEGER range 0 to 3; -- Count from 0 to 3 in each bit
variable FIFOhead, FIFOtail : INTEGER range 0 to 4; -- FIFO head and tail

begin
if Reset = '0' then -- Reset
--RRegL <= '0';
--RRegLcache <= '0';
BitPos := 0;
FIFOhead := 0;
FIFOtail := 0;
elsif Rising_Edge(Clk) then

DataO <= FIFO(FIFOtail)(7 downto 0); -- always output whatever is on the FIFO tail
Debug <= FIFO(FIFOtail)(0); -- a signal to the outside world for debugging on
logic analyzer
Break <= FIFO(FIFOtail)(8);

if (ReadS = '1' and FIFOhead /= FIFOtail) then -- advance FIFO on read edge
if(FIFOtail = 3) then
FIFOtail := 0;
else
FIFOtail := FIFOtail + 1;
end if;
else
Debug <= '0';
end if;

if(FIFOhead /= FIFOtail) then -- there is stuff in the FIFO
RxAv <= '1'; -- Indicate there is data avaliable to be read
else
RxAv <= '0';
end if;

if Enable = '1' then
case BitPos is
when 0 => -- idle
if RxD = '0' then -- Start Bit
SampleCnt := 0;
BitPos := 1;
end if;
when 10 => -- Stop Bit
BitPos := 11; -- next is holding pattern for breaks
if(FIFOhead = 3) then
FIFOhead := 0; -- wrap around
else
FIFOhead := FIFOhead + 1;
end if;
FIFO(FIFOhead)(7 downto 0) <= RReg; -- DUMMY 'WAIT'
FIFO(FIFOhead)(8) <= RxD; -- stash the break bit
FIFO(FIFOhead)(7 downto 0) <= RReg; -- stash the recieved data

when 11 => -- Holding pattern for break release (so only one break is
recieved)
if(RxD = '1') then
BitPos := 0;
end if;
when others =>
if SampleCnt = 1 then -- Sample RxD on 1
RReg(BitPos-2) <= RxD; -- Deserialisation
end if;
if SampleCnt = 3 then -- Increment BitPos on 3
BitPos := BitPos + 1;
end if;
end case;
if SampleCnt = 3 then
SampleCnt := 0;
else
sampleCnt := SampleCnt + 1;
end if;

end if;
end if;
end process;
end Behaviour;
..............
 
If, as you say, one of the clocks is derived from the other, then they
have a fixed delay or phase relationship, and you should not have a problem.
If, however, these two clocks are incoherent, you have a real tricky
problem on your hands, and ignoring that will just get you deeper and
deeper into trouble.
Keep the design synchronous. Double-synchronize to reduce metastability
problems. Flip-flops are almost free these days.

Peter Alfke, Xilinx
============
Matt wrote:
Mike Treseler wrote:

The change you show should not have made any difference. Post the complete process. Something else is going on.

Thanks for the reply, Mike - here's the whole reciever UART process I'm
currently synth'ing... I started with a basic UART design from freecores.org and
wound up rewriting a bunch of it in order to process things like break
conditions and the like, as well as adding in the small FIFO to help with
handling data flow. As written below, the UART seems to function pretty much
normally when synthesized into the chip. However, beyond the problem I
origionally mentioned (the FIFOhead not seeming to update right away) this UART
also seems to have the quirk of occasionally letting two of the same received
byte slip thru when data is constantly streaming in.

Unfortunatly this system contains two seperate clocks - one which is devided
down to run the UART at standard baud rates, and another which drives the main
chunk of the system which reads the recived bytes from the UART. It seems that
on occasion (and this is verifiable on a logic analyzer) the clocks seem to line
up such that status data is not read correctly, and the UART is somehow being
read twice in quick succession.

Do I need to include a higher-level syncronization method to ensure the two
clocks don't cause issues when inevitably lining up such that one is reading
data controlled by the other, whilst the data is in the middle of a transition?

I've played with a couple possible solutions, but nothing seems to work with
the double-reads. This seems like a nice simple recieving UART, but I'm stumped.
Any ideas?

Regards,
-- Matt

................
entity RxUnit is
port (
Clk : in Std_Logic; -- system clock signal
Reset : in Std_Logic; -- Reset input
Enable : in Std_Logic; -- Enable input
ReadA : in Std_logic; -- Async Read Received Byte
RxD : in Std_Logic; -- RS-232 data input
RxAv : out Std_Logic; -- Byte available
DataO : out Std_Logic_Vector(7 downto 0); -- Byte received
Break : out Std_Logic; -- Break Detected
Debug : out Std_Logic); -- debug
end entity;

architecture Behaviour of RxUnit is
signal RReg : Std_Logic_Vector(7 downto 0); -- receive register
signal ReadS : Std_Logic; -- Synchronised load signal

component synchroniser is
port (
C1 : in Std_Logic; -- Asynchronous signal
C : in Std_Logic; -- Clock
O : out Std_logic);-- Synchronised signal
end component;

-- the FIFO
type FIFOarraytype is array (integer range 0 to 4) of std_logic_vector(8
downto 0);
signal FIFO:FIFOarraytype;

begin

-- Synchronise Read on Clk
SyncLoad : Synchroniser port map (ReadA, Clk, ReadS);
--Busy <= LoadS or TBufL;

-- Rx Process
RxProc : process(Clk,Reset,Enable,RxD,ReadS)
variable BitPos : INTEGER range 0 to 11; -- Position of the bit in the frame
variable SampleCnt : INTEGER range 0 to 3; -- Count from 0 to 3 in each bit
variable FIFOhead, FIFOtail : INTEGER range 0 to 4; -- FIFO head and tail

begin
if Reset = '0' then -- Reset
--RRegL <= '0';
--RRegLcache <= '0';
BitPos := 0;
FIFOhead := 0;
FIFOtail := 0;
elsif Rising_Edge(Clk) then

DataO <= FIFO(FIFOtail)(7 downto 0); -- always output whatever is on the FIFO tail
Debug <= FIFO(FIFOtail)(0); -- a signal to the outside world for debugging on
logic analyzer
Break <= FIFO(FIFOtail)(8);

if (ReadS = '1' and FIFOhead /= FIFOtail) then -- advance FIFO on read edge
if(FIFOtail = 3) then
FIFOtail := 0;
else
FIFOtail := FIFOtail + 1;
end if;
else
Debug <= '0';
end if;

if(FIFOhead /= FIFOtail) then -- there is stuff in the FIFO
RxAv <= '1'; -- Indicate there is data avaliable to be read
else
RxAv <= '0';
end if;

if Enable = '1' then
case BitPos is
when 0 => -- idle
if RxD = '0' then -- Start Bit
SampleCnt := 0;
BitPos := 1;
end if;
when 10 => -- Stop Bit
BitPos := 11; -- next is holding pattern for breaks
if(FIFOhead = 3) then
FIFOhead := 0; -- wrap around
else
FIFOhead := FIFOhead + 1;
end if;
FIFO(FIFOhead)(7 downto 0) <= RReg; -- DUMMY 'WAIT'
FIFO(FIFOhead)(8) <= RxD; -- stash the break bit
FIFO(FIFOhead)(7 downto 0) <= RReg; -- stash the recieved data

when 11 => -- Holding pattern for break release (so only one break is
recieved)
if(RxD = '1') then
BitPos := 0;
end if;
when others =
if SampleCnt = 1 then -- Sample RxD on 1
RReg(BitPos-2) <= RxD; -- Deserialisation
end if;
if SampleCnt = 3 then -- Increment BitPos on 3
BitPos := BitPos + 1;
end if;
end case;
if SampleCnt = 3 then
SampleCnt := 0;
else
sampleCnt := SampleCnt + 1;
end if;

end if;
end if;
end process;
end Behaviour;
.............
 
On Wed, 02 Jul 2003 13:38:32 -0700, Mike Treseler
<mike.treseler@flukenetworks.com> wrote:

Matt wrote:

The two FIFO array assignment statements at the bottom are the
predominant problem.... The object is to assign the break bit to the 9th
bit of the array of 9-bit words
............
end if;
FIFO(FIFOhead)(7 downto 0) <= RReg; -- DUMMY
FIFO(FIFOhead)(8) <= RxD; -- stash the break bit
FIFO(FIFOhead)(7 downto 0) <= RReg; -- stash the received data
............

then both assignments work properly. There appears to be some amount
of latency inherent in updating the variable before it can be used as an
index, but why?


The change you show should not have made any difference.
Post the complete process. Something else is going on.

Try changing if(FIFOhead = 3) to
if(FIFOhead >= 3)
I agree, something else may be going on.

Be aware that if :
a) this is all within a single process, and
b) Fifohead is a signal not a variable, the assignment of the new value
to Fifohead is postponed to the end of the process (or explicit Wait)
thus Fifohead will have the old value at the point of the assignments to
Fifio(Fifohead). This MUST be the case to avoid race conditions within
clocked processes, as a little thought will show.

FIFO(FIFOhead)(7 downto 0) <= RReg; -- DUMMY
FIFO(FIFOhead)(8) <= RxD; -- stash the break bit
Another potential problem can arise, where the fields within a
std_logic_vector are addressed by variables and must synthesise to an
assignment to the whole vector.
For that reason, an assignment to the whole vector is to be preferred.

FIFO(FIFOhead)RxD & RReg; -- DUMMY
However, since you use numeric constants 8, 7 downto 0 here, I don't
THINK this is the problem, unless it is a tools bug.

- Brian
 
Matt wrote:

seeming to update right away) this UART also seems to have the quirk of
occasionally letting two of the same received byte slip thru when data
is constantly streaming in.
Quirks like this smell like a synchronization problem.
Consider using the synchronous template for all synth code.

Unfortunatly this system contains two seperate clocks - one which is
devided down to run the UART at standard baud rates, and another which
drives the main chunk of the system which reads the recived bytes from
the UART. It seems that on occasion (and this is verifiable on a logic
analyzer) the clocks seem to line up such that status data is not read
correctly, and the UART is somehow being read twice in quick succession.
You have identified and verified a synchronization problem.


Do I need to include a higher-level syncronization method to ensure
the two clocks don't cause issues when inevitably lining up such that
one is reading data controlled by the other, whilst the data is in the
middle of a transition?
No. Use only only the faster clock as a clock.
Inputs including former clocks are all synched
with two dflops and become inputs that
never appear in a sensitivity list.

RxProc : process(Clk,Reset,Enable,RxD,ReadS)
Change to

RxProc : process(Clk,Reset)

and watch the other inputs events synchronously.


-- Mike Treseler
 

Welcome to EDABoard.com

Sponsor

Back
Top