Monday, September 14, 2009

HDL Functions

If you need to create a function in HDL you're in luck, cause I had to learn it myself last week. And lucky for me it was very simple.

In my particular case I was using an enumerated signal type and I needed to convert that signal back to a std_logic_vector signal such that I could output that signal for debugging purposes. Below is the code I used to convert two enumerated inputs to a single logic vector signal. Notice that the syntax is very similar to "process" definitions. The only key difference is the "return" declaration after the function declaration. This return declaration only requires the data type. It does not need to know what size the vector is (if it is a vector). This is nice since it potentially allows the user to have variable sized inputs...although I have not tried this myself, so it might not be synthesize-able.

function enum2std_logic(
arg1:STATE_TYPE;
arg2:SUBSTATE_TYPE)
return std_logic_vector is
variable val: std_logic_vector(3 downto 0);
begin
case arg1 is
when IDLE =>
val(3 downto 1):="000";
when READ1 =>
val(3 downto 1):="001";
when READ2 =>
val(3 downto 1):="010";
when WRITE1 =>
val(3 downto 1):="011";
when WRITE2 =>
val(3 downto 1):="100";
when others =>
val(3 downto 1):="000";
end case;
case arg2 is
when Processing =>
val(0):='0';
when Waiting =>
val(0):='1';
end case;
return val;
end function enum2std_logic;

Hope this helps.

HDL Enumerations

If you are like me and have trouble remembering what bits correspond to what setting or action in your code then enumerated types are your best friend.

To create an enumerated type just follow this syntax:
type STATE_TYPE is (IDLE, READ1, READ2, WRITE1, WRITE2);
attribute ENUM_ENCODING: STRING;
attribute ENUM_ENCODING of STATE_TYPE:type is "000 001 010 011 100";

This creates a data type called STATE_TYPE that contains the enumerations: IDLE, READ1, READ2, WRITE1, WRITE2

These enumerations use the following encoding respectively: 000, 001, 010, 011, 100

All you have to do to create a signal that uses such an enumerated type is specify STATE_TYPE (or whatever you choose to call it) as the data type in your signal declaration.

Hope this helps.

HDL Statemachines

Often times in HDL programming we need to describe what is know as a statemachine. For those unfamiliar with what statemachines are please refer to:
Finite-State-Machines

State machines require the use of both combinational logic and registers. The registers are used to hold the state variable information that is required to make the decision in the "next" clock cycle. The combinatorial logic is used to set the criteria for transitioning from one state to the next.

In this article I will show an example of how you might choose to implement a statemachine. This is not necessarily the best or most efficient way to implement one, but it is the way that I found easiest to understand.

If you have been following my HDL articles up to this point you probably noticed that I have only shown an architecture containing a single process. In the case of a statemachine, you must have at least 2 processes defined.
  • One process controls the updating of the state variables
  • One process handles the logic and navigation to the "next" state
Suppose we have a system that requires the use of a statemachine that contains two states, 0 and 1, which are mapped to a signal called "state". Also, suppose a logic variable that is used to navigate from one state to the next is define as "input" which can also take on the value of 0 or 1. Finally, lets suppose the logic that this statemachine follows is:

If state=0
If input=0
stay in state 0
Else
go to state 1
End if;
Else
If input=1
state in state 1
Else
go to state 0
End if;
End if;


To create this system using a statemachine is quite simple. First lets create the state update process:

update_states: process (clk)
begin
if(clk'EVENT and clk='1') then
current_state<=next_state; end if; end process;


The process above uses 3 signals.
  1. clk = This is the clk to the system, and in this case we are operating on the positive edge of the clock; however, you can make it operate on whatever part of the clock signal you wish.
  2. current_state = This is the current state we are in. This is to be used in the combinational logic.
  3. next_state = This is the next state that we will transition to in our statemachine.
You might be wondering, why do we have two state variables when you clearly defined having just one?

First, think of a REAL system that operates on clock edges; lets just say we have 2 casscaded positive edge triggered D-Flip Flops. What happens when you try to grab a value at the output of the first flip flop (which is the input to the second flip flop) and simultaneously try to write a new value at the input to 2nd flip flop?

The problem is, trying to simulateously read and write on a signal (or line) is undeterministic. We must remember that HDL uses concurrency, so we don't know whether the read or the write operation occurred first. Because of this, we must define two signals, one which is used to indicate the current state, that we can use to "read" from, and we define another signal that indicates the next state, that we can "write" to.

Now that we have our update_states process defined we can now work on the logic. In this example our logic is VERY simple.


    state_machine: process (clk)
    begin
    if(clk'EVENT and clk='1') then
    if (current_state='0') then
    if (input='0')
    next_state<=next_state; else next_state<='1'; end if; else if (input='1') next_state<=next_state; else next_state<='0'; end if; end if; end if; end process;


    And there you have it...your two processes that make the simple statemachine we defined. Of course, for this to work in an actual design, you will need to define the clk, current_state, next_state, and input signals. Which I am sure you can do if you read my previous tutorials.