// ========== 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.
/*******************************************************************************
* 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
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
);
/*******************************************************************************
* 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
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
;
for (pb
= csr_list
; (p
= *pb
) != NULL
; pb
= (csr_reg_t
**)&p
->next
)
if (reg_type
<= p
->reg_type
)
if (p
&& reg_type
== p
->reg_type
)
new_csr
= (csr_reg_t
*)new csr_reg_t
;
init_csr_reg (new_csr
, reg_type
,csrtab
,csr_fields
,cumsum
);
/*******************************************************************************
* Read csr from its storage object
common_csr::csr_read_reg (Module
*csr_obj
, csr_reg_t
*csr_reg
, uint64_t offset
,
int idx
= (int)((offset
- csr_reg
->offset
) / 8);
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
];
csr_obj
->debug_err("%s:csr_read_reg :%s invalid offset:%016llx\n",csr_obj
->getName(), csr_reg
->name
,offset
);
/*******************************************************************************
* Write csr to its storage object
common_csr::csr_write_reg (Module
*csr_obj
, csr_reg_t
*csr_reg
, uint64_t offset
,
int idx
= (int)((offset
- csr_reg
->offset
) / 8);
csr_reg
->value
[idx
] = reg_value
;
csr_obj
->debug_more("%s:csr_write_reg :%s value:%016llx\n",csr_obj
->getName(), csr_reg
->name
,reg_value
);
csr_obj
->debug_err("%s:csr_write_reg :%s invalid offset:%016llx\n",csr_obj
->getName(), csr_reg
->name
,offset
);
/*******************************************************************************
* Given a register's field name, extract its value
common_csr::csr_get_field(Module
*csr_obj
, csr_reg_t
*csr_reg
, const char *field_name
,
csr_read_reg(csr_obj
, csr_reg
, offset
, ®_value
);
for (i
= 0; i
< csr_reg
->num_fields
; i
++) {
if (!strcmp(csr_reg
->fields
[i
].name
, field_name
)) {
(63 - (csr_reg
->fields
[i
].l
- csr_reg
->fields
[i
].r
));
reg_value
>>= csr_reg
->fields
[i
].r
;
csr_obj
->debug_more("%s:Get field %s.%s: 0x%llx\n", csr_obj
->getName(),csr_reg
->name
, field_name
, reg_value
);
csr_obj
->debug_err("%s:unknown field '%s' in register '%s'\n",csr_obj
->getName(),field_name
, csr_reg
->name
);
/*******************************************************************************
* Given a register's field name, set its value
common_csr::csr_set_field(Module
*csr_obj
, csr_reg_t
*csr_reg
, const char *field_name
,
uint64_t field_value
, uint64_t offset
)
csr_read_reg(csr_obj
, csr_reg
, offset
, ®_value
);
for (i
= 0; i
< csr_reg
->num_fields
; i
++) {
if (!strcmp(csr_reg
->fields
[i
].name
, field_name
)) {
LWord(-1) >> (63 - csr_reg
->fields
[i
].l
);
LWord(-1) << (csr_reg
->fields
[i
].r
);
uint64_t mask
= maskl
& maskr
;
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
;
reg_value
|= field_value
;
csr_write_reg(csr_obj
, csr_reg
, offset
, reg_value
);
csr_obj
->debug_err("%s:unknown field '%s' in register '%s'\n",csr_obj
->getName(), field_name
, csr_reg
->name
);
/*******************************************************************************
* Given a register's name, get its regtype
* Return -1 if not found.
common_csr::csr_get_reg_by_name(char *regname
,csrtab_t
*csrtab
,uint64_t ncsrtab
)
for (i
= ncsrtab
; 0 <= --i
; )
if (!strcmp(regname
, csrtab
[i
].name
))
return (csr_reg_type_t
)(-1);
} /* csr_get_reg_by_name */
* 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.
common_csr::csr_value_get_field(Module
*csr_obj
, csr_reg_t
*csr_reg
,
const char *field_name
, uint64_t reg_value
)
for (i
= 0; i
< csr_reg
->num_fields
; i
++) {
if (!strcmp(csr_reg
->fields
[i
].name
, field_name
)) {
(63 - (csr_reg
->fields
[i
].l
- csr_reg
->fields
[i
].r
));
reg_value
>>= csr_reg
->fields
[i
].r
;
csr_obj
->debug_more("%s:Get field %s.%s: 0x%llx\n",csr_obj
->getName(),csr_reg
->name
, field_name
, reg_value
);
csr_obj
->debug_err("%s:unknown field '%s' in register '%s'\n", csr_obj
->getName(),field_name
, csr_reg
->name
);
* Returns true if the field specified by 'field_name' for the given register
* object has changed values between 'reg_value1' and 'reg_value2'
common_csr::csr_field_changed(Module
*csr_obj
, csr_reg_t
*csr_reg
,
uint64_t reg_value1
, uint64_t reg_value2
)
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
);
/*******************************************************************************
* 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.
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
;
(63 - (csr_reg
->fields
[bit
].l
- csr_reg
->fields
[bit
].r
));
bit_value
= (reg_value
>> csr_reg
->fields
[bit
].r
) & mask
;
name
= csr_reg
->fields
[bit
].name
;
csr_obj
->debug_more("%s:Get field name %s.%s: 0x%llx\n",csr_obj
->getName(),csr_reg
->name
, name
, reg_value
);
} /* csr_get_field_name*/
/*******************************************************************************
* Write the csr reset value to its storage object
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
)
csr_reg
= csr_get_regtype(csr_list
, type
,csrtab
,csr_fields
,cumsum
);
rc
= csr_write_reg(csr_obj
, csr_reg
, offset
, value
);
/*******************************************************************************
* 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)
* 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).
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
;
*new_value
= old_value
& ~*new_value
;
csr_reg_alias
= csr_get_regtype(csr_list
, rw1s
? rw1s
: rw
,csrtab
,csr_fields
,cumsum
);
*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
);
} /* csr_write_mask_reg */
/*******************************************************************************
* This function operates on a pair of aliased CSR 'csr_reg' of type
* 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
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
)
uint64_t old_value
= 0, new_value
;
/* 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_C(-1) >> (63 - csr_reg->fields[i].l);
UINT64_C(-1) << (csr_reg->fields[i].r);
uint64_t mask = maskl & maskr;
new_value = field_value << csr_reg->fields[i].r;
* 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);
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
);
} /* csr_set_mask_field */
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
) {
/* 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
;