Unable to synthesize code. GHDL throws an array bounds error - vhdl

I'm new to Stack Overflow and to VHDL too. I have completed the logic of an N-bit shifter and tested it using a testbench. But am unable to synthesize it.
While synthesizing I get an error saying "left and right bounds of a slice must be either constant or dynamic" (it is in line 37 and 45, also visible in the attached picture). Can somebody please tell what I need to fix (and perhaps how)?
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
use work.types.all;
use work.functions.all;
use work.casts.all;
entity logbarrel is
generic ( N : natural := 32
);
port ( a : in std_logic_vector(N-1 downto 0); -- input data word
func : in std_logic_vector( 2 downto 0); -- ctrl word (000=>>, 001=<<, 010=*>, 011=<*, 100=>>>)
shamt : in std_logic_vector(log2(N)-1 downto 0); -- shift amount
y : out std_logic_vector(N-1 downto 0) -- output data word
);
end;
architecture rtl1 of logbarrel is
begin
process(all)
constant stage : natural := log2(N); -- number of stages
variable rotr : arr_of_slv(stage-1 downto 0)(N-1 downto 0); -- rotated words
variable mask : arr_of_slv( N-1 downto 0)(N-1 downto 0); -- masks for all possible shifts
variable sh : std_logic_vector(shamt'range) := (others =>'0'); -- used as actual shift amount
begin
-- left or right shift
if to_int(func) = 1 OR to_int(func) = 3 then --checking for left, easier
sh := (others =>'0'); --left makes sh = 000
else
sh := (0 => '1', others =>'0'); --right makes sh = 001
end if;
-- 1st stage
if shamt(0) = '1' then -- shift if needed
rotr(stage-1) := a(N*(1-to_int(sh))+2*to_int(sh)-2 downto 0) & a(N-1 downto N*(1-to_int(sh))+2*to_int(sh)-2+1); --rotate
else
rotr(stage-1) := a; --no shift
end if;
-- i-th stage
for i in stage-2 downto 0 loop
if shamt(stage-i-1) = '1' then -- shift if needed
rotr(i) := rotr(i+1)(N*(1-to_int(sh))+(2*to_int(sh)-1)*2**(stage-i-1)-1 downto 0) & rotr(i+1)(N-1 downto N*(1-to_int(sh))+(2*to_int(sh)-1)*2**(stage-i-1)); --rotate
else
rotr(i) := rotr(i+1); --no shift at this level
end if;
end loop;
-- mask the rotated data if needed
for i in 0 to N-1 loop
case func is
when "000" | "100" => mask(i) := (N-1 downto N-1-i+1 => '0') & (N-i-1 downto 0 => '1'); -- right shift
when "001" => mask(i) := (N-1 downto i => '1') & (i-1 downto 0 => '0'); -- left shift
when "010" | "011" => mask(i) := (others => '1'); -- rotate
when others => mask(i) := (others => '0'); -- this case 101 should not occur
end case;
end loop;
-- output masking
y <= (N-1 downto N-to_int(shamt) => a(N-1)) & (rotr(0)(N-to_int(shamt)-1 downto 0) AND mask(to_int(shamt))(N-to_int(shamt)-1 downto 0)) when func = "100" else -- masking for arith. right shift
rotr(0) AND mask(to_int(shamt)); -- masking for all other cases
end process;
end;
Here's the original code skeleton, on which I had to change the lines only where TODO was written
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
use work.types.all;
use work.functions.all;
use work.casts.all;
entity logbarrel is
generic ( N : natural := 32
);
port ( a : in std_logic_vector(N-1 downto 0); -- input data word
func : in std_logic_vector( 2 downto 0); -- ctrl word (000=>>, 001=<<, 010=*>, 011=<*, 100=>>>)
shamt : in std_logic_vector(log2(N)-1 downto 0); -- shift amount
y : out std_logic_vector(N-1 downto 0) -- output data word
);
end;
architecture rtl1 of logbarrel is
begin
process(all)
constant stage : natural := log2(N); -- number of stages
variable rotr : arr_of_slv(stage-1 downto 0)(N-1 downto 0); -- rotated words
variable mask : arr_of_slv( N-1 downto 0)(N-1 downto 0); -- masks for all possible shifts
variable sh : std_logic_vector(shamt'range) := (others =>'0'); -- used as actual shift amount
begin
-- left or right shift
if TODO then
sh := TODO
else
sh := TODO
end if;
-- 1st stage
if TODO then -- shift if needed
rotr(stage-1) := TODO
else
rotr(stage-1) := TODO
end if;
-- i-th stage
for i in TODO loop
if TODO then -- shift if needed
rotr(i) := TODO
else
rotr(i) := TODO
end if;
end loop;
-- mask the rotated data if needed
for i in 0 to N-1 loop
case func is
when TODO => mask(i) := TODO -- right shift
when TODO => mask(i) := TODO -- left shift
when TODO => mask(i) := TODO -- rotate
when others => mask(i) := TODO -- this case 101 should not occur
end case;
end loop;
-- output masking
y <= TODO when TODO else -- masking for arith. right shift
TODO -- masking for all other cases
end process;
end;
And here is the testbench used to test this as an instantiation. (It also initializes another such entity, I'll paste its code below, in case you want it).
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use work.casts.all;
use work.functions.all;
entity shifter_tb is
generic( N : natural := 32;
ainit: natural := 16#72345678#);
end;
architecture test of shifter_tb is
signal a, y1, y2 : std_logic_vector(N-1 downto 0):= to_slv(ainit,N);
signal func : std_logic_vector( 2 downto 0);
signal shamt : std_logic_vector(log2(N)-1 downto 0);
begin
stimuli: process
begin
-- for i in 0 to 2**a'length-1 loop
-- a <= to_slv(i, a'length);
for j in 0 to 4 loop --2**func'length-1 loop
func <= to_slv(j, func'length);
for k in 0 to 2**shamt'length-1 loop
shamt <= to_slv(k, shamt'length);
wait for 10 ns;
case func is
when "000" => assert (y1 = y2)
report strs(y1) & strs(y2) & " = " &
str(a) & " >> " & strs(to_int(shamt)) & str(func) ;
when "001" => assert (y1 = y2)
report strs(y1) & str(y2) & " = " &
str(a) & " << " & strs(to_int(shamt)) & str(func) ;
when "010" => assert (y1 = y2)
report strs(y1) & str(y2) & " = " &
str(a) & " *> " & strs(to_int(shamt)) & str(func) ;
when "011" => assert (y1 = y2)
report strs(y1) & str(y2) & " = " &
str(a) & " <* " & strs(to_int(shamt)) & str(func) ;
when others => assert (y1 = y2)
report strs(y1) & str(y2) & " = " &
str(a) & " >>> " & strs(to_int(shamt)) & str(func) ;
end case;
end loop;
end loop;
--end loop;
wait;
end process;
shifter1_inst: entity work.shifter
generic map (N => N)
port map (a, func, shamt, y1);
shifter2_inst: entity work.logbarrel
generic map (N => N)
port map (a, func, shamt, y2);
end;
The other entity called shifter (the golden model):
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
use work.types.all;
use work.functions.all;
use work.casts.all;
entity shifter is
generic ( N : natural := 32
);
port ( a : in std_logic_vector(N-1 downto 0);
func : in std_logic_vector( 2 downto 0);
shamt : in std_logic_vector(log2(N)-1 downto 0);
y : out std_logic_vector(N-1 downto 0)
);
end;
architecture rtl of shifter is
begin
process(all)
variable rotr, rotl, ashr, lshr, lshl : arr_of_slv(N-1 downto 0)(N-1 downto 0);
begin
lshr(0) := a; lshl(0) := a; ashr(0) := a; rotr(0) := a; rotl(0) := a;
for i in 1 to N-1 loop
lshr(i) := (i-1 downto 0 => '0') & a(N-1 downto i);
lshl(i) := a((N-1)-i downto 0) & (i-1 downto 0 => '0');
ashr(i) := (i-1 downto 0 => a(N-1)) & a(N-1 downto i);
rotr(i) := a( i-1 downto 0) & a(N-1 downto i);
rotl(i) := a((N-1)-i downto 0) & a(N-1 downto N-i);
end loop;
y <= lshr(to_int(shamt)) when func = "000" else
lshl(to_int(shamt)) when func = "001" else
rotr(to_int(shamt)) when func = "010" else
rotl(to_int(shamt)) when func = "011" else
ashr(to_int(shamt));
end process;
end;
And finally the header files (not sure what they're called in the VHDL world) that are being used in the testbench and the instantiated architectures:
types:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package types is
constant width : integer := 32;
subtype byte is natural range 7 downto 0;
subtype logic is std_logic;
subtype byteT is std_logic_vector(byte);
subtype word is std_logic_vector(width-1 downto 0);
subtype uword is unsigned(width-1 downto 0);
subtype sword is signed (width-1 downto 0);
type arr_of_slv is array (natural range <>) of std_logic_vector;
type matrix is array (natural range <>, natural range <>) of std_logic;
end;
package body types is
end;
functions:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.casts.all;
use work.types.all;
package functions is
function log2 (a : natural) return natural;
function replicate(s : std_logic; n: integer) return std_logic_vector;
function decode(arg : std_logic_vector) return std_logic_vector;
function mux(sel, x : std_logic_vector) return std_logic;
function mux(sel : std_logic_vector; x : arr_of_slv) return std_logic_vector;
-- function mux(sel : std_logic_vector; x : arr_of_slv (0 TO M-1)(N-1 downto 0)) return std_logic_vector is
function reduce(Inputs : std_logic_vector ) return std_logic_vector;
--function reduction( Inputs : arr_of_slv ) return std_logic_vector;
end;
package body functions is
function log2 (a: natural) return natural IS
variable val : natural := a;
variable log : natural := 0;
begin
for i in a downto 0 loop
val := val / 2;
if val > 0 then
log := log + 1;
end if;
end loop;
return log;
end;
function replicate(s: std_logic; n: integer) return std_logic_vector is
variable r : std_logic_vector(n-1 downto 0);
begin
for i in 0 to n-1 loop
r(i) := s;
end loop;
return r;
end;
function decode (arg : std_logic_vector) return std_logic_vector is
variable res : std_logic_vector((2**arg'length)-1 downto 0);
begin
res(to_int(arg)) := '1';
return res;
end;
function mux( sel, x : std_logic_vector ) return std_logic is
begin
return x(to_int(sel));
end;
function mux( sel : std_logic_vector; x: arr_of_slv) return std_logic_vector is
begin
-- assert Inputs'length <= 2 ** sel'length
-- report "Inputs size: " & integer'image(Inputs'length) & " is too big for the select";
return x(to_int(sel));
end;
-- function mux(sel : std_logic_vector; x : arr_of_slv (0 TO M-1)(N-1 downto 0)) return std_logic_vector is
-- variable y : std_logic_vector(x(0)'length-1 downto 0);
-- begin
-- y := x(to_int(sel));
-- return y;
-- end;
function reduce( Inputs : std_logic_vector ) return std_logic_vector is
constant N : integer := Inputs'length;
variable inp : std_logic_vector(N-1 downto 0);
begin
inp := Inputs;
if(N = 4) then
return inp(1 downto 0) xor inp(3 downto 2);
else
return reduce(inp((N-1) downto N/2)) xor reduce(inp(((N/2)-1) downto 0));
end if;
end;
-- function reduction( Inputs: arr_of_slv ) return std_logic_vector is
-- constant N : integer := Inputs'length;
-- variable inp : arr_of_slv(N-1 downto 0, 12-1 downto 0);
-- begin
-- --return x"1234"; --Inputs(0);
-- inp := Inputs;
-- if N = 1 then
-- return inp(0);
-- elsif N > 1 then
-- return reduction(inp(N-1 downto N/2)) xor reduction(inp(N/2-1 downto 0));
-- end if;
-- end;
end;
casts:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package casts is
function to_int(arg: std_logic_vector) return natural;
function to_sint(arg: std_logic_vector) return natural;
function to_int(arg: unsigned) return natural;
function to_int(arg: signed) return natural;
function to_slv(arg: integer; bits: integer) return std_logic_vector;
function to_slv(arg: unsigned) return std_logic_vector;
function to_slv(arg: signed) return std_logic_vector;
function to_slv(arg: std_ulogic_vector) return std_logic_vector;
function to_sslv(arg: integer; bits: natural) return std_logic_vector;
function str(s: std_ulogic_vector) return string;
function str(s: integer) return string;
function strs(s: std_ulogic_vector) return string;
function strs(s: integer) return string;
function strs(s: std_logic) return string;
function str(s: std_logic) return character;
end;
package body casts is
subtype logic is std_logic;
type logic_vector is array (natural range <>) of std_logic;
function to_int (arg: std_logic_vector) return natural IS
begin
return to_integer(unsigned(arg));
end;
function to_sint (arg: std_logic_vector) return natural IS
variable x : signed(arg'range);
begin
x := signed(arg);
return to_integer(x);
end;
function to_int (arg: unsigned) return natural IS
begin
return to_integer(arg);
end;
function to_int (arg: signed) return natural IS
begin
return to_integer(arg);
end;
function to_slv(arg: integer; bits: integer) return std_logic_vector is
begin
return std_logic_vector(to_unsigned(arg,bits));
end;
function to_sslv(arg: integer; bits: natural) return std_logic_vector is
begin
return std_logic_vector(to_signed(arg,bits));
end;
function to_slv(arg: unsigned) return std_logic_vector IS
begin
return std_logic_vector(arg);
end;
function to_slv(arg: std_ulogic_vector) return std_logic_vector IS
begin
return to_stdlogicvector(arg);
end;
function to_slv(arg: signed) return std_logic_vector IS
begin
return std_logic_vector(arg);
end;
function chr2sl (ch: in character) return std_logic is
begin
case ch is
when 'U' | 'u' => return 'U';
when 'X' | 'x' => return 'X';
when '0' => return '0';
when '1' => return '1';
when 'Z' | 'z' => return 'Z';
when 'W' | 'w' => return 'W';
when 'L' | 'l' => return 'L';
when 'H' | 'h' => return 'H';
when '-' => return '-';
when OTHERS => assert false
report "Illegal Character found" & ch
severity error;
return 'U';
end case;
end;
function str2sl (s: string) return std_logic_vector is
variable vector: std_logic_vector(s'LEFT - 1 DOWNTO 0);
begin
for i in s'RANGE loop
vector(i-1) := chr2sl(s(i));
end loop;
return vector;
end;
function to_char(s: std_ulogic) return character is
begin
case s is
when 'X' => return 'X';
when '0' => return '0';
when '1' => return '1';
when 'Z' => return 'Z';
when 'U' => return 'U';
when 'W' => return 'W';
when 'L' => return 'L';
when 'H' => return 'H';
when '-' => return '-';
end case;
end;
function str(s: std_ulogic_vector) return string is
variable ret:string(1 to s'length);
variable K : integer:= 1;
begin
for J in s'range loop
ret(K) := to_char(s(J));
K := K + 1;
end loop;
return ret;
end;
function strs(s: std_ulogic_vector) return string is
begin
return str(s) & ' ';
end;
function str(s: std_logic) return character is
begin
return to_char(s);
end;
function strs(s: std_logic) return string is
begin
return str(s) & ' ';
end;
function to_nstring(s: natural) return string is
variable ret, iret : string(1 to 16);
variable k, j : integer;
variable s1, s2, s3: natural := 0;
begin
s1 := s;
ret(1) := '0';
k := 1;
while (s1 > 0 and K < 16) loop
s2 := s1 / 10;
s3 := s1 - (s2 * 10);
if (s3 = 0) then
ret(k) := '0';
elsif (s3 = 1) then
ret(k) := '1';
elsif (s3 = 2) then
ret(k) := '2';
elsif (s3 = 3) then
ret(k) := '3';
elsif (s3 = 4) then
ret(k) := '4';
elsif (s3 = 5) then
ret(k) := '5';
elsif (s3 = 6) then
ret(k) := '6';
elsif (s3 = 7) then
ret(k) := '7';
elsif (s3 = 8) then
ret(k) := '8';
elsif (s3 = 9) then
ret(k) := '9';
end if;
k := k + 1;
s1 := s2;
end loop;
if (k > 1) then
k := k-1;
end if;
J := 1;
while (k > 0) loop
iret(j) := ret(k);
k := k-1;
j := j+1;
end loop;
return iret;
end;
function str(s: integer) return string is
begin
if (s < 0) then
return "-" & to_nstring(-s);
else
return to_nstring(s);
end if;
end;
function strs(s: integer) return string is
begin
return str(s) & ' ';
end;
end;

Related

How to fix 'ERROR:Xst - basic_stringFATAL_ERROR' error in Xilinx fpga?

I have been trying to synthesize a vhdl code which simulates perfectly in Active HDL but I get the following error when synthesizing.
ERROR:Xst - basic_stringFATAL_ERROR:Xst:Portability/export/Port_Main.h:159:1.18 - This application has discovered an exceptional condition from which it cannot recover. For technical support on this issue, please visit http://www.xilinx.com/support.
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_UNSIGNED.all;
--use IEEE.NUMERIC_STD_UNSIGNED.all;
library work;
use work.common.all;
library UNISIM;
use UNISIM.VComponents.all;
entity main is
port(
CLK : in STD_LOGIC;
reset : in STD_LOGIC;
V_Out : out STD_LOGIC
);
end main;
--}} End of automatically maintained section
architecture main of main is
signal text : string (1 to 15) := "This is a Test.";
signal text_len : integer := 15;
signal x : integer := 50;
signal y : integer := 50;
type vramt is array (0 to H_480_272p_AV*V_480_272p_AV-1) of std_logic_vector (0 downto 0);
signal vram : vramt := (others => (others => '0'));
--signal vram : std_logic_vector(H_480_272p_AV*V_480_272p_AV-1 downto 0) := (others => '0');
attribute RAM_STYLE : string;
attribute RAM_STYLE of vram: signal is "BLOCK";
signal vram_we : std_logic;
signal vram_addr, vram_wraddr : INTEGER range 0 to H_480_272p_AV*V_480_272p_AV-1;
signal rom_addr : std_logic_vector(10 downto 0);
signal rom_data : std_logic_vector(7 downto 0);
begin
inst_get_char : entity work.Font_Rom PORT MAP (
clk => CLK,
addr => rom_addr,
data => rom_data
);
Process (CLK)
begin
if rising_edge (CLK) then
if vram_addr = H_480_272p_AV*V_480_272p_AV-1 then
vram_addr <= 0;
end if;
vram_addr <= vram_addr + 1;
V_Out <= vram(vram_addr)(0);
end if;
end process;
Process (CLK)
variable char_count : integer := 1;
variable pix_line : integer := 0;
variable bit_count : integer := 0;
variable curr_char : std_logic_vector(7 downto 0);
variable bit_data : std_logic;
begin
if rising_edge(CLK) then
if bit_count = 0 then
rom_addr <= std_logic_vector(to_unsigned(character'pos(text(char_count)), 7)) & std_logic_vector(to_unsigned(pix_line, 4));
end if;
bit_data := rom_data(bit_count);
vram_wraddr <= (y + pix_line)*H_480_272p_AV + (x + bit_count + (8* (char_count-1)));
vram(vram_wraddr)(0) <= bit_data;
if bit_count = 7 then
bit_count := 0;
if pix_line = 15 then
pix_line := 0;
if char_count = text_len then
char_count := 1;
else
char_count := char_count + 1;
end if;
else
pix_line := pix_line + 1;
end if;
else
bit_count := bit_count + 1;
end if;
end if;
end Process;
end main;

Unexpected function output when function parameter is negated

I have a priority encoding function that returns a vector containing a 1 at the position where the first 1 is found in the input vector. The function works as expected, unless I try to negate the input vector. Here's an example that demonstrates the unexpected behavior:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
entity tb IS
end tb;
architecture run of tb is
constant N : natural := 5;
function get_first_one_in_vec (vec_in: std_logic_vector) return std_logic_vector is
variable ret: std_logic_vector(vec_in'high downto vec_in'low);
begin
ret := (others => '0');
for i in vec_in'low to vec_in'high loop
if vec_in(i)='1' then
ret(i) := '1';
exit;
end if;
end loop;
return ret;
end get_first_one_in_vec;
signal a : std_logic_vector(N-1 downto 0);
signal abar : std_logic_vector(N-1 downto 0);
signal first_a : std_logic_vector(N-1 downto 0);
signal first_nota : std_logic_vector(N-1 downto 0);
signal first_abar : std_logic_vector(N-1 downto 0);
begin
process
begin
a <= "10100";
wait for 10 ns;
a <= "01011";
wait for 10 ns;
wait;
end process;
abar <= not(a);
first_a <= get_first_one_in_vec(a);
first_nota <= get_first_one_in_vec(not(a));
first_abar <= get_first_one_in_vec(abar);
end run;
To my understanding, first_nota should be the same as first_abar. However, my simulator (ModelSim - Intel FPGA Starter Edition 10.5b, rev. 2016.10) thinks otherwise, as you can see here:
What am I missing here?
This works OK:
function get_first_one_in_vec (vec_in: std_logic_vector) return std_logic_vector is
variable ret: std_logic_vector(vec_in'length downto 1);
variable inp: std_logic_vector(vec_in'length downto 1) := vec_in;
begin
ret := (others => '0');
for i in inp'right to inp'left loop
if inp(i)='1' then
ret(i) := '1';
exit;
end if;
end loop;
return ret;
end get_first_one_in_vec;
https://www.edaplayground.com/x/3zP_
Why does yours not work? Well, when you call your function with the not operator* as part of the expression:
first_nota <= get_first_one_in_vec(not a);
the numbering of the input to the function is changed to 1 to by the not operator. Why? Here is the code for the not operator and you can see why:
-------------------------------------------------------------------
-- not
-------------------------------------------------------------------
FUNCTION "not" ( l : std_logic_vector ) RETURN std_logic_vector IS
-- pragma built_in SYN_NOT
-- pragma subpgm_id 204
--synopsys synthesis_off
ALIAS lv : std_logic_vector ( 1 TO l'LENGTH ) IS l;
VARIABLE result : std_logic_vector ( 1 TO l'LENGTH ) := (OTHERS => 'X');
--synopsys synthesis_on
BEGIN
--synopsys synthesis_off
FOR i IN result'RANGE LOOP
result(i) := not_table( lv(i) );
END LOOP;
RETURN result;
--synopsys synthesis_on
END;
---------------------------------------------------------------------
Anyway, this breaks your code (which starts scanning from the other end of the word).
One way of making function agnostic to the ordering of the numbering of its input is to normalise the inputs like this:
variable inp: std_logic_vector(vec_in'length downto 1) := vec_in;
Once you have done this, you're in control. So, instead of loops from 'high downto 'low, we can be more explicit and loop from 'right to 'left:
for i in inp'right to inp'left loop
not is an operator not a function. You don't need the brackets.

"Iteration limit reached at time" when i try to simulate my code

I'm trying to implement Booth Algorithm in VHDL, already run a "paper test" and the code apparently works but when I simulate it I'm not getting the desire results... Then I replace the code to do an A-Shift to test but when I simulate my code I'm getting this error:
Error (suppressible): (vsim-3601) Iteration limit 5000 reached at time 180 ns.
I just replace this line: P := STD_LOGIC_VECTOR(unsigned(P) SRA 1);
For this: P := P(16) & P(16 downto 1);
This is the code atm:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY algor_booth IS
PORT(oper1 : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
oper2 : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
sel : IN STD_LOGIC;
result : OUT STD_LOGIC_VECTOR(15 DOWNTO 0)
);
END ENTITY;
ARCHITECTURE algor OF algor_booth IS
BEGIN
PROCESS (sel)
VARIABLE A, S, P: STD_LOGIC_VECTOR(16 DOWNTO 0);
VARIABLE Ma2: STD_LOGIC_VECTOR(7 DOWNTO 0);
--VARIABLE flag: STD_LOGIC;
BEGIN
IF sel = '0' THEN
Ma2 := (NOT oper1) + 1;
A := oper1 & "00000000" & '0';
S := Ma2 & "00000000" & '0';
P := "00000000" & oper2 & '0';
ELSE
--flag := '0';
FOR i IN 1 TO 8 LOOP
IF P(1 DOWNTO 0) = "01" THEN
P := P + A;
--flag := '0';
--P(17) := flag;
ELSIF P(1 DOWNTO 0) = "10" THEN
P := P + S;
--flag := '1';
--P(17) := flag;
END IF;
--P(17) := flag;
P := P(16) & P(16 downto 1);
--P(17) := flag;
END LOOP;
result <= P(16 DOWNTO 1);
END IF;
END PROCESS;
END algor;
After trying a lot, just changed this line: P := P(16) & P(16 downto 1);
For this one: P(16 downto 0) := P(17 downto 1);
And problem solved!
Here is the fixed code:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY algor_booth IS
PORT(oper1 : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
oper2 : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
sel : IN STD_LOGIC;
result : OUT STD_LOGIC_VECTOR(15 DOWNTO 0)
);
END ENTITY;
ARCHITECTURE algor OF algor_booth IS
BEGIN
PROCESS (oper1, oper2)
VARIABLE A, S, P: STD_LOGIC_VECTOR(17 DOWNTO 0);
VARIABLE Ma2: STD_LOGIC_VECTOR(7 DOWNTO 0);
VARIABLE flag: STD_LOGIC;
BEGIN
Ma2 := (NOT oper1) + 1;
A := '0' & oper1 & "00000000" & '0';
S := '0' & Ma2 & "00000000" & '0';
P := '0' & "00000000" & oper2 & '0';
flag := '0';
FOR i IN 1 TO 8 LOOP
IF (P(1) = '0' AND P(0) = '1') THEN
flag := '0';
P(17) := flag;
P := P + A;
ELSIF (P(1) = '1' AND P(0) = '0') THEN
flag := '1';
P(17) := flag;
P := P + S;
END IF;
P(17) := flag;
P(16 downto 0) := P(17 downto 1);
P(17) := flag;
END LOOP;
result <= P(16 DOWNTO 1);
END PROCESS;
END algor;
Thanks for your help guys!

Is there a way to print the values of a signal to a file from a modelsim simulation?

I need to get the values of several signals to check them against the simulation (the simulation is in Matlab). There are many values, and I want to get them in a file so that I could run it in a script and avoid copying the values by hand.
Is there a way to automatically print the values of several signals into a text file?
(The design is implemented in VHDL)
First make functions that convert std_logic and std_logic_vector to
string like:
function to_bstring(sl : std_logic) return string is
variable sl_str_v : string(1 to 3); -- std_logic image with quotes around
begin
sl_str_v := std_logic'image(sl);
return "" & sl_str_v(2); -- "" & character to get string
end function;
function to_bstring(slv : std_logic_vector) return string is
alias slv_norm : std_logic_vector(1 to slv'length) is slv;
variable sl_str_v : string(1 to 1); -- String of std_logic
variable res_v : string(1 to slv'length);
begin
for idx in slv_norm'range loop
sl_str_v := to_bstring(slv_norm(idx));
res_v(idx) := sl_str_v(1);
end loop;
return res_v;
end function;
Using the bit-wise format has the advantage that any non-01 values will show
with the exact std_logic value, which is not the case for e.g. hex
presentation.
Then make process that writes the strings from std_logic and
std_logic_vector to file for example at rising_edge(clk) like:
library std;
use std.textio.all;
...
process (clk) is
variable line_v : line;
file out_file : text open write_mode is "out.txt";
begin
if rising_edge(clk) then
write(line_v, to_bstring(rst) & " " & to_bstring(cnt_1) & " " & to_bstring(cnt_3));
writeline(out_file, line_v);
end if;
end process;
The example above uses rst as std_logic, and cnt_1 and cnt_3 as
std_logic_vector(7 downto 0). The resulting output in "out.txt" is then:
1 00000000 00000000
1 00000000 00000000
1 00000000 00000000
0 00000000 00000000
0 00000001 00000011
0 00000010 00000110
0 00000011 00001001
0 00000100 00001100
0 00000101 00001111
0 00000110 00010010
I would like to present a flexible way to convert std_logic(_vector) to a string:
First you can define two functions to convert std_logic-bits and digits to a character:
FUNCTION to_char(value : STD_LOGIC) RETURN CHARACTER IS
BEGIN
CASE value IS
WHEN 'U' => RETURN 'U';
WHEN 'X' => RETURN 'X';
WHEN '0' => RETURN '0';
WHEN '1' => RETURN '1';
WHEN 'Z' => RETURN 'Z';
WHEN 'W' => RETURN 'W';
WHEN 'L' => RETURN 'L';
WHEN 'H' => RETURN 'H';
WHEN '-' => RETURN '-';
WHEN OTHERS => RETURN 'X';
END CASE;
END FUNCTION;
function to_char(value : natural) return character is
begin
if (value < 10) then
return character'val(character'pos('0') + value);
elsif (value < 16) then
return character'val(character'pos('A') + value - 10);
else
return 'X';
end if;
end function;
And now it's possible to define two to_string functions which convert from boolean and std_logic_vector to string:
function to_string(value : boolean) return string is
begin
return str_to_upper(boolean'image(value)); -- ite(value, "TRUE", "FALSE");
end function;
FUNCTION to_string(slv : STD_LOGIC_VECTOR; format : CHARACTER; length : NATURAL := 0; fill : CHARACTER := '0') RETURN STRING IS
CONSTANT int : INTEGER := ite((slv'length <= 31), to_integer(unsigned(resize(slv, 31))), 0);
CONSTANT str : STRING := INTEGER'image(int);
CONSTANT bin_len : POSITIVE := slv'length;
CONSTANT dec_len : POSITIVE := str'length;--log10ceilnz(int);
CONSTANT hex_len : POSITIVE := ite(((bin_len MOD 4) = 0), (bin_len / 4), (bin_len / 4) + 1);
CONSTANT len : NATURAL := ite((format = 'b'), bin_len,
ite((format = 'd'), dec_len,
ite((format = 'h'), hex_len, 0)));
VARIABLE j : NATURAL := 0;
VARIABLE Result : STRING(1 TO ite((length = 0), len, imax(len, length))) := (OTHERS => fill);
BEGIN
IF (format = 'b') THEN
FOR i IN Result'reverse_range LOOP
Result(i) := to_char(slv(j));
j := j + 1;
END LOOP;
ELSIF (format = 'd') THEN
Result(Result'length - str'length + 1 TO Result'high) := str;
ELSIF (format = 'h') THEN
FOR i IN Result'reverse_range LOOP
Result(i) := to_char(to_integer(unsigned(slv((j * 4) + 3 DOWNTO (j * 4)))));
j := j + 1;
END LOOP;
ELSE
REPORT "unknown format" SEVERITY FAILURE;
END IF;
RETURN Result;
END FUNCTION;
This to_string function can convert std_logic_vectors to binary (format='b'), dicimal (format='d') and hex (format='h'). Optionally you can define a minimum length for the string, if length is greater then 0, and a fill-character if the required length of the std_logic_vector is shorter then length.
And here are the required helper function:
-- calculate the minimum of two inputs
function imin(arg1 : integer; arg2 : integer) return integer is
begin
if arg1 < arg2 then return arg1; end if;
return arg2;
end function;
-- if-then-else for strings
FUNCTION ite(cond : BOOLEAN; value1 : STRING; value2 : STRING) RETURN STRING IS
BEGIN
IF cond THEN
RETURN value1;
ELSE
RETURN value2;
END IF;
END FUNCTION;
-- a resize function for std_logic_vector
function resize(vec : std_logic_vector; length : natural; fill : std_logic := '0') return std_logic_vector is
constant high2b : natural := vec'low+length-1;
constant highcp : natural := imin(vec'high, high2b);
variable res_up : std_logic_vector(vec'low to high2b);
variable res_dn : std_logic_vector(high2b downto vec'low);
begin
if vec'ascending then
res_up := (others => fill);
res_up(vec'low to highcp) := vec(vec'low to highcp);
return res_up;
else
res_dn := (others => fill);
res_dn(highcp downto vec'low) := vec(highcp downto vec'low);
return res_dn;
end if;
end function;
Ok, this solution looks a bit long, but if you gather some of this functions -- and maybe overload them for several types -- you get an extended type converting system and in which you can convert nearly every type to every other type or representation.
Because there's more than one way to skin a cat:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-- library std;
use std.textio.all;
entity changed_morten is
end entity;
architecture foo of changed_morten is
signal clk: std_logic := '0';
signal rst: std_logic := '1';
signal cnt_1: unsigned (7 downto 0);
signal cnt_3: unsigned (7 downto 0);
function string_it (arg:unsigned) return string is
variable ret: string (1 to arg'LENGTH);
variable str: string (1 to 3); -- enumerated type "'X'"
alias varg: unsigned (1 to arg'LENGTH) is arg;
begin
if arg'LENGTH = 0 then
ret := "";
else
for i in varg'range loop
str := std_logic'IMAGE(varg(i));
ret(i) := str(2); -- the actual character
end loop;
end if;
return ret;
end function;
begin
PRINT:
process (clk) is
variable line_v : line;
variable str: string (1 to 3); -- size matches charcter enumeration
file out_file : text open write_mode is "out.txt";
begin
if rising_edge(clk) then
str := std_logic'IMAGE(rst);
write ( line_v,
str(2) & " " &
string_it(cnt_1) & " " &
string_it(cnt_3) & " "
);
writeline(out_file, line_v);
end if;
end process;
COUNTER1:
process (clk,rst)
begin
if rst = '1' then
cnt_1 <= (others => '0');
elsif rising_edge(clk) then
cnt_1 <= cnt_1 + 1;
end if;
end process;
COUNTER3:
process (clk,rst)
begin
if rst = '1' then
cnt_3 <= (others => '0');
elsif rising_edge(clk) then
cnt_3 <= cnt_3 + 3;
end if;
end process;
RESET:
process
begin
wait until rising_edge(clk);
wait until rising_edge(clk);
wait until rising_edge(clk);
rst <= '0';
wait;
end process;
CLOCK:
process
begin
wait for 10 ns;
clk <= not clk;
if Now > 210 ns then
wait;
end if;
end process;
end architecture;
And mostly because Morten's expression
"" & std_logic'image(sl)(2); -- "" & character to get string
isn't accepted by ghdl, it's not an indexed name, the string is unnamed.
The issue appears to be caused by the lack of recognition of the function call ('IMAGE) being recognized as a prefix for the indexed name. For any ghdl users you'd want to use an intermediary named string target for the output of the attribute function call (shown in the string_it function and in line in the PRINT process). I submitted a bug report.
Addendum
Another way to express Morten's to_bstring(sl : std_logic) return string function is:
function to_bstring(sl : std_logic) return string is
variable sl_str_v : string(1 to 3) := std_logic'image(sl); -- character literal length 3
begin
return "" & sl_str_v(2); -- "" & character to get string
end function;
And the reason this works is because function calls are dynamically elaborated, meaning the string sl_str_v is created each time the function is called.
See IEEE Std 1076-1993 12.5 Dynamic elaboration, b.:
Execution of a subprogram call involves the elaboration of the
parameter interface list of the corresponding subprogram declaration;
this involves the elaboration of each interface declaration to create
the corresponding formal parameters. Actual parameters are then
associated with formal parameters. Finally, if the designator of the
subprogram is not decorated with the 'FOREIGN attribute defined in
package STANDARD, the declarative part of the corresponding subprogram
body is elaborated and the sequence of statements in the subprogram
body is executed.
The description of dynamic elaboration of a subprogram call has been expanded a bit in IEEE Std 1076-2008, 14.6.

fatal error in modelsim during simulation

This is my main code in VHDL:
library ieee;
USE ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity pid is
port( error ,Kp, Ti, Td ,dt: in std_logic_vector(7 downto 0);
reset : in std_logic;
output :out std_logic_vector(31 downto 0) );
end pid;
architecture pid_arch of pid is
-------------------------------- functions
function add_vec(num1,num2,num3: in std_logic_vector(15 downto 0)) return std_logic_vector is
variable v_TEST_VARIABLE1: integer;
variable v_TEST_VARIABLE2: integer;
variable v_TEST_VARIABLE3: integer;
variable n_times1: integer;
variable n_times2: integer;
variable sum: integer;
begin
v_TEST_VARIABLE1 := to_integer(unsigned(num1)) ;
v_TEST_VARIABLE2 := to_integer(unsigned(num2)) ;
v_TEST_VARIABLE3 := to_integer(unsigned(num3 ));
--for n_times1 in 1 to v_TEST_VARIABLE2 loop
-- v_TEST_VARIABLE1: = v_TEST_VARIABLE1 + '1';
-- end loop;
-- for n_times2 in 1 to v_TEST_VARIABLE3 loop
-- v_TEST_VARIABLE1:= v_TEST_VARIABLE1 + '1';
-- end loop;
sum:= v_TEST_VARIABLE1+ v_TEST_VARIABLE2 + v_TEST_VARIABLE3;
return std_logic_vector(to_unsigned(sum,32));
end add_vec;
-----------------------------------
function sub(num1, num2: in std_logic_vector(7 downto 0)) return std_logic_vector is
variable v_TEST_VARIABLE1: integer;
variable v_TEST_VARIABLE2: integer;
variable difference: integer;
begin
v_TEST_VARIABLE1 := to_integer(unsigned(num1)) ;
v_TEST_VARIABLE2 := to_integer(unsigned(num2)) ;
difference := v_TEST_VARIABLE1 - v_TEST_VARIABLE2;
return std_logic_vector(to_unsigned(difference,8));
end sub;
------------------------------------
function mul(num1,num2 : in std_logic_vector(7 DOWNTO 0)) return std_logic_vector is
variable v_TEST_VARIABLE1 : integer;
variable v_TEST_VARIABLE2 : integer;
variable n_times: integer:=1;
variable product: integer:=0;
begin
v_TEST_VARIABLE1 := to_integer(unsigned(num1)) ;
v_TEST_VARIABLE2 := to_integer(unsigned(num2)) ;
for n_times in 1 to v_TEST_VARIABLE2 loop
product:=product + v_TEST_VARIABLE1;
end loop;
return std_logic_vector(to_unsigned(product,16));
end mul;
--------------------------------
function div(num1, num2 : in std_logic_vector(7 DOWNTO 0)) return std_logic_vector is
variable v_TEST_VARIABLE1 : integer;
variable v_TEST_VARIABLE2 : integer;
variable quotient :integer;
-- begin
--P3: PROCESS(num1, num2)
variable n_times: integer:=1;
begin
if num1>num2 then
v_TEST_VARIABLE1 := to_integer(unsigned(num1)) ;
v_TEST_VARIABLE2 := to_integer(unsigned(num2)) ;
L1:loop
n_times := n_times + 1;
exit when ((v_TEST_VARIABLE2 - v_TEST_VARIABLE1)>0);
v_TEST_VARIABLE1 := v_TEST_VARIABLE1 - v_TEST_VARIABLE2;
end loop L1;
quotient := n_times-1;
elsif num2>num1 then
v_TEST_VARIABLE1 := to_integer(unsigned(num1)) ;
v_TEST_VARIABLE2 := to_integer(unsigned(num2)) ;
L2:loop
n_times:=n_times+1;
exit when ((v_TEST_VARIABLE1 - v_TEST_VARIABLE2)>0);
v_TEST_VARIABLE2 := v_TEST_VARIABLE2 - v_TEST_VARIABLE1;
quotient := n_times-1;
end loop L2;
else
quotient := 1;
end if;
return std_logic_vector(to_unsigned(quotient,16));
-- end PROCESS P3;
end div;
---------------------------------
function derivative(error, previous_error, dt :in std_logic_vector(7 downto 0)) return std_logic_vector is
variable derivative_val: std_logic_vector(15 downto 0);
begin
derivative_val := div(sub(error,previous_error),dt);
return derivative_val;
end derivative;
--------------------------------------------
function integration(error,dt:in std_logic_vector(7 downto 0);current_integration :in std_logic_vector(15 downto 0);reset : in std_logic) return std_logic_vector is
begin
if (reset='1') then
return "0000000000000000";
else
--current_integration := add_vec(current_integration, mul(error,dt),x"0000");
-- return current_integration;
return add_vec(current_integration, mul(error,dt),x"0000");
end if;
end integration;
-------------------------
begin
P1:PROCESS (reset ,error , Kp, Ti, Td)
variable proportional_term : std_logic_vector(15 downto 0):=x"0000";
variable derivative1: std_logic_vector(15 downto 0) := x"0000";
variable derivative_term: std_logic_vector(31 downto 0) ;
variable integration1: std_logic_vector(15 downto 0) :=x"0000";
variable integration_term : std_logic_vector(15 downto 0) := x"0000";
variable current_integration: std_logic_vector(15 downto 0) ;
variable previous_error: std_logic_vector(7 downto 0) := "00000000";
variable v1: std_logic_vector( 15 downto 0);
variable v2 : std_logic_vector( 23 downto 0);
variable v3 : std_logic_vector (7 downto 0);
------------------checked till here
begin
if (reset='1') then
-- output <= x"00000000";
previous_error :="00000000";
current_integration := x"0000";
else
--output <= Kp*(error + integration/Ti + derivative*Td);
current_integration := integration1;
end if;
-- proportional_term := mul(Kp,error);
proportional_term := std_logic_vector(unsigned(Kp) * unsigned(error));
-- derivative_term := mul(mul(Kp,Td), derivative(error, previous_error,dt));
v1 :=std_logic_vector(unsigned(Kp)*unsigned(Td));
derivative1 := derivative(error, previous_error,dt);
derivative_term := std_logic_vector(unsigned(v1)*unsigned(derivative1));
integration1 :=integration(error,dt,current_integration,reset);
v2 :=std_logic_vector((unsigned(Kp)*unsigned(integration1)));
v3 := std_logic_vector(resize(unsigned(v2),8));
integration_term := div( v3, Ti);
-- integration_term := div(mul(Kp, integration(error,dt,current_integration,reset)) , Ti);
previous_error :=error;
output <= add_vec(std_logic_vector(resize(unsigned(proportional_term),16)) , std_logic_vector(resize(unsigned(derivative_term),16)), std_logic_vector(resize(unsigned(integration_term),16)));
--output <= x"0000";
--Kp*(error + integration/Ti + derivative*Td);
END PROCESS P1;
end pid_arch;
And this is the testbench:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use IEEE.numeric_std.all;
ENTITY pid_2_tb IS
END pid_2_tb;
ARCHITECTURE behavior OF pid_2_tb IS
COMPONENT pid --'test' is the name of the module needed to be tested.
port(error ,Kp, Ti, Td ,dt: in std_logic_vector(7 downto 0);
reset : in std_logic;
output :out std_logic_vector(31 downto 0) );
END COMPONENT;
signal error : std_logic_vector(7 downto 0) := "00000000";
signal Kp : std_logic_vector(7 downto 0) := "00001000";
signal Ti : std_logic_vector(7 downto 0) := "00000001";
signal Td : std_logic_vector(7 downto 0) := "00000001";
signal dt : std_logic_vector(7 downto 0) := "00000001";
signal reset : std_logic := '1';
signal output : std_logic_vector(31 downto 0);
constant clk_period : time := 1 ns;
BEGIN
uut: pid PORT MAP (
error => error,
Kp => Kp,
Ti => Ti,
Td => Td,
dt => dt,
reset => reset,
output => output
);
clk_process :process
begin
error <= "00000001";
reset <= '1';
wait for clk_period/2;
error <= "00000010";
reset <= '0';
wait for clk_period/2; --for next 0.5 ns signal is '1'.
end process;
-- Stimulus process
stim_proc: process
begin
wait for 17 ns;
error <= "00000011";
reset <= '0';
wait for 1 ns;
error <= "00000010";
reset <= '0';
wait;
end process;
END;
The two show no error on compilation. I have tried simulating for smaller programs using the same functions, and that worked well.
But on simulation it gives Fatal error. What can be the reasons for the same?
I am a newbie in vhdl. Please help me out.
Thanks in advance.
Your process P1 in entity pid loops continuously. I would imagine Modelsim uses a guard timer to cause an exception when something spins continuously.
I found this by divide and conquer:
ghdl -a pid.vhdl # analyze, also contains pid_2_tb entity/architecture
ghdl -e pid_2_tb # elaborates
ghdl -r pid_2_tb --stop-time=100ns # run the simulation (batch mode) guard time to stop)
Ran forever so:
ghdl -e pid # elaborate just the component
ghdl -r pid --stop-time=30ns # run just the component
../../../src/ieee/numeric_std-body.v93:2098:7:#0ms:(assertion warning): NUMERIC_STD.TO_INTEGER: metavalue detected, returning 0
../../../src/ieee/numeric_std-body.v93:2098:7:#0ms:(assertion warning): NUMERIC_STD.TO_INTEGER: metavalue detected, returning 0
(And it was at least doing something - while still running forever).
So knew which part of your design (entity/architecture pid) to focus on. Looked immediately at the process and found no wait nor a sensitivity statement.
Commented out the sensitivity list in P1 and put a wait statement before the first function call (derivative). That finished.
Moved the wait statement before the next function call in P1 (to div). Never finished.
So your derivative function doesn't complete. And horror of horrors the derivative function contains calls to to div and sub.
Looking in the first function call (to div) in function derivative and we find not one but two loop unbounded loop statements:
function div(num1, num2 : in std_logic_vector(7 downto 0))
return std_logic_vector is
variable v_test_variable1: integer;
variable v_test_variable2: integer;
variable quotient: integer;
variable n_times: integer:= 1;
begin
if num1 > num2 then
v_test_variable1 := to_integer(unsigned(num1)) ;
v_test_variable2 := to_integer(unsigned(num2)) ;
l1:
loop
n_times := n_times + 1;
exit when ((v_test_variable2 - v_test_variable1) > 0);
v_test_variable1 := v_test_variable1 - v_test_variable2;
end loop l1;
quotient := n_times - 1;
elsif num2 > num1 then
v_test_variable1 := to_integer(unsigned(num1));
v_test_variable2 := to_integer(unsigned(num2));
l2:
loop
n_times := n_times + 1;
exit when ((v_test_variable1 - v_test_variable2) > 0);
v_test_variable2 := v_test_variable2 - v_test_variable1;
quotient := n_times - 1;
end loop l2;
else
quotient := 1;
end if;
return std_logic_vector(to_unsigned(quotient,16));
end div;
I'm not inclined to independently test your algorithm (say in C or use report statements) but I'd guess the difference between v_test_variable1 and v_test_variable2 doesn't go positive in one of the two loops, or one of them should compare Less Than instead of Greater Than. Another possibility is that you zero something out.
Your code doesn't look synthesis eligible, either. You don't have loops that are unbounded. Loops are unrolled in synthesis and required to have a static number of iterations.
And of course you could have an additional problem somewhere else.
The div function uses a loop where the exit condition never becomes true,
whereby the div function will never return, thus the simulation time will
never advance.
One relevant part of the div code is in:
elsif num2 > num1 then
v_TEST_VARIABLE1 := to_integer(unsigned(num1));
v_TEST_VARIABLE2 := to_integer(unsigned(num2));
L2 : loop
n_times := n_times+1;
exit when ((v_TEST_VARIABLE1 - v_TEST_VARIABLE2) > 0);
v_TEST_VARIABLE2 := v_TEST_VARIABLE2 - v_TEST_VARIABLE1;
quotient := n_times-1;
end loop L2;
But if num1 is 0 (zero) then v_TEST_VARIABLE2 is never decremented in the
loop, thus ((v_TEST_VARIABLE1 - v_TEST_VARIABLE2) > 0) never becomes true.
The div function must be updated to handle this case also, or arguments must
be guaranteed never to result in the case.

Resources