bidirectional bus

O

Olaf Petzold

Guest
Hi,

what's wrong with the code below? I've got on data bus and my_data a
'X' Vector (Forcing Unknown) on reading (both register contents work
against). It seems to be a principle problem of me. What happend here?
The goal is a sequential read back of data written before. Attached a
screen shot (hopefully be distributed on news server).

Thanks
Olaf

---8<---
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity bus_test is
end entity bus_test;

architecture behaviorial of bus_test is
signal done : boolean := false;
signal clk, reset : std_logic := '0';
signal address : unsigned(7 downto 0);
signal data : std_logic_vector(7 downto 0);
signal my_data : std_logic_vector(data'range);
signal rd, wr : std_logic;
constant MY_ADDRESS1 : unsigned(address'range) := b"1000_0000";
constant MY_ADDRESS2 : unsigned(address'range) := b"1001_0000";
constant TST_DATA1 : std_logic_vector(data'range)
:= b"10101010";
constant TST_DATA2 : std_logic_vector(data'range)
:= b"01010101";
begin

clk_proc : process is
constant PERIOD : time := 10 ns;
begin
clk <= '0';
if done then wait; end if;
wait for PERIOD/2;
clk <= '1';
wait for PERIOD/2;
end process clk_proc;

rst : reset <= '1', '0' after 15 ns;

register_set : block is
signal m_register1 : std_logic_vector(data'range);
signal m_register2 : std_logic_vector(data'range);
begin
rdwr_proc : process (clk, reset) is
begin
if (reset = '1') then
data <= (others => 'Z');
elsif rising_edge(clk) then
if (wr = '1') and (rd = '0') then
case address is
when MY_ADDRESS1 => m_register1 <= data;
when MY_ADDRESS2 => m_register2 <= data;
when others => null;
end case;
elsif (wr = '0') and (rd = '1') then
case address is
when MY_ADDRESS1 => data <= m_register1;
when MY_ADDRESS2 => data <= m_register2;
when others => null;
end case;
else
data <= (others => 'Z');
end if;
end if;
end process rdwr_proc;
end block register_set;

TB : process is
------------------------------------------
procedure tic is
begin
wait until rising_edge(clk);
end procedure tic;
------------------------------------------
procedure do_wr (
constant addr : in unsigned;
constant dat : in std_logic_vector) is
begin
wr <= '1';
address <= addr;
data <= dat;
tic;
wr <= '0';
end procedure do_wr;
------------------------------------------
procedure do_rd (
constant addr : in unsigned;
signal dat : out std_logic_vector) is
begin
rd <= '1';
address <= addr;
tic;
dat <= data;
rd <= '0';
end procedure do_rd;
------------------------------------------
begin
my_data <= (others => '0');
rd <= '0';
wr <= '0';
address <= (others => '0');
data <= (others => '0');
wait until (reset = '0');
tic; tic;

do_wr(MY_ADDRESS1, TST_DATA1);
do_wr(MY_ADDRESS2, TST_DATA2);
tic;

do_rd(MY_ADDRESS1, my_data);
do_rd(MY_ADDRESS2, my_data);
tic;
assert (my_data = TST_DATA1)
report "* missmatch 1 *" severity error;
assert (my_data = TST_DATA2)
report "* missmatch 2 *" severity error;
tic;
done <= true;

end process TB;
end architecture behaviorial;
--->8---
 
Hi Olaf!

Guess do_wr should release the bus when the write operation has finished:

procedure do_wr (
constant addr : in unsigned;
constant dat : in std_logic_vector) is
begin
wr <= '1';
address <= addr;
data <= dat;
tic;
wr <= '0';
data <= (others => 'Z');
end procedure do_wr;
Also consider to initialize data to Z in the TB process. But that's a
cosmetic issue.

Cheers

Arnim
 
Arnim Laeuger schrieb:
Hi Olaf!

Guess do_wr should release the bus when the write operation has finished:

procedure do_wr (
constant addr : in unsigned;
constant dat : in std_logic_vector) is
begin
wr <= '1';
address <= addr;
data <= dat;
tic;
wr <= '0';

data <= (others => 'Z');

end procedure do_wr;


Also consider to initialize data to Z in the TB process. But that's a
cosmetic issue.
thanks, I did as you mentioned, the wr proc is terminated by setting
the data bus to HighZ. Unfortunally the 2nd read is missing in my data.

Thanks
Olaf

.....
------------------------------------------
procedure do_wr (
constant addr : in unsigned;
constant dat : in std_logic_vector) is
begin
wr <= '1';
address <= addr;
data <= dat;
tic;
wr <= '0';
data <= (others => 'Z');
end procedure do_wr;
------------------------------------------
procedure do_rd (
constant addr : in unsigned;
signal dat : out std_logic_vector) is
begin
rd <= '1';
address <= addr;
tic;
dat <= data;
rd <= '0';
--data <= (others => 'Z'); -- same problem
end procedure do_rd;
------------------------------------------
begin
my_data <= (others => '0');
rd <= '0';
wr <= '0';
address <= (others => '0');
data <= (others => 'Z');
wait until (reset = '0');
tic; tic;
.....
 
thanks, I did as you mentioned, the wr proc is terminated by setting the
data bus to HighZ. Unfortunally the 2nd read is missing in my data.

procedure do_rd (
constant addr : in unsigned;
signal dat : out std_logic_vector) is
begin
rd <= '1';
address <= addr;
tic;
dat <= data;
rd <= '0';
--data <= (others => 'Z'); -- same problem
end procedure do_rd;
Procedure do_rd reads "data" on the rising clock edge when "data" still
contains the old value. The new value is scheduled by rdwr_proc during
the same delta cycle but this is not visible until simulation progresses
to the next delta cycle. That's why the expected value is visible on
"data" while "my_data" is delayed by one clock cycle.

In other words, do_rd expects that the registers can be read
asynchronously ("data" is valid during the same clock cycle) and saves
the value with the next rising clock edge. This doesn't work because the
registers are read synchronously ("data" is valid during the next clock
cycle).

For your behavioral test bench code, you could save "data" with a small
delay after the rising clock edge. Just long enough to skip all delta
cycles and the simulator increases time.

procedure do_rd (
constant addr : in unsigned;
signal dat : out std_logic_vector) is
begin
rd <= '1';
address <= addr;
tic;
wait for 1 ps; -- anything > 0 fs
dat <= data;
rd <= '0';
--data <= (others => 'Z'); -- same problem
end procedure do_rd;
The synchronous way is:

procedure do_rd (
constant addr : in unsigned;
signal dat : out std_logic_vector) is
begin
rd <= '1';
address <= addr;
tic;
tic;
dat <= data;
rd <= '0';
--data <= (others => 'Z'); -- same problem
end procedure do_rd;

Cheers

Arnim
 
Thank you for your explanations. I will test it tomorrow.

For your behavioral test bench code, you could save "data" with a small
delay after the rising clock edge. Just long enough to skip all delta
cycles and the simulator increases time.

procedure do_rd (
constant addr : in unsigned;
signal dat : out std_logic_vector) is
begin
rd <= '1';
address <= addr;
tic;
wait for 1 ps; -- anything > 0 fs
and how can I solve it for synthesis tools, like the xilinx tools?


Thanks
Olaf
 

Welcome to EDABoard.com

Sponsor

Back
Top