(EDITAR: Se agregó el código de desmontaje C18)
Necesito optimizar una función escrita en C para un PIC18f4585. Estoy usando C18 para compilar.
La función que estoy tratando de reescribir en ensamblador es:
void readResetTimers (void)
{
register unsigned char tmr0_temp;
register unsigned char tmr1_temp;
tmr0_temp = TMR0L;
TMR0L = 0;
tmr1_temp = TMR1L;
TMR1L = 0;
tmr0_value = tmr0_temp;
tmr1_value = tmr1_temp;
}
Pensé que, en cambio, podría usar el código ensamblador para cargar el valor de cada registro en las variables tmr0_value y tmr1_value tal como se declaran en el espacio de nombres global, sin embargo, mi sistema no funciona cuando sustituyo el siguiente código en:
void readResetTimers (void)
{
_asm
MOVF TMR0L, 0, 1
MOVWF tmr0_value, 1
CLRF TMR0L,0
MOVF TMR1L, 0, 1
MOVWF tmr1_value, 1
CLRF TMR1L,0
_endasm
}
Cualquier idea sería apreciada, Saludos.
void readResetTimers (void)
04D4 CFD9 MOVFF 0xfd9, 0xfe6
04D6 FFE6 NOP
04D8 CFE1 MOVFF 0xfe1, 0xfd9
04DA FFD9 NOP
04DC 0E02 MOVLW 0x2
04DE 26E1 ADDWF 0xfe1, F, ACCESS
405: {
406: register unsigned char tmr0_temp;
407: register unsigned char tmr1_temp;
408:
409: /* Read the two timers into CPU registers and reset them
410: * as quickly as absolutely possible.
411: */
412:
413: tmr0_temp = TMR0L;
04E0 50D6 MOVF 0xfd6, W, ACCESS
04E2 6EDF MOVWF 0xfdf, ACCESS
414: TMR0L = 0;
04E4 6AD6 CLRF 0xfd6, ACCESS
415: tmr1_temp = TMR1L;
04E6 0E01 MOVLW 0x1
04E8 CFCE MOVFF 0xfce, 0xfdb
04EA FFDB NOP
416: TMR1L = 0;
04EC 6ACE CLRF 0xfce, ACCESS
417:
418: tmr0_value = tmr0_temp;
04EE CFDF MOVFF 0xfdf, 0xe4
04F0 F0E4 NOP
419: tmr1_value = tmr1_temp;
04F2 CFDB MOVFF 0xfdb, 0xe5
04F4 F0E5 NOP
431:
432: }
Como desea reemplazar toda la subrutina, el ensamblador en línea es un poco tonto. Escribe toda la rutina en ensamblador. De esa manera, el compilador no puede interferir haciendo cosas al entrar y salir de la rutina y cosas por el estilo.
También sería mejor explicar lo que realmente quiere que haga esta rutina que definirla implícitamente con código C. Tienes:
tmr0_temp = TMR0L; TMR0L = 0; tmr1_temp = TMR1L; TMR1L = 0; tmr0_valor = tmr0_temp; tmr1_valor = tmr1_temp;
Aparentemente, desea una instantánea del temporizador 0 en modo de 16 bits en una variable separada. Su código anterior no funcionará para eso en todos los casos, ya que no se ocupó del incremento de bytes altos entre las dos lecturas.
A menos que acceda a los dos registros finales en una rutina que podría verse interrumpida por esta, no es necesario el registro temporal. En realidad, sin deshabilitar las interrupciones, no puede garantizar que el valor final de 16 bits se escriba atómicamente de todos modos. O te importa la actualización atómica o no. Su método no tiene sentido, ya que parece importarle una parte, pero al final no lo garantiza.
También está reiniciando el temporizador a 0, lo que suele ser una mala idea. Esto suele ser el resultado de querer hacer mediciones secuenciales de intervalos de tiempo sin haberlo pensado muy bien. Si la razón por la que necesita que esta rutina se ejecute tan rápido es porque desea minimizar las instrucciones que pierde al reiniciar el temporizador, entonces esta es definitivamente la forma incorrecta de hacerlo. Tome una instantánea en cada punto entre el que desea medir el intervalo, luego haga una resta de 16 bits sin signo. Eso le dará el intervalo sin ciclos perdidos cuando se reinicie el temporizador.
Si puede permitirse que el temporizador se apague durante algunos ciclos, simplemente apáguelo, léalo, bórrelo y reinícielo. Realmente no veo un caso en el que tu método tenga sentido.
En cualquier caso, aquí hay un fragmento de código de ejemplo que toma una instantánea constante del temporizador 0 mientras lo deja en ejecución (no probado, ni siquiera verificado la sintaxis):
instantánea externa t0; instantánea de 16 bits del temporizador 0 ;**************************************************** ******************* ; ; Subrutina T0_GRAB ; ; Tome el valor actual del temporizador 0 en T0SNAPSHOT. El temporizador ; continuar corriendo todo el tiempo. ; global t0_grab t0_grab banksel t0snapshot; establece el banco para acceder a la variable de salida t0_retry ;volver aquí si cambió el byte alto movf tmr0h, w ;obtiene el byte alto del temporizador movwf t0snapshot+1 ;guardarlo movff tmr0l, t0snapshot+0 ;toma el byte bajo xorwf tmr0h, w ;compruebe el byte alto de nuevo bnz t0_retry; el byte alto cambió, ¿intentar de nuevo? devolver
Tenga en cuenta esta construcción llamada "comentarios" en esta rutina. Esas son cosas muy útiles que necesita aprender. El código no documentado realmente no es ningún código.
adam lorenzo
Kaz
chib