//===========================================================================
|
//===========================================================================
|
// $Id: pci_blue_arbiter.v,v 1.1 2002-02-01 13:39:43 mihad Exp $
|
// $Id: pci_blue_arbiter.v,v 1.2 2002-03-21 07:35:50 mihad Exp $
|
//
|
//
|
// Copyright 2001 Blue Beaver. All Rights Reserved.
|
// Copyright 2001 Blue Beaver. All Rights Reserved.
|
//
|
//
|
// Summary: A synthesizable PCI Arbiter. This will have 4 external PCI
|
// Summary: A synthesizable PCI Arbiter. This will have 4 external PCI
|
// Request/Grant pairs and one internal Request/Grant Pair.
|
// Request/Grant pairs and one internal Request/Grant Pair.
|
// A Compile-time option selects whether to include an un-latched
|
// A Compile-time option selects whether to include an un-latched
|
// IRDY_L signal ithe arbitration. This might make the bus use
|
// IRDY_L signal ithe arbitration. This might make the bus use
|
// slightly more efficient. But there would be more load in
|
// slightly more efficient. But there would be more load in
|
// IRDY_L, a very timing critical signal. Not sure which is best.
|
// IRDY_L, a very timing critical signal. Not sure which is best.
|
//
|
//
|
// This library is free software; you can distribute it and/or modify it
|
// This library is free software; you can distribute it and/or modify it
|
// under the terms of the GNU Lesser General Public License as published
|
// under the terms of the GNU Lesser General Public License as published
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
// (at your option) any later version.
|
// (at your option) any later version.
|
//
|
//
|
// This library is distributed in the hope that it will be useful, but
|
// This library is distributed in the hope that it will be useful, but
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
// See the GNU Lesser General Public License for more details.
|
// See the GNU Lesser General Public License for more details.
|
//
|
//
|
// You should have received a copy of the GNU Lesser General Public License
|
// You should have received a copy of the GNU Lesser General Public License
|
// along with this library. If not, write to
|
// along with this library. If not, write to
|
// Free Software Foundation, Inc.
|
// Free Software Foundation, Inc.
|
// 59 Temple Place, Suite 330
|
// 59 Temple Place, Suite 330
|
// Boston, MA 02111-1307 USA
|
// Boston, MA 02111-1307 USA
|
//
|
//
|
// Author's note about this license: The intention of the Author and of
|
// Author's note about this license: The intention of the Author and of
|
// the Gnu Lesser General Public License is that users should be able to
|
// the Gnu Lesser General Public License is that users should be able to
|
// use this code for any purpose, including combining it with other source
|
// use this code for any purpose, including combining it with other source
|
// code, combining it with other logic, translated it into a gate-level
|
// code, combining it with other logic, translated it into a gate-level
|
// representation, or projected it into gates in a programmable or
|
// representation, or projected it into gates in a programmable or
|
// hardwired chip, as long as the users of the resulting source, compiled
|
// hardwired chip, as long as the users of the resulting source, compiled
|
// source, or chip are given the means to get a copy of this source code
|
// source, or chip are given the means to get a copy of this source code
|
// with no new restrictions on redistribution of this source.
|
// with no new restrictions on redistribution of this source.
|
//
|
//
|
// If you make changes, even substantial changes, to this code, or use
|
// If you make changes, even substantial changes, to this code, or use
|
// substantial parts of this code as an inseparable part of another work
|
// substantial parts of this code as an inseparable part of another work
|
// of authorship, the users of the resulting IP must be given the means
|
// of authorship, the users of the resulting IP must be given the means
|
// to get a copy of the modified or combined source code, with no new
|
// to get a copy of the modified or combined source code, with no new
|
// restrictions on redistribution of the resulting source.
|
// restrictions on redistribution of the resulting source.
|
//
|
//
|
// Separate parts of the combined source code, compiled code, or chip,
|
// Separate parts of the combined source code, compiled code, or chip,
|
// which are NOT derived from this source code do NOT need to be offered
|
// which are NOT derived from this source code do NOT need to be offered
|
// to the final user of the chip merely because they are used in
|
// to the final user of the chip merely because they are used in
|
// combination with this code. Other code is not forced to fall under
|
// combination with this code. Other code is not forced to fall under
|
// the GNU Lesser General Public License when it is linked to this code.
|
// the GNU Lesser General Public License when it is linked to this code.
|
// The license terms of other source code linked to this code might require
|
// The license terms of other source code linked to this code might require
|
// that it NOT be made available to users. The GNU Lesser General Public
|
// that it NOT be made available to users. The GNU Lesser General Public
|
// License does not prevent this code from being used in such a situation,
|
// License does not prevent this code from being used in such a situation,
|
// as long as the user of the resulting IP is given the means to get a
|
// as long as the user of the resulting IP is given the means to get a
|
// copy of this component of the IP with no new restrictions on
|
// copy of this component of the IP with no new restrictions on
|
// redistribution of this source.
|
// redistribution of this source.
|
//
|
//
|
// This code was developed using VeriLogger Pro, by Synapticad.
|
// This code was developed using VeriLogger Pro, by Synapticad.
|
// Their support is greatly appreciated.
|
// Their support is greatly appreciated.
|
//
|
//
|
// NOTE: This PCI Arbiter is an implementation of the arbiter ideas
|
// NOTE: This PCI Arbiter is an implementation of the arbiter ideas
|
// described in the PCI Local Bus Specification Revision 2.2,
|
// described in the PCI Local Bus Specification Revision 2.2,
|
// section 3.4.
|
// section 3.4.
|
//
|
//
|
// NOTE: This arbiter serves 4 external Request/Grant pairs and one
|
// NOTE: This arbiter serves 4 external Request/Grant pairs and one
|
// internal Request/Grant pair. It would be attractive to
|
// internal Request/Grant pair. It would be attractive to
|
// try to implement the 2-level arbitration given in the
|
// try to implement the 2-level arbitration given in the
|
// implementation note.
|
// implementation note.
|
//
|
//
|
// NOTE: Upon Reset, this Arbiter parks the bus on the Internal Grant.
|
// NOTE: Upon Reset, this Arbiter parks the bus on the Internal Grant.
|
//
|
//
|
// NOTE: The 4 arbitration rules given in the PCI Local Bus Specification
|
// NOTE: The 4 arbitration rules given in the PCI Local Bus Specification
|
// Revision 2.2, section 3.4.1, are:
|
// Revision 2.2, section 3.4.1, are:
|
// 0) Be fair. Do not starve anyone. However, priorities are OK.
|
// 0) Be fair. Do not starve anyone. However, priorities are OK.
|
// 1) If GNT_L is Deasserted and FRAME_L is asserted on the same
|
// 1) If GNT_L is Deasserted and FRAME_L is asserted on the same
|
// clock, a valid reference is started
|
// clock, a valid reference is started
|
// 2) One GNT_L can be deasserted the same clock which another
|
// 2) One GNT_L can be deasserted the same clock which another
|
// GNT_L is asserted if NOT in Idle state. If in Idle state,
|
// GNT_L is asserted if NOT in Idle state. If in Idle state,
|
// one clock with no GNT at all must be inserted to avoid
|
// one clock with no GNT at all must be inserted to avoid
|
// contention on the AD and PAR lines.
|
// contention on the AD and PAR lines.
|
// 3) When FRAME_L is deasserted, GNT_L may be deasserted at
|
// 3) When FRAME_L is deasserted, GNT_L may be deasserted at
|
// any time.
|
// any time.
|
//
|
//
|
// NOTE: The arbiter can assume a device is "broken" if it receives REQ,
|
// NOTE: The arbiter can assume a device is "broken" if it receives REQ,
|
// assertes GNT, and no FRAME is asserted, for 16 clocks. It is legal
|
// assertes GNT, and no FRAME is asserted, for 16 clocks. It is legal
|
// to ignore that device's REQ signal after that, and report the
|
// to ignore that device's REQ signal after that, and report the
|
// problem to the host. This device just moves on to the next REQ.
|
// problem to the host. This device just moves on to the next REQ.
|
//
|
//
|
// NOTE: When the Arbiter is on-chip, the FRAME signal must NOT be the
|
// NOTE: When the Arbiter is on-chip, the FRAME signal must NOT be the
|
// external FRAME signal when the internam PCI device is driving
|
// external FRAME signal when the internam PCI device is driving
|
// the bus. In the case that the internal device is driving the
|
// the bus. In the case that the internal device is driving the
|
// bus, the INTERNAL FRAME signal must be used. This is due to
|
// bus, the INTERNAL FRAME signal must be used. This is due to
|
// time-of-flight concerns on the external PCI bus. See the PCI
|
// time-of-flight concerns on the external PCI bus. See the PCI
|
// Local Bus Specification Revision 2.2, section 3.10 item 9.
|
// Local Bus Specification Revision 2.2, section 3.10 item 9.
|
//
|
//
|
// NOTE: It is not clear when a change in bus ownership should occur.
|
// NOTE: It is not clear when a change in bus ownership should occur.
|
// This arbiter grants a device the bus, and then waits until
|
// This arbiter grants a device the bus, and then waits until
|
// the device has started a reference before granting to a new
|
// the device has started a reference before granting to a new
|
// device. If no other requests are pending, the grant stays put.
|
// device. If no other requests are pending, the grant stays put.
|
//
|
//
|
//===========================================================================
|
//===========================================================================
|
|
|
`timescale 1ns/1ps
|
// synopsys translate_off
|
|
`include "timescale.v"
|
|
// synopsys translate_on
|
|
|
// Allows printing of Arbiter Debug info. Usually not defined
|
// Allows printing of Arbiter Debug info. Usually not defined
|
//`define PCI_TRACE_ARB 1
|
//`define PCI_TRACE_ARB 1
|
|
|
module pci_blue_arbiter (
|
module pci_blue_arbiter (
|
pci_int_req_direct, pci_ext_req_prev,
|
pci_int_req_direct, pci_ext_req_prev,
|
pci_int_gnt_direct_out, pci_ext_gnt_direct_out,
|
pci_int_gnt_direct_out, pci_ext_gnt_direct_out,
|
pci_frame_prev, pci_irdy_prev, pci_irdy_now,
|
pci_frame_prev, pci_irdy_prev, pci_irdy_now,
|
arbitration_enable,
|
arbitration_enable,
|
pci_clk, pci_reset_comb
|
pci_clk, pci_reset_comb
|
);
|
);
|
|
|
`include "pci_blue_options.vh"
|
`include "pci_blue_options.vh"
|
`include "pci_blue_constants.vh"
|
`include "pci_blue_constants.vh"
|
|
|
input pci_int_req_direct; // direct from internal flop clocked with pci_clk
|
input pci_int_req_direct; // direct from internal flop clocked with pci_clk
|
input [3:0] pci_ext_req_prev;
|
input [3:0] pci_ext_req_prev;
|
output pci_int_gnt_direct_out;
|
output pci_int_gnt_direct_out;
|
output [3:0] pci_ext_gnt_direct_out;
|
output [3:0] pci_ext_gnt_direct_out;
|
input pci_frame_prev, pci_irdy_prev, pci_irdy_now;
|
input pci_frame_prev, pci_irdy_prev, pci_irdy_now;
|
input arbitration_enable;
|
input arbitration_enable;
|
input pci_clk, pci_reset_comb;
|
input pci_clk, pci_reset_comb;
|
|
|
// detect the deassertion of reset, hopefully without metastability
|
// detect the deassertion of reset, hopefully without metastability
|
reg prev_unreset, prev_prev_unreset;
|
reg prev_unreset, prev_prev_unreset;
|
reg arbiter_init;
|
reg arbiter_init;
|
always @(posedge pci_clk or posedge pci_reset_comb)
|
always @(posedge pci_clk or posedge pci_reset_comb)
|
begin
|
begin
|
if (pci_reset_comb)
|
if (pci_reset_comb)
|
begin
|
begin
|
prev_unreset <= 1'b0;
|
prev_unreset <= 1'b0;
|
prev_prev_unreset <= 1'b0;
|
prev_prev_unreset <= 1'b0;
|
arbiter_init <= 1'b0;
|
arbiter_init <= 1'b0;
|
end
|
end
|
else
|
else
|
begin
|
begin
|
prev_unreset <= 1'b1;
|
prev_unreset <= 1'b1;
|
prev_prev_unreset <= prev_unreset;
|
prev_prev_unreset <= prev_unreset;
|
// init arbiter when reset goes away, or when user disables arbiter
|
// init arbiter when reset goes away, or when user disables arbiter
|
arbiter_init <= ~prev_prev_unreset | ~arbitration_enable;
|
arbiter_init <= ~prev_prev_unreset | ~arbitration_enable;
|
end
|
end
|
end
|
end
|
|
|
// watch for bus activity.
|
// watch for bus activity.
|
reg prev_prev_frame;
|
reg prev_prev_frame;
|
always @(posedge pci_clk)
|
always @(posedge pci_clk)
|
begin
|
begin
|
prev_prev_frame <= pci_frame_prev;
|
prev_prev_frame <= pci_frame_prev;
|
end
|
end
|
|
|
// approximate, but always conservative
|
// approximate, but always conservative
|
// wire pci_bus_not_idle = pci_frame_prev;
|
// wire pci_bus_not_idle = pci_frame_prev;
|
// expensive because irdy is critical
|
// expensive because irdy is critical
|
`define INCLUDE_FAST_IRDY_INPUT
|
`define INCLUDE_FAST_IRDY_INPUT
|
`ifdef INCLUDE_FAST_IRDY_INPUT
|
`ifdef INCLUDE_FAST_IRDY_INPUT
|
wire pci_bus_not_idle = pci_frame_prev | pci_irdy_now;
|
wire pci_bus_not_idle = pci_frame_prev | pci_irdy_now;
|
`else // INCLUDE_FAST_IRDY_INPUT
|
`else // INCLUDE_FAST_IRDY_INPUT
|
wire pci_bus_not_idle = pci_frame_prev;
|
wire pci_bus_not_idle = pci_frame_prev;
|
`endif // INCLUDE_FAST_IRDY_INPUT
|
`endif // INCLUDE_FAST_IRDY_INPUT
|
wire pci_bus_went_idle = ~pci_frame_prev & ~pci_irdy_prev;
|
wire pci_bus_went_idle = ~pci_frame_prev & ~pci_irdy_prev;
|
wire pci_address_phase = pci_frame_prev & ~prev_prev_frame;
|
wire pci_address_phase = pci_frame_prev & ~prev_prev_frame;
|
|
|
// upon assertion of reset, remove all bus grants.
|
// upon assertion of reset, remove all bus grants.
|
// note that the PCI Local Bus Specification Revision 2.2,
|
// note that the PCI Local Bus Specification Revision 2.2,
|
// section 2.2.4, says the devices must ignore GNT_L when
|
// section 2.2.4, says the devices must ignore GNT_L when
|
// reset is asserted, no matter what it's value is.
|
// reset is asserted, no matter what it's value is.
|
// upon reset, all requests are pulled HIGH by motherboard pullups,
|
// upon reset, all requests are pulled HIGH by motherboard pullups,
|
// because upon reset, all PCI devices are supposed to HIGH-Z
|
// because upon reset, all PCI devices are supposed to HIGH-Z
|
// their request lines. See the PCI Local Bus Specification
|
// their request lines. See the PCI Local Bus Specification
|
// Revision 2.2, section 2.2.4. The internal device cannot
|
// Revision 2.2, section 2.2.4. The internal device cannot
|
// be tristated, Instead, it de-requests.
|
// be tristated, Instead, it de-requests.
|
// upon deassertion of reset, park the bus on the internal device.
|
// upon deassertion of reset, park the bus on the internal device.
|
// note that the bus parking will not happen if the PCI Clock is
|
// note that the bus parking will not happen if the PCI Clock is
|
// not running.
|
// not running.
|
// after initialization, the bus is parked at the last bus user.
|
// after initialization, the bus is parked at the last bus user.
|
|
|
// round_robin arbitration. No priorities or anything.
|
// round_robin arbitration. No priorities or anything.
|
// Note this can change constantly as new requests come in
|
// Note this can change constantly as new requests come in
|
reg [4:0] prev_master; // remembered from last good arbitration
|
reg [4:0] prev_master; // remembered from last good arbitration
|
wire [4:0] present_requestors = {pci_ext_req_prev[3:0], pci_int_req_direct};
|
wire [4:0] present_requestors = {pci_ext_req_prev[3:0], pci_int_req_direct};
|
wire [4:0] no_master = 5'h00;
|
wire [4:0] no_master = 5'h00;
|
wire [4:0] internal_master = 5'h01;
|
wire [4:0] internal_master = 5'h01;
|
|
|
wire New_Master_Wants_Bus =
|
wire New_Master_Wants_Bus =
|
(present_requestors != 5'h00)
|
(present_requestors != 5'h00)
|
&& (present_requestors != prev_master);
|
&& (present_requestors != prev_master);
|
wire New_Master_Stopped_Requesting =
|
wire New_Master_Stopped_Requesting =
|
((present_requestors & prev_master) == 5'h00);
|
((present_requestors & prev_master) == 5'h00);
|
|
|
wire [4:0] next_master =
|
wire [4:0] next_master =
|
((prev_master == 5'h00) || (prev_master == 5'h01))
|
((prev_master == 5'h00) || (prev_master == 5'h01))
|
? ( (present_requestors[1]) ? 5'h02
|
? ( (present_requestors[1]) ? 5'h02
|
: ((present_requestors[2]) ? 5'h04
|
: ((present_requestors[2]) ? 5'h04
|
: ((present_requestors[3]) ? 5'h08
|
: ((present_requestors[3]) ? 5'h08
|
: ((present_requestors[4]) ? 5'h10
|
: ((present_requestors[4]) ? 5'h10
|
: 5'h01))))
|
: 5'h01))))
|
: ((prev_master == 5'h02)
|
: ((prev_master == 5'h02)
|
? ( (present_requestors[2]) ? 5'h04
|
? ( (present_requestors[2]) ? 5'h04
|
: ((present_requestors[3]) ? 5'h08
|
: ((present_requestors[3]) ? 5'h08
|
: ((present_requestors[4]) ? 5'h10
|
: ((present_requestors[4]) ? 5'h10
|
: ((present_requestors[0]) ? 5'h01
|
: ((present_requestors[0]) ? 5'h01
|
: 5'h02))))
|
: 5'h02))))
|
: ((prev_master == 5'h04)
|
: ((prev_master == 5'h04)
|
? ( (present_requestors[3]) ? 5'h08
|
? ( (present_requestors[3]) ? 5'h08
|
: ((present_requestors[4]) ? 5'h10
|
: ((present_requestors[4]) ? 5'h10
|
: ((present_requestors[0]) ? 5'h01
|
: ((present_requestors[0]) ? 5'h01
|
: ((present_requestors[1]) ? 5'h02
|
: ((present_requestors[1]) ? 5'h02
|
: 5'h04))))
|
: 5'h04))))
|
: ((prev_master == 5'h08)
|
: ((prev_master == 5'h08)
|
? ( (present_requestors[4]) ? 5'h10
|
? ( (present_requestors[4]) ? 5'h10
|
: ((present_requestors[0]) ? 5'h01
|
: ((present_requestors[0]) ? 5'h01
|
: ((present_requestors[1]) ? 5'h02
|
: ((present_requestors[1]) ? 5'h02
|
: ((present_requestors[2]) ? 5'h04
|
: ((present_requestors[2]) ? 5'h04
|
: 5'h08))))
|
: 5'h08))))
|
: // ((prev_master == 5'h10) || (more than 1 bit set)) ?
|
: // ((prev_master == 5'h10) || (more than 1 bit set)) ?
|
( (present_requestors[0]) ? 5'h01
|
( (present_requestors[0]) ? 5'h01
|
: ((present_requestors[1]) ? 5'h02
|
: ((present_requestors[1]) ? 5'h02
|
: ((present_requestors[2]) ? 5'h04
|
: ((present_requestors[2]) ? 5'h04
|
: ((present_requestors[3]) ? 5'h08
|
: ((present_requestors[3]) ? 5'h08
|
: 5'h10))))
|
: 5'h10))))
|
) ) );
|
) ) );
|
|
|
// state machine moves to next state when a new request is available and
|
// state machine moves to next state when a new request is available and
|
// the previous grent has resulted in a memory reference, or when the
|
// the previous grent has resulted in a memory reference, or when the
|
// bus has been idle too long.
|
// bus has been idle too long.
|
//
|
//
|
// When the PCI Bus is not Idle, it is fine to deassert one grant and
|
// When the PCI Bus is not Idle, it is fine to deassert one grant and
|
// assert another the next clock. If the bus is NOT Idle, there must be
|
// assert another the next clock. If the bus is NOT Idle, there must be
|
// a one clock delay between the deassertion of one GNT and the next GNT.
|
// a one clock delay between the deassertion of one GNT and the next GNT.
|
// Refer to the PCI Local Bus Specification Revision 2.2, section 3.4.1.
|
// Refer to the PCI Local Bus Specification Revision 2.2, section 3.4.1.
|
//
|
//
|
// In order to remove any dependence on the IRDY and TRDY signals directly
|
// In order to remove any dependence on the IRDY and TRDY signals directly
|
// received from the PCI Bus, this arbiter uses the latched versions.
|
// received from the PCI Bus, this arbiter uses the latched versions.
|
// The PCI Bus is Idle whenever BOTH FRAME and IRDY are deasserted. This
|
// The PCI Bus is Idle whenever BOTH FRAME and IRDY are deasserted. This
|
// arbiter uses an approximation of that. It uses the Latched FRAME
|
// arbiter uses an approximation of that. It uses the Latched FRAME
|
// signal alone. This is not too bad, because each reference ends with
|
// signal alone. This is not too bad, because each reference ends with
|
// FRAME going deasserted and IRDY going asserted for at least one clock.
|
// FRAME going deasserted and IRDY going asserted for at least one clock.
|
// Latched FRAME is valid for 1 clock after Frame goes away, which is
|
// Latched FRAME is valid for 1 clock after Frame goes away, which is
|
// automatically also a non-idle clock. Latched FRAME is a conservative
|
// automatically also a non-idle clock. Latched FRAME is a conservative
|
// estimate of whether the bus is idle or not. When Latched FRAME is
|
// estimate of whether the bus is idle or not. When Latched FRAME is
|
// not asserted, the Arbiter will deassert all GNT signals for one clock
|
// not asserted, the Arbiter will deassert all GNT signals for one clock
|
// before asserting a new GNT.
|
// before asserting a new GNT.
|
//
|
//
|
// The event sequence is as follows:
|
// The event sequence is as follows:
|
// 1) at time minus infinity, some device gets bus mastership
|
// 1) at time minus infinity, some device gets bus mastership
|
// 2) at time before 0, the arbiter decides the first device is done
|
// 2) at time before 0, the arbiter decides the first device is done
|
// 3) at time -1, a new device requests
|
// 3) at time -1, a new device requests
|
// 4) at time 0, the old device is ungranted, and the new device is granted
|
// 4) at time 0, the old device is ungranted, and the new device is granted
|
// 5) at time 0, the old device might start a new reference or continue an old one
|
// 5) at time 0, the old device might start a new reference or continue an old one
|
// 6) at time 1, the new device gets a chance to see the grant
|
// 6) at time 1, the new device gets a chance to see the grant
|
// 7) at time 1, the new device can drive the bus ONLY if it is idle
|
// 7) at time 1, the new device can drive the bus ONLY if it is idle
|
// 8) at time 2, the arbiter sees whether the bus was idle at time 1
|
// 8) at time 2, the arbiter sees whether the bus was idle at time 1
|
// from time 2 on, it watches to see when the bus finally goes idle
|
// from time 2 on, it watches to see when the bus finally goes idle
|
// 9) whenever the arbiter sees the bus going idle, it starts counting
|
// 9) whenever the arbiter sees the bus going idle, it starts counting
|
// a counter to 16. It also watches for a transition on frame indicating
|
// a counter to 16. It also watches for a transition on frame indicating
|
// that an address phase has happened.
|
// that an address phase has happened.
|
// 10) when the timer expires or the address phase happens, the arbiter
|
// 10) when the timer expires or the address phase happens, the arbiter
|
// rearbitrates to give the next requestor a chance.
|
// rearbitrates to give the next requestor a chance.
|
|
|
parameter PCI_ARBITER_HAPPILY_WAITING = 5'b00001;
|
parameter PCI_ARBITER_HAPPILY_WAITING = 5'b00001;
|
parameter PCI_ARBITER_REMOVE_GNT = 5'b00010;
|
parameter PCI_ARBITER_REMOVE_GNT = 5'b00010;
|
parameter PCI_ARBITER_DELAY_ONE = 5'b00100;
|
parameter PCI_ARBITER_DELAY_ONE = 5'b00100;
|
parameter PCI_ARBITER_WAIT_FOR_IDLE = 5'b01000;
|
parameter PCI_ARBITER_WAIT_FOR_IDLE = 5'b01000;
|
parameter PCI_ARBITER_WAIT_FOR_ADDRESS = 5'b10000;
|
parameter PCI_ARBITER_WAIT_FOR_ADDRESS = 5'b10000;
|
reg [4:0] PCI_Arbiter_State;
|
reg [4:0] PCI_Arbiter_State;
|
|
|
reg [4:0] new_master;
|
reg [4:0] new_master;
|
reg [3:0] gnt_timeout;
|
reg [3:0] gnt_timeout;
|
always @(posedge pci_clk or posedge pci_reset_comb)
|
always @(posedge pci_clk or posedge pci_reset_comb)
|
begin
|
begin
|
if (pci_reset_comb)
|
if (pci_reset_comb)
|
begin
|
begin
|
PCI_Arbiter_State <= PCI_ARBITER_HAPPILY_WAITING;
|
PCI_Arbiter_State <= PCI_ARBITER_HAPPILY_WAITING;
|
prev_master <= no_master;
|
prev_master <= no_master;
|
new_master <= no_master;
|
new_master <= no_master;
|
gnt_timeout <= 4'h0;
|
gnt_timeout <= 4'h0;
|
end
|
end
|
else
|
else
|
begin
|
begin
|
if (arbiter_init)
|
if (arbiter_init)
|
begin
|
begin
|
PCI_Arbiter_State <= PCI_ARBITER_HAPPILY_WAITING;
|
PCI_Arbiter_State <= PCI_ARBITER_HAPPILY_WAITING;
|
prev_master <= internal_master;
|
prev_master <= internal_master;
|
new_master <= internal_master;
|
new_master <= internal_master;
|
gnt_timeout <= 4'h0;
|
gnt_timeout <= 4'h0;
|
end
|
end
|
else
|
else
|
begin
|
begin
|
case (PCI_Arbiter_State)
|
case (PCI_Arbiter_State)
|
PCI_ARBITER_HAPPILY_WAITING:
|
PCI_ARBITER_HAPPILY_WAITING:
|
begin
|
begin
|
gnt_timeout <= 4'h0; // all cases
|
gnt_timeout <= 4'h0; // all cases
|
if (New_Master_Wants_Bus)
|
if (New_Master_Wants_Bus)
|
begin
|
begin
|
if (pci_bus_not_idle)
|
if (pci_bus_not_idle)
|
begin // directly grant new bus owner
|
begin // directly grant new bus owner
|
PCI_Arbiter_State <= PCI_ARBITER_DELAY_ONE;
|
PCI_Arbiter_State <= PCI_ARBITER_DELAY_ONE;
|
prev_master <= next_master;
|
prev_master <= next_master;
|
new_master <= next_master;
|
new_master <= next_master;
|
end
|
end
|
else
|
else
|
begin // case that bus is idle. make no grant for 1 clock
|
begin // case that bus is idle. make no grant for 1 clock
|
PCI_Arbiter_State <= PCI_ARBITER_REMOVE_GNT;
|
PCI_Arbiter_State <= PCI_ARBITER_REMOVE_GNT;
|
prev_master <= prev_master;
|
prev_master <= prev_master;
|
new_master <= no_master;
|
new_master <= no_master;
|
end
|
end
|
end
|
end
|
else
|
else
|
begin // no requestor or same requestor. Park on previous winner
|
begin // no requestor or same requestor. Park on previous winner
|
PCI_Arbiter_State <= PCI_ARBITER_HAPPILY_WAITING;
|
PCI_Arbiter_State <= PCI_ARBITER_HAPPILY_WAITING;
|
prev_master <= prev_master;
|
prev_master <= prev_master;
|
new_master <= prev_master;
|
new_master <= prev_master;
|
end
|
end
|
end
|
end
|
PCI_ARBITER_REMOVE_GNT:
|
PCI_ARBITER_REMOVE_GNT:
|
begin
|
begin
|
if (New_Master_Wants_Bus)
|
if (New_Master_Wants_Bus)
|
begin // directly grant new bus owner
|
begin // directly grant new bus owner
|
PCI_Arbiter_State <= PCI_ARBITER_DELAY_ONE;
|
PCI_Arbiter_State <= PCI_ARBITER_DELAY_ONE;
|
prev_master <= next_master;
|
prev_master <= next_master;
|
new_master <= next_master;
|
new_master <= next_master;
|
end
|
end
|
else
|
else
|
begin // requestor gave up. Park on previous winner
|
begin // requestor gave up. Park on previous winner
|
PCI_Arbiter_State <= PCI_ARBITER_HAPPILY_WAITING;
|
PCI_Arbiter_State <= PCI_ARBITER_HAPPILY_WAITING;
|
prev_master <= prev_master;
|
prev_master <= prev_master;
|
new_master <= prev_master;
|
new_master <= prev_master;
|
end
|
end
|
end
|
end
|
PCI_ARBITER_DELAY_ONE:
|
PCI_ARBITER_DELAY_ONE:
|
begin // wait for pipelined copy of FRAME, IRDY to become valid
|
begin // wait for pipelined copy of FRAME, IRDY to become valid
|
prev_master <= prev_master; // all cases
|
prev_master <= prev_master; // all cases
|
new_master <= prev_master; // all cases
|
new_master <= prev_master; // all cases
|
gnt_timeout <= 4'h0; // all cases
|
gnt_timeout <= 4'h0; // all cases
|
if (New_Master_Stopped_Requesting)
|
if (New_Master_Stopped_Requesting)
|
begin // requestor removed request! Never happens. Rearb immediately.
|
begin // requestor removed request! Never happens. Rearb immediately.
|
PCI_Arbiter_State <= PCI_ARBITER_HAPPILY_WAITING;
|
PCI_Arbiter_State <= PCI_ARBITER_HAPPILY_WAITING;
|
end
|
end
|
else
|
else
|
begin // start looking for bus idle, when new master takes over
|
begin // start looking for bus idle, when new master takes over
|
PCI_Arbiter_State <= PCI_ARBITER_WAIT_FOR_IDLE;
|
PCI_Arbiter_State <= PCI_ARBITER_WAIT_FOR_IDLE;
|
end
|
end
|
end
|
end
|
PCI_ARBITER_WAIT_FOR_IDLE:
|
PCI_ARBITER_WAIT_FOR_IDLE:
|
begin // A new master is granted, but can't start until the PCI bus is idle
|
begin // A new master is granted, but can't start until the PCI bus is idle
|
prev_master <= prev_master; // all cases
|
prev_master <= prev_master; // all cases
|
new_master <= prev_master; // all cases
|
new_master <= prev_master; // all cases
|
gnt_timeout <= 4'h0; // all cases
|
gnt_timeout <= 4'h0; // all cases
|
if (New_Master_Stopped_Requesting)
|
if (New_Master_Stopped_Requesting)
|
begin // requestor removed request! Never happens. Rearb immediately.
|
begin // requestor removed request! Never happens. Rearb immediately.
|
PCI_Arbiter_State <= PCI_ARBITER_HAPPILY_WAITING;
|
PCI_Arbiter_State <= PCI_ARBITER_HAPPILY_WAITING;
|
end
|
end
|
else
|
else
|
begin
|
begin
|
if (pci_bus_went_idle)
|
if (pci_bus_went_idle)
|
begin // now the new master can take control by driving an address
|
begin // now the new master can take control by driving an address
|
PCI_Arbiter_State <= PCI_ARBITER_WAIT_FOR_ADDRESS;
|
PCI_Arbiter_State <= PCI_ARBITER_WAIT_FOR_ADDRESS;
|
end
|
end
|
else
|
else
|
begin // wait for old master to release bus
|
begin // wait for old master to release bus
|
PCI_Arbiter_State <= PCI_ARBITER_WAIT_FOR_IDLE;
|
PCI_Arbiter_State <= PCI_ARBITER_WAIT_FOR_IDLE;
|
end
|
end
|
end
|
end
|
end
|
end
|
PCI_ARBITER_WAIT_FOR_ADDRESS:
|
PCI_ARBITER_WAIT_FOR_ADDRESS:
|
begin
|
begin
|
gnt_timeout <= gnt_timeout + 4'h1; // all cases
|
gnt_timeout <= gnt_timeout + 4'h1; // all cases
|
if (New_Master_Stopped_Requesting)
|
if (New_Master_Stopped_Requesting)
|
begin // requestor removed request! Never happens. Rearb immediately.
|
begin // requestor removed request! Never happens. Rearb immediately.
|
PCI_Arbiter_State <= PCI_ARBITER_HAPPILY_WAITING;
|
PCI_Arbiter_State <= PCI_ARBITER_HAPPILY_WAITING;
|
prev_master <= prev_master;
|
prev_master <= prev_master;
|
new_master <= prev_master;
|
new_master <= prev_master;
|
end
|
end
|
else
|
else
|
begin
|
begin
|
if (pci_address_phase || (gnt_timeout == 4'hF))
|
if (pci_address_phase || (gnt_timeout == 4'hF))
|
begin
|
begin
|
`ifdef INCLUDE_FAST_IRDY_ON_IDLE_TERM
|
`ifdef INCLUDE_FAST_IRDY_ON_IDLE_TERM
|
// This term makes some improvement in arbitration timing, but not sure how
|
// This term makes some improvement in arbitration timing, but not sure how
|
// much. With the term, certain wait states at the end of single-word or burst
|
// much. With the term, certain wait states at the end of single-word or burst
|
// transfers are eliminated. The arbitration time in the case of a genuinely
|
// transfers are eliminated. The arbitration time in the case of a genuinely
|
// idle bus isn't changed however. Presently not using this.
|
// idle bus isn't changed however. Presently not using this.
|
if (New_Master_Wants_Bus)
|
if (New_Master_Wants_Bus)
|
begin // safe to rearbitrate. Is anyone waiting?
|
begin // safe to rearbitrate. Is anyone waiting?
|
if (pci_bus_not_idle) // bus is busy, switch instantly
|
if (pci_bus_not_idle) // bus is busy, switch instantly
|
begin
|
begin
|
PCI_Arbiter_State <= PCI_ARBITER_DELAY_ONE;
|
PCI_Arbiter_State <= PCI_ARBITER_DELAY_ONE;
|
prev_master <= next_master;
|
prev_master <= next_master;
|
new_master <= next_master;
|
new_master <= next_master;
|
end
|
end
|
else // bus is idle, force an idle period
|
else // bus is idle, force an idle period
|
begin
|
begin
|
PCI_Arbiter_State <= PCI_ARBITER_REMOVE_GNT;
|
PCI_Arbiter_State <= PCI_ARBITER_REMOVE_GNT;
|
prev_master <= prev_master;
|
prev_master <= prev_master;
|
new_master <= no_master;
|
new_master <= no_master;
|
end
|
end
|
end
|
end
|
else
|
else
|
`endif // INCLUDE_FAST_IRDY_ON_IDLE_TERM
|
`endif // INCLUDE_FAST_IRDY_ON_IDLE_TERM
|
begin // no requestor or same requestor. Park on previous winner
|
begin // no requestor or same requestor. Park on previous winner
|
PCI_Arbiter_State <= PCI_ARBITER_HAPPILY_WAITING;
|
PCI_Arbiter_State <= PCI_ARBITER_HAPPILY_WAITING;
|
prev_master <= prev_master;
|
prev_master <= prev_master;
|
new_master <= prev_master;
|
new_master <= prev_master;
|
end
|
end
|
end
|
end
|
else
|
else
|
begin // no addres phase or timeout yet. Just keep looking
|
begin // no addres phase or timeout yet. Just keep looking
|
PCI_Arbiter_State <= PCI_ARBITER_WAIT_FOR_ADDRESS;
|
PCI_Arbiter_State <= PCI_ARBITER_WAIT_FOR_ADDRESS;
|
prev_master <= prev_master;
|
prev_master <= prev_master;
|
new_master <= prev_master;
|
new_master <= prev_master;
|
end
|
end
|
end
|
end
|
end
|
end
|
default:
|
default:
|
begin
|
begin
|
PCI_Arbiter_State <= PCI_ARBITER_HAPPILY_WAITING;
|
PCI_Arbiter_State <= PCI_ARBITER_HAPPILY_WAITING;
|
prev_master <= internal_master;
|
prev_master <= internal_master;
|
new_master <= internal_master;
|
new_master <= internal_master;
|
gnt_timeout <= 4'h0;
|
gnt_timeout <= 4'h0;
|
end
|
end
|
endcase
|
endcase
|
end
|
end
|
end
|
end
|
end
|
end
|
|
|
assign pci_int_gnt_direct_out = new_master[0];
|
assign pci_int_gnt_direct_out = new_master[0];
|
assign pci_ext_gnt_direct_out = new_master[4:1];
|
assign pci_ext_gnt_direct_out = new_master[4:1];
|
|
|
// synopsys translate_off
|
// synopsys translate_off
|
`ifdef PCI_TRACE_ARB
|
`ifdef PCI_TRACE_ARB
|
always @(posedge pci_clk or posedge pci_reset_comb)
|
always @(posedge pci_clk or posedge pci_reset_comb)
|
begin
|
begin
|
if (pci_reset_comb)
|
if (pci_reset_comb)
|
begin
|
begin
|
$display ("async reset");
|
$display ("async reset");
|
end
|
end
|
else
|
else
|
begin
|
begin
|
if (arbiter_init)
|
if (arbiter_init)
|
begin
|
begin
|
$display ("sync reset");
|
$display ("sync reset");
|
end
|
end
|
else
|
else
|
begin
|
begin
|
case (PCI_Arbiter_State)
|
case (PCI_Arbiter_State)
|
PCI_ARBITER_HAPPILY_WAITING:
|
PCI_ARBITER_HAPPILY_WAITING:
|
begin
|
begin
|
if (New_Master_Wants_Bus)
|
if (New_Master_Wants_Bus)
|
begin // new requestor. Either ungrant for 1 clock if idle or go directly
|
begin // new requestor. Either ungrant for 1 clock if idle or go directly
|
if (pci_bus_not_idle) // indication that bus is busy
|
if (pci_bus_not_idle) // indication that bus is busy
|
begin
|
begin
|
$display ("Waiting, New Master, Bus Not Idle %x %x",
|
$display ("Waiting, New Master, Bus Not Idle %x %x",
|
present_requestors, prev_master);
|
present_requestors, prev_master);
|
end
|
end
|
else
|
else
|
begin // case that bus is idle. make no grant for 1 clock
|
begin // case that bus is idle. make no grant for 1 clock
|
$display ("Waiting, New Master, Bus Idle %x %x",
|
$display ("Waiting, New Master, Bus Idle %x %x",
|
present_requestors, prev_master);
|
present_requestors, prev_master);
|
end
|
end
|
end
|
end
|
else
|
else
|
begin // no reason to change. Park on previous winner
|
begin // no reason to change. Park on previous winner
|
$display ("Waiting, No New Master %x %x",
|
$display ("Waiting, No New Master %x %x",
|
present_requestors, prev_master);
|
present_requestors, prev_master);
|
end
|
end
|
end
|
end
|
PCI_ARBITER_REMOVE_GNT:
|
PCI_ARBITER_REMOVE_GNT:
|
begin // pick the new winner, or the previous winner if the requestor left
|
begin // pick the new winner, or the previous winner if the requestor left
|
if (New_Master_Wants_Bus)
|
if (New_Master_Wants_Bus)
|
begin // new requestor wins. Wait for it's reference before rearbitrating
|
begin // new requestor wins. Wait for it's reference before rearbitrating
|
$display ("Remove Gnt, New Master still requesting %x %x",
|
$display ("Remove Gnt, New Master still requesting %x %x",
|
present_requestors, prev_master);
|
present_requestors, prev_master);
|
end
|
end
|
else
|
else
|
begin // no reason to change. Park on previous winner
|
begin // no reason to change. Park on previous winner
|
$display ("Remove Gnt, New Master removed request %x %x",
|
$display ("Remove Gnt, New Master removed request %x %x",
|
present_requestors, prev_master);
|
present_requestors, prev_master);
|
end
|
end
|
end
|
end
|
PCI_ARBITER_DELAY_ONE:
|
PCI_ARBITER_DELAY_ONE:
|
begin // wait for pipelined copy of FRAME, IRDY to become valid
|
begin // wait for pipelined copy of FRAME, IRDY to become valid
|
$display ("Delay 1, wait for Frame and IRDY pipeline %x %x",
|
$display ("Delay 1, wait for Frame and IRDY pipeline %x %x",
|
present_requestors, prev_master);
|
present_requestors, prev_master);
|
end
|
end
|
PCI_ARBITER_WAIT_FOR_IDLE:
|
PCI_ARBITER_WAIT_FOR_IDLE:
|
begin // A new master is granted, but can't start until the PCI bus is idle
|
begin // A new master is granted, but can't start until the PCI bus is idle
|
if (New_Master_Stopped_Requesting)
|
if (New_Master_Stopped_Requesting)
|
begin // requestor removed request! Never happens. Rearb immediately.
|
begin // requestor removed request! Never happens. Rearb immediately.
|
$display ("Waiting for Idle, New Master removed request %x %x",
|
$display ("Waiting for Idle, New Master removed request %x %x",
|
present_requestors, prev_master);
|
present_requestors, prev_master);
|
end
|
end
|
else
|
else
|
begin
|
begin
|
if (pci_bus_went_idle)
|
if (pci_bus_went_idle)
|
begin // now the new master can take control
|
begin // now the new master can take control
|
$display ("Waiting for Idle, went idle, New Master still requesting %x %x",
|
$display ("Waiting for Idle, went idle, New Master still requesting %x %x",
|
present_requestors, prev_master);
|
present_requestors, prev_master);
|
end
|
end
|
else
|
else
|
begin // wait for old master to release bus
|
begin // wait for old master to release bus
|
$display ("Waiting for Idle, not idle, New Master still requesting %x %x",
|
$display ("Waiting for Idle, not idle, New Master still requesting %x %x",
|
present_requestors, prev_master);
|
present_requestors, prev_master);
|
end
|
end
|
end
|
end
|
end
|
end
|
PCI_ARBITER_WAIT_FOR_ADDRESS:
|
PCI_ARBITER_WAIT_FOR_ADDRESS:
|
begin
|
begin
|
if (New_Master_Stopped_Requesting)
|
if (New_Master_Stopped_Requesting)
|
begin // requestor removed request! Never happens. Rearb immediately.
|
begin // requestor removed request! Never happens. Rearb immediately.
|
$display ("Waiting for Address, New Master removed request %x %x",
|
$display ("Waiting for Address, New Master removed request %x %x",
|
present_requestors, prev_master);
|
present_requestors, prev_master);
|
end
|
end
|
else
|
else
|
begin
|
begin
|
if ((pci_address_phase == 1'b1) || (gnt_timeout == 4'hF))
|
if ((pci_address_phase == 1'b1) || (gnt_timeout == 4'hF))
|
begin // safe to rearbitrate. Is anyone waiting?
|
begin // safe to rearbitrate. Is anyone waiting?
|
if (New_Master_Wants_Bus)
|
if (New_Master_Wants_Bus)
|
begin
|
begin
|
if (pci_bus_not_idle) // bus is busy, switch instantly
|
if (pci_bus_not_idle) // bus is busy, switch instantly
|
begin
|
begin
|
$display ("Waiting for Address, Address or Timeout, New Master still requesting, bus was busy %x %x",
|
$display ("Waiting for Address, Address or Timeout, New Master still requesting, bus was busy %x %x",
|
present_requestors, prev_master);
|
present_requestors, prev_master);
|
end
|
end
|
else // bus is idle, force an idle period
|
else // bus is idle, force an idle period
|
begin
|
begin
|
$display ("Waiting for Address, Address or Timeout, New Master still requesting, bus was idle %x %x",
|
$display ("Waiting for Address, Address or Timeout, New Master still requesting, bus was idle %x %x",
|
present_requestors, prev_master);
|
present_requestors, prev_master);
|
end
|
end
|
end
|
end
|
else
|
else
|
begin // no reason to change. Park on previous winner
|
begin // no reason to change. Park on previous winner
|
$display ("Waiting for Address, No New Master, giving up %x %x",
|
$display ("Waiting for Address, No New Master, giving up %x %x",
|
present_requestors, prev_master);
|
present_requestors, prev_master);
|
end
|
end
|
end
|
end
|
else
|
else
|
begin
|
begin
|
$display ("Waiting for Address, New Master still requesting, no address or timeout yet %x %x",
|
$display ("Waiting for Address, New Master still requesting, no address or timeout yet %x %x",
|
present_requestors, prev_master);
|
present_requestors, prev_master);
|
end
|
end
|
end
|
end
|
end
|
end
|
default:
|
default:
|
begin
|
begin
|
$display ("PCI Arbiter went insane with REQ 'h%x at time %t",
|
$display ("PCI Arbiter went insane with REQ 'h%x at time %t",
|
present_requestors, $time);
|
present_requestors, $time);
|
end
|
end
|
endcase
|
endcase
|
end
|
end
|
end
|
end
|
end
|
end
|
`endif // PCI_TRACE_ARB
|
`endif // PCI_TRACE_ARB
|
// synopsys translate_on
|
// synopsys translate_on
|
endmodule
|
endmodule
|
|
|
|
|