OpenCores
URL https://opencores.org/ocsvn/pci_to_wb/pci_to_wb/trunk

Subversion Repositories pci_to_wb

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /pci_to_wb
    from Rev 1 to Rev 2
    Reverse comparison

Rev 1 → Rev 2

/trunk/PCI_to_WB.vhd
0,0 → 1,603
--+------------------------------------------------------------------+
--| |
--| PCI_TARGET -> Wishbone_MASTER interface (PCI_to_WB) v1.9 |
--| |
--| The first, original PCI module is from: |
--| Ben Jackson, http://www.ben.com/minipci/verilog.php |
--| |
--| The second, modified module "pci_mini" is from: |
--| Istvan Nagy, buenos@freemail.hu |
--| |
--| |
--| DOWNLOADED FROM OPENCORES. License = LGPL. |
--| |
--+------------------------------------------------------------------+
--| I used the code of the original pci_mini module to create |
--| a PCI to WB interface with direct read accesses (not |
--| like before, where data would be available only on |
--| a second PCI read) because that didn't work in my system. |
--| Thanks to Ben Jackson and Istvan Nagy for their works! |
--| I would not have been able to design such a core without |
--| the provided code base. |
--| Nelson Scheja (Lord_Nelson@opencores.org). |
--+------------------------------------------------------------------+----------------------------+
-- ########## General info ##########
 
-- The core implements a 16 MB memory image which is relocable on the WB bus:
-- WB_address = 4 * baseaddr + PCI_addr[23:2], where baseaddr is the WB image relocation
-- register (BAR0).
-- Only Dword aligned Dword accesses are allowed on the PCI. This way we can have access to the
-- full 32 bit WB address space through a 16 MB PCI window. The addressing on the WB bus is
-- Dword addressing, while on the PCI bus, it is byte addressing: PCI_addr / 4 = WB_address.
-- That means, when the PCI address is increasing by 4 ( = 4 Bytes = 1 Dword), the WB address
-- is increasing by 1 ( = 1 Dword, too).
 
-- Nearly full Wishbone compatible; single exception is master arbitration (through signals
-- wb_req and wb_gnt) which is not implemented.
 
-- (Remember, most PCI signals are active low, so I call them "asserted" when they are 0!
-- Only exceptions are clk, idsel and par, which are active high.)
 
-- The duration of a complete PCI cycle depends on the PCI command and the reaction time of the
-- PCI master and the addressed WB slave. Generally, Memory Reads need the most time to complete
-- (as the data path is the longest), and Config Writes are fastest.
 
 
-- ########## PCI bus support ##########
 
-- Intended PCI operation mode is 33 MHz, 32 bit.
 
-- Supported PCI commands are Config Read / Write, Memory Read / Write. Only single Dword
-- accesses are supported. (As the cbe bits are ignored for MemRead and MemWrite, a full DWord
-- is always transferred on these commands. Still, Byte or Word accesses are not recommended.)
 
-- The core supports only single reads / writes, that means only one data phase per PCI
-- cycle. Bursts are not allowed. In the first data phase, it asserts the stop signal
-- together with trdy to enforce a so-called "target initiated disconnect". This makes sure
-- that the PCI master will never try to extend a cycle past the first data phase.
 
-- When no WB response has been sent for WB_MAX_LAT clock cycles during a MemRead or MemWrite,
-- the core signals "Target-Abort" to the master. WB_MAX_LAT is user-definable in the range
-- from 0h to Fh.
 
-- DEVSEL timing is "fast". That means, devsel will be asserted the next clock edge after the
-- assertion of frame.
 
-- Parity of outgoing data is generated (one clock cycle after driving the ad lines). Parity
-- check of incoming address/data is not implemented. Thus, perr is held in high impedance the
-- whole time.
 
-- System Error indication is not implemented, thus serr is high impedance the whole time.
 
 
-- ########## Wishbone bus support ##########
 
-- Implemented Wishbone signals: wb_adr_o, wb_dat_o, wb_dat_i, wb_sel_o, wb_cyc_o, wb_stb_o,
-- wb_we_o, wb_ack_i, wb_err_i.
-- Not implemented Wishbone signals: clk, rst, rty, req, gnt, lock, stall, tag signals.
 
