Author Topic: VHDL assigning to and from array gives "XXXX"  (Read 3171 times)

0 Members and 1 Guest are viewing this topic.

Offline ivan747Topic starter

  • Super Contributor
  • ***
  • Posts: 2046
  • Country: us
VHDL assigning to and from array gives "XXXX"
« on: September 27, 2023, 11:20:46 pm »
Hi everyone,

I am writing a small dual port memory. If both the read address rdptr and write address wrptr are set to the same location, the data output is "XXXXXXXXX". Why is this?
I suspect this happens every time I try to assign to and from the same array location at the same time. I am simulating this on ModelSim 10.5 if that matters.

Code: [Select]
entity fifo is
port(
      DataIn: in  std_logic_vector(8 downto 0);
      DataOut: out std_logic_vector(8 downto 0);
      rden, wren: in  std_logic
      [...]
);
end entity fifo;

architecture rtl of fifo is
type fifo_array is array(7 downto 0) of std_logic_vector(8 downto 0); 
signal fifo:  fifo_array;
[...]

begin

wrProc: process(wrptr,wren) is
begin
if(wren = '1') then
fifo(wrptr) <= DataIn;
end if;
end process wrProc;

rdProc: process(rdptr,rden) is
begin
if(rden = '1') then
DataOut <= fifo(rdptr);
end if;
end process rdProc;
       [...]
end rtl;




The fix I came up with is adding an if statement to catch this condition.

Code: [Select]
wrProc: process(wrptr,wren) is
begin
if(wren = '1') then
fifo(to_integer(wrptr)) <= DataIn;
end if;
end process wrProc;

rdProc: process(rdptr,rden) is
begin
if(rden = '1') then
if(rdptr = wrptr) then    -- We need this to not
DataOut <= DataIn; -- get XXXX on DataOut
else
DataOut <= fifo(to_integer(rdptr));
end if;
end if;
end process rdProc;

[...]


This works, but it doesn't feel very elegant to me. I'm having the feeling this will add adding an implicit multiplexer and comparator that should be unnecessary.

Any insights? I'm curious about why this is happening. It looks like one of those traps for young players that Dave always mentions.
« Last Edit: September 27, 2023, 11:31:08 pm by ivan747 »
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 15173
  • Country: fr
Re: VHDL assigning to and from array gives "XXXX"
« Reply #1 on: September 28, 2023, 12:44:00 am »
This comes from the fact your two processes are clockless. Which is definitely not a very good idea here.
 

Offline ivan747Topic starter

  • Super Contributor
  • ***
  • Posts: 2046
  • Country: us
Re: VHDL assigning to and from array gives "XXXX"
« Reply #2 on: September 28, 2023, 01:32:58 am »
This comes from the fact your two processes are clockless. Which is definitely not a very good idea here.

Thanks! I just noticed that if I add DataIn to the sensitivity list of wrProc and add fifo to the sensitivity list of rdProc, some of the weird behavior goes away (it's no longer latching on the last value of DataIn or fifo respectively). But adding a huge piece of memory to a sensitivity list sounds negligent.

I moved over to conditional assignments and it's much better now:

Code: [Select]
fifo(to_integer(wrptr)) <= DataIn when wren = '1';

DataOut    <= fifo(to_integer(rdptr)) when rden = '1'; else
"ZZZZZZZZZ" when rden = '0' else
"UUUUUUUUU";


There is still an implied latch when writing but that's the point of memory, I guess.  :-+

I also had a bug in a section of the code I haven't posted here, that dealt with addresses. In one of the process statements I was incrementing the write address using the increment read address signal. I still don't know why the data output would be "XXXXXXXXX" though, I can't think of a way that would be possible. Who knows, I'm kind of tired and maybe missed a double assignment. That's my only explanation.
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 15173
  • Country: fr
Re: VHDL assigning to and from array gives "XXXX"
« Reply #3 on: September 28, 2023, 06:59:48 am »
Yes, but I'd still recommend implementing clocked memories for anything used outside of pure simulation.
You have implemented a combinatorial dual-port memory, which will give you poor performance (low Fmax) and a lot of potential timing issues in real-life implementations. Don't do that, or do that only if there's an absolutely good reason for doing so.
 

Online AndyC_772

  • Super Contributor
  • ***
  • Posts: 4268
  • Country: gb
  • Professional design engineer
    • Cawte Engineering | Reliable Electronics
Re: VHDL assigning to and from array gives "XXXX"
« Reply #4 on: September 28, 2023, 07:38:44 am »
adding a huge piece of memory to a sensitivity list sounds negligent.

It's completely normal to have a process be sensitive to every signal that's referenced within it. VHDL-2008 allows 'process (all)' as a shortcut.

I'll echo what others have said, though... you *really* need a clock for this to ever work in practice. As a bonus, it might even then be able to use the hard RAM blocks that most FPGAs include, rather than soaking up a huge amount of expensive, asynchronous logic.

Offline ivan747Topic starter

  • Super Contributor
  • ***
  • Posts: 2046
  • Country: us
Re: VHDL assigning to and from array gives "XXXX"
« Reply #5 on: September 28, 2023, 03:09:21 pm »
Thanks for the feedback! I went back to having a clock for the actual register access and it's everything is closer to what it should be.

There are other sections of the component that I'm having problems with but that's because the spec isn't very specific for some timings, and I'm having to guess from the test bench. But don't worry about that, it's my homework.

Something that caught my attention is that I still have to do the conditional assignment for some reason:
It was timing
Code: [Select]
rwProc: process(clk,rdptr, wrptr, wren, full) is
begin
if(rising_edge(clk)) then
if(wren = '1') then
fifo(to_integer(wrptr)) <= DataIn;
end if;

if(rdptr = wrptr) then
   dmuxout <= DataIn;
else
   dmuxout <= fifo(to_integer(rdptr));
end if;
-- If I don't add this condition, dmuxout is assigned "UUUU" when rdptr=wrptr
end if;
end process rwProc;

But overall less issues than before.


It was timing, I was writing to one address and reading from the next one which is undefined yet.

I'll try to break these into two separate processes (read and write) and see what happens.
« Last Edit: September 28, 2023, 03:20:07 pm by ivan747 »
 

Offline ivan747Topic starter

  • Super Contributor
  • ***
  • Posts: 2046
  • Country: us
Re: VHDL assigning to and from array gives "XXXX"
« Reply #6 on: September 28, 2023, 03:36:26 pm »
Ok, I fixed the timings and the original problem came back. But, I noticed that I only get "XXXXXXXXXX" when I assign (maybe latch?) to and from the same memory pointer on the same clock cycle edge. Even if I put reading and writing on separate processes.

The problem is when I'm reading with a clock I am creating a latch implicitly, so if read and write to the same location is done on the same edge the read is delayed by one clock cycle, and the test bench tests the reads after 3/4 of a cycle. I think the "XXXXXXXXX" output happens because I was assigning "UUUUUUUUU" to the output signal because of the delay.

Another way of looking at is is that signal assignments happen after the process block is done. Because the process block is not done, I am reading from the previous value of the fifo, not the value I just assigned when writing.

So I fixed it by writing on the rising edge of the clock and reading on the falling edge of the clock. The other solution is to have asynchronous reads.




By the way do FPGAs implement all the states of std_logic? Sounds a little wasteful but at the same time they also have some tri-state circuits.
« Last Edit: September 28, 2023, 04:40:41 pm by ivan747 »
 

Online AndyC_772

  • Super Contributor
  • ***
  • Posts: 4268
  • Country: gb
  • Professional design engineer
    • Cawte Engineering | Reliable Electronics
Re: VHDL assigning to and from array gives "XXXX"
« Reply #7 on: September 28, 2023, 09:11:39 pm »
It's important to recognise that the behaviour of VHDL is well defined.

Within a clocked process, the value of every signal is effectively frozen immediately before the instant the active clock edge occurs. So, for example, the classic 'how not to swap two variables' example:

Code: [Select]
if rising_edge (clk) then
  b <= a;
  a <= b;
end if

...actually DOES work, because the two assignments aren't executed one after the other like they would be if the code were being executed on a CPU. They don't both end up equal to the original value of 'a' like you might expect.

Instead, what the code means is: at the instant the clock arrives, 'b' takes the value that 'a' had immediately before the clock, and 'a' takes the value that 'b' had immediately before the clock.

With a DPRAM, if you read and write the same address on the same edge, you'd normally expect the output to equal the old contents of the address being accessed, because at the instant the clock arrives the new value hasn't been latched into memory yet.

By explicitly including a condition that the output should equal the new input if both the read and write pointers are equal, you're effectively bypassing the memory entirely - and that's completely OK if that's how you want your logic to work. Some FPGAs actually include this 'shoot through' or 'bypass' feature when you instantiate their internal RAM blocks.
 
The following users thanked this post: ivan747

Offline ivan747Topic starter

  • Super Contributor
  • ***
  • Posts: 2046
  • Country: us
Re: VHDL assigning to and from array gives "XXXX"
« Reply #8 on: September 29, 2023, 01:55:21 pm »

With a DPRAM, if you read and write the same address on the same edge, you'd normally expect the output to equal the old contents of the address being accessed, because at the instant the clock arrives the new value hasn't been latched into memory yet.

By explicitly including a condition that the output should equal the new input if both the read and write pointers are equal, you're effectively bypassing the memory entirely - and that's completely OK if that's how you want your logic to work. Some FPGAs actually include this 'shoot through' or 'bypass' feature when you instantiate their internal RAM blocks.


This is my case, the test bench that validates my work is expecting the output to equal the input within the same clock cycle.


Thank you very much for the explanation. I hadn't seen that mentioned in the book.  :-+ Much appreciated!
 

Offline asmi

  • Super Contributor
  • ***
  • Posts: 2777
  • Country: ca
Re: VHDL assigning to and from array gives "XXXX"
« Reply #9 on: September 29, 2023, 06:29:35 pm »
In Xilinx 7 series devices BlockRAM can be configured in WRITE_FIRST, READ_FIRST or NO_CHANGE write mode on a per-port basis. WRITE_FIRST is the default mode, in which the written value shows up at the output ("write before the read"), READ_FIRST outputs value that was there before the write ("read before the write"), NO_CHANGE keeps whatever value there was as a result of a previous read operation.
However, there is a warning:
Quote
Conflict Avoidance
The 7 series FPGAs block RAM is a true dual-port RAM where both ports can access any memory location at any time. When accessing the same memory location from both ports, you must, however, observe certain restrictions. There are two fundamentally different situations: The two ports either have a common clock (synchronous clocking), or the clock frequency and phase is different for the two ports (asynchronous clocking).

Asynchronous Clocking
Asynchronous clocking is the more general case, where the active edges of both clocks do not occur simultaneously:
  • There are no timing restrictions when both ports perform a read operation.
  • When one port performs a write operation, the other port must not read or write access the same memory location. Therefore, the READ_FIRST mode should be avoided in true asynchronous applications, because there is no guarantee that the old data will be read (in both TDP and SDP modes). The WRITE_FIRST mode is the recommended mode when asynchronous clocks might cause simultaneous read/write operations on the same port address. The simulation model produces an error if this condition is violated. If this restriction is ignored, a read or write operation produces unpredictable results. There is, however, no risk of physical damage to the device. If a read and write operation is performed, then the write stores valid data at the write location.

Synchronous Clocking
Synchronous clocking is the special case, where the active edges of both port clocks occur
simultaneously:
  • Synchronous clocking is defined as both clock input pins being driven by the same clock.
  • There are no timing restrictions when both ports perform a read operation.
  • When one port performs a write operation, the other port must not write into the same location, unless both ports write identical data.
  • When one port performs a write operation, the write operation succeeds; the other port can reliably read data from the same location if the write port is in READ_FIRST mode. DATA_OUT on both ports then reflects the previously stored data. If the write port is in either WRITE_FIRST or in NO_CHANGE mode, then the DATA_OUT on the read port would become invalid (unreliable). The mode setting of the read-port does not affect this operation.


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf