library ieee; use ieee.std_logic_1164.all; use work.std_arith.all; entity pcimas is port( clk: in std_logic; -- PCI clock (input) efi: in std_logic; -- empty FIFO (input) eqi: in std_logic; -- previous address and current address are equal gnti: in std_logic; -- PCI grant (input) areni: inout std_logic; -- FIFO address read enable dren0i: inout std_logic; -- FIFO data read enable for the lower 64 bit FIFOs dren1i: inout std_logic; -- FIFO data read enable for the upper 64 bit FIFOs reqi: inout std_logic; -- request PCI bus framei: inout std_logic; -- PCI frame signal tboei: inout std_logic; -- translation buffer output enable (MBaddr->PCI addr) oeai: inout std_logic; -- output enable for the address FIFOs oed0i: inout std_logic; -- output enable for the lower 64 bit data FIFOs oed1i: inout std_logic; -- output enable for the upper 64 bit data FIFOs irdyi: inout std_logic; -- PCI initiator ready signal trdyi: in std_logic; -- PCI target ready signal (input) adder_lth: inout std_logic; -- latches the current address for the adder adder_oei: inout std_logic; -- enables the output of the adder on the PCI bus addr_lth: inout std_logic; -- latches the address on the adder tbwei: out std_logic; -- translation buffer write enable stopi: in std_logic; -- PCI stop (input) cbei: out std_logic_vector(7 downto 0); -- PCI control lines req64i: out std_logic; -- PCI request 64 bit line inctl: inout std_logic; -- signals that the cpld is in control (active) mas_inctli:inout std_logic; -- parhigh0: in std_logic; -- input for parity calculation (input for par64) parhigh1: in std_logic; -- input for parity calculation (input for par64) parhigh2: in std_logic; -- input for parity calculation (input for par64) parhigh3: in std_logic; -- input for parity calculation (input for par64) mas_en: in std_logic; -- enable this cpld if high, otherwise stay in reset par64: inout std_logic -- parity output for the upper 32 PCI bits. ); attribute pin_numbers of pcimas:entity is "cbei(0):36 cbei(1):40 cbei(2):43 cbei(3):37 " & "cbei(4):42 cbei(5):38 cbei(6):41 cbei(7):39 " & "oeai:26 oed0i:29 oed1i:25 dren1i:27 dren0i:24 " & "addr_lth:7 tbwei:18 stopi:4 eqi:17 efi:16 clk:13 " & "adder_oei:9 adder_lth:2 "& "areni:19 gnti:20 reqi:30 inctl:3 framei:31 irdyi:6 trdyi:15 " & "req64i:28 tboei:5 " & "parhigh3:10 parhigh2:32 parhigh1:33 parhigh0:35 par64:14 " & "mas_en:21 mas_inctli:8"; end pcimas; architecture archpci of pcimas is type states is (IDLE,LATCH,READY,ADDR,DATA0,DATA1); attribute state_encoding of states: type is one_hot_one; signal state: states; -- the states of our state machine signal pre_fth: std_logic; -- 1 if we have pre-fetched the next address -- 0 if we have not (and want to do so) signal zframei,zirdyi,zreq64i,ztboei,ztbwei: std_logic; signal zcbei: std_logic_vector(7 downto 0); signal zpar64,par0_d,par1_d,par2_d,par3_d: std_logic; signal par64oe,tbwe_inctl, retryi: std_logic; signal intefi: std_logic; -- internal empty flag -- the empty flag may change while we are in a state. This could lead -- to unpredicatble results if we are not careful. Therefore only use -- efi to fill intefi. Never put efi into the condition of an if statement, -- for example. Always use intefi. begin pci_machine: process(clk,mas_en) begin if (mas_en='0') then -- this is the same as "reset". As long as the cpld is not enabled, -- it will keep resetting itself. -- this might not be pretty, but it gives us one additional pin to use -- for the FIFO read enables. state<=IDLE; -- areni <='1'; -- we can't reset this one, but I guess it should be ok. zframei<='1'; zreq64i<='1'; ztboei<='1'; reqi<='1'; zirdyi<='1'; oeai<='1'; oed0i<='1'; oed1i<='1'; adder_lth<='0'; addr_lth <='0'; adder_oei<='1'; -- areni <='1'; -- for some reason leaving this in fails the device fitting. dren0i<='1'; dren1i<='1'; inctl<='0'; tbwe_inctl<='0'; mas_inctli<='1'; par64oe<='0'; intefi <= '0'; retryi<='1'; elsif (clk'event and clk='1') then -- this is were all the action is concentrated. -- In this state machine, data from the MBus is put onto the PCI bus and -- from there through the CIA into main memory. -- Change state each pci clk cycle. case state is when IDLE=> -- wait for empty flag to go high, or retry a transfer inctl <= '0'; mas_inctli <= '1'; par64oe <= '0'; adder_oei <= '1'; ztbwei <= '1'; -- do something if: -- the FIFOs have some data in them -- (and we are allowed to take it). This is the method by -- which DMA gets started. -- or if we are supposed to retry sending data because previously -- we had gotten a stop on the PCI bus. -- or if we had pre-fetched an address that didn't agree with the -- previous address. if ((intefi='1' and mas_en='1') or retryi='0' or pre_fth='1') then reqi <= '0'; -- request the PCI bus -- get the first pieces of address and data to the FIFO output lines: areni <= pre_fth or (not retryi); -- enable reading the address FIFO dren0i <= (not retryi); -- enable reading the data FIFOs dren1i <= (not retryi); -- enable reading the other 4 data FIFOs state <= LATCH; else areni <= '1'; dren0i <= '1'; dren1i <= '1'; reqi <= reqi; tbwe_inctl <= '0'; -- this comes from the PREIDLE state. intefi <= efi; state <= state; end if; when LATCH=> -- latch address for lookahead (unless in retry ) tbwe_inctl <= '0'; addr_lth <= retryi; ztboei <= '0'; mas_inctli <= '0'; areni <= '1'; dren0i <= '1'; dren1i <= '1'; state <= READY; when READY=> -- wait to get PCI bus, when granted bus assert address and frame* addr_lth <= '0'; if (gnti='0' and framei='1' and irdyi='1')then -- we have been granted access to the PCI bus. -- assert the corresponding signals, put the address on the -- PCI bus and get ready to transfer data. inctl <= '1'; tbwe_inctl <= '1'; oeai <= '0'; adder_oei <= '1'; zframei <= '0'; zreq64i <= '0'; zcbei <= b"00000111"; intefi <= efi; -- update the internal empty flag as late as possible state <= ADDR; else -- ... still waiting for the PCI bus ... inctl <= inctl; tbwe_inctl <= tbwe_inctl; oeai <= oeai; adder_oei <= adder_oei; zcbei <= zcbei; state <= state; end if; when ADDR=> -- address has been latched by CIA, now assert irdy*, data0 oeai <= '1'; par64oe <= '1'; oed0i <= '0'; zirdyi <= '0'; adder_lth <= '1'; zcbei <= b"00000000"; -- do a look-ahead on the address here, since we know -- that at this point, address and data FIFOs are in synch. -- (or course, only if we have something and we are not retrying. areni <= (not intefi) or (not retryi); -- set the pre_fth variable to keep track of this, -- but only if we are not retrying. -- if we are not retrying, we should not update pre_fth. if(retryi='1') then pre_fth <= intefi; end if; state <= DATA0; when DATA0=> -- if trdy* is low, data has been transferred -- if trydy (or stop) is high, wait in this state ztboei <= '1'; intefi <= efi; -- update the internal empty FIFO flag areni <= '1'; dren0i <= '1'; dren1i <= '1'; adder_lth <= '0'; adder_oei <= '0'; -- if (stopi='0' or (trdyi='0' and (intefi = '0' or eqi='1')) ) then if (stopi='0' or (trdyi='0' and (pre_fth = '0' or eqi='1')) ) then -- end the PCI cycle if someone else asserted stop on the PCI bus -- (this would come from the CIA), -- or if (while target ready is still low) the FIFOs are empty -- or the next address is not the same as the current one. zframei <= '1'; zreq64i <= '1'; reqi <= '1'; elsif (trdyi='0') then dren0i <= '0'; -- read next lower 64 bits of the data end if; if (stopi='0' or trdyi='0') then oed0i <= '1'; -- turn off oe for lower 64 bits and on for upper 64 oed1i <= '0'; ztbwei <= trdyi; retryi <= stopi; -- added 5/7/01 state<= DATA1; else oed0i <= oed0i; oed1i <= oed1i; ztbwei <= ztbwei; state <= state; end if; when DATA1=> if (trdyi='0' and framei='0')then -- we are still in the burst, get the next data dren0i <= '1'; dren1i <= '0'; -- only get the next-to-next address if there is anything areni <= (not intefi); pre_fth <= intefi; oed1i <= '1'; oed0i <= '0'; ztbwei <= '1'; adder_lth <= '1'; state <= DATA0; elsif ((stopi='0' or trdyi='0') and framei='1') then -- we just stopped the burst in DATA0. dren0i <= '1'; zirdyi <= '1'; oed1i <= '1'; ztbwei <= '1'; adder_lth <= '0'; intefi <= efi; -- sample the empty FIFO flag to speed things up -- pre_fth <= (not stopi); -- . state <= IDLE; else areni <= '1'; dren0i <= '1'; dren1i <= '1'; pre_fth <= pre_fth; oed1i <= oed1i; oed0i <= oed0i; ztbwei <= ztbwei; zirdyi <= zirdyi; state <= state; end if; when OTHERS=> state <= IDLE; end case; end if; end process pci_machine; tboe_tri:process(mas_inctli,ztboei) begin if (mas_inctli='0') then tboei<=ztboei; else tboei<='Z'; end if; end process tboe_tri; tbwe_tri:process(tbwe_inctl,ztbwei) begin if (tbwe_inctl='1') then tbwei<=ztbwei; else tbwei<='Z'; end if; end process tbwe_tri; pci_tri: process(inctl,zframei,zirdyi,zreq64i,zcbei) begin if (inctl='1') then framei<=zframei; irdyi<=zirdyi; req64i<=zreq64i; cbei<=zcbei; else framei<='Z'; irdyi<='Z'; req64i<='Z'; cbei<=(others=>'Z'); end if; end process pci_tri; zpar64 <= par0_d xor par1_d xor par2_d xor par3_d; par64_ff: process(clk) begin if (clk'event and clk='1') then par0_d<=parhigh0; par1_d<=parhigh1; par2_d<=parhigh2; par3_d<=parhigh3; end if; end process par64_ff; par64_tri: process(par64oe,zpar64) begin if (par64oe='1') then par64<=zpar64; else par64<='Z'; end if; end process par64_tri; end archpci;