OpenCores
URL https://opencores.org/ocsvn/ddr2_sdram/ddr2_sdram/trunk

Subversion Repositories ddr2_sdram

[/] [ddr2_sdram/] [trunk/] [DDR2_Control_VHDL.vhd] - Rev 2

Compare with Previous | Blame | View Log

---------------------------------------------------------------------
-- File :			DDR2_Control_VHDL.vhd
-- Projekt :		Prj_12_DDR2
-- Zweck :			DDR2-Verwaltung (Init,Read,Write)
-- Datum :        19.08.2011
-- Version :      2.0
-- Plattform :    XILINX Spartan-3A
-- FPGA :         XC3S700A-FGG484
-- Sprache :      VHDL
-- ISE :				ISE-Design-Suite V:13.1
-- Autor :        UB
-- Mail :         Becker_U(at)gmx.de
---------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
 
	--------------------------------------------
	-- Beschreibung :
	--
	-- das DDR2-RAM hat 512 MBit (64MByte) Speicherplatz
	-- organisiert in 16Bit Woertern
	--
	-- es werden immer Datenworte von 64Bit ausgelesen
	-- oder geschrieben (weil der Burst-Mode auf 4 steht)
	-- aus dem Grund ist der Daten-Vektor für Read/Write
	-- 64Bit breit
	--
	-- das RAM ist ein 4 Blöcke unterteilt (zu je 16Mbyte)
	-- Bank "00" bis Bank "11" : 2Bit
	--
	-- jeder Block ist in 8192 Reihen zu je 1024 Spalten organisiert
	-- ROW "0000000000000" bis "1111111111111" : 13Bit
	-- COL "0000000000" bis "1111111111" : 10Bit
	--
	-- die übergebene Adresse an die FIFO Komponente
	-- mit 25 Bit setzt sich dann so zusammen
	--
	-- input_adress =  ROW & COL & BANK
	--    (25Bit)     13Bit 10Bit  2Bit
	-- pro Adresse stehen 16bit Daten
	-- 
	-- in diesem Demo-Programm wird nur Bank=0
	-- COL=0 und ROW= 0 bis 15 benutzt
	---------------------------------------------
	--
	-- das CONTROL steuert die READ und WRITE funktion
	-- je nachdem welcher Button gedrückt wurde
	--
	--------------------------------------------
	-- Vorsicht !! zur Adressierung :
	-- Der Burst-Mode steht FIX auf "4"
	-- damit werden IMMER 4 (16bit) Zellen gelesen
	-- und beschrieben (also imer 64Bit)
	--
	-- wenn also das 64bit Wort "123456789ABCDEF0" in Adr 0
	-- geschrieben wird, sieht der Speicher danach so aus :
	-- Row 0 Col 0 = "1234"
	-- Row 0 Col 1 = "5678"
	-- Row 0 Col 2 = "9ABC"
	-- Row 0 Col 3 = "DEF0"
	--
	-- Der Col-Counter muss also immer um 4 Adressen
	-- incrementiert / decrementiert werden
	--
	-- in der Demo hier wird nur der ROW-Counter verändert
	-- 
	--------------------------------------------
 
 
 
entity DDR2_Control_VHDL is
 
	--------------------------------------------
	-- Port Deklerationen
	--------------------------------------------
	port (
		reset_in : in std_logic;
		clk_in : in std_logic;
		clk90_in : in std_logic;		
		init_done : in std_logic;
		command_register : out std_logic_vector(2 downto 0);
		input_adress : out std_logic_vector(24 downto 0);
		input_data : out std_logic_vector(31 downto 0);
		output_data : in std_logic_vector(31 downto 0);
		cmd_ack : in std_logic;
		data_valid : in std_logic;
		burst_done : out std_logic;
		auto_ref_req : in std_logic;
		debounce_in : in std_logic_vector(7 downto 0);
		risingedge_in : in std_logic_vector(3 downto 0);
		data_out : out std_logic_vector(7 downto 0)
	);
 
end DDR2_Control_VHDL;
 
