4
\$\begingroup\$

I've implemented a VHDL program that sums up the positions of switches and shows it on a 7-segment LED, but I've had to use lots of temporaries and a division. Is there a better way?

library ieee;
use ieee.std_logic_1164.all;

entity light is
  port(
        LEDR : out std_logic_vector(0 to 9);
        LEDG : out std_logic_vector(0 to 7);
        SW : in std_logic_vector(0 to 9);
        KEY : in std_logic_vector(0 to 3);
        HEX0 : out std_logic_vector(0 to 6);
        HEX1 : out std_logic_vector(0 to 6);
        HEX2 : out std_logic_vector(0 to 6);
        HEX3 : out std_logic_vector(0 to 6)
  );
end light;



architecture arch of light is

signal sum, sum2 : integer := 0;
signal x1,x2,x3,x4,x5,x6,x7,x8,x9 : integer := 0;

function led_value(x:integer)
    return std_logic_vector is
begin
    case x is
       when 0 => return "0000001";
        when 1 => return "1001111";
        when 2 => return "0010010";
        when 3 => return "0000110";
        when 4 => return "1001100";
        when 5 => return "0100100";
        when 6 => return "0100000";
        when 7 => return "0001111";
        when 8 => return "0000000";
        when 9 => return "0000100";
        when others => return "1111111";
    end case;
end led_value;

begin
    x1 <= 1 when sw(1) = '1' else 0;
    x2 <= 2 when sw(2) = '1' else 0;
    x3 <= 3 when sw(3) = '1' else 0;
    x4 <= 4 when sw(4) = '1' else 0;
    x5 <= 5 when sw(5) = '1' else 0;
    x6 <= 6 when sw(6) = '1' else 0;
    x7 <= 7 when sw(7) = '1' else 0;
    x8 <= 8 when sw(8) = '1' else 0;
    x9 <= 9 when sw(9) = '1' else 0;

    sum <= x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9;
    sum2 <= (sum - sum mod 10) / 10;

    hex0 <= led_value(sum mod 10);
    hex1 <= led_value(sum2);
    hex2 <= led_value(11);
    hex3 <= led_value(11);
end arch;
\$\endgroup\$
2
  • \$\begingroup\$ Do you have a preference in which base the switches should be counted? \$\endgroup\$
    – Mast
    Commented Aug 31, 2016 at 13:39
  • \$\begingroup\$ @Mast well the idea was to count them in Base 10, so SW(1) contributes a 1 if switched, SW(8) an 8, and so on. \$\endgroup\$ Commented Aug 31, 2016 at 15:06

1 Answer 1

1
\$\begingroup\$

This is some old question, but lets answer it.

Synthesis software is not that dumb. It will evaluate the potential outcomes of a function and generate reduced logic from that. Often you have to aid the synthesis software somewhat. You could do that by writing a function which internally resolves the things you want.

N.B. constraining the range of your integers keep the resource usage low. Else everything will be implemented as a 32-bit value

library ieee;
use ieee.std_logic_1164.all;

entity light is
  port(
        SW : in std_logic_vector(0 to 9); -- why 'to' and not 'downto'??
        KEY : in std_logic_vector(0 to 3); -- downto is normally used
        HEX0 : out std_logic_vector(0 to 6);
        HEX1 : out std_logic_vector(0 to 6);
        HEX2 : out std_logic_vector(0 to 6);
        HEX3 : out std_logic_vector(0 to 6);
        LEDR : out std_logic_vector(0 to 9);
        LEDG : out std_logic_vector(0 to 7)
  );
end light;

architecture arch of light is
    function hex_decode(x:integer)
        return std_logic_vector is
    begin
        case x is
            when 0 => return "0000001";
            when 1 => return "1001111";
            when 2 => return "0010010";
            when 3 => return "0000110";
            when 4 => return "1001100";
            when 5 => return "0100100";
            when 6 => return "0100000";
            when 7 => return "0001111";
            when 8 => return "0000000";
            when 9 => return "0000100";
            when others => return "1111111";
        end case;
    end hex_decode;

    function add_input(input : std_logic_vector(0 to 9))
        return natural is
        variable sum : natural range 0 to 45 := 0;
    begin
        for i in 1 to 9 loop
            if input(i)='1' then
                sum := sum + i;
            end if;
        end loop;
        return sum;
    end function add_input;

    function select_decimal(input : natural; sel: natural)
        return natural is
        variable output : natural range 0 to 9;
    begin
        output := (input / (10**sel)) mod 10;
        return output;
    end function select_decimal;

    signal switch_value : natural range 0 to 45;
begin

    switch_value <= add_input(sw);

    hex0 <= hex_decode(select_decimal(switch_value, 0));
    hex1 <= hex_decode(select_decimal(switch_value, 1));
    hex2 <= hex_decode(select_decimal(switch_value, 2));
    hex3 <= hex_decode(select_decimal(switch_value, 3));
end arch;

Result in Vivado:

---------------------------------------------------------------------------------
Start RTL Component Statistics 
---------------------------------------------------------------------------------
Detailed RTL Component Info : 
+---Adders : 
       8 Input      6 Bit       Adders := 1     
+---Muxes : 
      11 Input      7 Bit        Muxes := 2     
       2 Input      6 Bit        Muxes := 1     
---------------------------------------------------------------------------------
Finished RTL Component Statistics 
---------------------------------------------------------------------------------
Report Cell Usage: 
+------+-------+------+
|      |Cell   |Count |
+------+-------+------+
|1     |CARRY4 |     2|
|2     |LUT2   |     2|
|3     |LUT3   |     1|
|4     |LUT4   |     4|
|5     |LUT5   |     7|
|6     |LUT6   |    15|
|7     |IBUF   |     9|
|8     |OBUF   |    28|
|9     |OBUFT  |    18|
+------+-------+------+

Report Instance Areas: 
+------+---------+-------+------+
|      |Instance |Module |Cells |
+------+---------+-------+------+
|1     |top      |       |    86|
+------+---------+-------+------+
\$\endgroup\$
11
  • \$\begingroup\$ You should avoid the division by using the double dabble algorithm to convert binary to decimal numbers. The binary to 7-segment encoder is low-active. That not a good design choice. Low-active conversation should be performed at the top-level VHDL file. \$\endgroup\$
    – Paebbels
    Commented Apr 1, 2017 at 3:16
  • \$\begingroup\$ -1. Your function doesn't include bit 0 of the input switches. The range of the integer makes no sense. A) so sum will never exceed 10, B) synthesis will strip off​ unused bits anyhow regardless of 32 or 6 bit. Moreover, 0..45 is not a power of two range. Initialization of variables does not work in Quartus. Note the original design uses only 2 digits. \$\endgroup\$
    – Paebbels
    Commented Apr 1, 2017 at 3:23
  • \$\begingroup\$ @paebbels you can either complain, or write your own, better answer. This question was asked six months ago, so you've had enough time to answer it. But nobody did, so I figured, I'd give it a try. \$\endgroup\$
    – JHBonarius
    Commented Apr 1, 2017 at 7:13
  • 1
    \$\begingroup\$ But @paebbels, I don't understand your second complaint about the range of sum. sum+0 is still sum, isn't it? And 1+2+3+4+5+6+7+8+9=45? Did you misread the question? I myself never had an issue with variable initialization, even in Quartus. \$\endgroup\$
    – JHBonarius
    Commented Apr 1, 2017 at 7:20
  • \$\begingroup\$ And I tried with no constraint on the integer, but vivado synthesis did not drop unused bits. I would show you if you tell me how to contract you. \$\endgroup\$
    – JHBonarius
    Commented Apr 1, 2017 at 7:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.