anatomia di unistruzione in arduino pt.2
TRANSCRIPT
Arduino:Anatomia di un’istruzione - 2
Enrico Colombini (Erix)
µhackademy 4 Novembre 2016
Setta il bit 5 di PORTB
Riassunto della puntata precedente
digitalWrite(LED_BUILTIN, HIGH);
*out |= bitmask;
esegue:
1 cifra hex = 4 cifre bin
Corso lampo di esadecimale
0 1 2 3 4 5 6 7 8 9 A B C D E F
8 + 2 = A (hex)
= A5 (hex)
Da qui all’hardware?
Questi sono solo dei caratteri
*out |= bitmask;
Vediamo l'eseguibile...
Compilazione
Codice sorgente (testo)
Compilazione + link
--> Codice eseguibile (binario)
Istruzioni per la MCU
Eseguite dall’hardware
61 e0 80 91 00 01 0c 9493 01 cf 93 df 93 c0 e0d1 e0 61 e0 88 81 0e 94cf 01 68 ee 73 e0 80 e090 e0 0e 94 09 01 60 e088 81 0e 94 cf 01 68 ee73 e0 80 e0 90 e0 df 91cf 91 0c 94 09 01
Alcune istruzioni di ‘Blink’
Tutto chiaro, no?
Non portatile
Linguaggio assembly (asm)
Umanamente leggibile
Corrisponde 1:1 alle istruzioni MCU
Si può usare per scrivere codice
...o per leggere l'eseguibile
(o embedded nel C)
Come si usa(va)
Sorgente Assembly
Assembler
Linker
Eseguibile
Sorgente C
Compilatore
Come si ricava?
Usi dell'assembly
Il C ottimizzato è un asm (quasi) portatile
Si usa l'asm in casi o punti particolari
Saperlo leggere per migliorare il C
Due modi
Dal C all'assembly
Sorgente C
Compilatore
Linker
Eseguibile
Assemblycon sorgente C
Disassemblato(meno informazioni)
(no sorgente C)
Disassemblare con Arduino
Dal file .elf
avr-objdump -d /tmp/build4048337971841970682.tmp/Blink.cpp.elf >blink.lst
(copiare, incollare e modificaredal'IDE di Arduino)
‘Blink’ eseguibile + assembly
0000039e <digitalWrite>: 39e: 1f 93 push r17 3a0: cf 93 push r28 3a2: df 93 push r29 3a4: 28 2f mov r18, r24 3a6: 30 e0 ldi r19, 0x00 ; 0 3a8: f9 01 movw r30, r18 3aa: e8 59 subi r30, 0x98 ; 152 3ac: ff 4f sbci r31, 0xFF ; 255 3ae: 84 91 lpm r24, Z 3b0: f9 01 movw r30, r18 3b2: e4 58 subi r30, 0x84 ; 132 3b4: ff 4f sbci r31, 0xFF ; 255 3b6: d4 91 lpm r29, Z 3b8: f9 01 movw r30, r18 3ba: e0 57 subi r30, 0x70 ; 112 3bc: ff 4f sbci r31, 0xFF ; 255 3be: c4 91 lpm r28, Z 3c0: cc 23 and r28, r28 3c2: c9 f0 breq .+50 ; 0x3f6 <digitalWrite+0x58> 3c4: 16 2f mov r17, r22
(etc.)
Mette a 1 un bit
3ee: ec 91 ld r30, X 3f0: ed 2b or r30, r29 3f2: ec 93 st X, r30
Che vuol dire?
Da digitalWrite:
Gli asm non sono tutti uguali
I concetti sì
Architettura e numero di bit
Organizzazione della memoria
Set di istruzioni
Modi di indirizzamento
Registri dei microcontrollori AVR
Alcuni sono dedicati
r0
r1
r2
r29
r30
r31
...
32 registri a 8 bit: le‘variabili’ della MCU
Pseudo-registria 16 bit:
r26 + r27 = X
Mettere a 1 un bit
ld r30, Xor r30, r29st X, r30
X=out, r29=bitmask, r30=temp.
Viene compilato in:
Il sorgente C:
*out |= bitmask;
Soluzioni ibride
C: scrivere senza librerie?
Massima efficienza
Pieno controllo (es. set più bit)
Costa in portatilità e lavoro
Blink ‘ibrido’ senza digitalWrite
#define LED_PORT PORTB#define LED_DDR DDRB#define LED_PIN PB5
void setup() { LED_DDR |= _BV(LED_PIN);}
void loop() { LED_PORT |= _BV(LED_PIN); delay(1000); LED_PORT &= ~_BV(LED_PIN); delay(1000);}
Macro: sostituzioni nel sorgente C
#define PB5 5
#define LED_PIN PB5
LED_PIN diventa 5
Preprocessore
Macro da sostituire
#define LED_PORT PORTB#define LED_PIN PB5
void loop() { LED_PORT |= _BV(LED_PIN);
// ... etc.
}
Mette un bit a 1
Sostituzione macro (1)
#define LED_PORT PORTB#define LED_PIN PB5
LED_PORT |= _BV(LED_PIN);
PORTB |= _BV(PB5);
Usare costanti
Sostituzione macro (2)
#define PB5 5
PORTB |= _BV(PB5);
PORTB |= _BV(5);
Definita in .h
Sostituzione macro (3)
#define _BV(bit) (1 << (bit))
PORTB |= _BV(5);
PORTB |= (1 << 5);
Crea una bitmask
Left shift
Bitmask
0x01
0x20
1
1 << 5
Sostituzione macro (3a)
#define _BV(bit) (1 << (bit))
PORTB |= _BV(5);
PORTB |= (1 << 5);
PORTB |= 0x20; //0010 0000
In sintesi: mette a 1 il PB5
Cos’è PORTB?
LED_PORT |= _BV(LED_PIN);
PORTB |= 0x20;
Sostituzione macro (4)
Cast a puntatore
PORTB |= 0x20;
(*(volatile uint8_t *)(0x05)) |= 0x20;
In sintesi
C puro
LED_PORT |= _BV(LED_PIN);
(*(volatile uint8_t *)(0x05)) |= 0x20;
Parliamo di efficienza
Quanto si guadagna?
Libreria di Arduino
vs.
Accesso diretto
digitalWrite
ld r30, Xor r30, r29st X, r30
3 istruzioni asm
È compilato in:
Il sorgente C:
*out |= bitmask;
Accesso diretto
sbi 0x05, 5
Più veloce, atomica
È compilato in:
Il sorgente C:
PORTB |= 0x20;
Perché la differenza?
PORTB
Leggere l'asm
Il compilatore non sa a quale casella punta
*out
Il compilatore sache è un registro di I/O
Sfruttare l'ottimizzatore
Arduino: solo -Os
Si può scrivere in C...
...con l'efficienza dell'assembly
Il debugging è più complicato
Contando l'intera funzione
Quasi 30:1
Accesso direttodigitalWrite
3.45 µs
0.125 µs
t
Accesso diretto
That's all folks!
Capire le librerie
Modificare le librerie
Programmare senza limiti
Divertirsi!