Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
10 years ago

integer'image(some_int) results in "Expression is not constant" error

What is the correct way to convert an always changing integer variable to a string (to be displayed on a VGA monitor)? I have a series of if statements that take care of padding (so that the resulting string is always a certain length but as soon as I change:

resulting_string <= integer'image(87465);

to:

resulting_string <= integer'image(some_int_var);

I get an "Expression is not constant" error. What is the correct way to convert an always changing integer variable (that could be any int within the integer limits) to a string?

8 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    The string type is not suitable for synthesis - it doesnt really have much meaning in hardware, it would be used more for debugging in simulation.

    What are you doing with the string? do you have some driver that can covert the characters in the string to some form of pixel matrix?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    The string type is not suitable for synthesis - it doesnt really have much meaning in hardware, it would be used more for debugging in simulation.

    What are you doing with the string? do you have some driver that can covert the characters in the string to some form of pixel matrix?

    --- Quote End ---

    Yes, I do. I have a font ROM that I use to tell me if a pixel should be on for any given character in a string. The only step remaining is to convert ints to strings.

    I went at it from every direction and finally found that I had to make a giant case block to get it to work. Now I can finally display rapidly changing variables that are really helpful for debugging. It's unfortunate that the solution had to be so retarded though..

    (I already have a ROM for displaying text that the resulting string is sent to.)

        function int_to_str(int : integer) return string is
            variable a : natural := 0;
            variable r : string(1 to 11);
        begin
            a := abs (int);
            case a is
                when 0    => r := "0          ";
                when 1    => r := "1          ";
                when 2    => r := "2          ";
                when 3    => r := "3          ";
                .
                .
                .
                when 1000 => r := "1000       ";
                when others => r := "???????????";
            end case;
            if (int < 0) then
                r := '-' & r(1 to 10);
            end if;
            return r;
        end int_to_str;
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Id be interested to see this rom - does it actually synthesise to a rom? with that many chars in the string, thats a massive lookup address..

    Using a string is really a software concept and not a hardware one - hence why you have to do a massive workaround like you have found to get it working.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I don't see how else I would do it. The ROM isn't really a rom anymore. I converted it into the code below.

    entity char_display is
        generic(
            text_length: integer := 1;
            addrWidth: integer := 11;
            dataWidth: integer := 8
        );
        port(
            text_to_be_displayed : in string(1 to text_length) := (others => NUL);
            origin_x : in integer;
            origin_y : in integer;
            current_x : in integer;
            current_y : in integer;
            this_px_is_text : out boolean;
            this_px_is_text_bg : out boolean
        );
    end char_display;
    architecture Behavioral of char_display is
       
        type rom_type is array (0 to 2**addrWidth-1) of std_logic_vector(dataWidth-1 downto 0);
        -- ROM definition
        signal ROM: rom_type := (   -- 2^11-by-8
            -- NUL: code x00
            "00000000", -- 0
            "00000000", -- 1
            "00000000", -- 2
            "00000000", -- 3
            "00000000", -- 4
            "00000000", -- 5
            "00000000", -- 6
            "00000000", -- 7
            "00000000", -- 8
            "00000000", -- 9
            "00000000", -- a
            "00000000", -- b
            "00000000", -- c
            "00000000", -- d
            "00000000", -- e
            "00000000", -- f
            -- SOH: code x01
            "00000000", -- 0
            "00000000", -- 1
            "01111110", -- 2  ******
            "10000001", -- 3 *      *
            "10100101", -- 4 * *  * *
            "10000001", -- 5 *      *
            "10000001", -- 6 *      *
            "10111101", -- 7 * **** *
            "10011001", -- 8 *  **  *
            "10000001", -- 9 *      *
            "10000001", -- a *      *
            "01111110", -- b  ******
            "00000000", -- c
            "00000000", -- d
            "00000000", -- e
            "00000000", -- f
            -- STX: code x02
            "00000000", -- 0
            "00000000", -- 1
            "01111110", -- 2  ******
            "11111111", -- 3 ********
            "11011011", -- 4 ** ** **
            "11111111", -- 5 ********
            "11111111", -- 6 ********
            "11000011", -- 7 **    **
            "11100111", -- 8 ***  ***
            "11111111", -- 9 ********
            "11111111", -- a ********
            "01111110", -- b  ******
            "00000000", -- c
            "00000000", -- d
            "00000000", -- e
            "00000000", -- f
                    .
                    .
                    .
        );
    begin
        process (text_to_be_displayed, origin_x, origin_y, current_x, current_y)
            (variables...)
        begin
            (combinational logic...)
        end process;    
    end Behavioral;

    It was originally this: https://github.com/madlittlemods/fp-v-ga-text

    but in my opinion it was super over-engineered. I reduced that mess down to the one entity shown above which is working great.

    My question is, if the way I'm doing it is so backwards, how would you describe a process that is equally code-minimal, easy to read, and efficient?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Usually, you would let software control something like this

    You provide the processor with a memory the size of the VGA screen. The software can do all the fancy graphics rather easily.

    Doing it in HDL is rather long winded and cumbersum, as you're finding.

    it's just easier to send data directly to a processor, rather than a VGA screen.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Wouldn't that be a lot more code and take a lot more time for someone other than the person who wrote it to read and understand? It is probably not as efficient either.

    I only need to display text, rectangles, circles and lines. I can make those fairly easily using the same techniques I have already utilized. I don't see why a soft processor is needed. The hardest part to figure out will likely end up being that retarded hack I had to use to get it to convert ints to strings.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I wouldnt really call it retarted, and I wouldnt really call it a hack.

    You need to understand what underlying hardware you're trying to generate, and offset that against user understanding.

    A string is just an array of chars, which is really just an array of bytes. You're using a rom to do this.

    In previous designs where Ive had graphics overlay, it has always come from a processor. Either 2 bits per pixel for black and white overlaikd (black, white, grey - level set by a register, and normal video) or colour at 24bit/pixel RGB. But in my case the processors were already there performing other tasks.

    I have also had a design with FPGA generated graphcis - and it ends up being long winded and overly complicated.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I'm actually not using a ROM or RAM for any of it. There is a giant std_logic_vector that dictates which pixels should be on or off for any given character. Then, to be able view non-character variables like integers, I have that ridiculous, giant case block which is used to convert an int to a string. I had a more elegant solution that actually performed some math to figure out, digit by digit, what the string needed to be for any given int but it didn't like that for reasons I can't remember and I had to use the giant case block instead.