/******************************************************************************/
/* test.ini: Initialization file to test the debug functionality              */
/******************************************************************************/
/* This file is part of the uVision/ARM development tools.                    */
/* Copyright (c) 2012-2017 Keil Software. All rights reserved.                */
/* This software may only be used under the terms of a valid, current,        */
/* end user license from KEIL for a compatible version of KEIL software       */
/* development tools. Nothing else gives you the right to use this software.  */
/******************************************************************************/

// ensure logging into file is turned off
LOG OFF

// overall test success flag
define int testSuccess;
testSuccess = 0;

// flags to show which particular tests succeeded
define char bpExecSuccess;
bpExecSuccess = 0;
define char bpReadSuccess;
bpReadSuccess = 0;
define char bpWriteSuccess;
bpWriteSuccess = 0;
define char memReadSuccess;
memReadSuccess = 0;
define char memWriteSuccess;
memWriteSuccess = 0;
define char regReadSuccess;
regReadSuccess = 0;
define char regWriteSuccess;
regWriteSuccess = 0;


// function to read and write registers
FUNC void RegReadWrite(void) {
  unsigned long VR0, VR1, VR2, VR3, VR4, VR5, VR6, VR7, VR8, VR9;
  unsigned long VR10, VR11, VR12, VR13, VR14, VR15, VxPSR;
  unsigned long VR_0, VR_1, VR_2, VR_3, VR_4, VR_5, VR_6, VR_7, VR_8, VR_9;
  unsigned long VR_10, VR_11, VR_12, VR_13, VR_14, VR_15, V_xPSR;
  unsigned long bogus;

  bogus = 0x0badF00D;

  printf("Register read started\n");

  // initialize temporary variables with bogus value
  VR0   = bogus;
  VR1   = bogus;
  VR2   = bogus;
  VR3   = bogus;
  VR4   = bogus;
  VR5   = bogus;
  VR6   = bogus;
  VR7   = bogus;
  VR8   = bogus;
  VR9   = bogus;
  VR10  = bogus;
  VR11  = bogus;
  VR12  = bogus;
  VR13  = bogus;
  VR14  = bogus;
  VR15  = bogus;
  VxPSR = bogus;

  // read and save current register values
  VR0   = R0;
  VR1   = R1;
  VR2   = R2;
  VR3   = R3;
  VR4   = R4;
  VR5   = R5;
  VR6   = R6;
  VR7   = R7;
  VR8   = R8;
  VR9   = R9;
  VR10  = R10;
  VR11  = R11;
  VR12  = R12;
  VR13  = R13;
  VR14  = R14;
  VR15  = R15;
  VxPSR = xPSR;

  // print read register values
  printf("R0   = 0x%x\n", VR0);
  printf("R1   = 0x%x\n", VR1);
  printf("R2   = 0x%x\n", VR2);
  printf("R3   = 0x%x\n", VR3);
  printf("R4   = 0x%x\n", VR4);
  printf("R5   = 0x%x\n", VR5);
  printf("R6   = 0x%x\n", VR6);
  printf("R7   = 0x%x\n", VR7);
  printf("R8   = 0x%x\n", VR8);
  printf("R9   = 0x%x\n", VR9);
  printf("R10  = 0x%x\n", VR10);
  printf("R11  = 0x%x\n", VR11);
  printf("R12  = 0x%x\n", VR12);
  printf("R13  = 0x%x\n", VR13);
  printf("R14  = 0x%x\n", VR14);
  printf("R15  = 0x%x\n", VR15);
  printf("xPSR = 0x%x\n", VxPSR);

  // check if all values differ from bogus value
  regReadSuccess =
    (VR0   != bogus) &&
    (VR1   != bogus) &&
    (VR2   != bogus) &&
    (VR3   != bogus) &&
    (VR4   != bogus) &&
    (VR5   != bogus) &&
    (VR6   != bogus) &&
    (VR7   != bogus) &&
    (VR8   != bogus) &&
    (VR9   != bogus) &&
    (VR10  != bogus) &&
    (VR11  != bogus) &&
    (VR12  != bogus) &&
    (VR13  != bogus) &&
    (VR14  != bogus) &&
    (VR15  != bogus) &&
    (VxPSR != bogus);

  if (regReadSuccess != 0) {
    printf("Register read passed\n");
  } else {
    printf("Register read failed\n");
    // there is no reason to test write if read fails
    return;
  }

  printf("Register write started\n");

  // fill all registers with bogus value
  R0   = bogus;
  R1   = bogus;
  R2   = bogus;
  R3   = bogus;
  R4   = bogus;
  R5   = bogus;
  R6   = bogus;
  R7   = bogus;
  R8   = bogus;
  R9   = bogus;
  R10  = bogus;
  R11  = bogus;
  R12  = bogus;
  // register R13-R15 and xPSR on hardware do not accept 0x0badf00d, use 0x0 instead
  R13  = 0x0;
  R14  = 0x0;
  R15  = 0x0;
  xPSR = 0x0;

  // read back into another array 
  VR_0   = R0;
  VR_1   = R1;
  VR_2   = R2;
  VR_3   = R3;
  VR_4   = R4;
  VR_5   = R5;
  VR_6   = R6;
  VR_7   = R7;
  VR_8   = R8;
  VR_9   = R9;
  VR_10  = R10;
  VR_11  = R11;
  VR_12  = R12;
  VR_13  = R13;
  VR_14  = R14;
  VR_15  = R15;
  V_xPSR = xPSR;

  // print the values again
  printf("R0   = 0x%x\n", VR_0);
  printf("R1   = 0x%x\n", VR_1);
  printf("R2   = 0x%x\n", VR_2);
  printf("R3   = 0x%x\n", VR_3);
  printf("R4   = 0x%x\n", VR_4);
  printf("R5   = 0x%x\n", VR_5);
  printf("R6   = 0x%x\n", VR_6);
  printf("R7   = 0x%x\n", VR_7);
  printf("R8   = 0x%x\n", VR_8);
  printf("R9   = 0x%x\n", VR_9);
  printf("R10  = 0x%x\n", VR_10);
  printf("R11  = 0x%x\n", VR_11);
  printf("R12  = 0x%x\n", VR_12);
  printf("R13  = 0x%x\n", VR_13);
  printf("R14  = 0x%x\n", VR_14);
  printf("R15  = 0x%x\n", VR_15);
  printf("xPSR = 0x%x\n", V_xPSR);

  // check if new values are bogus
  regWriteSuccess =
    (VR_0   == bogus) &&
    (VR_1   == bogus) &&
    (VR_2   == bogus) &&
    (VR_3   == bogus) &&
    (VR_4   == bogus) &&
    (VR_5   == bogus) &&
    (VR_6   == bogus) &&
    (VR_7   == bogus) &&
    (VR_8   == bogus) &&
    (VR_9   == bogus) &&
    (VR_10  == bogus) &&
    (VR_11  == bogus) &&
    (VR_12  == bogus) &&
    (VR_13  == 0x0)   &&
    (VR_14  == 0x0)   &&
    (VR_15  == 0x0)   && 
    (V_xPSR == 0x0);

  if (regWriteSuccess != 0) {
    printf("Register write passed\n");
  } else {
    printf("Register write failed\n");
  }

  // write saved values back into registers
  // values are required to be written correctly for the rest of the test
  R0   = VR0;
  R1   = VR1;
  R2   = VR2;
  R3   = VR3;
  R4   = VR4;
  R5   = VR5;
  R6   = VR6;
  R7   = VR7;
  R8   = VR8;
  R9   = VR9;
  R10  = VR10;
  R11  = VR11;
  R12  = VR12;
  R13  = VR13;
  R14  = VR14;
  R15  = VR15;
  xPSR = VxPSR;
}


