Sunteți pe pagina 1din 66

Aebeedec Jan H. Luciano Engr.

Gillert Bongcac
BSECE-5 CSC 127

Lab 1.1

In this lab, you will:


• Learn how to invoke a Verilog simulation
• Recognize common syntax errors

Using a text editor, enter the following Verilog modules in separate files.
• Fix any syntax errors or warnings in the specification or any that you may introduce.

Module HELLO
hello.v initial $write(“Hello World!\n”);
endmodule;

module \HI;
hi.v initial $write(“Hi there!\n”);
end module;

Simulating each module separately using a single Verilog simulator, modelsim shows the following
output:

HELLO.v HI.v

Simulating both module together using the same Verilog simulator, modelsim shows the following
output:

vsim HI HELLO vsim HELLO HI

Questions:

1. Reverse the order in which the modules are specified on the command line. Are the results
different?
Answer:
As the order of the way modules are specified is reversed, the results also show a
reversed order which demonstrates how dependent the results are to the way the modules are
sequenced.

2. Should you care?


Answer:
It depends on what is asked. Of course, if a specific order in the result is
required, I should care.
Lab 1.2

In this lab, you will:


• Work with always blocks
• Work with initial blocks
• Use the $finish statement

Enter the following Verilog module in a file:

module HELLO;
always
begin
end
endmodule

Simulate the module

What is happening?
Answer:
Modelsim seems to display blank results infinitely.

To help diagnose what is going on, add a $write statement inside the always block

module HELLO;
always
begin
$write(“Hi!\n”);
end
endmodule;

Try to simulate the module again.

Does the output confirm your suspicions?


Answer:
Yes it does! Adding the $write statement confirms that using the always statement indeed
makes the output display results infinitely.
In this case, it displays Hi.

Edit the module and insert a $finish statement at the end of the always block.
Simulate the module again.

How is the simulation different?


Answer:
When the result is displayed, a dialog box appears automatically asking for one to finish the
simulation or not.

Edit the module and replace the “always” keyword with “initial”. The change turns the always
block into an initial block.
Simulate the module again
Is the simulation behavior different?
Answer:
Yes! It is different since the result only occurred once.

Why did the simulation terminate by itself?


Answer:
The simulation terminated by itself automatically since the program requires only a single run
and also, the “$finish” statement that pops out a dialog box allowing the user to choose for the
simulation whether to finish or not, isn’t present.
Lab 2.1

In this lab, you will:


• Learn to use various operators
• Witness the effect of operation sizes
• Use registers as targets of assignments
• Use concatenated assignment targets
• Learn the difference between a vector and a memory

In directory ~/lab2.1, you will find a file name “try.v”. It contains an initial block with a
single $write statement that is used to display the binary result of an expression.
Replace the “<expression>” in the $write statement with each of the expressions on the
next slide.

What are the results you expect?


Answer:
Upon analysing the code, my expected results are listed below.

Expression Expected Result

