songa
songa

Reputation: 53

VHDL How to convert std_logic_vector (one variable of Nbits) to std_logic variables (N variables of 1bit) and vice-versa?

I have the following VHDL code to 1k x 8bit RAM:

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY RAM IS
PORT(
    DATA : INOUT STD_LOGIC_VECTOR(7 DOWNTO 0); -- data to/from external pin on bi-dir 8 bit bus 
    ADDR : IN STD_LOGIC_VECTOR(9 DOWNTO 0);    -- address from external pin on input 10 bit bus 
    RW   : IN STD_LOGIC;
    CS   : IN STD_LOGIC
);
END ENTITY;
ARCHITECTURE BEV OF RAM IS
    TYPE MEM IS ARRAY (1023 DOWNTO 0) OF STD_LOGIC_VECTOR(7 DOWNTO 0);
    SIGNAL MEMORY : MEM;
    SIGNAL ADDRESS : INTEGER RANGE 0 TO 1023;
    BEGIN
    PROCESS(ADDR, DATA, RW, CS)
        BEGIN
        ADDRESS <= CONV_INTEGER(ADDR);
        IF(CS = '0')THEN
            IF(RW = '0') THEN
                MEMORY(ADDRESS) <= DATA;
            ELSE
                DATA <= MEMORY(ADDRESS);
            END IF;
        ELSE
            DATA <= "ZZZZZZZZ";
        END IF;
    END PROCESS;
END BEV;

But I'd like the following final port:

(I just put the part that initializes the PORTs of the module, to show what I would like to modify the above code)

ENTITY RAM IS
PORT(
    D0 : INOUT STD_LOGIC;  -- data to/from external pin on bi-dir 1 bit wire LSB
    D1 : INOUT STD_LOGIC;  -- data to/from external pin on bi-dir 1 bit wire
    D2 : INOUT STD_LOGIC;  -- data to/from external pin on bi-dir 1 bit wire
    D3 : INOUT STD_LOGIC;  -- data to/from external pin on bi-dir 1 bit wire
    D4 : INOUT STD_LOGIC;  -- data to/from external pin on bi-dir 1 bit wire
    D5 : INOUT STD_LOGIC;  -- data to/from external pin on bi-dir 1 bit wire
    D6 : INOUT STD_LOGIC;  -- data to/from external pin on bi-dir 1 bit wire
    D7 : INOUT STD_LOGIC;  -- data to/from external pin on bi-dir 1 bit wire HSB

    A0 : IN STD_LOGIC;  -- address from external pin on input 1 bit wire LSB
    A1 : IN STD_LOGIC;  -- address from external pin on input 1 bit wire
    A2 : IN STD_LOGIC;  -- address from external pin on input 1 bit wire
    A3 : IN STD_LOGIC;  -- address from external pin on input 1 bit wire
    A4 : IN STD_LOGIC;  -- address from external pin on input 1 bit wire
    A5 : IN STD_LOGIC;  -- address from external pin on input 1 bit wire
    A6 : IN STD_LOGIC;  -- address from external pin on input 1 bit wire
    A7 : IN STD_LOGIC;  -- address from external pin on input 1 bit wire
    A8 : IN STD_LOGIC;  -- address from external pin on input 1 bit wire
    A9 : IN STD_LOGIC;  -- address from external pin on input 1 bit wire HSB

    RW   : IN STD_LOGIC;
    CS   : IN STD_LOGIC
);
END ENTITY;

I would like to replace the STD_LOGIC_VECTORs by STD_LOGICs (wires).

Could someone help me with this? :)

Edited in 2015 JAN 15

Hi, I'd like so much to thank everyone who contributed to this post. And now I'd like also to add a few things, that I learned during this period, on the same subject, to help beginners like me.

There are 2 ways to "make" a memory (if there are more ways, I still not learned!): Or using internal logic of FPGA (as seen here earlier, in this post)... Or using internal memory of FPGA (from what I understand, this is possible only in models that have this internal memory).

In the first case, FPGA consumption is large, and if you want to do something else, perhaps will not be possible (which is my case).

In the second case the FPGA consumption is 0 or minimum. There will be only the consumption of internal memory, saving the logic of the FPGA.

So, I figured it would be better for me, to use the ready model, that Altera Quartus offers and modifies it as I learned here. It was also cool, that in this way I learned also other forms of how to write a program in VHDL.

In the first case, is used "PROCESS ()" and "END PROCESS;" and this way I can use the "IF () THEN", as seen in the examples presented here (above).

But in the second case (below), is not possible to use the "IF () THEN". After a brief search, I found the document "VHDL Math Tricks of the Trade.pdf", and learned that it could use the following sentence:

X <= VALUE when (LOGIC) else ANOTHER_VALUE;

This way I managed to solve another problem that existed in the second option of memory (in the library), which is the fact of not having a control pin to put the memory in tri-state or disables it.

In the example below I managed to fit buses (address and data) and add a pin control, as I needed. (I left the original part commented)

Once again, I like to thank, the help of those who participated in the post, with excellent examples.

Thank you guys.

-- ============================================================
--  megafunction wizard: %ROM: 1-PORT%
--
-- GENERATION: STANDARD
-- VERSION: WM1.0
-- MODULE: altsyncram 
-- File Name: ROM.vhd
-- Megafunction Name(s): altsyncram
-- Simulation Library Files(s): altera_mf
-- ============================================================

LIBRARY ieee;
USE ieee.std_logic_1164.all;

LIBRARY altera_mf;
USE altera_mf.all;

ENTITY ROM IS
    PORT
    (
        A0  : IN STD_LOGIC;
        A1  : IN STD_LOGIC;
        A2  : IN STD_LOGIC;
        A3  : IN STD_LOGIC;
        A4  : IN STD_LOGIC;
        A5  : IN STD_LOGIC;
        A6  : IN STD_LOGIC;
        A7  : IN STD_LOGIC;
        A8  : IN STD_LOGIC;
        A9  : IN STD_LOGIC;
        A10 : IN STD_LOGIC;
        D7  : OUT STD_LOGIC;
        D6  : OUT STD_LOGIC;
        D5  : OUT STD_LOGIC;
        D4  : OUT STD_LOGIC;
        D3  : OUT STD_LOGIC;
        D2  : OUT STD_LOGIC;
        D1  : OUT STD_LOGIC;
        D0  : OUT STD_LOGIC;
        CLK : IN STD_LOGIC  := '1';
        CS  : IN STD_LOGIC  := '1'

--      address : IN STD_LOGIC_VECTOR (10 DOWNTO 0);
--      clock   : IN STD_LOGIC  := '1';
--      q       : OUT STD_LOGIC_VECTOR (7 DOWNTO 0)
);
END ROM;

ARCHITECTURE SYN OF rom IS

SIGNAL sub_wire0 : STD_LOGIC_VECTOR (7 DOWNTO 0);

COMPONENT altsyncram
GENERIC (
    address_aclr_a         : STRING;
    clock_enable_input_a   : STRING;
    clock_enable_output_a  : STRING;
    init_file              : STRING;
    intended_device_family : STRING;
    lpm_hint               : STRING;
    lpm_type               : STRING;
    numwords_a             : NATURAL;
    operation_mode         : STRING;
    outdata_aclr_a         : STRING;
    outdata_reg_a          : STRING;
    widthad_a              : NATURAL;
    width_a                : NATURAL;
    width_byteena_a        : NATURAL
);
PORT (
        address_a : IN STD_LOGIC_VECTOR (10 DOWNTO 0);
        clock0    : IN STD_LOGIC ;
        q_a       : OUT STD_LOGIC_VECTOR (7 DOWNTO 0)
);
END COMPONENT;

BEGIN
--  q <= sub_wire0(7 DOWNTO 0);
    (D7,D6,D5,D4,D3,D2,D1,D0) <= sub_wire0(7 DOWNTO 0) when (CS <= '0') else std_logic_vector'("ZZZZZZZZ");

altsyncram_component : altsyncram
GENERIC MAP (
    address_aclr_a         => "NONE",
    clock_enable_input_a   => "BYPASS",
    clock_enable_output_a  => "BYPASS",
    init_file              => "ROM.mif",
    intended_device_family => "Cyclone IV E",
    lpm_hint               => "ENABLE_RUNTIME_MOD=NO",
    lpm_type               => "altsyncram",
    numwords_a             => 2048,
    operation_mode         => "ROM",
    outdata_aclr_a         => "NONE",
    outdata_reg_a          => "CLOCK0",
    widthad_a              => 11,
    width_a                => 8,
    width_byteena_a        => 1
)
    PORT MAP (
--      address_a => address,
        address_a => (A10,A9,A8,A7,A6,A5,A4,A3,A2,A1,A0),
--      clock0    => clock,
        clock0    => CLK,
        q_a       => sub_wire0
    );

END SYN;

