-- EE552 PORTA-AMP Project -- file: mem_mgmt_cont.vhd -- Author: Kevin Mlazgar -- -- --Max Speed: 34.02 MHz (258 LCs) - normal --Max Speed: 39.68 MHz (260 LCs) - optimized for speed... -- --Chip/ Input Output Bidir Memory Memory LCs --POF Device Pins Pins Pins Bits % Utilized LCs % Utilized -- --mem_mgmt_cont -- EPF10K20RC240-4 20 34 16 0 0 % 258 22 % -- -- Revision 3.0 -- moved DRAM interface to a separate module...dram_int.vhd -- Revision 2.0 1999/11/27 -- Modified to integrate a DRAM controller. -- Reduced addressable memory to 8MB. -- Designed around the Micron 8MB EDO SIMM: MT16D232M-60 X -- see dm53.pdf at www.micron.com for specifics. -- -- -- Revision 1.1 1999/11/15 -- Simulated and fixed errors... -- Revision 1.1 1999/11/14 -- Limited implementation with only memory framing and capability of a -- single song. Memory framing is beneficial in that we have 2^12 frames -- of memory each with 2^13 words which are accessed via offsets. -- Where a word is 16 bits wide, for a total of 64MB. -- With smaller address pieces any ripple-carry counters used to increment -- addresses will be MUCH faster... -- -- Revision 1.0 1999/10/10 -- initial revision. -- -- This module handles the interaction between its client the -- Master Control module of the PORTA-AMP and the SDRAM Interface. -- It implements memory framing and internally keeps track of all SDRAM -- addressing. -- All the Master Control can do is write or read a single song sequentially -- to or from memory. -- All reads by the Master Control will be ignored unless a song has previously -- been written... -- -- -- TESTING: -- Annotations: -- NOTE: ALL data from external sources is inserted manually -- 1. verify that cannot read when have not yet written to memory -- 2. verify that mc_ram_ready goes low upon master issuing a read/write -- VOID 3. verify that wait for sdram client interface to be ready before -- issuing a read/write -- VOID 4. verify that on a write to sdram client interface: -- dpath_r_w = '0' -- dpath_csn = '0' -- dpath_primary_datapath is being driven with the write data -- 5. verify that will wait till write is over -- 6. verify that address incremented for subsequent writes/reads -- 7. verify address starts at zero for first read -- VOID 8. verify only drive read data to master when it is valid: -- during wait_for_end_of_master_read since mc_ram_ready signal -- returns to high in that state after a read... -- 9. verify address returns to zero on a read when reach end of song... -- 10. verify once start writing the track that keep in write loop till -- mc_ram_read_write goes high; then go to wait_for_command -- 11. verify once start reading the track that keep in read loop till -- mc_ram_read_write goes low; then go to wait_for_command -- 12. verify periodic CBR refreshes at least every 15.625us. -- 13. verify that latch a command that occurs on rising edge of -- clock when exiting wait_for_command state to do a refresh. library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use work.sdram_package.all; package mem_mgmt_cont_pkg is component mem_mgmt_cont is generic ( datawidth : positive := 16; -- addresswidth = framewidth + offsetwidth addresswidth : positive := 22; framewidth : positive := 12; offsetwidth : positive := 10; bank_addrwidth : positive := 2; -- don't change this... -- dram_addrwidth = (addresswidth - bank_addrwidth)/2 dram_addrwidth : positive := 10 -- for an 8MB SIMM ); port ( -- clock mem_mgmt_clk : in std_logic; -- reset mem_mgmt_reset : in std_logic; -- **************************** -- ** DRAM Interface Signals ** -- RAS lines to DRAM -- acts as bank select rasn : out std_logic_vector(3 downto 0); -- CASN line to common CASN line on DRAM DIMM casn : out std_logic; -- write enable line to DRAM -- '1' indicates a READ to DRAM -- '0' indicates a WRITE from DRAM wen : out std_logic; -- data path to DRAM dram_datapath : inout std_logic_vector(15 downto 0); -- address path to DRAM (time multiplexed address lines) dram_addresspath : out std_logic_vector(dram_addrwidth-1 downto 0); -- ****************************** -- ** Porta-AMP Direct Signals ** -- signal to the master indicating that the interface is ready for -- a command. -- The master should NEVER address the sdram interface if this -- signal is low. -- If a read or write had been issued or a refresh is in progress this -- signal will go low during the access. When it goes high again there -- is valid data available on the mc_datapath_out for a read, -- or the write is done. mc_ram_ready : out std_logic; -- client active-high Chip Select signal is asserted when cpu is addressing -- the memory management controller. -- The data will be loaded into the write_data register of -- the primary data path if a write is also being issued... mc_ram_enable : in std_logic; -- client read/writen line -- '1' indicates a READ -- '0' indicates a WRITE -- A 1 clock period latency is required to switch between these. -- i.e. wait a period before asserting mc_ram_enable! -- While doing a read or a write hold this signal at its value and -- assert mc_ram_enable to do another read or write. Once this signal -- is changed a further read or write will occur at the start of memory. mc_ram_read_write : in std_logic; -- signal indicating that there is no valid song data in sdram or -- that have reached end of present song... mc_ram_no_data : out std_logic; -- data path to Porta_AMP master mc_datapath_in : in std_logic_vector(15 downto 0); mc_datapath_out : buffer std_logic_vector(15 downto 0) ); end component mem_mgmt_cont; end package mem_mgmt_cont_pkg; library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; library work; use work.sdram_package.all; use work.dram_int_pkg.all; entity mem_mgmt_cont is generic ( datawidth : positive := 16; -- addresswidth = framewidth + offsetwidth addresswidth : positive := 22; framewidth : positive := 12; offsetwidth : positive := 10; bank_addrwidth : positive := 2; -- don't change this... -- dram_addrwidth = (addresswidth - bank_addrwidth)/2 dram_addrwidth : positive := 10 -- for an 8MB SIMM ); port ( -- clock mem_mgmt_clk : in std_logic; -- reset mem_mgmt_reset : in std_logic; -- **************************** -- ** DRAM Interface Signals ** -- RAS lines to DRAM -- acts as bank select rasn : out std_logic_vector(3 downto 0); -- CASN line to common CASN line on DRAM DIMM casn : out std_logic; -- write enable line to DRAM -- '1' indicates a READ to DRAM -- '0' indicates a WRITE from DRAM wen : out std_logic; -- data path to DRAM dram_datapath : inout std_logic_vector(15 downto 0); -- address path to DRAM (time multiplexed address lines) dram_addresspath : out std_logic_vector(dram_addrwidth-1 downto 0); -- ****************************** -- ** Porta-AMP Direct Signals ** -- signal to the master indicating that the interface is ready for -- a command. -- The master should NEVER address the sdram interface if this -- signal is low. -- If a read or write had been issued or a refresh is in progress this -- signal will go low during the access. When it goes high again there -- is valid data available on the mc_datapath_out for a read, -- or the write is done. mc_ram_ready : out std_logic; -- client active-high Chip Select signal is asserted when cpu is addressing -- the memory management controller. -- The data will be loaded into the write_data register of -- the primary data path if a write is also being issued... mc_ram_enable : in std_logic; -- client read/writen line -- '1' indicates a READ -- '0' indicates a WRITE -- A 1 clock period latency is required to switch between these. -- i.e. wait a period before asserting mc_ram_enable! -- While doing a read or a write hold this signal at its value and -- assert mc_ram_enable to do another read or write. Once this signal -- is changed a further read or write will occur at the start of memory. mc_ram_read_write : in std_logic; -- signal that indicates whether raw data is requested or -- whether a song name is requested -- NOT IMPLEMENTED -- mc_ram_data_select : in std_logic; -- signal that indicates whether the client interface controller's -- internal track up/down parallel load register should be incremented -- or decremented. Or whether the present track should be deleted. -- -- 000 no command -- 001 increment track count by 1 -- 010 decrement track count by 1 -- 011 delete present track -- 100 go to start of present track -- mc_ram_track_control : in std_logic_vector(2 downto 0); -- signal indicating that there is no valid song data in sdram or -- that have reached end of present song... mc_ram_no_data : out std_logic; -- signal indicating that are on the last track in memory -- mc_last_track : out std_logic; -- data path to Porta_AMP master mc_datapath_in : in std_logic_vector(15 downto 0); mc_datapath_out : buffer std_logic_vector(15 downto 0) ); end entity mem_mgmt_cont; architecture mixed of mem_mgmt_cont is -- state enumeration type state_type is (wait_for_command, write_issue, write_check_for_ack, write_wait1, write_wait2, write_rfrsh_wait1, write_rfrsh_wait2, increment_write_offset_addr, increment_write_frame_addr, assign_song_end_addr, wait_for_end_of_master_write, read_issue, read_check_for_ack, read_wait1, read_wait2, read_rfrsh_wait1, read_rfrsh_wait2, increment_read_offset_addr, increment_read_frame_addr, check_if_end_of_song, wait_for_end_of_master_read ); signal state : state_type; -- the current state constant frame_addr_top : positive := addresswidth - 1; -- 21 constant frame_addr_bottom : positive := addresswidth - framewidth; -- 22-11 = 11 constant offset_addr_top : positive := frame_addr_bottom - 1; -- 10 constant offset_addr_bottom : positive := frame_addr_bottom - offsetwidth; -- 11-11 = 0 -- always all '0's signal no_track_detect_addr : std_logic_vector(addresswidth-1 downto 0); -- present address reading/writing from/to in DRAM signal song_active_address : std_logic_vector(addresswidth-1 downto 0); -- signal song_active_frame : std_logic_vector(framewidth-1 downto 0); -- signal song_active_offset : std_logic_vector(offsetwidth-1 downto 0); -- used to tell if offset address has looped -- signal offset_done : std_logic_vector(offsetwidth-1 downto 0); -- Below signals used to ignore address bits A8 and A9 in troubleshooting -- Since the address when eventually sent to the DRAM goes as two chunks -- each 10 bits in size (A9-A0) in order to ignore A8 and A9, bits 18, 19, -- 9 and 8 of the song_active_address must be set to zero... signal song_active_frame : std_logic_vector(framewidth-3 downto 0); alias song_active_frame_bank : std_logic_vector(1 downto 0) is song_active_frame(framewidth-3 downto framewidth-4); alias song_active_frame_addr : std_logic_vector(framewidth-5 downto 0) is song_active_frame(framewidth-5 downto 0); signal song_active_offset : std_logic_vector(offsetwidth-3 downto 0); signal offset_done : std_logic_vector(offsetwidth-3 downto 0); signal bits_18_19 : std_logic_vector(1 downto 0); signal bits_9_8 : std_logic_vector(1 downto 0); -- last address of track in DRAM signal song_end_address : std_logic_vector(addresswidth-1 downto 0); signal write_data_load : std_logic; -- indicates no song data in memory signal no_data : std_logic; -- indicates that end of song has been reached -- signal song_end : std_logic; -- signal from/to the component dram interface... signal mmc_datapath_in_int : std_logic_vector(datawidth-1 downto 0); signal mmc_ram_ready_int : std_logic; signal mmc_ram_enable_int : std_logic; signal mmc_ram_read_write_int : std_logic; signal mmc_cmd_ack_int : std_logic; signal inv_mem_mgmt_reset : std_logic; begin -- mixed no_track_detect_addr <= (others => '0'); offset_done <= (others => '0'); inv_mem_mgmt_reset <= not mem_mgmt_reset; mc_ram_no_data <= no_data; --song_active_address <= song_active_frame & song_active_offset; bits_18_19 <= (others => '0'); bits_9_8 <= (others => '0'); song_active_address <= song_active_frame_bank & bits_18_19 & song_active_frame_addr & bits_9_8 & song_active_offset; dram_simm : dram_int generic map ( datawidth => datawidth, -- addresswidth = framewidth + offsetwidth addresswidth => addresswidth, dram_addrwidth => dram_addrwidth -- for an 8 MB SIMM ) port map ( -- clock dram_int_clk => mem_mgmt_clk, -- reset dram_int_reset => mem_mgmt_reset, -- **************************** -- ** DRAM Interface Signals ** -- RAS lines to DRAM -- acts as bank select rasn => rasn, -- CASN line to common CASN line on DRAM DIMM casn => casn, -- write enable line to DRAM -- '1' indicates a READ to DRAM -- '0' indicates a WRITE from DRAM wen => wen, -- data path to DRAM dram_datapath => dram_datapath, -- address path to DRAM (time multiplexed address lines) dram_addresspath => dram_addresspath, -- ****************************** -- ** Porta-AMP Direct Signals ** -- This signal should be checked immediately after a command is -- issued to the DRAM interface to ensure that the command -- has not been prempted by the refresh. -- If it has been the command must be resent... mmc_cmd_ack => mmc_cmd_ack_int, -- signal to the master indicating that the interface is ready for -- a command. -- The master should NEVER address the dram interface if this -- signal is low. -- If a read or write had been issued or a refresh is in progress this -- signal will go low during the access. When it goes high again there -- is valid data available on the mc_datapath_out for a read, -- or the write is done. mmc_ram_ready => mmc_ram_ready_int, -- client active-high Chip Select signal is asserted when cpu is addressing -- the memory management controller. -- The data will be loaded into the write_data register of -- the primary data path if a write is also being issued... mmc_ram_enable => mmc_ram_enable_int, -- client read/writen line -- '1' indicates a READ -- '0' indicates a WRITE -- A 1 clock period latency is required to switch between these. -- i.e. wait a period before asserting mmc_ram_enable! -- While doing a read or a write hold this signal at its value and -- assert mmc_ram_enable to do another read or write. Once this signal -- is changed a further read or write will occur at the start of memory. mmc_ram_read_write => mmc_ram_read_write_int, -- address path from memory mgmt cont mmc_dram_address_in => song_active_address, -- data path to memory mgmt cont mmc_datapath_in => mmc_datapath_in_int, mmc_datapath_out => mc_datapath_out ); -- write data from client to memory mgmt cont write_data : generic_register port map( -- Clear generic_register_clr => inv_mem_mgmt_reset, -- Clock enable generic_register_clk_enable => write_data_load, -- Clock generic_register_clk => mem_mgmt_clk, -- D inputs generic_register_d => mc_datapath_in, -- Q outputs generic_register_q => mmc_datapath_in_int ); -- determine if have a song in memory... no_track_detect : process(mem_mgmt_clk) begin if no_track_detect_addr = song_end_address then no_data <= '1'; else no_data <= '0'; end if; end process no_track_detect; -- keep track of end address during a write end_address : process(mem_mgmt_clk, inv_mem_mgmt_reset) begin if inv_mem_mgmt_reset = '1' then song_end_address <= (others => '0'); elsif rising_edge(mem_mgmt_clk) then -- only assign it in a state after active address changed if state = assign_song_end_addr then song_end_address <= song_active_address; else song_end_address <= song_end_address; end if; end if; end process end_address; -- increment the address after each read or write to DRAM offset_address_increment : process(mem_mgmt_clk, inv_mem_mgmt_reset) begin if inv_mem_mgmt_reset = '1' then song_active_offset <= (others => '0'); elsif rising_edge(mem_mgmt_clk) then if state = wait_for_command then song_active_offset <= (others => '0'); elsif state = increment_write_offset_addr or state = increment_read_offset_addr then song_active_offset <= song_active_offset + 1; else song_active_offset <= song_active_offset; end if; end if; end process offset_address_increment; -- increment frame address if offset address has looped frame_address_increment : process(mem_mgmt_clk, inv_mem_mgmt_reset) begin if inv_mem_mgmt_reset = '1' then song_active_frame <= (others => '0'); elsif rising_edge(mem_mgmt_clk) then if state = wait_for_command then song_active_frame <= (others => '0'); elsif state = increment_write_frame_addr or state = increment_read_frame_addr then if song_active_offset = offset_done then -- increment to next frame in memory song_active_frame <= song_active_frame + 1; else song_active_frame <= song_active_frame; end if; else song_active_frame <= song_active_frame; end if; end if; end process frame_address_increment; with state select write_data_load <= '1' when wait_for_command, '1' when wait_for_end_of_master_write, '0' when others; with state select mc_ram_ready <= '1' when wait_for_command, '1' when wait_for_end_of_master_write, '1' when wait_for_end_of_master_read, '0' when others; with state select mmc_ram_enable_int <= '1' when write_issue, '1' when read_issue, '0' when others; with state select mmc_ram_read_write_int <= '0' when write_issue, '1' when others; -- purpose: state machine controlling logic for mem_mgmt_cont -- type: memoryless -- inputs: -- outputs: state state_logic : process (mem_mgmt_clk, inv_mem_mgmt_reset) begin -- process state_logic if inv_mem_mgmt_reset = '1' then state <= wait_for_command; elsif rising_edge(mem_mgmt_clk) then case state is -- wait for command -- addressing starts at zero here -- mc_ram_ready signal IS asserted here. when wait_for_command => if mc_ram_enable = '1' and mc_ram_read_write = '0' then state <= write_issue; elsif mc_ram_enable = '1' and mc_ram_read_write = '1' and no_data = '0' then state <= read_issue; else state <= wait_for_command; end if; -- -- WRITE LOGIC -- when write_issue => if mmc_ram_ready_int = '1' then state <= write_check_for_ack; else state <= write_issue; end if; -- detect if dram interface was leaving state to do a refresh -- at the same time that a write was issued... when write_check_for_ack => if mmc_cmd_ack_int = '1' then -- no refresh in progress state <= write_wait1; else -- refresh in progress state <= write_rfrsh_wait1; end if; when write_wait1 => if mmc_ram_ready_int = '0' then state <= write_wait2; else state <= write_wait1; -- should NEVER occur end if; when write_wait2 => if mmc_ram_ready_int = '1' then state <= increment_write_offset_addr; else state <= write_wait2; end if; when write_rfrsh_wait1 => if mmc_ram_ready_int = '0' then state <= write_rfrsh_wait2; else state <= write_rfrsh_wait1; -- should NEVER occur end if; when write_rfrsh_wait2 => if mmc_ram_ready_int = '1' then state <= write_issue; else state <= write_rfrsh_wait2; end if; -- increment offset addr to write to in memory when increment_write_offset_addr => state <= increment_write_frame_addr; -- increment frame addr to write to in memory, if required when increment_write_frame_addr => state <= assign_song_end_addr; -- assign the value of the song end signal which -- will be used during reads to ensure we do not go beyond -- valid data... when assign_song_end_addr => state <= wait_for_end_of_master_write; -- wait for master control to quit writing the song -- mc_ram_ready signal IS asserted here. when wait_for_end_of_master_write => if mc_ram_enable = '1' and mc_ram_read_write = '0' then state <= write_issue; elsif mc_ram_enable = '0' and mc_ram_read_write = '0' then state <= wait_for_end_of_master_write; else state <= wait_for_command; end if; -- -- READ LOGIC -- when read_issue => if mmc_ram_ready_int = '1' then state <= read_check_for_ack; else state <= read_issue; end if; -- detect if dram interface was leaving state to do a refresh -- at the same time that a write was issued... when read_check_for_ack => if mmc_cmd_ack_int = '1' then -- no refresh in progress state <= read_wait1; else -- refresh in progress state <= read_rfrsh_wait1; end if; when read_wait1 => if mmc_ram_ready_int = '0' then state <= read_wait2; else state <= read_wait1; -- should NEVER occur end if; when read_wait2 => if mmc_ram_ready_int = '1' then state <= increment_read_offset_addr; else state <= read_wait2; end if; when read_rfrsh_wait1 => if mmc_ram_ready_int = '0' then state <= read_rfrsh_wait2; else state <= read_rfrsh_wait1; -- should NEVER occur end if; when read_rfrsh_wait2 => if mmc_ram_ready_int = '1' then state <= read_issue; else state <= read_rfrsh_wait2; end if; -- increment offset addr to write to in memory when increment_read_offset_addr => state <= increment_read_frame_addr; -- increment frame addr to write to in memory, if required when increment_read_frame_addr => state <= check_if_end_of_song; -- if the end of the song then go to wait_for_command state -- which will initialize the active address to zero... when check_if_end_of_song => if song_end_address = song_active_address then state <= wait_for_command; else state <= wait_for_end_of_master_read; end if; -- wait for master control to quit reading the song -- mc_ram_ready signal IS asserted here. when wait_for_end_of_master_read => if mc_ram_enable = '1' and mc_ram_read_write = '1' then state <= read_issue; elsif mc_ram_enable = '0' and mc_ram_read_write = '1' then state <= wait_for_end_of_master_read; else state <= wait_for_command; end if; end case; end if; end process state_logic; end mixed;