Electronic – VHDL Aggregate on Left Side of Assignment : Error in Simulator

errorsimulationvhdl

I'm designing a counter with a combinational carry out (not registered). To do this I have a concurrent assignment to create the unregistered sum with carry by extending the unsigned input before incrementing and assigning the sum to an aggregate of the incremented value and the carry out as shown below. Count_a, the register, is in a clocked process with a simple assignment of nxt_cnt_a.

  Carry_Out_a : out std_logic
...
  constant Cntr_Width : positive := 13;
  signal Count_a, nxt_cnt_a : unsigned(Cntr_Width - 1 downto 0) := (others => '0');

  (Carry_Out_a, nxt_cnt_a) <= RESIZE(Count_a, nxt_cnt_a'length + 1) + 1;

This synthesizes fine and produces exactly the adder with register plus a combinational carry output. But it won't simulate in Active-HDL. It compiles OK, but I get a run time error.

# RUNTIME: Fatal Error: RUNTIME_0046 VHDL_test.vhd (130): Incompatible ranges; left: (0 to 13), right: (0 downto 0).

The resize function should create an unsigned of the right length and the addition operator is supposed to convert the integer to the same width unsigned before adding, giving the correct size result.

So why is a run time message being generated? Is this a bug in the simulator? If the syntax is bad, why would it not be caught when the code is initially analyzed?

Do I need to post the entire design? It's currently 142 lines, but I could pare it down to a couple of dozen. The rest of the design is the same counter written in more verbose manners as test cases. This form is the simplest, so I'd like to get it working.

Here is the full test code. In this one the error is on line 26.

-- Test synthesis of counters and carry out flags
library ieee;
use ieee.NUMERIC_STD.all;
use ieee.std_logic_1164.all;
-- use work.Common.all;

entity VHDL_test is
  generic(
    CLK_HZ : REAL := 33.554432E6 );
  port(
    Clk         : in  std_logic := '1';
    Cnt_En      : in  std_logic := '1';
    Test_Out_a  : out std_logic;
    Carry_Out_a : out std_logic
  );
end VHDL_test;

architecture TB_ARCH of VHDL_test is
  constant Clock_Half_Period : time := 500 ms / CLK_HZ;  -- 14901 ps;
  constant Cntr_Width : positive := 13;
  constant Cntr_Modulus : positive := 2**Cntr_Width;
  signal Count_a, nxt_cnt_a : unsigned(Cntr_Width - 1 downto 0) := (others => '0');
begin
  -- Clk_gen: Clk <= not Clk after Clock_Half_Period; -- comment out for synth

  (Carry_Out_a, nxt_cnt_a) <= RESIZE(Count_a, nxt_cnt_a'length + 1) + 1; -- error

  test_ag: process (Clk) is
  begin
    if rising_edge(Clk) then
      Test_Out_a <= Carry_Out_a;
      if (Cnt_En OR not Carry_Out_a) then
        Count_a  <= nxt_cnt_a;
      end if;
    end if;
  end process test_ag;

end TB_ARCH;  -- VHDL_test 

This error has gotten worse, lol I thought I had a work around, but trying to use this in a useful program it fails with the forms that were working in the test code. The only difference was the test code was assigning the carry bit directly to the output std_logic. So I added a test case to use a signal declared in the entity.

  signal Test : std_logic := '1';

  (Test, nxt_cnt_a) <= ("0" & Count_a) - 1; -- works
  -- (Carry_Out_a, nxt_cnt_a) <= RESIZE(Count_a, nxt_cnt_a'length + 1) - 1; -- fails
  -- (Carry_Out_a, nxt_cnt_a) <= RESIZE(Count_a, nxt_cnt_a'length + 1) - One_uns; -- works
  -- (Carry_Out_a, nxt_cnt_a) <= ("0" & Count_a) - 1; -- works

Of course it works in the test code. In my work code I also tried making Test into an unsigned (0 downto 0) which also fails. The error is a bit different now.

# RUNTIME: Fatal Error: RUNTIME_0046 MilliSec.vhd (52): Incompatible ranges; left: (0 to 0), right: (12 downto 0).

Best Answer

Now that we have a testcase, ghdl reports:

ghdl -a --std=08 VHDL_test.vhd
VHDL_test.vhd:26:17:error: can't match 'nxt_cnt_a' with type std_ulogic
VHDL_test.vhd:26:17:error: target is not a signal name

Which is a little less confused than your simulator, that the error is to do with mixing different types within an aggregate. (but see edit below : this is no longer an error in VHDL-2008 : and is compiled correctly by the current GHDL 1.0-dev build.

Now obviously we can do it by brute force : widening the intermediate signal for example...

  signal Count_a: unsigned(Cntr_Width - 1 downto 0) := (others => '0');
  signal nxt_cnt_a : unsigned(Cntr_Width downto 0) := (others => '0');
begin
  --(Carry_Out_a, nxt_cnt_a) <= RESIZE(Count_a, nxt_cnt_a'length + 1) + 1;
  nxt_cnt_a <= RESIZE(Count_a, nxt_cnt_a'length ) + 1 ;
  Carry_Out_a <= nxt_cnt_a(Cntr_Width);
  
        -- in synch process
        Count_a  <= nxt_cnt_a(Count_a'range);

so you have a workaround, but it would be nice to get the aggregate working...

Relevant : (from the VHDL-2008 LRM)

9.3.3.3 Array aggregates For an aggregate of a one-dimensional array type, each choice shall specify values of the index type, and the expression of each element association shall be of either the element type or the type of the aggregate. If the type of the expression of an element association is the type of the aggregate, then either the element association shall be positional or the choice shall be a discrete range.

I think we need to make it clear somehow that the aggregate type is unsigned.

EDIT: My reading suggests that this should in fact work: std_ulogic is a valid element type for unsigned, and the unsigned component of the aggregate should define its type.

Xilinx Vivado (2018.2) reproduces the compile error shown by ghdl(above) in VHDL(old) mode. However in VHDL-2008, it successfully compiles, and (making Clk an internal signal) simulates without runtime error.

Which leads me to suspect we are seeing TWO tool bugs:

ghdl - while excellent - does still have some holes in VHDL-2008 support (as has Vivado, which doesn't even support conditionals on std_logic yet) and this does seem to be one of the points where it hasn't caught up with -2008. EDIT : Now resolved : the current build DOES compile this case correctly with no runtime error.

your simulator : while it parses this expression, it doesn't appear to compile it correctly, leading to the runtime error you see. The fact that two other simulators run it happily supports this being a tool bug.

Now we see the value of a simple testcase : I think it is worth making the Clk changes to run standalone, and submitting to Aldec tech support for their review.