Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / common / csr_common.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: csr_common.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 ============================================
/*
* Copyright (c) 2003-2004 by Sun Microsystems, Inc.
* All rights reserved.
*/
#include "csr_common.h"
#include "string.h"
#include "assert.h"
/*******************************************************************************
* csr_get_reg
*
* Given a register's offset, find the register in the given list of
* registers. If it does not exist, create it and insert it in the
* list.
*/
csr_reg_t *
common_csr::csr_get_reg (csr_reg_t **csr_list, uint64_t offset,csrtab_t *csrtab,csr_field_t *csr_fields,uint64_t *cumsum)
{
return csr_get_regtype(csr_list, csr_offset2reg(offset),csrtab,csr_fields,cumsum);
} /* csr_get_reg */
/*******************************************************************************
* csr_get_regtype
*
* Given a register's type, find the register in the given list of
* registers. If it does not exist, create it and insert it in the
* list.
*/
csr_reg_t *
common_csr::csr_get_regtype (csr_reg_t **csr_list, csr_reg_type_t reg_type,csrtab_t *csrtab,csr_field_t *csr_fields,uint64_t *cumsum)
{
csr_reg_t *p=NULL, **pb=NULL, *new_csr=NULL;
assert(csr_list);
for (pb = csr_list; (p = *pb) != NULL; pb = (csr_reg_t **)&p->next)
if (reg_type <= p->reg_type)
break;
if (p && reg_type == p->reg_type)
return p;
new_csr = (csr_reg_t *)new csr_reg_t;
init_csr_reg (new_csr, reg_type,csrtab,csr_fields,cumsum);
new_csr->next = p;
*pb = new_csr;
return new_csr;
} /* csr_get_regtype */
/*******************************************************************************
* csr_read_reg
*
* Read csr from its storage object
*/
int
common_csr::csr_read_reg (Module *csr_obj, csr_reg_t *csr_reg, uint64_t offset,
uint64_t *value)
{
int idx = (int)((offset - csr_reg->offset) / 8);
if(idx >=0){
if(csr_obj){
csr_obj->debug_more("%s: csr_read_reg:%s value:%016llx\n",csr_obj->getName(), csr_reg->name,csr_reg->value[idx]);
}
*value = csr_reg->value[idx];
return TRUE;
}
csr_obj->debug_err("%s:csr_read_reg :%s invalid offset:%016llx\n",csr_obj->getName(), csr_reg->name,offset);
return FALSE;
} /* csr_read_reg */
/*******************************************************************************
* csr_write_reg
*
* Write csr to its storage object
*/
int
common_csr::csr_write_reg (Module *csr_obj, csr_reg_t *csr_reg, uint64_t offset,
uint64_t reg_value)
{
int idx = (int)((offset - csr_reg->offset) / 8);
if(idx >= 0){
csr_reg->value[idx] = reg_value;
if(csr_obj){
csr_obj->debug_more("%s:csr_write_reg :%s value:%016llx\n",csr_obj->getName(), csr_reg->name,reg_value);
}
return TRUE;
}
csr_obj->debug_err("%s:csr_write_reg :%s invalid offset:%016llx\n",csr_obj->getName(), csr_reg->name,offset);
return FALSE;
} /* csr_write_reg */
/*******************************************************************************
* csr_get_field
*
* Given a register's field name, extract its value
*/
uint64_t
common_csr::csr_get_field(Module *csr_obj, csr_reg_t *csr_reg, const char *field_name,
uint64_t offset)
{
int i;
uint64_t reg_value = 0;
csr_read_reg(csr_obj, csr_reg, offset, &reg_value);
for (i = 0; i < csr_reg->num_fields; i++) {
if (!strcmp(csr_reg->fields[i].name, field_name)) {
uint64_t mask;
mask = LWord(-1) >>
(63 - (csr_reg->fields[i].l - csr_reg->fields[i].r));
reg_value >>= csr_reg->fields[i].r;
reg_value &= mask;
if (csr_obj)
csr_obj->debug_more("%s:Get field %s.%s: 0x%llx\n", csr_obj->getName(),csr_reg->name, field_name, reg_value);
return reg_value;
}
}
if (csr_obj)
csr_obj->debug_err("%s:unknown field '%s' in register '%s'\n",csr_obj->getName(),field_name, csr_reg->name);
return 0;
} /* csr_get_field */
/*******************************************************************************
* csr_set_field
*
* Given a register's field name, set its value
*/
uint64_t
common_csr::csr_set_field(Module *csr_obj, csr_reg_t *csr_reg, const char *field_name ,
uint64_t field_value, uint64_t offset)
{
int i;
uint64_t reg_value = 0;
csr_read_reg(csr_obj, csr_reg, offset, &reg_value);
for (i = 0; i < csr_reg->num_fields; i++) {
if (!strcmp(csr_reg->fields[i].name, field_name)) {
uint64_t maskl =
LWord(-1) >> (63 - csr_reg->fields[i].l);
uint64_t maskr =
LWord(-1) << (csr_reg->fields[i].r);
uint64_t mask = maskl & maskr;
if (csr_obj)
csr_obj->debug_more("%s:Set field %s.%s: 0x%llx\n",csr_obj->getName(),csr_reg->name, field_name, field_value);
field_value <<= csr_reg->fields[i].r;
field_value &= mask;
reg_value &= ~mask;
reg_value |= field_value;
csr_write_reg(csr_obj, csr_reg, offset, reg_value);
return reg_value;
}
}
if (csr_obj)
csr_obj->debug_err("%s:unknown field '%s' in register '%s'\n",csr_obj->getName(), field_name, csr_reg->name);
return reg_value;
} /* csr_set_field */
/*******************************************************************************
* csr_get_reg_by_name
* Given a register's name, get its regtype
* Return -1 if not found.
*/
csr_reg_type_t
common_csr::csr_get_reg_by_name(char *regname,csrtab_t *csrtab,uint64_t ncsrtab)
{
int64_t i;
for (i = ncsrtab; 0 <= --i; )
if (!strcmp(regname, csrtab[i].name))
return csrtab[i].type;
return (csr_reg_type_t)(-1);
} /* csr_get_reg_by_name */
/*
* csr_value_get_field
*
* Side-effect free way to extract a value of a register's field. csr_reg must
* point to a valid register object, but its value will be ignored: instead,
* 'reg_value' will be used.
*/
uint64_t
common_csr::csr_value_get_field(Module *csr_obj, csr_reg_t *csr_reg,
const char *field_name, uint64_t reg_value)
{
int i;
for (i = 0; i < csr_reg->num_fields; i++) {
if (!strcmp(csr_reg->fields[i].name, field_name)) {
uint64_t mask;
mask = LWord(-1) >>
(63 - (csr_reg->fields[i].l - csr_reg->fields[i].r));
reg_value >>= csr_reg->fields[i].r;
reg_value &= mask;
if(csr_obj){
csr_obj->debug_more("%s:Get field %s.%s: 0x%llx\n",csr_obj->getName(),csr_reg->name, field_name, reg_value);
}
return reg_value;
}
}
if(csr_obj){
csr_obj->debug_err("%s:unknown field '%s' in register '%s'\n", csr_obj->getName(),field_name, csr_reg->name);
}
return 0;
}
/*
* csr_field_changed
*
* Returns true if the field specified by 'field_name' for the given register
* object has changed values between 'reg_value1' and 'reg_value2'
*/
int
common_csr::csr_field_changed(Module *csr_obj, csr_reg_t *csr_reg,
const char *field_name,
uint64_t reg_value1, uint64_t reg_value2)
{
uint64_t first, second;
first = csr_value_get_field(csr_obj, csr_reg, field_name, reg_value1);
second = csr_value_get_field(csr_obj, csr_reg, field_name, reg_value2);
return first != second;
}
/*******************************************************************************
* csr_get_field_name
*
* Given 'csr_reg' and 'reg_value', check the field at the given 'bit' position
* and return the field name if that bit field is set.
*/
const char *
common_csr::csr_get_field_name(Module *csr_obj, csr_reg_t *csr_reg, int bit, uint64_t reg_value)
{
uint64_t mask, bit_value;
const char *name = NULL;
mask = LWord(-1) >>
(63 - (csr_reg->fields[bit].l - csr_reg->fields[bit].r));
bit_value = (reg_value >> csr_reg->fields[bit].r) & mask;
if (bit_value) {
name = csr_reg->fields[bit].name;
if (csr_obj)
csr_obj->debug_more("%s:Get field name %s.%s: 0x%llx\n",csr_obj->getName(),csr_reg->name, name, reg_value);
}
return name;
} /* csr_get_field_name*/
/*******************************************************************************
* csr_reset_reg
*
* Write the csr reset value to its storage object
*/
bool
common_csr::csr_reset_reg(Module *csr_obj, csr_reg_t **csr_list,uint64_t value, csr_reg_type_t type,csrtab_t *csrtab,csr_field_t *csr_fields,uint64_t *cumsum, uint64_t offset)
{
bool rc = FALSE;
csr_reg_t *csr_reg;
csr_reg = csr_get_regtype(csr_list, type,csrtab,csr_fields,cumsum);
rc = csr_write_reg(csr_obj, csr_reg, offset, value);
return rc;
} /* csr_reset_reg */
/*******************************************************************************
* csr_write_mask_reg
*
* This function operates on a pair of aliased CSRs whose types are indicated
* by the input value of the last three arguments either as
*
* case A: (rw1c, rw1s, 0)
* or
* case B: (rw1c, 0, rw)
*
* For either case, it computes the new value of the given aliased register
* csr_reg whose type is one of the rw1c, rw1c and rw, and updates both the
* aliased registers. The purpose is to keep the stored csr value of the pair
* in sync so either one can be used for the corresponding read op).
*/
bool
common_csr::csr_write_mask_reg(Module *csr_obj, csr_reg_t **csr_list,csr_reg_type_t type,csrtab_t *csrtab,csr_field_t *csr_fields,uint64_t *cumsum,uint64_t old_value, uint64_t *new_value, csr_reg_type_t rw1c, csr_reg_type_t rw1s, csr_reg_type_t rw, uint64_t offset)
{
csr_reg_t *csr_reg_alias;
bool rc = FALSE;
if (type == rw1c) {
*new_value = old_value & ~*new_value;
csr_reg_alias = csr_get_regtype(csr_list, rw1s ? rw1s : rw,csrtab,csr_fields,cumsum);
}
else {
if (type == rw1s)
*new_value = old_value | *new_value;
csr_reg_alias = csr_get_regtype(csr_list, rw1c,csrtab,csr_fields,cumsum);
}
assert(csr_reg_alias->depth == 1);
rc = csr_write_reg(csr_obj, csr_reg_alias, csr_reg_alias->offset, *new_value);
// update the actual register as well.
csr_reg_t * csr_reg = csr_get_regtype(csr_list,type,csrtab,csr_fields,cumsum);
rc |= csr_write_reg(csr_obj,csr_reg,csr_reg->offset, *new_value);
return rc;
} /* csr_write_mask_reg */
/*******************************************************************************
* csr_set_mask_field
*
* This function operates on a pair of aliased CSR 'csr_reg' of type
*
* ('rw1c', 'rw').
*
* Given the 'field_name' and 'field_value', it computes the new value of the
* given CSR 'csr_reg' in terms of its type (either rw1c or rw), and stores
* the new value in the storage for both CSRs. The purpose is to keep the
* stored csr value of the pair in sync so either one can be used for the
* corresponding read op.
*/
bool
common_csr::csr_set_mask_field(Module *csr_obj,csr_reg_t **csr_list,csrtab_t *csrtab,csr_field_t *csr_fields,uint64_t *cumsum,csr_reg_t *csr_reg,const char *field_name,uint64_t field_value, csr_reg_type_t rw1c, csr_reg_type_t rw, uint64_t offset)
{
int i;
uint64_t old_value = 0, new_value;
bool rc = FALSE;
/* read the old value in csr_reg */
// csr_read_reg(csr_obj, csr_reg, offset, &old_value);
csr_reg_t* csr_rw1c = csr_get_regtype(csr_list,rw1c,csrtab,csr_fields,cumsum);
csr_set_field(csr_obj,csr_rw1c,field_name,field_value,csr_rw1c->offset);
csr_reg_t* csr_rw = csr_get_regtype(csr_list,rw,csrtab,csr_fields,cumsum);
csr_set_field(csr_obj,csr_rw,field_name,field_value,csr_rw->offset);
/* left shift the field_value to a 64 bit value */
/* for (i = 0; i < csr_reg->num_fields; i++) {
if (!strcmp(csr_reg->fields[i].name, field_name)) {
uint64_t maskl =
UINT64_C(-1) >> (63 - csr_reg->fields[i].l);
uint64_t maskr =
UINT64_C(-1) << (csr_reg->fields[i].r);
uint64_t mask = maskl & maskr;
new_value = field_value << csr_reg->fields[i].r;
new_value &= mask;
break;
}
}
*/
/*
* computes the new_value of the given register 'csr_reg' and update
* the other aliased register
*/
// rc = csr_write_mask_reg(csr_obj, csr_list,csr_reg->reg_type,csrtab,csr_fields,cumsum,old_value,&new_value, rw1c, 0, rw, offset);
/*
* finally update the given register with the new_value
*/
//rc = csr_write_reg(csr_obj, csr_reg, offset, new_value);
if (csr_obj){
csr_obj->debug_more("%s:csr_set_mask_field:Set field '%s' in register '%s','%s'\n", csr_obj->getName() ,field_name, csr_rw->name,csr_rw1c->name);
}
return rc;
} /* csr_set_mask_field */
void
common_csr::init_csr_reg (csr_reg_t *csr_reg, csr_reg_type_t reg_type,csrtab_t *csrtab,csr_field_t *csr_fields, uint64_t *cumsum) {
int i;
/* initialize the structure */
csr_reg->reg_type = reg_type;
csr_reg->name = csrtab[reg_type].name;
csr_reg->offset = csrtab[reg_type].offset;
csr_reg->read_mask = csrtab[reg_type].read_mask;
csr_reg->read_only_mask = csrtab[reg_type].read_only_mask;
csr_reg->write_mask = csrtab[reg_type].write_mask;
csr_reg->write_only_mask = csrtab[reg_type].write_only_mask;
csr_reg->clear_mask = csrtab[reg_type].clear_mask;
csr_reg->set_mask = csrtab[reg_type].set_mask;
csr_reg->power_on_reset = csrtab[reg_type].power_on_reset;
csr_reg->depth = csrtab[reg_type].depth;
csr_reg->num_fields = csrtab[reg_type].num_fields;
csr_reg->value = (uint64_t *)new uint64_t[csrtab[reg_type].depth];
for(i=0; i<csrtab[reg_type].depth; i++) {
csr_reg->value[i] = csr_reg->power_on_reset;
}
csr_reg->fields = (csr_field_t *) new csr_field_t[(csrtab[reg_type].num_fields)];
for(i=0; i<csrtab[reg_type].num_fields; i++) {
csr_reg->fields[i].name = csr_fields[cumsum[reg_type]+i].name;
csr_reg->fields[i].l = csr_fields[cumsum[reg_type]+i].l;
csr_reg->fields[i].r = csr_fields[cumsum[reg_type]+i].r;
}
csr_reg->sp_access = csrtab[reg_type].sp_access;
csr_reg->jtag_access = csrtab[reg_type].jtag_access;
csr_reg->domain_access = csrtab[reg_type].domain_access;
csr_reg->next = NULL;
} /* init_csr_reg */