Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / cpus / vonk / ss / lib / cpu / src / SS_Tracer.h
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: SS_Tracer.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 __SS_Tracer_h__
#define __SS_Tracer_h__
#include <string.h>
#include "SS_Registers.h"
#include "SS_Types.h"
#include "SS_Trap.h"
#include "SS_Instr.h"
class SS_Tte;
class SS_Tlb;
class SS_Tracer
{
public:
enum TrapMode
{
NO_TRAP,
TRAP,
INST_TRAP,
DATA_TRAP
};
enum MemAccess
{
LD_CODE = 0x01,
ST_DATA = 0x02,
LD_DATA = 0x03,
ST_PART = 0x04, // data[0] = rd, data[1] = bytemask
ST_SWAP = 0x05, // data[0] = rd
LD_SWAP = 0x07, // data[0] = rd
ST_CAS = 0x08, // data[0] = rd, data[1] = rs2
LD_CAS = 0x09, // data[0] = rd
ST_LDST = 0x0a, // data[0] = store value (ldstub stores 0xff)
LD_LDST = 0x0b, // data[0] = rd
FLUSH = 0x10, // data == 0 in mem_access call
PREFETCH = 0x11 // data == 0 in mem_access call
};
static int is_fetch( MemAccess ma ) { return ma == LD_CODE; }
static int is_load( MemAccess ma ) { return (ma & 1) == 1; }
static int is_store( MemAccess ma ) { return (ma & 1) == 0; }
static int is_cohere( MemAccess ma ) { return (ma & 0x10) == 0x10; }
SS_Tracer()
:
hook_exe_instr(0),
hook_reg_value(0),
hook_trap(0),
hook_mem_access(0),
hook_asi_access(0),
hook_tlb_update(0),
hook_hwop(0),
hook_end_instr(0),
trap_mode(NO_TRAP),
trap_addr(0),
next(0)
{
memset(state,0,sizeof(state));
}
virtual ~SS_Tracer() {}
void (*hook_exe_instr) ( SS_Tracer*, SS_Vaddr pc, SS_Tte* tte, SS_Instr* i );
void (*hook_reg_value) ( SS_Tracer*, SS_Registers::Index index, uint64_t value );
void (*hook_trap) ( SS_Tracer*, SS_Trap::Type tt, TrapMode mode, SS_Vaddr ea );
void (*hook_mem_access)( SS_Tracer*, MemAccess, SS_Vaddr, SS_Tte*, uint_t size, uint64_t* data );
void (*hook_asi_access)( SS_Tracer*, MemAccess, uint8_t asi, SS_Vaddr, uint64_t* data );
void (*hook_tlb_update)( SS_Tracer*, bool insert, SS_Tlb* tlb, uint_t index, SS_Tte* tte );
void (*hook_hwop) ( SS_Tracer*, MemAccess type, SS_Paddr addr, uint_t size, uint64_t *value );
void (*hook_end_instr) ( SS_Tracer* );
SS_Tracer* next; // There can be more then one tracer per strand
bool need_mem_trc()
{
if (hook_mem_access)
return true;
else if (next)
return next->need_mem_trc();
else
return false;
}
// exe_instr() is called for every instruction to trace its
// virtual pc, physical pc and the instruction word executed.
void exe_instr( SS_Vaddr pc, SS_Tte* tte, SS_Instr* i )
{
if (hook_exe_instr) (hook_exe_instr)(this,pc,tte,i);
if (next) next->exe_instr(pc,tte,i);
}
// reg_value() is called for each register that changed value as a
// result of executing an instruction. Note that this is a template
// function to allow for product spefic SS_Registers::Index extensions.
// The given index is casted to SS_Register::Index.
template<class Index>
void reg_value( Index index, uint64_t value )
{
if (hook_reg_value) (hook_reg_value)(this,SS_Registers::Index(index),value);
if (next) next->reg_value(SS_Registers::Index(index),value);
}
// trap() is called to trace trapping
void trap( SS_Trap::Type trap_type )
{
// in cosim mode, there are likely two (or more) SS_Tracer objects are
// registered (i.e., linked by 'next' field) for each strand. When a trap
// occurres, we have to traverse through all of them to perform each
// object's own trace function. If a trap is a mmu trap, then an
// inst_trap() or data_trap() will be called before the trap() is called,
// since inst_trap() and data_trap() may deposit more specific
// trap_mode and trap_addr information, we should not overwrite those
// fields in such case.
if (trap_mode == NO_TRAP)
{
trap_mode = TRAP;
trap_addr = 0;
}
if (hook_trap) (hook_trap)(this,trap_type,trap_mode,trap_addr);
if (next) next->trap(trap_type);
}
// mem_access() is called before memory is written and/or after
// memory is read. Note atomic instruction do both read and write.
void mem_access( MemAccess type, SS_Vaddr va, SS_Tte* tte, uint_t size, uint64_t* data )
{
if (hook_mem_access) (hook_mem_access)(this,type,va,tte,size,data);
if (next) next->mem_access(type,va,tte,size,data);
}
// asi_access is called after non translating asi is read/written
void asi_access( MemAccess type, uint8_t asi, SS_Vaddr va, uint64_t* data )
{
if (hook_asi_access) (hook_asi_access)(this,type,asi,va,data);
if (next) next->asi_access(type,asi,va,data);
}
// tlb_update() is called whenever a tte is inserted or removed from the
// tlb. The tte can not be cached. All values need need to be read in
// during the call tlb_update() call.
void tlb_update( bool insert, SS_Tlb* tlb, uint_t index, SS_Tte* tte )
{
if (hook_tlb_update) (hook_tlb_update)(this,insert,tlb,index,tte);
if (next) next->tlb_update(insert,tlb,index,tte);
}
// hwop() is called whenever a hw state machine access memory to
// to fetch tte from tsb.
void hwop( MemAccess type, SS_Paddr addr, uint_t size, uint64_t *value )
{
if (hook_hwop) (hook_hwop)(this,type, addr, size, value);
if (next) next->hwop(type, addr, size, value);
}
// end_instr() is called when all the above tracing interface calls
// have been made. Its can be used to for example the output trace record
// for an instruction.
void end_instr()
{
if (hook_end_instr) (hook_end_instr)(this);
if (next) next->end_instr();
}
void inst_trap( SS_Vaddr ea )
{
trap_mode = INST_TRAP;
trap_addr = ea;
if (next) next->inst_trap(ea);
}
void data_trap( SS_Vaddr ea )
{
trap_mode = DATA_TRAP;
trap_addr = ea;
if (next) next->data_trap(ea);
}
void cmp_state( SS_Registers::Index i, uint64_t v )
{
if (state[i] != v)
{
reg_value(i,v);
state[i] = v;
}
if (next) next->cmp_state(i,v);
}
TrapMode get_trap_mode() { return trap_mode; }
// ToDo: This state vector should really not be here.
uint64_t state[SS_Registers::INDEX_END - SS_Registers::INDEX_BEGIN];
protected:
TrapMode trap_mode;
SS_Vaddr trap_addr;
};
#endif