You are on page 1of 12

Modelling RAMs & ROMs

Memories are technology dependent!


Needs to be generated by a RAM/ROM generator to function properly

But, sometimes the models have compatibility or library problems and doesnt work...

F8 : Modelling of Complex Systems

We can make a simple model of RAM or ROMs functionality and use that in our simulations.

Use a variable to store the values, NOT a signal!

FIFOs & Delay buffers


DataIn DataOut

Modeling RAM-Memories
Memory: process(Address,En,Data,rw) variable mem:array(Addressrange) of std_logic_vector(Datarange); begin if (En=1) then if (rw=1) then Data<=mem(Address); else Address mem(Address):=Data; end if; else Data Data<=(others=>Z); end if; end process;

process(clk) begin if (clk=1) and clkevent then FIFO(7 downto 0)<=FIFO(6 downto 0) & DataIn; end if; end process;

FIFOs are easy to model if they are made from Registers, but if they are implemented using a memory, a memory model is needed.

En r/w

Modeling ROM-Memories
Memory: process(Address,En,Data) variable mem:array(Addressrange) of std_logic_vector(Datarange); variable init: boolean:=false; begin if (not(init)) then initiate mem by reading data from file system init:=true; end if; if (En=1) then Address Data<=mem(Address); else Data<=(others=>Z); end if; Data end process;

memory.mif files (Alteras Memory Interchange Format)


-- First comes a lot of header lines containing the Altera disclaimer information -- Quartus II generated Memory Initialization File (.mif) WIDTH=8; DEPTH=8192; ADDRESS_RADIX=UNS; DATA_RADIX=UNS; CONTENT BEGIN 0 : 0; 1 : 1; 2 : 2; [3..8191] : 0; END;

En

Reading in data to a ROM


architecture behave of ROM is FILE rom_file:TEXT is IN myromdata.mif; begin process(address,data,ce) variable init:boolean:=false; variable in_line:LINE; variable mem:mem_type; begin if not(init) then -- process header in .mif file ... -- mem_size is in header for i in 0 to mem_size-1 loop readline(file,in_line); read(in_line,at); read(in_line,value) mem(at)<=conv_value(value); end for; init:=true; end if;

File Access: Text Input and Output


Basic file operations in VHDL are limited to unformatted input/output VHDL supports the TEXTIO package for input and output of ASCII text
TEXTIO is included in STD library

The following data types can be used by TEXTIO:


Bit, Bit_vector Boolean Character, String Integer, Real Time (VHDL2002 - ?)

std_logic_vector

File access types


type LINE is access STRING; -- pointer to string value type TEXT is file of string; -- a file of variable length -- ASCII records type SIDE is (RIGHT,LEFT); -- for justifying output data -- within a field subtype WIDTH is NATURAL; -- for specifying width of -- fields Writing to a file

Read and Write


Reading from a file
READLINE reads a line from the file into a LINE buffer READ gets data from the buffer

WRITE puts data into a LINE buffer WRITELINE writes the data in the LINE buffer to file

READ and WRITE have several formatting parameters


Right or left justification Field width Unit displayed (for time)

Default Files

Opening files NOT backward compatible!


USE std.textio.all;

FILE output:TEXT OPEN write_mode is std_output;


FILE my_file:text is IN my_file.txt; -- VHDL87

FILE input:TEXT OPEN read_mode is std_input;


FILE my_file:text open read_mode is my_file.txt; -- VHDL93

File Access (ctd.)


-- We can also declare file access for our own types type file_type is file of element_type; -- and use it in our programs file my_file:file_type; -- The simulator creates an implicitly declared procedure procedure file_open( file f: file_type; external_name:in string; open_kind:in file_open_kind:=read_mode); -- Read more in the book by Ashenden, chapter 18.

Example : ppm_file_handler
TYPE PPM_FILE_TYPE is FILE of CHARACTER; ...

