Melhorando código assembly

Software e Hardware para uC PIC

Moderadores: andre_luis, 51, guest2003, Renie

Melhorando código assembly

Mensagempor zielpunkt » 12 Out 2006 19:12

Olá, para os que, como eu, sofrem com o assembly.

Programar em assembly não é o que podemos chamar de um passeio no parque. Mas para os MCU, principalmente quando espaço x custo x desempenho é crítico, um código asm bem feito ainda é, penso, importante. Acho que o assunto não é necessariamente novidade mas há algum tempo comecei a utilizar algumas macros que possibilitaram tornar o meu trabalho em assembly um pouco mais "elegante", eu diria, e sem inchar muito o código. Elas foram desenvolvidas pelo Mike Predko, nos idos de 1999, e venho adaptando alguns includes importantes para o meu uso a partir delas. São umas tais de "varstart" junto com a principal que é a "varadd". Elas permitem que se criem includes do tipo "usart.inc", "ht1380.inc", "lcd2x16.inc" e muitos outros módulos que se tornam razoavelmente portáveis ou, pelo menos, diminuem um pouco o trabalho com novos códigos. Claro que inicialmente é tudo "na unha". Mas o programa principal fica, a partir desses includes, bastante mais "legível" e de melhor manutenção. Seguem alguns trechos de código interessantes:

;*****************************************************
;*****************************************************
; VARS.inc
;*****************************************************
; VARSTART (BEGIN/END ADDRESSES) PLACES ON MCU REGS
; VARADD (LABEL, SIZE) SPECIFY VARIABLE AND ITS SIZE
;
VARSTART MACRO MSTART, MEND
IFDEF VARSTARTVAR
ERROR "'VARSTART' INVOCATION REPEATED MORE THAN ONCE!"
ELSE
#DEFINE VARSTARTVAR
ENDIF

VARCURRENT SET MSTART
VAREND SET MEND

ENDM

VARADD MACRO VARNAME, SIZE
IF (VARCURRENT>VAREND)
ERROR "TOO MANY VARIABLES FOR ALLOCATED FILE REGISTERS!"
ENDIF

VARNAME EQU VARCURRENT
VARCURRENT SET VARCURRENT+SIZE

ENDM
;*****************************************************

Então, você poderia iniciar seu código principal assim:

;*****************************************************
;*****************************************************
INCLUDE "p16f877A.inc"
INCLUDE "BANK_MACROS.inc"

; DECLARE PROCESSOR SPEED (Hz) -> USADO PARA "usart.inc" e "delayms.inc"
CONSTANT SPEED = 8000000
ERRORLEVEL -302

__CONFIG _BODEN_OFF & _CP_OFF & _CPD_OFF & _WDT_OFF e etc .....

; VARIABLES
INCLUDE "VARS.inc"

VARSTART 0X27, 0X6F ; (BANK0, UNTIL LEAST 16 MIRRORED ADRESSES)

VARADD ARROW_TMP,1
VARADD BCD_TMP,1
VARADD BUFFER,1
VARADD BUFFER2,1
VARADD BUFFER3,1
... etc, etc (esses são os registradores utilizados no código do programa principal)
;*****************************************************
ORG 0X000 ; INICIO EM '0'
GOTO MAIN

ORG 0X04 ; RTI START
GOTO INTERRUPT_ROUTINE
; INCLUDES FILES
INCLUDE "USART.inc"
INCLUDE "HT1380.inc"
INCLUDE "LCD2X16.inc"

;*****************************************************
;*****************************************************
....o seu código....

;*****************************************************

Utilizando a macro "varadd" dentro dos includes que voce cria, são definidas automaticamente as posições das variáveis utilizadas dentro dos mesmos, na compilação, sem conflito com as demais utilizadas no programa. Um exemplo para "usart.inc":

;*****************************************************
; USART.inc
; PIC16 INTERNAL HARDWARE USART DRIVER - by zielpunkt
;
; STATEMENTS: USART_TX
; USART_RX
;
; INPUT: W = DATA TO SEND
;
; OUTPUT: VAR_USART_DATA = DATA RECEIVED
; VAR_USART_RXDAT_FLAG = 1, DATA RECEIVED OCCOURS
; VAR_USART_RXERR_FLAG = 1, ERROR WHEN RECEIVING
;*****************************************************
VARADD VAR_USART_FLAGS,1
VARADD VAR_USART,1
VARADD VAR_USART_DATA,1

#DEFINE VAR_USART_RXERR_FLAG VAR_USART_FLAGS, 0 ; 1, ASSIGN ERROR WHEN RECEIVING
#DEFINE VAR_USART_RXDAT_FLAG VAR_USART_FLAGS, 1 ; 1, ASSIGN THERE ARE DATA RECEIVED
#DEFINE VAR_USART_INTER_FLAG VAR_USART_FLAGS, 2 ; 1, ASSIGN THAT GIE WAS 'ON'
;
;******************************************************************************
;******************************************************************************
; MACROS
;******************************************************************************
;******************************************************************************
USART_INI MACRO
CALL USART_INI_
ENDM

USART_TX MACRO
CALL USART_TX_
ENDM

USART_RX MACRO
CALL USART_RX_
ENDM
;
;*****************************************
;*****************************************
; USART SETUP
;*****************************************
;*****************************************
USART_INI_
IF ((SPEED - 4000000) == 0)
MOVLW .25
MOVWF VAR_USART
ENDIF

