Tutorials - PIC

 

Il file .HEX


I files .HEX nei PIC

Il file .hex viene generato dall' assembler in funzione della lista sorgente.

  • Il suo contenuto è la sequenza di codici che saranno scritti nella memoria programma e che il processore dovrà eseguire. 
     
  • Questi sono scritti come valori esadecimali in modo da poter essere passati ad un dispositivo di programmazione per la loro scrittura nel chip.
     
  • Il file è un semplice formato testo ASCII per rendere facilmente portabile il file stesso.
     
  • Il testo è formattato secondo uno standard stabilito, il che consente di usarlo su dispositivi di programmazione di diversi produttori.

In effetti non esiste un solo standard (e ci mancherebbe che ci si decida a fare qualcosa di standard...), ma diversi "standard" studiati da vari produttori: in particolare per i PIC si usano correntemente gli "standard" della Intel, ovvero dei file con estensione hex.

Formato standard Menmonico Estensione file Impiego
Intel Hex Format INHX8M .hex dispositivi a 8 bit
Intel Hex 32 Format INHX32 .hex dispositivi a16 bit
Intel Split Hex Format INHX8S .hxl, .hxh altri

Quello utilizzato principalmente è l' Intel Hex Format, con estensione .hex, anche se teoricamente è possibile usare altri "standard".
Anzi, gli assemblatori o i compilatori spesso hanno la possibilità di scegliere diversi formati, per potersi adattare a diversi sistemi di programmazione.


Cosa c'è dentro un file .HEX

Andando a leggere con un qualsiasi editor questo file .hex (è un file di testo), si troverà un pacchetto di caratteri del genere :

:020000040000FA
:0400000000000828CC
:0400080000000900EB
:1000100083018B018C0186018316BF308100003083
:0600200086008312861524
:02400E00B93FB8
:00000001FF


in cui ogni riga è del tipo :

:LLAAAATTDDDD... .DDCC

i cui elementi sono

  • : un due punti (o column in inglese) iniziale
     
  • LL due cifre esadecimali che rappresentano il numero di byte presenti nella riga. Il massimo di dati in una riga è 16, quindi il valore massimo applicabile a questi due byte è 10H
     
  • AAAA quattro cifre hex che indicano la posizione di inizio in cui scrivere i byte.
    Poichè una istruzione è lunga due byte.In effetti si tratta, per i PIC 16F, di 14 bit, per cui i primi due bit più significativi saranno sempre 0. L' indirizzo di programmazione in memoria è shiftato a sinistra di uno. Quindi per indicare l' indirizzo 0004h si troverà scritto 0008h.
     
  • TT due cifre che indicano il tipo di record :
    00 - data record
    01 - end-of-file record
    02 - extended segment address record (non usato per il PIC)
    03 - start segment address record (non usato per il PIC)
    04 - extended linear address records (non usato per il PIC)
    05 - Start linear address record (non usato per il PIC)
    Quindi nella prima riga e nelle seguenti conterranno 00, mentre nell' ultima 01. Gli altri valori sono stati inseriti da Intel in relazione alle CPU a 16, 32 e 64 bit ed ovviamente non sono usati nei PIC a 8 bit.
     
  • DD: due cifre hex che contengono il valore dei byte nella forma byte basso/ byte alto (gli opcode PIC sono da due bytes); come detto prima si può arrivare ad un massimo di 16 dati su una sola riga 
     
  • CC: due cifre hex del checksum della riga (complemento a due della somma di tutti i bytes precedenti della stessa riga). Serve al dispositivo di programmazione per verificare la correttezza dei dati ricevuti.

L' ultima riga è l' end-of-file record, tipicamente con questa forma :
 
:00000001FF
 
dove :

  • 00 è il numero dei dati nella riga, che, essendo la chiusura,  non ne contiene
  • 0000 è il valore attribuito all' indirizzo, che, in questa riga, non ha significato.
  • 01 è il valore che indica che la riga è l' end-of-record
  • FF è il checksum calcolato (qui deriva da  01h + NOT(00h + 00h + 00h + 01h) che fa FFh).