PROCEDURE WriteData( VARIABLE data_out : IN INTEGER RANGE 0 to 255; FILE FileOut : PPM_FILE_TYPE ) IS VARIABLE char : CHARACTER; -- A temporary character BEGIN char := character'val(data_out); -- Write the character char to the output file WRITE(FileOut, char); END WriteData;

Example : ppm_file_handler
PROCEDURE ReadData( VARIABLE data_in : OUT INTEGER RANGE 0 to 255; FILE FileIn : Std.TextIO.Text; VARIABLE HashTable : HashTable_Type ) IS VARIABLE buf : STRING(1 DOWNTO 1); -- The read character i.e. one char of the string. VARIABLE len : INTEGER; -- A dummy var. for getting the READ syntax right VARIABLE char : CHARACTER; -- A temporary character VARIABLE int : INTEGER RANGE 0 TO 255; -- The integer value of a the read ASCII character BEGIN READ(FileIn, buf, len); char := buf(1); int := HashTable(char); data_in:=int; END ReadData; -- Read 1 character from the input file -- Extraction of curr. read character -- Make the char integer val. survive

Name Regions
The VHDL hierarchy is composed of Name Regions
Each component instantiation is expanded internally Access to signals higher up in hierarchy is allowed by using the full name of the signals Useful for doing power calculations & debugging
(Verilog allows probing signals downwards in hierarchy also, which is very useful when debugging since it is allows probing the lower level hierarchies from the test bench)

Resolving Naming conflicts Name regions


architecture test_naming of test is signal q:bit; begin s1: process(clk) begin q<=not(q); end process; s2: process(clk) variable q:integer; -- this declaration hides -- the signal q for this process -- s2 begin q:=q+1; q2<=work.q; -- but here it is again. end process; end test_naming;

Name regions (ctd.)


architecture test_naming of test is signal q:bit; begin s1: block signal tmp:integer; begin tmp<=fir(q,tmp); q<=to_bitvector(tmp)(0); end block; s2: block(clk) begin q2<=guarded work.s1.tmp; end block; end test_naming;

Example : ROM ppm_file_handler


