Процессор ATMEGA2560
С++, максимальная оптимизация по скорости.
Полный текст приведен во вложении, там же lst - файл.
Проблема в функции tpzBINtoBCD, в следующем ее фрагменте:
Код
while(true)
{
bool isLim = res.loc == bcd;
...
}
{
bool isLim = res.loc == bcd;
...
}
res.loc и bcd - это объекты типа TBCDLocation (фактически - "указатель на тетраду байта", т.е. указатель на байт + признак старший\младший). Оператор == для них перегружен так:
Код
INLINE bool TBCDLocation::operator==(const TBCDLocation& b)
{
return buf==b.buf && isFH==b.isFH;
}
{
return buf==b.buf && isFH==b.isFH;
}
Впрочем, если "проинлайнить" его руками, т.е. написать bool isLim = res.loc.buf == bcd.buf && res.loc.isFH==bcd.isFH - ничего не изменится.
Так вот, этот кусочек компилится так:
Код
250: bool isLim = res.loc == bcd;
+0000011A: 1502 CP R16,R2 Compare
+0000011B: 0513 CPC R17,R3 Compare with carry
+0000011C: F429 BRNE PC+0x06 Branch if not equal
+0000011D: 2F12 MOV R17,R18 Copy register <<<<<
+0000011E: 1514 CP R17,R4 Compare
+0000011F: F411 BRNE PC+0x03 Branch if not equal
+00000120: E0E1 LDI R30,0x01 Load immediate
+00000121: C001 RJMP PC+0x0002 Relative jump
+00000122: E0E0 LDI R30,0x00 Load immediate
+00000123: 2E5E MOV R5,R30 Copy register
+0000011A: 1502 CP R16,R2 Compare
+0000011B: 0513 CPC R17,R3 Compare with carry
+0000011C: F429 BRNE PC+0x06 Branch if not equal
+0000011D: 2F12 MOV R17,R18 Copy register <<<<<
+0000011E: 1514 CP R17,R4 Compare
+0000011F: F411 BRNE PC+0x03 Branch if not equal
+00000120: E0E1 LDI R30,0x01 Load immediate
+00000121: C001 RJMP PC+0x0002 Relative jump
+00000122: E0E0 LDI R30,0x00 Load immediate
+00000123: 2E5E MOV R5,R30 Copy register
res.loc лежит в трех регистрах: 17,16 - указатель на байт и 18 - признак старший\младший.
В указанной строчке 17 регистр перетирается 18-м и больше нигде не восстанавливается. Соответственно, при следующем обращении к res.loc получается бяка.
Если переписать функцию tpzBINtoBCD так, чтобы loc и isOverflow лежали в отдельных переменных и "собирались вместе" перед return, все прекрасно работает (этот вариант функции закомментирован в прилагаемом файле).
При этом получается такой ассемблерный код:
Код
313: bool isLim = msBCD == bcd;
+00000112: 1768 CP R22,R24 Compare
+00000113: 0779 CPC R23,R25 Compare with carry
+00000114: F421 BRNE PC+0x05 Branch if not equal
+00000115: 16BB CP R11,R27 Compare
+00000116: F411 BRNE PC+0x03 Branch if not equal
+00000117: E0E1 LDI R30,0x01 Load immediate
+00000118: C001 RJMP PC+0x0002 Relative jump
+00000119: E0E0 LDI R30,0x00 Load immediate
+0000011A: 2E3E MOV R3,R30 Copy register
+00000112: 1768 CP R22,R24 Compare
+00000113: 0779 CPC R23,R25 Compare with carry
+00000114: F421 BRNE PC+0x05 Branch if not equal
+00000115: 16BB CP R11,R27 Compare
+00000116: F411 BRNE PC+0x03 Branch if not equal
+00000117: E0E1 LDI R30,0x01 Load immediate
+00000118: C001 RJMP PC+0x0002 Relative jump
+00000119: E0E0 LDI R30,0x00 Load immediate
+0000011A: 2E3E MOV R3,R30 Copy register
С точностью до номеров регистров все так же, как и выше, но нехорошего MOV уже нет.
Без оптимизации все работает и в первом варианте.
PS. программка тестовая, соответственно прерывания не включались.
PPS. пробовал скомпилировать под ATMEGA128 - проблема осталась.