• 0
Sign in to follow this  
Tickstart

Something simple is apparently impossible. Incr/decr number.

Question

Hi, I'm just beginning with FPGA's, I bought a Basys 3 this past tuesday.

I'm trying to increment a 4-bit value with the on-board Up-button and decrease it with the Down-button. What is a straight forward way of doing this?? I've tried to get this to work for the last two days. The buttons are debounced, so that's not an issue.

I've tried keeping the value in a signal vector and depending on which button is pressed, add a one or add a two's complement -1. The adding is done with a 4 bit adder I built, which works.

 

I'm sort of new to VHDL and digital design so any useful tips or hints or general advice are very much appreciated.

Instead of getting 1, 2, 3, 4, 5, 6 etc when pressing the Up button, I get a very weird pattern.. See attached photo (the arrows were meant to show that the pattern repeated itself after a number of presses).

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
--use IEEE.STD_LOGIC_UNSIGNED.ALL;
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity btn_map is
    Port ( btnD, btnU : in STD_LOGIC;							--btnU/D stands for up/down
           key : out STD_LOGIC_VECTOR (3 downto 0));
end btn_map;

architecture Behavioral of btn_map is

component trig_4b_Adder is
    Port ( clk : in STD_LOGIC;			--I modified the adder with some D-flops to not create a combinatorial loop (hence the clk)
           c, y : in STD_LOGIC_VECTOR (3 downto 0);				--c/y are the two 4-bit inputs to the adder
           s : out STD_LOGIC_VECTOR (3 downto 0));				--s = result
end component;

signal val, add_sub, new_key : STD_LOGIC_VECTOR (3 downto 0) := (others => '0');
signal trigger : STD_LOGIC := '0';		-- clock for the adder, "keypressed"

begin

    Adder: trig_4b_Adder port map(clk => trigger, c => val, y => add_sub, s => new_key); -- add_sub is either the +1, -1 or 0
    
    process(btnD, btnU)
        variable minus : STD_LOGIC_VECTOR (3 downto 0) := "1111";
        variable plus : STD_LOGIC_VECTOR (3 downto 0) := "0001";
        variable zero : STD_LOGIC_VECTOR (3 downto 0) := "0000";
        begin
            if btnD = '1' then
                add_sub <= minus;
            elsif btnU = '1' then
                add_sub <= plus;
            else
                add_sub <= zero; -- (sub zero lol)
            end if;
        end process;
                               
    trigger <= btnU or btnD;		-- start the adder
    val <= new_key;	-- I want to save the result from the adder till next clock cycle	-- these two lines of code feel bad for some reason,
    key <= new_key; -- key is the output from this module					-- like my design is inherently flawed somehow..
    
end Behavioral;

 

IMG_20170422_040209832.jpg

Edited by Tickstart

Share this post


Link to post
Share on other sites

Recommended Posts

  • 0

@Tickstart,

32 minutes ago, Tickstart said:

Let's roll back for a minute, I'd love to hear how you (as in all of you) would go about this problem :) Just need a fresh pair of eyes.

Sure!  For starters, I'd use the code @hamster posted above for debouncing the button inputs. As I said above, his final piece of code was better than the one I had written for the same purpose.

Second, I'd keep track of the last (debounced) button state, as well as the current (debounced) button state.  When the current button state is down and different from the last one, I'd look at the two buttons, up and down.  If both were pressed or neither were pressed, I'd do nothing.  Otherwise I'd adjust the counter.  Forgive the Verilog, but the result would look something like:

reg	[3:0]	counter;

reg	last_up, last_down, this_up, this_down;
initial last_up = 1'b0;
initial last_down = 1'b0;
initial this_up = 1'b0;
initial this_down = 1'b0;
initial	counter = 0;

always @(posedge i_clk)
begin
	//
	last_up   <= button_up;
    last_down <= button_down;
    //
    this_up   <= (button_up)&&(!last_up);
    this_down <= (button_down)&&(!last_down);
    //
    case({this_up, this_down})
    2'b01: if (counter) 
    		counter <= counter - 1'b1; 
            else
            counter <= 4'h9;
    2'b10: if (counter < 4'h9)
    		counter <= counter + 1'b1;
            else
            counter <= 4'h0;
    default: counter <= counter;
    endcase
end

Congrats on getting the 7Seg up and running too!  I agree with you as well, though, that ... you'd think the 7segment display would be harder than getting this simple counter up and running.  Still, handling asynchronous input (such as the buttons) is enough to ... how did @zygot put it?  Keep a professional up at night?  ;)

Good luck on your project, and keep us posted if you need any more help.

Dan

Share this post


Link to post
Share on other sites
  • 0

Tickstart,these

