// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: ssi.vr
// 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
// ========== Copyright Header End ============================================
#include <vera_defines.vrh>
#include "std_display_defines.vri"
#include "plusArgMacros.vri"
#include "std_display_class.vrh"
local string className = "SSI";
local StandardDisplay dbg;
local string dispmonScope = "SSI";
integer send, send_int, send_parity_error;//Synchronization variables
integer ssi_timeout, ssi_parity_error, ssi_side_effect;
reg [63:0] ssi_int_soft, ssi_int_parity, ssi_int_mask, ssi_response_latency;//These are shadow registers
task new(StandardDisplay dbgHndl, ssi_iport ncu, ssi_oport ssi);
task pulse_ssi_int_l(integer pulsedelay, integer pulsewidth);
task generate_pulse(integer pulsedelay, integer pulsewidth);
task CLASSNAME::new(StandardDisplay dbgHndl, ssi_iport ncu, ssi_oport ssi) {
this.send_parity_error = 0;
this.ssi_parity_error = 0;
this.ssi_side_effect = 0;
if (mChkPlusarg(ssi_mon) || mChkPlusarg(SSI_MON)) ssi_mon = 1;
* Tasks for SSI user event generation
task CLASSNAME::pulse_ssi_int_l(integer pulsedelay, integer pulsewidth) {
generate_pulse(pulsedelay, pulsewidth);
task CLASSNAME::generate_pulse(integer pulsedelay, integer pulsewidth) {
for(i=0; i<=pulsedelay; i++) {
for(i=0; i<=pulsewidth; i++) {
task CLASSNAME::SsiMon() {
printf("SSI_PINS: SSI_INT %x\n", ssi.$int_l);
task CLASSNAME::SsiDem() {
if (ncu.$reset !== 0) @(negedge ncu.$reset);
// while(ncu.$reset != 1) {
if (ncu.$reset !== 1) @(posedge ncu.$reset);
integer i, rcv_data_width;
while (ncu.$data != 1) @(posedge ncu.$clk);
//printf ("SSI: %d: NCU requesting data %h\n", get_time(LO), ncu.$data);
//printf("SSI: MOSI = %h i=%d\n", ncu.$data, i);
if (ssi_mon) PR_NORMAL(dispmonScope, MON_NORMAL, psprintf("SSI Rcv: NCU cmd = 0x%h (read = %0d, size = %0d bytes)", ncu_cmd, ncu_cmd[2], 1 << ncu_cmd[1:0]));
//printf("SSI: MOSI = %h i=%d\n", ncu.$data, i);
//if (ssi_mon) PR_NORMAL(dispmonScope, MON_NORMAL, psprintf("SSI Rcv: ADDR decoded = 0x%x", ncu_addr));
//The length of recieved data depends on the byte size
2'b00: rcv_data_width = 7;
2'b01: rcv_data_width = 15;
2'b10: rcv_data_width = 31;
2'b11: rcv_data_width = 63;
for (i=rcv_data_width; i>=0; i--) {
//printf("SSI: MOSI = %h i=%d\n", ncu.$data, i);
if (ssi_mon) PR_NORMAL(dispmonScope, MON_NORMAL, psprintf("SSI Rcv: WR cmd rcvd addr=0x%h dataWidth=%0d data=0x%x", ncu_addr, rcv_data_width+1, ncu_data));
//printf("SSI: %d WR cmd rcvd size=%d data=0x%x\n", get_time(LO), rcv_data_width, ncu_data, get_time(LO));
if (ssi_mon) PR_NORMAL(dispmonScope, MON_NORMAL, psprintf("SSI Rcv: RD cmd rcvd addr=0x%h dataWidth=%0d data=0x%x", ncu_addr, rcv_data_width+1, ncu_data));
//printf("SSI: RD cmd rcvd size=%d data=0x%x\n", rcv_data_width, ncu_data);
//printf("SSI: MOSI = %h i=%d\n", ncu.$data, i);
////printf ("The parity calculated is %h\n", ^{1'b1, ncu_cmd, ncu_addr});
if (parity != (^{1'b1, ncu_cmd, ncu_addr})) {
//Decode address to update shadow registers
//ssi_int_soft = ff_fff0_0000
//ssi_int_parity = ff_fff0_0010
//ssi_int_mask = ff_fff0_0020
//ssi_response_latency = ff_fff0_0030
//ssi_timeout = ff_fff1_0000
//ssi_parity_error = ff_fff2_0000
//ssi_side_effect = ff_fff3_0000
8'h00: ssi_int_soft = ncu_data;
8'h10: ssi_int_parity = ncu_data;
8'h20: ssi_int_mask = ncu_data;
8'h30: ssi_response_latency = ncu_data;
//printf ("SSI: %d cmd received is %h, addr received is %h, data received is %h, SEND is set\n", get_time(LO),ncu_cmd, ncu_addr, ncu_data);
reg [7:0] gpio_0_latency;
reg [7:0] gpio_0_duration;
reg [7:0] gpio_1_latency;
reg [7:0] gpio_1_duration;
gpio_0_latency = GPIO_0[7:0];
gpio_0_duration = GPIO_0[15:8];
while( gpio_0_latency ) {
gpio_0_latency = gpio_0_latency - 1;
while( gpio_0_duration ) {
gpio_0_duration = gpio_0_duration - 1;
gpio_1_latency = GPIO_1[7:0];
gpio_1_duration = GPIO_1[15:8];
while( gpio_1_latency ) {
gpio_1_latency = gpio_1_latency - 1;
while( gpio_0_duration ) {
gpio_1_duration = gpio_1_duration - 1;
reg post_int, cyc, post_cyc, randcyc;
reg parity_int, parity_detect_enable;
reg soft_enable, parity_enable;
post_int = 0; cyc=0; post_cyc=1'b1; randcyc=0; int_latency=8'b0;
while( ~(post_int | cyc) ) {
post_int = ssi_int_soft[8];
//printf("SSI: ssi_int_soft = 0x%x\n", ssi_int_soft);
//printf("Entered post Int\n");
int_latency = ssi_int_soft[7:0];
post_int = ssi_int_soft[8];
post_cyc = ssi_int_soft[10];
randcyc = ssi_int_soft[11];
//if their is a latency set then interrupt
while(int_latency != 8'h00) {
int_latency = int_latency - 1;
//interrupt after int_latency cycles
//printf("SSI: CYC interrupt set\n");
while(int_latency != 8'h00) {
int_latency = int_latency - 1;
int_latency = ssi_int_soft[7:0];
//pulse the iterrupt for 8 SSI
//printf("SSI: Deassert post_int\n");
// read and/or write gMem
integer i, trans_data_width;
reg [63:0] read_data, transmit_data, tmp_data;
@(posedge ssi.$clk); // wait for Rcv() to set send true
//printf ("SSI: %d send set to 1\n", get_time(LO));
tmpAddr = {12'hfff, ncu_addr};
read_data = gMem.read_mem({tmpAddr[39:3], 3'b0});
//printf ("SSI: READ from GLOBAL tmpAddr=0x%h data=0x%h\n", tmpAddr, read_data);
// tmp_data = {ncu_data[7:0], ncu_data[15:8], ncu_data[23:16], ncu_data[31:24], ncu_data[39:32], ncu_data[47:40], ncu_data[55:48], ncu_data[63:56]};
//printf ("SSI: %d Read made from global memory ncu_cmd=0x%x\n", get_time(LO), ncu_cmd);
if (ncu_cmd[2] == 1'b1) {
if (ssi_mon) PR_NORMAL(dispmonScope, MON_NORMAL, psprintf("SSI Send: RD request addr = 0x%h", ncu_addr));
//printf("SSI: RD request made\n");
3'b000: transmit_data = {read_data[7:0]};
3'b001: transmit_data = {read_data[15:8]};
3'b010: transmit_data = {read_data[23:16]};
3'b011: transmit_data = {read_data[31:24]};
3'b100: transmit_data = {read_data[39:32]};
3'b101: transmit_data = {read_data[47:40]};
3'b110: transmit_data = {read_data[55:48]};
3'b111: transmit_data = {read_data[63:56]};
if (ssi_mon) PR_NORMAL(dispmonScope, MON_NORMAL, psprintf("SSI Send: BYTE RD req addr=0x%x data=0x%x", ncu_addr, transmit_data));
2'b00: transmit_data = {read_data[15:0]};
2'b01: transmit_data = {read_data[31:16]};
2'b10: transmit_data = {read_data[47:32]};
2'b11: transmit_data = {read_data[63:48]};
if (ssi_mon) PR_NORMAL(dispmonScope, MON_NORMAL, psprintf("SSI Send: HALF WORD RD req addr=0x%x data=0x%x", ncu_addr, transmit_data));
transmit_data = tmpAddr[2] == 1'b1 ? read_data[31:0] : read_data[63:32];
if (ssi_mon) PR_NORMAL(dispmonScope, MON_NORMAL, psprintf("SSI Send: WORD RD req addr=0x%x data=0x%x", ncu_addr, transmit_data));
transmit_data = read_data[63:0];
if (ssi_mon) PR_NORMAL(dispmonScope, MON_NORMAL, psprintf("SSI Send: DOUBLE WORD RD req addr=0x%x data=0x%x", ncu_addr, transmit_data));
////printf ("data read is %h, data to send is %h\n", read_data, send_data);
//printf("SSI: WRITE command recieved\n");
//if (ssi_mon) PR_NORMAL(dispmonScope, MON_NORMAL, psprintf("SSI Send: WR request addr = 0x%h", ncu_addr));
3'b000: transmit_data = {read_data[63:8], ncu_data[7:0]};
3'b001: transmit_data = {read_data[63:16], ncu_data[7:0], read_data[7:0]};
3'b010: transmit_data = {read_data[63:24], ncu_data[7:0], read_data[15:0]};
3'b011: transmit_data = {read_data[63:32], ncu_data[7:0], read_data[23:0]};
3'b100: transmit_data = {read_data[63:40], ncu_data[7:0], read_data[31:0]};
3'b101: transmit_data = {read_data[63:48], ncu_data[7:0], read_data[39:0]};
3'b110: transmit_data = {read_data[63:56], ncu_data[7:0], read_data[47:0]};
3'b111: transmit_data = { ncu_data[7:0], read_data[55:0]};
if (ssi_mon) PR_NORMAL(dispmonScope, MON_NORMAL, psprintf("SSI Send: WR Byte req done addr=0x%x data=0x%h mergedData=0x%h", ncu_addr, ncu_data[7:0], transmit_data));
2'b00: transmit_data = {read_data[63:16], ncu_data[15:0]};
2'b01: transmit_data = {read_data[63:32], ncu_data[15:0], read_data[15:0]};
2'b10: transmit_data = {read_data[63:48], ncu_data[15:0], read_data[31:0]};
2'b11: transmit_data = { ncu_data[15:0], read_data[47:0]};
if (ssi_mon) PR_NORMAL(dispmonScope, MON_NORMAL, psprintf("SSI Send: WR HALF req done addr=0x%x data=0x%h mergedData=0x%h", ncu_addr, ncu_data[15:0], transmit_data));
transmit_data = tmpAddr[2] == 1'b1 ? {read_data[63:32], ncu_data[31:0]} : {ncu_data[31:0], read_data[31:0]};
if (ssi_mon) PR_NORMAL(dispmonScope, MON_NORMAL, psprintf("SSI Send: WR WORD req done addr=0x%x data=0x%h mergedData=0x%h", ncu_addr, ncu_data[31:0], transmit_data));
transmit_data = ncu_data[63:0];
if (ssi_mon) PR_NORMAL(dispmonScope, MON_NORMAL, psprintf("SSI Send: WR DOUBLE req done addr=0x%x data=0x%h mergedData=0x%h", ncu_addr, ncu_data, transmit_data));
gMem.write_mem({tmpAddr[39:3], 3'b0}, transmit_data);
//printf("SSI: Did a write to the global memmory\n");
* Added one cycle latency
* Starting response to master
for (i=trans_data_width; i>=0; i--) {
ssi.$data = transmit_data[i];
send_parity = send_parity ^ transmit_data[i];
send_parity = send_parity^1;
ssi.$data = ^{1'b1, send_parity};