|
Обработка математических ошибок в ARM |
|
|
|
Jan 14 2015, 14:36
|
Участник

Группа: Участник
Сообщений: 22
Регистрация: 9-12-14
Пользователь №: 84 046

|
Здравствуйте! Я использую IAR EWARM 6.40 и STM32F407 (с FPU). Нужно останавливать контроллер при возникновении математических ошибок, например, при log(-1). В этом случае я получаю NaN в качестве результата, но по умолчанию никакого вызова функции или exception не происходит. Нету ли для ARM функции, аналогичной стандартной _matherr (math.h)? На других архитектурах она вызывается при следующих ошибках: Код DOMAIN = 1, /* argument domain error -- log (-1) */ SING, /* argument singularity -- pow (0,-2)) */ OVERFLOW, /* overflow range error -- exp (1000) */ UNDERFLOW, /* underflow range error -- exp (-1000) */ TLOSS, /* total loss of significance -- sin(10e70) */ PLOSS, /* partial loss of signif. -- not used */ STACKFAULT /* floating point unit stack overflow */ Через FPU все эти ошибки, как я понял, тоже нельзя определить, например, регистр FPSCR Cortex-M4 среди битов исключений domain error не имеет: Bit 7 IDC: Input denormal cumulative exception bit. Cumulative exception bit for floating-point exception. 1: Indicates that the corresponding exception occurred since 0 was last written to it. Bit 6:5 Reserved Bit 4 IXC: Inexact cumulative exception bit. Cumulative exception bit for floating-point exception. 1: Indicates that the corresponding exception occurred since 0 was last written to it. Bit 3 UFC: Underflow cumulative exception bit. Cumulative exception bit for floating-point exception. 1: Indicates that the corresponding exception occurred since 0 was last written to it. Bit 2 OFC: Overflow cumulative exception bit. Cumulative exception bit for floating-point exception. 1: Indicates that the corresponding exception occurred since 0 was last written to it. Bit 1 DZC: Division by zero cumulative exception bit. Cumulative exception bit for floating-point exception. 1: Indicates that the corresponding exception occurred since 0 was last written to it. Bit 0 IOC: Invalid operation cumulative exception bit. Cumulative exception bit for floating-point exception. 1: Indicates that the corresponding exception occurred since 0 was last written to it.Мне даже переполнение при результате операции 0.Infinite не удалось зафиксировать в этих флагах. Может, что-то не так сделал, но вроде бы в любом случае ситуацию log(-1) ни один из этих флагов не должен определять? Заранее спасибо.
|
|
|
|
|
Jan 14 2015, 17:02
|
Участник

Группа: Участник
Сообщений: 22
Регистрация: 9-12-14
Пользователь №: 84 046

|
А можно поподробнее, что за errno? Отмечу еще раз, что мне нужна не просто проверка на ошибки (не делать же ее после каждой операции), а что-то вроде исключения, если результат математической операции = NaN, Inf, etc.
|
|
|
|
|
Jan 14 2015, 19:17
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(cyrax0 @ Jan 14 2015, 20:02)  А можно поподробнее, что за errno? Это стандарт языка Си. Читайте учебники. Цитата(cyrax0 @ Jan 14 2015, 20:02)  Отмечу еще раз, что мне нужна не просто проверка на ошибки (не делать же ее после каждой операции), а что-то вроде исключения, если результат математической операции = NaN, Inf, etc. Хотеть не вредно. Я не в курсе, но не удивлюсь, если в яре для STM32F4 этого нет. Так что да, делайте проверку после и/или перед каждой операцией. На самом деле это совсем не сложно.
|
|
|
|
|
Jan 14 2015, 19:43
|
Участник

Группа: Участник
Сообщений: 22
Регистрация: 9-12-14
Пользователь №: 84 046

|
Цитата Насколько я помню, Вам нужно переопределить хандлер matherr() который должен отвечать за обработку ошибки. Хотелось бы, только в моей среде в math.h эта функция не описана, как и ее аргумент exception, поэтому переопределять нечего  . Цитата Так что да, делайте проверку после и/или перед каждой операцией. На самом деле это совсем не сложно. Если бы этот вариант подходил, я бы здесь не писал.
Сообщение отредактировал cyrax0 - Jan 14 2015, 19:45
|
|
|
|
|
Jan 14 2015, 22:42
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(cyrax0 @ Jan 14 2015, 20:02)  А можно поподробнее, что за errno? Отмечу еще раз, что мне нужна не просто проверка на ошибки (не делать же ее после каждой операции), а что-то вроде исключения, если результат математической операции = NaN, Inf, etc. А чем плоха проверка результата? Неприятие к этой процедуре можно было еще объяснить, если бы STM32F вычислял логарифмы аппаратно, но ведь этого-то нет! Он способен лишь на то, чтобы выполнять с плавающей точкой 4 арифметрических действия. Ну, еще два числа умеет сравнивать. Но ведь функций-то вычислять аппаратно он не умеет! А, стало быть, все эти логарифмы, экспоненты и тригонометрия - галимая эмуляция  . А раз так, то вы крайне незначительно замедлите вычисление логарифма, если решитесь на проверку результата. Опять же всегда можно создать свою функцию типа my_log(), которая вызывает нативную функцию log(), проверяя после нее результат. Учитывая эти обстоятельства, предлагаю вам просто заглянуть в исходники и поглядеть, как там реализована функция log(). Я сама заглядывала (только у меня EWARM не 6.40, а 7.30), но нашла там лишь присвоение кода ошибки глобальной переменной errno. Хотя в хидере xmath.h есть что-то похожее на возможность установки собственного хэндлера для реакции на математические ошибки. Глубже не разбиралась.
|
|
|
|
|
Jan 15 2015, 05:26
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(cyrax0 @ Jan 15 2015, 01:43)  Если бы этот вариант подходил, я бы здесь не писал. Ну Вам же уже подсказали, что при ошибках, состояние ошибки сохраняется в errno (я сам не уверен что для всех желаемых Вами случаев). Если Вам нужно именно прерывание, в чем проблема? В Вашем STM32F407 отсутствует MPU? Через MPU защищаете некую область памяти от записи, линкуете туда errno и получаете прерывание MPU каждый раз при попытке записи в errno. Фсё. В особо извращённом случае, можно errno смаппировать на регистр данных какой-нить неиспользуемой периферии, например - буфер передаваемых данных SPI и разрешить прерывание на завершение передачи от этой периферии. Цитата(_Pasha @ Jan 15 2015, 10:32)  Собственно можно пойти далеко в обход: написать нужный функционал на плюсах, но при этом переопределить оператор = Ну да, и как прикажете быть например с: a = log(-1) + 1 ? Если идти в обход плюсами, то нужно описать errno как класс, перегрузить оператор присвоения ему и внутрь этого перегруженного оператора вставить вызов обработчика ошибки. Но это возможно только если не используется предкомпилённых математических библиотек, а все они компилятся в исходниках с проектом.
|
|
|
|
|
Jan 15 2015, 07:59
|
Участник

Группа: Участник
Сообщений: 22
Регистрация: 9-12-14
Пользователь №: 84 046

|
Цитата(Xenia @ Jan 15 2015, 02:42)  А чем плоха проверка результата? Неприятие к этой процедуре можно было еще объяснить, если бы STM32F вычислял логарифмы аппаратно, но ведь этого-то нет! У нас математические алгоритмы пишут разные сотрудники, и кто-то может забыть проверить результат. Поэтому нужно проверять такие ошибки на системном уровне. Цитата Хотя в хидере xmath.h есть что-то похожее на возможность установки собственного хэндлера для реакции на математические ошибки. Глубже не разбиралась. Хорошая мысль, но похоже эта _Feraise не вызывается автоматически, по крайней мере брекпоинт на нее не ставится. Либо у меня не подключена DLib, не знаю, как это делается. Цитата Через MPU защищаете некую область памяти от записи, линкуете туда errno и получаете прерывание MPU каждый раз при попытке записи в errno. Прикольная идея, спасибо. Под линковкой понимается приделать к errno: Код @ какой-то_адрес и как это сделать, модифицировать стандартный код?
|
|
|
|
|
Jan 15 2015, 08:20
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(cyrax0 @ Jan 15 2015, 13:59)  Прикольная идея, спасибо. Под линковкой понимается приделать к errno: Код @ какой-то_адрес и как это сделать, модифицировать стандартный код? Если errno не вынесен в отдельную секцию, которую можно отдельно линковать, то придётся править исходники - вынести его в отдельную секцию. Если вынесен (или в секции, где он находится, остальные переменные используются как read-only) - то библиотеку править не надо, только свой icf-файл. Посмотрите свой map-файл - в какой секции находится errno.
|
|
|
|
|
Jan 15 2015, 08:35
|
Участник

Группа: Участник
Сообщений: 22
Регистрация: 9-12-14
Пользователь №: 84 046

|
Не очень понимаю, с какой стати errno может быть вынесен в отдельную секцию. У меня стандартные секции ROM, RAM, CMMRAM. В map-файле errno, скорее всего, вот он: __iar_Errno 0x20008bdc 0x4 Data Gb errno.o [3] Находится в стандартной секции RAM.
Если править библиотеки, то проще уж наверное в math.h добавить проверку аргументов, чтобы не заморачиваться с MPU? С ним я еще не работал.
|
|
|
|
|
Jan 15 2015, 09:08
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(cyrax0 @ Jan 15 2015, 10:59)  У нас математические алгоритмы пишут разные сотрудники, и кто-то может забыть проверить результат. Поэтому нужно проверять такие ошибки на системном уровне. Уровни разные бывают. Совсем не сложно обернуть код сотрудников-вредителей макросами, тогда функции будут с проверками на ошибки и вообще с чем угодно. А если привлечь Си++, то можно и операторы переопределить. Цитата(jcxz @ Jan 15 2015, 11:20)  Если errno не вынесен в отдельную секцию, которую можно отдельно линковать, то придётся править исходники - вынести его в отдельную секцию. Не факт. Вроде бы линкеры позволяют размещать данные в том числе по имени объектного файла. Нужно только вычислить, в каком файле определяется errno. Кроме того, можно обработать файл библиотеки ELF-тулзами и подменить название секции.
|
|
|
|
|
Jan 15 2015, 09:25
|
Участник

Группа: Участник
Сообщений: 22
Регистрация: 9-12-14
Пользователь №: 84 046

|
Цитата А если привлечь Си++, то можно и операторы переопределить. В итоге так, скорее всего, и придется сделать. Минус в том, что вместо math.h нужно будет подключать условный safemath.h, что с учетом сотрудников-вредителей не факт, что будет выполняться. Не проверять же мне потом все их программы. Цитата Вроде бы линкеры позволяют размещать данные в том числе по имени объектного файла. Нужно только вычислить, в каком файле определяется errno. Ну похоже, что файл я определил - это errno.c. Если его объектный файл действительно можно разместить в какой-то секции средствами icf или еще какими, было бы круто.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|