I haven't made any "description" of you nor do I think that you're stupid... so please don't amend my comments to garner an unearned insult. If I want to insult you I will do so without there being any doubt about it. Actually, there was the one time I DID try and insult someone intentionally and he just thought that I was funny.... what an ass ( a MENSA member ) so I've given that up. Really, I don't want to insult anyone ( other than that guy...) but seem to have a knack for doing it unintentionally. It's a "gift" I suppose....

So, thanks for the background. This is helpful and I think that we can get somewhere.

First off, the fact that even with over 20 years of experience writing HDL code professionally I write test benches for all of my design modules should be a big hint as to what kind of advice you will get from me, Learn how to write testbenches. There is help on the internet if you look for it. Testbenches don't solve all problems as they only do what you make the test... meaning that you have to understand what to test for. This reason alone is why you need to use them. Your skill designing solutions to problems will get better as your testbenches improve. Trust me on this.

You state: "I don't really like vhdl's functions and processes and procedures, they're confusing and obfuscating."

Yes they are... until you understand the concepts. Until you do using VHDL or Verilog will be a very painful exercise for you. And will System C and whatever becomes popular down the road as well. This is something that I can't help you with... you need to decide that it's worth your time and effort. Having some sort of mentor might help. You don't have to take a course but it wouldn't hurt either. As I mentioned before FPGA design concepts are different from standard computer languages ( I've used C, PASCAL, ADA, PYTHON, numerous assembly languages, custom languages, etc, etc.) . If you don't have an interest in learning them you will be a very frustrated person doing your FPGA development. That's just advice not a judgement about you.

So, it should be no surprise to you that I disagree with your last statement: "Just need a fresh pair of eyes". But you are under no obligation to take my advise.

Share this post


Link to post
Share on other sites
  • 0
2 hours ago, Tickstart said:

Let's roll back for a minute, I'd love to hear how you (as in all of you) would go about this problem :) Just need a fresh pair of eyes. The numbers I get are consistent and wrong, but the adder works in other applications.

Hi!

So here is how I would do it.... 

First thoughts about the design - nothing particularly tricky in timing or complexity, so might as well have a single clock domain running at the board's system clock (100Mhz or 50Mhz or whatever). The only thing that is timing sensitive is the button debounce, so a little bit of tweaking might be needed there.

At a glance the following low level components are needed:

- debounce : a button debouncer. Important point - this just generates a single-cycle pulse when a button has been held down long enough
    inputs  - clk 
            - button_raw
    outputs - button_debounced

- up_down_counter : An Up/Down counter with Clock enable. The guts are as follows:
      if rising_edge(clk) then
         if clock_enable = 1 then
            if count_up = '1' and count_down = '1' then
               NULL;
            elsif count_up = '1' then 
               count <= count + 1;
            elsif count_down = '1' then 
               count <= count - 1;
            end if;
         end if;
      end if;
      
   inputs - clock 
          - clock_enable
          - count_up 
          - count_down
   outputs - digit (4 bits)
      
- next_prev_counter : Much like the up_down counter, but outputs
   "0001", "0010", "0100" or "1000" based on 'next' & 'prev' inputs
  Bonus points for it changes to an output of "0000" if no next or prev input is received for 5 seconds

  inputs - clock 
          - next 
          - prev
   outputs - active (4 bits, 'one hot' encoded)
  
- seven_seg_display :  Takes four 4-bit values and displays them on 
   the seven segment display. Maybe add four 'blink' inputs to indicate
   which digit is active (or use the decimal point?)
   
   (This will be the most demanding of the modules)
   inputs  - clock
           - digit0 (4 bits)
           - blink0 
           - digit1 (4 bits)
           - blink1 
           - digit2 (4 bits)
           - blink2 
           - digit3 (4 bits)
           - blink3
   outputs - segments  (7 bits)
           - segment_select (4 bits)

           
- lock_unlock_test : Takes four 4-bit values and asserts the 'unlock' output. A nice idea would be to debounce this - e.g. the correct code has to be present for a second before the unlock signal is asserted.
   
So then it would be 
- Writing each of these five components
- Testing each of these in isolation (either with simulation or on H/W). For newbies H/W is best, just to see how hard debug is, discovering why simulation is so awesome.

With that done, then just assemble the entire system with a top level 'structural' module, with the following component instances:

- 4 x debounce : One for each button (up, down, left, right)

- 1 x next_prev_counter : Logically used to select the digit with focus - connect the next to the debounced right button, the prev to the debounced left button

- 4 x up_down_counter : One for each digit
     connect the count_up to the debounced up button
     connect the count_down to the debounced down button
     connect the clock_enable to the output of the next_prev_counter, so only one digit will change at a time.
  
- 1 x seven_seg_display :  Wire the digits to each of the up_down_counter instances.
   connect the blink input to the output of the next_prev_counter, so you can see which digit has focus.
           
