/******************************************************************************/
/* */
/* 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. */
/* */
/******************************************************************************/
// @(#)afx_mon.v 1.15 1/5/94
/* This is the basic AFX monitor module
which is used to monitor the AFX transactions
*/
// updates:
//
// 1 dec 1992
// fixed checking addr/size for illegal transfers, display of
// sized transfers, counting address transactions
// 2.0 8 dec 1992
// change over to AFX rev 2
// 2.1 1 mar 1993
// changes to match the latest spec (rev. 2.1);
// timeout and latency checks, new signal names
module afx_mon
;
// parameters & defines /////////////////////////////////////////////////
parameter TRACE = 1; // if set, will print transactions
parameter FIFOSIZE = 4;
parameter READ_LAT = 1; // value to check for, read latency
// should be set to 1 or 0
parameter [31:0]
TIMEOUT = 32'd2047, // afx timeout value measured in gclks
REPEAT = 32'd2047; // repeats of timeout error message
// this is the afx space for for Physical address <30:29>
parameter AFXPA =2'b01;
parameter [1:0]
WR_REPLY = 2'b10, // reply r/w bits
RD_REPLY = 2'b11;
// wires & registers /////////////////////////////////////////
// Substitute the correct module for master_blob
wire falcon_exists
= 1'b1; // hardwired to 1, this is the lazy way John Petry
wire mon_clk
= `SSPARC_CORE.w_gclk;
wire [1:0] p_reply
= `SSPARC_CORE.pcic_p_reply;
// wire [1:0] s_reply = `SS_SCOPE.w_s_reply;
wire [1:0] s_reply
= {`SSPARC_CORE.w_s_reply, `SS_SCOPE.mc_mwe_l};
wire write_l
= `SS_SCOPE.mc_mwe_l;
// wire lo_addr = `SS_SCOPE.lo_addr;
wire lo_addr
= `SSPARC_CORE.w_s_reply;
// wire [14:0] ab = `SS_SCOPE.ab[15:1];
wire [14:0] ab
= {`SSPARC_CORE.w_ab_out, `SS_SCOPE.mc_memaddr};
wire aen
= `SSPARC_CORE.w_aen;
reg [1:0] mon_p_rply
;
reg [1:0] mon_s_rply
;
// Fake output enables until we hook them up
//reg ram_oe, cpu_oe, afx_oe;
//reg ram_oe;
wire ram_oe
= Msystem.TheRam.ram_output;
wire cpu_oe
= `SS_SCOPE.b_mem_oen;
`ifdef A24_STUB
// wire afx_oe = Msystem.fstub.afxs.db_en;
`else
// wire afx_oe = Msystem.fstub.afxs.read_oe_l;
`endif
wire afx_oe
= 1'b0 ;
// State
reg read_flag
, write_flag
;
reg read_pend
;
reg [7:0] write_count
, addr_count
;
reg [14:0] ab_hi
, ab_low
;
reg [31:0] save_addr
;
reg [3:0] save_mask
;
reg [7:0] disp_byte
; // used for displaying data
reg [15:0] disp_hword
;
reg [31:0] disp_word
;
reg [31:0] timer
; // afx bus timeout counter
reg timer_en
; // timer enable
// Decoded address, data, size
wire [28:3] address
= {ab_hi[0], ab_hi[14:1], ab_low[10:0]};
// temporarily change this to allow a view of PCI data via
// the separate read and write paths. - JP
wire [63:0] data
= `SS_SCOPE.b_memdata;
wire [63:0] read_data
= `SSPARC_CORE.b_memdata_in;
wire [63:0] write_data
= `SS_SCOPE.w_b_memdata_out;
wire [3:0] mask
= ab_low[14:11];
// initial blocks /////////////////////////////////////////////////
// Initialize variables
initial
begin
// The following three should go away
// Init states
read_flag = 0;
write_flag = 0;
read_pend = 0;
write_count = 0;
addr_count = 0;
timer = 0;
timer_en = 0;
ab_hi = 'hX;
ab_low = 'hX;
mon_p_rply = 0;
mon_s_rply = 0;
save_addr[31:29] = AFXPA;
end
// always blocks /////////////////////////////////////////////////
// Check for driver fights
wire fight1
= (ram_oe & cpu_oe);
wire fight2
= (ram_oe & afx_oe);
wire fight3
= (cpu_oe & afx_oe);
wire driver_fight
= (fight1 | fight2 | fight3);
// always @ (posedge driver_fight) begin
// $display("*** Error: afx_monitor: driver fight, ram_oe = %d, cpu_oe = %d, afx_oe = %d",
// ram_oe, cpu_oe, afx_oe);
// Mclocks.error_count = Mclocks.error_count + 1;
// // AT THIS POINT, WE SHOULD YANK A FLAG THAT STOPS THE SIM
// end
// Here's the fun part, check for correct operation of the AFX bus
// It all starts on the leading edge of the clock...
always @ (posedge mon_clk) begin
//
// Check address stuff
if (aen == 1) begin
// High address
if (lo_addr == 1'b0) begin
ab_hi = ab;
end
// Low address, launch command
else if ((lo_addr == 1'b1) &&
(~falcon_exists || (address[28] == 1'b1))) begin
timer = 0;
timer_en = 1;
ab_low = ab;
// check for illegal mask code
if (mask == 4'b1111) begin
$display("*** Error: afx_monitor: illegal mask code = 1111");
Mclocks.error_count = Mclocks.error_count + 1;
// YANK THE HALT SIM LINE
end
// check fifo counts
if (write_l == 1'b0) begin // write cmd
addr_count = addr_count + 1;
if (addr_count > FIFOSIZE) begin
$display("*** Error: afx_monitor: too many write commands on address bus");
Mclocks.error_count = Mclocks.error_count + 1;
// YANK THE HALT SIM LINE
end
end
else begin // read cmd
if (read_pend == 1) begin
$display("*** Error: afx_monitor: too many read commands on address bus");
Mclocks.error_count = Mclocks.error_count + 1;
// YANK THE HALT SIM LINE
end
else begin
read_pend = 1; // set the flag until read
end
end
end
// if not 0 or 1, then bad data on lo_addr!
else if ((lo_addr !== 1'b1) && (lo_addr !== 1'b0)) begin
$display("*** Error: afx_monitor: bad data on lo_addr = %b", lo_addr);
end
end
// Check for command
// Write
if ((s_reply == WR_REPLY) &&
(~falcon_exists || (address[28] == 1'b1))) begin
write_flag = 1;
write_count = write_count + 1;
// Check for buffer overflow
if (write_count > FIFOSIZE) begin
$display("*** Error: afx_monitor: too many writes");
Mclocks.error_count = Mclocks.error_count + 1;
// YANK THE HALT SIM LINE
end
if (read_flag == 1) begin
$display("*** Error: afx_monitor: write during read");
Mclocks.error_count = Mclocks.error_count + 1;
// YANK THE HALT SIM LINE
end
end
// Read
else if ((s_reply == RD_REPLY) &&
(~falcon_exists || (address[28] == 1'b1))) begin
read_flag = 1;
end
// Check for replies
// Write
if (p_reply == WR_REPLY) begin
// Check for buffer underflow
if (write_count == 0) begin
$display("*** Error: afx_monitor: too many write replies");
Mclocks.error_count = Mclocks.error_count + 1;
// YANK THE HALT SIM LINE
end
write_count = write_count - 1;
if (write_count == 0)
timer_en = 0;
addr_count = addr_count - 1;
end
// Read
else if (p_reply == RD_REPLY) begin
if (read_flag == 0) begin
$display("*** Error: afx_monitor: bogus read reply");
Mclocks.error_count = Mclocks.error_count + 1;
// YANK THE HALT SIM LINE
end
if (write_count != 0) begin
$display("*** Error: afx_monitor: write buf not flushed");
Mclocks.error_count = Mclocks.error_count + 1;
// YANK THE HALT SIM LINE
end
if (TRACE == 1) begin // if set, write out transaction
save_addr[28:3] = address[28:3];
case (mask)
// byte reads /////////////////////////////////////////
4'b0000: begin
save_addr[2:0] = 3'b000;
disp_byte = read_data[63:56];
$display("\n\t%s: RD (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_byte, save_addr, mask);
end
4'b0001: begin
save_addr[2:0] = 3'b001;
disp_byte = read_data[55:48];
$display("\n\t%s: RD (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_byte, save_addr, mask);
end
4'b0010: begin
save_addr[2:0] = 3'b010;
disp_byte = read_data[47:40];
$display("\n\t%s: RD (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_byte, save_addr, mask);
end
4'b0011: begin
save_addr[2:0] = 3'b011;
disp_byte = read_data[39:32];
$display("\n\t%s: RD (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_byte, save_addr, mask);
end
4'b0100: begin
save_addr[2:0] = 3'b100;
disp_byte = read_data[31:24];
$display("\n\t%s: RD (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_byte, save_addr, mask);
end
4'b0101: begin
save_addr[2:0] = 3'b101;
disp_byte = read_data[23:16];
$display("\n\t%s: RD (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_byte, save_addr, mask);
end
4'b0110: begin
save_addr[2:0] = 3'b110;
disp_byte = read_data[15:8];
$display("\n\t%s: RD (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_byte, save_addr, mask);
end
4'b0111: begin
save_addr[2:0] = 3'b111;
disp_byte = read_data[7:0];
$display("\n\t%s: RD (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_byte, save_addr, mask);
end
// halfword reads /////////////////////////////////////
4'b1000: begin
save_addr[2:0] = 3'b000;
disp_hword = read_data[63:48];
$display("\n\t%s: RD (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_hword, save_addr, mask);
end
4'b1010: begin
save_addr[2:0] = 3'b010;
disp_hword = read_data[47:32];
$display("\n\t%s: RD (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_hword, save_addr, mask);
end
4'b1100: begin
save_addr[2:0] = 3'b100;
disp_hword = read_data[31:16];
$display("\n\t%s: RD (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_hword, save_addr, mask);
end
4'b1110: begin
save_addr[2:0] = 3'b110;
disp_hword = read_data[15:0];
$display("\n\t%s: RD (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_hword, save_addr, mask);
end
// word reads /////////////////////////////////////////
4'b1001: begin
save_addr[2:0] = 3'b000;
disp_word = read_data[63:32];
$display("\n\t%s: RD (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_word, save_addr, mask);
end
4'b1101: begin
save_addr[2:0] = 3'b100;
disp_word = read_data[31:0];
$display("\n\t%s: RD (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_word, save_addr, mask);
end
// doubleword reads ///////////////////////////////////
4'b1011: begin
save_addr[2:0] = 3'b000;
$display("\n\t%s: RD (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
read_data, save_addr, mask);
end
endcase // mask
end // if (TRACE == 1)
read_flag = 0;
read_pend = 0;
timer_en = 0;
end // if (p_reply == RD_REPLY)
// check for read latency violation
/*
if ((s_reply == RD_REPLY) && (write_count > READ_LAT)) begin
$display("*** Error: afx_monitor: read latency violation, write fifo = %d deep.",
write_count);
Mclocks.error_count = Mclocks.error_count + 1;
// YANK THE HALT SIM LINE
end //
*/
end // always @ (posedge mon_clk)
// Display write trace
always @ (posedge write_flag) begin
// save info from 1st cycle of write
save_addr[28:3] = address[28:3];
save_mask = mask;
// Wait until data is asserted
@(posedge mon_clk)
if (TRACE == 1) begin
case (mask)
// byte writes ////////////////////////////////////////////
4'b0000: begin
save_addr[2:0] = 3'b000;
disp_byte = write_data[63:56];
$display("\n\t%s: WR (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_byte, save_addr, save_mask);
end
4'b0001: begin
save_addr[2:0] = 3'b001;
disp_byte = write_data[55:48];
$display("\n\t%s: WR (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_byte, save_addr, save_mask);
end
4'b0010: begin
save_addr[2:0] = 3'b010;
disp_byte = write_data[47:40];
$display("\n\t%s: WR (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_byte, save_addr, save_mask);
end
4'b0011: begin
save_addr[2:0] = 3'b011;
disp_byte = write_data[39:32];
$display("\n\t%s: WR (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_byte, save_addr, save_mask);
end
4'b0100: begin
save_addr[2:0] = 3'b100;
disp_byte = write_data[31:24];
$display("\n\t%s: WR (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_byte, save_addr, save_mask);
end
4'b0101: begin
save_addr[2:0] = 3'b101;
disp_byte = write_data[23:16];
$display("\n\t%s: WR (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_byte, save_addr, save_mask);
end
4'b0110: begin
save_addr[2:0] = 3'b110;
disp_byte = write_data[15:8];
$display("\n\t%s: WR (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_byte, save_addr, save_mask);
end
4'b0111: begin
save_addr[2:0] = 3'b111;
disp_byte = write_data[7:0];
$display("\n\t%s: WR (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_byte, save_addr, save_mask);
end
// halfword writes ////////////////////////////////////////
4'b1000: begin
save_addr[2:0] = 3'b000;
disp_hword = write_data[63:48];
$display("\n\t%s: WR (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_hword, save_addr, save_mask);
end
4'b1010: begin
save_addr[2:0] = 3'b010;
disp_hword = write_data[47:32];
$display("\n\t%s: WR (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_hword, save_addr, save_mask);
end
4'b1100: begin
save_addr[2:0] = 3'b100;
disp_hword = write_data[31:16];
$display("\n\t%s: WR (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_hword, save_addr, save_mask);
end
4'b1110: begin
save_addr[2:0] = 3'b110;
disp_hword = write_data[15:0];
$display("\n\t%s: WR (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_hword, save_addr, save_mask);
end
// word writes ////////////////////////////////////////////
4'b1001: begin
save_addr[2:0] = 3'b000;
disp_word = write_data[63:32];
$display("\n\t%s: WR (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_word, save_addr, save_mask);
end
4'b1101: begin
save_addr[2:0] = 3'b100;
disp_word = write_data[31:0];
$display("\n\t%s: WR (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
disp_word, save_addr, save_mask);
end
// doubleword writes //////////////////////////////////////
4'b1011: begin
save_addr[2:0] = 3'b000;
$display("\n\t%s: WR (%x)@(%x) mask(%x)",
save_addr[28] ? "PCI" : "AFX",
write_data, save_addr, save_mask);
end
endcase
end // if (TRACE == 1)
write_flag = 0;
end // always @ (posedge write_flag)
always @(posedge mon_clk) begin
#1 if (timer_en == 1) begin
timer = timer + 1;
// this actually counts in the same cycle as timer_en
// gets set, so need to wait until count is greater than...
if (timer >= TIMEOUT) begin
// only report timeout error every REPEAT clocks over
if (((timer - TIMEOUT) % REPEAT) == 0) begin
$display("*** Warning: afx_monitor: access timed out, timer = %d gclk's.", timer);
Mclocks.warning_count = Mclocks.warning_count + 1;
reset_flags;
// YANK THE HALT SIM LINE
end
end
end
else timer = 0;
end // always @(posedge mon_clk)
// tasks /////////////////////////////////////////////////////////
// resets flags, variables, pointers, etc. when an error occurs
task reset_flags;
begin
read_flag = 0;
write_flag = 0;
read_pend = 0;
write_count = 0;
addr_count = 0;
ab_hi = 'hX;
ab_low = 'hX;
end
endtask // reset_flags
endmodule // module afx_mon
This page: |
Created: | Thu Aug 19 11:59:52 1999 |
| From: |
../../../sparc_v8/system/rtl/afx_mon.v
|