PROCESS(address) VARIABLE hash_table : HashTable_Type; VARIABLE init:boolean:=FALSE; VARIABLE pointer:INTEGER:=0; subtype uint8 is integer range 0 to 255; -- use integers to speed up simulation type mem_type is ARRAY (0 to 2**(Address'high+1)-1) of uint8; VARIABLE mem:mem_type:=(others=>255); VARIABLE header_length:header_length_type; VARIABLE header:header_type; FILE FileIn:TEXT OPEN Read_Mode IS "datain.ppm"; variable data_in:uint8; BEGIN IF not(init) THEN CreateHashTable(hash_table); ReadHeader(FileIn, hash_table, header, header_length); work.ppm_file_handler.ppm_header<=header; work.ppm_file_handler.ppm_header_length<=header_length; WHILE NOT Endfile(FileIn) LOOP ReadData(data_in, FileIn, hash_table); mem(pointer):=data_in; pointer:=pointer+1; END LOOP; init:=true; ELSE pointer:=conv_integer(unsigned(Address)); q<=conv_std_logic_vector(mem(pointer),8); END IF; END PROCESS;

Example : RAM ppm_file_handler


SHARED VARIABLE mem:mem_type:=(others=>255); SIGNAL int_address:integer range 0 to mem_type'high; SIGNAL dump_ppm:boolean:=false; int_address<=conv_integer(unsigned(address)); PROCESS(int_address,data,we) VARIABLE data_in:uint8; BEGIN data_in:=conv_integer(unsigned(data)); IF (WE='1') THEN mem(int_address):=data_in; END IF; END PROCESS; q<=conv_std_logic_vector(mem(int_address),8); dump_ppm<=work.ppm_file_handler.dump_ppm; PROCESS(dump_ppm) FILE FileOut:PPM_FILE_TYPE OPEN Write_Mode IS "dataout.ppm"; variable data_in:uint8; BEGIN IF dump_ppm'event and dump_ppm THEN WriteHeader(FileOut, work.ppm_file_handler.ppm_header, work.ppm_file_handler.ppm_header_length ); FOR i in 0 to 57599 LOOP -- Picture is 120*160*3=57600 Bytes long... data_in:=mem(i); WriteData(data_in, FileOut); END LOOP; END IF; END PROCESS;

Generating Memories in Altera...

Select what to generate...

Specify memory type and file name...

Choose Data and Address width...

Turn on or off input and output registers...

Set block type and initiation file (not mandatory)...

(But cannot have DFFs on address input!)

Good choice for ROMs

And generate the VHDL file...

Generated Entity
LIBRARY ieee; USE ieee.std_logic_1164.all; LIBRARY lpm; USE lpm.lpm_components.all; ENTITY single_port_memory IS PORT ( address : IN STD_LOGIC_VECTOR (11 DOWNTO 0); we : IN STD_LOGIC := '1'; data : IN STD_LOGIC_VECTOR (7 DOWNTO 0); q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) ); END single_port_memory;

Use Fake Architecture for Testing purpose


ARCHITECTURE fake OF single_port_memory IS BEGIN -- For debugging CTRLs with RAMs & ROMs inside FPGAs data <= address (7 downto 0); END fake;

Debugging inside an FPGA is difficult


Having a RAM/ROM makes it even more difficult Using a known sequence helps

Testing Complex Systems

Use the SignalTap Logic Analyzer to debug!

Testing Complex Systems


Hard requirements on test bench Extensive use of file system May require multi-language simulations

Testbench requirements
Testbench should model real case
Reactive testbenches
Complicated FSM behaviour

Traffic generators
Traffic distributions: Normal, Gaussian, etc. Traffic patterns: Local traffic, Global traffic, Bursty traffic, etc. Easiest way to read data from Matlab genererated file

Analysis
Analyse and determine if faults occur, preferably automatic Log results in file Use Matlab for analysis of results from traffic patterns

Reactive Testbenches
Use behavioural style for testbench modelling
May result in delta delay problems when testing FSMs Use after statement to introduce or force a small delay

Example of complex testbench


process variable test_case: integer:=0; begin if test_case=0 then for i in 0 to 63 loop a<=conv_integer(i); wait on clk until clk=1; wait for 1 fs; -- let other processes finish first. end loop; elsif test_case=1 then .... end if; test_case=test_case+1; end process;

Use ASSERT statements to specify and log abnormal behaviour and/or to abort simulation
(SystemVerilog allows also TIME dependent assertions, which is very useful when specifying FSM dependent operating conditions - used in Formal Verification)

Complex Sequential statements


a:for i in s1range loop b: for j in s2range loop next a when s1(i)=X; -- skip exit a when s2(j)=1; exit b when s2(j)=Z; q<=s1(i) and s2(j); wait on clk until clk=1; end loop b; wait on clk until clk=1; end loop a; -- stop -- skip -- loops may have a label

Unconditional loops
i:=0; a:loop -- unconditional loop => loop forever exit a when i=97; i:=i+1; q<=sample(i) wait on clk until clk=1; end loop a;

Example : ppm_file_handler
LOOP READ(FileIn, buf, len);
...

Assert Statement
The ASSERT statement is used for displaying text when certain conditions are NOT met ASSERT statement classifies the text message in four categories
Note -- relays information about conditions to the user Warning -- alerts the user to conditions that are not expected, but not fatal Error -- relays conditions that will cause the model to work incorrectly Failure -- alerts the user to conditions that are catastrophic

-- Read 1 character from the input file

CASE state IS WHEN 0 => IF int = 50 THEN state := 1; ELSE state := 0; END IF; WHEN 1 =>
...

WHEN 3 => IF int = 10 THEN EXIT; ELSIF int = 2 THEN state := 1; ELSE state := 0; END IF; WHEN OTHERS => null; END CASE; END LOOP;

Assert Syntax
Syntax of the ASSERT statement
ASSERT condition REPORT violation statement SEVERITY level; G

Assert Example
Assume type state is (good, reset); We specify the Normal operating conditions assert triggers on abnormal operating conditions
PROCEDURE display_state (current_state : IN state) IS BEGIN ASSERT (current_state = reset) REPORT Status of State: good SEVERITY NOTE; ASSERT (current_state /= reset) REPORT Status of State: reset SEVERITY WARNING; END display_state; G

The ASSERT statement will trigger when the condition is false The violation statement must be enclosed in quotes
ASSERT (NOT((j=1) AND (k=1))) REPORT Set and Reset are both 1 SEVERITY ERROR;

ASSERT statements may have some implementation defined action associated with the various SEVERITY levels

Assert Example: Debugging complex FSMs


read_ctrl_interface: process(...) begin avalon_slave_readdata<=(others=>'Z'); if avalon_slave_chipselect='1' then if avalon_slave_read='1' then case avalon_slave_address is when "00000" => -- write data status register avalon_slave_readdata<=write_status_reg; if (row_pos=0) and (col_pos=0) and (layer_pos=0) then assert false report "reading write data status" severity note; end if; when "00001" => -- read status register if (row_pos=0) and (col_pos=0) and (layer_pos=0) then assert false report "reading read status register, v1.0 style - Should not happen in v2.0" severity note; NULL; when "00010" => -- sending interrupt register value to NioS avalon_slave_readdata<=zeros(31 downto interrupt_reg'length) & interrupt_reg; if (row_pos=0) and (col_pos=0) and (layer_pos=0) then assert false report "reading interrupt_reg, v1.0 style - Should not happen in v2.0" severity note; end if; when 00011 => ...

Making assert stmnt print things on the screen


Define print functions that returns strings:
Function print_digit(a:integer range 0 to 9) return string is variable ret:string(1 to 1); Begin case a is when 0 => ret:=0; Etc... Function print_number(a:integer) return string is variable ret:string(1 to 10); Begin tmp:=a; for i in 10 downto 0 loop ret(i)=print_digit(tmp mod 10); tmp:=tmp/10; end loop; return ret; End print_number;

ASSERT false REPORT A has the value & print_number(a) SEVERITY NOTE;

Assert Statements in Entity Body


Entities may contain statements but, they can only be
Concurrent assertion statements Passive concurrent procedure calls Passive process statements

Logging results on File


This procedure displays the current state of an FSM with the states (reset, good) similar to the assert example displayed earlier
USE STD.TEXTIO.ALL; TYPE state IS (reset, good); PROCEDURE display_state (current_state : IN state) IS VARIABLE k : LINE; FILE flush : TEXT IS OUTPUT; -- Output has screen as default VARIABLE state_string : STRING (1 to 7); BEGIN PROCESS (current_state) BEGIN CASE current_state IS WHEN reset => state_string := "reset "; WHEN good => state_string := "good "; END CASE; WRITE (k, state_string, LEFT, 7); END PROCESS; WRITELINE (flush, k); END display_state;

Example
ENTITY multiplexor IS PORT (a, b: IN BIT; select: IN BIT; output: OUT BIT); BEGIN check: PROCESS(a, b) BEGIN ASSERT a/=b REPORT a equals b SEVERITY NOTE; END PROCESS; END multiplexor;

Multi-language simulations
Use the VHDL Foreign Language Interface and/or Use the Modelsim simulation engine to run mixmode/multi-language simulations
VHDL Verilog SystemC

Foreign Language Interface (FLI)


VHDL provides for some use of foreign languages
Subprogram or architecture body can have non-VHDL implementation Designer has access to previously written code or code difficult to write in VHDL

The use of foreign code is mainly implementation dependent Foreign variables, signals, or entities are not possible Good for modeling memories, processors and parsing complicated file formats!!!
ATTRIBUTE FOREIGN OF name: construct IS "information/parameters";

FLI Example
ENTITY and2 IS PORT(a, b: IN BIT; c: OUT BIT); END and2; ARCHITECTURE c_model OF and2 IS ATTRIBUTE FOREIGN OF c_model: ARCHITECTURE IS "xxand2(A, B, C)"; BEGIN END c_model;

Modelsim FLI Example


Written in accordance with modelsim version 5.4 --------------------------------------------------------------This program demonstrate 1) INPUT and 2) OUTPUT between VHDL & C for the following data types: 1. Integer 2. Array of Integer 3. Real 4. Array of Real Corresponding C-Types for different VHDL types are given in FLI chapter of ModelSim Manual.

The c_model architecture is declared as FOREIGN


No statements are needed in the architecture body as they will never be executed The implementation calls the "xxand2" function to perform the actions for the and2 entity

Modelsim FLI Example (ctd.)


Note-1: The same VHDL type might require a different C type depending on if it is IN or OUT/INOUT or depending on if it is a variable or a signal. Note-2: VHDL arrays of any type (real/integer), of any class (signal/variable) and of any mode (IN/OUT) result in the same C-Type, named varID. To compile & link do: *) cc -c test.c *) ld -G -o test.so test.o *) vcom -93 test.vhdl *) vsim > run 100

Modelsim FLI VHDL-code


package pkg is type int_array is array (integer range <>) of integer; procedure my_proc ( variable COEF : in integer; variable in_VAR : in int_array(3 downto 0); variable out_VAR : out int_array(3 downto 0) ); attribute foreign of my_proc : function is "my_proc test.so"; end; -- end pkg declaration package body pkg is procedure my_proc ( variable COEF : in variable in_VAR : in variable out_VAR : out begin report "ERROR: foreign end; end; -- end pkg body

integer; int_array(3 downto 0); int_array(3 downto 0)) is subprogram my_proc not called";

Modelsim compliant C-code


test.c /* The C-func (in test.c) is written in accordance with modelsim version 5.4 */ #include <stdio.h> #include "/opt/local/esd/tools/mentor/modelsim-5.4/modeltech/include/mti.h void my_proc(int COEF, mtiVariableIdT in_VAR, mtiVariableIdT out_VAR) { int i; /* iteration index */ int *in_VARptr; int *out_VARptr; /* get a pointer to the array */ in_VARptr =(int *)mti_GetArrayVarValue(in_VAR, NULL); /* get a pointer to the array */ out_VARptr =(int *)mti_GetArrayVarValue(out_VAR, NULL); for(i=0; i<4; i++){ *out_VARptr = *in_VARptr * COEF; in_VARptr++; out_VARptr++; } }

