Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / model / verilog / niu / mdio_mmd_model / mdio_mmd_model.v
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: mdio_mmd_model.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 ============================================
`include "mdio_model_defines.vh"
module mdio_mmd_model (reset, mdc, mdio_in, mdio_out, mdio_en);
input reset;
input mdc;
input mdio_in;
output mdio_out;
output mdio_en;
wire mdio_en_id_match_pre;
wire mdio_en_id_match_post;
wire mdio_en = mdio_en_id_match_post;
wire mdio_out;
reg mdio_d;
integer bit_cnt;
integer bit_cnt_preamble;
integer bit_cnt_read;
reg [3:0] state;
reg [3:0] next_state;
reg [1:0] st;
reg [1:0] op;
reg [4:0] prtad;
reg [4:0] phyad;
reg [4:0] devad;
reg [4:0] regad;
reg [15:0] addr;
reg [1:0] ta;
reg [15:0] data;
reg write_en_22;
reg write_en_45;
reg [15:0] read_data;
// storage
reg [15:0] memory [65535:0]; // supports upto 64K registers
// debug
wire [15:0] memory0 = memory[0];
wire [15:0] memory1 = memory[1];
wire [15:0] memory2 = memory[2];
wire [15:0] memory3 = memory[3];
wire [15:0] memory4 = memory[4];
wire [15:0] memory5 = memory[5];
wire [15:0] memory6 = memory[6];
wire [15:0] memory7 = memory[7];
wire [15:0] memory8 = memory[8];
wire [15:0] memory9 = memory[9];
wire [15:0] memory100 = memory[100];
wire [15:0] memory200 = memory[200];
parameter MY_PRT_ID = `MDIO_MMD_MODEL_PRT_ID;
parameter MY_PHY_ID = `MDIO_MMD_MODEL_PHY_ID;
parameter MY_DEV_ID = `MDIO_MMD_MODEL_DEV_ID;
parameter
IDLE = 0,
PREAMBLE= 1,
ST = 2,
OP = 3,
PRTAD = 4,
PHYAD = 5,
DEVAD = 6,
REGAD = 7,
TA = 8,
ADDR = 9,
DATA_RD = 10,
DATA_RDP= 11,
DATA_WR = 12;
assign mdio_out = ((next_state == DATA_RD | next_state == DATA_RDP) &&
(bit_cnt_read == 17) && (op[1] == 1'b1)) ?
1'bz : ((next_state == DATA_RD | next_state == DATA_RDP) &&
(bit_cnt_read == 16) && (op[1] == 1'b1)) ?
1'b0 : ((next_state == DATA_RD | next_state == DATA_RDP |
state == DATA_RD | state == DATA_RDP) &&
(op[1] == 1'b1)) ?
read_data[bit_cnt_read] : 1'bz;
assign mdio_en_id_match_pre = ((next_state == DATA_RD | next_state == DATA_RDP) &&
(bit_cnt_read == 17) && (op[1] == 1'b1)) ?
1'b1 : ((next_state == DATA_RD | next_state == DATA_RDP) &&
(bit_cnt_read == 16) && (op[1] == 1'b1)) ?
1'b1 : ((next_state == DATA_RD | next_state == DATA_RDP |
state == DATA_RD | state == DATA_RDP) &&
(op[1] == 1'b1)) ?
1'b1 : 1'b0;
assign mdio_en_id_match_post = ((st == 2'b01) && (phyad[4:0] == MY_PHY_ID)) ? // Claus22
mdio_en_id_match_pre :
((st == 2'b00) && (prtad[4:0] == MY_PRT_ID) && (devad[4:0] == MY_DEV_ID)) ?
mdio_en_id_match_pre : 1'b0;
// combinational logic
always @(reset or state or mdio_in or bit_cnt or st or op or bit_cnt_read or bit_cnt_preamble)
begin
case (state)
IDLE :
if(reset)
next_state = IDLE;
else if(mdio_in === 1'b1)
next_state = PREAMBLE;
else
next_state = IDLE;
PREAMBLE :
if((mdio_in === 1'b0) && (bit_cnt_preamble < 31))
next_state = IDLE;
else if((mdio_in == 1'b0) && (bit_cnt_preamble >= 31))
next_state = ST;
else
next_state = PREAMBLE;
ST :
if((bit_cnt == 0) && ((st == 2'b11) | (st == 2'b10))) begin
$display("<%0d> MDIO_DEBUG: ERROR: Invalid MDIO transaction st:%h , state:%h, next_state:%h %m",
$time, st, state, next_state);
next_state = IDLE;
end
else if(bit_cnt == 0)
next_state = OP;
else
next_state = ST;
OP :
if((bit_cnt == 0) && (st == 2'b01))
next_state = PHYAD;
else if((bit_cnt == 0) && (st == 2'b00))
next_state = PRTAD;
else
next_state = OP;
PHYAD : // Claus22 Specific
if(bit_cnt == 0)
next_state = REGAD;
else
next_state = PHYAD;
PRTAD : // Claus45 specific
if(bit_cnt == 0)
next_state = DEVAD;
else
next_state = PRTAD;
DEVAD : // Claus45 specific
if((bit_cnt == 0) && (op == 2'b00))
next_state = TA;
else if((bit_cnt == 0) && (op == 2'b01))
next_state = TA;
else if((bit_cnt == 0) && (op == 2'b11))
next_state = DATA_RD;
else if((bit_cnt == 0) && (op == 2'b10) && (st == 2'b01)) // Claus22 specific
next_state = DATA_RD;
else if((bit_cnt == 0) && (op == 2'b10) && (st == 2'b00)) // Claus45 specific
next_state = DATA_RDP;
else
next_state = DEVAD;
REGAD :
if((bit_cnt == 0) && (op == 2'b00))
next_state = TA;
else if((bit_cnt == 0) && (op == 2'b01))
next_state = TA;
else if((bit_cnt == 0) && (op == 2'b11))
next_state = DATA_RD;
else if((bit_cnt == 0) && (op == 2'b10) && (st == 2'b01)) // Claus22 specific
next_state = DATA_RD;
else if((bit_cnt == 0) && (op == 2'b10) && (st == 2'b00)) // Claus45 specific
next_state = DATA_RDP;
else
next_state = REGAD;
TA :
if((bit_cnt == 0) && (op == 2'b00))
next_state = ADDR;
else if((bit_cnt == 0) && (op == 2'b01))
next_state = DATA_WR;
else
next_state = TA;
ADDR :
if(bit_cnt == 0)
next_state = IDLE;
else
next_state = ADDR;
DATA_WR :
if(bit_cnt == 0)
next_state = IDLE;
else
next_state = DATA_WR;
DATA_RD :
if(bit_cnt_read == 0)
next_state = IDLE;
else
next_state = DATA_RD;
DATA_RDP :
if(bit_cnt_read == 0)
next_state = IDLE;
else
next_state = DATA_RDP;
default :
next_state = IDLE;
endcase
end
always @(posedge mdc)
begin
if(reset) begin
state <= #1 4'h0;
bit_cnt <= #1 7'd31;
mdio_d <= #1 1'bz;
write_en_22 <= #1 1'b0;
write_en_45 <= #1 1'b0;
bit_cnt_read <= #1 7'd0;
end
else begin
state <= #1 next_state;
mdio_d <= #1 mdio_in;
end
// default
write_en_22 <= #1 1'b0;
write_en_45 <= #1 1'b0;
bit_cnt_read <= #1 bit_cnt_read - 1;
// bit_cnt update
if(state == IDLE) begin
bit_cnt <= #1 31;
bit_cnt_preamble <= #1 0;
end
else if(state == PREAMBLE) begin
bit_cnt_preamble <= #1 bit_cnt_preamble + 1;
bit_cnt <= #1 1;
end
else if((state == ST) && (bit_cnt == 0))
bit_cnt <= #1 1;
else if((state == OP) && (bit_cnt == 0))
bit_cnt <= #1 4;
else if((state == PHYAD) && (bit_cnt == 0))
bit_cnt <= #1 4;
else if((state == PRTAD) && (bit_cnt == 0))
bit_cnt <= #1 4;
else if((state == DEVAD) && (bit_cnt == 0))
bit_cnt <= #1 1;
else if((state == REGAD) && (bit_cnt == 0))
bit_cnt <= #1 1;
else if((state == TA) && (bit_cnt == 0))
bit_cnt <= #1 15;
else if((state == ADDR) && (bit_cnt == 0))
bit_cnt <= #1 31;
else if((state == DATA_WR) && (bit_cnt == 0))
bit_cnt <= #1 31;
else if((state == DATA_RD) && (bit_cnt == 0))
bit_cnt <= #1 31;
else if((state == DATA_RDP) && (bit_cnt == 0))
bit_cnt <= #1 31;
else
bit_cnt <= #1 bit_cnt - 1;
// bit_cnt_read
if((state == DEVAD) && (bit_cnt == 1))
bit_cnt_read <= #1 17;
if((state == REGAD) && (bit_cnt == 1))
bit_cnt_read <= #1 17;
// st
if(state == IDLE)
st <= #1 0;
else if(state == ST)
st[bit_cnt] <= #1 mdio_d;
// op
if(state == IDLE)
op <= #1 0;
else if(state == OP)
op[bit_cnt] <= #1 mdio_d;
// prtad
if(state == IDLE)
prtad <= #1 0;
else if(state == PRTAD)
prtad[bit_cnt]<= #1 mdio_d;
// phyad
if(state == IDLE)
phyad <= #1 0;
else if(state == PHYAD)
phyad[bit_cnt]<= #1 mdio_d;
// devad
if(state == IDLE)
devad <= #1 0;
else if(state == DEVAD) begin
devad[bit_cnt]<= #1 mdio_d;
read_data <= #1 memory[addr];
end
// regad
if(state == IDLE)
regad <= #1 0;
else if(state == REGAD) begin
regad[bit_cnt]<= #1 mdio_d;
read_data <= #1 memory[{regad[4:1], mdio_d}];
end
// ta
if(state == IDLE)
ta <= #1 0;
else if(state == TA)
ta[bit_cnt] <= #1 mdio_d;
// addr
if(state == ADDR)
addr[bit_cnt] <= #1 mdio_d;
// data
if(state == IDLE)
data <= #1 0;
if(state == DATA_WR)
data[bit_cnt] <= #1 mdio_d;
// Write
if((state == DATA_WR) && (st == 2'b01) && (bit_cnt == 0)) // Claus22
if(phyad[4:0] == MY_PHY_ID)
write_en_22 <= #1 1'b1;
// Write
if((state == DATA_WR) && (st == 2'b00) && (bit_cnt == 0)) // Claus45
if((prtad[4:0] == MY_PRT_ID) && (devad[4:0] == MY_DEV_ID)) begin
write_en_45 <= #1 1'b1;
regad <= #1 addr;
end
if(write_en_22 == 1'b1) begin
memory[regad] <= #1 data;
$display("<%0d> MDIO_DEBUG: Write addr:%h data:%h Claus22 %m", $time, regad, data);
end
if(write_en_45 == 1'b1) begin
memory[addr] <= #1 data;
$display("<%0d> MDIO_DEBUG: Write addr:%h data:%h Claus45 %m", $time, addr, data);
end
// Read
if((state == DATA_RD) && (st == 2'b01)) begin // Claus22
if(phyad[4:0] == MY_PHY_ID) begin
if(bit_cnt == 0)
$display("<%0d> MDIO_DEBUG: Read addr:%h data:%h Claus22 %m", $time, regad, memory[regad]);
end
end
// Read
if((state == DATA_RD) && (st == 2'b00)) begin // Claus45
if((prtad[4:0] == MY_PRT_ID) && (devad[4:0] == MY_DEV_ID)) begin
if(bit_cnt == 0)
$display("<%0d> MDIO_DEBUG: Read addr:%h data:%h Claus45 %m", $time, addr, memory[addr]);
end
end
// Read post-read-increment-address
if((state == DATA_RDP) && (st == 2'b00)) begin // Claus45
if((prtad[4:0] == MY_PRT_ID) && (devad[4:0] == MY_DEV_ID)) begin
addr <= #1 addr + 1;
if(bit_cnt == 0)
$display("<%0d> MDIO_DEBUG: Read addr:%h data:%h %m", $time, addr, memory[addr]);
end
end
end // always
`ifdef AXIS
`else // AXIS
// logic to test poll mode in MIF
// Provides facilities to modify mmd memory content
reg [15:0] modify_mmd_memory_address;
reg [15:0] modify_mmd_memory_data;
reg [15:0] modify_mmd_memory_time;
reg modify_mmd_memory_enable;
integer ret_code;
initial
begin
modify_mmd_memory_address = 16'hFFFF;
modify_mmd_memory_data = 16'h0;
modify_mmd_memory_time = 16'h0;
modify_mmd_memory_enable = 1'b0;
if ($test$plusargs("MODIFY_MMD_MEMORY_ADDRESS="))
modify_mmd_memory_enable = 1'b1;
if ($test$plusargs("MODIFY_MMD_MEMORY_ADDRESS="))
ret_code = $value$plusargs("MODIFY_MMD_MEMORY_ADDRESS=%h", modify_mmd_memory_address);
if ($test$plusargs("MODIFY_MMD_MEMORY_DATA="))
ret_code = $value$plusargs("MODIFY_MMD_MEMORY_DATA=%h", modify_mmd_memory_data);
if ($test$plusargs("MODIFY_MMD_MEMORY_TIME="))
ret_code = $value$plusargs("MODIFY_MMD_MEMORY_TIME=%d", modify_mmd_memory_time);
// corrupt
if(modify_mmd_memory_enable) begin
$display("<%0d> MDIO_DEBUG: modify mmd memory at time:%0d mdc cycles addr:%h data:%h %m",
$time, modify_mmd_memory_time, modify_mmd_memory_address, modify_mmd_memory_data);
repeat(modify_mmd_memory_time) @(posedge mdc);
$display("<%0d> MDIO_DEBUG: modify mmd memory now time:%0d mdc cycles addr:%h data:%h %m",
$time, modify_mmd_memory_time, modify_mmd_memory_address, modify_mmd_memory_data);
memory[modify_mmd_memory_address] = modify_mmd_memory_data;
end
end
reg force_mmd_mdio_bus_enable;
reg force_mmd_mdio_bus_value;
reg [31:0] force_mmd_mdio_bus_time;
initial
begin
if ($test$plusargs("FORCE_MMD_MDIO_BUS_ENABLE"))
force_mmd_mdio_bus_enable = 1'b1;
else
force_mmd_mdio_bus_enable = 1'b0;
if ($test$plusargs("FORCE_MMD_MDIO_BUS_VALUE="))
ret_code = $value$plusargs("FORCE_MMD_MDIO_BUS_VALUE=%d", force_mmd_mdio_bus_value);
if ($test$plusargs("FORCE_MMD_MDIO_BUS_TIME="))
ret_code = $value$plusargs("FORCE_MMD_MDIO_BUS_TIME=%d", force_mmd_mdio_bus_time);
if(force_mmd_mdio_bus_enable) begin
$display("<%0d> MDIO_DEBUG: force mmd mdio at time:%0d mdc cycles %m",
$time, force_mmd_mdio_bus_time);
repeat(force_mmd_mdio_bus_time) @(posedge mdc);
force mdio_out = force_mmd_mdio_bus_value;
force mdio_en = force_mmd_mdio_bus_value;
force mdio_in = force_mmd_mdio_bus_value;
$display("<%0d> MDIO_DEBUG: force mmd mdio now time:%0d mdc cycles %m",
$time, force_mmd_mdio_bus_time);
end
end
`endif // AXIS
endmodule