1
votes

I have some 48 bit unsigned numbers that I want to write to a file from my VHDL testbench. Unfortunately, the way I have always done it in the past, converting to integer, does not work for numbers larger than 32 bits.

Here is how I have always done it with numbers smaller than 32 bits.

write(L=>result_line, value=>to_integer(unsigned(C_combo_out)));

Here is what I would like to do but the unsigned type is not supported.

write(L=>result_line, value=>unsigned(C_combo_out));

C_combo_out is a 48 bit std_logic_vector that represents an unsigned integer. Note, I really want numbers in the output file, not strings of '1' and '0'.

1
Sorry there were some faults in my solution. I changed log10ceil to div_ceil(length, 3) to approximate the result length. A version that trims leading zeros was uploaded to PoC.StringsPaebbels

1 Answers

1
votes

So you need numbers of base 10?

Exporting large numbers of base 16 would be very simple, especially if another tool or language post-processes your output. Numbers of base 10 and larger than 2**31 need special treatment.

You could use the double dabble algorithmn to convert such large numbers into a BCD representation and than convert the BCD number to ASCII for file export.

This should convert large std_logic_vectors to decimal numbers:

function raw_format_slv_dec(slv : STD_LOGIC_VECTOR) return STRING is
  function div_ceil(a : NATURAL; b : POSITIVE) return NATURAL is  -- calculates: ceil(a / b)
  begin
    return (a + (b - 1)) / b;
  end function;

  variable Result     : STRING(1 to div_ceil(slv'length, 3));

  subtype TT_BCD      is INTEGER range 0 to 31;
  type TT_BCD_VECTOR  is array(natural range <>) of TT_BCD;

  variable Temp   : TT_BCD_VECTOR(div_ceil(slv'length, 3) - 1 downto 0)    := (others => 0);
  variable Carry  : T_UINT_8;

begin
  for i in slv'range loop
    if (slv(i) = '0') then
      Carry      := 0;
    else
      Carry      := 1;
    end if;
    for j in Temp'reverse_range loop
      Temp(j)    := Temp(j) * 2 + Carry;
      if (Temp(j) > 9) then
        Carry    := 1;
        Temp(j)  := Temp(j) - 10;
      else
        Carry    := 0;
      end if;
    end loop;
  end loop;

  for i in Result'range loop
    Result(i)    := CHARACTER'val(to_integer(Temp(Temp'high - i + 1)));
  end loop;

  -- trim leading zeros, except the last
  return Result;
end function;

An extended version was uploaded to PoC's strings package.

Appendix: Run a testbench on PoC.strings package

The PoC-Library comes with testbenches, so you can run it from console. There are 4 simple steps, which need to be executed:

  1. Download PoC
  2. Configure your preferred simulator tool chain(s):

    cd <PoCRoot>
    ./poc.sh --configure
    
  3. Setup: Create a my_project.vhdl in <PoCRoot>/tb/common/ from template <PoCRoot>/src/common/my_project.vhdl.template. Configure the two constants with that file.

  4. Run the simulation:

    cd <PoCRoot>/tb
    ./testbench.sh --isim PoC.common.strings -g
    

If you run the simulation without -g it should look like this:

Simulating on console
(clickable)

If you run the simulation with option -g, it will run in GUI-mode and look like this:

iSim GUI with constants
(clickable)

Further information:
- List of used files
- Testbench

If you have further questions, please refer to the AUTHORS file and contact me or my colleagues directly.