Modelsim FLI VHDL-code (ctd.)


library ieee; use ieee.std_logic_1164.all; use work.pkg.all; entity test is end test; architecture test_FLI of test is signal CLK : std_logic := '0'; signal Storage : int_array(7 downto 0) := (0, 0, 0, 0, 4, 3, 2, 1); signal probe_COEF : integer; begin CLK <= not (CLK) after 10 ns; process (CLK) This process calls the FLI function ... end process; End test_FLI;

Modelsim FLI VHDL-code (ctd.)


process (CLK) variable COEF : integer := 1; variable in_VAR : int_array(3 downto 0); variable out_VAR : int_array(3 downto 0); begin if rising_edge(CLK) then Storage(0) <= Storage(0) + 1; in_VAR := Storage(3 downto 0); my_proc(COEF, in_VAR, out_VAR); Storage(7 downto 4) <= out_VAR; COEF := COEF + 1; probe_COEF <= COEF; end if; end process;

Mixed Language Simulations


ModelSim single-kernel simulation allows you to simulate designs that are written in VHDL and/or Verilog. The boundaries between VHDL and Verilog are enforced at the level of a design unit.
This means that although a design unit must be either all VHDL or all Verilog, it may instantiate design units from either language. Any instance in the design hierarchy may be a design unit from either HDL without restriction.

Single-kernal simulation allows the top-level design unit to be either VHDL or Verilog.
As you traverse the design hierarchy, instantiations may freely switch back and forth between VHDL and Verilog.

