#ifndef _fastsim_h
#define _fastsim_h
/******************************************************************************
** FILE: fastsim.h -- Part of the FastSim simulation system.
** Interface to the fastsim runtime system.
*/
#include <sys/types.h>
#include <libelf.h>
#include <math.h>
#include <assert.h>
void xmain(); /* Main function defined in Facile */
/******************************************************************************
* Value of simulator command line options.
*/
extern int verbose;
extern int debug_level;
extern char* execfile;
extern char* logfile;
/******************************************************************************
* External functions called by FastSim that can be overridden.
* Default versions of these functions are provided in libfs.a.
*/
void xexit(); /* called on simulator exit */
void xno_instruction(); /* may be called by Facile ?exec attribute */
void xno_default(); /* may be called by Facile switch statements */
/******************************************************************************
* External functions called by FastSim that cannot be overridden.
*/
/* Interface to detect SIGSEGV and SIGBUS signals */
extern void* xmem_test_address; /* address to test */
extern unsigned char xmem_test_flag; /* set to true surrounding test */
extern unsigned char xmem_test_failed; /* result of test; true if failed */
unsigned char xmem_load8_test(void *va);
unsigned short xmem_load16_test(void *va);
unsigned long xmem_load32_test(void *va);
unsigned long long xmem_load64_test(void *va);
/* There should probably be some corresponding store tests */
/* write message to a log file */
void xlog(int lvl, const char*, ...);
/* dump simulator statistics to the logfile */
extern size_t nstat;
void xstats();
/******************************************************************************
* Other definitions used in the Facile/C interface.
*/
#define TARGET_VADDR_MASK 0x80000000 /* Or'ed with all target addresses to
generate translated target addr */
/* Types used by generated simulators */
typedef char* string_t;
typedef unsigned char cc_t;
typedef unsigned long token_stream_t;
typedef struct queue {
unsigned char size; /* max # of elements in allocated array */
unsigned char length; /* # of elemets in use (ie, queue length) */
unsigned char begin; /* index of first element in the queue */
unsigned char end; /* just past the last element in the queue */
void *data; /* dynamically allocated array */
} queue_t;
/* Allocate a new queue data array to fix queue after assignment */
void queue_realloc(queue_t*, unsigned long width);
/* Reallocate a queue data array when more space is needed */
void queue_grow(queue_t*, unsigned long width);
/* Global variables defined by the simulation framework */
extern Elf *elf;
extern caddr_t break_value;
/* Interface functions to query & manipulate simulation data */
token_stream_t start_pc();
unsigned long start_sp();
static inline token_stream_t token_stream(unsigned long addr) { return addr; }
static inline unsigned char stream_lt(token_stream_t s1, token_stream_t s2)
{ return s1 < s2; }
static inline unsigned char stream_le(token_stream_t s1, token_stream_t s2)
{ return s1 <= s2; }
static inline unsigned char stream_eq(token_stream_t s1, token_stream_t s2)
{ return s1 == s2; }
static inline unsigned char stream_ne(token_stream_t s1, token_stream_t s2)
{ return s1 != s2; }
static inline unsigned char stream_ge(token_stream_t s1, token_stream_t s2)
{ return s1 >= s2; }
static inline unsigned char stream_gt(token_stream_t s1, token_stream_t s2)
{ return s1 > s2; }
static inline token_stream_t stream_add(token_stream_t stream,
unsigned long delta)
{ return stream + delta; }
static inline token_stream_t stream_sub(token_stream_t stream,
unsigned long delta)
{ return stream - delta; }
unsigned long stream_bits32(token_stream_t,
unsigned long offset, unsigned long width,
unsigned long lo, unsigned long hi);
unsigned long long stream_bits64(token_stream_t,
unsigned long offset, unsigned long width,
unsigned long lo, unsigned long hi);
unsigned long sign_extend32(unsigned long src, unsigned long width);
unsigned long long sign_extend64(unsigned long long src, unsigned long width);
union Cast32 {
float f;
signed long s;
unsigned long u;
};
extern union Cast32 cast32;
union Cast64 {
double f;
signed long long s;
unsigned long long u;
};
extern union Cast64 cast64;
/* floating point sqrt */
float fsqrt32(float);
double fsqrt64(double);
/* operators on signed/unsigned long values that set condition codes */
ulong_t uadd32_cc(cc_t*, ulong_t, ulong_t);
long sadd32_cc(cc_t*, long, long);
ulong_t usub32_cc(cc_t*, ulong_t, ulong_t);
long ssub32_cc(cc_t*, long, long);
ulong_t uand32_cc(cc_t*, ulong_t, ulong_t);
ulong_t uor32_cc(cc_t*, ulong_t, ulong_t);
ulong_t uxor32_cc(cc_t*, ulong_t, ulong_t);
/* operators on signed/unsigned long long values that set condition codes */
u_longlong_t uadd64_cc(cc_t*, u_longlong_t, u_longlong_t);
longlong_t sadd64_cc(cc_t*, longlong_t, longlong_t);
u_longlong_t usub64_cc(cc_t*, u_longlong_t, u_longlong_t);
longlong_t ssub64_cc(cc_t*, longlong_t, longlong_t);
u_longlong_t uand64_cc(cc_t*, u_longlong_t, u_longlong_t);
u_longlong_t uor64_cc(cc_t*, u_longlong_t, u_longlong_t);
u_longlong_t uxor64_cc(cc_t*, u_longlong_t, u_longlong_t);
/* floating point operators that set condition codes */
float fsub32_cc(cc_t*, float, float);
double fsub64_cc(cc_t*, double, double);
extern void* dummybuf;
/******************************************************************************
* Types, variables, and functions to support fast-forwarding.
*
* The primary function is fast_forward(), which looks up the given RTS data
* in the memoization cache and tries to switch to the fast-forwarded version
* of the simulator. Upon return, the RTS data in the "init" variable will be
* set to the correct value for whatever point the simulation has reached and
* slow simulation can be (re)started.
*/
typedef struct {
size_t bytes;
long buf[0x100];
} pack_data_t;
typedef struct {
size_t bytes;
void* buf;
} packed_queue_t;
/* RTS data should be packed into pack_data before calling
* either fast_forward() or write_result(). */
extern pack_data_t pack_data;
/* make sure last word of pack_data.buf han no random data */
static inline size_t
fill_pack_data()
{
size_t words, align;
words = (pack_data.bytes+3) / 4;
assert(words < 0x100);
align = pack_data.bytes & 0x3;
if(align) pack_data.buf[words-1] &= 0xffffffff << (8*(4 - align));
return words*4;
}
/* Try to switch to fast-forwarded simulation */
void fast_forward();
/* Insure static versions of global vars have the same structure as their
* dynamic versions. Called at start of recovery from memoization miss. */
void ff_copy_to_stat();
/*
* The following structures are used to store
* control data in the memoization cache */
#define INDEX_ACTION 0
#define DLL32_ACTION 0x7fff
#define DLL64_ACTION 0x7ffe
#define RESULT1_ACTION -1
#define RESULT8_ACTION -2
#define RESULTN_ACTION -3
typedef struct Action {
ushort_t action; /* >=0 for actions; <0 for results */
ushort_t bytes; /* bytes to previous action or result */
} action_t;
typedef struct Result8 {
char action; /* -1 for 1 bit results; otherwise -2 */
uchar_t result; /* up to 8 bits of result data */
ushort_t bytes; /* bytes to previous action or result */
void *next;
} result_8_t;
typedef struct ResultN {
char action; /* should always be -3 */
uchar_t words; /* # of words of result data */
ushort_t bytes; /* bytes to previous action or result */
struct ResultN *next;
} result_N_t;
#define ACTION_BYTES(act) (((action_t*)(act))->bytes & 0xfffc)
#define ACTION_FLAGS(act) (((action_t*)(act))->bytes & 0x0003)
#define IS_RESULT(xx) (*((signed char*)(xx)) < 0)
/* Fast-forwarded version of main (generated by fs) */
void ff_main(action_t*);
/*
* Flags providing info about or control of the fast-forwarding process */
/* True if a fast-forwarding simulator was generated */
extern int ff_memoize;
/* True if transitioning back to slow-sim */
extern int ff_recover;
/*
* Functions called by automatically generated code */
/* Allocate unitialized bytes in the memoization cache */
void *ff_alloc(size_t);
/* Allocate and initialize a new action structure */
void ff_write_action(ushort_t);
/* Allocate and initialize a record to verify the RTS data in pack_data */
void ff_write_result_N();
/* Returns a pointer to packed data written by ff_write_result_N */
void *ff_recover_result_N();
/* Allocate and initialize a record to verify up to 8 bits of data */
uchar_t ff_write_result_8(uchar_t);
/* Allocate and initialize a record to verify 1 bit of data */
int ff_write_result_1(int);
/* Miss processing */
void ff_miss_result_N(result_N_t*,size_t);
void ff_miss_result_8(result_8_t*,uchar_t);
void ff_miss_result_1(result_8_t*,int);
/* Search the linked list of possible successors
* to find the given result identifier. */
static inline void*
ff_find_result_N(void *data)
{
result_N_t *rr, *rr0 = (result_N_t*)data;
size_t bytes = fill_pack_data();
size_t words = bytes / 4;
#ifdef STATS
extern u_longlong_t count_resultN_fast;
++count_resultN_fast;
#endif
for(rr=rr0; rr; rr=(result_N_t*)rr->next) {
long* data = (long*)(rr+1);
assert(rr->action == RESULTN_ACTION);
if(rr->words == words && !memcmp(data,pack_data.buf,bytes))
return data + words;
}
ff_miss_result_N(rr0,bytes); /* longjmp return */
assert(!"Should not be here!");
return NULL;
}
/* Search the linked list of possible successors
* to find the given result identifier. */
static inline void*
ff_find_result_8(void *data, uchar_t result)
{
result_8_t *rr, *rr0 = (result_8_t*)data;
#ifdef STATS
extern u_longlong_t count_result8_fast;
++count_result8_fast;
#endif
for(rr=rr0; rr; rr=(result_8_t*)rr->next) {
assert(rr->action == RESULT8_ACTION);
if(rr->result == result) return rr+1;
}
ff_miss_result_8(rr0,result); /* longjmp return */
assert(!"Should not be here!");
return NULL;
}
/* Same as above, but optimized for the case where there
* are only 2 possible results (ie, IF or WHILE). */
static inline void*
ff_find_result_1(void *data, int result)
{
result_8_t *rr0 = (result_8_t*)data;
#ifdef STATS
extern u_longlong_t count_result1_fast;
++count_result1_fast;
#endif
assert(rr0->action == RESULT1_ACTION);
if((int)rr0->result == result) return rr0+1;
if(rr0->next) return rr0->next;
ff_miss_result_1(rr0,result); /* jongjmp return */
assert(!"Should not be here!");
return NULL;
}
/* Process the INDEX action */
void* ff_index_action(action_t*);
/* Process the DLL action */
void* ff_dll_action(action_t*);
#ifdef STATS
extern u_longlong_t count_action_fast;
#define COUNT_ACTIONS ++count_action_fast;
#else
#define COUNT_ACTIONS
#endif
#endif