// function to write predefined numbers into test_array1
FUNC void MemWrite(unsigned long address) {
  unsigned int i;
  unsigned int val;

  printf("Memory write started\n");
  val = 0x1000;
  for (i = 0; i < 256; i++) {
    _WWORD(address, val);
    val++;
    address += 4;
  }
  printf("Memory write completed\n");
}

// function to read from test_array2 and check if write and read was successful
FUNC void MemRead(unsigned long address) {
  unsigned int i;
  unsigned int val, v;

  printf("Memory read started\n");
  val = 0x1000;
  memReadSuccess = 1;  // assume it is true
  for (i = 0; i < 256; i++) {
    v = _RWORD(address);
    if (v != val) {
      memReadSuccess = 0;
    }
    val++;
    address += 4;
  }
  if (memReadSuccess != 0) {
    printf("Memory read passed\n");
  } else {
    printf("Memory read failed\n");
  }
}


// check execution breakpoint
FUNC void CheckBpExec(unsigned long address) {
  // PC should be at address and value of bpTestCounter variable should be 9

  if ((R15 == address) && (`bpTestCounter == 9)) {
    bpExecSuccess = 1;
  }
  printf("Execution breakpoint (%d): %d\n", `bpTestCounter, bpExecSuccess);
}

// check breakpoint on read
FUNC void CheckBpRead(int test_state) {
  // PC should be at address

  if (`test_state == test_state) {
    bpReadSuccess = 1;
  }
  printf("Breakpoint on read: %d\n",bpReadSuccess);
}


// check breakpoint on write
FUNC void CheckBpWrite(int test_state) {
  // PC should be at address

  if (`test_state == test_state) {
    bpWriteSuccess = 1;
  }
  printf("Breakpoint on write: %d\n", bpWriteSuccess);
}


// evaluate test
FUNC void EvalSuccess(void) {
  char success;

  success = testSuccess &&
            bpExecSuccess && bpReadSuccess && bpWriteSuccess &&
            regReadSuccess && regWriteSuccess &&
            memReadSuccess && memWriteSuccess;

  exec("LOG >.\\test_results.txt");

  // print test results to log file
  if (success) {
    printf("Test passed!\n");
  } else {
    printf("Test failed!\n");
  }

  printf("\nIndividual test results:\n");

  printf("Execution breakpoint: ");
  if (bpExecSuccess) {
    printf("passed\n");
  } else {
    printf("failed\n");
  }

  printf("Breakpoint on read:   ");
  if (bpReadSuccess) {
    printf("passed\n");
  } else {
    printf("failed\n");
  }

  printf("Breakpoint on write:  ");
  if (bpWriteSuccess) {
    printf("passed\n");
  } else {
    printf("failed\n");
  }
  
  printf("Register read:        ");
  if (regReadSuccess) {
    printf("passed\n");
  } else {
    printf("failed\n");
  }

  printf("Register write:       ");
  if (regWriteSuccess) {
    printf("passed\n");
  } else {
    printf("failed\n");
  }

  printf("Memory read:          ");
  if (memReadSuccess) {
    printf("passed\n");
  } else {
    printf("failed\n");
  }

  printf("Memory write:         ");
  if (memWriteSuccess) {
    printf("passed\n");
  } else {
    printf("failed\n");
  }

  printf("Control flow:         ");
  if (testSuccess) {
    printf("passed\n");
  } else {
    printf("failed\n");
  }

  exec("LOG OFF");
}


LOG >.\\test.log                // start logging

RegReadWrite();                 // check register read/write

BK *                            // remove all existing breakpoints
BS \test.c\43, 9                // set execution breakpoint (hit count=9)
G                               // run to break point
CheckBpExec(\test.c\43);        // check execution breakpoint

BK *                            // remove all existing breakpoints
BS READ test_success            // set a read access breakpoint
G                               // run to break point
CheckBpRead(11);                // check breakpoint on read

BK *                            // remove all existing breakpoints
BS WRITE test_success           // set a write access breakpoint
G                               // run to break point
CheckBpWrite(12);               // check breakpoint on write

BK *                            // remove all existing breakpoints
G,\test.c\61                    // run until line 61
MemWrite(&test_array1[0]);      // test memory write

G,\test.c\69                    // run until line 69
memWriteSuccess = `mem_rw_success;  // application memory test result
MemRead(&test_array2[0]);       // test memory read

T 3                             // step 3 times

`test_state -= 16;              // modify 'test_state' application variable

G,\test.c\88                    // run until line 88

testSuccess = `test_success;    // read 'test_success' application variable

LOG OFF                         // stop logging

EvalSuccess();                  // evaluate test results

EXIT                            // exit debug mode
