?? flatmem.c
字號:
/* flatmem.c - Fast ARMulator memory interface.
* (formerly known as armflat.c.)
* Copyright (C) Advanced RISC Machines Limited, 1995-1998.
* Copyright (C) 1998-2001 ARM Limited.
* All rights reserved.
*
* RCS $Revision: 1.1.2.31.2.3 $
* Checkin $Date: 2003/09/24 16:40:02 $
* Revising $Author: dsinclai $
*/
#include <string.h> /* for memset */
#include <ctype.h> /* for toupper */
#include "rdi.h"
#include "rdi_priv.h"
#include "rdi_prop.h"
#include "simplelinks.h"
#include "armul_callbackid.h"
#include "perip2rdi.h" /* Perip2Memret */
#include "minperip.h"
#include "addcounter.h"
#include "armul_lib.h" /* for ARMul_SIRange() */
#include "armul_agent.h" /* for ARMulAgent_* */
#define ACDTEST(FUNC,RET) if (FUNC == RDIError_BufferFull) \
RET = RDIError_BufferFull
#include "armul_mem.h" /* for ARMul_Cycles ... */
#include "rdi_conf.h"
#include "armul_cnf.h"
#include "clxlist.h"
#include "armul_cyc.h"
#define NO_BYTELANES
/* NUL_BIU owns ABus now. */
/* #define FLAT_OWNS_ABUS */
/* debug options */
#ifndef NDEBUG
# if 1
# define VERBOSE_NewLeafPageAllocated
# else
# define VERBOSE_BUS
# define VERBOSE_PERIPHERAL_ICYCLES
# define VERBOSE_MEM_TYPE
# define VERBOSE_CYCLE_DESC
# endif
#endif
#ifdef VERBOSE_DABORT
# define return_PERIP_DABORT \
printf("\n*** Flatmem returns PERIP_DABORT ***\n"); \
return_PERIP_DABORT
#else
# define return_PERIP_DABORT return PERIP_DABORT
#endif
#ifdef HOST_ENDIAN_BIG
# define HostEndian 1
#elif defined(HOST_ENDIAN_LITTLE)
# define HostEndian 0
#else
# error "HOST_ENDIAN_UNKNOWN"
#endif
#define NUMPAGES 64 * 1024
#define ARMFLAT_PAGESIZE 64 * 1024
#define PAGEBITS 16
#define OFFSETBITS_WORD 0xfffc
typedef struct {
ARMword memory[ARMFLAT_PAGESIZE/4];
} mempage;
typedef struct {
mempage *page[NUMPAGES];
} memory;
BEGIN_STATE_DECL(Flatmem)
/* things that need to be accessed quickly at the start */
unsigned read_bigend, write_bigend;
unsigned int sa_memacc_flag;
ARMul_Cycles cycles;
ARMul_Cycles saved_cycles;
ARMTime saved_bus_BusyUntil;
ARMword LowestPeripheralAddress, HighestPeripheralAddress;
ARMword byteAddrXor,hwordAddrXor; /* for reads */
#ifdef FLAT_OWNS_ABUS /*F*/
/* Was ARMul_State->as_ABus */
ARMul_Bus fm_ABus;
#endif
ARMul_Bus *p_ABus;
ARMul_MemInterface bus_mem;
ARMul_MemInterfaceRef mem_ref;
memory mem; /* big data structure in the middle */
/* things that are rarely accessed at the end */
ARMul_MemType memtype;
bool memory_byte_sex; /* memory bytesex is fixed */
bool BaseMemoryEnabled;
double clk;
ARMTime clk_speed;
struct GenericAccessCallback *NewPageAllocated;
RDI_AgentHandle agent;
bool bI_Cycles;
char *mf_CycleNames[16];
END_STATE_DECL(Flatmem) /* toplevel; */
#define toplevel FlatmemState
/*
* ARMulator callbacks
*/
static unsigned ARMFlat_DebugEvents(void *handle, void *data)
{
toplevel *top=(toplevel *)handle;
ARMul_Event *evt = (ARMul_Event *)data;
if(evt->event == DebugEvent_RunCodeSequence)
{
/* save cycle counts */
top->saved_bus_BusyUntil = top->p_ABus->bus_BusyUntil;
top->saved_cycles = top->cycles;
}
if(evt->event == DebugEvent_EndCodeSequence)
{
/* restore cycle counts */
top->p_ABus->bus_BusyUntil = top->saved_bus_BusyUntil;
top->cycles = top->saved_cycles;
}
return FALSE;
}
static void ConfigChange(void *handle, unsigned bNewBigend)
{
toplevel *top=(toplevel *)handle;
/* bigendian swapping for reads is ALWAYS done by the memory model */
top->read_bigend = bNewBigend; /* ((newValue & ARM_MMU_B) != 0); */
top->byteAddrXor = ( top->read_bigend != HostEndian ) ? 3 : 0;
top->hwordAddrXor = ( top->read_bigend != HostEndian ) ? 2 : 0;
#ifdef VERBOSE_CONFIGCHANGE
printf("Flatmem:ConfigChange bNewBigend:%u\n",(unsigned)bNewBigend);
#endif
/* If we have "fixed" bigend for the memory, then swapping for writes is
* fixed, otherwise it is the same as for reads
*/
if (top->memory_byte_sex == FALSE)
top->write_bigend = top->read_bigend;
}
/* static void Interrupt(void *handle,unsigned int which) */
static unsigned Flatmem_ConfigEvents(void *handle, void *data)
{
toplevel *top=(toplevel *)handle;
ARMul_Event *evt = (ARMul_Event *)data;
switch (evt->event)
{
case ConfigEvent_Reset:
memset(&top->cycles,0,sizeof(top->cycles));
top->p_ABus->bus_BusyUntil = 0;
ARMul_BusLimits(top->p_ABus, &top->LowestPeripheralAddress,
&top->HighestPeripheralAddress, 1);
break;
case ConfigEvent_EndiannessChanged:
ConfigChange(handle, evt->data1);
break;
default:
return ARMFlat_DebugEvents(handle, data);
}
return FALSE;
}
static void ARMFlat_SetBaseMemoryEnable(toplevel *top, uint32 value)
{
top->BaseMemoryEnabled = BOOLIFY(value);
}
#define GET_PRIMARY_ID(argx) (*(unsigned *)argx)
#define GET_INDEXED_ID(argx,ndex) (((unsigned *)argx)[ndex])
static int UnkRDIInfo(void *handle, unsigned type, ARMword *arg1,ARMword *arg2)
{
toplevel *top = (toplevel *)handle;
int retVal = RDIError_UnimplementedMessage;
if (!top->BaseMemoryEnabled)
return retVal;
switch(type) {
case RDICycles:
{
void *state = NULL; /* ARMul_State, top->state; */
ARMTime total;
ARMul_AddCounterValue64(state, arg1, arg2, top->cycles.NumScycles);
ARMul_AddCounterValue64(state, arg1, arg2, top->cycles.NumNcycles);
ARMul_AddCounterValue64(state, arg1, arg2, top->cycles.NumIcycles);
ARMul_AddCounterValue64(state, arg1, arg2, top->cycles.NumCcycles);
total = (top->cycles.NumScycles + top->cycles.NumNcycles +
top->cycles.NumIcycles + top->cycles.NumCcycles);
ARMul_AddCounterValue64(state, arg1, arg2, total);
break; /* Allow more */
}
case RDIRequestCyclesDesc:
{
void *state = NULL;
if (top->memtype == ARMul_MemType_PipelinedARM9 ||
top->memtype == ARMul_MemType_StrongARM ||
top->memtype == ARMul_MemType_ARM9)
{
if( top->memtype == ARMul_MemType_StrongARM) {
top->mf_CycleNames[1]="Core_ID";
top->mf_CycleNames[0]="Core_IOnly";
top->mf_CycleNames[2]="Core_Idles";
top->mf_CycleNames[3]="Core_DOnly";
} else {
top->mf_CycleNames[1]="ID_Cycles";
top->mf_CycleNames[0]="IBus_Cycles";
top->mf_CycleNames[2]="Idle_Cycles";
top->mf_CycleNames[3]="DBus_Cycles";
}
ACDTEST(ARMul_AddCounterDesc(
NULL, arg1, arg2,
top->mf_CycleNames[1] /*"ID_Cycles"*/), retVal);
ACDTEST(ARMul_AddCounterDesc(
NULL, arg1, arg2,
top->mf_CycleNames[0]/*"IBus_Cycles"*/), retVal);
ACDTEST(ARMul_AddCounterDesc(
NULL, arg1, arg2,
top->mf_CycleNames[2]/*"Idle_Cycles"*/), retVal);
ACDTEST(ARMul_AddCounterDesc(
NULL, arg1, arg2,
top->mf_CycleNames[3]/*"DBus_Cycles"*/), retVal);
#ifdef VERBOSE_CYCLE_DESC
printf("ARMflat RDIRequestCyclesDesc Harvard.\n");
#endif
} else {
top->mf_CycleNames[1]="S_Cycles";
top->mf_CycleNames[0]="N_Cycles";
top->mf_CycleNames[2]="I_Cycles";
top->mf_CycleNames[3]="C_Cycles";
if(!top->bI_Cycles)
ARMulif_ReadCycleNames(&top->mf_CycleNames[0],16,
top->memtype,top->config);
ACDTEST(ARMul_AddCounterDesc(
NULL, arg1, arg2,
top->mf_CycleNames[1]/*"S_Cycles"*/), retVal);
ACDTEST(ARMul_AddCounterDesc(
NULL, arg1, arg2,
top->mf_CycleNames[0]/*"N_Cycles"*/), retVal);
ACDTEST(ARMul_AddCounterDesc(
NULL, arg1, arg2,
top->mf_CycleNames[2]/*"I_Cycles"*/), retVal);
ACDTEST(ARMul_AddCounterDesc(
NULL, arg1, arg2,
top->mf_CycleNames[3]/*"C_Cycles"*/), retVal);
}
ACDTEST(ARMul_AddCounterDesc(state, arg1, arg2, "Total"), retVal);
break; /* Allow more */
}
case RDIProperty_SetAsNumeric:
{ /* Currently, only signals. */
unsigned ID = (unsigned)arg1;
switch (ID)
{
case RDIPropID_ARMSignal_BaseMemoryEnable:
ARMFlat_SetBaseMemoryEnable(top,*arg2);
ARMul_BusLimits(top->p_ABus, &top->LowestPeripheralAddress,
&top->HighestPeripheralAddress, 1);
return RDIError_NoError;
default: break;
}
break;
}
case RDIInfo_RegisterCallback:
{
unsigned ID = GET_PRIMARY_ID(arg1);
switch(ID)
{
case ARMulCallbackID_NewLeafPageAllocated:
#ifdef VERBOSE_NewLeafPageAllocated
printf("\nflatmem.c:RDIInfo_RegisterCallback:ARMulCallbackID_NewLeafPageAllocated\n");
#endif
return ARMulif_InstallGenericAccessCallback(&top->NewPageAllocated,
(GenericAccessCallback*)arg2);
default: break;
}
break;
}
case RDIInfo_DeregisterCallback:
{
unsigned ID = GET_PRIMARY_ID(arg1);
switch(ID)
{
case ARMulCallbackID_NewLeafPageAllocated:
return ARMulif_RemoveGenericAccessCallback(&top->NewPageAllocated,
(void*)arg2);
default: break;
}
break;
}
case RDIInfo_QueryMemInterface:
{
unsigned ID = GET_PRIMARY_ID(arg1);
switch (ID) {
case ARMulBusID_Memory: /* Leaf memory, usually flat */
*(ARMul_MemInterface**)arg2 = top->mem_ref.mif;
return RDIError_NoError;
default:break;
}
break;
}
#ifdef FLAT_OWNS_ABUS
case RDIInfo_QueryBus:
{
void **pBus = (void**)arg2;
char const *name = (char const *)arg1;
if (name[0]==(char)0 || name[1]==(char)0) {
/* Flatmem only uses single-char names only so far. */
switch(*name) {
case '\0':
case 'A':
*pBus = top->p_ABus;
return RDIError_NoError;
default:
break;
}
}
}
#endif
default: break;
}
return retVal;
}
/*
* Predeclare the memory access functions so that the initialisation function
* can fill them in
*/
#ifdef PIPELINED
static void NextCycle(void *,ARMword,ARMul_acc);
static void NextDCycle(void *,ARMword,ARMul_acc);
static void NextICycle(void *,ARMword,ARMul_acc);
#endif
#ifdef OldCode
static armul_MemAccAsync MemAccessAsync;
#endif
static void MemAccessHarvard(void *,ARMword,ARMword *,ARMul_acc, int *,
ARMword,ARMword *,ARMul_acc, int *);
static int MemAccess(void *,ARMword,ARMword *,ARMul_acc);
static int MemAccessCached(void *,ARMword,ARMword *,ARMul_acc);
static int MemAccessThumb(void *,ARMword,ARMword *,ARMul_acc);
/* This expects D,I call-pairs, and accounts like Harvard. */
static int MemAccessSA(void *,ARMword,ARMword *,ARMul_acc);
#ifndef NO_BYTELANES
static int MemAccessBL(void *,ARMword,ARMword *,ARMul_acc);
#endif
#ifdef MEM_ACCESS2_DISTINCT
static int MemAccess2(void *,ARMword,ARMword *,ARMword *,ARMul_acc);
#endif
static unsigned int DataCacheBusy(void *);
static const ARMul_Cycles *Flat_ReadCycles(void *handle);
static unsigned long Flat_GetCycleLength(void *handle);
static unsigned Flat_MemInfo(void *handle, unsigned type, ARMword *pID,
uint64 *data);
static GenericAccessFunc flat_newPage;
/* Needed for VC++6 */
static double u64_to_dbl(uint64 v)
{
int64 v2 = (int64)v;
return (double)v2;
}
static ARMTime Flat_ReadClock(void *handle)
{
/* returns a us count */
toplevel *top=(toplevel *)handle;
double t=(u64_to_dbl(top->cycles.NumNcycles) +
u64_to_dbl(top->cycles.NumScycles) +
u64_to_dbl(top->cycles.NumIcycles) +
u64_to_dbl(top->cycles.NumCcycles))*top->clk;
#if 0
printf("Flat_ReadClock->%f (clk=%f)\n",t,top->clk);
#endif
return (ARMTime)(int64)t;
}
/* armmmu requires log2(0) == 0 */
static int flatmem_log2(unsigned int value)
{
unsigned short n = 0;
while( (value >>= 1) != 0 )
{
n++;
}
return n;
}
static int flatmem_masterInfo(toplevel *top, unsigned type,
ARMword *address, uint64 *data)
{
return top->mem_ref.master_info ?
top->mem_ref.master_info(top->mem_ref.handle,
type,address,data) :
RDIError_UnimplementedMessage;
}
BEGIN_INIT(Flatmem)
{
/* Leaf memory, usually flatmem */
static uint32 ID_Mem[2] = {ARMulBusID_Memory,0};
ARMul_MemInterface *interf =
ARMulif_QueryMemInterface(&state->coredesc, &ID_Mem[0]); /* "mif" */
ARMul_MemType memtype;
bool_int verbose = ToolConf_DLookupBool(config,(tag_t)"VERBOSE",FALSE);
memory *mem;
unsigned page;
ARMword clk_speed = 0;
const char *option;
toplevel *top=(toplevel *)state;
if (top == NULL)
return RDIError_OutOfStore;
/* If we didn't get the connection we wanted, to replace the
* built-in armflat, then ask for the output of the bus-interface. */
if (interf == NULL)
{
/* Output of NUL_BIU (from cache or uncached core) */
static uint32 ID_Bus[2] = {ARMulBusID_Bus,0};
interf = ARMulif_QueryMemInterface(&state->coredesc, &ID_Bus[0]);
}
top->bI_Cycles = ToolConf_DLookupBool(config,(tag_t)"ICycles",FALSE);
#ifdef FLAT_OWNS_ABUS /*F*/
top->p_ABus = &top->fm_ABus;
#endif
if (!interf)
{
static uint32 ID_CORE[2] = {ARMulBusID_Core,0};
interf =
ARMulif_QueryMemInterface(&state->coredesc, &ID_CORE[0]);
#ifdef VERBOSE /* Not really a failure - we expect this for uncached cores. */
Hostif_PrettyPrint(hostif,config,
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -