Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / common / regdef / include / Register.h
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: Register.h
* 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 ============================================
*/
#ifndef __Register_h
#define __Register_h
#include <stddef.h>
#include <assert.h>
#include <iostream>
#include <fstream>
#include <string>
#include "Block.h"
#include "Object.h"
#include "Datatype.h"
#include "Signature.h"
using namespace std;
/** @file Register.h
* Register.h provides a set of classes for representing registers.
*
* @see RegisterModule
*/
/** @defgroup RegisterModule The Register Module
*
* Registers are 8, 16, 32 or 64 bits wide, and are composed of Fields.
* Fields are contiguous collections of bits within a Register. The value
* of a Register can be accessed at the Register level or at the
* Field level. Care is taken to ensure that large arrays of 64-bit registers
* are implemented efficiently - in terms of memory usage and run-time
* cost. Note that there is significant waste in the storage of narrower
* registers since they are held in 64-bit containers (with unused upper bits
* always zero).
*
* The classes and types defined here are:
* - AccessType
* - Register
* - Field
*
* The following classes are also defined in this file, but are not
* intended for use outside Register/Field implementation:
* - RegisterType
* - RegisterState
* - RegisterInfo
* - FieldType
*
* The "public" interface provided by this file consists of AccessType,
* Register and Field. The other classes are internal and not intended
* for use outside the Register/Field implementation.
*
* Note that there are no FieldState/FieldInfo classes. This is because
* the register state and info are held in RegisterState/RegisterInfo
* and the field-level mechanisms pull out the necessary bits from
* the register. There are (too) many friendships
* between the various register and field classes - they work together
* very closely and this avoids having to define a lot more methods
* to access the internal state. Originally, this class was implemented
* as just Register and Field classes with simple array container
* classes that replicated registers. This was very inefficient for
* large register arrays, which turned out to be a significant problem at
* run-time. The classes were then restructured and rewritten so that only
* RegisterState/RegisterInfo had to be replicated for every element in a
* RegisterArray, and the amount of overhead data in this class was
* massively reduced.
*
* See also RegisterArray.h
*
* @{
*/
/** AccessType is an enumerated type used to distinguish the various
* supported access types. The access types are specified at the
* Field level. Since a Register can contain more than one Field,
* then a Register can have multiple access types associated with
* its Fields. The access types are:
* - Access_RC: read-to-clear.
* - Access_RO: read-only.
* - Access_RW: read-write.
* - Access_RW1C: read, write-one-to-clear.
* - Access_RW1S: read, write-one-to-set.
* - Access_RCW1C: read-to-clear, write-one-to-clear.
* - Access_RCW1S: read-to-clear, write-one-to-set.
* - Access_WO: read undefined, write-only.
* - Access_L: read as zero, write-only.
*/
typedef enum {
Access_RC, /**< - READ: return value and clear.
- WRITE: set value. */
Access_RO, /**< - READ: return value.
- WRITE: ignored. */
Access_RW, /**< - READ: return value.
- WRITE: set value. */
Access_RW1C, /**< - READ: return value.
- WRITE: clear the bits written as "1". */
Access_RW1S, /**< - READ: return value.
- WRITE: set the bits written as "1". */
Access_RCW1C, /**< - READ: return value and clear.
- WRITE: clear the bits written as "1". */
Access_RCW1S, /**< - READ: return value and clear.
- WRITE: set the bits written as "1". */
Access_WO, /**< - READ: undefined.
- WRITE: set value. */
Access_L /**< - READ: return zero.
- WRITE: set value. */
} AccessType;
/** The static constant value used for an undefined Register value. */
// static const Data UNDEFINED_DATA = Data(0xCAFEBABEBEEFFACE);
static const Data UNDEFINED_DATA = Data(0x0);
class FieldType; // forward reference
/** RegisterType contains the type information for a Register. These are
* static properties of a Register that are not typically modified once
* the Register has been created, and are consistent across all elements in a
* RegisterArray. A number of the fields in RegisterType are used to
* accelerate accesses to that Register by pre-calculating mask values,
* and also collate relevant information from the FieldType classes for the
* Register. Two booleans are used to keep track of whether the call-back
* mechanism has been enabled for read and write accesses. It is possible
* to enable/disable this mechanism on-the-fly but it is typically a
* static property. The call-back flags for a RegisterArray apply to every
* Register element in that array.
*
* Note that RegisterType is used in the implementation of the Register class.
* There should be no reason to use this class from elsewhere since Register
* provides a complete public interface to registers. Most of the state
* inside RegisterType is private without any direct access methods.
*/
class RegisterType
{
friend class Register;
friend class RegisterArray;
friend class FieldType;
public:
/** Constructor for RegisterType.
* @param w width of the Register in bytes (1, 2, 4 or 8 bytes).
*/
RegisterType(uint w=8);
private:
void check(string n);
uint widthBits;
uint widthBytes;
Data widthMask;
Data checkMask;
Data writeMask;
Data writeOneToClearMask;
Data writeOneToSetMask;
Data readMask;
Data readAsUndefinedMask;
Data readAsZeroMask;
Data readToClearMask;
Data resetValue;
Data resetAssigned;
bool writeBlockCB;
bool readBlockCB;
List<FieldType> fieldTypes;
};
/** RegisterState holds the value for a particular Register in a 64-bit
* container.
*
* The RegisterState class contains the value for an undefined Register, and
* this is also used to derive the value for an undefined Field. This is
* arranged so that if all Fields of a Register are given the undefined
* Field value, then the value of the Register is the undefined Register
* value. Note that a "randomized" undefined value is good for catching
* discrepanies between hardware and software views of registers, but 0x0
* is more convenient when tracing or debugging.
*
* Note that RegisterState is used in the implementation of the Register
* class. There should be no reason to use this class from elsewhere since
* Register provides a complete public interface to registers.
*/
class RegisterState
{
friend class Register;
friend class RegisterArray;
friend class Field;
public:
/** Constructor for RegisterState.
* @param v initial value of the Register (defaults to UNDEFINED_DATA).
*/
RegisterState(Data v=UNDEFINED_DATA)
{
value=v;
}
private:
Data value;
};
/** RegisterInfo holds other information associated with each RegisterState
* instance. This includes fields to track whether this Register is
* clean/dirty (used for tracing) and whether this Register has been
* assigned a value (ie. initialized - this information is maintained
* but not actually used for anything yet). The reason for separating
* out RegisterInfo from RegisterInfo is to give more efficient memory
* usage (smaller class size).
*
* TODO - one idea for the assigned bit is to ensure that unassigned
* Register instances can take an UNDEFINED_DATA value without having
* to set them to this value at construction or reset time. This could
* be useful to reduce the amount of memory initialization
* (and in-core memory) required for the simulation of very large
* RegisterArrays. In fact, the RegisterState instance of an unassigned
* RegisterArray could be allocated lazily (ie. on first write). This
* would require modifications to all register and field access mechanisms
* (get, set, read, write, etc) to catch accesses to unassigned state.
* This potential optimization does not seem worthwhile yet and thus has
* not been implemented. Note that care has been taken to minimize the amount
* of overhead for large RegisterArrays and this has been sufficient so far.
*
* Note that RegisterInfo is used in the implementation of the Register
* class. There should be no reason to use this class from elsewhere since
* Register provides a complete public interface to registers.
*/
class RegisterInfo
{
friend class Register;
friend class RegisterArray;
friend class Field;
public:
/** Constructor for RegisterInfo.
* @param a initial setting for the assigned bit (defaults to unassigned).
* @param b initial setting of the clean bit (defaults to dirty).
*/
RegisterInfo(bool a=false, bool b=false)
{
assigned=a;
clean=b;
}
/** Get the assigned boolean. */
bool getAssigned() const { return assigned; }
/** Set the assigned boolean.
* @param b the new value for the assigned boolean. */
void setAssigned(bool b) { assigned = b; }
/** Get the clean boolean. */
bool getClean() const { return clean; }
/** Set the clean boolean.
* @param b the new value for the clean boolean. */
void setClean(bool b) { clean = b; }
/** Get the dirty boolean. */
bool getDirty() const { return !clean; }
/** Set the dirty boolean.
* @param b the new value for the dirty boolean. */
void setDirty(bool b) { clean = !b; }
private:
bool assigned;
bool clean;
};
/** The Register class provides mechanisms to construct and access Register
* instances. After a Register is constructed, it is necessary to construct
* one or more instances of the Field class and associate them with the
* Register. A Register must be populated with Fields to define how each
* bit in the Register should behave for reads and writes, and to specify
* any defined initial value for the Register.
*
* Internally, the Register class contains pointers to RegisterType and
* RegisterState instances, which hold the type and state for this
* Register respectively. For a RegisterArray, an array of Registers is
* not allocated since this is too expensive. Instead one RegisterState
* is allocated for each Register in the array, and one RegisterType is
* allocated for the whole array. When a RegisterArray is subscripted to
* yield a Register, an instance of the Register class is initialized
* appropriately. This is returned-by-value so that the state is
* provided by the caller of the RegisterArray subscription operator.
* This Register instance gets destructed when it goes out of
* scope or is deallocated by the caller. Additionally, the returned
* Register refers to the correct RegisterState structure in the original
* RegisterArray so that writes/sets to the returned Register structure
* will correctly update the value in the array. In some ways it is more
* appropriate to consider the Register structure as a register
* handle, and not the register value itself.
*/
class Register
{
friend class Field;
friend class RegisterArray;
public:
/** Constructor for Register.
* @param n the basename for this Register.
* @param b a pointer to the Block with which this Register is associated.
* The fullname of this Register is scoped within that Block.
* @param a the address of this Register.
* @param w the width of this Register in bytes, defaults to 8 bytes.
*
* If the parent block is specified as NULL (which is its default), then
* this Register will not be associated with any parent and will not
* be included in any of the register mechanisms provided by the Block
* class. In particular the Register will not be in the print, reset,
* sign or trace trees, and the Register will not be included in the
* address map of that Block. Additionally, the call-back mechanism
* for side-effecting reads/writes cannnot be used.
*
* If there is no parent block then no interpretation will be placed on
* the address by the Register class. This mechanism is convenient for
* modelling structures that have similar structure to registers
* (e.g. composed of fields) but that are not architectural state.
* If the Register class is used in this way, then it is up to the
* user to provide all required infrastructure (such as a call to
* reset its state). The RegisterArray/FieldArray classes do not
* support Blockless registers.
*/
Register(string n, Block *b=NULL, Addr a=Addr(0), uint w=8);
/** The copy constructor for Register. The destination Register is marked
* as derived so that destructing that Register does not deallocate the
* heap state allocated by the source Register. It is assumed that
* non-derived Register instances (the original source of one or more
* copies) will out-live all copies. This is reasonable since non-derived
* Register instances correspond to architectural state and should be
* allocated for the entire simulation.
* @param r the source Register for the copy construction.
*/
Register(const Register &r);
/** Constructor for Register with no parameters to initialize the register
* to a default state. This is provided for the RegisterArray::lookup()
* mechanism. */
Register();
/** Destructor for Register. This is virtual so that the appropriate
* destructor for any derived class is used. */
virtual ~Register();
/** The copy assignment operator for Register. The destination Register is
* marked as derived so that destructing that Register does not deallocate
* the heap state allocated by the source Register. It is assumed that
* non-derived Register instances (the original source of one or more
* copies) will out-live all copies. This is reasonable since non-derived
* Register instances correspond to architectural state and should be
* allocated for the entire simulation.
* @param r the source Register for the copy assignment.
*/
Register &operator=(const Register &r);
/** Clone a new copy of this Register. This creates a Register instance
* using new and performs a shallow copy of this Register into the new
* Register. The new Register is marked as derived so that deletion of
* the new Register does not deallocate the heap state of this Register.
* A pointer to the new Register is returned, and it is the responsibility
* of the caller to delete the pointer when the new Register is no
* longer required. This is a virtual function so that it can be
* overloaded by sub-classes of Register as appropriate. */
virtual Register *clone() const { return new Register(*this); }
/** Get the basename of this Register. */
string getBaseName() const;
/** Get the fullname of this Register. */
string getFullName() const;
/** Get the address of this Register. */
Addr getAddr() const { return addr; }
/** Get the width in bytes of this Register. */
uint getWidth() const { return regType->widthBytes; }
/** Get a pointer to the Data associated with this Register. */
Data *getPtr() { return &regState->value; }
/** Return true if this Register is an element in a RegisterArray,
* otherwise false. */
bool isElement() const { return element; }
/** If this Register is an element in a RegisterArray, get the index
* of this element. If this Register is not an element in a RegisterArray
* the behavior of this method is undefined. */
uint getIndex() const { assert(element); return index; }
/** Get the value of this Register. This returns the value of the full
* width of the Register regardless of the AccessType settings of the
* associated fields. For Registers that are narrower than 64 bits, the
* upper unused bits will be returned as zero. This method is suitable
* for simulator code that models internal hardware
* accesses. It should not be used to model software accesses to the
* architectural state - these should use the Register::read method.
*/
inline Data get() const
{
return regState->value;
}
/** Get the value of this Register. This returns the value of the full
* width of the Register regardless of the AccessType settings of the
* associated fields. For Registers that are narrower than 64 bits, the
* upper unused bits will be returned as zero. This method is suitable
* for simulator code that models internal hardware
* accesses. It should not be used to model software accesses to the
* architectural state - these should use the Register::read method.
*/
inline operator Data() const
{
return regState->value;
}
/** Get the reset value of this Register. For Registers that are narrower
* than 64 bits, the upper unused bits will be returned as zero. */
Data getResetValue() const
{
return regType->resetValue;
}
/** Set the value of this Register. This sets the value for the full width
* of the Register regardless of the AccessType settings of the associated
* fields. For Registers that are narrower than 64 bits, the
* upper unused bits will be forced to zero, regardless of the parameter d.
* This method is suitable for simulator code that models internal
* hardware accesses. It should not be used to model software accesses
* to the architectural state - these should use the Register::write method.
* @param d the new Data value for this Register.
*/
inline void set(Data d)
{
regState->value = d & regType->widthMask;
regInfo->assigned = true;
regInfo->clean = false;
}
/** Set the value of this Register. This sets the value for the full width
* of the Register regardless of the AccessType settings of the associated
* fields. For Registers that are narrower than 64 bits, the
* upper unused bits will be forced to zero, regardless of the parameter d.
* This method is suitable for simulator code that models internal
* hardware accesses. It should not be used to model software accesses
* to the architectural state - these should use the Register::write method.
* @param d the new Data value for this Register.
*/
inline Register &operator=(Data d)
{
set(d);
return *this;
}
/** Read the value of this Register. This returns from the value with
* the AccessType of each Field applied appropriately. For Registers
* that are narrower than 64 bits, the upper unused bits will be
* returned as zero. There may be other hardware side-effects caused by the
* act of reading, as required by the architecture specification for
* this Register. This method is suitable to model software
* accesses to the architectural state. Other uses should consider
* the Register::get method.
*/
Data read()
{
Data original = regState->value;
Data d = (original & regType->readMask) |
(UNDEFINED_DATA & regType->readAsUndefinedMask);
if (regType->readToClearMask != 0) {
regState->value &= ~regType->readToClearMask;
regInfo->assigned = true;
regInfo->clean = false;
}
d = regReadCB(block, original, d);
if (regType->readBlockCB) {
assert(block != NULL);
d = block->regReadBlockCB(this, original, d);
}
return d;
}
/** Write the value of this Register. This writes to the value with
* the AccessType of each Field applied appropriately. For Registers
* that are narrower than 64 bits, the upper unused bits will be
* forced to zero, regardless of the parameter d. There may be other
* hardware side-effects caused by the act of writing, as required by
* the architecture specification for this Register. This method should
* be used to model software accesses to the architectural state. Other
* uses should consider the Register::set method.
* @param d the new Data value for this Register.
*/
void write(Data d)
{
Data original = regState->value;
if (regType->writeMask != 0) {
regState->value = (original & ~regType->writeMask) |
(d & regType->writeMask);
regInfo->assigned = true;
regInfo->clean = false;
}
if (regType->writeOneToClearMask != 0) {
Data clearMask = d & regType->writeOneToClearMask;
if (clearMask != 0) {
regState->value &= ~clearMask;
regInfo->assigned = true;
regInfo->clean = false;
}
}
if (regType->writeOneToSetMask != 0) {
Data setMask = d & regType->writeOneToSetMask;
if (setMask != 0) {
regState->value |= setMask;
regInfo->assigned = true;
regInfo->clean = false;
}
}
regWriteCB(block, original, d);
if (regType->writeBlockCB) {
assert(block != NULL);
block->regWriteBlockCB(this, original, d);
}
}
/** Call-back function for when a register is read from.
* @param b the Block associated with this Register, or NULL if no Block.
* @param origValue the value of this register prior to the read.
* @param readValue the result of the read of this register (following
* the conventions for the FieldType of each Field in the
* Register).
* @result the value that will be returned for this read.
*
* The regReadCB virtual method provides a call-back function called
* upon any read from this register. This can be
* be used to monitor accesses, trigger control side-effects or
* over-ride the default access semantics. The call-back function is
* called AFTER the architectural state of the register has been
* accessed/updated for the access, though the call-back has the opportunity
* to modify the architectural state if it needs to.
*
* Typically, the call-back will return readValue as the result. However,
* the call-back code has the opportunity to return any value allowing
* the FieldType conventions to be over-ridden if required. The value
* of the Register after the read can be accessed via the Register pointer.
* It must not be read/written as this will cause recursion into the
* call-back mechanism!! Instead, use Register::get and Register::set to
* access the register value directly.
*
* This is a virtual method, and its default implementation is to
* return the expected read value with no side-effects. Subclasses
* of Register can over-ride this method so that specific code is executed
* when a register is read from. It is NOT necessary to enable the
* Register-level call-back mechanism - providing a virtual method that
* over-rides Register::regReadCB is sufficient to catch the call-back.
*
* See also Block::regReadCB(). Note that Register-level call-backs are
* made before Block-level call-backs.
*/
virtual Data regReadCB(Block *b, Data origValue, Data readValue)
{
return readValue;
}
/** Call-back function for when a register is written to.
* @param b the Block associated with this Register, or NULL if no Block.
* @param origValue the value of this register prior to the write.
* @param writeValue the value that is being written to the register.
*
* The regWriteCB virtual method provides a call-back function called
* upon any write to this register. This can be
* be used to monitor accesses, trigger control side-effects or
* over-ride the default access semantics. The call-back function is
* called AFTER the architectural state of the register has been
* accessed/updated for the access, though the call-back has the opportunity
* to modify the architectural state if it needs to.
*
* The value of the Register after the write can be accessed via the
* Register pointer. It must not be read/written as this will cause
* recursion into the call-back mechanism!! Instead, use Register::get
* and Register::set to access the register value directly.
* Typically, the call-back will not modify the register value. However,
* the call-back code has the opportunity to write any value allowing
* the FieldType conventions to be over-ridden if required.
*
* This is a virtual method, and its default implementation is empty
* so that there are no side-effects. Subclasses of Register can over-ride
* this method so that specific code is executed when a register is
* written to. It is NOT necessary to enable the
* Register-level call-back mechanism - providing a virtual method that
* over-rides Register::regWriteCB is sufficient to catch the call-back.
*
* See also Block::regWriteCB(). Note that Register-level call-backs are
* made before Block-level call-backs.
*/
virtual void regWriteCB(Block *b, Data origValue, Data writeValue) {}
/** Mark this Register as unassigned and give this Register
* an undefined value. */
void undefined()
{
regState->value = UNDEFINED_DATA & regType->widthMask;
regInfo->assigned = false;
regInfo->clean = false;
}
/** Make this Register dirty. */
void makeDirty() { regInfo->clean = false; }
/** Make this Register clean. */
void makeClean() { regInfo->clean = true; }
/** Return true if this Register is dirty, else false. */
bool isDirty() { return !regInfo->clean; }
/** Return true if this Register is clean, else false. */
bool isClean() { return regInfo->clean; }
/** Enable write Block-level call-backs for this Register. */
void enableWriteBlockCB()
{
assert(block != NULL);
regType->writeBlockCB = true;
}
/** Disable write Block-level call-backs for this Register. */
void disableWriteBlockCB()
{
regType->writeBlockCB = false;
}
/** Enable read Block-level call-backs for this Register. */
void enableReadBlockCB()
{
assert(block != NULL);
regType->readBlockCB = true;
}
/** Disable read Block-level call-backs for this Register. */
void disableReadBlockCB()
{
regType->readBlockCB = false;
}
/** Print this Register to the specified output stream. */
void printThis(ostream &os);
/** Reset this Register to its initial value. */
void resetThis();
/** Create the Signature for this Register so that it can subsequently
* be traced.
* @param ofs the output file stream.*/
void signThis(ofstream &ofs);
/** Trace this Register to the specified output stream.
* @param ofs the output file stream.*/
void traceThis(ofstream &ofs);
private:
/** Initialize a derived Register to the specified values.
* @param b a pointer to the Block with which this Register is associated.
* @param a the address of this Register.
* @param e true if the Register is an element in an array, else false.
* @param i the index of the Register in the array if e is true.
* @param rt the RegisterType for this Register.
* @param rs the RegisterState for this Register.
* @param ri the RegisterInfo for this Register.
* @param s the Signature for this Register.
*/
void init(Block *b, Addr a, bool e, uint i, RegisterType *rt,
RegisterState *rs, RegisterInfo *ri, Signature *s);
string baseName;
Block *block;
Addr addr;
bool derived;
bool element;
uint index;
RegisterType *regType;
RegisterState *regState;
RegisterInfo *regInfo;
Signature *mySignature;
};
/** FieldType contains the type information for a Field. These are
* static properties of a Field that cannot be modified once the Field
* has been created, and are consistent across all elements in a FieldArray.
*
* Note that FieldType is used in the implementation of the Field class.
* There should be no reason to use this class from elsewhere since Field
* provides a complete public interface to fields. Most of the state
* inside FieldType is private without any direct access methods.
*/
class FieldType
{
friend class Field;
friend class FieldArray;
friend class Register;
public:
/** Constructor for FieldType.
* @param f the fullname of the associated Register.
* @param n the basename of this field.
* @param r the RegisterType to which this FieldType belongs.
* @param a the AccessType of this field.
* @param e the end bit position of this field (highest bit number).
* @param s the start bit position of this field (lowest bit number).
* @param b field has a defined initial value if true, otherwise
* undefined.
* @param d the initial value of the field (if it has one).
*/
FieldType(string f, string n, RegisterType *r, AccessType a,
uint e, uint s, bool b=false, Data d=0);
/** Get the basename of this FieldType. */
string getBaseName() const { return baseName; }
/** Get the access type of this FieldType as a string. */
string getAccessType() const;
private:
bool overlap(FieldType *f);
void check(RegisterType *r, string n);
string baseName;
RegisterType *regType;
AccessType access;
uint start;
uint end;
Data regMask;
Data fieldMask;
Data resetValue;
};
/** The Field class provides mechanisms to construct and access Field
* instances. When a Field is constructed, it is associated with a
* Register instance. The Register provides the state for the field
* (in the RegisterState class), while the Field provides the type
* information which is then collated into the RegisterType class.
*
* Internally, the Field class contains pointers to FieldType, RegisterType
* and RegisterState instances. For a FieldArray, an array of Fields is
* not allocated since this is too expensive. Instead just one FieldType is
* allocated for the whole array. When a FieldArray is subscripted to
* yield a Field, an instance of the Field class is initialized
* appropriately. This is returned-by-value so that the state is
* provided by the caller of the FieldArray subscription operator.
* This Field instance gets destructed when it goes out of
* scope or is deallocated by the caller. Additionally, the returned
* Field refers to the correct RegisterState structure in the original
* RegisterArray so that writes/sets to the returned Field structure
* will correctly update the value in the array. In some ways it is more
* appropriate to consider the Field structure as a field
* handle, and not the field value itself.
*/
class Field
{
friend class FieldArray;
public:
/** Constructor for Field.
* @param n the basename of this field.
* @param r the Register to which this Field belongs.
* @param a the AccessType of this field.
* @param e the end bit position of this field (highest bit number).
* @param s the start bit position of this field (lowest bit number).
* @param b field has a defined initial value if true, otherwise
* undefined.
* @param d the initial value of the field (if it has one).
*/
Field(string n, Register *r, AccessType a,
uint e, uint s, bool b=false, Data d=0);
/** The copy constructor for Field. The destination Field is marked
* as derived so that destructing that Field does not deallocate the
* heap state allocated by the source Field. It is assumed that
* non-derived Field instances (the original source of one or more
* copies) will out-live all copies. This is reasonable since non-derived
* Field instances correspond to architectural state and should be
* allocated for the entire simulation.
*/
Field(const Field &f);
/** Constructor for Field with no parameters to initialize the field
* to a default state. This is provided for the FieldArray::lookup()
* mechanism. */
Field();
/** Destructor for Field */
~Field();
/** The copy assignment operator for Field. The destination Field is
* marked as derived so that destructing that Field does not deallocate
* the heap state allocated by the source Field. It is assumed that
* non-derived Field instances (the original source of one or more
* copies) will out-live all copies. This is reasonable since non-derived
* Field instances correspond to architectural state and should be
* allocated for the entire simulation.
* @param f the source Field for the copy assignment.
*/
Field &operator=(const Field &f);
/** Get the basename of this Field. */
string getBaseName() const;
/** Get the fullname of this Field. */
string getFullName() const;
/** Get the access type of this field. */
AccessType getAccessType() const { return fieldType->access; }
/** Get the start bit number of this field. */
uint getStartBit() const { return fieldType->start; }
/** Get the end bit number of this field. */
uint getEndBit() const { return fieldType->end; }
/** Get a bit-mask for masking the field when the field is held
* in the appropriate bit positions in the associated Register. */
Data getRegMask() const { return fieldType->regMask; }
/** Get a bit-mask for masking the field when the lowest bit of
* field is held in bit 0 of a Data variable. */
Data getFieldMask() const { return fieldType->fieldMask; }
/** Get the value of this Field. This returns the full field value
* regardless of the AccessType setting. The value will be shifted
* down to bit 0 and masked to the width of the field. This method
* is suitable for simulator code that models internal hardware
* accesses.
*/
inline Data get() const
{
return (reg->regState->value >> fieldType->start) & fieldType->fieldMask;
}
/** Get the value of this Field. This returns the full field value
* regardless of the AccessType setting. The value will be shifted
* down to bit 0 and masked to the width of the field. This method
* is suitable for simulator code that models internal hardware
* accesses.
*/
inline operator Data() const
{
return get();
}
/** Get the value of this Field without shifting. This returns the full
* field value regardless of the AccessType setting. The value will
* NOT be shifted but will be left in the same bit position as the field
* in the whole Register. The value will be masked to the width of the
* field. This method is suitable for simulator code that models
* internal hardware accesses.
*/
inline Data getNoShift() const
{
return reg->regState->value & fieldType->regMask;
}
/** Get the reset value of this Field. */
Data getResetValue() const
{
return fieldType->resetValue;
}
/** Set the value of this Field. This sets the full field value
* regardless of the AccessType setting. The provided value will
* be shifted up to the start bit position of the field and masked
* to the width of the field. This method is suitable
* for simulator code that models internal hardware accesses.
* @param d the new Data value for the Field.
*/
inline void set(Data d)
{
reg->regState->value = (reg->regState->value & ~fieldType->regMask) |
((d & fieldType->fieldMask) << fieldType->start);
reg->regInfo->assigned = true;
reg->regInfo->clean = false;
}
/** Set the value of this Field. This sets the full field value
* regardless of the AccessType setting. The provided value will
* be shifted up to the start bit position of the field and masked
* to the width of the field. This method is suitable
* for simulator code that models internal hardware accesses.
* @param d the new Data value for the Field.
*/
inline Field &operator=(Data d)
{
set(d);
return *this;
}
/** Set the value of this Field without shifting. This sets the full field
* value regardless of the AccessType setting. The provided value will
* NOT be shifted and is required to already be in the same bit position
* as the field in the whole Register. It will be masked to the width of
* the field. This method is suitable for simulator code that models
* internal hardware accesses.
* @param d the new Data value for the Field.
*/
inline void setNoShift(Data d)
{
reg->regState->value = (reg->regState->value & ~fieldType->regMask) |
(d & fieldType->regMask);
reg->regInfo->assigned = true;
reg->regInfo->clean = false;
}
/** Read the value of this Field. This returns the value with
* the AccessType of each Field applied appropriately. Note that the
* Register call-back mechanism is applied only to whole Register
* reads/writes and not Field reads/writes. For this reason, architectural
* reads of Register values should use Register::read, and not be broken
* down into Field-level reads.
*/
Data read()
{
Data d;
if (fieldType->access == Access_WO)
d = (UNDEFINED_DATA >> fieldType->start) & fieldType->fieldMask;
else if (fieldType->access == Access_L)
d = 0;
else
d = (reg->regState->value >> fieldType->start) & fieldType->fieldMask;
if (fieldType->access == Access_RC ||
fieldType->access == Access_RCW1C ||
fieldType->access == Access_RCW1S) {
reg->regState->value &= ~fieldType->regMask;
reg->regInfo->assigned = true;
reg->regInfo->clean = false;
}
return d;
}
/** Write the value of this Field. This writes to the value with
* the AccessType of each Field applied appropriately. Note that the
* Register call-back mechanism is applied only to whole Register
* reads/writes and not Field reads/writes. For this reason, architectural
* writes to Register values should use Register::write, and not be broken
* down into Field-level writes.
* @param d the new Data value for the Field.
*/
void write(Data d)
{
if (fieldType->access == Access_RW1C ||
fieldType->access == Access_RCW1C) {
Data clearMask = (d & fieldType->fieldMask) << fieldType->start;
if (clearMask != 0) {
reg->regState->value &= ~clearMask;
reg->regInfo->assigned = true;
reg->regInfo->clean = false;
}
}
else if (fieldType->access == Access_RW1S ||
fieldType->access == Access_RCW1S) {
Data setMask = (d & fieldType->fieldMask) << fieldType->start;
if (setMask != 0) {
reg->regState->value |= setMask;
reg->regInfo->assigned = true;
reg->regInfo->clean = false;
}
}
else if (fieldType->access != Access_RO) {
reg->regState->value = (reg->regState->value & ~fieldType->regMask) |
((d & fieldType->fieldMask) << fieldType->start);
reg->regInfo->assigned = true;
reg->regInfo->clean = false;
}
}
private:
bool derived;
Register *reg;
FieldType *fieldType;
};
/** @} */
#endif