Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Altera_Forum
Honored Contributor I
3,108 Views

4 bit universal shift register using vhdl

Heya guys 

 

for a small exercise, i have been asked to design a 4 bit universal shift register in VHDL. i was wondering if someone could help me start off somewhere as i am completely confused how to go about it. 

 

i have attached a copy of the exercise with this thread 

 

kind regards Daniel
0 Kudos
21 Replies
Altera_Forum
Honored Contributor I
820 Views

Altera_Forum
Honored Contributor I
820 Views

Start by learning what is shift register :) I doubt someone will do Your homework here...

Altera_Forum
Honored Contributor I
820 Views

no i dont need anyone to do my work for me, i just need a rough idea of how i can start to implement it into VHDL. thanks

Altera_Forum
Honored Contributor I
820 Views

 

--- Quote Start ---  

no i dont need anyone to do my work for me, i just need a rough idea of how i can start to implement it into VHDL. thanks 

--- Quote End ---  

 

You already were given a 'rough idea'. Now it's up to you to come back and ask a more specific question based on what you've learned about shift registers, VHDL, or whatever topic you actually need help with. Fishing for someone to give up and write your code for you is pathetic. Specifically, what is it about a shift register or VHDL has you baffled? 

 

Kevin Jennings
Altera_Forum
Honored Contributor I
820 Views

i have made a start to it but i dnt know if i am on the right track. 

here is the code so far 

 

entity universal_shift_register is 

Port ( SIR, SIL, CLK, RST, : in STD_LOGIC; 

D : in STD_LOGIC_VECTOR (3 downto 0); 

Q : out STD_LOGIC_VECTOR (3 downto 0)); 

 

end universal_shift_register; 

 

architecture Behavioral of universal_shift_register is 

 

begin 

 

process (CLK) 

Variable: REG: std_logic_vector (3 downto 0); 

if clk'event and clk= '1' then 

if  

 

end Behavioral; 

 

give me feedback please. i also have (s0 s1) as inputs but i am not sure if i am supposed to incule them and how
Altera_Forum
Honored Contributor I
820 Views

most of the code is missing.

Altera_Forum
Honored Contributor I
820 Views

 

--- Quote Start ---  

i have made a start to it but i dnt know if i am on the right track. 

here is the code so far 

 

entity universal_shift_register is 

Port ( SIR, SIL, CLK, RST, : in STD_LOGIC; 

D : in STD_LOGIC_VECTOR (3 downto 0); 

Q : out STD_LOGIC_VECTOR (3 downto 0)); 

 

end universal_shift_register; 

 

--- Quote End ---  

 

 

You're missing S1 and S0 inputs...add them 

 

 

--- Quote Start ---  

 

architecture Behavioral of universal_shift_register is 

 

begin 

 

process (CLK) 

Variable: REG: std_logic_vector (3 downto 0); 

if clk'event and clk= '1' then 

if  

 

end Behavioral; 

 

give me feedback please. i also have (s0 s1) as inputs but i am not sure if i am supposed to incule them and how 

--- Quote End ---  

 

- S1 and S0 are listed in the definition so why wouldn't you need them? 

- The process will also need to have RST in the sensitivity list since the description says that RST is an asynchronous reset input. If RST had been a synchronous reset, then RST would not be in the sensitivity list. Besides the sensitivity list, then you'll need to add code to support RST (as well as the other inputs) like this... 

 

signal REG: std_logic_vector (3 downto 0); 

... 

process (CLK) 

if rising_edge(clk) then 

.. Here you add your code for computing REG as a  

.. function of SIR, SIL, S1, S0 

end if; 

if (RST = '1') then 

.. Here you define what REG should be set to when it is reset 

end if ; 

end process;  

Q <= REG; -- Set the output of the entity 

Note: With REG as a variable, you wouldn't be able to set the Q output outside of the process. If you tried to set 'Q <= REG' inside the process, then there would be an extra clock cycle delay that would probably not be desired. 

 

Kevin Jennings
Altera_Forum
Honored Contributor I
820 Views

thanks alot Kevin Jennings, that was great help, i was able to finish the coding. but i may need some help on carrying out a Test Bench for it please. 

 

here is the final coding 

 

entity USR is 

Port ( D : in STD_LOGIC_VECTOR (3 downto 0); 

CLK, RST : in STD_LOGIC; 

SIR, SIL : in STD_LOGIC; 

S :in STD_LOGIC_VECTOR (1 downto 0); 

Q : out STD_LOGIC_VECTOR (3 downto 0)); 