-- ============================================================
-- CNX file retrieval info
-- ============================================================
-- Retrieval info: PRIVATE: ADDRESSSTALL_A NUMERIC "0"
-- Retrieval info: PRIVATE: AclrAddr NUMERIC "0"
-- Retrieval info: PRIVATE: AclrByte NUMERIC "0"
-- Retrieval info: PRIVATE: AclrOutput NUMERIC "0"
-- Retrieval info: PRIVATE: BYTE_ENABLE NUMERIC "0"
-- Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "8"
-- Retrieval info: PRIVATE: BlankMemory NUMERIC "0"
-- Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "0"
-- Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "0"
-- Retrieval info: PRIVATE: Clken NUMERIC "0"
-- Retrieval info: PRIVATE: IMPLEMENT_IN_LES NUMERIC "0"
-- Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_A"
-- Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0"
-- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone IV E"
-- Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0"
-- Retrieval info: PRIVATE: JTAG_ID STRING "NONE"
-- Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0"
-- Retrieval info: PRIVATE: MIFfilename STRING "ROM.mif"
-- Retrieval info: PRIVATE: NUMWORDS_A NUMERIC "2048"
-- Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0"
-- Retrieval info: PRIVATE: RegAddr NUMERIC "1"
-- Retrieval info: PRIVATE: RegOutput NUMERIC "1"
-- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0"
-- Retrieval info: PRIVATE: SingleClock NUMERIC "1"
-- Retrieval info: PRIVATE: UseDQRAM NUMERIC "0"
-- Retrieval info: PRIVATE: WidthAddr NUMERIC "11"
-- Retrieval info: PRIVATE: WidthData NUMERIC "8"
-- Retrieval info: PRIVATE: rden NUMERIC "0"
-- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
-- Retrieval info: CONSTANT: ADDRESS_ACLR_A STRING "NONE"
-- Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "BYPASS"
-- Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_A STRING "BYPASS"
-- Retrieval info: CONSTANT: INIT_FILE STRING "ROM.mif"
-- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone IV E"
-- Retrieval info: CONSTANT: LPM_HINT STRING "ENABLE_RUNTIME_MOD=NO"
-- Retrieval info: CONSTANT: LPM_TYPE STRING "altsyncram"
-- Retrieval info: CONSTANT: NUMWORDS_A NUMERIC "2048"
-- Retrieval info: CONSTANT: OPERATION_MODE STRING "ROM"
-- Retrieval info: CONSTANT: OUTDATA_ACLR_A STRING "NONE"
-- Retrieval info: CONSTANT: OUTDATA_REG_A STRING "CLOCK0"
-- Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "11"
-- Retrieval info: CONSTANT: WIDTH_A NUMERIC "8"
-- Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1"
-- Retrieval info: USED_PORT: address 0 0 11 0 INPUT NODEFVAL "address[10..0]"
-- Retrieval info: USED_PORT: clock 0 0 0 0 INPUT VCC "clock"
-- Retrieval info: USED_PORT: q 0 0 8 0 OUTPUT NODEFVAL "q[7..0]"
-- Retrieval info: CONNECT: @address_a 0 0 11 0 address 0 0 11 0
-- Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0
-- Retrieval info: CONNECT: q 0 0 8 0 @q_a 0 0 8 0
-- Retrieval info: GEN_FILE: TYPE_NORMAL ROM.vhd TRUE
-- Retrieval info: GEN_FILE: TYPE_NORMAL ROM.inc FALSE
-- Retrieval info: GEN_FILE: TYPE_NORMAL ROM.cmp TRUE
-- Retrieval info: GEN_FILE: TYPE_NORMAL ROM.bsf TRUE
-- Retrieval info: GEN_FILE: TYPE_NORMAL ROM_inst.vhd FALSE
-- Retrieval info: LIB_FILE: altera_mf

Upvotes: 1

Views: 3868

Answers (2)

pwolfsberger
pwolfsberger

Reputation: 366

There are two options you can explore that I can think of.

The first would be to use the concatenation operator and intermediate internal signals.

Example 1:

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY RAM IS
PORT(
  D0 : INOUT STD_LOGIC;  -- data to/from external pin on bi-dir 1 bit wire LSB
  D1 : INOUT STD_LOGIC;  -- data to/from external pin on bi-dir 1 bit wire
  D2 : INOUT STD_LOGIC;  -- data to/from external pin on bi-dir 1 bit wire
  D3 : INOUT STD_LOGIC;  -- data to/from external pin on bi-dir 1 bit wire
  D4 : INOUT STD_LOGIC;  -- data to/from external pin on bi-dir 1 bit wire
  D5 : INOUT STD_LOGIC;  -- data to/from external pin on bi-dir 1 bit wire
  D6 : INOUT STD_LOGIC;  -- data to/from external pin on bi-dir 1 bit wire
  D7 : INOUT STD_LOGIC;  -- data to/from external pin on bi-dir 1 bit wire HSB
);
END ENTITY;
ARCHITECTURE BEV OF RAM IS
  SIGNAL data_in_i     :STD_LOGIC_VECTOR(7 downto 0);
  SIGNAL data_out_i    :STD_LOGIC_VECTOR(7 downto 0);