-- The signals wb_rst and wb_clk are not generated as this is actually the job of the Syscon
-- module and should be done outside this core. Still, it could come in handy to use the core
-- also as Syscon, so these two ports and their processes are only commented out and can be
-- quickly reactivated if necessary.
 
-- Attention! The core was intended for a Wishbone bus scenario where it is the only master.
-- Thus, no arbitration methods are supported, which actually is not 100% WB compatible. Do not
-- put another master on the same WB bus as this core! The advantage is fewer logic units and
-- faster bus cycles (because the core asserts wb_cyc and wb_stb at the same time and doesn't
-- have to wait for a grant in between).
 
-- Supported commands are single read / write. Pipelined mode is not supported.
 
-- All bits of the signal wb_sel are always driven high during normal operation because all WB
-- accesses use 4 Bytes. Only when reset is asserted, wb_sel = 0000.
 
 
-- ########## Device Compatibility ##########
 
-- The core was tested and used on a Xilinx Spartan3 XC3S1000 FT256-4. The PCI master was a
-- MPC5200 microcontroller.
 
-- There are no Xilinx-specific components defined in the code, so theoretically it should be
-- compatible to FPGAs of all developers.
 
-- Utilization (extract from Xilinx ISE Map Report): Slices 183; Slice Reg 143; LUTs 194.
 
-- The IEEE library numeric_std is used.
 
 
-- ########## Change log ##########
 
-- Merged PCI state machine, WB state machine and Address decoder into a single big process to
-- allow faster PCI reaction and reduce amount of signals.
-- Made the interrupt asynchronously to clk to ensure fastest possible interrupt generation.
-- In Config cycles, it is now paid attention to the Byte Enable bits cbe.
-- Target-Abort is generated when no response (ack or err) has come from the Wishbone for
-- WB_MAX_LAT clock cycles.
-- Completely modified the internal structure of the config signals.
-- Made the interrupt port information configurable via generic.
-- Removed everything that's got to do with interrupts, as an INTA pin is not mandatory for PCI
-- and WB has no definition of an interrupt request protocol.
-- Realized main_state signal (formerly pci_state) as an enum type and let it also control all
-- the sub states (deleted former sub_state).
 
 
-- ########## ToDos / Problems ##########
 
-- Implement parity check?
-- Implement WB byte select?
-- Check WB Timeout counter accuracy! Don't know whether the cycle count is perfectly correct.
-- Assertion of trdy and stop lasts for about 10 clock cycles when scoped in reality! Reason
-- unclear, maybe an effect due to the slow pullups?
-- Uncorrect handling of wb_err assertion (it seems)! Stop isn't asserted sometimes.
--+-----------------------------------------------------------------------------------------------+
 