end entity USR; 

 

architecture Behavioral of USR is 

 

begin 

 

process(CLK, RST) is 

variable REG : std_logic_vector(3 downto 0); 

begin 

if (RST = '0') then 

reg := (others => '0'); 

elsif rising_edge(clk) then  

case S is 

when "11" => 

REG := D; 

when "01" => 

REG := SIR & REG(3 downto 1); 

when "10" => 

REG := REG(2 downto 0) & SIL; 

when others => 

null; 

end case; 

end if; 

Q <= REG; 

end process; 

 

end architecture;
Altera_Forum
Honored Contributor I
820 Views

Is there any reason you've used a variable? why didnt you just assign Q wherever reg is? its bad practice to assign a signal outside of a clocked branch. 

 

As for the test bench - what problems do you need help with?
Altera_Forum
Honored Contributor I
820 Views

i used variable because my lecturer uses it alot in his notes so i thought i may aswell use it since after all he is the one that gave me the task. so do u insist that i should assign Q wherever Reg is? because i got the idea from a book

Altera_Forum
Honored Contributor I
820 Views

Do you understand the difference between variables and signals? signals are far safer if you're unsure. 

 

Your code should work fine, and I assume compile ok - but its not really a standard way of doing things.
Altera_Forum
Honored Contributor I
820 Views

I re-wrote the program again with the signal in there and REG replaced by Q but i am getting an error (Line 43: Syntax error near "signal".) 

 

 

entity USR is 

Port ( D : in STD_LOGIC_VECTOR (3 downto 0); 

CLK, RST : in STD_LOGIC; 

SIR, SIL : in STD_LOGIC; 

S :in STD_LOGIC_VECTOR (1 downto 0); 

Q : out STD_LOGIC_VECTOR (3 downto 0)); 

end entity USR; 

 

architecture Behavioral of USR is 

 

begin 

signal Q :std_logic_vector(3 downto 0); 

process(CLK, RST) is 

begin 

if (RST = '0') then 

Q := (others => '0'); 

elsif rising_edge(clk) then  

case S is 

when "11" => 

Q := D; 

when "01" => 

Q := SIR & REG(3 downto 1); 

when "10" => 

Q := REG(2 downto 0) & SIL; 

when others => 

null; 

end case; 

end if; 

end process; 

 

end architecture; 

 

 

like i said earlier that i am quite new to VHDL and i am still reading through all my notes and trying to get my head around it.
Altera_Forum
Honored Contributor I
820 Views

signal assignments are done with <=  

variables are := 

 

also replace the other refences to reg with Q 

 

Otherwise this code should be identical. As you're new to VHDL - stay away from variables for now (and point your lecturer in this direction too. But my previous experience with lecturers and VHDL is that they really dont know a lot about VHDL).
Altera_Forum
Honored Contributor I
820 Views

thanks thats a lesson learnt for me. i am going to have a go at the testbench and read more about implementing it with my coding

Altera_Forum
Honored Contributor I
820 Views

Remember - you can do a lot more in a testbench than you would do for a real system. Stuff like this is perfectly normal: 

 

signal clk : std_logic := '0'; 

 

clkc <= not clk after 10 ns; --50MHz clock
Altera_Forum
Honored Contributor I
820 Views

 

--- Quote Start ---  

i am going to have a go at the testbench and read more about implementing it with my coding 

--- Quote End ---  

 

 

Here's an example testbench in VHDL to get you started: 

 

http://www.alteraforum.com/forum/showthread.php?t=32386 

 

Cheers, 

Dave
Altera_Forum
Honored Contributor I
820 Views

 

--- Quote Start ---  

I re-wrote the program again with the signal in there and REG replaced by Q but i am getting an error (Line 43: Syntax error near "signal".) 

 

--- Quote End ---  

 

That's because your declaration for Q was not in the right spot...see below 

 

--- Quote Start ---  

 

entity USR is 

Port ( D : in STD_LOGIC_VECTOR (3 downto 0); 

CLK, RST : in STD_LOGIC; 

SIR, SIL : in STD_LOGIC; 

S :in STD_LOGIC_VECTOR (1 downto 0); 

Q : out STD_LOGIC_VECTOR (3 downto 0)); 

end entity USR; 

 

architecture Behavioral of USR is 

 

begin 

