{"id":338,"date":"2015-01-29T15:30:06","date_gmt":"2015-01-29T23:30:06","guid":{"rendered":"http:\/\/www.beyond-circuits.com\/wordpress\/?page_id=338"},"modified":"2016-07-05T14:44:24","modified_gmt":"2016-07-05T22:44:24","slug":"tutorial7","status":"publish","type":"page","link":"https:\/\/www.beyond-circuits.com\/wordpress\/tutorial\/tutorial7\/","title":{"rendered":"Tutorial 7: Counting the Seconds, the Human Edition"},"content":{"rendered":"<p>In <a title=\"Tutorial 6 \u2013 Counting the Seconds\" href=\"https:\/\/www.beyond-circuits.com\/wordpress\/tutorial\/tutorial6\/\">Tutorial 6<\/a> we made a counter, but it counted in hexadecimal\u2013 not exactly human-friendly! In this tutorial, we&#8217;ll count make a counter that counts seconds the way a stopwatch does. That is, counting up from zero to 59, and then wrapping.<\/p>\n<h1>Counting in Decimal, the Hardware Way<\/h1>\n<p>If you had to do this assignment in software, it would be pretty simple: just use division and modulo operators to get the decimal digits, then send those out. But we have a problem:\u00a0those operators are actually very expensive in hardware. In the hardware world we can do something much simpler\u2013 just count in decimal. In order to do that, we&#8217;ll create a module that\u00a0represents a decimal digit. Old-school computers used to do this all the time. It&#8217;s called BCD or Binary Coded Decimal. HP actually made a line of personal computers in the early 1980s called the <em>Series 80<\/em> that used BCD instead of binary. Most handheld calculators do this as well. BCD has the advantage that it does rounding exactly the same way that humans do, so you get results that are more sensible to people. Ironically, it isn&#8217;t used much these days because it&#8217;s more complicated and takes more hardware than doing calculations in binary.<\/p>\n<p>Anyway, here is my module which implements a BCD digit:<\/p>\n<pre><code>`timescale 1ns\/1ns\r\nmodule bcd_digit\r\n  #(\r\n    parameter modulus = 10\r\n    )\r\n  (\r\n   input clk,\r\n   input carry_in,\r\n   output reg [$clog2(modulus)-1:0] digit,\r\n   output carry_out\r\n   );\r\n\r\n  initial digit = 0;\r\n\r\n  assign carry_out = carry_in &amp;&amp; digit == modulus-1;\r\n\r\n  always @(posedge clk)\r\n    if (carry_in)\r\n      if (carry_out)\r\n\tdigit &lt;= 0;\r\n      else\r\n\tdigit &lt;= digit+1;\r\n\r\nendmodule\r\n<\/code><\/pre>\n<p>It&#8217;s quite simple, really. First, there is a parameter <em>modulus<\/em> which indicates where the digit should wrap. There is a\u00a0<em>carry_in<\/em> input which says to increment the digit, the digit output, and a <em>carry_out<\/em> output which can be used to connect to the next more significant digit. Since we use a parameter for the modulus, we can&#8217;t correctly use a fixed width for the digit output. The number of bits required for the job depends on the value for <em>modulus<\/em>. So, we use the built-in <b>$clog2<\/b> function to take the log base 2 of <em>modulus<\/em>. This function basically returns the number of bits required to hold the value of its input.<\/p>\n<p>Change the binary counter in the <em>top<\/em> module for two BCD digits like this.<\/p>\n<pre><code>  wire [7:0] sec_count;\r\n  wire ones_carry_out; \t    \r\n  bcd_digit #(10) ones_digit\r\n    (\r\n     .clk(clk),\r\n     .carry_in(sec_pulse),\r\n     .digit(sec_count[3:0]),\r\n     .carry_out(ones_carry_out)\r\n     );\r\n  \r\n  bcd_digit #(6) tens_digit\r\n    (\r\n     .clk(clk),\r\n     .carry_in(ones_carry_out),\r\n     .digit(sec_count[6:4]),\r\n     .carry_out()\r\n     );\r\n  assign sec_count[7] = 0;\r\n<\/code><\/pre>\n<p>Notice how we only pass three bits to the tens digit, since it has a maximum value of 5. We need to also set bit seven of <em>digit<\/em> so that it is defined.<\/p>\n<h1>Changing the Test<\/h1>\n<p>If we simulate, we&#8217;re obviously going to have a bunch of failures. We need to modify our model to match our\u00a0new behavior. Here&#8217;s my code for the rewritten model. In this case, we can go ahead and use division and modulo operators. The model is software, so those are OK to use.<\/p>\n<pre><code>`timescale 1ns\/1ns\r\nmodule model\r\n  #(\r\n    parameter ms_limit = 100000\r\n    )\r\n  (\r\n   input clk,\r\n   output [7:0] seconds\r\n   );\r\n  \r\n  integer counter = 0;\r\n  always @(posedge clk)\r\n    counter &lt;= counter+1;\r\n\r\n  reg [7:0] seconds_value;\r\n  always @(posedge clk)\r\n    seconds_value &lt;= (counter \/ (ms_limit * 1000))%60;\r\n\r\n  assign seconds[3:0] = seconds_value % 10;\r\n  assign seconds[7:4] = seconds_value \/ 10;\r\n\r\nendmodule\r\n<\/code><\/pre>\n<h2>Running the Simulation<\/h2>\n<p>If we go ahead and run the simulation, we get the following:<\/p>\n<pre><code>\r\nrun all\r\nSimulation complete at time 14000000.000000ns.\r\n*** Simulation PASSED 0\/2800002\r\n$finish called at time : 14 ms : File \"\/home\/pete\/tutorial7\/tutorial7.srcs\/sim_1\/new\/bench.v\" Line 89\r\n<\/code><\/pre>\n<p>In other words, it works, and the test passes. This illustrates an important point. Our test now uses a model of the correct behavior, and the model tells the test what the expected results are. This way, we don&#8217;t have to change the test bench when the behavior of the RTL changes.<\/p>\n<p>Now, I&#8217;m not completely happy with the simulation, because it does not check that the count wraps from 59 back to zero. Let&#8217;s\u00a0change the wait statement to wait for that to happen. I simply had it wait for the count to go back to 1 after it waited for the count to go to 20.<\/p>\n<h1>Adding More Digits<\/h1>\n<p>That was too easy. Lets add digits for tenths and hundredths of seconds, as well as minutes and hours. This means lots of digit values, so it&#8217;s best to keep them in a wide bus. First, we&#8217;re going to introduce the Verilog notion of a <b>localparam<\/b>. This is like a parameter value, but it can&#8217;t be overriden in the module instantiation. The <strong>localparam<\/strong> declaration can appear anywhere before its use. Here is my definition of the number of digits we need:<\/p>\n<pre><code>  localparam num_digits = 3 + 2 + 2 + 2;<\/code><\/pre>\n<p>We need three millisecond digits, two second digits, two minute digits, and two hour digits. Next, we declare the bus which will hold the digits and the bus that holds the carry values.<\/p>\n<pre><code>  wire [num_digits*4-1:0] time_digits;\r\n  wire [num_digits-1:0] carry;\r\n  assign carry[0] = ms_pulse;\r\n<\/code><\/pre>\n<p>Here, we also assign the least significant bit of the <em>carry<\/em> signal to be the same as the <em>ms_pulse<\/em> signal.<\/p>\n<p>Then we just instantiate a bunch of digits:<\/p>\n<pre><code>  bcd_digit #(10) digit0\t\/\/ 1 ms\r\n    (\r\n     .clk(clk),\r\n     .carry_in(carry[0]),\r\n     .digit(time_digits[3:0]),\r\n     .carry_out(carry[1])\r\n     );\r\n\r\n  bcd_digit #(10) digit1\t\/\/ 10 ms\r\n    (\r\n     .clk(clk),\r\n     .carry_in(carry[1]),\r\n     .digit(time_digits[7:4]),\r\n     .carry_out(carry[2])\r\n     );\r\n\r\n  bcd_digit #(10) digit2\t\/\/ 100 ms\r\n    (\r\n     .clk(clk),\r\n     .carry_in(carry[2]),\r\n     .digit(time_digits[11:8]),\r\n     .carry_out(carry[3])\r\n     );\r\n\r\n  bcd_digit #(10) digit3\t\/\/ 1 s\r\n    (\r\n     .clk(clk),\r\n     .carry_in(carry[3]),\r\n     .digit(time_digits[15:12]),\r\n     .carry_out(carry[4])\r\n     );\r\n\r\n  bcd_digit #(6) digit4\t\t\/\/ 10 s\r\n    (\r\n     .clk(clk),\r\n     .carry_in(carry[4]),\r\n     .digit(time_digits[18:16]),\r\n     .carry_out(carry[5])\r\n     );\r\n  assign time_digits[19] = 0;\r\n\r\n  bcd_digit #(10) digit5\t\/\/ 1 min\r\n    (\r\n     .clk(clk),\r\n     .carry_in(carry[5]),\r\n     .digit(time_digits[23:20]),\r\n     .carry_out(carry[6])\r\n     );\r\n\r\n  bcd_digit #(6) digit6\t\t\/\/ 10 min\r\n    (\r\n     .clk(clk),\r\n     .carry_in(carry[6]),\r\n     .digit(time_digits[26:24]),\r\n     .carry_out(carry[7])\r\n     );\r\n  assign time_digits[27] = 0;\r\n\r\n  bcd_digit #(10) digit7\t\/\/ 1 hour\r\n    (\r\n     .clk(clk),\r\n     .carry_in(carry[7]),\r\n     .digit(time_digits[31:28]),\r\n     .carry_out(carry[8])\r\n     );\r\n\r\n  bcd_digit #(10) digit8\t\/\/ 10 hour\r\n    (\r\n     .clk(clk),\r\n     .carry_in(carry[8]),\r\n     .digit(time_digits[35:32]),\r\n     .carry_out()\r\n     );\r\n<\/code><\/pre>\n<p>All that is left is to set the digits that we want to look at:<\/p>\n<pre><code>  assign digit = ssdcat_pre ? time_digits[19:16] : time_digits[15:12];\r\n<\/code><\/pre>\n<p>If you simulate this, everything works just the same as\u00a0before and the test passes. However,\u00a0we won&#8217;t be able to\u00a0see the other digits.<\/p>\n<h2>Looking at the Other Digits<\/h2>\n<p>How can we look at all those digits now if we only have a two digit display? My solution is to use the switches to indicate which pair of digits you want to see. To do this, we&#8217;ll use another <b>case<\/b> statement. Change the declaration of the <em>digit<\/em> signal to be a <b>reg<\/b>,\u00a0then add the following always block to set the <em>digit<\/em> signal based on the <em>switch<\/em> values. Here is my always block.<\/p>\n<pre><code>  always @(*)\r\n    case(1'b1)\r\n      switch[3]: digit = ssdcat_pre ? time_digits[35:32] : time_digits[31:28];\r\n      switch[2]: digit = ssdcat_pre ? time_digits[27:24] : time_digits[23:20];\r\n      switch[1]: digit = ssdcat_pre ? time_digits[19:16] : time_digits[15:12];\r\n      switch[0]: digit = ssdcat_pre ? time_digits[11: 8] : time_digits[7 :4 ];\r\n      default:   digit = ssdcat_pre ? time_digits[19:16] : time_digits[15:12];\r\n    endcase\r\n<\/code><\/pre>\n<p>Note that this <b>case<\/b> statement looks a little backwards. Rather than a variable in the <b>case<\/b> statement, we just have a constant 1-bit one. Then, in the place where we normally put the value, we have a variable. This is a pretty common Verilog idiom. What we&#8217;ve coded is a case for when switch 3 is set. If it is set, then the other switch values don&#8217;t matter. So if both switch 3 and 2 are set, then the time will show the same as if switch 3 were the only one set. Verilog just looks down the list to see the first one that matches and then selects that. In hardware we refer to this as a &#8220;priority encoding&#8221;.<\/p>\n<p>If we simulate this, we would get lots of error. Remember that we set our switch values at random? This will cause the digit outputs to go haywire. If we want our simulation to pass, we&#8217;d better exclude the low four bits of switch from turning on. We can do that by modifying the random assignment to the switch values like this:<\/p>\n<pre><code>  always @(posedge clk)\r\n    switch &lt;= $random &amp; 8'hf0;\r\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>In Tutorial 6 we made a counter, but it counted in hexadecimal\u2013 not exactly human-friendly! In this tutorial, we&#8217;ll count make a counter that counts seconds the way a stopwatch does. That is, counting up from zero to 59, and &hellip; <a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/tutorial\/tutorial7\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"parent":226,"menu_order":7,"comment_status":"open","ping_status":"open","template":"","meta":{"footnotes":""},"class_list":["post-338","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/pages\/338","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/comments?post=338"}],"version-history":[{"count":9,"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/pages\/338\/revisions"}],"predecessor-version":[{"id":991,"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/pages\/338\/revisions\/991"}],"up":[{"embeddable":true,"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/pages\/226"}],"wp:attachment":[{"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/media?parent=338"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}