Enkla men fatala buggar
Re: Enkla men fatala buggar
Ja, det går ju inte att "cacha" t.ex "PORTA", det kan ju ändra sig
hur det vill på porten utan att cachen har en susning.
Och visst, en massa optimeringar kopplas ifrån, men det är ju
just det som man vill uppnå, så det är inget "problem".
hur det vill på porten utan att cachen har en susning.
Och visst, en massa optimeringar kopplas ifrån, men det är ju
just det som man vill uppnå, så det är inget "problem".
Re: Enkla men fatala buggar
Att cache för de addresser som är deklarerade på detta sätt inaktiveras elller gås förbi.
Re: Enkla men fatala buggar
Cachen fungerar inte på det sättet, i alla fall inte i de flesta uProllar.
Det handlar helt enkelt om att förhindra kompilatorn från att optimera bort kod, som den tror är onödig.
Ponera att du har deklarerat en variabel,
sedan väntar du på att variabeln skall få ett visst värde:
Kompilatorn kan i vissa lägen få för sig att "a" aldrig kommer att få värdet 100, eftersom "a" inte används någon annan stans i programmet, följaktligen tar kompilatorn bort alla referenser för "a" och ersätter det hela med
I dessa lägen behöver man använda "volitile"
(enkel och kort förklaring)
Det handlar helt enkelt om att förhindra kompilatorn från att optimera bort kod, som den tror är onödig.
Ponera att du har deklarerat en variabel,
Kod: Markera allt
unsigned char a;
Kod: Markera allt
while (a!=100);
Vilket inte är meningen, eftersom i detta fallet kan "a" få ett värde från något annat, a kan vara en port, till exempel, eller också kan man ha en DMA-överföring som startas någon annanstans och ger "a" ett värde.while(1)
I dessa lägen behöver man använda "volitile"
(enkel och kort förklaring)
Re: Enkla men fatala buggar
Jag tror inte heller att cachen någonsin är inblandad vid läsning
från hårdvaruportar. Men det viktiga är, som sagt, att kompilatorn
inte ska försöka vara smart och göra gissningar kring variablen.
> Det handlar helt enkelt om att förhindra kompilatorn från att optimera bort kod,
Eller att *flytta* på kod, t.ex flytta ut "myvar = PORTA;" från en loop och lägga
det en gång *innan* loopen eftersom PORTA (ju) inte ändras i loopen. En vanlig
C optimering.
från hårdvaruportar. Men det viktiga är, som sagt, att kompilatorn
inte ska försöka vara smart och göra gissningar kring variablen.
> Det handlar helt enkelt om att förhindra kompilatorn från att optimera bort kod,
Eller att *flytta* på kod, t.ex flytta ut "myvar = PORTA;" från en loop och lägga
det en gång *innan* loopen eftersom PORTA (ju) inte ändras i loopen. En vanlig
C optimering.
Re: Enkla men fatala buggar
Det stämmer! Men det finns ju kod som fungerar så länge inte kompilatorn utnyttjar dessa delar av standarden bokstavligt så att säga, vilket kan vara svårfelsökt. Moderna gcc-versioner har dock bra varningar för detta har jag för mig.kimmen skrev:Sådan aliasing är ju inte heller tillåten enligt C-standarden, så det är med all rätt GCC gör sådana antaganden.
Re: Enkla men fatala buggar
Inte på ARMv7, där cachas volatile. Det ända som avgör ifall någoting fastnar i Cache är hur man har satt upp sina page tabeller.blueint skrev:Att cache för de addresser som är deklarerade på detta sätt inaktiveras elller gås förbi.
Så t.ex PORTA skall vara volatile OCH den pagen skall markeras som device.
På ARM är volatile är bara till för kompilatorn, CPUn bryr sig inte ett dugg. Den kollar bara på page tabeller.
Re: Enkla men fatala buggar
Vad menas med "page tabeller" på ARM? det är ju rätt många som inte har någon MMU.
Re: Enkla men fatala buggar
Bra poäng, tror endast det gäller ARMv7-AR arkitekturen. Altså Cortex A processorerna och kanske också Cortex R serien.blueint skrev:Vad menas med "page tabeller" på ARM? det är ju rätt många som inte har någon MMU.
Vet inte hur ARMv7-M fungerar, kanske är mer som de andra uC?
Tror att Cortex-M har fördefinerade adressspann där IO skall ligga men att man kan komma runt det med en MPU.
Sedan så tror jag inte Cortex-M har någon inbyggd cache utan det är upp till tillverkaren (t.ex TI) att implementera en sådan.
Re: Enkla men fatala buggar
Samma som på andra processorer. https://en.wikipedia.org/wiki/Page_tableblueint skrev:Vad menas med "page tabeller" på ARM? det är ju rätt många som inte har någon MMU.
Volatile har inget med minnescachning att göra, det är ett kompilatordirektiv.
ARM finns i olika versioner, med eller utan cache, ARM7TDMI tex har inte cache, det är bara en kärna. ARM720T har cahe och MMU. Samma med ARM9.
En del processesorer har en MPU istället för MMU.
-
- Inlägg: 466
- Blev medlem: 20 februari 2011, 23:32:40
- Ort: Gävle
Re: Enkla men fatala buggar
volatile används även med fördel på globala variabler som delas mellan main() och interrupt-rutiner. Brukar funka bra ändå om man inte optimerar, men slår man på optimering kan det gå åt skogen.
För övrigt skrev en jobbarkompis något liknande följande kod och fattade inte varför det inte funkade
if(!strcmp("foo->bar->string", "MinFinaJämförelseSträng")) ...
bit96 skrev väldigt utförliga kommentarer till det där att plocka ut high och low nibble. Det tycker jag verkar lite väl mycket.
Det är bra med kommentarer, men man får inte kluttra ner koden med för mycket kommentarer heller. Förekommer sådana bitshiftningar
ofta i ens kod så räcker det med en kort kommentar före varje om ens det imho då.
Kommentarer ska främst vara där det inte alls är uppenbart vad koden gör.
Dåligt:
Kanske motiverat:
Fast där agerar 4.5V mest som en påminnelse om vad power_good är bra för och det bör man ju rimligtvis ha koll
på, lätt att kolla upp. Dessutom kan ju definitionen lätt ändras och man missar att uppdatera kommentaren, lurigt.
Motiverat:
MVH: Mikael
För övrigt skrev en jobbarkompis något liknande följande kod och fattade inte varför det inte funkade
if(!strcmp("foo->bar->string", "MinFinaJämförelseSträng")) ...
bit96 skrev väldigt utförliga kommentarer till det där att plocka ut high och low nibble. Det tycker jag verkar lite väl mycket.
Det är bra med kommentarer, men man får inte kluttra ner koden med för mycket kommentarer heller. Förekommer sådana bitshiftningar
ofta i ens kod så räcker det med en kort kommentar före varje om ens det imho då.
Kommentarer ska främst vara där det inte alls är uppenbart vad koden gör.
Dåligt:
Kod: Markera allt
printf("Value %d\n"); // Skriver ut "Value" följt av värdet och enterslag
if(lcd_on) ... // Om LCD:n är på
Kod: Markera allt
if(lcd_on && power_good) ... // Om LCD:n är på och spänningen är över 4.5V
på, lätt att kolla upp. Dessutom kan ju definitionen lätt ändras och man missar att uppdatera kommentaren, lurigt.
Motiverat:
Kod: Markera allt
if(power_down)
{
power_on(); // Kretsen kan vara av och måste initieras ordentligt för att kunna stängas av korrekt.
power_off();
}
Re: Enkla men fatala buggar
För den där "if(!strcmp("foo->bar->string", "MinFinaJämförelseSträng")) ..." så måste man också kontrollera att foo är en giltig pekare, och att bar också är det samt till sist string. Annars kan man få mycket intressanta resultat ..
Re: Enkla men fatala buggar
Jag antar att citationstecken skall bort på första parametern annans kommer if-villkoret aldrig uppfyllas.adent skrev: if(!strcmp("foo->bar->string", "MinFinaJämförelseSträng")) ...
Vad de gäller kommentarer så är det naturligtvis individuellt.
Men jag menar att de skall uttrycka vad som händer i ett större sammanhang.
Det skall nästan vara som att läsa en berättelse.
Man förstår vad som händer även om man inte läser koden.
Kod: Markera allt
printf("Value %d\n"); // Skriver ut "Value" följt av värdet och enterslag
if(lcd_on) ... // Om LCD:n är på
Att tala om att printf() skriver ut är meningslöst, det ser man ändå. Kommentaren blir bara en upprepning av koden.
Istället bör man tala om varför och vad som är syftet, t.ex. /* Skriv ut PID-inställningens P-värde */
(Det saknas för övrigt en parameter i printf()-exemplet)
"// Om LCD:n är på" är meningslös information.
Möjligen skulle man kunna skriva syftet med if-testen.
if(lcd_on) ... /* Om LCD:n är på så rensa skärmen eller nåt... */
Alltså, kommentaren kan handla om vad som är syftet med koden, inte vara en text-upprepning av vad koden gör.
Men ibland är koden komplicerad och då bör kommentaren istället beskriva med ord vad som händer.
Det är en avvägningssak som inte är helt lätt.
Re: Enkla men fatala buggar
Interruptköer kan skapa problem.
Vi har haft en bug som plågat oss ett tag.
Problemet är att den bara inträffat typ en gång varannan vecka, helt slumpmässigt.
Det visade sig att det var uppköing av interrupt som orsakade problemet, och det inträffar bara när vissa saker händer inom ett intervall om runt 200 ns eller så.
Vi har ett UART tx interrupt, vilket ger interrupt när det finns plats i TX-bufferten.
När interruptet inträffarer, stänger vi av RX-interruptet (för att inte störa TX)
Samt nollställer TX-Int-flaggan, därefter fyller vi på Bufferten.
När Bufferten är påfylld sista gången, stänger vi av TX-interruptet och slår på RX-interruptet.
Mellan det vi slår av flaggan och slår på RX är det runt 200-300ns instruktioner, dock har det visat sig att vid vissa tillfällen, typ varannan vecka eller så, så hinner vi tömma TX-bufferten innan vi hinner slå av TX-interruptet, vilket då innebär att det blir uppköat, och återgenereras, trots att vi inte har något att sända, vilket i sin tur innebar att RX aldrig blev påslaget.
Lösning, rensa INT-flaggan det sista innan man hoppar ur rutinen (elementärt egentligen), dock har aldrig problemet visat sig "Inhouse"
Vi har haft en bug som plågat oss ett tag.
Problemet är att den bara inträffat typ en gång varannan vecka, helt slumpmässigt.
Det visade sig att det var uppköing av interrupt som orsakade problemet, och det inträffar bara när vissa saker händer inom ett intervall om runt 200 ns eller så.
Vi har ett UART tx interrupt, vilket ger interrupt när det finns plats i TX-bufferten.
När interruptet inträffarer, stänger vi av RX-interruptet (för att inte störa TX)
Samt nollställer TX-Int-flaggan, därefter fyller vi på Bufferten.
När Bufferten är påfylld sista gången, stänger vi av TX-interruptet och slår på RX-interruptet.
Mellan det vi slår av flaggan och slår på RX är det runt 200-300ns instruktioner, dock har det visat sig att vid vissa tillfällen, typ varannan vecka eller så, så hinner vi tömma TX-bufferten innan vi hinner slå av TX-interruptet, vilket då innebär att det blir uppköat, och återgenereras, trots att vi inte har något att sända, vilket i sin tur innebar att RX aldrig blev påslaget.
Lösning, rensa INT-flaggan det sista innan man hoppar ur rutinen (elementärt egentligen), dock har aldrig problemet visat sig "Inhouse"
Re: Enkla men fatala buggar
Alltså, kommentarer ska inte förklara *vad* koden gör utan *varför* den gör det.
Om man behöver kommentarer för att förklara vad koden utför så har man skrivit dålig kod.
Edit: alltså precis som Bit96 skrev ovan...
/johan
Om man behöver kommentarer för att förklara vad koden utför så har man skrivit dålig kod.
Edit: alltså precis som Bit96 skrev ovan...
/johan