architecture Verhalten of DDR2_Control_VHDL is
 
	--------------------------------------------
	-- Einbinden einer Componente
	-- zum schreiben eines 64Bit Wertes
	--------------------------------------------
	COMPONENT DDR2_Write_VHDL
	PORT (
		reset_in : in std_logic;
		clk_in : in std_logic;
		clk90_in : in std_logic;	
		w_command_register : out std_logic_vector(2 downto 0);
		w_cmd_ack : in std_logic;
		w_burst_done : out std_logic;
		write_en : in std_logic;
		write_busy : out std_logic;
		input_data : out std_logic_vector(31 downto 0);
		write_data : in std_logic_vector(63 downto 0)
	);
	END COMPONENT DDR2_Write_VHDL;
 
	--------------------------------------------
	-- Einbinden einer Componente
	-- zum lesen eines 64Bit Wertes
	--------------------------------------------
	COMPONENT DDR2_Read_VHDL
	PORT (
		reset_in : in std_logic;
		clk_in : in std_logic;
		clk90_in : in std_logic;
		r_command_register : out std_logic_vector(2 downto 0);
		r_cmd_ack : in std_logic;
		r_burst_done : out std_logic;	
		r_data_valid : in std_logic;			
		read_en : in std_logic;
		read_busy : out std_logic;
		output_data : in std_logic_vector(31 downto 0);
		read_data : out std_logic_vector(63 downto 0)
	);
	END COMPONENT DDR2_Read_VHDL;	
 
	--------------------------------------------
	-- Interne Signale
	--------------------------------------------
 
	constant INIT_PAUSE : integer := 133000; -- pause 1ms (Wichtig !!)
	signal v_counter :  natural range 0 to INIT_PAUSE := INIT_PAUSE;	
 
	--------------------------------------------
	-- 16 Konstante Werte erzeugen, die beim INIT
	-- (Auto-Write) ins RAM geschrieben werden
	-- ein Wert ist 64Bit = 8 Byte breit
	--------------------------------------------
	constant MAX_ADR : integer := 15; -- 0 bis 15 = 16 Werte
	type RAM_DATA_TYP is array (0 to MAX_ADR) of std_logic_vector(63 downto 0);
	constant RAM_DATA : RAM_DATA_TYP :=
	(
		x"0123456789ABCDEF", x"123456789ABCDEF0", x"23456789ABCDEF01", x"3456789ABCDEF012",
		x"456789ABCDEF0123", x"56789ABCDEF01234", others => (x"639CC6398C7318E7")
	);
	signal v_array_pos :  natural range 0 to MAX_ADR+1 := 0;	
 
	--------------------------------------------
	-- Definition der ROW,COL,BANK adressen
	--------------------------------------------
	signal v_ROW : std_logic_vector(12 downto 0):= (others => '0'); -- 13Bit
	signal v_COL : std_logic_vector(9 downto 0):= (others => '0');  -- 10Bit
	signal v_BANK : std_logic_vector(1 downto 0):= (others => '0'); -- 2Bit
 
	-- zwischenspeicher fuer daten
	signal v_write_data : std_logic_vector(63 downto 0):= (others => '0');	
	signal v_read_data : std_logic_vector(63 downto 0):= (others => '0');		
 
	--------------------------------------------
	-- Ein Konstanter Wert, der mit WRITE-Button
	-- ins RAM geschrieben wird
	--------------------------------------------	
	constant CONST_DATA : std_logic_vector(63 downto 0):= x"31CE629DC43B8877";
 
	--------------------------------------------
	-- State-Machine-Typen
	--------------------------------------------	
	type STATE_M_TYPE is (
		M1_START_UP,
		M2_WAIT_4_DONE,
		M3_AUTO_WRITE_START,
		M4_AUTO_WRITE_INIT,
		M5_AUTO_WRITING,
		M6_AUTO_READ_INIT,
		M7_AUTO_READING,
		M8_NOP,
		M9_WRITE_INIT,
		M10_WRITING,
		M11_READ_INIT,
		M12_READING
	);
	signal STATE_M : STATE_M_TYPE := M1_START_UP;	
 
	--------------------------------------------
	-- sonstige Signale
	--------------------------------------------		
	signal v_write_en : std_logic:='0'; -- '1'=chip-select
	signal v_read_en : std_logic:='0'; -- '1'=chip-select
	signal v_write_busy : std_logic; -- '1'=belegt, '0'=frei
	signal v_read_busy : std_logic; -- '1'=belegt, '0'=frei
	signal v_main_command_register : std_logic_vector(2 downto 0):= (others => '0');
	signal v_write_command_register : std_logic_vector(2 downto 0):= (others => '0');
	signal v_read_command_register : std_logic_vector(2 downto 0):= (others => '0');
	signal v_write_burst_done : std_logic;
	signal v_read_burst_done : std_logic;	
 
begin
 
	--------------------------------------------------
	-- Instantz einer Componente erzeugen und verbinden
	-- zum schreiben eines 64Bit Wertes
	--------------------------------------------------
	INST_DDR2_Write_VHDL : DDR2_Write_VHDL
	PORT MAP (
		reset_in => reset_in,
		clk_in => clk_in,
		clk90_in => clk90_in,
		w_command_register => v_write_command_register,
		w_cmd_ack => cmd_ack,
		w_burst_done => v_write_burst_done,
		write_en => v_write_en,
		write_busy => v_write_busy,
		input_data => input_data,
		write_data => v_write_data
	);
 
	--------------------------------------------------
	-- Instantz einer Componente erzeugen und verbinden
	-- zum lesen eines 64Bit Wertes
	--------------------------------------------------
	INST_DDR2_Read_VHDL : DDR2_Read_VHDL
	PORT MAP (
		reset_in => reset_in,
		clk_in => clk_in,
		clk90_in => clk90_in,
		r_command_register => v_read_command_register,
		r_cmd_ack => cmd_ack,
		r_burst_done => v_read_burst_done,	
		r_data_valid => data_valid,	
		read_en => v_read_en,
		read_busy => v_read_busy,
		output_data => output_data,
		read_data => v_read_data
	);		
 
	-----------------------------------------
	-- State-Machine :
	--   1. wartet nach Reset 1ms
	--   2. sendet das INIT-Kommando an das RAM
	--   3. Wartet auf das INIT_DONE vom RAM
	--   4. Schreiben von 16 Datenwerten ins RAM
	--   5. Auslesen von Adr0
	--   6. Warte auf Tastendrück
	--
	--     7a. North/South = ändern der Adresse (ROW)
	--     7b. East = auslesen eines Wertes
	--     7c. West = schreiben eines Wertes
	--   8. Sprung zu Punkt 6
	-----------------------------------------	
	P_State_Main : process(clk_in,reset_in)
	begin
		if reset_in = '1' then
			-- reset button ist gedrueckt
			STATE_M <= M1_START_UP;
			v_write_en <= '0';
			v_read_en <= '0';
			v_main_command_register <= "000"; -- NOP
			v_counter <= INIT_PAUSE;			
			v_ROW <= (others => '0');	
			v_COL <= (others => '0');
			v_BANK <= (others => '0');
			v_array_pos	<= 0;
		elsif falling_edge(clk_in) then
			case STATE_M is
			   -----------------------------------------------------
				-- INITIALISIERUNG vom RAM : WICHTIG !! :
				-- nach dem Reset wird 1ms gewartet und danach
				-- wird das INIT-Kommando an das RAM gesendet
				-- und auf das Init-Done-Signal vom RAM gewartet
				-----------------------------------------------------
				when M1_START_UP =>
					-- warte 1ms nach Reset bis RAM bereit
					-- WICHTIG !! das steht so im Datasheet
					if v_counter = 0 then					
						-- nach 1ms INIT-Kommando (für einen Clock) anlegen
						STATE_M <= M2_WAIT_4_DONE;
						v_main_command_register <= "010";	-- INIT-CMD	
					else 
						v_main_command_register <= "000"; -- NOP
						v_counter <= v_counter - 1;
					end if;	
				when M2_WAIT_4_DONE =>
					-- warte auf Init-Done-Signal vom RAM
					v_main_command_register <= "000"; -- NOP
					if (init_done = '1') then
						-- das RAM ist jetzt bereit
						STATE_M <= M3_AUTO_WRITE_START;	
					end if;
			   -----------------------------------------------------
				-- automatisches schreiben von ein paar Werten :
				-- es werden 16 feste Datenwerte in die Adressen 0-15
				-- ins RAM geschrieben
				-----------------------------------------------------					
				when M3_AUTO_WRITE_START =>
					-- automatisches schreiben von daten ins RAM
					if v_array_pos > MAX_ADR then
						-- wenn alle adressen geschrieben sind
						STATE_M <= M6_AUTO_READ_INIT;
						v_ROW <= (others => '0');
					else
						if v_write_busy = '0' and auto_ref_req = '0' then
							-- wenn RAM nicht beschäftigt ist, starte das schreiben
							STATE_M <= M4_AUTO_WRITE_INIT;
						end if;
					end if;
				when M4_AUTO_WRITE_INIT =>					
					-- warten bis zum schreiben bereit
					if v_write_busy = '0' and v_write_en='0' then
						-- daten zum schreiben freigeben
						v_write_en <= '1';
					elsif v_write_busy = '1' and v_write_en='1' then
						-- daten werden geschrieben
						v_write_en <= '0';
						STATE_M <= M5_AUTO_WRITING;
					end if;
				when M5_AUTO_WRITING =>								
					-- warte bis schreiben fertig
					if v_write_busy = '0' then
						-- naechste adresse beschreiben						
						v_array_pos <= v_array_pos +1;
						v_ROW <= v_ROW +1;
						STATE_M <= M3_AUTO_WRITE_START;
					end if;	
			   -----------------------------------------------------
				-- automatisches lesen von einem Wert :
				-- es wird der Inhalt von Adr 0 vom RAM ausgelesen
				-----------------------------------------------------					
				when M6_AUTO_READ_INIT =>
					-- automatisches lesen vom RAM  (ein wert)
					-- warten bis zum lesen bereit
					if v_read_busy = '0' and v_read_en='0' and auto_ref_req = '0' then 
						-- daten zum lesen freigeben
						v_read_en <= '1';						
					elsif v_read_busy = '1' and v_read_en='1' then
						-- daten werden gelesen
						v_read_en <= '0';						
						STATE_M <= M7_AUTO_READING;
					end if;
				when M7_AUTO_READING =>
					-- warte bis lesen fertig
					if v_read_busy = '0' then						
						STATE_M <= M8_NOP;
					end if;					
			   -----------------------------------------------------
				-- Dauerloop : warten auf User-Eingabe :
				-- hier wird gewartet, bis einer der 4 Buttons
				-- gedrückt wurde
				-----------------------------------------------------						
				when M8_NOP =>
					-- warte auf Taste fuer READ oder WRITE
					v_write_en <= '0';
					v_read_en <= '0';					
					if risingedge_in(3) = '1' and v_write_busy = '0' and auto_ref_req = '0' then
						-- button = west
						-- write starten (nur wenn nicht busy und kein refresh-zyklus)
						STATE_M <= M9_WRITE_INIT;
					elsif risingedge_in(0) = '1' and v_read_busy = '0' and auto_ref_req = '0' then
					   -- button = east
						-- read starten (nur wenn nicht busy und kein refresh-zyklus)
						STATE_M <= M11_READ_INIT;
					end if;					
					-- warte auf Taste fuer Adr-Up oder Adr-Down								
					if risingedge_in(1)='1' and v_ROW < 255 then
						-- button = north
						v_ROW <= v_ROW + 1;
					elsif risingedge_in(2)='1' and v_ROW > 0 then
						-- button = south
						v_ROW <= v_ROW - 1;
					end if;
			   -----------------------------------------------------
				-- WRITE : schreiben eines Wertes ins RAM :
				-- ein fester Datenwert wird in die aktuelle Adresse
				-- ins RAM geschrieben
				-----------------------------------------------------						
				when M9_WRITE_INIT =>					
					-- warten bis zum schreiben bereit
					if v_write_busy = '0' and v_write_en='0' then
						-- daten zum schreiben freigeben
						v_write_en <= '1';
					elsif v_write_busy = '1' and v_write_en='1' then
						-- daten werden geschrieben
						v_write_en <= '0';
						STATE_M <= M10_WRITING;
					end if;
				when M10_WRITING =>								
					-- warte bis schreiben fertig
					if v_write_busy = '0' then
						STATE_M <= M8_NOP;
					end if;
			   -----------------------------------------------------
				-- READ : lesen eines Wertes vom RAM :
				-- die aktuelle Adresse vom RAM wird ausgelesen
				-----------------------------------------------------						
				when M11_READ_INIT =>					
					-- warten bis zum lesen bereit
					if v_read_busy = '0' and v_read_en='0' then 
						-- daten zum lesen freigeben
						v_read_en <= '1';
					elsif v_read_busy = '1' and v_read_en='1' then
						-- daten werden gelesen
						v_read_en <= '0';						
						STATE_M <= M12_READING;
					end if;
				when M12_READING =>
					-- warte bis lesen fertig
					if v_read_busy = '0' then						
						STATE_M <= M8_NOP;
					end if;									
				when others =>
					NULL;
			end case;
		end if;
	end process P_State_Main;	
 
	-----------------------------------------
	-- Weiterleitung von Signalen
	-- in Abhängigkeit von Read oder Write :
	-----------------------------------------	
	P_SIGNAL : process(clk_in)
	begin
		if falling_edge(clk_in) then
			if STATE_M=M4_AUTO_WRITE_INIT or STATE_M=M5_AUTO_WRITING then
			   -----------------------------------------------------
				-- automatisches schreiben von ein paar Werten
				-----------------------------------------------------	
				v_write_data <= RAM_DATA(v_array_pos);							
				input_adress <= v_ROW & v_COL & v_BANK;
				command_register <= v_write_command_register;
				burst_done <= v_write_burst_done;					
			elsif STATE_M=M6_AUTO_READ_INIT or STATE_M=M7_AUTO_READING then
			   -----------------------------------------------------
				-- automatisches lesen von einem Wert
				-----------------------------------------------------
				v_write_data <= (others => '0'); 				
				input_adress <= v_ROW & v_COL & v_BANK;
				command_register <= v_read_command_register;
				burst_done <= v_read_burst_done;				
			elsif STATE_M=M9_WRITE_INIT or STATE_M=M10_WRITING then
			   -----------------------------------------------------
				-- WRITE : schreiben eines Wertes ins RAM
				-----------------------------------------------------	
				v_write_data <= CONST_DATA;				
				input_adress <= v_ROW & v_COL & v_BANK;
				command_register <= v_write_command_register;
				burst_done <= v_write_burst_done;				
			elsif STATE_M=M11_READ_INIT or STATE_M=M12_READING then
			   -----------------------------------------------------
				-- READ : lesen eines Wertes vom RAM
				-----------------------------------------------------
				v_write_data <= (others => '0'); 				
				input_adress <= v_ROW & v_COL & v_BANK;
				command_register <= v_read_command_register;
				burst_done <= v_read_burst_done;				
			else
			   -----------------------------------------------------
				-- Dauerloop oder INIT
				-----------------------------------------------------	
				v_write_data <= (others => '0');				
				input_adress <= (others => '0');				
				command_register <= v_main_command_register;
				burst_done <= '0';				
			end if;
		end if;
	end process P_SIGNAL;
 
	-----------------------------------------
	-- Ausgabe der gelesenen Daten
	-- je nach Schalterstellung
	-----------------------------------------	
	P_DataOut : process(clk_in,reset_in)
	begin
		if reset_in = '1' then
			-- reset button ist gedrueckt
			data_out <= (others => '0');
		elsif falling_edge(clk_in) then
			if debounce_in(7 downto 5)="000" then data_out <= v_read_data(7 downto 0);
			elsif debounce_in(7 downto 5)="001" then data_out <= v_read_data(15 downto 8);
			elsif debounce_in(7 downto 5)="010" then data_out <= v_read_data(23 downto 16);
			elsif debounce_in(7 downto 5)="011" then data_out <= v_read_data(31 downto 24);
			elsif debounce_in(7 downto 5)="100" then data_out <= v_read_data(39 downto 32);
			elsif debounce_in(7 downto 5)="101" then data_out <= v_read_data(47 downto 40);
			elsif debounce_in(7 downto 5)="110" then data_out <= v_read_data(55 downto 48);
			elsif debounce_in(7 downto 5)="111" then data_out <= v_read_data(63 downto 56);
			end if;
			-------------------------------------------			
		end if;
	end process P_DataOut;
 
end Verhalten;
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.