I'm trying to make a 8-bit shift register using D flipflop.
The problem is that when simulating it takes two clock rising edges for the register to shift, one for the D input to change, the other for the Q to change. I don't know why.
entity Registry_8 is
port (input : in std_logic;
output : out std_logic;
clk : in std_logic;
clear : in std_logic;
load : in std_logic;
LR : in std_logic;
pIn : in std_logic_vector (7 downto 0);
pOut : out std_logic_vector (7 downto 0);
shift : in std_logic);
end Registry_8;
architecture Behavioral of Registry_8 is
component D_flipflop
port(D, clk, clear, preset : in std_logic;
Q, Q_b : out std_logic);
end component;
signal D, Q : std_logic_vector (7 downto 0);
begin
GEN_FLIP :
for i in 0 to 7 generate
D_i : D_flipflop port map(clk => clk, preset => '0', clear => clear, D => D(i), Q => Q(i));
end generate GEN_FLIP;
process (clk, load, LR, shift)
begin
if (load = '1')
then D <= pIn;
end if;
if (clk'event and clk = '1' and shift = '1')
then
if (LR = '0')
then D(7 downto 0) <= Q(6 downto 0) & input;
output <= Q(7);
else
D(7 downto 0) <= input & Q(7 downto 1);
output <= Q(0);
end if;
end if;
end process;
pOut <= Q;
end Behavioral;
In the process, there is clock edge sensitive condition with the expression:
clk'event and clk = '1'
The process thereby implements an additional level of sequential logic (flip
flops), but you probably wanted to create a process for purely combinatorial
design, like:
process (all) is
begin
if (load = '1') then
D <= pIn;
end if;
if shift = '1' then
if (LR = '0') then
D(7 downto 0) <= Q(6 downto 0) & input;
output <= Q(7);
else
D(7 downto 0) <= input & Q(7 downto 1);
output <= Q(0);
end if;
end if;
end process;
Note that VHDL-2008 all is used as sensitivity list above, to automatically
include all signals used in a process for combinatorial design.
Related
i am new in the fpga filed ,
im trying to sample 2 inputs that rises with clock at the same time.
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith;
use ieee.numeric_std.all;
ENTITY hold_threat IS
PORT (
pwr_gt_thresh : IN std_logic;
clk : IN std_logic;
reset : IN std_logic;
hw_seperation_bin_number : in std_logic_vector(12 downto 0);
fft_raw_index : in std_logic_vector (12 downto 0);
fft_data_valid : in std_logic;
threat_exists_buffered_pulse : out std_logic;
pwr_gt_thresh_out : out std_logic;
threat_end_index :out std_logic_vector (12 downto 0);
threat_start_index :out std_logic_vector (12 downto 0)
);
END hold_threat;
ARCHITECTURE behavoral OF hold_threat IS
signal s_threat_exists_buffered_pulse : std_logic;
signal s_pwr_gt_thresh_out : std_logic;
signal hw_seperation_bin_number_counter : integer range 0 to 8191;
signal s_fft_start_index : std_logic_vector (13 downto 0);
signal s_fft_end_index : std_logic_vector (12 downto 0);
signal s_new_count : std_logic;
begin
threat_start_index <= s_fft_start_index(12 downto 0);
threat_end_index <= s_fft_end_index;
threat_exists_buffered_pulse <= s_threat_exists_buffered_pulse;
pwr_gt_thresh_out <= s_pwr_gt_thresh_out;
process(reset, clk)
begin
if reset = '1' then
hw_seperation_bin_number_counter <= to_integer(unsigned(hw_seperation_bin_number)) -1 ;
s_threat_exists_buffered_pulse <= '0';
s_fft_start_index <="11" & X"FFF";
s_fft_end_index <= '1' & X"FFF";
s_new_count <= '0' ;
elsif rising_edge(clk) then
if(fft_data_valid = '1') then
if (pwr_gt_thresh = '1' ) then
hw_seperation_bin_number_counter <= to_integer(unsigned(hw_seperation_bin_number)) -1;
s_new_count <='1';
s_threat_exists_buffered_pulse <= '1';
if(s_fft_start_index(13) = '1' ) then
s_fft_start_index<= '0'& fft_raw_index;
else
s_fft_start_index<= s_fft_start_index;
end if;
else
if( hw_seperation_bin_number_counter = 0 ) and s_new_count ='1'then
s_threat_exists_buffered_pulse <= '0';
s_fft_end_index<= fft_raw_index;
s_new_count <= '0';
elsif (s_new_count ='1') then
hw_seperation_bin_number_counter <= hw_seperation_bin_number_counter - 1;
s_threat_exists_buffered_pulse <= '1';
end if;
end if;
else -- clock , no data valid
s_threat_exists_buffered_pulse <= s_threat_exists_buffered_pulse;
if (s_new_count = '0') then
hw_seperation_bin_number_counter <= to_integer(unsigned(hw_seperation_bin_number)) -1 ;
s_fft_start_index <="11" & X"FFF";
s_fft_end_index <= '1' & X"FFF";
else
hw_seperation_bin_number_counter <= hw_seperation_bin_number_counter;
s_fft_start_index <=s_fft_start_index;
s_fft_end_index <= s_fft_end_index;
end if;
end if;
end if;
end process;
END ARCHITECTURE behavoral;
in the simulation the clock ,pwr_gt_thresh , fft_data_valid rise together at the same time but the condition
elsif rising_edge(clk) then
if(fft_data_valid = '1') then
if (pwr_gt_thresh = '1' ) then
is never true .
if i change the simulation so that the data rise before the clock everything works good
why the data and the clock cannot rise together ?
Disclaimer: For more complete details you might want to do some research on "setup time" for clocked logic. And while you're at it, keep reading on "hold time".
In just three sentences:
The signal on a sampled data line needs to fulfill some timing requirements to be "caught" correctly. The time before the clock edge is the setup time. The time the signal has to be stable is the hold time.
Something to think about for fun:
You will come across values of real hardware that specify negative setup times. Was does this mean?
I made a simple multiplication unit (16-bit operands, 32-bit result) based on the "shift-left, add" principle, and it does not work properly in the adder part when the overflow bit needs to be considered.
I have an idea what should be done (make a 17-bit sum vector and add an overflow bit to the product), but I don't know how to implement it. Below you can find the waveform file where I am showing the error location and the MPU.vhd file. The screenshot does not show the final result, but it is obvious that it will be wrong. How can I get it to work with large 16-bit numbers?
MPU.vhd
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity MPU_OP is
port (C: in std_logic; -- Clock
RST : in std_logic; -- Reset
LAB : in std_logic; -- Load A and B, P <= 0
SHIFT : in std_logic; -- Shift B and P
OUTHL : in std_logic; -- Output most(0) or least(1) significant word P
DA : in std_logic_vector(15 downto 0); -- Data A
DB : in std_logic_vector(15 downto 0); -- Data B
DP : out std_logic_vector(15 downto 0)); -- Word result P
end entity;
architecture BEH of MPU_OP is
signal A, B : std_logic_vector(15 downto 0); -- A, B
signal Pi, Ai, Si : integer;
signal S : signed(15 downto 0); -- Sum
signal S2 : signed(16 downto 0);
signal P : signed(31 downto 0); -- Product
begin
RG_A : process(C, RST) -- Register for A
begin
if (RST = '1') then
A <= X"0000";
elsif rising_edge(C) then `-- Reg_A`
if LAB = '1' then
A <= DA;
end if;
end if;
end process;
RG_B : process(C, RST) -- Register for B
begin
if (RST = '1') then
B <= X"0000";
elsif rising_edge(C) then
if LAB = '1' then
B <= DB;
elsif (SHIFT = '1') then
B <= std_logic_vector(shift_left(unsigned(B), 1)); `-- Reg_B`
end if;
end if;
end process;
Adder : process (C)
begin
Pi <= to_integer(unsigned(std_logic_vector(P(15 downto 0))));
Ai <= to_integer(unsigned(A));
if B(15) = '1' then
S <= P(15 downto 0) + signed(A); -- Adder
Si <= Pi + Ai;
else
S <= P(15 downto 0);
Si <= Pi;
S2 <= to_signed(Si, S2'length);
end if;
end process;
RG_P : process (C, RST, P) -- Register for P
begin
if RST = '1' then
P <= X"00000000";
elsif rising_edge(C) then
if LAB = '1' then
P <= X"00000000";
elsif SHIFT = '1' then
if B /= "1000000000000000" then
P <= P(30 downto 16) & S & '0'; -- Shift LEFT `-- Reg_Product`
else
P <= P(31 downto 16) & S;
end if;
end if;
end if;
end process;
MUX_P : DP <= std_logic_vector(P(15 downto 0)) when OUTHL = '1' else
std_logic_vector(P(31 downto 16));
end architecture;
Below is the minimal code to reproduce the above problem and the testbench for it.
MPU.vhd
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity MPU_TEST is
port (C: in std_logic;
LAB : in std_logic;
SHIFT : in std_logic;
DA : in std_logic_vector(15 downto 0);
DB : in std_logic_vector(15 downto 0);
DP : out std_logic_vector(31 downto 0));
end entity;
architecture BEH of MPU_TEST is
signal A, B : std_logic_vector(15 downto 0);
signal S : signed(15 downto 0);
signal P : signed(31 downto 0);
begin
RG_A : process(C)
begin
if rising_edge(C) then
if LAB = '1' then
A <= DA;
end if;
end if;
end process;
RG_B : process(C)
begin
if rising_edge(C) then
if LAB = '1' then
B <= DB;
elsif (SHIFT = '1') then
B <= std_logic_vector(shift_left(unsigned(B), 1));
end if;
end if;
end process;
Adder : process (C)
begin
if B(15) = '1' then
S <= P(15 downto 0) + signed(A);
else
S <= P(15 downto 0);
end if;
end process;
RG_P : process (C, P)
begin
if rising_edge(C) then
if LAB = '1' then
P <= X"00000000";
elsif SHIFT = '1' then
if B /= "1000000000000000" then
P <= P(30 downto 16) & S & '0';
else
P <= P(31 downto 16) & S;
end if;
end if;
end if;
end process;
DP <= std_logic_vector(P);
end architecture;
MPU_TB.vhd
library ieee;
use ieee.NUMERIC_STD.all;
use ieee.std_logic_1164.all;
entity mpu_test_tb is
end mpu_test_tb;
architecture TB_ARCHITECTURE of mpu_test_tb is
component mpu_test
port(
C : in STD_LOGIC;
LAB : in STD_LOGIC;
SHIFT : in STD_LOGIC;
DA : in STD_LOGIC_VECTOR(15 downto 0);
DB : in STD_LOGIC_VECTOR(15 downto 0);
DP : out STD_LOGIC_VECTOR(31 downto 0) );
end component;
signal C : STD_LOGIC;
signal LAB : STD_LOGIC;
signal SHIFT : STD_LOGIC;
signal DA : STD_LOGIC_VECTOR(15 downto 0);
signal DB : STD_LOGIC_VECTOR(15 downto 0);
signal DP : STD_LOGIC_VECTOR(31 downto 0);
begin
UUT : mpu_test
port map (
C => C,
LAB => LAB,
SHIFT => SHIFT,
DA => DA,
DB => DB,
DP => DP
);
process
begin
C <= '0';
wait for 5 ns;
C <= '1';
wait for 5 ns;
end process;
LAB <= '1', '0' after 10 ns;
SHIFT <= '0', '1' after 10 ns, '0' after 170 ns;
DA <= X"1234";
DB <= X"F234";
end TB_ARCHITECTURE;
And a new signal with an incorrect multiplication result. The error occurs in adder.
I managed to get it to work. I explicitly added "0" when shifting the product and added a 17th bit to S to keep the overflow bit. Also, the signal ranges have been changed, which should be stored in the product and sum. Ended up with the code below.
MPU.vhd
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity MPU_TEST is
port (C: in std_logic;
LAB : in std_logic;
SHIFT : in std_logic;
DA : in std_logic_vector(15 downto 0);
DB : in std_logic_vector(15 downto 0);
DP : out std_logic_vector(31 downto 0));
end entity;
architecture BEH of MPU_TEST is
signal A, B : std_logic_vector(15 downto 0);
signal S : signed(16 downto 0);
signal P : signed(31 downto 0);
begin
RG_A : process(C)
begin
if rising_edge(C) then
if LAB = '1' then
A <= DA;
end if;
end if;
end process;
RG_B : process(C)
begin
if rising_edge(C) then
if LAB = '1' then
B <= DB;
elsif (SHIFT = '1') then
B <= std_logic_vector(shift_left(unsigned(B), 1));
end if;
end if;
end process;
Adder : process (C)
begin
if B(15) = '1' then
S <= P(16 downto 0) + signed(A);
else
S <= P(16 downto 0);
end if;
end process;
RG_P : process (C, P)
begin
if rising_edge(C) then
if LAB = '1' then
P <= X"00000000";
elsif SHIFT = '1' then
if B /= "1000000000000000" then
P <= P(30 downto 17) & S & '0';
else
P <= P(31 downto 17) & S;
end if;
end if;
end if;
end process;
DP <= std_logic_vector(P);
end architecture;
Simulation screenshots of the correct waveforms
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity struture_test is
Port ( clk : in STD_LOGIC;
rst : in STD_LOGIC;
Init : in STD_LOGIC;
i_ia : in STD_LOGIC_VECTOR (11 downto 0);
i_ib : in STD_LOGIC_VECTOR (11 downto 0);
end_s : out std_logic;
result : out STD_LOGIC_VECTOR (11 downto 0));
end struture_test;
architecture Behavioral of struture_test is
signal en_sn : std_logic := '0';
begin
PROCESS (clk,rst)
variable acc : signed (23 downto 0) ;
variable x : signed (35 downto 0) ;
begin
if (rst = '0') then
result <= (others => '0');
end_s <= '0';
elsif (rising_edge (clk)) then
if ((Init) = '1') then
acc := signed (i_ia)*signed (i_ib);
x := acc * signed (i_ia);
result <= std_logic_vector (x(23 downto 12));
end_s <= '1';
else
end_s <= '0';
end if;
end if;
end process;
end Behavioral;
Hi everyone
I have a project which includes some blocks. The blocks link each other through Init or End Signal. It means that The End signal of one Block is connected to Init signal of the following block.
I'm confused about that Does the above code make a good Init and a End signal ?
If I change my code and convert it into Pipelined structure to operate with the higher frequency clock. The variables convert into the signals
PROCESS (clk,rst)
signal acc : signed (23 downto 0) ;
signal x : signed (35 downto 0) ;
begin
if (rst = '0') then
result <= (others => '0');
end_s <= '0';
elsif (rising_edge (clk)) then
if ((Init) = '1') then
acc <= signed (i_ia)*signed (i_ib);
x <= acc * signed (i_ia);
result <= std_logic_vector (x(23 downto 12));
end_s <= '1';
else
end_s <= '0';
end if;
end if;
end process;
How to create Init and End signal in this case? The block illustrates in the picture
The idea is good, but the code is wrong. In addition it has some bad coding smells.
Basic rules:
Do not use asynchronous resets.
You can not declare signals in processes. Process allow variable declarations; architectures allow signal declarations.
Each signal assignment in a clock process creates a flip-flop / delay of one clock cycle. So it's 3 clock cycles delay in total, but you end signal is only delayed by one cycle.
Do not enable pipelined operations. Use a delayed chain of valid bits.
Do not reset pipeline results, because underlying hardware resources like DSP (multiplication) units do not support resets.
Changed code:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity struture_test is
port (
clk : in std_logic;
rst : in std_logic;
Init : in std_logic;
i_ia : in std_logic_vector(11 downto 0);
i_ib : in std_logic_vector(11 downto 0);
end_s : out std_logic;
result : out std_logic_vector(11 downto 0) := (others => '0');
);
end entity;
architecture rtl of struture_test is
signal ValidChain : std_logic_value(2 downto 0) := (others => '0');
signal ia_delayed : signed(i_ia'range) := (others => '0');
signal acc : signed(23 downto 0) := (others => '0');
signal x : signed(35 downto 0) := (others => '0');
begin
process(clk)
begin
if rising_edge(clk) then
ValidChain <= ValidChain(ValidChain'high - 1 downto ValidChain'low) & Init;
acc <= signed(i_ia) * signed(i_ib);
ia_delayed <= signed(i_ia);
x <= acc * ia_delayed;
result <= std_logic_vector(x(23 downto 12));
end if;
end process;
end_s <= ValidChain(ValidChain'high);
end architecture;
Please note: Signal i_ia used in the 2nd multiplication needs to be delayed by one cycle, otherwise you would mix ia values from different pipeline cycles.
I have a custom designed shift register that has as input DL(leftmost input), DR(rightmost), CLR that clears and loads DR, S that shifts right and W that loads leftmost. After testing it, the rightmost is being loaded but not the left. I have reread the code multiple times, but I can't figure out what is wrong. Here's the code:
library IEEE;
use IEEE.std_logic_1164.all;
entity shiftregister is
port (
CLK, CLR: in STD_LOGIC;
S: in STD_LOGIC; --Shift right
W: in STD_LOGIC; --Write
Cin: in STD_LOGIC; --possible carry in from the addition
DL: in STD_LOGIC_VECTOR (7 downto 0); --left load for addition result
DR: in STD_LOGIC_VECTOR (7 downto 0); --right load for initial multiplier
Q: out STD_LOGIC_VECTOR (15 downto 0)
);
end shiftregister ;
architecture shiftregister of shiftregister is
signal IQ: std_logic_vector(15 downto 0):= (others => '0');
begin
process (CLK)
begin
if(CLK'event and CLK='1') then
if CLR = '1' then
IQ(7 downto 0) <= DR; --CLR clears and initializes the multiplier
IQ(15 downto 8) <= (others => '0');
else
if (S='1') then
IQ <= Cin & IQ(15 downto 1);
elsif (W='1') then
IQ(15 downto 8) <= DL;
end if;
end if;
end if;
end process;
Q<=IQ;
end shiftregister;
Waveform
TestBench
library IEEE;
use IEEE.std_logic_1164.all;
entity register_tb is
end register_tb;
architecture register_tb of register_tb is
component shiftregister is port (
CLK, CLR: in STD_LOGIC;
S: in STD_LOGIC; --Shift right
W: in STD_LOGIC; --Write
Cin: in STD_LOGIC; --possible carry in from the addition
DL: in STD_LOGIC_VECTOR (7 downto 0); --left load for addition result
DR: in STD_LOGIC_VECTOR (7 downto 0); --right load for initial multiplier
Q: out STD_LOGIC_VECTOR (15 downto 0)
);
end component;
signal CLK: std_logic:='0';
signal CLR: std_logic:='1';
signal Cin: std_logic:='0';
signal S: std_logic:='1';
signal W: std_logic:='0';
signal DL, DR: std_logic_vector(7 downto 0):="00000000";
signal Q: std_logic_vector(15 downto 0):="0000000000000000";
begin
U0: shiftregister port map (CLK, CLR, S, W, Cin, DL,DR,Q);
CLR <= not CLR after 20 ns;
CLK <= not CLK after 5 ns;
W <= not W after 10 ns;
DL <= "10101010" after 10 ns;
DR <= "00110011" after 10 ns;
end register_tb;
Your simulation shows that your S input is always high. The way you have your conditions setup, this means that the last elsif statement will not execute because S has priority over W. If you want your write to have priority over your shift operation, you should switch your conditions
if (W='1') then
IQ(15 downto 8) <= DL;
elsif (S='1') then
IQ <= Cin & IQ(15 downto 1);
end if;
Based on your comment for the desired behaviour, you could do something like this:
if (S='1' and W='1') then
IQ <= Cin & DL & IQ(7 downto 1);
elsif (W='1') then -- S=0
IQ(15 downto 8) <= DL;
elsif (S='1') then -- W=0
IQ <= Cin & IQ(15 downto 1);
end if; -- W=0 & S=0
Some improvements:
(1) Remove all signal but CLK from sensitivity list. Your process has no async signals, so only clock is needed in sensitivity list.
process(CLK)
(2) Assign zero only to the required bits -> question of taste ;)
IQ(7 downto 0) <= DR; --CLR clears and initializes the multiplier
IQ(15 downto 8) <= (others => '0');
(3) A elsif statement can clarify the assignment precedence:
if (S='1') then
IQ <= Cin & IQ(15 downto 1);
elsif (W='1') then
IQ(15 downto 8) <= DL;
end if;
(4) Line Q <= IQ; produces a second 16-bit register. I think this is not intended. Move this line outside of the process.
I'm trying to make a VHDL code for 4-bit universal shift register, where I want to load 4 bits and choose the shift-operation from the ctrl. I don't know how to implement a clock divider to run the outputs on a FPGA.
Here is my code so far:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity shift_register is
generic(N : integer := 4);
port(
clk, reset : in std_logic;
ctrl : in std_logic_vector(1 downto 0);
d : in std_logic_vector((N-1) downto 0);
q : out std_logic_vector((N-1) downto 0)
);
end shift_register;
architecture Behavioral of shift_register is
signal r_reg : std_logic_vector((N-1) downto 0);
signal r_next : std_logic_vector((N-1) downto 0);
begin
process(clk, reset)
begin
if(reset = '1') then
r_reg <= (others => '0');
elsif(clk'event and clk = '1') then
r_reg <= r_next;
end if;
end process;
with ctrl select
r_next <=
r_reg when "00", --do nothing
r_reg(N-2 downto 0) & d(0) when "01", --shift left
d(N-1) & r_reg(N-1 downto 1)when "10", --shift right
d when others; --load
q <= r_reg;
end Behavioral;
Divider code template with enable asserted a single cycle every RATIO clock cycles:
library ieee;
use ieee.numeric_std.all;
architecture syn of mdl is
constant RATIO : natural := 10;
signal prescale : std_logic_vector(9 downto 0); -- Scale to fit RATIO - 1
signal enable : std_logic;
begin
process (clk, reset) is
begin
if reset = '1' then
enable <= '0';
prescale <= std_logic_vector(to_unsigned(RATIO - 1, prescale'length));
elsif rising_edge(clk) then
if unsigned(prescale) = 0 then
enable <= '1';
prescale <= std_logic_vector(to_unsigned(RATIO - 1, prescale'length));
else
enable <= '0';
prescale <= std_logic_vector(unsigned(prescale) - 1);
end if;
end if;
end process;
end architecture;