• Aucun résultat trouvé

Outputs Encoded within State Bits

Dans le document Programmable VHDL (Page 164-170)

An alternative way to acquire the state machine outputs in teo is to use the state bits themselves as outputs. A counter is an example of a state machine for which the outputs are also the state bits. This may work better than the previous method for some criteria, but it requires a slightly different implementation in which you must choose your state encoding carefully: You must choose a state encoding so that the outputs correspond to the values held by the state registers, as shown in Figure 5-9. This approach makes the design more difficult to comprehend and maintain, so it is only recommended for those cases that require specific area and performance optimization not provided by the current synthesis directives.

I

..

Inputs

... -

State Next next_state ...

...

State current_state

... ...

Logic Registers

Outputs

... ...

Figure 5-9 Moore machine with outputs encoded within state registers

We'll use the memory controller again to illustrate the concept of encoding the outputs within the state registers. With seven states in the machine, the fewest number of state bits that we can use is three. We also have two outputs, addr( 1) and addr(O), that we would like to have propagated to the output pins in teo time (the other two outputs are not critical and can take tC02 time), so altogether we need at most seven macrocells (five for flip-flops and two for combinatorial outputs). Our task now

151

152

is to create a state encoding such that addr( 1) and addr( 0) are two of the state bits. To choose the encoding, we start by creating a table of the present state and outputs that we wish to encode. We will use this table as the starting point for our state encoding table.

State addr(l) addr(O)

idle 0 0

decision 0 0

readl 0 0

read2 0 1

read3 1 0

read4 1 1

write 0 0

Next, we examine the table, looking for the set of outputs that appears with the greatest frequency.

The set of outputs "00" appears with the greatest frequency-four times. To create our state encoding table from here, we need to distinguish the state encoding for idle, decision, read], and write, all of which have address outputs of "00". To create a unique encoding for each state, we need an additional two bits. For each of the four states with the same outputs, we must assign a unique combination of the additional encoding bits. We choose to order the bits sequentially as illustrated in the following table.

State addr(1) addr(O) stl stO

idle 0 0 0 0

decision 0 0 0 1

readl 0 0 1 0

read2 0 1

read3 1 0

read4 1 1

write 0 0 1 1

The remaining states have unique outputs, so we choose to fill in the encoding table with "00" for these entries, although any arbitrary set of two bits will do. Our final encoding scheme follows.

State addr(1) addr(O) stl stO

idle 0 0 0 0

decision 0 0 0 1

State addr(1) addr(O) stl stO

readl 0 0 1 0

read2 0 1 0 0

read3 1 0 0 0

read4 1 1 0 0

write 0 0 1 1

We now have a unique state encoding for each state. You can see that with this scheme we had to use more than the fewest possible number of state bits to encode seven states. But now two of the outputs, addr(l) and addr( 0), are encoded in the state bits. If these outputs were not encoded, to implement the design, a total of seven macrocells would be required for both the state bits (three registers) and the outputs (two registers for raddr(l) and raddr(O), and two macrocells for oe and we), as in the implementation of Listing 5-5 in which two of the outputs were decoded in parallel with the state bits. Although in our new implementation we need to use more state bits than in the previous case, we need fewer total macrocells (six): four for the state encoding and addr outputs, and two for the oe and we outputs. This analysis is for a CPLD implementation; we will discuss an FPGA implementation in the following paragraph.

In an FPGA, the savings in logic resources is not as clear. Four registers and additional logic cells for the next-state logic as well as the output logic for oe and we are required. Without determining the complexity of the next-state and output logic, we can only make educated guesses about the number of logic cells required. Thus, for an FPGA, there is no clear advantage in using this implementation over the previous one in which the outputs are decoded in parallel output registers. The quickest way to find out is often to use software to synthesize the code and see first hand what the setup, internal flip-flop to flip-flop, and clock-to-out delays are. Later in the chapter, we'll choose a method that is more assured to help us achieve an efficient implementation in an FPGA. Nevertheless, the

performance of this state machine is small enough that its implementation in an FPGA will not differ by much regardless of how it is described. For now, we'll proceed, assuming that we will target this design implementation to a CPLD.

Because we will be implementing this design in a CPLD, we will see if fewer total macrocells are required to encode all four state machine outputs in the state encoding. We start, as we did before, by creating a table of present state and outputs.

State addr(l) addr(O) oe we

idle 0 0 0 0

decision 0 0 0 0

readl 0 0 1 0

read2 0 1 1 0

read3 1 0 1 0

read4 1 1 1 0

153

154

State addr(l) addr(O) oe we

write

o o o

Next, we examine the table, looking for the set of outputs that appears with the greatest frequency. If all outputs were unique, then our state encoding would be complete. In this case, the set of outputs

"0000" appears twice (once for state idle and once for state decision), so we must distinguish between idle and decision by adding an additional bit (one bit is sufficient to distinguish two values).

We arbitrarily choose '0' for idle and '1' for decision. Next we arbitrarily choose to fill the remaining entries in the table with '0'. We could choose either '0' or '1' for any of these entries because the state encoding would remain unique regardless of which value we choose. Our final state encoding appears below.

State addr(l) addr(O) oe we stO

idle 0 0 0 0 0

decision 0 0 0 0 1

read 1 0 0 1 0 0

read2 0 1 1 0 0

read3 1 0 1 0 0

read4 1 1 1 0 0

write 0 0 0 1 0

