Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / legion / src / devices / mem_bus / libdumbtod / dumbtod.c
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: dumbtod.c
* 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 ============================================
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "@(#)dumbtod.c 1.13 07/02/15 SMI"
/*
* This is a very generic TOD device.
* It provides a single read-only 64-bit register that
* contains the time in standard Unix form: number of seconds
* since Jan 1, 1970 UST.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <time.h>
#include <strings.h>
#include "basics.h"
#include "allocate.h"
#include "lexer.h"
#include "simcore.h"
#include "config.h"
#include "dumpinfo.h"
#include "fatal.h"
#include "device.h"
#define DBGX(s) do { } while (0)
/*
* Registers
* addr RW SZ Function
* ----- -- ------ --------------
* 0x00 R 64-bit time_t
*/
static void dtod_parse(config_dev_t *);
static void dtod_init(config_dev_t *);
static void dtod_dump(config_dev_t *);
static bool_t dtod_cpu_access(simcpu_t *sp, config_addr_t * cap,
tpaddr_t offset, maccess_t op, uint64_t * regp);
dev_type_t dev_type_dumbtod = {
"dumbtod",
dtod_parse,
dtod_init,
dtod_dump,
generic_device_non_cacheable,
dtod_cpu_access,
DEV_MAGIC
};
typedef struct {
time_t start_time;
uint64_t sysclkfreq;
uint64_t todfreq;
} dtod_state_t;
/*
* Complete the creation and parsing of this specific device
*/
static void
dtod_parse(config_dev_t *config_devp)
{
dtod_state_t * dtp;
lexer_tok_t tok;
if (config_devp->addrp->range != 8)
fatal("dumbtod: dumbtod requires address space size of 0x8");
DBG( printf("dumbtod_parse: parsing device %d\n", config_devp->device_id); );
dtp = (void*)Xcalloc(1, dtod_state_t);
dtp->todfreq = 1; /* defaults to 1 */
config_devp->devp = dtp;
tok = lex_get_token();
switch(tok) {
case T_S_Colon:
return;
case T_L_Brace:
break;
default:
lex_fatal("unexpected token");
}
/*
* Parse the optional tod frequency
*/
tok = lex_get_token();
if (strcmp(lex.strp,"frequency") == 0) {
dtp->todfreq = parse_number_assign();
if (dtp->todfreq == 0x0)
lex_fatal("dumbtod: dumbtod cannot have a tod freq of 0");
printf("dumbtod_parse: setting tod frequency of %lld\n", dtp->todfreq);
}
lex_get(T_R_Brace);
}
/*
* Initialise the device after parsing is complete
*/
static void
dtod_init(config_dev_t *config_devp)
{
dtod_state_t * dtp;
dtp = config_devp->devp;
dtp->start_time = time(NULL);
dtp->sysclkfreq = 0; /* find put from first CPU access */
}
/*
* Configuration dump
*/
void
dtod_dump(config_dev_t *config_devp)
{
}
static bool_t
dtod_cpu_access(simcpu_t *sp, config_addr_t *cap, tpaddr_t offset, maccess_t op,
uint64_t *regp)
{
dtod_state_t * dtp;
if ((op & MA_Op_Mask) != MA_Ld && (op & MA_Op_Mask) != MA_LdSigned) {
EXEC_WARNING(("dumbtod: Illegal access - only loads allowed "
"to TOD device"));
return (false);
}
if (offset != 0 || (op & MA_Size_Mask) != MA_Size64) {
EXEC_WARNING(("dumbtod: Illegal device load access (%d bytes) "
"- offset (0x%d) not 8-byte sized or aligned",
1<<(op & MA_Size_Mask), offset));
return (false);
}
dtp = cap->config_devp->devp;
#if WALL_TIME /* { */
if (options.walltime) {
*regp = time(NULL) * dtp->todfreq;
return (true);
}
#endif /* } */
if (dtp->sysclkfreq == 0) {
/* First time through - obtain clock frequency. */
dtp->sysclkfreq = sp->config_procp->domainp->sysclkfreq;
}
*regp = (dtp->start_time + (time_t)(sp->cycle / dtp->sysclkfreq)) * dtp->todfreq;
return (true);
}