"failstar" sounds like a name for a cruise liner from the 80s. As "*" isn't a desirable part of directory names, just name the whole thing "fail/", the core parts being stored in "fail/core/". Additionally fixing two build system dependency issues: - missing jobserver -> protomessages dependency - broken bochs -> fail dependency (add_custom_target DEPENDS only allows plain file dependencies ... cmake for the win) git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@956 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
363 lines
11 KiB
C++
363 lines
11 KiB
C++
/*
|
|
* Copyright (c) 2005-2011 Imperas Software Ltd., www.imperas.com
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
|
* either express or implied.
|
|
*
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <iostream>
|
|
|
|
#include "platform.hpp"
|
|
#include "statreg.hpp"
|
|
#include "SAL/SALInst.hpp"
|
|
|
|
#include "icm/icmCpuManager.h"
|
|
#include "icm/icmQuery.h"
|
|
|
|
// enable relaxed scheduling for maximum performance
|
|
//#define SIM_ATTRS (ICM_ATTR_RELAXED_SCHED|ICM_ATTR_TRACE)
|
|
#define SIM_ATTRS (ICM_ATTR_RELAXED_SCHED)
|
|
|
|
// GDB port
|
|
#define GDB_PORT 1234
|
|
|
|
// Variables set by arguments
|
|
const char *variant = "Cortex-M3"; // the model variant
|
|
|
|
using namespace std;
|
|
|
|
ARM_Cortex_M3 arm;
|
|
|
|
ARM_Cortex_M3::ARM_Cortex_M3() {
|
|
}
|
|
|
|
ARM_Cortex_M3::~ARM_Cortex_M3() {
|
|
delete platform;
|
|
delete cpu;
|
|
delete attrList;
|
|
}
|
|
|
|
void ARM_Cortex_M3::init(bool gdb=false) {
|
|
|
|
// initialize OVPsim, enabling verbose mode to get statistics at end of execution
|
|
platform = new icmPlatform("CortexM3Platform", //name
|
|
ICM_VERBOSE|ICM_STOP_ON_CTRLC, //attributes
|
|
gdb ? "rsp" : 0, // optional protocol
|
|
gdb ? GDB_PORT : 0); // optional port number
|
|
|
|
|
|
// const char *armModel = icmGetVlnvString(NULL, "arm.ovpworld.org", "processor", "armm", "1.0", "model");
|
|
const char *armModel = "/srv/scratch/hoffmann/test/build/lib/libarmmModel.so";
|
|
const char *armSemihost = icmGetVlnvString(NULL, "arm.ovpworld.org", "semihosting", "armNewlib", "1.0", "model");
|
|
|
|
attrList = new icmAttrListObject();
|
|
|
|
attrList->addAttr("endian", "little");
|
|
attrList->addAttr("compatibility", "nopBKPT");
|
|
attrList->addAttr("variant", variant);
|
|
attrList->addAttr("UAL", "1");
|
|
attrList->addAttr("fail_salp", &sal::simulator);
|
|
|
|
char cpuname[64];
|
|
sprintf(cpuname,"cpu-%s", variant);
|
|
|
|
// create a processor instance
|
|
cpu = new icmProcessorObject(
|
|
cpuname, // CPU name
|
|
"armm", // CPU type
|
|
0, // CPU cpuId
|
|
0, // CPU model flags
|
|
32, // address bits
|
|
armModel, // model file
|
|
"modelAttrs", // morpher attributes
|
|
SIM_ATTRS, // attributes
|
|
attrList, // user-defined attributes
|
|
armSemihost, // semi-hosting file
|
|
"modelAttrs" // semi-hosting attributes
|
|
);
|
|
|
|
// Nominate this processor to be attached to a debugger
|
|
if(gdb) cpu->debugThisProcessor();
|
|
|
|
processorP = cpu->getProcessorP();
|
|
}
|
|
|
|
void ARM_Cortex_M3::createFullMMC(const char *vlnRoot=0) {
|
|
// TODO: ELF Groesse auslesen per OVP (hat funktionen) und dann den Bereich als MMC einrichten...
|
|
/* const char *mmc_model = icmGetVlnvString("/srv/scratch/sirozipp/build/lib", "ovpworld.org", "mmc", "failMMC", "1.0", "model");
|
|
if(mmc_model == NULL) {
|
|
std::cerr << "mmc_model not found!" << std::endl;
|
|
exit(1);
|
|
}
|
|
*/
|
|
const char *mmc_model = "/srv/scratch/sirozipp/build/lib/libflaky.so";
|
|
|
|
// create full MMCs
|
|
mmcInstr = new icmMmcObject("mmci", mmc_model, "modelAttrs", 0, False);
|
|
mmcData = new icmMmcObject("mmcd", mmc_model, "modelAttrs", 0, False);
|
|
|
|
// create processor instruction and data bus
|
|
instrBus = new icmBusObject("instrbus", 32);
|
|
dataBus = new icmBusObject("databus", 32);
|
|
|
|
// create processor main bus
|
|
mainBus = new icmBusObject("mainbus", 32);
|
|
|
|
// connect processor ports to their buses
|
|
cpu->connect(*instrBus, *dataBus);
|
|
|
|
// connect mmcs to buses
|
|
mmcInstr->connect(*instrBus, "sp1", False);
|
|
mmcData->connect(*dataBus, "sp1", False);
|
|
|
|
// connet master ports of mmc to main bus
|
|
mmcInstr->connect(*mainBus, "mp1", True);
|
|
mmcData->connect(*mainBus, "mp1", True);
|
|
|
|
// create simulated memory
|
|
Addr appHighAddr, appLowAddr;
|
|
|
|
appHighAddr = 0xFFFFFFFF;
|
|
appLowAddr = 0x0;
|
|
icmMem0 = new icmMemoryObject("mem1", ICM_PRIV_RWX, appHighAddr-appLowAddr);
|
|
|
|
// connect memory to main bus
|
|
icmMem0->connect("mp1", *mainBus, 0);
|
|
}
|
|
|
|
static ICM_MEM_READ_FN(extMemRead) {
|
|
unsigned char res[4];
|
|
// Int32 tmpres = *(Int32*)value;
|
|
// icmPrintf("EXTERNAL MEMORY: Reading 0x%08x from 0x%08x\n", *(Int32*)value, (Int32)address);
|
|
// *(Int32*) value = (Int32)arm.mem[(address-arm.offset)>>2];
|
|
|
|
sal::simulator.onMemoryAccessEvent(address, 4, false, ovpplatform.getPC());
|
|
|
|
res[0] = arm.mem[(address-arm.offset)+0];
|
|
res[1] = arm.mem[(address-arm.offset)+1];
|
|
res[2] = arm.mem[(address-arm.offset)+2];
|
|
res[3] = arm.mem[(address-arm.offset)+3];
|
|
|
|
// icmPrintf("Reading [0] 0x%08x, [1] 0x%08x, [2] 0x%08x, [3] 0x%08x\n", arm.mem[(address-arm.offset)+0], arm.mem[(address-arm.offset)+1], arm.mem[(address-arm.offset)+2], arm.mem[(address-arm.offset)+3]);
|
|
|
|
*(Int32*)value = (res[3] << 24) | (res[2] << 16) | (res[1] << 8) | res[0];
|
|
//
|
|
// icmPrintf("Reading: 0x%08x\n", (res[3] << 24) | (res[2] << 16) | (res[1] << 8) | res[0]);
|
|
|
|
// icmPrintf("Callback: Reading 0x%08x from mem[0x%08x] should be 0x%08x from [0x%08x]\n", *(Int32*)value, (Int32)(address-arm.offset), tmpres, (Int32) address);
|
|
|
|
}
|
|
|
|
static ICM_MEM_WRITE_FN(extMemWrite) {
|
|
// icmPrintf("EXTERNAL MEMORY: Writing 0x%08x to 0x%08x\n", (Int32)value, (Int32)address);
|
|
// icmPrintf("Callback: Writing 0x%08x to mem[0x%08x] should be 0x%08x from [0x%08x]\n", *(Int32*)value, (Int32)(address-arm.offset), *(Int32*) value, (Int32) address);
|
|
sal::simulator.onMemoryAccessEvent(address, 4, true, ovpplatform.getPC());
|
|
|
|
Int32 val = *(Int32*)value;
|
|
|
|
arm.mem[(address-arm.offset) + 0] = val & 0xFF;
|
|
arm.mem[(address-arm.offset) + 1] = (val >> 8) & 0xFF;
|
|
arm.mem[(address-arm.offset) + 2] = (val >> 16) & 0xFF;
|
|
arm.mem[(address-arm.offset) + 3] = (val >> 24) & 0xFF;
|
|
|
|
// icmPrintf("Writing [0] 0x%08x, [1] 0x%08x, [2] 0x%08x, [3] 0x%08x\n", val & 0xFF, (val >> 8) & 0xFF, (val >> 16) & 0xFF, (val >> 24) & 0xFF);
|
|
// icmPrintf("Writing [0] 0x%08x, [1] 0x%08x, [2] 0x%08x, [3] 0x%08x\n", arm.mem[(address-arm.offset)+0], arm.mem[(address-arm.offset)+1], arm.mem[(address-arm.offset)+2], arm.mem[(address-arm.offset)+3]);
|
|
|
|
// Int32 res = arm.mem[(address-arm.offset)+0] | arm.mem[(address-arm.offset)+1] << 8 | arm.mem[(address-arm.offset)+2] << 16 | arm.mem[(address-arm.offset)+3] << 24;
|
|
|
|
// icmPrintf("Callback: Writing 0x%08x to mem[0x%08x] should be 0x%08x to [0x%08x]\n", res, (Int32)(address-arm.offset), *(Int32*) value, (Int32) address);
|
|
// arm.mem[(address-arm.offset) >> 2] = *(Int32*) value;
|
|
}
|
|
|
|
static ICM_MEM_READ_FN(extTextRead) {
|
|
// Int16 val = *(Int16*)value;
|
|
*(Int16*) value = (Int16)arm.textmem[(address-arm.textOffset)>>1];
|
|
// icmPrintf("Callback: Reading 0x%04x from textmem[0x%08x] should be 0x%04x from [0x%08x]\n", *(Int16*)value, (Int32)(address-arm.textOffset), val, (Int32) address);
|
|
}
|
|
|
|
static ICM_MEM_WRITE_FN(extTextWrite) {
|
|
arm.textmem[(address-arm.textOffset) >> 1] = *(Int16*) value;
|
|
}
|
|
|
|
void ARM_Cortex_M3::mapMemToCallback() {
|
|
// create processor bus
|
|
mainBus = new icmBusObject("mainbus", 32);
|
|
|
|
// connect the processor bus
|
|
cpu->connect(*mainBus, *mainBus);
|
|
|
|
// create simulated memory
|
|
Addr appHighAddr, appLowAddr, textLowAddr, textHighAddr, LowAddr, LowAddrH, HighAddr, HighAddrL;
|
|
|
|
appLowAddr = offset;
|
|
appHighAddr = appLowAddr + memSize - 1;
|
|
|
|
textLowAddr = textOffset;
|
|
textHighAddr = textLowAddr + textMemSize - 1;
|
|
|
|
// check which section is first
|
|
if(appLowAddr < textLowAddr) {
|
|
LowAddr = appLowAddr;
|
|
LowAddrH = appHighAddr;
|
|
HighAddr = textHighAddr;
|
|
HighAddrL = textLowAddr;
|
|
} else {
|
|
LowAddr = textLowAddr;
|
|
LowAddrH = textHighAddr;
|
|
HighAddr = appHighAddr;
|
|
HighAddrL = appLowAddr;
|
|
}
|
|
|
|
// Memory from 0x0 to LowAddr
|
|
icmMem0 = new icmMemoryObject("mem0", ICM_PRIV_RWX, LowAddr - 1);
|
|
// Memory after callback mem to end
|
|
icmMem1 = new icmMemoryObject("mem1", ICM_PRIV_RWX, 0xFFFFFFFF - HighAddr - 1);
|
|
// Memory between text and other sections
|
|
icmMem2 = new icmMemoryObject("mem2", ICM_PRIV_RWX, HighAddrL - LowAddrH - 1 -1);
|
|
|
|
// map the adress range appLowAddr:appHighAddr externally to the processor
|
|
mainBus->mapExternalMemory("external", ICM_PRIV_RWX, appLowAddr, appHighAddr,
|
|
extMemRead, // read callback
|
|
extMemWrite, // write callback
|
|
0);
|
|
|
|
mainBus->mapExternalMemory("exttext", ICM_PRIV_RWX, textLowAddr, textHighAddr,
|
|
extTextRead,
|
|
extTextWrite,
|
|
0);
|
|
|
|
// just build memory before external memory if it's not at the beginning
|
|
if(LowAddr > 0x0) {
|
|
icmMem0->connect("mp1", *mainBus, 0x0);
|
|
}
|
|
|
|
if(HighAddr < 0xffffffff) {
|
|
icmMem1->connect("mp2", *mainBus, HighAddr+1);
|
|
}
|
|
|
|
if(LowAddrH != HighAddrL) {
|
|
icmMem2->connect("mp3", *mainBus, LowAddrH+1);
|
|
}
|
|
|
|
mainBus->printConnections();
|
|
}
|
|
|
|
|
|
void ARM_Cortex_M3::makeGPRegister() {
|
|
const string names[] = {"r0", "r1", "r2", "r3", "r4", "r5",
|
|
"r6", "r7", "r8", "r9", "r10", "r11", "r12"};
|
|
|
|
|
|
|
|
for(int i = 0; i <= 12; ++i) {
|
|
icmRegInfoP reg = icmGetRegByIndex(processorP, i);
|
|
sal::simulator.makeGPRegister(32, (void *)reg, names[i]);
|
|
}
|
|
|
|
// set SP pointer
|
|
// ARM Cortex M3: SP pointer is ID 13
|
|
icmRegInfoP sp_reg = icmGetRegByIndex(processorP, 13);
|
|
setSPReg(sp_reg);
|
|
}
|
|
|
|
void ARM_Cortex_M3::makeSTRegister() {
|
|
OVPStatusRegister *streg = new CortexM3StatusRegister();
|
|
|
|
sal::simulator.makeSTRegister(streg, "sp");
|
|
}
|
|
|
|
void ARM_Cortex_M3::makePCRegister() {
|
|
// ARM Cortex M3: PC pointer is ID 15
|
|
icmRegInfoP pc_reg = icmGetRegByIndex(processorP, 15);
|
|
sal::simulator.makePCRegister(32, (void *)pc_reg, "PC");
|
|
}
|
|
|
|
int ARM_Cortex_M3::startSimulation(const char *app) {
|
|
bool loadPhysical = true;
|
|
bool verbose = true;
|
|
bool useEntry = true;
|
|
if(!cpu->loadLocalMemory(app, loadPhysical, verbose, useEntry))
|
|
return -1;
|
|
|
|
// application is loaded, now fill the callback memory with program data
|
|
fillCallbackMemory();
|
|
|
|
// icmSimulatePlatform();
|
|
|
|
while(1) {
|
|
// save PC
|
|
Addr pc_ptr = cpu->getPC();
|
|
|
|
sal::simulator.onInstrPtrChanged(pc_ptr);
|
|
|
|
// simulate the platform
|
|
icmStopReason stopreason = cpu->simulate(1);
|
|
|
|
if(stopreason!=0x00) {
|
|
// was simulation interrupted or did it complete
|
|
if(stopreason==ICM_SR_INTERRUPT) {
|
|
icmPrintf("*** simulation interrupted\n");
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
//icmTerminate();
|
|
|
|
return 0;
|
|
}
|
|
|
|
void ARM_Cortex_M3::makeCallbackMemory(size_t sizeText, size_t offText, size_t sizeMem, size_t offMem) {
|
|
mem = new unsigned char[sizeMem];
|
|
//mem = new Int32[sizeMem>>2];
|
|
textmem = new Int16[sizeText>>1];
|
|
offset = offMem;
|
|
textOffset = offText;
|
|
memSize = sizeMem;
|
|
textMemSize = sizeText;
|
|
}
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
if(argc != 2) {
|
|
std::cerr << "Usage: " << argv[0] << " application" << std::endl;
|
|
exit(1);
|
|
}
|
|
|
|
arm.init(false);
|
|
|
|
// arm.createFullMMC();
|
|
|
|
// arm.makeCallbackMemory(0x100, 0x20000000);
|
|
// arm.makeCallbackMemory(0x8034, 0x0, 0x11c, 0x82e8);
|
|
// arm.makeCallbackMemory(0x8034, 0x0, 0x940, 0x8040);
|
|
arm.makeCallbackMemory(0x802c, 0x0, 0x930, 0x8038);
|
|
arm.mapMemToCallback();
|
|
|
|
|
|
ovpplatform.setCpu((void *) &arm);
|
|
|
|
arm.makeGPRegister();
|
|
arm.makeSTRegister();
|
|
arm.makePCRegister();
|
|
|
|
sal::simulator.finishedRegisterCreation();
|
|
|
|
arm.startSimulation(argv[1]);
|
|
}
|