0
votes

I'm trying to modify a source code for do a sum (for example) and other maths function using switch and hex display.

This is the main code:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.seven_segment_pkg.all;

entity Switch7Segment is
  port (
    SW       : in  std_logic_vector(9 downto 0);
    HEX0     : out std_logic_vector(6 downto 0);
    HEX1     : out std_logic_vector(6 downto 0);
    HEX2     : out std_logic_vector(6 downto 0);
    HEX3     : out std_logic_vector(6 downto 0);
    KEY      : in  std_logic_vector(3 downto 0);
    CLOCK_50 : in  std_logic
    );
end entity Switch7Segment;

architecture behavior of Switch7Segment is
  signal segments1 : std_logic_vector(13 downto 0);
  signal segments2 : std_logic_vector(13 downto 0);
  signal segmentsR : std_logic_vector(13 downto 0);  -- Range changed from 27 downto 0 to allow compile
  signal input1    : integer;
  signal input2    : integer;
  signal result    : unsigned(31 downto 0);  -- Range added to allow compile
  signal temp      : integer;
begin

  input1 <= to_integer(unsigned(SW(4 downto 0)));
  input2 <= to_integer(unsigned(SW(9 downto 5)));

  segments1 <= unsigned_to_seven_segment(value => unsigned(SW(4 downto 0)), number_of_digits => 2, value_is_bcd => false);
  segments2 <= unsigned_to_seven_segment(value => unsigned(SW(9 downto 5)), number_of_digits => 2, value_is_bcd => false);

  HEX1 <= segments1(13 downto 7);
  HEX0 <= segments1(6 downto 0);
  HEX3 <= segments2(13 downto 7);
  HEX2 <= segments2(6 downto 0);

  process(CLOCK_50)
  begin
    if (CLOCK_50' EVENT and CLOCK_50 = '1' AND KEY(0) = '1') then
      temp      <= input1+input2;
      result    <= to_unsigned(integer(temp), result'length);
      segmentsR <= unsigned_to_seven_segment(value => unsigned(result), number_of_digits => 2, value_is_bcd => false);
      HEX1      <= segmentsR(13 downto 7);
      HEX0      <= segmentsR(6 downto 0);
    end if;
  end process;

end architecture;

And then there is the package:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

package seven_segment_pkg is
-- Return a std_logic_vector ready for driving a number of 7-segment displays.
  function unsigned_to_seven_segment(value : unsigned; number_of_digits : integer; value_is_bcd : boolean)
    return std_logic_vector;
end;

package body seven_segment_pkg is

  function seven_seg_from_bcd_digit(bcd_digit : std_logic_vector(3 downto 0)) return std_logic_vector is
  begin
    case bcd_digit is
      --                   abcdefg
      when x"0"   => return "1000000";
      when x"1"   => return "1111001";
      when x"2"   => return "0100100";
      when x"3"   => return "0110000";
      when x"4"   => return "0011001";
      when x"5"   => return "0010010";
      when x"6"   => return "0000010";
      when x"7"   => return "1111000";
      when x"8"   => return "0000000";
      when x"9"   => return "0010000";
      when x"a"   => return "0001000";
      when x"b"   => return "0000011";
      when x"c"   => return "1000110";
      when x"d"   => return "0100001";
      when x"e"   => return "0000110";
      when x"f"   => return "1110001";
      when others => return "0000000";
    end case;
  end function;

  -- Return a vector ready for driving a series of 7-segment displays.
  function unsigned_to_seven_segment(
    value            : unsigned;
    -- Number of 7-segment displays (determines output vector width: W = 7*N)
    number_of_digits : integer;
    -- When true, treat the input value as a BCD number where every 4 bits hold one
    -- digit from 0 to A. When false, treat the input number as an unsigned integer.
    value_is_bcd     : boolean
    ) return std_logic_vector is

    variable segments      : std_logic_vector(number_of_digits*7-1 downto 0);
    variable bcd_quotient  : unsigned(value'range);
    variable bcd_remainder : unsigned(3 downto 0);
  begin

    if value_is_bcd then
      for i in 0 to number_of_digits-1 loop
        segments(i*7+6 downto i*7) := seven_seg_from_bcd_digit(
          std_logic_vector(value(i*4+3 downto i*4))
          );
      end loop;
    else
      bcd_quotient := value;
      for i in 0 to number_of_digits-1 loop
        bcd_remainder := resize(bcd_quotient mod 10, 4);
        bcd_quotient  := bcd_quotient / 10;
        segments(i*7+6 downto i*7) := seven_seg_from_bcd_digit(
          std_logic_vector(bcd_remainder)
          );
      end loop;

    end if;

    return segments;
  end function;

end package body;

I think that there is an error that at the moment i never signed here that is the length of the result. if we compile this VHDL code Quartus will tell us that the function is for 13 element and not for 27. But i don't see an obstacle to resolve it....my problem is about outputs (HEX0.....HEX3)

If i modify the code and i insert

 signal segmentsR: std_logic_vector(13 downto 0);

I resolve the problem of the length but i will see error 10028 (multiple constant drivers). If i understood correct, i can't assign two times at the same vector two different value or something similar is correct? maybe i always think like a C++ / C programmer. I think that if i use CLOCK the problem will be resolve but is not true...

2

2 Answers

2
votes

The problem is that there are drivers for HEX0 and HEX1 both before the process and in the process, but any signal/port should only be driven from one place in typical synthesized code.

If the HEX0 and HEX1 are driven from the process, then remove the drivers before the process.

0
votes

Conceptually, a multiple drivers error means that your behavioral code (remember: VHDL describes how a circuit works) isn't able to be synthesized. Or, if you have really special synthesizing code, it will give you unexpected results.

In my experience, this error results when I write code with undefined behavior -- for example, if in two processes I modify the same variable (say, X) based on some condition, then the hardware could run into an undefined state where both conditions are met -- how should the variable be modified? If you are familiar to race conditions or mutual exclusion, this should look familiar. Hardware languages don't have easy support for mutex and the like, so they warn you and won't let you do the bad thing.

In your case, I think you could clarify your code and simplify things by assigning default values to your top-level ports, like so:

entity Switch7Segment is
port (
    SW       : in  std_logic_vector(9 downto 0);
    HEX0     : out std_logic_vector(6 downto 0);
    HEX1     : out std_logic_vector(6 downto 0) := (others => '0');
    HEX2     : out std_logic_vector(6 downto 0) := (others => '0');
    HEX3     : out std_logic_vector(6 downto 0);
    KEY      : in  std_logic_vector(3 downto 0);
    CLOCK_50 : in  std_logic
);
end entity Switch7Segment;

This provides a default value for an entity. Whatever creates the entity can provide a different value than the default. Read more here: http://vhdl.renerta.com/mobile/source/vhd00051.htm

It looks like your default value is more complicated (based on the inputs of the function). In this case, I would either (1) change my interface so that the caller provides the information or (2) write a function and a constant in a package and use the function/constant as the default value.

Another possible solution is using generics and default value. This would let you use the bits of the SW field in you default values. (ie: something like HEX2 : out std_logic_vector(6 downto 0) := (SW(xx downto yy), where SW is defined in the generics port)