How to shift std_logic_vector? - vhdl

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;
```

Related

How can i reduce number of ALMs in my VHDL design?

I'm trying to implement an alarm module for the digital clock in VHDL. I have written architecture for it, but when I run Compilation I get too many Adaptive Logic Modules (around 2000), which I think is too much. I will post my code below.
I think division and modulus operation could be causing it, in this line of code.
alarm_hour1 <= std_logic_vector(to_unsigned(savedHours/10,alarm_hour1'length));
alarm_hour0 <= std_logic_vector(to_unsigned(savedHours mod 10,alarm_hour0'length));
alarm_minute1 <= std_logic_vector(to_unsigned(savedMinutes/10,alarm_minute1'length));
alarm_minute0 <= std_logic_vector(to_unsigned(savedMinutes mod 10,alarm_minute0'length));
Still, I'm not sure how can I work around this.
Also, I would be very grateful if You give more comments on my design, and point out some mistakes, and ways how I can improve my design. I'm fairly new to VHDL so any advice is appreciated.
Thanks a lot.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity alarm is
port(
--INPUTS
reset : in std_logic;
clock : in std_logic;
alarm_enable : in std_logic;
alarm_set : in std_logic;
alarm_increment : in std_logic;
alarm_decrement : in std_logic;
currentTime_hour1 : in std_logic_vector(3 downto 0);
currentTime_hour0 : in std_logic_vector(3 downto 0);
currentTime_minute1 : in std_logic_vector(3 downto 0);
currentTime_minute0 : in std_logic_vector(3 downto 0);
--OUTPUTS
alarm_buzzer : out std_logic;
alarm_hour1 : buffer std_logic_vector(3 downto 0) := "0000";
alarm_hour0 : buffer std_logic_vector(3 downto 0) := "0000";
alarm_minute1 : buffer std_logic_vector(3 downto 0) := "0000";
alarm_minute0 : buffer std_logic_vector(3 downto 0) := "0000"
);
end alarm;
architecture alarmBehaviour of alarm is
--ALARM TIME
signal savedHours : integer := 0;
signal savedMinutes : integer := 0;
signal incrementDecrementbuttonDetect : std_logic;
signal set_lastButtonState : std_logic := '0';
signal setButtonDetect : std_logic := '0';
--STATE MACHINE
type state_type is (idle, setHour, setMinute);
signal state_reg, state_next : state_type;
begin
incrementDecrementbuttonDetect <= alarm_increment or alarm_decrement;
--STATE REGISTER
process(clock, reset)
begin
if (reset = '1') then
state_reg <= idle;
elsif rising_edge(clock) then
state_reg <= state_next;
end if;
end process;
--SET BUTTON PRESSED
process(clock)
begin
if(rising_edge(clock)) then
if(alarm_set = '1' and set_lastButtonState = '0') then
setButtonDetect <= '1';
else
setButtonDetect <= '0';
end if;
set_lastButtonState <= alarm_set;
end if;
end process;
--NEXT STATE
process(state_reg, setButtonDetect)
begin
case state_reg is
when idle =>
if setButtonDetect = '1' then
state_next <= setHour;
else
state_next <= idle;
end if;
when setHour =>
if setButtonDetect = '1' then
state_next <= setMinute;
else
state_next <= setHour;
end if;
when setMinute =>
if setButtonDetect = '1' then
state_next <= idle;
else
state_next <= setMinute;
end if;
end case;
end process;
process (incrementDecrementbuttonDetect, state_reg)
begin
if rising_edge(incrementDecrementbuttonDetect) then
case state_reg is
when idle =>
when setHour =>
if alarm_increment = '1' then
if savedHours = 23 then
savedHours <= 0;
else
savedHours <= savedHours + 1;
end if;
else null;
end if;
if alarm_decrement = '1' then
if savedHours = 0 then
savedHours <= 23;
else
savedHours <= savedHours - 1;
end if;
else null;
end if;
when setMinute =>
if alarm_increment = '1' then
if savedMinutes = 59 then
savedMinutes <= 0;
else
savedMinutes <= savedMinutes + 1;
end if;
else null;
end if;
if alarm_decrement = '1' then
if savedMinutes = 0 then
savedMinutes <= 59;
else
savedMinutes <= savedMinutes - 1;
end if;
else null;
end if;
end case;
end if;
end process;
alarm_hour1 <= std_logic_vector(to_unsigned(savedHours/10,alarm_hour1'length));
alarm_hour0 <= std_logic_vector(to_unsigned(savedHours mod 10,alarm_hour0'length));
alarm_minute1 <= std_logic_vector(to_unsigned(savedMinutes/10,alarm_minute1'length));
alarm_minute0 <= std_logic_vector(to_unsigned(savedMinutes mod 10,alarm_minute0'length));
--ALARM BUZZER CONDITION
process (currentTime_hour1, currentTime_hour0, currentTime_minute1, currentTime_minute0,
alarm_enable, alarm_hour1, alarm_hour0, alarm_minute1, alarm_minute0)
begin
if((alarm_hour1 = currentTime_hour1) and (alarm_hour0 = currentTime_hour0)
and (alarm_minute1 = currentTime_minute1) and (alarm_minute0 = currentTime_minute0) and alarm_enable = '1') then
alarm_buzzer <= '1';
else
alarm_buzzer <= '0';
end if;
end process;
end alarmBehaviour;
Consider keeping the alarm time in Binary-Coded Decimal (BCD) format instead of binary format, whereby you can compare it directly with the current time, that is provided in BCD format.
This is a good example of how using the appropriate internal data format can reduce the computational problem significantly, since you can simply eliminate the costly division and modulo operations by keeping just one data format (BCD) instead of mixing BCD and binary data formats.
The range of signals savedHours and savedMinutes is not specified, so Quartus assumes they are 32 bits wide. Inference of a divider with one 32-bit operand results into a large tree of conditional subtractions.
Updating your code to something like
--ALARM TIME
signal savedHours : natural range 0 to 23 := 0;
signal savedMinutes : natural range 0 to 59 := 0;
will very likely result into less ALM usage.
Also, please note that rising_edge should be used for clock signals only (at VHDL starter level). Instead of connecting logic to the clock input of a register, what you probably want is some button debounce logic.

Spikes or glitches in Modelsim

I've been learning VHDL for a while and I'm making a project right now. I made a NCO (Numerically controlled Oscillator) and a cordic algorithm to produce sine and cosine with a certain frequency.
I don't know why I get spikes on my waves in Modelsim. I guess they are caused by the case statement when it changes the quadrant for the cordic algorithm to work with angles between -180 and +180.
I've read that it could be a "normal" behavior of Modelsim because of the iterations of the simulator (VHDL delta cycles). But I don't know how and if I should fix them.
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;
ENTITY phase_accumulator_module IS
GENERIC (
LGTBL: INTEGER := 16; --lunghezza table log base 2
W: INTEGER := 32;
OW: INTEGER := 16
);
PORT (
clk: IN STD_LOGIC;
reset: IN STD_LOGIC;
i_dphase: IN STD_LOGIC_VECTOR(W-1 DOWNTO 0);
o_val: BUFFER STD_LOGIC_VECTOR(W-1 DOWNTO 0);
o_val_test:BUFFER STD_LOGIC_VECTOR(OW-1 DOWNTO 0);
o_val_laser: BUFFER STD_LOGIC_VECTOR(W-1 DOWNTO 0);
quadrant: BUFFER STD_LOGIC_VECTOR(1 DOWNTO 0)
);
END phase_accumulator_module;
ARCHITECTURE behave OF phase_accumulator_module IS
SIGNAL r_step,r_step_laser,r_step_test: STD_LOGIC_VECTOR(W-1 DOWNTO 0) := (OTHERS => '0');
SIGNAL r_phase,r_phase_laser,r_phase_test: STD_LOGIC_VECTOR(W-1 DOWNTO 0) := (OTHERS => '0');
SIGNAL r_phase_pipe,r_phase_laser_pipe: STD_LOGIC_VECTOR(W-1 DOWNTO 0) := (OTHERS => '0');
CONSTANT P: INTEGER := LGTBL;
BEGIN
R_Step_pro: PROCESS(clk,reset)
BEGIN
IF(reset='1') THEN
r_step <= (OTHERS=>'0');
r_step_test <= (OTHERS=>'0');
r_step_laser <= (OTHERS=>'0');
ELSE IF(rising_edge(clk)) THEN
r_step <= i_dphase; -- 2^W*f/fs
r_step_test <= i_dphase; --test signal
r_step_laser <= STD_LOGIC_VECTOR(SHIFT_RIGHT(UNSIGNED(i_dphase),1));
END IF;
END IF;
END PROCESS R_Step_pro;
R_phase_pro: PROCESS(clk,reset)
BEGIN
IF(reset='1') THEN
r_phase <= (OTHERS=>'0');
r_phase_test <= (OTHERS=>'0');
r_phase_laser <= (OTHERS=>'0');
o_val <= (OTHERS=>'0');
o_val_test <= (OTHERS=>'0');
o_val_laser <= (OTHERS=>'0');
ELSE IF(rising_edge(clk)) THEN
r_phase <= STD_LOGIC_VECTOR(UNSIGNED(r_phase) + UNSIGNED(r_step));
r_phase_test <= STD_LOGIC_VECTOR(UNSIGNED(r_phase_test) + UNSIGNED(r_step_test)); --test signal
r_phase_laser <= STD_LOGIC_VECTOR(UNSIGNED(r_phase_laser) + UNSIGNED(r_step_laser));
quadrant <= r_phase(W-1 DOWNTO w-2);
CASE quadrant IS
WHEN "00" | "11" =>
r_phase_pipe <= r_phase;
r_phase_laser_pipe <= r_phase_laser;
WHEN "01" =>
r_phase_pipe <= "00" & r_phase(W-3 DOWNTO 0);
r_phase_laser_pipe <= "00" & r_phase_laser(W-3 DOWNTO 0);
WHEN "10" =>
r_phase_pipe <= "11" & r_phase(W-3 DOWNTO 0);
r_phase_laser_pipe <= "11" & r_phase_laser(W-3 DOWNTO 0);
WHEN OTHERS =>
null;
END CASE;
o_val_test <= r_phase_test(W-1 DOWNTO W-P);
o_val <= r_phase_pipe;
o_val_laser <= r_phase_laser_pipe;
END IF;
END IF;
END PROCESS R_phase_pro;
END behave;
This is the cordic algotithm vhdl file:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;
ENTITY signal_gen_cordic_module IS
GENERIC (
bits: INTEGER := 16;
bits_out_c: INTEGER := 32;
iter : INTEGER := 32
);
PORT (
clk: IN STD_LOGIC;
reset: IN STD_LOGIC;
locked: IN STD_LOGIC;
z0: IN STD_LOGIC_VECTOR (bits_out_c-1 DOWNTO 0);
quadrant: IN STD_LOGIC_VECTOR(1 DOWNTO 0);
sine,cosine: BUFFER STD_LOGIC_VECTOR(bits-1 DOWNTO 0)
);
END signal_gen_cordic_module;
ARCHITECTURE behave OF signal_gen_cordic_module IS
TYPE temp IS ARRAY (0 TO iter-1) OF STD_LOGIC_VECTOR(bits_out_c-1 DOWNTO 0);
SIGNAL x_temp,y_temp,z_temp: temp;
CONSTANT x0: SIGNED(bits_out_c-1 DOWNTO 0) := "00000000000000000010111100011010"; --0.6072*2^16
CONSTANT y0: SIGNED(bits_out_c-1 DOWNTO 0) := "00000000000000000000000000000000";
SIGNAL x00,y00: SIGNED(bits_out_c-1 DOWNTO 0);
TYPE atand IS ARRAY (0 TO iter-1) OF STD_LOGIC_VECTOR(bits_out_c-1 DOWNTO 0);
CONSTANT arctan: atand :=
(
x"20000000",
x"12E4051E",
x"09FB385B",
x"051111D4",
x"028B0D43",
x"0145D7E1",
x"00A2F61E",
x"00517C55",
x"0028BE53",
x"00145F2F",
x"000A2F98",
x"000517CC",
x"00028BE6",
x"000145F3",
x"0000A2FA",
x"0000517D",
x"000028BE",
x"0000145F",
x"00000A30",
x"00000518",
x"0000028C",
x"00000146",
x"000000A3",
x"00000051",
x"00000029",
x"00000014",
x"0000000A",
x"00000005",
x"00000003",
x"00000001",
x"00000001",
x"00000000"
);
BEGIN
PROCESS(clk,reset)
BEGIN
IF(reset='1') THEN
cosine <= (OTHERS=>'0');
sine <= (OTHERS=>'0');
FOR i IN iter-1 DOWNTO 0 LOOP
x_temp(i) <= (OTHERS=>'0');
y_temp(i) <= (OTHERS=>'0');
z_temp(i) <= (OTHERS=>'0');
END LOOP;
ELSE IF(rising_edge(clk)) THEN
IF(locked='1') THEN
IF(quadrant="00" OR quadrant="11") THEN
x00 <= x0;
y00 <= y0;
ELSE IF(quadrant="01") THEN
x00 <= -y0;
y00 <= x0;
ELSE
x00 <= y0;
y00 <= -x0;
END IF;
END IF;
x_temp(0) <= STD_LOGIC_VECTOR(x00);
y_temp(0) <= STD_LOGIC_VECTOR(y00);
z_temp(0) <= z0;
FOR i IN 0 TO iter-2 LOOP
IF(z_temp(i)(z0'HIGH)='1') THEN
x_temp(i+1) <= STD_LOGIC_VECTOR(SIGNED(x_temp(i)) + SHIFT_RIGHT(SIGNED(y_temp(i)),i));
y_temp(i+1) <= STD_LOGIC_VECTOR(SIGNED(y_temp(i)) - SHIFT_RIGHT(SIGNED(x_temp(i)),i));
z_temp(i+1) <= STD_LOGIC_VECTOR(SIGNED(z_temp(i)) + SIGNED(arctan(i)));
ELSE
x_temp(i+1) <= STD_LOGIC_VECTOR(SIGNED(x_temp(i)) - SHIFT_RIGHT(SIGNED(y_temp(i)),i));
y_temp(i+1) <= STD_LOGIC_VECTOR(SIGNED(y_temp(i)) + SHIFT_RIGHT(SIGNED(x_temp(i)),i));
z_temp(i+1) <= STD_LOGIC_VECTOR(SIGNED(z_temp(i)) - SIGNED(arctan(i)));
END IF;
END LOOP;
cosine <= STD_LOGIC_VECTOR(RESIZE(SIGNED(x_temp(iter-1)),bits));
sine <= STD_LOGIC_VECTOR(RESIZE(SIGNED(y_temp(iter-1)),bits));
END IF;
END IF;
END IF;
END PROCESS;
END behave;
My modelsim version is 10.5b. Thank you for any help! :)

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.

Interface DHT22 to FPGA - elbert v2

Now i make a circuit to measure temperature and humidity, then display on LCD. This is my code for DHT22, i use Elbert V2.
After genarating my project, it did not go right.
I tested and my program did not to come to "end_sl"( last state). And i dont know why?. Any suggestions for me? thank you.
my code
----------------------------------------------------------------------------------------------------------------------------------------------------------------
entity DHT11 is
generic (
CLK_PERIOD_NS : positive := 83; -- 12MHz
N: positive:= 40);
port(
clk,rst : in std_logic ;
singer_bus: inout std_logic;
dataout: out std_logic_vector (N-1 downto 0);
tick_done: out std_logic
);
end DHT11;
architecture Behavioral of DHT11 is
constant DELAY_1_MS: positive := 1*10**6/CLK_PERIOD_NS+1;
constant DELAY_40_US: positive := 40*10**3/CLK_PERIOD_NS+1;
constant DELAY_80_US: positive := 80*10**3/CLK_PERIOD_NS+1;
constant DELAY_50_US: positive := 50*10**3/CLK_PERIOD_NS+1; --
constant TIME_70_US: positive := 80*10**3/CLK_PERIOD_NS+1; --bit > 70 us
constant TIME_28_uS: positive := 30*10**3/CLK_PERIOD_NS+1; -- bit 0 > 28 us
constant MAX_DELAY : positive := 5*10**6/CLK_PERIOD_NS+1; -- 5 ms
type state_type is (reset,start_m,wait_res_sl,response_sl,delay_sl,start_sl,consider_logic,end_sl);
signal index, next_index : natural range 0 to MAX_DELAY;
signal state, next_state : state_type;
signal data_out,next_data_out: std_logic_vector (N-1 downto 0);
signal bit_in, next_bit_in: std_logic;
signal number_bit,next_number_bit: natural range 0 to 40;
signal oe: std_logic; -- help to set input and output port.
begin
--register
regis_state:process (clk,rst) begin
if rst = '1' then
state <= reset;
index <= MAX_DELAY;
number_bit <= 0;
bit_in <= '1';
data_out <= (others => '0');
elsif rising_edge(clk) then
state <= next_state;
index <= next_index;
number_bit <= next_number_bit;
bit_in <= next_bit_in;
data_out <= next_data_out;
end if;
end process regis_state;
proces_state: process (singer_bus,index,state,bit_in,number_bit,data_out) begin
tick_done <= '0';
next_data_out <= data_out;
next_number_bit <= number_bit;
next_state <= state;
next_data_out <= data_out;
next_index <= index;
dataout <= (others => '0');
oe <= '0';
next_bit_in <= bit_in;
case(state) is
when reset => -- initial
if index = 0 then
next_state <= start_m;
next_index <= DELAY_1_MS;
next_number_bit <= N-1;
else
next_state <= reset;
next_index <= index - 1;
end if;
when start_m => -- master send '1' in 1ms
if index = 0 then
next_state <= wait_res_sl;
next_index <= DELAY_40_US;
else
oe <= '1';
next_state <= start_m;
next_index <= index -1;
end if ;
when wait_res_sl => -- wait for slave response in 40us --
next_bit_in <= singer_bus;
if bit_in ='1' and next_bit_in = '0' then --
next_state <= response_sl;
else
next_state <= wait_res_sl;
end if;
when response_sl => -- slave response in 80us
next_bit_in <= singer_bus;
if bit_in ='0' and next_bit_in = '1' then
next_state <= delay_sl;
else
next_state <= response_sl;
end if;
when delay_sl => -- wait for slave delay in 80us
if bit_in = '1' and next_bit_in ='0' then
next_state <= start_sl;
else
next_state <= delay_sl;
end if;
when start_sl => -- start to prepare in 50us
if (bit_in = '0') and (next_bit_in = '1') then
next_state <= consider_logic;
next_index <= 0;
elsif number_bit = 0 then
next_state <= end_sl;
next_index <= DELAY_50_US;
else
next_state <= start_sl;
end if;
when consider_logic => -- determine 1 bit-data of slave
next_index <= index + 1;
next_bit_in <= singer_bus;
if bit_in = '1' and next_bit_in = '0' then -- the end of logic state
next_number_bit <= number_bit -1;
if (index < TIME_28_uS) then -- time ~ 28 us - logic = '0'
next_data_out <= data_out(N-2 downto 0) & '0';
elsif (index < TIME_70_US) then -- time ~70 us - logic ='1'
next_data_out <= data_out(N-2 downto 0) & '1';
end if;
next_state <= start_sl;
next_index <= DELAY_50_US;
elsif bit_in ='1' and next_bit_in ='1' then
next_state <= consider_logic;
end if;
when end_sl => -- tick_done = '1' then dataout has full 40 bit.
if index = 0 then
next_index <= MAX_DELAY;
next_state <= reset;
else
tick_done <= '1';
dataout <= data_out;
next_index <= index -1;
next_state <= end_sl;
end if;
end case;
end process proces_state;
--tristate IOBUFFER
singer_bus <= '0' when oe ='1' else 'Z';
end Behavioral;
There are many errors in your code. How did you debug exactly? Because it seems like you did not.
Why wait for 60 ms after the reset? you waste (valuable) simulation time. 6 ms is more then enough.
Looking at the simulation output, you can see the state does not advance at all: it's stuck ini wait_res_sl. The problem is that you have not added all the signals read in the process to the sensitivity list. I.e.
bit_in ='1' and next_bit_in = '0'
Will not detect a change if next_bit_in is not in the sensitivity list.
A problem -a common mistake made- is that your 'test bench' only provides input stimuli.... But it does not actually test anything.
And then the counters. Why is the delay counter called index? It doesn't index anything.
Why do your time delays not match their label? 70us -> 80 us. 28us -> 30 us.
Small thing don't call a RTL architecture behavioral
I tried to clean your code, seems to work now.
library ieee;
use ieee.std_logic_1164.all;
entity dht2 is
generic (
clk_period_ns : positive := 83; -- 12mhz
data_width: positive:= 40);
port(
clk,rst : in std_logic ;
singer_bus: inout std_logic;
dataout: out std_logic_vector(data_width-1 downto 0);
tick_done: out std_logic
);
end entity;
architecture rtl of dht2 is
constant delay_1_ms: positive := 1*10**6/clk_period_ns+1;
constant delay_40_us: positive := 40*10**3/clk_period_ns+1;
constant delay_80_us: positive := 80*10**3/clk_period_ns+1;
constant delay_50_us: positive := 50*10**3/clk_period_ns+1; --
constant time_70_us: positive := 70*10**3/clk_period_ns+1; --bit > 70 us
constant time_28_us: positive := 28*10**3/clk_period_ns+1; -- bit 0 > 28 us
constant max_delay : positive := 5*10**6/clk_period_ns+1; -- 5 ms
signal input_sync : std_logic_vector(0 to 2);
type state_type is (reset,start_m,wait_res_sl,response_sl,delay_sl,start_sl,consider_logic,end_sl);
signal state : state_type;
signal delay_counter : natural range 0 to max_delay;
signal data_out : std_logic_vector (data_width-1 downto 0);
signal bus_rising_edge, bus_falling_edge : boolean;
signal number_bit : natural range 0 to data_width;
signal oe: std_logic; -- help to set input and output port.
begin
input_syncronizer : process(clk) begin
if rising_edge(clk) then
input_sync <= to_x01(singer_bus)&input_sync(0 to 1);
end if;
end process;
bus_rising_edge <= input_sync(1 to 2) = "10";
bus_falling_edge <= input_sync(1 to 2) = "01";
--register
regis_state:process (clk) begin
if rising_edge(clk) then
case(state) is
when reset => -- initial
if delay_counter = 0 then
number_bit <= data_width;
oe <= '1';
delay_counter <= delay_1_ms;
state <= start_m;
else
delay_counter <= delay_counter - 1;
end if;
when start_m => -- master send '1' in 1ms
if delay_counter = 0 then
oe <= '0';
delay_counter <= delay_40_us;
state <= wait_res_sl;
else
delay_counter <= delay_counter -1;
end if ;
when wait_res_sl => -- wait for slave response in 40us --
if bus_falling_edge then --
state <= response_sl;
end if;
when response_sl => -- slave response in 80us
if bus_rising_edge then
state <= delay_sl;
end if;
when delay_sl => -- wait for slave delay in 80us
if bus_falling_edge then
state <= start_sl;
end if;
when start_sl => -- start to prepare in 50us
if bus_rising_edge then
delay_counter <= 0;
state <= consider_logic;
elsif number_bit = 0 then
delay_counter <= delay_50_us;
state <= end_sl;
end if;
when consider_logic => -- determine 1 bit-data of slave
if bus_falling_edge then -- the end of logic state
number_bit <= number_bit - 1;
if (delay_counter < time_28_us) then -- time ~ 28 us - logic = '0'
data_out <= data_out(data_width-2 downto 0) & '0';
elsif (delay_counter < time_70_us) then -- time ~70 us - logic ='1'
data_out <= data_out(data_width-2 downto 0) & '1';
end if;
delay_counter <= delay_50_us;
state <= start_sl;
end if;
delay_counter <= delay_counter + 1;
when end_sl => -- tick_done = '1' then dataout has full 40 bit.
if delay_counter = 0 then
delay_counter <= max_delay;
state <= reset;
else
tick_done <= '1';
dataout <= data_out;
delay_counter <= delay_counter - 1;
end if;
end case;
if rst = '1' then
number_bit <= 0;
data_out <= (others => '0');
delay_counter <= max_delay;
state <= reset;
end if;
end if;
end process regis_state;
--tristate iobuffer
singer_bus <= '0' when oe ='1' else 'Z';
end architecture;
And test bench: I added one check, but you should make more checks: every time you do something, it should have an effect. You should test if that effect actually happens.
entity dht2_tb is end dht2_tb;
library ieee;
architecture behavior of dht2_tb is
use ieee.std_logic_1164.all;
--inputs
signal clk : std_logic := '0';
signal rst : std_logic := '0';
--bidirs
signal singer_bus : std_logic := 'H';
--outputs
signal tick_done : std_logic;
-- clock period definitions
constant clk_period : time := 83.33 ns; -- 12mhz
use ieee.math_real.all;
-- This function generates a 'slv_length'-bit std_logic_vector with
-- random values.
function random_slv(slv_length : positive) return std_logic_vector is
variable output : std_logic_vector(slv_length-1 downto 0);
variable seed1, seed2 : positive := 65; -- required for the uniform function
variable rand : real;
-- Assume mantissa of 23, according to IEEE-754:
-- as UNIFORM returns a 32-bit floating point value between 0 and 1
-- only 23 bits will be random: the rest has no value to us.
constant rand_bits : positive := 23;
-- for simplicity, calculate remaining number of bits here
constant end_bits : natural := slv_length rem rand_bits;
use ieee.numeric_std.all;
begin
-- fill sets of 23-bit of the output with the random values.
for i in 0 to slv_length/rand_bits-1 loop
uniform(seed1, seed2, rand); -- create random float
-- convert float to int and fill output
output((i+1)*rand_bits-1 downto i*rand_bits) :=
std_logic_vector(to_unsigned(integer(rand*(2.0**rand_bits)), rand_bits));
end loop;
-- fill final bits (< 23, so above loop will not work.
uniform(seed1, seed2, rand);
if end_bits /= 0 then
output(slv_length-1 downto slv_length-end_bits) :=
std_logic_vector(to_unsigned(integer(rand*(2.0**end_bits)), end_bits));
end if;
return output;
end function;
-- input + output definitions
constant test_data_length : positive := 32;
constant test_data : std_logic_vector(test_data_length-1 downto 0) := random_slv(test_data_length);
signal data_out : std_logic_vector(test_data_length-1 downto 0);
begin
-- instantiate the unit under test (uut)
uut: entity work.dht2 -- use entity instantiation: no component declaration needed
generic map (
clk_period_ns => clk_period / 1 ns,
data_width => test_data_length)
port map (
clk => clk,
rst => rst,
singer_bus => singer_bus,
dataout => data_out,
tick_done => tick_done
);
-- clock stimuli
clk_process: process begin
clk <= '0', '1' after clk_period/2;
wait for clk_period;
end process;
-- reset stimuli
rst_proc : process begin
rst <= '1', '0' after 100 us;
wait;
end process;
-- bidir bus pull-up
-- as you drive the bus from the uut and this test bench, it is a bidir
-- you need to simulate a pull-up ('H' = weak '1'). slv will resolve this.
singer_bus <= 'H';
-- stimulus process
bus_proc: process
-- we use procedures for stimuli. Increases maintainability of test bench
-- procedure bus_init initializes the slave device. (copied this from your code)
procedure bus_init is begin
-- singer_bus <= 'Z'; -- initial
wait for 6 ms;
-- singer_bus <= '0'; -- master send
-- wait for 1 ms;
singer_bus <= 'Z'; -- wait response for slave
wait for 40 us;
singer_bus <= '0'; -- slave pull low
wait for 80 us;
singer_bus <= 'Z'; -- slave pull up
wait for 80 us;
end procedure;
function to_string(input : std_logic_vector) return string is
variable output : string(1 to input'length);
variable j : positive := 1;
begin
for i in input'range loop
output(j) := std_logic'image(input(i))(2);
j := j + 1;
end loop;
return output;
end function;
-- procedure send_data
procedure send_data(data : std_logic_vector) is begin
-- we can now send a vector of data,length detected automatically
for i in data'range loop
singer_bus <= '0'; -- slave start data transmission
wait for 50 us;
singer_bus <= 'Z'; -- slave send bit;
-- I found the only difference between sending bit '0'
-- and '1' is the length of the delay after a '0' was send.
case data(i) is
when '0' => wait for 24 us;
when '1' => wait for 68 us;
when others =>
report "metavalues not supported for bus_proc send_data"
severity failure;
end case;
singer_bus <= '0';
end loop;
-- next is VHDL-2008 (else use ieee.std_logic_textio.all;)
report "transmitted: "&to_string(data);
end procedure;
begin
wait until rst = '0';
bus_init; -- call procedure
send_data(test_data); -- call procedure
wait for 100 us; -- final delay
singer_bus <= 'Z'; -- release bus
report "received: "&to_string(data_out);
-- test correctness of output
assert data_out = test_data
report "data output does not match send data"
severity error;
report "end of simulation" severity failure;
end process;
end architecture;

divisor for std_logic_vector VHDL

I try to implement a divisor for std_logic_vector with the language VHDL.
After I have implemented it, I have to use GHDL but encountered this error :
vhdl:error: bound check failure at divisor.vhdl
It's correspond to this :
else ....
nb_reg <= (2*nb);
My code is :
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity div is
generic
(
DATA_WIDTH : natural := 8;
ADDR_WIDTH : natural := 3
);
port (
clk : in std_logic;
reset : in std_logic;
raddr : in natural range 0 to 2**ADDR_WIDTH - 1;
waddr : in natural range 0 to 2**ADDR_WIDTH - 1;
max : in std_logic_vector((DATA_WIDTH -1) downto 0);
data : in std_logic_vector((DATA_WIDTH -1) downto 0);
q : out std_logic_vector((DATA_WIDTH -1) downto 0)
);
end div;
architecture rtl of div is
-- Build a 2-D array type for the RAM
subtype word_t is unsigned((DATA_WIDTH-1) downto 0);
type memory_t is array(natural range <>) of word_t;
-- Declare the RAM signal.
signal ram, div : memory_t((2**ADDR_WIDTH)-1 downto 0);
-- Declare the n and max_reg signal.
signal n,m : unsigned(((2*DATA_WIDTH)-1) downto 0);
signal max_reg : unsigned(((2*DATA_WIDTH)-1) downto 0);
signal nb : unsigned(((2*DATA_WIDTH)-1) downto 0);
signal nb_reg : unsigned(((4*DATA_WIDTH)-3) downto 0);
-- Build div_reg, ram_reg
type memory_reg is array(natural range <>) of unsigned(((2*DATA_WIDTH)-1) downto 0);
signal ram_reg: memory_reg((2**ADDR_WIDTH)-1 downto 0);
begin
process(clk,reset)
begin
if (reset = '1') then
ram(waddr) <= X"00";
div(waddr) <= X"00";
max_reg <= X"0000";
ram_reg(waddr) <= X"0000";
n <= X"0000";
nb <= X"0000";
--nb_reg(((4*DATA_WIDTH)-3) downto 0) <= "0";
m <= X"0000";
elsif(rising_edge(clk)) then
ram(waddr) <= unsigned(data);
max_reg((DATA_WIDTH -1) downto 0) <= unsigned(max);
ram_reg(waddr)((DATA_WIDTH-1) downto 0) <= ram(waddr)((DATA_WIDTH-1) downto 0);
nb <= (nb+1);
if (ram(waddr) = max_reg)then
div(waddr) <= div(waddr)+1;
elsif (ram(waddr) > max_reg)then
while ((div(waddr)*(ram(waddr)) > max_reg) or (m <(DATA_WIDTH -1))) loop
div(waddr) <= (div(waddr))+1;
max_reg <= (max_reg) - (ram_reg(waddr));
m <= m+1;
end loop;
m <= (m-1);
while (((div(waddr)*ram_reg(waddr)) < max_reg-1) or (n <(DATA_WIDTH)-(m))) loop
ram_reg(waddr)(((2*DATA_WIDTH)-1) downto 1) <= ram_reg(waddr)(((2*DATA_WIDTH)-2) downto 0);
ram_reg(waddr)(0) <= '0';
n <= n+1;
nb_reg <= (nb*2);
nb(((2*DATA_WIDTH)-1) downto 0) <= nb_reg(((2*DATA_WIDTH)-1) downto 0);
end loop;
ram_reg(waddr) <= ram_reg(waddr) - (max_reg);
div(waddr) <= (div(waddr))+(1/(nb));
else
while (((div(waddr)*ram_reg(waddr)) < max_reg-1) or (n <(DATA_WIDTH)-(m))) loop
ram_reg(waddr)(((2*DATA_WIDTH)-1) downto 1) <= ram_reg(waddr)(((2*DATA_WIDTH)-2) downto 0);
ram_reg(waddr)(0) <= '0';
n <= n+1;
nb_reg <= (2*nb);
nb(((2*DATA_WIDTH)-1) downto 0) <= nb_reg(((2*DATA_WIDTH)-1) downto 0);
end loop;
ram_reg(waddr) <= ram_reg(waddr) - (max_reg);
div(waddr) <= (div(waddr))+(1/(nb));
end if;
else null;
end if;
end process;
q <= std_logic_vector(div(waddr));
end rtl;
The test bench :
-- descrizione del Test_bench
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity div_tb is
end div_tb;
architecture behaviour of div_tb is
--dichiarazione dei COMPONENT ovvero la Unit Under Test
component div is
generic
(
DATA_WIDTH : natural := 8;
ADDR_WIDTH : natural := 3
);
port
(
clk : in std_logic;
reset : in std_logic;
raddr : in natural range 0 to 2**ADDR_WIDTH - 1;
waddr : in natural range 0 to 2**ADDR_WIDTH - 1;
max : in std_logic_vector((DATA_WIDTH -1) downto 0);
data : in std_logic_vector((DATA_WIDTH -1) downto 0);
q : out std_logic_vector((DATA_WIDTH -1) downto 0)
);
end component;
-- Clock period definitions
constant clk_period : time := 1 us;
constant DATA_WIDTH : natural := 8;
constant ADDR_WIDTH : natural := 3;
signal CLK_tb: std_logic := '0';
signal RESET_tb: std_logic := '1';
signal raddr_tb, waddr_tb : natural range 0 to 2**ADDR_WIDTH - 1;
signal data_tb, q_tb, max_tb : std_logic_vector((DATA_WIDTH -1) downto 0);
signal I : integer := 0; -- variabile per il conteggio dei clock
begin
clk_process: process --processo di generazione del CLK
begin
CLK_tb <= '0';
wait for clk_period/2;
CLK_tb <= '1';
wait for clk_period/2;
I<=I+1;
if I=200 then wait; -- durata della simulazione: 30 colpi di CLK
else null;
end if;
end process;
-- istanziazione della Unit Under Test
UUT: div generic map (ADDR_WIDTH => 3, DATA_WIDTH => 8)
port map (clk=>clk_tb, reset=>RESET_tb, raddr => raddr_tb, waddr => waddr_tb , data => data_tb, q => q_tb, max => max_tb);
stimoli: process
begin
RESET_tb <= '1';
wait for clk_period*3;
RESET_tb <= '0';
wait;
end process;
we: process
begin
max_tb <= "11100110";
wait;
end process;
Data : process
begin
data_tb <= "00000000"; raddr_tb <= 0; waddr_tb <= 0; wait for clk_period*3;
data_tb <= "01010110"; raddr_tb <= 1; waddr_tb <= 1; wait for clk_period*8;
data_tb <= "01000110"; raddr_tb <= 2; waddr_tb <= 2; wait for clk_period*8;
data_tb <= "11001110"; raddr_tb <= 3; waddr_tb <= 3; wait for clk_period*8;
data_tb <= "01000111"; raddr_tb <= 4; waddr_tb <= 4; wait for clk_period*8;
data_tb <= "11100110"; raddr_tb <= 5; waddr_tb <= 5; wait for clk_period*8;
data_tb <= "01000110"; raddr_tb <= 6; waddr_tb <= 6; wait for clk_period*8;
data_tb <= "01010110"; raddr_tb <= 7; waddr_tb <= 7; wait for clk_period*8;
wait;
end process;
end behaviour;
I use the 2007 version of GHDL and it is not possible for me to update, my teacher wants me to use this one.
Could somebody help me with this code?
The multiplication operator in the numeric_std package is defined thus for multiplying a natural by an unsigned:
-- Id: A.18
function "*" (L: NATURAL; R: UNSIGNED) return UNSIGNED;
-- Result subtype: UNSIGNED((R'LENGTH+R'LENGTH-1) downto 0)
-- Result: Multiplies an UNSIGNED vector, R, with a nonnegative
-- INTEGER, L. L is converted to an UNSIGNED vector of
-- SIZE R'LENGTH before multiplication.
As you can see, the output is twice the width of the unsigned argument minus 1. In this line
nb <= std_logic_vector(2*unsigned(nb));
you are assigning the result back to the unsigned operand, which obviously is not a different width to itself.
So, you either need an intermediate variable of the right width or perhaps a shift left?

Resources