Fehler bei Single Multiplikation mit kleinen Werten
Bug Report:
Betrifft Bascom nach dem letzten Update auf 2.0.7.7
Hier liegt ein Fehler bei der Berechnung von Single-Variablen vor. Wenn man eine Variable nur oft genug mit 0.9 multipliziert, wird die wie erwartet 0. Wenn man weiter macht wird sie irgendwann NAN und dann irgendwann irgendwas ganz großes. Hier ein Beispielprogrämmchen mit dem der Fehler auf einem xmega nachvollzogen werden kann.
Code:
$regfile = "xm256a3def.dat"
$crystal = 32000000 '32MHz
$hwstack = 256
$swstack = 256
$framesize = 256
$lib "xmega.lib"
$external _xmegafix_clear
$external _xmegafix_rol_r1014
Config Portf.3 = Output
Config Portf.2 = Input
Dim A As Single
Dim Loopcount As Long
Config Osc = Enabled , 32mhzosc = Enabled
Config Sysclock = 32mhz , Prescalea = 1 , Prescalebc = 1_1
Config Com7 = 9600 , Mode = Asynchroneous , Parity = None , Stopbits = 1 , Databits = 8
Open "COM7:" For Binary As #1
A = 10
Wait 5
Do
Incr Loopcount
A = A * 0.9
Print #1 , Loopcount ; " " ; A
Loop
Der Fehler tritt nach 853 Durchgängen (NAN) und nach 1485 Durchgängen (3924871168.0) auf. Ändert man die Zeile A=A*0.9 in
A=A*9
A=A/10
funktioniert alles einwandfrei. Es scheint, daß der Fehler nur bei Multiplikationen von sehr kleinen Werten auftritt. Ob es noch andere Fälle gibt ist mir zumindest nicht bekannt. Bei Bascom 2.0.7.6 tritt der Fehler nicht auf.
nosave Interrupt-Service-Routine Fallstricke
BASCOM-AVR Demo Version 2.0.7.5 auf ATTiny25
Es ist kein unmittelbarer Fehler, den ich in BASCOM-AVR Version 2.0.7.5 festgestellt habe, aber doch ein Verhalten, daß eine intensive Fehlersuche zur Folge hatte.
Zum schnellen Datenaustausch hatte ich eine Interruptserviceroutine in Assembler mit auch noch einem timingkritischen Abschnitt darin ohne Sichern der Prozessorregister (bzw manuellem Sichern, Stichwort: nosave) geschrieben.
Da es zu Problemen kam, nahm ich das Programm mittels Disassembler unter die Lupe und fand heraus, daß BASCOM ohne Meldung Assemblerbefehle austauscht, anstatt eine Fehlermeldung oder zumindest eine Warnung zu erzeugen. Außerdem wird dabei ein Register benutzt, daß man in einer "nosave ISR" möglicherweise nicht gesichert hat. Siehe Kommentare im Code:
Code:
'### Verkürztes kompilierbares Demo zur Problembeschreibung
'### BASCOM-AVR Demo Version 2.0.7.5 (Compiler Version 2.0.7.5)
'
$regfile = "ATtiny25.DAT"
$framesize = 32
$swstack = 32
$hwstack = 34
$crystal = 16000000
Pcmsk = Bits(pcint3 , Pcint4)
On Pcint0 Isr_receive_data_compelled Nosave 'keine Register sichern
Enable Pcint0
Enable Interrupts
Do
Loop
End 'end program
Isr_receive_data_compelled:
sbi gifr, pcif 'löschen Interrupt Flag
'### Mit Bascom assembliert und dann mit ReAVR von ja-tools zum Überprüfen
'### disassembliert zeigte, daß aus der SBI Zeile ohne Warnung Folgendes entstand
'### und dabei r23 verändert wurde.
'###
'### lds r23,(p3A+0x20) ; io register
'### ori r23,k20
'### sts (p3A+0x20),r23 ; io register
'###
'### OK, SBI kann nicht auf das GIFR im ATTiny25 zugreifen, da das Register außerhalb
'### des Adressbereiches von SBI liegt.
'###
'### In einer ISR, die keine Register sichert kann die Änderung von r23 OHNE Warnung
'### aber fatal werden. Bei zeitkritischen Routinen können außerdem die zusätzlichen
'### Takte des Ersatzcodes noch graue Haare wachsen lassen wenn man von dem Austausch
'### zunächst nichts mitbekommt - Programm läuft ja eigentlich.
Return
In der gleichen "nosave ISR" verwendete ich folgendes Kommando:
Loadadr Flash_data(write_block_array_pointer) , X
Hier wird das Register r10 verändert. (Das X für r26, r27 steht, ist normalerweise bekannt)
Problem ist nicht weitergemeldet und vielleicht ist das ja auch irgendwo dokumentiert.