{"id":449,"date":"2015-02-20T20:34:31","date_gmt":"2015-02-21T04:34:31","guid":{"rendered":"http:\/\/www.beyond-circuits.com\/wordpress\/?page_id=449"},"modified":"2026-10-23T13:53:40","modified_gmt":"2026-10-23T21:53:40","slug":"tutorial13","status":"publish","type":"page","link":"https:\/\/www.beyond-circuits.com\/wordpress\/tutorial\/tutorial13\/","title":{"rendered":"Tutorial 13: Creating an IP Component"},"content":{"rendered":"<p>In this tutorial we will build an IP component that can be used by the ARM processor to implement the stopwatch ourunctions we used in our earlier tutorials. The main components of this IP block will be:<\/p>\n<ul>\n<li>A set of registers controlled by the ARM which control the value shown on the LEDs or the SSD<\/li>\n<li>A set of registers that\u00a0the ARM reads, which read the value of the encoder register, the button and switch inputs, and a timer value maintained by the FPGA logic.<\/li>\n<li>The encoder block from <a title=\"Tutorial 12 \u2013 Rotary Encoder\" href=\"https:\/\/www.beyond-circuits.com\/wordpress\/tutorial\/tutorial12\/\">tutorial 12<\/a><\/li>\n<li>The debounce logic from <a title=\"Tutorial 11 \u2013 A Debounce Circuit\" href=\"https:\/\/www.beyond-circuits.com\/wordpress\/tutorial\/tutorial11\/\">tutorial 11<\/a><\/li>\n<li>The seven segment display controller from <a title=\"Tutorial 5 \u2013 The Other Digit\" href=\"https:\/\/www.beyond-circuits.com\/wordpress\/tutorial\/tutorial5\/\">tutorial 5<\/a><\/li>\n<li>A millisecond counter which the ARM uses to measure the passage of time<\/li>\n<\/ul>\n<h1>Creating the project<\/h1>\n<ol>\n<li><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure1.png\"><img loading=\"lazy\" decoding=\"async\" class=\" size-medium wp-image-451 alignright\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure1-300x176.png\" alt=\"figure1\" width=\"300\" height=\"176\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure1-300x176.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure1.png 471w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>Launch Vivado<\/li>\n<li>Select <b><em>Create New Project<\/em><\/b> from the <em>Getting Started<\/em> screen.<\/li>\n<li><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure2.png\"><img loading=\"lazy\" decoding=\"async\" class=\" size-medium wp-image-453 alignright\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure2-300x211.png\" alt=\"figure2\" width=\"300\" height=\"211\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure2-300x211.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure2-427x300.png 427w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure2.png 575w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>The <em>New Project<\/em> box will open. Click <b><em>Next<\/em><\/b>.<\/li>\n<li>Create a new project called <em>stopwatch_controller<\/em>. Click <b><em>Next<\/em><\/b>.<\/li>\n<li>Select <em>RTL Project<\/em> for the Project Type and click <b><em>Next<\/em><\/b>.<\/li>\n<li>In the <em>Add Sources<\/em> select <b><em>Verilog<\/em><\/b> as the <b><em>Target Language<\/em><\/b>, and clock <b><em>Next<\/em><\/b>.<\/li>\n<li>The <em>Add Existing IP (optional)<\/em> dialog opens. We have no existing IP, so click <b><em>Next<\/em><\/b>.<\/li>\n<li><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure3.png\"><img loading=\"lazy\" decoding=\"async\" class=\" size-medium wp-image-454 alignright\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure3-300x180.png\" alt=\"figure3\" width=\"300\" height=\"180\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure3-300x180.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure3-500x300.png 500w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure3.png 820w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>The <em>Add Constraints (optional)<\/em> dialog opens. We will add our constraints later, so click <b><em>Next<\/em><\/b>.<\/li>\n<li>When the <em>Default Part<\/em> dialog opens, select <em>Boards<\/em> and then select the <em>ZedBoard<\/em> option and clock <b><em>Next<\/em><\/b>.<\/li>\n<li>Click <em><strong>Finish<\/strong><\/em> in the <em>New Project Summary<\/em> dialog to finish creating the project.<\/li>\n<li><\/li>\n<\/ol>\n<h1>Create the IP Block<\/h1>\n<ol>\n<li><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure4.png\"><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-456 alignright\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure4.png\" alt=\"figure4\" width=\"272\" height=\"157\" \/><\/a>From the <strong><em>Tools<\/em><\/strong> menu, select <em><strong>Create and Package IP<\/strong><\/em>. This launches the <em>Create and Package IP Wizard.\u00a0<\/em>We will use this wizard to create an IP block so that the ARM can control the seven segment display, the LEDs and switches, and the rotary encoder.<\/li>\n<li>Click <strong><em>Next<\/em><\/strong> in response to the <em>Create and Package IP<\/em> dialog.<\/li>\n<li><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure5.png\"><img loading=\"lazy\" decoding=\"async\" class=\" size-medium wp-image-457 alignright\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure5-300x196.png\" alt=\"figure5\" width=\"300\" height=\"196\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure5-300x196.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure5-459x300.png 459w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure5.png 514w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>Select that we want to <em>Create a new AXI4 peripheral<\/em>\u00a0in the <em>Choose Create Peripheral or Package IP<\/em> dialog. Then click <strong><em>Next<\/em><\/strong>.<\/li>\n<li>Fill out the Peripheral Details dialog according to the figure. This gives users some identifying information when the use the IP block. Click <strong><em>Next<\/em><\/strong>.<\/li>\n<li><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure6.png\"><img loading=\"lazy\" decoding=\"async\" class=\" size-medium wp-image-465 alignright\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure6-300x220.png\" alt=\"figure6\" width=\"300\" height=\"220\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure6-300x220.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure6-408x300.png 408w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure6.png 765w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>The <em>Add Interfaces<\/em> dialog box lets us setup the interface between the ARM and our IP block. We want an AXI-<em>Lite<\/em> interface with eight registers. We also want a 32-bit Slave interface. Leave the <em>Name<\/em> field as the default. When finished click <strong><em>Next<\/em><\/strong>.<\/li>\n<li>In the <em>Create Peripheral<\/em> dialog select the <em>Edit IP<\/em> option and then\u00a0click <strong><em>Finish<\/em><\/strong>. A new Vivado project called <strong>edit_stopwatch_controller_v1_0<\/strong> will be created.<\/li>\n<\/ol>\n<p>It is important to note that this is a new project, not the one we created at the beginning of this tutorial. This new project exists while we are creating or editing our IP block, but when we complete the IP block, it will be packaged and stored in our IP repository, and this project will be deleted. If you need to edit or modify the IP block, you need to follow the steps provided later in this tutorial.<\/p>\n<h2>Editing the Verilog<\/h2>\n<p>Two source files have been created. These are:<\/p>\n<ul>\n<li><b>stopwatch_controller_v1_0<\/b> \u2014 This file instantiates the AXI-Lite interface.<\/li>\n<li><b>stopwatch_controller_v1_0_S00_AXI<\/b> \u2014 This file contains the AXI-Lite bus functionality. As it is now, this file just implements four 32-bit registers with an AXI-Lite interface.<\/li>\n<\/ul>\n<p>We need to be able to control a number of output values, as well as to write to an 8-bit value to drive on the seven segment display. We also need an 8-bit value to drive the eight LED outputs. Further, we&#8217;ll need\u00a0need to be able to read an 8-bit register which holds the value of the rotary encoder and the value of the input switches and buttons. We will use the following address mapping:<\/p>\n<div class=\"table-responsive\"><table  style=\"width:100%; \"  class=\"easy-table easy-table-default \" border=\"0\">\n<thead>\r\n<tr><th >Address<\/th>\n<th > Register<\/th>\n<\/tr>\n<\/thead>\n<tbody>\r\n<tr><td >0<\/td>\n<td > SSD output<\/td>\n<\/tr>\n\r\n<tr><td >1<\/td>\n<td > LED output<\/td>\n<\/tr>\n\r\n<tr><td >2<\/td>\n<td > switches<\/td>\n<\/tr>\n\r\n<tr><td >3<\/td>\n<td > buttons<\/td>\n<\/tr>\n\r\n<tr><td >4<\/td>\n<td > rotary encoder value<\/td>\n<\/tr>\n\r\n<tr><td >5<\/td>\n<td > rotary encoder switch<\/td>\n<\/tr>\n\r\n<tr><td >6<\/td>\n<td > rotary encoder shaft button<\/td>\n<\/tr>\n\r\n<tr><td >7<\/td>\n<td > timer<\/td>\n<\/tr>\n<\/tbody><\/table><\/div>\n<p>The SSD output register will just cause whatever is written to that register to display on the seven segment display. Likewise, the LED output register will cause the eight bits written to that register to appear on the eight LEDs.<\/p>\n<p>The ARM will read the values of the switches from an 8-bit register at address 2, and the value of the buttons from a 5-bit register at address 3.<br \/>\nFor the rotary encoder, we will manage the rotary pulses in hardware on the FPGA. We will keep an 8-bit register and increment or decrement it as appropriate based on the <em>enc_a<\/em> and <em>enc_b<\/em> inputs. The ARM will be able to read the value of this register at address 4. The single bit value for the rotary encoder switch and shaft button will be read at addresses 5 and 6 respectively.<\/p>\n<p>Finally, we will make a special 32-bit counter which increments once per millisecond at address 7. This will be used by the software to control timing.<\/p>\n<p>When the <em>Create and Package IP Wizard<\/em> ran it created a Verilog module called <strong>stopwatch_controller_v1_0_S00_AXI<\/strong>\u00a0which implements eight 32-bit registers that can be written and read by the ARM. If you look at the Verilog code you will find that the registers inside the module are called <em>slv_reg0<\/em> through <em>slv_reg7<\/em>. Please keep in mind that we will be discussing two entirely different things called registers. The first is flip-flop elements used throughout our Verilog code that are declared with the <strong>reg<\/strong> keyword. The second type are values which can be written and read by the ARM. Confusingly, sometimes these second type of registers are declared using the Verilog <strong>wire<\/strong> keyword and they aren&#8217;t registers at all in the Verilog sense. After a while this won&#8217;t be as confusing as you might think.<\/p>\n<p>Anyway, if you look at our register list above, only the first two can be written by the ARM. It doesn&#8217;t do us any good to keep them hidden away in the\u00a0<strong>stopwatch_controller_v1_0_S00_AXI<\/strong> module, so we will bring them out as outputs of the module. Just declare them as output reg values (in the Verilog sense) of the module.<\/p>\n<p>In the Verilog code you will find eight lines that declare the slv_reg0 through slv_reg7 variables. Go ahead and cut them out and paste them in the port declaration part of the module right below the comment &lt;code&gt;\/\/ Users to add ports here&lt;\/code&gt;. Declare <em>slv_reg0<\/em> and <em>slv_reg1<\/em> to be <strong>reg<\/strong> outputs. Don&#8217;t forget to change the semicolon at the end of the line to a comma! These two registers (ARM sense) are outputs of the\u00a0<strong>stopwatch_controller_v1_0_S00_AXI <\/strong>module<strong>\u00a0<\/strong>because it is the ARM which controls their value. The other registers are inputs to the module because their value is controlled by the FPGA. The value of those registers can only be read by the ARM. Go ahead and declare them as module inputs now. Here is what my code looks like now:<\/p>\n<pre><code>\t\t\/\/ Users to add ports here\r\n    \toutput reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg0,\r\n        output reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg1,\r\n        input wire [C_S_AXI_DATA_WIDTH-1:0] slv_reg2,\r\n        input wire [C_S_AXI_DATA_WIDTH-1:0] slv_reg3,\r\n        input wire [C_S_AXI_DATA_WIDTH-1:0] slv_reg4,\r\n        input wire [C_S_AXI_DATA_WIDTH-1:0] slv_reg5,\r\n        input wire [C_S_AXI_DATA_WIDTH-1:0] slv_reg6,\r\n        input wire [C_S_AXI_DATA_WIDTH-1:0] slv_reg7,\r\n<\/code><\/pre>\n<p>Now, we need to remove all the code in the module which writes to registers <em>slv_reg2<\/em> through <em>slv_reg7<\/em>. Remember, the ARM does not get to control those values. Search down in your text editor for <em>slv_reg2<\/em>. Delete any references you see to assigning to these registers. In the end, you should only see references to these register values in the port declaration and in the <strong>case<\/strong> statement where the module drives the data back to the ARM. Go ahead and save your module.<\/p>\n<h2>Adding the logic<\/h2>\n<p>Now go ahead and edit the <strong>stopwatch_controller_v1_0<\/strong> module. Notice that the module instantiates the <b>stopwatch_controller_v1_0_S00_AXI<\/b> module. We added eight ports to that module so we should go ahead and add them to the instantiation of the module as well. We&#8217;ll just leave them unconnected for now. My code for that looks like this:<\/p>\n<pre><code>\/\/ Instantiation of Axi Bus Interface S00_AXI\r\n\tstopwatch_controller_v1_0_S00_AXI # ( \r\n\t\t.C_S_AXI_DATA_WIDTH(C_S00_AXI_DATA_WIDTH),\r\n\t\t.C_S_AXI_ADDR_WIDTH(C_S00_AXI_ADDR_WIDTH)\r\n\t) stopwatch_controller_v1_0_S00_AXI_inst (\r\n\t    .slv_reg0(),\r\n\t    .slv_reg1(),\r\n\t    .slv_reg2(),\r\n\t    .slv_reg3(),\r\n\t    .slv_reg4(),\r\n\t    .slv_reg5(),\r\n\t    .slv_reg6(),\r\n\t    .slv_reg7(),\r\n\t    .S_AXI_ACLK(s00_axi_aclk),\r\n<\/code><\/pre>\n<p>Next, we need to add the ports to this module. In our final design, these new ports will connect up with the outside world. We declare ports for the SSD and SSD cathode signals, the switches, the buttons, the LEDs, and the signals for the rotary encoder. Do this right below the comment which reads <code>\/\/ Users to add ports here<\/code>. Here is what I have:<\/p>\n<pre><code>\t\t\/\/ Users to add ports here\r\n                input wire clk,\r\n\t\toutput wire [6:0] ssd,\r\n\t\toutput wire ssdcat,\r\n\t\toutput wire [7:0] led,\r\n\t\tinput wire [4:0] btn,\r\n\t\tinput wire [7:0] switch,\r\n\t\tinput wire enc_a,\r\n\t\tinput wire enc_b,\r\n\t\tinput wire enc_sw,\r\n\t\tinput wire enc_btn,\r\n\t\t\/\/ User ports ends\r\n<\/code><\/pre>\n<p>OK, now the real work begins. The easiest thing is the LED values. Those come directly from the ARM register <em>slv_reg1<\/em>. We just need to hook that output from the register module to the LEDs. The only gotcha is that the register is 32 bits and we only need eight. We can just wire up the <em>led<\/em> output to the <em>slv_reg1<\/em> output of the register module, but that will give us some warnings that the widths don&#8217;t match. To keep things clean, we will connect up a 32-bit value that comes from concatenating a 24-bit Z value with our 8-bit <em>led<\/em> output. It&#8217;s important to note that we can&#8217;t use zero values here, because we would then be driving those <em>into<\/em> the register module. Here is the modification to the instantiation of the register module:<\/p>\n<pre><code>        .slv_reg1({24'bz,led}),<\/code><\/pre>\n<p>Next, let&#8217;s deal with the SSD value. Remember, what is coming out of the register module is an 8-bit value which\u00a0we want to display on the seven segment display. Specifically, this is <em>not<\/em> the value of the <em>ssd<\/em> output. We will need to declare a new 8-bit wire to hold this value in our module. Let&#8217;s call that <em>ssd_value<\/em>. We need to declare that before we instantiate the register module.<\/p>\n<pre><code>\twire [7:0] ssd_value;<\/code><\/pre>\n<p>Then we need to connect that to the <em>slv_reg0<\/em> output of the register module. Here is that modified connection:<\/p>\n<pre><code>\t    .slv_reg0({24'bz,ssd_value}),<\/code><\/pre>\n<p>We need to debounce all of the button and switch inputs. We will need signals to hold the debounced versions of those inputs so go ahead and declare those now. This is just like in the previous tutorial. Put these declarations right after the <em>ssd_value<\/em> declaration. Here is what I have:<\/p>\n<pre><code>\twire [7:0] switch_db;\r\n\twire [4:0] btn_db;\r\n\twire enc_a_db;\r\n\twire enc_b_db;\r\n\twire enc_sw_db;\r\n\twire enc_btn_db;\r\n<\/code><\/pre>\n<p>Now some of these just go straight into the register module. Let&#8217;s put those in now. As with the first two register values, we have some width mismatches. We will use a concatenation here as well, but since we are driving inputs into the module, we&#8217;re going to need to give them an actual value. We will use zero for that. Here are the modified register module ports:<\/p>\n<pre><code>\t    .slv_reg0({24'bz,ssd_value}),\r\n\t    .slv_reg1({24'bz,led}),\r\n\t    .slv_reg2({24'b0,switch_db}),\r\n\t    .slv_reg3({27'b0,btn_db}),\r\n\t    .slv_reg4(),\r\n\t    .slv_reg5({31'b0,enc_sw_db}),\r\n\t    .slv_reg6({31'b0,enc_btn_db}),\r\n\t    .slv_reg7(),\r\n<\/code><\/pre>\n<p>Notice that we still have to declare the 8-bit register which holds the rotary encoder value and the 32-bit timer value. Add the declarations for those before the register module instantiation like this:<\/p>\n<pre><code>\twire [7:0] encoder_value;\r\n\treg [31:0] timer = 0;\r\n<\/code><\/pre>\n<p>And add those to the register module instantiation as well:<\/p>\n<pre><code>\t    .slv_reg0({24'bz,ssd_value}),\r\n\t    .slv_reg1({24'bz,led}),\r\n\t    .slv_reg2({24'b0,switch_db}),\r\n\t    .slv_reg3({27'b0,btn_db}),\r\n\t    .slv_reg4({24'b0,encoder_value}),\r\n\t    .slv_reg5({31'b0,enc_sw_db}),\r\n\t    .slv_reg6({31'b0,enc_btn_db}),\r\n\t    .slv_reg7(timer),\r\n<\/code><\/pre>\n<p>Now is probably a good time to check that the code you have so far compiles correctly. You can click on the <b>Elaborated Design<\/b> flow under the <b>RTL Analysis<\/b> section of the <em>Flow Navigator<\/em> window. This will check your design for errors. When you are done, you can click on the <b>Project Manager<\/b> flow to get back to editing your design.<\/p>\n<h2>Debounce<\/h2>\n<p>Next, we will instantiate the debounce module from <a title=\"Tutorial 11 \u2013 A Debounce Circuit\" href=\"https:\/\/www.beyond-circuits.com\/wordpress\/tutorial\/tutorial11\/\">tutorial 11<\/a>. We don&#8217;t need to bother with connecting the rising edge or falling edge outputs. We just need the debounced outputs. In case you are worried that this is inefficient, the synthesis tools will take care of removing any logic which does not produce an output. So rest assured: anything that is unused will not occupy space on the device.<\/p>\n<p>Instantiate the debounce module like this. Note that this module does not have the <em>ms_limit<\/em> parameter so we just use a literal value of 300,000. Your code should go at the end of the module where the comments in the module indicate.<\/p>\n<pre><code>    debounce\r\n    #(\r\n      .width(17),\r\n      .bounce_limit(300000)\r\n      )\r\n    debounce\r\n    (\r\n     .clk(clk),\r\n     .switch_in({enc_a,enc_b,enc_sw,enc_btn,\r\n\t\t btn,switch}),\r\n     .switch_out({enc_a_db,enc_b_db,enc_sw_db,enc_btn_db,\r\n\t\t  btn_db,switch_db}),\r\n     .switch_rise(),\r\n     .switch_fall()\r\n     );\r\n<\/code><\/pre>\n<p><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure7.png\"><img loading=\"lazy\" decoding=\"async\" class=\" size-medium wp-image-470 alignright\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure7-300x146.png\" alt=\"figure7\" width=\"300\" height=\"146\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure7-300x146.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure7.png 407w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>Save the code and look in the <em>Sources<\/em> window in the <b>Project Manager<\/b> flow. You will see that we have an undefined module called <em>debounce<\/em>.<\/p>\n<p>We need to add the <em>debounce<\/em> module from <a title=\"Tutorial 11 \u2013 A Debounce Circuit\" href=\"https:\/\/www.beyond-circuits.com\/wordpress\/tutorial\/tutorial11\/\">tutorial 11<\/a> to our design. Click the <em>Add Sources<\/em> button or type ctrl-A to add a source file. Select <em>Add or create design sources<\/em> and click <b><em>Next<\/em><\/b>. Click <em>Add Files&#8230;<\/em> and browse to your <em>debounce<\/em> module. Check the box that says <em>Copy sources into IP Directory<\/em>. Then click <b><em>Finish<\/em><\/b>. You should then see the debounce module properly defined in the <em>Sources<\/em> window.<\/p>\n<p>Click on the <b>RTL Analysis<\/b> flow. At the top of the <b>Elaborated Design<\/b> window, you should see an indication that the design sources have been modified. Click the <em>Reload<\/em> button to recheck your code. It will build a little block diagram of your design so far. You should see the <em>debounce<\/em> module connected to the <em>stopwatch_controller_v1_0_S00_AXI<\/em> module. Go back to the <b>Project Manager<\/b> flow.<\/p>\n<h2>SSD control<\/h2>\n<p>We also need to add the logic to control the seven segment display. This is just like in <a title=\"Tutorial 12 \u2013 Rotary Encoder\" href=\"https:\/\/www.beyond-circuits.com\/wordpress\/tutorial\/tutorial12\/\">tutorial 12<\/a>, except the name of the signal connected to the <em>value<\/em> input is different and we don&#8217;t have the <em>ms_limit<\/em> parameter.<\/p>\n<pre><code>  ssd\r\n    #(100000)\r\n  ssd\r\n    (\r\n     .clk(clk),\r\n     .value(ssd_value),\r\n     .ssd(ssd),\r\n     .ssdcat(ssdcat)\r\n     );\r\n<\/code><\/pre>\n<p>Go ahead and add the <em>ssd<\/em> module to the design using the <em>Add Sources<\/em> button. Elaborate the design again to check your RTL.<\/p>\n<h2>Rotary Encoder<\/h2>\n<p><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure8.png\"><img loading=\"lazy\" decoding=\"async\" class=\" size-medium wp-image-475 alignright\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure8-300x212.png\" alt=\"figure8\" width=\"300\" height=\"212\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure8-300x212.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure8-425x300.png 425w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure8.png 558w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>Now we need to add the logic from the rotary encoder. Let&#8217;s go ahead and put that in a module of its own and instantiate that in our top level. Add another source file, but this time, select <em>Create File<\/em> in the <em>Add or Create Design Sources<\/em> dialog box. Enter the name <code>encoder.v<\/code> for the file name. You cannot use the default location however. See my <a title=\"Putting New Files in the Right Place \u2013 The Vivado Edition\" href=\"https:\/\/www.beyond-circuits.com\/wordpress\/2015\/03\/putting-new-files-in-the-right-place-the-vivado-edition\/\">blog post<\/a> on the subject for more details. In <em>File location<\/em>, navigate to the <em>stopwatch_controller_v1_0<\/em>\u00a0directory in the <em>ip_repo<\/em> directory and then select the <em>hdl<\/em>\u00a0directory. This will place the new file in the correct location so that it is picked up by the IP packager. Click <b><em>OK<\/em><\/b>, and then click <b><em>Finish<\/em><\/b>. It will then bring up the <em>Define Module<\/em> dialog box. Just click <b><em>OK<\/em><\/b> until the dialog boxes go away. If you think it&#8217;s easier to declare module ports with the dialog box than typing the Verilog code, you might want to go back to <a title=\"Tutorial 1 \u2013 The Simplest FPGA in the World\" href=\"https:\/\/www.beyond-circuits.com\/wordpress\/tutorial\/tutorial1\/\">tutorial 1<\/a>. Or maybe you are just used to coding in VHDL.<\/p>\n<p>Edit the encoder.v file and add your code from <a title=\"Tutorial 12 \u2013 Rotary Encoder\" href=\"https:\/\/www.beyond-circuits.com\/wordpress\/tutorial\/tutorial12\/\">tutorial 12<\/a>. Make sure to add the input and output port declarations as well. I have changed the names around a little and added a parameter to let a user specify an arbitrary width for the register. Here is my code:<\/p>\n<pre><code>`timescale 1ns \/ 1ns\r\nmodule encoder\r\n #(\r\n     parameter width = 8\r\n  )\r\n  (\r\n    input clk,\r\n    input a_rise,\r\n    input b_value,\r\n    output reg [width-1:0] value\r\n  );\r\n    initial value = 0;\r\n    always @(posedge clk)\r\n      if (a_rise)\r\n        if (!b_value)\r\n      value &lt;= value-1;\r\n        else\r\n      value &lt;= value+1;\r\n \r\nendmodule\r\n<\/code><\/pre>\n<p>We also need to instantiate the <em>encoder<\/em> module. However, we&#8217;ve forgotten something. The encoder module needs to see the rise signal on the <em>enc_a<\/em> input. We can either modify the <em>encoder<\/em> module to detect the rise on the encoder input, or we can connect the a signal between the appropriate rise output of the <em>debounce<\/em> module and the <em>encoder<\/em> module. In general, it is best to keep the interface to modules as simple as possible, and I think the correct decision is to put the logic inside the <em>encoder<\/em> module. Speaking of keeping things generalized, we should probably remove the requirement that the inputs be synchronized to the module&#8217;s clock. In our case they are, but they might not be in other cases where the <em>encoder<\/em> module is used. One other minor quibble: you may have noticed that in <a title=\"Tutorial 12 \u2013 Rotary Encoder\" href=\"https:\/\/www.beyond-circuits.com\/wordpress\/tutorial\/tutorial12\/\">tutorial 12<\/a> the display always started at a value of 01. That&#8217;s because the idle state of the A input from the encoder is actually high, yet we were initializing the rise detector circuit with all zeroes. That made the rise get detected when the FPGA first started up. We could initialize the rise detector here to all ones and that would not happen. But is that the case for all rotary encoders? We should probably make that a parameter as well. So let&#8217;s make a little change to that. Here is the modified module:<\/p>\n<pre><code>`timescale 1ns \/ 1ns\r\nmodule encoder\r\n #(\r\n     parameter width = 8,\r\n     parameter a_rest_state = 1\r\n  )\r\n  (\r\n    input clk,\r\n    input a_value,\r\n    input b_value,\r\n    output reg [width-1:0] value\r\n  );\r\n    reg [1:0] a_shift = {2 {a_rest_state[0]}};\r\n    always @(posedge clk) a_shift &lt;= {a_shift,a_value};\r\n    initial value = 0;\r\n    always @(posedge clk)\r\n      if (a_shift == 2'b01)\r\n        if (!b_value)\r\n      value &lt;= value-1;\r\n        else\r\n      value &lt;= value+1;\r\nendmodule\r\n<\/code><\/pre>\n<p>Let&#8217;s take a little closer look at where we declare <em>a_shift<\/em>. The initialization value has two interesting features. The first is a repeated concatenation. The expression <code>{2 {a_rest_state[0]}}<\/code> means that the value in the inner curly braces is to be repeated the number of times mentioned in the outer braces. So in other words the expression <code>{2 {value}}<\/code> equivalent to <code>{value,value}<\/code>. The expression <code>{4 {value}}<\/code> is equivalent to the expression <code>{value,value,value,value}<\/code>. The other thing to note is that we are only concerned with the least significant bit of the <em>a_rest_state<\/em> parameter. It is critical that we only concatenate the 1-bit value. If we were to not do the bit select in the concatenation we would end up concatenating a 32-bit expression. This would result in a 64-bit expression and we would use the low two bits, causing\u00a0<em>a_shift<\/em> to initialize to the value 2&#8217;b01 rather than the desired value of 2&#8217;b11.<\/p>\n<p>Now that we have perfected our <em>encoder<\/em> module, we turn our attention to instantiating it in the top module. Here is the code I have for that:<\/p>\n<pre><code>    encoder\r\n       #(8,1)\r\n    encoder\r\n       (\r\n        .clk(clk),\r\n        .a_value(enc_a_db),\r\n        .b_value(enc_b_db),\r\n        .value(encoder_value)\r\n        );\r\n<\/code><\/pre>\n<h2>The timer register<\/h2>\n<p>All that&#8217;s\u00a0left is to implement the timer counter. Basically, we just want a 32-bit register which increments once every millisecond. This means we also need to have a counter to count\u00a0the milliseconds as well. In thinking about this, it seems like we should probably add a <em>ms_limit<\/em> parameter to our design as well so a user of the IP block could use a clock of arbitrary frequency. Let&#8217;s go ahead and add that now. First add the parameter to the <b>stopwatch_controller_v1_0<\/b> module. Set the default value to 100000.<\/p>\n<pre><code>\/\/ Users to add parameters here\r\nparameter ms_limit = 100000,\r\n\/\/ User parameters ends\r\n<\/code><\/pre>\n<p>We also need to modify the instantiations of <em>debounce<\/em> and <em>ssd<\/em> to use the <em>ms_limit<\/em> parameter. Remember, we used a value based on <em>ms_limit<\/em> for the <em>debounce<\/em> module. So we&#8217;ll need to turn that back into an expression based on <em>ms_limit<\/em>.<\/p>\n<p>Let&#8217;s code the timer now. First, we need the millisecond counter. You should be familiar with doing this from previous tutorials. Here is the code that I have:<\/p>\n<pre><code>        reg [$clog2(ms_limit)-1:0] ms_counter = 0;\r\n        wire ms_limit_reached = ms_counter == ms_limit-1;\r\n        always @(posedge clk)\r\n            if (ms_limit_reached)\r\n                ms_counter &lt;= 0;\r\n            else\r\n                ms_counter &lt;= ms_counter+1;\r\n                \r\n        always @(posedge clk)\r\n            if (ms_limit_reached)\r\n                timer &lt;= timer+1;\r\n<\/code><\/pre>\n<p>You can go ahead and check the code by elaborating, and you can even run a synthesis to make sure everything is OK.<\/p>\n<h2>Packaging the IP<\/h2>\n<p><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure9.png\"><img loading=\"lazy\" decoding=\"async\" class=\" size-medium wp-image-481 alignright\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure9-300x122.png\" alt=\"figure9\" width=\"300\" height=\"122\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure9-300x122.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure9-500x203.png 500w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure9.png 873w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>Next we turn to packaging the IP component. In the <b>Project Manager<\/b> flow, you will see a tab labeled <em>Package IP &#8211; stopwatch_controller<\/em>. <a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure10.png\"><img loading=\"lazy\" decoding=\"async\" class=\" size-medium wp-image-482 alignright\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure10-300x108.png\" alt=\"figure10\" width=\"300\" height=\"108\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure10-300x108.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure10-1024x368.png 1024w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure10-500x179.png 500w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure10.png 1039w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>Click on the tab now. You will see a number of <em>Packaging Steps<\/em>. Some of these are checked indicating that they are complete, while others need to be updated. Go ahead and click on <b>File Groups<\/b>. You will see something like the figure to the right. Go ahead and click the link that says <em>Merge Changes from File Groups Wizard<\/em>.<a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure11.png\"><img loading=\"lazy\" decoding=\"async\" class=\" size-medium wp-image-483 alignright\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure11-300x202.png\" alt=\"figure11\" width=\"300\" height=\"202\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure11-300x202.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure11.png 423w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a> I noticed that when I ran the merge that there were warnings about the <em>encoder.v<\/em> file not having a relative path to the IP root directory. I&#8217;m not sure why I got that message\u2013 maybe it was because we created the file, rather than importing it. In any case, select the file in the <em>Sources<\/em> window and right click and select <em>Copy All Files Into Project<\/em>.<\/p>\n<p>Now go to the <em>Customization Parameters<\/em> step and run the link for that step as well. Notice that this has now included the <em>ms_limit<\/em> parameter into the <em>Customization Parameters<\/em>. After this, select the <em>Customization GUI<\/em> step which allows to change what a user sees when they try to customize the IP block. You need to click on the plus icon on the <em>Layout<\/em> panel to add the <em>ms_limit<\/em> parameter. You can drag the parameter around in the Layout panel to make the parameter appear on the same page as the four existing AXI parameters.<\/p>\n<p>Go to the <em>Review and Package<\/em> flow and click the link <em>edit package settings<\/em>. Make sure the option <em>Create archive of IP<\/em> is checked. Click <strong><em>OK<\/em><\/strong>. Then click <strong><em>Re-Package IP<\/em><\/strong>. Click <strong><em>OK<\/em><\/strong> to close the project.<\/p>\n<p>You will now be placed back in the project we created at the beginning of this tutorial.<\/p>\n<h1>Packaging<\/h1>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-medium wp-image-535 alignright\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure12-300x159.png\" alt=\"figure12\" width=\"300\" height=\"159\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure12-300x159.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure12-500x265.png 500w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/02\/figure12.png 609w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/>A key concept is the idea of an IP package and an IP repository. When you package your IP, Vivado places it in the IP repository. If you want to edit the IP open the <em>IP Catalog<\/em>\u00a0from the <em>Project Manager<\/em> flow. Then select your IP component from the <em>IP Catalog\u00a0<\/em>tab. Right click on your component and select<em> Edit in IP Packager<\/em>. This will reopen the package and edit in the appropriate context. You can then repackage the IP when you have finished your edits.<\/p>\n<h1>Summary<\/h1>\n<p>We have successfully created an IP block that we can use in the next tutorial to talk with the ARM processor. When the Package IP process completes you will be back in the project you originally created. This is where we will start our next tutorial.<\/p>\n<h1>Files<\/h1>\n<p>Here are the files I have for this tutorial.<\/p>\n<ul>\n<li><a title=\"stopwatch_controller_v1_0.v\" href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/tutorials\/tutorial13\/stopwatch_controller_v1_0.v\">stopwatch_controller_v1_0.v<\/a><\/li>\n<li><a title=\"stopwatch_controller_v1_0_S00_AXI.v\" href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/tutorials\/tutorial13\/stopwatch_controller_v1_0_S00_AXI.v\">stopwatch_controller_v1_0_S00_AXI.v<\/a><\/li>\n<li><a title=\"ssd.v\" href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/tutorials\/tutorial13\/ssd.v\">ssd.v<\/a><\/li>\n<li><a title=\"debounce.v\" href=\"https:\/\/www.beyond-circuits.com\/repos\/tutorial\/trunk\/rtl\/debounce.v\">debounce.v<\/a><\/li>\n<li><a title=\"encoder.v\" href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/tutorials\/tutorial13\/encoder.v\">encoder.v<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>In this tutorial we will build an IP component that can be used by the ARM processor to implement the stopwatch ourunctions we used in our earlier tutorials. The main components of this IP block will be: A set of &hellip; <a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/tutorial\/tutorial13\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"parent":226,"menu_order":13,"comment_status":"open","ping_status":"open","template":"","meta":{"footnotes":""},"class_list":["post-449","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/pages\/449","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=449"}],"version-history":[{"count":34,"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/pages\/449\/revisions"}],"predecessor-version":[{"id":1388,"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/pages\/449\/revisions\/1388"}],"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=449"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}