Mixed Language Simulations


Once a Verilog module is compiled into a library (using the vlog command), you can use the vgencomp command to write its equivalent VHDL component declaration to standard output. Optional switches allow you to generate bit or vl_logic port types; std_logic port types are generated by default. Syntax
vgencomp [-help] [-lib <library_name>] [-b] [-s] [-v] <module_name>

Mixed Language Simulations


-help -lib <library_name> Displays the commands options and arguments. Optional. Specifies the pathname of the working library. If not specified, the default library work is used. Optional. Causes vgencomp to generate bit port types. Optional. Used for the explicit declaration of default std_logic port types. Optional. Causes vgencomp to generate vl_logic port types.Optional. Specifies the name of the Verilog module to be accessed. Required.

-b -s -v <module_name>

Example: Verilog and VHDL mixed


This example uses a Verilog module that is compiled into the work library. The module begins as Verilog source code:

Example: Verilog and VHDL mixed


and writes the following to stdout: component top generic( width : integer := 8; delay : real := 4.500000; filename : string := "file.in" ); port( i1 : in std_logic; o1 : out std_logic_vector(7 downto 0); o2 : out std_logic_vector(4 to 7); io1 : inout std_logic_vector --? (width-1 downto 0) ); end component;

module top(i1, o1, o2, io1); parameter width = 8; parameter delay = 4.5; parameter filename = "file.in"; input i1; output [7:0] o1; output [4:7] o2; inout [width-1:0] io1; endmodule After compiling (with vlog) , vgencomp is invoked on the compiled module: vgencomp top

Component/Technology Libraries
Used to verify post-synthesis behaviour May require usage of
Configuration files Global signals

Configuration files
A configuration allows you to replace a component inside the testbench without rewriting the code
Example
CONFIGURATION new_components OF test IS for test_exor for U1:exor use entity work.exor(structural) for structural for all:inverter use lsi10k.not_gate(behave) end for; end for; end for; end for; END new_components;

To use with Modelsim compiler:


vlib lsi10k vcom <file.vhd> -work lsi10k - creates a library name lsi10k - stores entities/components etc - from file.vhd in library lsi10k

Appendix
a b

Example: Power Calculation

c d e f g

Example: Power Calculation (ctd.)


VDD VL VOH VL VSS
Co

Example: Power Calculation


a
C
i

VDD VH VOL VH VSS


Co

q and
C
i

q <= a and b;

C
o

1) Find the VHDL source code for the component library

E=0.5*VDD*(VDD-VSS)*Co = (VSS=0 V) = 0.5*VDD*VDD*Co P=dE/dt

2) Use a script to modify the VHDL code a) Add a power calculation for each input and output in the description of the gate b) repeat step 2a) for every gate in the library 3) Recompile and store the VHDL code in a new library

Global resolved signal in package


package power_pack is type real_vector is array(integer range <>) of real; function sum(a:real_vector) return real; constant VDD:real:=5.0; end power_pack; package body power_pack is function sum(a:real_vector) return real is variable ret:real:=0.0; begin for i in arange loop ret:=ret+a(i); end loop; return ret; end sum; end power_pack; -- Volt signal switched_cap:sum real; -- Fahrad

Global resolved signal in package


a
Ci

and
Ci

q
Co

process(a) begin work.power_pack.switched_cap<=transport Ci_and; work.power_pack.switched_cap<=transport 0.0 after 1 ns; end process;

Example: Power Calculation (ctd.)


use work.power_pack.all; library lsi10k; use lsi10k.all; architecture test_circuit of test is signal a,b,q0,q1, ... :bit; signal energy:real; begin U0:and_gate port map(a,b,q0); U1:and_gate port map(c,d,q1); ... a<=not(a) after 10 ns; b<=not(b) after 20 ns; ... energy<=0.5*VDD*VDD*work.power_pack.switched_cap; end test_circuit;

You might also like