BEGIN
  data_in_i <= D7 & D6 & D5 & D4 & D3 & D2 & D1 & D0;

  ...
  D7 <= data_out_i(7);
  D6 <= data_out_i(6);
  D5 <= data_out_i(5);
  D4 <= data_out_i(4);
  D3 <= data_out_i(3);
  D2 <= data_out_i(2);
  D1 <= data_out_i(1);
  D0 <= data_out_i(0);
  ...
END BEV;

Personally, I think this is a bit ugly and not as flexible. I'm not sure what your intentions are with splitting up the ports buses into individual bits, but I feel a better solution might be to leave the RAM entity as is and directly assign each bit of the STD_LOGIC_VECTOR inputs when instantiating it in your design.

Example 2:

ram_i: ENTITY work.RAM
PORT MAP(
  D(0) => data0, 
  D(1) => data1,
  D(2) => data2, 
  D(3) => data3, 
  D(4) => data4, 
  D(5) => data5, 
  D(6) => data6, 
  D(7) => data7
);

Upvotes: 2

user1155120
user1155120

Reputation:

You can use aggregates:

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

entity ram is
    port(
        d0: inout std_logic;
        d1: inout std_logic;
        d2: inout std_logic;
        d3: inout std_logic;
        d4: inout std_logic;
        d5: inout std_logic;
        d6: inout std_logic;
        d7: inout std_logic;
        a0: in    std_logic;
        a1: in    std_logic;
        a2: in    std_logic;
        a3: in    std_logic;
        a4: in    std_logic;
        a5: in    std_logic;
        a6: in    std_logic;
        a8: in    std_logic;
        a7: in    std_logic;
        a9: in    std_logic;
        rw: in    std_logic;
        cs: in    std_logic
    );
end entity;
architecture foo of ram is
    type mem is array (1023 downto 0) of std_logic_vector(7 downto 0);
    signal memory : mem;
    signal address : integer range 0 to 1023;
begin
    process(a9,a8,a7,a6,a5,a4,a3,a2,a1,a0,d7,d6,d5,d4,d3,d2,d1,d0,rw,cs)
        begin
        address <= to_integer(unsigned'(a9,a8,a7,a6,a5,a4,a3,a2,a1,a0));
        if cs = '0' then
            if rw = '0' then
                memory(address) <= (d7 & d6 & d5 & d4 & d3 & d2 & d1 & d0);
            else
                (d7,d6,d5,d4,d3,d2,d1,d0) <= std_logic_vector'(memory(address));
            end if;
        else
            (d7,d6,d5,d4,d3,d2,d1,d0) <= std_logic_vector'("ZZZZZZZZ");
        end if;
    end process;
end architecture;

library ieee;
use ieee.std_logic_1164.all;

entity ramtest_tb is
end entity;

architecture foo of ramtest_tb is
    signal a0,a1,a2,a3,a4,a5,a6,a7,a8,a9: std_logic := '0';
    signal d0,d1,d2,d3,d4,d5,d6,d7: std_logic := 'Z';
    signal rw: std_logic := '1';
    signal cs: std_logic := '1';
begin
DUT:
    entity work.ram
        port map (
            d0 => d0,
            d1 => d1,
            d2 => d2,
            d3 => d3,
            d4 => d4,
            d5 => d5,
            d6 => d6,
            d7 => d7,
            a0 => a0,
            a1 => a1,
            a2 => a2,
            a3 => a3,
            a4 => a4,
            a5 => a5,
            a6 => a6,
            a7 => a7,
            a8 => a8,
            a9 => a9,
            rw => rw,
            cs => cs
        );
TEST:
    process
    begin
        wait for 10 ns;
        rw <= '0';
        a5 <= '1'; a3 <= '1'; a1 <= '1'; --42
        wait for 10 ns;
        cs <= '0';
        (d7,d6,d5,d4,d3,d2,d1,d0) <= std_logic_vector'("10101010");
        wait for 10 ns;
        cs <= '1';
        (d7,d6,d5,d4,d3,d2,d1,d0) <= std_logic_vector'("ZZZZZZZZ");
        wait for 10 ns;
        rw <= '1';
        wait for 10 ns;
        cs <= '0';
        wait for 10 ns;
        cs <= '1';
        wait for 10 ns;
        wait;
    end process;

end architecture;

Which gives you:

ramtest_tb.png clickable

A working RAM.

Upvotes: 2

Related Questions