1 "00000000000000000000000000000001"
1'b1 "1"
-1 "11111111111111111111111111111111"
-1'b1 "1"
1 << 1 "00000000000000000000000000000010"
1'b1 << 1 "0"
&4'b1111 "1"
&4'b111 "0"
|4'b0x10 "1"
|4'b0x00 "x"
4'b1111 & 1 "00000000000000000000000000000001"
~4'b1000 "0111"
!4'b1000 "0"
(1'b1) ? 1'bz : 3'bx "00z"
(1'bx) ? 1'b1 : 1'b0 "x"
(!1'bx) ? 1'b1 : 1'b0 "x"
(2'b10 & 2'b01) ? 1'b1 : 1'b0 "0"
(2'b10 && 2'b01) ? 1'b1 : 1'b0 "1"
(1'bx == 1'bx) ? 1'b1 : 1'b0 "x"
1'bx === 1'bx) ? 1'b1 : 1'b0 "1"
{1'b1, {2'b01, 3'b1}} "101001"
{3{1'b1, 2'bz}} "1zz1zz1zz"
Modelsim displayed the following results:
1 - # Result = “00000000000000000000000000000001”
1'b1 – # Result = “1”
-1 – # Result = “11111111111111111111111111111111”
-1’b1 – # Result = “1”
1<<1 – # Result = “00000000000000000000000000000010”
1’b1<<1 – # Result = “0”
&4’b1111 – # Result = “1”
&4’b111 – # Result = “0”
|4’b0x10 – # Result = “1”
|4’b0x00 – # Result = “x”
4’b1111 & 1 – # Result = “00000000000000000000000000000001”
~4’b1000 – # Result = “0111”
!4’b1000 – # Result = “0”
(1'b1) ? 1'bz : 3'bx – # Result = “00z”
(1'bx) ? 1'b1 : 1'b0 – # Result = “x”
(!1'bx) ? 1'b1 : 1'b0 – # Result = “x”
(2'b10 & 2'b01) ? 1'b1 : 1'b0 – # Result = “0”
(2'b10 && 2'b01) ? 1'b1 : 1'b0 – # Result = “1”
(1'bx == 1'bx) ? 1'b1 : 1'b0 – # Result = “x”
(1'bx === 1'bx) ? 1'b1 : 1'b0 – # Result = “1”
{1'b1, {2'b01, 3'b1}} – # Result = “101001”
{3{1'b1, 2'bz}} – # Result = “1zz1zz1zz”

Repeat the exercise, this time assigning the result of the expression to an 8-bit register,
then displaying the contents of the register.
Displayed results in Modelsim:
1'b1
1'b1
-1'b1
-1'b1
1<<1
1’b1<<1
&4’b1111
&4’b111
|4’b0x10
|4’b0x00
4’b1111 & 1
~4’b1000
!4’b1000
(1'b1) ? 1'bz : 3'bx
(1'bx) ? 1'b1 : 1'b0
(!1'bx) ? 1'b1 : 1'b0
(2'b10 & 2'b01) ? 1'b1 : 1'b0
(2'b10 && 2'b01) ? 1'b1 : 1'b0
(1'bx == 1'bx) ? 1'b1 : 1'b0
(1'bx === 1'bx) ? 1'b1 : 1'b0
{1'b1, {2'b01, 3'b1}}
{3{1'b1, 2'bz}}

Explain any difference.


Answer:
The results in this simulation always contain 8-digits to it unlike the results in our first simulated
program. It is expected for this to happen since an 8-bit register is used.
Lab 2.2

In this lab, you will:


• Learn how to use the if and case statements
• Learn how unknowns are handled in the if and case statements
• See how a case statement can be used to model an FSM

Operands != and !== designates different functions. The former indicates logical inequality while
the latter denotes not synthesizable. In the code, instead of setting the register to 1’b1 it was set to 1’bx
so, when the computer reads the “if statement” the set register will not be implemented and the rest of
the preceding statements of the code will not displayed.

The problem can simply be fixed by replacing the != by !==.


The Output in the transcript gives # R = c0

After 8 transitions, the machine is stuck in state 3’b010. Why?


Answer:
Since state 3’b010 is displayed repeatedly, the case statement will continue to display the last
state if it doesn’t find any matching state as the previous. The 8th transition in the program is
terminated due to the if (i == 8) $finish block.
The case statement acts like the ‘===’ operator since case does not ignore don’t cares, but reads and
outputs them instead.
What is the transition sequence? Why?
Answer:
In casez, during simulation, an inadvertent x signal in casez, will not be matched by a 0 or 1 in
the case choice.
For the first to the sixth transitions, operation goes from top to bottom, i.e. 001,100, 000, 010,
x00, 0zz. In the 7th transition, state 3’b0zz matches state 3’b001 thus generating the next new state
3’b100. In here, 3’bxxx was ignored because, as aforementioned, casez ignores an x signal and does not
take it as a don’t care. Then 3’b100 is compared and 8th state 3’b000 is displayed. The program is
thereafter terminated due to the if (i == 8) $finish block.

casex statemement
What is the transition sequence? Why?
Answer:
In casex, the choices may contain z, x, or ? which are used as don’t cares for comparison. Casex
uses x as a don’t care which can be used to minimize logic.
The transition sequence is 001, 001, 001, … In the comparison process during simulation, state
3’bxxx outputs the new state 3’b001 in the first transition. To find the next new state (second transition)
3’b001 is then compared starting from the top case condition and satisfies 3’bxxx, generating 3’b001.
This repeats until the 8th transition is reached and the program is terminated due to the if (i == 8)
$finish block.
Lab 2.3

An always statement isn’t valid in an initial statement since it signifies a free-running process and it
is a concurrent statement that is continuously executed during simulation. An initial statement indicates
a process executed exactly once making the two statements unsuitable and cannot be placed in a single
Verilog code.
Walking Code generation

Modelsim simulation
ModelSim Simulation
Modelsim Simulation
Lab 2.4

In this lab, you will:


• Learn to recognize common syntax errors in functions and tasks
• Learn how to use functions and tasks
• Learn how arguments are passed to functions and tasks
syntax.v with correction

Modelsim Simulation
Lab 3.1

In this lab, you will:


• Learn how to use a waveform viewer
• Learn to use the # statement
• Learn how to use the @ statement
• Learn the difference between various sampling techniques
• Identify problems caused by event ordering and simulation startup
Simulating the model to verify that the correct waveform is generated,
Why is the message sequence different?
Answer:
The statement only monitors the positive change (or rising edge) of the waveform.

Why is the message sequence different?


Answer:
The statement only monitors the negative change (falling edge) of the waveform.
Why is the message sequence different?
Answer:
The message sequence is actually similar to the first simulation, always@(R).
Why are they different? Explain the differences.
Answer:
They are different because delay is introduced to register R. These delays are also
placed in different orientations, resulting different results.
Lab 3.2

In this lab, you will:


• Learn how to single-step through a model execution
• Witness the sequential execution of parallel blocks
• Examine the sequence of event-driven simulation
Simuling model.v in Modelsim yields,
Lab 4

vave.v

ModelSim result:
Sample.v

ModelSim result:

Answer:
The above waveform differs because of the delays that are placed in a different syntax
of “wave.v” in lab 3.1
Lab 4.2

bug.v

ModelSim Result:
*no errors were encountered.
bus.v

ModelSim Result:
Modified Verilog Module:

bus.v

ModelSim Result:
*When wire [3:0] BUS; is replaced with wor [3:0] BUS:

ModelSim result:

*When wire [3:0] BUS; is replaced with wand[3:0] BUS:

ModelSim Result:
DELAYS WERE ADDED:

#(3) were added:

ModelSim result:

#(2,4) were added:

ModelSim result:
#(2,4,6) were added:

ModelSim result:
sample.v
ModelSim result:
Lab 5.1

adder.v

noop.v
sub.v

Instantiation
Simulation

The method of instantiation used is by position, it is done by placing the ports in exactly the
same positions in the port lists of both the template and the instance.

rules.v
It is observed that wire W can be readily connected to either input, output and inout of the
lower-level module. R, on the other hand, can only be connected to the input of the lower level module
and not to the output and inout.
In connecting R to the output or inout of the lower-level module, one way not to cause any
syntax errors is to pass the value of R to W through an assign statement. In this way R is connected
to the lower-level module ports through W.
design.v
Original Output:
Modified design.v

Simulation shows a similar waveform, hence, the correctness is still verified.


Lab 5.2

inverter.v

testinv.v
Question:
In compiling and simulating the 2 modules together, why is the order suddenly significant?
The order of the modules is significant when both are compiled and simulated
simultaneously because of timescale declarations on modules. The first module entered must
contain the timescale declaration if it is the top module of the succeeding instantiated modules.
Otherwise, if the top module doesn’t declare one, even if lower modules contain timescales
themselves, the simulation always fails.

Table for various timescales on the tester and inverter modules:


Modified testinv.v

Running the simulation with the timescale pairs below, the first timescale shows the same
reported delays as before while the second shows a different one. Instead of 3.6 µs-2.2 µs rise-fall,
the result for the second timescale pair shows 3.6ns-2.2ns.
Tester - 1ns/1ns - 1ps/1ps
Inverter - 1ns/100p - 1ns/100ps
Modifying again by replacing the calls to the $realtime task by calls to the $time task:

Running the simulation with the timescale pairs below, the first timescale shows the same
reported delays as before while the second still shows a different one. Instead of 3.6 ns-2.2 ns rise-
fall, the result for the second timescale pair shows 4ns-2ns. This is because $time tasks only return
integer values and not real ones.
Tester - 1ns/1ns - 1ns/1ns
Inverter - 1ns/1ns - 1ns/100ps
Lab 5.3
inverter.v

testinv.v

Simulation
Using parameter to declare rise and fall delay:

It was verified that they have the same output.

Modifying the tester module to override the rise and fall delays, using the positional notation:

INVERTER #(4.5, 1.6) DUT(...);

With this modification, the delays of the inverter are now changed to 4.5-1.6 ns from 3.6-2.2 ns.

Question:
Is it possible to override only the fall delay parameter if it is declared second? It is possible to override
only the fall delay parameter by using only one delay in the overriding inverter and declaring the fall
delay parameter first in the inverter module. Hence, rule of thumb is simple: the first delay parameter
to be declared in the inverter module will be the delay that’s subject for overriding.
Answer:
Modifying the parameter override from positional to using a defparam statement (using the proper
names for the parameters):
defpram DUT.RISE = 4.5,
DUT.FALL = 1.6;

The result shows the same overriding values. And changing the order in which parameters are
declared doesn’t show significant changes in the delays.

Question:
Can you specify an override value for rise-delay parameter only? For the fall-delay parameter only?
How? Verify your hypothesis.
Answer:
Yes, we can override value for the rise-delay parameter only as well as for the fall-delay parameter only.
As stated before, we use the positional notation of overriding in the tester module. Using positional
notation, and a single value in its delay, the overridden delay parameter will depend on which
parameter was declared first in the inverter module. Simply declare parameter for rise-delay first if you
want it overridden. You do the same thing for the fall-delay parameter if you want fall-delay overridden.

This order overrides the rise-delay:

This order overrides the fall-delay:

In the tester module, add 3 parameters defined, to 0.8, 1.0, 1.2 to represent scaling factors for best,
typical, and worst-case operating conditions, respectively.

The simulation looks like this:

Hence, the correctness is still verified.


Lab 5.4

testnot.v

Simulation
# Fall delay = 2.200 ns
# Rise delay = 3.600 ns

Like before, the simulation shows the same delay values.


Modifying the timescale to 100ps/10ps gives different delay values:
# Fall delay = 0.220 ns
# Rise delay = 0.360 ns

Question:
How does that compare to using an inverter module rather than an inverter primitive?
Answer:
Using an inverter primitive inside the tester module makes the inverter totally dependent to the
tester at the level of timescale. On the other hand, using a separate inverter module sets the inverters
timescale independent to that of the tester. Hence, even if the tester module timescale is modified as
long as the inverter timescale is retained, the simulation will show no significant change in delay values

Behavioral Description

rfilebeh.v

Simulation
Gate Level Description

rfileprm.v

Simulation
testdsgn.v

It was observed that the gate-level model was the easiest model to debug than the behavioural model.
Both descriptions were simulated separately. Supposedly, both simulations must have a different
CPU time required for simulation. The behavioral description is expected to have the fastest simulation
time over the gate-level description using primitives. But eventually, no noticeable performance
difference was observed. The difference might be rather easily viewed depending on the user’s level of
knowledge about the software – there might be a certain step to do it which was not specified in this
exercise.
Question:
1. Which model was quickest to write/modify?
Answer:
The behavioral model was quickest to modify between the 2 descriptions because it only has
short codes.
2. Which model simulated the fastest?
Answer”
The Behavioral model is expected to be the fastest.

sample.v
Simulation

S1: The machine scans for a sample every 10 ns during a transition. It reads a sample but waits
for 10 ns before catching it.

S2: The machine scans for a sample every 10 ns during a transition. It catches the current state
of the input after 10ns.

S3: The machine delays every input transitions every 10 ns.

S4: The machine scans for a sample every 10 ns and catches it right then and there.

S5: Similar to S4, but uses primitive buffer to sample the input.
Lab 6.1

monitor.v
Simulation:

$monitor used to emulate the displaying function


Simulation

Explain the differences in the reported changes.


Answer:
We can see an obvious difference between the 2 “monitoring” functions based on their simulations.
Although both are the same in that both displays once every time R changes its value, they do not have
the same level of sensitivity. The first one using a $display function inside an always block displays every
time there is a single change in R value even the change occurs in the absence of delay. The one using
$monitor inside the initial block displays only one value change per time delay and it is usually the last
one. Replacing the $display statement with a $strobe statement made the function the same with the
$monitor statement in the initial block.

dumprom.v

rom.v
rom.dat

modified rom.v to set values for rom.dat

Simulation
dump2rom.v

Simulation
Why is the content of both ROMs identical?
Answer:
The ROMs in dump2rom.v are identical because both instantiates the same ROM module, rom.v which
also contains only 1 file rom.dat that holds the ROM values.

Override the ROM initialization file parameter of each ROM instance with different filenames.
Create these new files, then simulate again. Verify that each ROM has the proper content.
rom1.v

rom2.dat

Simulation:
Lab 6.2

forever.v
Run your test procedure against each arbiter individually using the commands:

using arbiter1.v as the Design Under Test (DUT):

using arbiter2.v as the Design Under Test (DUT):

using arbiter3.v as the Design Under Test (DUT):


Which arbiter works?
What is wrong with the arbiters that do not work?
Answer:
The first arbiter is the only arbiter that worked among the three. The second arbiter tested didn’t pass
the requirement that the grant assertion must particularly fall within 100ns. The last arbiter tested also
failed because it didn’t follow the requirement that grant desertion must particularly fall within 10ns.
Their waveforms are shown below.

Arbiter 1

Arbiter 2

Arbiter 3

Note: Register a monitors the correctness of the grant assertion, while register b monitors the
correctness of the grant
desertion.

S-ar putea să vă placă și