pci_mtf.vhd

来自「The GRLIB IP Library is an integrated se」· VHDL 代码 · 共 1,463 行 · 第 1/4 页

VHD
1,463
字号
        readt_dly := '1';        if r.t.msel = '1' then          v.t.wdel := (fifort_limit and r2.m.fifo.side) or r.t.lwrite;          v.t.fifo.raddr := r.t.fifo.raddr + (r.t.read and not fifort_limit and t_valid);        end if;      end if;      if write_access = '1' then        v.t.fifo.waddr := r.t.fifo.waddr + (r.t.msel and not r.t.read and not ben_err);        t_fifo_write := r.t.msel;        v.t.addr := r.t.addr + ((r.t.csel and not r.t.read) & "00");      end if;      tabort := habort;    else v.t.wdel := '0'; end if;    -- Config space read access    case r.t.addr(7 downto 2) is    when "000000" =>      -- 0x00, device & vendor id      cdata := conv_std_logic_vector(DEVICE_ID, 16) &      conv_std_logic_vector(VENDOR_ID, 16);    when "000001" =>      -- 0x04, status & command      cdata(1) := r.comm.men; cdata(2) := r.comm.msen;      cdata(4) := r.comm.mwie; cdata(6) := r.comm.per;      cdata(24) := r.stat.dped; cdata(26) := '1';      cdata(27) := r.stat.sta; cdata(28) := r.stat.rta;      cdata(29) := r.stat.rma; cdata(31) := r.stat.dpe;    when "000010" =>      -- 0x08, class code & revision      cdata(31 downto 8) := conv_std_logic_vector(16#0B4000#,24);    when "000011" =>      -- 0x0C, latency & cacheline size      cdata(7 downto 0) := r.cline;      cdata(15 downto 8) := r.ltim;    when "000100" =>      -- 0x10, BAR0      cdata(31 downto MADDR_WIDTH) := r.bar0;    when "000101" =>      -- 0x14, BAR1      cdata(31 downto DMAMADDR_WIDTH) := r.bar1;    when "001111" =>      -- 0x3C, Interrupts & Latency timer settings      cdata(7 downto 0) := r.intline; -- Interrupt line      cdata(8) := '1'; -- Use interrupt pin INTA#      if fifodepth < 11 then cdata(fifodepth+13) := '1'; end if; --Define wanted burst period    when others =>    end case;    -- Config space write access    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 (r.t.csel and write_access) = '1' then      case r.t.addr(7 downto 2) is      when "000001" =>      -- 0x04, status & command        v.comm.men := cwdata(1);        if MASTER = 1 then v.comm.msen := cwdata(2); end if;        v.comm.mwie := cwdata(4); v.comm.per := cwdata(6);        v.stat.dped := r.stat.dped and not cwdata(24); -- Sticky bit        v.stat.sta := r.stat.sta and not cwdata(27); -- Sticky bit        v.stat.rta := r.stat.rta and not cwdata(28); -- Sticky bit        v.stat.rma := r.stat.rma and not cwdata(29); -- Sticky bit        v.stat.dpe := r.stat.dpe and not cwdata(31); -- Sticky bit      when "000011" =>      -- 0x0c, latency & cacheline size        if FIFO_DEPTH <= 7 then v.cline(FIFO_DEPTH - 1 downto 0) := cwdata(FIFO_DEPTH - 1 downto 0);        else v.cline := cwdata(7 downto 0); end if;        v.ltim := cwdata(15 downto 8);      when "000100" =>      -- 0x10, BAR0        v.bar0 := cwdata(31 downto MADDR_WIDTH);        if v.bar0 = zero(31 downto MADDR_WIDTH) then v.bar0_conf := '0'; else v.bar0_conf := '1'; end if;      when "000101" =>      -- 0x14, BAR1        v.bar1 := cwdata(31 downto DMAMADDR_WIDTH);        if v.bar1 = zero(31 downto DMAMADDR_WIDTH) then v.bar1_conf := '0'; else v.bar1_conf := '1'; end if;      when "001111" =>  -- 0x3C, Interrupts & Latency timer settings        v.intline := cwdata(7 downto 0); -- Interrupt line      when others =>      end case;    end if;    -- Page bar write    if (r.t.psel and write_access) = '1' then v.page := pr.ad(31 downto MADDR_WIDTH - 1); end if;    -- Command and address decode    case pr.cbe is    when CONF_READ | CONF_WRITE =>      if pr.ad(1 downto 0) = "00" then chit := '1'; end if;      if pr.host = '0' then --Active low        if pr.ad(31 downto 11) = "000000000000000000000" then hosthit := '1'; end if;      end if;    when MEM_READ | MEM_WRITE =>      if pr.ad(31 downto MADDR_WIDTH) = r.bar0 then        phit := r.bar0_conf and pr.ad(MADDR_WIDTH - 1);        mhit0 := r.bar0_conf and not pr.ad(MADDR_WIDTH - 1);      elsif pr.ad(31 downto DMAMADDR_WIDTH) = r.bar1 then        mhit1 := r.bar1_conf;      end if;    when MEM_R_MULT | MEM_R_LINE | MEM_W_INV =>      if pr.ad(31 downto MADDR_WIDTH - 1) = r.bar0 & '0' then mhit0 := r.bar0_conf;      elsif pr.ad(31 downto DMAMADDR_WIDTH) = r.bar1 then mhit1 := r.bar1_conf; end if;    when others => phit := '0'; mhit0 := '0'; chit := '0'; mhit1 := '0';    end case;    -- Hit detect    hit := r.t.csel or r.t.msel or r.t.psel;    if (hstart and r.pci.devsel) = '1' then      if (r.t.pending or r.t.lwrite) = '0' then        hstart := not hstart_ack;        v.t.fifo.raddr := (others => '0');      end if;    end if;    -- Target timeout counter    if (hit and pr.trdy and not (pr.frame and pr.irdy)) = '1' then      if r.t.cnt /= "000" then v.t.cnt := r.t.cnt - 1;      else tto := '1'; end if;    else v.t.cnt := (0 => '0', others => '1'); end if;    -- Ready to transfer data    if ((r.t.csel and not readt_dly) or r.t.psel) = '1'       or ((((memwrite and not r.pci.devsel) = '1')       or (memread = '1' and not (hstart_ack and v.t.wdel) = '1')) and ben_err = '0')       then ready := '1'; else ready := '0'; t_read_side := r.t.read and not hstart; end if;    -- Terminate current transaction    if (((r.t.fifo.waddr >= (FIFO_FULL - "10") and r.t.fifo.side = '1')    or (t_valid = '0') or r.pci.stop = '0') and pcii.frame = '0')    or ((r.t.read xor r.t.lwrite) = '0' and r.pci.devsel = '0')    or (tto = '1') or (ben_err = '1')    then term := '1'; else term := '0'; end if;    -- Retry transfer    if r.t.state = b_busy then      if not ((r.t.read and not r.t.lwrite and hstart_ack and read_match) = '1'      or (r.t.read or hstart or hstart_ack) = '0'      or ((r.t.csel or r.t.psel) and not hstart and not hstart_ack) = '1')      then retry := '1'; end if;    end if;    -- target state machine    case r.t.state is    when idle  =>      if pr.frame = '0' then v.t.state := b_busy; end if; -- !HIT ?      v.t.addr := pr.ad;      if readpref = 1 then v.t.burst := '1';      else v.t.burst := pr.cbe(3); end if;      v.t.read := not pr.cbe(0); v.t.mult := not pr.cbe(1);      v.t.csel := (pr.idsel or hosthit) and chit; v.t.psel := phit;      v.t.msel := r.comm.men and (mhit0 or mhit1); v.t.barsel := mhit1;    when turn_ar =>      if pr.frame = '1' then v.t.state := idle;      else v.t.state := b_busy; end if; -- !HIT ?      v.t.addr := pr.ad; v.t.wdel := '1';      if readpref = 1 then v.t.burst := '1';      else v.t.burst := pr.cbe(3); end if;      v.t.read := not pr.cbe(0); v.t.mult := not pr.cbe(1);      v.t.csel := (pr.idsel or hosthit) and chit; v.t.psel := phit;      v.t.msel := r.comm.men and (mhit0 or mhit1); v.t.barsel := mhit1;    when b_busy  =>      if (pr.frame and pr.irdy) = '1' then v.t.state := idle;      elsif hit = '1' then v.t.state := s_data;        v.t.fifo.raddr := r.t.fifo.raddr + (r.t.read and r.t.msel); readt_dly := '1';        if r.t.pending = '0' then v.t.pending := retry and not hstart_ack; end if;      else v.t.state := backoff; end if;    when s_data  =>      if r.t.pending = '1' then v.t.pending := not ((habort or not r.pci.trdy) and read_match); end if;      if (pcii.frame = '0' and r.pci.stop ='0' and (r.pci.trdy or not pcii.irdy) = '1') then        v.t.state := backoff;        if r.t.last = '0' then v.t.last := r.t.msel and r.t.lwrite and v.t.wdel; end if;        v.t.fifo.raddr := r.t.fifo.raddr - (r.t.read and r.t.msel and not fifort_limit);      elsif (pcii.frame = '1' and (r.pci.trdy = '0' or r.pci.stop = '0')) then        v.t.state := turn_ar;        if r.t.last = '0' then v.t.last := r.t.msel and r.t.lwrite and v.t.wdel; end if;        v.t.fifo.raddr := r.t.fifo.raddr - (r.t.read and r.t.msel and not fifort_limit);      end if;    when backoff =>      if pcii.frame = '1' then v.t.state := turn_ar; end if;    end case;    -- #TRDY assert    if (v.t.state = s_data and habort = '0' and ready = '1' and retry = '0') then v.pci.trdy := '0'; end if;    -- #STOP assert    if (v.t.state = backoff or (v.t.state = s_data and ((tabort or ((term or retry) and not habort)) = '1'))) then      v.pci.stop := '0'; end if;    -- #DEVSEL assert    if (((v.t.state = backoff and r.pci.devsel = '0') or v.t.state = s_data) and (read_match and tabort) = '0') then v.pci.devsel := '0'; end if;    -- Enable #TRDY, #STOP and #DEVSEL    if (v.t.state = s_data) or (v.t.state = backoff) or (v.t.state = turn_ar) then      v.pci.oe_ctrl := not hit;    else v.pci.oe_ctrl := '1'; end if;    -- Signaled target abort    if (r.pci.devsel and not (r.pci.stop or r.pci.oe_ctrl)) = '1' then v.stat.sta := '1'; end if;    -- Latched signals to AHB backend    if (r.t.state = b_busy) then      if (hstart or hstart_ack) = '0' then -- must be idle        v.t.lwrite := not r.t.read;        case pr.cbe is        when "0000" => v.t.lsize := "10";        when "1100" => v.t.lsize := "01";        when "1110" => v.t.lsize := "00";        when others => v.t.lsize := "10";        end case;        if r.t.msel = '1' then          v.t.lburst := r.t.burst;          if r.t.barsel = '0' then v.t.laddr := r.page & r.t.addr(MADDR_WIDTH-2 downto 0);          else  v.t.laddr := r2.dmapage & r.t.addr(DMAMADDR_WIDTH-1 downto 0); end if;          v.t.lmult :=  r.t.mult;          rtdone := '0'; v.t.fifo.waddr := (others => '0');          hstart := r.t.read and r.t.msel;        end if;      end if;    end if;    -- Read data mux    if r.t.csel = '1' then tad := cdata;    elsif r.t.psel = '1' then      tad(31 downto MADDR_WIDTH-1) := r.page;      tad(MADDR_WIDTH-2 downto 0) := zero32(MADDR_WIDTH-2 downto 0);    elsif (r.t.state = b_busy or (r.pci.trdy or pcii.irdy) = '0') then tad := fifo1o.rdata(31 downto 0);    end if;    -- FIFO controller    if ((fifowt_limit and write_access) = '1' or (r.t.last or rtdone) = '1') then      if hstart = hstart_ack then        if rtdone = '0' then hstart := not hstart_ack; v.t.fifo.side := hstart; end if;        if r.t.last = '1' then rtdone := '1'; v.t.last := '0';        else v.t.fifo.waddr := (others => '0');          if rtdone = '1' then            rtdone := '0'; hstart := '0'; v.t.fifo.side := '0';          end if;        end if;      end if;    end if;    if (fifort_limit and v.t.wdel) = '1' then      if hstart_ack = '1' then hstart := '0'; v.t.fifo.raddr := (others => '0');      else v.t.fifo.raddr := (others => '0'); end if;    end if;----- *** PCI TARGET END*** ------------- *** PCI MASTER *** --------  if MASTER = 1 then    bus_idle := pcii.frame and pcii.irdy;    data_transfer := not (pcii.trdy or r.pci.irdy);    data_transfer_r := not (pr.trdy or pr.irdy);    data_phase := not ((pcii.trdy and pcii.stop) or r.pci.irdy);    targ_d_w_data := not (pr.stop or pr.trdy);    targ_abort := pr.devsel and not pr.stop;    -- Request from AHB backend to start PCI transaction    if (pstart and not pstart_ack) = '1' then      if (r.m.fstate = idle and r.m.request = '0') then        v.m.request := '1';        rmdone := '0'; v.m.valid := '1';        v.m.fifo.waddr := (others => '0');        v.m.hwrite := r2.s.pcicomm(0);      end if;    end if;    -- Master timeout and DEVSEL timeout    if ((pr.irdy and not pr.frame) or (pr.devsel and not r.pci.oe_frame)) = '1' then      if r.m.cnt /= "000" then v.m.cnt := r.m.cnt - 1;      else mto := '1'; end if;    else v.m.cnt := (others => '1'); end if;    -- Latency counter    if r.pci.frame = '0' then      if r.m.ltim > "00000000" then v.m.ltim := r.m.ltim - '1';      else lto := '1'; end if;    else      v.m.ltim := r.ltim;    end if;    -- Last data    case r2.s.pcicomm is    when MEM_R_MULT | MEM_R_LINE =>      if (r.m.fifo.waddr >= (FIFO_FULL - "10") and r.m.fifo.side = '1') then        comp := '1';      else comp := '0'; end if;    when MEM_WRITE | MEM_W_INV => comp := not r.m.valid;    when others => comp := '1';    end case;    -- Minimun latency    if lto = '0' then grant := '0'; end if;    -- Data parity error detected    if (r.m.fstate /= idle and r.stat.dped = '0') then v.stat.dped := r.comm.per and not pcii.perr; end if;    -- FIFO control state machine    case r.m.fstate is    when idle =>      if (r.m.request and bus_idle and not pcii.gnt) = '1' and (r.m.state = idle or r.m.state = dr_bus) then        v.m.fstate := addr; v.m.fifo.waddr := (others => '0'); v.m.fifo.side := '0'; m_request := '1';      end if;    when addr =>      if (wsdone = '1' and (r.m.fifo.raddr + '1') = r2.s.fifo.waddr) then v.m.valid := '0'; end if;      if fiform_limit = '1' then v.m.fstate := last1;      else v.m.fstate := incr; end if;      v.m.fifo.raddr := r.m.fifo.raddr + r.m.hwrite;      v.m.first := '1'; v.m.firstw := '1';    when incr =>      d_ready := '1';      if data_transfer = '1' then        if fiform_limit = '1' then v.m.fstate := last1; v.m.split := not backendnr; end if;        if (wsdone = '1' and (r.m.fifo.raddr + pcii.stop) = r2.s.fifo.waddr) then v.m.valid := '0'; end if;        v.m.fifo.raddr := r.m.fifo.raddr + r.m.hwrite;        v.m.first := '0';      end if;      if data_transfer_r = '1' then        if fifowm_stop = '1' then          if r.m.firstw = '1' then            if (fifowm_limit and pr.stop) = '1' then v.m.fifo.side := not r.m.fifo.side; v.m.firstw := '0'; pstart_ack := pstart; end if;          end if;        end if;        v.m.fifo.waddr := r.m.fifo.waddr + (not r.m.hwrite);      end if;      if pr.stop = '0' then        if targ_abort = '1' then v.m.fstate := abort;        elsif targ_d_w_data = '1' then v.m.fstate := ttermwd;        elsif r.m.first = '1' then v.m.fstate := t_retry;        else v.m.fstate := ttermnd; end if;      elsif mto = '1' then v.m.fstate := abort;      elsif grant = '1' then        if r.m.hwrite = '0' then rmdone := not r.m.fifo.side; v.m.fifo.side := '1'; v.m.fstate := done; pstart_ack := pstart;        else v.m.fstate := idle; end if;      elsif (pr.frame and not r.m.first) = '1' then        if r.m.hwrite = '0' then rmdone := not r.m.fifo.side; v.m.fifo.side := '1'; v.m.fstate := done; pstart_ack := pstart;        else v.m.fstate := done; pstart_ack := pstart; end if;      elsif (pr.devsel and not r.m.first) = '1' then        if r.m.hwrite = '0' then rmdone := not r.m.fifo.side; v.m.fifo.side := '1'; v.m.fstate := done; pstart_ack := pstart;        else v.m.fstate := idle; end if;      end if;    when last1 =>      if (pr.trdy and not pr.stop) = '1' then        if targ_abort = '1' then v.m.fstate := abort;        elsif targ_d_w_data = '1' then v.m.fstate := ttermwd;        else v.m.fstate := ttermnd; v.m.valid := '1'; end if;      elsif (pr.frame and not r.m.first and not r.m.split) = '1' then v.m.fstate := done; rmdone := not r.m.fifo.side; pstart_ack := pstart;      elsif data_transfer = '1' then        if r.m.valid = '1' then v.m.fstate := sync; pstart_ack := pstart;        else v.m.fstate := done; rmdone := not r.m.fifo.side; pstart_ack := pstart; end if;      else d_ready := '1';      end if;    when sync =>      if pstart = not pstart_ack then        v.m.split := '0';        if ((r.m.split or (pr.trdy and not pr.stop and not r.m.split))  = '1' or r.m.state /= m_data) then v.m.fstate := idle; d_ready := '1';        else          if (wsdone = '1' and (r.m.fifo.raddr + '1') = r2.s.fifo.waddr) then v.m.valid := '0'; end if;          v.m.fstate := incr; data_transfer := '1'; v.m.fifo.raddr := r.m.fifo.raddr + r.m.hwrite; d_ready := '1';        end if;      else m_read_side := '1';      end if;    when t_retry => v.m.fifo.raddr := r.m.fifo.raddr - r.m.hwrite; v.m.fstate := idle;    when ttermwd =>      if data_transfer = '1' then v.m.fifo.raddr := r.m.fifo.raddr + r.m.hwrite;      elsif pr.trdy = '1' then v.m.fifo.raddr := r.m.fifo.raddr - r.m.hwrite;        if (r.m.hwrite and r.m.valid) = '1' then v.m.fstate := idle;        else v.m.fstate := done; rmdone := not r.m.fifo.side; v.m.fifo.side := '1'; pstart_ack := pstart; end if;      end if;    when ttermnd =>

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?