With five bits, the state registers are now able to hold all the outputs. This is a savings of one macrocell over the case in which only addr( 1) and addr(O) are encoded and a savings of two macrocells over the case in which the outputs are decoded either in parallel with or serially from the state bits. In general, macrocell savings depend upon the uniqueness of the state machine outputs on a state-by-state basis. Typically, the worst case will require you to use the same number of macrocells as when decoding the outputs in parallel registers. For state machines implemented in CPLDs, this technique will often produce the implementation that uses the fewest macrocells and achieves the best possible clock-to-out times.

We're now ready to design the state machine, and we'll start by coding the state assignments.

Whereas before you simply indicated the states in an enumerated type, now you will have to explicitly declare the state encoding with constants. Listing 5-6 illustrates this point, in which presenCstate and nexCstate are declared as std_logic_ vectors, rather than the enumerated type, State Type, and the state encoding is specified with constants. (Some synthesis tools allow an enumerated type to be used in conjunction with an attribute or a directive as an alternative to defining constants to specify the state encoding.)

library ieee;

use ieee.std_logic_1164.all;

entity memory_controller is port reset, read_write, ready, burst, clk

bus_id

in std_logic;

in std_logic_vector(7 downto 0);

out std_logic;

oe, we

addr out std_logic_vector(l downto 0)

) ;

end memory_controller;

architecture state_machine of memory_controller is signal state: std_logic_vector(4 downto 0);

constant idle

std_logic_vector(4 downto 0) std_logic_vector(4 downto 0) std_logic_vector(4 downto 0) std_logic_vector(4 downto 0) std_logic_vector(4 downto 0) std_logic_vector(4 downto 0) std_logic_vector(4 downto 0) state_tr:process(reset, clk) begin

if (clk'event and clk='l') then

156

state <= idle;

else

state <= write;

end if;

when others => state <= u _____ u;

end case;

end if;

end if;

end process state_tr;

-- outputs associated with register values we <= state(l);

oe <= state(2);

addr <= state(4 downto 3);

end state_machine; --architecture

Listing 5-6 State machine with outputs encoded in state registers

In this implementation, we used one process to describe and synchronize the state transitions. This process, state_tr, is identical to that of Listing 5-3. The procedure for translating the state diagram to a CASE-WHEN construct changes only slightly. All combinations of the vector state must be accounted for in the CASE-WHEN construct. Thus, the following code is used to indicate that illegal states are don't care conditions:

when others => state <= state-U- - - " ;

More will be said about illegal states and don't cares in our discussion of fault tolerance later in the chapter.

Because the state encoding was explicitly declared and this encoding was chosen such that it would contain present state outputs, the outputs can be assigned directly from the state variable, as follows:

-- outputs associated with register values we <= state(l);

oe <= state(2);

addr <= state(4 downto 3);

Accessing the outputs in this way (i.e., directly from the state flip-flops) means that they will be available teo after the rising edge of the clock, instead of going through the extra pass through the logic array and coming out in te02' as was the case with the original implementation.

This new implementation ensures that an extra pass is not needed to decode several state bits in generating the state machine outputs. Consequently, the outputs are available at the device pins sooner. In addition, this method typically requires fewer macrocells than the method of decoding the outputs in parallel output registers. Equations produced from synthesis are below. Only five equations are required because none of the outputs need to be decoded. State bit names are replaced by the names of the outputs.

state_O.D =

/addr_l.Q * /addr_O.Q * /oe.Q * /we.Q * /reset * /state_O.Q * bus_id_7 * bus_id_6 * bus_id_5 * bus_id_4 * /bus_id_3 * /bus_id_2 * bus_id_l * bus_id_O

addr_l.D

=

/addr_l.Q * addr_O.Q * oe.Q * /we.Q * /reset * ready * /state_O.Q

+ addr_l.Q * oe.Q * /we.Q * /reset * /ready * /state_O.Q + addr_l.Q * /addr_O.Q * oe.Q * /we.Q * /reset * /state_O.Q addr_O.D =

oe.D

we.D

/addr_O.Q * oe.Q * /we.Q * /reset * ready * burst * /state_O.Q + addr_l.Q * /addr_O.Q * oe.Q * /we.Q * /reset * ready *

/state_O.Q

+ addr_O.Q * oe.Q * /we.Q * /reset * /ready * /state_O.Q

/addr_l.Q * /addr_O.Q * /oe.Q * /we.Q * /reset * read_write * state_O.Q

+ addr_l.Q * /addr_O.Q * oe.Q * /we.Q * /reset * /state_O.Q + /addr_O.Q * oe.Q * /we.Q * /reset * burst * Istate_O.Q + /addr_l.Q * addr_O.Q * oe.Q * /we.Q * /reset * /state_O.Q + oe.Q * /we.Q * /reset * /ready * /state_O.Q

/addr_l.Q * /addr_O.Q * /oe.Q * we.Q * /reset * /ready * Istate_O.Q

+ /addr_l.Q * laddr_O.Q * /oe.Q * /we.Q * /reset * fread_write * state_O.Q

We've spent considerable time explaining this design technique and its benefits, so we'll reiterate the drawbacks. First is the extra time and effort required to choose a state encoding that maps well to your state machine's outputs. Second is the loss of readability (and therefore, ease of maintenance and debugging) of the original code. Also, more product terms are typically required. Eventually, synthesis optimization may allow you to use the code of Listing 5-2 to achieve this implementation.

Until then, you will have to decide when to use the different state machine design techniques based on your goals.

To this point, all of the equations that have been generated are for D-type flip-flops. Most CPLD macrocells can also be configured to implement T-type flip-flops. Using T-type flip-flops is transparent to the user. The report file would simply indicate their usage.

Dans le document Programmable VHDL (Page 164-170)