include "UART_PAD.inc"
include "memory.inc"
include "m8c.inc"

export _ED_PAD_init
export _ED_PAD_isData
export _ED_PAD_getData
export _ED_PAD_RX_ISR
export _ED_PAD_TX_ISR
export _ED_PAD_putData
export _ED_PAD_fStatus;

ED_PAD_TXBUFFERSIZE: equ 80h ; must be power of 2
ED_PAD_TXBUFFERMASK: equ (ED_PAD_TXBUFFERSIZE-1)

ED_PAD_RXBUFFERSIZE: equ 100h ; must be power of 2
ED_PAD_RXBUFFERMASK: equ (ED_PAD_RXBUFFERSIZE-1)

;-----------------------------------------------
; Variable Allocation
;-----------------------------------------------
AREA InterruptRAM (RAM, REL, CON)

 ED_PAD_RX_outpos:		BLK  1
 ED_PAD_RX_inpos:      BLK  1
 ED_PAD_TX_outpos:     BLK  1
 ED_PAD_TX_inpos:      BLK  1
 ED_PAD_TX_inprogress: BLK  1
 ;ED_PAD_RX_bufavail:   BLK  1
 ED_PAD_TX_bufavail:   BLK  1
 
_ED_PAD_fStatus:
 ED_PAD_fStatus:       BLK  1

AREA UART_PAD_RAM (RAM, REL, CON)
  ED_PAD_RxBuffer:     BLK ED_PAD_RXBUFFERSIZE
AREA UART_PAD_RAM2 (RAM, REL, CON)
  ED_PAD_TxBuffer:     BLK ED_PAD_TXBUFFERSIZE

;-----------------------------------------------
;  Global Symbols
;-----------------------------------------------

AREA UserModules (ROM, REL, CON)

;-----------------------------------------------
;  init
;-----------------------------------------------

_ED_PAD_init:
	RAM_PROLOGUE RAM_USE_CLASS_3
	RAM_SETPAGE_CUR >ED_PAD_RX_inpos
	mov [ED_PAD_RX_inpos], 0
	mov [ED_PAD_RX_outpos], 0
	mov [ED_PAD_TX_inpos], 0
	mov [ED_PAD_TX_outpos], 0
	mov [ED_PAD_TX_inprogress], 0
	mov [ED_PAD_TX_bufavail], ED_PAD_TXBUFFERSIZE-1
	RAM_EPILOGUE RAM_USE_CLASS_3
	ret

;-----------------------------------------------
;  isData
;-----------------------------------------------

_ED_PAD_isData:
	RAM_PROLOGUE RAM_USE_CLASS_3
	
	RAM_SETPAGE_CUR >ED_PAD_RX_inpos
	mov A, [ED_PAD_RX_outpos]
	sub A, [ED_PAD_RX_inpos]
	
	RAM_EPILOGUE RAM_USE_CLASS_3
	ret

;-----------------------------------------------
;  getData
;-----------------------------------------------
_ED_PAD_getData:
	RAM_PROLOGUE RAM_USE_CLASS_3
	
	RAM_SETPAGE_CUR >ED_PAD_RX_inpos
    RAM_SETPAGE_IDX >ED_PAD_RxBuffer

	mov  X,[ED_PAD_RX_outpos]                               ; Load X with byte counter
 	mov  A, [X+ED_PAD_RxBuffer]
 	inc  [ED_PAD_RX_outpos]
 	and  [ED_PAD_RX_outpos], ED_PAD_RXBUFFERMASK
 	
	RAM_EPILOGUE RAM_USE_CLASS_3
	ret



;-----------------------------------------------
;  RX ISR
;-----------------------------------------------
_ED_PAD_RX_ISR:
   push A
   push X
   
   IF SYSTEM_LARGE_MEMORY_MODEL
      REG_PRESERVE IDX_PP
    ENDIF
   
    mov  A,REG[UART_PAD_RX_CONTROL_REG]                    ; Read the control register

; this is needless... we wouldn't be here unless it switched.
; maybe this is useful if people are reconfiguring and we might
; have an interrupt pending from a previous configuration...
;   push A                                                  ; Store copy for later test
                                                           ; IF real RX interrupt
;   and  A,UART_PAD_RX_REG_FULL                            ; Did really really get an IRQ
;   jnz  .UARTRX_ReadRx                                     ; Data ready, go get it
;   pop  A                                                  ; Restore stack
;   jmp  .RESTORE_IDX_PP

;.UARTRX_ReadRx:
;   pop  A                                                  ; Restore status flags
                                                           ; IF there is no error, get data
                                                           ; Check for parity or framing error
   and  A,UART_PAD_RX_ERROR
   jz   .UARTRX_NO_ERROR                                   ; If there is not an Error go read data

   or   [ED_PAD_fStatus],A                                ; Set error flags (parity,framing,overrun) bits
   mov  A,REG[UART_PAD_RX_BUFFER_REG ]                    ; Read the data buffer to clear it.
   and  A,UART_PAD_RX_FRAMING_ERROR                       ; Check for framing error special case
   jz   .RESTORE_IDX_PP                                    ; Not framing error, all done

                                                           ; Disable and re-enable RX to reset after
                                                           ; framing error.
   and   REG[UART_PAD_RX_CONTROL_REG], ~UART_PAD_RX_ENABLE   ; Disable RX
   or    REG[UART_PAD_RX_CONTROL_REG],  UART_PAD_RX_ENABLE   ; Enable RX
   jmp  .RESTORE_IDX_PP                                    ; Done with framing error, leave.


