Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / design / sys / iop / niu / rtl / xdeferral.v
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: xdeferral.v
// Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved
// 4150 Network Circle, Santa Clara, California 95054, U.S.A.
//
// * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 2 of the License.
//
// This 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 program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// For the avoidance of doubt, and except that if any non-GPL license
// choice is available it will apply instead, Sun elects to use only
// the General Public License version 2 (GPLv2) at this time for any
// software where a choice of GPL license versions is made
// available with the language indicating that GPLv2 or any later version
// may be used, or where a choice of which version of the GPL is applied is
// otherwise unspecified.
//
// Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
// CA 95054 USA or visit www.sun.com if you need additional information or
// have any questions.
//
// ========== Copyright Header End ============================================
/*%W% %G%*/
/*************************************************************************
*
* File Name : xdeferral.v
* Author Name : John Lo
* Description :
* Parent Module: tx_xmac
* Child Module: none
* Interface Mod:
* Date Created : 6/8/00
*
* Copyright (c) 2002, Sun Microsystems, Inc.
* Sun Proprietary and Confidential
*
* Modification :
*
* Synthesis Notes:
*
*************************************************************************/
`include "xmac.h"
module xdeferral (
tx_clk,
tx_reset,
mii_mode,
gmii_mode,
tx_byte_count_en,
tx_en_8bit,
stretch_mode,
stretch_constant,
stretch_ratio,
ipg_value,
tx_on_half, // to modify last_byte_position
add_crc, // cond1 plus !no_crc -> add 4 crc bytes
eop_txclk,
last_byte_position,
var_min_ipg_en,
pa_time,
back2back_swap_reg1,
set_back2back,
// outputs
tx_swap,
ipg_done,
final_ipg_clks,
// internal observation
full_case_last_byte_position,
adjust2crc_full_case_last_byte_position,
adjust2crc_full_case_last_byte_position_is_3_or_7,
stretch_full_case_last_byte_position,
stretch_clks,
stretch_bytes,
stretch_1_more_clk,
B_eop,
minus_4bytes,
no_wasted_BW // no wasted band width (bytes).
);
input tx_clk;
input tx_reset;
// vlint flag_input_port_not_connected off
input mii_mode;
input gmii_mode;
// vlint flag_input_port_not_connected on
input tx_byte_count_en;
input [7:0] tx_en_8bit;
input stretch_mode;
input [2:0] stretch_constant;
input [4:0] stretch_ratio;
input [2:0] ipg_value;
input tx_on_half; // to modify last_byte_position
input add_crc; // cond1 plus !no_crc -> add 4 crc bytes
input eop_txclk;
input [2:0] last_byte_position;
input var_min_ipg_en;
input pa_time;
input back2back_swap_reg1;
input set_back2back;
// outputs
output tx_swap;
output ipg_done;
output [`BYTE] final_ipg_clks;
// internal observation
output [2:0] full_case_last_byte_position;
output [2:0] adjust2crc_full_case_last_byte_position;
output adjust2crc_full_case_last_byte_position_is_3_or_7;
output [3:0] stretch_full_case_last_byte_position;
output [`BYTE] stretch_clks;
output [2:0] stretch_bytes;
output stretch_1_more_clk;
output B_eop;
output minus_4bytes;
output no_wasted_BW; // no wasted band width (bytes).
// vlint flag_dangling_net_within_module off
// vlint flag_net_has_no_load off
// vlint flag_input_port_not_connected off
wire mii_mode;
wire gmii_mode;
// vlint flag_input_port_not_connected on
// vlint flag_net_has_no_load on
// vlint flag_dangling_net_within_module on
/* ------------- start of stretch mode logic ---------------------- */
// This implementation enable the residue bits to be available for
// next coming packet ipg extension calculation.
reg [4:0] addend_stretch_byte_count;
wire [4:0] new_stretch_byte_count;
reg [4:0] nx_stretch_byte_count;
wire [4:0] stretch_byte_count;
reg stretch_1byte;
// addend selection mux
always @ (tx_en_8bit or tx_byte_count_en or stretch_mode)
if (tx_byte_count_en & stretch_mode)
casex (tx_en_8bit) // synopsys parallel_case full_case
8'b1xxxxxxx: addend_stretch_byte_count = 8;
8'b01xxxxxx: addend_stretch_byte_count = 7;
8'b001xxxxx: addend_stretch_byte_count = 6;
8'b0001xxxx: addend_stretch_byte_count = 5;
8'b00001xxx: addend_stretch_byte_count = 4;
8'b000001xx: addend_stretch_byte_count = 3;
8'b0000001x: addend_stretch_byte_count = 2;
8'b00000001: addend_stretch_byte_count = 1;
8'b00000000: addend_stretch_byte_count = 0;
default: addend_stretch_byte_count = 0;
endcase // casex(tx_en_8bit)
else addend_stretch_byte_count = 0;
// adder
assign new_stretch_byte_count =
(stretch_byte_count + addend_stretch_byte_count);
// subtractor
// The stretch_ratio in octet should not be bigger than data path width.
always @ (new_stretch_byte_count or stretch_ratio)
if ((new_stretch_byte_count >= stretch_ratio))
begin
// Since it exceeds stretch_ratio, one more byte is added (stretched)
// to IPG (stretch_1byte=1).
// The purpose of subtract stretch_ratio is to get the residue
// byte count for next round calculation.
nx_stretch_byte_count = new_stretch_byte_count - stretch_ratio;
stretch_1byte = 1; // add one byte per stretch_ratio
end
else
begin
nx_stretch_byte_count = new_stretch_byte_count;
stretch_1byte = 0;
end
RegRst #(5) stretch_byte_count_RegRst(
.clk(tx_clk),
.reset(tx_reset | (~stretch_mode) | (pa_time & ~set_back2back)),
.din(nx_stretch_byte_count),
.qout(stretch_byte_count));
// stretch_size counter
wire [10:0] stretch_size;
wire [10:0] nx_stretch_size;
assign nx_stretch_size = stretch_1byte ? (stretch_size + 1) :
stretch_size;
RegRst2 #(11) stretch_size_RegRst2(
.clk(tx_clk),
.reset(tx_reset | (~stretch_mode) | pa_time),
.reset_value({8'b0,stretch_constant[2:0]}),
.din(nx_stretch_size),
.qout(stretch_size));
wire [`BYTE] stretch_clks = nx_stretch_size[10:3];
wire [2:0] stretch_bytes = nx_stretch_size[2:0];
/* ------------- end of stretch mode logic ------------------------ */
/* ------------------- credit management logic ------------------- */
// add_crc is valid only at eop_txclk time
// For cond2 and cond3 runt packets, the eop is always at the 3rd
// byte of A side then add fcs to make 64 bytes to meet min pkt size.
// tx_on_half takes care of cond2 and cond3 caes.
// add_crc takes care of cond1 and normal cases.
// add_crc = ~no_crc | add_fcs;
// \\ originai implementation. Before modifying for stretch_mode.
// wire [2:0] full_case_last_byte_position = tx_on_half ? 3'h3:
// last_byte_position[2:0];
wire [2:0] org_full_case_last_byte_position = tx_on_half ? 3'h3:
last_byte_position[2:0];
wire [3:0] stretch_full_case_last_byte_position =
{1'b0,org_full_case_last_byte_position[2:0]} +
{1'b0,stretch_bytes[2:0]};
xMUX_2to1 #(3) full_case_last_byte_positio_xMUX_2to1(
.din0(org_full_case_last_byte_position[2:0]),
.din1(stretch_full_case_last_byte_position[2:0]),
.sel(stretch_mode),
.dout(full_case_last_byte_position[2:0]));
wire [2:0] adjust2crc_full_case_last_byte_position = add_crc ?
(full_case_last_byte_position[2:0] + `FOUR_CRC_BYTES) :
full_case_last_byte_position[2:0] ;
wire adjust2crc_full_case_last_byte_position_is_3_or_7 =
(&adjust2crc_full_case_last_byte_position[`MERGE_A_B]);
wire [1:0] pos_credit = (3 -
adjust2crc_full_case_last_byte_position[`MERGE_A_B]);
wire [1:0] neg_credit = (1 +
adjust2crc_full_case_last_byte_position[`MERGE_A_B]);
wire no_wasted_BW = adjust2crc_full_case_last_byte_position_is_3_or_7 &
(ipg_value[2:0] == 3'h3);
// By default or when var_min_ipg_en == 0, the xdeferral logic will
// generate more than 12 bytes ipg (always minus_4bytes == 0) at
// the end of each packet.
//
// In var_min_ipg_en == 1 mode.
// When the current_credit is negative at the eop_txclk time, the
// minus_4bytes == 0, this will make the logic default to not subtract
// 4 bytes ipg. The end results of ipg shown in the waveform should
// be longer than min_ipg (12 bytes). Vise versa.
reg [4:0] current_credit;
wire minus_4bytes = eop_txclk &
(current_credit >= `CREDIT_BIAS) &
(~no_wasted_BW) &
var_min_ipg_en ;
wire [4:0] net_credit = minus_4bytes ?
current_credit - {3'b0,neg_credit[1:0]} :
current_credit + {3'b0,pos_credit[1:0]} ;
always @ (posedge tx_clk)
if (tx_reset)
current_credit <= `CREDIT_BIAS;
else if (eop_txclk)
current_credit <= net_credit;
else
current_credit <= current_credit; // hold
// synopsys translate_off
// diag purpose
always @ (/*AUTOSENSE*/`CREDIT_BIAS or current_credit or gmii_mode
or mii_mode or stretch_mode or tx_reset)
if ( stretch_mode & (!tx_reset) & ~(mii_mode | gmii_mode) & ((current_credit < (`CREDIT_BIAS - 3)) | (current_credit > (`CREDIT_BIAS + 3))))
$display("\n (* ERROR: at sim time = %d, in xdeferral.v, current credit is wrong => current_credit = %h *) \n", $time, current_credit);
else ;
// synopsys translate_on
/* ------------------- end of credit management logic ------------ */
/* ------------------- ipg_timer logic ---------------------------- */
// final_ipg_value is the tx_clk number which is 4 bytes in granularity.
// @ eop_txclk only
wire [2:0] final_ipg_value = ipg_value[2:0] - {2'b0,minus_4bytes};
// synopsys translate_off
// diag purpose
always @ (/*AUTOSENSE*/final_ipg_value or gmii_mode or mii_mode
or stretch_mode or tx_reset)
if ( stretch_mode & (!tx_reset) & ~(mii_mode | gmii_mode) & (final_ipg_value < 2))
$display("\n (* ERROR: at sim time = %d, in xdeferral.v, final_ipg_value less than 2 clk (less than 8 byte times), final_ipg_value = %h *) \n", $time, final_ipg_value);
else ;
// synopsys translate_on
reg temp_tx_swap;
reg set_tx_swap;
reg [`BYTE] ipg_timer;
reg [2:0] rounded_ipg_clks;
wire ipg_timer_ce = (|ipg_timer[`BYTE]);
wire ipg_done = ~ipg_timer_ce;
// It has to use nx_ipg_extension_count. Since eop_txclk and
// inc_ipg_extension_count can happen at the same time.
wire stretch_1_more_clk = stretch_mode &
stretch_full_case_last_byte_position[3];
wire [`BYTE] final_ipg_clks = {5'b0,rounded_ipg_clks[2:0]} +
stretch_clks[`BYTE] +
{7'b0,stretch_1_more_clk};
always @ (posedge tx_clk)
if (tx_reset)
begin
temp_tx_swap <= 0 ;
ipg_timer <= 0 ;
end
else if (eop_txclk) // load final_ipg_value at eop time.
begin
temp_tx_swap <= set_tx_swap ;
ipg_timer <= final_ipg_clks;
end
else if (ipg_timer_ce)
begin
temp_tx_swap <= temp_tx_swap ; // hold
ipg_timer <= ipg_timer - 1 ; // 8 byte time per txclk
end
else // hold
begin
temp_tx_swap <= temp_tx_swap ; // hold
ipg_timer <= ipg_timer ;
end
xREG #(1) tx_swap_xREG(.din(temp_tx_swap),
.clk(tx_clk),
.en(pa_time),
.reset(tx_reset),
.qout(tx_swap));
wire B_eop = full_case_last_byte_position[2]; // eop byte is in byte 4~7.
always @ (/*AUTOSENSE*/B_eop or add_crc or back2back_swap_reg1
or eop_txclk or final_ipg_value)
if (eop_txclk)
casex (final_ipg_value) // synopsys parallel_case full_case
3'h2: casex ({add_crc,B_eop}) // synopsys parallel_case full_case
2'b00: begin // eop in A side
rounded_ipg_clks = {2'b0,back2back_swap_reg1} ? 3'd1 : 3'd0;
set_tx_swap = back2back_swap_reg1 ? 1'b0 : 1'b1; // flip
end
2'b01: begin // eop in B side
rounded_ipg_clks = 3'd1;
set_tx_swap = back2back_swap_reg1 ? 1'b1 : 1'b0; // flip
end
2'b10: begin // eop in A side
rounded_ipg_clks = 3'd1;
set_tx_swap = back2back_swap_reg1 ? 1'b1 : 1'b0; // flip
end
2'b11: begin // eop in B side
rounded_ipg_clks = {2'b0,back2back_swap_reg1} ? 3'd2 : 3'd1;
set_tx_swap = back2back_swap_reg1 ? 1'b0 : 1'b1; // flip
end
endcase
3'h3: casex ({add_crc,B_eop}) // synopsys parallel_case full_case
2'b00: begin // eop in A side
rounded_ipg_clks = 3'd1;
set_tx_swap = back2back_swap_reg1 ? 1'b1 : 1'b0; // flip
end
2'b01: begin // eop in B side
rounded_ipg_clks = {2'b0,back2back_swap_reg1} ? 3'd2 : 3'd1;
set_tx_swap = back2back_swap_reg1 ? 1'b0 : 1'b1; // flip
end
2'b10: begin // eop in A side
rounded_ipg_clks = {2'b0,back2back_swap_reg1} ? 3'd2 : 3'd1;
set_tx_swap = back2back_swap_reg1 ? 1'b0 : 1'b1; // flip
end
2'b11: begin // eop in B side
rounded_ipg_clks = 3'd2;
set_tx_swap = back2back_swap_reg1 ? 1'b1 : 1'b0; // flip
end
endcase
3'h4: casex ({add_crc,B_eop}) // synopsys parallel_case full_case
2'b00: begin // eop in A side
rounded_ipg_clks = {2'b0,back2back_swap_reg1} ? 3'd2 : 3'd1;
set_tx_swap = back2back_swap_reg1 ? 1'b0 : 1'b1;
end
2'b01: begin // eop in B side
rounded_ipg_clks = 3'd2;
set_tx_swap = back2back_swap_reg1 ? 1'b1 : 1'b0;
end
2'b10: begin // eop in A side
rounded_ipg_clks = 3'd2;
set_tx_swap = back2back_swap_reg1 ? 1'b1 : 1'b0;
end
2'b11: begin // eop in B side
rounded_ipg_clks = {2'b0,back2back_swap_reg1} ? 3'd3 : 3'd2;
set_tx_swap = back2back_swap_reg1 ? 1'b0 : 1'b1;
end
endcase
3'h5: casex ({add_crc,B_eop}) // synopsys parallel_case full_case
2'b00: begin // eop in A side
rounded_ipg_clks = 3'd2;
set_tx_swap = back2back_swap_reg1 ? 1'b1 : 1'b0;
end
2'b01: begin // eop in B side
rounded_ipg_clks = {2'b0,back2back_swap_reg1} ? 3'd3 : 3'd2;
set_tx_swap = back2back_swap_reg1 ? 1'b0 : 1'b1;
end
2'b10: begin // eop in A side
rounded_ipg_clks = {2'b0,back2back_swap_reg1} ? 3'd3 : 3'd2;
set_tx_swap = back2back_swap_reg1 ? 1'b0 : 1'b1;
end
2'b11: begin // eop in B side
rounded_ipg_clks = 3'd3;
set_tx_swap = back2back_swap_reg1 ? 1'b1 : 1'b0;
end
endcase
3'h6: casex ({add_crc,B_eop}) // synopsys parallel_case full_case
2'b00: begin // eop in A side
rounded_ipg_clks = {2'b0,back2back_swap_reg1} ? 3'd3 : 3'd2;
set_tx_swap = back2back_swap_reg1 ? 1'b0 : 1'b1;
end
2'b01: begin // eop in B side
rounded_ipg_clks = 3'd3;
set_tx_swap = back2back_swap_reg1 ? 1'b1 : 1'b0;
end
2'b10: begin // eop in A side
rounded_ipg_clks = 3'd3;
set_tx_swap = back2back_swap_reg1 ? 1'b1 : 1'b0;
end
2'b11: begin // eop in B side
rounded_ipg_clks = {2'b0,back2back_swap_reg1} ? 3'd4 : 3'd3;
set_tx_swap = back2back_swap_reg1 ? 1'b0 : 1'b1;
end
endcase
3'h7: casex ({add_crc,B_eop}) // synopsys parallel_case full_case
2'b00: begin // eop in A side
rounded_ipg_clks = 3'd3;
set_tx_swap = back2back_swap_reg1 ? 1'b1 : 1'b0;
end
2'b01: begin // eop in B side
rounded_ipg_clks = {2'b0,back2back_swap_reg1} ? 3'd4 : 3'd3;
set_tx_swap = back2back_swap_reg1 ? 1'b0 : 1'b1;
end
2'b10: begin // eop in A side
rounded_ipg_clks = {2'b0,back2back_swap_reg1} ? 3'd4 : 3'd3;
set_tx_swap = back2back_swap_reg1 ? 1'b0 : 1'b1;
end
2'b11: begin // eop in B side
rounded_ipg_clks = 3'd4;
set_tx_swap = back2back_swap_reg1 ? 1'b1 : 1'b0;
end
endcase
default: // default to final_ipg_value = 3
begin
casex ({add_crc,B_eop}) // synopsys parallel_case full_case
2'b00: begin // eop in A side
rounded_ipg_clks = 3'd1;
set_tx_swap = back2back_swap_reg1 ? 1'b1 : 1'b0;
end
2'b01: begin // eop in B side
rounded_ipg_clks = {2'b0,back2back_swap_reg1} ? 3'd2 : 3'd1;
set_tx_swap = back2back_swap_reg1 ? 1'b0 : 1'b1;
end
2'b10: begin // eop in A side
rounded_ipg_clks = {2'b0,back2back_swap_reg1} ? 3'd2 : 3'd1;
set_tx_swap = back2back_swap_reg1 ? 1'b0 : 1'b1;
end
2'b11: begin // eop in B side
rounded_ipg_clks = 3'd2;
set_tx_swap = back2back_swap_reg1 ? 1'b1 : 1'b0;
end
endcase // casex({add_crc,B_eop})
end // case: endcase...
endcase // casex(final_ipg_value)
else begin
rounded_ipg_clks = 3'd2;
set_tx_swap = 1'b0;
end // else: !if(eop_txclk)
/* ------------------- end of ipg_timer logic --------------------- */
endmodule // xdeferral