t-edson / PicPas

Compilador en Pascal para microcontroladores PIC / Pascal compiler for PIC microcontrollers
GNU General Public License v2.0
87 stars 27 forks source link

Definir variables numéricas tipo word como absolute o implementar Low(word) y High(word) #5

Closed AguHDz closed 7 years ago

AguHDz commented 7 years ago

Hola, he intentado acceder desde ensamblador a las partes LOW y HIGH de una variable numérica tipo word.

No he encontrado un modo ya implementado de acceder a ellas, y realizando pruebas he intentado definir esto:

var
   resultado : word absolute $20;
   resultadoLOW : byte absolute $20;
   resultadoHIGH : byte absolute $21;

Sin embardo, el resultado no ha sido el esperado ya que el compilador asigna la misma dirección a la parte alta y baja de la variable tipor word si se define como absoluta:

resultado@0 EQU 0x020
resultado@1 EQU 0x020
resultadoLOW EQU 0x020
resultadoHIGH EQU 0x021

Supongo que en principio (sin optimizaciones) resultado@1 debería haber ocupado la dirección 0x021.

¿Se complicado implementar las función High(word) y Low(word) de conversión para acceder a las partes LOW y HIGH de variables word?

Gracias. Un saludo.

t-edson commented 7 years ago

El tipo WORD está un poco descuidado en las últimas versiones de PicPas, pero voy a revisarlo. PicPas plantea un problema diferente la mayoría de compiladores, porque los bytes asignados a las variables WORD, no siempre son consecutivas. Eso implica dos preguntas:

  1. ¿Cómo declaras una variable WORD en ABSOLUTE, si un WORD tiene dos direcciones?
  2. ¿Cómo accedes a las dos direcciones de una variable Word?

Las funciones internas Pascal, LO() y HI(), no permiten obtener las direcciones de los bytes, sino solo sus valores. Lo que se necesitaría, realmente sería una sintaxis nueva para acceder a cada byte de un Word. Estoy tentado a definir que las direcciones para un word, se definan siempre como consecutivas, y así, se ahorraría problemas.

t-edson commented 7 years ago

Este problema, está relacionado con un viejo pendiente de PicPas, y es el poder acceder a cada bit independiente de un Byte. Algo como PORTB.1 := 1; Entendiendo que todo byte es un conjunto de bits. De la misma forma se podría acceder a cada byte de un Word, usando campos. Algo como: resultado.low := $FF; Entendiendo que todo Word es la unión de dos bytes.

AguHDz commented 7 years ago

No soy capaz de entender la ventaja de que las variables de más de 1 byte ocupen posiciones no consecutivas. Seguramente tiene alguna, pero salvo en algún caso en que quede poca RAM o algo así, no le veo la ventaja, y aún menos en la programación de microcontroladores donde se ahorra mucho código si los bytes de información están ordenados de manera consecutiva. Además, si algún día PicPas maneja punteros a datos y matrices, al no ocupar posiciones consecutivas, el manejo se me hace ingobernable y muy poco práctico. Si por algún motivo te parece más conveniente u óptimo que no siempre ocupen posiciones consecutivas, se puede llegar a una solución intermedia en la que la variables de más de un byte declaradas como absolute ocupen posiciones de memoria consecutiva, y las no declaradas como absolute que sea el compilador el que decida durante la optimización.

En cuanto a las variables word como absolute, lo esperado sería que ocupen la posición indicada y la siguiente, si es Longint la indicada y las 3 siguientes, una Double la indicada y las 7 siguientes, etc.

Hi() y Lo() deben devolver precisamente el contenido de las posiciones de memoria, y además en forma de variable tipo byte. En principio la dirección que ocupen es indiferente, y si se necesitara conocer su dirección en la memoria RAM solo sería necesario declarar la variable como absolute y el problema estaría resuelto. :)

AguHDz commented 7 years ago

resultado.low y resultado.high sería otra solución, bueno, lo mismo que High() y Low() pero escrito de otra manera, de todas formas la asignación de valores no la veo tan necesaria (se pueden asignar facilmente de una sola vez como un dato word, sobre todo si un dato word se puede asignar en hexadecimal que no lo he probado) , pero el problema viene cuando quieres hacer algo como la salida de un puerto que siempre debe ser un tipo de dato byte, el byte bajo es fácil de sacar, pero la parte alta es en donde se me han planteado las dudas y problema. En realidad lo que estaba intentado codificar eran las operaciones multiplicación y división escritas como procedimientos en ensamblador con dos datos de entrada en tipo numérico byte y el resultado en tipo word.

t-edson commented 7 years ago

Sí. El poner direcciones no consecutivas para variables Word, es un tema de optimización, para aprovechar mejor la RAM. Podría incluirse una forma de desactivar esta característica. Las funciones Hi() y Lo(), en Pascal estándar, no devuelven variables, sino que son funciones. Podría implementarse como variables en PicPas, pero las propiedades .High y .Low, serían los más apropiados. Habría que ver, si es factible la implementación, y por lo que veo sí lo sería, porque PicPas permite definir operadores por tipo.. habría que definir el operador "." para el tipo Word, y luego los métodos Low y High. Sería un bonito experimento para definir métodos. Pero hay un problema técnico de devolución de resultados, porque aquí se debe devolver una variable, que no ha sido declarada. Ya se verá..

t-edson commented 7 years ago

Por otro lado, he intentado reproducir el error que indicas, pero no lo logro. Si creo este código:

