I would like to probe a tristate signal using chipscope.
According to this answer record, it can't be done, so this is what I started with (only relevant code included):
-- Tristate signals
FPGA_SMB0_SDA <= sysmon_iic_data;
FPGA_SMB0_SCL <= sysmon_iic_clk;
-- Output signals
DEBUG_LED0 <= '0';
DEBUG_LED1 <= '0';
Which builds fine with no errors.
Attempt 1:
This is my first attempt at generating a debug signal for probing that's just an out:
-- Tristate signals
FPGA_SMB0_SDA <= sysmon_iic_data;
FPGA_SMB0_SCL <= sysmon_iic_clk;
-- Generating new output signals using tristate (tristate signals are either '0' or 'X' for IIC)
sysmon_iic_data_debug <= '0' when (sysmon_iic_data = '0') else '1';
sysmon_iic_clk_debug <= '0' when (sysmon_iic_clk = '0') else '1';
-- connecting debug outs to debug leds (so that the debug signals aren't optimized out)
DEBUG_LED0 <= sysmon_iic_data_debug;
DEBUG_LED1 <= sysmon_iic_clk_debug;
The above code passes synthesis but NGDbuild gives the following errors:
ERROR:ConstraintSystem:59 - Constraint <IOSTANDARD = LVCMOS25 ;>
[frm121401u1r1.ucf(333)]: NET "FPGA_SMB0_SDA"
not found. Please verify that:
1. The specified design element actually exists in the original design.
2. The specified object is spelled correctly in the constraint source file.
The above is repeated 8 times, twice for each net.
Attempt 2:
Second thing I tried was using a process:
FPGA_SMB0_SDA <= sysmon_iic_data;
FPGA_SMB0_SCL <= sysmon_iic_clk;
gen_sysmon_debug : process(refclk_10m,refclk_10m_rst)
begin
if (refclk_10m_rst = '1') then
sysmon_iic_data_debug <= '0';
sysmon_iic_clk_debug <= '0';
elsif (rising_edge(refclk_10m)) then
if (sysmon_iic_clk = '0') then
sysmon_iic_clk_debug <= '0';
else
sysmon_iic_clk_debug <= '1';
end if;
if (sysmon_iic_data = '0') then
sysmon_iic_data_debug <= '0';
else
sysmon_iic_data_debug <= '1';
end if;
end if;
end process;
DEBUG_LED0 <= sysmon_iic_data_debug;
DEBUG_LED1 <= sysmon_iic_clk_debug;
That gave me this NGDbuild error:
ERROR:NgdBuild:924 - bidirect pad net 'FPGA_SMB0_SDA' is driving non-buffer primitives:
pin D on block sysmon_iic_data with type FDC,
Two of those, one for SDA and one for SCL
More Info:
This is what's in my UCF:
NET "DEBUG_LED0" LOC = "AK33" | IOSTANDARD = LVCMOS25 ;
NET "DEBUG_LED1" LOC = "AK34" | IOSTANDARD = LVCMOS25 ;
...
NET "FPGA_SMB0_SCL" LOC = "G13" | IOSTANDARD = LVCMOS25 ;
NET "FPGA_SMB0_SDA" LOC = "H13" | IOSTANDARD = LVCMOS25 ;
And top-level vhdl net definitions:
DEBUG_LED0 : out std_logic;
DEBUG_LED1 : out std_logic;
FPGA_SMB0_SCL : inout std_logic;
FPGA_SMB0_SDA : inout std_logic;
and in uBlaze .mhs:
PORT xps_iic_1_Sda_pin = xps_iic_1_Sda, DIR = IO, BUFFER_TYPE = NONE
PORT xps_iic_1_Scl_pin = xps_iic_1_Scl, DIR = IO, BUFFER_TYPE = NONE
I'm completely at a loss why I'm getting these NGDbuild errors, anyone have any ideas?
Your net is probably getting renamed now you've connected another signal to it :(
Take the constraints out, let it build.
Load the NCD file into FPGA editor and see what the net ends up being called, and use that in your UCF.
Or instantiate all the IOBs yourself in the top level VHDL file, then you know the nae of the net between the IOB "pin" and the real pin won't change and you can constrain that net.
Related
This question already has an answer here:
VHDL: Unable to read output status
(1 answer)
Closed 4 years ago.
library IEEE;
use IEEE.std_logic_1164.all;
entity doorlock is
port( reset : in std_logic;
enable : in std_logic;
password : in std_logic_vector (7 downto 0);
door : out std_logic_vector (7 downto 0);
lock : out std_logic;
alarm : out std_logic;
turnoff : out std_logic);
end doorlock;
--password is 10(decimal no.) which is 00010000(binary no.)
architecture DDL of doorlock is
signal err_count : integer range 0 to 5 := 0;
begin
lock <= '0' when (reset = '0');
alarm <= '0' when (reset = '0');
turnoff <= '0' when (reset = '0');
door <= "00000000" when (reset = '0');
lock <= '0' when (enable <= '0');
process(password)
begin
if (password = "-------1") then
door <= "00000000";
elsif (password = "------10") then
door <= "00000001";
elsif (password = "-----100") then
door <= "00000011";
elsif (password = "----1000") then
door <= "00000111";
elsif (password = "---00000") then
door <= "00001111";
elsif (password = "--110000") then
door <= "00011111";
elsif (password = "-1010000") then
door <= "00111111";
elsif (password = "10010000") then
door <= "01111111";
elsif (password = "00010000") then
door <= "11111111";
end if;
err_count <= err_count + 1;
end process;
alarm <= '1' when (err_count = 3);
turnoff <= '1' when (err_count = 5);
lock <= '1' when (door = "11111111" and turnoff = '0' and alarm = '0');
end DDL;
I made this code for my homework making digital door lock.
And this line have error as I compile it.
lock <= '1' when (door = "11111111" and turnoff = '0' and alarm = '0');
Error is like this below
** Error: D:\modelsim\Door.vhd(53): Cannot read output "alarm".
VHDL 2008 allows reading outputs.
This facility is enabled by compiling with -2008.
** Error: D:\modelsim\Door.vhd(53): Cannot read output "door".
VHDL 2008 allows reading outputs.
This facility is enabled by compiling with -2008.
** Error: D:\modelsim\Door.vhd(53): Cannot read output "turnoff".
VHDL 2008 allows reading outputs.
This facility is enabled by compiling with -2008.
** Error: D:\modelsim\Door.vhd(55): VHDL Compiler exiting
I don't know why it happens please help me
First off: "Please help me" is not a good question. Better would be something like "Modelsim error "cannot read output" when compiling"
Second off: The error is quite descriptive. "Cannot read output "alarm"". alarm is declared as
alarm : out std_logic;
Thus it is an output port. In pre-2008 VHDL it was not allowed to read output ports. Next the compiler hints on how to fix it:
"VHDL 2008 allows reading outputs. This facility is enabled by compiling with -2008."
So do so!
In your modelsim compilation window select "default options"
And then set to VHDL-2008
Alternatively you can actually do what is described (add the -2008) on the command line:
vcom -reportprogress 300 -work work -2008 doorlock.vhd
Voila. Finished! Not?
No wait, still doesn't work!
You have a multiple driver error. In line 23 it states:
door <= "00000000" when (reset = '0');
This acts as a latch, effectively being the same as
process(reset) begin
if reset = '0' then
door <= "00000000";
end if;
end process;
Thus once reset='0' has occurred, the process will drive door to a fixed value. In the password-triggered process you again drive door! This will resolve badly. E.g. if (password = "------10"), then door <= "00000001". This will resolve:
resolve("00000000", "00000001") = "0000000X"
Because connecting '0' to '1' is equivalently a short-circuit.
So let's look at proper design. You're now triggering on a change of password. Not so nice, but it's possible. I would use another trigger, like the enable signal that is not being used. But anyhow: we introduce an extra signal to detect the change password_delay. But more importantly we introduce a clock. In digital hardware most systems use a clock. Finally, we use the new VHDL-2008 statement case? to decode the don't cares.
Together the VHDL-2008 code becomes:
library IEEE;
use IEEE.std_logic_1164.all;
entity doorlock is
port(
clk : in std_logic;
reset : in std_logic;
enable : in std_logic;
password : in std_logic_vector (7 downto 0);
door : out std_logic_vector (7 downto 0);
lock : out std_logic;
alarm : out std_logic;
turnoff : out std_logic
);
end doorlock;
--password is 10(decimal no.) which is 00010000(binary no.)
architecture DDL of doorlock is
signal password_delay : std_logic_vector(password'range) := password;
use ieee.numeric_std_unsigned.all;
signal err_count : integer range 0 to 5 := 0;
begin
clk_proc : process(clk) begin
if rising_edge(clk) then
if reset = '0' then
door <= (others => '0');
lock <= '0';
alarm <= '0';
turnoff <= '0';
err_count <= 0;
else -- no reset :)
if password /= password_delay then
case? password is
when "-------1" => door <= "00000000";
when "------10" => door <= "00000001";
when "-----100" => door <= "00000011";
when "----1000" => door <= "00000111";
when "---00000" => door <= "00001111";
when "--110000" => door <= "00011111";
when "-1010000" => door <= "00111111";
when "10010000" => door <= "01111111";
when "00010000" => door <= "11111111";
when others => null;
end case?;
err_count <= err_count + 1;
end if;
case err_count is
when 3 => alarm <= '1';
when 5 => turnoff <= '1';
when others => null;
end case;
if door = "11111111" and turnoff = '0' and alarm = '0' then
lock <= '1';
end if;
end if;
password_delay <= password;
end if;
end process;
end DDL;
That's something different, eh? I'm sorry, but I don't have time to write a test bench for you.
NOTE: The code gives a compiler warning
Warning: C:/HDL/doorlock/doorlock.vhd(20): (vcom-1013) Initial value of "password_delay" depends on value of signal "password".
Ignore this. This is required for simulation as else undefined initial value of password_delaywill cause a trigger of password /= password_delay.
Have JUST started learning how to use this tool so if my question seems silly i apologize in advance. I have searched the error in numerous forums (already answered posts , not mine) and couldn't understand what i was doing wrong so here is my question:
My Behavioral Code:
----------------------------------------------------------------------------- -----
-- Company:
-- Engineer:
--
-- Create Date: 01:47:22 07/07/2015
-- Design Name:
-- Module Name: Module_1 - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------- -----
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned valuessss
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity Module_1 is
port (A,B,WE,reset : in std_logic;
clk : in std_logic;
DIN : in signed(3 downto 0);
FULL,EMPTY,ERROR : out std_logic:= '0';
PARKFREE : out signed(3 downto 0)
);
end Module_1;
architecture Behavioral of Module_1 is
signal current_state,next_state:std_ulogic_vector(1 downto 0);
signal empty_bf, full_bf :std_ulogic;
signal enter, reset_b : std_ulogic := '0' ;
constant s0: std_ulogic_vector (1 downto 0):="00";
constant s1: std_ulogic_vector (1 downto 0):="10";
constant s2: std_ulogic_vector (1 downto 0):="11";
constant s3: std_ulogic_vector (1 downto 0):="01";
signal park_counter,buffr: signed(3 downto 0):="0000";
signal PARKTOTAL,free_park_counter: signed(3 downto 0):= "1111";
begin
p1: process (clk,reset,reset_b)
begin
if (reset = '1') then
current_state <= s0;
elsif clk'event and clk = '1' then
current_state <= next_state;
end if;
end process p1;
p2: process (current_state,A,B)
begin
next_state <= current_state;
case current_state is
when s0 =>
if A = '1' then
enter <= '1';
next_state <= s1;
elsif B = '1' then
next_state <= s3;
end if;
when s1 =>
if A = '0' then
enter <= '0';
next_state <= s0;
elsif B = '1' then
next_state <= s2;
end if;
when s2 =>
if A = '0' then
next_state <= s3;
elsif B = '0' then
next_state <= s1;
end if;
when s3 =>
if B = '0' then
enter <= '0';
next_state <= s0;
elsif A = '1' then
next_state <= s2;
end if;
when others =>
end case;
end process p2;
p3: process(current_state,A,B)
begin
case current_state is
when s1 =>
if enter = '0' and A = '0' and empty_bf = '0' then
park_counter <= park_counter - 1;
free_park_counter <= free_park_counter + 1;
ERROR <= '0';
end if;
when s3 =>
if enter = '1' and B = '0' and full_bf = '0' then
park_counter <= park_counter + 1;
free_park_counter <= free_park_counter - 1;
ERROR <= '0';
end if;
when others =>
end case;
end process p3;
max: process(WE)
begin
if clk'event and clk = '1' and WE = '1' then
PARKTOTAL <= DIN ;
buffr <= DIN ;
if (free_park_counter < buffr - park_counter) then
ERROR <= '1';
reset_b <= '1';
else free_park_counter <= buffr - park_counter;
end if;
end if;
end process max;
incr: process(free_park_counter,DIN)
begin
PARKFREE <= free_park_counter;
if (free_park_counter = 15) then
EMPTY <= '1';
empty_bf <= '1';
else EMPTY <= '0';
empty_bf <= '0';
end if;
if (free_park_counter = 0) then
FULL <= '1';
full_bf <= '1';
else FULL <= '0';
full_bf <= '0';
end if;
end process incr;
end Behavioral;
My Testbench
----------------------------------------------------------------------------- ---
-- Company:
-- Engineer:
--
-- Create Date: 02:17:07 07/11/2015
-- Design Name:
-- Module Name: D:/Users/ErgasiaFPGA/Testbench.vhd
-- Project Name: ErgasiaFPGA
-- Target Device:
-- Tool versions:
-- Description:
--
-- VHDL Test Bench Created by ISE for module: Module_1
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
-- Notes:
-- This testbench has been automatically generated using types std_logic and
-- std_logic_vector for the ports of the unit under test. Xilinx recommends
-- that these types always be used for the top-level I/O of a design in order
-- to guarantee that the testbench will bind correctly to the post-implementation
-- simulation model.
--------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
ENTITY Testbench IS
END Testbench;
ARCHITECTURE behavior OF Testbench IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT Module_1
PORT(
A : IN std_logic;
B : IN std_logic;
WE : IN std_logic;
reset : IN std_logic;
clk : IN std_logic;
DIN : IN signed(3 downto 0);
FULL : OUT std_logic;
EMPTY : OUT std_logic;
ERROR : OUT std_logic;
PARKFREE : OUT signed(3 downto 0)
);
END COMPONENT;
--Inputs
signal A : std_logic := '0';
signal B : std_logic := '0';
signal WE : std_logic := '0';
signal reset : std_logic := '0';
signal clk : std_logic := '0';
signal DIN : signed(3 downto 0) := (others => '0');
--Outputs
signal FULL : std_logic;
signal EMPTY : std_logic;
signal ERROR : std_logic;
signal PARKFREE : signed(3 downto 0);
-- Clock period definitions
constant clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: Module_1 PORT MAP (
A => A,
B => B,
WE => WE,
reset => reset,
clk => clk,
DIN => DIN,
FULL => FULL,
EMPTY => EMPTY,
ERROR => ERROR,
PARKFREE => PARKFREE
);
-- Clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
reset <= '1' ;
wait for 100 ns;
reset <= '0' ;
wait for clk_period*10;
-- insert stimulus here
A <= '1' ;
wait for clk_period*5;
B <= '1' ;
wait for clk_period*5;
A <= '0' ;
wait for clk_period*5;
B <= '0' ;
wait for clk_period*5;
B <= '1' ;
wait for clk_period*5;
A <= '1' ;
wait for clk_period*5;
B <= '0' ;
wait for clk_period*5;
A <= '0' ;
wait;
end process;
END;
I posted the whole code just in case i'm missing something in some part of it that i wouldn't think about. So , when i ISim it , with any "succesful" trigger of p3...
Referencing it again here:
p3: process(current_state,A,B)
begin
case current_state is
when s1 =>
if enter = '0' and A = '0' and empty_bf = '0' then
park_counter <= park_counter - 1;
free_park_counter <= free_park_counter + 1;
ERROR <= '0';
end if;
when s3 =>
if enter = '1' and B = '0' and full_bf = '0' then
park_counter <= park_counter + 1;
free_park_counter <= free_park_counter - 1;
ERROR <= '0';
end if;
when others =>
end case;
end process p3;
...the ISim says that in this part
"There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)."
and proceeds to make Xs of some of the values after that part , although all of the signals have been initialized (at least the ones in this part)
The "park_counter <= park_counter + 1;" part works correctly in the simulation but the "free_park_counter <= free_park_counter -1;" doesn't. This completely baffles me as they are declared as the same type and are both initialized the same way , even with different values.
So what am i missing or even doing blatantly wrong? Any help will be incredibly appreciated. Only looking for the error , if you could please contain optimizations since i'm looking to learn through trial and error and thought and would like to struggle to make it better myself
In addition , please be patient with my responses since i log on 2 to 3 times per day. Thanks in advance
Your design is non-workable per Brian's answer. Your testbench causes the messages when going from s3 or s1 to s0 before the clock edge. free_park_counter goes to 'U's. (Once it gets U's it won't loop further, no events occur without a signal value change).
Your counters should be clocked to prevent combinatorial looping, plus they likely won't synthesize a clock usefully due to uneven combinatorial delays. Sensitivity lists should likewise be complete, if for no other reason than the intent is to make simulation match the synthesized result.
Looking at the result of your testbench:
(clickable)
We can compare that with the messages from the arithmetic operators found in the Synopsys package std_logic_arith:
../../../src/synopsys/std_logic_arith.vhdl:315:20:#350ns:(assertion warning): There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es).
../../../src/synopsys/std_logic_arith.vhdl:315:20:#350ns:(assertion warning): There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es).
../../../src/synopsys/std_logic_arith.vhdl:315:20:#550ns:(assertion warning): There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es).
The signals displayed in the waveform are selected in order of importance and appearance a first pass selection and we immediately see we also get 'U's on free_park_counter as well as ERROR.
ERROR catches attention because you hadn't mentioned it previously. When asking 'where to the 'U' come from ?' it becomes apparent the issue is there are drivers on ERROR and free_park_counter in both processes p3 and max. The messages are a side effect.
Each process assigning a signal provides a driver. Signals with multiple drivers are either resolved or result in an error for non-resolved types.
The resolved value of free_park_counter with one or more elements having a metavalue will cause the diagnostic messages produced by package std_logic_arith. The 'U's in the waveform are caused by the resolution of the two drivers.
The difficulty your audience had in noticing the two drivers may be in part due to your strong insistence on focusing on process p3, which is not well specified. The title and focus of your question also seems a bit unclear. Without a Minimal Complete and Verifiable example there was also bound to be less scrutiny.
You might expect as a minimum to consolidate all the assignments to ERROR and free_park_counter into a single process. ERROR should likely be registered, and I'd expect something named park_counter would likely want to be registered, too.
There is some confusion in the question title : declaring a signal and setting its value are entirely separate.
Initialising a signal (in the declaration) will influence its value, but not fully determine it. If the initialisation and another driving value are different, the result probably will be 'X'. Likewise if the signal is driven from different processes which disagree on its value.
Now, you are using a multiple-process form of state machine, where the operations are split between clocked and combinational processes. These are recommended by more than one textbook. This is unfortunate because they are notoriously difficult to get right, and for example, a moment's inspection will show that the sensitivity list on process P3 is wrong.
Fixing P3's sensitivity list may not affect the problem, because P3 also drives its own inputs in what is known as a combinational loop. Consider that, if the process wakes up several times because of glitches on the combinational inputs in its sensitivity list, the additions will take place several times...
Rewriting these three processes in the form of a single clocked process P1, (which is, unfortunately, not well taught in several textbooks) will avoid all of these difficulties.
In ISim, if you browse the tree menu on the left you are able to add to then signals window any internal signal you want. Add all of them, rerun the simulation and look for the signals that have 'U'|'X'|'W'|'Z'|'-' values. This should give us a lead to track down the problem.
If you are really new to VHDL, this answer of mine should help you undersand some of the basic concepts of this description language :)
VHDL - iSIM output uninitialised, doesn't change states
Another advice that I learned the hard way, but you can think about it after we solved this problem: textbooks and even Xilinx describe how to implement finite state machines with two or even three distinct processes. This comes from an educational approach where FSM are splitted in synchronous logic and asynchronous logic. In practice, this is doing more harm than good: most of the FSM can be described with a single synchronous process. Google it (or if you are interested we can talk about it) and try it, you will get the hang of it really quickly and it will really simplify the code (you won't even need two separate signals for the states anymore!).
actually I want to make a local controller which will enable the latch.
As you can seen on my code below, the signal en will take the output from w AND x to enable the latch. After that, w and x will fetch the en. For example, initially, let say the w and x values start at 1, the en will become 1 and cause the latch to fetch data from data_in to data_out. After that, en will become the input of w and x and cause the latch to disable. However, the circuit didn't work when I tested it using university waveform program. The data_out didnt take the value of data_in. I can't figure out what is the problem still I'm new in VHDL. Hope you can assist/advice me on this :) Sorry for my bad english.
library ieee;
use ieee.std_logic_1164.all;
entity gasp_ctrl is
port(
w,x : inout std_logic; --! bidirectional wire
data_in : in std_logic; --! Data In when latch is enable
data_out: out std_logic --
);
end gasp_ctrl;
architecture ctrl of gasp_ctrl is
signal en, ww, xx : std_logic;
begin
en <= w and x; ------
ww <= en;
xx <= not en;
w <= ww;
x <= xx;
-------- Latch ------
process(en)
begin
if(en = '1') then
data_out <= data_in;
end if;
end process;
end gasp_ctrl;
Your code lines form a combinatorial loop:
en <= w and x;
ww <= en;
xx <= not en;
w <= ww;
x <= xx;
If you wan't to describe asynchronous gates and delays, then you must instantiate the primitives by hand, otherwise the synthesis compiler will optimize your lines and complain about signal loops.
I'm trying to simulate RAM type memory, the input and output are presented on the same lines and the functionality and selected via 3 control pins. ceN is for enabling the device (otherwise the output is high Z), weN is for enabling writing into the RAM and oeN is not enabling output to data_io vector. These controls are all active low type.
This passes compilation under Quartus II but does not simulate well with Modelsim or with the built in simulation of Quartus.
library ieee ;
use ieee.std_logic_1164.all ;
entity ram1 is
port ( address : in integer range 0 to 255 ;
ceN : in std_logic ;
weN : in std_logic ;
oeN : in std_logic ;
data_io : buffer std_logic_vector(7 downto 0) ) ;
end ram1 ;
architecture arc_ram1 of ram1 is
type mem_array is array (0 to 255) of std_logic_vector(7 downto 0) ;
signal ram : mem_array ;
signal data : std_logic_vector(7 downto 0) ;
begin
process ( address , ceN , weN , oeN , data_io )
begin
-- write to RAM
if ceN = '0' then
if weN = '0' then
ram(address) <= to_x01(data_io) ;
elsif oeN = '0' then
data_io <= ram(address) ;
end if ;
else
data_io <= (others => 'Z') ;
end if ;
end process ;
end arc_ram1 ;
You've created some transparent latches!
Make your processes synchronous, eg
process(clk)
begin
if rising_edge(clk) then
...
end if;
end process;
As an example, there's a big difference between the following:
process(en, d)
signal q : std_logic;
begin
if en = '1' then
q <= d;
end if;
end process;
and the following:
process(clk)
signal q : std_logic;
begin
if rising_edge(clk) then
if en = '1' then
q <= d;
end if;
end if;
end process;
The first of these examples is a transparent latch, the latter is a regular flip flop. The former will be vulnerable to brief errors in the input, and commonly fail to map to real hardware. The latter is the way to design proper FPGA logic. Quartus will probably let you get away with it with a warning, but it's certainly not what you want!
Also, check your warnings to see if Quartus inferred transparent latches instead of the RAM block you wanted. It can still build, even though this behaviour is almost never intentional.
You do want to switch the type of the data_io signal to inout. When you do that you're implying a tri-state buffer. That means in your logic (including your testbench) you have to ensure that whenever one side is driving the interface, the other side is driving a 'Z' else the bus will have two drivers and the simulator will display an 'X' if both drivers have equal drive strengths.
Here's a simple test sequence that should work with your DUT to show that the RAM read/write logic is working correctly:
test: process is
begin
address <= 0;
data_io <= (others => 'Z');
ceN <= '0';
oeN <= '0';
weN <= '1';
wait for 20 ns;
address <= 0;
data_io <= (others => '1');
oeN <= '1';
weN <= '0';
wait for 20 ns;
address <= 0;
data_io <= (others => 'Z');
oeN <= '0';
weN <= '1';
wait for 20 ns;
address <= 1;
data_io <= (others => '0');
oeN <= '1';
weN <= '0';
wait for 20 ns;
address <= 1;
data_io <= (others => 'Z');
oeN <= '0';
weN <= '1';
wait for 20 ns;
address <= 0;
wait for 20 ns;
end process test;
I had to modify your logic to ensure that the RAM isn't driving the data_io bus when the testbench is trying to drive it during a memory write:
process ( address , ceN , oeN, weN , data_io )
begin
-- write to RAM
if ceN = '0' then
if weN = '0' then
ram(address) <= to_x01(data_io) ;
data_io <= (others => 'Z') ; -- *** Added this ***
elsif oeN = '0' then
data_io <= ram(address) ;
end if ;
else
data_io <= (others => 'Z') ;
end if ;
end process ;
The reason I had to add the line that tri-states the data_io bus during a write might be easier to understand if you code the process this way:
process ( address , ceN , oeN, weN , data_io )
begin
-- write to RAM
if ((ceN = '0') and (weN = '0')) then
ram(address) <= to_x01(data_io) ;
end if ;
-- read from RAM
if ((ceN = '0') and (oeN = '0')) then
data_io <= ram(address) ;
else
data_io <= (others => 'Z') ;
end if ;
end process ;
Description:
I want to include vhdl assert statements to report when set_delay and hold_delay time violations occur. I am not sure how to do this with my code and I have been to many places on the web and I don't understand. Please give examples with my code.
Code:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY dff IS
GENERIC (set_delay : TIME := 3 NS; prop_delay : TIME := 12 NS;
hold_delay : TIME := 5 NS);
PORT (d, set, rst, clk : IN BIT; q : OUT BIT; nq : OUT BIT := '1');
END dff;
--
ARCHITECTURE dff OF dff IS
SIGNAL state : BIT := '0';
BEGIN
dff: PROCESS
BEGIN
wait until rst;
wait until set;
wait until clk;
IF set = '1' THEN
q <= '1' AFTER set_delay;
nq <= '0' AFTER set_delay;
ELSIF rst = '1' THEN
q <= '0' AFTER prop_delay;
nq <= '1' AFTER prop_delay;
ELSIF clk = '1' AND clk'EVENT THEN
q <= d AFTER hold_delay;
nq <= NOT d AFTER hold_delay;
END IF;
END PROCESS dff;
END dff;
I do understand that the general assert syntax is:
ASSERT
condition
REPORT
"message"
SEVERITY
severity level;
Part of my problem is that I don't know where to put these assert statements and I am not sure how I would write them.
I would introduce additional signals in which you store the time of the last manipulation. Then I'd add other process which manage the signals and check the times:.
time_debug : block
signal t_setup, t_hold : time := 0 ns;
begin
setup_check : process (clk)
begin
if clk'event and clk = '1' then
t_hold <= now;
assert (t_setup - now)>set_delay REPORT "Setup time violated." SEVERITY note;
end if;
end process setup_check;
hold_check: process (d)
begin
if d'event then
t_setup <= now;
assert (t_hold - now)>hold_delay REPORT "Hold time violated." SEVERITY note;
end if;
end process hold_check;
end block time_debug;
What this does is it saves the time of the last positive clock edge and the time of the last input change. Now every time either d changes or the clock rises the delays are checked. I couldn't verify this in a compiler because I don't have one set up here, but I'll gladly do so if there are problems with this solution.
I personally like to keep debug stuff in a dedicated block, so I can easily keep track of which signals I only use for debugging and can later easily remove them. It also makes it easier to add all debug signals to e.g. modelsim's wave screen.
Also note that these asserts and reports will only work in simulation.