1

I'm trying to model a RAM chip in VHDL with generic parameters for the address and data bus widths and for the base address where the RAM is placed in the address space. My problem is that I cannot figure out how to get a slice of an generic unconstrained array parameter to compare it against a std_logic_vector signal.

This the reduced code that is intended to compute the "chip select" signal:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity e is
    generic (
        BASE_ADDR :std_logic_vector := x"C000";
        CELL_ADDR_WIDTH :integer := 4
    );
    port (
        address :in std_logic_vector (BASE_ADDR'length-1 downto 0)
    );
end;

architecture behavioral of e is

    constant ADDR_WIDTH :integer := BASE_ADDR'length;

    signal cs :std_logic;

begin

    cs <= '1' when address(ADDR_WIDTH-1 downto CELL_ADDR_WIDTH) = BASE_ADDR(ADDR_WIDTH-1 downto CELL_ADDR_WIDTH) else '0';

end behavioral;

The Lattice ispLEVER VHDL compiler reports the following error:

23:64:23:110|Slice range direction does not match argument range

The message is caused by the expression BASE_ADDR(ADDR_WIDTH-1 downto CELL_ADDR_WIDTH).

How is a slice of the generic unconstrained array BASE_ADDR accessed correctly in VHDL?

2
  • 2
    Your unconstrained array defaults to a "to" range because the index type of std_logic_vector is integer and integer in turn is defined with a to range :). So use the to keyword in your slice. Commented Oct 3, 2017 at 18:36
  • You'll could also add an alias to your architecture declarative region - alias BASEADDR: std_logic_vector(BASE_ADDR'LENGTH - 1 downto 0) is BASE_ADDR; to define a direction and use that - cs <= '1' when address(ADDR_WIDTH-1 downto CELL_ADDR_WIDTH) = BASEADDR(ADDR_WIDTH-1 downto CELL_ADDR_WIDTH) else '0'; Commented Oct 3, 2017 at 18:53

1 Answer 1

1

Both solutions suggested by @Paebbels and @user1155120 resolve the VHDL compilation error. I quote the suggestions here with the code updated accordingly.

@Paebbels: Use to in slice

Your unconstrained array defaults to a "to" range because the index type of std_logic_vector is integer and integer in turn is defined with a to range :). So use the to keyword in your slice.

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity e is
    generic (
        BASE_ADDR :std_logic_vector := x"C000";
        CELL_ADDR_WIDTH :integer := 4
    );
    port (
        address :in std_logic_vector (BASE_ADDR'length-1 downto 0)
    );
end;

architecture behavioral of e is

    constant ADDR_WIDTH :integer := BASE_ADDR'length;

    signal cs :std_logic;

begin

    cs <= '1' when address(ADDR_WIDTH-1 downto CELL_ADDR_WIDTH) = BASE_ADDR(ADDR_WIDTH-1 to CELL_ADDR_WIDTH) else '0';

end behavioral;

@user1155120: Declare an alias to define a direction

You'll could also add an alias to your architecture declarative region - alias BASEADDR: std_logic_vector(BASE_ADDR'LENGTH - 1 downto 0) is BASE_ADDR; to define a direction and use that - cs <= '1' when address(ADDR_WIDTH-1 downto CELL_ADDR_WIDTH) = BASEADDR(ADDR_WIDTH-1 downto CELL_ADDR_WIDTH) else '0';

I used a more prominent name for the alias:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity e is
    generic (
        BASE_ADDR :std_logic_vector := x"C000";
        CELL_ADDR_WIDTH :integer := 4
    );
    port (
        address :in std_logic_vector (BASE_ADDR'length-1 downto 0)
    );
end;

architecture behavioral of e is

    constant ADDR_WIDTH :integer := BASE_ADDR'length;

    signal cs :std_logic;

    alias BASE_ADDR_ALIAS: std_logic_vector(BASE_ADDR'LENGTH - 1 downto 0) is BASE_ADDR;

begin

    cs <= '1' when address(ADDR_WIDTH-1 downto CELL_ADDR_WIDTH) = BASE_ADDR_ALIAS(ADDR_WIDTH-1 downto CELL_ADDR_WIDTH) else '0';

end behavioral;
Sign up to request clarification or add additional context in comments.

3 Comments

There's no need to make aliases prominent. An alias is an alternate name for a named entity (IEEE Std 1076-2008, 6.6 Alias declarations). They can be used for brevity as in selected names (8.3) as in implicitly declared aliases (6.6.3 Nonobject aliases) used for making enumeration names visible by the context of overload resolution (12.5).
I find names confusing that look very similar like BASE_ADDR and BASEADDR, therefore I thought I'd make the names more distinguishable in this code example. Of course your original suggestion is also technically correct.
If it's lack of confusion you're after considering simplifying the design specification.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.