{$FREQUENCY 8 MHZ }
{$PROCESSOR PIC16F84A}
var
   resultado : word absolute $20;
   resultadoLOW : byte absolute $20;
   resultadoHIGH : byte absolute $21;
begin                          
  resultado := 1;
  resultadoLOW := 0;
  resultadoHIGH := 0;
end.

Lo que ami me genera es:

;===RAM usage===
resultado@0 EQU 0x020
resultado@1 EQU 0x00C
resultadoLOW EQU 0x020
resultadoHIGH EQU 0x021
AguHDz commented 7 years ago

Supongo que porque había definido más variables, era una parte de un programa más amplio.

Pero mira:

{$FREQUENCY 8 MHZ }
{$PROCESSOR PIC16F84A}
var
   resultado : word absolute $0C;
   resultadoLOW : byte absolute $0C;
   resultadoHIGH : byte absolute $0D;
begin                          
  resultado := 1;
  resultadoLOW := 0;
  resultadoHIGH := 0;
end.

Si defino la variable word en la primera posición que el compilador considera libre (la $0C), si se asignan valores consecutivos a las dos posiciones de memoria de la variable tipo word, con lo que las variables LOW y HIGH quedan perfectas...

;===RAM usage===
resultado@0 EQU 0x00C
resultado@1 EQU 0x00D
resultadoLOW EQU 0x00C
resultadoHIGH EQU 0x00D

Si el resultado fuera siempre en este orden, el problema estaría resuelto (por lo menos, desde mi punto de vista)... creo que con este "truco" de superponer variables tipo byte y word lo que estamos haciendo es algo muy parecido al uso de punteros.

AguHDz commented 7 years ago

Estuve buscando el código fuente que produjo el error:

resultado@0 EQU 0x020
resultado@1 EQU 0x020

pero supongo que como eran pruebas, reescribí nuevo código en el mismo fichero y no lo he podido recuperar. Pero algún bug debe haber para que en determinadas circunstancias defina en la misma posición de la memoria los dos bytes de un dato tipo word. Estoy seguro de que es un copia y pega, por lo que ese código ensamblador se generó de alguna manera o en alguna combinación, con no se que parámetros. De todas maneras, si no se arregla de manera "colateral" al actualizar o corregir otras secciones del compilador, tarde o temprano volverá a salir en algún lado.

t-edson commented 7 years ago

Más parece un "bug", pero mientras no se pueda reproducir, no se podrá corregir. La nueva versión modificará diversas rutinas del procesamiento del tipo Word, y como tu dices, podría haber un efecto colateral, pero esa no es la filosofía de diseño de PicPas. Aún no he revisado la asignación de memoria para el tipo Word. Si encuentro alguna novedad, te aviso.

t-edson commented 7 years ago

El acceso a los bytes de un Word, se está habilitando en la versión 0.6.7, asi como el acceso a los bits de un Byte. Ya está próxima a liberarse.

t-edson commented 7 years ago

Ya está solucionado en la versión 0.6.7. Puedes definir variables Byte como:

w: word;
w1: byte absolute w.Low;
w1: byte absolute w.High;

Pero esto no es siquiera necesario, si quieres acceder desde un bloque ASM, porque desde allí mismo, se puede acceder a los bytes de un word.

AguHDz commented 7 years ago

Enhorabuena! Funciona perfectamente. Este es el ejemplo de aplicación que dio lugar ha hablar de este error que ya se puede cerrar como resuelto. Un procedimiento escrito en ASM que multiplica dos datos en formato bytes, y el resultado lo guarda en una variable tipo word.

var
  resultado : word;  // Variable global necesaria para devolver el valor de multiplicacion.

//***********************************************************************
//  PROCEDIMIENTO: Multiplicacion
//  Multiplica dos valores de 8 bits.
//  El resultado queda almacenado en una variable global llamada resultado.
//  Por ahora PicPas (v.0.6.7) no permite el uso de funciones.
//***********************************************************************
procedure Multiplicar (multiplicando, multiplicador : byte);
begin
ASM
;Inicializacion de Registros
  BCF STATUS,5              ; RP0=0 / Trabajamos en el Banco de memoria 0.
  CLRF resultado.LOW        ; Limpia el byte bajo de la variable global resultado.
  CLRF resultado.HIGH       ; Limpia el byte alto de la variable global resultado.
;Comprueba multiplicacion por cero.
  MOVLW $00
  SUBWF multiplicador,W
  BTFSC STATUS,2
  GOTO MULT_FIN             ; Si multiplicador = 0 entonces acabar.
;LOOP de multiplicacion
MULT_LOOP:
  MOVF multiplicando,W      ; Carga el multiplicador en el registro W.
  ADDWF resultado.LOW,F     ; Suma el valor de multiplicando al byte bajo de la variable global resultado
  BTFSC STATUS,0            ; Comprueba el bit CARRY del registro STATUS.
  INCF resultado.HIGH,F     ; Si CARRY es 0 resultado.LOW se ha desbordado se incrementa resultado.HIGH
  DECFSZ multiplicador,F    ; Decrementa multiplicador y comprueba si ha llegado a cero.
  GOTO MULT_LOOP            ; nuevo paso del bucle de multiplicacion.
MULT_FIN:
END
end;
t-edson commented 7 years ago

Excelente, voy a incluir tu código, en la lista de ejemplos de PicPas, si me lo permites.

AguHDz commented 7 years ago

Por supuesto que si te lo permito, puedes añadir, modificar o incluir cualquier código de los que hago públicos.