My function does not return a value, and I do not understand why? VHDL - vhdl

Part of code in VHDL. Workspace ISE.
My function does not return a value, and I do not understand why
Note that appears to me in ISE is "function 'con_integer14' does not always return a value."
The Function is:
function con_integer14 (vNumberSTD : std_logic_vector(14 downto 0)) return integer is
variable vCounter : integer range 0 to 16 := 0;
variable vNumberINT : integer range 0 to 16384 := 0;
begin
if (vCounter = 0) then
if ((vNumberSTD(vCounter)) = '1') then
vNumberINT := (vNumberINT+(2**vCounter));
elsif ((vNumberSTD(vCounter)) = '0') then
vNumberINT := vNumberINT;
end if;
vCounter := (vCounter+1);
elsif ((vCounter >= 1)or(vCounter < 14)) then
if ((vNumberSTD(vCounter)) = '1') then
vNumberINT := (vNumberINT+(2**vCounter));
elsif ((vNumberSTD(vCounter)) = '0') then
vNumberINT := vNumberINT;
end if;
vCounter := (vCounter+1);
elsif (vCounter = 14) then
if ((vNumberSTD(vCounter)) = '1') then
vNumberINT := (vNumberINT+(2**vCounter));
elsif ((vNumberSTD(vCounter)) = '0') then
vNumberINT := vNumberINT;
end if;
vCounter := (vCounter+1);
elsif (vCounter = 15) then
return vNumberINT;
vCounter := 0;
elsif (vCounter > 15) then
vNumberINT := 0;
vCounter := 0;
end if;
end function con_integer14;
Please help me, thank you :)

