// ========== Copyright Header Begin ========================================== // // OpenSPARC T1 Processor File: ucb_flow_jbi.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: ucb_flow_jbi // Description: Unit Control Block // - supports 1B/2B/4B/8B/16B read with flow control // - supports 1B/2B/4B/8B write with flow control // - does NOT support ifill request // - supports interrupt return to IO Bridge // - provides 1+2 deep buffer for incoming requests // from the IO Bridge // - provides single buffer for returns going back // to the IO Bridge // // This module is customized for the JBI. // // Data bus width to and from the IO Bridge is // configured through parameters UCB_IOB_WIDTH and // IOB_UCB_WIDTH. Supported widths are: // // IOB_UCB_WIDTH UCB_IOB_WIDTH // ---------------------------- // 32 8 // 16 8 // 8 8 // 4 4 */ //////////////////////////////////////////////////////////////////////// // 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 //////////////////////////////////////////////////////////////////////// `define UCB_BUF_DEPTH 2 `define UCB_BUF_WIDTH 64+(`UCB_ADDR_HI-`UCB_ADDR_LO+1)+(`UCB_SIZE_HI-`UCB_SIZE_LO+1)+(`UCB_BUF_HI-`UCB_BUF_LO+1)+(`UCB_THR_HI-`UCB_THR_LO+1)+1+1 module ucb_flow_jbi (/*AUTOARG*/ // Outputs ucb_iob_stall, rd_req_vld, wr_req_vld, thr_id_in, buf_id_in, size_in, addr_in, data_in, ack_busy, int_busy, ucb_iob_vld, ucb_iob_data, // Inputs clk, rst_l, iob_ucb_vld, iob_ucb_data, req_acpted, rd_ack_vld, rd_nack_vld, thr_id_out, buf_id_out, data128, data_out, int_vld, int_typ, int_thr_id, dev_id, int_stat, int_vec, iob_ucb_stall ); // synopsys template parameter IOB_UCB_WIDTH = 32; // data bus width from IOB to UCB parameter UCB_IOB_WIDTH = 8; // data bus width from UCB to IOB parameter REG_WIDTH = 128; // please do not change this parameter // Globals input clk; input rst_l; // Request from IO Bridge input iob_ucb_vld; input [IOB_UCB_WIDTH-1:0] iob_ucb_data; output ucb_iob_stall; // Request to local unit output rd_req_vld; output wr_req_vld; output [`UCB_THR_HI-`UCB_THR_LO:0] thr_id_in; output [`UCB_BUF_HI-`UCB_BUF_LO:0] buf_id_in; output [`UCB_SIZE_HI-`UCB_SIZE_LO:0] size_in; // only pertinent to JBI and SPI output [`UCB_ADDR_HI-`UCB_ADDR_LO:0] addr_in; output [`UCB_DATA_HI-`UCB_DATA_LO:0] data_in; input req_acpted; // Ack/Nack from local unit input rd_ack_vld; input rd_nack_vld; input [`UCB_THR_HI-`UCB_THR_LO:0] thr_id_out; input [`UCB_BUF_HI-`UCB_BUF_LO:0] buf_id_out; input data128; // set to 1 if data returned is 128 bit input [REG_WIDTH-1:0] data_out; output ack_busy; // Interrupt from local unit input int_vld; input [`UCB_PKT_HI-`UCB_PKT_LO:0] int_typ; // interrupt type input [`UCB_THR_HI-`UCB_THR_LO:0] int_thr_id; // interrupt thread ID input [`UCB_INT_DEV_HI-`UCB_INT_DEV_LO:0] dev_id; // interrupt device ID input [`UCB_INT_STAT_HI-`UCB_INT_STAT_LO:0] int_stat; // interrupt status input [`UCB_INT_VEC_HI-`UCB_INT_VEC_LO:0] int_vec; // interrupt vector output int_busy; // Output to IO Bridge output ucb_iob_vld; output [UCB_IOB_WIDTH-1:0] ucb_iob_data; input iob_ucb_stall; // Local signals wire indata_buf_vld; wire [127:0] indata_buf; wire ucb_iob_stall_a1; wire read_pending; wire write_pending; wire rd_buf; wire [`UCB_BUF_DEPTH-1:0] buf_head_next; wire [`UCB_BUF_DEPTH-1:0] buf_head; wire wr_buf; wire [`UCB_BUF_DEPTH-1:0] buf_tail_next; wire [`UCB_BUF_DEPTH-1:0] buf_tail; wire buf_full_next; wire buf_full; wire buf_empty_next; wire buf_empty; wire [`UCB_BUF_WIDTH-1:0] req_in; wire buf0_en; wire [`UCB_BUF_WIDTH-1:0] buf0; wire buf1_en; wire [`UCB_BUF_WIDTH-1:0] buf1; wire [`UCB_BUF_WIDTH-1:0] req_out; wire rd_req_vld_nq; wire wr_req_vld_nq; wire ack_buf_rd; wire ack_buf_wr; wire ack_buf_vld; wire ack_buf_vld_next; wire ack_buf_is_nack; wire ack_buf_is_data128; wire [`UCB_PKT_HI-`UCB_PKT_LO:0] ack_typ_out; wire [REG_WIDTH+`UCB_BUF_HI-`UCB_PKT_LO:0] ack_buf_in; wire [REG_WIDTH+`UCB_BUF_HI-`UCB_PKT_LO:0] ack_buf; wire [(REG_WIDTH+64)/UCB_IOB_WIDTH-1:0] ack_buf_vec; wire int_buf_rd; wire int_buf_wr; wire int_buf_vld; wire int_buf_vld_next; wire [`UCB_INT_VEC_HI-`UCB_PKT_LO:0] int_buf_in; wire [`UCB_INT_VEC_HI-`UCB_PKT_LO:0] int_buf; wire [(REG_WIDTH+64)/UCB_IOB_WIDTH-1:0] int_buf_vec; wire int_last_rd; wire outdata_buf_busy; wire outdata_buf_wr; wire [REG_WIDTH+63:0] outdata_buf_in; wire [(REG_WIDTH+64)/UCB_IOB_WIDTH-1:0] outdata_vec_in; //////////////////////////////////////////////////////////////////////// // Code starts here //////////////////////////////////////////////////////////////////////// /************************************************************ * Inbound Data ************************************************************/ // Register size is hardcoded to 64 bits here ucb_bus_in #(IOB_UCB_WIDTH,64) ucb_bus_in (.rst_l(rst_l), .clk(clk), .vld(iob_ucb_vld), .data(iob_ucb_data), .stall(ucb_iob_stall), .indata_buf_vld(indata_buf_vld), .indata_buf(indata_buf), .stall_a1(ucb_iob_stall_a1)); /************************************************************ * Decode inbound packet type ************************************************************/ assign read_pending = (indata_buf[`UCB_PKT_HI:`UCB_PKT_LO] == `UCB_READ_REQ) & indata_buf_vld; assign write_pending = (indata_buf[`UCB_PKT_HI:`UCB_PKT_LO] == `UCB_WRITE_REQ) & indata_buf_vld; assign ucb_iob_stall_a1 = (read_pending | write_pending) & buf_full; /************************************************************ * Inbound buffer ************************************************************/ // Head pointer assign rd_buf = req_acpted; assign buf_head_next = ~rst_l ? `UCB_BUF_DEPTH'b01 : rd_buf ? {buf_head[`UCB_BUF_DEPTH-2:0], buf_head[`UCB_BUF_DEPTH-1]} : buf_head; dff_ns #(`UCB_BUF_DEPTH) buf_head_ff (.din(buf_head_next), .clk(clk), .q(buf_head)); // Tail pointer assign wr_buf = (read_pending | write_pending) & ~buf_full; assign buf_tail_next = ~rst_l ? `UCB_BUF_DEPTH'b01 : wr_buf ? {buf_tail[`UCB_BUF_DEPTH-2:0], buf_tail[`UCB_BUF_DEPTH-1]} : buf_tail; dff_ns #(`UCB_BUF_DEPTH) buf_tail_ff (.din(buf_tail_next), .clk(clk), .q(buf_tail)); // Buffer full assign buf_full_next = (buf_head_next == buf_tail_next) & wr_buf; dffrle_ns #(1) buf_full_ff (.din(buf_full_next), .rst_l(rst_l), .en(rd_buf|wr_buf), .clk(clk), .q(buf_full)); // Buffer empty assign buf_empty_next = ((buf_head_next == buf_tail_next) & rd_buf) | ~rst_l; dffe_ns #(1) buf_empty_ff (.din(buf_empty_next), .en(rd_buf|wr_buf|~rst_l), .clk(clk), .q(buf_empty)); assign req_in = {indata_buf[`UCB_DATA_HI:`UCB_DATA_LO], indata_buf[`UCB_ADDR_HI:`UCB_ADDR_LO], indata_buf[`UCB_SIZE_HI:`UCB_SIZE_LO], indata_buf[`UCB_BUF_HI:`UCB_BUF_LO], indata_buf[`UCB_THR_HI:`UCB_THR_LO], write_pending, read_pending}; // Buffer 0 assign buf0_en = buf_tail[0] & wr_buf; dffe_ns #(`UCB_BUF_WIDTH) buf0_ff (.din(req_in), .en(buf0_en), .clk(clk), .q(buf0)); // Buffer 1 assign buf1_en = buf_tail[1] & wr_buf; dffe_ns #(`UCB_BUF_WIDTH) buf1_ff (.din(req_in), .en(buf1_en), .clk(clk), .q(buf1)); assign req_out = buf_head[0] ? buf0 : buf_head[1] ? buf1 : {`UCB_BUF_WIDTH{1'b0}}; /************************************************************ * Inbound interface to local unit ************************************************************/ assign {data_in, addr_in, size_in, buf_id_in, thr_id_in, wr_req_vld_nq, rd_req_vld_nq} = req_out; assign rd_req_vld = rd_req_vld_nq & ~buf_empty; assign wr_req_vld = wr_req_vld_nq & ~buf_empty; /************************************************************ * Outbound Ack/Nack ************************************************************/ assign ack_buf_wr = rd_ack_vld | rd_nack_vld; assign ack_buf_vld_next = ack_buf_wr ? 1'b1 : ack_buf_rd ? 1'b0 : ack_buf_vld; dffrl_ns #(1) ack_buf_vld_ff (.din(ack_buf_vld_next), .clk(clk), .rst_l(rst_l), .q(ack_buf_vld)); dffe_ns #(1) ack_buf_is_nack_ff (.din(rd_nack_vld), .en(ack_buf_wr), .clk(clk), .q(ack_buf_is_nack)); dffe_ns #(1) ack_buf_is_data128_ff (.din(data128), .en(ack_buf_wr), .clk(clk), .q(ack_buf_is_data128)); assign ack_typ_out = rd_ack_vld ? `UCB_READ_ACK: `UCB_READ_NACK; assign ack_buf_in = {data_out, buf_id_out, thr_id_out, ack_typ_out}; dffe_ns #(REG_WIDTH+`UCB_BUF_HI-`UCB_PKT_LO+1) ack_buf_ff (.din(ack_buf_in), .en(ack_buf_wr), .clk(clk), .q(ack_buf)); assign ack_buf_vec = ack_buf_is_nack ? {{REG_WIDTH/UCB_IOB_WIDTH{1'b0}}, {64/UCB_IOB_WIDTH{1'b1}}} : ack_buf_is_data128 ? {(REG_WIDTH+64)/UCB_IOB_WIDTH{1'b1}} : {(64+64)/UCB_IOB_WIDTH{1'b1}}; assign ack_busy = ack_buf_vld; /************************************************************ * Outbound Interrupt ************************************************************/ // Assertion: int_buf_wr shoudn't be asserted if int_buf_busy assign int_buf_wr = int_vld; assign int_buf_vld_next = int_buf_wr ? 1'b1 : int_buf_rd ? 1'b0 : int_buf_vld; dffrl_ns #(1) int_buf_vld_ff (.din(int_buf_vld_next), .clk(clk), .rst_l(rst_l), .q(int_buf_vld)); assign int_buf_in = {int_vec, int_stat, dev_id, int_thr_id, int_typ}; dffe_ns #(`UCB_INT_VEC_HI-`UCB_PKT_LO+1) int_buf_ff (.din(int_buf_in), .en(int_buf_wr), .clk(clk), .q(int_buf)); assign int_buf_vec = {{REG_WIDTH/UCB_IOB_WIDTH{1'b0}}, {64/UCB_IOB_WIDTH{1'b1}}}; assign int_busy = int_buf_vld; /************************************************************ * Outbound ack/interrupt Arbitration ************************************************************/ dffrle_ns #(1) int_last_rd_ff (.din(int_buf_rd), .en(ack_buf_rd|int_buf_rd), .rst_l(rst_l), .clk(clk), .q(int_last_rd)); assign ack_buf_rd = ~outdata_buf_busy & ack_buf_vld & (~int_buf_vld | int_last_rd); assign int_buf_rd = ~outdata_buf_busy & int_buf_vld & (~ack_buf_vld | ~int_last_rd); assign outdata_buf_wr = ack_buf_rd | int_buf_rd; assign outdata_buf_in = ack_buf_rd ? {ack_buf[REG_WIDTH+`UCB_BUF_HI:`UCB_BUF_HI+1], {(`UCB_RSV_HI-`UCB_RSV_LO+1){1'b0}}, {(`UCB_ADDR_HI-`UCB_ADDR_LO+1){1'b0}}, {(`UCB_SIZE_HI-`UCB_SIZE_LO+1){1'b0}}, ack_buf[`UCB_BUF_HI:`UCB_BUF_LO], ack_buf[`UCB_THR_HI:`UCB_THR_LO], ack_buf[`UCB_PKT_HI:`UCB_PKT_LO]}: {{REG_WIDTH{1'b0}}, {(`UCB_INT_RSV_HI-`UCB_INT_RSV_LO+1){1'b0}}, int_buf[`UCB_INT_VEC_HI:`UCB_INT_VEC_LO], int_buf[`UCB_INT_STAT_HI:`UCB_INT_STAT_LO], int_buf[`UCB_INT_DEV_HI:`UCB_INT_DEV_LO], int_buf[`UCB_THR_HI:`UCB_THR_LO], int_buf[`UCB_PKT_HI:`UCB_PKT_LO]}; assign outdata_vec_in = ack_buf_rd ? ack_buf_vec : int_buf_vec; ucb_bus_out #(UCB_IOB_WIDTH, REG_WIDTH) ucb_bus_out (.rst_l(rst_l), .clk(clk), .outdata_buf_wr(outdata_buf_wr), .outdata_buf_in(outdata_buf_in), .outdata_vec_in(outdata_vec_in), .outdata_buf_busy(outdata_buf_busy), .vld(ucb_iob_vld), .data(ucb_iob_data), .stall(iob_ucb_stall)); `undef UCB_BUF_WIDTH endmodule // ucb_flow_jbi // Local Variables: // verilog-library-directories:(".") // End: