1
votes

I would like to perform some arithmetic operation between an unsigned number and an unsigned fixed point number in VHDL:

signal A : ufixed(11 downto -8);
signal B : unsigned(11 downto 0);
signal C : ufixed(A'range);

What would be the best way to perform an arithmetic operation on the integer parts, something like this:

C <= A - B;

I could not find any information on converting an unsigned to an ufixed while keeping the same "value". Do I have to convert B to a std_logic_vector, pad 0s, and use the to_ufixed() procedure?

Is there any sane way to do this type of operations? Thanks for any suggestions!

Update: add minimal example

I tried both suggestions using GHDL but still got a error saying: bound check failure at (the assignment operation) line.

Unfortunately I am still having trouble to make modelsim work on my Linux system.

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

entity sub is
  port (
    A : in ufixed (11 downto -8);
    B : in unsigned (11 downto 0);
    C : out ufixed (11 downto -8));
end entity;

architecture RTL of sub is
begin
  -- C <= A - to_ufixed(B, 11, -8);
  C <= A - ufixed(B);
end architecture;

Testbench file:

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

entity sub_tb is
end entity sub_tb;

architecture sim of sub_tb is
  -- component ports
  signal A : ufixed (11 downto -8)  := (others => '0');
  signal B : unsigned (11 downto 0) := (others => '0');
  signal C : ufixed (11 downto -8);

begin  -- architecture sim

  -- component instantiation
  DUT: entity work.sub
    port map (
      A => A,
      B => B,
      C => C);

  -- waveform generation
  WaveGen_Proc: process
  begin
    A <= "00000000111110000000";
    B <= "000000000000";
    wait for 100 ns;
    B <= "000000000001";
    wait for 100 ns;
    B <= "000000001110";

  end process WaveGen_Proc;

end architecture sim;

ghdl -r --std=08 sub_tb
./sub_tb:error: bound check failure at sub_tb.vhdl:16
./sub_tb:error: simulation failed
2
Do I have to convert B to a std_logic_vector, pad 0s, and use the to_ufixed() procedure? is a yes/no question (No). Is there any sane way to do this type of operations is not a specific programming question. Provide a minimal reproducible example with a specific error, show what you've tried.user1155120
@user1155120 I have added a minimal example as you suggested.Fanpeng

2 Answers

2
votes

There is a to_ufixed function in the fixed_pkg package:

  function to_ufixed (
    arg                     : UNRESOLVED_UNSIGNED;             -- unsigned
    constant left_index     : INTEGER;  -- left index (high index)
    constant right_index    : INTEGER                   := 0;  -- right index
    constant overflow_style : fixed_overflow_style_type := fixed_overflow_style;
    constant round_style    : fixed_round_style_type    := fixed_round_style)
    return UNRESOLVED_ufixed;

So, how about:

C <= A - to_ufixed(B, 11, -8);
1
votes

Matthew Taylor's answer is correct, however you will also have to declare C differently.

When adding two fixed point numbers of the same size, the result will be 1 bit larger in the integer portion.

Therefore, the C should be declared as:

signal C : ufixed(12 downto -8);

If you happen to do know that the magnitude of your values will stay below 12 bits, or if you would like it to saturate, you can use the fixed point resize function, which is described in the user guide.

To learn more about how the fixed point package works, you will want to read the fixed package user guide. It can be found here. There is a table in there that shows how to calculate the size of fixed point arithmetic results, based on the operand sizes (it's on the second page).