¿Cómo simular una memoria 8x4 usando VHDL?

0

¿Por qué este código:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.ALL;
use ieee.std_logic_arith.all;

entity memorie8x4 is
        port(

        cs:             in std_logic; -- cs = 1 => chip selected
        rw:             in std_logic; -- rw = 1 => read; 0 => write
        address: in std_logic_vector(2 downto 0);
        output:         inout std_logic_vector(3 downto 0) -- tip inout ca sa putem si citi si scrie

        );
end memorie8x4;

architecture Behavioral of memorie8x4 is

        type MEM_array is array(0 to 7) -- 3 biti de adresa
                of std_logic_vector(3 downto 0);
        signal mem8x4: MEM_array := (others => "0000"); -- valorile noastre prestabilite

        signal out_sig: std_logic_vector(3 downto 0) := "ZZZZ";
begin
        -- este output doar cand suntem in read mode. Cand suntem in write mode e input
        -- ( starea Z e impedanta mare ca sa putem citi valori de la portul output )
        output <= out_sig when (cs = '1' and rw = '1') else (others => 'Z');

        process(cs, rw)
        begin
                if cs = '0' then
                        out_sig <= "ZZZZ";
                else -- chip-ul este selectat
                        if rw = '1' then --modul read a fost selectat
                                case address is
                                        when "000" => out_sig <= mem8x4(0);
                                        when "001" => out_sig <= mem8x4(1);
                                        when "010" => out_sig <= mem8x4(2);
                                        when "011" => out_sig <= mem8x4(3);
                                        when "100" => out_sig <= mem8x4(4);
                                        when "101" => out_sig <= mem8x4(5);
                                        when "110" => out_sig <= mem8x4(6);
                                        when "111" => out_sig <= mem8x4(7);
                                        when others => out_sig <= "0000";
                                end case;
                        else -- modul write a fost selectat
                                case address is
                                        when "000" => mem8x4(0) <= output;
                                        when "001" => mem8x4(1) <= output;
                                        when "010" => mem8x4(2) <= output;
                                        when "011" => mem8x4(3) <= output;
                                        when "100" => mem8x4(4) <= output;
                                        when "101" => mem8x4(5) <= output;
                                        when "110" => mem8x4(6) <= output;
                                        when "111" => mem8x4(7) <= output;
                                        when others => mem8x4 <= (others => "0000");
                                end case;
                        end if;
                end if;

        end process;

end Behavioral;

Con este banco de pruebas:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

ENTITY mem8x4_tb IS
END mem8x4_tb;

ARCHITECTURE behavior OF mem8x4_tb IS

    -- Component Declaration for the Unit Under Test (UUT)

    COMPONENT memorie8x4
    PORT(
         cs : IN  std_logic;
         rw : IN  std_logic;
         address : IN  std_logic_vector(2 downto 0);
         output : INOUT  std_logic_vector(3 downto 0)
        );
    END COMPONENT;


   --Inputs
   signal cs : std_logic := '0'; -- default neselectat
   signal rw : std_logic := '1'; -- default read mode
   signal address : std_logic_vector(2 downto 0) := (others => '0'); -- default adresa 0

   signal output : std_logic_vector(3 downto 0) := "0000";

BEGIN

        -- Instantiate the Unit Under Test (UUT)
   uut: memorie8x4 PORT MAP (
          cs => cs,
          rw => rw,
          address => address,
          output => output
        );

   -- vreau sa citesc o valoare din memorie, dupa care sa inchid chip-ul,
        -- sa scriu o valoare in memorie, sa inchid chip-ul, sa trec in read
        -- si sa citesc daca valoarea a fost scrisa
        process
        begin

                wait for 10 ns;
                address <= "010"; -- selectez adresa
                rw <= '1'; -- trec in modul read
                cs <= '1'; -- activez memoria -> citesc output-ul
                wait for 10 ns;
                cs <= '0'; -- dezactivez memoria
                rw <= '0'; -- trec in modul write
                output <= "0110"; -- scriu ceva la output
                cs <= '1'; -- activez memoria, se scrie in memorie
                wait for 10 ns;
                cs <= '0'; -- dezactivez memoria
                rw <= '1'; -- trec in modul read
                address <= "001";
                cs <= '1';
                wait for 10 ns;
                address <= "010";
                --cs <= '1'; -- activez memoria, citesc valoarea de la output
                wait;
        end process;
END;

¿No funciona como debería? ¿Qué estoy haciendo mal? Así es como se ve la simulación:

    
pregunta Calin

3 respuestas

1

