Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / legion / src / procs / sunsparc / include / ss_common.h
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: ss_common.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 ============================================
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SS_COMMON_H
#define _SS_COMMON_H
#pragma ident "@(#)ss_common.h 1.54 07/03/07 SMI"
#ifdef __cplusplus
extern "C" {
#endif
#include "basics.h"
#include "fatal.h"
#include "allocate.h"
#include "simcore.h"
#include "config.h"
#include "options.h"
#include "strutil.h"
#include "fileutil.h"
#include "lexer.h"
#include "parser.h"
#include "strings.h"
#include "strutil.h"
#include "createthr.h"
#include "tsparcv9.h"
#include "sparcv9regs.h"
#include "tsparcv9internal.h"
#include "execinstns.h" /* autogenerated core defined instructions */
#include "sparcv9decode.h"
#include "sparcv9instns.h" /* autogenerated sparcv9 instruction definitions */
#include "xicache.h"
#include "xdcache.h"
#include "dumpinfo.h"
#include "device.h"
#include "callback.h"
#include "bswap.h"
#if 1 /* { */
#define RW_lock_t volatile int64_t
#define RW_rdlock(_l) ss_rdlock(_l)
#define RW_wrlock(_l) ss_wrlock(_l)
#define RW_unlock(_l) ss_unlock(_l)
#define RW_lock_init(_l, _a) do { *(_l) = 0; } while (0)
extern void ss_rdlock(RW_lock_t *);
extern void ss_wrlock(RW_lock_t *);
extern void ss_unlock(RW_lock_t *);
#elif HAS_POSIX_RW_LOCK /* } { */
#define RW_lock_t pthread_rwlock_t
#define RW_rdlock(_l) pthread_rwlock_rdlock(_l)
#define RW_wrlock(_l) pthread_rwlock_wrlock(_l)
#define RW_unlock(_l) pthread_rwlock_unlock(_l)
#define RW_lock_init(_l, _a) pthread_rwlock_init(_l, _a)
#else /* } { */
#define RW_lock_t pthread_mutex_t
#define RW_rdlock(_l) pthread_mutex_lock(_l)
#define RW_wrlock(_l) pthread_mutex_lock(_l)
#define RW_unlock(_l) pthread_mutex_unlock(_l)
#define RW_lock_init(_l, _a) pthread_mutex_init(_l, _a)
#endif /* } */
/*
* SunSPARC / this file specific definitions
*/
#ifndef NDEBUG /* { */
#define DBG_CMP 0x100000000000LL
#define DBGCMP(_s) do { if (debug_bits & DBG_CMP) { _s; } } while (0)
#define DBG_TM 0x80000000000LL
#define DBGTM(_s) do { if (debug_bits & DBG_TM) { _s; } } while (0)
#define DBG_SCRATCH 0x10000000000LL
#define DBGSCRATCH(_s) do { if (debug_bits & DBG_SCRATCH) { _s; } } while (0)
#define DBG_DAE 0x8000000000LL
#define DBGDAE(_s) do { if (debug_bits & DBG_DAE) { _s; } } while (0)
#define DBG_LE 0x2000000LL
#define DBGLE(_s) do { if (debug_bits & DBG_LE) { _s } } while (0) /* debug little endian */
#define DBG_ALIGN 0x4000000LL
#define DBGALIGN(_s) do { if (debug_bits & DBG_ALIGN) { _s } } while (0)
#define DBG_EPM 0x80LL
#define DBGEPM(_s) do { if (debug_bits & DBG_EPM) { _s } } while (0)
#define DBG_HCALL 0x8000LL
#define DBGHC(s) do { if (debug_bits & DBG_HCALL) { s } } while (0) /* debug hcalls */
#define DBG_PIC 0x10000LL
#define DBGPIC(s) do { if (debug_bits & DBG_PIC) { s } } while (0) /* debug Perf Cntrs */
#define DBG_SOFTINT 0x10000000LL
#define DBGSOFTINT(s) do { if (debug_bits & DBG_SOFTINT) { s } } while (0)
#define DBG_TICK 0x20000000LL
#define DBGTICK(s) do { if (debug_bits & DBG_TICK) { s } } while (0)
#define DBG_TICK_READ 0x4000000000LL
#define DBGTICKREAD(s) do { if (debug_bits & DBG_TICK_READ) { s } } while (0)
#define DBG_EXCEPT 0x20000LL
#define DBGE(s) do { if (debug_bits & DBG_EXCEPT) { s } } while (0) /* debug exceptions */
#define DBG_HPSTATE 0x40000LL
#define DBGHPS(s) do { if (debug_bits & DBG_HPSTATE) { s } } while (0) /* debug hpstate changes */
#define DBG_MMU 0x80000LL
#define DBGMMU(s) do { if (debug_bits & DBG_MMU) { s } } while (0) /* debug mmu */
#define DBG_MISS 0x100000LL
#define DBGMISS(s) do { if (debug_bits & DBG_MISS) { s } } while (0) /* debug mmu miss */
#define DBG_MC 0x200000LL
#define DBGMC(s) do { if (debug_bits & DBG_MC) { s } } while (0) /* debug dram controllers */
#define DBG_TS 0x400000LL
#define DBGTSTACK(s) do { if (debug_bits & DBG_TS) { s } } while (0) /* debug TSTATE etc. */
#define DBG_ERR 0x800000LL
#define DBGERR(s) do { if (debug_bits & DBG_ERR) { s } } while (0) /* debug error injection */
#define DBG_SSI 0x1000000LL
#define DBGSSI(s) do { if (debug_bits & DBG_SSI) { s } } while (0) /* debug SSI interrupts */
#define DBG_MONDO 0x8000000LL
#define DBGMONDO(s) do { if (debug_bits & DBG_MONDO) { s } } while (0) /* debug mondo interrupts */
#define DBG_ERR_TRAP 0x200000000LL
#define DBGERRTRAP(s) do { if (debug_bits & DBG_ERR_TRAP) { s } } while (0) /* debug error trap generation */
#define DBG_MUL_NODE 0x4000LL
#define DBGMULNODE(s) do { if (debug_bits & DBG_MUL_NODE) { s } } while (0) /* debug multinode, only VF for now */
/*
* debug_bits values already reserved:
*
* 0x1 DBG_BASIC
* 0x2 DBG_EL
* 0x4 DBG_EL_MIN
* 0x8 < not reserved >
* ...
* 0x40 < not reserved >
* 0x80 DBG_EPM
* 0x100 < not reserved >
* ...
* 0x2000 < not reserved >
* 0x4000 DBG_MUL_NODE
* 0x8000 DBG_HCALL
* 0x10000 DBG_PIC
* 0x20000 DBG_EXCEPT
* 0x40000 DBG_HPSTATE
* 0x80000 DBG_MMU
* 0x100000 DBG_MISS
* 0x200000 DBG_MC
* 0x400000 DBG_TS
* 0x800000 DBG_ERR
* 0x1000000 DBG_SSI
* 0x2000000 DBG_LE
* 0x4000000 DBG_ALIGN
* 0x8000000 DBG_MONDO
* 0x10000000 DBG_SOFTINT
* 0x20000000 DBG_TICK
* 0x40000000 DBG_DECODE
* 0x80000000 DBG_DEV
* 0x100000000 DBG_EXEC_LOOP
* 0x200000000 DBG_ERR_TRAP
* 0x1000000000 DBG_FSR
* 0x2000000000 DBG_FPRS
* 0x4000000000 DBG_TICK_READ
* 0x8000000000 DBG_DAE
* 0x10000000000 DBG_SCRATCH
* 0x20000000000 DBG_XCACHE
* 0x40000000000 DBG_FP
* 0x80000000000 DBG_TM
* 0x100000000000 DBG_CMP
*/
#else /* } { */
#define DBGCMP(_s) do { } while (0)
#define DBGTM(_s) do { } while (0)
#define DBGSCRATCH(_s) do { } while (0)
#define DBGDAE(_s) do { } while (0)
#define DBGLE(_s) do { } while (0) /* debug little endian */
#define DBGPIC(s) do { } while (0) /* debug Perf Cntrs */
#define DBGSOFTINT(s) do { } while (0)
#define DBGTICK(s) do { } while (0)
#define DBGTICKREAD(s) do { } while (0)
#define DBGEPM(_s) do { } while (0)
#define DBGALIGN(_s) do { } while (0)
#define DBGHC(s) do { } while (0) /* debug exceptions */
#define DBGE(s) do { } while (0) /* debug exceptions */
#define DBGHPS(s) do { } while (0) /* debug exceptions */
#define DBGMMU(s) do { } while (0) /* debug exceptions */
#define DBGMISS(s) do { } while (0) /* debug exceptions */
#define DBGMC(s) do { } while (0) /* debug dram controllers */
#define DBGERR(s) do { } while (0) /* debug error injection */
#define DBGTSTACK(s) do { } while (0) /* debug TSTATE etc. */
#define DBGSSI(s) do { } while (0) /* debug SSI interrupts */
#define DBGMONDO(s) do { } while (0) /* debug mondo interrupts */
#define DBGERRTRAP(s) do { } while (0) /* debug error trap generation */
#define DBGMULNODE(s) do { } while (0) /* debug multinode, only VF for now */
#endif /* } */
typedef enum {
TFlag_Not_Poss, TFlag_Priv, TFlag_HypPriv
} tflag_t;
#define T( _name ) SS_trap_##_name, #_name /* SunSPARC standard trap naming convention */
#define TN1( _name ) N1_trap_##_name, #_name /* Niagara1 specific trap naming convention */
#define TN2( _name ) N2_trap_##_name, #_name /* Niagara2 standard trap naming convention */
#define TRK( _name ) RK_trap_##_name, #_name /* Rock standard trap naming convention */
#define X TFlag_Not_Poss /* Cant be generated by HW - SW emulated only */
#define SW TFlag_Not_Poss /* Cant be generated by HW - SW emulated only */
#define P TFlag_Priv
#define H TFlag_HypPriv
#define UH TFlag_HypPriv /* legal, but unexpected by hypervisor (supervisor error) */
#define Pri(_maj, _min) (((_maj)<<16)|(_min))
#define E( _name ) _name, #_name /* Error naming convention */
#define B( _name, _i ) #_name, ((uint64_t)1 << _i) /* Error field name, bit position in CERER */
/*
* macros used for determing the fields of sun4v TTE format
*/
#define SUN4V_TTED_V_BIT 63
#define SUN4V_TTED_V(n) (uint_t)((uint64_t)n >> SUN4V_TTED_V_BIT)
#define SUN4V_TTED_NFO(n) (uint_t)(((uint64_t)n >> 62) & 0x1)
#define SUN4V_TTED_IE(n) (uint_t)(((uint64_t)n >> 12) & 0x1)
#define SUN4V_TTED_E(n) (uint_t)(((uint64_t)n >> 11) & 0x1)
#define SUN4V_TTED_CP(n) (uint_t)(((uint64_t)n >> 10) & 0x1)
#define SUN4V_TTED_CV(n) (uint_t)(((uint64_t)n >> 9) & 0x1)
#define SUN4V_TTED_P(n) (uint_t)(((uint64_t)n >> 8) & 0x1)
#define SUN4V_TTED_EP(n) (uint_t)(((uint64_t)n >> 7) & 0x1)
#define SUN4V_TTED_X(n) SUN4V_TTED_EP(n)
#define SUN4V_TTED_W(n) (uint_t)(((uint64_t)n >> 6) & 0x1)
#define SUN4V_TTED_PS(n) (uint_t)((uint64_t)n & MASK64(3, 0))
#define SUN4V_TTET_VA(n) ((uint64_t)n & MASK64(41, 0))
#define SUN4V_TTE_ENTRY_SIZE 16
/* Use global array for this calculation */
extern uint8_t ss_page_size_shift[];
#define SUN4V_PAGE_SIZE_SHIFT(ps) ((uint_t)(ss_page_size_shift[(ps)]))
/*
* SunSPARC CPU core structures and typedefs
*/
/*
* Common set of strand core identification fields for use in SS_STRAND
* structures:
* core: core number
* vthread: thread number within the core
* vcore_id: the thread number within the chip
*/
#define SS_CORE_NUM_FIELDS \
uint_t core; \
uint_t vthread; \
uint64_t vcore_id;
/* SSR => Strand Specific Registers */
typedef enum {
SSR_ScratchPad0 = 0,
SSR_ScratchPad1,
SSR_ScratchPad2,
SSR_ScratchPad3,
SSR_ScratchPad4, /* hypervisor only (Niagara) */
SSR_ScratchPad5, /* hypervisor only (Niagara) */
SSR_ScratchPad6,
SSR_ScratchPad7,
#ifdef ROCK
/* Hypervisor Scratchpad Registers (0x00 to 0x18) */
SSR_ScratchPad8,
SSR_ScratchPad9,
SSR_ScratchPad10,
SSR_ScratchPad11,
#endif
SSR_Num_Regs
} ss_strand_regs_t;
typedef struct SS_TLB ss_tlb_t;
typedef struct NA_QUEUE {
uint16_t head, tail;
} na_queue_t;
typedef struct SS_MMU ss_mmu_t;
typedef struct SS_ERROR ss_error_t;
/* Numbers for the SunSPARC strand interrupt queues */
typedef enum {
NA_Q_mondo = 0,
NA_Q_device = 1,
NA_Q_resumable = 2,
NA_Q_unresumable = 3
} na_qnum_t;
typedef struct SS_L1_CACHE {
RW_lock_t rwlock;
uint64_t * tagp;
uint64_t * datap;
uint64_t bist_ctl; /* asi 0x42 va 0x00 ASI_SPARC_BIST_CTL_REG */
uint64_t inst_mask; /* asi 0x42 va 0x08 ASI_INST_MASK_REG */
bool_t assocdis; /* asi 0x42 va 0x10 ASI_LSU_DIAG_REG */
} ss_l1_cache_t;
#define BIT(i) ((uint64_t)1<<i)
#define BIT_TEST(_val, _bit) (((_val)>>(_bit)) & 0x1)
/*
* Context Type Encoding defined by SunSPARC
*
* N.B. These values are used as defined in the Rock DFSR
* so they cannot be changed to arbitrary values other than
* the ones listed below.
*/
typedef enum {
ss_ctx_primary = 0,
ss_ctx_secondary = 1,
ss_ctx_nucleus = 2,
ss_ctx_reserved = 3
} ss_ctx_t;
#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
/* Sparc Error Address Register Fields */
#define I_SYND(val) ((val & 0xff) << 16)
#define I_REG_WIN(val) ((val & 0x3) << 9)
#define I_REG_NUM(val) ((val & 0x1f) << 4)
#define F_REG_NUM(val) ((val & 0x3f) << 4)
#define EVEN_SYND(val) ((val & 0x7f) << 24)
#define ODD_SYND(val) ((val & 0x7f) << 16)
#define TLB_INDEX(val) ((val & 0x3f) << 4)
#define MMU_PC(val) (val & 0xfffffffffff0) /* PC:47-4 Rsvd:3-0 */
#define MMU_VA(val) (val & 0xfffffffffff0) /* VA:47-4 Rsvd:3-0 */
#define L1_PA(val) (val & 0xfffffffff0) /* PA:39-4 Rsvd:3-0 */
/* ECC Codes section in Appendix A of PRM 1.2 */
#define IREG_FAKE_SYND_SINGLE 0x83 /* single bit error on data bit 0 */
#define IREG_FAKE_SYND_DOUBLE 0x73 /* uncorrectable double bit error */
#define FREG_FAKE_SYND_SINGLE 0x43 /* single bit error on bit 0 */
#define FREG_FAKE_SYND_DOUBLE 0x33 /* uncorrectible double bit error */
/*
* Bitfield definitions for the LSU_CONTROL register
*/
#if defined(NIAGARA1) /* { */
#define LSU_CTRL_WATCH_VM MASK64(32,25)
#define LSU_CTRL_WATCH_VR MASK64(22,22)
#define LSU_CTRL_WATCH_VW MASK64(21,21)
#endif /* } */
#if defined(NIAGARA2) /* { */
#define LSU_CTRL_WATCH_MODE MASK64(34,33)
#define LSU_CTRL_WATCH_BM MASK64(32,25)
#define LSU_CTRL_WATCH_RE MASK64(24,24)
#define LSU_CTRL_WATCH_WE MASK64(23,23)
#define LSU_CTRL_SPEC_EN MASK64(4,4)
#endif /* } */
#define LSU_CTRL_DMMU_EN MASK64(3,3)
#define LSU_CTRL_IMMU_EN MASK64(2,2)
#define LSU_CTRL_DC_EN MASK64(1,1)
#define LSU_CTRL_IC_EN MASK64(0,0)
#if defined(NIAGARA1) /* { */
#define LSU_CTRL_REG_MASK (LSU_CTRL_WATCH_VM | LSU_CTRL_WATCH_VR | \
LSU_CTRL_WATCH_VW | LSU_CTRL_DMMU_EN | \
LSU_CTRL_IMMU_EN | LSU_CTRL_DC_EN | \
LSU_CTRL_IC_EN)
#endif /* } */
#if defined(NIAGARA2) /* { */
#define LSU_CTRL_REG_MASK (LSU_CTRL_WATCH_MODE | LSU_CTRL_WATCH_BM | \
LSU_CTRL_WATCH_RE | LSU_CTRL_WATCH_WE | \
LSU_CTRL_SPEC_EN | LSU_CTRL_DMMU_EN | \
LSU_CTRL_IMMU_EN | LSU_CTRL_DC_EN | \
LSU_CTRL_IC_EN)
#endif /* } */
#define LSU_CTRL_INITVAL (0LL)
#endif /* } */
/*
* Functions and definitions for TLB and MMU code
*/
/* FIXME:
* This macro is a place holder for the correct register setup
* that is required in order to be able to deliver a particular
* fault resulting from a memory reference.
*/
#define MEMORY_ACCESS_TRAP() do { } while (0)
/*
* SunSPARC CPU TLB structures
*/
/*
* Each hash table is divided into buckets, based on pfn, context and partid
* The chains attached to a bucket are designed to have multiple readers and
* only a single writer/modifier at any one time.
*
* FIXME: However, operations like entry probling and invalidate all etc. don't
* use the hash ...
* ... I'm going to assume that TLB contention between strands is sufficiently
* low that we can get away with a single rw lock for the entire TLB.
* This should be enough to get something working - we'll fix the performance
* later when we get a chance to profile the running code ....
*
* Naturally, if we don't share TLBs between strand threads then there is no
* need for any locks.
*
* Otherwise we have to implement a fair multiple-reader, single writer locking
* scheme, that is hopefully fast - ish.
*
* FIXME: we use Solaris' reader/writer locks to get this working, but I suspect
* they are tediously slow - quick measurement indicates they take around 400 instructions
* to take and release an uncontested lock !! Need to profile this code and see if this is
* a performance bottleneck. But for now this is sufficient to get this working.
*
* NOTE: if this is very low contention, we should probably simply move to a mutex
* per bucket, since the performance of Solaris' mutexes is about twice that of the rwlock.
* Increasing the number of buckets and better hashing alg would also reduce contention.
*
*/
#ifdef ROCK /* { */
typedef uint32_t matchcontext_t;
#else /* } { */
typedef uint16_t matchcontext_t;
#endif /* } */
#define INVALID_PFN -1LL
#define SS_TLB_REAL_CONTEXT ((matchcontext_t)-1)
#define SS_TLB_INVALID_CONTEXT ((matchcontext_t)-2)
#define SS_TLB_INVALID_PARTID ((uint16_t)-1)
#define SS_NUCLEUS_CONTEXT 0
typedef struct TLB_ENTRY tlb_entry_t;
typedef enum {
SS_TLB_FLAG_READ = 0x001, /* niagara doesn't have read bit */
SS_TLB_FLAG_WRITE = 0x002, /* writeable */
SS_TLB_FLAG_EXEC = 0x004, /* executable */
SS_TLB_FLAG_PRIV = 0x008, /* privileged */
SS_TLB_FLAG_CP = 0x010, /* cachable in physically-indexed cache */
SS_TLB_FLAG_E = 0x020, /* side-effect */
SS_TLB_FLAG_NFO = 0x040, /* no-fault-only */
SS_TLB_FLAG_IE = 0x080, /* Invert Endian */
SS_TLB_FLAG_V = 0x100, /* valid */
SS_TLB_FLAG_LOCKED = 0x200 /* locked */
} tlb_flags_t;
struct TLB_ENTRY {
uint64_t tag_pfn;
uint64_t pa_offset; /* (i.e. pa-va) */
uint64_t data; /* as returned by the data register read */
uint8_t match_shift;
bool_t is_real; /* true for RA to PA, false for VA to PA translation */
tlb_flags_t flags;
uint16_t tag_context; /* context value in TLB entry tag field */
matchcontext_t match_context; /* context used when matching entries; 0..12 bits */
/* -1 if this is a real translation not a virtual one */
/* -2 if this is not a valid translation */
uint16_t partid;
sint16_t hashidx; /* used to help find the entry in the hash for unhooking */
/* == -1 if the entry is on the free list */
tlb_entry_t * nextp;
};
/*
* Niagara max page size is 256MB .. this value is used for
* the TLB hashing index value
*/
#define SS_MAX_PAGE_SIZE_BITS 28
#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
/*
* Niagara VA hole
*/
#define SS_VA_HOLE_LB 0x0000800000000000
#define SS_VA_HOLE_UB 0xffff7fffffffffff
/* Extend 48 bit VA to 64 bits */
#define VA48(_va) (((int64_t)(_va) << 16) >> 16)
#define VA48_WARNING(_sp, _va) do {\
if ((_va) != VA48(_va))\
EXEC_WARNING(("@pc=0x%llx not a 48-bit VA 0x%llx",\
sp->pc, (_va)));\
} while (0)
#define VA48_ASSERT(_va) ASSERT((_va) == VA48(_va))
#endif /* } */
typedef struct {
tlb_entry_t * ptr;
} tlb_hash_bucket_t;
/*
* TLB organisation is independent of the
* search hash - and is merely determined by the
* behaviour of the insert / demap functions.
*/
#if defined(NIAGARA1) || defined(NIAGARA2) /* { */
#define SS_TLB_HASH_ENTRIES 32 /* modest number */
#endif /* } */
#ifdef ROCK /* { */
#define SS_TLB_HASH_ENTRIES 256 /* less modest number */
#endif /* } */
#define SS_TLB_HASH_MASK (SS_TLB_HASH_ENTRIES-1)
/* define replacement policy when all entries are valid: */
#define SS_TLB_REPLACE_RROBIN 1
/* #define SS_TLB_REPLACE_RANDOM 1 */
struct SS_TLB {
uint_t nentries;
RW_lock_t rwlock;
tlb_entry_t * freep;
tlb_hash_bucket_t hash[SS_TLB_HASH_ENTRIES];
tlb_entry_t * tlb_entryp;
bool_t parity;
uint_t shares;
#if SS_TLB_REPLACE_RROBIN /* { */
uint_t last_replaced;
#endif /* } */
#ifdef ROCK /* { */
uint8_t *lru_array;
#endif /* } */
};
typedef struct SS_TLB_SPEC {
uint_t nentries;
bool_t parity;
} ss_tlb_spec_t;
typedef struct ERROR_PROC {
tvaddr_t ldac_addr;
tvaddr_t ldau_addr;
tvaddr_t dac_addr;
tvaddr_t dau_addr;
} error_proc_t;
/*
* SunSPARC CPU specific info about how a debugger instance is
* attached ... handled as a hidden data type from the debugger,
* but provides this module info on which strand etc. the debugger
* is actually attached to.
*/
typedef struct {
domain_t * domainp;
config_proc_t * config_procp;
uint_t core;
uint_t strand;
sparcv9_cpu_t* strandp;
} ss_dbgr_t;
typedef enum SS_DEMAP ss_demap_t;
typedef enum {
NA_mem_read, NA_mem_write, NA_mem_clear
} dbgr_mem_op_t;
/*
* All memory ASIs bit3=1 if the ASI is Little Endian
*/
#define SS_ASI_LE_MASK (1 << 3)
typedef enum {
MF_Normal = 0x01, /* if normal access, else alternate address space being used */
MF_MMU_Bypass = 0x02, /* if this ld/st should bypass MMU translation */
MF_Has_Priv = 0x04, /* if access is from priv or hpriv mode */
MF_No_Fault = 0x08, /* No faulting load specified */
MF_IO_Access = 0x10, /* Not a cacheable access - e.g. REAL_IO */
MF_Blk_Init = 0x20, /* Block Initialize effect */
MF_Atomic_Access = 0x40, /* Atomic instruction access (including 128-bit atomic load) */
MF_TLB_Real_Ctx = 0x80, /* Search TLB RA->PA mapping (due to ASI_*_real_* access) */
MF_Little_Endian = 0x100
} mem_flags_t;
#if ERROR_INJECTION
typedef enum {
IFETCH = 0x01,
LD = 0x02,
ASI_LD = 0x04,
ST = 0x08,
ANY_OP = 0xff
} error_op_t;
typedef uint64_t error_type_t;
#define ss_set_errcheck(npp) do { \
npp->error_check = npp->errorp->ldac_addr | \
npp->errorp->ldau_addr | npp->errorp->dac_addr | \
npp->errorp->dau_addr; \
} while (0)
#endif /* ERROR_INJECTION */
/* The processor specific structure. */
typedef struct SS_PROC ss_proc_t;
/*
* functions defined outside the CPU loadable modules
*/
extern void host_atomic_get128be(uint64_t *, uint64_t *, uint64_t *);
/*
* extern definitions used by more than one libsunsparc source file
*/
extern void ss_parse(domain_t*, config_proc_t*);
extern void ss_parse_tlb(ss_tlb_spec_t *);
extern void ss_init(domain_t*, config_proc_t*);
extern void ss_dump(domain_t*, config_proc_t*);
extern bool_t ss_dbgr_regread(void*, uint_t, uint64_t*);
extern bool_t ss_dbgr_regwrite(void*, uint_t, uint64_t);
extern void ss_exec_setup(simcpu_t*);
extern void ss_exec_cleanup(simcpu_t*);
extern bool_t ss_save_state(simcpu_t*);
extern void ss_check_async_event(simcpu_t*);
extern void ss_take_exception(simcpu_t*);
extern void ss_dump_tlbs(config_proc_t*, bool_t);
extern void ss_dump_tlbs_nolock(config_proc_t*, bool_t);
extern void ss_dump_instruction_counts(config_proc_t*);
extern uint64_t ss_ext_signal(config_proc_t*, ext_sig_t, void*);
extern bool_t ss_dev_mem_access(config_proc_t *config_procp, tpaddr_t addr,
uint8_t *datap, uint64_t size, dev_access_t type);
extern void * ss_dbgr_attach(domain_t*, config_proc_t*, char*);
extern void ss_dbgr_detach(void*);
extern uint64_t ss_dbgr_mem_read(void*, tvaddr_t, bool_t, uint8_t*, uint64_t);
extern uint64_t ss_dbgr_mem_write(void*, tvaddr_t, bool_t, uint8_t*, uint64_t);
extern uint64_t ss_dbgr_mem_clear(void*, tvaddr_t, bool_t, uint64_t);
extern void ss_dbgr_set_break(void*, tvaddr_t);
extern void ss_dbgr_clear_break(void*, tvaddr_t);
extern void ss_tlb_unhash(ss_tlb_t*, tlb_entry_t*);
extern void ss_tlb_unfree(ss_tlb_t*, tlb_entry_t*);
extern void ss_free_tlb_entry(ss_tlb_t*, tlb_entry_t*);
extern void ss_tlb_scrub(simcpu_t *, ss_tlb_t*, bool_t);
extern void ss_xic_miss(simcpu_t*, xicache_line_t*, tvaddr_t);
extern bool_t ss_tm_chkpt(simcpu_t *, tvaddr_t);
extern void ss_tm_commit(simcpu_t *);
extern void ss_tm_fail(simcpu_t *, uint64_t);
extern uint64_t ss_read_pstate(sparcv9_cpu_t *);
#if ERROR_INJECTION
extern error_conf_t * new_errconf(error_op_t, error_type_t);
extern error_conf_t * find_errconf(simcpu_t*, error_op_t, error_type_t);
extern bool_t remove_errconf(simcpu_t * sp, error_conf_t * rmep);
extern void dump_errconf(error_conf_t*);
extern void extract_error_type(error_conf_t * errorconfp);
extern void update_errflags(simcpu_t * sp);
extern void clear_errflags(simcpu_t * sp);
extern void ss_error_condition(simcpu_t*, error_conf_t*);
extern void tlb_entry_error_match(simcpu_t*, ss_mmu_t*, tlb_entry_t*);
#endif /* ERROR_INJECTION */
#if !defined(NDEBUG) /* { */
extern void ss_tlb_contents(FILE*, ss_tlb_t*, bool_t);
#endif /* } */
extern uint64_t ss_cpu_mem(domain_t *, void*, sparcv9_cpu_t*, dbgr_mem_op_t, tvaddr_t, bool_t, uint8_t*, uint_t);
extern void ss_asi_access( simcpu_t*, maccess_t, uint_t, uint_t, uint64_t, uint64_t, asi_flag_t);
extern bool_t ss_demap(simcpu_t*, ss_demap_t, ss_mmu_t*, ss_tlb_t*, uint_t, bool_t, uint_t, tvaddr_t);
extern void ss_tlb_flush_shares(simcpu_t *, ss_tlb_t *, bool_t);
extern uint64_t ss_read_tick(simcpu_t*);
extern void ss_write_tick(simcpu_t*, uint64_t);
extern uint64_t ss_read_stick(simcpu_t*);
extern void ss_write_stick(simcpu_t*, uint64_t);
extern void ss_recomp_tick_target(simcpu_t*);
extern uint64_t ss_tick_cmpr_read(simcpu_t *, tick_compare_t *);
extern void ss_tick_cmpr_write(simcpu_t *, tick_compare_t *, uint64_t);
extern void ss_recomp_cycle_target(simcpu_t*);
extern void ss_memory_asi_access(simcpu_t*, maccess_t, uint64_t*, mem_flags_t, uint_t, uint_t, uint_t, tvaddr_t, tvaddr_t);
extern void ss_check_interrupts(simcpu_t*);
extern uint8_t host_ldstub(uint8_t *, uint8_t, uint8_t);
extern uint32_t host_cas32(uint32_t *, uint32_t, uint32_t);
extern uint64_t host_cas64(uint64_t *, uint64_t, uint64_t);
extern uint32_t host_swap(uint32_t *, uint32_t);
extern void v9_set_fsr_lower(simcpu_t*, uint64_t);
extern void v9_set_fsr(simcpu_t*, uint64_t);
extern void v9_set_fsr_fp_op(simcpu_t*, uint64_t);
extern uint64_t v9_get_fsr(simcpu_t*);
extern void ss_change_exec_state(ss_proc_t *npp, uint64_t running_status);
extern uint64_t xor_bits(uint64_t);
uint_t ss_get_cpuid(simcpu_t *sp);
void ss_trash_regs(sparcv9_cpu_t * v9p, uint64_t val);
/*
* CPU version macros
*/
#define SS_VER_MANUF_OFFSET 48 /* bits 63:48 */
#define SS_VER_IMPL_OFFSET 32 /* bits 47:32 */
#define SS_VER_MASK_OFFSET 24 /* bits 31:24 */
#define SS_VER_MAXGL_OFFSET 16 /* bits 18:16 */
#define SS_VER_MAXTL_OFFSET 8 /* bits 15:8:0 */
#define SS_VER_NWINS_OFFSET 0 /* bits 4:0 */
#define SS_MAKE_VER_UPPER40(manuf, impl, mask) \
((manuf<<SS_VER_MANUF_OFFSET)| \
(impl<<SS_VER_IMPL_OFFSET)| \
(mask<<SS_VER_MASK_OFFSET))
#define SS_MAKE_VER_LOWER24(ngl, maxtl, nwins) \
(((ngl-1)<<SS_VER_MAXGL_OFFSET)| \
(maxtl<<SS_VER_MAXTL_OFFSET)| \
((nwins-1)<<SS_VER_NWINS_OFFSET))
#define RSVD_MASK(_sp, mask, val, asi, addr) \
do { \
if ((val) & ~(mask)) { \
EXEC_WARNING(("pc=0x%llx : stxa 0x%llx, [0x%x]0x%x: " \
"Attempted store to rsvd fields being masked out", \
(_sp)->pc, (val), (addr), (asi))); \
(val) &= (mask); \
} \
} while (0)
/*
* Identical to above RSVD_MASK macro, but safe for use when _sp pointer may be NULL.
* Should be kept in sync with the above macro for any changes.
*/
#define ROCK_RSVD_MASK(_sp, mask, val, asi, addr) \
do { \
if ((val) & ~(mask)) { \
if ((_sp) != NULL) { \
EXEC_WARNING(("pc=0x%llx : stxa 0x%llx, [0x%x]0x%x: " \
"Attempted store to rsvd fields being masked out", \
(_sp)->pc, (val), (addr), (asi))); \
} else { \
EXEC_WARNING(("System controller access : stxa 0x%llx, [0x%x]0x%x: " \
"Attempted store to rsvd fields being masked out", \
(val), (addr), (asi))); \
} \
(val) &= (mask); \
} \
} while (0)
#ifdef __cplusplus
}
#endif
#endif /* _SS_COMMON_H */