Exceptions

Let us know what you think about the chipKIT, and what can be done to make it better!
Post Reply
WestfW
Posts: 148
Joined: Wed May 25, 2011 12:17 am

Exceptions

Post by WestfW » Wed Aug 10, 2011 12:41 am

The PIC32 has several exceptions not present on simpler CPUs (bus error and address error particularly.) The current error handler goes into an infinite loop (intentionally) on these exceptions, which means that relatively minor pointer issues can cause mysterious "hangs."

Code: Select all

const char * foo = "testing";  // put string in flash
pgm_read_word(foo+1);  // attempt "unaligned access"
Can the default exception handler be replaced with something more informative? I tried the obvious hack of copying it into my sketch and adding Serial.print (since I'm using serial anyway), but it didn't seem to work; I'm not sure what state the CPU is in, or what state the arduino functions NEED the CPU to be in, to do stuff" during exceptions...

Code: Select all

static unsigned int _epc_code;
static unsigned int _excep_addr;

void _general_exception_handler(void)
{
	asm volatile("mfc0 %0,$13" : "=r" (_epc_code));
	asm volatile("mfc0 %0,$14" : "=r" (_excep_addr));

	_epc_code = (_epc_code & 0x0000007C) >> 2;
  Serial.print("Exception: ");
  Serial.print(_epc_code, HEX);
  Serial.print(" @ ");
  Serial.println(_excep_addr, HEX);
	while (1)
	{
		// Examine _excep_code to identify the type of exception
		// Examine _excep_addr to find the address that caused the exception
	}
}

whoover
Posts: 41
Joined: Wed Jul 27, 2011 11:43 pm

Re: Exceptions

Post by whoover » Sat Aug 13, 2011 1:08 am

It would be nice to standardize this... I opened a feature request for this (along with fix that allows try/catch blocks):

Here's the enhancement...

exceptions.h

Code: Select all

#include <setjmp.h>

#include "WProgram.h"
#include "wiring_private.h"

#define TRY if(!(_excep_code = setjmp(_excep_buf)))
#define CATCH else 
#define EXCEPTION_NUM_EXCEPTIONS 14

// declared static in case exception condition would prevent
// auto variable being created
static enum {
	EXCEP_IRQ = 0,			// interrupt
	EXCEP_AdEL = 4,			// address error exception (load or ifetch)
	EXCEP_AdES,				// address error exception (store)
	EXCEP_IBE,				// bus error (ifetch)
	EXCEP_DBE,				// bus error (load/store)
	EXCEP_Sys,				// syscall
	EXCEP_Bp,				// breakpoint
	EXCEP_RI,				// reserved instruction
	EXCEP_CpU,				// coprocessor unusable
	EXCEP_Overflow,			// arithmetic overflow
	EXCEP_Trap,				// trap (possible divide by zero)
	EXCEP_IS1 = 16,			// implementation specfic 1
	EXCEP_CEU,				// CorExtend Unuseable
	EXCEP_C2E				// coprocessor 2
} _excep_codes;
static jmp_buf _excep_buf;
static unsigned int _excep_code; // exception code corresponds to _excep_codes
static unsigned int _excep_addr; // exception address
static unsigned int _excep_stat; // status register


#ifdef __cplusplus
extern "C" {
#endif
void _general_exception_handler(unsigned cause, unsigned status) {
  _excep_code = (cause & 0x0000007C) >> 2;
  _excep_stat = status;
  _excep_addr = __builtin_mfc0(_CP0_EPC, _CP0_EPC_SELECT);
  if ((cause & 0x80000000) != 0)
    _excep_addr += 4;
  longjmp(_excep_buf, _excep_code);
}
#ifdef __cplusplus
}
#endif
Here's an example...

Code: Select all

#include <exceptions.h>

#define NUMERATOR 777
#define TEST_COUNT 3

char testC;
char *c1 = &testC;
char *c2;
char str[] = {"TEST STRING"};
int denominator = TEST_COUNT;

void setup() {
  Serial.begin(115200);
  testC = 48;
  Serial.println("============ STARTING TESTS ============");
}

void loop() {
  if (denominator >= 0) {
    TRY {
      Serial.print("============ Testing trap exception... denominator: ");
      Serial.print(denominator);
      int testTrap = NUMERATOR / denominator;
      Serial.print(" Result: ");
      Serial.println(testTrap);
      Serial.println("Successful division... Testing address exception...");
      if (denominator != 2) {
        memcpy(c1, str, sizeof(str));
        Serial.println(c1);
      } else {
        memcpy(c2, str, sizeof(str));
        Serial.println(c2);
        Serial.println("!!!!!!!!!!! SHOULD NEVER PRINT !!!!!!!!!!!");
      }
      Serial.println("============ No exceptions in this loop... moving on");
    } CATCH {
      Serial.println();
      Serial.println("#######################################################");
      if (_excep_code == EXCEP_Trap) {
        Serial.print("Trap exception: ");
      } else if (_excep_code == EXCEP_DBE) {
        Serial.print("Bus error (load/store) exception: ");
      } else {
        Serial.print("Unknown exception: ");
      }
      Serial.print(_excep_code);
      Serial.println();
      Serial.println("#######################################################");
    }
    denominator--;
  } else if (denominator == -1) {
    Serial.print("============ ALL TESTS COMPLETE ============");
    denominator--;
  }
}
... and the example output:

Code: Select all

============ STARTING TESTS ============
============ Testing trap exception... denominator: 3 Result: 259
Successful division... Testing address exception...
TEST STRING
============ No exceptions in this loop... moving on 
============ Testing trap exception... denominator: 2 Result: 388
Successful division... Testing address exception...

#######################################################
Bus error (load/store) exception: 7
#######################################################
============ Testing trap exception... denominator: 1 Result: 777
Successful division... Testing address exception...
TEST STRING
============ No exceptions in this loop... moving on 
============ Testing trap exception... denominator: 0
#######################################################
Trap exception: 13
#######################################################
============ ALL TESTS COMPLETE ============

jumpin_jack
Posts: 22
Joined: Wed Jun 15, 2011 7:04 am

Re: Exceptions

Post by jumpin_jack » Sat Aug 13, 2011 9:45 pm

Interesting! It looks like you guys have both put a lot of thought into general exception handling. Do you guys know of any tricks for recovering from an address error due to pointer misalignment? Obviously, the best way is to identify potential problems in my code and fix them, but is there a way to write a general exception handler to handle cases that I may miss?

whoover
Posts: 41
Joined: Wed Jul 27, 2011 11:43 pm

Re: Exceptions

Post by whoover » Sat Aug 13, 2011 11:47 pm

The exeptions.h will recover from pointer errors. Put your suspect code within the TRY block and your recovery code in the CATCH block.

username
Posts: 10
Joined: Mon Jan 16, 2012 9:53 pm

Re: Exceptions

Post by username » Mon Jan 16, 2012 10:12 pm

I just posted ( forum/viewtopic.php?f=19&t=775 ) seconding the idea that exceptions.h become part of the package. Thanks a lot!

-Scott

whoover
Posts: 41
Joined: Wed Jul 27, 2011 11:43 pm

Re: Exceptions

Post by whoover » Mon Feb 06, 2012 4:52 pm

There may be some legitimate reasons why they don't want to add it to the standard package that I'm just not aware of. If you would like to comment of the closed issue it can be found here.

shivensys
Posts: 6
Joined: Tue Oct 13, 2015 2:57 pm

Re: Exceptions

Post by shivensys » Sun Apr 02, 2017 4:26 pm

Hi, I realize that this is a really old thread so apologies in advance.... I am trying to track down a mysterious hang.

i am running Chipkit core 1.3.1 building on Arduino IDE 1.6.12 on a CMOD board.

When I run the code posted earlier I get the following output:

Code: Select all

============ STARTING TESTS ============
============ Testing trap exception... denominator: 3 Result: 259
Successful division... Testing address exception...
TEST STRING
============ No exceptions in this loop... moving on
============ Testing trap exception... denominator: 2 Result: 388
Successful division... Testing address exception...
so it never seems to get to the catch block after executing this line.

memcpy(c2, str, sizeof(str));

Any thoughts?

Thanks in advance, Patrick

Post Reply