IF ((SPEED - 8000000) == 0)
MOVLW .51
MOVWF VAR_USART
ENDIF

MOVFW VAR_USART
BANK1 ; TXSTA SETUP
MOVWF SPBRG ;

MOVLW B'00100100' ; ENABLE TX, ASYNC MODE, 8 BIT, HIGH SPEED
MOVWF TXSTA ;

BANK0 ; RCSTA SETUP
MOVLW B'10010000' ; ENABLE RX, 8 BIT, RX STOPED, ADDRESS DISABLED
MOVWF RCSTA ;
RETURN ;
;*****************************************
;*****************************************
; LOCAL - DISABLE INTERRUPTS
;*****************************************
;*****************************************
USART_DEAL_INTERR

BTFSS INTCON, GIE ; THERE WAS GIE_ON?
RETURN ; NO, JUST BACK

BCF INTCON,GIE ; DISABLE ALL INTERRUPTS
BTFSC INTCON,GIE ; IS INTCON DISABLED ?
GOTO $-1 ; NO, WAITING....
BSF VAR_USART_INTER_FLAG; ASSIGN IT
RETURN
;*****************************************
;*****************************************
; SUB SEND DATA BYTE BY SERIAL
;*****************************************
;*****************************************
USART_TX_
BCF VAR_USART_INTER_FLAG; DEAL INTERRUPTS
CALL USART_DEAL_INTERR ;

BANK1 ;
BTFSS TXSTA,TRMT ; IS TX BUFFER EMPTY ?
GOTO $-1 ;
BANK0 ;

MOVWF TXREG ; SEND 'W' DATA

BTFSC VAR_USART_INTER_FLAG; THERE WERE INTERRUPTS ON?
BSF INTCON,GIE ; YES, ENABLE INTERRUPTS
RETURN
;*****************************************
;*****************************************
; SUB RECEIVE DATA FROM SERIAL
;*****************************************
;*****************************************
USART_RX_
BCF VAR_USART_RXERR_FLAG; NO ERROR, YET...
BCF VAR_USART_RXDAT_FLAG; NO DATA RECEIVED, YET...

BSF RCSTA,CREN ; ENABLE SERIAL RECEIVER
BTFSS PIR1,RCIF ; WAS RECEIVED DATA ?
RETURN ; NO DATA RECEIVED

; BTFSS RCSTA,FERR ; IS BIT_STOP OK? (FERR=0=OK)
; GOTO $+3 ;
; BSF VAR_USART_RXERR_FLAG; RETURNS WITH ERROR ASSIGNED
; RETURN

BCF PIR1, RCIF ; CLEAR INTERRUPT FLAG
BSF VAR_USART_RXDAT_FLAG; ASSIGN SERIAL DATA RECEIVED
MOVFW RCREG ; TRANFER THE DATA TO 'W'
MOVWF VAR_USART_DATA ; AND THEN TO BUFFER
RETURN
;*****************************************************

O resultado disso é que voce passa a criar bibliotecas práticas dos principais periféricos que utiliza e pode utilizar chamadas do tipo "usart_tx", "usart_rx", "rtc_read", "lcd_print", etc, a partir do programa principal. São apenas idéias e alguns fragmentos de código que podem parecer um pouco confusos, mas que, mesmo com algumas limitações, funcionam. Principalmente para a visualização de um código asm mais "limpo". É isso.

zielpunkt
"Talento é mais barato que sal. O que separa a pessoa talentosa da bem-sucedida é muito trabalho duro." [ Stephen King ]
zielpunkt
Byte
 
Mensagens: 376
Registrado em: 12 Out 2006 11:36
Localização: Sao Paulo - SP

Mensagempor mastk » 14 Out 2006 21:21

Interresando cara, então o esquema fica assim, dentro da macro declarada, basta pra variaveis q vou nescessitar:

VARADD TEMPO;variavel de tempo usada na rotina de delay

Bem a tecnica de macro eu uso a mili a ano tambem, vc pega tudo pronto, feito por vc msm, tudo confiavel, o codigo sai em pouco instantes pequeno e eficiente, muito melhor q C, eu acho :wink:

Só falta testar pra fixar a tecnica na cabeça...
Avatar do usuário
mastk
Dword
 
Mensagens: 4407
Registrado em: 14 Out 2006 20:43

Mensagempor zielpunkt » 16 Out 2006 09:57

Então, mastk, o pai da idéia tem um texto interesante a respeito: http://www.rentron.com/Myke8.htm. É aquilo: sempre vai depender de fazer muita coisa na raça, mas no final, diferente de uma macro que vc insere repetidas vezes no corpo do programa, esses acabam ficando meio como 'componentes' (na verdade, são as suas subrotinas, só que mais inteligentes e flexíveis). Têm várias limitações, claro, e nem dá pra comparar com a sofisticação que o 'C' oferece, mas deixa as coisas um pouco mais automáticas no assembly. É isso.

zielpunkt.
"Talento é mais barato que sal. O que separa a pessoa talentosa da bem-sucedida é muito trabalho duro." [ Stephen King ]
zielpunkt
Byte
 
Mensagens: 376
Registrado em: 12 Out 2006 11:36
Localização: Sao Paulo - SP


Voltar para PIC

Quem está online

Usuários navegando neste fórum: Nenhum usuário registrado e 1 visitante

x