I'm trying to output different (non-constant) values over serial. Serial communication is working fine but there doesn't seem to be an elegant, synthesizable way to convert any integer/natural/std_logic_vector/unsigned/signed type of any size and value to an array of 8-bit std_logic_vectors based on the ASCII table. That is super weird because what I'm trying to do is not uncommon.
One way I can do this is with big lookup tables or long, nested chains of if-elsif-else statements but that seems very inefficient and inelegant.
This doesn't sysnthesize:
eight_bit_result <= std_logic_vector(to_unsigned(character'pos(some_integer), 8));
ISE 14.7 breaks with a vague error caused by some header file. Even if it did work, it wouldn't work for values outside of 0-255. What is the right way to do this?
EDIT:
I wrote a quick and dirty function to cover integer values 0-9999. It needs no clocked process, no extra entity, etc. The proposed answers so far seem overly complicated.
function get_ascii_array_from_int(i : integer range 0 to 9999) return char_array is
variable result : char_array(0 to 3) := (x"30", x"30", x"30", x"30"); -- 0000
begin
if i >= 0 then
if i < 1000 then
result(0) := x"30"; -- 0
result(1 to 3) := get_ascii_array_from_int_hundreds(i);
elsif i < 2000 then
result(0) := x"31"; -- 1
result(1 to 3) := get_ascii_array_from_int_hundreds(i-1000);
elsif i < 3000 then
result(0) := x"32"; -- 2
result(1 to 3) := get_ascii_array_from_int_hundreds(i-2000);
elsif i < 4000 then
result(0) := x"33"; -- 3
result(1 to 3) := get_ascii_array_from_int_hundreds(i-3000);
elsif i < 5000 then
result(0) := x"34"; -- 4
result(1 to 3) := get_ascii_array_from_int_hundreds(i-4000);
elsif i < 6000 then
result(0) := x"35"; -- 5
result(1 to 3) := get_ascii_array_from_int_hundreds(i-5000);
elsif i < 7000 then
result(0) := x"36"; -- 6
result(1 to 3) := get_ascii_array_from_int_hundreds(i-6000);
elsif i < 8000 then
result(0) := x"37"; -- 7
result(1 to 3) := get_ascii_array_from_int_hundreds(i-7000);
elsif i < 9000 then
result(0) := x"38"; -- 8
result(1 to 3) := get_ascii_array_from_int_hundreds(i-8000);
else
result(0) := x"39"; -- 9
result(1 to 3) := get_ascii_array_from_int_hundreds(i-9000);
end if;
else
result := (x"6e", x"65", x"67", x"23"); -- "neg#"
end if;
return result;
end get_ascii_array_from_int;
As you may have guessed there are three other methods: get_ascii_array_from_int_hundreds get_ascii_array_from_int_tens get_ascii_array_from_int_ones
Say what you will about the this function but keep in mind that it produces the correct result when I need it, not several cycles later, and is simple and straightforward. I can easily expand it to cover negative numbers and larger numbers.