;-------------------------------------------------------------------------------
; MSP430 Assembler Code Template for use with TI Code Composer Studio
; Módulo: pt.asm
; Fecha: 9 nov. 2025
; Author: ayboc
;-------------------------------------------------------------------------------

            .cdecls C,LIST,"msp430.h"       ; Include device header file
            .cdecls C,LIST,"msp430ports.h"
            .cdecls C,LIST,"pt.h"
            
;-------------------------------------------------------------------------------
            .text                           ; Assemble into program memory.
            .retain                         ; Override ELF conditional linking
                                            ; and retain current section.
            .retainrefs                     ; And retain any sections that have
                                            ; references to current section.

			.global TabPuertos, TabBits
			.global ptConfigura, ptLee, ptEscribe, ptLeeDir, ptEscDir, ptLeeHabRes, ptEscHabRes
			.global ptLeeHabIRQ, ptEscHabIRQ, ptLeeIRQ, ptBorraIRQ, ptLeeFlanco, ptEscFlanco

;********************************************************************************
; ptDecodifica
;
; Dado un puerto codificado de tipo puerto_pt, devuelve la dirección base del mismo
; y su máscara de bit.
; Entrada: R12: puerto
; Salida: R11: Dirección base del puerto (NULL en caso de error)
;         R12: Polaridad:Número de puerto (MSB:LSB)
;		  R15: Máscara del bit
; Conserva: Todo lo demás
;********************************************************************************
ptDecodifica
			mov.b	r12, r15				;R15=Puerto
			and.b	#0x7, r15				;R15=nº de bit
			mov.b	TabBits(r15), r15		;R15=Máscara del bit
			rra.w	r12
			rra.w	r12
			rra.w	r12
			mov.b	r12, r11				;R11=puerto

			;Precondiciones
			and.b	#0xF, r11				;R11=nº de puerto
			cmp.w	#MINP, r11				;Puerto menor que mínimo?
			jl		ptDecErr				;...sí, salir con error
			cmp.w	#MAXP+1, r11			;...no. Puerto mayor que máximo?
			jge		ptDecErr				;...sí, salir con error
			rla.w	r11						;R11=offset en TabPuertos
			mov.w	TabPuertos(r11), r11	;R11=Dirección base del puerto

			;Mover bit 4 a bit 8 y borrar bit 4 (polaridad)
			bit.b	#BIT4, r12				;BIT4 al carry
			jnc		ptDecNo					;Si es cero, no hacer nada
			bis.w	#BIT8, r12				;Mover a BIT8
ptDecNo		bic.w	#0xFEF0, r12			;Borrar BIT4 y MSB excepto BIT8
			jmp		ptDecFin
ptDecErr	clr.w	r14						;Código de salida con error
ptDecFin	ret


;********************************************************************************
; int ptLeeAlgo (puerto_t pt, int donde);
;********************************************************************************
ptLeeAlgo	call	#ptDecodifica			;Obtener dirección base y máscara de puerto
			tst.w	r11						;Puerto erróneo?
			jz		ptEscAlgoF				;...sí, salir

			;Para ciertos registros, comprobar si el puerto está entre 1 y 4
			cmp.b	#PIES, r13				;Es un registro relacionado con las interrupciones?
			jlo		ptLeeAlgoNo				;...no, no hace falta comprobar nada más
											;...sí. El registro debe estar en el rango [1, 4]
			cmp.b	#1, r12					;Menor que 1?
			jlo		ptLeeAlgoF				;...sí, salir
			cmp.b	#5, r12					;...no. Mayor que 4?
			jhs		ptLeeAlgoF				;...sí, salir
ptLeeAlgoNo

			;Leer bit
			add.w	r13, r11				;R11=dirección absoluta del registro a tratar
			mov.b	@r11, r12				;Leer registro completo
			and.b	r15, r12				;Dejar sólo el bit deseado
ptLeeAlgoF	ret

;********************************************************************************
; void ptEscAlgo (puerto_t pt, int algo, int donde);
;********************************************************************************
ptEscAlgo	call	#ptDecodifica			;Obtener dirección base y máscara de puerto
			tst.w	r11						;Puerto erróneo?
			jz		ptEscAlgoF				;...sí, salir

			;Para ciertos registros, comprobar si el puerto está entre 1 y 4
			cmp.b	#PIES, r14				;Es un registro relacionado con las interrupciones?
			jlo		ptEscAlgoNo				;...no, no hace falta comprobar nada más
											;...sí. El registro debe estar en el rango [1, 4]
			cmp.b	#1, r12					;Menor que 1?
			jlo		ptEscAlgoF				;...sí, salir
			cmp.b	#5, r12					;...no. Mayor que 4?
			jhs		ptEscAlgoF				;...sí, salir
ptEscAlgoNo

			;Configurar bit
			add.w	r14, r11				;R11=dirección absoluta del registro a tratar
			tst.w	r13						;Qué se quiere escribir?
			jnz		ptEscAlgo1				;...1. Escribir 1
ptEscAlgo0	bic.b	r15, 0(r11)				;...Escribir 0
			jmp		ptEscAlgoF
ptEscAlgo1	bis.b	r15, 0(r11)				;Escribir 1
ptEscAlgoF	ret

;-------------------------------------------------------------------------------
; puerto_t ptConfigura (int puerto, int bit, int modo);
;-------------------------------------------------------------------------------
ptConfigura	;Precondiciones
			cmp.w	#MINP, r12				;puerto menor que mínimo?
			jl		ptConfErr				;...sí, salir con error
			cmp.w	#MAXP+1, r12			;...no. Puerto mayor que máximo?
			jge		ptConfErr				;...sí, salir con error
			and.b	#0x7, r13				;Dejar sólo los 3 lsb de bit
			push.w	r12						;Apilar número de puerto

			;Crear puerto en R12
			rla.w	r12						;Mover puerto 3 bits a la izquierda
			mov.w	r12, r15				;R15=2*puerto (offset en TabPuertos)
			rla.w	r12
			rla.w	r12
			add.b	r13, r12				;Fusionar con el número de puerto
			bit.b	#MD_POL, r14			;Activo en alta?
			jz		ptConf1					;...sí, puerto listo
			bis.b	#BIT7, r12				;...no, activar polaridad inversa...
			xor.b	#MD_VINI, r14			;...y conmutar bit inicial

			;Configurar puerto según las opciones
ptConf1		mov.w	TabPuertos(r15), r15	;R15=Dirección base del puerto
			mov.b	TabBits(r13), r13		;R13=Máscara bit

			;Copiar bits de función a los registros de ídem
ptConfFunc	bit.b	#MD_FUNC0, r14			;Primero el SEL0
			jz		ptResetSel0
			bis.b	r13, PSEL0(r15)
			jmp		ptConfSel1
ptResetSel0	bic.b	r13, PSEL0(r15)
ptConfSel1	bit.b	#MD_FUNC1, r14			;Ahora el SEL1
			jz		ptResetSel1
			bis.b	r13, PSEL1(r15)
			jmp		ptConfDir
ptResetSel1	bic.b	r13, PSEL1(r15)
			;jmp		ptConfDir

			;Copiar tipo (entrada, salida,...)
ptConfDir	mov.b	r14, r11				;R11 = modo
			and.b	#MD_TIPO, r11			;R11 = tipo
			rla.b	r11						;Multiplicar por dos para implementar tabla de saltos
			add.w	r11, pc
			jmp		ptConfEnt
			jmp		ptConfEntPU
			jmp		ptConfEntPD
			;jmp	ptConfSal

			;Puerto como salida
ptConfSal	bit.b	#MD_FUNC, r14			;Puerto configurado como E/S?
			jnz		ptConfSalF				;...no, no escribir valor inicial
			bit.b	#MD_VINI, r14			;Valor inicial (ya incluye la polaridad)
			jc		ptConfSal1
ptConfSal0	bic.b	r13, POUT(r15)			;Puerto a 0
			jmp		ptConfSalF
ptConfSal1	bis.b	r13, POUT(r15)			;Puerto a 1
ptConfSalF	bis.b	r13, PDIR(r15)			;Puerto como salida
			jmp		ptConfSF

			;Puerto como entrada
ptConfEnt	bic.b	r13, PDIR(r15)			;Puerto como entrada
			bic.b	r13, PREN(r15)			;Desactivar resistencia
			jmp		ptConfSF

			;Puerto como entrada con resistencia de pullup
ptConfEntPU	bic.b	r13, PDIR(r15)			;Puerto como entrada
			bis.b	r13, PREN(r15)			;Activar resistencia
			bis.b	r13, POUT(r15)			;...de pullup
			jmp		ptConfSF

			;Puerto como entrada con resistencia de pulldown
ptConfEntPD	bic.b	r13, PDIR(r15)			;Puerto como entrada
			bis.b	r13, PREN(r15)			;Activar resistencia
			bic.b	r13, POUT(r15)			;...de pulldown
			;jmp		ptConfSF

			;Configurar selección de flanco. Sólo puertos 1 a 4