.UARTRX_NO_ERROR:
   mov  A,REG[UART_PAD_RX_BUFFER_REG ]                    ; Read the data buffer

                                                           ; IF buffer not full
   tst  [ED_PAD_fStatus],UART_PAD_RX_BUF_CMDTERM         ; Check for buffer full
   jnz  .RESTORE_IDX_PP                                    ; All done

; we have a good input character now
   mov  X,[ED_PAD_RX_inpos]                              ; Load X with byte counter
   RAM_SETPAGE_IDX >ED_PAD_RxBuffer
   RAM_CHANGE_PAGE_MODE FLAG_PGMODE_10b  
   mov  [X+ED_PAD_RxBuffer],A                            ; store data in array
   RAM_CHANGE_PAGE_MODE FLAG_PGMODE_00b 
   
   inc  [ED_PAD_RX_inpos]                                  ; Inc the pointer
   and  [ED_PAD_RX_inpos], ED_PAD_RXBUFFERMASK
   
;   jmp  .RESTORE_IDX_PP

.RESTORE_IDX_PP:
   IF SYSTEM_LARGE_MEMORY_MODEL
      REG_RESTORE IDX_PP
   ENDIF

.END_UARTRX_ISR:
   pop  X
   pop  A


UART_PAD_RX_ISR_END:
   reti


;-----------------------------------------------
;  putData
;-----------------------------------------------
_ED_PAD_putData:
	RAM_PROLOGUE RAM_USE_CLASS_3
	RAM_SETPAGE_CUR >ED_PAD_TX_inprogress
	
	; if we're about to overrun our buffer space, loop!
.waitloop:
	cmp  [ED_PAD_TX_bufavail], 0x01
	jc   .waitloop
	
	M8C_DisableGInt 		; avoid race conditions
	; our main concern is us deciding to enqueue the byte since
	; the ISR is inprogress, but the ISR simultaneously exiting.
	; so we protect our decision and enqueuing by disabling 
	; interrupts.

	; if the ISR is still expecting another interrupt, just enqueue this one	
	tst [ED_PAD_TX_inprogress], 0x01
	jnz ED_PAD_enqueue

	; now it's possible that the ISR thinks it's finished (it just
	; wrote the last byte), but the last byte is still transmitting.
	; We don't want to block in this case, but rather put the byte
	; into the queue (since another interrupt is still pending.)
	tst reg[UART_PAD_TX_CONTROL_REG], UART_PAD_TX_BUFFER_EMPTY
	jz  ED_PAD_enqueue  ; The buffer isn't empty; enqueue the byte!
	
; send immediately
	or [ED_PAD_TX_inprogress], 0x1
	
	M8C_EnableGInt

    mov REG[UART_PAD_TX_BUFFER_REG], A     ; Write data to Tx Port

	RAM_EPILOGUE RAM_USE_CLASS_3
	ret
	
ED_PAD_enqueue:
    RAM_SETPAGE_IDX >ED_PAD_TxBuffer

	mov  X,[ED_PAD_TX_inpos]                               ; Load X with byte counter
	mov  [X+ED_PAD_TxBuffer], A

 	inc  [ED_PAD_TX_inpos]
 	and  [ED_PAD_TX_inpos], ED_PAD_TXBUFFERMASK

	dec  [ED_PAD_TX_bufavail]
	M8C_EnableGInt
 	
	RAM_EPILOGUE RAM_USE_CLASS_3
	ret
	
;-----------------------------------------------
;  TX_IRQ
;-----------------------------------------------
_ED_PAD_TX_ISR:
   push A
   push X
   
   IF SYSTEM_LARGE_MEMORY_MODEL
      REG_PRESERVE IDX_PP
   ENDIF
   
   mov  A, [ED_PAD_TX_outpos]                              ; Load X with byte counter
   cmp  A, [ED_PAD_TX_inpos]	; are we done?
   jz   ED_PAD_TX_ISR_COMPLETE

   ; nope, send another character. A still contains outpos
   RAM_SETPAGE_IDX >ED_PAD_TxBuffer

   mov  X, A
   RAM_CHANGE_PAGE_MODE FLAG_PGMODE_10b 
   mov  A, [X+ED_PAD_TxBuffer]
   RAM_CHANGE_PAGE_MODE FLAG_PGMODE_00b 
   mov REG[UART_PAD_TX_BUFFER_REG], A    ; Write data to Tx Port

   inc [ED_PAD_TX_outpos]
   and [ED_PAD_TX_outpos], ED_PAD_TXBUFFERMASK

   inc  [ED_PAD_TX_bufavail]

   IF SYSTEM_LARGE_MEMORY_MODEL
      REG_RESTORE IDX_PP
   ENDIF
   
   pop X
   pop A
   reti
   
ED_PAD_TX_ISR_COMPLETE:
   mov [ED_PAD_TX_inprogress], 0

   IF SYSTEM_LARGE_MEMORY_MODEL
      REG_RESTORE IDX_PP
   ENDIF

   pop X
   pop A
   reti
	
;-----------------------------------------------
;  getTxBufData
;-----------------------------------------------
_ED_PAD_getTxBufAvail:
	RAM_PROLOGUE RAM_USE_CLASS_3
	
	RAM_SETPAGE_CUR >ED_PAD_TX_bufavail
 
 	mov  A, [ED_PAD_TX_bufavail]

	RAM_EPILOGUE RAM_USE_CLASS_3
	ret

; end of file UART_PADINT.asm

