/******************************************************************************/
/* */
/* Copyright (c) 1999 Sun Microsystems, Inc. All rights reserved. */
/* */
/* The contents of this file are subject to the current version of the Sun */
/* Community Source License, microSPARCII ("the License"). You may not use */
/* this file except in compliance with the License. You may obtain a copy */
/* of the License by searching for "Sun Community Source License" on the */
/* World Wide Web at http://www.sun.com. See the License for the rights, */
/* obligations, and limitations governing use of the contents of this file. */
/* */
/* Sun Microsystems, Inc. has intellectual property rights relating to the */
/* technology embodied in these files. In particular, and without limitation, */
/* these intellectual property rights may include one or more U.S. patents, */
/* foreign patents, or pending applications. */
/* */
/* Sun, Sun Microsystems, the Sun logo, all Sun-based trademarks and logos, */
/* Solaris, Java and all Java-based trademarks and logos are trademarks or */
/* registered trademarks of Sun Microsystems, Inc. in the United States and */
/* other countries. microSPARC is a trademark or registered trademark of */
/* SPARC International, Inc. All SPARC trademarks are used under license and */
/* are trademarks or registered trademarks of SPARC International, Inc. in */
/* the United States and other countries. Products bearing SPARC trademarks */
/* are based upon an architecture developed by Sun Microsystems, Inc. */
/* */
/******************************************************************************/
/***************************************************************************
****************************************************************************
***
*** Program File: @(#)arbiter.v
***
*** Description:
*** This file contains the arbiter module for falcon. I accepts 4 requests
*** from external sources, and one from the host. In responce, a single
*** grant goes out on the following clock edge.
***
***
*** Revision: Delete Lock pin and functionality. Pin needed for 208
*** pin package, and functionality limited because of afx bus locking
*** on read requests while pci locking at the same time (deadlock).
*** In order to gain more pins in a 208 pin package, the idsels which
*** had dedicated pins, are being deleted. A new request (req_conf) is
*** being added as an input to the arbiter, which is from the host
*** interface. When it is active, the host is requesting that the arbiter
*** stick to the grant for several clocks (like done in state WAITF
*** already). When the arbiter is in state WAITF with the host grant,
*** the grant_conf will go active. This is used to precharge the idle
*** pci bus with an address that is resistively coupled to the idsel's
*** of the slave pci interfaces. (Note. other subsystems are also
*** capable of configuring subsystems that available on the pci bus).
*** Revision: Add an arbiter disable input pin, which when disabled,
*** the internal arbiter is not used, and an external arbiter is used.
*** In this case, the falcon could act as a slave device, or it could
*** still be a master, but does not include arbitration. When the
*** arbiter is disabled the req_conf_ operations will not work, so
*** configuration cycles should not be made by the master or slave.
*** The req_ in will reflect the grant to the falcon, and the granto_
*** pin will reflect the request of the falcon host when the internal
*** arbiter is disabled.
*** Revision: ? added ability to programmably assign the priority to
*** each request/grant pair.
*** Revision: ? added standby logic, that monitors for any external pci
*** activity, and causes go_standby to go off. Also added the quiencensce
*** input, that will cause the arbitration to go into a slow down mode,
*** and preventing some external master from retrying too quickly when
*** the quiecense control is set (like during iotlb updating).
*** NOTE: the programmable assignment of priorities may (probably will)
*** not cause the standby function to work.
*** Corrected single cycle error edge case, where bus was parked on an
*** external master, which just started a transfer (wiht out raising
*** request, since it had the grant already) and went into standby AND
*** pcic_idle, then transcation started. Fix is to delay going into
*** standby until one clock after bus park request is generated.
***
****************************************************************************
****************************************************************************/
module arbiter
(
req_, // PCI requests from the external slots
req_host_, // request from the host
granto_, // PCI grants to external slots
granto_host_, // grant to the host
req_conf_, // Request from AFX slave interface, asking
// for notification of sticking on host grant.
grant_conf_, // Notification to AFX slave interface, that
// the pci bus is stuck (WAITF) at the host.
arb_lvl_en, // Configuration register, enable additional
// levels of arbitration.
reset, // PCI reset
clock, // PCI clock
bus_idle, // _frame_i & _irdy_i, bus idle from pci_core
new_frame, // ~_frame_i & _frame_in, new frame pulse,
// when frame first goes active.
arb_disable, // disable internal arbiter, turn around req/gnt
arb_asgn_reg, // arbiter assignment of req/grnt priorities
req_quiescence, // bus going to signal retry while quiescent,
// therefore slow down arbitration.
mm_go_standby, // bit of MID, causing programmable standby
turn_off_standby, // reset of MID register bit with external activity.
pin_go_standby, // external pin of package
go_standby, // qualified OR of pin and programmable bit
pcic_idle, // AND of all pcic idles, and delayed turn on too.
any_xint, // any interrupt, turns go_standby off
sm_idle, // afx slave state machine idle (on gclk)
mas_idle, // pci master state machine idle (on pci clk)
afx_m_idle, // afx master state machine idle (also on pci clk!)
// includes both fifo's empty for xmit and rcv
// add to support pci configuration operations
pci_slave_mode,
pci_slave_idsel,
pci_clk_sync, // pci clock, for resyncing
pci_clk_sync_, // pci clock, for resyncing
slave_idle // pci slave state machine idle (on pci clk)
);
// The arbiter is used to select between all requests to use the PCI bus.
// It is not defined as part of the PCI bus specification. It must
// exhibit "fairness" as required as part of the PCI spec. This arbiter
// does not provide the "lock" function.
input reset
;
input clock
;
input arb_lvl_en
;
input req_conf_
;
input req_host_
;
input bus_idle
;
input new_frame
;
input arb_disable
;
input [14:0] arb_asgn_reg
;
input req_quiescence
;
input mm_go_standby
;
input pin_go_standby
;
input any_xint
;
input sm_idle
;
input mas_idle
;
input afx_m_idle
;
input pci_slave_mode
;
output pci_slave_idsel
;
wire pci_slave_idsel;
input slave_idle
;
input pci_clk_sync
;
input pci_clk_sync_
;
output go_standby
;
output turn_off_standby
;
output pcic_idle
;
input [3:0] req_
;
output granto_host_
;
output [3:0] granto_
;
output grant_conf_
;
`define ARB_IDLE 2'b00
`define ARB_WAIT1 2'b01
`define ARB_WAITF 2'b11
`define ARB_BUSY 2'b10
reg any_x_req_ff
;
reg any_x_act_d1
;
reg any_x_act_d2
;
reg any_x_act_d3
;
reg any_x_act_d4
;
reg going_d1
;
reg going_d2
;
reg going_d3
;
reg going_d4
;
reg standby_park_req_d1
;
reg standby_park_req_d2
;
wire any_x_active
= any_x_req_ff | any_xint ;
wire turn_off_standby = any_x_active | any_x_act_d1 | any_x_act_d2
| any_x_act_d3 | any_x_act_d4 ;
wire hold_off_standby
= turn_off_standby | ~standby_park_req_d1
| ~standby_park_req_d2;
wire prog_go_standby
;
wire standby_park_req
= ~turn_off_standby & (prog_go_standby | pin_go_standby);
wire go_standby = ~hold_off_standby & (prog_go_standby | pin_go_standby);
wire any_x_req
= ~req_[3] | ~req_[2] | ~(req_[1] | pci_slave_mode)| ~req_[0];
wire pcic_going_idle
= sm_idle & mas_idle & afx_m_idle & slave_idle;
wire pcic_idle = pcic_going_idle & going_d1 & going_d2 & going_d3 & going_d4 ;
sync sync_mm( .out (prog_go_standby),
.in_clk (pci_clk_sync_),
.out_clk(pci_clk_sync),
.in (mm_go_standby)
);
always @(posedge clock)
begin
if (reset)
begin
any_x_req_ff <= #1 1'b0;
any_x_act_d1 <= #1 1'b0;
any_x_act_d2 <= #1 1'b0;
any_x_act_d3 <= #1 1'b0;
any_x_act_d4 <= #1 1'b0;
going_d1 <= #1 1'b1;
going_d2 <= #1 1'b1;
going_d3 <= #1 1'b1;
going_d4 <= #1 1'b1;
standby_park_req_d1 <= #1 1'b0;
standby_park_req_d2 <= #1 1'b0;
end
else
begin
any_x_req_ff <= #1 any_x_req ;
any_x_act_d1 <= #1 any_x_active ;
any_x_act_d2 <= #1 any_x_act_d1;
any_x_act_d3 <= #1 any_x_act_d2;
any_x_act_d4 <= #1 any_x_act_d3;
going_d1 <= #1 pcic_going_idle;
going_d2 <= #1 going_d1;
going_d3 <= #1 going_d2;
going_d4 <= #1 going_d3;
standby_park_req_d1 <= #1 standby_park_req;
standby_park_req_d2 <= #1 standby_park_req_d1;
end
end
// Revision: The input arb_asgn_reg[14:0] is used to assign the input
// requests (and grant outputs too) to a different signal in this module.
// In that way, the design of this module does not really change, but
// instead a new funciton is added, that reroutes the input request
// to other input requests before the fixed priorities are used. This
// makes the priorities appear programmable. (note the outputs have to
// be routed also, to match the requests).
//
// This is the monitoring for who used the bus last, in order to determine
// who will be given priority in the future. The saving of who used the
// bus last is established each time the frame signal is asserted after
// being deasserted. This is the start of a new transaction. The grants
// that were asserted in the cycle before the frame signal is asserted
// are used to determine which master asserted the frame. This monitoring
// is used if there is multilevel priority as described in the PCI
// specification (2.1, page 56). The last master to be granted the bus
// at each level (even if not currently granted at that level) must be
// remembered in order to be fair for subsequent requests.
//
// When arb_lvl_en is true, priorities are assigned as follows:
//
// Host vs. level1 -----Level 0 (one bit of storage)
// |
// slots 0 or 1 or level2 -----Level 1 (two bits of storage)
// |
// slots 2 or 3 -----Level 2 (one bit of storage)
//
// Every time a level is used, which position was used is saved so next
// time that level is accessed, then some other position is selected.
//
reg [3:0] grant_
; // Which master is granted this cycle.
reg grant_host_
; // Which master is granted this cycle.
reg [4:0] grant_last_
; // Which master was granted last cycle.
reg [4:0] last_master_
; // Which master asserted frame last.
reg l0_lst_
; // last level 0 granted bus
reg [1:0] l1_lst_
; // last level 1 granted bus
reg l2_lst_
; // last level 2 granted bus
wire req_keep_bus_
; // request to keep the bus at the master
assign req_keep_bus_ = req_conf_ & ~req_quiescence & ~standby_park_req ;
wire [4:0] reqs_
={asgn_map_func({(req_host_ & req_keep_bus_),req_},arb_asgn_reg[14:12]),
asgn_map_func({(req_host_ & req_keep_bus_),req_},arb_asgn_reg[11:9]),
asgn_map_func({(req_host_ & req_keep_bus_),req_},arb_asgn_reg[8:6]),
asgn_map_func({(req_host_ & req_keep_bus_),req_},arb_asgn_reg[5:3]),
asgn_map_func({(req_host_ & req_keep_bus_),req_},arb_asgn_reg[2:0])};
wire grant_conf_ = req_keep_bus_ | granto_host_;
wire [4:0] nxt_grnt_
= nxt_grnt_gen_(arb_lvl_en,last_master_,reqs_,l0_lst_,l1_lst_,l2_lst_);
wire [4:0] remapd_grnt0_
= asgn_out_func(grant_[0],arb_asgn_reg[2:0]) ;
wire [4:0] remapd_grnt1_
= asgn_out_func(grant_[1],arb_asgn_reg[5:3]) ;
wire [4:0] remapd_grnt2_
= asgn_out_func(grant_[2],arb_asgn_reg[8:6]) ;
wire [4:0] remapd_grnt3_
= asgn_out_func(grant_[3],arb_asgn_reg[11:9]) ;
wire [4:0] remapd_grnth_
= asgn_out_func(grant_host_,arb_asgn_reg[14:12]) ;
wire [4:0] grants_
= (remapd_grnth_ & remapd_grnt3_ & remapd_grnt2_ & remapd_grnt1_ & remapd_grnt0_);
wire granto_host_ = (arb_disable & req_[0] |
~arb_disable & grants_[4]);
wire [3:0] granto_ = arb_disable ? {2'b1, req_keep_bus_,(req_host_ & req_keep_bus_)}: grants_[3:0];
// add to support pci slave mode configuration operations
assign pci_slave_idsel = req_[1] & pci_slave_mode;
function [4:0] nxt_grnt_gen_;
input arb_lvl_en;
input [4:0] last_master_;
input [4:0] reqs_;
input l0_lst_; // Not used in this function (may not be
// needed in design at all! (since last_master
// msb is if host used bus last.)
input [1:0] l1_lst_;
input l2_lst_;
reg [4:0] tmp_nxt_grnt_;
begin
casex(arb_lvl_en)
1'b0: // fixed rotating priorities
begin
casex(last_master_)
5'b01111:
begin
casex(reqs_)
5'bxxxx0: tmp_nxt_grnt_ = 5'b11110;
5'bxxx01: tmp_nxt_grnt_ = 5'b11101;
5'bxx011: tmp_nxt_grnt_ = 5'b11011;
5'bx0111: tmp_nxt_grnt_ = 5'b10111;
5'b01111: tmp_nxt_grnt_ = 5'b01111;
default: tmp_nxt_grnt_ = last_master_;
endcase
end
5'b11110:
begin
casex(reqs_)
5'bxxx0x: tmp_nxt_grnt_ = 5'b11101;
5'bxx01x: tmp_nxt_grnt_ = 5'b11011;
5'bx011x: tmp_nxt_grnt_ = 5'b10111;
5'b0111x: tmp_nxt_grnt_ = 5'b01111;
5'b11110: tmp_nxt_grnt_ = 5'b11110;
default: tmp_nxt_grnt_ = last_master_;
endcase
end
5'b11101:
begin
casex(reqs_)
5'bxx0xx: tmp_nxt_grnt_ = 5'b11011;
5'bx01xx: tmp_nxt_grnt_ = 5'b10111;
5'b011xx: tmp_nxt_grnt_ = 5'b01111;
5'b111x0: tmp_nxt_grnt_ = 5'b11110;
5'b11101: tmp_nxt_grnt_ = 5'b11101;
default: tmp_nxt_grnt_ = last_master_;
endcase
end
5'b11011:
begin
casex(reqs_)
5'bx0xxx: tmp_nxt_grnt_ = 5'b10111;
5'b01xxx: tmp_nxt_grnt_ = 5'b01111;
5'b11xx0: tmp_nxt_grnt_ = 5'b11110;
5'b11x01: tmp_nxt_grnt_ = 5'b11101;
5'b11011: tmp_nxt_grnt_ = 5'b11011;
default: tmp_nxt_grnt_ = last_master_;
endcase
end
5'b10111:
begin
casex(reqs_)
5'b0xxxx: tmp_nxt_grnt_ = 5'b01111;
5'b1xxx0: tmp_nxt_grnt_ = 5'b11110;
5'b1xx01: tmp_nxt_grnt_ = 5'b11101;
5'b1x011: tmp_nxt_grnt_ = 5'b11011;
5'b10111: tmp_nxt_grnt_ = 5'b10111;
default: tmp_nxt_grnt_ = last_master_;
endcase
end
5'b11111:
begin
casex(reqs_)
5'b0xxxx: tmp_nxt_grnt_ = 5'b01111;
5'b1xxx0: tmp_nxt_grnt_ = 5'b11110;
5'b1xx01: tmp_nxt_grnt_ = 5'b11101;
5'b1x011: tmp_nxt_grnt_ = 5'b11011;
5'b10111: tmp_nxt_grnt_ = 5'b10111;
default: tmp_nxt_grnt_ = last_master_;
endcase
end
default: tmp_nxt_grnt_ = 5'b01111; // assign host next grant if
// last_master is hosed!
endcase
end
// This is the three level priority area. Level 0 alternates
// between the host and all other slots. The host is granted
// access to the bus up to 50% of the accesses. Level 1 consists
// of slots 0 and 1. A third level 1 position is given to level 2
// slots, which are slots 2 and 3.
//
// Level 0 ---> Host vs level 1 (alternates every transaction)
// |
// v
// Level 1 ------> slot 0 vs 1 vs level 2 (rotates every Level 1 transaction)
// |
// v
// Level 2 ---------> slot 2 vs 3 (alternates every Level 2 transaction)
1'b1: // three levels of priority
begin
casex(last_master_)
5'b01111: // host (level 0) went last
begin // check who was last user at each level (level 0 known to be host)
casex({l1_lst_[1:0],l2_lst_})
3'b1x1: // last level 1 user was really a level 2 slot (3)
begin // therefore slot 0 will be next level 1 user
casex(reqs_[4:0])
5'bxxxx0: tmp_nxt_grnt_ = 5'b11110; // slot 0 request and grant
5'bxxx01: tmp_nxt_grnt_ = 5'b11101; // slot 1 request and grant
// no level 1 requests so check level 2 below
5'bxx011: tmp_nxt_grnt_ = 5'b11011; // slot 2 request and grant
5'bx0111: tmp_nxt_grnt_ = 5'b10111; // slot 3 request and grant
// no level 1 or 2 requests
5'b01111: tmp_nxt_grnt_ = 5'b01111; // defaults back to host
default: tmp_nxt_grnt_ = last_master_; // no level 1 or 2 requests
endcase
end
3'b1x0: // last level 1 user was really a level 2 slot (2)
begin
casex(reqs_[4:0])
5'bxxxx0: tmp_nxt_grnt_ = 5'b11110; // slot 0 request and grant
5'bxxx01: tmp_nxt_grnt_ = 5'b11101; // slot 1 request and grant
// no level 1 requests so check level 2 below
5'bx0x11: tmp_nxt_grnt_ = 5'b10111; // slot 3 request and grant
5'bx1011: tmp_nxt_grnt_ = 5'b11011; // slot 2 request and grant
// no level 1 or 2 requests
5'b01111: tmp_nxt_grnt_ = 5'b01111; // defaults back to host
default: tmp_nxt_grnt_ = last_master_; // no level 1 or 2 requests
endcase
end
3'b000: // last level 1 user was slot 0, last level 2 was slot 2
begin
casex(reqs_[4:0])
// go right to level 1 requests first (slot 1)
// only check slot 1 at level 1, then go to level 2, slot 3 next
5'bxxx0x: tmp_nxt_grnt_ = 5'b11101; // slot 1 request and grant
// no level 2 requests so check level 1 below
5'bx0x1x: tmp_nxt_grnt_ = 5'b10111; // slot 3 request and grant
5'bx101x: tmp_nxt_grnt_ = 5'b11011; // slot 2 request and grant
// go back to level 1 requests now (slot 0)
5'bx1110: tmp_nxt_grnt_ = 5'b11110; // slot 0 request and grant
// no level 1 or 2 requests
5'b01111: tmp_nxt_grnt_ = 5'b01111; // defaults back to host
default: tmp_nxt_grnt_ = last_master_; // no level 1 or 2 requests
endcase
end
3'b001: // last level 1 user was slot 0, last level 2 was slot 3
begin
casex(reqs_[4:0])
// go right to level 1 requests first (slot 1)
// only check slot 1 at level 1, then go to level 2, slot 2 next
5'bxxx0x: tmp_nxt_grnt_ = 5'b11101; // slot 1 request and grant
// go right to level 2 requests first (slot 2 before slot 3)
5'bxx01x: tmp_nxt_grnt_ = 5'b11011; // slot 2 request and grant
5'bx011x: tmp_nxt_grnt_ = 5'b10111; // slot 3 request and grant
// go back to level 1 requests now (slot 0)
5'bx1110: tmp_nxt_grnt_ = 5'b11110; // slot 0 request and grant
// no level 1 or 2 requests
5'b01111: tmp_nxt_grnt_ = 5'b01111; // defaults back to host
default: tmp_nxt_grnt_ = last_master_; // no level 1 or 2 requests
endcase
end
3'b010: // last level 1 user was slot 1, last level 2 was slot 2
begin
casex(reqs_[4:0])
// go right to level 2 requests first (slot 3 first)
5'bx0xxx: tmp_nxt_grnt_ = 5'b10111; // slot 3 request and grant
5'bx10xx: tmp_nxt_grnt_ = 5'b11011; // slot 2 request and grant
// no level 2 requests so check level 1 below
5'bx11x0: tmp_nxt_grnt_ = 5'b11110; // slot 0 request and grant
5'bx1101: tmp_nxt_grnt_ = 5'b11101; // slot 1 request and grant
// no level 1 or 2 requests
5'b01111: tmp_nxt_grnt_ = 5'b01111; // defaults back to host
default: tmp_nxt_grnt_ = last_master_; // no level 1 or 2 requests
endcase
end
3'b011: // last level 1 user was slot 0, last level 2 was slot 3
begin
casex(reqs_[4:0])
// go right to level 2 requests first (slot 2 first)
5'bxx0xx: tmp_nxt_grnt_ = 5'b11011; // slot 2 request and grant
5'bx01xx: tmp_nxt_grnt_ = 5'b10111; // slot 3 request and grant
// no level 2 requests so check level 1 below
5'bx11x0: tmp_nxt_grnt_ = 5'b11110; // slot 0 request and grant
5'bx1101: tmp_nxt_grnt_ = 5'b11101; // slot 1 request and grant
// no level 1 or 2 requests
5'b01111: tmp_nxt_grnt_ = 5'b01111; // defaults back to host
default: tmp_nxt_grnt_ = last_master_; // no level 1 or 2 requests
endcase
end
default: tmp_nxt_grnt_ = last_master_;
endcase
end
5'b11110: // level 1, slot 0 went last, slot 1 goes next
begin // check who was last user level 2 (level 0 and 1 known)
casex(l2_lst_)
1'b0: // last level 2 user was slot 2
begin
casex(reqs_[4:0])
5'b0xxxx: tmp_nxt_grnt_ = 5'b01111; // host request and grant
5'b1xx0x: tmp_nxt_grnt_ = 5'b11101; // slot 1 request and grant
// no level 1 requests so check level 2 below
5'b10x1x: tmp_nxt_grnt_ = 5'b10111; // slot 3 request and grant
5'b1101x: tmp_nxt_grnt_ = 5'b11011; // slot 2 request and grant
// then go back to level 1 again
5'b11110: tmp_nxt_grnt_ = 5'b11110; // slot 0 request and grant
default: tmp_nxt_grnt_ = last_master_; // no level 1 or 2 requests
endcase
end
1'b1: // last level 2 user was slot 3
begin
casex(reqs_[4:0])
5'b0xxxx: tmp_nxt_grnt_ = 5'b01111; // host request and grant
5'b1xx0x: tmp_nxt_grnt_ = 5'b11101; // slot 1 request and grant
// no level 1 requests so check level 2 below
5'b1x01x: tmp_nxt_grnt_ = 5'b11011; // slot 2 request and grant
5'b1011x: tmp_nxt_grnt_ = 5'b10111; // slot 3 request and grant
// then go back to level 1 again
5'b11110: tmp_nxt_grnt_ = 5'b11110; // slot 0 request and grant
default: tmp_nxt_grnt_ = last_master_; // no level 1 or 2 requests
endcase
end
default: tmp_nxt_grnt_ = last_master_;
endcase
end
5'b11101: // level 1, slot 1 went last, level 2 goes next
begin
casex(l2_lst_)
1'b0: // last level 2 user was slot 2
begin
casex(reqs_[4:0])
5'b0xxxx: tmp_nxt_grnt_ = 5'b01111; // host request and grant
// now check level 2 below
5'b10xxx: tmp_nxt_grnt_ = 5'b10111; // slot 3 request and grant
5'b110xx: tmp_nxt_grnt_ = 5'b11011; // slot 2 request and grant
// then go back to level 1 again
5'b111x0: tmp_nxt_grnt_ = 5'b11110; // slot 0 request and grant
5'b11101: tmp_nxt_grnt_ = 5'b11101; // slot 1 request and grant
default: tmp_nxt_grnt_ = last_master_; // no level 1 or 2 requests
endcase
end
1'b1: // last level 2 user was slot 3
begin
casex(reqs_[4:0])
5'b0xxxx: tmp_nxt_grnt_ = 5'b01111; // host request and grant
// now check level 2 below
5'b1x0xx: tmp_nxt_grnt_ = 5'b11011; // slot 2 request and grant
5'b101xx: tmp_nxt_grnt_ = 5'b10111; // slot 3 request and grant
// then go back to level 1 again
5'b111x0: tmp_nxt_grnt_ = 5'b11110; // slot 0 request and grant
5'b11101: tmp_nxt_grnt_ = 5'b11101; // slot 1 request and grant
default: tmp_nxt_grnt_ = last_master_; // no level 1 or 2 requests
endcase
end
endcase
end
5'b11011: // level 2, slot 2 went last, slot 3 goes next
begin
casex(reqs_[4:0])
5'b0xxxx: tmp_nxt_grnt_ = 5'b01111; // host request and grant
// now check level 1 below
5'b1xxx0: tmp_nxt_grnt_ = 5'b11110; // slot 0 request and grant
5'b1xx01: tmp_nxt_grnt_ = 5'b11101; // slot 1 request and grant
// then go back to level 2 again
5'b10x11: tmp_nxt_grnt_ = 5'b10111; // slot 3 request and grant
5'b11011: tmp_nxt_grnt_ = 5'b11011; // slot 2 request and grant
default: tmp_nxt_grnt_ = last_master_; // no level 1 or 2 requests
endcase
end
5'b10111: // level 2, slot 3 went last, slot 2 goes next
begin
casex(reqs_[4:0])
5'b0xxxx: tmp_nxt_grnt_ = 5'b01111; // host request and grant
// now check level 1 below
5'b1xxx0: tmp_nxt_grnt_ = 5'b11110; // slot 0 request and grant
5'b1xx01: tmp_nxt_grnt_ = 5'b11101; // slot 1 request and grant
// then go back to level 2 again
5'b1x011: tmp_nxt_grnt_ = 5'b11011; // slot 2 request and grant
5'b10111: tmp_nxt_grnt_ = 5'b10111; // slot 3 request and grant
default: tmp_nxt_grnt_ = last_master_; // no level 1 or 2 requests
endcase
end
default: tmp_nxt_grnt_ = 5'b01111; // assign host next grant if
endcase // last_master_ is hosed.
end
default: tmp_nxt_grnt_ = last_master_;
endcase
nxt_grnt_gen_ = tmp_nxt_grnt_;
end
endfunction
// Process requests in generating grants.
reg [3:0] Wait4FrameCnt
;
reg [1:0] arb_state
;
// rev 2.0 does not use term req_new, instead uses term req_any
wire req_new
= |( last_master_[4:0] & ~reqs_ );
wire req_current_grnt
= |( ~{grant_host_,grant_} & ~reqs_ );
wire req_any
= ~&reqs_;
wire StopWait4Frame
= &Wait4FrameCnt ;
wire clkLast
= (new_frame | ((arb_state == `ARB_WAITF) & StopWait4Frame));
wire l2Last
= ~&grant_last_[1:0]; // any level 2 grants?
always @(posedge clock)
begin
if (arb_state == `ARB_WAITF)
Wait4FrameCnt <= #1 (Wait4FrameCnt + 1'b1);
else
Wait4FrameCnt <= #1 4'b0000;
end
wire [4:0] grant_last_in
= (reset ? 5'b11111 : { grant_host_,grant_ }) ;
always @(posedge clock)
begin
grant_last_ <= #1 grant_last_in;
if (reset)
begin
last_master_ <= 5'b01111;
l0_lst_ <= 1'b0;
l1_lst_ <= 2'b00;
l2_lst_ <= 1'b0;
end
else if (clkLast && ~grant_last_[4]) // last master was host
begin
last_master_ <= #1 grant_last_;
l0_lst_ <= #1 grant_last_[4];
end
else if (clkLast && l2Last) // last master was level 2
begin
last_master_ <= #1 grant_last_;
l0_lst_ <= #1 grant_last_[4];
l1_lst_ <= #1 ({ ~&grant_last_[3:2],grant_last_[0] });
end
else if (clkLast) // last master was level 3
begin
last_master_ <= #1 grant_last_;
l0_lst_ <= #1 grant_last_[4];
l1_lst_ <= #1 ({ ~&grant_last_[3:2],grant_last_[0] });
l2_lst_ <= #1 grant_last_[2];
end
end
function [1:0] arb_sm;
input [1:0] arb_state;
input new_frame;
input bus_idle;
input req_new;
input req_any;
input req_current_grnt;
input StopWait4Frame;
// note: a input that compares the next grants (internal only)
// with the current requests is needed for ARB_WAITF testing.
// Also someting that counts on the 16 waits for a frame.
reg [1:0] ns; // next state
begin
case (arb_state)
// ARB_IDLE is used when the bus is parked on a position (last master).
// It is also used to ignore all other requests when the bus is locked.
// During idle the bus is granted to the last_master that used the bus,
// or if there is a new_request (not last_master), all grants are turned
// off for one cycle to prevent a parked master that has been doing
// address stepping from conflicting with the next master.
`ARB_IDLE: // ARB_IDLE
begin
if (new_frame)
begin // last master took bus
ns = `ARB_BUSY;
end
else if (req_current_grnt)
begin // last master asks for bus
ns = `ARB_WAITF;
end
// rev 2.0 chng else if (req_new)
else if (req_any)
begin // other master asks for bus
ns = `ARB_WAIT1;
end
else ns = `ARB_IDLE;
end
// ARB_WAIT1 is used to allow the bus to be idle one cycle where there is no
// grants since a master may use the bus just when it has a grant, even though
// it has no request, for address stepping. During ARB_WAIT1, the current set of
// requests are examined and a next grant made based on the highest priority
// request. If there are no requests (it dropped out?) the state machine returns
// back to ARB_IDLE and gives the grant to the last_master.
`ARB_WAIT1: // ARB_WAIT1
begin
if (new_frame)
begin // last granted took bus
ns = `ARB_BUSY;
end
// rev 2.0 chng else if (req_new)
else if (req_any)
begin // any master wants bus; arbitrate!
ns = `ARB_WAITF;
end
else ns = `ARB_IDLE;
end
// ARB_WAITF is used to insure that a master that has been granted the bus and
// has kept it's request on, will respond by starting a transaction within
// 16 clocks. If it doesn't, it will be marked as the last_master, which will
// automatically give it the lowest priority. If it drops it's request during
// this wait time, the state machine will return to ARB_WAIT1 in order to
// rearbitrate and either return to ARB_IDLE or ARB_WAITF if there is another
// request. NOTE: WAITF is also used when a configuration cycle is needed.
`ARB_WAITF:
begin
if (new_frame)
begin // last granted took bus
ns = `ARB_BUSY;
end
else if (~req_current_grnt || StopWait4Frame )
begin // no request anymore or timeout
ns = `ARB_WAIT1;
end
else ns = `ARB_WAITF;
end
// ARB_BUSY is used to monitor transactions. When a transaction starts, the
// busy state is entered. During this time, if the bus is not locked, all
// input requests can be monitored and a grant supplied to the highest
// priority output. At the completion of a transaction, if the bus is locked
// or there are no other requests (req_new based on last_master) the state
// machine returns to idle. If there are other requests and the bus in not
// locked, the highest priority is granted and transitions to ARB_WAITF is made.
`ARB_BUSY: // ARB_BUSY
begin
if (bus_idle && req_current_grnt )
begin // current request also has grant
ns = `ARB_WAITF;
end
else if (bus_idle && req_any)
begin // request but not matching current grant
ns = `ARB_WAIT1;
end
else if (bus_idle )
begin // no requests, grant to last master to use bus
ns = `ARB_IDLE;
end
else ns = `ARB_BUSY;
end
default:
begin
ns = `ARB_IDLE; // ERROR; just for testing
end
endcase
arb_sm[1:0] = ns;
end
endfunction
wire [1:0] arb_state_in
= arb_sm(arb_state, new_frame, bus_idle, req_new, req_any, req_current_grnt, StopWait4Frame );
always @(posedge clock)
begin
if (reset)
begin
arb_state <= `ARB_IDLE;
end
else
begin
arb_state <= #1 arb_state_in;
end
end
// see notes in log for 3/5/97
always @(posedge clock)
begin
// in rev 2.0 change req_new to req_any
// if (reset || ((arb_state == `ARB_IDLE) && ~new_frame && ~req_current_grnt && req_new) ||
if (reset || ((arb_state == `ARB_IDLE) && ~new_frame && ~req_current_grnt && req_any) ||
((arb_state == `ARB_WAITF) && ~new_frame && ~req_current_grnt) ||
((arb_state == `ARB_WAITF) && ~new_frame && StopWait4Frame) ||
((arb_state == `ARB_BUSY) && bus_idle && req_any && ~req_current_grnt) )
begin // going to WAIT1: turn off all grants for one clock cycle
grant_host_ <= #1 1'b1;
grant_ <= #1 4'b1111;
end
// following lines are added for rev 2.0
else if (((arb_state == `ARB_WAITF) & new_frame) |
((arb_state == `ARB_WAITF) & req_current_grnt & ~StopWait4Frame) |
((arb_state == `ARB_WAIT1) & new_frame) | // this term could be deleted to allow
// arbitration this cycle (no grnt should
// be true this cycle anyway!)
((arb_state == `ARB_BUSY) & bus_idle & req_current_grnt) |
((arb_state == `ARB_BUSY) & bus_idle & req_any & ~req_current_grnt ) |
((arb_state == `ARB_BUSY) & bus_idle & ~req_any ) |
((arb_state == `ARB_IDLE) & new_frame ) |
((arb_state == `ARB_IDLE) & req_current_grnt ) |
((arb_state == `ARB_IDLE) & ~req_any ) )
begin // going to hold current grant while waiting
grant_host_ <= #1 grant_host_;
grant_ <= #1 grant_[3:0];
end
// The following else is redundant, since last_master is default as part of arbitration.
// else if (arb_state == `ARB_IDLE)
// begin // put out grant to last master that used bus
// grant_host_ <= #1 last_master_[4];
// grant_ <= #1 last_master_[3:0];
// end
else
begin // arbitrate! highest priority goes out (finally)
grant_host_ <= #1 nxt_grnt_[4];
grant_ <= #1 nxt_grnt_[3:0];
end
end
function [4:0] asgn_out_func;
input grant_;
input [2:0] arb_asgn_reg;
reg [4:0] tmp_asgn_out_func;
begin
casex ({grant_,arb_asgn_reg})
4'b1xxx: tmp_asgn_out_func = 5'b11111; // no grant out
4'b01xx: tmp_asgn_out_func = 5'b01111; // grant out to host
4'b0000: tmp_asgn_out_func = 5'b11110; // grant out to slot 0
4'b0001: tmp_asgn_out_func = 5'b11101; // grant out to slot 1
4'b0010: tmp_asgn_out_func = 5'b11011; // grant out to slot 2
4'b0011: tmp_asgn_out_func = 5'b10111; // grant out to slot 3
default: tmp_asgn_out_func = 5'b11111; // no grant out
endcase
asgn_out_func = tmp_asgn_out_func;
end
endfunction
function asgn_map_func;
input [4:0] req_in_;
input [2:0] arb_asgn_reg;
reg tmp_asgn_map_func;
begin
casex ({arb_asgn_reg,req_in_})
8'bxxx11111: tmp_asgn_map_func = 1'b1; // outputs off
8'b000xxxx1: tmp_asgn_map_func = 1'b1; // map postition 0 to output
8'b000xxxx0: tmp_asgn_map_func = 1'b0; // map postition 0 to output
8'b001xxx1x: tmp_asgn_map_func = 1'b1; // map postition 1 to output
8'b001xxx0x: tmp_asgn_map_func = 1'b0; // map postition 1 to output
8'b010xx1xx: tmp_asgn_map_func = 1'b1; // map postition 2 to output
8'b010xx0xx: tmp_asgn_map_func = 1'b0; // map postition 2 to output
8'b011x1xxx: tmp_asgn_map_func = 1'b1; // map postition 3 to output
8'b011x0xxx: tmp_asgn_map_func = 1'b0; // map postition 3 to output
8'b1xx1xxxx: tmp_asgn_map_func = 1'b1; // map postition 4 to output
8'b1xx0xxxx: tmp_asgn_map_func = 1'b0; // map postition 4 to output
default: tmp_asgn_map_func = 1'b1; // output off
endcase
asgn_map_func = tmp_asgn_map_func;
end
endfunction
endmodule
This page: |
Created: | Thu Aug 19 12:02:43 1999 |
| From: |
../../../sparc_v8/ssparc/pcic/arbiter/rtl/arbiter.v
|