VHDL buffer variable vs out variable - vhdl

I work in a VHDL program and I need to do a RAM 256 using the ALTERA DE2-115. The outputs will show in a seven segment display.
The problem is that: I have a dataout output variable. Then the variable has the following values of the temp_ram array:
dataout <= temp_ram(conv_integer(dir));
Then I want to divide the vaules of dataout to put in the seven segment
dataout(7 downto 4)
dataout(3 downto 0)
This shows the following error:
Error (10309): VHDL Interface Declaration error in RAM.vhd(45): interface object "dataout" of mode out cannot be read. Change object mode to buffer.
When I change to buffer and this run prefect, but I can't understand what happen

For cross-platform compatibility and code-reusability, I'd recommend an intermediate signal ( dataout_int can be used by other statements) :
dataout_int <= temp_ram(conv_integer(dir));
and assign the output to this intermediate signal:
dataout <= dataout_int;

You are using conv_integer from a Synopsys package. Please use only official IEEE packages.
dataout is a signal, not a variable, because you use a signal assignment statement. Moreover, the signal is a port of mode out. (Ports are signals as well).
Besides static typing, VHDL is also checking directions of signal in ports. Your signal is of mode out so it can't be read.
Als a solution, you can:
use an intermediate signal,
use mode buffer, which is not supported by all synthesis tools equally
use VHDL-2008, which allows ports of mode out to be read.
Quartus support some VHDL-2008 features.

Related

how does inout parameters be implemented?

I know what the inout parameters is and how to use them. Assume that we have an inout parameter io and want to create a bidirectional static RAM such as the following code :
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY sram IS
port(
clk : IN std_logic;
wr : IN std_logic;
io : INOUT std_logic;
addr : IN INTEGER RANGE 0 TO 7
);
END sram;
ARCHITECTURE behavioral OF sram IS
TYPE matrix IS ARRAY (0 TO 7) OF std_logic;
SIGNAL mem : matrix;
BEGIN
PROCESS(clk)
BEGIN
IF rising_edge(clk) THEN
IF wr = '1' THEN
mem(addr) <= io;
END IF;
END IF;
END PROCESS;
io <= mem(addr) WHEN wr = '0' ELSE 'Z';
END behavioral;
We can create an instance of sram and write on it such as the following code :
io <= '1' WHEN wr = '1' ELSE 'Z';
Question : How can synthesis tool control the multiple assignments and judge between multiple drivers ? What hardware is implemented to do it ?
Thanks for comments and answers ...
For typical FPGA and ASIC devices, implementation of tristate capabilities are only available on the IO, like for example in an Altera Arria 10 FPGA:
So for such devices, the internal RAMs are always implemented with dedicated input and output ports, thus not using any internal tristate capabilities.
Even if a RAM is connected to external IOs that support tristate, then the internal RAM block is still typically created with dedicated input and output ports, so the connection to a tristate capable pin on the device is handled through an in-out buffer with the output enable and tristate capability.
If internal design tries to use tristate capabilities or multiple drivers when this is not supported by the device, then the synthesis tool will generate and error, typically saying that multiple drivers are not supported for the same net.
On Xilinx devices, the schematics are similar.
This is an image of primitive IOBUF:
The green part is the output driver with tristate control; the blue part is the input driver. The complete IOB (Input/Output Block) consists of several primitives:
IOB registers (input, output, tristate control)
delay chains
wires to combine two IOBs to a differential IOB (**BUFDS)
capability to drive clock networks (CC-IOB - clock capable IOB)
pullup, pulldown, ...
driver (IOBUF)
pin/ball (IPAD, OPAD, IOPAD) - this includes ESD protection
How does synthesis work?
Xilinx synthesis tools (XST / Synth) add IPAD or OPAD primitives for every wire in your top-level component's port description. A pad is just the primitive to represent a physical pin or ball under the FPGA package.
If you enabled to automatically add I/O buffers, the tool will add IBUF, OBUF, IOBUF, IBUFDS, ... primitives between every PAD and top-level port. It uses the port direction (in, out, inout) to infer the correct buffer type. If this option is disabled (default = on) you have to manually add buffers for every I/O pin. In some cases XST gets offended: I added some IOBUFs with tristate control by hand so XST declined to infer the missing buffers. So I had to add all buffers by hand ...
While using Xilinx XST it's possible to use tristate buses (port direction = inout) beneath the top-level. XST will report that it added (virtual) tristate buffers. These buffers get trimmed if the direction of each bit of the bus has an obvious direction and no multiple driver problem.
This does not work in iSim.

