📄 ahb_slv.vhd
字号:
-------------------------------------------------------------------------------- This file is a part of the GRLIB VHDL IP LIBRARY-- Copyright (C) 2003, Gaisler Research---- This program is free software; you can redistribute it and/or modify-- it under the terms of the GNU General Public License as published by-- the Free Software Foundation; either version 2 of the License, or-- (at your option) any later version.---- This program is distributed in the hope that it will be useful,-- but WITHOUT ANY WARRANTY; without even the implied warranty of-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-- GNU General Public License for more details.---- You should have received a copy of the GNU General Public License-- along with this program; if not, write to the Free Software-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ------------------------------------------------------------------------------- Entity: ahb_slv-- File: ahb_slv.vhd-- Author: David Lindh - Gaisler Research-- Description: AMBA AHB slave interface for DDR-RAM memory controller------------------------------------------------------------------------------library ieee;use ieee.std_logic_1164.all;library grlib;use grlib.amba.all;use grlib.stdlib.all;library gaisler;use grlib.devices.all;use gaisler.memctrl.all;library techmap;use techmap.gencomp.all;use techmap.allmem.all;use gaisler.ddrrec.all;entity ahb_slv is generic ( hindex : integer := 0; haddr : integer := 0; hmask : integer := 16#f80#; sepclk : integer := 0; dqsize : integer := 64; dmsize : integer := 8; tech : integer := virtex2); port ( rst : in std_ulogic; hclk : in std_ulogic; clk0 : in std_ulogic; csi : in ahb_ctrl_in_type; cso : out ahb_ctrl_out_type);end ahb_slv;architecture rtl of ahb_slv is -- Configuration for AMBA PlugNplay constant REVISION : integer := 0; constant HCONFIG : ahb_config_type := ( 0 => ahb_device_reg ( VENDOR_GAISLER, GAISLER_DDRMP, 0, REVISION, 0), 4 => ahb_membar(haddr, '1', '1', hmask), others => zero32); type burst_mask_type is array (buffersize-1 downto 0) of integer range 1 to 8; type hsize_type is array (4 downto 0) of integer range 8 to 128; constant hsize_array : hsize_type := (128, 64, 32, 16, 8); signal ahbr : ahb_reg_type; signal ahbri : ahb_reg_type; signal csi_synced : ahb_ctrl_in_type; signal DSRAM_i : syncram_dp_in_type; signal DSRAM_o : syncram_dp_out_type; signal ASRAM_i : syncram_2p_in_type; signal ASRAM_o : syncram_2p_out_type; signal vcc : std_ulogic; begin -- rtl vcc <= '1'; ------------------------------------------------------------------------------- --AMBA AHB control combinatiorial part ------------------------------------------------------------------------------- ahbcomb : process(ahbr, rst, csi, csi_synced, DSRAM_o) variable v : ahb_reg_type; -- local variables for registers variable next_rw_cmd_valid : std_logic_vector((log2(buffersize)-1) downto 0); begin v := ahbr; next_rw_cmd_valid := v.rw_cmd_valid +1; v.new_burst := '0'; v.sync_write := '0'; v.sync2_write := '0'; ------------------------------------------------------------------------------- -- Give respons on prevoius address cycle (DATA CYCLE) ------------------------------------------------------------------------------- -- If read and read prediction in previos cycle. Both couldn't be -- written into address syncram (sync2) if ahbr.sync2_busy = '1' then v.sync2_adr := v.pre_read_buffer; v.sync2_wdata := '0' & ahbr.pre_read_adr; v.sync2_write := '1'; v.sync2_busy := '0'; end if; -- In case of a write followed by a read both will try to use sync_ram -- in same cycle, delays read. if ahbr.sync_busy = '1' then v.sync_adr := ahbr.sync_busy_adr; v.doRead := '1'; -- Write data to address given in previous cycle elsif ahbr.doWrite = '1' then -- If first word set all datamasks if conv_std_logic_vector(v.writecounter,4)(0) = '0' then v.sync_wdata((2*(dmsize+dqsize))-1 downto 2*dqsize) := (others => '1'); end if; -- Write data to syncram v.even_odd_write := (conv_integer(conv_std_logic_vector(v.writecounter,4)(0))); for i in 0 to dqsize-1 loop if i >= v.startp*8 and i < (v.startp+v.burst_hsize)*8 then v.sync_wdata(i + v.even_odd_write*dqsize) := csi.ahbsi.hwdata(i+(v.ahbstartp-v.startp)*8); end if; end loop; -- Clear masks for valid bytes for i in 0 to dmsize-1 loop if i >= v.startp and i < (v.startp+v.burst_hsize) then v.sync_wdata((2*dqsize)+v.even_odd_write*dmsize+i) := '0'; end if; end loop; v.sync_adr := v.use_write_buffer & conv_std_logic_vector(v.writecounter,4)(2 downto 1); v.sync_write := '1'; -- Increase mask counter v.burst_dm(conv_integer(v.use_write_buffer)) := v.writecounter+1; v.doWrite := '0'; end if; ------------------------------------------------------------------------------- -- Analyze incomming command on AHB (ADDRESS CYCLE)------------------------------------------------------------------------------- v.sync_busy := '0'; -- An error occured in previous address cycle if ahbr.prev_error = '1' then v.hresp := HRESP_ERROR; v.hready := '1'; v.prev_retry := '0'; v.prev_error := '0'; -- A retry occured in previous address cycle elsif ahbr.prev_retry = '1' then v.hresp := HRESP_RETRY; v.hready := '1'; v.prev_retry := '0'; v.prev_error := '0'; -- Slave selected and previous transfer complete elsif csi.ahbsi.hsel(hindex) = '1' and csi.ahbsi.hready = '1' then v.prev_retry := '0'; v.prev_error := '0'; -- Check if hsize is within range if hsize_array(conv_integer(csi.ahbsi.hsize)) > dqsize and csi.ahbsi.htrans(1) = '1' then assert false report "AHB HSIZE cannot be greater then DQ size" severity error; v.hresp := HRESP_ERROR; v.hready := '0'; v.prev_error := '1'; -- BUSY or IDLE command elsif csi.ahbsi.htrans(1) = '0' then v.hresp := HRESP_OKAY; v.hready := '1'; -- If idle, begin write burst (if waiting) if csi.ahbsi.htrans = HTRANS_IDLE then v.w_data_valid := v.rw_cmd_valid; v.pre_read_valid := '0'; end if; -- SEQ or NONSEQ command else -- Calculate valid bits for transfer according to big endian case ahbdata is when 8 => v.ahboffset := "000"; when 16 => v.ahboffset := "00" & csi.ahbsi.haddr(0); when 32 => v.ahboffset := "0" & csi.ahbsi.haddr(1 downto 0); when 64 => v.ahboffset := csi.ahbsi.haddr(2 downto 0); when others => null; end case; case dqsize is when 8 => v.rwadrbuffer := csi.ahbsi.haddr; v.offset := "000"; when 16 => v.rwadrbuffer := "0" & csi.ahbsi.haddr(31 downto 1); v.offset := "00" & csi.ahbsi.haddr(0); when 32 => v.rwadrbuffer := "00" & csi.ahbsi.haddr(31 downto 2); v.offset := "0" & csi.ahbsi.haddr(1 downto 0); when 64 => v.rwadrbuffer := "000" & csi.ahbsi.haddr(31 downto 3); v.offset := csi.ahbsi.haddr(2 downto 0); when others => null; end case; case csi.ahbsi.hsize is when "000" => v.burst_hsize:= 1; v.startp:= ((dqsize-8)/8) - conv_integer(v.offset); v.ahbstartp := ((ahbdata-8)/8) - conv_integer(v.ahboffset); when "001" => v.burst_hsize:= 2; v.offset(0):= '0'; v.startp:= ((dqsize-16)/8) - conv_integer(v.offset); v.ahbstartp:= ((ahbdata-16)/8) - conv_integer(v.ahboffset); when "010" => v.burst_hsize:= 4; v.offset(1 downto 0) := "00"; v.startp:= ((dqsize-32)/8) - conv_integer(v.offset); v.ahbstartp:= ((ahbdata-32)/8) - conv_integer(v.ahboffset); when "011" => v.burst_hsize:= 8; v.offset(2 downto 0) := "000"; v.startp:= 0; v.ahbstartp := 0; when others => assert false report "Too large HSIZE" severity error; v.hresp := HRESP_ERROR; v.hready := '0'; v.prev_error := '1'; end case; ------------------------------------------------------------------------------- -- SEQUENCIAL, continuation of burst -- Read (seq) if (csi.ahbsi.hwrite = '0' and csi.ahbsi.htrans = HTRANS_SEQ and csi.ahbsi.hburst = HBURST_INCR and v.offset /= "000") then -- Do nothing, requested data is in the same ahb word as -- already is on ahb bus elsif (csi.ahbsi.hwrite = '0' and csi.ahbsi.htrans = HTRANS_SEQ and csi.ahbsi.hburst = HBURST_INCR) then -- Check that new command can be part of current burst if v.readcounter /= v.blockburstlength then -- Read from Syncram v.sync_write := '0'; v.doRead := '1'; else if csi_synced.locked = '0' then -- Check if a prediction was made that matches this new address if v.pre_read_valid = '1' then v.use_read_buffer := v.pre_read_buffer; v.readcounter := 0; v.blockburstlength := csi_synced.burstlength; -- Read from Syncram v.sync_write := '0'; v.doRead := '1'; v.pre_read_valid := '0'; -- Make new read prediction if buffer not full if (v.pre_read_buffer+1) /= csi_synced.rw_cmd_done and csi_synced.r_predict = '1' then v.pre_read_adr := v.rwadrbuffer + csi_synced.burstlength; v.pre_read_buffer := v.pre_read_buffer +1; v.pre_read_valid := '1'; v.sync2_write := '1'; v.sync2_wdata := '0' & v.pre_read_adr; v.sync2_adr := v.pre_read_buffer; v.rw_cmd_valid := v.pre_read_buffer; v.w_data_valid := v.pre_read_buffer; end if; -- No prediction was made, treat as non sequencial else v.new_burst := '1'; end if; else v.new_burst := '1'; end if; end if; -- Write (seq) elsif csi.ahbsi.hwrite = '1' and csi.ahbsi.htrans = HTRANS_SEQ then v.pre_read_valid := '0'; -- Check that new command can be part of current burst if v.offset /= "000" then v.doWrite := '1'; v.hresp := HRESP_OKAY; v.hready := '1'; elsif v.writecounter+1 /= v.blockburstlength and csi_synced.locked = '0' then v.writecounter := v.writecounter +1; v.doWrite := '1'; v.hresp := HRESP_OKAY; v.hready := '1'; -- Command has to start new burst else v.w_data_valid := v.rw_cmd_valid; v.rw_cmd_valid := v.use_write_buffer; v.new_burst := '1'; end if; end if;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -