blob: e78d8fef63399421b955dc09411e6fe714243eda [file] [log] [blame] [edit]
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T1 Processor File: i2c_fctrl.v
// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
//
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
//
// The above named program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
//
// ========== Copyright Header End ============================================
////////////////////////////////////////////////////////////////////////
/*
// Module Name: i2c_fctrl (io-to-cpu fast control)
// Description:
*/
////////////////////////////////////////////////////////////////////////
// Global header file includes
////////////////////////////////////////////////////////////////////////
`include "sys.h" // system level definition file which contains the
// time scale definition
`include "iop.h"
////////////////////////////////////////////////////////////////////////
// Local header file includes / local defines
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// Interface signal list declarations
////////////////////////////////////////////////////////////////////////
module i2c_fctrl (/*AUTOARG*/
// Outputs
int_buf_sel_next, io_buf_sel_next, int_buf_rd, io_buf_rd,
int_buf_hit_hwm, io_buf_head_f, int_buf_wr, int_buf_tail_ptr,
int_buf_head_ptr, io_buf_head_ptr,
// Inputs
cpu_rst_l, cpu_clk, tx_sync, rx_sync, cpx_iob_grant_cx2,
int_buf_cpx_req, io_buf_cpx_req, iob_cpx_req_next,
cpu_mondo_rd_d2, cpu_mondo_wr_d2, io_buf_tail_s
);
////////////////////////////////////////////////////////////////////////
// Signal declarations
////////////////////////////////////////////////////////////////////////
// Global interface
input cpu_rst_l;
input cpu_clk;
input tx_sync;
input rx_sync;
// Crossbar interface
input [`IOB_CPU_WIDTH-1:0] cpx_iob_grant_cx2;
// i2c fast datapath interface
input [`IOB_CPU_WIDTH-1:0] int_buf_cpx_req;
input [`IOB_CPU_WIDTH-1:0] io_buf_cpx_req;
input [`IOB_CPU_WIDTH-1:0] iob_cpx_req_next;
output int_buf_sel_next;
output io_buf_sel_next;
output int_buf_rd;
output io_buf_rd;
// c2i fast control interface
input cpu_mondo_rd_d2;
input cpu_mondo_wr_d2;
output int_buf_hit_hwm;
// i2c slow control interface
input [`IOB_IO_BUF_INDEX:0] io_buf_tail_s;
output [`IOB_IO_BUF_INDEX:0] io_buf_head_f;
// Interrupt table read result buffer interface
output int_buf_wr;
output [`IOB_INT_BUF_INDEX-1:0] int_buf_tail_ptr;
output [`IOB_INT_BUF_INDEX-1:0] int_buf_head_ptr;
// IO buffer interface
output [`IOB_IO_BUF_INDEX-1:0] io_buf_head_ptr;
// Internal signals
wire [`IOB_CPU_WIDTH-1:0] cpx_buf_full;
wire [`IOB_CPU_WIDTH-1:0] cpx_iob_grant;
wire cpu_mondo_rdwr_d2;
wire [`IOB_INT_BUF_INDEX:0] int_buf_tail;
wire [`IOB_INT_BUF_INDEX:0] int_buf_tail_plus;
wire [`IOB_INT_BUF_INDEX:0] int_buf_tail_plus10;
wire [`IOB_INT_BUF_INDEX:0] int_buf_head;
wire [`IOB_INT_BUF_INDEX:0] int_buf_head_prev;
wire [`IOB_INT_BUF_INDEX:0] int_buf_head_plus1;
wire int_buf_head_inc;
wire int_buf_empty;
wire int_buf_empty_prev;
wire int_buf_vld;
wire int_buf_vld_next;
wire [`IOB_IO_BUF_INDEX:0] io_buf_head;
wire [`IOB_IO_BUF_INDEX:0] io_buf_head_prev;
wire [`IOB_IO_BUF_INDEX:0] io_buf_head_plus1;
wire io_buf_head_inc;
wire [`IOB_IO_BUF_INDEX:0] io_buf_tail;
wire io_buf_empty;
wire io_buf_empty_prev;
wire io_buf_vld;
wire io_buf_vld_next;
////////////////////////////////////////////////////////////////////////
// Code starts here
////////////////////////////////////////////////////////////////////////
/************************************************************
* IO-to-CPX Mux Control
************************************************************/
// Generate mux selects
assign int_buf_sel_next = ~|(cpx_buf_full & ~cpx_iob_grant & int_buf_cpx_req) &
int_buf_vld;
assign io_buf_sel_next = ~|(cpx_buf_full & ~cpx_iob_grant & io_buf_cpx_req) &
~int_buf_sel_next & io_buf_vld;
/************************************************************
* Flop grant from CPX
************************************************************/
dffrl_ns #(`IOB_CPU_WIDTH) cpx_iob_grant_ff (.din(cpx_iob_grant_cx2),
.clk(cpu_clk),
.rst_l(cpu_rst_l),
.q(cpx_iob_grant));
/************************************************************
* Counters to keep track of each CPX's buffer level
************************************************************/
// CPX0 Count
i2c_cpx_cnt count0 (.rst_l(cpu_rst_l),
.clk(cpu_clk),
.iob_cpx_req_next(iob_cpx_req_next[0]),
.cpx_iob_grant(cpx_iob_grant[0]),
.cpx_buf_full(cpx_buf_full[0]));
// CPX1 Count
i2c_cpx_cnt count1 (.rst_l(cpu_rst_l),
.clk(cpu_clk),
.iob_cpx_req_next(iob_cpx_req_next[1]),
.cpx_iob_grant(cpx_iob_grant[1]),
.cpx_buf_full(cpx_buf_full[1]));
// CPX2 Count
i2c_cpx_cnt count2 (.rst_l(cpu_rst_l),
.clk(cpu_clk),
.iob_cpx_req_next(iob_cpx_req_next[2]),
.cpx_iob_grant(cpx_iob_grant[2]),
.cpx_buf_full(cpx_buf_full[2]));
// CPX3 Count
i2c_cpx_cnt count3 (.rst_l(cpu_rst_l),
.clk(cpu_clk),
.iob_cpx_req_next(iob_cpx_req_next[3]),
.cpx_iob_grant(cpx_iob_grant[3]),
.cpx_buf_full(cpx_buf_full[3]));
// CPX4 Count
i2c_cpx_cnt count4 (.rst_l(cpu_rst_l),
.clk(cpu_clk),
.iob_cpx_req_next(iob_cpx_req_next[4]),
.cpx_iob_grant(cpx_iob_grant[4]),
.cpx_buf_full(cpx_buf_full[4]));
// CPX5 Count
i2c_cpx_cnt count5 (.rst_l(cpu_rst_l),
.clk(cpu_clk),
.iob_cpx_req_next(iob_cpx_req_next[5]),
.cpx_iob_grant(cpx_iob_grant[5]),
.cpx_buf_full(cpx_buf_full[5]));
// CPX6 Count
i2c_cpx_cnt count6 (.rst_l(cpu_rst_l),
.clk(cpu_clk),
.iob_cpx_req_next(iob_cpx_req_next[6]),
.cpx_iob_grant(cpx_iob_grant[6]),
.cpx_buf_full(cpx_buf_full[6]));
// CPX7 Count
i2c_cpx_cnt count7 (.rst_l(cpu_rst_l),
.clk(cpu_clk),
.iob_cpx_req_next(iob_cpx_req_next[7]),
.cpx_iob_grant(cpx_iob_grant[7]),
.cpx_buf_full(cpx_buf_full[7]));
/************************************************************
* Interrupt Status Table Read Result Buffer Control
* An 16 deep buffer to store interrupt table read results.
*
* __decode int stat table read
* flop req |
* | | __read int stat table here
* | | |
* | | | __flop read result
* | | | |
* | | | | __tail pointer increment
* | | | | |
* | | | | | compute hwm __stall sent here
* | | | | | | |
* V V V V d2 V V V
* PQ PA PX1 rptr PX2 C1 C2 C3 C4 C5 rptr
* PQ PA PX1 rptr PX2 C1 C2 C3 C4 C5 rptr
* PQ PA PX1 rptr PX2 C1 C2 C3 C4
* PQ PA PX1 rptr PX2 C1 C2 C3
* PQ PA PX1 rptr PX2 C1 C2
* PQ PA PX1 rptr PX2 C1
* PQ PA PX1 rptr PX2
* PQ PA PX1 rptr
* PQ PA PX1 rptr
* PQ PA PX1 rptr
* PQ PA PX1
* --> PQ
* |
* |
* packet in this PQ is stalled
*
* When stall is signalled, there can potentially be 10 packets in C4, C3,
* C2, C1, PX2, rptr, PX1, PA, PQ, and PQ-1 that need to be queued in the CPU shared buffer.
************************************************************/
assign cpu_mondo_rdwr_d2 = cpu_mondo_rd_d2 | cpu_mondo_wr_d2;
assign int_buf_wr = cpu_mondo_rdwr_d2;
// Tail pointer to interrupt table read result buffer
dffrle_ns #(`IOB_INT_BUF_INDEX+1) int_buf_tail_ff (.din(int_buf_tail_plus),
.rst_l(cpu_rst_l),
.en(int_buf_wr),
.clk(cpu_clk),
.q(int_buf_tail));
assign int_buf_tail_plus = int_buf_tail + 5'b1;
assign int_buf_tail_ptr = int_buf_tail[`IOB_INT_BUF_INDEX-1:0];
assign int_buf_tail_plus10 = int_buf_tail + 5'b01010;
assign int_buf_hit_hwm = ((int_buf_tail_plus10[`IOB_INT_BUF_INDEX] != int_buf_head[`IOB_INT_BUF_INDEX]) &
(int_buf_tail_plus10[`IOB_INT_BUF_INDEX-1:0] >= int_buf_head[`IOB_INT_BUF_INDEX-1:0])) |
((int_buf_tail_plus10[`IOB_INT_BUF_INDEX] == int_buf_head[`IOB_INT_BUF_INDEX]) &
(int_buf_tail_plus10[`IOB_INT_BUF_INDEX-1:0] <= int_buf_head[`IOB_INT_BUF_INDEX-1:0]));
// Head pointer to interrupt table read result buffer
dffrl_ns #(`IOB_INT_BUF_INDEX+1) int_buf_head_prev_ff (.din(int_buf_head),
.clk(cpu_clk),
.rst_l(cpu_rst_l),
.q(int_buf_head_prev));
assign int_buf_head_plus1 = int_buf_head_prev + 4'b1;
assign int_buf_head = int_buf_head_inc ? int_buf_head_plus1 :
int_buf_head_prev;
assign int_buf_head_ptr = int_buf_head[`IOB_INT_BUF_INDEX-1:0];
// Interrupt table read result buffer is empty if head == tail
assign int_buf_empty = (int_buf_head == int_buf_tail);
dff_ns #(1) int_buf_empty_prev_ff (.din(int_buf_empty|~cpu_rst_l),
.clk(cpu_clk),
.q(int_buf_empty_prev));
assign int_buf_head_inc = ~int_buf_empty_prev &
((int_buf_vld & int_buf_sel_next) |
~int_buf_vld);
// This read signal corresponds to the access already in the memory
assign int_buf_rd = int_buf_head_inc;
assign int_buf_vld_next = int_buf_rd |
(int_buf_vld & ~int_buf_sel_next);
dffrl_ns #(1) int_buf_vld_ff (.din(int_buf_vld_next),
.clk(cpu_clk),
.rst_l(cpu_rst_l),
.q(int_buf_vld));
/************************************************************
* IO Buffer Control
************************************************************/
// Head pointer to io buffer
dffrl_ns #(`IOB_IO_BUF_INDEX+1) io_buf_head_prev_ff (.din(io_buf_head),
.clk(cpu_clk),
.rst_l(cpu_rst_l),
.q(io_buf_head_prev));
assign io_buf_head_plus1 = io_buf_head_prev + 5'b1;
assign io_buf_head = io_buf_head_inc ? io_buf_head_plus1 :
io_buf_head_prev;
assign io_buf_head_ptr = io_buf_head[`IOB_IO_BUF_INDEX-1:0];
dffrle_ns #(`IOB_IO_BUF_INDEX+1) io_buf_head_f_ff (.din(io_buf_head),
.rst_l(cpu_rst_l),
.en(tx_sync),
.clk(cpu_clk),
.q(io_buf_head_f));
// Flop tail pointer once to convert to cpu clock domain
dffrle_ns #(`IOB_IO_BUF_INDEX+1) io_buf_tail_ff (.din(io_buf_tail_s),
.rst_l(cpu_rst_l),
.en(rx_sync),
.clk(cpu_clk),
.q(io_buf_tail));
// IO buffer is empty if head == tail
assign io_buf_empty = (io_buf_head == io_buf_tail);
dff_ns #(1) io_buf_empty_prev_ff (.din(io_buf_empty|~cpu_rst_l),
.clk(cpu_clk),
.q(io_buf_empty_prev));
assign io_buf_head_inc = ~io_buf_empty_prev &
((io_buf_vld & io_buf_sel_next) |
~io_buf_vld);
// This read signal corresponds to the access already in the memory
assign io_buf_rd = io_buf_head_inc;
assign io_buf_vld_next = io_buf_rd |
(io_buf_vld & ~io_buf_sel_next);
dffrl_ns #(1) io_buf_vld_ff (.din(io_buf_vld_next),
.clk(cpu_clk),
.rst_l(cpu_rst_l),
.q(io_buf_vld));
endmodule // i2c_fctrl