ptConfSF	pop.w 	r11						;R11=puerto
			tst.b	r11						;Es cero?
			jz		ptConfFin				;...sí, hemos terminado
			cmp.b	#5, r11					;...no. Puerto > 4?
			jhs		ptConfFin				;...sí, hemos terminado
			bit.b	#MD_SF, r14				;Leer flanco de sensibilidad
			jc		ptConfFB				;Flanco de bajada
ptConfFS	bic.b	r13, PIES(r15)			;Flanco de subida
			jmp		ptConfIE
ptConfFB	bis.b	r13, PIES(r15)			;Flanco de bajada
			;jmp	ptConfIE

			;Configurar las interrupciones. Sólo puertos 1 a 4
ptConfIE	bit.b	#MD_IRQ, r14			;Interrupciones requeridas?
			jc		pfConfSiIRQ				;...sí
pfConfNoIRQ	bic.b	r13, PIE(r15)			;...no. Deshabilitar interrupciones
			jmp		ptConfFin
pfConfSiIRQ	bic.b	r13, PIFG(r15)			;Borrar flag de interrupción
			bis.b	r13, PIE(r15)			;Habilitar interrupciones
			jmp		ptConfFin

ptConfErr	mov.w	#-1, r12				;Salir con error
ptConfFin	ret

;-------------------------------------------------------------------------------
; int ptLee (puerto_t pt);
;-------------------------------------------------------------------------------
ptLee		push	r12						;Guardar puerto
			mov.w	#PIN, r13
			call	#ptLeeAlgo
			pop		r13						;Recuperar puerto
			bit.w	#BIT7, r13				;Activo en alta?
			jz		ptLeeFin				;...sí. Salir
			xor.b	r15, r12				;...no. Invertir
ptLeeFin	ret

;-------------------------------------------------------------------------------
; void ptEscribe (puerto_t pt, int valor);
;-------------------------------------------------------------------------------
ptEscribe	bit.w	#-1, r13				;c=bool(R13)
			clr.w	r13
			rlc.w	r13						;R13=bool(R13)
			bit.b	#BIT7, r12				;Qué polaridad tiene el puerto?
			jnc		ptEscSigue				;...positiva, seguir
			xor.b	#BIT0, r13				;...negativa. Invertir valor
ptEscSigue	mov.w	#POUT, r14
			jmp		ptEscAlgo

;-------------------------------------------------------------------------------
; int ptLeeDir (puerto_t pt);
;-------------------------------------------------------------------------------
ptLeeHabDir	mov.w	#PDIR, r13
			jmp		ptLeeAlgo

;-------------------------------------------------------------------------------
; void ptEscDir (puerto_t pt, int salida);
;-------------------------------------------------------------------------------
ptEscDir	mov.w	#PDIR, r14
			jmp		ptEscAlgo

;-------------------------------------------------------------------------------
; int ptLeeHabRes (puerto_t pt);
;-------------------------------------------------------------------------------
ptLeeHabRes	mov.w	#PREN, r13
			jmp		ptLeeAlgo

;-------------------------------------------------------------------------------
; void ptEscHabRes (puerto_t pt, int siono);
; NOTA: Habría que indicar si de pullup o pulldown
;-------------------------------------------------------------------------------
ptEscHabRes	mov.w	#PREN, r14
			jmp		ptEscAlgo

;-------------------------------------------------------------------------------
; int ptLeeHabIRQ (puerto_t pt);
;-------------------------------------------------------------------------------
ptLeeHabIRQ	mov.w	#PIE, r13
			jmp		ptLeeAlgo

;-------------------------------------------------------------------------------
; void ptEscHabIRQ (puerto_t pt, int siono);
;-------------------------------------------------------------------------------
ptEscHabIRQ	mov.w	#PIE, r14
			jmp		ptEscAlgo

;-------------------------------------------------------------------------------
; int ptLeeIRQ (puerto_t pt);
;-------------------------------------------------------------------------------
ptLeeIRQ	mov.w	#PIFG, r13
			jmp		ptLeeAlgo

;-------------------------------------------------------------------------------
; int ptBorraIRQ (puerto_t pt);
;-------------------------------------------------------------------------------
ptBorraIRQ	clr.w	r13						;Escribir un 0
			mov.w	#PIFG, r14				;En PxIFG
			jmp		ptEscAlgo

;-------------------------------------------------------------------------------
; int ptLeeFlanco (puerto_t pt);
;-------------------------------------------------------------------------------
ptLeeFlanco	mov.w	#PIES, r13
			jmp		ptLeeAlgo

;-------------------------------------------------------------------------------
; void ptEscFlanco (puerto_t pt, int flanco);
;-------------------------------------------------------------------------------
ptEscFlanco	mov.w	#PIES, r14
			jmp		ptEscAlgo