Per le altre righe vediamo qualche esempio. Nel listato qui sopra la seconda riga contiene :

:0400000000000828CC

indica che ci sono 04 byte che saranno scritti a partire da 0000. Il valore di questo indirizzo è specificato da uno statement (ORG 00H) nella lista sorgente visibile più avanti.
La sequenza degli opcode è : 00000828 e il checksum è CC (esadecimale).
La riga successiva :
 
:0400080000000900EB

indica che ci sono 04 byte che saranno scritti a partire da 0004 (0008 è 0004 shiftato a sinistra di 1). Anche qui, l' indirizzo è specificato da uno statement del sorgente (ORG 04H).
La sequenza degli opcode è : 00000900 e il checksum è EB (esadecimale).

Quindi, a partire dalla locazione 0000, la sequenza da inserire è 000002808, poi si passa a 0004 dove va inserita la sequenza 00000009 : abbiamo detto che i byte si trovano nella disposizione basso/alto, ovvero in questo caso 00000828 00000900, e per "interpretarli" li devo scambiare di posizione.
Per chi volesse fare del reverse engeneering:

  locazione        opcode      mnemonico PIC
  0000              0000          nop
  0001              2808          goto  08h
  0004              0000          nop
  0005              0009          retfie

e così via. Ed in effetti l' hex in esempio è derivato dall' assemblaggio del seguente sorgente :

;*************************************************
; Prova
; (c) 2005, AF
; rev.  1.0  23-02-2005
;*************************************************


                PROCESSOR        16F876
                INCLUDE          "P16F876.INC"
               
                RADIX            DEC
                
  __config _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF 
            & _LVP_OFF & _BODEN_OFF
 
;***************************************************
;Reset Vector

                ORG      00H
Reset nop
      goto Main

;Interrupt vector

                ORG      04H
ISR nop
  retfie
;===================================================
   ORG   08H

Main: ;Power_ON reset
  clrf  STATUS       ;do initializaion (bank 0)
  clrf  INTCON       ;disable all IRQ
  clrf  PIE1

  clrf  PORTB

  bsf   STATUS, RP0  ; bank1
  movlw b'10111111'  ; no RBPU
  movwf OPTION_REG
  movlw 0x00           
  movwf TRISB        ; PB as out
  bcf   STATUS,RP0   ; bank0
  bsf   PORTB, 3     ; PB 3 = 1  
  goto  $            ; locked loop

                END
Da osservare che:
  •  la maggior parte del testo sono commenti (evidenziati in verde), che non finiscono in alcun modo nel file .hex
     
  • anche gli statement (PROCESSOR, INCLUDE, RADIX, ORG, END) non finiscono direttamente nel file .hex, ma servono all' Assembler per organizzare correttamente i codici in uscita. 

Ad esempio, la penultima riga del file .hex  contiene il record  : 

:02400E00B93FB8

Questa riga riporta il valore assegnato al Registro di Configurazione del processore dallo statement  __config e dalla successiva lunga stringa di mnemonici, il cui corrispondente esadecimale compilato è il numero 3FB9h.
Il registro di configurazione  per il processore specificato dagli statement PROCESSOR e INCLUDE, ovvero il 16F876, si trova alla locazione 2007h (che, scritto shiftato a sinistra di una posizione, diventa 400Eh).
Per chi non ci credesse :
 
2007h  --> 0010 0000 0000 0111b
             2    0    0    7 h

 
che, shiftato a sinistra di una posizione diventa :
 
           0100 0000 0000 1110b  --> 400Eh
             4    0    0    E h

Per curiosità, la linea __config si trova normalmente all' inizio del testo del sorgente, dopo la definizione del processore, in quanto essa è stabilisce  strettamente a come si comporterà quel determinato processore, fissando alcune caratteristiche del suo funzionamento hardware; nel file .hex, invece, finirà sul fondo perchè l' indirizzo interno del registro del PIC in cui verranno scritti i 4 byte ha un valore molto più alto di tutti gli altri registri accessibili. Quindi, essendo la lista .hex organizzata grosso modo in ordine ascendente per quello che riguarda gli indirizzi, il valore di __config finirà tipicamente nella penultima riga. 


 


Alcune note non secondarie

  1. ll file .hex di Intel è accettato da tutti i dispositivi di programmazione e quindi rende la scelta di questo indipendente sia dal processore che dall'assembler usato.
    Come informazione generale va detto che non tutti i dispositivi di programmazione accettano tutti i possibili formati "standard" per i file .hex. 
    Quindi, prima di procedere all' acquisto di un programmatore o all' auto costruzione, verificate se il software di gestione prevede il formato o i formati che intendete utilizzare.
     

  2. Il file .hex di un PIC16 o di un PIC18 o di un ARM o di un ST6 saranno esattamente uguali per quanto riguarda la STRUTTURA.
    Ma completamente diversi per quanto riguarda il contenuto HEX dei codici di istruzione.
    Questo perchè lo standard Intel definisce COME debba essere strutturato il file di scambio esadecimale, ma non COSA debba contenere, il che dipende dalle caratteristiche del processore.
     

  3. Quindi, Assembler per processori diversi produrranno file .hex con le caratteristiche generali qui spiegate, ma per ogni processore ci sarà una diversa relazione opcode - valore del byte scritto. 

    Quindi, un .hex, pure scritto con la massima aderenza a questo standard, sarà adeguato alla programmazione solo ed esclusivamente del dispositivo per cui è stato compilato e non sarà utilizzabile in alcun modo per altri processori. 

    Al limite, un file .hex per un certo processore può essere usato per un altro all' interno della stessa famiglia solo ed esclusivamente se le risorse dei due processori sono identiche; se ci sono differenze anche minime e la compilazione non ne tiene, programmare un chip con l' .hex previsto per un' altro non darà alcun risultato utile.
       

  4. Sul sito di Intel è possibile recuperare un .pdf dal titolo "Hexadecimal Object File Format Specification" che contiene tutte le informazioni a riguardo del suo formato hex.
     

  5. Per conoscenza, esistono anche editor specifici per il trattamento dei file .hex e programmi di conversione dal formato .hex al binario, reperibili in rete. 
     

  6. Esistono anche dei disassembler, ovvero programmi per risalire dal file .hex alla sequenza di opcode. Ovviamente un disassembler deve essere adatto ad uno specifico processore, in quanto ogni processore ha la sua equivalenza tra set di istruzioni e codici binari.
    In particolare, i file .hex generati compilando sorgenti scritti con linguaggi ad alto livello saranno particolarmente complessi e una loro "decodifica" manuale diventa una impresa al di sopra delle normali possibilità.

Queste informazioni riguardo al file .HEX possono parere superflue, ma può capitare il caso in cui sia necessario andare a vedere cosa sta scritto in una certa locazione e quindi ci si trova a confrontarsi con il file .HEX. Per cui, meglio sapere come è fatto.

Dato che questo file è una lista di testo ASCII, non occorre alcun editor particolare per vederlo o modificarlo.
Chiaramente si consigliano editor per programmazione, mentre word processor non sono l' ideale, perchè tendono a dare formattazione ad un testo che deve restare così come sta senza alcuna variazione indotta dal sistema di consultazione (dato che sono la lista delle istruzioni che andrà inserita nella memoria programma del processore).

Quindi, niente Word, Wordpad o simili. Meglio Programmer's Notepad, Notepad++, TextEdit, Textpad, ecc.


ATTENZIONE:

Il file .HEX è una lista di testo che può essere modificata come un qualsiasi testo.

MA NON E' un qualsiasi testo !

Quindi, anche la più piccola modifica manuale" a questo file può essere fatta solamente a ragion veduta.
Altrimenti il file verrà rifiutato dal sistema di programmazione se i checksum non sono corretti e, se fosse accettato, ma le istruzioni modificate in modo arbitrario, il programma non funzionerebbe.

Quindi, potete editare il file .hex per visionarlo, ma se lo modificate, fatelo su una copia, in modo da non danneggiare l' originale che, in pratica, potrà essere prodotto correttamente o modificato correttamente solo attraverso la compilazione del sorgente.

 


 

 

Copyright © afg. Tutti i diritti riservati.
Aggiornato il 23/04/13.