Inferred RAM doesn't initialize in ModelSim Altera edition

I have a memory module for an Altera FPGA target that I've written to be inferred into one of Altera's ALTSYNCRAM blocks. The memory is 1024x16 and I have a memory initialization file specified with an attribute.
When synthesizing, the synthesis report indicates that it generated the type of RAM block that I wanted, and it notes that the initialization file is the one I specified.
When trying to simulate with Altera's edition of ModelSim, the data signal starts out completely uninitialized, and I can't figure out why.
I looked on forums and such and some people mentioned that ModelSim might not support the ".mif" format that I was using, but would support ".hex" so I changed my initialization file to ".hex". I also read that relative file paths can be an issue, but I checked my simulation directory and it looks like QuartusII copied the initialization file into that directory when I tried to simulate.
Any ideas on why the memory isn't being initialized and how to make it do so?
A heavily trimmed model that contains the inferred memory:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
--use work.types.all;
entity CPU is
--...
end entity CPU;
architecture rtl of CPU is
--these types are actually included in a package
subtype reg is std_logic_vector(15 downto 0);
type mem is array (0 to 1023) of reg;
--...
--memory read port
signal MR : reg;
signal MRA : std_logic_vector(9 downto 0); --flops
--memory write port
signal MW : reg; --flops
signal MWA : std_logic_vector(9 downto 0); --flops
signal MWE : std_logic; --flop
signal data : mem;
attribute ram_init_file : string;
attribute ram_init_file of data : signal is "RAM_init.hex";
attribute ramstyle : string;
attribute ramstyle of data : signal is "no_rw_check";
begin
--...
--memory spec
MR <= data(to_integer(unsigned(MRA(9 downto 0))));
memory_process : process(clk)
begin
if (clk'event and clk = '1') then
if(MWE = '1') then
data(to_integer(unsigned(MWA(9 downto 0)))) <= MW;
end if;
end if;
end process;
end architecture rtl; --CPU
Modelsim does not show any warnings or errors while compiling CPU.vhd, nor does it have any indication of loading the initialization file.
This is my first design using Altera software or memory initialization files, and it wouldn't surprise me if the problem was something really basic, or I'm approaching this from a fundamentally incorrect angle.
I'd normally define the memory with a constant in a package, but this is for a class, and it requires that I have a memory initialization file (it requires .mif format too, but that's only a 3 character change between simulation and synthesis file).
It looks like Modelsim may have a "mem load" command you can use at the start of your simulation in order to initialize the memory. Take a look at the end of this thread:
Initialization altsyncram
Being able to initialize RAM on an FPGA depends on both the synthesizer and the specific FPGA you are using. Some FPGA families support this, others don't. I know this is not the answer you want to hear, but you'll need to check the documentation from Altera.
Modelsim does not pay attention to synthesis attributes. That is a vendor specific convention. You can refer to them in simulation as with any other user-defined attribute but it doesn't know that some attributes invoke special behavior in various third-party synthesizers.
If you want to initialize the RAM for simulation you will need to do one of the following:
Write a function that reads the contents of the memory file and call it during initialization of the data signal.
Convert the memory contents to a VHDL constant defined in a separate package and assign the constant to the data signal as the initializer. This can be automated with a script.
Use the Verilog system task $readmemh (requires Modelsim with mixed language license)
For option 1, the function should be of the form:
impure function read_mem(fname : string) return mem is
variable data : mem;
begin
-- ** Perform read with textio **
...
return data;
end function;
signal data : mem := read_mem(data'ram_init_file);
The Quartus documentation on RAM initialization is sparse and only demonstrates initialized data assigned from within a VHDL process rather than reading from a file. The Xilinx documentation on RAM/ROM inferencing (p258) provides examples for doing this with general purpose VHDL. The same technique can be used for simulating a design targeted to Altera. XST supports this use of file I/O for synthesis but Quartus may choke on it. If that is the case you will have to use a configuration to swap between a synthesis oriented RAM model and one specifically for simulation that initializes with the function.
The Xilinx example only shows how to read files with ASCII binary. I have a general purpose ROM component that reads hex as well as binary which you can adapt into a RAM for what you need.

How to place component parts on RAM on chip

I am making some kind of cache and i am using some tables (big ones) inside entity which are composed of std_logic_vectors and i am doing it in Quartus 2 web edition.
Everything works fine in simulation, but when i try to synthesize it its being done ONLY with latches, AND and OR components.
Is there any way to specify Quartus to use memory modules for those tables instead of these combination elements? Or maybe something can be done from VHDL code itself.
library ieee;
use ieee.std_logic_1164.all;
package UTIL_PACK is
type matrix16x8 is array (0 to 15) of std_logic_vector(0 to 7);
type matrix2p4x8 is array (0 to 2**4) of matrix16x8;
end package;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.util_pack.all;
entity RAM16B is
port(
signal RD: in std_logic;
signal WR: in std_logic;
signal CLK: in std_logic;
signal A: in std_logic_vector(7 downto 0);
signal D: inout matrix16x8;
signal FC: out std_logic
);
end entity ;
architecture RAM16B_IMPL of RAM16B is
signal memory: matrix2p4x8 := ((others => (others => (others => 'Z'))));
begin
run:process(clk)is
variable slot:integer range 0 to 15 :=0;
begin
if(clk='1') then
slot := TO_INTEGER(unsigned(A)) rem 16;
if(rd = '1')then
FC<='0';
for i in 0 to 3 loop
D(i) <= memory(i)(slot);
end loop;
FC<='1';
elsif(wr = '1')then
FC<='0';
for i in 0 to 3 loop
memory(i)(slot) <= D(i);
end loop;
FC<='1';
else
FC <= 'Z';
D <= ( others => ( others => 'Z' ));
end if;
else
FC <= 'Z';
D <= ( others => ( others => 'Z' ));
end if;
end process;
end architecture RAM16B_IMPL;
RAM consists of 16 blocks of memory, each block is 16 bytes. I am trying to read more data parallely so I am reading/writing 16 bytes of data per cycle. Slot defines block in which reading/writing is being done.
If you really want to make sure you use the hard memory blocks, you should either use the mega-function wizard to craft a custom ram component, or directly instantiate an altsyncram component from the library and use the generics to configure it how you want (this can be tricky if you're not extremely familiar with the options). This causes porting issues, but any time you infer ram you generally have porting issues anyway. Using a custom library component just makes it very obvious and easy to identify where you might have problems if you ever do need to migrate to something else.
As for your specific implementation, there's no way you're going to get latches automatically migrated into the hard ram blocks which are edge driven devices. Use rising_edge(clk) instead of clk='1' in your process to fix this.
Also, there is no support for tri-state operation internal to the chip, you need independent data in and data out ports. You are getting lots of discrete logic because and & or gates are being used to emulate a tri-state bus (and because of the latch issue, above).
Yes, you can do it from your VHDL code. To make sure that Quartus understands that you are modeling a memory, you should code it as described in Altera's Recommended HDL Coding Styles guide. Take a look at the section called Inferring Memory Functions from HDL Code (http://www.altera.com/literature/hb/qts/qts_qii51007.pdf), then modify your code accordingly.
It is probably a good idea to start with the exact memory model suggested by Altera, and making sure that Quartus synthesizes the design using the FPGA's dedicated memory bits. Next, you can gradually change your model to implement the desired behavior, always synthesizing and looking at the compilation reports to make sure your changes didn't deviate from what Quartus infers as a memory block.

How do User Constraint Files actually work?

I got WebPack up and running on my machine again and after synthesizing a simple design and uploading it to my FPGA, I encountered quite a problem with my understanding.
When there is a line like this in the user constraint file:
NET "W1A<0>" LOC = "P18" ;
How exactly does the synthesis software determine how this pin gets assigned to by the VHDL code?
For instance, take this example code I've been provided with:
entity Webpack_Quickstart is
Port (
W1A : out STD_LOGIC_VECTOR(15 downto 0);
rx : in STD_LOGIC;
tx : inout STD_LOGIC;
clk : in STD_LOGIC
);
end Webpack_Quickstart;
architecture Behavioral of Webpack_Quickstart is
signal counter : STD_LOGIC_VECTOR(47 downto 0) := (others => '0');
begin
W1A(0) <= '1';
end;
How exactly does this code make the WIA0 pin on my FPGA turn on? What is the link? Is it just the name of the port in the entity declaration is there more magic involved?
Your .ucf constraints are applied in the implementation phase. At this point your design has been synthesized, and the available top-level nets are thus "known". So yes, it is only a matter of matching equally named nets to equally named constraints.
The syntax is slightly different though (using <> instead of () for indexing vectors for instance), but otherwise it's just a simple string match.
The easiest way to initially configure your pin constraints, especially for large designs, is to just use one of the graphical tools (PlanAhead, if it's included in the WebPack) to assign the pins, and generate an initial .ucf file.
I find that making small changes later on is easiest to do by hand using the standard ISE text editor directly though.

Error : Identifier 'q' is not readable in architecture of T Flip Flop

I am trying to model a T Flip Flop using VHDL.
library ieee;
use ieee.std_logic_1164.all;
entity tff is
port (
clk: std_logic;
t: in bit;
q: out bit;
qbar: out bit);
end tff;
architecture tff_arch of tff is
begin
process(clk)
begin
if (clk = '1' and t = '1')
then
q <= not q;
qbar <= not qbar;
end if;
end process;
end tff_arch;
But the error i am getting is
Error: CSVHDL0168: tff.vhdl: (line 17): Identifier 'q' is not readable
Error: CSVHDL0168: tff.vhdl: (line 18): Identifier 'qbar' is not readable
The reason of error i think is, i am using "not q", when q has not been initialized. Correct me here, if i am wrong.
And what to do to get around this problem? I have modeled D Flip flop and its test bench waveform correctly using Symphony EDA free version.
In the old days you couldn't read an output, so you had to either:
make it an inout (which is a bit unpleasant as you are fudging the direction you really mean, just so you can read it) - this works, but is not widely used in industry (as far as I'm aware)
make it a buffer, but that had downsides (prior to VHDL-2002) in that you have to make all the rest of the hierarchy of that signal driven by buffers. Almost never used in my experience.
use and intermediate signal (which you can read) and then use an assignment to set the output to the value of that signal. This is the idiomatic way of doing it amongst practising engineers.
Since VHDL-2008 you can read output ports (although the stated intention of this is for it only to be used for verification purposes). You'll probably need a tool switch to enable VHDL-2008 mode. (And it may be that your particular simulator/synthesiser still doesn't support VHDL-2008, which shows the staggering pace of development in the EDA tools world!)
q is an output of the entity.
You can't read an output. It's that simple.
You need an internal version that you use for the feedback loop, and then q <= local_q;
Can't remember VHDL very well, but this might give you a clue:
The problem is that q is only a signal out of your entity, so there is nothing to access when you try to read it.
So, to not solve your homework, think of it this way:
Either you need to have q as an input in order to access it (probably not what you want) or you need to store q (or at least next value of q) internally. This can be done by specifying q (or q_next) as a signal in the architecture part. For example:
architecture tff_arch of tff is
signal q_next: std_logic;
begin
and so on. The same goes for your qbar signal.

Resources