You are on page 1of 10

18-240: Structure and Design of Digital Systems

Lab 3a: Tic Tock


Objective and Overview
In this lab, you will explore FSM design and implementation strategies. You will
implement the same simple FSM in two dierent ways. You will discover that testing
FSMs requires a dierent method of testbench construction. You will implement your
design on the Altera FPGA, compare the synthesis results of the two versions, and then
add additional capability to the FSM.

I recommend reviewing the reading from LDVUS 7.3, especially section 7.3.2, as
preparation for this lab. In addition, I highly recommend ensuring your lab partner has
read (and understands) those sections as well..

Schedule and Scoring


Lab 3a is a two-week exercise. You will want to accomplish some of the design task
prior to coming to lab, but the remainder should be easily completed during your lab
sessions.

The lab is worth 40 points, split among five tasks: Structural Implementation, Abstract
Implementation, Coverage, Synthesis and Expansion. The first four tasks are worth 5
points each, for a total of 20 points. The Expansion task is worth 20 points (10 points
for manual mode and the remainder for using the hardware).

The first four tasks should probably be completed during your first week in lab. The
Expansion task is designed for your second week in lab. Due to the scheduling of
Spring Break, there are actually 3 weeks of calendar time for this lab. You aren't
expected to actually work on this lab during Spring Break, of course.

All tasks are to be completed during lab and demonstrated to the TA by the conclusion
of the 2nd lab session. There is no lab report required for this lab.

A Note about Collaboration


Lab 3, both Part A and Part B, will be accomplished in the same team. By now, you
should be getting used to working with a random partner, which is a great skill to have
as a modern engineer. Continue to be a good teammate, communicate well, and work
well.

Once again, all work you turn in for this lab is expected to be that of your team. You
may ask other students for general assistance, but you may not copy their work.
Likewise, you may not copy work from other sources.

The Mission: More Zorgian Change Machines


After your stunning success with the Zorgian change calculator, the Zorgians are back
with another request. Your industrial and spaceborne contacts indicate the Zorgians
have a big contract up their sleeves (yes, plural) and are simply testing you to see how
well you can design a simple FSM. Youll want to do a spectacular job on this project
in the hopes of landing a cushy Zorgian contract thatll fill your pockets with
pentagons.

Imagine a very simple soda machine where all the products cost 4 circles. The
customer can deposit a series of pentagons, triangles and circles (one at a time) and
anytime they have accumulated 4 or more circles, a soda will drop. Any extra value will
be accumulated and applied to the next order. So, if a Zaggie (their name for an
adolescent Zorgian) puts in a circle (after the machine is reset) nothing happens. If they
then put in a pentagon, a soda drops and 2 circles are still credited. If they then put in
a triangle, another soda would dropwith a credit of 1 circle.

Design a Moore machine to help the Zorgians with this project. Your FSM will take a
two bit input describing the coin that was inserted (2'b01 for a circle, 2'b10 for a
triangle, 2'b11 for a pentagon and 2'b00 for no coin). The FSM will have two outputs.
The first, drop, is a 0 when no soda drops and 1 when one soda drops (or more -- if a
pentagon is inserted when there are already 3 credits built up, the customer will only
get a single soda and zero credits will result. Dont worry, an ancient Zorgian
superstition makes them think this is a lucky circumstance). The second output,
credit, is a 4-bit BCD value indicating how much credit remains.

First, draw the state transition diagram for your FSM. Next, design the next state and
output logic. Use a fully-encoded assignment scheme. Your state-transition table is
probably somewhat large, so we arent going to force you to K-map it or run QM to
minimize the equations. By this point, you are the experts of combinational circuit
design, so make good choices to design the next-state and output-generation logic.
Make sure your design is correct before moving on.

Part 1: Structural Implementation


Implement your FSM in synthesizable SystemVerilog, using a structural-ish style. You
need not use strictly structural style (i.e. gates) for your combinational circuitry, but you
will have explicit flip-flops.

