https://wiki.dcae.pub.ro/api.php?action=feedcontributions&user=Zhascsi&feedformat=atomWikiLabs - Contribuții utilizator [ro]2024-03-29T15:29:28ZContribuții utilizatorMediaWiki 1.31.1https://wiki.dcae.pub.ro/index.php?title=Digital_Integrated_Circuits_(lab)&diff=7583Digital Integrated Circuits (lab)2024-02-25T16:40:42Z<p>Zhascsi: </p>
<hr />
<div># [[Applications 1 | Laboratory 1]]<br />
# [[Applications 2 | Laboratory 2]]<br />
# [[Applications 3 | Laboratory 3]]<br />
# [[Applications 4 | Laboratory 4]]<br />
# [[Applications 5 | Laboratory 5]]<br />
# Test 1<br />
<br />
== Verilog Tutorials ==<br />
* [http://www.asic-world.com/verilog/veritut.html Verilog Tutorial] from ASIC World<br />
* [http://chipverify.com/verilog/verilog-tutorial Verilog Tutorial] from Chip Verify<br />
* [http://www.emmelmann.org/Library/Tutorials/docs/verilog_ref_guide/vlog_ref_top.html Verilog reference guide]<br />
<br />
== Software ==<br />
* [https://www.xilinx.com/products/design-tools/vivado/vivado-ml.html Vivado™ ML Standard Edition free]<br />
* [https://wiki.dcae.pub.ro/images/2/24/VivadoNewProjectTutorial.pdf Vivado New Project Tutorial]<br />
<br />
== Hardware ==<br />
[https://www.realdigital.org/hardware/boolean Boolean Board] from RealDigital<br />
* [https://www.realdigital.org/doc/02013cd17602c8af749f00561f88ae21 Boolean Board - user manual]<br />
* [[Boolean Board - Pinout]]<br />
<br />
<!--<br />
* [https://dpoauwgwqsy2x.cloudfront.net/Download/pynqz2_user_manual_v1_0.pdf Pynq-Z2 - user manual]<br />
* [[Pynq-Z2 - Pinout]]<br />
--></div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_4&diff=7520Applications 42023-03-27T11:09:07Z<p>Zhascsi: /* top design module */</p>
<hr />
<div>== <span id="transcoder">Exercise 1</span> ==<br />
<br />
=== transcoder ===<br />
<br />
Design a '''transcoder''' circuit, that converts a 4-bit integer from the range 0 ... 9 to a 7-bit combination that shows the integer's value on a 7-segment display. The input of the module should be named '''value''', and the output '''seg'''.<br />
<br />
[[Fișier: segment.png]]<br />
<br />
The output bits would control the segments of a digit display, one bit for each segment. The segment is lit when the corresponding bit is '''0''', otherwise it is off (negative logic).<br />
<br />
[[Fișier: digits.png]]<br />
<br />
For all numbers greater than 9 the digit must be off. All these 6 cases may be covered in a single assignment under the '''default''' case.<br />
<br />
Because '''seg''' values are easier to handle in binary, the assigned values for '''seg''' should be given as binary constants. A number in binary format (or a combination of bit values) must be preceded by the base specificator, <syntaxhighlight lang="Verilog" inline>'b</syntaxhighlight>, according to the template ''numberOfBits''''''b'''''value'' as in the following examples:<br />
<br />
{| class="wikitable" style="text-align: center;<br />
| <syntaxhighlight lang="Verilog" inline>8'b11</syntaxhighlight> || 3, in binary format on 8 bits<br />
|-<br />
| <syntaxhighlight lang="Verilog" inline>8'b00000011</syntaxhighlight> || 3, in binary format on 8 bits. Leading zeros are explicitly written<br />
|-<br />
| <syntaxhighlight lang="Verilog" inline>8'b0000_0011</syntaxhighlight> || when there are many bits, the underline, '''_''', may be used to split bits into smaller groups that are easier to read<br />
|}<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module transcoder(<br />
input [3:0] value,<br />
output reg [6:0] seg<br />
);<br />
<br />
always @(*) begin<br />
case (value)<br />
4'd0: seg = 7'b1000000;<br />
4'd1: seg = 7'b1111001;<br />
4'd2: seg = 7'b0100100;<br />
// other 7 cases (for value = 3, 4, ... , 9<br />
default: seg = 7'b1111111; // all segments are off<br />
endcase <br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
'''Coding style:'''<br />
* '''case''' statements should always include the '''default''' case.<br />
<br />
Open the ''transcoder'' VPL activity on Moodle, upload the source file of the transcoder, run the test and check the results. In case of errors fix the design and retry. After you get TEST PASS on Moodle, proceed to implementation.<br />
<br />
=== top design module ===<br />
<br />
The transcoder is wrapped in a top module that takes care also of the digits control.<br />
A digit is active (the segments are displayed) if its common anode (the anode common to all segments of the digit) is connected to the power supply through a controlled switch. The digit is enabled if the corresponding control bit is 0.<br />
There are 4 digits in a display bloc, each with its control signal. These digits share the segment 7-bit control signal. To display different values on those digits, the digit segment combinations should be multiplexed in time.<br />
For this exercise only the rigthmost digit is active.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module top(<br />
input [3:0] num,<br />
output [6:0] seg,<br />
output [7:0] anode <br />
);<br />
<br />
transcoder transcoder(<br />
.value (num),<br />
.seg (seg)<br />
);<br />
<br />
assign anode = 8'b11111110; // activate the rightmost digit<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
=== implementation ===<br />
<br />
Test the transcoder by connecting its 4 bit input to SW3, SW2, SW1, SW0, and displaying the output on the rightmost digit of a 7-segment display.<br />
<br />
<br />
=== hexadecimal digit ===<br />
<br />
The transcoder may be extended to show hexadecimal digits greater than 9. Use the most common 7-segment symbols for them:<br />
<br />
[[Fișier: letters.png]]<br />
<br />
<br />
<br />
== Exercise 2 ==<br />
<br />
Implement a 3 bit adder whose result is displayed as a hexadecimal digit.<br />
<br />
[[Fișier: app4_adder.png]]<br />
<br />
The result of the 3 bit addition is an integer in the range [0 ... 14], and it may be written in the hexadecimal base using only one digit.<br />
The transcoder must be extended to show all hexadecimal digits, including those greater than 9.<br />
<br />
# change the transcoder description such that to display all hexadecimal digits<br />
# the top-level module instantiates the adder and the transcoder, and generates the 8-bit combination that controls all 8 digits<br />
# assign switches SW15, SW14 and SW13 for the input '''a''', SW2, SW1, SW0 for the input '''b'''.<br />
<br />
<br />
== Exercise 3 ==<br />
Implement a 3 x 3 bits multiplier, with the result shown in decimal base as a 2 digits number.<br />
<br />
[[Fișier: app4_multiplier.png]]<br />
<br />
This project comprises a top module with 4 blocks. The first block, ''multiplier'', takes in two 3 bit numbers, ''a'' and ''b'', and delivers the result of their multiplication in binary format. The input operands and the result are treated as unsigned integers (natural numbers).<br />
The next block, ''BCD converter'', converts the result from the binary format to the decimal. The decimal digits are coded in binary, therefore a multidigit number is coded<br />
in the so called BCD format (Binary-coded decimal), where each decimal digit is represented as a 4 bit number.<br />
<br />
[[Fișier: app4_bcd.png]]<br />
<br />
<!--<br />
# create a new project in a new folder<br />
# create a new sorce file for the top module, which is described structurally<br />
# create a new source file for the multiplier. The multiplier is described behaviorally using a continuous assignment.<br />
# copy from the folder of Exercise 1 or Exercice 2 the source file of the transcoder module into the folder of this project. Add the file to the project.<br />
# create a new source file for the BCD converter. Use a behavioral description with integer division operators ('''/''' and '''%'''). The quotient will be the first digit value (the digit of tens), the remainder will be the last digit (the digit of units).<br />
# assign switches SW[9], SW[8] and SW[7] for the input a, SW[2], SW[1] and SW[0] for the input b, Digit0 pins for seg0, and Digit1 pins for seg1<br />
# implement and check that the result of multiplying two 3 bit numbers is correctly displayed on two digits in decimal format. If the result is smaller than ten, the first digit will show a leading 0)<br />
--><br />
<br />
<br />
== Exercise 4 ==<br />
=== Caesar cipher ===<br />
<br />
The Caesar cipher is the simplest substitution cipher. A plain text message is encrypted by replacing each letter from the message by another one that is some fixed number of positions down the alphabet. All letters of the alphabet are changed using the same fixed number of positions. The letters are “shifted” down the alphabet, this code being also named shift cipher.<br />
In this exercise and the following ones, we assume that the plain and encoded messages contain only ASCII uppercase letters A to Z, without blank spaces between words. The encryption is done such that A-Z set of letters are translated to letters from the same set A-Z. For example, if the shift is of 3 positions down the alphabet, '''A''' translates to '''D''', '''B''' to '''E''', '''C''' to '''F''', a.s.o. To achieve the circularity of the encoding, '''W''' translates to '''Z''', '''X''' to '''A''', '''Y''' to '''B''' and '''Z''' to '''C'''.<br />
<br />
[[Fișier: Dic_lab4_cipher_shift.png]]<br />
<br />
=== ASCII code ===<br />
The ASCII code is the widest used character encoding standard in digital technology. Originally limited to 7 bits it usually uses 8 bits to code for the Latin alphabet letters, uppercase and lowercase, digits, punctuation marks, some special symbols, and some commands. We need to know the ASCII codes for the uppercase letters of the alphabet:<br />
<br />
{| class="wikitable" style="text-align: center;<br />
| Letter || A||B||C||D||E||F||G||H||I||J||K||L||M||N||O||P||Q||R||S||T||U||V||W||X||Y||Z<br />
|-<br />
| hex code|| 41||42||43||44||45||46||47||48||49||4a||4b||4c||4d||4e||4f||50||51||52||53||54||55||56||57||58||59||5a<br />
|}<br />
<br />
=== Caesar encoder ===<br />
Your goal is to design a configurable Caesar encoder, where the shift is set from the outside. The circuit receives an ASCII letter on data_in input, shifts it by a number of positions given by the key input and outputs the resulting letter as data_out. It is supposed that the input data are restricted to the A-Z ASCII codes and the shift is an unsigned integer no greater than 26 (the length of the alphabet) <br />
<br />
[[Fișier: Dic_lab4_caesar.png]]<br />
<br />
The implementation adds the shift number to the ASCII code of the input letter and corrects the sum such that the output ASCII code is also in the A-Z range of ASCII codes.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
assign data_out = data_in + shift > 8'd90 ?<br />
data_in + shift - 8'd26 :<br />
data_in + shift;<br />
</syntaxhighlight><br />
<br />
=== Caesar decoding ===<br />
The Caesar encrypted message is easy to decode: we need only to shift back all letters to undo the coding. Of course the decoder needs to know the shift number (by the way, the Caesar code may be easily broken by trying for the encrypted message various shifts until a meaningful message is found).<br />
To reverse the coding of our Caesar encoder, the decoder uses shift_decode = 26 - shift_code<br />
<br />
[[Fișier: Dic_lab4_caesar_tb.png]]<br />
<br />
=== Testbench ===<br />
The testbench instantiates two Caesar encoder modules. The first one is the encoder itself, that generates the encoded message. The second instance uses the reversed shift to decode the encrypted message. The shift value (for example 13) may be assigned directly to the shift port of the instance as a literal constant:<br />
<syntaxhighlight lang="Verilog"><br />
caesar encoder (<br />
.shift (8'd13),<br />
// other port connections<br />
);<br />
</syntaxhighlight><br />
<br />
The constant value assigned to an input port is actually a hardwired connection of its bits to the power supply and to the ground.<br />
<br />
The testbench generates a sequence of ASCII values for the data_sent input of the encoder. The verilog language allows you to assign to an 8-bit logic variable an ASCII value as a character:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
#0 data_sent = "C";<br />
#1 data_sent = "O";<br />
#1 data_sent = "M";<br />
#1 data_sent = "B";<br />
#1 data_sent = "I";<br />
#1 data_sent = "N";<br />
#1 data_sent = "A";<br />
#1 data_sent = "T";<br />
#1 data_sent = "I";<br />
#1 data_sent = "O";<br />
#1 data_sent = "N";<br />
#1 data_sent = "A";<br />
#1 data_sent = "L";<br />
#1 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
To display the ASCII values on the waveforms in simulation, right-click the name of the variable in the Simulation panel and select from the pop-up menu '''radix''' -> '''ASCII'''</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Digital_Integrated_Circuits_(lab)&diff=7519Digital Integrated Circuits (lab)2023-03-26T11:26:18Z<p>Zhascsi: </p>
<hr />
<div># [[Applications 1 | Laboratory 1]]<br />
# [[Applications 2 | Laboratory 2]]<br />
# [[Applications 3 | Laboratory 3]]<br />
# [[Applications 4 | Laboratory 4]]<br />
# [[Applications 5 | Laboratory 5]]<br />
# Test 1<br />
<br />
== Verilog Tutorials ==<br />
* [http://www.asic-world.com/verilog/veritut.html Verilog Tutorial] from ASIC World<br />
* [http://chipverify.com/verilog/verilog-tutorial Verilog Tutorial] from Chip Verify<br />
* [http://www.emmelmann.org/Library/Tutorials/docs/verilog_ref_guide/vlog_ref_top.html Verilog reference guide]<br />
<br />
== Software ==<br />
* [https://www.xilinx.com/products/design-tools/vivado/vivado-ml.html Vivado™ ML Standard Edition free]<br />
* [https://wiki.dcae.pub.ro/images/2/24/VivadoNewProjectTutorial.pdf Vivado New Project Tutorial]<br />
<br />
== Hardware ==<br />
* [https://www.realdigital.org/doc/02013cd17602c8af749f00561f88ae21 Boolean Board - user manual]<br />
* [[Boolean Board - Pinout]]<br />
<br />
<br />
* [https://dpoauwgwqsy2x.cloudfront.net/Download/pynqz2_user_manual_v1_0.pdf Pynq-Z2 - user manual]<br />
* [[Pynq-Z2 - Pinout]]</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Digital_Integrated_Circuits_(lab)&diff=7518Digital Integrated Circuits (lab)2023-03-21T23:45:20Z<p>Zhascsi: /* Hardware */</p>
<hr />
<div># [[Applications 1 | Laboratory 1]]<br />
# [[Applications 2 | Laboratory 2]]<br />
# [[Applications 3 | Laboratory 3]]<br />
# [[Applications 4 | Laboratory 4]]<br />
<br />
== Verilog Tutorials ==<br />
* [http://www.asic-world.com/verilog/veritut.html Verilog Tutorial] from ASIC World<br />
* [http://chipverify.com/verilog/verilog-tutorial Verilog Tutorial] from Chip Verify<br />
* [http://www.emmelmann.org/Library/Tutorials/docs/verilog_ref_guide/vlog_ref_top.html Verilog reference guide]<br />
<br />
== Software ==<br />
* [https://www.xilinx.com/products/design-tools/vivado/vivado-ml.html Vivado™ ML Standard Edition free]<br />
* [https://wiki.dcae.pub.ro/images/2/24/VivadoNewProjectTutorial.pdf Vivado New Project Tutorial]<br />
<br />
== Hardware ==<br />
* [https://www.realdigital.org/doc/02013cd17602c8af749f00561f88ae21 Boolean Board - user manual]<br />
* [[Boolean Board - Pinout]]<br />
<br />
<br />
* [https://dpoauwgwqsy2x.cloudfront.net/Download/pynqz2_user_manual_v1_0.pdf Pynq-Z2 - user manual]<br />
* [[Pynq-Z2 - Pinout]]</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Digital_Integrated_Circuits_(lab)&diff=7517Digital Integrated Circuits (lab)2023-03-21T23:44:26Z<p>Zhascsi: </p>
<hr />
<div># [[Applications 1 | Laboratory 1]]<br />
# [[Applications 2 | Laboratory 2]]<br />
# [[Applications 3 | Laboratory 3]]<br />
# [[Applications 4 | Laboratory 4]]<br />
<br />
== Verilog Tutorials ==<br />
* [http://www.asic-world.com/verilog/veritut.html Verilog Tutorial] from ASIC World<br />
* [http://chipverify.com/verilog/verilog-tutorial Verilog Tutorial] from Chip Verify<br />
* [http://www.emmelmann.org/Library/Tutorials/docs/verilog_ref_guide/vlog_ref_top.html Verilog reference guide]<br />
<br />
== Software ==<br />
* [https://www.xilinx.com/products/design-tools/vivado/vivado-ml.html Vivado™ ML Standard Edition free]<br />
* [https://wiki.dcae.pub.ro/images/2/24/VivadoNewProjectTutorial.pdf Vivado New Project Tutorial]<br />
<br />
== Hardware ==<br />
* [https://dpoauwgwqsy2x.cloudfront.net/Download/pynqz2_user_manual_v1_0.pdf Pynq-Z2 - user manual]<br />
* [[Pynq-Z2 - Pinout]].<br />
<br />
* [https://www.realdigital.org/doc/02013cd17602c8af749f00561f88ae21 Boolean Board - user manual]<br />
* [[Boolean Board - Pinout]].</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_4&diff=7516Applications 42023-03-21T23:43:56Z<p>Zhascsi: </p>
<hr />
<div>== <span id="transcoder">Exercise 1</span> ==<br />
<br />
=== transcoder ===<br />
<br />
Design a '''transcoder''' circuit, that converts a 4-bit integer from the range 0 ... 9 to a 7-bit combination that shows the integer's value on a 7-segment display. The input of the module should be named '''value''', and the output '''seg'''.<br />
<br />
[[Fișier: segment.png]]<br />
<br />
The output bits would control the segments of a digit display, one bit for each segment. The segment is lit when the corresponding bit is '''0''', otherwise it is off (negative logic).<br />
<br />
[[Fișier: digits.png]]<br />
<br />
For all numbers greater than 9 the digit must be off. All these 6 cases may be covered in a single assignment under the '''default''' case.<br />
<br />
Because '''seg''' values are easier to handle in binary, the assigned values for '''seg''' should be given as binary constants. A number in binary format (or a combination of bit values) must be preceded by the base specificator, <syntaxhighlight lang="Verilog" inline>'b</syntaxhighlight>, according to the template ''numberOfBits''''''b'''''value'' as in the following examples:<br />
<br />
{| class="wikitable" style="text-align: center;<br />
| <syntaxhighlight lang="Verilog" inline>8'b11</syntaxhighlight> || 3, in binary format on 8 bits<br />
|-<br />
| <syntaxhighlight lang="Verilog" inline>8'b00000011</syntaxhighlight> || 3, in binary format on 8 bits. Leading zeros are explicitly written<br />
|-<br />
| <syntaxhighlight lang="Verilog" inline>8'b0000_0011</syntaxhighlight> || when there are many bits, the underline, '''_''', may be used to split bits into smaller groups that are easier to read<br />
|}<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module transcoder(<br />
input [3:0] value,<br />
output reg [6:0] seg<br />
);<br />
<br />
always @(*) begin<br />
case (value)<br />
4'd0: seg = 7'b1000000;<br />
4'd1: seg = 7'b1111001;<br />
4'd2: seg = 7'b0100100;<br />
// other 7 cases (for value = 3, 4, ... , 9<br />
default: seg = 7'b1111111; // all segments are off<br />
endcase <br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
'''Coding style:'''<br />
* '''case''' statements should always include the '''default''' case.<br />
<br />
Open the ''transcoder'' VPL activity on Moodle, upload the source file of the transcoder, run the test and check the results. In case of errors fix the design and retry. After you get TEST PASS on Moodle, proceed to implementation.<br />
<br />
=== top design module ===<br />
<br />
The transcoder is wrapped in a top module that takes care also of the digits control.<br />
A digit is active (the segments are displayed) if its common anode (the anode common to all segments of the digit) is connected to the power supply through a controlled switch. The digit is enabled if the corresponding control bit is 0.<br />
There are 4 digits in a display bloc, each with its control signal. These digits share the segment 7-bit control signal. To display different values on those digits, the digit segment combinations should be multiplexed in time.<br />
For this exercise only the rigthmost digit is active.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module top(<br />
input [3:0] num,<br />
output [6:0] seg,<br />
output [7:0] anode <br />
);<br />
<br />
transcoder transcoder(<br />
.value (num)<br />
.seg (seg)<br />
);<br />
<br />
assign anode = 8'b11111110; // activate the rightmost digit<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
<br />
=== implementation ===<br />
<br />
Test the transcoder by connecting its 4 bit input to SW3, SW2, SW1, SW0, and displaying the output on the rightmost digit of a 7-segment display.<br />
<br />
<br />
=== hexadecimal digit ===<br />
<br />
The transcoder may be extended to show hexadecimal digits greater than 9. Use the most common 7-segment symbols for them:<br />
<br />
[[Fișier: letters.png]]<br />
<br />
<br />
<br />
== Exercise 2 ==<br />
<br />
Implement a 3 bit adder whose result is displayed as a hexadecimal digit.<br />
<br />
[[Fișier: app4_adder.png]]<br />
<br />
The result of the 3 bit addition is an integer in the range [0 ... 14], and it may be written in the hexadecimal base using only one digit.<br />
The transcoder must be extended to show all hexadecimal digits, including those greater than 9.<br />
<br />
# change the transcoder description such that to display all hexadecimal digits<br />
# the top-level module instantiates the adder and the transcoder, and generates the 8-bit combination that controls all 8 digits<br />
# assign switches SW15, SW14 and SW13 for the input '''a''', SW2, SW1, SW0 for the input '''b'''.<br />
<br />
<br />
== Exercise 3 ==<br />
Implement a 3 x 3 bits multiplier, with the result shown in decimal base as a 2 digits number.<br />
<br />
[[Fișier: app4_multiplier.png]]<br />
<br />
This project comprises a top module with 4 blocks. The first block, ''multiplier'', takes in two 3 bit numbers, ''a'' and ''b'', and delivers the result of their multiplication in binary format. The input operands and the result are treated as unsigned integers (natural numbers).<br />
The next block, ''BCD converter'', converts the result from the binary format to the decimal. The decimal digits are coded in binary, therefore a multidigit number is coded<br />
in the so called BCD format (Binary-coded decimal), where each decimal digit is represented as a 4 bit number.<br />
<br />
[[Fișier: app4_bcd.png]]<br />
<br />
<!--<br />
# create a new project in a new folder<br />
# create a new sorce file for the top module, which is described structurally<br />
# create a new source file for the multiplier. The multiplier is described behaviorally using a continuous assignment.<br />
# copy from the folder of Exercise 1 or Exercice 2 the source file of the transcoder module into the folder of this project. Add the file to the project.<br />
# create a new source file for the BCD converter. Use a behavioral description with integer division operators ('''/''' and '''%'''). The quotient will be the first digit value (the digit of tens), the remainder will be the last digit (the digit of units).<br />
# assign switches SW[9], SW[8] and SW[7] for the input a, SW[2], SW[1] and SW[0] for the input b, Digit0 pins for seg0, and Digit1 pins for seg1<br />
# implement and check that the result of multiplying two 3 bit numbers is correctly displayed on two digits in decimal format. If the result is smaller than ten, the first digit will show a leading 0)<br />
--><br />
<br />
<br />
== Exercise 4 ==<br />
=== Caesar cipher ===<br />
<br />
The Caesar cipher is the simplest substitution cipher. A plain text message is encrypted by replacing each letter from the message by another one that is some fixed number of positions down the alphabet. All letters of the alphabet are changed using the same fixed number of positions. The letters are “shifted” down the alphabet, this code being also named shift cipher.<br />
In this exercise and the following ones, we assume that the plain and encoded messages contain only ASCII uppercase letters A to Z, without blank spaces between words. The encryption is done such that A-Z set of letters are translated to letters from the same set A-Z. For example, if the shift is of 3 positions down the alphabet, '''A''' translates to '''D''', '''B''' to '''E''', '''C''' to '''F''', a.s.o. To achieve the circularity of the encoding, '''W''' translates to '''Z''', '''X''' to '''A''', '''Y''' to '''B''' and '''Z''' to '''C'''.<br />
<br />
[[Fișier: Dic_lab4_cipher_shift.png]]<br />
<br />
=== ASCII code ===<br />
The ASCII code is the widest used character encoding standard in digital technology. Originally limited to 7 bits it usually uses 8 bits to code for the Latin alphabet letters, uppercase and lowercase, digits, punctuation marks, some special symbols, and some commands. We need to know the ASCII codes for the uppercase letters of the alphabet:<br />
<br />
{| class="wikitable" style="text-align: center;<br />
| Letter || A||B||C||D||E||F||G||H||I||J||K||L||M||N||O||P||Q||R||S||T||U||V||W||X||Y||Z<br />
|-<br />
| hex code|| 41||42||43||44||45||46||47||48||49||4a||4b||4c||4d||4e||4f||50||51||52||53||54||55||56||57||58||59||5a<br />
|}<br />
<br />
=== Caesar encoder ===<br />
Your goal is to design a configurable Caesar encoder, where the shift is set from the outside. The circuit receives an ASCII letter on data_in input, shifts it by a number of positions given by the key input and outputs the resulting letter as data_out. It is supposed that the input data are restricted to the A-Z ASCII codes and the shift is an unsigned integer no greater than 26 (the length of the alphabet) <br />
<br />
[[Fișier: Dic_lab4_caesar.png]]<br />
<br />
The implementation adds the shift number to the ASCII code of the input letter and corrects the sum such that the output ASCII code is also in the A-Z range of ASCII codes.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
assign data_out = data_in + shift > 8'd90 ?<br />
data_in + shift - 8'd26 :<br />
data_in + shift;<br />
</syntaxhighlight><br />
<br />
=== Caesar decoding ===<br />
The Caesar encrypted message is easy to decode: we need only to shift back all letters to undo the coding. Of course the decoder needs to know the shift number (by the way, the Caesar code may be easily broken by trying for the encrypted message various shifts until a meaningful message is found).<br />
To reverse the coding of our Caesar encoder, the decoder uses shift_decode = 26 - shift_code<br />
<br />
[[Fișier: Dic_lab4_caesar_tb.png]]<br />
<br />
=== Testbench ===<br />
The testbench instantiates two Caesar encoder modules. The first one is the encoder itself, that generates the encoded message. The second instance uses the reversed shift to decode the encrypted message. The shift value (for example 13) may be assigned directly to the shift port of the instance as a literal constant:<br />
<syntaxhighlight lang="Verilog"><br />
caesar encoder (<br />
.shift (8'd13),<br />
// other port connections<br />
);<br />
</syntaxhighlight><br />
<br />
The constant value assigned to an input port is actually a hardwired connection of its bits to the power supply and to the ground.<br />
<br />
The testbench generates a sequence of ASCII values for the data_sent input of the encoder. The verilog language allows you to assign to an 8-bit logic variable an ASCII value as a character:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
#0 data_sent = "C";<br />
#1 data_sent = "O";<br />
#1 data_sent = "M";<br />
#1 data_sent = "B";<br />
#1 data_sent = "I";<br />
#1 data_sent = "N";<br />
#1 data_sent = "A";<br />
#1 data_sent = "T";<br />
#1 data_sent = "I";<br />
#1 data_sent = "O";<br />
#1 data_sent = "N";<br />
#1 data_sent = "A";<br />
#1 data_sent = "L";<br />
#1 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
To display the ASCII values on the waveforms in simulation, right-click the name of the variable in the Simulation panel and select from the pop-up menu '''radix''' -> '''ASCII'''</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_4&diff=7514Applications 42023-03-20T09:28:02Z<p>Zhascsi: </p>
<hr />
<div>== Exercise 1 ==<br />
=== Caesar cipher ===<br />
<br />
The Caesar cipher is the simplest substitution cipher. A plain text message is encrypted by replacing each letter from the message by another one that is some fixed number of positions down the alphabet. All letters of the alphabet are changed using the same fixed number of positions. The letters are “shifted” down the alphabet, this code being also named shift cipher.<br />
In this exercise and the following ones, we assume that the plain and encoded messages contain only ASCII uppercase letters A to Z, without blank spaces between words. The encryption is done such that A-Z set of letters are translated to letters from the same set A-Z. For example, if the shift is of 3 positions down the alphabet, '''A''' translates to '''D''', '''B''' to '''E''', '''C''' to '''F''', a.s.o. To achieve the circularity of the encoding, '''W''' translates to '''Z''', '''X''' to '''A''', '''Y''' to '''B''' and '''Z''' to '''C'''.<br />
<br />
[[Fișier: Dic_lab4_cipher_shift.png]]<br />
<br />
=== ASCII code ===<br />
The ASCII code is the widest used character encoding standard in digital technology. Originally limited to 7 bits it usually uses 8 bits to code for the Latin alphabet letters, uppercase and lowercase, digits, punctuation marks, some special symbols, and some commands. We need to know the ASCII codes for the uppercase letters of the alphabet:<br />
<br />
{| class="wikitable" style="text-align: center;<br />
| Letter || A||B||C||D||E||F||G||H||I||J||K||L||M||N||O||P||Q||R||S||T||U||V||W||X||Y||Z<br />
|-<br />
| hex code|| 41||42||43||44||45||46||47||48||49||4a||4b||4c||4d||4e||4f||50||51||52||53||54||55||56||57||58||59||5a<br />
|}<br />
<br />
=== Caesar encoder ===<br />
Your goal is to design a configurable Caesar encoder, where the shift is set from the outside. The circuit receives an ASCII letter on data_in input, shifts it by a number of positions given by the key input and outputs the resulting letter as data_out. It is supposed that the input data are restricted to the A-Z ASCII codes and the shift is an unsigned integer no greater than 26 (the length of the alphabet) <br />
<br />
[[Fișier: Dic_lab4_caesar.png]]<br />
<br />
The implementation adds the shift number to the ASCII code of the input letter and corrects the sum such that the output ASCII code is also in the A-Z range of ASCII codes.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
assign data_out = data_in + shift > 8'd90 ?<br />
data_in + shift - 8'd26 :<br />
data_in + shift;<br />
</syntaxhighlight><br />
<br />
=== Caesar decoding ===<br />
The Caesar encrypted message is easy to decode: we need only to shift back all letters to undo the coding. Of course the decoder needs to know the shift number (by the way, the Caesar code may be easily broken by trying for the encrypted message various shifts until a meaningful message is found).<br />
To reverse the coding of our Caesar encoder, the decoder uses shift_decode = 26 - shift_code<br />
<br />
[[Fișier: Dic_lab4_caesar_tb.png]]<br />
<br />
=== Testbench ===<br />
The testbench instantiates two Caesar encoder modules. The first one is the encoder itself, that generates the encoded message. The second instance uses the reversed shift to decode the encrypted message. The shift value (for example 13) may be assigned directly to the shift port of the instance as a literal constant:<br />
<syntaxhighlight lang="Verilog"><br />
caesar encoder (<br />
.shift (8'd13),<br />
// other port connections<br />
);<br />
</syntaxhighlight><br />
<br />
The constant value assigned to an input port is actually a hardwired connection of its bits to the power supply and to the ground.<br />
<br />
The testbench generates a sequence of ASCII values for the data_sent input of the encoder. The verilog language allows you to assign to an 8-bit logic variable an ASCII value as a character:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
#0 data_sent = "C";<br />
#1 data_sent = "O";<br />
#1 data_sent = "M";<br />
#1 data_sent = "B";<br />
#1 data_sent = "I";<br />
#1 data_sent = "N";<br />
#1 data_sent = "A";<br />
#1 data_sent = "T";<br />
#1 data_sent = "I";<br />
#1 data_sent = "O";<br />
#1 data_sent = "N";<br />
#1 data_sent = "A";<br />
#1 data_sent = "L";<br />
#1 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
To display the ASCII values on the waveforms in simulation, right-click the name of the variable in the Simulation panel and select from the pop-up menu '''radix''' -> '''ASCII'''<br />
<br />
<br />
== <span id="transcoder">Exercise 2</span> ==<br />
<br />
Make a 7-segment display transcoder using a '''case''' block that displays values from 0 to 9. The input of the module will be called '''value''' and the output '''seg'''.<br />
<br />
[[Fișier: segment.png]]<br />
<br />
The output bits would control the segments of a digit display, one bit for each segment. The segment is lit when the corresponding bit is '''0''', otherwise it is off (negative logic).<br />
<br />
[[Fișier: digits.png]]<br />
<br />
For all numbers greater than 9 the digit must be off. All these 6 cases may be covered in a single assignment under the '''default''' case.<br />
<br />
Because '''seg''' values are easier to handle in binary, the assigned values for '''seg''' should be given as binary constants. A number in binary format (or a combination of bit values) must be preceded by the base specificator, <syntaxhighlight lang="Verilog" inline>'b</syntaxhighlight>, according to the template ''numberOfBits''''''b'''''value'' as in the following examples:<br />
<br />
{| class="wikitable" style="text-align: center;<br />
| <syntaxhighlight lang="Verilog" inline>8'b11</syntaxhighlight> || 3, in binary format on 8 bits<br />
|-<br />
| <syntaxhighlight lang="Verilog" inline>8'b00000011</syntaxhighlight> || 3, in binary format on 8 bits. Leading zeros are explicitly written<br />
|-<br />
| <syntaxhighlight lang="Verilog" inline>8'b0000_0011</syntaxhighlight> || when there are many bits, the underline, '''_''', may be used to split bits into smaller groups that are easier to read<br />
|}<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module transcoder(<br />
input [3:0] value,<br />
output reg [6:0] seg<br />
);<br />
<br />
always @(*) begin<br />
case (value)<br />
4'd0: seg = 7'b1000000;<br />
4'd1: seg = 7'b1111001;<br />
4'd2: seg = 7'b0100100;<br />
// other 7 cases (for value = 3, 4, ... , 9<br />
default: seg = 7'b1111111; // all segments are off<br />
endcase <br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
<!--<br />
Open the ''transcoder'' VPL activity on Moodle, upload the source file of the transcoder, run the test and check the results. In case of errors fix the design and retry. After you get TEST PASS on Moodle, proceed to implementation.<br />
<br />
Test the transcoder by connecting its 4 bit input to BTN[3], BTN[2], BTN[1] and BTN[0], and displaying the output on a 7-segment display, the right digit (Digit0) of PMOD-SSD <!--(DE1-SOC for) display.--><br />
<br />
'''Coding style:'''<br />
* '''case''' statements should always include the '''default''' case.<br />
<br />
The transcoder may be extended to show hexadecimal digits greater than 9. Use the most common 7-segment symbols for them:<br />
<br />
[[Fișier: letters.png]]<br />
<br />
<br />
<br />
== Exercise 3 ==<br />
<br />
Implement a 3 bit adder whose result is displayed as a hexadecimal digit.<br />
<br />
[[Fișier: app4_adder.png]]<br />
<br />
The result of the 3 bit addition is an integer in the range [0 ... 14], and it may be written in the hexadecimal base using only one digit.<br />
The transcoder must be extended to show all hexadecimal digits, including those greater than 9.<br />
<br />
# create a new project in a new folder<br />
# create a new source file for the top-level module<br />
# create a new source file for the adder. The adder is described behaviorally using a continuous assignment.<br />
# copy from the folder of Exercise 1 the source file of the transcoder module into the folder of this project. Add the file to the project.<br />
# change the transcoder description such that to display all hexadecimal digits<br />
# the top-level module has a structural description. It contains only the instances of the adder and of the transcoder.<br />
# assign switches SW[9], SW[8] and SW[7] for the input '''a''', SW[2], SW[1] and SW[0] for the input '''b''', and Digit0 pins for the output '''seg'''<br />
# implement and check that the result of adding two 3 bit numbers is correctly displayed on Digit0 (in hexadecimal)<br />
<br />
== Exercise 3 ==<br />
Implement a 3 x 3 bits multiplier, with the result shown in decimal base as a 2 digits number.<br />
<br />
[[Fișier: app4_multiplier.png]]<br />
<br />
This project comprises a top module with 4 blocks. The first block, ''multiplier'', takes in two 3 bit numbers, ''a'' and ''b'', and delivers the result of their multiplication in binary format. The input operands and the result are treated as unsigned integers (natural numbers).<br />
The next block, ''BCD converter'', converts the result from the binary format to the decimal. The decimal digits are coded in binary, therefore a multidigit number is coded<br />
in the so called BCD format (Binary-coded decimal), where each decimal digit is represented as a 4 bit number.<br />
<br />
[[Fișier: app4_bcd.png]]<br />
<br />
# create a new project in a new folder<br />
# create a new sorce file for the top module, which is described structurally<br />
# create a new source file for the multiplier. The multiplier is described behaviorally using a continuous assignment.<br />
# copy from the folder of Exercise 1 or Exercice 2 the source file of the transcoder module into the folder of this project. Add the file to the project.<br />
# create a new source file for the BCD converter. Use a behavioral description with integer division operators ('''/''' and '''%'''). The quotient will be the first digit value (the digit of tens), the remainder will be the last digit (the digit of units).<br />
# assign switches SW[9], SW[8] and SW[7] for the input a, SW[2], SW[1] and SW[0] for the input b, Digit0 pins for seg0, and Digit1 pins for seg1<br />
# implement and check that the result of multiplying two 3 bit numbers is correctly displayed on two digits in decimal format. If the result is smaller than ten, the first digit will show a leading 0)<br />
--></div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_3&diff=7511Applications 32023-03-13T10:00:53Z<p>Zhascsi: /* 4 to 1 multiplexer, structural description */</p>
<hr />
<div>Many ways to describe a module:<br />
* ''Behavioral'' description: Uses one or more '''always''' blocks that encloses procedural statements;<br />
* ''Data-flow'' description: employs parallel continuous assignments ('''assign'''), usually with logic operators;<br />
* ''Structural'' description: sub-blocks (module instances, gate primitives) connected together;<br />
* ''Mixed'' description: combines two or all of the above kinds of description;<br />
<br />
== Exercise 1 ==<br />
<br />
Mux 2:1 (two to one multiplexer) is the simplest selection logic circuit. It selects between two inputs, in0 and in1, according to the value of the selection input, s:<br />
<br />
{| class="wikitable" style="text-align: center;<br />
! scope="col"| s<br />
! scope="col"| y<br />
|-<br />
|0 ||'''in0'''<br />
|-<br />
|1 ||'''in1'''<br />
|}<br />
[[Fișier: Mux2.png]]<br />
<br />
<br />
=== 2 to 1 multiplexer, data-flow description ===<br />
<br />
Use one or more continuous assignments. A ''continuous assignment'' is a single assignment statement attached to an '''assign''' keyword. A continuous assignment updates the value of the RHS variable whenever any variable from the RHS expression changes. The RHS expressions is a logic expression, an expression that employs logic operators.<br />
Logic expressions employ only logic operators.<br />
<br />
{| class="wikitable" style="text-align: center;<br />
! scope="col"| operator<br />
! scope="col"| function<br />
! scope="col"| example<br />
|-<br />
|~ ||not||~a<br />
|-<br />
|& ||and|| a & b<br />
|-<br />
| &#124; ||or|| a &#124; b<br />
|-<br />
|^ ||xor|| a ^ b<br />
|}<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module mux2(<br />
input s,<br />
input [1:0] in,<br />
output y<br />
);<br />
<br />
// dataflow description<br />
assign y = (s & in[1]) | (~s & in[0]);<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
'''Note:''' The variable whose value is updated through a continuous assignment should be declared of type '''wire'''.<br />
<br />
<br />
=== 2 to 1 multiplexer, behavioral description ===<br />
<br />
Uses one or more '''always''' blocks. The template of an '''always''' block is:<br />
<br />
'''always @('''''sensitivity list''''') begin'''<br /><br />
&nbsp;&nbsp;''block of statements''<br /><br />
'''end'''<br />
<br />
For combinational circuits the safest way to declare the sensitivity list is to use the wildcard ('''*''').<br />
It stands for all variables that appear inside RHS expressions of the '''always''' block.<br />
The statements employed may be assignments, conditional assignments and procedural statements ('''if''', '''case''').<br />
The '''always''' block of statements is executed whenever any of the variables from the sensitivity list changes its value. The statements are executed in the exact order in which they appear inside the '''always''' block. <br />
<br />
<syntaxhighlight lang="Verilog"><br />
module mux2(<br />
input s,<br />
input [1:0] in,<br />
output y<br />
);<br />
<br />
// behavioral description with if-else<br />
always @(*) begin<br />
if(s)<br />
y = in[1];<br />
else<br />
y = in[0];<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
'''Note:''' Any variable that gets its value through assignments inside an '''always''' block must be declared of type '''reg'''.<br />
If the variable is also an output of the module, the output is declared as <syntaxhighlight lang="Verilog" inline>output reg</syntaxhighlight>.<br />
<br />
'''Note:''' Bit selection operator ('''[ ]''') is used to select a bit (or a couple of consecutive bits) from a multibit variable. '''in[0]''' is bit 0 from the input vector '''in'''.<br />
<br />
<br />
=== 2 to 1 multiplexer, alternative behavioral description ===<br />
<br />
The same module may be described using different procedural statements. Some descriptions may be higher-level than others. Usually, the higher the level of description, the shorter is the code.<br />
<br />
The codes below show three alternative behavioral descriptions for the above multiplexer:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// behavioral description with case<br />
always @(*) begin<br />
case(s)<br />
0: y = in[0];<br />
1: y = in[1];<br />
endcase<br />
end<br />
</syntaxhighlight><br />
<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// behavioral description with conditional assignment<br />
always @(*) begin<br />
y = s ? in[1] : in[0]; <br />
end<br />
</syntaxhighlight><br />
<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// behavioral description with vector selection<br />
always @(*) begin<br />
y = in[s]; <br />
end<br />
</syntaxhighlight><br />
<br />
'''Note:''' The last two alternatives may be also employed in continuous assignments, because they are single statements. For example vector selection may be used inside an '''assign''' instead of an '''always''': <syntaxhighlight lang="Verilog" inline>assign y = in[s];</syntaxhighlight>.<br />
<br />
<br />
=== 2 to 1 multiplexer, structural description: gate-level === <br />
<br />
The ''gate-level description'' is a structural description that uses only logic gates. Verilog language offers predefined logic gates that may be instantiated in structural descriptions. The verilog gate primitives are '''not''', '''and''', '''nand''', '''or''', '''nor''', '''xor''', and '''xnor'''.<br />
Except for the '''not''' gate, all other primitive gates may have 2, 3 or more inputs.<br />
<br />
All gate primitives are instantiated using the same template: ''gatePrimitiveType'' myGate'''('''''outputConnection, inputConnection1, inputConnection2 ...''''')''' as in the following examples:<br />
<br />
<syntaxhighlight lang="Verilog" inline>not g1(dout, din);</syntaxhighlight> is a '''not''' gate with dout at output and din connected at its input.<br />
<br />
<syntaxhighlight lang="Verilog" inline>nand g2(dout, d1, d2);</syntaxhighlight> is a '''nand''' gate with dout at output and two wires, d1 and d2, connected to its inputs.<br />
<br />
<syntaxhighlight lang="Verilog" inline>nand g3(dout, d1, d2, d3, d4);</syntaxhighlight> is a '''nand''' gate with dout at output and four inputs, connected to d1, d2, d3 and d4.<br />
<br />
[[Fișier: Mux2a.png]]<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module mux2(<br />
input s,<br />
input [1:0] in,<br />
output y<br />
);<br />
<br />
wire s_n;<br />
wire w1;<br />
wire w0;<br />
<br />
// gate-level structural description<br />
not (s_n, s);<br />
and (w1, in[1], s);<br />
and (w0, in[0], s_n);<br />
or (y, w1, w0);<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
<br />
=== 2 to 1 multiplexer, FPGA implementation ===<br />
<br />
Implement one of the previous multiplexer descriptions using 2 buttons (BTN0 and BTN1 ) for the inputs in0 and in1, one switch (SW0) for selection, and one LED (LED0) for the multiplexer output (y):<br />
<br />
[[Fișier: Dic_lab3_mux_fpga.png]]<br />
<br />
The constraints file sets the connections between the mux ports and the FPGA pins.<br />
<br />
<syntaxhighlight><br />
##Switches<br />
set_property -dict { PACKAGE_PIN V2 IOSTANDARD LVCMOS33 } [get_ports { s }]; #SW 0<br />
<br />
##Buttons<br />
set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { in[0] }]; #BTN 0<br />
set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { in[1] }]; #BTN 1<br />
<br />
##LEDs<br />
set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { y }]; #LED 0<br />
</syntaxhighlight><br />
<br />
<br />
== Exercise 2 ==<br />
<br />
Write a testbench for the 2:1 multiplexer, using verilog statements to generate all input combinations. There are 3 input bits: one selection bit, and two input bits to select from. Therefore there are possible 8 input combinations. An exhaustive verification should check the output for all those 8 input combinations:<br />
<br />
{| class="wikitable"<br />
|-<br />
! s !! in[1] !! in[0]<br />
|-<br />
| 0|| 0|| 0<br />
|-<br />
| 0 || 0|| 1<br />
|-<br />
| 0|| 1|| 0<br />
|-<br />
| 0|| 1|| 1<br />
|-<br />
| 1|| 0|| 0<br />
|-<br />
| 1|| 0|| 1<br />
|-<br />
| 1|| 1|| 0<br />
|-<br />
| 1|| 1|| 1<br />
|}<br />
<br />
A convenient way is to generate those 8 combinations in the order in which they appear in the truth table, starting with '''0 0 0''', continuing with '''0 0 1''', '''0 1 0''', a.s.o.<br />
There are many ways to generate such a combination of values for the dut input variables:<br />
<br />
=== simple assignments ===<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
{s, a, b} = 3'b000;<br />
#1 {s, a, b} = 3'b001;<br />
#1 {s, a, b} = 3'b010;<br />
#1 {s, a, b} = 3'b011;<br />
#1 {s, a, b} = 3'b100;<br />
#1 {s, a, b} = 3'b101;<br />
#1 {s, a, b} = 3'b110;<br />
#1 {s, a, b} = 3'b111;<br />
#1 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
<br />
=== for statement ===<br />
Its template is:<br />
<br />
'''for('''''initial_assignment''''';''' ''expression''''';''' ''step_assignment''''')''' ''block of statements'';<br />
<br />
The foor loop is repeated until the ''expression'' evaluates true. The simplest '''for''' statement uses an integer index that is incremented at the end of each iteration.<br />
The for loop below generates all combinations from 000 to 111 for tree logic variables, s, a and b. The index must be declared as a variable of type '''integer'''.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
integer index;<br />
initial begin<br />
{s, a, b} = 0;<br />
for(index = 0; index < 8; index = index + 1) begin<br />
#1 {s, a, b} = {s, a, b} + 1;<br />
end<br />
#1 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
<br />
=== repeat statement ===<br />
<br />
Its syntax is '''repeat''' (''number of times'') ''block of statements''<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
{s, a, b} = 0;<br />
repeat (8) #1 {s, a, b} = {s, a, b} + 1;<br />
#1 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
<br />
== Exercise 3 ==<br />
<br />
The half-adder is the simplest, 1-bit, adder. It implements the addition of two bits.<br />
<br />
{| class="wikitable" style="text-align: center;<br />
! scope="col"| a<br />
! scope="col"| b<br />
! scope="col"| s<br />
|-<br />
|0 ||0 || 0 0<br />
|-<br />
|0 ||1 || 0 1<br />
|-<br />
|1 ||0 || 0 1<br />
|-<br />
|1 ||1 || 1 0<br />
|}<br />
<br />
[[Fișier: Dic_lab2_adder.png]]<br />
<br />
This table may be read either as the addition table, with '''s''' considered as a base-2 number value, or it may be read as a truth table, if '''s''' is viewed as a pair of two logic values. Each bit of '''s''' may be computed as a logic function with two arguments.<br />
<br />
<br />
=== half adder, data-flow description ===<br />
<br />
Use data flow description with '''assign''' statement for each output. They are concurrent assignments: in simulation they are evaluated in parallel, mimicking the parallelism of the real circuits.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// data-flow description<br />
assign s[0] = a ^ b;<br />
assign s[1] = a & b;<br />
</syntaxhighlight><br />
<br />
'''Note:''' Despite '''s''' being declared as one variable, its bits are separately updated by concurrent assignments. <br />
<br />
<br />
=== half adder, structural description ===<br />
<br />
[[Fișier: half_adder.png]]<br />
<br />
Using gate primitives, a possible structural description of the half-adder may be:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// gate-level description<br />
xor g1(s[0], a, b);<br />
and g2(s[1], a, b);<br />
</syntaxhighlight><br />
<br />
<br />
== Exercise 4 ==<br />
=== 4 to 1 multiplexer, behavioral description ===<br />
<br />
[[Fișier: mux4.png]]<br />
<br />
'''case''' instruction. Selects between multiple cases. Template<br />
<br />
'''case('''''selectVariable''''')'''<br /><br />
&nbsp;&nbsp;''value1'' ''':''' ''instruction block 1''<br /><br />
&nbsp;&nbsp;''value2'' ''':''' ''instruction block 2''<br /><br />
&nbsp;&nbsp; a.s.o.<br /><br />
'''endcase'''<br />
<br />
''value1'', ''value2'' a.s.o. are integer values of the ''selectVariable''<br />
<br />
<syntaxhighlight lang="Verilog"><br />
always @(*) begin<br />
case(s)<br />
0: y = in[0];<br />
1: y = in[1];<br />
2: y = in[2];<br />
3: y = in[3];<br />
endcase<br />
end<br />
</syntaxhighlight><br />
<br />
'''s''' is a two-bit variable, therefore it may take values from the integer set {0, 1, 2, 3}.<br />
<br />
'''Note:''' The '''case''' statement employed for a combinational logic circuit description SHOULD update the variable it controls for any possible value of the ''selectVariable''.<br />
<br />
'''Note:''' As in Exercise 1, a much more compact description is possible with bit selection, <syntaxhighlight lang="Verilog" inline>assign y = in[s];</syntaxhighlight>.<br />
<br />
== Exercise 5 ==<br />
=== 4 to 1 multiplexer, structural description ===<br />
<br />
[[Fișier: mux4b.png]]<br />
<br />
Design the 4 to 1 multiplexer using three instances of the 2 to 1 multiplexer (from Exercise 1).<br />
<br />
Be careful to distinctly name each instance and each internal wire!</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_3&diff=7510Applications 32023-03-13T09:46:39Z<p>Zhascsi: /* 4 to 1 multiplexer, behavioral description */</p>
<hr />
<div>Many ways to describe a module:<br />
* ''Behavioral'' description: Uses one or more '''always''' blocks that encloses procedural statements;<br />
* ''Data-flow'' description: employs parallel continuous assignments ('''assign'''), usually with logic operators;<br />
* ''Structural'' description: sub-blocks (module instances, gate primitives) connected together;<br />
* ''Mixed'' description: combines two or all of the above kinds of description;<br />
<br />
== Exercise 1 ==<br />
<br />
Mux 2:1 (two to one multiplexer) is the simplest selection logic circuit. It selects between two inputs, in0 and in1, according to the value of the selection input, s:<br />
<br />
{| class="wikitable" style="text-align: center;<br />
! scope="col"| s<br />
! scope="col"| y<br />
|-<br />
|0 ||'''in0'''<br />
|-<br />
|1 ||'''in1'''<br />
|}<br />
[[Fișier: Mux2.png]]<br />
<br />
<br />
=== 2 to 1 multiplexer, data-flow description ===<br />
<br />
Use one or more continuous assignments. A ''continuous assignment'' is a single assignment statement attached to an '''assign''' keyword. A continuous assignment updates the value of the RHS variable whenever any variable from the RHS expression changes. The RHS expressions is a logic expression, an expression that employs logic operators.<br />
Logic expressions employ only logic operators.<br />
<br />
{| class="wikitable" style="text-align: center;<br />
! scope="col"| operator<br />
! scope="col"| function<br />
! scope="col"| example<br />
|-<br />
|~ ||not||~a<br />
|-<br />
|& ||and|| a & b<br />
|-<br />
| &#124; ||or|| a &#124; b<br />
|-<br />
|^ ||xor|| a ^ b<br />
|}<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module mux2(<br />
input s,<br />
input [1:0] in,<br />
output y<br />
);<br />
<br />
// dataflow description<br />
assign y = (s & in[1]) | (~s & in[0]);<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
'''Note:''' The variable whose value is updated through a continuous assignment should be declared of type '''wire'''.<br />
<br />
<br />
=== 2 to 1 multiplexer, behavioral description ===<br />
<br />
Uses one or more '''always''' blocks. The template of an '''always''' block is:<br />
<br />
'''always @('''''sensitivity list''''') begin'''<br /><br />
&nbsp;&nbsp;''block of statements''<br /><br />
'''end'''<br />
<br />
For combinational circuits the safest way to declare the sensitivity list is to use the wildcard ('''*''').<br />
It stands for all variables that appear inside RHS expressions of the '''always''' block.<br />
The statements employed may be assignments, conditional assignments and procedural statements ('''if''', '''case''').<br />
The '''always''' block of statements is executed whenever any of the variables from the sensitivity list changes its value. The statements are executed in the exact order in which they appear inside the '''always''' block. <br />
<br />
<syntaxhighlight lang="Verilog"><br />
module mux2(<br />
input s,<br />
input [1:0] in,<br />
output y<br />
);<br />
<br />
// behavioral description with if-else<br />
always @(*) begin<br />
if(s)<br />
y = in[1];<br />
else<br />
y = in[0];<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
'''Note:''' Any variable that gets its value through assignments inside an '''always''' block must be declared of type '''reg'''.<br />
If the variable is also an output of the module, the output is declared as <syntaxhighlight lang="Verilog" inline>output reg</syntaxhighlight>.<br />
<br />
'''Note:''' Bit selection operator ('''[ ]''') is used to select a bit (or a couple of consecutive bits) from a multibit variable. '''in[0]''' is bit 0 from the input vector '''in'''.<br />
<br />
<br />
=== 2 to 1 multiplexer, alternative behavioral description ===<br />
<br />
The same module may be described using different procedural statements. Some descriptions may be higher-level than others. Usually, the higher the level of description, the shorter is the code.<br />
<br />
The codes below show three alternative behavioral descriptions for the above multiplexer:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// behavioral description with case<br />
always @(*) begin<br />
case(s)<br />
0: y = in[0];<br />
1: y = in[1];<br />
endcase<br />
end<br />
</syntaxhighlight><br />
<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// behavioral description with conditional assignment<br />
always @(*) begin<br />
y = s ? in[1] : in[0]; <br />
end<br />
</syntaxhighlight><br />
<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// behavioral description with vector selection<br />
always @(*) begin<br />
y = in[s]; <br />
end<br />
</syntaxhighlight><br />
<br />
'''Note:''' The last two alternatives may be also employed in continuous assignments, because they are single statements. For example vector selection may be used inside an '''assign''' instead of an '''always''': <syntaxhighlight lang="Verilog" inline>assign y = in[s];</syntaxhighlight>.<br />
<br />
<br />
=== 2 to 1 multiplexer, structural description: gate-level === <br />
<br />
The ''gate-level description'' is a structural description that uses only logic gates. Verilog language offers predefined logic gates that may be instantiated in structural descriptions. The verilog gate primitives are '''not''', '''and''', '''nand''', '''or''', '''nor''', '''xor''', and '''xnor'''.<br />
Except for the '''not''' gate, all other primitive gates may have 2, 3 or more inputs.<br />
<br />
All gate primitives are instantiated using the same template: ''gatePrimitiveType'' myGate'''('''''outputConnection, inputConnection1, inputConnection2 ...''''')''' as in the following examples:<br />
<br />
<syntaxhighlight lang="Verilog" inline>not g1(dout, din);</syntaxhighlight> is a '''not''' gate with dout at output and din connected at its input.<br />
<br />
<syntaxhighlight lang="Verilog" inline>nand g2(dout, d1, d2);</syntaxhighlight> is a '''nand''' gate with dout at output and two wires, d1 and d2, connected to its inputs.<br />
<br />
<syntaxhighlight lang="Verilog" inline>nand g3(dout, d1, d2, d3, d4);</syntaxhighlight> is a '''nand''' gate with dout at output and four inputs, connected to d1, d2, d3 and d4.<br />
<br />
[[Fișier: Mux2a.png]]<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module mux2(<br />
input s,<br />
input [1:0] in,<br />
output y<br />
);<br />
<br />
wire s_n;<br />
wire w1;<br />
wire w0;<br />
<br />
// gate-level structural description<br />
not (s_n, s);<br />
and (w1, in[1], s);<br />
and (w0, in[0], s_n);<br />
or (y, w1, w0);<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
<br />
=== 2 to 1 multiplexer, FPGA implementation ===<br />
<br />
Implement one of the previous multiplexer descriptions using 2 buttons (BTN0 and BTN1 ) for the inputs in0 and in1, one switch (SW0) for selection, and one LED (LED0) for the multiplexer output (y):<br />
<br />
[[Fișier: Dic_lab3_mux_fpga.png]]<br />
<br />
The constraints file sets the connections between the mux ports and the FPGA pins.<br />
<br />
<syntaxhighlight><br />
##Switches<br />
set_property -dict { PACKAGE_PIN V2 IOSTANDARD LVCMOS33 } [get_ports { s }]; #SW 0<br />
<br />
##Buttons<br />
set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { in[0] }]; #BTN 0<br />
set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { in[1] }]; #BTN 1<br />
<br />
##LEDs<br />
set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { y }]; #LED 0<br />
</syntaxhighlight><br />
<br />
<br />
== Exercise 2 ==<br />
<br />
Write a testbench for the 2:1 multiplexer, using verilog statements to generate all input combinations. There are 3 input bits: one selection bit, and two input bits to select from. Therefore there are possible 8 input combinations. An exhaustive verification should check the output for all those 8 input combinations:<br />
<br />
{| class="wikitable"<br />
|-<br />
! s !! in[1] !! in[0]<br />
|-<br />
| 0|| 0|| 0<br />
|-<br />
| 0 || 0|| 1<br />
|-<br />
| 0|| 1|| 0<br />
|-<br />
| 0|| 1|| 1<br />
|-<br />
| 1|| 0|| 0<br />
|-<br />
| 1|| 0|| 1<br />
|-<br />
| 1|| 1|| 0<br />
|-<br />
| 1|| 1|| 1<br />
|}<br />
<br />
A convenient way is to generate those 8 combinations in the order in which they appear in the truth table, starting with '''0 0 0''', continuing with '''0 0 1''', '''0 1 0''', a.s.o.<br />
There are many ways to generate such a combination of values for the dut input variables:<br />
<br />
=== simple assignments ===<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
{s, a, b} = 3'b000;<br />
#1 {s, a, b} = 3'b001;<br />
#1 {s, a, b} = 3'b010;<br />
#1 {s, a, b} = 3'b011;<br />
#1 {s, a, b} = 3'b100;<br />
#1 {s, a, b} = 3'b101;<br />
#1 {s, a, b} = 3'b110;<br />
#1 {s, a, b} = 3'b111;<br />
#1 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
<br />
=== for statement ===<br />
Its template is:<br />
<br />
'''for('''''initial_assignment''''';''' ''expression''''';''' ''step_assignment''''')''' ''block of statements'';<br />
<br />
The foor loop is repeated until the ''expression'' evaluates true. The simplest '''for''' statement uses an integer index that is incremented at the end of each iteration.<br />
The for loop below generates all combinations from 000 to 111 for tree logic variables, s, a and b. The index must be declared as a variable of type '''integer'''.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
integer index;<br />
initial begin<br />
{s, a, b} = 0;<br />
for(index = 0; index < 8; index = index + 1) begin<br />
#1 {s, a, b} = {s, a, b} + 1;<br />
end<br />
#1 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
<br />
=== repeat statement ===<br />
<br />
Its syntax is '''repeat''' (''number of times'') ''block of statements''<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
{s, a, b} = 0;<br />
repeat (8) #1 {s, a, b} = {s, a, b} + 1;<br />
#1 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
<br />
== Exercise 3 ==<br />
<br />
The half-adder is the simplest, 1-bit, adder. It implements the addition of two bits.<br />
<br />
{| class="wikitable" style="text-align: center;<br />
! scope="col"| a<br />
! scope="col"| b<br />
! scope="col"| s<br />
|-<br />
|0 ||0 || 0 0<br />
|-<br />
|0 ||1 || 0 1<br />
|-<br />
|1 ||0 || 0 1<br />
|-<br />
|1 ||1 || 1 0<br />
|}<br />
<br />
[[Fișier: Dic_lab2_adder.png]]<br />
<br />
This table may be read either as the addition table, with '''s''' considered as a base-2 number value, or it may be read as a truth table, if '''s''' is viewed as a pair of two logic values. Each bit of '''s''' may be computed as a logic function with two arguments.<br />
<br />
<br />
=== half adder, data-flow description ===<br />
<br />
Use data flow description with '''assign''' statement for each output. They are concurrent assignments: in simulation they are evaluated in parallel, mimicking the parallelism of the real circuits.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// data-flow description<br />
assign s[0] = a ^ b;<br />
assign s[1] = a & b;<br />
</syntaxhighlight><br />
<br />
'''Note:''' Despite '''s''' being declared as one variable, its bits are separately updated by concurrent assignments. <br />
<br />
<br />
=== half adder, structural description ===<br />
<br />
[[Fișier: half_adder.png]]<br />
<br />
Using gate primitives, a possible structural description of the half-adder may be:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// gate-level description<br />
xor g1(s[0], a, b);<br />
and g2(s[1], a, b);<br />
</syntaxhighlight><br />
<br />
<br />
== Exercise 4 ==<br />
=== 4 to 1 multiplexer, behavioral description ===<br />
<br />
[[Fișier: mux4.png]]<br />
<br />
'''case''' instruction. Selects between multiple cases. Template<br />
<br />
'''case('''''selectVariable''''')'''<br /><br />
&nbsp;&nbsp;''value1'' ''':''' ''instruction block 1''<br /><br />
&nbsp;&nbsp;''value2'' ''':''' ''instruction block 2''<br /><br />
&nbsp;&nbsp; a.s.o.<br /><br />
'''endcase'''<br />
<br />
''value1'', ''value2'' a.s.o. are integer values of the ''selectVariable''<br />
<br />
<syntaxhighlight lang="Verilog"><br />
always @(*) begin<br />
case(s)<br />
0: y = in[0];<br />
1: y = in[1];<br />
2: y = in[2];<br />
3: y = in[3];<br />
endcase<br />
end<br />
</syntaxhighlight><br />
<br />
'''s''' is a two-bit variable, therefore it may take values from the integer set {0, 1, 2, 3}.<br />
<br />
'''Note:''' The '''case''' statement employed for a combinational logic circuit description SHOULD update the variable it controls for any possible value of the ''selectVariable''.<br />
<br />
'''Note:''' As in Exercise 1, a much more compact description is possible with bit selection, <syntaxhighlight lang="Verilog" inline>assign y = in[s];</syntaxhighlight>.<br />
<br />
== Exercise 5 ==<br />
=== 4 to 1 multiplexer, structural description ===<br />
<br />
[[Fișier: mux4b.png]]<br />
<br />
Implement the 4 to 1 multiplexer using three instances of the 2 to 1 multiplexer (add to the project one of the design source files from Exercise 1).<br />
<br />
Be careful to distinctly name each instance and each internal wire!</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Digital_Integrated_Circuits_(lab)&diff=7509Digital Integrated Circuits (lab)2023-03-13T02:16:03Z<p>Zhascsi: </p>
<hr />
<div># [[Applications 1 | Laboratory 1]]<br />
# [[Applications 2 | Laboratory 2]]<br />
# [[Applications 3 | Laboratory 3]]<br />
<br />
== Verilog Tutorials ==<br />
* [http://www.asic-world.com/verilog/veritut.html Verilog Tutorial] from ASIC World<br />
* [http://chipverify.com/verilog/verilog-tutorial Verilog Tutorial] from Chip Verify<br />
* [http://www.emmelmann.org/Library/Tutorials/docs/verilog_ref_guide/vlog_ref_top.html Verilog reference guide]<br />
<br />
== Software ==<br />
* [https://www.xilinx.com/products/design-tools/vivado/vivado-ml.html Vivado™ ML Standard Edition free]<br />
* [https://wiki.dcae.pub.ro/images/2/24/VivadoNewProjectTutorial.pdf Vivado New Project Tutorial]<br />
<br />
== Hardware ==<br />
* [https://dpoauwgwqsy2x.cloudfront.net/Download/pynqz2_user_manual_v1_0.pdf Pynq-Z2 - user manual]<br />
* [[Pynq-Z2 - Pinout]].<br />
<br />
* [https://www.realdigital.org/doc/02013cd17602c8af749f00561f88ae21 Boolean Board - user manual]<br />
* [[Boolean Board - Pinout]].</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_3&diff=7508Applications 32023-03-13T02:10:13Z<p>Zhascsi: </p>
<hr />
<div>Many ways to describe a module:<br />
* ''Behavioral'' description: Uses one or more '''always''' blocks that encloses procedural statements;<br />
* ''Data-flow'' description: employs parallel continuous assignments ('''assign'''), usually with logic operators;<br />
* ''Structural'' description: sub-blocks (module instances, gate primitives) connected together;<br />
* ''Mixed'' description: combines two or all of the above kinds of description;<br />
<br />
== Exercise 1 ==<br />
<br />
Mux 2:1 (two to one multiplexer) is the simplest selection logic circuit. It selects between two inputs, in0 and in1, according to the value of the selection input, s:<br />
<br />
{| class="wikitable" style="text-align: center;<br />
! scope="col"| s<br />
! scope="col"| y<br />
|-<br />
|0 ||'''in0'''<br />
|-<br />
|1 ||'''in1'''<br />
|}<br />
[[Fișier: Mux2.png]]<br />
<br />
<br />
=== 2 to 1 multiplexer, data-flow description ===<br />
<br />
Use one or more continuous assignments. A ''continuous assignment'' is a single assignment statement attached to an '''assign''' keyword. A continuous assignment updates the value of the RHS variable whenever any variable from the RHS expression changes. The RHS expressions is a logic expression, an expression that employs logic operators.<br />
Logic expressions employ only logic operators.<br />
<br />
{| class="wikitable" style="text-align: center;<br />
! scope="col"| operator<br />
! scope="col"| function<br />
! scope="col"| example<br />
|-<br />
|~ ||not||~a<br />
|-<br />
|& ||and|| a & b<br />
|-<br />
| &#124; ||or|| a &#124; b<br />
|-<br />
|^ ||xor|| a ^ b<br />
|}<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module mux2(<br />
input s,<br />
input [1:0] in,<br />
output y<br />
);<br />
<br />
// dataflow description<br />
assign y = (s & in[1]) | (~s & in[0]);<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
'''Note:''' The variable whose value is updated through a continuous assignment should be declared of type '''wire'''.<br />
<br />
<br />
=== 2 to 1 multiplexer, behavioral description ===<br />
<br />
Uses one or more '''always''' blocks. The template of an '''always''' block is:<br />
<br />
'''always @('''''sensitivity list''''') begin'''<br /><br />
&nbsp;&nbsp;''block of statements''<br /><br />
'''end'''<br />
<br />
For combinational circuits the safest way to declare the sensitivity list is to use the wildcard ('''*''').<br />
It stands for all variables that appear inside RHS expressions of the '''always''' block.<br />
The statements employed may be assignments, conditional assignments and procedural statements ('''if''', '''case''').<br />
The '''always''' block of statements is executed whenever any of the variables from the sensitivity list changes its value. The statements are executed in the exact order in which they appear inside the '''always''' block. <br />
<br />
<syntaxhighlight lang="Verilog"><br />
module mux2(<br />
input s,<br />
input [1:0] in,<br />
output y<br />
);<br />
<br />
// behavioral description with if-else<br />
always @(*) begin<br />
if(s)<br />
y = in[1];<br />
else<br />
y = in[0];<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
'''Note:''' Any variable that gets its value through assignments inside an '''always''' block must be declared of type '''reg'''.<br />
If the variable is also an output of the module, the output is declared as <syntaxhighlight lang="Verilog" inline>output reg</syntaxhighlight>.<br />
<br />
'''Note:''' Bit selection operator ('''[ ]''') is used to select a bit (or a couple of consecutive bits) from a multibit variable. '''in[0]''' is bit 0 from the input vector '''in'''.<br />
<br />
<br />
=== 2 to 1 multiplexer, alternative behavioral description ===<br />
<br />
The same module may be described using different procedural statements. Some descriptions may be higher-level than others. Usually, the higher the level of description, the shorter is the code.<br />
<br />
The codes below show three alternative behavioral descriptions for the above multiplexer:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// behavioral description with case<br />
always @(*) begin<br />
case(s)<br />
0: y = in[0];<br />
1: y = in[1];<br />
endcase<br />
end<br />
</syntaxhighlight><br />
<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// behavioral description with conditional assignment<br />
always @(*) begin<br />
y = s ? in[1] : in[0]; <br />
end<br />
</syntaxhighlight><br />
<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// behavioral description with vector selection<br />
always @(*) begin<br />
y = in[s]; <br />
end<br />
</syntaxhighlight><br />
<br />
'''Note:''' The last two alternatives may be also employed in continuous assignments, because they are single statements. For example vector selection may be used inside an '''assign''' instead of an '''always''': <syntaxhighlight lang="Verilog" inline>assign y = in[s];</syntaxhighlight>.<br />
<br />
<br />
=== 2 to 1 multiplexer, structural description: gate-level === <br />
<br />
The ''gate-level description'' is a structural description that uses only logic gates. Verilog language offers predefined logic gates that may be instantiated in structural descriptions. The verilog gate primitives are '''not''', '''and''', '''nand''', '''or''', '''nor''', '''xor''', and '''xnor'''.<br />
Except for the '''not''' gate, all other primitive gates may have 2, 3 or more inputs.<br />
<br />
All gate primitives are instantiated using the same template: ''gatePrimitiveType'' myGate'''('''''outputConnection, inputConnection1, inputConnection2 ...''''')''' as in the following examples:<br />
<br />
<syntaxhighlight lang="Verilog" inline>not g1(dout, din);</syntaxhighlight> is a '''not''' gate with dout at output and din connected at its input.<br />
<br />
<syntaxhighlight lang="Verilog" inline>nand g2(dout, d1, d2);</syntaxhighlight> is a '''nand''' gate with dout at output and two wires, d1 and d2, connected to its inputs.<br />
<br />
<syntaxhighlight lang="Verilog" inline>nand g3(dout, d1, d2, d3, d4);</syntaxhighlight> is a '''nand''' gate with dout at output and four inputs, connected to d1, d2, d3 and d4.<br />
<br />
[[Fișier: Mux2a.png]]<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module mux2(<br />
input s,<br />
input [1:0] in,<br />
output y<br />
);<br />
<br />
wire s_n;<br />
wire w1;<br />
wire w0;<br />
<br />
// gate-level structural description<br />
not (s_n, s);<br />
and (w1, in[1], s);<br />
and (w0, in[0], s_n);<br />
or (y, w1, w0);<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
<br />
=== 2 to 1 multiplexer, FPGA implementation ===<br />
<br />
Implement one of the previous multiplexer descriptions using 2 buttons (BTN0 and BTN1 ) for the inputs in0 and in1, one switch (SW0) for selection, and one LED (LED0) for the multiplexer output (y):<br />
<br />
[[Fișier: Dic_lab3_mux_fpga.png]]<br />
<br />
The constraints file sets the connections between the mux ports and the FPGA pins.<br />
<br />
<syntaxhighlight><br />
##Switches<br />
set_property -dict { PACKAGE_PIN V2 IOSTANDARD LVCMOS33 } [get_ports { s }]; #SW 0<br />
<br />
##Buttons<br />
set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { in[0] }]; #BTN 0<br />
set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { in[1] }]; #BTN 1<br />
<br />
##LEDs<br />
set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { y }]; #LED 0<br />
</syntaxhighlight><br />
<br />
<br />
== Exercise 2 ==<br />
<br />
Write a testbench for the 2:1 multiplexer, using verilog statements to generate all input combinations. There are 3 input bits: one selection bit, and two input bits to select from. Therefore there are possible 8 input combinations. An exhaustive verification should check the output for all those 8 input combinations:<br />
<br />
{| class="wikitable"<br />
|-<br />
! s !! in[1] !! in[0]<br />
|-<br />
| 0|| 0|| 0<br />
|-<br />
| 0 || 0|| 1<br />
|-<br />
| 0|| 1|| 0<br />
|-<br />
| 0|| 1|| 1<br />
|-<br />
| 1|| 0|| 0<br />
|-<br />
| 1|| 0|| 1<br />
|-<br />
| 1|| 1|| 0<br />
|-<br />
| 1|| 1|| 1<br />
|}<br />
<br />
A convenient way is to generate those 8 combinations in the order in which they appear in the truth table, starting with '''0 0 0''', continuing with '''0 0 1''', '''0 1 0''', a.s.o.<br />
There are many ways to generate such a combination of values for the dut input variables:<br />
<br />
=== simple assignments ===<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
{s, a, b} = 3'b000;<br />
#1 {s, a, b} = 3'b001;<br />
#1 {s, a, b} = 3'b010;<br />
#1 {s, a, b} = 3'b011;<br />
#1 {s, a, b} = 3'b100;<br />
#1 {s, a, b} = 3'b101;<br />
#1 {s, a, b} = 3'b110;<br />
#1 {s, a, b} = 3'b111;<br />
#1 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
<br />
=== for statement ===<br />
Its template is:<br />
<br />
'''for('''''initial_assignment''''';''' ''expression''''';''' ''step_assignment''''')''' ''block of statements'';<br />
<br />
The foor loop is repeated until the ''expression'' evaluates true. The simplest '''for''' statement uses an integer index that is incremented at the end of each iteration.<br />
The for loop below generates all combinations from 000 to 111 for tree logic variables, s, a and b. The index must be declared as a variable of type '''integer'''.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
integer index;<br />
initial begin<br />
{s, a, b} = 0;<br />
for(index = 0; index < 8; index = index + 1) begin<br />
#1 {s, a, b} = {s, a, b} + 1;<br />
end<br />
#1 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
<br />
=== repeat statement ===<br />
<br />
Its syntax is '''repeat''' (''number of times'') ''block of statements''<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
{s, a, b} = 0;<br />
repeat (8) #1 {s, a, b} = {s, a, b} + 1;<br />
#1 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
<br />
== Exercise 3 ==<br />
<br />
The half-adder is the simplest, 1-bit, adder. It implements the addition of two bits.<br />
<br />
{| class="wikitable" style="text-align: center;<br />
! scope="col"| a<br />
! scope="col"| b<br />
! scope="col"| s<br />
|-<br />
|0 ||0 || 0 0<br />
|-<br />
|0 ||1 || 0 1<br />
|-<br />
|1 ||0 || 0 1<br />
|-<br />
|1 ||1 || 1 0<br />
|}<br />
<br />
[[Fișier: Dic_lab2_adder.png]]<br />
<br />
This table may be read either as the addition table, with '''s''' considered as a base-2 number value, or it may be read as a truth table, if '''s''' is viewed as a pair of two logic values. Each bit of '''s''' may be computed as a logic function with two arguments.<br />
<br />
<br />
=== half adder, data-flow description ===<br />
<br />
Use data flow description with '''assign''' statement for each output. They are concurrent assignments: in simulation they are evaluated in parallel, mimicking the parallelism of the real circuits.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// data-flow description<br />
assign s[0] = a ^ b;<br />
assign s[1] = a & b;<br />
</syntaxhighlight><br />
<br />
'''Note:''' Despite '''s''' being declared as one variable, its bits are separately updated by concurrent assignments. <br />
<br />
<br />
=== half adder, structural description ===<br />
<br />
[[Fișier: half_adder.png]]<br />
<br />
Using gate primitives, a possible structural description of the half-adder may be:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// gate-level description<br />
xor g1(s[0], a, b);<br />
and g2(s[1], a, b);<br />
</syntaxhighlight><br />
<br />
<br />
== Exercise 4 ==<br />
=== 4 to 1 multiplexer, behavioral description ===<br />
<br />
[[Fișier: mux4.png]]<br />
<br />
'''case''' instruction. Selects between multiple cases. Template<br />
<br />
'''case('''''selectVariable''''')'''<br /><br />
&nbsp;&nbsp;''value1'' ''':''' ''instruction block 1''<br /><br />
&nbsp;&nbsp;''value2'' ''':''' ''instruction block 2''<br /><br />
&nbsp;&nbsp; a.s.o.<br /><br />
'''endcase'''<br />
<br />
''value1'', ''value2'' a.s.o. are integer values of the ''selectVariable''<br />
<br />
<syntaxhighlight lang="Verilog"><br />
case(s)<br />
0: y = in[0];<br />
1: y = in[1];<br />
2: y = in[2];<br />
3: y = in[3];<br />
endcase <br />
</syntaxhighlight><br />
<br />
'''Note:''' As in Exercise 1, a much more compact description is possible with bit selection, <syntaxhighlight lang="Verilog" inline>assign y = in[s];</syntaxhighlight>.<br />
<br />
<br />
== Exercise 5 ==<br />
=== 4 to 1 multiplexer, structural description ===<br />
<br />
[[Fișier: mux4b.png]]<br />
<br />
Implement the 4 to 1 multiplexer using three instances of the 2 to 1 multiplexer (add to the project one of the design source files from Exercise 1).<br />
<br />
Be careful to distinctly name each instance and each internal wire!</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_3&diff=7507Applications 32023-03-13T02:08:20Z<p>Zhascsi: /* for statement */</p>
<hr />
<div>Many ways to describe a module:<br />
* ''Behavioral'' description: Uses one or more '''always''' blocks that encloses procedural statements;<br />
* ''Data-flow'' description: employs parallel continuous assignments ('''assign'''), usually with logic operators;<br />
* ''Structural'' description: sub-blocks (module instances, gate primitives) connected together;<br />
* ''Mixed'' description: combines two or all of the above kinds of description;<br />
<br />
== Exercise 1 ==<br />
<br />
Mux 2:1 (two to one multiplexer) is the simplest selection logic circuit. It selects between two inputs, in0 and in1, according to the value of the selection input, s:<br />
<br />
{| class="wikitable" style="text-align: center;<br />
! scope="col"| s<br />
! scope="col"| y<br />
|-<br />
|0 ||'''in0'''<br />
|-<br />
|1 ||'''in1'''<br />
|}<br />
[[Fișier: Mux2.png]]<br />
<br />
<br />
=== 2 to 1 multiplexer, data-flow description ===<br />
<br />
Use one or more continuous assignments. A ''continuous assignment'' is a single assignment statement attached to an '''assign''' keyword. A continuous assignment updates the value of the RHS variable whenever any variable from the RHS expression changes. The RHS expressions is a logic expression, an expression that employs logic operators.<br />
Logic expressions employ only logic operators.<br />
<br />
{| class="wikitable" style="text-align: center;<br />
! scope="col"| operator<br />
! scope="col"| function<br />
! scope="col"| example<br />
|-<br />
|~ ||not||~a<br />
|-<br />
|& ||and|| a & b<br />
|-<br />
| &#124; ||or|| a &#124; b<br />
|-<br />
|^ ||xor|| a ^ b<br />
|}<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module mux2(<br />
input s,<br />
input [1:0] in,<br />
output y<br />
);<br />
<br />
// dataflow description<br />
assign y = (s & in[1]) | (~s & in[0]);<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
'''Note:''' The variable whose value is updated through a continuous assignment should be declared of type '''wire'''.<br />
<br />
<br />
=== 2 to 1 multiplexer, behavioral description ===<br />
<br />
Uses one or more '''always''' blocks. The template of an '''always''' block is:<br />
<br />
'''always @('''''sensitivity list''''') begin'''<br /><br />
&nbsp;&nbsp;''block of statements''<br /><br />
'''end'''<br />
<br />
For combinational circuits the safest way to declare the sensitivity list is to use the wildcard ('''*''').<br />
It stands for all variables that appear inside RHS expressions of the '''always''' block.<br />
The statements employed may be assignments, conditional assignments and procedural statements ('''if''', '''case''').<br />
The '''always''' block of statements is executed whenever any of the variables from the sensitivity list changes its value. The statements are executed in the exact order in which they appear inside the '''always''' block. <br />
<br />
<syntaxhighlight lang="Verilog"><br />
module mux2(<br />
input s,<br />
input [1:0] in,<br />
output y<br />
);<br />
<br />
// behavioral description with if-else<br />
always @(*) begin<br />
if(s)<br />
y = in[1];<br />
else<br />
y = in[0];<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
'''Note:''' Any variable that gets its value through assignments inside an '''always''' block must be declared of type '''reg'''.<br />
If the variable is also an output of the module, the output is declared as <syntaxhighlight lang="Verilog" inline>output reg</syntaxhighlight>.<br />
<br />
'''Note:''' Bit selection operator ('''[ ]''') is used to select a bit (or a couple of consecutive bits) from a multibit variable. '''in[0]''' is bit 0 from the input vector '''in'''.<br />
<br />
<br />
=== 2 to 1 multiplexer, alternative behavioral description ===<br />
<br />
The same module may be described using different procedural statements. Some descriptions may be higher-level than others. Usually, the higher the level of description, the shorter is the code.<br />
<br />
The codes below show three alternative behavioral descriptions for the above multiplexer:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// behavioral description with case<br />
always @(*) begin<br />
case(s)<br />
0: y = in[0];<br />
1: y = in[1];<br />
endcase<br />
end<br />
</syntaxhighlight><br />
<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// behavioral description with conditional assignment<br />
always @(*) begin<br />
y = s ? in[1] : in[0]; <br />
end<br />
</syntaxhighlight><br />
<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// behavioral description with vector selection<br />
always @(*) begin<br />
y = in[s]; <br />
end<br />
</syntaxhighlight><br />
<br />
'''Note:''' The last two alternatives may be also employed in continuous assignments, because they are single statements. For example vector selection may be used inside an '''assign''' instead of an '''always''': <syntaxhighlight lang="Verilog" inline>assign y = in[s];</syntaxhighlight>.<br />
<br />
<br />
=== 2 to 1 multiplexer, structural description: gate-level === <br />
<br />
The ''gate-level description'' is a structural description that uses only logic gates. Verilog language offers predefined logic gates that may be instantiated in structural descriptions. The verilog gate primitives are '''not''', '''and''', '''nand''', '''or''', '''nor''', '''xor''', and '''xnor'''.<br />
Except for the '''not''' gate, all other primitive gates may have 2, 3 or more inputs.<br />
<br />
All gate primitives are instantiated using the same template: ''gatePrimitiveType'' myGate'''('''''outputConnection, inputConnection1, inputConnection2 ...''''')''' as in the following examples:<br />
<br />
<syntaxhighlight lang="Verilog" inline>not g1(dout, din);</syntaxhighlight> is a '''not''' gate with dout at output and din connected at its input.<br />
<br />
<syntaxhighlight lang="Verilog" inline>nand g2(dout, d1, d2);</syntaxhighlight> is a '''nand''' gate with dout at output and two wires, d1 and d2, connected to its inputs.<br />
<br />
<syntaxhighlight lang="Verilog" inline>nand g3(dout, d1, d2, d3, d4);</syntaxhighlight> is a '''nand''' gate with dout at output and four inputs, connected to d1, d2, d3 and d4.<br />
<br />
[[Fișier: Mux2a.png]]<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module mux2(<br />
input s,<br />
input [1:0] in,<br />
output y<br />
);<br />
<br />
wire s_n;<br />
wire w1;<br />
wire w0;<br />
<br />
// gate-level structural description<br />
not (s_n, s);<br />
and (w1, in[1], s);<br />
and (w0, in[0], s_n);<br />
or (y, w1, w0);<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
<br />
=== 2 to 1 multiplexer, FPGA implementation ===<br />
<br />
Implement one of the previous multiplexer descriptions using 2 buttons (BTN0 and BTN1 ) for the inputs in0 and in1, one switch (SW0) for selection, and one LED (LED0) for the multiplexer output (y):<br />
<br />
[[Fișier: Dic_lab3_mux_fpga.png]]<br />
<br />
The constraints file sets the connections between the mux ports and the FPGA pins.<br />
<br />
<syntaxhighlight><br />
##Switches<br />
set_property -dict { PACKAGE_PIN V2 IOSTANDARD LVCMOS33 } [get_ports { s }]; #SW 0<br />
<br />
##Buttons<br />
set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { in[0] }]; #BTN 0<br />
set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { in[1] }]; #BTN 1<br />
<br />
##LEDs<br />
set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { y }]; #LED 0<br />
</syntaxhighlight><br />
<br />
<br />
== Exercise 2 ==<br />
<br />
Write a testbench for the 2:1 multiplexer, using verilog statements to generate all input combinations. There are 3 input bits: one selection bit, and two input bits to select from. Therefore there are possible 8 input combinations. An exhaustive verification should check the output for all those 8 input combinations:<br />
<br />
{| class="wikitable"<br />
|-<br />
! s !! in[1] !! in[0]<br />
|-<br />
| 0|| 0|| 0<br />
|-<br />
| 0 || 0|| 1<br />
|-<br />
| 0|| 1|| 0<br />
|-<br />
| 0|| 1|| 1<br />
|-<br />
| 1|| 0|| 0<br />
|-<br />
| 1|| 0|| 1<br />
|-<br />
| 1|| 1|| 0<br />
|-<br />
| 1|| 1|| 1<br />
|}<br />
<br />
A convenient way is to generate those 8 combinations in the order in which they appear in the truth table, starting with '''0 0 0''', continuing with '''0 0 1''', '''0 1 0''', a.s.o.<br />
There are many ways to generate such a combination of values for the dut input variables:<br />
<br />
=== simple assignments ===<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
{s, a, b} = 3'b000;<br />
#1 {s, a, b} = 3'b001;<br />
#1 {s, a, b} = 3'b010;<br />
#1 {s, a, b} = 3'b011;<br />
#1 {s, a, b} = 3'b100;<br />
#1 {s, a, b} = 3'b101;<br />
#1 {s, a, b} = 3'b110;<br />
#1 {s, a, b} = 3'b111;<br />
#1 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
<br />
=== for statement ===<br />
Its template is:<br />
<br />
'''for('''''initial_assignment''''';''' ''expression''''';''' ''step_assignment''''')''' ''block of statements'';<br />
<br />
The foor loop is repeated until the ''expression'' evaluates true. The simplest '''for''' statement uses an integer index that is incremented at the end of each iteration.<br />
The for loop below generates all combinations from 000 to 111 for tree logic variables, s, a and b. The index must be declared as a variable of type '''integer'''.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
integer index;<br />
initial begin<br />
{s, a, b} = 0;<br />
for(index = 0; index < 8; index = index + 1) begin<br />
#1 {s, a, b} = {s, a, b} + 1;<br />
end<br />
#1 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
=== repeat statement ===<br />
<br />
Its syntax is '''repeat''' (''number of times'') ''block of statements''<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
{s, a, b} = 0;<br />
repeat (8) #1 {s, a, b} = {s, a, b} + 1;<br />
#1 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
<br />
== Exercise 3 ==<br />
<br />
The half-adder is the simplest, 1-bit, adder. It implements the addition of two bits.<br />
<br />
{| class="wikitable" style="text-align: center;<br />
! scope="col"| a<br />
! scope="col"| b<br />
! scope="col"| s<br />
|-<br />
|0 ||0 || 0 0<br />
|-<br />
|0 ||1 || 0 1<br />
|-<br />
|1 ||0 || 0 1<br />
|-<br />
|1 ||1 || 1 0<br />
|}<br />
<br />
[[Fișier: Dic_lab2_adder.png]]<br />
<br />
This table may be read either as the addition table, with '''s''' considered as a base-2 number value, or it may be read as a truth table, if '''s''' is viewed as a pair of two logic values. Each bit of '''s''' may be computed as a logic function with two arguments.<br />
<br />
=== half adder, data-flow description ===<br />
<br />
Use data flow description with '''assign''' statement for each output. They are concurrent assignments: in simulation they are evaluated in parallel, mimicking the parallelism of the real circuits.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// data-flow description<br />
assign s[0] = a ^ b;<br />
assign s[1] = a & b;<br />
</syntaxhighlight><br />
<br />
'''Note:''' Despite '''s''' being declared as one variable, its bits are separately updated by concurrent assignments. <br />
<br />
<br />
=== half adder, structural description ===<br />
<br />
[[Fișier: half_adder.png]]<br />
<br />
Using gate primitives, a possible structural description of the half-adder may be:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// gate-level description<br />
xor g1(s[0], a, b);<br />
and g2(s[1], a, b);<br />
</syntaxhighlight><br />
<br />
<br />
== Exercise 4 ==<br />
=== 4 to 1 multiplexer, behavioral description ===<br />
<br />
[[Fișier: mux4.png]]<br />
<br />
'''case''' instruction. Selects between multiple cases. Template<br />
<br />
'''case('''''selectVariable''''')'''<br /><br />
&nbsp;&nbsp;''value1'' ''':''' ''instruction block 1''<br /><br />
&nbsp;&nbsp;''value2'' ''':''' ''instruction block 2''<br /><br />
&nbsp;&nbsp; a.s.o.<br /><br />
'''endcase'''<br />
<br />
''value1'', ''value2'' a.s.o. are integer values of the ''selectVariable''<br />
<br />
<syntaxhighlight lang="Verilog"><br />
case(s)<br />
0: y = in[0];<br />
1: y = in[1];<br />
2: y = in[2];<br />
3: y = in[3];<br />
endcase <br />
</syntaxhighlight><br />
<br />
'''Note:''' As in Exercise 1, a much more compact description is possible with bit selection, <syntaxhighlight lang="Verilog" inline>assign y = in[s];</syntaxhighlight>.<br />
<br />
<br />
== Exercise 5 ==<br />
=== 4 to 1 multiplexer, structural description ===<br />
<br />
[[Fișier: mux4b.png]]<br />
<br />
Implement the 4 to 1 multiplexer using three instances of the 2 to 1 multiplexer (add to the project one of the design source files from Exercise 1).<br />
<br />
Be careful to distinctly name each instance and each internal wire!</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_3&diff=7506Applications 32023-03-13T02:03:03Z<p>Zhascsi: </p>
<hr />
<div>Many ways to describe a module:<br />
* ''Behavioral'' description: Uses one or more '''always''' blocks that encloses procedural statements;<br />
* ''Data-flow'' description: employs parallel continuous assignments ('''assign'''), usually with logic operators;<br />
* ''Structural'' description: sub-blocks (module instances, gate primitives) connected together;<br />
* ''Mixed'' description: combines two or all of the above kinds of description;<br />
<br />
== Exercise 1 ==<br />
<br />
Mux 2:1 (two to one multiplexer) is the simplest selection logic circuit. It selects between two inputs, in0 and in1, according to the value of the selection input, s:<br />
<br />
{| class="wikitable" style="text-align: center;<br />
! scope="col"| s<br />
! scope="col"| y<br />
|-<br />
|0 ||'''in0'''<br />
|-<br />
|1 ||'''in1'''<br />
|}<br />
[[Fișier: Mux2.png]]<br />
<br />
<br />
=== 2 to 1 multiplexer, data-flow description ===<br />
<br />
Use one or more continuous assignments. A ''continuous assignment'' is a single assignment statement attached to an '''assign''' keyword. A continuous assignment updates the value of the RHS variable whenever any variable from the RHS expression changes. The RHS expressions is a logic expression, an expression that employs logic operators.<br />
Logic expressions employ only logic operators.<br />
<br />
{| class="wikitable" style="text-align: center;<br />
! scope="col"| operator<br />
! scope="col"| function<br />
! scope="col"| example<br />
|-<br />
|~ ||not||~a<br />
|-<br />
|& ||and|| a & b<br />
|-<br />
| &#124; ||or|| a &#124; b<br />
|-<br />
|^ ||xor|| a ^ b<br />
|}<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module mux2(<br />
input s,<br />
input [1:0] in,<br />
output y<br />
);<br />
<br />
// dataflow description<br />
assign y = (s & in[1]) | (~s & in[0]);<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
'''Note:''' The variable whose value is updated through a continuous assignment should be declared of type '''wire'''.<br />
<br />
<br />
=== 2 to 1 multiplexer, behavioral description ===<br />
<br />
Uses one or more '''always''' blocks. The template of an '''always''' block is:<br />
<br />
'''always @('''''sensitivity list''''') begin'''<br /><br />
&nbsp;&nbsp;''block of statements''<br /><br />
'''end'''<br />
<br />
For combinational circuits the safest way to declare the sensitivity list is to use the wildcard ('''*''').<br />
It stands for all variables that appear inside RHS expressions of the '''always''' block.<br />
The statements employed may be assignments, conditional assignments and procedural statements ('''if''', '''case''').<br />
The '''always''' block of statements is executed whenever any of the variables from the sensitivity list changes its value. The statements are executed in the exact order in which they appear inside the '''always''' block. <br />
<br />
<syntaxhighlight lang="Verilog"><br />
module mux2(<br />
input s,<br />
input [1:0] in,<br />
output y<br />
);<br />
<br />
// behavioral description with if-else<br />
always @(*) begin<br />
if(s)<br />
y = in[1];<br />
else<br />
y = in[0];<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
'''Note:''' Any variable that gets its value through assignments inside an '''always''' block must be declared of type '''reg'''.<br />
If the variable is also an output of the module, the output is declared as <syntaxhighlight lang="Verilog" inline>output reg</syntaxhighlight>.<br />
<br />
'''Note:''' Bit selection operator ('''[ ]''') is used to select a bit (or a couple of consecutive bits) from a multibit variable. '''in[0]''' is bit 0 from the input vector '''in'''.<br />
<br />
<br />
=== 2 to 1 multiplexer, alternative behavioral description ===<br />
<br />
The same module may be described using different procedural statements. Some descriptions may be higher-level than others. Usually, the higher the level of description, the shorter is the code.<br />
<br />
The codes below show three alternative behavioral descriptions for the above multiplexer:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// behavioral description with case<br />
always @(*) begin<br />
case(s)<br />
0: y = in[0];<br />
1: y = in[1];<br />
endcase<br />
end<br />
</syntaxhighlight><br />
<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// behavioral description with conditional assignment<br />
always @(*) begin<br />
y = s ? in[1] : in[0]; <br />
end<br />
</syntaxhighlight><br />
<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// behavioral description with vector selection<br />
always @(*) begin<br />
y = in[s]; <br />
end<br />
</syntaxhighlight><br />
<br />
'''Note:''' The last two alternatives may be also employed in continuous assignments, because they are single statements. For example vector selection may be used inside an '''assign''' instead of an '''always''': <syntaxhighlight lang="Verilog" inline>assign y = in[s];</syntaxhighlight>.<br />
<br />
<br />
=== 2 to 1 multiplexer, structural description: gate-level === <br />
<br />
The ''gate-level description'' is a structural description that uses only logic gates. Verilog language offers predefined logic gates that may be instantiated in structural descriptions. The verilog gate primitives are '''not''', '''and''', '''nand''', '''or''', '''nor''', '''xor''', and '''xnor'''.<br />
Except for the '''not''' gate, all other primitive gates may have 2, 3 or more inputs.<br />
<br />
All gate primitives are instantiated using the same template: ''gatePrimitiveType'' myGate'''('''''outputConnection, inputConnection1, inputConnection2 ...''''')''' as in the following examples:<br />
<br />
<syntaxhighlight lang="Verilog" inline>not g1(dout, din);</syntaxhighlight> is a '''not''' gate with dout at output and din connected at its input.<br />
<br />
<syntaxhighlight lang="Verilog" inline>nand g2(dout, d1, d2);</syntaxhighlight> is a '''nand''' gate with dout at output and two wires, d1 and d2, connected to its inputs.<br />
<br />
<syntaxhighlight lang="Verilog" inline>nand g3(dout, d1, d2, d3, d4);</syntaxhighlight> is a '''nand''' gate with dout at output and four inputs, connected to d1, d2, d3 and d4.<br />
<br />
[[Fișier: Mux2a.png]]<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module mux2(<br />
input s,<br />
input [1:0] in,<br />
output y<br />
);<br />
<br />
wire s_n;<br />
wire w1;<br />
wire w0;<br />
<br />
// gate-level structural description<br />
not (s_n, s);<br />
and (w1, in[1], s);<br />
and (w0, in[0], s_n);<br />
or (y, w1, w0);<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
<br />
=== 2 to 1 multiplexer, FPGA implementation ===<br />
<br />
Implement one of the previous multiplexer descriptions using 2 buttons (BTN0 and BTN1 ) for the inputs in0 and in1, one switch (SW0) for selection, and one LED (LED0) for the multiplexer output (y):<br />
<br />
[[Fișier: Dic_lab3_mux_fpga.png]]<br />
<br />
The constraints file sets the connections between the mux ports and the FPGA pins.<br />
<br />
<syntaxhighlight><br />
##Switches<br />
set_property -dict { PACKAGE_PIN V2 IOSTANDARD LVCMOS33 } [get_ports { s }]; #SW 0<br />
<br />
##Buttons<br />
set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { in[0] }]; #BTN 0<br />
set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { in[1] }]; #BTN 1<br />
<br />
##LEDs<br />
set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { y }]; #LED 0<br />
</syntaxhighlight><br />
<br />
<br />
== Exercise 2 ==<br />
<br />
Write a testbench for the 2:1 multiplexer, using verilog statements to generate all input combinations. There are 3 input bits: one selection bit, and two input bits to select from. Therefore there are possible 8 input combinations. An exhaustive verification should check the output for all those 8 input combinations:<br />
<br />
{| class="wikitable"<br />
|-<br />
! s !! in[1] !! in[0]<br />
|-<br />
| 0|| 0|| 0<br />
|-<br />
| 0 || 0|| 1<br />
|-<br />
| 0|| 1|| 0<br />
|-<br />
| 0|| 1|| 1<br />
|-<br />
| 1|| 0|| 0<br />
|-<br />
| 1|| 0|| 1<br />
|-<br />
| 1|| 1|| 0<br />
|-<br />
| 1|| 1|| 1<br />
|}<br />
<br />
A convenient way is to generate those 8 combinations in the order in which they appear in the truth table, starting with '''0 0 0''', continuing with '''0 0 1''', '''0 1 0''', a.s.o.<br />
There are many ways to generate such a combination of values for the dut input variables:<br />
<br />
=== simple assignments ===<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
{s, a, b} = 3'b000;<br />
#1 {s, a, b} = 3'b001;<br />
#1 {s, a, b} = 3'b010;<br />
#1 {s, a, b} = 3'b011;<br />
#1 {s, a, b} = 3'b100;<br />
#1 {s, a, b} = 3'b101;<br />
#1 {s, a, b} = 3'b110;<br />
#1 {s, a, b} = 3'b111;<br />
#1 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
<br />
=== for statement ===<br />
Its template is:<br />
<br />
'''for('''''initial_assignment''''';''' ''expression''''';''' ''step_assignment''''')''' ''block of statements'';<br />
<br />
The foor loop is repeated until the ''expression'' evaluates true. The simplest '''for''' statement uses an integer index that is incremented at the end of each iteration.<br />
The for loop below generates all combinations from 000 to 111 for tree logic variables, s, a and b. The index must be declared as a variable of type '''integer'''.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
integer index<br />
initial begin<br />
{s, a, b} = 0;<br />
for(index = 0; index < 8; index = index + 1) begin<br />
#1 {s, a, b} = {s, a, b} + 1;<br />
end<br />
#1 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
<br />
=== repeat statement ===<br />
<br />
Its syntax is '''repeat''' (''number of times'') ''block of statements''<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
{s, a, b} = 0;<br />
repeat (8) #1 {s, a, b} = {s, a, b} + 1;<br />
#1 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
<br />
== Exercise 3 ==<br />
<br />
The half-adder is the simplest, 1-bit, adder. It implements the addition of two bits.<br />
<br />
{| class="wikitable" style="text-align: center;<br />
! scope="col"| a<br />
! scope="col"| b<br />
! scope="col"| s<br />
|-<br />
|0 ||0 || 0 0<br />
|-<br />
|0 ||1 || 0 1<br />
|-<br />
|1 ||0 || 0 1<br />
|-<br />
|1 ||1 || 1 0<br />
|}<br />
<br />
[[Fișier: Dic_lab2_adder.png]]<br />
<br />
This table may be read either as the addition table, with '''s''' considered as a base-2 number value, or it may be read as a truth table, if '''s''' is viewed as a pair of two logic values. Each bit of '''s''' may be computed as a logic function with two arguments.<br />
<br />
=== half adder, data-flow description ===<br />
<br />
Use data flow description with '''assign''' statement for each output. They are concurrent assignments: in simulation they are evaluated in parallel, mimicking the parallelism of the real circuits.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// data-flow description<br />
assign s[0] = a ^ b;<br />
assign s[1] = a & b;<br />
</syntaxhighlight><br />
<br />
'''Note:''' Despite '''s''' being declared as one variable, its bits are separately updated by concurrent assignments. <br />
<br />
<br />
=== half adder, structural description ===<br />
<br />
[[Fișier: half_adder.png]]<br />
<br />
Using gate primitives, a possible structural description of the half-adder may be:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
// gate-level description<br />
xor g1(s[0], a, b);<br />
and g2(s[1], a, b);<br />
</syntaxhighlight><br />
<br />
<br />
== Exercise 4 ==<br />
=== 4 to 1 multiplexer, behavioral description ===<br />
<br />
[[Fișier: mux4.png]]<br />
<br />
'''case''' instruction. Selects between multiple cases. Template<br />
<br />
'''case('''''selectVariable''''')'''<br /><br />
&nbsp;&nbsp;''value1'' ''':''' ''instruction block 1''<br /><br />
&nbsp;&nbsp;''value2'' ''':''' ''instruction block 2''<br /><br />
&nbsp;&nbsp; a.s.o.<br /><br />
'''endcase'''<br />
<br />
''value1'', ''value2'' a.s.o. are integer values of the ''selectVariable''<br />
<br />
<syntaxhighlight lang="Verilog"><br />
case(s)<br />
0: y = in[0];<br />
1: y = in[1];<br />
2: y = in[2];<br />
3: y = in[3];<br />
endcase <br />
</syntaxhighlight><br />
<br />
'''Note:''' As in Exercise 1, a much more compact description is possible with bit selection, <syntaxhighlight lang="Verilog" inline>assign y = in[s];</syntaxhighlight>.<br />
<br />
<br />
== Exercise 5 ==<br />
=== 4 to 1 multiplexer, structural description ===<br />
<br />
[[Fișier: mux4b.png]]<br />
<br />
Implement the 4 to 1 multiplexer using three instances of the 2 to 1 multiplexer (add to the project one of the design source files from Exercise 1).<br />
<br />
Be careful to distinctly name each instance and each internal wire!</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Fi%C8%99ier:Half_adder.png&diff=7505Fișier:Half adder.png2023-03-13T01:12:24Z<p>Zhascsi: Zhascsi a încărcat o versiune nouă pentru Fișier:Half adder.png</p>
<hr />
<div></div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_3&diff=7504Applications 32023-03-12T23:31:23Z<p>Zhascsi: </p>
<hr />
<div>Many ways to describe a module:<br />
* ''Behavioral'' description: Uses one or more '''always''' blocks that encloses procedural statements;<br />
* ''Data-flow'' description: employs parallel continuous assignments ('''assign'''), usually with logic operators;<br />
* ''Structural'' description: sub-blocks (module instances, gate primitives) connected together;<br />
* ''Mixed'' description: combines two or all of the above kinds of description;<br />
<br />
== Exercise 1 ==<br />
=== half adder - gate-level description ===<br />
<br />
The half-adder is the simplest, 1-bit, adder. It implements the addition of two bits.<br />
<br />
{| class="wikitable" style="text-align: center;<br />
! scope="col"| a<br />
! scope="col"| b<br />
! scope="col"| c<br />
|-<br />
|0 ||0 || 0 0<br />
|-<br />
|0 ||1 || 0 1<br />
|-<br />
|1 ||0 || 0 1<br />
|-<br />
|1 ||1 || 1 0<br />
|}<br />
<br />
[[Fișier: app2_sum.png]]<br />
<br />
Use data flow description (a simpler kind of behavioral description that uses logic expressions).<br />
Logic expressions employ only logic operators.<br />
<br />
{| class="wikitable" style="text-align: center;<br />
! scope="col"| operator<br />
! scope="col"| function<br />
|-<br />
|~ ||not<br />
|-<br />
|& ||and<br />
|-<br />
| &#124; ||or<br />
|-<br />
|^ ||xor<br />
|}<br />
<br />
One '''assign''' instruction for each output. Concurrent assignments (in simulation they are evaluated in parallel, mimicking the parallelism of the real circuits)<br />
<br />
<syntaxhighlight lang="Verilog"><br />
assign c[0] = a ^ b;<br />
assign c[1] = a & b;<br />
</syntaxhighlight><br />
<br />
Bit selection operator ('''[ ]''') is used to select a bit (or a couple of consecutive bits) from a multibit variable.<br />
If c is declared as a 2 bit output, each of its bits may be separately controlled. The index must be a positive integer in the range set when the variable was declared.<br />
If myVariable was declared of type <syntaxhighlight lang="Verilog" inline>output [7:0]</syntaxhighlight>, then the integer used for selection must not exceed 7.<br />
<br />
=== repeat statement in testbenches ===<br />
An ''exahaustive test'' is a test that generates all possible combinations of values for the inputs of the dut.<br />
Write a testbench for the half-adder that uses a '''repeat''' statement to generate all input combinations, and a concatenation operator that makes possible to update two or more variables at the same time.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
{a, b} = 0;<br />
repeat (4) #1 {a, b} = {a, b} + 1;<br />
end<br />
</syntaxhighlight><br />
<br />
Some remarks:<br />
* There is no increment operator in verilog.<br />
* Adding 1 to 3 on 2 bits turns around to 0.<br />
* A delay may precede a statement.<br />
<br />
== Exercise 2 ==<br />
=== 1-bit half adder - structural description ===<br />
<br />
Work on the same project as that of Exercise 1. You need only to modify the description of the half-adder module. <br />
<br />
'''Gate-level description''' = a structural description that uses only logic gates.<br />
<br />
Verilog gate primitives: '''not''', '''and''', '''nand''', '''or''', '''nor''', '''xor''' and '''xnor'''.<br />
Except for the '''not''' gate, all other primitive gates may have 2, 3 or more inputs.<br />
<br />
All gate primitives are instantiated using the same template: ''gatePrimitiveType'' myGate'''('''''outputConnection, inputConnection1, inputConnection2 ...''''')''' as in the following examples:<br />
<br />
<syntaxhighlight lang="Verilog" inline>not g1(dout, din);</syntaxhighlight> is a '''not''' gate with dout at output and din connected at its input.<br />
<br />
<syntaxhighlight lang="Verilog" inline>nand g2(dout, d1, d2);</syntaxhighlight> is a '''nand''' gate with dout at output and two wires, d1 and d2, connected to its inputs.<br />
<br />
<syntaxhighlight lang="Verilog" inline>nand g3(dout, d1, d2, d3, d4);</syntaxhighlight> is a '''nand''' gate with dout at output and four inputs, connected to d1, d2, d3 and d4.<br />
<br />
[[Fișier: half_adder.png]]<br />
<br />
Using gate primitives, a possible structural description of the half-adder may be:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
xor g1(c[0], a, b);<br />
and g2(c[1], a, b);<br />
</syntaxhighlight><br />
<br />
Recompile the design file (from the simulator), and restart simulation.<br />
<br />
Implement the design using 2 switches (SW0 and SW1) as inputs a and b, and two LEDs (LED0 and LED1) to show the result, c.<br />
<br />
== Exercise 3 ==<br />
=== 2 to 1 multiplexer, behavioral description ===<br />
<br />
Mux 2:1 (two to one multiplexer) is the simplest selection logic circuit. It selects between two inputs, in0 and in1, according to the value of the selection input, s:<br />
<br />
{| class="wikitable" style="text-align: center;<br />
! scope="col"| s<br />
! scope="col"| y<br />
|-<br />
|0 ||'''in0'''<br />
|-<br />
|1 ||'''in1'''<br />
|}<br />
[[Fișier: Mux2.png]]<br />
<br />
'''always''' block. Used for behavioral descriptions. Template:<br />
<br />
'''always @('''''sensitivity list''''') begin'''<br /><br />
&nbsp;&nbsp;''block of instructions''<br /><br />
'''end'''<br />
<br />
For combinational circuits the safest way to declare the sensitivity list is to use the wildcard ('''*''').<br />
It stands for all variables that appear on RHS expressions and in evaluation expressions.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
always @(*) begin<br />
if(s)<br />
c = in[1];<br />
else<br />
c = in[0];<br />
end<br />
</syntaxhighlight><br />
<br />
Any variable that gets value through assignments inside an '''always''' block must be declared of type '''reg'''.<br />
If the variable is also an output of the module, the output is declared as <syntaxhighlight lang="Verilog" inline>output reg</syntaxhighlight>.<br />
<br />
=== for statement in testbenches ===<br />
Write a testbench using a '''for''' statement to generate all input combinations. Its template is:<br />
<br />
'''for('''''initial_assignment''''';''' ''expression''''';''' ''step_assignment''''')''' ''block of statements'';<br />
<br />
The foor loop is repeated until the ''expression'' evaluates true. The simplest '''for''' statement uses an integer index that is incremented at the end of each iteration.<br />
The for loop below generates all combinations from 000 to 111 for tree logic variables, s, a and b. The index must be declared as a variable of type '''integer'''.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
{s, a, b} = 0;<br />
for(index = 0; index < 8; index = index + 1) begin<br />
#1 {s, a, b} = {s, a, b} + 1;<br />
end<br />
end<br />
</syntaxhighlight><br />
<br />
== Exercise 4 ==<br />
=== 2 to 1 multiplexer - gate-level description ===<br />
<br />
Work on the same project as that of Exercise 3. You need only to modify the description of the 2 to 1 multiplexer module. <br />
<br />
Implement the 2 to 1 multiplexer using only verilog gate primitives. For simulation you may reuse the testbench from Exercise 3 (copy its file into the directory of this project and set it as the testbench). Change the type of the multiplexer's instance in the testbench, if it is different from Exercise 3.<br />
<br />
[[Fișier: Mux2a.png]]<br />
<br />
Recompile the design file (from the simulator), and restart simulation.<br />
<br />
Implement the design using 2 buttons (BTN0 and BTN1 ) for the inputs in0 and in1, one switch (SW0) for selection, and one LED (LED0) for the multiplexer output (c):<br />
<br />
[[Fișier: Dic_lab3_mux_fpga.png]]<br />
<br />
The constraints file sets the connections between the mux ports and the FPGA pins.<br />
Taking the first constraint as an example, fill in the missing port names for the next three constraints:<br />
<br />
<syntaxhighlight><br />
##Switches<br />
set_property -dict { PACKAGE_PIN V2 IOSTANDARD LVCMOS33 } [get_ports { s }]; #SW 0<br />
<br />
##Buttons<br />
set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { in[0] }]; #BTN 0<br />
set_property -dict { PACKAGE_PIN J5 IOSTANDARD LVCMOS33 } [get_ports { in[1] }]; #BTN 1<br />
<br />
##LEDs<br />
set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { y }]; #LED 0<br />
</syntaxhighlight><br />
<br />
== Exercise 5 ==<br />
=== 4 to 1 multiplexer - behavioral description ===<br />
<br />
[[Fișier: mux4.png]]<br />
<br />
'''case''' instruction. Selects between multiple cases. Template<br />
<br />
'''case('''''selectVariable''''')'''<br /><br />
&nbsp;&nbsp;''value1'' ''':''' ''instruction block 1''<br /><br />
&nbsp;&nbsp;''value2'' ''':''' ''instruction block 2''<br /><br />
&nbsp;&nbsp; a.s.o.<br /><br />
'''endcase'''<br />
<br />
''value1'', ''value2'' a.s.o. are integer values of the ''selectVariable''<br />
<br />
<syntaxhighlight lang="Verilog"><br />
case(s)<br />
0: c = in[0];<br />
1: c = in[1];<br />
2: c = in[2];<br />
3: c = in[3];<br />
endcase <br />
</syntaxhighlight><br />
<br />
== Exercise 6 ==<br />
=== 4 to 1 multiplexer - structural description ===<br />
<br />
[[Fișier: mux4b.png]]<br />
<br />
Implement the 4 to 1 multiplexer using three instances of the 2 to 1 multiplexer (add to the project the file of that module either from Exercise 3, or Exercise 4) and a primitive gate.<br />
<br />
Be careful to distinctly name each instance and each internal wire!</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Fi%C8%99ier:Mux4a.png&diff=7503Fișier:Mux4a.png2023-03-12T22:44:11Z<p>Zhascsi: Zhascsi a încărcat o versiune nouă pentru Fișier:Mux4a.png</p>
<hr />
<div></div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Fi%C8%99ier:Mux2.png&diff=7502Fișier:Mux2.png2023-03-12T22:43:31Z<p>Zhascsi: Zhascsi a încărcat o versiune nouă pentru Fișier:Mux2.png</p>
<hr />
<div></div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Fi%C8%99ier:Mux4.png&diff=7501Fișier:Mux4.png2023-03-12T22:42:49Z<p>Zhascsi: Zhascsi a încărcat o versiune nouă pentru Fișier:Mux4.png</p>
<hr />
<div></div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Fi%C8%99ier:Mux2a.png&diff=7500Fișier:Mux2a.png2023-03-12T22:41:57Z<p>Zhascsi: Zhascsi a încărcat o versiune nouă pentru Fișier:Mux2a.png</p>
<hr />
<div></div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Fi%C8%99ier:Mux4b.png&diff=7499Fișier:Mux4b.png2023-03-12T22:40:05Z<p>Zhascsi: Zhascsi a încărcat o versiune nouă pentru Fișier:Mux4b.png</p>
<hr />
<div></div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Fi%C8%99ier:Dic_lab3_mux_fpga.png&diff=7498Fișier:Dic lab3 mux fpga.png2023-03-12T22:32:55Z<p>Zhascsi: Zhascsi a încărcat o versiune nouă pentru Fișier:Dic lab3 mux fpga.png</p>
<hr />
<div></div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Digital_Integrated_Circuits_(lab)&diff=7497Digital Integrated Circuits (lab)2023-03-12T13:16:48Z<p>Zhascsi: </p>
<hr />
<div># [[Applications 1 | Laboratory 1]]<br />
# [[Applications 2 | Laboratory 2]]<br />
<br />
== Verilog Tutorials ==<br />
* [http://www.asic-world.com/verilog/veritut.html Verilog Tutorial] from ASIC World<br />
* [http://chipverify.com/verilog/verilog-tutorial Verilog Tutorial] from Chip Verify<br />
* [http://www.emmelmann.org/Library/Tutorials/docs/verilog_ref_guide/vlog_ref_top.html Verilog reference guide]<br />
<br />
== Software ==<br />
* [https://www.xilinx.com/products/design-tools/vivado/vivado-ml.html Vivado™ ML Standard Edition free]<br />
* [https://wiki.dcae.pub.ro/images/2/24/VivadoNewProjectTutorial.pdf Vivado New Project Tutorial]<br />
<br />
== Hardware ==<br />
* [https://dpoauwgwqsy2x.cloudfront.net/Download/pynqz2_user_manual_v1_0.pdf Pynq-Z2 - user manual]<br />
* [[Pynq-Z2 - Pinout]].<br />
<br />
* [https://www.realdigital.org/doc/02013cd17602c8af749f00561f88ae21 Boolean Board - user manual]<br />
* [[Boolean Board - Pinout]].</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_2&diff=7496Applications 22023-03-12T12:11:08Z<p>Zhascsi: /* Exercise 4 */</p>
<hr />
<div>=== Exercise 1 : 1 bit adder ===<br />
<br />
==== Module declaration ====<br />
<br />
[[Fișier: Dic_lab2_adder.png]]<br />
<br />
Any Verilog circuit or block is enclosed within the keywords '''module''' and '''endmodule'''.<br />
The '''module''' keyword is followed by the name of the module. This name begins with a letter (Verilog is case-sensitive) or underscore (''_''), uses alphanumeric characters and underscores, and should be a meaningful one (adder, adder_32, counter, lshift_register, Serial_to_Parallel_converter, etc).<br />
<br />
Right after the module name comes the interface description, a list of port declarations, separated by commas and enclosed within parentheses. It is strongly recommended to declare each port on a separate line, even if some ports have the same direction and size. Also it is recommended to group the declarations by their direction.<br />
A port declaration starts with the keyword that defines the port's direction: '''input''' or '''output'''. For one-bit ports the declaration comprises only the direction and the name.<br />
Port names follow the same naming rules used for module names. A port name should be a unique identifier inside the module's code - its scope is limited to the module.<br />
<br />
A multi-bit port declaration defines the width of the port through two indices within brackets and separated by a colon: '''['''''msb''''':'''''lsb''''']'''. The first index denotes the most significant bit (MSB), the second one is the least significant bit. MSB should always be greater than MSB. Usually the LSB index is 0, therefore if the width of the port is ''N'', the first index would be ''N-1''.<br />
<br />
The module declaration comprises the keyword '''module''', the module name and its interface, and ends with a semicolon:<br />
<syntaxhighlight lang="Verilog"><br />
module adder ( // keyword '''module''' followed by the module's name and the opening parenthesis of the interface<br />
input a, // one-bit input port named 'a'<br />
input b, // one-bit input port named 'b'<br />
output [1:0] s // two-bit output port. Bit 1 is MSB, bit 0 is LSB. There is no comma after the last port declaration<br />
); // the closing parenthesis of the interface and the semicolon that ends the module's declaration<br />
</syntaxhighlight><br />
<br />
'''Note:''' All input ports should be variables of '''wire''' type. The '''wire''' type is therefore implicit for port declaration, and may be ommited.<br />
If the output port variable has no explicit type, it is also implicitly of the '''wire''' type.<br />
<br />
==== Module description ====<br />
Anything written between the module's declaration and the keyword '''endmodule''' is part of the module's description.<br />
<br />
A module may be described by ''what'' it does. This is a ''behavioral description''.<br />
Very simple modules could be described using a single instruction, that assigns to the output the result value of an expression over the inputs. Because Verilog is a description language, not a programming language, the assignments that describe how logic values are generated from other logic values are attached to special Verilog keywords. One such keyword is '''assign'''. It is followed by a single assignment: '''assign''' ''y = E(x1, x2, ... xN)''; It is forbidden to use the left-hand variable (''y'') inside the right-hand expression.<br />
<br />
The one-bit adder may be described by a simple expression that computes the output value as the addition of its inputs:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
assign s = a + b; // variable value s is always equal to the sum of a and b <br />
</syntaxhighlight><br />
<br />
The '''assign''' statement describes something that is continuously evaluated. It may be viewed as a small black box with an output and some inputs. The left-hand variable is updated immediately whenever any of the variables in the right-hand expression changes its value. The physical circuit that implements the '''assign''' statement is a combinational logic circuit (CLC) that reacts immediately to any change at its inputs.<br />
<br />
The full code of the ''adder'' module:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder (<br />
input a,<br />
input b,<br />
output [1:0] s<br />
);<br />
<br />
assign s = a + b;<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Testbench module ====<br />
<br />
[[Fișier: Dic_lab2_adder_tb.png]]<br />
<br />
The testbench is another module, therefore it is defined in a separate file. Also, the testbench is a simulation file - it cannot be synthesized and implemented.<br />
Always follow these rules:<br />
* each module is defined in a separate file<br />
* the name of the file is the name of the module, or closely resembles it<br />
<br />
The testbench has no interface. All signals are generated internally. Therefore the testbench declaration has an empty interface list, '''module''' ''testbenchName'''''();''', or the parentheses may be missing at all, '''module''' ''testbenchName''''';'''<br />
<br />
It is recommended to include in the name of the testbench the name of the module to be tested. The testbench for the ''adder'' module may be named ''adder_testbench'', ''test_adder'', ''adder_tb'', a.s.o.<br />
<br />
As for any module, the description follows the module declaration.<br />
The testbench ''instantiates'' the module to be tested and generates values for the signals connected to the inputs of the tested module. The testbench is used only in simulation, it cannot be synthesized. However, this restriction is turned to an advantage because the testbench may use procedural statements freely, as in ordinary programming languages, to generate whatever sequence of values for the stimuli is desired.<br />
<br />
The DUT (device under test) is a block inside the testbench module. It is an ''instance'' of a module. The module is like a blueprint, while the instance is a materialization of that blueprint. For those familiar with object-oriented programming this may sound familiar. The module is like a class, and the instance is an object of that type.<br />
<br />
A module instantiation starts with the ''moduleName'' followed by the ''instanceName'' and the list of its external connections enclosed within parentheses.<br />
Usually, the module instantiated in the testbench is named ''dut'' (device under test). The instance name should be a unique name inside the module where it's instantiated.<br />
<br />
The list of connections connects each port of the instance to a signal of the testbench. It is strongly recommended to write each connection on a separate line. You may write the connections in the same order as in the interface declaration for that module. You should have at most ONE connection for each port, but some ports may be leaved unconnected if they are not used. A connection is declared with a dot ('''.''') immediately followed by the name of the port and finally the name of the signal connected to that port, enclosed in parentheses: '''.'''''modulePin'''''('''''varName''''')'''<br />
. The connections in the list are separated by commas.<br />
<br />
The ''adder'' module is instantiated with the name ''dut''. Its inputs receive signals ''num1'' and ''num2'', and its output is connected to a wire named ''result'':<br />
<br />
<syntaxhighlight lang="Verilog"><br />
adder dut ( // a module of type 'adder' is instantiated. The name of this instance is 'dut'<br />
.a (num1 ), // port 'a' is connected to signal 'num1'<br />
.b (num2 ), // port 'b' is connected to signal 'num2'<br />
.s (result) // port 's' is connected to 'result'. There is no comma after the last connection<br />
); // the closing parenthesis of the interface and the semicolon that ends the module's instantiation<br />
</syntaxhighlight><br />
<br />
All signals and wires connected to an instance should be declared, and the declarations should precede the instantiation.<br />
<br />
The signals connected to the instance inputs are stimuli generated by the testbench. They should be declared as variables of type '''reg'''. The instance outputs should be declared as variables of type '''wire'''. The variable declaration begins with the type ('''reg''' or '''wire''') and ends with the variable's name. We strongly recommend to declare each variable in a separate line. Also, you should NOT initialize a variable in the declaration statement (keep in mind that Verilog is a description language, not a programming language).<br />
For the multi-bit signals the declaration must specify the width, in the same way you declare the width of a multi-bit port in the interface of a module.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
reg num1; // one-bit variable of type reg and named 'num1'<br />
reg num2; // one-bit variable of type reg and named 'num2'<br />
wire [1:0] result; // two-bit variable of type wire and named 'result'<br />
</syntaxhighlight><br />
<br />
As a rule of thumb, keep in mind that any output of an instance could be declared only as a wire, whereas the inputs to an instance are declared of type '''reg''' if you give them values using explicit assignment statements.<br />
<br />
The stimuli for the ''adder'' block are generated as in Laboratory 1, using a Verilog '''initial''' block, inside which you assign values to signals ''num1'' and ''num2''. To thoroughly test the ''adder'' block it is useful to generate all possible combinations of values for those two signals. One such sequence of binary value pairs may be ''00'', ''01'', ''10'', ''11'':<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
num1 = 1'b0; num2 = 1'b0; // begin with both adder inputs zero<br />
#5 num1 = 1'b0; num2 = 1'b1; // after a delay, change the value of one input of the adder<br />
#5 num1 = 1'b1; num2 = 1'b0; // go to the next combination of values<br />
#5 num1 = 1'b1; num2 = 1'b1;<br />
#5 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
'''Note:''' as in Laboratory 1, you may generate the values for ''num1'' and ''num2'' in a single statement, combining them into one two-bit bundle (for example <syntaxhighlight lang="Verilog">{num1, num2} = 2'b01;</syntaxhighlight>)<br />
<br />
The full code of the ''adder'' testbench module:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder_tb;<br />
<br />
// declarations<br />
reg num1;<br />
reg num2;<br />
wire [1:0] result;<br />
<br />
// instantion<br />
adder dut (<br />
.a (num1 ),<br />
.b (num2 ),<br />
.s (result)<br />
); <br />
<br />
// stimuli generation<br />
initial begin<br />
{num1, num2} = 2'b00;<br />
#5 {num1, num2} = 2'b01;<br />
#5 {num1, num2} = 2'b10;<br />
#5 {num1, num2} = 2'b11;<br />
#5 $stop;<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Module simulation ====<br />
<br />
Simulate the ''adder_tb'' testbench and check on the waveforms that the output of the ''adder'' module is indeed the sum of its input values.<br />
<br />
=== Exercise 2 : 2 bit adder ===<br />
<br />
[[Fișier: Dic_lab2_adder2.png]]<br />
<br />
==== design module ====<br />
<br />
The 2 bit adder has almost the same interface as the 1 bit adder. All names are the same, only their widths are different. The inputs are 2 bits wide, the output has 3 bits, to accommodate the biggest possible result (3 + 3 = 6).<br />
Since the description is high-level, employing the add operator, it is exactly the same as for the previous adder.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder2 (<br />
input [1:0] a,<br />
input [1:0] b,<br />
output [2:0] s<br />
);<br />
<br />
assign s = a + b;<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== simulation module ====<br />
<br />
The 2 bit adder module has two inputs of 2 bits each. That means there are more input combinations to be tested, actually 16 (4 values for the one input, and 4 values for the other one). To run through all those 16 combinations the pair of statements '''num1 ='''''value1''; '''num2 ='''''value2''; may be employed 16 times with different values.<br />
If the combinations are generated in a systematic way (for example in the increasing order of the input values), a '''for''' statement is more convenient.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder2_tb;<br />
<br />
// declarations<br />
reg [1:0] num1;<br />
reg [1:0] num2;<br />
wire [2:0] result;<br />
<br />
// instantion of a 2 bit adder<br />
adder2 dut (<br />
.a (num1 ),<br />
.b (num2 ),<br />
.s (result)<br />
); <br />
<br />
// stimuli generation<br />
integer i; // integer type variable used to control the for loop<br />
initial begin<br />
{num1, num2} = 0; // initial values of the adder2 inputs<br />
for(i = 0; i < 16; i = i + 1) // the control variable runs from 0 to 15. After the last iteration it is incremented (again) to 16 and the loop is terminated.<br />
#5 {num1, num2} = {num1, num2} + 1; // a nonzero delay is mandatory to ensure that each combination lasts at least one simulation step.<br />
#5 $stop;<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Implementation ====<br />
<br />
To implement the adder on the FPGA and to interact with it we should imagine some means to set and to change the adder input values and to see the value of its output. The FPGA board allows us to interact with the circuit implemented inside the FPGA through switches, push buttons and various LEDs that are connected to FPGA pins, which may be configured to be wired inside the FPGA to the ports of the implemented module. The FPGA pins assignment is done through the constraints file. For each pin assignment there is a line that instructs the implementation tool to connect the port with a given name to a particular FPGA pin, and also sets the parameters of the I/O pad of that pin. For example<br />
<br />
<syntaxhighlight><br />
set_property -dict { PACKAGE_PIN T2 IOSTANDARD LVCMOS33 } [get_ports { a[1] }];<br />
</syntaxhighlight><br />
<br />
is a constraint that connects the first bit of a input to the FPGA pin labelled T2.<br />
<br />
'''Note:''' For each FPGA board you may find constraints files with constraints for all FPGA pins, with indications as to which switch, button, LED, a.s.o. is connected to which FPGA pin. All constraints are commented. You should uncomment only the lines for the switches, buttons, LEDs a.s.o. that you want to use, and replace the port names with the names of ports from your module. For multi-bit ports there must be one separate connection constraint for each port bit, since each port bit needs a separate FPGA pin.<br />
<br />
The 2 bit adder will be tested using four switches to set the input values, and three LEDs to show the output 3-bit value:<br />
<br />
[[Fișier: Dic_lab2_adder_fpga.png]]<br />
<br />
<syntaxhighlight><br />
##Switches<br />
set_property -dict { PACKAGE_PIN T2 IOSTANDARD LVCMOS33 } [get_ports { a[1] }]; #SW 3<br />
set_property -dict { PACKAGE_PIN U1 IOSTANDARD LVCMOS33 } [get_ports { a[0] }]; #SW 2<br />
set_property -dict { PACKAGE_PIN U2 IOSTANDARD LVCMOS33 } [get_ports { b[1] }]; #SW 1<br />
set_property -dict { PACKAGE_PIN V2 IOSTANDARD LVCMOS33 } [get_ports { b[0] }]; #SW 0<br />
<br />
##LEDs<br />
set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { s[0] }]; #LED 0<br />
set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { s[1] }]; #LED 1<br />
set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { s[2] }]; #LED 2<br />
</syntaxhighlight><br />
<br />
=== Exercise 3 ===<br />
design and verify in simulation a 2 by 2 bit multiplier. The output has 4 bits, to cover the whole range of the multiplication. The biggest output value is 9 (= 3 x 3).<br />
The description is behavioral, using the multiplication operator.<br />
<br />
[[Fișier: app2_mult.png]]<br />
<br />
=== Exercise 4 ===<br />
Design a source file for top-level entity. It instantiates two 1 bit adder modules (desined in Exercise 1) and one multiplier module from Exercise 3.<br />
The whole circuit has a multilevel hierarchy with mixed description: the top-level has a ''structural description'', while the low-level blocks have ''behavioral descriptions''.<br />
<br />
'''Note:''' If two or more instances of the same module appear inside another module description, they should have distinct instance names. Each instance should be uniquely identified.<br />
<br />
'''Note:''' The structural description has instances and wires that connect the instances between them, and to the ports.<br />
<br />
[[Fișier: app2_multsum.png]]<br />
<br />
Write a testbench source file for the top-level entity.</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_2&diff=7495Applications 22023-03-08T00:58:23Z<p>Zhascsi: /* Exercise 4 */</p>
<hr />
<div>=== Exercise 1 : 1 bit adder ===<br />
<br />
==== Module declaration ====<br />
<br />
[[Fișier: Dic_lab2_adder.png]]<br />
<br />
Any Verilog circuit or block is enclosed within the keywords '''module''' and '''endmodule'''.<br />
The '''module''' keyword is followed by the name of the module. This name begins with a letter (Verilog is case-sensitive) or underscore (''_''), uses alphanumeric characters and underscores, and should be a meaningful one (adder, adder_32, counter, lshift_register, Serial_to_Parallel_converter, etc).<br />
<br />
Right after the module name comes the interface description, a list of port declarations, separated by commas and enclosed within parentheses. It is strongly recommended to declare each port on a separate line, even if some ports have the same direction and size. Also it is recommended to group the declarations by their direction.<br />
A port declaration starts with the keyword that defines the port's direction: '''input''' or '''output'''. For one-bit ports the declaration comprises only the direction and the name.<br />
Port names follow the same naming rules used for module names. A port name should be a unique identifier inside the module's code - its scope is limited to the module.<br />
<br />
A multi-bit port declaration defines the width of the port through two indices within brackets and separated by a colon: '''['''''msb''''':'''''lsb''''']'''. The first index denotes the most significant bit (MSB), the second one is the least significant bit. MSB should always be greater than MSB. Usually the LSB index is 0, therefore if the width of the port is ''N'', the first index would be ''N-1''.<br />
<br />
The module declaration comprises the keyword '''module''', the module name and its interface, and ends with a semicolon:<br />
<syntaxhighlight lang="Verilog"><br />
module adder ( // keyword '''module''' followed by the module's name and the opening parenthesis of the interface<br />
input a, // one-bit input port named 'a'<br />
input b, // one-bit input port named 'b'<br />
output [1:0] s // two-bit output port. Bit 1 is MSB, bit 0 is LSB. There is no comma after the last port declaration<br />
); // the closing parenthesis of the interface and the semicolon that ends the module's declaration<br />
</syntaxhighlight><br />
<br />
'''Note:''' All input ports should be variables of '''wire''' type. The '''wire''' type is therefore implicit for port declaration, and may be ommited.<br />
If the output port variable has no explicit type, it is also implicitly of the '''wire''' type.<br />
<br />
==== Module description ====<br />
Anything written between the module's declaration and the keyword '''endmodule''' is part of the module's description.<br />
<br />
A module may be described by ''what'' it does. This is a ''behavioral description''.<br />
Very simple modules could be described using a single instruction, that assigns to the output the result value of an expression over the inputs. Because Verilog is a description language, not a programming language, the assignments that describe how logic values are generated from other logic values are attached to special Verilog keywords. One such keyword is '''assign'''. It is followed by a single assignment: '''assign''' ''y = E(x1, x2, ... xN)''; It is forbidden to use the left-hand variable (''y'') inside the right-hand expression.<br />
<br />
The one-bit adder may be described by a simple expression that computes the output value as the addition of its inputs:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
assign s = a + b; // variable value s is always equal to the sum of a and b <br />
</syntaxhighlight><br />
<br />
The '''assign''' statement describes something that is continuously evaluated. It may be viewed as a small black box with an output and some inputs. The left-hand variable is updated immediately whenever any of the variables in the right-hand expression changes its value. The physical circuit that implements the '''assign''' statement is a combinational logic circuit (CLC) that reacts immediately to any change at its inputs.<br />
<br />
The full code of the ''adder'' module:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder (<br />
input a,<br />
input b,<br />
output [1:0] s<br />
);<br />
<br />
assign s = a + b;<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Testbench module ====<br />
<br />
[[Fișier: Dic_lab2_adder_tb.png]]<br />
<br />
The testbench is another module, therefore it is defined in a separate file. Also, the testbench is a simulation file - it cannot be synthesized and implemented.<br />
Always follow these rules:<br />
* each module is defined in a separate file<br />
* the name of the file is the name of the module, or closely resembles it<br />
<br />
The testbench has no interface. All signals are generated internally. Therefore the testbench declaration has an empty interface list, '''module''' ''testbenchName'''''();''', or the parentheses may be missing at all, '''module''' ''testbenchName''''';'''<br />
<br />
It is recommended to include in the name of the testbench the name of the module to be tested. The testbench for the ''adder'' module may be named ''adder_testbench'', ''test_adder'', ''adder_tb'', a.s.o.<br />
<br />
As for any module, the description follows the module declaration.<br />
The testbench ''instantiates'' the module to be tested and generates values for the signals connected to the inputs of the tested module. The testbench is used only in simulation, it cannot be synthesized. However, this restriction is turned to an advantage because the testbench may use procedural statements freely, as in ordinary programming languages, to generate whatever sequence of values for the stimuli is desired.<br />
<br />
The DUT (device under test) is a block inside the testbench module. It is an ''instance'' of a module. The module is like a blueprint, while the instance is a materialization of that blueprint. For those familiar with object-oriented programming this may sound familiar. The module is like a class, and the instance is an object of that type.<br />
<br />
A module instantiation starts with the ''moduleName'' followed by the ''instanceName'' and the list of its external connections enclosed within parentheses.<br />
Usually, the module instantiated in the testbench is named ''dut'' (device under test). The instance name should be a unique name inside the module where it's instantiated.<br />
<br />
The list of connections connects each port of the instance to a signal of the testbench. It is strongly recommended to write each connection on a separate line. You may write the connections in the same order as in the interface declaration for that module. You should have at most ONE connection for each port, but some ports may be leaved unconnected if they are not used. A connection is declared with a dot ('''.''') immediately followed by the name of the port and finally the name of the signal connected to that port, enclosed in parentheses: '''.'''''modulePin'''''('''''varName''''')'''<br />
. The connections in the list are separated by commas.<br />
<br />
The ''adder'' module is instantiated with the name ''dut''. Its inputs receive signals ''num1'' and ''num2'', and its output is connected to a wire named ''result'':<br />
<br />
<syntaxhighlight lang="Verilog"><br />
adder dut ( // a module of type 'adder' is instantiated. The name of this instance is 'dut'<br />
.a (num1 ), // port 'a' is connected to signal 'num1'<br />
.b (num2 ), // port 'b' is connected to signal 'num2'<br />
.s (result) // port 's' is connected to 'result'. There is no comma after the last connection<br />
); // the closing parenthesis of the interface and the semicolon that ends the module's instantiation<br />
</syntaxhighlight><br />
<br />
All signals and wires connected to an instance should be declared, and the declarations should precede the instantiation.<br />
<br />
The signals connected to the instance inputs are stimuli generated by the testbench. They should be declared as variables of type '''reg'''. The instance outputs should be declared as variables of type '''wire'''. The variable declaration begins with the type ('''reg''' or '''wire''') and ends with the variable's name. We strongly recommend to declare each variable in a separate line. Also, you should NOT initialize a variable in the declaration statement (keep in mind that Verilog is a description language, not a programming language).<br />
For the multi-bit signals the declaration must specify the width, in the same way you declare the width of a multi-bit port in the interface of a module.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
reg num1; // one-bit variable of type reg and named 'num1'<br />
reg num2; // one-bit variable of type reg and named 'num2'<br />
wire [1:0] result; // two-bit variable of type wire and named 'result'<br />
</syntaxhighlight><br />
<br />
As a rule of thumb, keep in mind that any output of an instance could be declared only as a wire, whereas the inputs to an instance are declared of type '''reg''' if you give them values using explicit assignment statements.<br />
<br />
The stimuli for the ''adder'' block are generated as in Laboratory 1, using a Verilog '''initial''' block, inside which you assign values to signals ''num1'' and ''num2''. To thoroughly test the ''adder'' block it is useful to generate all possible combinations of values for those two signals. One such sequence of binary value pairs may be ''00'', ''01'', ''10'', ''11'':<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
num1 = 1'b0; num2 = 1'b0; // begin with both adder inputs zero<br />
#5 num1 = 1'b0; num2 = 1'b1; // after a delay, change the value of one input of the adder<br />
#5 num1 = 1'b1; num2 = 1'b0; // go to the next combination of values<br />
#5 num1 = 1'b1; num2 = 1'b1;<br />
#5 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
'''Note:''' as in Laboratory 1, you may generate the values for ''num1'' and ''num2'' in a single statement, combining them into one two-bit bundle (for example <syntaxhighlight lang="Verilog">{num1, num2} = 2'b01;</syntaxhighlight>)<br />
<br />
The full code of the ''adder'' testbench module:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder_tb;<br />
<br />
// declarations<br />
reg num1;<br />
reg num2;<br />
wire [1:0] result;<br />
<br />
// instantion<br />
adder dut (<br />
.a (num1 ),<br />
.b (num2 ),<br />
.s (result)<br />
); <br />
<br />
// stimuli generation<br />
initial begin<br />
{num1, num2} = 2'b00;<br />
#5 {num1, num2} = 2'b01;<br />
#5 {num1, num2} = 2'b10;<br />
#5 {num1, num2} = 2'b11;<br />
#5 $stop;<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Module simulation ====<br />
<br />
Simulate the ''adder_tb'' testbench and check on the waveforms that the output of the ''adder'' module is indeed the sum of its input values.<br />
<br />
=== Exercise 2 : 2 bit adder ===<br />
<br />
[[Fișier: Dic_lab2_adder2.png]]<br />
<br />
==== design module ====<br />
<br />
The 2 bit adder has almost the same interface as the 1 bit adder. All names are the same, only their widths are different. The inputs are 2 bits wide, the output has 3 bits, to accommodate the biggest possible result (3 + 3 = 6).<br />
Since the description is high-level, employing the add operator, it is exactly the same as for the previous adder.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder2 (<br />
input [1:0] a,<br />
input [1:0] b,<br />
output [2:0] s<br />
);<br />
<br />
assign s = a + b;<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== simulation module ====<br />
<br />
The 2 bit adder module has two inputs of 2 bits each. That means there are more input combinations to be tested, actually 16 (4 values for the one input, and 4 values for the other one). To run through all those 16 combinations the pair of statements '''num1 ='''''value1''; '''num2 ='''''value2''; may be employed 16 times with different values.<br />
If the combinations are generated in a systematic way (for example in the increasing order of the input values), a '''for''' statement is more convenient.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder2_tb;<br />
<br />
// declarations<br />
reg [1:0] num1;<br />
reg [1:0] num2;<br />
wire [2:0] result;<br />
<br />
// instantion of a 2 bit adder<br />
adder2 dut (<br />
.a (num1 ),<br />
.b (num2 ),<br />
.s (result)<br />
); <br />
<br />
// stimuli generation<br />
integer i; // integer type variable used to control the for loop<br />
initial begin<br />
{num1, num2} = 0; // initial values of the adder2 inputs<br />
for(i = 0; i < 16; i = i + 1) // the control variable runs from 0 to 15. After the last iteration it is incremented (again) to 16 and the loop is terminated.<br />
#5 {num1, num2} = {num1, num2} + 1; // a nonzero delay is mandatory to ensure that each combination lasts at least one simulation step.<br />
#5 $stop;<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Implementation ====<br />
<br />
To implement the adder on the FPGA and to interact with it we should imagine some means to set and to change the adder input values and to see the value of its output. The FPGA board allows us to interact with the circuit implemented inside the FPGA through switches, push buttons and various LEDs that are connected to FPGA pins, which may be configured to be wired inside the FPGA to the ports of the implemented module. The FPGA pins assignment is done through the constraints file. For each pin assignment there is a line that instructs the implementation tool to connect the port with a given name to a particular FPGA pin, and also sets the parameters of the I/O pad of that pin. For example<br />
<br />
<syntaxhighlight><br />
set_property -dict { PACKAGE_PIN T2 IOSTANDARD LVCMOS33 } [get_ports { a[1] }];<br />
</syntaxhighlight><br />
<br />
is a constraint that connects the first bit of a input to the FPGA pin labelled T2.<br />
<br />
'''Note:''' For each FPGA board you may find constraints files with constraints for all FPGA pins, with indications as to which switch, button, LED, a.s.o. is connected to which FPGA pin. All constraints are commented. You should uncomment only the lines for the switches, buttons, LEDs a.s.o. that you want to use, and replace the port names with the names of ports from your module. For multi-bit ports there must be one separate connection constraint for each port bit, since each port bit needs a separate FPGA pin.<br />
<br />
The 2 bit adder will be tested using four switches to set the input values, and three LEDs to show the output 3-bit value:<br />
<br />
[[Fișier: Dic_lab2_adder_fpga.png]]<br />
<br />
<syntaxhighlight><br />
##Switches<br />
set_property -dict { PACKAGE_PIN T2 IOSTANDARD LVCMOS33 } [get_ports { a[1] }]; #SW 3<br />
set_property -dict { PACKAGE_PIN U1 IOSTANDARD LVCMOS33 } [get_ports { a[0] }]; #SW 2<br />
set_property -dict { PACKAGE_PIN U2 IOSTANDARD LVCMOS33 } [get_ports { b[1] }]; #SW 1<br />
set_property -dict { PACKAGE_PIN V2 IOSTANDARD LVCMOS33 } [get_ports { b[0] }]; #SW 0<br />
<br />
##LEDs<br />
set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { s[0] }]; #LED 0<br />
set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { s[1] }]; #LED 1<br />
set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { s[2] }]; #LED 2<br />
</syntaxhighlight><br />
<br />
=== Exercise 3 ===<br />
design and verify in simulation a 2 by 2 bit multiplier. The output has 4 bits, to cover the whole range of the multiplication. The biggest output value is 9 (= 3 x 3).<br />
The description is behavioral, using the multiplication operator.<br />
<br />
[[Fișier: app2_mult.png]]<br />
<br />
=== Exercise 4 ===<br />
Design a source file for top-level entity. It instantiates two 1 bit adder modules (desined in Exercise 1) and one multiplier module from Exercise 3.<br />
The whole circuit has a multilevel hierarchy with mixed description: the top-level has a ''structural description'', while the low-level blocks have ''behavioral descriptions''.<br />
<br />
'''Note:''' If two or more instances of the same module appear inside another module desciption, they should have distinct instance names. Each instance should be uniquely identified.<br />
'''Note:''' The structural description has instances and wires that connect the instances between them and to the ports.<br />
<br />
[[Fișier: app2_multsum.png]]<br />
<br />
Write a testbench source file for the top-level entity.</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_2&diff=7494Applications 22023-03-08T00:50:13Z<p>Zhascsi: /* Implementation */</p>
<hr />
<div>=== Exercise 1 : 1 bit adder ===<br />
<br />
==== Module declaration ====<br />
<br />
[[Fișier: Dic_lab2_adder.png]]<br />
<br />
Any Verilog circuit or block is enclosed within the keywords '''module''' and '''endmodule'''.<br />
The '''module''' keyword is followed by the name of the module. This name begins with a letter (Verilog is case-sensitive) or underscore (''_''), uses alphanumeric characters and underscores, and should be a meaningful one (adder, adder_32, counter, lshift_register, Serial_to_Parallel_converter, etc).<br />
<br />
Right after the module name comes the interface description, a list of port declarations, separated by commas and enclosed within parentheses. It is strongly recommended to declare each port on a separate line, even if some ports have the same direction and size. Also it is recommended to group the declarations by their direction.<br />
A port declaration starts with the keyword that defines the port's direction: '''input''' or '''output'''. For one-bit ports the declaration comprises only the direction and the name.<br />
Port names follow the same naming rules used for module names. A port name should be a unique identifier inside the module's code - its scope is limited to the module.<br />
<br />
A multi-bit port declaration defines the width of the port through two indices within brackets and separated by a colon: '''['''''msb''''':'''''lsb''''']'''. The first index denotes the most significant bit (MSB), the second one is the least significant bit. MSB should always be greater than MSB. Usually the LSB index is 0, therefore if the width of the port is ''N'', the first index would be ''N-1''.<br />
<br />
The module declaration comprises the keyword '''module''', the module name and its interface, and ends with a semicolon:<br />
<syntaxhighlight lang="Verilog"><br />
module adder ( // keyword '''module''' followed by the module's name and the opening parenthesis of the interface<br />
input a, // one-bit input port named 'a'<br />
input b, // one-bit input port named 'b'<br />
output [1:0] s // two-bit output port. Bit 1 is MSB, bit 0 is LSB. There is no comma after the last port declaration<br />
); // the closing parenthesis of the interface and the semicolon that ends the module's declaration<br />
</syntaxhighlight><br />
<br />
'''Note:''' All input ports should be variables of '''wire''' type. The '''wire''' type is therefore implicit for port declaration, and may be ommited.<br />
If the output port variable has no explicit type, it is also implicitly of the '''wire''' type.<br />
<br />
==== Module description ====<br />
Anything written between the module's declaration and the keyword '''endmodule''' is part of the module's description.<br />
<br />
A module may be described by ''what'' it does. This is a ''behavioral description''.<br />
Very simple modules could be described using a single instruction, that assigns to the output the result value of an expression over the inputs. Because Verilog is a description language, not a programming language, the assignments that describe how logic values are generated from other logic values are attached to special Verilog keywords. One such keyword is '''assign'''. It is followed by a single assignment: '''assign''' ''y = E(x1, x2, ... xN)''; It is forbidden to use the left-hand variable (''y'') inside the right-hand expression.<br />
<br />
The one-bit adder may be described by a simple expression that computes the output value as the addition of its inputs:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
assign s = a + b; // variable value s is always equal to the sum of a and b <br />
</syntaxhighlight><br />
<br />
The '''assign''' statement describes something that is continuously evaluated. It may be viewed as a small black box with an output and some inputs. The left-hand variable is updated immediately whenever any of the variables in the right-hand expression changes its value. The physical circuit that implements the '''assign''' statement is a combinational logic circuit (CLC) that reacts immediately to any change at its inputs.<br />
<br />
The full code of the ''adder'' module:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder (<br />
input a,<br />
input b,<br />
output [1:0] s<br />
);<br />
<br />
assign s = a + b;<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Testbench module ====<br />
<br />
[[Fișier: Dic_lab2_adder_tb.png]]<br />
<br />
The testbench is another module, therefore it is defined in a separate file. Also, the testbench is a simulation file - it cannot be synthesized and implemented.<br />
Always follow these rules:<br />
* each module is defined in a separate file<br />
* the name of the file is the name of the module, or closely resembles it<br />
<br />
The testbench has no interface. All signals are generated internally. Therefore the testbench declaration has an empty interface list, '''module''' ''testbenchName'''''();''', or the parentheses may be missing at all, '''module''' ''testbenchName''''';'''<br />
<br />
It is recommended to include in the name of the testbench the name of the module to be tested. The testbench for the ''adder'' module may be named ''adder_testbench'', ''test_adder'', ''adder_tb'', a.s.o.<br />
<br />
As for any module, the description follows the module declaration.<br />
The testbench ''instantiates'' the module to be tested and generates values for the signals connected to the inputs of the tested module. The testbench is used only in simulation, it cannot be synthesized. However, this restriction is turned to an advantage because the testbench may use procedural statements freely, as in ordinary programming languages, to generate whatever sequence of values for the stimuli is desired.<br />
<br />
The DUT (device under test) is a block inside the testbench module. It is an ''instance'' of a module. The module is like a blueprint, while the instance is a materialization of that blueprint. For those familiar with object-oriented programming this may sound familiar. The module is like a class, and the instance is an object of that type.<br />
<br />
A module instantiation starts with the ''moduleName'' followed by the ''instanceName'' and the list of its external connections enclosed within parentheses.<br />
Usually, the module instantiated in the testbench is named ''dut'' (device under test). The instance name should be a unique name inside the module where it's instantiated.<br />
<br />
The list of connections connects each port of the instance to a signal of the testbench. It is strongly recommended to write each connection on a separate line. You may write the connections in the same order as in the interface declaration for that module. You should have at most ONE connection for each port, but some ports may be leaved unconnected if they are not used. A connection is declared with a dot ('''.''') immediately followed by the name of the port and finally the name of the signal connected to that port, enclosed in parentheses: '''.'''''modulePin'''''('''''varName''''')'''<br />
. The connections in the list are separated by commas.<br />
<br />
The ''adder'' module is instantiated with the name ''dut''. Its inputs receive signals ''num1'' and ''num2'', and its output is connected to a wire named ''result'':<br />
<br />
<syntaxhighlight lang="Verilog"><br />
adder dut ( // a module of type 'adder' is instantiated. The name of this instance is 'dut'<br />
.a (num1 ), // port 'a' is connected to signal 'num1'<br />
.b (num2 ), // port 'b' is connected to signal 'num2'<br />
.s (result) // port 's' is connected to 'result'. There is no comma after the last connection<br />
); // the closing parenthesis of the interface and the semicolon that ends the module's instantiation<br />
</syntaxhighlight><br />
<br />
All signals and wires connected to an instance should be declared, and the declarations should precede the instantiation.<br />
<br />
The signals connected to the instance inputs are stimuli generated by the testbench. They should be declared as variables of type '''reg'''. The instance outputs should be declared as variables of type '''wire'''. The variable declaration begins with the type ('''reg''' or '''wire''') and ends with the variable's name. We strongly recommend to declare each variable in a separate line. Also, you should NOT initialize a variable in the declaration statement (keep in mind that Verilog is a description language, not a programming language).<br />
For the multi-bit signals the declaration must specify the width, in the same way you declare the width of a multi-bit port in the interface of a module.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
reg num1; // one-bit variable of type reg and named 'num1'<br />
reg num2; // one-bit variable of type reg and named 'num2'<br />
wire [1:0] result; // two-bit variable of type wire and named 'result'<br />
</syntaxhighlight><br />
<br />
As a rule of thumb, keep in mind that any output of an instance could be declared only as a wire, whereas the inputs to an instance are declared of type '''reg''' if you give them values using explicit assignment statements.<br />
<br />
The stimuli for the ''adder'' block are generated as in Laboratory 1, using a Verilog '''initial''' block, inside which you assign values to signals ''num1'' and ''num2''. To thoroughly test the ''adder'' block it is useful to generate all possible combinations of values for those two signals. One such sequence of binary value pairs may be ''00'', ''01'', ''10'', ''11'':<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
num1 = 1'b0; num2 = 1'b0; // begin with both adder inputs zero<br />
#5 num1 = 1'b0; num2 = 1'b1; // after a delay, change the value of one input of the adder<br />
#5 num1 = 1'b1; num2 = 1'b0; // go to the next combination of values<br />
#5 num1 = 1'b1; num2 = 1'b1;<br />
#5 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
'''Note:''' as in Laboratory 1, you may generate the values for ''num1'' and ''num2'' in a single statement, combining them into one two-bit bundle (for example <syntaxhighlight lang="Verilog">{num1, num2} = 2'b01;</syntaxhighlight>)<br />
<br />
The full code of the ''adder'' testbench module:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder_tb;<br />
<br />
// declarations<br />
reg num1;<br />
reg num2;<br />
wire [1:0] result;<br />
<br />
// instantion<br />
adder dut (<br />
.a (num1 ),<br />
.b (num2 ),<br />
.s (result)<br />
); <br />
<br />
// stimuli generation<br />
initial begin<br />
{num1, num2} = 2'b00;<br />
#5 {num1, num2} = 2'b01;<br />
#5 {num1, num2} = 2'b10;<br />
#5 {num1, num2} = 2'b11;<br />
#5 $stop;<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Module simulation ====<br />
<br />
Simulate the ''adder_tb'' testbench and check on the waveforms that the output of the ''adder'' module is indeed the sum of its input values.<br />
<br />
=== Exercise 2 : 2 bit adder ===<br />
<br />
[[Fișier: Dic_lab2_adder2.png]]<br />
<br />
==== design module ====<br />
<br />
The 2 bit adder has almost the same interface as the 1 bit adder. All names are the same, only their widths are different. The inputs are 2 bits wide, the output has 3 bits, to accommodate the biggest possible result (3 + 3 = 6).<br />
Since the description is high-level, employing the add operator, it is exactly the same as for the previous adder.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder2 (<br />
input [1:0] a,<br />
input [1:0] b,<br />
output [2:0] s<br />
);<br />
<br />
assign s = a + b;<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== simulation module ====<br />
<br />
The 2 bit adder module has two inputs of 2 bits each. That means there are more input combinations to be tested, actually 16 (4 values for the one input, and 4 values for the other one). To run through all those 16 combinations the pair of statements '''num1 ='''''value1''; '''num2 ='''''value2''; may be employed 16 times with different values.<br />
If the combinations are generated in a systematic way (for example in the increasing order of the input values), a '''for''' statement is more convenient.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder2_tb;<br />
<br />
// declarations<br />
reg [1:0] num1;<br />
reg [1:0] num2;<br />
wire [2:0] result;<br />
<br />
// instantion of a 2 bit adder<br />
adder2 dut (<br />
.a (num1 ),<br />
.b (num2 ),<br />
.s (result)<br />
); <br />
<br />
// stimuli generation<br />
integer i; // integer type variable used to control the for loop<br />
initial begin<br />
{num1, num2} = 0; // initial values of the adder2 inputs<br />
for(i = 0; i < 16; i = i + 1) // the control variable runs from 0 to 15. After the last iteration it is incremented (again) to 16 and the loop is terminated.<br />
#5 {num1, num2} = {num1, num2} + 1; // a nonzero delay is mandatory to ensure that each combination lasts at least one simulation step.<br />
#5 $stop;<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Implementation ====<br />
<br />
To implement the adder on the FPGA and to interact with it we should imagine some means to set and to change the adder input values and to see the value of its output. The FPGA board allows us to interact with the circuit implemented inside the FPGA through switches, push buttons and various LEDs that are connected to FPGA pins, which may be configured to be wired inside the FPGA to the ports of the implemented module. The FPGA pins assignment is done through the constraints file. For each pin assignment there is a line that instructs the implementation tool to connect the port with a given name to a particular FPGA pin, and also sets the parameters of the I/O pad of that pin. For example<br />
<br />
<syntaxhighlight><br />
set_property -dict { PACKAGE_PIN T2 IOSTANDARD LVCMOS33 } [get_ports { a[1] }];<br />
</syntaxhighlight><br />
<br />
is a constraint that connects the first bit of a input to the FPGA pin labelled T2.<br />
<br />
'''Note:''' For each FPGA board you may find constraints files with constraints for all FPGA pins, with indications as to which switch, button, LED, a.s.o. is connected to which FPGA pin. All constraints are commented. You should uncomment only the lines for the switches, buttons, LEDs a.s.o. that you want to use, and replace the port names with the names of ports from your module. For multi-bit ports there must be one separate connection constraint for each port bit, since each port bit needs a separate FPGA pin.<br />
<br />
The 2 bit adder will be tested using four switches to set the input values, and three LEDs to show the output 3-bit value:<br />
<br />
[[Fișier: Dic_lab2_adder_fpga.png]]<br />
<br />
<syntaxhighlight><br />
##Switches<br />
set_property -dict { PACKAGE_PIN T2 IOSTANDARD LVCMOS33 } [get_ports { a[1] }]; #SW 3<br />
set_property -dict { PACKAGE_PIN U1 IOSTANDARD LVCMOS33 } [get_ports { a[0] }]; #SW 2<br />
set_property -dict { PACKAGE_PIN U2 IOSTANDARD LVCMOS33 } [get_ports { b[1] }]; #SW 1<br />
set_property -dict { PACKAGE_PIN V2 IOSTANDARD LVCMOS33 } [get_ports { b[0] }]; #SW 0<br />
<br />
##LEDs<br />
set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { s[0] }]; #LED 0<br />
set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { s[1] }]; #LED 1<br />
set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { s[2] }]; #LED 2<br />
</syntaxhighlight><br />
<br />
=== Exercise 3 ===<br />
design and verify in simulation a 2 by 2 bit multiplier. The output has 4 bits, to cover the whole range of the multiplication. The biggest output value is 9 (= 3 x 3).<br />
The description is behavioral, using the multiplication operator.<br />
<br />
[[Fișier: app2_mult.png]]<br />
<br />
=== Exercise 4 ===<br />
design source file for top-level entity<br />
Multilevel hierarchy. Mixed description: top-level - structural description, low-level - behavioral description.<br />
* same module type, different instance names<br />
* internal wires for interinstance connections<br />
<br />
[[Fișier: app2_multsum.png]]<br />
<br />
testbench source file for the top-level entity<br />
* '''$monitor(%b...,'''''varName1,...''''')'''<br />
* format specifiers '''%b''' for binary (logic) values, '''%d''' for decimal values</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_2&diff=7493Applications 22023-03-08T00:47:14Z<p>Zhascsi: /* Implementation */</p>
<hr />
<div>=== Exercise 1 : 1 bit adder ===<br />
<br />
==== Module declaration ====<br />
<br />
[[Fișier: Dic_lab2_adder.png]]<br />
<br />
Any Verilog circuit or block is enclosed within the keywords '''module''' and '''endmodule'''.<br />
The '''module''' keyword is followed by the name of the module. This name begins with a letter (Verilog is case-sensitive) or underscore (''_''), uses alphanumeric characters and underscores, and should be a meaningful one (adder, adder_32, counter, lshift_register, Serial_to_Parallel_converter, etc).<br />
<br />
Right after the module name comes the interface description, a list of port declarations, separated by commas and enclosed within parentheses. It is strongly recommended to declare each port on a separate line, even if some ports have the same direction and size. Also it is recommended to group the declarations by their direction.<br />
A port declaration starts with the keyword that defines the port's direction: '''input''' or '''output'''. For one-bit ports the declaration comprises only the direction and the name.<br />
Port names follow the same naming rules used for module names. A port name should be a unique identifier inside the module's code - its scope is limited to the module.<br />
<br />
A multi-bit port declaration defines the width of the port through two indices within brackets and separated by a colon: '''['''''msb''''':'''''lsb''''']'''. The first index denotes the most significant bit (MSB), the second one is the least significant bit. MSB should always be greater than MSB. Usually the LSB index is 0, therefore if the width of the port is ''N'', the first index would be ''N-1''.<br />
<br />
The module declaration comprises the keyword '''module''', the module name and its interface, and ends with a semicolon:<br />
<syntaxhighlight lang="Verilog"><br />
module adder ( // keyword '''module''' followed by the module's name and the opening parenthesis of the interface<br />
input a, // one-bit input port named 'a'<br />
input b, // one-bit input port named 'b'<br />
output [1:0] s // two-bit output port. Bit 1 is MSB, bit 0 is LSB. There is no comma after the last port declaration<br />
); // the closing parenthesis of the interface and the semicolon that ends the module's declaration<br />
</syntaxhighlight><br />
<br />
'''Note:''' All input ports should be variables of '''wire''' type. The '''wire''' type is therefore implicit for port declaration, and may be ommited.<br />
If the output port variable has no explicit type, it is also implicitly of the '''wire''' type.<br />
<br />
==== Module description ====<br />
Anything written between the module's declaration and the keyword '''endmodule''' is part of the module's description.<br />
<br />
A module may be described by ''what'' it does. This is a ''behavioral description''.<br />
Very simple modules could be described using a single instruction, that assigns to the output the result value of an expression over the inputs. Because Verilog is a description language, not a programming language, the assignments that describe how logic values are generated from other logic values are attached to special Verilog keywords. One such keyword is '''assign'''. It is followed by a single assignment: '''assign''' ''y = E(x1, x2, ... xN)''; It is forbidden to use the left-hand variable (''y'') inside the right-hand expression.<br />
<br />
The one-bit adder may be described by a simple expression that computes the output value as the addition of its inputs:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
assign s = a + b; // variable value s is always equal to the sum of a and b <br />
</syntaxhighlight><br />
<br />
The '''assign''' statement describes something that is continuously evaluated. It may be viewed as a small black box with an output and some inputs. The left-hand variable is updated immediately whenever any of the variables in the right-hand expression changes its value. The physical circuit that implements the '''assign''' statement is a combinational logic circuit (CLC) that reacts immediately to any change at its inputs.<br />
<br />
The full code of the ''adder'' module:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder (<br />
input a,<br />
input b,<br />
output [1:0] s<br />
);<br />
<br />
assign s = a + b;<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Testbench module ====<br />
<br />
[[Fișier: Dic_lab2_adder_tb.png]]<br />
<br />
The testbench is another module, therefore it is defined in a separate file. Also, the testbench is a simulation file - it cannot be synthesized and implemented.<br />
Always follow these rules:<br />
* each module is defined in a separate file<br />
* the name of the file is the name of the module, or closely resembles it<br />
<br />
The testbench has no interface. All signals are generated internally. Therefore the testbench declaration has an empty interface list, '''module''' ''testbenchName'''''();''', or the parentheses may be missing at all, '''module''' ''testbenchName''''';'''<br />
<br />
It is recommended to include in the name of the testbench the name of the module to be tested. The testbench for the ''adder'' module may be named ''adder_testbench'', ''test_adder'', ''adder_tb'', a.s.o.<br />
<br />
As for any module, the description follows the module declaration.<br />
The testbench ''instantiates'' the module to be tested and generates values for the signals connected to the inputs of the tested module. The testbench is used only in simulation, it cannot be synthesized. However, this restriction is turned to an advantage because the testbench may use procedural statements freely, as in ordinary programming languages, to generate whatever sequence of values for the stimuli is desired.<br />
<br />
The DUT (device under test) is a block inside the testbench module. It is an ''instance'' of a module. The module is like a blueprint, while the instance is a materialization of that blueprint. For those familiar with object-oriented programming this may sound familiar. The module is like a class, and the instance is an object of that type.<br />
<br />
A module instantiation starts with the ''moduleName'' followed by the ''instanceName'' and the list of its external connections enclosed within parentheses.<br />
Usually, the module instantiated in the testbench is named ''dut'' (device under test). The instance name should be a unique name inside the module where it's instantiated.<br />
<br />
The list of connections connects each port of the instance to a signal of the testbench. It is strongly recommended to write each connection on a separate line. You may write the connections in the same order as in the interface declaration for that module. You should have at most ONE connection for each port, but some ports may be leaved unconnected if they are not used. A connection is declared with a dot ('''.''') immediately followed by the name of the port and finally the name of the signal connected to that port, enclosed in parentheses: '''.'''''modulePin'''''('''''varName''''')'''<br />
. The connections in the list are separated by commas.<br />
<br />
The ''adder'' module is instantiated with the name ''dut''. Its inputs receive signals ''num1'' and ''num2'', and its output is connected to a wire named ''result'':<br />
<br />
<syntaxhighlight lang="Verilog"><br />
adder dut ( // a module of type 'adder' is instantiated. The name of this instance is 'dut'<br />
.a (num1 ), // port 'a' is connected to signal 'num1'<br />
.b (num2 ), // port 'b' is connected to signal 'num2'<br />
.s (result) // port 's' is connected to 'result'. There is no comma after the last connection<br />
); // the closing parenthesis of the interface and the semicolon that ends the module's instantiation<br />
</syntaxhighlight><br />
<br />
All signals and wires connected to an instance should be declared, and the declarations should precede the instantiation.<br />
<br />
The signals connected to the instance inputs are stimuli generated by the testbench. They should be declared as variables of type '''reg'''. The instance outputs should be declared as variables of type '''wire'''. The variable declaration begins with the type ('''reg''' or '''wire''') and ends with the variable's name. We strongly recommend to declare each variable in a separate line. Also, you should NOT initialize a variable in the declaration statement (keep in mind that Verilog is a description language, not a programming language).<br />
For the multi-bit signals the declaration must specify the width, in the same way you declare the width of a multi-bit port in the interface of a module.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
reg num1; // one-bit variable of type reg and named 'num1'<br />
reg num2; // one-bit variable of type reg and named 'num2'<br />
wire [1:0] result; // two-bit variable of type wire and named 'result'<br />
</syntaxhighlight><br />
<br />
As a rule of thumb, keep in mind that any output of an instance could be declared only as a wire, whereas the inputs to an instance are declared of type '''reg''' if you give them values using explicit assignment statements.<br />
<br />
The stimuli for the ''adder'' block are generated as in Laboratory 1, using a Verilog '''initial''' block, inside which you assign values to signals ''num1'' and ''num2''. To thoroughly test the ''adder'' block it is useful to generate all possible combinations of values for those two signals. One such sequence of binary value pairs may be ''00'', ''01'', ''10'', ''11'':<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
num1 = 1'b0; num2 = 1'b0; // begin with both adder inputs zero<br />
#5 num1 = 1'b0; num2 = 1'b1; // after a delay, change the value of one input of the adder<br />
#5 num1 = 1'b1; num2 = 1'b0; // go to the next combination of values<br />
#5 num1 = 1'b1; num2 = 1'b1;<br />
#5 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
'''Note:''' as in Laboratory 1, you may generate the values for ''num1'' and ''num2'' in a single statement, combining them into one two-bit bundle (for example <syntaxhighlight lang="Verilog">{num1, num2} = 2'b01;</syntaxhighlight>)<br />
<br />
The full code of the ''adder'' testbench module:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder_tb;<br />
<br />
// declarations<br />
reg num1;<br />
reg num2;<br />
wire [1:0] result;<br />
<br />
// instantion<br />
adder dut (<br />
.a (num1 ),<br />
.b (num2 ),<br />
.s (result)<br />
); <br />
<br />
// stimuli generation<br />
initial begin<br />
{num1, num2} = 2'b00;<br />
#5 {num1, num2} = 2'b01;<br />
#5 {num1, num2} = 2'b10;<br />
#5 {num1, num2} = 2'b11;<br />
#5 $stop;<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Module simulation ====<br />
<br />
Simulate the ''adder_tb'' testbench and check on the waveforms that the output of the ''adder'' module is indeed the sum of its input values.<br />
<br />
=== Exercise 2 : 2 bit adder ===<br />
<br />
[[Fișier: Dic_lab2_adder2.png]]<br />
<br />
==== design module ====<br />
<br />
The 2 bit adder has almost the same interface as the 1 bit adder. All names are the same, only their widths are different. The inputs are 2 bits wide, the output has 3 bits, to accommodate the biggest possible result (3 + 3 = 6).<br />
Since the description is high-level, employing the add operator, it is exactly the same as for the previous adder.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder2 (<br />
input [1:0] a,<br />
input [1:0] b,<br />
output [2:0] s<br />
);<br />
<br />
assign s = a + b;<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== simulation module ====<br />
<br />
The 2 bit adder module has two inputs of 2 bits each. That means there are more input combinations to be tested, actually 16 (4 values for the one input, and 4 values for the other one). To run through all those 16 combinations the pair of statements '''num1 ='''''value1''; '''num2 ='''''value2''; may be employed 16 times with different values.<br />
If the combinations are generated in a systematic way (for example in the increasing order of the input values), a '''for''' statement is more convenient.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder2_tb;<br />
<br />
// declarations<br />
reg [1:0] num1;<br />
reg [1:0] num2;<br />
wire [2:0] result;<br />
<br />
// instantion of a 2 bit adder<br />
adder2 dut (<br />
.a (num1 ),<br />
.b (num2 ),<br />
.s (result)<br />
); <br />
<br />
// stimuli generation<br />
integer i; // integer type variable used to control the for loop<br />
initial begin<br />
{num1, num2} = 0; // initial values of the adder2 inputs<br />
for(i = 0; i < 16; i = i + 1) // the control variable runs from 0 to 15. After the last iteration it is incremented (again) to 16 and the loop is terminated.<br />
#5 {num1, num2} = {num1, num2} + 1; // a nonzero delay is mandatory to ensure that each combination lasts at least one simulation step.<br />
#5 $stop;<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Implementation ====<br />
<br />
To implement the adder on the FPGA and to interact with it we should imagine some means to set and to change the adder input values and to see the value of its output. The FPGA board allows us to interact with the circuit implemented inside the FPGA through switches, push buttons and various LEDs that are connected to FPGA pins, which may be configured to be wired inside the FPGA to the ports of the implemented module. The FPGA pins assignment is done through the constraints file. For each pin assignment there is a line that instructs the implementation tool to connect the port with a given name to a particular FPGA pin, and also sets the parameters of the I/O pad of that pin. For example<br />
<br />
<syntaxhighlight><br />
set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS33 } [get_ports { num1 }];<br />
</syntaxhighlight><br />
<br />
is a constraint that connects the port num1 to the FPGA pin labelled M20.<br />
<br />
Hopefully, for each FPGA board you may find constraints files with constraints for all FPGA pins, with indications as to which switch, button, LED, a.s.o. is connected to which FPGA pin. All constraints are commented. You should uncomment only the lines for the switches, buttons, LEDs a.s.o. that you want to use, and replace the port names with the names of ports from your module. For multi-bit ports there must be one separate connection constraint for each port bit, since each port bit needs a separate FPGA pin.<br />
<br />
The 2 bit adder will be tested using four switches to set the input values, and three LEDs to show the output 3-bit value:<br />
<br />
[[Fișier: Dic_lab2_adder_fpga.png]]<br />
<br />
<syntaxhighlight><br />
##Switches<br />
set_property -dict { PACKAGE_PIN T2 IOSTANDARD LVCMOS33 } [get_ports { a[1] }]; #SW 3<br />
set_property -dict { PACKAGE_PIN U1 IOSTANDARD LVCMOS33 } [get_ports { a[0] }]; #SW 2<br />
set_property -dict { PACKAGE_PIN U2 IOSTANDARD LVCMOS33 } [get_ports { b[1] }]; #SW 1<br />
set_property -dict { PACKAGE_PIN V2 IOSTANDARD LVCMOS33 } [get_ports { b[0] }]; #SW 0<br />
<br />
##LEDs<br />
set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { s[0] }]; #LED 0<br />
set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { s[1] }]; #LED 1<br />
set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { s[2] }]; #LED 2<br />
</syntaxhighlight><br />
<br />
=== Exercise 3 ===<br />
design and verify in simulation a 2 by 2 bit multiplier. The output has 4 bits, to cover the whole range of the multiplication. The biggest output value is 9 (= 3 x 3).<br />
The description is behavioral, using the multiplication operator.<br />
<br />
[[Fișier: app2_mult.png]]<br />
<br />
=== Exercise 4 ===<br />
design source file for top-level entity<br />
Multilevel hierarchy. Mixed description: top-level - structural description, low-level - behavioral description.<br />
* same module type, different instance names<br />
* internal wires for interinstance connections<br />
<br />
[[Fișier: app2_multsum.png]]<br />
<br />
testbench source file for the top-level entity<br />
* '''$monitor(%b...,'''''varName1,...''''')'''<br />
* format specifiers '''%b''' for binary (logic) values, '''%d''' for decimal values</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_2&diff=7492Applications 22023-03-08T00:43:52Z<p>Zhascsi: /* simulation module */</p>
<hr />
<div>=== Exercise 1 : 1 bit adder ===<br />
<br />
==== Module declaration ====<br />
<br />
[[Fișier: Dic_lab2_adder.png]]<br />
<br />
Any Verilog circuit or block is enclosed within the keywords '''module''' and '''endmodule'''.<br />
The '''module''' keyword is followed by the name of the module. This name begins with a letter (Verilog is case-sensitive) or underscore (''_''), uses alphanumeric characters and underscores, and should be a meaningful one (adder, adder_32, counter, lshift_register, Serial_to_Parallel_converter, etc).<br />
<br />
Right after the module name comes the interface description, a list of port declarations, separated by commas and enclosed within parentheses. It is strongly recommended to declare each port on a separate line, even if some ports have the same direction and size. Also it is recommended to group the declarations by their direction.<br />
A port declaration starts with the keyword that defines the port's direction: '''input''' or '''output'''. For one-bit ports the declaration comprises only the direction and the name.<br />
Port names follow the same naming rules used for module names. A port name should be a unique identifier inside the module's code - its scope is limited to the module.<br />
<br />
A multi-bit port declaration defines the width of the port through two indices within brackets and separated by a colon: '''['''''msb''''':'''''lsb''''']'''. The first index denotes the most significant bit (MSB), the second one is the least significant bit. MSB should always be greater than MSB. Usually the LSB index is 0, therefore if the width of the port is ''N'', the first index would be ''N-1''.<br />
<br />
The module declaration comprises the keyword '''module''', the module name and its interface, and ends with a semicolon:<br />
<syntaxhighlight lang="Verilog"><br />
module adder ( // keyword '''module''' followed by the module's name and the opening parenthesis of the interface<br />
input a, // one-bit input port named 'a'<br />
input b, // one-bit input port named 'b'<br />
output [1:0] s // two-bit output port. Bit 1 is MSB, bit 0 is LSB. There is no comma after the last port declaration<br />
); // the closing parenthesis of the interface and the semicolon that ends the module's declaration<br />
</syntaxhighlight><br />
<br />
'''Note:''' All input ports should be variables of '''wire''' type. The '''wire''' type is therefore implicit for port declaration, and may be ommited.<br />
If the output port variable has no explicit type, it is also implicitly of the '''wire''' type.<br />
<br />
==== Module description ====<br />
Anything written between the module's declaration and the keyword '''endmodule''' is part of the module's description.<br />
<br />
A module may be described by ''what'' it does. This is a ''behavioral description''.<br />
Very simple modules could be described using a single instruction, that assigns to the output the result value of an expression over the inputs. Because Verilog is a description language, not a programming language, the assignments that describe how logic values are generated from other logic values are attached to special Verilog keywords. One such keyword is '''assign'''. It is followed by a single assignment: '''assign''' ''y = E(x1, x2, ... xN)''; It is forbidden to use the left-hand variable (''y'') inside the right-hand expression.<br />
<br />
The one-bit adder may be described by a simple expression that computes the output value as the addition of its inputs:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
assign s = a + b; // variable value s is always equal to the sum of a and b <br />
</syntaxhighlight><br />
<br />
The '''assign''' statement describes something that is continuously evaluated. It may be viewed as a small black box with an output and some inputs. The left-hand variable is updated immediately whenever any of the variables in the right-hand expression changes its value. The physical circuit that implements the '''assign''' statement is a combinational logic circuit (CLC) that reacts immediately to any change at its inputs.<br />
<br />
The full code of the ''adder'' module:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder (<br />
input a,<br />
input b,<br />
output [1:0] s<br />
);<br />
<br />
assign s = a + b;<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Testbench module ====<br />
<br />
[[Fișier: Dic_lab2_adder_tb.png]]<br />
<br />
The testbench is another module, therefore it is defined in a separate file. Also, the testbench is a simulation file - it cannot be synthesized and implemented.<br />
Always follow these rules:<br />
* each module is defined in a separate file<br />
* the name of the file is the name of the module, or closely resembles it<br />
<br />
The testbench has no interface. All signals are generated internally. Therefore the testbench declaration has an empty interface list, '''module''' ''testbenchName'''''();''', or the parentheses may be missing at all, '''module''' ''testbenchName''''';'''<br />
<br />
It is recommended to include in the name of the testbench the name of the module to be tested. The testbench for the ''adder'' module may be named ''adder_testbench'', ''test_adder'', ''adder_tb'', a.s.o.<br />
<br />
As for any module, the description follows the module declaration.<br />
The testbench ''instantiates'' the module to be tested and generates values for the signals connected to the inputs of the tested module. The testbench is used only in simulation, it cannot be synthesized. However, this restriction is turned to an advantage because the testbench may use procedural statements freely, as in ordinary programming languages, to generate whatever sequence of values for the stimuli is desired.<br />
<br />
The DUT (device under test) is a block inside the testbench module. It is an ''instance'' of a module. The module is like a blueprint, while the instance is a materialization of that blueprint. For those familiar with object-oriented programming this may sound familiar. The module is like a class, and the instance is an object of that type.<br />
<br />
A module instantiation starts with the ''moduleName'' followed by the ''instanceName'' and the list of its external connections enclosed within parentheses.<br />
Usually, the module instantiated in the testbench is named ''dut'' (device under test). The instance name should be a unique name inside the module where it's instantiated.<br />
<br />
The list of connections connects each port of the instance to a signal of the testbench. It is strongly recommended to write each connection on a separate line. You may write the connections in the same order as in the interface declaration for that module. You should have at most ONE connection for each port, but some ports may be leaved unconnected if they are not used. A connection is declared with a dot ('''.''') immediately followed by the name of the port and finally the name of the signal connected to that port, enclosed in parentheses: '''.'''''modulePin'''''('''''varName''''')'''<br />
. The connections in the list are separated by commas.<br />
<br />
The ''adder'' module is instantiated with the name ''dut''. Its inputs receive signals ''num1'' and ''num2'', and its output is connected to a wire named ''result'':<br />
<br />
<syntaxhighlight lang="Verilog"><br />
adder dut ( // a module of type 'adder' is instantiated. The name of this instance is 'dut'<br />
.a (num1 ), // port 'a' is connected to signal 'num1'<br />
.b (num2 ), // port 'b' is connected to signal 'num2'<br />
.s (result) // port 's' is connected to 'result'. There is no comma after the last connection<br />
); // the closing parenthesis of the interface and the semicolon that ends the module's instantiation<br />
</syntaxhighlight><br />
<br />
All signals and wires connected to an instance should be declared, and the declarations should precede the instantiation.<br />
<br />
The signals connected to the instance inputs are stimuli generated by the testbench. They should be declared as variables of type '''reg'''. The instance outputs should be declared as variables of type '''wire'''. The variable declaration begins with the type ('''reg''' or '''wire''') and ends with the variable's name. We strongly recommend to declare each variable in a separate line. Also, you should NOT initialize a variable in the declaration statement (keep in mind that Verilog is a description language, not a programming language).<br />
For the multi-bit signals the declaration must specify the width, in the same way you declare the width of a multi-bit port in the interface of a module.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
reg num1; // one-bit variable of type reg and named 'num1'<br />
reg num2; // one-bit variable of type reg and named 'num2'<br />
wire [1:0] result; // two-bit variable of type wire and named 'result'<br />
</syntaxhighlight><br />
<br />
As a rule of thumb, keep in mind that any output of an instance could be declared only as a wire, whereas the inputs to an instance are declared of type '''reg''' if you give them values using explicit assignment statements.<br />
<br />
The stimuli for the ''adder'' block are generated as in Laboratory 1, using a Verilog '''initial''' block, inside which you assign values to signals ''num1'' and ''num2''. To thoroughly test the ''adder'' block it is useful to generate all possible combinations of values for those two signals. One such sequence of binary value pairs may be ''00'', ''01'', ''10'', ''11'':<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
num1 = 1'b0; num2 = 1'b0; // begin with both adder inputs zero<br />
#5 num1 = 1'b0; num2 = 1'b1; // after a delay, change the value of one input of the adder<br />
#5 num1 = 1'b1; num2 = 1'b0; // go to the next combination of values<br />
#5 num1 = 1'b1; num2 = 1'b1;<br />
#5 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
'''Note:''' as in Laboratory 1, you may generate the values for ''num1'' and ''num2'' in a single statement, combining them into one two-bit bundle (for example <syntaxhighlight lang="Verilog">{num1, num2} = 2'b01;</syntaxhighlight>)<br />
<br />
The full code of the ''adder'' testbench module:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder_tb;<br />
<br />
// declarations<br />
reg num1;<br />
reg num2;<br />
wire [1:0] result;<br />
<br />
// instantion<br />
adder dut (<br />
.a (num1 ),<br />
.b (num2 ),<br />
.s (result)<br />
); <br />
<br />
// stimuli generation<br />
initial begin<br />
{num1, num2} = 2'b00;<br />
#5 {num1, num2} = 2'b01;<br />
#5 {num1, num2} = 2'b10;<br />
#5 {num1, num2} = 2'b11;<br />
#5 $stop;<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Module simulation ====<br />
<br />
Simulate the ''adder_tb'' testbench and check on the waveforms that the output of the ''adder'' module is indeed the sum of its input values.<br />
<br />
=== Exercise 2 : 2 bit adder ===<br />
<br />
[[Fișier: Dic_lab2_adder2.png]]<br />
<br />
==== design module ====<br />
<br />
The 2 bit adder has almost the same interface as the 1 bit adder. All names are the same, only their widths are different. The inputs are 2 bits wide, the output has 3 bits, to accommodate the biggest possible result (3 + 3 = 6).<br />
Since the description is high-level, employing the add operator, it is exactly the same as for the previous adder.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder2 (<br />
input [1:0] a,<br />
input [1:0] b,<br />
output [2:0] s<br />
);<br />
<br />
assign s = a + b;<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== simulation module ====<br />
<br />
The 2 bit adder module has two inputs of 2 bits each. That means there are more input combinations to be tested, actually 16 (4 values for the one input, and 4 values for the other one). To run through all those 16 combinations the pair of statements '''num1 ='''''value1''; '''num2 ='''''value2''; may be employed 16 times with different values.<br />
If the combinations are generated in a systematic way (for example in the increasing order of the input values), a '''for''' statement is more convenient.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder2_tb;<br />
<br />
// declarations<br />
reg [1:0] num1;<br />
reg [1:0] num2;<br />
wire [2:0] result;<br />
<br />
// instantion of a 2 bit adder<br />
adder2 dut (<br />
.a (num1 ),<br />
.b (num2 ),<br />
.s (result)<br />
); <br />
<br />
// stimuli generation<br />
integer i; // integer type variable used to control the for loop<br />
initial begin<br />
{num1, num2} = 0; // initial values of the adder2 inputs<br />
for(i = 0; i < 16; i = i + 1) // the control variable runs from 0 to 15. After the last iteration it is incremented (again) to 16 and the loop is terminated.<br />
#5 {num1, num2} = {num1, num2} + 1; // a nonzero delay is mandatory to ensure that each combination lasts at least one simulation step.<br />
#5 $stop;<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Implementation ====<br />
<br />
To implement the adder on the FPGA and to interact with it we should imagine some means to set and to change the adder input values and to see the value of its output. The FPGA board allows us to interact with the circuit implemented inside the FPGA through switches, push buttons and various LEDs that are connected to FPGA pins, which may be configured to be wired inside the FPGA to the ports of the implemented module. The FPGA pins assignment is done through the constraints file. For each pin assignment there is a line that instructs the implementation tool to connect the port with a given name to a particular FPGA pin, and also sets the parameters of the I/O pad of that pin. For example<br />
<br />
<syntaxhighlight><br />
set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS33 } [get_ports { num1 }];<br />
</syntaxhighlight><br />
<br />
is a constraint that connects the port num1 to the FPGA pin labelled M20.<br />
<br />
Hopefully, for each FPGA board you may find constraints files with constraints for all FPGA pins, with indications as to which switch, button, LED, a.s.o. is connected to which FPGA pin. All constraints are commented. You should uncomment only the lines for the switches, buttons, LEDs a.s.o. that you want to use, and replace the port names with the names of ports from your module. For multi-bit ports there must be one separate connection constraint for each port bit, since each port bit needs a separate FPGA pin.<br />
<br />
The 2 bit adder will be tested using four switches to set the input values, and three LEDs to show the output 3-bit value:<br />
<br />
[[Fișier: Dic_lab2_adder_fpga.png]]<br />
<br />
<syntaxhighlight><br />
##Switches<br />
set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS33 } [get_ports { a }]; #SW 0<br />
set_property -dict { PACKAGE_PIN M19 IOSTANDARD LVCMOS33 } [get_ports { b }]; #SW 1<br />
<br />
##LEDs<br />
set_property -dict { PACKAGE_PIN R14 IOSTANDARD LVCMOS33 } [get_ports { s[0] }]; #LED 0<br />
set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { s[1] }]; #LED 1<br />
</syntaxhighlight><br />
<br />
=== Exercise 3 ===<br />
design and verify in simulation a 2 by 2 bit multiplier. The output has 4 bits, to cover the whole range of the multiplication. The biggest output value is 9 (= 3 x 3).<br />
The description is behavioral, using the multiplication operator.<br />
<br />
[[Fișier: app2_mult.png]]<br />
<br />
=== Exercise 4 ===<br />
design source file for top-level entity<br />
Multilevel hierarchy. Mixed description: top-level - structural description, low-level - behavioral description.<br />
* same module type, different instance names<br />
* internal wires for interinstance connections<br />
<br />
[[Fișier: app2_multsum.png]]<br />
<br />
testbench source file for the top-level entity<br />
* '''$monitor(%b...,'''''varName1,...''''')'''<br />
* format specifiers '''%b''' for binary (logic) values, '''%d''' for decimal values</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_2&diff=7491Applications 22023-03-08T00:43:05Z<p>Zhascsi: /* simulation module */</p>
<hr />
<div>=== Exercise 1 : 1 bit adder ===<br />
<br />
==== Module declaration ====<br />
<br />
[[Fișier: Dic_lab2_adder.png]]<br />
<br />
Any Verilog circuit or block is enclosed within the keywords '''module''' and '''endmodule'''.<br />
The '''module''' keyword is followed by the name of the module. This name begins with a letter (Verilog is case-sensitive) or underscore (''_''), uses alphanumeric characters and underscores, and should be a meaningful one (adder, adder_32, counter, lshift_register, Serial_to_Parallel_converter, etc).<br />
<br />
Right after the module name comes the interface description, a list of port declarations, separated by commas and enclosed within parentheses. It is strongly recommended to declare each port on a separate line, even if some ports have the same direction and size. Also it is recommended to group the declarations by their direction.<br />
A port declaration starts with the keyword that defines the port's direction: '''input''' or '''output'''. For one-bit ports the declaration comprises only the direction and the name.<br />
Port names follow the same naming rules used for module names. A port name should be a unique identifier inside the module's code - its scope is limited to the module.<br />
<br />
A multi-bit port declaration defines the width of the port through two indices within brackets and separated by a colon: '''['''''msb''''':'''''lsb''''']'''. The first index denotes the most significant bit (MSB), the second one is the least significant bit. MSB should always be greater than MSB. Usually the LSB index is 0, therefore if the width of the port is ''N'', the first index would be ''N-1''.<br />
<br />
The module declaration comprises the keyword '''module''', the module name and its interface, and ends with a semicolon:<br />
<syntaxhighlight lang="Verilog"><br />
module adder ( // keyword '''module''' followed by the module's name and the opening parenthesis of the interface<br />
input a, // one-bit input port named 'a'<br />
input b, // one-bit input port named 'b'<br />
output [1:0] s // two-bit output port. Bit 1 is MSB, bit 0 is LSB. There is no comma after the last port declaration<br />
); // the closing parenthesis of the interface and the semicolon that ends the module's declaration<br />
</syntaxhighlight><br />
<br />
'''Note:''' All input ports should be variables of '''wire''' type. The '''wire''' type is therefore implicit for port declaration, and may be ommited.<br />
If the output port variable has no explicit type, it is also implicitly of the '''wire''' type.<br />
<br />
==== Module description ====<br />
Anything written between the module's declaration and the keyword '''endmodule''' is part of the module's description.<br />
<br />
A module may be described by ''what'' it does. This is a ''behavioral description''.<br />
Very simple modules could be described using a single instruction, that assigns to the output the result value of an expression over the inputs. Because Verilog is a description language, not a programming language, the assignments that describe how logic values are generated from other logic values are attached to special Verilog keywords. One such keyword is '''assign'''. It is followed by a single assignment: '''assign''' ''y = E(x1, x2, ... xN)''; It is forbidden to use the left-hand variable (''y'') inside the right-hand expression.<br />
<br />
The one-bit adder may be described by a simple expression that computes the output value as the addition of its inputs:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
assign s = a + b; // variable value s is always equal to the sum of a and b <br />
</syntaxhighlight><br />
<br />
The '''assign''' statement describes something that is continuously evaluated. It may be viewed as a small black box with an output and some inputs. The left-hand variable is updated immediately whenever any of the variables in the right-hand expression changes its value. The physical circuit that implements the '''assign''' statement is a combinational logic circuit (CLC) that reacts immediately to any change at its inputs.<br />
<br />
The full code of the ''adder'' module:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder (<br />
input a,<br />
input b,<br />
output [1:0] s<br />
);<br />
<br />
assign s = a + b;<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Testbench module ====<br />
<br />
[[Fișier: Dic_lab2_adder_tb.png]]<br />
<br />
The testbench is another module, therefore it is defined in a separate file. Also, the testbench is a simulation file - it cannot be synthesized and implemented.<br />
Always follow these rules:<br />
* each module is defined in a separate file<br />
* the name of the file is the name of the module, or closely resembles it<br />
<br />
The testbench has no interface. All signals are generated internally. Therefore the testbench declaration has an empty interface list, '''module''' ''testbenchName'''''();''', or the parentheses may be missing at all, '''module''' ''testbenchName''''';'''<br />
<br />
It is recommended to include in the name of the testbench the name of the module to be tested. The testbench for the ''adder'' module may be named ''adder_testbench'', ''test_adder'', ''adder_tb'', a.s.o.<br />
<br />
As for any module, the description follows the module declaration.<br />
The testbench ''instantiates'' the module to be tested and generates values for the signals connected to the inputs of the tested module. The testbench is used only in simulation, it cannot be synthesized. However, this restriction is turned to an advantage because the testbench may use procedural statements freely, as in ordinary programming languages, to generate whatever sequence of values for the stimuli is desired.<br />
<br />
The DUT (device under test) is a block inside the testbench module. It is an ''instance'' of a module. The module is like a blueprint, while the instance is a materialization of that blueprint. For those familiar with object-oriented programming this may sound familiar. The module is like a class, and the instance is an object of that type.<br />
<br />
A module instantiation starts with the ''moduleName'' followed by the ''instanceName'' and the list of its external connections enclosed within parentheses.<br />
Usually, the module instantiated in the testbench is named ''dut'' (device under test). The instance name should be a unique name inside the module where it's instantiated.<br />
<br />
The list of connections connects each port of the instance to a signal of the testbench. It is strongly recommended to write each connection on a separate line. You may write the connections in the same order as in the interface declaration for that module. You should have at most ONE connection for each port, but some ports may be leaved unconnected if they are not used. A connection is declared with a dot ('''.''') immediately followed by the name of the port and finally the name of the signal connected to that port, enclosed in parentheses: '''.'''''modulePin'''''('''''varName''''')'''<br />
. The connections in the list are separated by commas.<br />
<br />
The ''adder'' module is instantiated with the name ''dut''. Its inputs receive signals ''num1'' and ''num2'', and its output is connected to a wire named ''result'':<br />
<br />
<syntaxhighlight lang="Verilog"><br />
adder dut ( // a module of type 'adder' is instantiated. The name of this instance is 'dut'<br />
.a (num1 ), // port 'a' is connected to signal 'num1'<br />
.b (num2 ), // port 'b' is connected to signal 'num2'<br />
.s (result) // port 's' is connected to 'result'. There is no comma after the last connection<br />
); // the closing parenthesis of the interface and the semicolon that ends the module's instantiation<br />
</syntaxhighlight><br />
<br />
All signals and wires connected to an instance should be declared, and the declarations should precede the instantiation.<br />
<br />
The signals connected to the instance inputs are stimuli generated by the testbench. They should be declared as variables of type '''reg'''. The instance outputs should be declared as variables of type '''wire'''. The variable declaration begins with the type ('''reg''' or '''wire''') and ends with the variable's name. We strongly recommend to declare each variable in a separate line. Also, you should NOT initialize a variable in the declaration statement (keep in mind that Verilog is a description language, not a programming language).<br />
For the multi-bit signals the declaration must specify the width, in the same way you declare the width of a multi-bit port in the interface of a module.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
reg num1; // one-bit variable of type reg and named 'num1'<br />
reg num2; // one-bit variable of type reg and named 'num2'<br />
wire [1:0] result; // two-bit variable of type wire and named 'result'<br />
</syntaxhighlight><br />
<br />
As a rule of thumb, keep in mind that any output of an instance could be declared only as a wire, whereas the inputs to an instance are declared of type '''reg''' if you give them values using explicit assignment statements.<br />
<br />
The stimuli for the ''adder'' block are generated as in Laboratory 1, using a Verilog '''initial''' block, inside which you assign values to signals ''num1'' and ''num2''. To thoroughly test the ''adder'' block it is useful to generate all possible combinations of values for those two signals. One such sequence of binary value pairs may be ''00'', ''01'', ''10'', ''11'':<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
num1 = 1'b0; num2 = 1'b0; // begin with both adder inputs zero<br />
#5 num1 = 1'b0; num2 = 1'b1; // after a delay, change the value of one input of the adder<br />
#5 num1 = 1'b1; num2 = 1'b0; // go to the next combination of values<br />
#5 num1 = 1'b1; num2 = 1'b1;<br />
#5 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
'''Note:''' as in Laboratory 1, you may generate the values for ''num1'' and ''num2'' in a single statement, combining them into one two-bit bundle (for example <syntaxhighlight lang="Verilog">{num1, num2} = 2'b01;</syntaxhighlight>)<br />
<br />
The full code of the ''adder'' testbench module:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder_tb;<br />
<br />
// declarations<br />
reg num1;<br />
reg num2;<br />
wire [1:0] result;<br />
<br />
// instantion<br />
adder dut (<br />
.a (num1 ),<br />
.b (num2 ),<br />
.s (result)<br />
); <br />
<br />
// stimuli generation<br />
initial begin<br />
{num1, num2} = 2'b00;<br />
#5 {num1, num2} = 2'b01;<br />
#5 {num1, num2} = 2'b10;<br />
#5 {num1, num2} = 2'b11;<br />
#5 $stop;<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Module simulation ====<br />
<br />
Simulate the ''adder_tb'' testbench and check on the waveforms that the output of the ''adder'' module is indeed the sum of its input values.<br />
<br />
=== Exercise 2 : 2 bit adder ===<br />
<br />
[[Fișier: Dic_lab2_adder2.png]]<br />
<br />
==== design module ====<br />
<br />
The 2 bit adder has almost the same interface as the 1 bit adder. All names are the same, only their widths are different. The inputs are 2 bits wide, the output has 3 bits, to accommodate the biggest possible result (3 + 3 = 6).<br />
Since the description is high-level, employing the add operator, it is exactly the same as for the previous adder.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder2 (<br />
input [1:0] a,<br />
input [1:0] b,<br />
output [2:0] s<br />
);<br />
<br />
assign s = a + b;<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== simulation module ====<br />
<br />
The 2 bit adder module has two inputs of 2 bits each. That means there are more input combinations to be tested, actually 16 (4 values for the one input, and 4 values for the other one). To run through all those 16 combinations the pair of statements '''num1 ='''''value1''; '''num2 ='''''value2''; may be employed 16 times with different values.<br />
If the combinations are generated in a systematic way (for example in the increasing order of the input values), a for statement is more convenient.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder2_tb;<br />
<br />
// declarations<br />
reg [1:0] num1;<br />
reg [1:0] num2;<br />
wire [2:0] result;<br />
<br />
// instantion of a 2 bit adder<br />
adder2 dut (<br />
.a (num1 ),<br />
.b (num2 ),<br />
.s (result)<br />
); <br />
<br />
// stimuli generation<br />
integer i; // integer type variable used to control the for loop<br />
initial begin<br />
{num1, num2} = 0; // initial values of the adder2 inputs<br />
for(i = 0; i < 16; i = i + 1) // the control variable runs from 0 to 15. After the last iteration it is incremented (again) to 16 and the loop is terminated.<br />
#5 {num1, num2} = {num1, num2} + 1; // a nonzero delay is mandatory to ensure that each combination lasts at least one simulation step.<br />
#5 $stop;<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Implementation ====<br />
<br />
To implement the adder on the FPGA and to interact with it we should imagine some means to set and to change the adder input values and to see the value of its output. The FPGA board allows us to interact with the circuit implemented inside the FPGA through switches, push buttons and various LEDs that are connected to FPGA pins, which may be configured to be wired inside the FPGA to the ports of the implemented module. The FPGA pins assignment is done through the constraints file. For each pin assignment there is a line that instructs the implementation tool to connect the port with a given name to a particular FPGA pin, and also sets the parameters of the I/O pad of that pin. For example<br />
<br />
<syntaxhighlight><br />
set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS33 } [get_ports { num1 }];<br />
</syntaxhighlight><br />
<br />
is a constraint that connects the port num1 to the FPGA pin labelled M20.<br />
<br />
Hopefully, for each FPGA board you may find constraints files with constraints for all FPGA pins, with indications as to which switch, button, LED, a.s.o. is connected to which FPGA pin. All constraints are commented. You should uncomment only the lines for the switches, buttons, LEDs a.s.o. that you want to use, and replace the port names with the names of ports from your module. For multi-bit ports there must be one separate connection constraint for each port bit, since each port bit needs a separate FPGA pin.<br />
<br />
The 2 bit adder will be tested using four switches to set the input values, and three LEDs to show the output 3-bit value:<br />
<br />
[[Fișier: Dic_lab2_adder_fpga.png]]<br />
<br />
<syntaxhighlight><br />
##Switches<br />
set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS33 } [get_ports { a }]; #SW 0<br />
set_property -dict { PACKAGE_PIN M19 IOSTANDARD LVCMOS33 } [get_ports { b }]; #SW 1<br />
<br />
##LEDs<br />
set_property -dict { PACKAGE_PIN R14 IOSTANDARD LVCMOS33 } [get_ports { s[0] }]; #LED 0<br />
set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { s[1] }]; #LED 1<br />
</syntaxhighlight><br />
<br />
=== Exercise 3 ===<br />
design and verify in simulation a 2 by 2 bit multiplier. The output has 4 bits, to cover the whole range of the multiplication. The biggest output value is 9 (= 3 x 3).<br />
The description is behavioral, using the multiplication operator.<br />
<br />
[[Fișier: app2_mult.png]]<br />
<br />
=== Exercise 4 ===<br />
design source file for top-level entity<br />
Multilevel hierarchy. Mixed description: top-level - structural description, low-level - behavioral description.<br />
* same module type, different instance names<br />
* internal wires for interinstance connections<br />
<br />
[[Fișier: app2_multsum.png]]<br />
<br />
testbench source file for the top-level entity<br />
* '''$monitor(%b...,'''''varName1,...''''')'''<br />
* format specifiers '''%b''' for binary (logic) values, '''%d''' for decimal values</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Digital_Integrated_Circuits_(lab)&diff=7490Digital Integrated Circuits (lab)2023-03-08T00:35:54Z<p>Zhascsi: </p>
<hr />
<div># [[Applications 1]]<br />
# [[Applications 2]]<br />
<br />
== Verilog Tutorials ==<br />
* [http://www.asic-world.com/verilog/veritut.html Verilog Tutorial] from ASIC World<br />
* [http://chipverify.com/verilog/verilog-tutorial Verilog Tutorial] from Chip Verify<br />
* [http://www.emmelmann.org/Library/Tutorials/docs/verilog_ref_guide/vlog_ref_top.html Verilog reference guide]<br />
<br />
== Software ==<br />
* [https://www.xilinx.com/products/design-tools/vivado/vivado-ml.html Vivado™ ML Standard Edition free]<br />
* [https://wiki.dcae.pub.ro/images/2/24/VivadoNewProjectTutorial.pdf Vivado New Project Tutorial]<br />
<br />
== Hardware ==<br />
* [https://dpoauwgwqsy2x.cloudfront.net/Download/pynqz2_user_manual_v1_0.pdf Pynq-Z2 - user manual]<br />
* [[Pynq-Z2 - Pinout]].<br />
<br />
* [https://www.realdigital.org/doc/02013cd17602c8af749f00561f88ae21 Boolean Board - user manual]<br />
* [[Boolean Board - Pinout]].</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_2&diff=7489Applications 22023-03-08T00:35:23Z<p>Zhascsi: </p>
<hr />
<div>=== Exercise 1 : 1 bit adder ===<br />
<br />
==== Module declaration ====<br />
<br />
[[Fișier: Dic_lab2_adder.png]]<br />
<br />
Any Verilog circuit or block is enclosed within the keywords '''module''' and '''endmodule'''.<br />
The '''module''' keyword is followed by the name of the module. This name begins with a letter (Verilog is case-sensitive) or underscore (''_''), uses alphanumeric characters and underscores, and should be a meaningful one (adder, adder_32, counter, lshift_register, Serial_to_Parallel_converter, etc).<br />
<br />
Right after the module name comes the interface description, a list of port declarations, separated by commas and enclosed within parentheses. It is strongly recommended to declare each port on a separate line, even if some ports have the same direction and size. Also it is recommended to group the declarations by their direction.<br />
A port declaration starts with the keyword that defines the port's direction: '''input''' or '''output'''. For one-bit ports the declaration comprises only the direction and the name.<br />
Port names follow the same naming rules used for module names. A port name should be a unique identifier inside the module's code - its scope is limited to the module.<br />
<br />
A multi-bit port declaration defines the width of the port through two indices within brackets and separated by a colon: '''['''''msb''''':'''''lsb''''']'''. The first index denotes the most significant bit (MSB), the second one is the least significant bit. MSB should always be greater than MSB. Usually the LSB index is 0, therefore if the width of the port is ''N'', the first index would be ''N-1''.<br />
<br />
The module declaration comprises the keyword '''module''', the module name and its interface, and ends with a semicolon:<br />
<syntaxhighlight lang="Verilog"><br />
module adder ( // keyword '''module''' followed by the module's name and the opening parenthesis of the interface<br />
input a, // one-bit input port named 'a'<br />
input b, // one-bit input port named 'b'<br />
output [1:0] s // two-bit output port. Bit 1 is MSB, bit 0 is LSB. There is no comma after the last port declaration<br />
); // the closing parenthesis of the interface and the semicolon that ends the module's declaration<br />
</syntaxhighlight><br />
<br />
'''Note:''' All input ports should be variables of '''wire''' type. The '''wire''' type is therefore implicit for port declaration, and may be ommited.<br />
If the output port variable has no explicit type, it is also implicitly of the '''wire''' type.<br />
<br />
==== Module description ====<br />
Anything written between the module's declaration and the keyword '''endmodule''' is part of the module's description.<br />
<br />
A module may be described by ''what'' it does. This is a ''behavioral description''.<br />
Very simple modules could be described using a single instruction, that assigns to the output the result value of an expression over the inputs. Because Verilog is a description language, not a programming language, the assignments that describe how logic values are generated from other logic values are attached to special Verilog keywords. One such keyword is '''assign'''. It is followed by a single assignment: '''assign''' ''y = E(x1, x2, ... xN)''; It is forbidden to use the left-hand variable (''y'') inside the right-hand expression.<br />
<br />
The one-bit adder may be described by a simple expression that computes the output value as the addition of its inputs:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
assign s = a + b; // variable value s is always equal to the sum of a and b <br />
</syntaxhighlight><br />
<br />
The '''assign''' statement describes something that is continuously evaluated. It may be viewed as a small black box with an output and some inputs. The left-hand variable is updated immediately whenever any of the variables in the right-hand expression changes its value. The physical circuit that implements the '''assign''' statement is a combinational logic circuit (CLC) that reacts immediately to any change at its inputs.<br />
<br />
The full code of the ''adder'' module:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder (<br />
input a,<br />
input b,<br />
output [1:0] s<br />
);<br />
<br />
assign s = a + b;<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Testbench module ====<br />
<br />
[[Fișier: Dic_lab2_adder_tb.png]]<br />
<br />
The testbench is another module, therefore it is defined in a separate file. Also, the testbench is a simulation file - it cannot be synthesized and implemented.<br />
Always follow these rules:<br />
* each module is defined in a separate file<br />
* the name of the file is the name of the module, or closely resembles it<br />
<br />
The testbench has no interface. All signals are generated internally. Therefore the testbench declaration has an empty interface list, '''module''' ''testbenchName'''''();''', or the parentheses may be missing at all, '''module''' ''testbenchName''''';'''<br />
<br />
It is recommended to include in the name of the testbench the name of the module to be tested. The testbench for the ''adder'' module may be named ''adder_testbench'', ''test_adder'', ''adder_tb'', a.s.o.<br />
<br />
As for any module, the description follows the module declaration.<br />
The testbench ''instantiates'' the module to be tested and generates values for the signals connected to the inputs of the tested module. The testbench is used only in simulation, it cannot be synthesized. However, this restriction is turned to an advantage because the testbench may use procedural statements freely, as in ordinary programming languages, to generate whatever sequence of values for the stimuli is desired.<br />
<br />
The DUT (device under test) is a block inside the testbench module. It is an ''instance'' of a module. The module is like a blueprint, while the instance is a materialization of that blueprint. For those familiar with object-oriented programming this may sound familiar. The module is like a class, and the instance is an object of that type.<br />
<br />
A module instantiation starts with the ''moduleName'' followed by the ''instanceName'' and the list of its external connections enclosed within parentheses.<br />
Usually, the module instantiated in the testbench is named ''dut'' (device under test). The instance name should be a unique name inside the module where it's instantiated.<br />
<br />
The list of connections connects each port of the instance to a signal of the testbench. It is strongly recommended to write each connection on a separate line. You may write the connections in the same order as in the interface declaration for that module. You should have at most ONE connection for each port, but some ports may be leaved unconnected if they are not used. A connection is declared with a dot ('''.''') immediately followed by the name of the port and finally the name of the signal connected to that port, enclosed in parentheses: '''.'''''modulePin'''''('''''varName''''')'''<br />
. The connections in the list are separated by commas.<br />
<br />
The ''adder'' module is instantiated with the name ''dut''. Its inputs receive signals ''num1'' and ''num2'', and its output is connected to a wire named ''result'':<br />
<br />
<syntaxhighlight lang="Verilog"><br />
adder dut ( // a module of type 'adder' is instantiated. The name of this instance is 'dut'<br />
.a (num1 ), // port 'a' is connected to signal 'num1'<br />
.b (num2 ), // port 'b' is connected to signal 'num2'<br />
.s (result) // port 's' is connected to 'result'. There is no comma after the last connection<br />
); // the closing parenthesis of the interface and the semicolon that ends the module's instantiation<br />
</syntaxhighlight><br />
<br />
All signals and wires connected to an instance should be declared, and the declarations should precede the instantiation.<br />
<br />
The signals connected to the instance inputs are stimuli generated by the testbench. They should be declared as variables of type '''reg'''. The instance outputs should be declared as variables of type '''wire'''. The variable declaration begins with the type ('''reg''' or '''wire''') and ends with the variable's name. We strongly recommend to declare each variable in a separate line. Also, you should NOT initialize a variable in the declaration statement (keep in mind that Verilog is a description language, not a programming language).<br />
For the multi-bit signals the declaration must specify the width, in the same way you declare the width of a multi-bit port in the interface of a module.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
reg num1; // one-bit variable of type reg and named 'num1'<br />
reg num2; // one-bit variable of type reg and named 'num2'<br />
wire [1:0] result; // two-bit variable of type wire and named 'result'<br />
</syntaxhighlight><br />
<br />
As a rule of thumb, keep in mind that any output of an instance could be declared only as a wire, whereas the inputs to an instance are declared of type '''reg''' if you give them values using explicit assignment statements.<br />
<br />
The stimuli for the ''adder'' block are generated as in Laboratory 1, using a Verilog '''initial''' block, inside which you assign values to signals ''num1'' and ''num2''. To thoroughly test the ''adder'' block it is useful to generate all possible combinations of values for those two signals. One such sequence of binary value pairs may be ''00'', ''01'', ''10'', ''11'':<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
num1 = 1'b0; num2 = 1'b0; // begin with both adder inputs zero<br />
#5 num1 = 1'b0; num2 = 1'b1; // after a delay, change the value of one input of the adder<br />
#5 num1 = 1'b1; num2 = 1'b0; // go to the next combination of values<br />
#5 num1 = 1'b1; num2 = 1'b1;<br />
#5 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
'''Note:''' as in Laboratory 1, you may generate the values for ''num1'' and ''num2'' in a single statement, combining them into one two-bit bundle (for example <syntaxhighlight lang="Verilog">{num1, num2} = 2'b01;</syntaxhighlight>)<br />
<br />
The full code of the ''adder'' testbench module:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder_tb;<br />
<br />
// declarations<br />
reg num1;<br />
reg num2;<br />
wire [1:0] result;<br />
<br />
// instantion<br />
adder dut (<br />
.a (num1 ),<br />
.b (num2 ),<br />
.s (result)<br />
); <br />
<br />
// stimuli generation<br />
initial begin<br />
{num1, num2} = 2'b00;<br />
#5 {num1, num2} = 2'b01;<br />
#5 {num1, num2} = 2'b10;<br />
#5 {num1, num2} = 2'b11;<br />
#5 $stop;<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Module simulation ====<br />
<br />
Simulate the ''adder_tb'' testbench and check on the waveforms that the output of the ''adder'' module is indeed the sum of its input values.<br />
<br />
=== Exercise 2 : 2 bit adder ===<br />
<br />
[[Fișier: Dic_lab2_adder2.png]]<br />
<br />
==== design module ====<br />
<br />
The 2 bit adder has almost the same interface as the 1 bit adder. All names are the same, only their widths are different. The inputs are 2 bits wide, the output has 3 bits, to accommodate the biggest possible result (3 + 3 = 6).<br />
Since the description is high-level, employing the add operator, it is exactly the same as for the previous adder.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder2 (<br />
input [1:0] a,<br />
input [1:0] b,<br />
output [2:0] s<br />
);<br />
<br />
assign s = a + b;<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== simulation module ====<br />
<br />
The 2 bit adder module has two inputs of 2 bits each. That means there are more input combinations to be tested, actually 16 (4 values for the one input, and 4 values for the other one). To run through all those 16 combinations the pair of statements ''''num1 =''''''value1''; ''''num2 =''''''value2''; may be employed 16 times with different values.<br />
If the combinations are generated in a systematic way (for example in the increasing order of the input values), a for statement is more convenient.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder2_tb;<br />
<br />
// declarations<br />
reg [1:0] num1;<br />
reg [1:0] num2;<br />
wire [2:0] result;<br />
<br />
// instantion of a 2 bit adder<br />
adder2 dut (<br />
.a (num1 ),<br />
.b (num2 ),<br />
.s (result)<br />
); <br />
<br />
// stimuli generation<br />
integer i; // integer type variable used to control the for loop<br />
initial begin<br />
{num1, num2} = 0; // initial values of the adder2 inputs<br />
for(i = 0; i < 16; i = i + 1) // the control variable runs from 0 to 15. After the last iteration it is incremented (again) to 16 and the loop is terminated.<br />
#5 {num1, num2} = {num1, num2} + 1; // a nonzero delay is mandatory to ensure that each combination lasts at least one simulation step.<br />
#5 $stop;<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Implementation ====<br />
<br />
To implement the adder on the FPGA and to interact with it we should imagine some means to set and to change the adder input values and to see the value of its output. The FPGA board allows us to interact with the circuit implemented inside the FPGA through switches, push buttons and various LEDs that are connected to FPGA pins, which may be configured to be wired inside the FPGA to the ports of the implemented module. The FPGA pins assignment is done through the constraints file. For each pin assignment there is a line that instructs the implementation tool to connect the port with a given name to a particular FPGA pin, and also sets the parameters of the I/O pad of that pin. For example<br />
<br />
<syntaxhighlight><br />
set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS33 } [get_ports { num1 }];<br />
</syntaxhighlight><br />
<br />
is a constraint that connects the port num1 to the FPGA pin labelled M20.<br />
<br />
Hopefully, for each FPGA board you may find constraints files with constraints for all FPGA pins, with indications as to which switch, button, LED, a.s.o. is connected to which FPGA pin. All constraints are commented. You should uncomment only the lines for the switches, buttons, LEDs a.s.o. that you want to use, and replace the port names with the names of ports from your module. For multi-bit ports there must be one separate connection constraint for each port bit, since each port bit needs a separate FPGA pin.<br />
<br />
The 2 bit adder will be tested using four switches to set the input values, and three LEDs to show the output 3-bit value:<br />
<br />
[[Fișier: Dic_lab2_adder_fpga.png]]<br />
<br />
<syntaxhighlight><br />
##Switches<br />
set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS33 } [get_ports { a }]; #SW 0<br />
set_property -dict { PACKAGE_PIN M19 IOSTANDARD LVCMOS33 } [get_ports { b }]; #SW 1<br />
<br />
##LEDs<br />
set_property -dict { PACKAGE_PIN R14 IOSTANDARD LVCMOS33 } [get_ports { s[0] }]; #LED 0<br />
set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { s[1] }]; #LED 1<br />
</syntaxhighlight><br />
<br />
=== Exercise 3 ===<br />
design and verify in simulation a 2 by 2 bit multiplier. The output has 4 bits, to cover the whole range of the multiplication. The biggest output value is 9 (= 3 x 3).<br />
The description is behavioral, using the multiplication operator.<br />
<br />
[[Fișier: app2_mult.png]]<br />
<br />
=== Exercise 4 ===<br />
design source file for top-level entity<br />
Multilevel hierarchy. Mixed description: top-level - structural description, low-level - behavioral description.<br />
* same module type, different instance names<br />
* internal wires for interinstance connections<br />
<br />
[[Fișier: app2_multsum.png]]<br />
<br />
testbench source file for the top-level entity<br />
* '''$monitor(%b...,'''''varName1,...''''')'''<br />
* format specifiers '''%b''' for binary (logic) values, '''%d''' for decimal values</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_2&diff=7488Applications 22023-03-08T00:28:54Z<p>Zhascsi: </p>
<hr />
<div>=== Exercise 1 : 1 bit adder ===<br />
<br />
==== Module declaration ====<br />
<br />
[[Fișier: Dic_lab2_adder.png]]<br />
<br />
Any Verilog circuit or block is enclosed within the keywords '''module''' and '''endmodule'''.<br />
The '''module''' keyword is followed by the name of the module. This name begins with a letter (Verilog is case-sensitive) or underscore (''_''), uses alphanumeric characters and underscores, and should be a meaningful one (adder, adder_32, counter, lshift_register, Serial_to_Parallel_converter, etc).<br />
<br />
Right after the module name comes the interface description, a list of port declarations, separated by commas and enclosed within parentheses. It is strongly recommended to declare each port on a separate line, even if some ports have the same direction and size. Also it is recommended to group the declarations by their direction.<br />
A port declaration starts with the keyword that defines the port's direction: '''input''' or '''output'''. For one-bit ports the declaration comprises only the direction and the name.<br />
Port names follow the same naming rules used for module names. A port name should be a unique identifier inside the module's code - its scope is limited to the module.<br />
<br />
A multi-bit port declaration defines the width of the port through two indices within brackets and separated by a colon: '''['''''msb''''':'''''lsb''''']'''. The first index denotes the most significant bit (MSB), the second one is the least significant bit. MSB should always be greater than MSB. Usually the LSB index is 0, therefore if the width of the port is ''N'', the first index would be ''N-1''.<br />
<br />
The module declaration comprises the keyword '''module''', the module name and its interface, and ends with a semicolon:<br />
<syntaxhighlight lang="Verilog"><br />
module adder ( // keyword '''module''' followed by the module's name and the opening parenthesis of the interface<br />
input a, // one-bit input port named 'a'<br />
input b, // one-bit input port named 'b'<br />
output [1:0] s // two-bit output port. Bit 1 is MSB, bit 0 is LSB. There is no comma after the last port declaration<br />
); // the closing parenthesis of the interface and the semicolon that ends the module's declaration<br />
</syntaxhighlight><br />
<br />
'''Note:''' All input ports should be variables of '''wire''' type. The '''wire''' type is therefore implicit for port declaration, and may be ommited.<br />
If the output port variable has no explicit type, it is also implicitly of the '''wire''' type.<br />
<br />
==== Module description ====<br />
Anything written between the module's declaration and the keyword '''endmodule''' is part of the module's description.<br />
<br />
A module may be described by ''what'' it does. This is a ''behavioral description''.<br />
Very simple modules could be described using a single instruction, that assigns to the output the result value of an expression over the inputs. Because Verilog is a description language, not a programming language, the assignments that describe how logic values are generated from other logic values are attached to special Verilog keywords. One such keyword is '''assign'''. It is followed by a single assignment: '''assign''' ''y = E(x1, x2, ... xN)''; It is forbidden to use the left-hand variable (''y'') inside the right-hand expression.<br />
<br />
The one-bit adder may be described by a simple expression that computes the output value as the addition of its inputs:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
assign s = a + b; // variable value s is always equal to the sum of a and b <br />
</syntaxhighlight><br />
<br />
The '''assign''' statement describes something that is continuously evaluated. It may be viewed as a small black box with an output and some inputs. The left-hand variable is updated immediately whenever any of the variables in the right-hand expression changes its value. The physical circuit that implements the '''assign''' statement is a combinational logic circuit (CLC) that reacts immediately to any change at its inputs.<br />
<br />
The full code of the ''adder'' module:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder (<br />
input a,<br />
input b,<br />
output [1:0] s<br />
);<br />
<br />
assign s = a + b;<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Testbench module ====<br />
<br />
[[Fișier: Dic_lab2_adder_tb.png]]<br />
<br />
The testbench is another module, therefore it is defined in a separate file. Also, the testbench is a simulation file - it cannot be synthesized and implemented.<br />
Always follow these rules:<br />
* each module is defined in a separate file<br />
* the name of the file is the name of the module, or closely resembles it<br />
<br />
The testbench has no interface. All signals are generated internally. Therefore the testbench declaration has an empty interface list, '''module''' ''testbenchName'''''();''', or the parentheses may be missing at all, '''module''' ''testbenchName''''';'''<br />
<br />
It is recommended to include in the name of the testbench the name of the module to be tested. The testbench for the ''adder'' module may be named ''adder_testbench'', ''test_adder'', ''adder_tb'', a.s.o.<br />
<br />
As for any module, the description follows the module declaration.<br />
The testbench ''instantiates'' the module to be tested and generates values for the signals connected to the inputs of the tested module. The testbench is used only in simulation, it cannot be synthesized. However, this restriction is turned to an advantage because the testbench may use procedural statements freely, as in ordinary programming languages, to generate whatever sequence of values for the stimuli is desired.<br />
<br />
The DUT (device under test) is a block inside the testbench module. It is an ''instance'' of a module. The module is like a blueprint, while the instance is a materialization of that blueprint. For those familiar with object-oriented programming this may sound familiar. The module is like a class, and the instance is an object of that type.<br />
<br />
A module instantiation starts with the ''moduleName'' followed by the ''instanceName'' and the list of its external connections enclosed within parentheses.<br />
Usually, the module instantiated in the testbench is named ''dut'' (device under test). The instance name should be a unique name inside the module where it's instantiated.<br />
<br />
The list of connections connects each port of the instance to a signal of the testbench. It is strongly recommended to write each connection on a separate line. You may write the connections in the same order as in the interface declaration for that module. You should have at most ONE connection for each port, but some ports may be leaved unconnected if they are not used. A connection is declared with a dot ('''.''') immediately followed by the name of the port and finally the name of the signal connected to that port, enclosed in parentheses: '''.'''''modulePin'''''('''''varName''''')'''<br />
. The connections in the list are separated by commas.<br />
<br />
The ''adder'' module is instantiated with the name ''dut''. Its inputs receive signals ''num1'' and ''num2'', and its output is connected to a wire named ''result'':<br />
<br />
<syntaxhighlight lang="Verilog"><br />
adder dut ( // a module of type 'adder' is instantiated. The name of this instance is 'dut'<br />
.a (num1 ), // port 'a' is connected to signal 'num1'<br />
.b (num2 ), // port 'b' is connected to signal 'num2'<br />
.s (result) // port 's' is connected to 'result'. There is no comma after the last connection<br />
); // the closing parenthesis of the interface and the semicolon that ends the module's instantiation<br />
</syntaxhighlight><br />
<br />
All signals and wires connected to an instance should be declared, and the declarations should precede the instantiation.<br />
<br />
The signals connected to the instance inputs are stimuli generated by the testbench. They should be declared as variables of type '''reg'''. The instance outputs should be declared as variables of type '''wire'''. The variable declaration begins with the type ('''reg''' or '''wire''') and ends with the variable's name. We strongly recommend to declare each variable in a separate line. Also, you should NOT initialize a variable in the declaration statement (keep in mind that Verilog is a description language, not a programming language).<br />
For the multi-bit signals the declaration must specify the width, in the same way you declare the width of a multi-bit port in the interface of a module.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
reg num1; // one-bit variable of type reg and named 'num1'<br />
reg num2; // one-bit variable of type reg and named 'num2'<br />
wire [1:0] result; // two-bit variable of type wire and named 'result'<br />
</syntaxhighlight><br />
<br />
As a rule of thumb, keep in mind that any output of an instance could be declared only as a wire, whereas the inputs to an instance are declared of type '''reg''' if you give them values using explicit assignment statements.<br />
<br />
The stimuli for the ''adder'' block are generated as in Laboratory 1, using a Verilog '''initial''' block, inside which you assign values to signals ''num1'' and ''num2''. To thoroughly test the ''adder'' block it is useful to generate all possible combinations of values for those two signals. One such sequence of binary value pairs may be ''00'', ''01'', ''10'', ''11'':<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
num1 = 1'b0; num2 = 1'b0; // begin with both adder inputs zero<br />
#5 num1 = 1'b0; num2 = 1'b1; // after a delay, change the value of one input of the adder<br />
#5 num1 = 1'b1; num2 = 1'b0; // go to the next combination of values<br />
#5 num1 = 1'b1; num2 = 1'b1;<br />
#5 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
'''Note:''' as in Laboratory 1, you may generate the values for ''num1'' and ''num2'' in a single statement, combining them into one two-bit bundle (for example <syntaxhighlight lang="Verilog">{num1, num2} = 2'b01;</syntaxhighlight>)<br />
<br />
The full code of the ''adder'' testbench module:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder_tb;<br />
<br />
// declarations<br />
reg num1;<br />
reg num2;<br />
wire [1:0] result;<br />
<br />
// instantion<br />
adder dut (<br />
.a (num1 ),<br />
.b (num2 ),<br />
.s (result)<br />
); <br />
<br />
// stimuli generation<br />
initial begin<br />
{num1, num2} = 2'b00;<br />
#5 {num1, num2} = 2'b01;<br />
#5 {num1, num2} = 2'b10;<br />
#5 {num1, num2} = 2'b11;<br />
#5 $stop;<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Module simulation ====<br />
<br />
Simulate the ''adder_tb'' testbench and check on the waveforms that the output of the ''adder'' module is indeed the sum of its input values.<br />
<br />
=== Exercise 2 : 2 bit adder ===<br />
<br />
[[Dic_lab2_adder2.png]]<br />
<br />
==== design module ====<br />
<br />
The 2 bit adder has almost the same interface as the 1 bit adder. All names are the same, only their widths are different. The inputs are 2 bits wide, the output has 3 bits, to accommodate the biggest possible result (3 + 3 = 6).<br />
Since the description is high-level, employing the add operator, it is exactly the same as for the previous adder.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder2 (<br />
input [1:0] a,<br />
input [1:0] b,<br />
output [2:0] s<br />
);<br />
<br />
assign s = a + b;<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== simulation module ====<br />
<br />
The 2 bit adder module has two inputs of 2 bits each. That means there are more input combinations to be tested, actually 16 (4 values for the one input, and 4 values for the other one). To run through all those 16 combinations the pair of statements ''''num1 =''''''value1''; ''''num2 =''''''value2''; may be employed 16 times with different values.<br />
If the combinations are generated in a systematic way (for example in the increasing order of the input values), a for statement is more convenient.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder2_tb;<br />
<br />
// declarations<br />
reg [1:0] num1;<br />
reg [1:0] num2;<br />
wire [2:0] result;<br />
<br />
// instantion of a 2 bit adder<br />
adder2 dut (<br />
.a (num1 ),<br />
.b (num2 ),<br />
.s (result)<br />
); <br />
<br />
// stimuli generation<br />
integer i; // integer type variable used to control the for loop<br />
initial begin<br />
{num1, num2} = 0; // initial values of the adder2 inputs<br />
for(i = 0; i < 16; i = i + 1) // the control variable runs from 0 to 15. After the last iteration it is incremented (again) to 16 and the loop is terminated.<br />
#5 {num1, num2} = {num1, num2} + 1; // a nonzero delay is mandatory to ensure that each combination lasts at least one simulation step.<br />
#5 $stop;<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Implementation ====<br />
<br />
To implement the adder on the FPGA and to interact with it we should imagine some means to set and to change the adder input values and to see the value of its output. The FPGA board allows us to interact with the circuit implemented inside the FPGA through switches, push buttons and various LEDs that are connected to FPGA pins, which may be configured to be wired inside the FPGA to the ports of the implemented module. The FPGA pins assignment is done through the constraints file. For each pin assignment there is a line that instructs the implementation tool to connect the port with a given name to a particular FPGA pin, and also sets the parameters of the I/O pad of that pin. For example<br />
<br />
<syntaxhighlight><br />
set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS33 } [get_ports { num1 }];<br />
</syntaxhighlight><br />
<br />
is a constraint that connects the port num1 to the FPGA pin labelled M20.<br />
<br />
Hopefully, for each FPGA board you may find constraints files with constraints for all FPGA pins, with indications as to which switch, button, LED, a.s.o. is connected to which FPGA pin. All constraints are commented. You should uncomment only the lines for the switches, buttons, LEDs a.s.o. that you want to use, and replace the port names with the names of ports from your module. For multi-bit ports there must be one separate connection constraint for each port bit, since each port bit needs a separate FPGA pin.<br />
<br />
The 2 bit adder will be tested using four switches to set the input values, and three LEDs to show the output 3-bit value:<br />
<br />
[[Fișier: Dic_lab2_adder_fpga.png]]<br />
<br />
<syntaxhighlight><br />
##Switches<br />
set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS33 } [get_ports { a }]; #SW 0<br />
set_property -dict { PACKAGE_PIN M19 IOSTANDARD LVCMOS33 } [get_ports { b }]; #SW 1<br />
<br />
##LEDs<br />
set_property -dict { PACKAGE_PIN R14 IOSTANDARD LVCMOS33 } [get_ports { s[0] }]; #LED 0<br />
set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { s[1] }]; #LED 1<br />
</syntaxhighlight><br />
<br />
=== Exercise 3 ===<br />
design and verify in simulation a 2 by 2 bit multiplier. The output has 4 bits, to cover the whole range of the multiplication. The biggest output value is 9 (= 3 x 3).<br />
The description is behavioral, using the multiplication operator.<br />
<br />
[[Fișier: app2_mult.png]]<br />
<br />
=== Exercise 4 ===<br />
design source file for top-level entity<br />
Multilevel hierarchy. Mixed description: top-level - structural description, low-level - behavioral description.<br />
* same module type, different instance names<br />
* internal wires for interinstance connections<br />
<br />
[[Fișier: app2_multsum.png]]<br />
<br />
testbench source file for the top-level entity<br />
* '''$monitor(%b...,'''''varName1,...''''')'''<br />
* format specifiers '''%b''' for binary (logic) values, '''%d''' for decimal values</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Fi%C8%99ier:Dic_lab2_adder2.png&diff=7487Fișier:Dic lab2 adder2.png2023-03-07T23:58:10Z<p>Zhascsi: </p>
<hr />
<div></div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_2&diff=7486Applications 22023-03-07T23:13:05Z<p>Zhascsi: /* Testbench module */</p>
<hr />
<div>=== Exercise 1 : 1 bit adder ===<br />
<br />
==== Module declaration ====<br />
<br />
[[Fișier: Dic_lab2_adder.png]]<br />
<br />
Any Verilog circuit or block is enclosed within the keywords '''module''' and '''endmodule'''.<br />
The '''module''' keyword is followed by the name of the module. This name begins with a letter (Verilog is case-sensitive) or underscore (''_''), uses alphanumeric characters and underscores, and should be a meaningful one (adder, adder_32, counter, lshift_register, Serial_to_Parallel_converter, etc).<br />
<br />
Right after the module name comes the interface description, a list of port declarations, separated by commas and enclosed within parentheses. It is strongly recommended to declare each port on a separate line, even if some ports have the same direction and size. Also it is recommended to group the declarations by their direction.<br />
A port declaration starts with the keyword that defines the port's direction: '''input''' or '''output'''. For one-bit ports the declaration comprises only the direction and the name.<br />
Port names follow the same naming rules used for module names. A port name should be a unique identifier inside the module's code - its scope is limited to the module.<br />
<br />
A multi-bit port declaration defines the width of the port through two indices within brackets and separated by a colon: '''['''''msb''''':'''''lsb''''']'''. The first index denotes the most significant bit (MSB), the second one is the least significant bit. MSB should always be greater than MSB. Usually the LSB index is 0, therefore if the width of the port is ''N'', the first index would be ''N-1''.<br />
<br />
The module declaration comprises the keyword '''module''', the module name and its interface, and ends with a semicolon:<br />
<syntaxhighlight lang="Verilog"><br />
module adder ( // keyword '''module''' followed by the module's name and the opening parenthesis of the interface<br />
input a, // one-bit input port named 'a'<br />
input b, // one-bit input port named 'b'<br />
output [1:0] s // two-bit output port. Bit 1 is MSB, bit 0 is LSB. There is no comma after the last port declaration<br />
); // the closing parenthesis of the interface and the semicolon that ends the module's declaration<br />
</syntaxhighlight><br />
<br />
'''Note:''' All input ports should be variables of '''wire''' type. The '''wire''' type is therefore implicit for port declaration, and may be ommited.<br />
If the output port variable has no explicit type, it is also implicitly of the '''wire''' type.<br />
<br />
==== Module description ====<br />
Anything written between the module's declaration and the keyword '''endmodule''' is part of the module's description.<br />
<br />
A module may be described by ''what'' it does. This is a ''behavioral description''.<br />
Very simple modules could be described using a single instruction, that assigns to the output the result value of an expression over the inputs. Because Verilog is a description language, not a programming language, the assignments that describe how logic values are generated from other logic values are attached to special Verilog keywords. One such keyword is '''assign'''. It is followed by a single assignment: '''assign''' ''y = E(x1, x2, ... xN)''; It is forbidden to use the left-hand variable (''y'') inside the right-hand expression.<br />
<br />
The one-bit adder may be described by a simple expression that computes the output value as the addition of its inputs:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
assign s = a + b; // variable value s is always equal to the sum of a and b <br />
</syntaxhighlight><br />
<br />
The '''assign''' statement describes something that is continuously evaluated. It may be viewed as a small black box with an output and some inputs. The left-hand variable is updated immediately whenever any of the variables in the right-hand expression changes its value. The physical circuit that implements the '''assign''' statement is a combinational logic circuit (CLC) that reacts immediately to any change at its inputs.<br />
<br />
The full code of the ''adder'' module:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder (<br />
input a,<br />
input b,<br />
output [1:0] s<br />
);<br />
<br />
assign s = a + b;<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Testbench module ====<br />
<br />
[[Fișier: Dic_lab2_adder_tb.png]]<br />
<br />
The testbench is another module, therefore it is defined in a separate file. Also, the testbench is a simulation file - it cannot be synthesized and implemented.<br />
Always follow these rules:<br />
* each module is defined in a separate file<br />
* the name of the file is the name of the module, or closely resembles it<br />
<br />
The testbench has no interface. All signals are generated internally. Therefore the testbench declaration has an empty interface list, '''module''' ''testbenchName'''''();''', or the parentheses may be missing at all, '''module''' ''testbenchName''''';'''<br />
<br />
It is recommended to include in the name of the testbench the name of the module to be tested. The testbench for the ''adder'' module may be named ''adder_testbench'', ''test_adder'', ''adder_tb'', a.s.o.<br />
<br />
As for any module, the description follows the module declaration.<br />
The testbench ''instantiates'' the module to be tested and generates values for the signals connected to the inputs of the tested module. The testbench is used only in simulation, it cannot be synthesized. However, this restriction is turned to an advantage because the testbench may use procedural statements freely, as in ordinary programming languages, to generate whatever sequence of values for the stimuli is desired.<br />
<br />
The DUT (device under test) is a block inside the testbench module. It is an ''instance'' of a module. The module is like a blueprint, while the instance is a materialization of that blueprint. For those familiar with object-oriented programming this may sound familiar. The module is like a class, and the instance is an object of that type.<br />
<br />
A module instantiation starts with the ''moduleName'' followed by the ''instanceName'' and the list of its external connections enclosed within parentheses.<br />
Usually, the module instantiated in the testbench is named ''dut'' (device under test). The instance name should be a unique name inside the module where it's instantiated.<br />
<br />
The list of connections connects each port of the instance to a signal of the testbench. It is strongly recommended to write each connection on a separate line. You may write the connections in the same order as in the interface declaration for that module. You should have at most ONE connection for each port, but some ports may be leaved unconnected if they are not used. A connection is declared with a dot ('''.''') immediately followed by the name of the port and finally the name of the signal connected to that port, enclosed in parentheses: '''.'''''modulePin'''''('''''varName''''')'''<br />
. The connections in the list are separated by commas.<br />
<br />
The ''adder'' module is instantiated with the name ''dut''. Its inputs receive signals ''num1'' and ''num2'', and its output is connected to a wire named ''result'':<br />
<br />
<syntaxhighlight lang="Verilog"><br />
adder dut ( // a module of type 'adder' is instantiated. The name of this instance is 'dut'<br />
.a (num1 ), // port 'a' is connected to signal 'num1'<br />
.b (num2 ), // port 'b' is connected to signal 'num2'<br />
.s (result) // port 's' is connected to 'result'. There is no comma after the last connection<br />
); // the closing parenthesis of the interface and the semicolon that ends the module's instantiation<br />
</syntaxhighlight><br />
<br />
All signals and wires connected to an instance should be declared, and the declarations should precede the instantiation.<br />
<br />
The signals connected to the instance inputs are stimuli generated by the testbench. They should be declared as variables of type '''reg'''. The instance outputs should be declared as variables of type '''wire'''. The variable declaration begins with the type ('''reg''' or '''wire''') and ends with the variable's name. We strongly recommend to declare each variable in a separate line. Also, you should NOT initialize a variable in the declaration statement (keep in mind that Verilog is a description language, not a programming language).<br />
For the multi-bit signals the declaration must specify the width, in the same way you declare the width of a multi-bit port in the interface of a module.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
reg num1; // one-bit variable of type reg and named 'num1'<br />
reg num2; // one-bit variable of type reg and named 'num2'<br />
wire [1:0] result; // two-bit variable of type wire and named 'result'<br />
</syntaxhighlight><br />
<br />
As a rule of thumb, keep in mind that any output of an instance could be declared only as a wire, whereas the inputs to an instance are declared of type '''reg''' if you give them values using explicit assignment statements.<br />
<br />
The stimuli for the ''adder'' block are generated as in Laboratory 1, using a Verilog '''initial''' block, inside which you assign values to signals ''num1'' and ''num2''. To thoroughly test the ''adder'' block it is useful to generate all possible combinations of values for those two signals. One such sequence of binary value pairs may be ''00'', ''01'', ''10'', ''11'':<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
num1 = 1'b0; num2 = 1'b0; // begin with both adder inputs zero<br />
#5 num1 = 1'b0; num2 = 1'b1; // after a delay, change the value of one input of the adder<br />
#5 num1 = 1'b1; num2 = 1'b0; // go to the next combination of values<br />
#5 num1 = 1'b1; num2 = 1'b1;<br />
#5 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
'''Note:''' as in Laboratory 1, you may generate the values for ''num1'' and ''num2'' in a single statement, combining them into one two-bit bundle (for example <syntaxhighlight lang="Verilog">{num1, num2} = 2'b01;</syntaxhighlight>)<br />
<br />
The full code of the ''adder'' testbench module:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder_tb;<br />
<br />
// declarations<br />
reg num1;<br />
reg num2;<br />
wire [1:0] result;<br />
<br />
// instantion<br />
adder dut (<br />
.a (num1 ),<br />
.b (num2 ),<br />
.s (result)<br />
); <br />
<br />
// stimuli generation<br />
initial begin<br />
{num1, num2} = 2'b00;<br />
#5 {num1, num2} = 2'b01;<br />
#5 {num1, num2} = 2'b10;<br />
#5 {num1, num2} = 2'b11;<br />
#5 $stop;<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Module simulation ====<br />
<br />
Simulate the ''adder_tb'' testbench and check on the waveforms that the output of the ''adder'' module is indeed the sum of its input values.<br />
<br />
==== Implementation ====<br />
<br />
To implement the adder on the FPGA and to interact with it we should imagine some means to set and to change the adder input values and to see the value of its output. The FPGA board allows us to interact with the circuit implemented inside the FPGA through a couple of switches, some push buttons and various LEDs that are connected to FPGA pins, which may be configured to be wired inside the FPGA to the ports of the implemented module. The FPGA pins assignment is done through the constraints file. For each pin assignment there is a line that instructs the implementation tool to connect the port with a given name to a particular FPGA pin, and also sets the parameters of the I/O pad of that pin. For example<br />
<br />
<syntaxhighlight><br />
set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS33 } [get_ports { num1 }];<br />
</syntaxhighlight><br />
<br />
is a constraint that connects the port num1 to the FPGA pin labelled M20.<br />
<br />
Hopefully, for each FPGA board you may find constraints files with constraints for all FPGA pins, with indications as to which switch, button, LED, a.s.o. is connected towhich FPGA pin. All constraints are commented. You should uncomment only the lines for the switches, buttons, LEDs a.s.o. that you want to use, and replace the port names with the names of ports from your module. For multi-bit ports there must be one separate connection constraint for each port bit, since each port bit needs a separate FPGA pin.<br />
<br />
The adder will be tested using two switches to set the input values, and two LEDs to show the output two-bit value:<br />
<br />
[[Fișier: Dic_lab2_adder_fpga.png]]<br />
<br />
<syntaxhighlight><br />
##Switches<br />
set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS33 } [get_ports { a }]; #SW 0<br />
set_property -dict { PACKAGE_PIN M19 IOSTANDARD LVCMOS33 } [get_ports { b }]; #SW 1<br />
<br />
##LEDs<br />
set_property -dict { PACKAGE_PIN R14 IOSTANDARD LVCMOS33 } [get_ports { c[0] }]; #LED 0<br />
set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { c[1] }]; #LED 1<br />
</syntaxhighlight><br />
<br />
=== Exercise 2 ===<br />
design source file for the 2 by 2 bit multiplier<br />
* operators in expressions<br />
<br />
[[Fișier: app2_mult.png]]<br />
<br />
testbench source file for the 2 by 2 bit multiplier<br />
* control instructions: '''repeat ('''''nrOfIterations''''')'''<br />
* parallel '''initial''' blocks<br />
<br />
=== Exercise 3 ===<br />
design source file for top-level entity<br />
Multilevel hierarchy. Mixed description: top-level - structural description, low-level - behavioral description.<br />
* same module type, different instance names<br />
* internal wires for interinstance connections<br />
<br />
[[Fișier: app2_multsum.png]]<br />
<br />
testbench source file for the top-level entity<br />
* concatenation operator '''{'''''varName1, varName2, ...'''''}'''<br />
* '''$monitor(%b...,'''''varName1,...''''')'''<br />
* format specifiers '''%b''' for binary (logic) values, '''%d''' for decimal values</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_2&diff=7485Applications 22023-03-07T22:39:46Z<p>Zhascsi: </p>
<hr />
<div>=== Exercise 1 : 1 bit adder ===<br />
<br />
==== Module declaration ====<br />
<br />
[[Fișier: Dic_lab2_adder.png]]<br />
<br />
Any Verilog circuit or block is enclosed within the keywords '''module''' and '''endmodule'''.<br />
The '''module''' keyword is followed by the name of the module. This name begins with a letter (Verilog is case-sensitive) or underscore (''_''), uses alphanumeric characters and underscores, and should be a meaningful one (adder, adder_32, counter, lshift_register, Serial_to_Parallel_converter, etc).<br />
<br />
Right after the module name comes the interface description, a list of port declarations, separated by commas and enclosed within parentheses. It is strongly recommended to declare each port on a separate line, even if some ports have the same direction and size. Also it is recommended to group the declarations by their direction.<br />
A port declaration starts with the keyword that defines the port's direction: '''input''' or '''output'''. For one-bit ports the declaration comprises only the direction and the name.<br />
Port names follow the same naming rules used for module names. A port name should be a unique identifier inside the module's code - its scope is limited to the module.<br />
<br />
A multi-bit port declaration defines the width of the port through two indices within brackets and separated by a colon: '''['''''msb''''':'''''lsb''''']'''. The first index denotes the most significant bit (MSB), the second one is the least significant bit. MSB should always be greater than MSB. Usually the LSB index is 0, therefore if the width of the port is ''N'', the first index would be ''N-1''.<br />
<br />
The module declaration comprises the keyword '''module''', the module name and its interface, and ends with a semicolon:<br />
<syntaxhighlight lang="Verilog"><br />
module adder ( // keyword '''module''' followed by the module's name and the opening parenthesis of the interface<br />
input a, // one-bit input port named 'a'<br />
input b, // one-bit input port named 'b'<br />
output [1:0] s // two-bit output port. Bit 1 is MSB, bit 0 is LSB. There is no comma after the last port declaration<br />
); // the closing parenthesis of the interface and the semicolon that ends the module's declaration<br />
</syntaxhighlight><br />
<br />
'''Note:''' All input ports should be variables of '''wire''' type. The '''wire''' type is therefore implicit for port declaration, and may be ommited.<br />
If the output port variable has no explicit type, it is also implicitly of the '''wire''' type.<br />
<br />
==== Module description ====<br />
Anything written between the module's declaration and the keyword '''endmodule''' is part of the module's description.<br />
<br />
A module may be described by ''what'' it does. This is a ''behavioral description''.<br />
Very simple modules could be described using a single instruction, that assigns to the output the result value of an expression over the inputs. Because Verilog is a description language, not a programming language, the assignments that describe how logic values are generated from other logic values are attached to special Verilog keywords. One such keyword is '''assign'''. It is followed by a single assignment: '''assign''' ''y = E(x1, x2, ... xN)''; It is forbidden to use the left-hand variable (''y'') inside the right-hand expression.<br />
<br />
The one-bit adder may be described by a simple expression that computes the output value as the addition of its inputs:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
assign s = a + b; // variable value s is always equal to the sum of a and b <br />
</syntaxhighlight><br />
<br />
The '''assign''' statement describes something that is continuously evaluated. It may be viewed as a small black box with an output and some inputs. The left-hand variable is updated immediately whenever any of the variables in the right-hand expression changes its value. The physical circuit that implements the '''assign''' statement is a combinational logic circuit (CLC) that reacts immediately to any change at its inputs.<br />
<br />
The full code of the ''adder'' module:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder (<br />
input a,<br />
input b,<br />
output [1:0] s<br />
);<br />
<br />
assign s = a + b;<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Testbench module ====<br />
<br />
[[Fișier: Dic_lab2_adder_tb.png]]<br />
<br />
The testbench is another module, therefore it is defined in a separate file. Also, the testbench is a simulation file - it cannot be synthesized and implemented.<br />
Always follow these rules:<br />
* each module is defined in a separate file<br />
* the name of the file is the name of the module, or closely resembles it<br />
<br />
The testbench has no interface. All signals are generated internally. Therefore the testbench declaration has an empty interface list, '''module''' ''testbenchName'''''();''', or the parentheses may be missing at all, '''module''' ''testbenchName''''';'''<br />
<br />
It is recommended to include in the name of the testbench the name of the module to be tested. The testbench for the ''adder'' module may be named ''adder_testbench'', ''test_adder'', ''adder_tb'', a.s.o.<br />
<br />
As for any module, the description follows the module declaration.<br />
The testbench ''instantiates'' the module to be tested and generates values for the signals connected to the inputs of the tested module. The testbench is used only in simulation, it cannot be synthesized. However, this restriction is turned to an advantage because the testbench may use procedural statements freely, as in ordinary programming languages, to generate whatever sequence of values for the stimuli is desired.<br />
<br />
The DUT (device under test) is a block inside the testbench module. It is an ''instance'' of a module. The module is like a blueprint, while the instance is a materialization of that blueprint. For those familiar with object-oriented programming this may sound familiar. The module is like a class, and the instance is an object of that type.<br />
<br />
A module instantiation starts with the ''moduleName'' followed by the ''instanceName'' and the list of its external connections enclosed within parentheses.<br />
Usually, the module instantiated in the testbench is named ''dut'' (device under test). The instance name should be a unique name inside the module where it's instantiated.<br />
<br />
The list of connections connects each port of the instance to a signal of the testbench. It is strongly recommended to write each connection on a separate line. You may write the connections in the same order as in the interface declaration for that module. You should have at most ONE connection for each port, but some ports may be leaved unconnected if they are not used. A connection is declared with a dot ('''.''') immediately followed by the name of the port and finally the name of the signal connected to that port, enclosed in parentheses: '''.'''''modulePin'''''('''''varName''''')'''<br />
. The connections in the list are separated by commas.<br />
<br />
The ''adder'' module is instantiated with the name ''dut''. Its inputs receive signals ''num1'' and ''num2'', and its output is connected to a wire named ''result'':<br />
<br />
<syntaxhighlight lang="Verilog"><br />
adder dut ( // a module of type 'adder' is instantiated. The name of this instance is 'dut'<br />
.a (num1 ), // port 'a' is connected to signal 'num1'<br />
.b (num2 ), // port 'b' is connected to signal 'num2'<br />
.s (result) // port 's' is connected to 'result'. There is no comma after the last connection<br />
); // the closing parenthesis of the interface and the semicolon that ends the module's instantiation<br />
</syntaxhighlight><br />
<br />
All signals and wires connected to an instance should be declared, and the declarations should precede the instantiation.<br />
<br />
The signals connected to the instance inputs are stimuli generated by the testbench. They should be declared as variables of type '''reg'''. The instance outputs should be declared as variables of type '''wire'''. The variable declaration begins with the type ('''reg''' or '''wire''') and ends with the variable's name. We strongly recommend to declare each variable in a separate line. Also, you should NOT initialize a variable in the declaration statement (keep in mind that Verilog is a description language, not a programming language).<br />
For the multi-bit signals the declaration must specify the width, in the same way you declare the width of a multi-bit port in the interface of a module.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
reg num1; // one-bit variable of type reg and named 'num1'<br />
reg num2; // one-bit variable of type reg and named 'num2'<br />
wire [1:0] result; // two-bit variable of type wire and named 'result'<br />
</syntaxhighlight><br />
<br />
As a rule of thumb, keep in mind that any output of an instance could be declared only as a wire, whereas the inputs to an instance are declared of type '''reg''' if you give them values using explicit assignment statements.<br />
<br />
The stimuli for the ''adder'' block are generated as in Laboratory 1, using a Verilog '''initial''' block, inside which you assign values to signals ''num1'' and ''num2''. To thoroughly test the ''adder'' block it is useful to generate all possible combinations of values for those two signals. One such sequence of binary value pairs may be ''00'', ''01'', ''10'', ''11'':<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
num1 = 1'b0; num2 = 1'b0;<br />
#5 num1 = 1'b0; num2 = 1'b1;<br />
#5 num1 = 1'b1; num2 = 1'b0;<br />
#5 num1 = 1'b1; num2 = 1'b1;<br />
#5 $stop;<br />
end<br />
</syntaxhighlight><br />
<br />
'''Note:''' as in Laboratory 1, you may generate the values for ''num1'' and ''num2'' in a single statement, combining them into one two-bit bundle (for example <syntaxhighlight lang="Verilog">{num1, num2} = 2'b01;</syntaxhighlight>)<br />
<br />
The full code of the ''adder'' testbench module:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
module adder_tb;<br />
<br />
// declarations<br />
reg num1;<br />
reg num2;<br />
wire [1:0] result;<br />
<br />
// instantion<br />
adder dut (<br />
.a (num1 ),<br />
.b (num2 ),<br />
.s (result)<br />
); <br />
<br />
// stimuli generation<br />
initial begin<br />
{num1, num2} = 2'b00; // begin with both adder inputs zero<br />
#5 {num1, num2} = 2'b01; // after a delay, change the value of one input of the adder<br />
#5 {num1, num2} = 2'b10; // go to the next combination of values<br />
#5 {num1, num2} = 2'b11;<br />
#5 $stop;<br />
end<br />
<br />
endmodule<br />
</syntaxhighlight><br />
<br />
==== Module simulation ====<br />
<br />
Simulate the ''adder_tb'' testbench and check on the waveforms that the output of the ''adder'' module is indeed the sum of its input values.<br />
<br />
==== Implementation ====<br />
<br />
To implement the adder on the FPGA and to interact with it we should imagine some means to set and to change the adder input values and to see the value of its output. The FPGA board allows us to interact with the circuit implemented inside the FPGA through a couple of switches, some push buttons and various LEDs that are connected to FPGA pins, which may be configured to be wired inside the FPGA to the ports of the implemented module. The FPGA pins assignment is done through the constraints file. For each pin assignment there is a line that instructs the implementation tool to connect the port with a given name to a particular FPGA pin, and also sets the parameters of the I/O pad of that pin. For example<br />
<br />
<syntaxhighlight><br />
set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS33 } [get_ports { num1 }];<br />
</syntaxhighlight><br />
<br />
is a constraint that connects the port num1 to the FPGA pin labelled M20.<br />
<br />
Hopefully, for each FPGA board you may find constraints files with constraints for all FPGA pins, with indications as to which switch, button, LED, a.s.o. is connected towhich FPGA pin. All constraints are commented. You should uncomment only the lines for the switches, buttons, LEDs a.s.o. that you want to use, and replace the port names with the names of ports from your module. For multi-bit ports there must be one separate connection constraint for each port bit, since each port bit needs a separate FPGA pin.<br />
<br />
The adder will be tested using two switches to set the input values, and two LEDs to show the output two-bit value:<br />
<br />
[[Fișier: Dic_lab2_adder_fpga.png]]<br />
<br />
<syntaxhighlight><br />
##Switches<br />
set_property -dict { PACKAGE_PIN M20 IOSTANDARD LVCMOS33 } [get_ports { a }]; #SW 0<br />
set_property -dict { PACKAGE_PIN M19 IOSTANDARD LVCMOS33 } [get_ports { b }]; #SW 1<br />
<br />
##LEDs<br />
set_property -dict { PACKAGE_PIN R14 IOSTANDARD LVCMOS33 } [get_ports { c[0] }]; #LED 0<br />
set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { c[1] }]; #LED 1<br />
</syntaxhighlight><br />
<br />
=== Exercise 2 ===<br />
design source file for the 2 by 2 bit multiplier<br />
* operators in expressions<br />
<br />
[[Fișier: app2_mult.png]]<br />
<br />
testbench source file for the 2 by 2 bit multiplier<br />
* control instructions: '''repeat ('''''nrOfIterations''''')'''<br />
* parallel '''initial''' blocks<br />
<br />
=== Exercise 3 ===<br />
design source file for top-level entity<br />
Multilevel hierarchy. Mixed description: top-level - structural description, low-level - behavioral description.<br />
* same module type, different instance names<br />
* internal wires for interinstance connections<br />
<br />
[[Fișier: app2_multsum.png]]<br />
<br />
testbench source file for the top-level entity<br />
* concatenation operator '''{'''''varName1, varName2, ...'''''}'''<br />
* '''$monitor(%b...,'''''varName1,...''''')'''<br />
* format specifiers '''%b''' for binary (logic) values, '''%d''' for decimal values</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Fi%C8%99ier:Dic_lab2_adder.png&diff=7484Fișier:Dic lab2 adder.png2023-03-07T22:08:09Z<p>Zhascsi: </p>
<hr />
<div></div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Fi%C8%99ier:Dic_lab2_adder_fpga.png&diff=7483Fișier:Dic lab2 adder fpga.png2023-03-07T10:33:51Z<p>Zhascsi: Zhascsi a încărcat o versiune nouă pentru Fișier:Dic lab2 adder fpga.png</p>
<hr />
<div></div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Fi%C8%99ier:Dic_lab2_adder_tb.png&diff=7477Fișier:Dic lab2 adder tb.png2023-03-06T09:57:08Z<p>Zhascsi: Zhascsi a încărcat o versiune nouă pentru Fișier:Dic lab2 adder tb.png</p>
<hr />
<div></div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Fi%C8%99ier:Dic_lab2_adder_tb.png&diff=7476Fișier:Dic lab2 adder tb.png2023-03-06T09:53:56Z<p>Zhascsi: Zhascsi a încărcat o versiune nouă pentru Fișier:Dic lab2 adder tb.png</p>
<hr />
<div></div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Digital_Integrated_Circuits_(lab)&diff=7461Digital Integrated Circuits (lab)2023-02-19T14:16:23Z<p>Zhascsi: Redirecționarea spre Digital Integrated Circuits (old lab) a fost ștearsă</p>
<hr />
<div># [[Applications 1]]<br />
<br />
== Verilog Tutorials ==<br />
* [http://www.asic-world.com/verilog/veritut.html Verilog Tutorial] from ASIC World<br />
* [http://chipverify.com/verilog/verilog-tutorial Verilog Tutorial] from Chip Verify<br />
* [http://www.emmelmann.org/Library/Tutorials/docs/verilog_ref_guide/vlog_ref_top.html Verilog reference guide]<br />
<br />
== Software ==<br />
* [https://www.xilinx.com/products/design-tools/vivado/vivado-ml.html Vivado™ ML Standard Edition free]<br />
* [https://wiki.dcae.pub.ro/images/2/24/VivadoNewProjectTutorial.pdf Vivado New Project Tutorial]<br />
<br />
== Hardware ==<br />
* [https://dpoauwgwqsy2x.cloudfront.net/Download/pynqz2_user_manual_v1_0.pdf Pynq-Z2 - user manual]<br />
* [[Pynq-Z2 - Pinout]].<br />
<br />
* [https://www.realdigital.org/doc/02013cd17602c8af749f00561f88ae21 Boolean Board - user manual]<br />
* [[Boolean Board - Pinout]].</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Main_Page&diff=7460Main Page2023-02-18T22:44:42Z<p>Zhascsi: </p>
<hr />
<div>The purpose of this page is the index the lab tutorials and tasks, as well as the auxiliary resources for the lectures and laboratories taught within the DCAE department.<br />
<br />
== Course List ==<br />
<br />
* [[Integrated Digital Circuits (lecture)]]<br />
* [[Data Structures and Algorithms]]<br />
* [[Power Semiconductor Devices]]<br />
<br />
== Laboratories List ==<br />
* [[Advanced Digital Systems]]<br />
* [[Data Structures and Algorithms (lab)]]<br />
* [[Digital Integrated Circuits (lab)|Digital Integrated Circuits]]<br />
* [[Digital Integrated Circuits (old lab)|Digital Integrated Circuits - old]]<br />
* [[Object Oriented Programming]]<br />
* [[Power Semiconductor Devices (lab)]]<br />
* [[Digital Systems Design - Project]]<br />
* [[Electronic Devices(lab)]]<br />
* [[Electronic Circuits(lab)]]<br />
<br />
== Seminaries List ==<br />
* [[Digital Integrated Circuits (sem)|Digital Integrated Circuits]]<br />
<br />
== Applications List ==<br />
* [[Digital Integrated Circuits (app)|Digital Integrated Circuits]]<br />
<br />
== Project List ==<br />
* [[Project 1 - Electronic Devices and Circuits |Electronic Devices and Circuits (Project 1)]]<br />
<br />
* [[Project Master |Project Master]]<br />
<br />
== Evaluation Forms ==<br />
* [[Evaluation Forms 2014-2015, Semester I]]<br />
* [[Evaluation Forms 2014-2015, Semester II]]</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Digital_Integrated_Circuits_(lab)&diff=7459Digital Integrated Circuits (lab)2023-02-18T22:43:47Z<p>Zhascsi: Zhascsi a redenumit pagina Digital Integrated Circuits (lab) în Digital Integrated Circuits (old lab)</p>
<hr />
<div>#REDIRECTEAZA [[Digital Integrated Circuits (old lab)]]</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Digital_Integrated_Circuits_(old_lab)&diff=7458Digital Integrated Circuits (old lab)2023-02-18T22:43:45Z<p>Zhascsi: Zhascsi a redenumit pagina Digital Integrated Circuits (lab) în Digital Integrated Circuits (old lab)</p>
<hr />
<div>== The Purpose of this Laboratory ==<br />
<br />
The purpose of the Digital Integrated Circuits laboratory is to introduce to students the necessary concepts for the digital design, and assimilation of a new language, Verilog, used for hardware description, as well as the familiarization with some software tools for simulation and synthesis. <br />
<br />
== Rules and Regulations ==<br />
<br />
The following rules apply to activities in Digital Integrated Circuits laboratory. <br />
* Laboratory activities are spread in 7 sessions where of 100 minutes each, and will consist in solving of various practical exercises and fulfilling the requirements indicated in laboratory platforms and by the instructor. <br />
* Students may be absent with the condition of recovering it later on with another group which is approved by an instructor. Any student has the right to do extra work or recover a lab session with another group at any time, but they will not have the priority over the workstations in the laboratory. <br />
* Only up to 14 students are allowed in laboratory room, where each of them will use a separate computer. Groups shall split in 2 semi-groups. Exceptionally, a student may choose to attend with another group from very beginning, but only if the semi-groups are incomplete.<br />
* The student evaluation will be made based on resolving the given assignments (50pts) and a lab-exam which will be held on the last laboratory session (50pts). Passive attendance doesn't count as a score. <br />
** The assignments will be given to students during the laboratory sessions, where each assignment is the evaluation of the related laboratory concepts. <br />
*** The assignments will be fulfilled during the laboratory session and at the end of each laboratory session, fulfilled assignments will be sent to instructor via email. <br />
*** Submitted assignments will be checked automatically against plagiarism and the grades will be graded according to a scale statement that will be sent to students with the assignment. <br />
*** Plagiarism of an assignment will lead to the loss of the whole grade of the related laboratory session. <br />
** Lab-exam consists of an implementation of a digital circuit, described in Verilog, using the knowledge that is gained during the laboratory sessions. <br />
* Failing this laboratory automatically leads to repeating it in one of the following academic years. On this subject there are no supplementary exams!<br />
* Besides the first laboratory session, it is mandatory that students read the laboratory platforms before the lab-session. In the first part of the lab, questions should be asked to clarify things that have not been understood after reading the platform.<br />
* While leaving laboratory room, do not shut down the computers. <br />
* Written Verilog models can be transferred at the beginning or at the end of the laboratory using personal email address. <br />
* Any damages of laboratory platforms, laboratory equipment, connection cables or computers (made intentionally by a student), will be given the grade 4 (Final Grade) for the subject. “ Damages made by the intentions of a student” mean:<br />
** Touching the metal parts of circuits which are sensitive to electrostatic discharge (MOS);<br />
** Changing the position of jumpers that will lead to circuit/PCB burn (without adequate understanding of circuit operation) <br />
** Bending probes and sensors, breaking the cables, or joints and couplings.<br />
** Damaging the laboratory equipment with improper measurements. (Measuring the voltage with ampere-meter, using the oscilloscope on a maximum sensitivity scale for measuring high voltages, shorting the output of a signal generator, shorting the power supply output, application of improper voltages to the test boards) or by applying improper voltages to the measured circuits; <br />
** Any physical intervention or rough handling of the case or switches of the panel;<br />
** Connecting the test boards with other electronic equipments while they are powered on.<br />
*Instructor will provide the following services for students:<br />
** Over the first ten minutes of each lab, Instructor will answer the questions of students about the previous labs and the questions regarding current lab materials that must have been read by students at home;<br />
** All the relevant questions from students about the ongoing laboratory will be answered. <br />
** In case a student asks a question that shows him/her not being prepared for the ongoing laboratory, then the student will be guided to find the info in the platform and will be politely asked to read the appropriate paragraph.<br />
** Classes will start at scheduled time, with maximum punctuality.<br />
<br />
== Tutorials and documentations == <br />
# Introduction. [[Verilog_EN]] syntax<br />
# [[Introduction to FPGA synthesis. Xilinx ISE.]] [[Xilinx ISE (13.4) Tutorial]]<br />
# [[Quartus_II_tutorial | Using the Altera Quartus II Synthesis Program]]<br />
# [[ROM Memory]]. [[IO_Device:_Segment_7_segment_display|IO_Device: The 7 segment display]]. [[Sequential_Circuits]].[[The Counter]].<br />
# [[RAM_Memory]]. [[The Debounce circuit]].<br />
# [[The Frequency Divider]]. [[The Variable Duty-Cycle Generator]]. [[The Decoder]].<br />
# [[Automata]]. [[PS2 keyboard]].<br />
<br />
== Laboratory works ==<br />
# [[DIC Lab Work 0]]<br />
# [[DIC Lab Work 1]]<br />
# [[DIC Lab Work 2]]<br />
# [[DIC Lab Work 3]]<br />
# [[DIC Lab Work 4]]<br />
# [[DIC Lab Work 5]]<br />
<br />
== Installation Tutorial for Xilinx ISE ==<br />
<br />
You may download the installation kit for the last version of Xilinx ISE WebPack from the company’s [http://www.xilinx.com/support/download/index.htm official Xilinx website]. Then select the appropriate version for your operating system. To continue, it is necessary to create an account. The installation kit is compressed into an archive file tar.gz. If you are using the Windows operating system, then you will need a special program to unpack the respective file. [http://www.7-zip.org/ 7-zip] is one of the options. <br />
<br />
You may also download the Xilinx ISE 14.7 from our department’s website: ftp://hermes.arh.pub.ro/public/kits/Xilinx_ISE_DS_14.7_1015_1.tar<br />
<br />
=== Installation on Windows ===<br />
<br />
First of all, download and install the setup kit of 7-zip. Unpack the files into a temporary folder ( you can remove them once installed the program). Then run the executable file setup.exe.<br />
In the window that asks you which edition you want to install, select ISE WebPACK. It is the only type of installation that does not require a license.<br />
In the window with installation options, select only Use multiple CPU cores for installer archive extraction(if applicable) also Aquire or Manage a License Key.<br />
As the last step you must select the destination folder for installation. And finally, remember to delete the temporary folder.<br />
After the installation is done, start Xilinx License Configuration Manager. Choose Get Free ISE WebPACK License and follow the instructions.<br />
<br />
=== Installation on Linux ===<br />
Once the setup kit is downloaded, it should be unpacked in a temporary folder. (So you can remove them once the program is installed). To install the software for all users on a Linux system, you must have rootprivileges. For this open a console and type: <br />
<syntaxhighlight lang="bash"><br />
su -<br />
</syntaxhighlight><br />
Next you will be asked for the root password. On Ubuntu, where the root has no password set by default, type:<br />
<syntaxhighlight lang="bash"><br />
sudo su -<br />
</syntaxhighlight><br />
<br />
Next you will be asked your user password.<br />
We will unpack the kit in the folder /tmp/. To do this, type:<br />
<syntaxhighlight lang="bash"><br />
mkdir/tmp/xilinx<br />
cd/tmp/xilinx<br />
tar-xf ~/Downloads/Xilinx_ISE_DS_Lin_13.4_O.87xd.3.0.tar<br />
</syntaxhighlight><br />
<br />
Let's consider that you have downloaded the setup kit to the folder Downloads from personal Home. If it is elsewhere, or if it has another name, change the path to the archive file.<br />
<br />
Now you must run the installer. Type:<br />
<syntaxhighlight lang="bash"><br />
cd/tmp/xilinx/Xilinx_ISE_DS_Lin_13.4_O.87xd.3.0/<br />
./xsetup.sh<br />
</syntaxhighlight><br />
<br />
== External Links ==<br />
# https://www.youtube.com/watch?v=lNuPy-r1GuQ - The Binary Logic explained with domino pieces.</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Laboratorul_1&diff=7419Laboratorul 12022-10-04T19:56:07Z<p>Zhascsi: /* REGS */</p>
<hr />
<div>=== ALU ===<br />
Unitatea aritmetico-logică, ALU, este responsabilă de execuţia instrucţiunilor.<br />
În primul rând, după cum ne şi sugerează numele, instrucţiunile aritmetice şi cele logice, dar şi celelalte categorii de instrucţiuni, în execuţia cărora intervin operaţii precum calculul unor adrese pentru instrucţiunile de acces la memorie sau pentru instrucţiunile de salt relativ.<br />
Concret, ALU primeşte operanzii unei instrucţiuni şi oferă rezultatul operaţiei specificate în codul instrucţiunii. De exemplu instrucţiunea de adunare determină în ALU adunarea celor doi operanzi de la intrare, suma acestora (rezultatul) apărând la ieşirea ALU. Un alt exemplu, instrucţiunea de salt relativ determină în ALU adunarea a două numere, valoarea contorului de program (PC) şi valoarea saltului relativ specificată în corpul instrucţiunii, rezultatul fiind noua valoare de contor de program, ce va fi încărcată în contorul de program.<br />
<br />
Complexitatea ALU este determinată în primul rând de complexitatea operaţiilor aritmetice ale instrucţiunilor din setul de instrucţiuni, însă depinde, uneori semnificativ, şi de performanţele avute în vedere (viteză, paralelism, consum redus) ce pot modifica radical structura aleasă.<br />
La nivel funcţional, fără a fi preocupaţi de implementarea efectivă, ALU poate fi privit ca un bloc multifuncţional a cărui funcţie este selectată de codul operaţiei instrucţiunii:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
always @(*) begin<br />
case(opcode)<br />
4'b0001: result = operand1 + operand2;<br />
4'b0010: result = operand1 - operand2;<br />
// urmeaza implementarea altor operatii<br />
endcase<br />
end<br />
</syntaxhighlight><br />
<br />
Descrieți funcțional (comportamental) un ALU de 8 biți ce execută operațiile din tabelul 1.<br />
<br />
[[Fișier: asc_lab1_alu.png]]<br />
<br />
{| class="wikitable" style="text-align: center;<br />
|+ Tabelul 1<br />
!opcode !! operație !! detalii<br />
|-<br />
| <code>ADD</code> || adunare ||<br />
|-<br />
| <code>SUB</code> || scădere || operandul 2 se scade din operandul 1<br />
|-<br />
| <code>AND</code> || ȘI logic || fiecare bit al rezultatului este ȘI logic între biții corespunzători ai operanzilor<br />
|-<br />
| <code>OR</code> || SAU logic || fiecare bit al rezultatului este SAU logic între biții corespunzători ai operanzilor<br />
|-<br />
| <code>XOR</code> || XOR logic || fiecare bit al rezultatului este SAU-EXCLUSIV logic între biții corespunzători ai operanzilor<br />
|-<br />
| <code>CMP</code> || comparație || Z și N se modifică conform tabelului 2<br />
|-<br />
| <code>LOAD</code> || transfer|| operandul2 este transferat la ieșirea ALU<br />
|- <br />
| <code>STORE</code> || transfer|| operandul2 este transferat la ieșirea ALU<br />
|}<br />
<br />
Tabelul 1 nu conține toate instrucțiunile setului de instrucțiuni, ci numai instrucțiunile care folosesc ALU. Pentru instrucțiunile ce nu folosesc ALU implementarea execuției lor în ALU poate fi ignorată, dar rezultatul de la ieșirea ALU nu trebuie scris în vreun registru.<br />
<br />
Rezultatul operației de comparație este semnalizat prin biții indicatori ai rezultatului:<br />
<br />
{| class="wikitable" style="text-align: center;<br />
|+ Tabelul 2<br />
! !! Z !! N<br />
|-<br />
| operand1 > operand2 || 0 || 0<br />
|-<br />
| operand1 = operand2 || 1 || 0<br />
|-<br />
| operand1 < operand2 || 0 || 1<br />
|}<br />
<br />
Biții indicatori sunt calculați pentru fiecare operație și reflectă starea rezultatului. Procesorul implementat în laborator are doi indicatori, '''Z''' și '''N'''. Dacă rezultatul este zero se activează bitul '''Z''' (zero). Dacă rezultatul este negativ se activează ieșirea '''N''' (negativ). Operația de comparație poate fi implementată ca o operație de scădere fără destinație (se salvează în procesor doar biții indicatori nu și rezultatul):<br />
<br />
<syntaxhighlight lang="Verilog"><br />
assign Z = (result == 0);<br />
assign N = result[7]; // în complement față de 2 bitul MSB este bit de semn<br />
</syntaxhighlight><br />
<br />
=== REGS ===<br />
<br />
Setul de registre are 16 registre de 8 biți. Fiecare registru poate fi sursa oricărui operand și poate fi destinație.<br />
Setul de registre poate avea porturi distincte pentru scriere și pentru citire, precum și porturi separate pentru fiecare operand citit.<br />
Implementarea aleasă pentru acest laborator are un set de registre cu trei porturi, un port pentru citirea primului operand ('''raddr1''', '''rdata1'''), altul pentru citirea celui de al doilea operand ('''raddr2''', '''rdata2''') și un port pentru scriere ('''waddr''', '''wdata'''). Portul de scriere folosește un semnal de control, '''wen''', ce activează scrierea numai pentru anumite instrucțiuni. Pentru accesul la un registru este nevoie de o adresă de 4 biți. Semnalele de adresă '''raddr1''', '''raddr2''' și '''waddr''' sunt de 4 biți. Datele sunt pe 8 biți, prin urmare registrele, ieșirile de date '''rdata1''' și '''rdata2''', dar și intrarea de date '''wdata''' sunt fiecare de câte 8 biți.<br />
<br />
[[Fișier: asc_lab1_regs.png]]<br />
<br />
Scrierea în setul de registre este secvențială, pe frontul semnalului de ceas de la intrarea '''clk''' (nereprezentată în figura de mai sus).<br />
<br />
<syntaxhighlight lang="Verilog"><br />
reg [7:0] registru [0:15]; // set de 16 registre a câte 8 biți fiecare<br />
<br />
// portul de scriere<br />
always @(posedge clk) begin<br />
if(wen) registru[waddr] <= wdata; // scriere sincronă - pe ceas - a valorii de la intrarea de date wdata în registrul destinație<br />
end<br />
<br />
// portul 1 de citire<br />
assign rdata1 = registru[raddr1]; // ieșirea rdata1 este valoarea din registrul cu numărul raddr1<br />
// portul 2 de citire<br />
// <- completați codul<br />
</syntaxhighlight><br />
<br />
=== RALU ===<br />
<br />
Unitatea aritmetico-logică împreună cu setul de registre formează RALU (Register and ALU).<br />
<br />
[[Fișier: asc_lab1_ralu.png]]<br />
<br />
=== validare RALU ===<br />
<br />
Scrieti un modul de testare ce instanțiază setul de registre și ALU, generează ceasul, semnalul de reset și o secvență de instrucțiuni.<br />
<br />
==== generarea ceasului ====<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
clk = 0; // initialization at time 0<br />
forever #10 clk = ~clk; // toggle the clock at each 10 simulation steps<br />
end<br />
</syntaxhighlight><br />
<br />
==== generarea semnalului de reset ====<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
rst = 0;<br />
#13 rst = 1; // reset activ în 1 logic<br />
#20 rst = 0;<br />
end<br />
</syntaxhighlight><br />
<br />
Întîrzierile sunt alese astfel încât fronturile semnalului de reset să nu coincidă cu fronturile ceasului.<br />
<br />
==== generarea secvenței de instrucțiuni ====<br />
<br />
La fiecare ceas se setează valorile intrărilor '''opcode''', '''sursa1''', '''sursa2''', '''dest''' și '''wen''' cu valori care să corespundă instrucțiunii dorite.<br />
Pentru a ne asigura că toate semnalele se modifică numai după frontul activ al ceasului, vom aștepta de fiecare dată acest front folosind instrucțiunea <syntaxhighlight lang="Verilog" inline>@(posedge clk);</syntaxhighlight><br />
Semnalul '''wen''' se setează la '''1''' sau la '''0''' după cum dorim ca '''wdata''' să se salveze sau nu în registrul destinație.<br />
Semnalul '''wen''' nu face parte din instrucțiune. În laboratorul 2 el va fi generat de unitatea de control a procesorului (UCP) în funcție de codul instrucțiunii. De exemplu instrucțiunea CMP nu modifică niciun registru ci doar biții indicatori, prin urmare '''wen''' va fi în permanență '''0''' pe durata procesării acestei instrucțiuni.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
opcode = 4'b0000; dest = 4'd0; sursa1 = 4'd0; sursa2 = 4'd0; wen = 1'b0;<br />
#26 // se așteaptă finalizarea resetului<br />
@(posedge clk);<br />
opcode = 4'b0001; dest = 4'd7; sursa1 = 4'd6; sursa2 = 4'd5; wen = 1'b1; // ADD R7 R6 R5 // R7 <- R6 + R5<br />
@(posedge clk);<br />
opcode = 4'b0010; dest = 4'd7; sursa1 = 4'd7; sursa2 = 4'd4; wen = 1'b1; // SUB R7 R7 R4 // R7 <- R7 - R4<br />
// alte instrucțiuni<br />
end<br />
</syntaxhighlight><br />
<br />
=== initializarea valorilor in registre ===<br />
<br />
Se poate face a) la reset, dacă modulul are intrare de reset, sau b) într-un bloc '''initial''' folosit doar pentru simulare.<br />
<br />
a)<br />
<br />
<syntaxhighlight lang="Verilog"><br />
always @(posedge clk) begin<br />
if(rst) begin<br />
registru[0] = 13;<br />
. . . <br />
end<br />
else begin<br />
if(wen) . . .<br />
end<br />
end<br />
</syntaxhighlight><br />
<br />
b)<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
registru[0] = 13;<br />
registru[1] = 27;<br />
. . . .<br />
end<br />
</syntaxhighlight><br />
<br />
Dacă blocul '''initial''' este scris în modulul de testare iar variabilele inițializate sunt din interiorul modului testat sau chiar dintr-un submodul al acestuia, numele acestora trebuie să fie complet, corespunzător ierarhiei.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
ralu.regs.registru[0] = 13;<br />
</syntaxhighlight></div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Laboratorul_1&diff=7418Laboratorul 12022-10-04T19:53:58Z<p>Zhascsi: /* generarea secvenței de instrucțiuni */</p>
<hr />
<div>=== ALU ===<br />
Unitatea aritmetico-logică, ALU, este responsabilă de execuţia instrucţiunilor.<br />
În primul rând, după cum ne şi sugerează numele, instrucţiunile aritmetice şi cele logice, dar şi celelalte categorii de instrucţiuni, în execuţia cărora intervin operaţii precum calculul unor adrese pentru instrucţiunile de acces la memorie sau pentru instrucţiunile de salt relativ.<br />
Concret, ALU primeşte operanzii unei instrucţiuni şi oferă rezultatul operaţiei specificate în codul instrucţiunii. De exemplu instrucţiunea de adunare determină în ALU adunarea celor doi operanzi de la intrare, suma acestora (rezultatul) apărând la ieşirea ALU. Un alt exemplu, instrucţiunea de salt relativ determină în ALU adunarea a două numere, valoarea contorului de program (PC) şi valoarea saltului relativ specificată în corpul instrucţiunii, rezultatul fiind noua valoare de contor de program, ce va fi încărcată în contorul de program.<br />
<br />
Complexitatea ALU este determinată în primul rând de complexitatea operaţiilor aritmetice ale instrucţiunilor din setul de instrucţiuni, însă depinde, uneori semnificativ, şi de performanţele avute în vedere (viteză, paralelism, consum redus) ce pot modifica radical structura aleasă.<br />
La nivel funcţional, fără a fi preocupaţi de implementarea efectivă, ALU poate fi privit ca un bloc multifuncţional a cărui funcţie este selectată de codul operaţiei instrucţiunii:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
always @(*) begin<br />
case(opcode)<br />
4'b0001: result = operand1 + operand2;<br />
4'b0010: result = operand1 - operand2;<br />
// urmeaza implementarea altor operatii<br />
endcase<br />
end<br />
</syntaxhighlight><br />
<br />
Descrieți funcțional (comportamental) un ALU de 8 biți ce execută operațiile din tabelul 1.<br />
<br />
[[Fișier: asc_lab1_alu.png]]<br />
<br />
{| class="wikitable" style="text-align: center;<br />
|+ Tabelul 1<br />
!opcode !! operație !! detalii<br />
|-<br />
| <code>ADD</code> || adunare ||<br />
|-<br />
| <code>SUB</code> || scădere || operandul 2 se scade din operandul 1<br />
|-<br />
| <code>AND</code> || ȘI logic || fiecare bit al rezultatului este ȘI logic între biții corespunzători ai operanzilor<br />
|-<br />
| <code>OR</code> || SAU logic || fiecare bit al rezultatului este SAU logic între biții corespunzători ai operanzilor<br />
|-<br />
| <code>XOR</code> || XOR logic || fiecare bit al rezultatului este SAU-EXCLUSIV logic între biții corespunzători ai operanzilor<br />
|-<br />
| <code>CMP</code> || comparație || Z și N se modifică conform tabelului 2<br />
|-<br />
| <code>LOAD</code> || transfer|| operandul2 este transferat la ieșirea ALU<br />
|- <br />
| <code>STORE</code> || transfer|| operandul2 este transferat la ieșirea ALU<br />
|}<br />
<br />
Tabelul 1 nu conține toate instrucțiunile setului de instrucțiuni, ci numai instrucțiunile care folosesc ALU. Pentru instrucțiunile ce nu folosesc ALU implementarea execuției lor în ALU poate fi ignorată, dar rezultatul de la ieșirea ALU nu trebuie scris în vreun registru.<br />
<br />
Rezultatul operației de comparație este semnalizat prin biții indicatori ai rezultatului:<br />
<br />
{| class="wikitable" style="text-align: center;<br />
|+ Tabelul 2<br />
! !! Z !! N<br />
|-<br />
| operand1 > operand2 || 0 || 0<br />
|-<br />
| operand1 = operand2 || 1 || 0<br />
|-<br />
| operand1 < operand2 || 0 || 1<br />
|}<br />
<br />
Biții indicatori sunt calculați pentru fiecare operație și reflectă starea rezultatului. Procesorul implementat în laborator are doi indicatori, '''Z''' și '''N'''. Dacă rezultatul este zero se activează bitul '''Z''' (zero). Dacă rezultatul este negativ se activează ieșirea '''N''' (negativ). Operația de comparație poate fi implementată ca o operație de scădere fără destinație (se salvează în procesor doar biții indicatori nu și rezultatul):<br />
<br />
<syntaxhighlight lang="Verilog"><br />
assign Z = (result == 0);<br />
assign N = result[7]; // în complement față de 2 bitul MSB este bit de semn<br />
</syntaxhighlight><br />
<br />
=== REGS ===<br />
<br />
Setul de registre are 16 registre de 8 biți. Fiecare registru poate fi sursa oricărui operand și poate fi destinație.<br />
Setul de registre poate avea porturi distincte pentru scriere și pentru citire, precum și porturi separate pentru fiecare operand citit.<br />
Implementarea aleasă pentru acest laborator are un set de registre cu trei porturi, un port pentru citirea primului operand ('''raddr1''', '''rdata1'''), altul pentru citirea celui de al doilea operand ('''raddr2''', '''rdata2''') și un port pentru scriere ('''waddr''', '''wdata'''). Portul de scriere folosește un semnal de control, '''wen''', ce activează scrierea numai pentru anumite instrucțiuni. Pentru accesul la un registru este nevoie de o adresă de 4 biți. Semnalele de adresă '''raddr1''', '''raddr2''' și '''waddr''' sunt de 4 biți. Datele sunt pe 8 biți, prin urmare registrele, ieșirile de date '''rdata1''' și '''rdata2''', dar și intrarea de date '''wdata''' sunt fiecare de câte 8 biți.<br />
<br />
[[Fișier: asc_lab1_regs.png]]<br />
<br />
Scrierea în setul de registre este secvențială, pe frontul semnalului de ceas de la intrarea '''clk''' (nereprezentată în figura de mai sus).<br />
<br />
<syntaxhighlight lang="Verilog"><br />
reg [7:0] registru [0:15]; // set de 16 registre a câte 8 biți fiecare<br />
<br />
// portul de scriere<br />
always @(posedge clk) begin<br />
if(wen) registru[waddr] <= wdata; // scriere sincronă - pe ceas - a rezultatului în registrul destinație<br />
end<br />
<br />
// portul 1 de citire<br />
assign rdata1 = registru[raddr1]; // ieșirea rdata1 este valoarea din registrul cu numărul raddr1<br />
// portul 2 de citire<br />
// <- completați codul<br />
</syntaxhighlight><br />
<br />
=== RALU ===<br />
<br />
Unitatea aritmetico-logică împreună cu setul de registre formează RALU (Register and ALU).<br />
<br />
[[Fișier: asc_lab1_ralu.png]]<br />
<br />
=== validare RALU ===<br />
<br />
Scrieti un modul de testare ce instanțiază setul de registre și ALU, generează ceasul, semnalul de reset și o secvență de instrucțiuni.<br />
<br />
==== generarea ceasului ====<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
clk = 0; // initialization at time 0<br />
forever #10 clk = ~clk; // toggle the clock at each 10 simulation steps<br />
end<br />
</syntaxhighlight><br />
<br />
==== generarea semnalului de reset ====<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
rst = 0;<br />
#13 rst = 1; // reset activ în 1 logic<br />
#20 rst = 0;<br />
end<br />
</syntaxhighlight><br />
<br />
Întîrzierile sunt alese astfel încât fronturile semnalului de reset să nu coincidă cu fronturile ceasului.<br />
<br />
==== generarea secvenței de instrucțiuni ====<br />
<br />
La fiecare ceas se setează valorile intrărilor '''opcode''', '''sursa1''', '''sursa2''', '''dest''' și '''wen''' cu valori care să corespundă instrucțiunii dorite.<br />
Pentru a ne asigura că toate semnalele se modifică numai după frontul activ al ceasului, vom aștepta de fiecare dată acest front folosind instrucțiunea <syntaxhighlight lang="Verilog" inline>@(posedge clk);</syntaxhighlight><br />
Semnalul '''wen''' se setează la '''1''' sau la '''0''' după cum dorim ca '''wdata''' să se salveze sau nu în registrul destinație.<br />
Semnalul '''wen''' nu face parte din instrucțiune. În laboratorul 2 el va fi generat de unitatea de control a procesorului (UCP) în funcție de codul instrucțiunii. De exemplu instrucțiunea CMP nu modifică niciun registru ci doar biții indicatori, prin urmare '''wen''' va fi în permanență '''0''' pe durata procesării acestei instrucțiuni.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
opcode = 4'b0000; dest = 4'd0; sursa1 = 4'd0; sursa2 = 4'd0; wen = 1'b0;<br />
#26 // se așteaptă finalizarea resetului<br />
@(posedge clk);<br />
opcode = 4'b0001; dest = 4'd7; sursa1 = 4'd6; sursa2 = 4'd5; wen = 1'b1; // ADD R7 R6 R5 // R7 <- R6 + R5<br />
@(posedge clk);<br />
opcode = 4'b0010; dest = 4'd7; sursa1 = 4'd7; sursa2 = 4'd4; wen = 1'b1; // SUB R7 R7 R4 // R7 <- R7 - R4<br />
// alte instrucțiuni<br />
end<br />
</syntaxhighlight><br />
<br />
=== initializarea valorilor in registre ===<br />
<br />
Se poate face a) la reset, dacă modulul are intrare de reset, sau b) într-un bloc '''initial''' folosit doar pentru simulare.<br />
<br />
a)<br />
<br />
<syntaxhighlight lang="Verilog"><br />
always @(posedge clk) begin<br />
if(rst) begin<br />
registru[0] = 13;<br />
. . . <br />
end<br />
else begin<br />
if(wen) . . .<br />
end<br />
end<br />
</syntaxhighlight><br />
<br />
b)<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
registru[0] = 13;<br />
registru[1] = 27;<br />
. . . .<br />
end<br />
</syntaxhighlight><br />
<br />
Dacă blocul '''initial''' este scris în modulul de testare iar variabilele inițializate sunt din interiorul modului testat sau chiar dintr-un submodul al acestuia, numele acestora trebuie să fie complet, corespunzător ierarhiei.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
ralu.regs.registru[0] = 13;<br />
</syntaxhighlight></div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Laboratorul_1&diff=7417Laboratorul 12022-10-04T18:23:53Z<p>Zhascsi: </p>
<hr />
<div>=== ALU ===<br />
Unitatea aritmetico-logică, ALU, este responsabilă de execuţia instrucţiunilor.<br />
În primul rând, după cum ne şi sugerează numele, instrucţiunile aritmetice şi cele logice, dar şi celelalte categorii de instrucţiuni, în execuţia cărora intervin operaţii precum calculul unor adrese pentru instrucţiunile de acces la memorie sau pentru instrucţiunile de salt relativ.<br />
Concret, ALU primeşte operanzii unei instrucţiuni şi oferă rezultatul operaţiei specificate în codul instrucţiunii. De exemplu instrucţiunea de adunare determină în ALU adunarea celor doi operanzi de la intrare, suma acestora (rezultatul) apărând la ieşirea ALU. Un alt exemplu, instrucţiunea de salt relativ determină în ALU adunarea a două numere, valoarea contorului de program (PC) şi valoarea saltului relativ specificată în corpul instrucţiunii, rezultatul fiind noua valoare de contor de program, ce va fi încărcată în contorul de program.<br />
<br />
Complexitatea ALU este determinată în primul rând de complexitatea operaţiilor aritmetice ale instrucţiunilor din setul de instrucţiuni, însă depinde, uneori semnificativ, şi de performanţele avute în vedere (viteză, paralelism, consum redus) ce pot modifica radical structura aleasă.<br />
La nivel funcţional, fără a fi preocupaţi de implementarea efectivă, ALU poate fi privit ca un bloc multifuncţional a cărui funcţie este selectată de codul operaţiei instrucţiunii:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
always @(*) begin<br />
case(opcode)<br />
4'b0001: result = operand1 + operand2;<br />
4'b0010: result = operand1 - operand2;<br />
// urmeaza implementarea altor operatii<br />
endcase<br />
end<br />
</syntaxhighlight><br />
<br />
Descrieți funcțional (comportamental) un ALU de 8 biți ce execută operațiile din tabelul 1.<br />
<br />
[[Fișier: asc_lab1_alu.png]]<br />
<br />
{| class="wikitable" style="text-align: center;<br />
|+ Tabelul 1<br />
!opcode !! operație !! detalii<br />
|-<br />
| <code>ADD</code> || adunare ||<br />
|-<br />
| <code>SUB</code> || scădere || operandul 2 se scade din operandul 1<br />
|-<br />
| <code>AND</code> || ȘI logic || fiecare bit al rezultatului este ȘI logic între biții corespunzători ai operanzilor<br />
|-<br />
| <code>OR</code> || SAU logic || fiecare bit al rezultatului este SAU logic între biții corespunzători ai operanzilor<br />
|-<br />
| <code>XOR</code> || XOR logic || fiecare bit al rezultatului este SAU-EXCLUSIV logic între biții corespunzători ai operanzilor<br />
|-<br />
| <code>CMP</code> || comparație || Z și N se modifică conform tabelului 2<br />
|-<br />
| <code>LOAD</code> || transfer|| operandul2 este transferat la ieșirea ALU<br />
|- <br />
| <code>STORE</code> || transfer|| operandul2 este transferat la ieșirea ALU<br />
|}<br />
<br />
Tabelul 1 nu conține toate instrucțiunile setului de instrucțiuni, ci numai instrucțiunile care folosesc ALU. Pentru instrucțiunile ce nu folosesc ALU implementarea execuției lor în ALU poate fi ignorată, dar rezultatul de la ieșirea ALU nu trebuie scris în vreun registru.<br />
<br />
Rezultatul operației de comparație este semnalizat prin biții indicatori ai rezultatului:<br />
<br />
{| class="wikitable" style="text-align: center;<br />
|+ Tabelul 2<br />
! !! Z !! N<br />
|-<br />
| operand1 > operand2 || 0 || 0<br />
|-<br />
| operand1 = operand2 || 1 || 0<br />
|-<br />
| operand1 < operand2 || 0 || 1<br />
|}<br />
<br />
Biții indicatori sunt calculați pentru fiecare operație și reflectă starea rezultatului. Procesorul implementat în laborator are doi indicatori, '''Z''' și '''N'''. Dacă rezultatul este zero se activează bitul '''Z''' (zero). Dacă rezultatul este negativ se activează ieșirea '''N''' (negativ). Operația de comparație poate fi implementată ca o operație de scădere fără destinație (se salvează în procesor doar biții indicatori nu și rezultatul):<br />
<br />
<syntaxhighlight lang="Verilog"><br />
assign Z = (result == 0);<br />
assign N = result[7]; // în complement față de 2 bitul MSB este bit de semn<br />
</syntaxhighlight><br />
<br />
=== REGS ===<br />
<br />
Setul de registre are 16 registre de 8 biți. Fiecare registru poate fi sursa oricărui operand și poate fi destinație.<br />
Setul de registre poate avea porturi distincte pentru scriere și pentru citire, precum și porturi separate pentru fiecare operand citit.<br />
Implementarea aleasă pentru acest laborator are un set de registre cu trei porturi, un port pentru citirea primului operand ('''raddr1''', '''rdata1'''), altul pentru citirea celui de al doilea operand ('''raddr2''', '''rdata2''') și un port pentru scriere ('''waddr''', '''wdata'''). Portul de scriere folosește un semnal de control, '''wen''', ce activează scrierea numai pentru anumite instrucțiuni. Pentru accesul la un registru este nevoie de o adresă de 4 biți. Semnalele de adresă '''raddr1''', '''raddr2''' și '''waddr''' sunt de 4 biți. Datele sunt pe 8 biți, prin urmare registrele, ieșirile de date '''rdata1''' și '''rdata2''', dar și intrarea de date '''wdata''' sunt fiecare de câte 8 biți.<br />
<br />
[[Fișier: asc_lab1_regs.png]]<br />
<br />
Scrierea în setul de registre este secvențială, pe frontul semnalului de ceas de la intrarea '''clk''' (nereprezentată în figura de mai sus).<br />
<br />
<syntaxhighlight lang="Verilog"><br />
reg [7:0] registru [0:15]; // set de 16 registre a câte 8 biți fiecare<br />
<br />
// portul de scriere<br />
always @(posedge clk) begin<br />
if(wen) registru[waddr] <= wdata; // scriere sincronă - pe ceas - a rezultatului în registrul destinație<br />
end<br />
<br />
// portul 1 de citire<br />
assign rdata1 = registru[raddr1]; // ieșirea rdata1 este valoarea din registrul cu numărul raddr1<br />
// portul 2 de citire<br />
// <- completați codul<br />
</syntaxhighlight><br />
<br />
=== RALU ===<br />
<br />
Unitatea aritmetico-logică împreună cu setul de registre formează RALU (Register and ALU).<br />
<br />
[[Fișier: asc_lab1_ralu.png]]<br />
<br />
=== validare RALU ===<br />
<br />
Scrieti un modul de testare ce instanțiază setul de registre și ALU, generează ceasul, semnalul de reset și o secvență de instrucțiuni.<br />
<br />
==== generarea ceasului ====<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
clk = 0; // initialization at time 0<br />
forever #10 clk = ~clk; // toggle the clock at each 10 simulation steps<br />
end<br />
</syntaxhighlight><br />
<br />
==== generarea semnalului de reset ====<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
rst = 0;<br />
#13 rst = 1; // reset activ în 1 logic<br />
#20 rst = 0;<br />
end<br />
</syntaxhighlight><br />
<br />
Întîrzierile sunt alese astfel încât fronturile semnalului de reset să nu coincidă cu fronturile ceasului.<br />
<br />
==== generarea secvenței de instrucțiuni ====<br />
<br />
La fiecare ceas se setează valorile intrărilor '''opcode''', '''sursa1''', '''sursa2''', '''dest''' și '''wen''' cu valori care să corespundă instrucțiunii dorite.<br />
Pentru a ne asigura că toate semnalele se modifică numai după frontul activ al ceasului, vom aștepta de fiecare dată acest front folosind instrucțiunea <syntaxhighlight lang="Verilog" inline>@(posedge clk);</syntaxhighlight><br />
Semnalul '''wen''' se setează la '''1''' sau la '''0''' după cum dorim ca rezultatul să se salveze sau nu în registrul destinație.<br />
Semnalul '''wen''' nu face parte din instrucțiune. În laboratorul 2 el va fi generat de unitatea de control a procesorului (UCP) în funcție de codul instrucțiunii. De exemplu instrucțiunea CMP nu modifică niciun registru ci doar biții indicatori, prin urmare '''wen''' va fi în permanență '''0''' pe durata procesării acestei instrucțiuni.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
opcode = 4'b0000; dest = 4'd0; sursa1 = 4'd0; sursa2 = 4'd0; wen = 1'b0;<br />
#26 // se așteaptă finalizarea resetului<br />
@(posedge clk);<br />
opcode = 4'b0001; dest = 4'd7; sursa1 = 4'd6; sursa2 = 4'd5; wen = 1'b1; // ADD R7 R6 R5 // R7 <- R6 + R5<br />
@(posedge clk);<br />
opcode = 4'b0010; dest = 4'd7; sursa1 = 4'd7; sursa2 = 4'd4; wen = 1'b1; // SUB R7 R7 R4 // R7 <- R7 - R4<br />
// alte instrucțiuni<br />
end<br />
</syntaxhighlight><br />
<br />
=== initializarea valorilor in registre ===<br />
<br />
Se poate face a) la reset, dacă modulul are intrare de reset, sau b) într-un bloc '''initial''' folosit doar pentru simulare.<br />
<br />
a)<br />
<br />
<syntaxhighlight lang="Verilog"><br />
always @(posedge clk) begin<br />
if(rst) begin<br />
registru[0] = 13;<br />
. . . <br />
end<br />
else begin<br />
if(wen) . . .<br />
end<br />
end<br />
</syntaxhighlight><br />
<br />
b)<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial begin<br />
registru[0] = 13;<br />
registru[1] = 27;<br />
. . . .<br />
end<br />
</syntaxhighlight><br />
<br />
Dacă blocul '''initial''' este scris în modulul de testare iar variabilele inițializate sunt din interiorul modului testat sau chiar dintr-un submodul al acestuia, numele acestora trebuie să fie complet, corespunzător ierarhiei.<br />
<br />
<syntaxhighlight lang="Verilog"><br />
ralu.regs.registru[0] = 13;<br />
</syntaxhighlight></div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_9&diff=7397Applications 92022-05-09T09:04:31Z<p>Zhascsi: /* Exercise 3 */</p>
<hr />
<div>Almost always the FSM is described behaviorally, leaving the CLC gate level generation and optimization to compiler/synthesizer. However, the usual behavioral description closely follows the block structure of the FSM, with one block that computes the transition function and another block that computes the output. The FSMs are of two categories:<br />
* Moore FSM, whose outputs depend only on the current state<br />
* Mealy FSM, whose outputs depend also on inputs<br />
<br />
Most often the Mealy FSM is a delayed Mealy FSM. Its output depends on the previous state and on the input values at transition time. <br />
<br />
<br />
== Exercise 1 ==<br />
<br />
''Design an automaton that determines the order in which two buttons are pressed. The buttons generate logic signals, '''a''' and '''b''', that are '''1''' if the corresponding button is pressed. The automaton has two logic outputs, '''Y1''' and '''Y2'''. '''Y1''' is asserted if '''a''' was pressed first, followed by '''b'''. '''Y2''' is asserted if '''b''' was pressed first, followed by '''a'''. The outputs remain asserted until reset. The reset is active '''0'''.''<br />
<br />
[[Fișier: appl9_ex1.png]]<br />
<br />
=== Moore FSM ===<br />
<br />
The circuit may be designed as a Moore FSM, with two separate states for those two particular output configurations. In the graph below only the transitions to different states are shown. If their conditions are not met, the FSM stays in the current state, whatever it is. In the final states, '''R''' or '''U''', the automaton stays until reset. From any state the reset forces the FSM to its initial state, '''S'''.<br />
<br />
[[Fișier: appl9_moore.png]]<br />
<br />
<br />
=== State coding ===<br />
<br />
It is not recommended to use explicit values whenever the state variable is used. To make code much more readable and easier to design and debug, the state values are parameters. Another advantage of using parameters is that the state explicit values are declared in a single place, at parameter declaration, therefore if their values need to be changed, only the parameter declaration is affected.<br />
<br />
The state values are internal design options, therefore the parameters used for states are local ones. They are declared as local parameters, using the template '''localparam''' ''name''=''value''; The names of parameters are upper case letters, and may include digits and underline.<br />
<br />
<syntaxhighlight lang = "verilog"><br />
localparam STATE_S = 3'd0;<br />
localparam STATE_P = 3'd1;<br />
...<br />
</syntaxhighlight><br />
<br />
'''Attention!'''<br />
* The state values must be distinct! Otherwise you may end with a state having multiple names.<br />
* Local parameter declarations are the first statements after the module interface. The order of statements for a module should be the following:<br />
# '''module'''<br />
# interface declaration (the list of inputs and outputs)<br />
# localparam declarations<br />
# internal wire and reg declarations<br />
# description (structural with instantiations or behavioral with always processes and continuos assignments)<br />
# '''endmodule'''<br />
<br />
=== State transitions ===<br />
<br />
All transitions are grouped in a single sequential '''always''' process, with a '''case''' statement that groups transitions by current state.<br />
The combinational function that computes the next state (the transition function) is implicitly described by the case statement and the statements for each case.<br />
The state is updated sequentially because the '''always''' process is sensitive only to clock edges.<br />
<br />
<syntaxhighlight lang = "verilog"><br />
always @(posedge clk) begin<br />
if(~rst)<br />
state <= STATE_S;<br />
else begin<br />
case(state)<br />
STATE_S: begin<br />
if(a)<br />
state <= STATE_P;<br />
else if(b)<br />
state <= STATE_T;<br />
else<br />
state <= state; // stays in the same state<br />
end<br />
STATE_P: begin<br />
if(b)<br />
state <= STATE_R;<br />
else<br />
state <= state;<br />
end<br />
// other states with their transitions<br />
default:<br />
state <= STATE_S; // from undefined states jump to the initial state<br />
endcase<br />
end<br />
end<br />
</syntaxhighlight><br />
<br />
'''Attention!'''<br />
* All assignments inside the sequential process are done with the nonblocking assignment operator, <syntaxhighlight lang="Verilog" inline><=</syntaxhighlight><br />
* Don't forget the '''default''' case!<br />
* The '''reg''' variable for the state must be declared with the required number of bits, which is the same as the number of bits declared for each value of the state value parameters.<br />
<br />
<br />
=== Outputs ===<br />
<br />
Since Moore outputs depend only on state they are described either through continuous assignments, or inside a combinational '''always''' process.<br />
<br />
If continuous assignments are used, the outputs are assigned logic expressions based on state:<br />
<br />
<syntaxhighlight lang = "verilog"><br />
assign y1 = (state == R);<br />
</syntaxhighlight><br />
<br />
The combinational '''always''' process is preferred when state values are easier to group by states:<br />
<syntaxhighlight lang = "verilog"><br />
always @(*) begin<br />
case(state)<br />
STATE_S: {y1, y2} = 2'b00;<br />
STATE_P: {y1, y2} = 2'b00;<br />
STATE_R: {y1, y2} = 2'b10;<br />
// other states with their outputs<br />
default: {y1, y2} = 2'b00;<br />
endcase<br />
end<br />
</syntaxhighlight><br />
<br />
'''Attention!'''<br />
* All assignments inside the combinational process are done with the blocking assignment operator, <syntaxhighlight lang="Verilog" inline>=</syntaxhighlight><br />
* Don't forget the '''default''' case!<br />
<br />
=== Requirements ===<br />
* Create a new project in a new folder<br />
* Design the automaton as the top level design entity<br />
* Design a testbench with the input signals generated as in the figure below.<br />
* Run simulation. If the design is correct the outputs should appear as in the figure.<br />
<!--* To implement the design assign KEY0, SW1 and SW2 to '''rst''', '''a''', and '''b''' inputs. Assign LEDR1 and LEDR2 to '''y1''' and '''y2''' outputs.--><br />
* To implement the design assign BTN0, BTN1 and BTN2 to '''rst''', '''a''', and '''b''' inputs. Assign LED1 and LED2 to '''y1''' and '''y2''' outputs.<br />
<br />
[[Fișier: appl9_moore_wave.png]]<br />
<br />
== Exercise 2 ==<br />
<br />
''Design an automaton that determines the order in which two buttons are pressed. The buttons generate logic signals, '''a''' and '''b''', that are '''1''' if the corresponding button is pressed. The automaton has two logic outputs, '''Y1''' and '''Y2'''. '''Y1''' is asserted if '''a''' was pressed first, followed by '''b'''. '''Y2''' is asserted if '''b''' was pressed first, followed by '''a'''. The outputs are asserted for ONLY ONE CLOCK CYCLE. The reset is active '''0'''.''<br />
<br />
[[Fișier: appl9_ex1.png]]<br />
<br />
<br />
=== Mealy FSM ===<br />
<br />
The circuit may be designed as a delayed Mealy FSM, with fewer states than if designed as a Moore FSM. In the graph below only the transitions to different states are shown. If their conditions are not met, the FSM stays in the current state, whatever it is. In the final state, '''V''', the outputs are active for one clock cycle, depending on the input values that determined the transition to it. All other transitions are with outputs '''0'''. From any state, the reset forces the FSM to its initial state, '''S'''.<br />
<br />
[[Fișier: appl9_mealy.png]]<br />
<br />
=== State transitions ===<br />
<br />
The transition function is described in the same way as for the Moore FSM. However, there are only 4 states, therefore the '''state''' variable and the state value parameters have only 2 bits. The '''case''' inside the sequential process for transitions has also fewer cases.<br />
<br />
<br />
=== Outputs ===<br />
<br />
Since the delayed Mealy outputs depend both on the previous state AND the previous input values (at the last transition) they are described inside a sequential '''always''' process.<br />
The outputs must be declared of '''reg''' type.<br />
<br />
<syntaxhighlight lang = "verilog"><br />
always @(posedge clk) begin<br />
if(~rst) begin<br />
y1 <= 1'b0;<br />
y2 <= 1'b0;<br />
end<br />
else begin<br />
case(state)<br />
STATE_S: begin<br />
y1 <= 1'b0;<br />
y2 <= 1'b0;<br />
end<br />
// other states with their outputs<br />
default: begin<br />
y1 <= 1'b0;<br />
y2 <= 1'b0;<br />
end<br />
endcase<br />
end<br />
end<br />
</syntaxhighlight><br />
<br />
'''Attention!'''<br />
* All assignments inside the sequential process are done with the nonblocking assignment operator, <syntaxhighlight lang="Verilog" inline><=</syntaxhighlight><br />
* Don't forget the '''default''' case!<br />
<br />
=== Requirements ===<br />
* Use the same project as before<br />
* Redesign the automaton as a Mealy FSM<br />
* The testbench should not be modified.<br />
* Run simulation. If the design is correct the outputs should appear as in the figure below. The differences from the previous waveform are in the state values and output pulses.<br />
<br />
<br />
[[Fișier: appl9_mealy_wave.png]]<br />
<br />
<br />
== Exercise 3 ==<br />
<br />
''Design an FSM for an automatic chocolate selling machine, which delivers chocolates at 2.5&#8364;. The machine accepts only coins of 50 cents and 1 euro, and does not return any change. When the amount of 2.5&#8364; or more is reached, the machine delivers a chocolate and will resume the process, subtracting 2.5&#8364; from the current amount. The process resumes with whatever amount remains after delivering, which may be 0 or 0.5&#8364;. ''<br />
<br />
The inputs are the digital signals '''cents''', '''euro''' and '''ack'''.<br />
<br />
When the user inserts a valid coin, the corresponding input, '''cents''' or '''euro''', is asserted and stays '''1''' for some clock cycles. The FSM considers the coin validated only after the corresponding input goes back to '''0'''.<br />
<br />
The output is a digital signal, '''deliver''', that is asserted when the amount reaches or surpasses 2.5&#8364; and stays asserted until the input '''ack''' is asserted. The FSM resumes the process after '''ack''' is deasserted.<br />
<br />
The internal states of the FSM may be equivalent to the current amount, 0, 0.5, 1, 1.5, 2, 2.5 and 3 euros.<br />
<br />
''Implement the FSM for the automatic chocolate selling machine using three push buttons for '''cents''', '''euro''' and '''ack''' inputs <!--(the pushbutton generates '''0''' when pressed)-->, an LED to indicate the '''deliver''' output, and another pushbutton for the reset (that resets the amount to 0).''<br />
<br />
<br />
'''Hint'''<br />
<br />
To easy the implementation and keep the FSM as simple as possible, the inputs '''cents''', '''euro''' and '''ack''', which are pulses of arbitrary length (that may last hundreds of thousands of clock cycles!), may be transformed to one cycle pulses, asserted during the clock cycle that follows the original pulse. The FSM uses these one clock cycle pulses to compute the transitions.<br />
<br />
As an example, the '''euro''' input is transformed to '''euro_p''' internal signal, whose pulses last one clock cycle. These internal signal is further used by the FSM.<br />
<br />
<syntaxhighlight lang = "verilog"><br />
...<br />
<br />
reg euro_d; // delayed version of the euro input<br />
wire euro_p; // one clock cycle pulse to be used by the FSM<br />
...<br />
always @(posedge clk) euro_d <= euro; // euro_d is the copy of euro input, shifted one clock cycle<br />
assign euro_p = euro_d & ~euro; // euro_p is asserted one clock cycle after euro pulse has ended<br />
...<br />
</syntaxhighlight><br />
<br />
[[Fișier: appl9_ex3wave.png]]</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_9&diff=7396Applications 92022-05-09T09:03:44Z<p>Zhascsi: /* Exercise 3 */</p>
<hr />
<div>Almost always the FSM is described behaviorally, leaving the CLC gate level generation and optimization to compiler/synthesizer. However, the usual behavioral description closely follows the block structure of the FSM, with one block that computes the transition function and another block that computes the output. The FSMs are of two categories:<br />
* Moore FSM, whose outputs depend only on the current state<br />
* Mealy FSM, whose outputs depend also on inputs<br />
<br />
Most often the Mealy FSM is a delayed Mealy FSM. Its output depends on the previous state and on the input values at transition time. <br />
<br />
<br />
== Exercise 1 ==<br />
<br />
''Design an automaton that determines the order in which two buttons are pressed. The buttons generate logic signals, '''a''' and '''b''', that are '''1''' if the corresponding button is pressed. The automaton has two logic outputs, '''Y1''' and '''Y2'''. '''Y1''' is asserted if '''a''' was pressed first, followed by '''b'''. '''Y2''' is asserted if '''b''' was pressed first, followed by '''a'''. The outputs remain asserted until reset. The reset is active '''0'''.''<br />
<br />
[[Fișier: appl9_ex1.png]]<br />
<br />
=== Moore FSM ===<br />
<br />
The circuit may be designed as a Moore FSM, with two separate states for those two particular output configurations. In the graph below only the transitions to different states are shown. If their conditions are not met, the FSM stays in the current state, whatever it is. In the final states, '''R''' or '''U''', the automaton stays until reset. From any state the reset forces the FSM to its initial state, '''S'''.<br />
<br />
[[Fișier: appl9_moore.png]]<br />
<br />
<br />
=== State coding ===<br />
<br />
It is not recommended to use explicit values whenever the state variable is used. To make code much more readable and easier to design and debug, the state values are parameters. Another advantage of using parameters is that the state explicit values are declared in a single place, at parameter declaration, therefore if their values need to be changed, only the parameter declaration is affected.<br />
<br />
The state values are internal design options, therefore the parameters used for states are local ones. They are declared as local parameters, using the template '''localparam''' ''name''=''value''; The names of parameters are upper case letters, and may include digits and underline.<br />
<br />
<syntaxhighlight lang = "verilog"><br />
localparam STATE_S = 3'd0;<br />
localparam STATE_P = 3'd1;<br />
...<br />
</syntaxhighlight><br />
<br />
'''Attention!'''<br />
* The state values must be distinct! Otherwise you may end with a state having multiple names.<br />
* Local parameter declarations are the first statements after the module interface. The order of statements for a module should be the following:<br />
# '''module'''<br />
# interface declaration (the list of inputs and outputs)<br />
# localparam declarations<br />
# internal wire and reg declarations<br />
# description (structural with instantiations or behavioral with always processes and continuos assignments)<br />
# '''endmodule'''<br />
<br />
=== State transitions ===<br />
<br />
All transitions are grouped in a single sequential '''always''' process, with a '''case''' statement that groups transitions by current state.<br />
The combinational function that computes the next state (the transition function) is implicitly described by the case statement and the statements for each case.<br />
The state is updated sequentially because the '''always''' process is sensitive only to clock edges.<br />
<br />
<syntaxhighlight lang = "verilog"><br />
always @(posedge clk) begin<br />
if(~rst)<br />
state <= STATE_S;<br />
else begin<br />
case(state)<br />
STATE_S: begin<br />
if(a)<br />
state <= STATE_P;<br />
else if(b)<br />
state <= STATE_T;<br />
else<br />
state <= state; // stays in the same state<br />
end<br />
STATE_P: begin<br />
if(b)<br />
state <= STATE_R;<br />
else<br />
state <= state;<br />
end<br />
// other states with their transitions<br />
default:<br />
state <= STATE_S; // from undefined states jump to the initial state<br />
endcase<br />
end<br />
end<br />
</syntaxhighlight><br />
<br />
'''Attention!'''<br />
* All assignments inside the sequential process are done with the nonblocking assignment operator, <syntaxhighlight lang="Verilog" inline><=</syntaxhighlight><br />
* Don't forget the '''default''' case!<br />
* The '''reg''' variable for the state must be declared with the required number of bits, which is the same as the number of bits declared for each value of the state value parameters.<br />
<br />
<br />
=== Outputs ===<br />
<br />
Since Moore outputs depend only on state they are described either through continuous assignments, or inside a combinational '''always''' process.<br />
<br />
If continuous assignments are used, the outputs are assigned logic expressions based on state:<br />
<br />
<syntaxhighlight lang = "verilog"><br />
assign y1 = (state == R);<br />
</syntaxhighlight><br />
<br />
The combinational '''always''' process is preferred when state values are easier to group by states:<br />
<syntaxhighlight lang = "verilog"><br />
always @(*) begin<br />
case(state)<br />
STATE_S: {y1, y2} = 2'b00;<br />
STATE_P: {y1, y2} = 2'b00;<br />
STATE_R: {y1, y2} = 2'b10;<br />
// other states with their outputs<br />
default: {y1, y2} = 2'b00;<br />
endcase<br />
end<br />
</syntaxhighlight><br />
<br />
'''Attention!'''<br />
* All assignments inside the combinational process are done with the blocking assignment operator, <syntaxhighlight lang="Verilog" inline>=</syntaxhighlight><br />
* Don't forget the '''default''' case!<br />
<br />
=== Requirements ===<br />
* Create a new project in a new folder<br />
* Design the automaton as the top level design entity<br />
* Design a testbench with the input signals generated as in the figure below.<br />
* Run simulation. If the design is correct the outputs should appear as in the figure.<br />
<!--* To implement the design assign KEY0, SW1 and SW2 to '''rst''', '''a''', and '''b''' inputs. Assign LEDR1 and LEDR2 to '''y1''' and '''y2''' outputs.--><br />
* To implement the design assign BTN0, BTN1 and BTN2 to '''rst''', '''a''', and '''b''' inputs. Assign LED1 and LED2 to '''y1''' and '''y2''' outputs.<br />
<br />
[[Fișier: appl9_moore_wave.png]]<br />
<br />
== Exercise 2 ==<br />
<br />
''Design an automaton that determines the order in which two buttons are pressed. The buttons generate logic signals, '''a''' and '''b''', that are '''1''' if the corresponding button is pressed. The automaton has two logic outputs, '''Y1''' and '''Y2'''. '''Y1''' is asserted if '''a''' was pressed first, followed by '''b'''. '''Y2''' is asserted if '''b''' was pressed first, followed by '''a'''. The outputs are asserted for ONLY ONE CLOCK CYCLE. The reset is active '''0'''.''<br />
<br />
[[Fișier: appl9_ex1.png]]<br />
<br />
<br />
=== Mealy FSM ===<br />
<br />
The circuit may be designed as a delayed Mealy FSM, with fewer states than if designed as a Moore FSM. In the graph below only the transitions to different states are shown. If their conditions are not met, the FSM stays in the current state, whatever it is. In the final state, '''V''', the outputs are active for one clock cycle, depending on the input values that determined the transition to it. All other transitions are with outputs '''0'''. From any state, the reset forces the FSM to its initial state, '''S'''.<br />
<br />
[[Fișier: appl9_mealy.png]]<br />
<br />
=== State transitions ===<br />
<br />
The transition function is described in the same way as for the Moore FSM. However, there are only 4 states, therefore the '''state''' variable and the state value parameters have only 2 bits. The '''case''' inside the sequential process for transitions has also fewer cases.<br />
<br />
<br />
=== Outputs ===<br />
<br />
Since the delayed Mealy outputs depend both on the previous state AND the previous input values (at the last transition) they are described inside a sequential '''always''' process.<br />
The outputs must be declared of '''reg''' type.<br />
<br />
<syntaxhighlight lang = "verilog"><br />
always @(posedge clk) begin<br />
if(~rst) begin<br />
y1 <= 1'b0;<br />
y2 <= 1'b0;<br />
end<br />
else begin<br />
case(state)<br />
STATE_S: begin<br />
y1 <= 1'b0;<br />
y2 <= 1'b0;<br />
end<br />
// other states with their outputs<br />
default: begin<br />
y1 <= 1'b0;<br />
y2 <= 1'b0;<br />
end<br />
endcase<br />
end<br />
end<br />
</syntaxhighlight><br />
<br />
'''Attention!'''<br />
* All assignments inside the sequential process are done with the nonblocking assignment operator, <syntaxhighlight lang="Verilog" inline><=</syntaxhighlight><br />
* Don't forget the '''default''' case!<br />
<br />
=== Requirements ===<br />
* Use the same project as before<br />
* Redesign the automaton as a Mealy FSM<br />
* The testbench should not be modified.<br />
* Run simulation. If the design is correct the outputs should appear as in the figure below. The differences from the previous waveform are in the state values and output pulses.<br />
<br />
<br />
[[Fișier: appl9_mealy_wave.png]]<br />
<br />
<br />
== Exercise 3 ==<br />
<br />
''Design an FSM for an automatic chocolate selling machine, which delivers chocolates at 2.5&#8364;. The machine accepts only coins of 50 cents and 1 euro, and does not return any change. When the amount of 2.5&#8364; or more is reached, the machine delivers a chocolate and will resume the process, subtracting 2.5&#8364; from the current amount. The process resumes with whatever amount remains after delivering, which may be 0 or 0.5&#8364;. ''<br />
<br />
The inputs are the digital signals '''cents''', '''euro''' and '''ack'''.<br />
<br />
When the user inserts a valid coin, the corresponding input, '''cents''' or '''euro''', is asserted and stays '''1''' for some clock cycles. The FSM considers the coin validated only after the corresponding input goes back to '''0'''.<br />
<br />
The output is a digital signal, '''deliver''', that is asserted when the amount reaches or surpasses 2.5&#8364; and stays asserted until the input '''ack''' is asserted. The FSM resumes the process after '''ack''' is deasserted.<br />
<br />
The internal states of the FSM may be equivalent to the current amount, 0, 0.5, 1, 1.5, 2, 2.5 and 3 euros.<br />
<br />
''Implement the FSM for the automatic chocolate selling machine using three push buttons for '''cents''', '''euro''' and '''ack''' inputs (<!--the pushbutton generates '''0''' when pressed-->), an LED to indicate the '''deliver''' output, and another pushbutton for the reset (that resets the amount to 0).''<br />
<br />
<br />
'''Hint'''<br />
<br />
To easy the implementation and keep the FSM as simple as possible, the inputs '''cents''', '''euro''' and '''ack''', which are pulses of arbitrary length (that may last hundreds of thousands of clock cycles!), may be transformed to one cycle pulses, asserted during the clock cycle that follows the original pulse. The FSM uses these one clock cycle pulses to compute the transitions.<br />
<br />
As an example, the '''euro''' input is transformed to '''euro_p''' internal signal, whose pulses last one clock cycle. These internal signal is further used by the FSM.<br />
<br />
<syntaxhighlight lang = "verilog"><br />
...<br />
<br />
reg euro_d; // delayed version of the euro input<br />
wire euro_p; // one clock cycle pulse to be used by the FSM<br />
...<br />
always @(posedge clk) euro_d <= euro; // euro_d is the copy of euro input, shifted one clock cycle<br />
assign euro_p = euro_d & ~euro; // euro_p is asserted one clock cycle after euro pulse has ended<br />
...<br />
</syntaxhighlight><br />
<br />
[[Fișier: appl9_ex3wave.png]]</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_9&diff=7395Applications 92022-05-09T06:58:57Z<p>Zhascsi: /* Requirements */</p>
<hr />
<div>Almost always the FSM is described behaviorally, leaving the CLC gate level generation and optimization to compiler/synthesizer. However, the usual behavioral description closely follows the block structure of the FSM, with one block that computes the transition function and another block that computes the output. The FSMs are of two categories:<br />
* Moore FSM, whose outputs depend only on the current state<br />
* Mealy FSM, whose outputs depend also on inputs<br />
<br />
Most often the Mealy FSM is a delayed Mealy FSM. Its output depends on the previous state and on the input values at transition time. <br />
<br />
<br />
== Exercise 1 ==<br />
<br />
''Design an automaton that determines the order in which two buttons are pressed. The buttons generate logic signals, '''a''' and '''b''', that are '''1''' if the corresponding button is pressed. The automaton has two logic outputs, '''Y1''' and '''Y2'''. '''Y1''' is asserted if '''a''' was pressed first, followed by '''b'''. '''Y2''' is asserted if '''b''' was pressed first, followed by '''a'''. The outputs remain asserted until reset. The reset is active '''0'''.''<br />
<br />
[[Fișier: appl9_ex1.png]]<br />
<br />
=== Moore FSM ===<br />
<br />
The circuit may be designed as a Moore FSM, with two separate states for those two particular output configurations. In the graph below only the transitions to different states are shown. If their conditions are not met, the FSM stays in the current state, whatever it is. In the final states, '''R''' or '''U''', the automaton stays until reset. From any state the reset forces the FSM to its initial state, '''S'''.<br />
<br />
[[Fișier: appl9_moore.png]]<br />
<br />
<br />
=== State coding ===<br />
<br />
It is not recommended to use explicit values whenever the state variable is used. To make code much more readable and easier to design and debug, the state values are parameters. Another advantage of using parameters is that the state explicit values are declared in a single place, at parameter declaration, therefore if their values need to be changed, only the parameter declaration is affected.<br />
<br />
The state values are internal design options, therefore the parameters used for states are local ones. They are declared as local parameters, using the template '''localparam''' ''name''=''value''; The names of parameters are upper case letters, and may include digits and underline.<br />
<br />
<syntaxhighlight lang = "verilog"><br />
localparam STATE_S = 3'd0;<br />
localparam STATE_P = 3'd1;<br />
...<br />
</syntaxhighlight><br />
<br />
'''Attention!'''<br />
* The state values must be distinct! Otherwise you may end with a state having multiple names.<br />
* Local parameter declarations are the first statements after the module interface. The order of statements for a module should be the following:<br />
# '''module'''<br />
# interface declaration (the list of inputs and outputs)<br />
# localparam declarations<br />
# internal wire and reg declarations<br />
# description (structural with instantiations or behavioral with always processes and continuos assignments)<br />
# '''endmodule'''<br />
<br />
=== State transitions ===<br />
<br />
All transitions are grouped in a single sequential '''always''' process, with a '''case''' statement that groups transitions by current state.<br />
The combinational function that computes the next state (the transition function) is implicitly described by the case statement and the statements for each case.<br />
The state is updated sequentially because the '''always''' process is sensitive only to clock edges.<br />
<br />
<syntaxhighlight lang = "verilog"><br />
always @(posedge clk) begin<br />
if(~rst)<br />
state <= STATE_S;<br />
else begin<br />
case(state)<br />
STATE_S: begin<br />
if(a)<br />
state <= STATE_P;<br />
else if(b)<br />
state <= STATE_T;<br />
else<br />
state <= state; // stays in the same state<br />
end<br />
STATE_P: begin<br />
if(b)<br />
state <= STATE_R;<br />
else<br />
state <= state;<br />
end<br />
// other states with their transitions<br />
default:<br />
state <= STATE_S; // from undefined states jump to the initial state<br />
endcase<br />
end<br />
end<br />
</syntaxhighlight><br />
<br />
'''Attention!'''<br />
* All assignments inside the sequential process are done with the nonblocking assignment operator, <syntaxhighlight lang="Verilog" inline><=</syntaxhighlight><br />
* Don't forget the '''default''' case!<br />
* The '''reg''' variable for the state must be declared with the required number of bits, which is the same as the number of bits declared for each value of the state value parameters.<br />
<br />
<br />
=== Outputs ===<br />
<br />
Since Moore outputs depend only on state they are described either through continuous assignments, or inside a combinational '''always''' process.<br />
<br />
If continuous assignments are used, the outputs are assigned logic expressions based on state:<br />
<br />
<syntaxhighlight lang = "verilog"><br />
assign y1 = (state == R);<br />
</syntaxhighlight><br />
<br />
The combinational '''always''' process is preferred when state values are easier to group by states:<br />
<syntaxhighlight lang = "verilog"><br />
always @(*) begin<br />
case(state)<br />
STATE_S: {y1, y2} = 2'b00;<br />
STATE_P: {y1, y2} = 2'b00;<br />
STATE_R: {y1, y2} = 2'b10;<br />
// other states with their outputs<br />
default: {y1, y2} = 2'b00;<br />
endcase<br />
end<br />
</syntaxhighlight><br />
<br />
'''Attention!'''<br />
* All assignments inside the combinational process are done with the blocking assignment operator, <syntaxhighlight lang="Verilog" inline>=</syntaxhighlight><br />
* Don't forget the '''default''' case!<br />
<br />
=== Requirements ===<br />
* Create a new project in a new folder<br />
* Design the automaton as the top level design entity<br />
* Design a testbench with the input signals generated as in the figure below.<br />
* Run simulation. If the design is correct the outputs should appear as in the figure.<br />
<!--* To implement the design assign KEY0, SW1 and SW2 to '''rst''', '''a''', and '''b''' inputs. Assign LEDR1 and LEDR2 to '''y1''' and '''y2''' outputs.--><br />
* To implement the design assign BTN0, BTN1 and BTN2 to '''rst''', '''a''', and '''b''' inputs. Assign LED1 and LED2 to '''y1''' and '''y2''' outputs.<br />
<br />
[[Fișier: appl9_moore_wave.png]]<br />
<br />
== Exercise 2 ==<br />
<br />
''Design an automaton that determines the order in which two buttons are pressed. The buttons generate logic signals, '''a''' and '''b''', that are '''1''' if the corresponding button is pressed. The automaton has two logic outputs, '''Y1''' and '''Y2'''. '''Y1''' is asserted if '''a''' was pressed first, followed by '''b'''. '''Y2''' is asserted if '''b''' was pressed first, followed by '''a'''. The outputs are asserted for ONLY ONE CLOCK CYCLE. The reset is active '''0'''.''<br />
<br />
[[Fișier: appl9_ex1.png]]<br />
<br />
<br />
=== Mealy FSM ===<br />
<br />
The circuit may be designed as a delayed Mealy FSM, with fewer states than if designed as a Moore FSM. In the graph below only the transitions to different states are shown. If their conditions are not met, the FSM stays in the current state, whatever it is. In the final state, '''V''', the outputs are active for one clock cycle, depending on the input values that determined the transition to it. All other transitions are with outputs '''0'''. From any state, the reset forces the FSM to its initial state, '''S'''.<br />
<br />
[[Fișier: appl9_mealy.png]]<br />
<br />
=== State transitions ===<br />
<br />
The transition function is described in the same way as for the Moore FSM. However, there are only 4 states, therefore the '''state''' variable and the state value parameters have only 2 bits. The '''case''' inside the sequential process for transitions has also fewer cases.<br />
<br />
<br />
=== Outputs ===<br />
<br />
Since the delayed Mealy outputs depend both on the previous state AND the previous input values (at the last transition) they are described inside a sequential '''always''' process.<br />
The outputs must be declared of '''reg''' type.<br />
<br />
<syntaxhighlight lang = "verilog"><br />
always @(posedge clk) begin<br />
if(~rst) begin<br />
y1 <= 1'b0;<br />
y2 <= 1'b0;<br />
end<br />
else begin<br />
case(state)<br />
STATE_S: begin<br />
y1 <= 1'b0;<br />
y2 <= 1'b0;<br />
end<br />
// other states with their outputs<br />
default: begin<br />
y1 <= 1'b0;<br />
y2 <= 1'b0;<br />
end<br />
endcase<br />
end<br />
end<br />
</syntaxhighlight><br />
<br />
'''Attention!'''<br />
* All assignments inside the sequential process are done with the nonblocking assignment operator, <syntaxhighlight lang="Verilog" inline><=</syntaxhighlight><br />
* Don't forget the '''default''' case!<br />
<br />
=== Requirements ===<br />
* Use the same project as before<br />
* Redesign the automaton as a Mealy FSM<br />
* The testbench should not be modified.<br />
* Run simulation. If the design is correct the outputs should appear as in the figure below. The differences from the previous waveform are in the state values and output pulses.<br />
<br />
<br />
[[Fișier: appl9_mealy_wave.png]]<br />
<br />
<br />
== Exercise 3 ==<br />
<br />
''Design an FSM for an automatic chocolate selling machine, which delivers chocolates at 2.5&#8364;. The machine accepts only coins of 50 cents and 1 euro, and does not return any change. When the amount of 2.5&#8364; or more is reached, the machine delivers a chocolate and will resume the process, subtracting 2.5&#8364; from the current amount. The process resumes with whatever amount remains after delivering, which may be 0 or 0.5&#8364;. ''<br />
<br />
The inputs are the digital signals '''cents''', '''euro''' and '''ack'''.<br />
<br />
When the user inserts a valid coin, the corresponding input, '''cents''' or '''euro''', is asserted and stays '''1''' for some clock cycles. The FSM considers the coin validated only after the corresponding input goes back to '''0'''.<br />
<br />
The output is a digital signal, '''deliver''', that is asserted when the amount reaches or surpasses 2.5&#8364; and stays asserted until the input '''ack''' is asserted. The FSM resumes the process after '''ack''' is deasserted.<br />
<br />
The internal states of the FSM may be equivalent to the current amount, 0, 0.5, 1, 1.5, 2, 2.5 and 3 euros.<br />
<br />
''Implement the FSM for the automatic chocolate selling machine using three push buttons for '''cents''', '''euro''' and '''ack''' inputs (the pushbutton generates '''0''' when pressed), an LED to indicate the '''deliver''' output, and another pushbutton for the reset (that resets the amount to 0).''<br />
<br />
<br />
'''Hint'''<br />
<br />
To easy the implementation and keep the FSM as simple as possible, the inputs '''cents''', '''euro''' and '''ack''', which are pulses of arbitrary length (that may last hundreds of thousands of clock cycles!), may be transformed to one cycle pulses, asserted during the clock cycle that follows the original pulse. The FSM uses these one clock cycle pulses to compute the transitions.<br />
<br />
As an example, the '''euro''' input is transformed to '''euro_p''' internal signal, whose pulses last one clock cycle. These internal signal is further used by the FSM.<br />
<br />
<syntaxhighlight lang = "verilog"><br />
...<br />
<br />
reg euro_d; // delayed version of the euro input<br />
wire euro_p; // one clock cycle pulse to be used by the FSM<br />
...<br />
always @(posedge clk) euro_d <= euro; // euro_d is the copy of euro input, shifted one clock cycle<br />
assign euro_p = euro_d & ~euro; // euro_p is asserted one clock cycle after euro pulse has ended<br />
...<br />
</syntaxhighlight><br />
<br />
[[Fișier: appl9_ex3wave.png]]</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_9&diff=7394Applications 92022-05-09T06:37:52Z<p>Zhascsi: /* Requirements */</p>
<hr />
<div>Almost always the FSM is described behaviorally, leaving the CLC gate level generation and optimization to compiler/synthesizer. However, the usual behavioral description closely follows the block structure of the FSM, with one block that computes the transition function and another block that computes the output. The FSMs are of two categories:<br />
* Moore FSM, whose outputs depend only on the current state<br />
* Mealy FSM, whose outputs depend also on inputs<br />
<br />
Most often the Mealy FSM is a delayed Mealy FSM. Its output depends on the previous state and on the input values at transition time. <br />
<br />
<br />
== Exercise 1 ==<br />
<br />
''Design an automaton that determines the order in which two buttons are pressed. The buttons generate logic signals, '''a''' and '''b''', that are '''1''' if the corresponding button is pressed. The automaton has two logic outputs, '''Y1''' and '''Y2'''. '''Y1''' is asserted if '''a''' was pressed first, followed by '''b'''. '''Y2''' is asserted if '''b''' was pressed first, followed by '''a'''. The outputs remain asserted until reset. The reset is active '''0'''.''<br />
<br />
[[Fișier: appl9_ex1.png]]<br />
<br />
=== Moore FSM ===<br />
<br />
The circuit may be designed as a Moore FSM, with two separate states for those two particular output configurations. In the graph below only the transitions to different states are shown. If their conditions are not met, the FSM stays in the current state, whatever it is. In the final states, '''R''' or '''U''', the automaton stays until reset. From any state the reset forces the FSM to its initial state, '''S'''.<br />
<br />
[[Fișier: appl9_moore.png]]<br />
<br />
<br />
=== State coding ===<br />
<br />
It is not recommended to use explicit values whenever the state variable is used. To make code much more readable and easier to design and debug, the state values are parameters. Another advantage of using parameters is that the state explicit values are declared in a single place, at parameter declaration, therefore if their values need to be changed, only the parameter declaration is affected.<br />
<br />
The state values are internal design options, therefore the parameters used for states are local ones. They are declared as local parameters, using the template '''localparam''' ''name''=''value''; The names of parameters are upper case letters, and may include digits and underline.<br />
<br />
<syntaxhighlight lang = "verilog"><br />
localparam STATE_S = 3'd0;<br />
localparam STATE_P = 3'd1;<br />
...<br />
</syntaxhighlight><br />
<br />
'''Attention!'''<br />
* The state values must be distinct! Otherwise you may end with a state having multiple names.<br />
* Local parameter declarations are the first statements after the module interface. The order of statements for a module should be the following:<br />
# '''module'''<br />
# interface declaration (the list of inputs and outputs)<br />
# localparam declarations<br />
# internal wire and reg declarations<br />
# description (structural with instantiations or behavioral with always processes and continuos assignments)<br />
# '''endmodule'''<br />
<br />
=== State transitions ===<br />
<br />
All transitions are grouped in a single sequential '''always''' process, with a '''case''' statement that groups transitions by current state.<br />
The combinational function that computes the next state (the transition function) is implicitly described by the case statement and the statements for each case.<br />
The state is updated sequentially because the '''always''' process is sensitive only to clock edges.<br />
<br />
<syntaxhighlight lang = "verilog"><br />
always @(posedge clk) begin<br />
if(~rst)<br />
state <= STATE_S;<br />
else begin<br />
case(state)<br />
STATE_S: begin<br />
if(a)<br />
state <= STATE_P;<br />
else if(b)<br />
state <= STATE_T;<br />
else<br />
state <= state; // stays in the same state<br />
end<br />
STATE_P: begin<br />
if(b)<br />
state <= STATE_R;<br />
else<br />
state <= state;<br />
end<br />
// other states with their transitions<br />
default:<br />
state <= STATE_S; // from undefined states jump to the initial state<br />
endcase<br />
end<br />
end<br />
</syntaxhighlight><br />
<br />
'''Attention!'''<br />
* All assignments inside the sequential process are done with the nonblocking assignment operator, <syntaxhighlight lang="Verilog" inline><=</syntaxhighlight><br />
* Don't forget the '''default''' case!<br />
* The '''reg''' variable for the state must be declared with the required number of bits, which is the same as the number of bits declared for each value of the state value parameters.<br />
<br />
<br />
=== Outputs ===<br />
<br />
Since Moore outputs depend only on state they are described either through continuous assignments, or inside a combinational '''always''' process.<br />
<br />
If continuous assignments are used, the outputs are assigned logic expressions based on state:<br />
<br />
<syntaxhighlight lang = "verilog"><br />
assign y1 = (state == R);<br />
</syntaxhighlight><br />
<br />
The combinational '''always''' process is preferred when state values are easier to group by states:<br />
<syntaxhighlight lang = "verilog"><br />
always @(*) begin<br />
case(state)<br />
STATE_S: {y1, y2} = 2'b00;<br />
STATE_P: {y1, y2} = 2'b00;<br />
STATE_R: {y1, y2} = 2'b10;<br />
// other states with their outputs<br />
default: {y1, y2} = 2'b00;<br />
endcase<br />
end<br />
</syntaxhighlight><br />
<br />
'''Attention!'''<br />
* All assignments inside the combinational process are done with the blocking assignment operator, <syntaxhighlight lang="Verilog" inline>=</syntaxhighlight><br />
* Don't forget the '''default''' case!<br />
<br />
=== Requirements ===<br />
* Create a new project in a new folder<br />
* Design the automaton as the top level design entity<br />
* Design a testbench with the input signals generated as in the figure below.<br />
* Run simulation. If the design is correct the outputs should appear as in the figure.<br />
<!--* To implement the design assign KEY0, SW1 and SW2 to '''rst''', '''a''', and '''b''' inputs. Assign LEDR1 and LEDR2 to '''y1''' and '''y2''' outputs.--><br />
* To implement the design assign SW1, BTN0 and BTN1 to '''rst''', '''a''', and '''b''' inputs. Assign LED0 and LED1 to '''y1''' and '''y2''' outputs.<br />
<br />
[[Fișier: appl9_moore_wave.png]]<br />
<br />
== Exercise 2 ==<br />
<br />
''Design an automaton that determines the order in which two buttons are pressed. The buttons generate logic signals, '''a''' and '''b''', that are '''1''' if the corresponding button is pressed. The automaton has two logic outputs, '''Y1''' and '''Y2'''. '''Y1''' is asserted if '''a''' was pressed first, followed by '''b'''. '''Y2''' is asserted if '''b''' was pressed first, followed by '''a'''. The outputs are asserted for ONLY ONE CLOCK CYCLE. The reset is active '''0'''.''<br />
<br />
[[Fișier: appl9_ex1.png]]<br />
<br />
<br />
=== Mealy FSM ===<br />
<br />
The circuit may be designed as a delayed Mealy FSM, with fewer states than if designed as a Moore FSM. In the graph below only the transitions to different states are shown. If their conditions are not met, the FSM stays in the current state, whatever it is. In the final state, '''V''', the outputs are active for one clock cycle, depending on the input values that determined the transition to it. All other transitions are with outputs '''0'''. From any state, the reset forces the FSM to its initial state, '''S'''.<br />
<br />
[[Fișier: appl9_mealy.png]]<br />
<br />
=== State transitions ===<br />
<br />
The transition function is described in the same way as for the Moore FSM. However, there are only 4 states, therefore the '''state''' variable and the state value parameters have only 2 bits. The '''case''' inside the sequential process for transitions has also fewer cases.<br />
<br />
<br />
=== Outputs ===<br />
<br />
Since the delayed Mealy outputs depend both on the previous state AND the previous input values (at the last transition) they are described inside a sequential '''always''' process.<br />
The outputs must be declared of '''reg''' type.<br />
<br />
<syntaxhighlight lang = "verilog"><br />
always @(posedge clk) begin<br />
if(~rst) begin<br />
y1 <= 1'b0;<br />
y2 <= 1'b0;<br />
end<br />
else begin<br />
case(state)<br />
STATE_S: begin<br />
y1 <= 1'b0;<br />
y2 <= 1'b0;<br />
end<br />
// other states with their outputs<br />
default: begin<br />
y1 <= 1'b0;<br />
y2 <= 1'b0;<br />
end<br />
endcase<br />
end<br />
end<br />
</syntaxhighlight><br />
<br />
'''Attention!'''<br />
* All assignments inside the sequential process are done with the nonblocking assignment operator, <syntaxhighlight lang="Verilog" inline><=</syntaxhighlight><br />
* Don't forget the '''default''' case!<br />
<br />
=== Requirements ===<br />
* Use the same project as before<br />
* Redesign the automaton as a Mealy FSM<br />
* The testbench should not be modified.<br />
* Run simulation. If the design is correct the outputs should appear as in the figure below. The differences from the previous waveform are in the state values and output pulses.<br />
<br />
<br />
[[Fișier: appl9_mealy_wave.png]]<br />
<br />
<br />
== Exercise 3 ==<br />
<br />
''Design an FSM for an automatic chocolate selling machine, which delivers chocolates at 2.5&#8364;. The machine accepts only coins of 50 cents and 1 euro, and does not return any change. When the amount of 2.5&#8364; or more is reached, the machine delivers a chocolate and will resume the process, subtracting 2.5&#8364; from the current amount. The process resumes with whatever amount remains after delivering, which may be 0 or 0.5&#8364;. ''<br />
<br />
The inputs are the digital signals '''cents''', '''euro''' and '''ack'''.<br />
<br />
When the user inserts a valid coin, the corresponding input, '''cents''' or '''euro''', is asserted and stays '''1''' for some clock cycles. The FSM considers the coin validated only after the corresponding input goes back to '''0'''.<br />
<br />
The output is a digital signal, '''deliver''', that is asserted when the amount reaches or surpasses 2.5&#8364; and stays asserted until the input '''ack''' is asserted. The FSM resumes the process after '''ack''' is deasserted.<br />
<br />
The internal states of the FSM may be equivalent to the current amount, 0, 0.5, 1, 1.5, 2, 2.5 and 3 euros.<br />
<br />
''Implement the FSM for the automatic chocolate selling machine using three push buttons for '''cents''', '''euro''' and '''ack''' inputs (the pushbutton generates '''0''' when pressed), an LED to indicate the '''deliver''' output, and another pushbutton for the reset (that resets the amount to 0).''<br />
<br />
<br />
'''Hint'''<br />
<br />
To easy the implementation and keep the FSM as simple as possible, the inputs '''cents''', '''euro''' and '''ack''', which are pulses of arbitrary length (that may last hundreds of thousands of clock cycles!), may be transformed to one cycle pulses, asserted during the clock cycle that follows the original pulse. The FSM uses these one clock cycle pulses to compute the transitions.<br />
<br />
As an example, the '''euro''' input is transformed to '''euro_p''' internal signal, whose pulses last one clock cycle. These internal signal is further used by the FSM.<br />
<br />
<syntaxhighlight lang = "verilog"><br />
...<br />
<br />
reg euro_d; // delayed version of the euro input<br />
wire euro_p; // one clock cycle pulse to be used by the FSM<br />
...<br />
always @(posedge clk) euro_d <= euro; // euro_d is the copy of euro input, shifted one clock cycle<br />
assign euro_p = euro_d & ~euro; // euro_p is asserted one clock cycle after euro pulse has ended<br />
...<br />
</syntaxhighlight><br />
<br />
[[Fișier: appl9_ex3wave.png]]</div>Zhascsihttps://wiki.dcae.pub.ro/index.php?title=Applications_8&diff=7390Applications 82022-05-02T06:03:46Z<p>Zhascsi: </p>
<hr />
<div>A random access memory is an address-based data storage block, with a highly regular structure, which may be logically defined either as a bi-dimensional array of bits, or a uni-dimensional list of data words. Each row of the array, or each item of the list has a unique address. The addresses form a contiguous set of integers, starting from zero and running up to the highest address which defines the size of the address space, usually a power of 2. The memory capacity is therefore the number of address locations, N, times the width of the memory location (or of the memory word), W. These two numbers are the main parameters of any memory:<br />
* N - the number of address locations, also the number of words;<br />
* W - the number of bits for each location, or the data word width;<br />
The storage capacity is N x W bits, but the memory capacity may also be given in bytes.<br />
<br />
Being a vector of words or a bidimensional array of bits, the memory could be described using a single bidimensional variable, usually declared as a vector of multibit '''reg''' items. A memory array of N locations, with W bits per location is declared as:<br />
<br />
<syntaxhighlight lang = "verilog"><br />
reg [W-1: 0] memory [0: N-1];<br />
</syntaxhighlight><br />
<br />
'''Attention!'''<br />
* the width of the word is declared as usual, with msb as the left index, <syntaxhighlight lang="Verilog" inline>[msb:0]</syntaxhighlight><br />
* the length of the memory is declared after the variable name, and starts with 0, the right index being the highest index of the vector, <syntaxhighlight lang="Verilog" inline>[0:endindex]</syntaxhighlight><br />
<br />
<br />
There are two kinds of memories:<br />
* read-only memories<br />
* writable memories<br />
<br />
Memories can also be classified by their synchronous or asynchronous character:<br />
* asynchronous - read data is immediately available at the output, write is performed as into a latch<br />
* synchronous - all operations are synchronized by one of the clock edges.<br />
<br />
<br />
== Exercise 1 ==<br />
=== ROM - Read-Only Memory ===<br />
<br />
It may be described as a purely combinational logic circuit, whose output (data) is a logic function of its input (address). The transcoder from [[Applications 4#transcoder|Applications 4]] is nothing else than a ROM, with '''value''' input acting as an address that selects a particular location from where data is read and sent out as '''seg'''. There it was described behaviorally with a '''case''' statement that had a branch for each combination of input value bits.<br />
<br />
[[Fișier: appl8_rom.png]]<br />
<br />
A more flexible description employs a single memory array, declared as a vector of '''reg''' variables, and a statement that assigns the selected (addressed) element of the memory vector to the memory output.<br />
<br />
<syntaxhighlight lang = "verilog"><br />
assign dout = memory[addr];<br />
</syntaxhighlight><br />
<br />
=== Memory initialization task ===<br />
<br />
Memory arrays may be initialized with predefined values from a text file using verilog system tasks '''$readmemb''' and '''$readmemh'''. '''$readmemb''' reads predefined values given in binary, while '''$readmemh''' is used if values are given in hexadecimal. These verilog system tasks have two mandatory arguments and two optional arguments, in the following order:<br />
# initialization filename, given as a string (between double quotes)<br />
# the memory array variable name<br />
# the start address (optional)<br />
# the end address (optional)<br />
If the start and end addresses are not given, the memory array is initialized from the first address (address zero) until the last address or until the end of initialization file is reached.<br />
<br />
If the memory initialization file, ''meminit.txt'', resides in the project's folder, and the memory array to be initialized is '''mem''' inside the memory instance '''dut''', the testbench may initialize the memory right at the beginning of the simulation:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial $readmemb("../../meminit.txt", dut.mem);<br />
</syntaxhighlight><br />
<br />
If the initialization is intended to be done for the implemented memory, the initialization process must be placed inside the memory module, in which case the memory array name is just the variable array to be initialized:<br />
<br />
<syntaxhighlight lang="Verilog"><br />
initial $readmemb("../../meminit.txt", mem);<br />
</syntaxhighlight><br />
<br />
The filename, the first argument of '''$readmemb''' and '''$readmemh''' tasks, may be given either relative to the simulation folder (as in the previous two examples), or as the complete absolute filename, with the pathname starting from the linux root, '''/''', for example <syntaxhighlight lang="Verilog" inline>"/home/student/rom/meminit.txt"</syntaxhighlight> if ''meminit.txt'' file resides in the project's folder ''rom'', created in the student's home directory ''/home/student''.<br />
<br />
=== Memory initialization file ===<br />
<br />
The initialization file is a text file with values written in binary (using '''0''' and '''1''' symbols) or in hexadecimal (using digits and letters '''a''' to '''f''', either uppercase of lowercase). Values are separated by white spaces, tabs or newlines. Comments (started with '''//''' as in verilog) are ignored. An example of a binary initialization file:<br />
<syntaxhighlight lang = "bash"><br />
// four values in binary text format<br />
00000011<br />
00001111<br />
00111111<br />
11111111<br />
</syntaxhighlight><br />
<br />
The same initialization sequence, but given as a hexadecimal text file:<br />
<syntaxhighlight lang = "bash"><br />
// four values in hexadecimal text format<br />
03<br />
0f<br />
3f<br />
ff<br />
</syntaxhighlight><br />
<br />
* Start a new project, '''rom''', in a newly created folder '''rom'''<br />
* Create a new verilog file ''rom.v'' that describes a 16x8 ROM using a vector variable and a continuous assignment.<br />
* Create a testbench, '''rom_tb''', that drives the input of '''rom''' with a sequence of addresses from 0 to highest one. Run simulation.<br />
* Open a text editor, write some values in binary format on successive lines, and save the file into the ''rom'' folder with the name ''meminit.txt''<br />
* In the testbench module add an '''initial''' process with a single statement that calls the system task for memory initialization. Run simulation.<br />
* Assign the segments of Digit0 from DE1-SOC display to '''dout''', and SW[3] ... SW[0] switches to '''addr'''. <br />
* In the '''rom''' module add an '''initial''' process with a single statement that calls the system task for memory initialization. Pay atention how its second argument is given - the array variable is now directly accesible. Compile the project and program the FPGA.<br />
<br />
<br />
== Exercise 2 ==<br />
=== RAM - Read-Write Memory ===<br />
<br />
A synchronous memory reacts only on clock edges. The addresses are sampled at clock edges, the output changes also on clock edges, and the write is performed on clock edges too.<br />
<br />
[[Fișier: appl8_ram.png]]<br />
<br />
The FPGA has dedicated blocks for memory implementation, the so called ''ram blocks'', or ''ramblocks''. In order for the synthesis to map a memory description to a ''ramblock'', the sequential description must conform to a template:<br />
<syntaxhighlight lang="Verilog"><br />
always @(posedge clk) begin<br />
if(~we) // if write is enabled,<br />
mem[addr] <= wdata; // update the addressed location to wdata value<br />
rdata <= mem[addr]; // data read from the addressed location is transferred to the output<br />
end<br />
</syntaxhighlight><br />
<br />
* Start a new project, '''ram''', in a new folder '''ram'''<br />
* Create a new verilog file ''ram.v'' that describes a 16x4 RAM using a vector variable and a sequential '''always''' process that assigns to '''rdata''' output the value of the memory location selected by '''addr'''. In the same process update the same location with '''wdata''' value if '''we''' input is active (active at '''0''').<br />
* Create a testbench, '''ram_tb''', which writes some data to four addresses, and then reads the same addresses in the same order, as indicated in the waveforms below. Don't forget the clock! Run simulation and check that the written data are correctly read afterwards.<br />
* Assign LEDs to the output, switches to the '''addr''' and '''wdata''' inputs, a push button (KEY0) to the write enable input (the push button generates '''0''' if pressed), and a 50 MHz source clock to '''clk''' input.<br />
* Compile, program the FPGA and test the RAM. Set switches to an address and a data value, then briefly push the write enable button. The LEDs will change accordingly. Change the address and data and push again the write enable button. Change back the address switches and see if the previously written configuration reappears on LED.<br />
<br />
[[Fișier: appl8_ram_wave.png]]<br />
<br />
<!--<br />
== Exercise 3 ==<br />
=== Programmable display ===<br />
<br />
These application employs a dual port synchronous RAM. One port, the ''read port'', is used to read data ('''rdata''') from the memory, using the read address '''raddr'''. The other, the ''write port'', accesses the same memory array, but using another address, '''waddr''', to write '''wdata''' into. The write operation is performed only if the write enable pin ('''we''') is active (here it is active '''0''').<br />
<br />
The data read from RAM is translated by the ROM into a 7 bit combination for the digit display. The RAM memory is read in sequence, address by address, changing the address at around each second. The sequence of 4 bit addresses are generated by a counter from which four suitable bits are chosen such that the rate of change is around 1 Hz.<br />
<br />
[[Fișier: appl8_ramrom.png]]<br />
<br />
* Start a new project, '''ramrom''', in a newly created folder '''ramrom'''.<br />
* Copy the ''rom.v'' file from Exercise 1 into this folder.<br />
* Add an initialization file to this folder, and ensures that ''rom.v'' initialization tasks reads it from the correct location.<br />
* Copy the ''ram.v'' from from Exercise 2 into this folder. Change '''ram''' description to a dual RAM.<br />
* Add '''cnt32.v''' to this project (you may reuse the '''cnt32''' module or file from the previous Application).<br />
* Create the top-level design file, ''ramrom.v''', and instantiate the modules and connect them as indicated.<br />
* Assign swithces, push button, clock source and digit display as shown.<br />
* Compile, program the FPGA, and play with the board switches and buttons.<br />
--></div>Zhascsi