Si observa lo que realmente está pasando (con el código VHDL originalmente publicado en la pregunta):

(clickable)

Verásquehayconflictosdecontroladoresporqueoutputesenrealidadmodoinoutyloestásconduciendoconstantementeenelbancodepruebas.

Sisimulaslasnuevasversionesdepastebindetucódigoconelreloj,encontraráselmismoconflictoentrelosdoscontroladoresdeoutput.

Aparentemente,tambiénestásperdiendoalgunosretrasosqueimpidenquealgunasdelascondicionesdetuseñaltenganefecto.Losarregléjuntoconlosconflictosdecontroladoresenlasiguientearquitectura:

architecturefooofmem8x4_tbisconstantREAD:std_logic:='1';constantWRITE:std_logic:='0';constantSELECTED:std_logic:='1';constantDISABLED:std_logic:='0';constantUNDRIVEN:std_logic_vector(3downto0):=(others=>'Z');signalcs:std_logic:=DISABLED;signalrw:std_logic:=READ;signaladdress:std_logic_vector(2downto0):=(others=>'0');signaloutput:std_logic_vector(3downto0);beginUUT:entitywork.memorie8x4portmap(cs=>cs,rw=>rw,address=>address,output=>output);STIMULUS:processbeginoutput<=UNDRIVEN;waitfor10ns;address<="010";
        rw <= READ;
        cs <= SELECTED;
        wait for 10 ns;
        cs <= DISABLED;
        rw <= WRITE;
        output <= "0110";
        wait for 10 ns;
        cs <= SELECTED;
        wait for 10 ns;
        cs <= DISABLED;
        rw <= READ;
        output <= (others => 'Z');
        wait for 10 ns;
        address <= "001";  
        cs <= SELECTED;
        wait for 10 ns;
        address <= "010";
        wait for 90 ns;
        wait;
    end process;
end architecture;

Esto también solicitó agregar una dirección y un resultado a la lista de sensibilidad del proceso en memorie8x4 , lo que provocó la eliminación de out_sig :

architecture foo of memorie8x4 is

    type MEM_array is array(0 to 7)  of std_logic_vector(3 downto 0);
    signal mem8x4: MEM_array := (others => "0000");
begin

    process(cs, rw, address, output)
    begin
        if cs = '0' then
            output <= "ZZZZ";
        else 
            if rw = '1' then  -- READ
                case address is
                    when "000" => output <= mem8x4(0);
                    when "001" => output <= mem8x4(1);
                    when "010" => output <= mem8x4(2);
                    when "011" => output <= mem8x4(3);
                    when "100" => output <= mem8x4(4);
                    when "101" => output <= mem8x4(5);
                    when "110" => output <= mem8x4(6);
                    when "111" => output <= mem8x4(7);
                    when others => output <= "0000";
                end case;      
            else              -- WRITE
                case address is
                    when "000" => mem8x4(0) <= output;
                    when "001" => mem8x4(1) <= output;
                    when "010" => mem8x4(2) <= output;
                    when "011" => mem8x4(3) <= output;
                    when "100" => mem8x4(4) <= output;
                    when "101" => mem8x4(5) <= output;
                    when "110" => mem8x4(6) <= output;
                    when "111" => mem8x4(7) <= output;
                    when others => mem8x4 <= (others => "XXXX"); -- invalid addr
                end case;
            end if;
        end if;
    end process;
end architecture;

Nota También cambié el valor de una dirección desconocida durante una escritura para invalidar toda la memoria, lo que representa no saber cuál será la dirección real escrita.

No sería seguro cambiar address mientras rw = '0' , en una implementación real, el retraso de propagación de los elementos address puede ser lo suficientemente largo como para causar escrituras erróneas.

Y eso da:

( clickable)

Donde puede ver que la escritura solo ocurrió cuando cs habilitó la memoria y ninguna de las direcciones presentadas en el banco de pruebas tiene el valor de memoria incorrecto.

    
respondido por el user8352
2

Su proceso es sensible a los cambios en cs y rw solamente. La salida cambia a desconocido en la transición de rw de bajo a alto con una dirección que nunca se asignó. Por lo tanto, está obteniendo un valor desconocido. Pero entonces no hay más transiciones de cs y rw , por lo que la simulación no está ejecutando ese proceso nuevamente y no está cambiando la salida. Es probable que también desee agregar address a la lista de sensibilidad.

    
respondido por el Eugene Sh.
0

¡Añadir una señal de reloj como esto parece funcionar! Testbench

    
respondido por el Calin

Lea otras preguntas en las etiquetas