Use continuous-assign statements for your combinational circuitry.

Use the following D-flip-flop module to hold the state. Note that this D-flip-flop has a
synchronous reset.

module dFlipFlop(
output logic q,
input logic d, clock, reset);
always @(posedge clock)
if (reset == 1)
q <= 0;
else
q <= d;
endmodule: dFlipFlop

Your FSM should look something like this.

module myExplicitFSM(
input logic [1:0] coin,
output logic
drop,
output logic [3:0] credit,
input logic
clock, reset);
// interconnect wires. Add more if needed
logic q0, q1, q2; // connect to FF outputs
logic d0, d1, d2; // connect to FF inputs
// Example instantiation of D-flip-flop.
// Add more as necessary.
dFlipFlop ffInst0(.d(d0), .clock(clock), .reset(reset), .q(q0));
// Next state logic goes here: combinational logic that
// drives next state (d0, etc) based upon input coin and
// the current state (q0, q1, etc).
assign ...
// Your output logic goes here: combinational logic that
// drives drop based upon current state (q0, etc).
always_comb ...
endmodule: myExplicitFSM

That wasnt so hard, was it?1 Dont start celebrating just yet. We still need to test it.
Previously, weve seen how easy it is to test combinational logic, but sequential logic is
an entirely dierent beast. Fortunately for us, our design is small enough that we can
test each state and each state transition. That wont always be the case, but we can
worry about that later.

You need to design a set of test vectors that will take the FSM through every state and
through every transition. Think about how to do this; remember, you can only control
the FSM by its input sequence. (Dont forget, you are allowed to reset the FSM in the
middle of the test.)

Good thing you are a master of combinational logic!

Below, we provide you with a sample testbench module that demonstrates a few key
aspects of sequential testbenches. Note that we are taking the state bits q1, q0 as
inputs, even though they arent regular outputs of our FSM. We do this because
testing the FSM is much easier when you can observe the state. So, youll need to go
back to your FSM and make changes so that the state bits are outputs of the module.