signal Q :std_logic_vector(3 downto 0); 

 

--- Quote End ---  

 

Any signal declarations belong before the 'begin', like this. 

architecture Behavioral of USR is 

signal xyz: ... 

begin 

... 

end Behavioral 

 

The next problem though is you've defined an internal signal called 'Q' which is also defined as an output of the entity. You can only define 'Q' once, otherwise you 'cover up' the outer definition. In this case, when you assign to 'Q' you will be assigning to the signal that is internal to the architecture, but there will be no way to assign to the 'Q' that is the output of the entity. 

 

--- Quote Start ---  

 

process(CLK, RST) is 

begin 

if (RST = '0') then 

Q := (others => '0'); 

elsif rising_edge(clk) then  

case S is 

when "11" => 

Q := D; 

when "01" => 

Q := SIR & REG(3 downto 1); 

when "10" => 

Q := REG(2 downto 0) & SIL; 

when others => 

null; 

end case; 

end if; 

end process; 

 

end architecture; 

 

--- Quote End ---  

 

As previously mentioned, you defined 'Q' as a signal which means you use '<=' rather than ':='. 

 

I don't see where REG is defined at all...signal? variable? 

Also, if you go back to my earlier post, you'll see that you didn't quite follow what (I think) I had which is that the assignment to Q is outside of the process. Something like this (just showing the bare bones, not all that you have) 

 

process(...) 

begin 

.. 

if rising_edge(Clk) then 

-- Set the signal 'REG' in here. 

end if; 

end process; 

Q <= Reg; 

 

