|
|
  |
Ошибка IAR или чтото еще? |
|
|
|
Dec 20 2006, 13:33
|
Местный
  
Группа: Свой
Сообщений: 235
Регистрация: 9-02-05
Пользователь №: 2 526

|
Цитата(Oldring @ Dec 19 2006, 19:50)  int расширяется до long до умножения. Потом должна вызываться стандартная библиотеченая функция перемножения длинных целых. Потом код самой функции должен скопировать результат из регистров в глобальную переменную. Или не скопировать. Моя уверенность, что это проблема не рассчета, а интерпретации результата, укрепляется. Пожалуй, автору пора научиться разбираться в листингах, порождаемых компилятором. 1. Для тех кто умеет разбираться в листингах - подскажите пожалуйста, как правильно интерпретировать неправильный результат? Если в результате вычислений у меня получается неверное значение, оно же выводится на дисплей, мне придется объяснить пользователям как правильно интерпретировать такой результат который должен быть в пределах от 0,7 до 20, а его зашкаливает за 50 000!!! 2. К сожалению, я не могу выложить всеь код, т.к. это больше 10 000 строк. Одно могу сказать, что данный блок вычислений работал нормально, пока вычисления производились с глобальной переменной. Потом, для экономии памяти я сделал вычисления с локальной. Вот тут то все и началось. Когда компиллятор поместил эту локальную переменную в регистры. Как только я заставил разместить ее в памяти, все заработало.
|
|
|
|
|
Dec 20 2006, 15:06
|
Местный
  
Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219

|
Цитата(Oldring @ Dec 18 2006, 19:08)  Цитата(Dog Pawlowa @ Dec 18 2006, 18:48)  Тогда мы по разному понимает слово "правильно". Я включал в это понятие учет возможности переполнения и максимальной независимости от констант. А Вы - нет?  Дело в том, что Билл написал просто чепуху про "естественную" свертку целочисленных констант перед вычислением выражения, а Вашего предложения я вообще почему-то не вижу в истории переписки. Так как так и не была озвучена информация про диапазоны операндов, хотелось бы все-таки увидеть, что именно Вы считаете "правильной" записью данного выражения, если это понятие "правильности" отличется от формальной правильности. Хотелось бы также узнать Ваше мнение по следующему вопросу: существует ли с точки зрения стандарта языка программирования С какая-либо разница между выражениями Код a * b * c / d и Код ((a * b) * c) / d ? И, кстати, считаете ли Вы что компилятор имеет право выражение Код a = b * 2 / 3; заменить на Код a = 0; ? Ну, я не думаю, что я написал чепуху. Дело в том, что операция умножения коммутативная операция, а операции умножения и деления имеют одинаковый уровень приоритета. Если взять Ваш пример, то в общем случае совершенно не важно в каком порядке производить вычисления, результат будет один и тот же. То есть Код b * c * d / e = (b * c * d) / e = b * c * (d / e) Проблема возникает именно потому, что появляются типы данных. Компилятор всегда производит перегруппировку выражения таким образом, чтобы код, вычисляющий данное выражения, был минимальным. Если в выражении имеются константы, то компилятор непременно выполнит все возможные вычисления с константами в соответствии с правилами арифметики. По умолчанию все константы имеют тип int, и если их тип не указан особо, то результат также будет иметь тип int. Естественно, что результат вычисления константного выражения может быть неверным, если программист специально об этом не позаботится. В данном случае, операнды d и e будут целыми константами и компилятор обязательно вычислит результат d/e, хотя он в общем случае будет некорректным. Если мы хотим получить корректный результат, то мы должны задать требуемый порядок вычислений явным образом с помощью скобок. Можно также изменить тип констант по умочанию с использованием соответствующих суффиксов.
|
|
|
|
Guest_Serg79_*
|
Dec 20 2006, 15:22
|
Guests

|
Sergio66 Ты сдесь воду то не баламуть а приведи нормальный пример своей функции которая у тебя не правельно считает. Что то типа токого: Код int my_bad_func(int a, int b, int c) { return a * b / c; } А то несешь какую то ахинею типа: Цитата Вот такой код: unsigned long int temp = INJ_time * data_temp_struct.FREQ * PRODUCTIVITY / 20000; тип INJ_time - unsigned long int. Эта переменная локальная. PRODUCTIVITY - константа Так вот, переменная temp размещалась компилятором в регистрах и все было плохо
Теперь я переменную temp сделал членом локальной структуры data_temp_struct Т.о. она стала размещаться в памяти а не в регистрах. Вот с этого все и заработало. data_temp_struct.temp = INJ_time * data_temp_struct.FREQ * PRODUCTIVITY / 20000; Если нашел ошибку то локалезуй ее. И напиши маленькую функцию которая позваляет ее воспроизвести. А разговоры типа: в регистре не правильно а в памяти правельно, бред сивой кабылы.Может у Тебя там полнейший бред написан, а Ты пытаешся все на компилятор свалить.
|
|
|
|
|
Dec 20 2006, 16:15
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Пока Sergio66 молчит, задам я свой вопрос, потому как проблема аналогичная. Имеем вот такой код: Код .....................
/* время возникновения импульса */ typedef struct { UINT32 Time; /* время возникновения импульса */ UCHAR TIFR_reg; /* сохраненные значения регистра флагов TIFR */
} Pulse_Time_t; ...................................
/***************************************************************************** Коррекция значения времени Корректирует время в зависимости от значения TIFR и младшего слова (ТС1) ******************************************************************************/ UINT32 PULSE_SENS_CorrectTime(Pulse_Time_t *Pulse) { UINT32 time = Pulse->Time; /* корректируем результат по состоянию флага OCF1A на момент считывания значений времени */ if(Pulse->TIFR_reg & (1 << OCF1A)) { time += 0x00010000; /* если флаг установлен, инкрементируем значение милисекунд */ if(SYSTIMER_COMPARE_VAL == LOWORD(time)) /* если значение счетчика равно константе в регистре сравнения, то мы это значение должны обнулить */ time &= 0xffff0000; }
/* преобразуем в мкс (закомментированный код НЕ РАБОТАЕТ )*/ /* Pulse->Time = ((UINT32)(LOWORD(time) >> 1) + (UINT32)(HIWORD(time)) * 1000); return 0; */
return ((UINT32)(LOWORD(time) >> 1) + (UINT32)(HIWORD(time)) * 1000); } Кто нибудь может объяснить, почему, когда я возвращаю результат преобразования в микросекунды в структуру Pulse_Time_t, результат в итоге НЕ правильный. Если возвращаю результа из функции - результат Правильный??? 2 Serg79 - научитесь изъясняться по-русски, а то Ваше чревовещание больше всего подходит под термин "Бред сивой кобылы" как по грамматическим ошибкам, так и по смыслу…
Бесплатный совет – пишите сообщения сначала в MS Word – по крайней мере, можно будет подумать, что Вы учили чего-то в школе хотя бы с соседом по парте, а свой букварь курили дома…
--------------------
|
|
|
|
|
Dec 20 2006, 16:30
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(_Bill @ Dec 20 2006, 15:06)  Код b * c * d / e = (b * c * d) / e = b * c * (d / e) Естественно, что результат вычисления константного выражения может быть неверным, если программист специально об этом не позаботится. В данном случае, операнды d и e будут целыми константами и компилятор обязательно вычислит результат d/e, хотя он в общем случае будет некорректным. Чушь. Домыслы. P.S. Хотел приложить текст стандарта - почему-то не добавился... Цитата(prottoss @ Dec 20 2006, 16:15)  НЕ правильный.
Бесплатный совет – пишите сообщения сначала в [/b]MS Word – по крайней мере, можно будет подумать, что Вы учили чего-то в школе хотя бы с соседом по парте, а свой букварь курили дома…
--------------------
Пишите в личку.
|
|
|
|
|
Dec 20 2006, 17:54
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(prottoss @ Dec 20 2006, 17:32)  Мда... Умные речи о значимости скобок не помогли... Финал - стоны зрителей, аншлаг, занавес закрывается Уличили А дизассемблер привести сложно? Или мы должны все бросить и посвятить вечер изучению ? Сами то смотрели?
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Dec 20 2006, 18:05
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(Dog Pawlowa @ Dec 20 2006, 21:54)  А дизассемблер привести сложно? Или мы должны все бросить и посвятить вечер изучению ? Сами то смотрели? Я смотрел, и не раз, пожалуйста, c чуйством глубокохо удовлетворения привожу листинг, смотрите: Код 218 /***************************************************************************** 219 Коррекция значения времени 220 Корректирует время в зависимости от значения TIFR и младшего слова (ТС1) 221 *************************************************************************** ***/ 222 //UINT32 PULSE_SENS_CorrectTime(Pulse_Time_t *Pulse)
\ In segment CODE, align 2, keep-with-next 223 void PULSE_SENS_CorrectTime(Pulse_Time_t *Pulse) \ PULSE_SENS_CorrectTime: 224 { \ 00000000 2F79 MOV R23, R25 \ 00000002 2E28 MOV R2, R24 \ 00000004 01F8 MOVW R31:R30, R17:R16 225 UINT32 time = Pulse->Time; \ 00000006 8100 LD R16, Z \ 00000008 8111 LDD R17, Z+1 \ 0000000A 8122 LDD R18, Z+2 \ 0000000C 8133 LDD R19, Z+3 226 227 /* корректируем результат по состоянию флага OCF1A 228 на момент считывания значений времени */ 229 if(Pulse->TIFR_reg & (1 << OCF1A)) \ 0000000E 8144 LDD R20, Z+4 \ 00000010 FF44 SBRS R20, 4 \ 00000012 C00A RJMP ??PULSE_SENS_CorrectTime_0 230 { 231 time += 0x00010000; /* если флаг установлен, инкрементируем значение милисекунд */ \ 00000014 5000 SUBI R16, 0 \ 00000016 4010 SBCI R17, 0 \ 00000018 4F2F SBCI R18, 255 \ 0000001A 4F3F SBCI R19, 255 232 if(SYSTIMER_COMPARE_VAL == LOWORD(time)) \ 0000001C 2F51 MOV R21, R17 \ 0000001E 3C0F CPI R16, 207 \ 00000020 4057 SBCI R21, 7 \ 00000022 F411 BRNE ??PULSE_SENS_CorrectTime_0 233 234 /* если значение счетчика равно константе в регистре сравнения, то мы это 235 значение должны обнулить */ 236 time &= 0xffff0000; \ 00000024 E000 LDI R16, 0 \ 00000026 E010 LDI R17, 0 237 } 238 239 /* преобразуем в мкс */ 240 Pulse->Time = ((UINT32)(LOWORD(time) >> 1) + (UINT32)(HIWORD(time)) * 1000); \ ??PULSE_SENS_CorrectTime_0: \ 00000028 01A8 MOVW R21:R20, R17:R16 \ 0000002A 9556 LSR R21 \ 0000002C 9547 ROR R20 \ 0000002E E060 LDI R22, 0 \ 00000030 0189 MOVW R17:R16, R19:R18 \ 00000032 01C8 MOVW R25:R24, R17:R16 \ 00000034 EE08 LDI R16, 232 \ 00000036 E013 LDI R17, 3 \ 00000038 E020 LDI R18, 0 \ 0000003A E030 LDI R19, 0 \ 0000003C 9F19 MUL R17, R25 \ 0000003E 0D20 ADD R18, R0 \ 00000040 1D31 ADC R19, R1 \ 00000042 9F18 MUL R17, R24 \ 00000044 2D10 MOV R17, R0 \ 00000046 0D21 ADD R18, R1 \ 00000048 1F36 ADC R19, R22 \ 0000004A 9F09 MUL R16, R25 \ 0000004C 0D10 ADD R17, R0 \ 0000004E 1D21 ADC R18, R1 \ 00000050 1F36 ADC R19, R22 \ 00000052 9F08 MUL R16, R24 \ 00000054 2D00 MOV R16, R0 \ 00000056 0D11 ADD R17, R1 \ 00000058 1F26 ADC R18, R22 \ 0000005A 1F36 ADC R19, R22 \ 0000005C 0F04 ADD R16, R20 \ 0000005E 1F15 ADC R17, R21 \ 00000060 1F26 ADC R18, R22 \ 00000062 1F36 ADC R19, R22 \ 00000064 8300 ST Z, R16 \ 00000066 8311 STD Z+1, R17 \ 00000068 8322 STD Z+2, R18 \ 0000006A 8333 STD Z+3, R19 241 //return ((UINT32)(LOWORD(time) >> 1) + (UINT32)(HIWORD(time)) * 1000); 242 } \ 0000006C 2D82 MOV R24, R2 \ 0000006E 2F97 MOV R25, R23 \ 00000070 9508 RET Что бы не напрягать попусту Ваши глаза и мозговые извилины, сделаю два замечания: В начале кода компилятор послушно берет адрес и формирует переменную time из регистров r16-19 Код 00000000 2F79 MOV R23, R25 \ 00000002 2E28 MOV R2, R24 \ 00000004 01F8 MOVW R31:R30, R17:R16 225 UINT32 time = Pulse->Time; \ 00000006 8100 LD R16, Z \ 00000008 8111 LDD R17, Z+1 \ 0000000A 8122 LDD R18, Z+2 \ 0000000C 8133 LDD R19, Z+3 В конце, так же послушно запихивает то, что пережевал обратно: Код \ 00000064 8300 ST Z, R16 \ 00000066 8311 STD Z+1, R17 \ 00000068 8322 STD Z+2, R18 \ 0000006A 8333 STD Z+3, R19 Что и как он там насчитал, меня мало интересует, но факт остается фактом, насчитал он не правильно
--------------------
|
|
|
|
|
Dec 20 2006, 19:12
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(Oldring @ Dec 20 2006, 22:57)  Чтобы не напрягать попусту наши извилины скомпилируйте теперь второй вариант и найдите отличия. И, кстати, это так ведь задумано - при каждом вызове функции портить Pulse->Time? Именно так и задуманно, с целью сэконмить несколько десятков байт памяти программ и несколько сотен наносекунд процессорного времени. Винигрет из команд MUL, MOV, ADD, ADC абсолютно одинаковый, за исключением того, что поменены функции регистровых пар R21:20 и R25:24 в "правильно работающем варианте". Возможно ошибка в этом, а возможно еще в чем то. НО, простите, нахрена я пишу на Си, чтобы потом перелопачивать этот же код на ассемблере? Думаю, что у Sergio66 аналогичная проблема. Возможно, это связанно именно с типом LONG... Кстати, я пользуюсь IAR v.4.10B а Sergio66 IAR v.4.20.
--------------------
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|