anas_z15

EE2026 Lab Assignment 3

Feb 20th, 2019
577
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*Some tips for EE2026 lab assignment 3:
  2. 1) Structure of project:
  3.     a) clock divider module - This module takes the input 100 MHz clock signal and outputs a slower frequency f.
  4.     b) "blink" module - This module takes the divided clock signal(s) from your earlier module(s) and the switch inputs to determine what happens to the 7-seg display
  5.     c) top module - This module is the one that instantiates a) and b) and establishes the links between them.
  6.  
  7.     - Following are some common variations of the above:
  8.         * 2 clock divider modules running in parallel, one to generate f1 and the other to generate f2
  9.         * 1 clock divider module that generates both f1 and f2
  10.         * 1 clock divider module that generates f according to the selector switch input
  11.         Therefore, the multiplexer controlling the frequency of output can be in either of the 3 modules, depending on which structure you choose.
  12.  
  13. 2) Implementing the logic
  14. I'll briefly outline how you might want to code module b). By default, your program should start off by displaying H as the first character. Therefore you can hardcode the output to show H at the start by declaring and initialising it as such:*/
  15. output reg [7:0] seg = 8'b________; //insert 8-bit binary value that controls segment A (LSB) through dp (MSB) in active low
  16. //It's advisable to define a reg array to store the corresponding binary values for all your characters. Suppose you need to display 10 characters, then it would be:
  17. reg [7:0] char [9:0]; //10 rows of 8-bit values
  18. //Next, you need to initialise all the characters. You can do this by using one initial block:
  19. initial begin
  20.     char[0] = 8'b________;
  21.     char[1] = 8'b________;
  22.     .
  23.     .
  24.     .
  25.     char[9] = 8'b________;
  26. end
  27. //Next, create ONE always block that becomes active at the rising edge of your divided clk:
  28. always @(posedge divided_clk) begin
  29.     ...
  30. end
  31. /*Within this block is where the heart of your code will be. Start off by checking if the program is unlocked. Then check if it is set to forward or reverse and display the characters according to the chosen order: use a counter that increments (or decrements for reverse) and set the value of seg to be char[counter]. Remember to reset the counter to 0 when it reaches 10 (or reset to 10 when it reaches 0 for reverse). Your counter should therefore be large enough to count up to the the total number of characters. In this case, 4 bits are required to count up to 9: */
  32. reg [3:0] counter = 0; //define and initialise this before the always block
  33.  
  34. //Thanks for reading this far. Hope you find it useful. If you still have the energy to go on, you might want to read on to find some code snippets and FAQ.
  35.  
  36. //CODE SNIPPETS
  37.  
  38. //if, else if, else
  39. if (cond1) begin //if only 1 line to execute, you can omit begin & end
  40.     //do sth
  41. end
  42. else if (cond2) begin
  43.     //do sth
  44. end
  45. else begin
  46.     //do sth
  47. end
  48.  
  49. //case
  50. case (selector)
  51.     <case1>: //do sth
  52.     <case2>: begin
  53.                 //do sth1
  54.                 //do sth2
  55.              end
  56.     <case3>: //do sth
  57.     <case4>: //do sth
  58.     default: //do sth
  59. endcase
  60.  
  61. //clock divider module to take 100 MHz input and output 1 Hz frequency
  62. module clk_div(
  63.     input clk,
  64.     output reg new_clk = 0
  65. );
  66.     integer count = 0; //alternatively, reg [25:0] count = 0
  67.     always @(posedge clk) begin
  68.         if (count < 50000000) // 100 000 000/(2*1)
  69.             count = count + 1;
  70.         else begin
  71.             count <= 0;
  72.             clk <= ~clk;
  73.         end      
  74.     end
  75. endmodule
  76.  
  77. /*
  78. FAQ
  79. 1) What is integer in Verilog? Why are you using it for the clock divider module instead of a regular reg?
  80. Ans: The IEEE Std 1364β„’-2005 reads as follows:
  81. "An integer is a general-purpose variable used for manipulating quantities that are not regarded as hardware registers."
  82. The integer is also a variable, like reg, except that it is 32-bit wide by default. It is therefore very useful when trying to implement a counter to count up to a very large number. To count up to a particular number x, you would have been asked to create an n-bit reg counter, whereby n is the binary logarithm of x, i.e n = log2(x). In the example given above, 2^25 = 33 554 432, while 2^26 = 67 108 864. The number that I'm trying to count up to is 49999999, which is in between 2^25 and 2^26. So you need at least 26 bits to store the number. Since an integer is 32-bit by default, it is big enough to count the required number. Alternatively, you can also define and use a 26-bit reg to store your counter.
  83.  
  84. 2) So does that mean I can use integer whenever I want to implement a counter in Verilog?
  85. Ans: Yes, but it does not mean that you should. It is advisable to first consider the magnitude of the number. In the example given above for the blink module, the counter needs to count up to 9 only. So it is immediately apparent that 4 bits are sufficient and therefore a reg should be considered here instead of an integer. Use integer if the number is really so big (nearly 32 bits wide) such as in the clock divider module.
  86.  
  87. 3) What is the difference between = and <=? What should I use?
  88. Ans: = is the blocking assignment and <= is the nonblocking assignment. = will block the execution of subsequent lines until the current line has finished executing. Use this when the assignment in line 2 depends on the value of assignment in line 1. On the other hand, <= is the nonblocking assignment. Assignment statements with <= within the same block of code will execute simultaneously, without regard for the order in which they are written in the code. Use this when the assignment in line 2 does not depend on the value of assignment in line 1. Confused? Compare the following 2 examples:*/
  89.     //Eg. 1 (initial value of a = 0)
  90.     a <= a+1;   //a = 1
  91.     b <= a;     //b = 0
  92.  
  93.     //Eg. 2 (initial value of a = 0)
  94.     a = a+1;    //a = 1
  95.     b = a;      //b = 1
  96. /*
  97.  
  98. 4) When writing the conditions for if..else or case statements, can you really just write it in decimal radix instead of binary?
  99. Ans: Yes, you can. Verilog will automatically take care of radix conversions for you. If unspecified, radix 10 is assumed. The following are therefore equivalent:*/
  100. if (a > 3) begin
  101.     //do sth
  102. end
  103.  
  104. if (a > 2'b11) begin
  105.     //do sth
  106. end
  107.  
  108. /*
  109. 5) Why should I put reg in my output?/What is the difference between reg and wire?/When should I use reg?
  110. Ans: Input and output ports default to the wire type unless their type is explicitly defined as reg. The following are therefore equivalent:*/
  111. //Eg. 3 (implicit declaration of wire)
  112. input a,
  113. output b
  114.  
  115. //Eg. 4 (explicit declaration of wire)
  116. input wire a,
  117. output wire b
  118. /*Verilog has 2 main data types: net and variable. The IEEE Std 1364β„’-2005 explains them as follows:
  119. "The net data types can represent physical connections between structural entities, such as gates. A net shall not store a value (except for the trireg net). Instead, its value shall be determined by the values of its drivers, such as a continuous assignment or a gate... If no driver is connected to a net, its value shall be high-impedance ( z ) unless the net is a trireg, in which case it shall hold the previously driven value."
  120.  
  121. "A variable is an abstraction of a data storage element. A variable shall store a value from one assignment to the next. An assignment statement in a procedure acts as a trigger that changes the value in the data storage element. The initialization value for reg, time, and integer data types shall be the unknown value, x . The default initialization value for real and realtime variable data types shall be 0.0 . If a variable declaration assignment is used, the variable shall take this value as if the assignment occurred in a blocking assignment in an initial construct."
  122.  
  123. Based on the above 2 paragraphs from the IEEE standard for Verilog, we can understand that a wire, being of a net type, cannot store any value, while a reg, being a variable, can store values between assignments. It is this property of memory that sets wire and reg apart. Suppose you would like to design a time-sensitive LED that flips its on-off state every second, you need to first ensure that you are able to store the current value of a LED so that you can flip it in future. In this example, you should therefore use the reg type for the LED output. In addition, you can also initialise the value at declaration, so that you can set the LED to be either on or off at start of the program. You can refer to the example at the top, where I showed you how to simultaneously declare and initialise a reg output to show the letter H on the 7-segment display. Another key point to note: "In Verilog, if a signal appears on the left hand side of <= or = in an always block, it must be declared as reg." [D. Harris, S. Harris, Digital Design and Computer Architecture (2 nd ed.), Morgan Kaufmann, 2012]
  124. */
Advertisement