Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / cpus / vonk / ss / api / pli / src / SS_PliSocket.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: SS_PliSocket.cc
// 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 ============================================
#include <strings.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include "SS_PliSocket.h"
// debug_level : 0 - silent
// 1 - trap
// 2 - trap + instr <=== cosim default
// 3 - trap + instr + delta + pli
// 4 - trap + instr + delta + pli + pli byte-by-byte
// in interactive mode (i.e., NASENV=pfe), set -sas_run_args=-DPLI_DEBUG=0,
// or not specify it at all. Otherwise the output (to sas.log) generated here
// can interfere with pfe output
SS_PliSocket::SS_PliSocket()/*{{{*/
:
replay(false),
debug_level(0),
reg_comp(1),
write_file(0),
read_file(0),
read_file_gz(0),
record_input(0),
record_output(0),
pliok(true)
{}
/*}}}*/
int SS_PliSocket::open_cosim( int socket_no )/*{{{*/
{
int socket_fd;
int fd;
time_t clock;
struct sockaddr_in cli_addr, serv_addr;
if ((fd = socket(AF_INET,SOCK_STREAM,0)) < 0)
{
perror("PLI: ERROR: Can't open stream socket");
exit(1);
}
bzero((char*)&serv_addr,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(socket_no);
if (bind(fd,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) < 0)
{
perror ("PLI: ERROR: Can't bind local address");
exit(1);
}
if (listen(fd,5) < 0)
{
perror ("PLI: ERROR: listen error");
exit(1);
}
FILE* opened = fopen("pli-socket-opened","w");
time(&clock);
fprintf(opened,"%s\n",ctime(&clock));
fclose(opened);
int accept_retry = 0;
int clilen = sizeof(cli_addr);
while ((socket_fd = accept(fd,(struct sockaddr*)&cli_addr,&clilen)) < 0)
{
if (accept_retry++ >= 2000)
{
fprintf(stdout,"PLI: ERROR: accept timeout\n");
exit(1);
}
}
if ((write_file = fdopen(socket_fd,"wb")) == 0)
{
perror("PLI: ERROR: Can't fdopen output socket");
exit(1);
}
socket_fd = dup(socket_fd);
if ((read_file = fdopen(socket_fd,"rb")) == 0)
{
perror("PLI: ERROR: Can't fdopen input socket");
exit(1);
}
return 0;
}
/*}}}*/
int SS_PliSocket::open_record( const std::string& record_fn )/*{{{*/
{
std::string inp;
std::string out;
if (record_fn.size() == 0)
{
inp = "dut";
out = "dut";
}
else
{
inp = record_fn;
out = record_fn;
}
inp += ".inp.gz";
out += ".out.gz";
if ((record_input = gzopen(inp.data(),"w")) == 0)
{
perror("PLI: ERROR: Cannot create record input cmd file for writing");
exit(-1);
}
if ((record_output = gzopen(out.data(),"w")) == 0)
{
perror("PLI: ERROR: Cannot create record output cmp file for writing");
exit(-1);
}
return 0;
}
/*}}}*/
int SS_PliSocket::open_replay( const std::string& replay_fn )/*{{{*/
{
std::string inp;
std::string out;
if (replay_fn.size() == 0)
{
inp = "ref";
out = "ref";
}
else
{
inp = replay_fn;
out = replay_fn;
}
inp += ".inp.gz";
out += ".out.gz";
replay = true;
if ((read_file_gz = gzopen(inp.data(),"r")) == 0)
{
perror("PLI: ERROR: Cannot open replay input file for reading");
exit(-1);
}
if ((check_file = gzopen(out.data(),"r")) == 0)
{
perror("PLI: ERROR: Cannot open replay output file for reading");
exit(-1);
}
return 0;
}
/*}}}*/
int SS_PliSocket::read( uint_t length )/*{{{*/
{
uint8_t* buf = buffer;
uint_t len = length;
while (1)
{
size_t n;
if (read_file)
n = fread(buf,1,len,read_file);
else
n = gzread(read_file_gz,buf,len);
if (n == 0)
{
if (replay)
perror( "PLI: Replay read 0 bytes");
else
perror("PLI: Socket read 0 bytes");
return 0;
}
len -= n;
if (len == 0)
{
if (debug() >= 4)
{
fprintf(stdout,"PLI:");
for (int i = 0; i < length; i++)
fprintf(stdout," %02x",buffer[i]);
fprintf(stdout,"\n");
}
if (record_input)
gzwrite(record_input,buffer,length);
return length;
}
buf += n;
}
}
/*}}}*/
int SS_PliSocket::write( const char* s )/*{{{*/
{
const size_t SIZE=256;
size_t length = strlen(s);
if (check_file)
{
char bfr[SIZE];
char* buf = bfr;
size_t len = length;
assert (len < SIZE);
while (len && !gzeof(check_file))
{
size_t n = gzread(check_file,buf,len);
buf += n;
len -= n;
}
*buf = '\0'; // properly zero terminate the reference string
// if reg_comp==1, then report any miscompare (during replay)
if ((reg_comp == 1) && (strncmp(s,bfr,length) != 0))
{
// This is a temporary fix for end of line versus
// space followed by end of line miscompare. It
// is caused by a misunderstanding of the format
// if the data send back to rtl. The old reference
// has onle newline while new dut expects space
// and newline.
if (strncmp(s,bfr,length) != 0)
{
fprintf(stdout,"ERROR: regession failed\n",s);
fprintf(stdout,"ref: %s\n",bfr);
fprintf(stdout,"dut: %s\n",s);
exit(-1);
}
}
}
else if (write_file)
fprintf(write_file,"%s",s);
if (record_output)
gzprintf(record_output,"%s",s);
// instr & delta in sas.log, do it here so that it is consistent with what
// we send over to testbench.
if (debug() >= 2)
{
if (strstr(s, ": [swvp"))
{
// instr, has \n at the end of the string
// 4: [swvp0,th00] <v:fffffffff000002c> <p:000000fff000002c> [8410a020] or %g2, 0x20, %g2
//===> 4: T0 <v:fffffffff000002c> <p:000000fff000002c> [8410a020] or %g2, 0x20, %g2
char* s1 = strchr((char*)s, ':');
char* s2 = strchr((char*)s, ']');
// strand-id
char nn[8];
strncpy(nn, (char*)(s1+11), (s2-s1-11));
// make syre the string is terminated properly
nn[s2-s1-11] = '\0';
sprintf(nn, " T%d", atoi(nn));
// re-arrange string
char ss[SIZE];
ss[0] = '\0';
strncat(ss, s, (s1-s));
strcat(ss, nn);
strcat(ss, (char*)(s2+1));
fprintf(stdout,"#%s", ss);
}
else if (strstr(s, "STEP: ") && (debug() >= 3))
{
fprintf(stdout, "\t%s\n", s);
}
}
return length;
}
/* }}}*/
int SS_PliSocket::write_err( const char* s )/*{{{*/
{
if (write_file)
return fprintf(write_file,"%s",s);
else
return 0;
}
/* }}}*/
int SS_PliSocket::write_err( char* format, va_list args )/*{{{*/
{
if (write_file)
return vfprintf(write_file, format, args);
else
return 0;
}
/* }}}*/
int SS_PliSocket::flush()/*{{{*/
{
if (write_file)
return fflush(write_file);
else
return 0;
}
/*}}}*/
int SS_PliSocket::close()/*{{{*/
{
if (replay)
{
replay = false;
gzclose(read_file);
}
else
{
fclose(write_file);
fclose(read_file);
}
read_file = 0;
read_file_gz = 0;
write_file = 0;
if (record_input)
{
gzclose(record_input);
record_input = 0;
}
if (record_output)
{
gzclose(record_output);
record_output = 0;
}
if (check_file)
{
gzclose(check_file);
check_file = 0;
}
return 0;
}
/*}}}*/
uint8_t SS_PliSocket::get8( uint_t ofs )/*{{{*/
{
return buffer[ofs];
}
/*}}}*/
uint16_t SS_PliSocket::get16( uint_t ofs )/*{{{*/
{
uint16_t val = (uint16_t(buffer[ofs]) << 8) | buffer[ofs + 1];
return val;
}
/*}}}*/
uint32_t SS_PliSocket::get32( uint_t ofs )/*{{{*/
{
uint32_t val = 0;
for (int n=4; n--; ofs++)
val = (val << 8) | buffer[ofs];
return val;
}
/*}}}*/
uint64_t SS_PliSocket::get40( uint_t ofs )/*{{{*/
{
uint64_t val = 0;
for (int n=5; n--; ofs++)
val = (val << 8) | buffer[ofs];
return val;
}
/*}}}*/
uint64_t SS_PliSocket::get48( uint_t ofs )/*{{{*/
{
uint64_t val = 0;
for (int n=6; n--; ofs++)
val = (val << 8) | buffer[ofs];
return val;
}
/*}}}*/
uint64_t SS_PliSocket::get64( uint_t ofs )/*{{{*/
{
uint64_t val = 0;
for (int n=8; n--; ofs++)
val = (val << 8) | buffer[ofs];
return val;
}
/*}}}*/