Far calcolare l' Assembler MPASM
L' Assembler non serve solamente a compilare istruzioni, ma ha anche
possibilità di calcolo che spesso il programmatore neofita non utilizza.
Ad esempio, MPASM è in grado di valutare, durante la compilazioni,
espressioni logiche e aritmetiche e con questo sollevare il programmatore da
un lavoro a volte complicato o noioso.
Il calcolatore dell' Assembler lavora in modo analogo a quello dei
linguaggi più complessi ed anche le dichiarazioni possono assumere aspetto
molto simile, ma è importante comprendere che questo lavoro avviene DURANTE
la compilazione e non ha niente a che fare con la struttura logica del
programma.
MPASM riconosce una serie di operatori logici e aritmetici :
Operatore |
Funzione |
Esempio |
! |
NOT |
if ! (a == b) |
- |
Negazione (complemento a 2) |
-1 * Length |
~ |
Complemento |
flags = ~flags |
high |
high byte |
movlw high CTR_Table |
low |
low byte |
movlw low CTR_Table |
upper |
upper byte |
movlw upper CTR_Table |
* |
Moltiplicazione |
a = b * c |
/ |
Divisone |
a = b / c |
% |
Modulo |
entry_len = tot_len % 16 |
+ |
Addizione |
tot_len = entry_len + 1 |
- |
Sottrazione |
entry_len = tot - 1 |
<< |
Left Shift |
flags = flags << 1 |
>> |
Right Shift |
flags = flags >> 1 |
>= |
Maggiore o uguale |
if entry_idx >=
num_entries |
> |
Maggiore |
if entry_idx >
num_entries |
< |
Minore |
if entry_idx <
num_entries |
<= |
Minore o uguale |
if entry_idx <=
num_entries |
== |
Uguale |
if entry_idx ==
num_entries |
= |
Non uguale |
if entry_idx !=
num_entries |
& |
Bitwise AND |
flags = flags &
ERROR_BIT |
^ |
Bitwise XOR |
flags = flags ^ ERROR_BIT |
| |
Bitwise OR |
flags = flags | ERROR_BIT |
&& |
AND logico |
if (len == 512) &&
(b == c) |
|| |
OR logico |
if (len == 512) || (b ==
c) |
= |
Set equal to |
entry_index = 0 |
+= |
Add and set |
entry_index += 1 |
-= |
Subtract and set |
entry_index -= 1 |
*= |
Multiply and set |
entry_index *=
entry_length |
/= |
Divide and set |
entry_total /=
entry_length |
%= |
Modulus and set |
entry_index %= 8 |
<<= |
Ledt shift and set |
flags <<= 3 |
>>= |
Right shift and set |
flags >>= 3 |
&= |
AND and set |
flags &= ERROR_FLAG |
|= |
OR and set |
flags |= ERROR_FLAG |
^= |
XOR and set |
flags ^= ERROR_FLAG |
++ |
Incremento |
i ++ |
-- |
Decremento |
ì -- |
Questi operatori, tipici del C, sono poco conosciuti in
Assembly, ma permettono diverse e potenti strutture anche in questo ambito.
AVVERTENZA
IMPORTANTE:
Gli operatori logici aritmetici dell' Assembler,
assieme alle direttive condizionali (if,
while, ecc), anche se simili a
quelli del C,
NON sono codici
di istruzione o generano codici di istruzione !
Questi
operatori, nell' Assembly, servono per realizzare assemblaggi condizionali.
Quindi NON agiscono sulla logica del programma, ma sulla struttura
dell' assemblaggio e non trasformano il Macro Assembler in un
linguaggio C. |
Detto questo, vediamo alcuni esempi.
Operatore incrementa/decrementa (++/--)
Il suo scopo è di incrementare (o decrementare una
variabile), ad esempio in un loop per inserire una serie di istruzioni a
seconda del valore di una variabile o di una costante.
e Debug.
Quindi questa sequenza NON viene eseguita nel programma a seconda del valore
assunto al momento da variabili durante l' esecuzione del programma.
Un altro esempio :
;
check bits in a register
while (i <
8)
; for 8 times
#if ((Register &
1) != 0 ; if bit 0 is set
.. instructions...
#endif
; shift right for check next bit
Register = Register >> 1
i = i + 1
endw |
Ecco un utile check automatico di superamento dello spazio durante le
assegnazioni in RAM con lo statement CBLOK.
La label di una assegnazione "vuota" (dummy) che occupa 0 bytes
viene attribuita all' ultima locazione di RAM assegnata; quindi viene
verificato se il suo indirizzo supera quello del banco (in questo caso il
Banco0, Access Ram). Se supera viene segnalato un errore.:
CBLOCK 0x00
; bank 0
ssTXBuf
ssRXCnt
DlyTcyCnt ; for DelayUS
...etc...
end_AccBank0:0 ; dummy for overrun check
ENDC
#if end_Accbank0 > 0x7F ; check for overrun
error "AccessRAM Bank0 space overrun"
#endif |
Con questa semplice aggiunta non c'è il rischio di aver assegnato memoria
al di fuori dei limiti consentiti e non c'è bisogno di effettuare alcun
calcolo : l' Assembler calcola per noi e ci avvisa dell' eventuale
errore.
Operatore di shift (>> e <<)
Esegue lo shift di un valore (0 o 1) di n volte.
;
Make GIE and TOIE = 1
; other bits = 0
movlw (1 <<
GIE) | (1 <<
TOIE))
movwf INTCON |
L' esempio qui sopra porta a 1 i bit 7 (GIE) e 5 (TOIE) del registro INTCON
La stessa operazione è eseguibile con una somma :
;
Make GIE and TOIE = 1
; other bits = 0
movlw (.128 +
.32) ; move b'10100000'
movwf INTCON |
o con un OR.
;
Make GIE and TOIE = 1
; other bits untouched
movlw b'10100000'
xorwf INTCON, f |
Ma si nota come nel primo caso l' uso delle lablel al posto di numeri
assoluto facilita la comprensione e la stesura del sorgente; infatti si
sfrutta l' assegnazione presente nel picxxx.ini in cui è dichiarato GIE = 7 e
TOIE = 5, non necessitando così di altra dichiarazione nel sorgente.
XOR (^)
L' operatore XOR inverte il valore dei bit.
Una applicazione può essere quella di invertire lo stato di alcuni bit con
una maschera oppure con shift
;
Make bit 0, 2, 6 = 0
movlw 0xFF ^ ((1<<0)
|(1<<2) |
(1<<6))
; this is equal to
andlw 0xBAh
; or
andlw ~ ((1<<0)
|(1<<2) | (1<<6)) |
Anche qui i numeri indicatori dei bit possono essere sostituiti con label
equivalenti, rendendo più semplice e chiara la scrittura.
Operatore Complemento (~)
L' operazione precedente equivale a
;
Make bit 0, 2, 6 = 0
andlw ~ ((1<<0)
|(1<<2) |
(1<<6)) |
High/Low/Upper
Questi operatori restituiscono il byte basso, alto e superiore di un numero
(a 3 bytes) o di un indirizzo a 20/21 bit.
Se l' estensione dell' indirizzamento è limitata a 64k, Upper non ha
importanza.
;
Pointer to Table (over 64k)
movlw low Table
; low of address
movwf save_low
movlw high Table
; high of address
movwf
save_mid
movlw upper Table
; upper of address
movwf save_up |
e anche da label:
;
move byte from a multi byte label
LABEL = 0xFA32CB
movlw low LABEL ; low byte
movwf save_low
; save_low = CBh
movlw high LABEL
; high byte
movwf save_high
; save_high = 32h
movlw upper Table ; upper byte
movwf save_up ; now save_upper = FAh
; |
Nei PIC16, che hanno limite di memoria programma inferiore agli Enhanced,
la componente Upper non ha peso (indirizzamento < 32K)
Sono possibili calcoli di ogni genere, anche di formule complesse.
Ecco alcuni esempi di calcoli effettuati in automatico da MPASM.
Esempio di calcoli relativo al clock. Gli elementi calcolati sono resi
sotto forma di label per essere utilizzati o elaborati ulteriormente durante
il programma.
; CLOCK frequency = internal osc. - default al POR
XTAL_FREQ equ 1000000
; INTIO1 1 MHz
CLOCK equ XTAL_FREQ/4
; processor clock [Hz]
TCYC equ 1000000000/CLOCK
; cycle time [ns]
|
Calcoli relativi a baudrate (USART), al clock di Timer1
e a quello dell' I2C (MSSP).
; calculates baudrate when BRGH = 1, adjust for rounding errors
#define CALC_HIGH_BAUD(BaudRate)
(((10*XTAL_FREQ/(16*BaudRate))+5)/10)-1
; calculates baudrate when BRGH = 0, adjust for rounding errors
#define CALC_LOW_BAUD(BaudRate)
(((10*XTAL_FREQ/(64*BaudRate))+5)/10)-1
; calculates timer1 delay when prescale is 1:8, TcikTime in msec
#define CALC_TIMER1(TickTime)
(0xFFFF-((TickTime*XTAL_FREQ)/32000))+1
; used for I2C calculations
#define I2CClock D'100000'
; define I2C bite rate
#define I2C_ClockValue (((XTAL_FREQ/I2CClock)/4)
-1)
....
; esempio di uso
movlw LOW(CALC_TIMER1(D'100'))
movwf TMR1L
; initialize Timer1 low
movlw HIGH(CALC_TIMER1(D'100'))
movwf TMR1H
; initialize Timer1 high
|
Esempio di settaggio di paramenti per macro
DEST_HIGH SET (HIGH(LABEL)&0x18)
; save bit's 4:5 of dest adress
SOURCE_HIGH SET (HIGH($)&0x18)
; source adress
DIFF_HIGH SET DEST_HIGH ^ SOURCE_HIGH
; get difference (XOR)
|
Esempio di calcolo di indirizzo per generare un warning
IF ((DIFF_HIGH&0x18)==0x18)
MESSG " WARNING ! Replace SHORT_CALL with LONG_CALL " LABEL
ENDIF
|
Esempio di calcolo per PWM (modulo CCP)
PWM_Period = (PR2 +
1)*4*Tosc*TMR2_PreScale_value
PR2 = (PWM_Period/(4 * Tosc * TMR2
Prescale)) - 1
PWM_Duty_Cycle = (CCPR1L_CCP1CON5_4)*Tosc*TMR2_Prescale_Value
|
Come si vede, la flessibilità del calcolatore di MPASM, unita all'uso di
label, permette di:
- evitare una parte consistente di calcoli manuali
- ottenere sorgenti con parametri facilmente modificabili
- adeguare automaticamente i parametri alle condizioni imposte
- trattare costanti come label evitando qualsiasi richiamo a valori
assoluti
- ottenere costanti che possono essere a loro volta ri elaborate e
trattate come label in altri punti del programma
Nel caso si superassero le possibilità di MPASM o fossero introdotti
elementi errati o non supportati, l' assembler invia un messaggio di errore.