Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / tod_4v / tod.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: tod.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 "tod.h"
static const char *tod_4v_help = "\
SAM N2 tod module (for Legion's virtual tod device)\n\
Sysconf format is :\n\
sysconf tod_4v <instance_name> base_pa=<start_addr> size=<map size> [tod=<mmddHHMMSSyyyy>]\n\
\'base_pa\' is the start address of memory mapped address, of the device CSRs\n\
\'size\' is the size of the CSR space\n\
\'tod\' is the time of day initial value. If ignored, current host system time is read\n\
For UI help type <instance name>\n\
For module specific info type \"modinfo <instance name>\"";
Module *Module::create(const char *_modname, const char *_instance_name){
return new tod4v(_modname, _instance_name);
}
const char * tod4v::get_help(){
return Module::get_help_string();
}
const char *
Module::get_help_string(){
return tod_4v_help;
}
tod4v::tod4v(const char * modname,const char * instance_name)
:Module(modname,instance_name){
start_pa = -1;
end_pa = 0;
size = 0;
set_fake_tod = false;
todstr = 0;
sim_time = 0;
event_fire_time = 0;
mmi_register_instance_cmd(getInstance(),tod_4v_help,tod_4v_ui_cmd);
}
bool tod4v::parse_arg(const char * arg){
if(argval("base",arg,&start_pa)){
debug_more("%s: base_pa %llx\n",getName(), start_pa);
return true;
}else if(argval("size",arg,&size)){
debug_more("%s: size %llx, end_pa %llx\n",getName(), size, start_pa + size - 1);
return true;
}else if(argval("tod",arg,&todstr)){
/* tod format is mmddHHMMSSyyyy , fakeSC.cc */
char buf[10];
char null[1];
null[0] = '\0';
if(strlen(todstr) != 14){
printf("tod format(mmddHHMMSSyyyy) incorrectly specified\n");
return false;
}
set_fake_tod = true;
time_str.tm_mon = atoi(strcpy(strncpy(buf,todstr,2) + 2,null) - 2) - 1;
time_str.tm_mday = atoi(strcpy(strncpy(buf,todstr+2,2) + 2,null) - 2);
time_str.tm_hour = atoi(strcpy(strncpy(buf,todstr+4,2) + 2,null)- 2);
time_str.tm_min = atoi(strcpy(strncpy(buf,todstr+6,2) + 2,null) - 2);
time_str.tm_sec = atoi(strcpy(strncpy(buf,todstr+8,2) + 2, null) - 2);
time_str.tm_year = atoi(strcpy(strncpy(buf,todstr+10,4) + 4,null) - 4) - 1900;
time_str.tm_isdst = -1;
}else
return false;
}
bool tod4v::check_args(){
if(start_pa == -1){
debug_err("%s:must specify start address\n",getName());
return false;
}else if(size == 0){
debug_err("%s:must specify size of address mapping\n",getName());
return false;
}else
return true;
}
void tod4v::init_done(){
if(mmi_map_physio(start_pa, size, (void *) this, tod4v_physio_access) != 0) {
debug_err("%s fatal error: unaable to map IO space\n");
exit(1);
}
end_pa = start_pa + size - 1;
if(set_fake_tod)
tod = mktime(&time_str);
else
tod = time(0);
// register a callback to fire every 1 sec, to increment the time
if(!restore_v5_dump()){
mmi_register_event(1000000,tod_1sec_callback,(void*)this,0);
event_fire_time = 1000000;
}
}
int tod4v::tod4v_physio_access(uint32_t cpuid, void* obj, uint64_t paddr,
mmi_bool_t wr, uint32_t size, uint64_t* buf, uint8_t bytemask){
tod4v* s = (tod4v*) obj;
if(wr)
s->tod4v_st(paddr,buf,size);
else
s->tod4v_ld(paddr,buf,size);
return 0;
}
int tod_4v_ui_cmd(void * obj, int argc, char * argv[]){
tod4v * i = (tod4v *)obj;
i->handle_ui(argc, argv);
return 0;
}
void tod4v::handle_ui(int argc, char * argv[]){
// dump restore are unpublished debug UI's
if(argc == 1){
ui_cmd_usage();
return;
}else if(!strcmp(argv[1],"dump")){
FILE * fp = stderr;
if(argv[2]){
fp = fopen(argv[2],"w");
if(!fp){
printf("%s dump: error opening file <%s>\n",getName(),argv[2]);
fp = stderr;
}
}
dump(fp);
if(fp != stderr)
fclose(fp);
}else if(!strcmp(argv[1],"restore")){
FILE * fp;
if(argv[2]){
fp = fopen(argv[2],"r");
if(fp){
restore(fp);
fclose(fp);
}else
printf("%s restore: error opening file <%s>\n",getName(),argv[2]);
}else
printf("%s restore: no restore filename specified\n",getName());
}else if(!strcmp(argv[1],"debug")){
if(argv[2]){
debug_level = atoi(argv[2]);
printf("%s: set debug level to %d\n",getName(),debug_level);
}else
printf("%s: current debug level %d\n",getName(),debug_level);
}else
debug_err("%s: unsupported UI command <%s>\n",getName(),argv[1]);
return;
}
void tod4v::tod4v_ld (uint64_t paddr, uint64_t *buf, int size){
uint64_t offset = paddr - start_pa;
assert(offset == 0);
assert(size == 8);
*buf = tod;
debug_more("%s: ld pa 0x%llx size %d value %llx \n", getName(), paddr, size, *buf );
return;
}
void tod4v::tod4v_st(uint64_t pa, uint64_t *buf, int size){
debug_err("%s: does not support store\n",getName());
debug_err("%s: st pa 0x%llx size %d value %llx\n",getName(),pa,size,*buf);
return;
}
void tod4v::timer_callback(){
tod += 1;
sim_time++;
debug_more("%s: sim time %i sec : current time of day %s", getName(),sim_time,ctime(&tod));
event_fire_time = mmi_get_time()+1000000;
mmi_register_event(event_fire_time,tod_1sec_callback,(void*)this,0);
}
void tod_1sec_callback(void * obj, void * ){
tod4v * t = (tod4v*) obj;
t->timer_callback();
}