library ieee;
use ieee.STD_LOGIC_1164.all;
use ieee.numeric_std.all;
 
 
entity pci_to_wb is
port(
--PCI signals
reset : in std_logic;
clk : in std_logic;
frame : in std_logic;
irdy : in std_logic;
trdy : out std_logic;
devsel : out std_logic;
idsel : in std_logic;
ad : inout std_logic_vector(31 downto 0) := (others => 'Z');
cbe : in std_logic_vector(3 downto 0);
par : inout std_logic := 'Z';
stop : out std_logic;
serr : out std_logic;
perr : out std_logic;
--Wishbone signals
-- wb_clk_o : out std_logic; --uncomment these two signals and their corresponding processes at the
-- wb_rst_o : out std_logic; --beginning of the architecture body to achieve syscon functionality
wb_adr_o : out std_logic_vector(31 downto 0);
wb_dat_o : out std_logic_vector(31 downto 0);
wb_dat_i : in std_logic_vector(31 downto 0);
wb_sel_o : out std_logic_vector(3 downto 0) := "0000";
wb_cyc_o : out std_logic := '0';
wb_stb_o : out std_logic := '0';
wb_we_o : out std_logic := '0';
wb_ack_i : in std_logic;
wb_err_i : in std_logic
);
end pci_to_wb;
 
 
architecture Behavioral of pci_to_wb is
--+------------------------------------------------------------------------------------+
--| Constants |
--+------------------------------------------------------------------------------------+
--user specific constants. Change them at your will.
constant DEVICE_ID : std_logic_vector := x"1337"; --It's leet. Yo.
constant VENDOR_ID : std_logic_vector := x"1234";
constant DEVICE_CLASS : std_logic_vector := x"118000"; --(068000=bridge/other, 078000=simple_comm_contr/other, 118000=data_acquisition/other)
constant DEVICE_REV : std_logic_vector := x"09"; --version of the PCI to WB module
constant SUBSYSTEM_ID : std_logic_vector := x"0001"; --card identifier
constant SUBSYSTEM_VENDOR_ID : std_logic_vector := x"9876";
constant WB_MAX_LAT : unsigned := x"4"; --defines how many clock cycles the WB has time to answer to wb_stb before Target-Abort is activated
-- supported PCI commands
constant CFGREAD : std_logic_vector := "1010";
constant CFGWRITE : std_logic_vector := "1011";
constant MEMREAD : std_logic_vector := "0110";
constant MEMWRITE : std_logic_vector := "0111";
--+------------------------------------------------------------------------------------+
--| Internal signals |
--+------------------------------------------------------------------------------------+
-- state machine flow
type main_state_type is (Idle, Cfg_read_1, Cfg_read_2, Cfg_write_1, Cfg_write_2,
Mem_read_1, Mem_read_2, Mem_read_3, Mem_write_1, Mem_write_2, Mem_write_3);
signal main_state : main_state_type := Idle;
signal wait_count : unsigned(3 downto 0) := x"0"; --counts up to WB_MAX_LAT while waiting on WB response
signal par_create : std_logic := '0'; --controls the parity generator: when 1, parity is generated, else not
signal pci_address : std_logic_vector(23 downto 2); --latch of AD lines during the address phase (upper 8 and lower 2 of the 32 bits are never used)
-- configuration registers
signal cfg_reg_0x00 : std_logic_vector(31 downto 0) := DEVICE_ID & VENDOR_ID;
signal cfg_reg_0x04 : std_logic_vector(31 downto 0) := x"00000000";
alias target_abort : std_logic is cfg_reg_0x04(27); --Target-Abort status bit (status register)
alias mem_ena : std_logic is cfg_reg_0x04(1); --memory space enable bit (command register)
signal cfg_reg_0x08 : std_logic_vector(31 downto 0) := DEVICE_CLASS & DEVICE_REV;
signal cfg_reg_0x10 : std_logic_vector(31 downto 0) := x"00000000";
alias baseaddr : std_logic_vector(7 downto 0) is cfg_reg_0x10(31 downto 24); --used for relocating the WB address space
signal cfg_reg_0x2c : std_logic_vector(31 downto 0) := SUBSYSTEM_ID & SUBSYSTEM_VENDOR_ID;
begin
--+------------------------------------------------------------------------------------+
--| Small signal processes |
--+------------------------------------------------------------------------------------+
--Wishbone clock and (asynchronous) reset:
-- wb_clk_o <= clk; --uncomment these two processes and their corresponding
-- wb_rst_o <= not reset; --signals in the entity to achieve syscon functionality
--these are not used:
serr <= 'Z';
perr <= 'Z';
--only dword accesses, so wb_sel can always be high (except during reset):
process(reset)
begin
if reset = '0' then
wb_sel_o <= "0000";
else
wb_sel_o <= "1111";
end if;
end process;
--+------------------------------------------------------------------------------------+
--| MAIN STATE MACHINE |
--+------------------------------------------------------------------------------------+
-- This process controls the translation from PCI protocol to Wishbone protocol.
-- It is realized as a state machine with five main states (defined with main_state).
-- Most main states are further divided into sub states (defined with sub_state)
-- to control the flow of execution during a PCI cycle.
process(reset, clk)
begin
if reset = '0' then
main_state <= Idle;
ad <= (others => 'Z');
devsel <= 'Z';
trdy <= 'Z';
stop <= 'Z';
par_create <= '0';
wait_count <= (others => '0');
target_abort<= '0';
mem_ena <= '0';
baseaddr <= (others => '0');
wb_adr_o <= (others => '0');
wb_dat_o <= (others => '0');
wb_cyc_o <= '0';
wb_stb_o <= '0';
wb_we_o <= '0';
elsif rising_edge(clk) then
case main_state is
-- ########## IDLE STATE ##########
-- State for between PCI cycles and during the address phase (which is identified by the
-- assertion of frame). While here, all signals to PCI, WB and internals are in deasserted
-- state. When the core is being addressed correctly by the PCI master, it asserts devsel
-- as response and changes to the state defined by the command bits (cbe).
when Idle =>
trdy <= 'Z';
stop <= 'Z';
devsel <= 'Z';
if frame = '0' then
pci_address <= ad(23 downto 2);
if idsel = '1' and ad(10 downto 8) = "000" and ad(1 downto 0) = "00" then --correct config space access
if cbe = CFGREAD then
devsel <= '0';
main_state <= Cfg_read_1;
elsif cbe = CFGWRITE then
devsel <= '0';
main_state <= Cfg_write_1;
end if;
elsif mem_ena = '1' and ad(31 downto 24) = baseaddr then --correct memory space access
if cbe = MEMREAD then
devsel <= '0';
main_state <= Mem_read_1;
elsif cbe = MEMWRITE then
devsel <= '0';
main_state <= Mem_write_1;
end if;
end if;
end if;
-- ########## CFG READ STATE ##########
-- The config register at the DWord address pci_address is read. Depending on the Byte Enables
-- cbe, the data is provided on ad When cbe(0) = 0, then byte 0 is all zeroes, etc. One
-- clock cycle later, the parity is provided and the PCI cycle is terminated.
--STAGE 1: gather register data internally in the first clock cycle where irdy is asserted
when Cfg_read_1 =>
if irdy = '0' then
case pci_address(7 downto 2) is
when "000000" => --0d*4 = 00h. Device ID (31 - 16), Vendor ID (15 - 0).
if cbe(3) = '0' then
ad(31 downto 24) <= cfg_reg_0x00(31 downto 24);
else
ad(31 downto 24) <= (others => '0');
end if;
if cbe(2) = '0' then
ad(23 downto 16) <= cfg_reg_0x00(23 downto 16);
else
ad(23 downto 16) <= (others => '0');
end if;
if cbe(1) = '0' then
ad(15 downto 8) <= cfg_reg_0x00(15 downto 8);
else
ad(15 downto 8) <= (others => '0');
end if;
if cbe(0) = '0' then
ad(7 downto 0) <= cfg_reg_0x00(7 downto 0);
else
ad(7 downto 0) <= (others => '0');
end if;
when "000001" => --1d*4 = 04h. Status (31 - 16), Command (15 - 0).
if cbe(3) = '0' then
ad(31 downto 24) <= cfg_reg_0x04(31 downto 24);
else
ad(31 downto 24) <= (others => '0');
end if;
ad(23 downto 8) <= (others => '0');
if cbe(0) = '0' then
ad(7 downto 0) <= cfg_reg_0x04(7 downto 0);
else
ad(7 downto 0) <= (others => '0');
end if;
when "000010" => --2d*4 = 08h. Class Code (31 - 8), Revision ID (7 - 0).
if cbe(3) = '0' then
ad(31 downto 24) <= cfg_reg_0x08(31 downto 24);
else
ad(31 downto 24) <= (others => '0');
end if;
if cbe(2) = '0' then
ad(23 downto 16) <= cfg_reg_0x08(23 downto 16);
else
ad(23 downto 16) <= (others => '0');
end if;
if cbe(1) = '0' then
ad(15 downto 8) <= cfg_reg_0x08(15 downto 8);
else
ad(15 downto 8) <= (others => '0');
end if;
if cbe(0) = '0' then
ad(7 downto 0) <= cfg_reg_0x08(7 downto 0);
else
ad(7 downto 0) <= (others => '0');
end if;
when "000100" => --4d*4 = 10h. Base Address Register 0, = baseaddr.
if cbe(3) = '0' then
ad(31 downto 24) <= cfg_reg_0x10(31 downto 24);
else
ad(31 downto 24) <= (others => '0');
end if;
ad(23 downto 0) <= (others => '0');
when "001011" => --11d*4 = 2Ch. Subsystem ID (31 - 16), Subsystem Vendor ID (15 - 0).
if cbe(3) = '0' then
ad(31 downto 24) <= cfg_reg_0x2c(31 downto 24);
else
ad(31 downto 24) <= (others => '0');
end if;
if cbe(2) = '0' then
ad(23 downto 16) <= cfg_reg_0x2c(23 downto 16);
else
ad(23 downto 16) <= (others => '0');
end if;
if cbe(1) = '0' then
ad(15 downto 8) <= cfg_reg_0x2c(15 downto 8);
else
ad(15 downto 8) <= (others => '0');
end if;
if cbe(0) = '0' then
ad(7 downto 0) <= cfg_reg_0x2c(7 downto 0);
else
ad(7 downto 0) <= (others => '0');
end if;
when others => --unsupported or reserved config registers.
ad <= (others => '0');
end case;
trdy <= '0';
stop <= '0';
par_create <= '1';
main_state <= Cfg_read_2;
end if;
--STAGE 2: one clock cycle later, end the PCI cycle
when Cfg_read_2 =>
ad <= (others => 'Z');
devsel <= '1';
trdy <= '1';
stop <= '1';
par_create <= '0';
main_state <= Idle;
-- ########## CFG WRITE STATE ##########
-- The config register at the DWord address pci_address is written, depending on the Byte Enables
-- cbe. Some bits are not writable, so nothing will be changed then. The status register
-- is special: When writing a 1 onto a bit, this bit is cleared; writing a 0 will have no
-- effect. One clock cycle later, the PCI cycle is terminated.
-- STAGE 1: return config values in the first clock cycle where irdy is asserted
when Cfg_write_1 =>
trdy <= '0';
stop <= '0';
if irdy = '0' then
case pci_address(7 downto 2) is
when "000001" => --1d*4 = 04h. Status (31 - 16), Command (15 - 0).
if cbe(3) = '0' and ad(27) = '1' then
target_abort<= '0'; --reset status bit Target-Abort when writing a 1 there
end if;
if cbe(0) = '0' then
mem_ena <= ad(1);
end if;
when "000100" => --4d*4 = 10h. Base Address Register 0 (BAR0).
if cbe(3) = '0' then
baseaddr <= ad(31 downto 24);
end if;
when others => --config registers that are reserved, unsupported or don't support writes.
null;
end case;
main_state <= Cfg_write_2;
end if;
--STAGE 2: one clock cycle later, end the PCI cycle
when Cfg_write_2 =>
devsel <= '1';
trdy <= '1';
stop <= '1';
main_state <= Idle;
-- ########## MEM READ STATE ##########
-- The data to be written and the address is provided for the Wishbone bus. Then,
-- wait for Wishbone response:
-- When ack_i is asserted (= data ready), signal "Disconnect with data" to PCI master,
-- provide the data and one clock cycle later the parity.
-- When err_i is asserted (= access error), signal "Target-Abort". In this case, no
-- data is provided and the third stage is not activated.
-- When neither ack_i nor err_i were asserted for WB_MAX_LAT clock cycles, signal
-- "Target-Abort". The third stage is not activated then, too.
--STAGE 1: save address for Wishbone in the first clock cycle where irdy is asserted and initiate WB action
when Mem_read_1 =>
if irdy = '0' then
wb_adr_o <= "0000000000" & pci_address;
wb_cyc_o <= '1'; --set the Wishbone master signals for a read cycle
wb_stb_o <= '1';
wait_count <= x"0"; --reset timeout counter
main_state <= Mem_read_2;
end if;
--STAGE 2: wait for Wishbone response, react accordingly to the PCI bus and end the WB cycle
when Mem_read_2 =>
if wb_ack_i = '1' then --WB transaction completed
wb_adr_o <= (others => '0');
wb_cyc_o <= '0';
wb_stb_o <= '0';
ad <= wb_dat_i;
trdy <= '0'; --trdy and stop asserted at the same time -> Disconnect
stop <= '0';
par_create <= '1';
main_state <= Mem_read_3;
elsif wb_err_i = '1' or wait_count = WB_MAX_LAT then --WB transaction aborted, or no WB answer for WB_MAX_LAT clock cycles
wb_adr_o <= (others => '0');
wb_cyc_o <= '0';
wb_stb_o <= '0';
devsel <= '1'; --stop asserted and devsel deasserted at the same time -> Target-Abort
stop <= '0';
target_abort <= '1'; --status register entry
main_state <= Idle;
end if;
wait_count <= wait_count + 1; --count the wait cycles
--STAGE 3: one clock cycle later, end the PCI cycle (only after Disconnect)
when Mem_read_3 =>
ad <= (others => 'Z');
devsel <= '1';
trdy <= '1';
stop <= '1';
par_create <= '0';
main_state <= Idle;
-- ########## MEM WRITE STATE ##########
-- The data to be written and the address is provided for the Wishbone bus. Then,
-- wait for Wishbone response:
-- When ack_i is asserted (= data was stored), signal "Disconnect with data" to PCI
-- master and end the PCI cycle on the next clock edge.
-- When err_i is asserted (= access error, no transaction), signal "Target-Abort". In
-- this case, no data was changed and the third stage is not activated.
-- When neither ack_i nor err_i were asserted for WB_MAX_LAT clock cycles, signal
-- "Target-Abort". The third stage is not activated then, too.
--STAGE 1: save write data for WB in the first clock cycle where irdy is asserted and initiate WB action
when Mem_write_1 =>
if irdy = '0' then
wb_adr_o <= x"00" & "00" & pci_address;
wb_dat_o <= ad;
wb_cyc_o <= '1'; --set the Wishbone master signals for a write cycle
wb_stb_o <= '1';
wb_we_o <= '1';
wait_count <= x"0"; --reset timeout counter
main_state <= Mem_write_2;
end if;
--STAGE 2: wait for Wishbone response, react accordingly to the PCI bus and end the WB cycle
when Mem_write_2 =>
if wb_ack_i = '1' then --WB transaction completed
wb_adr_o <= (others => '0');
wb_dat_o <= (others => '0');
wb_cyc_o <= '0';
wb_stb_o <= '0';
wb_we_o <= '0';
trdy <= '0'; --trdy and stop asserted at the same time -> Disconnect
stop <= '0';
main_state <= Mem_write_3;
elsif wb_err_i = '1' or wait_count = WB_MAX_LAT then --WB transaction aborted, or no WB answer for WB_MAX_LAT clock cycles
wb_adr_o <= (others => '0');
wb_dat_o <= (others => '0');
wb_cyc_o <= '0';
wb_stb_o <= '0';
wb_we_o <= '0';
devsel <= '1'; --stop asserted and devsel deasserted at the same time -> Target-Abort
stop <= '0';
target_abort<= '1'; --status register entry
main_state <= Idle;
end if;
wait_count <= wait_count + 1; --count the wait cycles
--STAGE 3: one clock cycle later, end the PCI cycle (only after Disconnect)
when Mem_write_3 =>
devsel <= '1';
trdy <= '1';
stop <= '1';
main_state <= Idle;
-- ########## undefined state ##########
-- This state normally should never occur. Just for completion.
when others =>
main_state <= Idle;
end case;
end if;
end process;
--+------------------------------------------------------------------------------------+
--| Parity generation |
--+------------------------------------------------------------------------------------+
-- This process calcutates the even parity of the ad and cbe lines when par_create is
-- asserted. The main state machine asserts par_create exactly when trdy is asserted
-- in a Read cycle (both Config and Memory). Because this process sees the assertion
-- of par_create only on the following clock edge, parity for the master is always
-- provided one clock cycle delayed to ad (which is required by PCI).
process(reset, clk)
begin
if reset = '0' then
par <= 'Z';
elsif rising_edge(clk) then
if par_create = '1' then
par <= ( ad(31) xor ad(30) xor ad(29) xor ad(28) ) xor
( ad(27) xor ad(26) xor ad(25) xor ad(24) ) xor
( ad(23) xor ad(22) xor ad(21) xor ad(20) ) xor
( ad(19) xor ad(18) xor ad(17) xor ad(16) ) xor
( ad(15) xor ad(14) xor ad(13) xor ad(12) ) xor
( ad(11) xor ad(10) xor ad(9) xor ad(8) ) xor
( ad(7) xor ad(6) xor ad(5) xor ad(4) ) xor
( ad(3) xor ad(2) xor ad(1) xor ad(0) ) xor
( cbe(3) xor cbe(2) xor cbe(1) xor cbe(0) );
else
par <= 'Z';
end if;
end if;
end process;
end Behavioral;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.