- 1x lock_unlock_test : Connect all the digits to the outputs of the up_down_counters, and connect the unlock output to the secret device of great importance (or just a spare LED!)

And if your low-level testing has been good, it should all just work! (yes, in a perfect world.. :) )

Edited by hamster

Share this post


Link to post
Share on other sites
  • 0

Thank you very much, especially @hamster, I will try to take notice of your approach. Although we have slightly different input methods (selecting position left & right) this is actually what I originally had in mind, but settled for something "easier" to kick things off.

I will read some vhdl tutorials to get a better foundation to stand on, you only get so far merely jumping right into something. However, I would like to get some feedback on my 7-segment module (which works btw).

(you all know this already but just for the sake of completion:) The (4 digit) 7-segment display has only one input for data even though it has four positions, meaning the pattern you supply will show up on all four positions simultaneously. You have control over which positions are lit though, so what you have to do is to very rapidly (due to the human eye) light only the position of the display you want the data you're putting in to show up.

I have done so by using a shifter to swap position each clock cycle (a divided clock, 95Hz or something), ie "1110" -> "1101" -> "1011" -> "0111". 1 means OFF btw. See picture of FSM.

Top module for the 7-segment display:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity hex7seg_top is
    Port ( clk : in STD_LOGIC;
           a, b, c, d, mask : in STD_LOGIC_VECTOR (3 downto 0); -- input data for each position, mask is if you want to disable some positions permanently
           dec : in STD_LOGIC; -- if you want to enable the decimal point
           seg : out STD_LOGIC_VECTOR (6 downto 0); -- the data line for the display
           an : out STD_LOGIC_VECTOR (3 downto 0); -- an is in the constraints file for the Basys 3, it governs which positions light up
           dp : out STD_LOGIC); -- decimal point output
end hex7seg_top;

architecture Behavioral of hex7seg_top is

component hex7seg
    Port ( x : in STD_LOGIC_VECTOR (3 downto 0);
           a_to_g : out STD_LOGIC_VECTOR (6 downto 0));
end component;

component shifter is
    Port ( clk : in STD_LOGIC;
           z : out STD_LOGIC_VECTOR (3 downto 0));
end component;

subtype Segment_Data is std_logic_vector(3 downto 0);
signal pos, seg_a, seg_b, seg_c, seg_d, seg_x : Segment_Data;

begin

    Decoder: hex7seg port map(x => seg_x, a_to_g => seg);
    Position: shifter port map(clk => clk, z => pos);
    
    -- ex: seg_d will be "1111" if position d is to be output to the display
    seg_d <= (others => not pos(0)); -- position d is vector position 0, c is 1 etc
    seg_c <= (others => not pos(1)); -- extend the pos-bit to a vector to be ANDed with
    seg_b <= (others => not pos(2)); -- the data later. 0 means ON hence the NOT pos(x).
    seg_a <= (others => not pos(3));
    
    -- the data to push to the decoder is selected, ex: seg_x will yield d if seg_d is all 1's
    seg_x <= (a and seg_a) or (b and seg_b) or (c and seg_c) or (d and seg_d); 
    
    -- an is the power output to the display, ex: mask = "0110" disables digits b and c
    an <= pos or mask;
    dp <= dec and pos(0); -- select position d for decimal point, arbitrary
    
end Behavioral;

Shifter according to the formula in the attached picture:

use IEEE.NUMERIC_STD.ALL;

entity shifter is
    Port ( clk : in STD_LOGIC;
           z : out STD_LOGIC_VECTOR (3 downto 0));
end shifter;

architecture Behavioral of shifter is

component D_flipflop
    Port ( clk, d, ce : in STD_LOGIC;
           q : out STD_LOGIC);
end component;

signal s0p, s1p, s0, s1 : STD_LOGIC;

begin

    dff0: D_flipflop port map(clk => clk, d => s0p, ce => '1', q => s0);
    dff1: D_flipflop port map(clk => clk, d => s1p, ce => '1', q => s1);
    
    s0p <= not s1;
    s1p <= s0;
    z <= (not s1 or s0) & (not s1 or not s0) & (s1 or not s0) & (s1 or s0);

end Behavioral;

Decoder, 7-segment:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity hex7seg is
    Port ( x : in STD_LOGIC_VECTOR (3 downto 0);
           a_to_g : out STD_LOGIC_VECTOR (6 downto 0));
end hex7seg;

architecture Behavioral of hex7seg is

begin
    process(x)
    begin
        case x is               --  GFEDCBA     see basys 3 7-seg
            when X"0" => a_to_g <= "1000000";   --0
            when X"1" => a_to_g <= "1111001";   --1
            when X"2" => a_to_g <= "0100100";   --2
            when X"3" => a_to_g <= "0110000";   --3
            when X"4" => a_to_g <= "0011001";   --4
            when X"5" => a_to_g <= "0010010";   --5
            when X"6" => a_to_g <= "0000010";   --6
            when X"7" => a_to_g <= "1111000";   --7
            when X"8" => a_to_g <= "0000000";   --8
            when X"9" => a_to_g <= "0010000";   --9
            when X"A" => a_to_g <= "0001000";   --A
            when X"B" => a_to_g <= "0000011";   --B
            when X"C" => a_to_g <= "1000110";   --C
            when X"D" => a_to_g <= "0100001";   --D
            when X"E" => a_to_g <= "0000110";   --E
            when others => a_to_g <= "0001110"; --F
        end case;
    end process;
end Behavioral;

 

IMG_20170423_121905502.jpg

Share this post


Link to post
Share on other sites
  • 0

Pardon me for back-tracking but I just re-read this thread a bit more carefully. The truth is that I just trust Hamster's opinion and didn't bother to read all of his code carefully to understand what he was trying to say.

He writes earlier:"The take-away wisdom being "always synchronise your async inputs" and "try really hard to never have more than one clock"

I'm not arguing with Hamster as I understand what he is trying to say but this sentence just irks me a bit so I feel the need to comment. As far as synchronising signals goes I think that it would be better to say that for all clocked processes signals that change due to any event, combinatorial logic or a different clock than the one in your process sensitivity list has to be conditioned (including synchronized) to the clock in your process. This is to avoid the effects of metastability in the process outputs. Metastability is unavoidable but you can, and MUST, minimize it's effects in the downstream logic states.  As to having more than one clock; this is often unavoidable. I've worked on systems with 10's of clock domains all of them being necessary. You DO have to synchronize any signal that changes due to a clock in a different clock domain to the clock listed in your process sensitivity list. There are a few standard ways to to do this some pretty good and some not so much for all situations. What I'd say is that even though the HDL languages allow you to decide that ANY signal can be used as a clock this is not good practice. Even good clock signals that are the outputs of expensive clock modules have jitter, drift, noise and other encumbrances that don't do your design efforts any good. Using a signal that is derived from combinatorial logic, though often a temptation, is a really bad idea for reasons that I won't go into at this time. FPGA devices have special clocking lines, clocking IO pins, and resources for a reason. The synthesis and routing tool logic expects signals labelled as clocks to behave as high quality clocks will have a lot of problems with badly behaved "clocks". Now I'm sure that there's someone who might read my "clarification" of Hamster's point and have as much problem with my comments as I had with Hamster's but I don;t think that this is the thread for detail on that level.