module fsmtestbench(
(input logic
input logic [3:0]
output logic [1:0]
output logic

drop, q2, q1, q0,


credit,
coin,
clock, reset);

initial begin
clock=0;
// Initialize the clock to 0
forever #10 clock = ~clock; // Every #10, invert the clock
end
initial begin
$monitor($time,, "state=%d, drop=%d, credit=%d, coin=%d",
{q2, q1, q0}, drop, credit, coin);
// initialize values
coin = 'b00; reset = 1;
// reset the FSM
@(posedge clock); // wait for a positive clock edge
@(posedge clock); // one edge is enough, but what the heck
@(posedge clock);
// release reset and start the vector: 01 01 01 01
@(posedge clock); // begin cycle 0
#1 reset = 0; // We delay by #1 so it is clear
coin = 'b01; // these changes are after the clk edge
@(posedge clock); // begin cycle 1
#1 coin = 'b01;
@(posedge clock); // begin cycle 2
#1 coin = 'b01;
@(posedge clock); // begin cycle 3
#1 coin = 'b01;
@(posedge clock);
#1 $stop;
end
endmodule: fsmtestbench

The most important new thing we see here is @(posedge clk);. When this is written
as a statement in an initial process, it instructs the simulation to wait until the next
positive clock edge before continuing to the next statement. In this way, we can easily
synchronize the input vector relative to the clock. For example, in the above, we are

changing the input coin slightly after the clock edge (by adding a delay #1) rather
than immediately after the clock edge. This helps to avoid any ambiguity2 about what
is the value of coin on the clock edge when viewing the simulation results.

Add a top module to connect your FSM to the testbench. Then, expand upon the
testbench skeleton to test all states and transitions in your FSM. Its useful to
document (in comments) what the desired FSM behavior is.

For credit: Show the TA simulation output proving that your testbench successfully
tests all your FSM states.

Part 2: A more abstract FSM design


The explicit style of FSM design is fine when you have a few states, but what happens
when things become complicated? We would never build a big combinational circuit at
the gate level, so why would we build a big sequential circuit at the gate and flip-flop
level? Instead, lets design the FSM at a higher level, and let the synthesis tool take
care of the low level logic. Lets look at a SystemVerilog FSM example that uses
symbolic state names and can be transcribed nearly literally from a state transition
table or diagram.

module myMoreAbstractFSM (
input logic [1:0] coin,
output logic
drop,
output logic [3:0] credit,
input logic
clock, reset);
// Define your states and state encodings here
// (increase bitwidth if you need more than eight states)
enum logic [2:0] {stateReset = 3'd0,
stateFoo = 3'd1...} currState, nextState;
// Next state logic is defined here. You are basically
//
transcribing the next-state column of the state
//
transition table into a SystemVerilog case statement
always_comb
case (currState)
stateReset: begin
// assign a value to nextState based on input, e.g.
nextState = (x == 1) ? stateFoo : stateBar;
end
// ...
// one case for each state in your FSM
// ...
2 There is no real ambiguity here. If you wrote x=1;@(posedge clock);x=0; x is 1 at the clock edge;
that is, every process triggered by the posedge clock will read x as 1. The ambiguity being dodged is
in the mind of designers reading your code. By being extra clear, the testbench is better understood and
verified to be correct.

default :
nextState = stateBar;
endcase
// Output logic defined here. You are basically transcribing
//
the output column of the state transition table into a
//
SystemVerilog case statement.
// Remember, if this is a Moore machine, this logic should
//
only depend on the current state. Otherwise, the
//
assignment would also involve the input value.
always_comb begin
case (currState)
stateReset: begin
drop = 1; credit = 3'd0;
end
// ...
// one case for each state in your FSM
// ...
default : drop = 0;
endcase
end
// Synchronous state update described here as an always block.
// In essence, these are your flip flops that will hold the
// state. This doesnt do anything interesting except to
// capture the new state value on each clock edge.
always_ff @(posedge clock)
if (reset)
currState <= stateReset; // or whatever
else
currState <= nextState;
endmodule: myMoreAbstractFSM

Note that we are careful to ensure the case statements generate combinational
circuitry either by providing a default to our case statements or by using unique
case.3 This will let us indicate to the synthesis tool that this is combinational logic, and
we have listed the cases we care about. By following this coding style closely, the
synthesis tool is able to infer that this is an FSM, and can even change our state
encoding to optimize for you. Recreate your FSM from Part 2 in this style. You can
use the same testbench as before to simulate this FSM, though you probably want to
modify it just a bit as you no longer have individual state bits. You can use the .name
magic to print your state names in the $monitor statement.

For Credit: This part will be checked o with Part 3.

You may find default statement a better choice here, as you have a synchronous reset. Can you
figure out why?
3

Part 3: Simulation with Coverage Analysis


An interesting simulation option in VCS is coverage analysis. By activating this option,
the simulator will keep track, on a line by line basis, of how many times each line of
your SystemVerilog description has been exercised. In this way, you can verify that
your simulation puts the FSM through each state and transition. For example, here are
a few lines of a coverage analysis output (for some other FSM):

27
28
29
30
31
32

1/1
0/1
1/1
1/1

==>

1/1

Saw00: if (in_val == 2'b11)


nextState = Saw0011;
else if (in_val == 2'b01)
nextState = Saw0001;
else
nextState = Init;

In the above, the first column of numbers shows the line numbers in your
SystemVerilog source. The second column indicates the number of times that line of
code was exercised out of the total executions of the block. See that this FSM was in
Saw00, but never transitioned to Saw0011. Note that if we had written a conditional
statement as

nextState = (x==1) ? stateB : stateC;

we would not be able to see the transitions individually the tool would just report
that it evaluated this line 4 times.

To simulate with coverage analysis, follow the normal routine to simulate your
SystemVerilog design. You will need to modify the compilation statement by providing
a coverage option such that "lines" are counted (-cm line). In addition, you'll may
want to force VCS to count continuous assignment statements (-cm_line
contassign):

vcs -sverilog -cm line -cm_line contassign *.sv

Next run your simulation, but request the simulation accumulate coverage data:

./simv -cm line

At this point, you have some coverage data (stored in a directory named simv.vdb),
but you want a readable coverage report, not a binary database of unreadable stu.
Use the "Unified Report Generator" to turn that stu into something useful.

urg -dir simv.vdb -format text

A report will be generated in the directory urgReport. The report is broken up into a
bunch of separate text files. The first, dashboard.txt, gives a very concise overview,
without much useful detail:

----------------------------------------------------------------Total Coverage Summary


SCORE LINE
84.51 84.51

The hierarchy.txt report gives a similarly concise overview, broken down by module.
The really useful detail is in modinfo.txt, which shows how many times each line was

executed and highlights (with ==>) any lines that weren't executed. Note also that
some lines aren't "coverable" in that they specify stu that doesn't actually execute.
These are lines with always_ff, begin, else, comments, endmodule, etc.

If you prefer prettier reports, you can skip the "-format text" part of the urg
command and you will get a series of html files.

Take a look at the report. Most of it is self explanatory. You might spot a statement
that was not executed, in which case you will need to update your testbench.

A second coverage option is particularly useful for this lab. Re-compile, re-simulate,
and re-urg your code with:

vcs -sverilog -cm fsm *.sv


./simv -cm fsm
urg -dir simv.vdb -format text

The fsm option in the cover flag is for FSM. Take a look at the new modinfo.txt file to
see that you get a report that knows about your FSM states. It tracks how often you
get to each state and how often each transition is followed. Useful, eh? Update your
testbench if any coverage statistic is lower than 100%.

There are two caveats with respect to getting VCS to show 100% test coverage. The
first is that the tool will count a transition as fully tested if the transition is ever taken.
To get full coverage, you need to actually take each transition for every combination of
inputs. For instance, if the transition from State0 to State1 happens when A=1 and
B=X, you actually need two dierent tests to cover this transition (where B=0 and
where B=1). If you only run a single test with B=0, the tool will still show 100%
coverage. So, you will need to have 100% coverage AND be able to show the TAs that
you have each possible combination tested.

The second caveat is that the tool wants you to follow the reset transition from each
and every state. I'm not at all concerned about testing those I figure if you've tested
reset at all, you probably got it correct. So, if VCS shows less than 100% coverage,
but you can show that it is only missing reset transitions, you will still get full credit.

It may be useful to run line and fsm coverage at the same time. The coverage metric
flag for that is -cm line+fsm.

For Credit: Show the TA your coverage report to prove your testbench has 100%
coverage of each FSM statement and each FSM state/transition.

Part 4: Synthesis
You now have two versions of the same FSM. In the first, you optimized the logic by
hand. In the second, you let the SystemVerilog tools optimize the logic for you.
Synthesize both designs using Quartus II on your lab computer. (Note: we no longer
want the state bits to be outputs of your FSM.) Compare the number of logic
elements, registers, and the maximum clock frequency (Fmax) needed by the two
designs. The first two measurements can be found in the Flow Summary, while the
clock frequency is found in the "TimeQuest Timing Analyzer, Slow 1200mv 85C Model,

Fmax Summary. Comparing the values for the two circuits, what do you think about
abstract models? In particular, can you say anything about the encoding mechanism
used?

Next, download the FSM onto the DE2-115 FPGA board (use your second design).
Assign clock to KEY0. Assign reset to SW5. Assign the coin input to SW1:SW0.
Assign the drop output to all 8 red LEDs (LEDR7:LEDR0) such that they light up when a
drink drops. Assign credit to HEX04.

For Credit: Demonstrate your circuit to the TA. Show the TA your size and speed
measurements for the two dierent circuits and explain your hypothesis about
encoding mechanisms. Be able to demonstrate what a synchronous reset means.

Part 5: Expansion
Hopefully you now understand the power of the abstract version of your FSM. It is
much easier to specify, debug and modify than the first version. And, that is exactly
what the Zorgians wish you to do for this part.

The Zorgians have now given you a useful piece of hardware a coin accepter. The
coin accepter will take the physical circles, triangles and pentagrams and generate
signals that your FPGA board can decode. If you don't happen to have any Zorgian
change on you; US nickels, dimes, and quarters will suce (respectively).

There are a few tricks to interpret the Zorgian coin accepter's signals, for which we
have helpfully given you an interface module. You will find the module coinAccepter
in the file coinAccepter.sv in the handout directory. Please include it in your design.
The module header looks like this:

module coinAccepter (
input logic CLOCK_50, // pin Y2
input logic reset,
input logic UART_RXD, // pin G12
input logic UART_RTS, // pin J13
output logic UART_TXD, // pin G9
output logic UART_CTS, // pin G14
output logic circle, triangle, pentagon,
input logic manualMode, manualClockL,
input logic manualCircleL, manualTriangleL, manualPentagonL,
output logic clock);

The first parts of this look a bit scary. All of the UART_X signals are used to read the
serial input from the accepter (and you don't have to worry about them, other than
hooking them up to the right pins). CLOCK_50 is a 50MHz clock signal that will be used
to drive your FSM as well as the coinAccepter. Yep, that's right, your FSM will blaze
along at 50MHz and you won't have to keep pushing the button each time.

Oops! The seven-segment LEDs need some sort of decoder to translate from a binary value. Hmm.. I
wonder where you will get such a decoder?
4

The circle, triangle and pentagon signals are the useful ones that will tell you when
a coin has been accepted. Only one of these three signals will be asserted at a time.
The tricky part is, when a coin has been accepted, the associated signal will be
asserted for more than one clock period. In fact, it probably will be many clock periods
(and you don't know how many something like 100mS worth) before it is deasserted. You will need to track the asserted and non-asserted nature of each signal.

Now, testing such an interface might be a bit tricky, especially as there is only one
physical piece of hardware for the entire lab section. Thus, we have built a debugging
interface into coinAccepter that's the next two lines. The manualMode signal tells
the interface whether it should look for physical hardware or not. Connect manualMode
to SW17. When asserted, the coinAccepter will ignore the UART_X signals and will look
to push buttons to tell it what to do. The manualClockL signal (hooked to KEY0) will be
used as it's clock. Hook manualCircleL to KEY1, manualTriangleL to KEY2 and
manualPentagonL to KEY3. Recall that the buttons are active low (i.e. a zero when
pressed)that's why these signals are active low. Now, you can simulate putting a
coin into the coinAccepter by pressing one of the buttons. Move your reset to SW0
(but keep it synchronous) you no longer have a coin input. The final signal is clock.
You should use this signal as the clock for your FSM. We will do the right things to
ensure your manual clock is actually debounced, or to provide you with the 50 MHz
clock on clock, depending on manualMode.

You will need to modify your FSM due to the changing nature of the inputs. You
certainly could convert the circle, triangle, pentagon signals into a 2-bit coin input, but
that is a bad idea. The nature of those signals has changed due to being active for
multiple clock edges. Rather, modify your FSM to work with the new signals. When
you are done, demonstrate your FSM in manual mode to the TA. If the TA approves,
you may connect up the hardware coin accepter and flip the manualMode switch
(SW17). The coin accepter has a serial connector that you should hook up to the RS232
port on the upper right of the FPGA board.

For Credit: 2 demonstrations of the coinAccepter FSM on the DE2-115 FPGA board.
The first is in manual mode, the second with the coin accepter hardware. During this
second demonstration, be ready to discuss the implications of having a synchronous
versus asynchronous reset when your FSM is using CLOCK_50.