What this structure will do is synchronously compute 'REG' (i.e. the inputs will get sampled, and a new value for REG will get computed only at the rising edge of the clock. The 'Q<=REG' assignment is immediate, whenever REG changes, Q will immediately change. 

 

As for variables versus signals, there is nothing inherently wrong with using either one, the tools don't care, don't think that there is anything 'less good' about using variables. However, signals and variables don't do the same thing so how you use them is different. Here is are some code example snippets that are not meant to demonstate any function, just to point out some of the differences in how you use a signal versus a variable. 

 

architecture EXAMPLE_1 of foo is 

signal A: std_logic; 

begin 

process 

variable B: std_logic; 

begin 

if rising_edge(Clock) then 

B := xyz; 

A <= B; 

end if; 

end RTL; 

 

architecture EXAMPLE_2 of foo is 

signal A: std_logic; 

begin 

process 

variable B: std_logic; 

begin 

if rising_edge(Clock) then 

B := xyz; 

end if; 

end RTL; 

A <= B; -- This is illegal because 'B' is not visible outside of the process 

 

architecture EXAMPLE_3 of foo is 

signal A: std_logic; 

begin 

process 

variable B: std_logic; 

begin 

if rising_edge(Clock) then 

A <= B; 

B := xyz; 

end if; 

end RTL; 

 

Some points for you to review and consider.  

- Variable assignments are immediate, if you single step through the code you can see immediately when the variable gets assigned, but not so with a signal. Some folks like that, others it doesn't matter. 

- If you compare Example 1 and 3 you'll see that the only difference is the placement of the statement 'B := xyz' in the process. As written, the two will produce different results. However, if you change 'B' from a variable to a signal (and change the assignment from := to <=) then Example 1 and 3 will produce exactly the same thing. 

- Variable are not visible outside the scope of the process. If you compare Examples 2 and 3, the only difference is the placement of the assignment of the signal 'A'. In example 3, the assignment is within the process but what it means is that there will be two clock cycles of delay between when 'xyz' changes and when 'A' changes. If you wanted to get rid of that delay you might think to move the assignment outside the process as shown in# 2, but this would create a syntax error because there is no 'B' that is in scope. The other solution is to move the assignment of 'B' to be before the assignment to 'A' as in# 1. In this simple case, that's probably the best route, but in a more complicated example it might not. The reason is that when you use variables, the order of the statements matters (like in a software programming language); if you change the order you change the behavior. With signals that is not the case, you can arrange the code as you see fit to better be able to maintain the code in the future. Since you are just starting out, this is not probably even on your radar, it will be if you start designing for real products down the road. If 'B' was a signal in Example 2, then the assignment of 'A' could be moved outside of the process to get rid of the extra clock cycle delay. 

- In the simulator, signal waveforms can be added after the fact without having to restart the sim; variables cannot. To display a variable, you'll have to restart the sim, add the variable to the wave window for display and then run. Debugging goes much faster when you don't have to restart just to see what is going on. Signals allow that, variable don't. 

 

In the end, both variables and signals have their places for use and how you end up thinking is the 'proper' way to use them is not necessarily the same as what someone else would think...neither person is 'right' or 'wrong'. Leaning more towards variables everywhere or signals everywhere simply reflects a person's preferences based on their historical use, how they first learned the language and many other factors. 

 

--- Quote Start ---  

 

like i said earlier that i am quite new to VHDL and i am still reading through all my notes and trying to get my head around it. 

--- Quote End ---  

 

 

Good luck...at some point everybody can clear the hurdle and things will seem much clearer. VHDL is not necessarily any easier or harder than any other language to learn...whether it is or not for a particular person depends on what they are used to with other languages that they have mastered. 

 

Kevin Jennings
Altera_Forum
Honored Contributor I
820 Views

thanks everyone and especially Kevin Jennings. i have corrected my code and i believe it works perfectly fine.the only problem finding how i can input my data into a test bench wave form as its all so confusing.

Altera_Forum
Honored Contributor I
820 Views

for the testbench, you can do it a couple of ways. 

1. VHDL has textio libraries, allowing you to input data from a text file. 

2. create a sequence in the testbench itself. For more complex designs, you can use functions, or procedures (or both, to create a bus functional model), even using psuedoramdom numbers (VHDL has a random number generator) or just directly control the data: 

 

d <= "0000", "0011" after 100 ns, "1111" after 200ns; 

 

or even better, synchronise it with the clock in a process: 

 

process begin d <= "0000"; for i in 1 to 10 loop wait until rising_edge(clk); --or falling edge if you want. Sometimes people do this to make the waveforms a little easier to read. end if; d <= "0011"; for i in 1 to 10 loop wait until rising_edge(clk); end if; d <= "1111"; for i in 1 to 10 loop wait until rising_edge(clk); end if; wait; end process;
Altera_Forum
Honored Contributor I
38 Views

 

--- Quote Start ---  

thanks everyone and especially Kevin Jennings. i have corrected my code and i believe it works perfectly fine.the only problem finding how i can input my data into a test bench wave form as its all so confusing. 

--- Quote End ---  

 

 

There are several approaches, but the most straightforward way in many cases is to simply write some more VHDL code that both generates the stimulus and checks the output of the thing you just wrote the code for.  

 

Here is a start that demonstrates a few different techniques. Normally I would separate the stimulus from the output checking simply because there is usually no clean way to put both inside the same process. In your case though, it can be done since after every clock cycle you can check the resulting output for correctness and then move on to setting up the inputs for the next clock. 

 

architecture rtl of testbench is signal sir, sil, rst: std_logic; signal clk: std_logic := '0'; signal s: std_logic_vector(1 downto 0); signal d: std_logic_vector(3 downto 0); signal q: std_logic_vector(3 downto 0); signal sim_complete: std_logic; begin clk <= not(clk) and not(sim_complete) after 10 ns; rst <= '0', '1' after 15 ns; main : process begin sir <= '0'; sil <= '0'; s <= "00"; d <= (others => '0'); wait until (rst = '1') and rising_edge(clk); assert (q = "0000") report "OOPS! Q outputs are not correct" severity ERROR; -- Add some code to setup s1 and s0 wait until rising_edge(clk); assert (q = ....) -- Based on your specification (i.e. -- the PDF from the original post), you can type -- in what you expect right here for what 'Q' should be ... -- Continue testing all of the other inputs and check the output sim_complete <= '1'; -- This will cause clk to stop, thus ending the sim wait; end process main; dut : entity work.universal_shift_register -- Or whatever it's called port map( sir => sir, sil => sil, ... ); end rtl;  

 

Some principles that are demonstrated in the above are: 

- Using VHDL itself to generate the inputs rather than some other external source file...after all a VHDL file is just as easy to edit as any other text file 

- Testbench that automatically stops itself when complete (see how the signal sim_complete is being used) 

- Self-checking testbench. The specification is used to generate the expected outputs and a VHDL assertion is used to verify that the result is correct. While you'll eyeball the output anyway to see the waveforms, the assertion statement will also be checking that you're not fooling yourself. 

- Additional lines of code (i.e. the testbench) are just as likely to have an error as the code you wrote for the device...both need to be debugged. 

 

Kevin Jennings
Reply