Since Hamster feels that giving you a code example is in your best interest ( I don't but nor do I take issue with doing so ) perhaps he would be generous enough to supply you with a nice testbench. Even if you have perfectly good code to work with you should know how to test it in simulation. Testbenches are your friend, not your enemy.

Share this post


Link to post
Share on other sites
  • 0

Having spare time on hands and following the last post I took a liberty to create a testbench using published materials. The VHDL code was taken from  here and the template for the testbench was created using this online tool here

The testbench is for the debouncer only and it's very simplistic but sufficient as a starting point. It is easy to copy internal signals to the entity port and get insights into its internal behaviour.

Thanks!

TB_Debouncer.vhd

DBounce.vhd

Share this post


Link to post
Share on other sites
  • 0

@Tickstart

Here's my equivalent of the 7-seg code you posted, just for comparison - it is just a hack, so the blink rate and update rates were just convenient, rather than to any hidden spec!

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity seven_seg is
    Port ( clk : in STD_LOGIC;
           segments   : out STD_LOGIC_VECTOR (6 downto 0);
           seg_select : out STD_LOGIC_VECTOR (3 downto 0);
           digit0     : in STD_LOGIC_VECTOR (3 downto 0);
           blink0     : in STD_LOGIC;
           digit1     : in STD_LOGIC_VECTOR (3 downto 0);
           blink1     : in STD_LOGIC;
           digit2     : in STD_LOGIC_VECTOR (3 downto 0);
           blink2     : in STD_LOGIC;
           digit3     : in STD_LOGIC_VECTOR (3 downto 0);
           blink3     : in STD_LOGIC);
end seven_seg;

architecture Behavioral of seven_seg is
    signal digit_count : unsigned(25 downto 0);
    signal to_decode : std_logic_vector(3 downto 0);
begin
                                    -- GFEDCBA
   with to_decode select segments <= "1000000" when "0000", -- Zero
                                      "1111001" when "0001", -- One
                                      "0100100" when "0010", -- Two
                                      "0110000" when "0011", -- Three
                                      "0011001" when "0100", -- Four
                                      "0010010" when "0101", -- Five
                                      "0000010" when "0110", -- Six
                                      "1111000" when "0111", -- Seven
                                      "0000000" when "1000", -- Eight
                                      "0011000" when "1001", -- Nine
                                      "0001000" when "1010", -- A
                                      "0000011" when "1011", -- B
                                      "1000110" when "1100", -- C
                                      "0100001" when "1101", -- D
                                      "0000110" when "1110", -- E
                                      "0001110" when others; -- F
                                 
process(clk)
    begin
        if rising_edge(clk) then
            seg_select <= "1111"; -- active low!
            case digit_count(digit_count'high-6 downto digit_count'high-7) is
                when "00" =>
                    seg_select(0) <= blink0 AND digit_count(digit_count'high);
                    to_decode  <= digit0;                    
                when "01" =>
                    seg_select(1) <= blink1 AND digit_count(digit_count'high);
                    to_decode  <= digit1;                    
                when "10" =>
                    seg_select(2) <= blink2 AND digit_count(digit_count'high);
                    to_decode  <= digit2;                    
                when others =>
                    seg_select(3) <= blink3 AND digit_count(digit_count'high);
                    to_decode  <= digit3;                    
            end case;
            digit_count <= digit_count + 1;
        end if;
    end process;
end Behavioral;
Edited by hamster

Share this post


Link to post
Share on other sites
  • 0

Oh, and with regards to test benches. Somethings are hard to prove with test benches, and easy to prove in real life. Especially things that involve timescales needed for human interaction.

Take the seven-segment display module. A 'full' test bench for that would be hard (test each digit for each value - 64 test patterns, each requiring at least enough time to update all output signals, 300 million cycles simulation cycles, and each blink test would need at least 64 million cycles for the counter to roll over - so half a billion simulation cycles.

Then it would need to inspect the simulation output, to check that the correct LEDs were on at the correct time.

Far easier to connect the digits to the switches on the dev board, the buttons to the blink inputs, download the design and manually verify it - a physical/manual test-bench :-) 

So I write VHDL testbenches when I know I will need to debug or otherwise inspect behavior of the internals.

For a button debouncer my personal view is that a test bench is a bit over the top, and it is hard to have the correct assumptions of how bad a really bad switch is -  and all my projects are for my own enjoyment, so I don't have to design to commercial standards of proof.

 

 

Share this post


Link to post
Share on other sites
  • 0
5 hours ago, Notarobot said:

Having spare time on hands and following the last post I took a liberty to create a testbench using published materials. The VHDL code was taken from  here and the template for the testbench was created using this online tool here

The testbench is for the debouncer only and it's very simplistic but sufficient as a starting point. It is easy to copy internal signals to the entity port and get insights into its internal behaviour.

Thanks!

TB_Debouncer.vhd

DBounce.vhd

@Notarobot's  code is much the same as mine in function. But style is a different. 

I wonder why it isn't just a single process like this:

process(clk)
    begin
        if(rising_edge(clk)) then
            if nreset = '0' then
 	        if DFF1 /= DFF2 then
                    q_reg <= (others => '0');   -- reset counter
                elsif q_reg(N-1) = '0' then 
	            q_reg <= q_reg + 1; 
                else
                    DB_out <= DFF2;
                end if;
                DFF1 <= button_in;
                DFF2 <= DFF1; 
            else
                q_reg <= (others => '0');
                DFF1 <= '0';
                DFF2 <= '0';
	    end if;
        end if;
    end process;
Edited by hamster

Share this post


Link to post
Share on other sites
  • 0

@hamster,

Using this occasion I wanted to thank you for you contributions. I've found a lot to learn from your site as well as from posts on this forum.

The debouncer code I posted is not mine. It is very similar to yours and I chose it because it has pretty clear description.

Also in my practice I use testbenches whenever I can. In cases when FPGA controls the equipment trial and error approach would be very costly. When the testbench is too complicated we used to built a physical test setup. Exhaustive testing is the major prerequisite of success in commercial environment.

Share this post


Link to post
Share on other sites
  • 0

Again, the following comments are not an argument with Hamster's statements about really long simulation times or "commercial quality" code verses "messin' around" quality code but I offer a slightly different perspective.

I write testbenches for my  "messin' around" quality code as often as for my "commercial quality" code. You can always figure out a way to shorten overly long simulation times when doing RTL level simulation. Timing simulations are a discussion for another thread. Really, there can be many types of verification exercises that concentrate on different aspects of the design code. Indeed, if you see writing verification code as an exercise in forcing yourself to think about where the possible issues might be this becomes a welcome and challenging habit. Actually writing good verification code can be more tricky and require more creativity than the actual design code. I don't create designs for hardware that I don't have and so testbenches are rarely the endpoint.... though occasionally I try out an idea just for experimentation purposes, expecting to use the idea later in a real project.

One thing that hardware can't tell you is if there are subtle issues with your design. Sure seeing a seven-segment display module change characters as expected might look like everything is just fine but really now... what's the fastest event that you can detect visually? Do you always believe what your see? Even if you own a really good oscilloscope and other test equipment there are things that you are likely to miss that a simulation can reveal. Simulations are not the be-all or end-all of good design practice but I believe that it's easy to get sloppy if you don't hold yourself to a certain standard.. even when just playing around for fun. Now I admit that not all of my testbenches are exhaustive exercises ( you can spend you life just testing stuff if you allow it to happen ) as I usually have a larger goal in mind. But I don't want to start bad habits and work by hope an assumptions that I got my design code correct. 

By the way your testbench can write out thousands of signal values to a text file for analysis in OCTAVE or MatLAB.

I used to be astonished, fixing other peoples software code how WRONG code implementations and even sometimes how wrong the basic concept can be but still look kinda correct.. mostly... most of the time. 4-5 people will have messed with it, patched it, massaged it and never understood what was going on all the time making imaginary fixes. You end up peeling back layers of changes until you eventually either get to the initial problem or just end up replacing it ( when allowed by the $$$ people...) Scary!

Anyway, if you are just starting out and learning an HDL language I heartily recommend that you get comfortable with verifying your "other" code... you know that one that you want to see working on you new Basys3 board. You may not guarantee that your design is bullet-proof developing a habit of using testbenches but I guarantee that if you start writing lots of design code that goes straight to hardware you will be fooling yourself that it's "working".

A debugged program is one for which you have not yet found the conditions that make it fail. -- Jerry Ogdin

 

Lastly, I don't get paid by "Council for Testbenches" or anyone else or see myself as an evangelist for the cause...

Share this post


Link to post
Share on other sites
  • 0

OK, I'll try an wrap this up and go on to other things.

You'll notice that my "help" has not been in the form of providing code examples, answering your questions directly or providing exactly what it is that you are looking for. Others have done that so you are being pretty well serviced in that regard. What I'd like to do is try and expand your perspective. Intelligence, educational degrees, and even to an extent experience are all nice things to have when trying achieve success in any endeavour. In my experience, attitude, having a structure to your thinking and problem solving efforts, being willing to continually challenge your assumptions and work product are far more important in determining what kind of experiences you'll have in life. This is true whether you are a student waiting to enter professional life or even a seasoned old hand just playing around with a new FPGA board. Believe me I understand the desire for immediate (OK immediate is a relative term ) gratification in seeing your project perform. You'll sustain your interest in FPGA or any other other endeavour far longer by forcing other goals into you thinking.

My advice:

- Your brain is telling you something when it complains that the tool ( in this case VHDL ) that you're using is confusing and flawed ( this is my interpretation of your comment ). The truth is that no tool is perfect for all tasks, or perfect for any for that matter ) but when multitudes of people use the same tool and achieve success the problem is not likely the tool. Your brain is telling you that perhaps you need to learn how to use your tools. So, I advise you to put off, if you can, getting your project to work until you are comfortable using your tool of choice. This will make your eyes roll... in VHDL integers aren't infinite... in fact the largest integer is a signed 32-bit value. Ouch! But the explicit advice here is to learn to listen to your brain and figure out what it is trying to tell you. That's the best advice I have to offer.

- Do read and try to understand well written code, and try to figure out why it is well written code, from experienced people even if the goal of their task is not very interesting. In life the shortest distance between two points is rarely a straight line. Somewhere in the documentation for OCTAVE the authors mention a quote from a book of my youth "How to build a Telescope". I'm paraphrasing here but the quote goes like this: " It takes less time to build a 5" mirror and an 8" mirror than it does to build an 8" mirror". As you probably don't have the book I'll explain. The reference is to the skill involved in hand grinding and polishing a glass bank into a shape suitable for use as an optical mirror that could be used in building a telescope. If you read the book you'll realize that what's involved in ending up with a usable 8" mirror is far more challenging than for a 5" mirror.You'll waste far less time and glass honing your skills and training your brain, hands and eyes trying to achieve what you really want by preparing yourself with a succession of less demanding objectives. This advice works for just about any endeavour.  

 

 

Share this post


Link to post
Share on other sites
  • 0
12 minutes ago, zygot said:

OK, I'll try an wrap this up and go on to other things.

Sigh, and here I thought this thread had already been wrapped up.  :)

12 minutes ago, zygot said:

My advice:

So, I advise you to put off, if you can, getting your project to work until you are comfortable using your tool of choice. ...  That's the best advice I have to offer.

Ouch!  Not my advice.  My advice: This is a perfect learner's project, I love it!  --keep going!  After a couple such projects, you will then be "comfortable using your tool of choice."

Also, I caught your comment above about having worked in the field for 20+ years and that you use test benches.  Ignoring all of the rest of the stuff you had to say about the importance of test benches, this one piece was enough to highlight for me that you found them valuable and that your recommendation had some weight behind it.  That simple statement above my have been the "best advice" you've offered.

12 minutes ago, zygot said:

- Do read and try to understand well written code, and try to figure out why it is well written code, from experienced people even if the goal of their task is not very interesting. ...  This advice works for just about any endeavour.  

On that note, thank you, @hamster!  I learned a lot from the several debouncing examples you posted above.  Thank you, for walking through several versions of how to do the same thing and discussing the problems with each.  Again, I learned a lot.

Dan

 

Share this post


Link to post
Share on other sites
  • 0

OK This is my last post on this thread, I promise! I wanted to say this and forgot ( not withstanding D@n's previous comments )

On tools:
I have a large garden behind my house. Near the garden is a shed and in the shed are a variety of tools that for all appearances are pretty simple devices; like a hoe, a shovel, a rake. Of, course using any of them effectively involves quite a bit more complexity than one might suppose. I'm referring a sight twist of the wrist for a particular effect, a slight alteration of angle of attack, etc. Now, if my aim is to dig a 2 foot hole for a post and I blindly pull out the closest tool in the shed and start flailing at the ground with it, and the tool happens to be a rake you might imagine that I'll spend many hours of frustrating work and never accomplish my goal. Why would anyone do such a thing with something as complicated as a computer-aided design language? But at some point we all do usually because we think that we're saving time or someone is pushing us to get results without taking the time to use our brains.

On testbenches:
One of the rarest gifts one can obtain is insight. You can't have valuable insight without a really solid foundation of knowledge; but knowledge alone doesn't often produce insight (I fully expect push-back with this statement). A simulator is a tool that can offer insight with surprising frequency if used correctly. It can also lie to you and tell you how wonderful you and your design are if used incorrectly. The same concept applies to all computer-aided design and lab tools.

On Personal behaviours:
We all know Newton's observation that "a body in motion tends to stay in motion". And we know that there are forces that work against that body having inertia; such as resistance.
There is an analogy to personal work ethic that has slightly different physics. If you go about your work in a sloppy, unstructured, mindless and lazy manner today, you will tend to gather momentum in a very unfortunate direction of sloppier, lazier, and less productive tomorrow. On the other hand it takes a lot of effort to maintain a course in the other direction as there are numerous forces working against you

I realise that D@n and I arrive a t different conclusions but I don't see a real competition here.

I'm done... really this time.

Share this post


Link to post
Share on other sites
  • 0
 

@Tickstart

Now that the commentators have handed you Dbounce.vhd and a testbench and thrown you back into the drink waving goodbye and saying"Have a nice swim!" How's it working out?

In DBounce.vhd:

Did you notice that the input signal nreset is expected to be synchronized to signal clk? If you use this module did you make sure that your nreset works with this code?

Did you notice that BD_OUT is declared as type buffer? Type buffer is actually new to me and  created some homework to do.  I typically have internal copies of signals declared as type out on the entity port and use a concurrent statement to assign the port signal to the internal signal. Of course I only do this when I want to read the state of that port signal when using type OUT. Just curious, were you familiar with type buffer? Did you try and synthesize DBouncd.vhd?

Personally, I find that the construction of DBounce.vhd is a bit odd. But that doesn't matter as it is presented as an example for de-bouncing a push-button, or anything else involving moving contacts.

Did you notice the sensitivity lists for the processes? Wonder why some have more than clk?

What did you think about ( in the context of the previous question ):

   process(clk, button_in)
    begin        
        if(rising_edge(clk)) then
            if(nreset = '0') then
                DFF1 <= '0';
                DFF2 <= '0';
            else
                DFF1 <= button_in;
                DFF2 <= DFF1;
            end if;
        end if;
    end process;

Did you simulate DBounce using the testbench?

Did you wonder if your simulator warns about potential metastability? Try aligning the button_in signal exactly in time with the clk by making this change in the testbench clocking process:

      clk <= '1', '0' after clock_period / 2;

Do you understand the concepts of setup and old time? Did your simulator? ( I'm assuming that you figured out how to sun the simulator in Vivado or ModelSim, change the source, re-compile, and restart a simulation as well as display the signals of interest.

What I like about the testbench is that it does  show you a way to have your simulator terminate when your testbench is over. Did you catch how that works. There are other ways to do the same thing. All of my simulations end in FAILURE but that's the way that I like it. This method just doesn't give you  a message that it did.

Did you wonder about the timing of the button_in assertions? Do the numbers make any difference?

Did you try running synthesis and then a post_synthesis timing simulation? ( this isn't the best example for timing simulations...)

Were any of these questions of interest to you?

I ask these questions out of curiosity and as a bit of feedback.

Share this post


Link to post
Share on other sites
  • 0

I accidentally deleted all my source files, that's how it's going. I want to kill myself but I'm too speechless to do anything.

Well, nothing else to do than start over.

Share this post


Link to post
Share on other sites
  • 0

OUCH!, I've had hard disks fail and have learned to save the irreplaceable stuff. I feel your pain.

I'm mulling over creating a project with the goal to provoke some thought and a bit of fear in HDL users of all experience levels. I might call it "Beware of Geeks bearing gifts..."

I'm not really interested in ( or in my opinion qualified to..)  training anyone but everyone relying on misplaced confidence in their coding work product needs a bit of reality realignment... as a public service. Assumptions kill! And no one has to look very far in their own work to find a few that need a bit of challenging.

Take a few deep breaths and forget about everything in the past... think of this as an easier way to re-boot your HDL journey.

Share this post


Link to post
Share on other sites
  • 0
On 4/25/2017 at 8:35 PM, zygot said:

Take a few deep breaths and forget about everything in the past... think of this as an easier way to re-boot your HDL journey.

Yes, I saw it as an oppurtunity to validate my progress and perhaps improve on things I did worse first time round.

I've been quite busy this week so not much time over for programming. Anyway, my up-/down counter still doesn't work.

On 4/22/2017 at 3:50 PM, Notarobot said:

Hi, here is a good explanation and code for the debouncer.

 

Thanks again for the debouncing theory, the picture in the link really helped, and made it fun to implement instead of just copying someone else's code. I modified it to act in a "key released"-fashion.

 

Anyway, back to the matter at hand: What's wrong with my code?

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_unsigned.all;

entity add_sub is
    Port ( inc, dec : in STD_LOGIC;
           c : out STD_LOGIC_VECTOR (3 downto 0));
end add_sub;

architecture Behavioral of add_sub is

signal count : STD_LOGIC_VECTOR (3 downto 0) := (others => '0');

begin

    process(inc, dec)
    begin
        if inc = '1' then
            count <= count + 1;
        elsif dec = '1' then
            count <= count - 1;
        else
            NULL;
        end if;   
    end process;
    
    c <= count;

end Behavioral;

The number shown on the display jumps all over the place, from A to 9, then F, 8, E, E, F, 6, 9 whatever. 

Share this post


Link to post
Share on other sites
  • 0

Here's where being able to use a simulator might help.

Your process is not clocked. Think about time, delay, storage and what's going on in your process. Simulate it and see what the simulator thinks of your code. I've already given you a broad hint in mentioning that I use concurrent statements and clocked processes ( OK in my state machines I use two processes, one clocked and one not...) I try and keep my concurrent statements and processes  separate though sometimes this makes the code hard to read so I don't. I keep track of processes and signals associated with each clock domain using comments and keeping them together in the code.

For the record it's entirely possible to have an whole design be combinatorial and not use a clock. I've had this as a work requirement for special purposes. Anyone doing that had better know what their doing and be very experienced if the design has any complexity at all; not for the inexperienced.

You can shut me up for good by not posting your simulation experience or question related to getting a simulation working as your next post....

 

Share this post


Link to post
Share on other sites
  • 0

By the way , the more you write the more convinced that you really need some help grasping the basics. VHDL was designed as a simulation language but was co-opted for synthesis because of its popularity. The language doesn't care about issues of synthesis but the synthesis tool sure does. A cursory reading of the syntax is not likely to be a helpful guide. With this in mind it should be clear that you can write perfectly fine VHDL code that can't be synthesized into something that works on hardware.

Share this post


Link to post
Share on other sites
  • 0
1 hour ago, zygot said:

Your process is not clocked. Think about time, delay, storage and what's going on in your process.

Why does it have to be clocked? Please just tell me. What about time, delay and storage? Honestly I have no grasp of what a "signal" is in vhdl or in the fpga (a LUT or something?) but rather than telling me how ignorant I am please enlighten me. It's weird to me that some of my code works just fine and other parts are just impossible to implement.

1 hour ago, TrapperBob said:

You are "counting" on count to have state when you write count <= count + 1 or count <= count - 1. However you have a combinatorial process defined.

Well, I don't know, maybe? Do I have to construct a register to store data?

Share this post


Link to post
Share on other sites
  • 0

Sorry, You didn't ask about your simulation results or about issues getting the latest posted code to simulate. I'm done with trying.

Don't you know anyone who's taken a first course in digital logic who might help you?

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this