
{"id":256,"date":"2018-09-27T13:32:35","date_gmt":"2018-09-27T13:32:35","guid":{"rendered":"http:\/\/blogs.plymouth.ac.uk\/embedded-systems\/?page_id=256"},"modified":"2018-09-27T13:44:40","modified_gmt":"2018-09-27T13:44:40","slug":"part-6-modelling-and-testing-synchronous-systems","status":"publish","type":"page","link":"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/fpga-and-vhdl\/test-benches\/part-6-modelling-and-testing-synchronous-systems\/","title":{"rendered":"Part 6 &#8211; Modelling and Testing Synchronous Systems"},"content":{"rendered":"<p><a href=\"http:\/\/blogs.plymouth.ac.uk\/embedded-systems\/fpga-and-vhdl\/test-benches\/part-5-timing-checks\/\">Prev<\/a><\/p>\n<p>The majority of sequential logic systems use a shared clock to synchronise outputs. We say such systems are &#8220;synchronous&#8221;. One of the most fundamental building blocks of a synchronous systems if the D-Type Flip-Flop.<\/p>\n<p>This is defined in the following VHDL:<\/p>\n<pre class=\"theme:xcode lang:default highlight:0 decode:true\">library ieee;\t\t\t\t\r\nuse ieee.std_logic_1164.all;\r\n\r\n--D-Type Flipflop primitive\r\nentity dff_primitive is\r\nport(  \tD:\tin std_logic;\r\n\tCLK:\tin std_logic;\r\n\tQ:\tout std_logic\r\n);\r\nend dff_primitive;\r\n\r\n--This component has two architecture\r\narchitecture v1 of dff_primitive is\r\n\r\nbegin\r\n\tprocess(CLK)\r\n\tbegin\r\n\t\t--Update Q on the rising edge of CLK\r\n\t\tif rising_edge(CLK) then\r\n\t\t\tQ &lt;= D; \r\n\t\t\t-- The absence of an else will result in a latching behviour\r\n\t\tend if;\r\n\tend process;\r\nend v1;<\/pre>\n<p>In words, the output\u00a0<span class=\"lang:default highlight:0 decode:true crayon-inline \">Q<\/span>\u00a0 is latched to the input value\u00a0<span class=\"lang:default highlight:0 decode:true crayon-inline \">D<\/span>\u00a0 on the rising edge of the clock\u00a0<span class=\"lang:default highlight:0 decode:true crayon-inline \">CLK<\/span>\u00a0 Note that this is <em>edge triggered<\/em>, and NOT level triggered. Special edge detection circuitry is is used in synthesis.<\/p>\n<p>Note how the\u00a0<span class=\"lang:default highlight:0 decode:true crayon-inline \">rising_edge<\/span>\u00a0 function is used in this example. This function only returns a boolean true when the signal changes from a low value (&#8216;0&#8217; or &#8216;L&#8217;) to a high value (&#8216;1&#8217; or &#8216;H&#8217;). It does not return true for a transition from &#8216;U&#8217; to &#8216;1&#8217;.<\/p>\n<h2>Testing<\/h2>\n<p>To test a D-Type Flip-Flop requires the generation of a clock. Ideally, we should also examine the outputs of the D-Type Flip-Flop for specific input sequences.<\/p>\n<p>Let&#8217;s look at a testbench to test the following:<\/p>\n<ul>\n<li>Latching a &#8216;0&#8217; input<\/li>\n<li>Latching a &#8216;1&#8217; input<\/li>\n<li>Ignoring input changes between clock edges<\/li>\n<\/ul>\n<p>For clarity, this will be limited to functional testing and will ignore timing such as set-up and hold-time violations.<\/p>\n<pre class=\"theme:xcode lang:default highlight:0 decode:true\">library ieee;\t\t\t\t\r\nuse ieee.std_logic_1164.all;\r\nuse ieee.numeric_std.all;\r\n--use ieee.std_logic_unsigned.all;\r\n--use std.textio.all;\r\n\r\nentity dff_test is\r\nend dff_test;\r\n\r\narchitecture v1 of dff_test is\r\n\t--Declare signals\r\n\tsignal D_INPUT     : std_logic;\r\n\tsignal CLK_INPUT   : std_logic := '0';\r\n\tsignal Q_OUTPUT    : std_logic;\r\n\tconstant Tclk      : time  := 50 ns;\r\n\tconstant Tsim\t   : time  := 1000 ns;\r\n\r\n\t--Simple procedure to check the level of a signal\r\n\tprocedure checkOutput(expected : std_logic) is\r\n\tbegin\r\n\t\tassert(Q_OUTPUT = expected)\r\n\t\t\treport \"DFF output incorrect\"\r\n\t\t\tseverity error;\r\n\tend checkOutput;\t\r\n\t\r\n\t--Simple procedures to wait on clock edges\r\n\tprocedure waitForClockToFall is\r\n\tbegin\r\n\t\twait until (CLK_INPUT'EVENT and CLK_INPUT = '0');\r\n\tend waitForClockToFall;\r\n\r\n\tprocedure waitForClockToRise is\r\n\tbegin\r\n\t\twait until (CLK_INPUT'EVENT and CLK_INPUT = '1');\r\n\tend waitForClockToRise;\r\n\r\nbegin\r\n\t--Instantiate v1 of the component type dlatch_primative\r\n\tu1: entity work.dff_primitive(v1) PORT MAP (\r\n\t\tD   =&gt; D_INPUT,\r\n\t\tCLK =&gt; CLK_INPUT,\r\n\t\tQ   =&gt; Q_OUTPUT\r\n\t);\r\n\r\n\tclock_process:\r\n\tprocess\r\n\t\tvariable t : time := 0 ns;\r\n\tbegin\r\n\t\tloop\r\n\t\t\tt := t + Tclk;\r\n\t\t\twait for Tclk;\r\n\t\t\tCLK_INPUT &lt;= not CLK_INPUT;\r\n\t\t\texit when t &gt;= Tsim;\r\n\t\tend loop;\r\n\t\twait;\r\n\tend process;\r\n\r\n\tmain_process:\r\n\tprocess \r\n\t\t--Declarations here\r\n\tbegin\t\r\n\t\t--Set on falling edge of clock so signal is stable on rising\r\n\t\twaitForClockToFall;\t\r\n\t\r\n\t\t-- latching a zero on the output\r\n\t\tD_INPUT &lt;= '0';\r\n\r\n\t\t--Check output\r\n\t\twaitForClockToRise;\r\n\t\tcheckOutput('0');\r\n\r\n\t\t--test latching a one\r\n\t\twaitForClockToFall;\r\n\t\tD_INPUT &lt;= '1';\t\t\r\n\t\t\r\n\t\twaitForClockToRise;\t\r\n\t\tcheckOutput('1');\r\n\r\n\t\twaitForClockToFall;\r\n\t\tcheckOutput('1');\r\n\t\t\r\n\t\t--show that input is ignored elsewhere\r\n\t\tD_INPUT &lt;= '0';\r\n\t\twait for (Tclk \/ 10);\r\n\t\tcheckOutput('1');\r\n\r\n\t\tD_INPUT &lt;= '1';\r\n\t\twait for (Tclk \/ 10);\r\n\t\tcheckOutput('1');\r\n\r\n\t\tD_INPUT &lt;= '0';\r\n\t\twait for (Tclk \/ 10);\r\n\t\tcheckOutput('1');\r\n\r\n\r\n\t\tD_INPUT &lt;= '0';\t\r\n\t\twaitForClockToFall;\r\n\t\twaitForClockToRise;\r\n\t\tcheckOutput('0');\r\n\t\t\r\n\t\t\t\t\t\r\n\t\t--End of test is to wait forever\r\n\t\twait;\r\n\tend process;\r\n\t\t\r\nend v1;<\/pre>\n<p>Before we examine this in more detail, let&#8217;s look at the simulation output:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-263 size-full\" src=\"http:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2018\/09\/snapshot7-1.png\" alt=\"\" width=\"1367\" height=\"205\" srcset=\"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2018\/09\/snapshot7-1.png 1367w, https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2018\/09\/snapshot7-1-300x45.png 300w, https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2018\/09\/snapshot7-1-768x115.png 768w, https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2018\/09\/snapshot7-1-1024x154.png 1024w, https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2018\/09\/snapshot7-1-560x84.png 560w, https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2018\/09\/snapshot7-1-260x39.png 260w, https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-content\/uploads\/sites\/94\/2018\/09\/snapshot7-1-160x24.png 160w\" sizes=\"auto, (max-width: 1367px) 100vw, 1367px\" \/><\/p>\n<p>There are some points of interest:<\/p>\n<ul>\n<li>At time &lt; 100ns, the input is undefined.<\/li>\n<li>At time &lt; 150ns, the output is undefined (suggesting this device may need a reset input)<\/li>\n<li>At times 150ns and 350ns there is a rising edge of clock, and a correct output transition to value &#8216;0&#8217;. This is shown to latch<\/li>\n<li>At time 250ns there is a rising edge of clock, and a correct output transition to value &#8216;1&#8217;. This is shown to latch<\/li>\n<li>At time 300ns and shortly after, there are some perturbations in the input. These are shown to be correctly ignored<\/li>\n<\/ul>\n<p>This is not exhaustive, but provides good coverage for illustrative purposes. Let&#8217;s now look more closely at the test-bench where we meet some new concepts:<\/p>\n<p>The component under test is instantiated as we&#8217;ve done before:<\/p>\n<pre class=\"theme:xcode lang:default highlight:0 decode:true \">\tu1: entity work.dff_primitive(v1) PORT MAP ( D =&gt; D_INPUT, CLK =&gt; CLK_INPUT, Q =&gt; Q_OUTPUT );<\/pre>\n<p>Therefore, we see that we should stimulate the <span class=\"lang:default highlight:0 decode:true crayon-inline \">D_INPUT<\/span> and <span class=\"lang:default highlight:0 decode:true crayon-inline \">CLK_INPUT<\/span> signals, while observing the <span class=\"lang:default highlight:0 decode:true crayon-inline \">Q_OUTPUT<\/span> signal.<\/p>\n<h3>Separation of Concerns<\/h3>\n<p>Note there are two process blocks in the testbench,\u00a0<span class=\"lang:default highlight:0 decode:true crayon-inline \">clock_process<\/span> which stimulates the\u00a0<span class=\"lang:default highlight:0 decode:true crayon-inline \">CLK_INPUT<\/span>\u00a0 signal and <span class=\"lang:default highlight:0 decode:true crayon-inline\">main_process<\/span> which stimulates (and checks) the\u00a0<span class=\"lang:default highlight:0 decode:true crayon-inline \">Q_OUTPUT<\/span>\u00a0 signal.<\/p>\n<ul>\n<li>They are separated to help simplify the structure<\/li>\n<li>The run concurrently<\/li>\n<li>Each will stimulate a unique set of signals<\/li>\n<\/ul>\n<p>It is good practise to factor out a task in this way. Each process block has a distinct responsibility.<\/p>\n<h3>Clock Process<\/h3>\n<p>The clock process has the single task of generating a clock signal for a defined period of time. In this example, the loop &#8211; end loop mechanism is used. We could equally have used a for-loop or some other approach.<\/p>\n<pre class=\"theme:xcode lang:default mark:7,8 highlight:0 decode:true\">\tclock_process:\r\n\tprocess\r\n\t\tvariable t : time := 0 ns;\r\n\tbegin\r\n\t\tloop\r\n\t\t\tt := t + Tclk;\r\n\t\t\twait for Tclk;\r\n\t\t\tCLK_INPUT &lt;= not CLK_INPUT;\r\n\t\t\texit when t &gt;= Tsim;\r\n\t\tend loop;\r\n\t\twait;\r\n\tend process;<\/pre>\n<p>The highlighted lines show how the clock signal is toggled every 50 ns. Note how a variable is used to keep track of time-elapsed, and that the loop exists once <span class=\"lang:default highlight:0 decode:true crayon-inline \">Tsim<\/span> ns have elapsed. To make the code more readable, two constants are defined in the testbench architecture:<\/p>\n<pre class=\"theme:xcode lang:default highlight:0 decode:true\">constant Tclk : time := 50 ns; \r\nconstant Tsim : time := 1000 ns;<\/pre>\n<h3>Main Process<\/h3>\n<p>Given that the clock signal is now managed elsewhere, the main process simply needs to stimulate the\u00a0<span class=\"lang:default highlight:0 decode:true crayon-inline \">D_INPUT<\/span>\u00a0 signal at the correct times and to check the output signal <span class=\"lang:default highlight:0 decode:true crayon-inline \">Q_OUTPUT<\/span>\u00a0. Here is a sample taken from this process:<\/p>\n<pre class=\"theme:xcode lang:default highlight:0 decode:true\">--Set on falling edge of clock so signal is stable on rising\r\nwaitForClockToFall;\t\r\n\t\r\n-- latching a zero on the output\r\nD_INPUT &lt;= '0';\r\n\r\n--Check output\r\nwaitForClockToRise;\r\ncheckOutput('0');<\/pre>\n<p>The procedure is as follows:<\/p>\n<ol>\n<li>The input signal <span class=\"lang:default highlight:0 decode:true crayon-inline \">D_INPUT<\/span>\u00a0 is forced to logic &#8216;0&#8217; after the fall of the clock edge (thus ensuring the input is stable for half a clock period before the rising edge)<\/li>\n<li>The simulation then waits for a rising edge of the clock <span class=\"lang:default highlight:0 decode:true crayon-inline\">CLK_INPUT<\/span><\/li>\n<li>The output signal <span class=\"lang:default highlight:0 decode:true crayon-inline \">Q_OUTPUT<\/span> is checked immediately (there is no propagation delay in a functional simulation).<\/li>\n<\/ol>\n<p>Note that three <strong>VHDL procedures<\/strong> were used to reduce code repetition and improve readability. The first waits for a falling clock edge.<\/p>\n<pre class=\"theme:xcode lang:default highlight:0 decode:true\">procedure waitForClockToFall is\r\nbegin\r\n\twait until (CLK_INPUT'EVENT and CLK_INPUT = '0');\r\nend waitForClockToFall;\r\n<\/pre>\n<p>This is invoked by simply writing\u00a0<span class=\"lang:default highlight:0 decode:true crayon-inline \">waitForClockToFall<\/span>\u00a0 in the testbench. The second is similar, and waits for a rising clock edge:<\/p>\n<pre class=\"theme:xcode lang:default highlight:0 decode:true\">procedure waitForClockToRise is\r\nbegin\r\n\twait until (CLK_INPUT'EVENT and CLK_INPUT = '1');\r\nend waitForClockToRise;<\/pre>\n<p>Finally, the <span class=\"lang:default highlight:0 decode:true crayon-inline \">checkOutput<\/span>\u00a0 procedure is defined. This is somewhat different from the preceding two examples as it takes an input parameter. Note that it is possible to have more than one parameter (each is separated by a semi-colon).<\/p>\n<pre class=\"theme:xcode lang:default highlight:0 decode:true\">procedure checkOutput(expected : std_logic) is\r\nbegin\r\n\tassert(Q_OUTPUT = expected)\r\n\t\treport \"DFF output incorrect\"\r\n\t\tseverity error;\r\nend checkOutput;\t\r\n<\/pre>\n<h3>Automatic Testing with assert<\/h3>\n<p>The last example used the all-important <span class=\"lang:default highlight:0 decode:true crayon-inline\">assert<\/span>\u00a0 function to test for a specific condition. Where this condition is found to be false, then a message is written to the terminal. The severity is set as <span class=\"lang:default highlight:0 decode:true crayon-inline \">note<\/span>\u00a0, <span class=\"lang:default highlight:0 decode:true crayon-inline \">warning<\/span>\u00a0,\u00a0<span class=\"lang:default highlight:0 decode:true crayon-inline \">error<\/span>\u00a0 or <span class=\"lang:default highlight:0 decode:true crayon-inline \">failure<\/span>\u00a0.<\/p>\n<p>When we run this simulation, we discover there are two errors reported!<\/p>\n<pre class=\"theme:dark-terminal lang:default highlight:0 decode:true \"># ** Error: DFF output incorrect\r\n# Time: 150 ns Iteration: 1 Instance: \/dff_test\r\n# ** Error: DFF output incorrect\r\n# Time: 250 ns Iteration: 1 Instance: \/dff_test<\/pre>\n<p>This might seem strange as the simulation, the output looked correct. Watch the following video to see how this is resolved.<\/p>\n<p><iframe loading=\"lazy\" title=\"Testing Synchronous VHDL with ASSERT in ModelSim\" width=\"750\" height=\"563\" src=\"https:\/\/www.youtube.com\/embed\/kUTtv_BCvfA?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe><\/p>\n<p>The issue was that the output signal <span class=\"lang:default highlight:0 decode:true crayon-inline \">Q_OUTPUT<\/span>\u00a0 was being observer too quickly for the simulator! The solution used in this example was to change the\u00a0<span class=\"lang:default highlight:0 decode:true crayon-inline \">waitForClockToFall<\/span>\u00a0 and\u00a0<span class=\"lang:default highlight:0 decode:true crayon-inline \">waitForClockToRise<\/span>\u00a0 procedures to wait 1ps\u00a0 beyond the clock edge.<\/p>\n<pre class=\"theme:xcode lang:default highlight:0 decode:true\">procedure waitForClockToFall is\r\nbegin\r\n\twait until (CLK_INPUT'DELAYED(1 ps)'EVENT and CLK_INPUT = '0');\r\nend waitForClockToFall;\r\n\r\nprocedure waitForClockToRise is\r\nbegin\r\n\twait until (CLK_INPUT'DELAYED(1 ps)'EVENT and CLK_INPUT = '1');\r\nend waitForClockToRise;<\/pre>\n<p>The attribute <span class=\"lang:default highlight:0 decode:true crayon-inline \">DELAYED<\/span>\u00a0 is useful for observing and\/or waiting on delayed versions of signals. Of course, if we were to model timing, such as propagation delay, this technique could be used as well.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Prev The majority of sequential logic systems use a shared clock to synchronise outputs. We say such systems are &#8220;synchronous&#8221;. One of the most fundamental building blocks of a synchronous systems if the D-Type Flip-Flop. This is defined in the following VHDL: library ieee; use ieee.std_logic_1164.all; &#8211;D-Type Flipflop primitive entity dff_primitive is port( D: in&hellip; <a class=\"more-link\" href=\"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/fpga-and-vhdl\/test-benches\/part-6-modelling-and-testing-synchronous-systems\/\">Continue reading <span class=\"screen-reader-text\">Part 6 &#8211; Modelling and Testing Synchronous Systems<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"parent":30,"menu_order":5,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-256","page","type-page","status-publish","hentry","entry"],"_links":{"self":[{"href":"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-json\/wp\/v2\/pages\/256","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-json\/wp\/v2\/comments?post=256"}],"version-history":[{"count":11,"href":"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-json\/wp\/v2\/pages\/256\/revisions"}],"predecessor-version":[{"id":270,"href":"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-json\/wp\/v2\/pages\/256\/revisions\/270"}],"up":[{"embeddable":true,"href":"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-json\/wp\/v2\/pages\/30"}],"wp:attachment":[{"href":"https:\/\/blogs.plymouth.ac.uk\/embedded-systems\/wp-json\/wp\/v2\/media?parent=256"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}