I'd go a step further and tell you your function never returns a value. I took the liberty of removing the superfluous parentheses and then took a look at the function's structure.
You're going to execute the first if statement and fail to return a value - there is no return statement in reach.
Add a test bench:
library ieee;
use ieee.std_logic_1164.all;
use work.foo.all;
entity fum is
end entity;
architecture fie of fum is
signal vNumberINT: integer range 0 to 16384;
signal vNumberSTD: std_logic_vector(14 downto 0) := "011001110111100";
begin
CALL:
process
begin
wait for 1 ns;
vNumberINT <= con_integer14(VNumberSTD);
wait for 1 ns;
wait;
end process;
end architecture;
Analyze it, elaborate it and run it:
ghdl -a something.vhdl
david_koontz#Macbook: ghdl -e fum
david_koontz#Macbook: ghdl -r fum
./fum:error: missing return in
function at something.vhdl:10
./fum:error: simulation failed
ghdl: compilation error
And we get it to tell us there's a missing return for the first if statement, that a call to it won't return a value.
To make a conversion routine that converts your std_logic_vector to integer you should use a loop statement with an iteration scheme based on the index range of the input vNumberSTD.
When the loop statement is done 'calculating' vNumberINT return VNumberINT.
Note that if you don't do anything specific about meta values for elements of vNumberSTD they will be treated as '0'.
And with some modifications:
library ieee;
use ieee.std_logic_1164.all;
package foo is
function con_integer14 (vNumberSTD: std_logic_vector(14 downto 0)) return integer;
function conv_slv_int (input: std_logic_vector) return natural;
end package;
package body foo is
function con_integer14 (vNumberSTD : std_logic_vector(14 downto 0)) return integer is
-- variable vCounter: integer range 0 to 16 := 0;
-- variable vNumberINT: integer range 0 to 16384 := 0;
variable vNumberINT: integer range 0 to 32767 := 0;
begin
-- if vCounter = 0 then
-- if vNumberSTD(vCounter) = '1' then
-- vNumberINT := vNumberINT + 2 ** vCounter;
-- elsif vNumberSTD(vCounter) = '0' then
-- vNumberINT := vNumberINT;
-- end if;
-- vCounter := vCounter + 1;
-- elsif vCounter >= 1 or vCounter < 14 then
-- if vNumberSTD(vCounter) = '1' then
-- vNumberINT := vNumberINT + 2 ** vCounter;
-- elsif vNumberSTD(vCounter) = '0' then
-- vNumberINT := vNumberINT;
-- end if;
-- vCounter := vCounter + 1;
-- elsif vCounter = 14 then
-- if vNumberSTD(vCounter) = '1' then
-- vNumberINT := vNumberINT + 2 ** vCounter;
-- elsif vNumberSTD(vCounter) = '0' then
-- vNumberINT := vNumberINT;
-- end if;
-- vCounter := vCounter + 1;
-- elsif vCounter = 15 then
-- return vNumberINT;
-- vCounter := 0;
-- elsif vCounter > 15 then
-- vNumberINT := 0;
-- vCounter := 0;
-- end if;
for i in vNumberSTD'range loop
report "vNumberSTD(" & integer'image(i) & ") = " & std_ulogic'image(vNumberSTD(i));
if vNumberSTD(i) = '1' then
vNumberINT := vNumberINT + 2 ** i;
report "vNumberINT = " & integer'image(vNumberINT);
end if;
end loop;
return vNumberINT;
end function con_integer14;
function conv_slv_int (input: std_logic_vector) return natural is
alias inp: std_logic_vector (input'LENGTH - 1 downto 0) is input;
variable int_equiv: natural range 0 to 2 ** input'LENGTH - 1 := 0;
begin
if Is_X(input) then -- announce meta values - interpreted as '0's
report "conv_slv_int input contains meta value";
end if;
for i in inp'RANGE loop
if To_bit(inp(i)) = '1' then -- convert 'H' to '1', 'L' to '0'
int_equiv := int_equiv + 2 ** i;
end if;
end loop;
return int_equiv;
end function;
end package body;
library ieee;
use ieee.std_logic_1164.all;
use work.foo.all;
entity fum is
end entity;
architecture fie of fum is
signal vNumberINT: integer range 0 to 32767;
signal vNumberSTD: std_logic_vector(14 downto 0) := "HX1001110111100";
begin
CALL:
process
begin
wait for 1 ns;
vNumberINT <= con_integer14(VNumberSTD);
wait for 1 ns;
report "vNumberINT = " &integer'image(vNumberINT);
report "conv_slv_int returns " & integer'image(conv_slv_int(vNumberSTD));
wait;
end process;
end architecture;
Notice I corrected the range of vNumberINT, it can be based on the argument to function con_integer14.
You can remove the report statements in the function. I used them to illustrate the function loop.
I added a second function showing conversion of any length std_logic_vector that will fit in a natural range. It will generate an error when called (function local variables elaborated) if the length of the input won't fit in an integer.
The second function also detects meta value inputs and converts 'H' to '1' and 'L' to '0' for each element of the input.
The use of the alias inp for he input allows us to always deal with the input as natural range, caring about length instead of left and right bounds.
When running the new test bench:
something.vhdl:45:13:#1ns:(report note): vNumberSTD(14) = 'H'
something.vhdl:45:13:#1ns:(report note): vNumberSTD(13) = 'X'
something.vhdl:45:13:#1ns:(report note): vNumberSTD(12) = '1'
something.vhdl:48:17:#1ns:(report note): vNumberINT = 4096
something.vhdl:45:13:#1ns:(report note): vNumberSTD(11) = '0'
something.vhdl:45:13:#1ns:(report note): vNumberSTD(10) = '0'
something.vhdl:45:13:#1ns:(report note): vNumberSTD(9) = '1'
something.vhdl:48:17:#1ns:(report note): vNumberINT = 4608
something.vhdl:45:13:#1ns:(report note): vNumberSTD(8) = '1'
something.vhdl:48:17:#1ns:(report note): vNumberINT = 4864
something.vhdl:45:13:#1ns:(report note): vNumberSTD(7) = '1'
something.vhdl:48:17:#1ns:(report note): vNumberINT = 4992
something.vhdl:45:13:#1ns:(report note): vNumberSTD(6) = '0'
something.vhdl:45:13:#1ns:(report note): vNumberSTD(5) = '1'
something.vhdl:48:17:#1ns:(report note): vNumberINT = 5024
something.vhdl:45:13:#1ns:(report note): vNumberSTD(4) = '1'
something.vhdl:48:17:#1ns:(report note): vNumberINT = 5040
something.vhdl:45:13:#1ns:(report note): vNumberSTD(3) = '1'
something.vhdl:48:17:#1ns:(report note): vNumberINT = 5048
something.vhdl:45:13:#1ns:(report note): vNumberSTD(2) = '1'
something.vhdl:48:17:#1ns:(report note): vNumberINT = 5052
something.vhdl:45:13:#1ns:(report note): vNumberSTD(1) = '0'
something.vhdl:45:13:#1ns:(report note): vNumberSTD(0) = '0'
something.vhdl:87:9:#2ns:(report note): vNumberINT = 5052
something.vhdl:59:17:#2ns:(report note): conv_slv_int input contains meta value
something.vhdl:88:9:#2ns:(report note): conv_slv_int returns 21436
We see that you can pass std_logic_vector to both that only conv_slt_int will interpret correctly.

Save yourself some time and use the built-in functions. If you just use numeric_std, then you can do the following:
library IEEE ;
use IEEE.numeric_std.all ;
...
signal Y_int : integer ;
signal A_slv15 : std_logic_vector(14 downto 0) ;
...
Y_int <= to_integer( unsigned( A_slv15) ) ;
If you also include numeric_std_unsigned (warning this is VHDL-2008 and may not yet be supported by your tools - try it and report a bug if it does not work) -
library IEEE ;
use IEEE.numeric_std.all ;
use IEEE.numeric_std_unsigned.all ;
...
signal Y_int : integer ;
signal A_slv15 : std_logic_vector(14 downto 0) ;
...
Y_int <= to_integer( A_slv15) ;

Like what has already been mentioned, you did not cover all possible conditions. It's always good to have a default assignment, either by having an "else" clause, or have a default before the if-elsif statement:
function con_integer14 (...) return integer is
begin
vNumberINT := -1;
if (vCounter = 0) then ...
elsif ...
elsif ... then return vNumberINT;
end if;
return vNumberINT;
end function con_integer14;
or alternatively,
function con_integer14 (...) return integer is
begin
if (vCounter = 0) then ...
elsif ...
elsif ... then return vNumberINT;
else
return vNumberINT;
end if;
end function con_integer14;
I personally prefer the first option, because some tools still complain that not all paths are covered for the second option, though in fact all paths were covered. Anyway, this is just a matter of style.
It seems to me that you are only returning a value when vCounter=15:
elsif (vCounter = 15) then return vNumberINT; ...
and this condition is not always met by your testbench (perhaps never met as analysed by David).
-daniel

Related

load VHDL sram from a file

I was curious why the following code doesn't work to load an sram memory array in VHDL? What am I missing?
here's my input file: ram_image.hex
be
ef
ca
fe
34
23
Here's the code where i attempt to load my_ram using the impure function load_sram_hex.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_textio.all;
use std.textio.all;
entity sram is
end entity;
architecture beh of sram is
constant sram_dw :integer := 8;
constant sram_aw :integer := 4;
constant sram_depth :integer := 2**sram_aw - 1;
type sram_t is array (0 to sram_depth-1) of std_logic_vector(sram_dw downto 0);
impure function load_sram_hex(filename : in string) return sram_t is
file f :text is in filename;
variable b :line;
variable mem :sram_t;
variable good :boolean;
variable m :line;
begin
for i in sram_t'range loop
readline(f, b);
hread(b, mem(i), good);
write(m, string'("HERE=> ") );
hwrite(m, mem(i));
writeline(output, m);
if (not good) then
exit;
end if;
end loop;
return mem;
end function;
signal my_ram : sram_t := load_sram_hex("ram_image.hex");
begin
process
variable m :line;
begin
wait for 10 ns;
for i in sram_t'range loop
write(m, string'("ram["));
write(m, i);
write(m, string'("] = "));
hwrite(m, my_ram(i));
writeline(output, m);
end loop;
wait for 1000 ns;
report "just kidding! end of testbench" severity failure;
end process;
end architecture;
Here you can see the output of the vhdl simulation is just x's even tough i loaded the memory...
## run all
ram[0] = XXX
ram[1] = XXX
ram[2] = XXX
ram[3] = XXX
ram[4] = XXX
ram[5] = XXX
ram[6] = XXX
ram[7] = XXX
ram[8] = XXX
ram[9] = XXX
ram[10] = XXX
ram[11] = XXX
ram[12] = XXX
ram[13] = XXX
ram[14] = XXX
Failure: just kidding! end of testbench
Time: 1010 ns Iteration: 0 Process: /sram/line__52 File: sram.vhd
This worked in vivado simulator for me:
-- FILE: ram_image.hex
-- ab
-- 12
-- ef
-- 14
-- 34
-- 23
library ieee;
use ieee.std_logic_1164.all;
use std.textio.all;
entity sram is
end entity;
architecture beh of sram is
constant sram_dw :integer := 8;
constant sram_aw :integer := 4;
constant sram_depth :integer := 2**sram_aw - 1;
type sram_t is array (0 to sram_depth-1) of std_logic_vector(sram_dw-1 downto 0);
shared variable my_ram :sram_t;
procedure hread_backport(
l :inout line;
value :out std_logic_vector
) is
variable offset :integer;
variable c :character;
variable good1 :boolean;
variable hex_val :std_logic_vector(3 downto 0);
begin
offset := 0;
value := (others => '0');
while (offset < value'high) loop
read(l, c, good1);
if (not good1) then exit; end if;
case c is
when '0' => hex_val := "0000";
when '1' => hex_val := "0001";
when '2' => hex_val := "0010";
when '3' => hex_val := "0011";
when '4' => hex_val := "0100";
when '5' => hex_val := "0101";
when '6' => hex_val := "0110";
when '7' => hex_val := "0111";
when '8' => hex_val := "1000";
when '9' => hex_val := "1001";
when 'A' | 'a' => hex_val := "1010";
when 'B' | 'b' => hex_val := "1011";
when 'C' | 'c' => hex_val := "1100";
when 'D' | 'd' => hex_val := "1101";
when 'E' | 'e' => hex_val := "1110";
when 'F' | 'f' => hex_val := "1111";
when others =>
hex_val := "XXXX";
assert false report "Found non-hex character'" & c & "'";
end case;
value( (value'high-offset) downto (value'high-offset-3) ) := hex_val;
offset := offset + 4;
end loop;
end procedure;
procedure sram_load_hex(filepath :string) is
file f :text;
variable b, m :line;
variable good :boolean;
begin
write(m, string'("opening file: ") & filepath );
writeline(output, m);
file_open(f, filepath, read_mode);
for i in sram_t'range loop
if (endfile(f)) then exit; end if;
readline(f, b);
hread_backport(b, my_ram(i));
end loop;
end procedure;
procedure sram_print_hex is
variable m :line;
begin
for i in sram_t'range loop
write(m, string'("read ram["));
write(m, i);
write(m, string'("] = "));
hwrite(m, my_ram(i));
writeline(output, m);
end loop;
end procedure;
begin
process
begin
sram_load_hex("C:/Users/racerx/Desktop/sandbox/sram/ram_image.hex");
wait;
end process;
process
begin
wait for 1000 ns;
sram_print_hex;
report "just kidding! end of testbench" severity failure;
end process;
end architecture;

How to correct a phase shift using a clock divider in VHDL?

I want to make a UART receiver that reads 8 consecutives bits with a parity bit at the end and with a simple stop bit. My FPGA have a clock of 100Mhz and the data that are transmitted to the uart have a rate of 56700 bauds. The dividing factor is 1736 (56700 * 1736 ≈ 100Mhz). The two outputs are the message of the input decoded by the uart and an error signal that indicates if the uart have correctly read the input. This is what I have :
library ieee;
use ieee.std_logic_1164.ALL;
use ieee.numeric_std.all;
entity uart_receiver is
generic (
clksPerBit : integer := 1736 -- Needs to be set correctly
);
port (
clk : in std_logic;
clk_en_uart : in std_logic ;
reset : in std_logic;
uart_rx : in std_logic;
error : out std_logic;
char : out std_logic_vector(7 downto 0)
);
end uart_receiver;
architecture uart_receiver_arch of uart_receiver is
type etat is (init, start_bit, receiving_bits, parity_bit,
stop_bit );
signal current_state : etat := init ;
signal error_signal : std_logic := '0';
signal clk_count : integer range 0 to clksPerBit-1 := 0;
signal bit_index : integer range 0 to 7 := 0; -- 8 Bits Total
signal data_byte : std_logic_vector(7 downto 0) := (others => '0');
begin
process (clk_en_uart)
begin
if rising_edge(clk_en_uart) then
end if;
end process;
process (clk,reset)
variable check_parity : integer range 0 to 7 := 0;
begin
if (reset = '1') then
current_state <= init;
error_signal <= '0';
clk_count <= 0;
bit_index <= 0;
data_byte <= (others => '0');
elsif rising_edge(clk) then
case current_state is
when init =>
clk_count <= 0;
Bit_Index <= 0;
if uart_rx = '0' then -- Start bit detected
current_state <= start_bit;
else
current_state <= init;
end if;
when start_bit =>
if clk_count = (clksPerBit-1)/2 then
if uart_rx = '0' then
clk_count <= 0; -- reset counter since we found the middle
current_state <= receiving_bits;
else
current_state <= init;
end if;
else
clk_count <= clk_count + 1;
current_state <= start_bit;
end if;
when receiving_bits =>
if clk_count < clksPerBit-1 then
clk_count <= clk_count + 1;
current_state <= receiving_bits;
else
clk_count <= 0;
data_byte(bit_index) <= uart_rx;
if bit_index < 7 then
bit_index <= bit_index + 1;
current_state <= receiving_bits ;
else
bit_index <= 0;
current_state <= parity_bit;
end if;
end if;
when parity_bit =>
if clk_count < clksPerBit-1 then
clk_count <= clk_count + 1;
current_state <= parity_bit;
else
for k in 0 to 7 loop
if ( data_byte(k) = '1' ) then
check_parity := check_parity + 1 ;
end if;
end loop;
if((uart_rx = '1' and check_parity mod 2 = 0) or (uart_rx = '0' and check_parity mod 2 = 1)) then
error_signal <= '1' ;
else
error_signal <= '0';
end if ;
current_state <= stop_bit;
end if;
when stop_bit =>
if clk_count < clksPerBit-1 then
clk_count <= clk_count + 1;
current_state <= stop_bit ;
else
clk_count <= 0;
current_state <= init;
end if;
when others =>
current_state <= init;
end case;
end if;
char <= data_byte ;
error <= error_signal ;
end process;
end uart_receiver_arch;
So there's a phase shift between the data that is transmitted to the uart and his clock. If there's a phase shift, I'm not reading the data at the right time. I think that this code is sufficient to solve this problem. But, I've created a clock_divider and I can't seem to find a way to use it in this code. This is my clock divider :
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity clock_divider is
generic (divfactor : positive := 1736);
Port (clk,clk2, reset : in STD_LOGIC ;
clkdiv, activationsig : out STD_LOGIC );
end clock_divider;
architecture clock_divider_arch of clock_divider is
begin
process(clk,reset)
variable clksigv : std_logic := '0' ;
variable activationsigv : std_logic := '0' ;
variable count : integer := 0 ;
begin
if (reset = '1') then
clksigv := '0' ;
activationsigv := '0' ;
count := 0 ;
elsif ( rising_edge(clk) ) then
count := count + 2 ;
if (activationsigv = '1') then
activationsigv := '0';
end if;
if ( count >= divfactor - 1 ) then
clksigv := not(clksigv) ;
if ( clksigv = '1' ) then
activationsigv := '1' ;
end if;
count := 0 ;
end if ;
end if ;
clkdiv <= clksigv ;
activationsig <= activationsigv;
end process ;
end clock_divider_arch;
The outputs of this clock divider are the clock divided and the activation signal that, when it is at '1', I have to read the data in the uart. So, the two outputs should also be inputs of the uart. In the uart_recevier, clk_en_uart is actually the clock divided, but I'm not using it because I don't know how.
I think that the solution is to 'activate' this divided clock when I enter in the start_bit case so that I have two clocks with the same phase and the same frequency, but I also think that it impossible to set a phase for a clock.
I'm not sure that I've clearly adressed my problem. If there's something that you don't understand in my code or in my explanation, feel free to ask questions.
Thank you for your help, hoping that I find a solution.
Sounds like the suggested solution is complicated for this problem.
A usual approach is that the receiver justs look for the falling edge of the start bit, then count for half a bit time (1736 / 2 cycles in your case), then samples the start bit value there, and subsequently samples the data, parity and stop bit values after each full bit time (1736 cycles in your case). After that start over looking for a new falling edge of the start bit.
The difference between the transmitter and receiver frequencies are then (usually) so small that the sample time will be practically in the middle for messages of only 11 bits at relative low bitrate, and the counter restart at falling edge of start bit ensures that any effect of long time frequency difference is removed.

Generating sine using cordic algorithm

I want to apologize for this + - popular question, but nowhere did I find a specific implementation on vhdl. I write the algorithm from scratch and I have a problem with math implementation. The output is invalid. nothing counts, but just shows 1 value. If someone knows what i need to do, how to fix it, would be very grateful for any help.
Math part
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--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 massive is
port (
clk : in std_logic;
reset : in std_logic;
sinus : out std_logic_vector (15 downto 0));
end massive;
architecture Behavioral of massive is
type my_type is array (0 to 16) of signed (15 downto 0);
signal x : my_type;
signal y : my_type;
signal z : my_type;
signal j : my_type := ("1010111111001000", "0110011111000101", "0011011011010100", "0001101111010101", "0000110111111000",
"0000011011111110", "0000001101111111", "0000000111000000", "0000000011100000", "0000000001110000",
"0000000000111000", "0000000000011100", "0000000000001110", "0000000000000111", "0000000000000100",
"0000000000000010", "0000000000000001");
begin
process(clk)
begin
x(0) <= "0000010100000110";
y(0) <= "0000000000000000";
z(0) <= "0000000000000000";
if rising_edge(clk) then
if reset <= '1' then
For n in 0 to 15 loop
if (z(n) >= 0) then
x(n+1) <= x(n) - (y(n)/2**n);
y(n+1) <= y(n) + (x(n)/2**n);
z(n+1) <= z(n) + j(n);
else
x(n+1) <= x(n) +(y(n)/2**n);
y(n+1) <= y(n) -(x(n)/2**n);
z(n+1) <= z(n) - j(n);
end if;
end loop;
sinus <= std_logic_vector(y(16));
end if;
end if;
end process;
end Behavioral;
Rotation part
entity step_control is
generic (
first : integer := 0;
second : integer := 1;
third : integer := 2;
fourth : integer := 3;
);
Port ( clk : in STD_LOGIC;
Angle : out STD_LOGIC_VECTOR (12 downto 0);
quarter_in : out STD_LOGIC_VECTOR (1 downto 0));
end step_control;
architecture Behavioral of step_control is
signal Ang : std_logic_vector (12 downto 0) := (others => '0');
signal state : unsigned (1 downto 0) := to_unsigned(first,2);
signal count_ang : std_logic_vector (11 downto 0) := (others => '0');
begin
process (clk)
begin
if (rising_edge(clk)) then
case(state) is
when to_unsigned(first,2) => if (count_ang >= 3999) then --00
state <= to_unsigned(second,2);
count_ang <= "000000010000";
quarter_in <= "01";
Ang <= Ang - 16;
else
state <= to_unsigned(first,2);
quarter_in <= "00";
Ang <= Ang + 16;
count_ang <= count_ang + 16;
end if;
when to_unsigned(second,2) => if (count_ang >= 3999) then --01
state <= to_unsigned(third,2);
count_ang <= "000000010000";
quarter_in <= "10";
Ang <= Ang + 16;
else
state <= to_unsigned(second,2);
quarter_in <= "01";
Ang <= Ang - 16;
count_ang <= count_ang + 16;
end if;
when to_unsigned(third,2) => if (count_ang >= 3999) then
state <= to_unsigned(fourth,2);
count_ang <= "000000010000";
quarter_in <= "11";
Ang <= Ang - 16;
else
state <= to_unsigned(third,2);
quarter_in <= "10";
Ang <= Ang + 16;
count_ang <= count_ang + 16;
end if;
when to_unsigned(fourth,2) => if (count_ang >= 3999) then
state <= to_unsigned(first,2);
count_ang <= "000000010000";
quarter_in <= "00";
Ang <= Ang + 16;
else
state <= to_unsigned(fourth,2);
quarter_in <= "11";
Ang <= Ang - 16;
count_ang <= count_ang + 16;
end if;
when others => count_ang <= (others => '0');
end case;
end if;
end process;
Angle <= Ang;
end Behavioral;
And testbench (but I do not know, I'm kind of all asking in the module. and my "empty" tesbench is obtained)
ENTITY testmass IS
END testmass;
ARCHITECTURE behavior OF testmass IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT massive
PORT(
clk : IN std_logic;
reset : IN std_logic;
sinus : OUT std_logic_vector(15 downto 0)
);
END COMPONENT;
--Inputs
signal clk : std_logic := '0';
signal reset : std_logic := '0';
--Outputs
signal sinus : std_logic_vector(15 downto 0);
-- Clock period definitions
constant clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: massive PORT MAP (
clk => clk,
reset => reset,
sinus => sinus
);
-- 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.
wait for 100 ns;
wait for clk_period*10;
-- insert stimulus here
wait;
end process;
END;
Your question isn't a Minimal, Complete and Verifiable example, it's not verifiable:
Describe the problem. "It doesn't work" is not a problem statement. Tell us what the expected behavior should be. Tell us what the exact wording of the error message is, and which line of code is producing it. Put a brief summary of the problem in the title of your question.
The output is invalid. nothing counts, but just shows 1 value.
What's the one value? When someone attempts to duplicate your problem one thing we see is assertion warnings for each evaluation of z(n) in the process in entity massive:
if (z(n) >= 0) then
The issue is subtle as basic to VHDL signals.
You assign values to signals in the process and expect them to be immediately available. That does not occur. No signal is updated while any process has yet to have been resumed and subsequently suspended in the current simulation cycle.
For each simulation time in the projected output waveform (a queue) there is only one entry. Subsequent assignments (which don't occur here) would result in only the last value being queued.
More important is that the future value isn't available in the current simulation cycle.
x, y and z can be variables declared in the process instead:
architecture foo of massive is
-- not predefined before -2008:
function to_string (inp: signed) return string is
variable image_str: string (1 to inp'length);
alias input_str: signed (1 to inp'length) is inp;
begin
for i in input_str'range loop
image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
end loop;
return image_str;
end function;
begin
process (clk)
type my_type is array (0 to 16) of signed (15 downto 0);
variable x: my_type;
variable y: my_type;
variable z: my_type;
constant j: my_type := ("1010111111001000", "0110011111000101",
"0011011011010100", "0001101111010101",
"0000110111111000", "0000011011111110",
"0000001101111111", "0000000111000000",
"0000000011100000", "0000000001110000",
"0000000000111000", "0000000000011100",
"0000000000001110", "0000000000000111",
"0000000000000100", "0000000000000010",
"0000000000000001");
begin
x(0) := "0000010100000110";
y(0) := "0000000000000000";
z(0) := "0000000000000000";
if rising_edge(clk) then
if reset = '0' then -- reset not driven condition was <=
report "init values:" & LF & HT &
"x(0) = " & to_string(x(0)) & LF & HT &
"y(0) = " & to_string(y(0)) & LF & HT &
"z(0) = " & to_string(z(0));
for n in 0 to 15 loop
if z(n) >= 0 then
x(n + 1) := x(n) - y(n) / 2 ** n;
y(n + 1) := y(n) + x(n) / 2 ** n;
z(n + 1) := z(n) + j(n);
else
x(n + 1) := x(n) + y(n) / 2 ** n;
y(n + 1) := y(n) - x(n) / 2 ** n;
z(n + 1) := z(n) - j(n);
end if;
report "n = " & integer'image(n) & LF & HT &
"x(" & integer'image(n + 1) & ") = " &
to_string(x(n + 1)) & LF & HT &
"y(" & integer'image(n + 1) & ") = " &
to_string(y(n + 1)) & LF & HT &
"z(" & integer'image(n + 1) & ") = " &
to_string(z(n + 1));
end loop;
sinus <= std_logic_vector(y(16));
report "sinus = " & to_string(y(16));
end if;
end if;
end process;
end architecture foo;
The report statements are added to allow the values to be output to the simulation console. Without the passage of time between successive assignments to variables values of variables in waveform have no useful meaning. There are simulators that won't report variables in waveform dumps.
And the above architecture produces:
ghdl -a testmass.vhdl
ghdl -e testmass
ghdl -r testmass
testmass.vhdl:86:17:#5ns:(report note): init values:
x(0) = 0000010100000110
y(0) = 0000000000000000
z(0) = 0000000000000000
testmass.vhdl:100:21:#5ns:(report note): n = 0
x(1) = 0000010100000110
y(1) = 0000010100000110
z(1) = 1010111111001000
testmass.vhdl:100:21:#5ns:(report note): n = 1
x(2) = 0000011110001001
y(2) = 0000001010000011
z(2) = 0100100000000011
testmass.vhdl:100:21:#5ns:(report note): n = 2
x(3) = 0000011011101001
y(3) = 0000010001100101
z(3) = 0111111011010111
testmass.vhdl:100:21:#5ns:(report note): n = 3
x(4) = 0000011001011101
y(4) = 0000010101000010
z(4) = 1001101010101100
testmass.vhdl:100:21:#5ns:(report note): n = 4
x(5) = 0000011010110001
y(5) = 0000010011011101
z(5) = 1000110010110100
testmass.vhdl:100:21:#5ns:(report note): n = 5
x(6) = 0000011011010111
y(6) = 0000010010101000
z(6) = 1000010110110110
testmass.vhdl:100:21:#5ns:(report note): n = 6
x(7) = 0000011011101001
y(7) = 0000010010001101
z(7) = 1000001000110111
testmass.vhdl:100:21:#5ns:(report note): n = 7
x(8) = 0000011011110010
y(8) = 0000010010000000
z(8) = 1000000001110111
testmass.vhdl:100:21:#5ns:(report note): n = 8
x(9) = 0000011011110110
y(9) = 0000010001111010
z(9) = 0111111110010111
testmass.vhdl:100:21:#5ns:(report note): n = 9
x(10) = 0000011011110100
y(10) = 0000010001111101
z(10) = 1000000000000111
testmass.vhdl:100:21:#5ns:(report note): n = 10
x(11) = 0000011011110101
y(11) = 0000010001111100
z(11) = 0111111111001111
testmass.vhdl:100:21:#5ns:(report note): n = 11
x(12) = 0000011011110101
y(12) = 0000010001111100
z(12) = 0111111111101011
testmass.vhdl:100:21:#5ns:(report note): n = 12
x(13) = 0000011011110101
y(13) = 0000010001111100
z(13) = 0111111111111001
testmass.vhdl:100:21:#5ns:(report note): n = 13
x(14) = 0000011011110101
y(14) = 0000010001111100
z(14) = 1000000000000000
testmass.vhdl:100:21:#5ns:(report note): n = 14
x(15) = 0000011011110101
y(15) = 0000010001111100
z(15) = 0111111111111100
testmass.vhdl:100:21:#5ns:(report note): n = 15
x(16) = 0000011011110101
y(16) = 0000010001111100
z(16) = 0111111111111110
testmass.vhdl:109:17:#5ns:(report note): sinus = 0000010001111100
Where we see the values of your array elements are changing instead of propagating 'X's through addition (or subtraction when z(n) < 0), assigned in the previous loop iteration.
Also note the reset doesn't change value in the testbench and there is an erroneous evaluation for it's value using the relational operator "<=" in the original massive process.
j is not assigned other than an initial value and is shown as a constant in the above architecture.
I'm personally somewhat skeptical you can perform these 16 chained additions or subtractions along with selecting which operation in one 10 ns clock.

How to shift std_logic_vector?

I want shift std_logic_vector.
But this code is has an error:
architecture led_main of testing is
signal clk_cnt : std_logic_vector(64 DOWNTO 0) := (others => '0');
signal led_buf : std_logic_vector( 3 downto 0 ) := "0001";
begin
process(clk)
begin
if rising_edge(clk) then
clk_cnt <= clk_cnt + 1;
if clk_cnt >= 24999999 then
led_buf <= led_buf(0) & led_buf(3 downto 1);
end if;
end if;
end process;
ground <= '0';
end led_main;
I think "0001", "0010", "0100" ...
Your shifter is OK. Actually, it's a rotator.
But your counter is to big (65 bits) and it doesn't roll over or reset to zero in a proper time. Your current design waits for 25M cycles and then shifts in every cycle from 25M to 2**64.
More over, you are using a non standard IEEE package to perform arithmetic operations (addition) on std_logic_vector. Please use type unsigned from package numeric_std.
The needed number of bits for your counter can be obtained by a log2 function like this:
function log2ceil(arg : positive) return natural is
variable tmp : positive;
variable log : natural;
begin
if arg = 1 then return 0; end if;
tmp := 1;
log := 0;
while arg > tmp loop
tmp := tmp * 2;
log := log + 1;
end loop;
return log;
end function;
Source: https://github.com/VLSI-EDA/PoC/blob/master/src/common/utils.vhdl
Full code rewrite:
use IEEE.numeric_std.all;
architecture led_main of testing is
constant CNT_MAX : positive := 25000000;
signal clk_cnt : unsigned(log2ceil(CNT_MAX) - 1 downto 0) := (others => '0');
signal led_buf : std_logic_vector( 3 downto 0 ) := "0001";
begin
process(clk)
begin
if rising_edge(clk) then
clk_cnt <= clk_cnt + 1;
if clk_cnt = (CNT_MAX - 1) then
clk_cnt <= (others => '0');
led_buf <= led_buf(0) & led_buf(3 downto 1);
end if;
end if;
end process;
end led_main;
```

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.

Resources