I am new to vhdl programming. I recently got a task to change value of std_logic_vector in a shift register sensitive to clock signal by pressing a button.
When I'm holding KEY(2) the value of shift register changes but it's not shifting unless I release the button. Is it possible to modify my code below so it would be sensitive to rising edge of KEY(2)? Or is there any other possibility to change a value of the vector by pressing the KEY(2) button and it would be shifting even if I'm holding the button?
Thank you for your answer. I would be really grateful and it would really help me a lot.
Sorry for my bad English. Have a nice time.
ENTITY hadvhdl IS PORT (
CLOCK_50 : IN STD_LOGIC;
KEY : IN STD_LOGIC_VECTOR (3 downto 0);
LEDR : OUT STD_LOGIC_VECTOR (15 downto 0)
);
END hadvhdl;
ARCHITECTURE rtl OF hadvhdl IS
shared variable register : std_logic_vector(15 downto 0) := (1 downto 0=>'1', others=>'0');
shared variable count : integer range 1 to 4 :=1;
BEGIN
changecount: process (KEY)
begin
if rising_edge(KEY(2)) then
if count<4 then
count := count + 1;
else
count := 1;
end if;
end if;
end process;
shift: process (CLOCK_50, KEY)
variable up : BOOLEAN := FALSE;
variable reg : std_logic_vector(15 downto 0) := (1 downto 0=>'1', others=>'0');
begin
if rising_edge(CLOCK_50) then
if (KEY(2)='1') then
case count is
when 1 => register := (1 downto 0=>'1', others=>'0');
when 2 => register := (2 downto 0=>'1', others=>'0');
when 3 => register := (3 downto 0=>'1', others=>'0');
when 4 => register := (4 downto 0=>'1', others=>'0');
end case;
end if;
reg := register;
LEDR <= reg;
if up then
reg := reg(0) & reg(15 downto 1);
else
reg := reg(14 downto 0) & reg(15);
end if;
register := reg;
end if;
end process;
END rtl;
Don't use variables! (at least as VHDL-beginner)
Don't use push buttons as clocks (e.g. in rising_edge)
Use only one clock in your design (seem o.k. in your case)
Keep in mind that a mechanical push button do bounces.
And here is a variant for an edge detection:
-- in entity
clk ; in std_logic;
sig_in : in std_logic;
...
signal sig_old : std_logic;
signal sig_rise : std_logic;
signal sig_fall : std_logic;
...
process
begin
wait until rising_edge( clk);
-- defaults
sig_rise <= '0';
sig_fall <= '0';
-- shift value in
sig_old <= sig_in;
-- do some real action
if sig_old = '0' and sig_in = '1' then
sig_rise <= '1';
end if;
if sig_old = '1' and sig_in = '0' then
sig_fall <= '1';
end if;
end process;
Related
I want to make 4kb byte addressable memory. sorry I'm new in VHDL
I wanted my code works first write 4byte number in adress 8 (rdwr=1, addr=1000, size=10(2^2byte), idata=10001100)
then wait 8 cycles to implement writing time(ivalid=0)
Second read 4byte number from adress 8(rdwr=0, addr=1000, size=10(2^2byte))
In my purpose, the "ready" signal should be '0' while waiting for writing time
but the signal is always 'U' in simulation. I tried to figure out what is the problem but i couldn't
Can anyone help me where did a make mistake?
Here is my code
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity Memory is
port (
clk: in std_logic;
ready: out std_logic; -- 0: busy, 1: ready
ivalid: in std_logic; -- 0: invalid, 1: valid
rdwr: in std_logic; -- 0: read, 1: write
addr: in unsigned(11 downto 0); -- byte address
size: in std_logic_vector(1 downto 0); -- 00/01/10/11: 1/2/4/8 bytes
idata: in std_logic_vector(63 downto 0);
ovalid: out std_logic; -- 0: invalid, 1: valid
odata: out std_logic_vector(63 downto 0)
);
end entity;
architecture Behavioral of Memory is
type ram_type is array (0 to (2**12)-1) of std_logic_vector(7 downto 0);
signal RAM : ram_type;
signal state : std_logic := '1'; --if ready '1'
signal queue : std_logic := '0'; --if something to do '1'
signal timer : integer := 0; --timer
signal curr_addr : unsigned(11 downto 0);
signal curr_size : std_logic_vector(1 downto 0);
signal curr_data : std_logic_vector(63 downto 0);
signal write : std_logic := '0';
signal read : std_logic := '0';
begin
process(clk)
variable vstate : std_logic := state;
variable vqueue : std_logic := queue; --if something to do '1'
variable vtimer : integer := timer; --timer
variable vcurr_addr : unsigned(11 downto 0) := curr_addr;
variable vcurr_size : std_logic_vector(1 downto 0) := curr_size;
variable vcurr_data : std_logic_vector(63 downto 0) := curr_data;
variable vwrite : std_logic := write;
variable vread : std_logic := read;
begin
--get input
if(rising_edge(clk)) then
ovalid <= '0';
if(vstate='1') then
if(ivalid='1') then
vcurr_addr := addr;
vcurr_size := size;
if(rdwr='0') then
--read
vread := '1';
else
vwrite := '1';
vcurr_data := idata;
end if;
vqueue := '1';
vtimer := 2**(to_integer(unsigned(vcurr_size)))-1;
end if;
end if;
--process
if(vqueue = '1') then
if(vtimer > 0) then
--wait for next cycle
ready <= '0';
vstate := '0';
vtimer := vtimer - 1;
else
--ok to go
if(vwrite = '1') then
--write
for x in 0 to 2**(to_integer(unsigned(vcurr_size)))-1 loop
for y in 0 to 7 loop
RAM(to_integer(vcurr_addr) + x)(y) <= vcurr_data(y + 8*x);
end loop;
end loop;
elsif(vread = '1') then
--read
for x in 0 to 7 loop
for y in 0 to 7 loop
if(x < 2**(to_integer(unsigned(vcurr_size)))) then
odata(y + 8*x) <= RAM(to_integer(vcurr_addr) + x)(y);
else
odata(y + 8*x) <= '0';
end if;
end loop;
end loop;
ovalid <= '1';
end if;
vqueue := '0';
vstate := '1';
ready <= '1';
end if;
end if;
--save variable to signals
state <= vstate;
queue <= vqueue;
timer <= vtimer;
curr_addr <=vcurr_addr;
curr_size <=vcurr_size;
curr_data<= vcurr_data;
write <= vwrite;
read <= vread;
end if;
end process;
end architecture;
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 12 bits vector called RDIBits and a in std_logic called InUartToUart. My question is: every time the clock goes to '1', i receive a bit in InUartToUart, and i want to concat all the 12 bits that i will receive in the RDIBits vector. Basically, its a serial communication, thats why i receive 1 bit each time. Is there any simple way to do this? Something similar to RDIBits += InUartToUart in JAVA.
I would code this slightly differently. Maybe consider this.
Sorry about the formatting, Im new to this site. I have also shown how you can initialise the variable.
signal RDIBits : std_logic_vector(11 downto 0) := (Others => '0');
...
process(clk)
begin
if ( rising_edge(clk) ) then
RDIBits(11 downto 1) <= RDIBits(10 downto 0);
RDIBits(0) <= InUartToUart;
end if;
end process;
I added some more things, like the entity, the IOs and a counter for the output register.
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;
ENTITY my_uart IS
PORT(
clk : IN std_logic; -- system clock
rst : IN std_logic; -- reset high active
---------------------------------------------
InUartToUart : IN std_logic;
DataOut : OUT std_logic_vector(11 downto 0)
);
END ENTITY;
ARCHITECTURE struct OF my_uart IS
signal RDIBits : std_logic_vector(11 downto 0);
signal counter : integer range 0 to 12;
begin
calc_proc: process(clk, rst)
begin
if (rst = '1') then
RDIBits <= (others => '0');
counter <= 0;
elsif ( rising_edge(clk) ) then
if (counter < 12) then
RDIBits <= RDIBits(10 downto 0) & InUartToUart;
counter <= counter + 1;
elsif (counter = 12) then
DataOut <= RDIBits;
counter <= 0;
end if;
end if;
end process;
END STRUCT;
This is a typical shift register application. For example:
signal RDIBits : std_logic_vector(11 downto 0);
...
process(clk)
begin
if ( rising_edge(clk) ) then
RDIBits <= RDIBits(10 downto 0) & InUartToUart;
end if;
end process;
Hi I have the program below that does what I want to do, shift 1 bit left or right depending on inputs s_right or s_enable. The numeric.std library contains shift operators and I want to start using them so I get a better grasp on the language but can find no good examples that show me the right way at using them
LIBRARY IEEE;
USE IEEE.std_logic_1164.all;
USE IEEE.numeric_std.all;
ENTITY S_REG8 IS
port ( clk, s_enable, s_right, ser_in : in std_logic;
ser_out : out std_logic
);
END ENTITY S_REG8;
ARCHITECTURE dflow OF S_REG8 IS
SIGNAL reg : std_logic_vector (7 DOWNTO 0); --7,6,5,4,3,2,1,0
SIGNAL selectors : std_logic_vector (1 DOWNTO 0);
BEGIN
SHIFT_REG:PROCESS (clk, s_enable, s_right)
BEGIN
selectors <= s_enable & s_right;
IF clk'EVENT and clk ='1' THEN
IF selectors <= "00" THEN
reg (7 DOWNTO 0) <= reg (7 DOWNTO 0);
ELSIF selectors <= "01" THEN
reg (7 DOWNTO 0) <= reg (7 DOWNTO 0);
ELSIF selectors <="10" THEN
reg (0) <= ser_in;
ser_out <= reg(7);
--reg <= std_logic_vector(shift_left(unsigned(reg), 1);
--SHIFT_LEFT (ARG: UNSIGNED; COUNT: NATURAL)
reg (7 DOWNTO 1) <= reg (6 DOWNTO 0);
ELSIF selectors <= "11" THEN
reg (7) <= ser_in;
ser_out <= reg(0);
--reg <= shift_right(std_logic_vector(reg));
reg (6 DOWNTO 0) <= reg (7 DOWNTO 1);
END IF;
END IF;
END PROCESS;
END ARCHITECTURE dflow;
Any help would be great thanks.
From package numeric_std, the body:
-- Id: S.1
function SHIFT_LEFT (ARG: UNSIGNED; COUNT: NATURAL) return UNSIGNED is
begin
if (ARG'LENGTH < 1) then return NAU;
end if;
return UNSIGNED(XSLL(STD_LOGIC_VECTOR(ARG), COUNT));
end SHIFT_LEFT;
-- Id: S.2
function SHIFT_RIGHT (ARG: UNSIGNED; COUNT: NATURAL) return UNSIGNED is
begin
if (ARG'LENGTH < 1) then return NAU;
end if;
return UNSIGNED(XSRL(STD_LOGIC_VECTOR(ARG), COUNT));
end SHIFT_RIGHT;
These call:
-----------------Local Subprograms - shift/rotate ops-------------------------
function XSLL (ARG: STD_LOGIC_VECTOR; COUNT: NATURAL) return STD_LOGIC_VECTOR
is
constant ARG_L: INTEGER := ARG'LENGTH-1;
alias XARG: STD_LOGIC_VECTOR(ARG_L downto 0) is ARG;
variable RESULT: STD_LOGIC_VECTOR(ARG_L downto 0) := (others => '0'); begin
if COUNT <= ARG_L then
RESULT(ARG_L downto COUNT) := XARG(ARG_L-COUNT downto 0);
end if;
return RESULT; end XSLL;
function XSRL (ARG: STD_LOGIC_VECTOR; COUNT: NATURAL) return STD_LOGIC_VECTOR
is
constant ARG_L: INTEGER := ARG'LENGTH-1;
alias XARG: STD_LOGIC_VECTOR(ARG_L downto 0) is ARG;
variable RESULT: STD_LOGIC_VECTOR(ARG_L downto 0) := (others => '0'); begin
if COUNT <= ARG_L then
RESULT(ARG_L-COUNT downto 0) := XARG(ARG_L downto COUNT);
end if;
return RESULT; end XSRL;
Where you find SHIFT_LEFT fills reg(0) with '0' and SHIFT_RIGHT fills reg(7) with '0'.
You had previously assigned ser_in to reg(7) and reg(0) respectively, those assignments would be lost (the last assignment in a sequence of statements wins).
So reverse the order of the assignments:
architecture fie of s_reg8 is
signal reg: std_logic_vector (7 downto 0);
signal selectors: std_logic_vector (1 downto 0);
begin
-- make process purely clock synchrnous
selectors <= s_enable & s_right;
-- ser_out multiplexer instead of flip flop:
ser_out <= reg(7) when s_right = '0' else
reg(0); -- when s_right = '1' else
-- 'X';
shift_reg:
process (clk)
begin
if rising_edge (clk) then -- immunity to metastability transitions
-- if clk'event and clk ='1' then
-- if selectors <= "00" then -- redundant
-- reg (7 downto 0) <= reg (7 downto 0);
-- if selectors <= "01" then -- redundant
-- reg (7 downto 0) <= reg (7 downto 0);
-- elsif selectors <= "10" then
if selectors = "10" then -- was elsif equality not
reg <= std_logic_vector(shift_left(unsigned(reg), 1));
-- also added missing right paren
reg (0) <= ser_in; -- change the order so this occurs
-- ser_out <= reg(7); -- no flip flop
-- reg <= std_logic_vector(shift_left(unsigned(reg), 1);
-- SHIFT_LEFT (ARG: UNSIGNED; COUNT: NATURAL)
-- reg (7 downto 1) <= reg (6 downto 0);
-- elsif selectors <= "11" then
elsif selectors = "11" then
reg <= std_logic_vector(shift_right(unsigned(reg),1));
-- missing distance, proper type conversion
reg (7) <= ser_in; -- change order so this assignment happens
-- ser_out <= reg(0); -- no flip flop
-- reg <= shift_right(std_logic_vector(reg));
-- reg (6 downto 0) <= reg (7 downto 1);
end if;
end if;
end process;
end architecture;
Notice this also gets rid of the ser_out flip flop using a 2:1 mux instead, get's rid of the superfluous 'hold' assignments to reg(7 downto 0), uses the rising_edge function for immunity to events from a metastability value on clk and moves the selectors assignment to a concurrent signal assignment, allowing the process to be purely clock synchronous.
With a testbench (for shift right only):
library ieee;
use ieee.std_logic_1164.all;
entity s_reg8_tb is
end entity;
architecture foo of s_reg8_tb is
signal clk: std_logic := '0';
signal s_enable: std_logic;
signal s_right: std_logic;
signal ser_in: std_logic;
signal ser_out: std_logic;
constant ser_in_val0: std_logic_vector (1 to 8) := x"B9";
constant ser_in_val1: std_logic_vector (1 to 8) := x"AC";
begin
CLOCK: -- clock period 20 ns
process
begin
wait for 10 ns;
clk <= not clk;
if now > 800 ns then -- automagically stop the clock
wait;
end if;
end process;
DUT:
entity work.s_reg8
port map (
clk => clk,
s_enable => s_enable,
s_right => s_right,
ser_in => ser_in,
ser_out => ser_out
);
STIMULUS:
process
begin
s_enable <= '1';
s_right <= '1';
for i in 1 to 8 loop
ser_in <= ser_in_val0(i);
wait for 20 ns; -- one clock period
end loop;
for i in 1 to 8 loop
ser_in <= ser_in_val1(i);
wait for 20 ns; -- one clock period
end loop;
for i in 1 to 8 loop -- so we get all val0 out
ser_in <= ser_in_val0(i);
wait for 20 ns; -- one clock period
end loop;
s_enable <= '0';
wait for 20 ns; -- one clock
wait;
end process;
end architecture;
We get:
Notice at this point we haven't tested s_enable nor s_right = '0', but SHIFT_RIGHT works. Will SHIFT_LEFT work?
The secret was assigning the serial in to reg(0) or reg(7) after the shift function.
Thanks for the detailed reply user1155120. I have used the description below to simulate the left and right shift of one bit through the register.
LIBRARY IEEE;
USE IEEE.std_logic_1164.all;
USE IEEE.numeric_std.all;
ENTITY S_REG8 IS
port ( clk, s_enable, s_right, ser_in : in std_logic;
ser_out : out std_logic
);
END ENTITY S_REG8;
ARCHITECTURE dflow OF S_REG8 IS
SIGNAL reg: std_logic_vector (7 downto 0);
SIGNAL selectors: std_logic_vector (1 downto 0);
BEGIN
selectors <= s_right & s_enable;
ser_out <= reg(7) when selectors = "01" else
reg(0);
shift_reg:
PROCESS (clk)
BEGIN
IF rising_edge (clk) THEN
IF selectors = "01" THEN
reg <= std_logic_vector(shift_left(unsigned(reg), 1));
reg (0) <= ser_in;
-- ser_out <= reg (7);
ELSIF selectors = "11" THEN
reg <= std_logic_vector(shift_right(unsigned(reg),1));
reg (7) <= ser_in;
-- ser_out <= reg (0);
END IF;
END IF;
END PROCESS;
END ARCHITECTURE;
For simulation I have been using Quartus II ModSim which I get the following results from:
The results look great. Adding a single 1 bit state into the register I can see it move to the left or right of the register depending on the toggling of inputs s_right or s_enable.
The use of the multiplexer on the set_out and reg(0) and (7) makes much more sense in comparison to the addition latch that I added to the original description.
MANY THANKS
I want to implement a random-number game on BASYS2. In this game there would be five LEDs chosen out of which one would turn on at random for a second or two (this time can be changed to increase or decrease the difficulty level of the game). Then the user is required to respond to this LED event by pressing the switch button behind it within the time that it is on. If he or she is able to do so successfully a point would be scored and it would be showed on the Seven Segment Display. If he or she fails no point would be scored. There would be 9 such events after which the game can be replayed.
Now following is my code (only for the random LED turning on). However, I am unable to fix it. Please somebody help. The FPGA I am using is BASYS2 SPARTAN 3E-100.
Thanks in advance to everyone.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_unsigned.ALL;
use IEEE.STD_LOGIC_arith.ALL;
entity random_number is
generic ( width : integer := 4 );
port (
clk : in std_logic;
reset : in std_logic;
random_num : out std_logic_vector (width-1 downto 0) --output vector
);
end random_number;
architecture Behavioral of random_number is
signal q: std_logic_vector(23 downto 0);
signal divided_clock: std_logic;
begin
process(clk, reset)
begin
if (reset = '1')then
q <= X"000000";
elsif(rising_edge(clk)) then
q <= q + 1;
end if;
end process;
divided_clock <= q(22);
process (divided_clock)
variable rand_temp : std_logic_vector(width-1 downto 0):=("1000");
variable temp : std_logic := '0';
begin
if(rising_edge(divided_clock)) then
temp := rand_temp(width-1) xor rand_temp(width-2);
rand_temp(width-1 downto 1) := rand_temp(width-2 downto 0);
rand_temp(0) := temp;
end if;
random_num <= rand_temp;
end process;
end Behavioral;
I think the second process should even run with the main clk and the devided clock should be an enable.
signal divided_enable: std_logic;
process(clk, reset)
begin
if (reset = '1')then
q <= X"000000";
elsif(rising_edge(clk)) then
q <= q + 1;
end if;
if (q(22) = '1') then
--short pulse wenn q bit 22 is high
divided_enable <= '1';
q <= (others => '0');
end if;
end process;
process (clk)
variable rand_temp : std_logic_vector(width-1 downto 0):=("1000");
variable temp : std_logic := '0';
begin
if(rising_edge(clk)) then
if(divided_enable = '1') then
temp := rand_temp(width-1) xor rand_temp(width-2);
rand_temp(width-1 downto 1) := rand_temp(width-2 downto 0);
rand_temp(0) := temp;
end if;
end if;
random_num <= rand_temp;
end process;
I don't know if this will fix all your problems. Please discribe compiler errors or errors in the behavior.