int main(int argc, const char *argv[])
{
	// Check arguments and ensure application to load specified
	if(!cmdParser(argc, argv)) {
		icmMessage("E", "platform", "Command Line parser error");
		return 1;
	}

	// the constructor
	createPlatform();

    icmSimulationStarting();

    // apply watchpoints in shared memory
    applyWatchpoints(handles.shared);

    // set register watchpoints for processor0 only
    applyRegWatchpoints(handles.processor0);

    // this is set to step for one instruction
    Bool          stepOver      = False;
    Bool          finished      = False;
    icmProcessorP stopProcessor = NULL;

    // query registers and register groups in processor0
    queryRegisters(handles.processor0);

    while(!finished) {

        // simulate the platform using the default scheduler
        if(stepOver) {
            icmSetICountBreakpoint(stopProcessor, 1);
            stopProcessor = icmSimulatePlatform();
            stepOver = False;
        } else {
            applyBreakpoints(handles.processor0);
            applyBreakpoints(handles.processor1);
            stopProcessor = icmSimulatePlatform();
            clearBreakpoints(handles.processor0);
            clearBreakpoints(handles.processor1);
        }

        switch(icmGetStopReason(stopProcessor)) {

            case ICM_SR_EXIT:
                finished = True;
                break;

            case ICM_SR_FINISH:
                finished = True;
                break;

            case ICM_SR_BP_ICOUNT:
                icmPrintf(
                    "Processor %s icount %u stopped at icount\n",
                     icmGetProcessorName(stopProcessor, "/"),
                    (Uns32)icmGetProcessorICount(stopProcessor)
                );
                break;

            case ICM_SR_BP_ADDRESS:
                icmPrintf(
                    "Processor %s icount %u stopped at address 0x%08x\n",
                    icmGetProcessorName(stopProcessor, "/"),
                    (Uns32)icmGetProcessorICount(stopProcessor),
                    (Uns32)icmGetPC(stopProcessor)
                );
                stepOver = True;
                break;

            case ICM_SR_WATCHPOINT:
                icmPrintf(
                    "Processor %s icount %u stopped at watchpoint\n",
                     icmGetProcessorName(stopProcessor, "/"),
                    (Uns32)icmGetProcessorICount(stopProcessor)
                );
                handleWatchpoints();
                break;

            default:
                icmPrintf(
                    "Processor %s icount %u stopped for reason %u\n",
                    icmGetProcessorName(stopProcessor, "/"),
                    (Uns32)icmGetProcessorICount(stopProcessor),
                    icmGetStopReason(stopProcessor)
                );
                break;
        }
    }

    icmTerminate();

    return 0;
}
//
// Virtual platform construction and simulation
//
int main(int argc, const char **argv) {

    // Check arguments
    if(!cmdParser(argc, argv)) {
    	icmMessage("E", PLATFORM, "Command Line parser error");
    	return 1;
    }

    // initialize OVPsim
    unsigned int icmAttrs = ICM_STOP_ON_CTRLC | ICM_GDB_CONSOLE;

    icmInitPlatform(ICM_VERSION, icmAttrs, 0, 0, PLATFORM);

    const char *modelFile    = "model." IMPERAS_SHRSUF;
    const char *semihostFile = icmGetVlnvString(NULL, "ovpworld.org", "modelSupport", "imperasExit", "1.0", "model");

    // create a processor instance
    icmProcessorP processor = icmNewProcessor(
        "cpu1",             // CPU name
        "or1k",             // CPU type
        0,                  // CPU cpuId
        0,                  // CPU model flags
        32,                 // address bits
        modelFile,          // model file
        "modelAttrs",       // morpher attributes
		MODEL_FLAGS,        // attributes
        0,                  // user-defined attributes
        semihostFile,       // semi-hosting file
        "modelAttrs"        // semi-hosting attributes
    );

    // create the processor bus
    icmBusP bus = icmNewBus("bus", 32);

    // connect the processors onto the busses
    icmConnectProcessorBusses(processor, bus, bus);

    // create memory
    icmMemoryP local = icmNewMemory("local", ICM_PRIV_RWX, 0xffffffff);

    // connect the memory onto the busses
    icmConnectMemoryToBus(bus, "mp1", local, 0x00000000);

    icmSimulationStarting();

    // query processor registers, execeptions and modes
    queryRegisters(processor);
    queryExceptions(processor);
    queryModes(processor);

    // run processor until done (no instruction limit)
    while(simulate(processor, -1)) {
        // keep going while processor is still running
    }

    // report the total number of instructions executed
    icmPrintf(
        "processor has executed " FMT_64u " instructions\n",
        icmGetProcessorICount(processor)
    );

    icmTerminate();

    return 0;
}
// Platform entry point
int main(int argc, char **argv) {

    // Get the name of the application to run from the command line
    if (argc != 2) {
        icmPrintf("usage: %s <pa application>\n", argv[0]);
        return -1;
    }

    // Initialize OVPsim, enabling verbose mode to get statistics at end of execution
    icmInit(ICM_VERBOSE | ICM_STOP_ON_CTRLC | ICM_ENABLE_IMPERAS_INTERCEPTS, NULL, 0);

    /***************************************************************************************************
       MURAC Primary Architecture
         - ARM processor
     ***************************************************************************************************/
#ifdef INTECEPT_OBJECT_SUPPORTED
    const char *armModel    = icmGetVlnvString(NULL, "arm.ovpworld.org", "processor", "arm", "1.0", "model");
#endif
    const char *armSemihost = icmGetVlnvString(NULL, "arm.ovpworld.org", "semihosting", "armNewlib", "1.0", "model");

    icmAttrListP armUserAttr = icmNewAttrList();
    icmAddStringAttr(armUserAttr, "compatibility", "gdb");
    icmAddStringAttr(armUserAttr, "variant", "Cortex-A8");
    icmAddStringAttr(armUserAttr, "UAL", "1");

    // Create the Primary Architecture (PA) processor
    icmProcessorP pa = icmNewProcessor(
        "pa",                // CPU name
        "arm",               // CPU type
        0,                   // CPU cpuId
        0,                   // CPU model flags
        32,                  // address bits
#ifdef INTECEPT_OBJECT_SUPPORTED
        armModel,            // model file
#else

        MURAC_PA_MODEL_FILE, // model file
#endif
        "modelAttrs",        // model attributes
        SIMULATION_FLAGS,    // simulation flags
        armUserAttr,         // user-defined attributes
        armSemihost,         // semi-hosting file
        "modelAttrs"         // semi-hosting attributes
    );

#ifdef INTECEPT_OBJECT_SUPPORTED
    // Add intercept libarary for MURAC Primary Architecture instructions
    icmAddInterceptObject(pa, "murac_pa", MURAC_PA_INSTRUCTIONS_FILE, "modelAttrs", 0);
#endif

    /***************************************************************************************************
       System Memory
     ***************************************************************************************************/
    // Local memory for the PA
    // the ARM processor toolchain sites code in lower memory and stack in higher memory
    // so we will use two memories
    // NOTE: this is just a consequence of the default linker script used
    icmMemoryP codeMemory = icmNewMemory("code_memory", ICM_PRIV_RWX, 0x9fffffff);
    icmMemoryP localPA    = icmNewMemory("local_pa_memory", ICM_PRIV_RWX, 0x0fffffff);

    // Local memory for the AA
    icmMemoryP localAA    = icmNewMemory("local_aa_memory", ICM_PRIV_RWX, 0x0fffffff);

    // Processor state memory (shared)
    icmMemoryP prStateMemory = icmNewMemory("pr_state_memory", ICM_PRIV_RWX, 0x100);

    /***************************************************************************************************
       System Bus connections
     ***************************************************************************************************/
    icmBusP busPA = icmNewBus("pa_bus", 32);
    icmBusP busAA = icmNewBus("aa_bus", 32);

    // Connect Primary Architecture to the pa bus
    icmConnectProcessorBusses(pa, busPA, busPA);

    // Connect memories to the busses
    icmConnectMemoryToBus(busPA, "pa_code_memory_port", codeMemory, 0x00000000);
    icmConnectMemoryToBus(busPA, "pa_local_memory_port", localPA, 0xf0000000);
    icmConnectMemoryToBus(busPA, "pa_pr_state_memory_port", prStateMemory, 0xcf000000);

    icmConnectMemoryToBus(busAA, "aa_code_memory_port", codeMemory, 0x00000000);
    icmConnectMemoryToBus(busAA, "aa_local_memory_port", localAA, 0xf0000000);
    icmConnectMemoryToBus(busAA, "aa_pr_state_memory_port", prStateMemory, 0xcf000000);

    /***************************************************************************************************
       MURAC Peripherals (Auxiliary Architecture)
     ***************************************************************************************************/
    icmAttrListP fpgaAttrs = icmNewAttrList();
    if(finishOnSoftReset) {
        icmAddUns64Attr(fpgaAttrs, "stoponsoftreset",  1);
    }
    icmPseP muracFpga = icmNewPSE("muracFpga", MURAC_AA_FPGA_PSE_FILE, fpgaAttrs, 0, 0);

    // Connect memory access ports to the bus
    icmConnectPSEBus(muracFpga, busAA, "fpga_memread", True, 0x00000000, 0xffffffff);
    icmConnectPSEBus(muracFpga, busAA, "fpga_memwrite", True, 0x00000000, 0xffffffff);
    
    /***************************************************************************************************
       System Interrupt connections
     ***************************************************************************************************/
    icmNetP intBrArch = icmNewNet("brArch");
    icmNetP intRetArch = icmNewNet("retArch");

    // connect the processor interrupt port to the net
    icmConnectProcessorNet(pa, intBrArch, "brarch", ICM_OUTPUT);
    // connect the FPGA interrupt port to the net
    icmConnectPSENet(muracFpga, intBrArch, "fpga_brarch", ICM_INPUT);

    // connect the processor interrupt port to the net
    icmConnectProcessorNet(pa, intRetArch, "fiq", ICM_INPUT);
    // connect the FPGA interrupt port to the net
    icmConnectPSENet(muracFpga, intRetArch, "fpga_retarch", ICM_OUTPUT);

    /***************************************************************************************************
       Information
     ***************************************************************************************************/

    // Show the bus connections
    icmPrintf("\nPrimary Architecture Bus Connections\n");
    icmPrintBusConnections(busPA);
    icmPrintf("\nAuxiliary Architecture Bus Connections\n");
    icmPrintBusConnections(busAA);
    icmPrintf("\nNet Connections\n");
    icmPrintNetConnections();
    icmPrintf("\n");

    /***************************************************************************************************
       MURAC Simulation
     ***************************************************************************************************/

    // Load the application code into the primary architecture memory
    icmLoadProcessorMemory(pa, argv[1], False, False, True);

    // Run the simulation until done (no instruction limit)
    icmProcessorP final = icmSimulatePlatform();
    if ( final && (icmGetStopReason(final) == ICM_SR_INTERRUPT ) ) {
        icmPrintf("*** MURAC simulation interrupted\n");
    }

    // report the total number of instructions executed
    icmPrintf("MURAC Primary Architecture has executed " FMT_64u " instructions\n", icmGetProcessorICount(pa));

    icmTerminate();
    
    return 0;

}
//
// Virtual platform construction and simulation
//
int main(int argc, const char **argv) {

    // Check arguments
    if(!cmdParser(argc, argv)) {
    	icmMessage("E", PLATFORM, "Command Line parser error");
    	return 1;
    }

    // initialize OVPsim
    unsigned int icmAttrs = ICM_STOP_ON_CTRLC;

    icmInitPlatform(ICM_VERSION, icmAttrs, 0, 0, PLATFORM);

    const char *modelFile    = "model." IMPERAS_SHRSUF;
    const char *semihostFile = icmGetVlnvString(NULL, "ovpworld.org", "modelSupport", "imperasExit", "1.0", "model");

    // create a processor instance
    icmProcessorP procA = icmNewProcessor(
        "procA",            // CPU name
        "or1k",             // CPU type
        0,                  // CPU cpuId
        0,                  // CPU model flags
        32,                 // address bits
        modelFile,          // model file
        "modelAttrs",       // morpher attributes
		MODEL_FLAGS,        // attributes
        0,                  // user-defined attributes
        semihostFile,       // semi-hosting file
        "modelAttrs"        // semi-hosting attributes
    );

    // create the processor bus
    icmBusP busA = icmNewBus("busA", 32);

    // connect the processors onto the busses
    icmConnectProcessorBusses(procA, busA, busA);

    // create memory
    icmMemoryP localA = icmNewMemory("localA", ICM_PRIV_RWX, 0xffffffff);

    // connect the memory onto the busses
    icmConnectMemoryToBus(busA, "mp1", localA, 0x00000000);


    // create a processor instance
    icmProcessorP procB = icmNewProcessor(
        "procB",             // CPU name
        "or1k",             // CPU type
        0,                  // CPU cpuId
        0,                  // CPU model flags
        32,                 // address bits
        modelFile,          // model file
        "modelAttrs",       // morpher attributes
		MODEL_FLAGS,        // attributes
        attrsForB(),        // user-defined attributes
        semihostFile,       // semi-hosting file
        "modelAttrs"        // semi-hosting attributes
    );

    // create the processor bus
    icmBusP busB = icmNewBus("busB", 32);

    // connect the processors onto the busses
    icmConnectProcessorBusses(procB, busB, busB);

    // create memory
    icmMemoryP localB = icmNewMemory("localB", ICM_PRIV_RWX, 0xffffffff);

    // connect the memory onto the busses
    icmConnectMemoryToBus(busB, "mp1", localB, 0x00000000);

    icmNetP n1 = icmNewNet("n1");
    icmNetP n2 = icmNewNet("n2");
    icmNetP n3 = icmNewNet("n3");

    icmConnectProcessorNet(procA, n1, "intr0", ICM_INPUT);
    icmConnectProcessorNet(procB, n2, "intr0", ICM_INPUT);
    icmConnectProcessorNet(procB, n3, "intr1", ICM_INPUT);

    // advance the processors, then interrupt
    icmSimulate(procA, 9);
    icmSimulate(procB, 9);
    icmPrintf("Interrupting A & B\n");
    icmWriteNet(n1, 1);
    icmWriteNet(n3, 1);
    icmSimulate(procA, 1);
    icmSimulate(procB, 1);
    icmWriteNet(n1, 0);
    icmWriteNet(n3, 0);
    icmSimulate(procA, 9);
    icmSimulate(procB, 9);

    icmPrintf("Interrupting B\n");
    icmWriteNet(n2, 1);
    icmSimulate(procA, 1);
    icmSimulate(procB, 1);
    icmWriteNet(n2, 0);
    icmSimulate(procA, 10);
    icmSimulate(procB, 10);

    // report the total number of instructions executed
    icmPrintf(
        "processor A has executed " FMT_64u " instructions\n",
        icmGetProcessorICount(procA)
    );
    icmPrintf(
        "processor B has executed " FMT_64u " instructions\n",
        icmGetProcessorICount(procB)
    );

    icmTerminate();

    return 0;
}