Introdução aos sistemas embebidos Introdução i) Modos de endereçamento PIC 16C54 Instruções sempre com 12 bits • • • imediato movlw k ; com 0 <= k <= 255 movlf k, f ; 0<= f <= 31 ; é no entanto impossível (não existe) pois na instrução não existe o ; campo f para indexar o ficheiro de registos. ; Uma solução com 2 instruções (a ultima directa), será: movlw movwf k f ; implicita ; directa directo (ou sobre o ficheiro de registos orientada ao byte) movf f, d ; se d=0 ou W -> para acumulador ou Wreg ; se d=1 ou F -> mantém no mesmo registo f (mas testa a flag Z (Z=0 sse conteúdo de f=0) movwf f ; W -> f incf f, d ; se d=0 ou W -> Wreg = f +1 ; se d=1 ou F -> f = f +1 incfsz f, d ; idêntico ao anterior mas se resultado = 0 salta a próxima instrução directo (ou sobre o ficheiro de registos orientada ao bit) Soluções guia prático 1 - 1 Introdução aos sistemas embebidos Não é possível operar sobre o acumulador, pois não tem o campo d. As operações possíveis são apenas: 7 • bcf bsf f, b ; o bit b do registo f é colocado a zero a um btfsc btfss f, b ; se o bit b do registo f é 0 salta a próxima instrução 1 0 f reg indirecto Idêntico ao directo, mas se for usado o registo INDF, o acesso é efectuado ao registo fxx, onde 0 <= xx <= 31 é dado pelo valor do registo FSR. acesso aos registos f10 (16), f11(16) ...: movlw 0x10 movwf FSR ; implicito ; directo w<- 0x10 FSR<- W movwf INDF movf INDF, W ; indirecto ; indirecto f10(16)<-W W<-f10(16) incf FSR, F movf INDF, W ; directo FSR->f0x11 ; indirecto W<-f11(16) O registo f0 ou INDF não existe fisicamente. Se em FSR for indexado este, i.e. FSR = 0, na leitura é lido 0 e a escrita corresponde a NOP. ii) Comprimento das instruções Instruções que mexem no PC demoram 2 ciclos. As restantes apenas um. Exemplos: goto call return incfsz Soluções guia prático 1 - 2 i.e. retlw 0 e semelhantes instruções condicionais, se a condição fôr verdadeira isto é se fôr saltada a próxima instrução. Introdução aos sistemas embebidos iii) Registo de Status o registo de STATUS é actualizado pelas instruções por cada instrução: iv) Definição de constantes Temp EQU 0x10 É equivalente à directiva do pr-processador C #define Temp 0x10 De modo que antes de se iniciar o assembler todas as ocorrências de Temp são substituídas por 0x10. E útil para dar nomes a constantes, que podem ser utilizadas no modo de endereçamento imediato, ou a registos. Soluções guia prático 1 - 3 Introdução aos sistemas embebidos 1. a. / b. Comparação por subtracção para números positivos: PIC não tem instruções nativas para este efeito. Uma forma de verificar se um numero é maior que o outro é: F–W se W maior que F, o resultado é negativo e a carry flag do registo STATUS é tem o valor 1. Se W menor ou igual a F, C=1. (Para ver se é igual deve-se testar a flag zero, que é seleccionada se o resultado de uma operação fôr zero. (Z = 1)) Para testar a flag C (Z) e saltar a próxima instrução se igual a 0 (ou 1): btfsc btfss STATUS, C STATUS, C (Z) (Z) Uma solução que usa esta técnica é apresentada a seguir: Solução 1: ; the example considers an array of 6 unsigned integer elements ; for testing with 16 elements change the value N_ELEMENTS to 16 LIST P=16C54 #INCLUDE "P16C5x.INC" N_ELEMENTS equ d'6' ; number of array elements MIN equ B'00000000' REG_BEGIN equ d'12' REG_END equ REG_BEGIN+N_ELEMENTS max equ d'10' address equ d'11' org 0x000 movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf d'10' REG_BEGIN d'11' REG_BEGIN+1 d'12' REG_BEGIN+2 d'13' REG_BEGIN+3 d'14' REG_BEGIN+4 d'2' REG_BEGIN+5 call max_array nop ; used for simulation: to insert a breakpoint ;loop goto loop ; another way to stop here Soluções guia prático 1 - 4 Introdução aos sistemas embebidos max_array ; set the address to the first array element movlw REG_BEGIN movwf address movwf FSR ; set max to minimum movlw MIN movwf max next movlw REG_END subwf address, W btfsc STATUS, Z goto end_loop movf INDF, W subwf max, W btfsc STATUS, C goto inc movf INDF, W movwf max inc incf address incf FSR goto next end_loop return END Comprimento do código: Comprimento do código para a rotina max_array: 32 instruções de 12 bits. (6 elementos) 19 instruções de 12 bits. O número de ciclos de relógio pode variar dependendo das vezes que fôr necessário actualizar o o valor do máximo. Assim o mínimo número de ciclo de relógio é dado quando o primeiro elemento do array é o maior positivo, isto é 127, e o máximo quando os elementos do array formam uma sucessão crescente. Tempo de execução em ciclos de relógio (para 6 elementos): mínimo: 104 máximo: 109 Outra solução possível optimizando um pouco o código anterior.: Solução 2: A técnica usada para endereçar o ficheiro de registo é idêntica à da solução anterior, e usa os registos apresentados a seguir. O ficheiro de registos desde baseadr até baseadr+dim-1, guarda o vector de números positivos, sendo utilizado INDFe FSR para o indexar: Soluções guia prático 1 - 5 Introdução aos sistemas embebidos counter FSR max baseadr . : baseadr+dim-1 Isto é, por exemplo: movf INDF, W W <- baseadr [FSR] Constantes utilizadas: minimum mínimo, por defeito 0. dim dimensão do array, por defeito 6. Registos: baseadr max counter Registo que guarda o primeiro elemento do array Registo que guarda o elemento máximo do array Registo utilizado como contador para indexar o array de registos desde baseadr até baseadr-1 list p=16c54 #include <p16c5x.inc> ; list directive to define processor ; processor specific variable definitions __CONFIG _CP_OFF & _WDT_ON & _RC_OSC ; '__CONFIG' directive is used to embed configuration word within .asm file. ; The lables following the directive are located in the respective .inc file. ; See respective data sheet for additional information on configuration word. ORG goto ;CONSTANT DEFINITIONS temp0 EQU temp1 EQU temp2 EQU temp3 EQU temp4 EQU temp5 EQU ;Minimum value allowed minimum EQU 0x1FF start 0x04 0x00 0x47 0x47 0x77 0x00 ; processor reset vector ;example ;example ;example ;example ;example ;example B'00000000' variable variable variable variable variable variable definition definition definition definition definition definition ;Binary ;FILE REGISTER ARRAY INIT ADR AND DIMENSION and maximum value returned baseadr EQU 0x10 ;Hexa dim EQU d'6' ;decimal max EQU baseadr-1 Soluções guia prático 1 - 6 Introdução aos sistemas embebidos ;LOAD ARRAY INTO FILE REGISTER start ORG 0x000 movlw temp0 movwf baseadr movlw temp1 movwf baseadr+1 movlw temp2 movwf baseadr+2 movlw temp3 movwf baseadr+3 movlw temp4 movwf baseadr+4 movlw temp5 movwf baseadr+5 wait call goto maximum wait ;SUB-ROUTINE FIND MAXIMUM IN ARRAY: baseadr[dim] (only unsigned numbers) ;Destroy registers: counter and max ; ;At exit max register holds maximum value of array ; counter EQU baseadr-2 ;COUNT TO END OF ARRAY maximum movlw minimum movwf max ; initialize max to minimum value allowed ; or simply: "clrf movlw dim movwf counter movlw baseadr movwf FSR loop movf INDF, W subwf max, W btfsc STATUS, C goto max" if minimum=0 ;initialize counter to array dimension ;put baseadr in FSR indirect register ; ; ; ; ; ; Compare fx with max (unsigned only) positivos i.e. 0 <= n <= 12 W <- baseadr[FSR] max - W if W > max jump (if carry=0 no actualization of max) inc movf INDF, W movwf max ; if fx greater: max <- fx incf FSR decfsz goto loop ; move to next element in array inc counter return END ; directive 'end of program' Comprimento do código: Comprimento do código para a rotina maximum: 29 instruções de 12 bits. (6 elementos) 16 instruções de 12 bits. Soluções guia prático 1 - 7 Introdução aos sistemas embebidos Tempo de execução em ciclos de relógio (para 6 elementos): mínimo 76 máximo 81 Embora o número de instruções seja apenas de menos 3 que no caso anterior, como o comprimento de cada iteração é reduzido (em termos de instruções), o número de ciclos de relógio também é reduzido. De notar que tanto nesta solução como na anterior a diferença de ciclo de relógio entre o caso máximo e mínimo é igual ao número de elementos do array menos um: Ciclos (máx) - Ciclos (min) = dim -1 = 5 Como o número de iterações é igual ao número de elementos, concluí-se que só uma instrução a mais é executada em cada iteração, que é precisamente a instrução que actualiza o registo que guarda o valor do elemento máximo. A análise de tempo é importante principalmente em sistemas de tempo real, pois nestes o tempo de execução tem de ser previsível, de modo que os processos se executem dentro de metas temporais previamente definidas. Neste caso a rotina não funciona em tempo constante, se bem que sejam possíveis soluções em tempo constante. Quando o tempo de execução não é constante, deve-se fazer uma análise de pior caso, determinando o tempo máximo. 1. c. / d. Para generalizar as soluções anteriores para números com sinal, pode-se utilizar duas técnicas. A primeira consiste em verificar a flag de Sinal, S, e de Overflow, O: Se S xor O == 1 A < B Senão A >= B Se o processador não disponibilizar no registo de STATUS a flag de Overflow esta pode ser obtida com o bit de carry que entra no BMS e o que saí, isto é a flag Carry. O = carry_in XOR carry_out Assim para o pic pode-se usar o algoritmo: OVERFLOW = carry_in XOR carry_out Se OVERFLOW XOR SIGNAL(A-B) == 1 Senão A >= B A<B Solução 1: Modificando a Solução 1 da alínea anterior segundo esta técnica, também para arrays com 6 elementos, têm-se: Soluções guia prático 1 - 8 Introdução aos sistemas embebidos LIST P=16C54 #INCLUDE "P16C5x.INC" N_ELEMENTS MIN REG_BEGIN REG_END max address sub_res aux1 equ equ equ equ equ equ equ equ d'6' B'10000000' ; minimum integer value d'12' REG_BEGIN+N_ELEMENTS d'10' d'11' d'9' d'8' org 0x000 movlw d'127' movwf REG_BEGIN movlw -d'1' movwf REG_BEGIN+1 movlw d'12' movwf REG_BEGIN+2 movlw d'15' movwf REG_BEGIN+3 movlw d'78' movwf REG_BEGIN+4 movlw d'100' movwf REG_BEGIN+5 call loop max_array goto loop max_array ; set movlw movwf movwf ; another way to stop in this position the address to the first array element REG_BEGIN address FSR ; set max to minimum movlw MIN movwf max next movlw subwf btfsc goto REG_END address, W STATUS, Z end_loop ; do the subtraction max-R[i] movf INDF, W subwf max, W movwf sub_res ; test the output carry/borrow of subtraction clrw btfsc STATUS, C movlw 0x80 ; if it is ONE xorwf sub_res, F ; xor carry with signal of subtraction ;test rlf movwf rlf the input carry/borrow in the MSB of subtraction max, W aux1 INDF, W Soluções guia prático 1 - 9 Introdução aos sistemas embebidos subwf aux1, W clrw btfsc STATUS, C movlw 0x80 xorwf sub_res, F ; if it is ONE btfss sub_res, 7 goto inc movf INDF, W movwf max inc incf incf goto address FSR next end_loop return END Comprimento do código: Comprimento do código para a rotina max_array: 45 instruções de 12 bits. (6 elementos) 32 instruções de 12 bits. Tempo de execução em ciclos de relógio (para 6 elementos): mínimo 182 máximo 187 São necessárias mais 13 instruções na sub-rotina max_array. Claro que o limite máximo e mínimo de tempo de execução também aumenta, no entanto a diferença permanece igual, 5 ciclos, o que indica que a diferença entre os dois casos continua a ser a actualização do elemento máximo. Solução 2: Pode-se tentar outra abordagem verificando o sinal de ambos os números. Assim quando o sinal de ambos os números fôr igual, mesmo que seja negativo, pode-se testar de acordo com a técnica da alínea a.. Os números negativos em complemento para dois são dados por: Módulo + número negativo para o caso de registos de 8 bits tem-se: Módulo (8 bits) = 28 = 256 256 256 256 = 255 = 254 = 253 0xFF 0xFE 0xFD B'11111111' B'11111110' B'11111101' (-127) = 129 (-128) = 128 0x81 0x80 B'10000001' B'10000000' = 127 =0 0x7F 0x00 B'01111111' B'00000000' + + + (-1) (-2) (-3) (...) 256 + 256 + positivos: Soluções guia prático 1 - 10 Introdução aos sistemas embebidos Deste modo, por exemplo: 2<3 2 - (+3) = -1 = FF (Carry = 0) 3>2 3 - (+2) = 1 (Carry = 1) -3 < -2 -3 - (-2) = -1 = FF (Carry = 0) -2 > -3 -2 - (-3) = 1 (Carry = 1) O que significa que a única alteração que deve ser efectuada na Solução 2 da alínea a., é verificar primeiramente, se os sinais do elemento corrente e do máximo são diferentes, de modo que o novo máximo seja o positivo. Além das alterações à rotina maximum é utilizado mais um registo do ficheiro para algumas operações aritméticas, principalmente devido às operações sobre bits e rotação não poderem ser efectuadas no acumulador. ;SUB-ROUTINE FIND MAXIMUM IN ARRAY: baseadr[dim] ;Destroy registers: counter, aux, max ; ;At exit max register holds maximum value of array ; counter EQU baseadr-2 ;COUNT TO END OF ARRAY aux EQU baseadr-3 ;AUX ARITHMETIC F REGISTER maximum movlw minimum movwf max ; initialize max to minimum value allowed movlw movwf movlw movwf dim counter baseadr FSR ;initialize counter to array dimension movf movwf movf xorwf btfss goto max, W aux INDF, W aux, F aux, 7 equal ;put baseadr in FSR indirect register loop ;test sign (bit 7) ; W <- baseadr[FSR] ;if equal sign then bit7 = 0 ;goto equal diff btfsc max, 7 goto actual goto inc ;if max negat. then fx posit. (and greater) ;goto actual ;else no actualization needed movf INDF, W subwf max, W btfsc STATUS, C ;compare fx with max (unsigned numbers) ; W <- baseadr[FSR] ;max - W ;if W > max jump (if carry=0 no ;actualization of max) equal goto inc Soluções guia prático 1 - 11 Introdução aos sistemas embebidos actual movf INDF, W movwf max ; if fx greater: max <- fx inc incf FSR decfsz counter goto loop ; move to next element in array return Comprimento do código: Comprimento do código para a rotina maximum: 37 instruções de 12 bits. (6 elementos) 24 instruções de 12 bits. Tempo de execução em ciclos de relógio (para 6 elementos): mínimo 105 máximo 117 Neste caso o tempo mínimo é obtido quando o valor máximo é encontrado no primeiro elemento, neste caso 128, todos os outros elementos são menores com sinal contrário, isto é negativo. O tempo máximo, sucede quando a sucessão é crescente e todos os elementos têm o mesmo sinal que o valor inicial, que neste caso é -128. Neste caso, como existem muito ramos de decisão, não é trivial determinar o ramo com comprimento máximo ou mínimo, e como tal sucede. Estes podem ser determinados, arranjando o código de forma semelhante a uma árvore de decisão, de modo a identificar os ramos maiores e menores, e em que casos é que são percorridos. Ainda se podia optimizar o código, fazendo com que o registo max seja inicializado com o primeiro elemento do array e não com a constante minimum, poupando-se assim uma iteração, e mantendo o mesmo número de instruções. Esta optimização poderia ser efectuada também para a alínea anterior. Código original maximum Modificações maximum movlw movwf minimum max movf movwf baseadr, W max movlw movwf movlw movwf dim counter baseadr FSR movlw movwf movlw movwf dim-1 counter baseadr+1 FSR Soluções guia prático 1 - 12