pci_gr.vhd
来自「sparc org, vhdl rtl code」· VHDL 代码 · 共 350 行
VHD
350 行
----------------------------------------------------------------------------
-- This file is a part of the LEON VHDL model
-- Copyright (C) Gaisler Research 2003
--
-- This library is free software; you can redistribute it and/or
-- modify it under the terms of the GNU Lesser General Public
-- License as published by the Free Software Foundation; either
-- version 2 of the License, or (at your option) any later version.
--
-- See the file COPYING.LGPL for the full details of the license.
-----------------------------------------------------------------------------
-- Entity: pci_gr
-- File: pci_gr.vhd
-- Author: Jiri Gaisler - Gaisler Research
-- Description: Simple PCI target interface
------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use work.amba.all;
use work.ambacomp.all;
use work.macro.all;
use work.leon_iface.all;
entity pci_gr is
generic (
device_id : integer := 0; -- PCI device ID
vendor_id : integer := 0; -- PCI vendor ID
nsync : integer range 1 to 2 := 1 -- 1 or 2 sync regs between clocks
);
port(
rst : in std_logic;
pcirst : in std_logic;
clk : in std_logic;
pciclk : in std_logic;
pcii : in pci_in_type;
pcio : out pci_out_type;
ahbmi : in ahb_mst_in_type;
ahbmo : out ahb_mst_out_type;
ahbsi : in ahb_slv_in_type;
ahbso : out ahb_slv_out_type
);
end;
architecture rtl of pci_gr is
constant CSYNC : integer := nsync-1;
constant MADDR_WIDTH : integer := 21;
constant zero : std_logic_vector(31 downto 0) := (others => '0');
subtype word4 is std_logic_vector(3 downto 0);
subtype word32 is std_logic_vector(31 downto 0);
constant pci_memory_read : word4 := "0110";
constant pci_memory_write : word4 := "0111";
constant pci_config_read : word4 := "1010";
constant pci_config_write : word4 := "1011";
type pci_input_type is record
ad : std_logic_vector(31 downto 0);
cbe : std_logic_vector(3 downto 0);
frame : std_logic;
devsel : std_logic;
idsel : std_logic;
trdy : std_logic;
irdy : std_logic;
par : std_logic;
stop : std_logic;
rst : std_logic;
end record;
type pci_target_state_type is (idle, b_busy, s_data, backoff, turn_ar);
type pci_reg_type is record
addr : std_logic_vector(MADDR_WIDTH-1 downto 0);
data : std_logic_vector(31 downto 0);
cmd : std_logic_vector(3 downto 0);
state : pci_target_state_type;
csel : std_logic;
msel : std_logic;
read : std_logic;
devsel : std_logic;
trdy : std_logic;
stop : std_logic;
par : std_logic;
oe_par : std_logic;
oe_ad : std_logic;
oe_ctrl : std_logic;
bar0 : std_logic_vector(31 downto MADDR_WIDTH);
page : std_logic_vector(31 downto MADDR_WIDTH-1);
men : std_logic;
laddr : std_logic_vector(31 downto 0);
ldata : std_logic_vector(31 downto 0);
lwrite : std_logic;
start : std_logic;
rready : std_logic_vector(csync downto 0);
wready : std_logic_vector(csync downto 0);
sync : std_logic_vector(csync downto 0);
end record;
type cpu_state_type is (idle, sync1, busy, sync2);
type cpu_reg_type is record
data : std_logic_vector(31 downto 0);
state : cpu_state_type;
start : std_logic_vector(csync downto 0);
sync : std_logic;
rready : std_logic;
wready : std_logic;
end record;
signal clk_int : std_logic;
signal pr : pci_input_type;
signal r, rin : pci_reg_type;
signal r2, r2in : cpu_reg_type;
signal dmai : ahb_dma_in_type;
signal dmao : ahb_dma_out_type;
begin
-- Back-end state machine (AHB clock domain)
comb : process (rst, r2, r, dmao)
variable vdmai : ahb_dma_in_type;
variable v : cpu_reg_type;
begin
v := r2;
vdmai.start := '0'; vdmai.burst := '0'; vdmai.size := "10";
vdmai.address := r.laddr(31 downto 2) & "00"; v.sync := '1';
vdmai.wdata := r.ldata; vdmai.write := r.lwrite;
v.start(0) := r2.start(csync); v.start(csync) := r.start;
case r2.state is
when idle =>
v.sync := '0';
if r2.start(0) = '1' then
if r.lwrite = '1' then v.state := sync1; v.wready := '0';
else v.state := busy; vdmai.start := '1'; end if;
end if;
when sync1 =>
if r2.start(0) = '0' then v.state := busy; vdmai.start := '1'; end if;
when busy =>
if dmao.active = '1' then
if dmao.ready = '1' then
v.rready := not r.lwrite; v.data := dmao.rdata; v.state := sync2;
end if;
else vdmai.start := '1'; end if;
when sync2 =>
if r2.start(0) = '0' then
v.state := idle; v.wready := '1'; v.rready := '0';
end if;
end case;
if rst = '0' then
v.state := idle; v.rready := '0'; v.wready := '1';
end if;
r2in <= v; dmai <= vdmai;
end process;
-- PCI target core (PCI clock domain)
pcicomb : process(pcirst, pr, pcii, r, r2)
variable v : pci_reg_type;
variable chit, mhit, hit, ready, cwrite, mwrite : std_logic;
variable cdata, cwdata : std_logic_vector(31 downto 0);
begin
v := r; v.trdy := '1'; v.stop := '1';
v.oe_ad := '1'; v.devsel := '1'; mwrite := '0';
v.rready(0) := r.rready(csync); v.rready(csync) := r2.rready;
v.wready(0) := r.wready(csync); v.wready(csync) := r2.wready;
v.sync(0) := r.sync(csync); v.sync(csync) := r2.sync;
-- address decoding
if (r.state = s_data) and ((pr.irdy or r.trdy or r.read) = '0') then
cwrite := r.csel;
if ((r.msel and r.addr(MADDR_WIDTH-1)) = '1') and (pr.cbe = "0000") then
v.page := pr.ad(31 downto MADDR_WIDTH-1);
end if;
if (pr.cbe = "0000") and (r.addr(MADDR_WIDTH-1) = '1') then
mwrite := r.msel;
end if;
else cwrite := '0'; end if;
cdata := (others => '0');
case r.addr(7 downto 2) is
when "000000" => -- 0x00, device & vendor id
cdata := std_logic_vector(conv_unsigned(DEVICE_ID, 16)) &
std_logic_vector(conv_unsigned(VENDOR_ID, 16));
when "000001" => -- 0x04, status & command
cdata(1) := r.men; cdata(25) := '1';
when "000010" => -- 0x08, class code & revision
when "000011" => -- 0x0c, latency & cacheline size
when "000100" => -- 0x10, BAR0
cdata(31 downto MADDR_WIDTH) := r.bar0;
when others =>
end case;
cwdata := pr.ad;
if pr.cbe(3) = '1' then cwdata(31 downto 24) := cdata(31 downto 24); end if;
if pr.cbe(2) = '1' then cwdata(23 downto 16) := cdata(23 downto 16); end if;
if pr.cbe(1) = '1' then cwdata(15 downto 8) := cdata(15 downto 8); end if;
if pr.cbe(0) = '1' then cwdata( 7 downto 0) := cdata( 7 downto 0); end if;
if cwrite = '1' then
case r.addr(7 downto 2) is
when "000001" => -- 0x04, status & command
v.men := cwdata(1);
when "000100" => -- 0x10, BAR0
v.bar0 := cwdata(31 downto MADDR_WIDTH);
when others =>
end case;
end if;
if (((pr.cbe = pci_config_read) or (pr.cbe = pci_config_write))
and (pr.ad(1 downto 0) = "00"))
then chit := '1'; else chit := '0'; end if;
if ((pr.cbe = pci_memory_read) or (pr.cbe = pci_memory_write))
and (r.bar0 = pr.ad(31 downto MADDR_WIDTH))
and (r.bar0 /= zero(31 downto MADDR_WIDTH))
then mhit := '1'; else mhit := '0'; end if;
hit := r.csel or r.msel;
ready := r.csel or (r.rready(0) and r.read) or (r.wready(0) and not r.read and not r.start) or
r.addr(MADDR_WIDTH-1);
-- target state machine
case r.state is
when idle =>
if pr.frame = '0' then v.state := b_busy; end if; -- !HIT ?
v.addr := pr.ad(MADDR_WIDTH-1 downto 0); v.cmd := pr.cbe;
v.csel := pr.idsel and chit;
v.msel := r.men and mhit; v.read := not pr.cbe(0);
if (r.sync(0) and r.start and r.lwrite) = '1' then v.start := '0'; end if;
when turn_ar =>
if pr.frame = '1' then v.state := idle; end if;
if pr.frame = '0' then v.state := b_busy; end if; -- !HIT ?
v.addr := pr.ad(MADDR_WIDTH-1 downto 0); v.cmd := pr.cbe;
v.csel := pr.idsel and chit;
v.msel := r.men and mhit; v.read := not pr.cbe(0);
if (r.sync(0) and r.start and r.lwrite) = '1' then v.start := '0'; end if;
when b_busy =>
if hit = '1' then
v.state := s_data; v.trdy := not ready; v.stop := pr.frame and ready;
v.devsel := '0';
else
v.state := backoff;
end if;
when s_data =>
v.stop := r.stop; v.devsel := '0';
v.trdy := r.trdy or not pcii.pci_irdy_in_n;
if (pcii.pci_frame_in_n and not pcii.pci_irdy_in_n) = '1' then
v.state := turn_ar; v.stop := '1'; v.trdy := '1'; v.devsel := '1';
end if;
when backoff =>
if pr.frame = '1' then v.state := idle; end if;
end case;
if ((r.state = s_data) or (r.state = turn_ar)) and
(((pr.irdy or pr.trdy) = '0') or
((not pr.irdy and not pr.stop and pr.trdy and not r.start and r.wready(0)) = '1'))
then
if (pr.trdy and r.read)= '0' then v.start := '0'; end if;
if (r.start = '0') and ((r.msel and not r.addr(MADDR_WIDTH-1)) = '1') and
(((pr.trdy and r.read) or (not pr.trdy and not r.read)) = '1')
then
v.laddr := r.page & r.addr(MADDR_WIDTH-2 downto 0);
v.ldata := pr.ad; v.lwrite := not r.read; v.start := '1';
end if;
end if;
if (v.state = s_data) and (r.read = '1') then v.oe_ad := '0'; end if;
v.oe_par := r.oe_ad;
if r.csel = '1' then v.data := cdata;
elsif r.addr(MADDR_WIDTH-1) = '1' then
v.data(31 downto MADDR_WIDTH-1) := r.page;
v.data(MADDR_WIDTH-2 downto 0) := (others => '0');
else v.data := r2.data; end if;
v.par := xorv(r.data & pcii.pci_cbein_n);
if (v.state = s_data) or (r.state = s_data) then
v.oe_ctrl := '0';
else v.oe_ctrl := '1'; end if;
if pr.rst = '0' then
v.state := idle; v.men := '0'; v.start := '0';
v.bar0 := (others => '0'); v.msel := '0'; v.csel := '0';
v.page := ('0', '1', others => '0');
end if;
rin <= v;
end process;
pcir : process (pciclk, pcirst, r2)
begin
if rising_edge (pciclk) then
pr.ad <= to_x01(pcii.pci_adin);
pr.cbe <= to_x01(pcii.pci_cbein_n);
pr.devsel <= to_x01(pcii.pci_devsel_in_n);
pr.frame <= to_x01(pcii.pci_frame_in_n);
pr.idsel <= to_x01(pcii.pci_idsel_in);
pr.irdy <= to_x01(pcii.pci_irdy_in_n);
pr.trdy <= to_x01(pcii.pci_trdy_in_n);
pr.par <= to_x01(pcii.pci_par_in);
pr.stop <= to_x01(pcii.pci_stop_in_n);
pr.rst <= to_x01(pcii.pci_rst_in_n);
r <= rin;
end if;
if pcirst = '0' then -- asynch reset required
r.oe_ad <= '1'; r.oe_ctrl <= '1'; r.oe_par <= '1';
end if;
end process;
cpur : process (clk)
begin
if rising_edge (clk) then
r2 <= r2in;
end if;
end process;
pcio.pci_cbe0_en_n <= '1';
pcio.pci_cbe1_en_n <= '1';
pcio.pci_cbe2_en_n <= '1';
pcio.pci_cbe3_en_n <= '1';
pcio.pci_cbeout_n <= "1111";
pcio.pci_aden_n <= (others => r.oe_ad);
pcio.pci_adout <= r.data;
pcio.pci_trdy_out_n <= r.trdy;
pcio.pci_ctrl_en_n <= r.oe_ctrl;
pcio.pci_stop_out_n <= r.stop;
pcio.pci_devsel_out_n <= r.devsel;
pcio.pci_par_out <= r.par;
pcio.pci_par_en_n <= r.oe_par;
pcio.pci_perr_out_n <= '1';
pcio.pci_perr_en_n <= '1';
pcio.pci_serr_out_n <= '1';
pcio.pci_serr_en_n <= '1';
pcio.pci_int_out_n <= '1';
pcio.pci_int_en_n <= '1';
pcio.pci_req_en_n <= '1';
pcio.pci_req_out_n <= '1';
pcio.pci_frame_en_n <= '1';
pcio.pci_frame_out_n <= '1';
pcio.pci_irdy_en_n <= '1';
pcio.pci_irdy_out_n <= '1';
pcio.pci_lock_en_n <= '1';
ahbso.hready <= '1';
ahbso.hresp <= HRESP_OKAY;
ahbmst0 : ahbmst port map (rst, clk, dmai, dmao, ahbmi, ahbmo);
end;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?