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;
asked Aug 31, 2016 at 13:30
\$\endgroup\$
2
  • \$\begingroup\$ Do you have a preference in which base the switches should be counted? \$\endgroup\$ 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|
+------+---------+-------+------+
answered Mar 27, 2017 at 8:51
\$\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\$ 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\$ 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\$ 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\$ 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\$ Commented Apr 1, 2017 at 7:24

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.