;****************************************************************************
;* Copyright 1990 to 1993 MBARI                                             *
;****************************************************************************
;* Summary  : Assembly language routines for IBC CPU                        *
;* Filename : ibc_asm.s                                                     *
;* Author   : Andrew Pearce                                                 *
;* Project  : New ROV IBC CPU Rev 1.0                                       *
;* Version  : 1.0                                                           *
;* Created  : 05/05/92                                                      *
;* Modified : 11/05/93                                                      *
;* Archived :                                                               *
;****************************************************************************
;* Modification History:
;* $Header: /usr/tiburon/.cvsroot/micro/ibc/boards/cpu196/ibc_asm.s,v 1.2 1997/05/07 15:26:43 pean Exp $
;* $Log: ibc_asm.s,v $
;* Revision 1.2  1997/05/07 15:26:43  pean
;* Cleaned up Include files and makefile for new directory structure.
;*
;* Revision 1.1.1.1  1997/05/02 18:51:28  pean
;* Initial check in of IBC microcontroller software
;*
; Revision 1.1  93/07/02  09:22:28  09:22:28  pean (Andrew Pearce)
; Initial revision
;
;Revision 1.3  92/07/23  15:36:39  15:36:39  pean (Andrew Pearce 408-647-3746)
;Fixed problem with ibcBusReadWord return status
;
;Revision 1.2  92/05/19  14:29:56  14:29:56  pean (Andrew Pearce 408-647-3746)
;Added support for analog humidity sensor and 82C59 PIC
;
;
;Revision 1.1  92/05/14  08:23:51  08:23:51  pean (Andrew Pearce 408-647-3746)
;Initial revision
;
;****************************************************************************
;
$TITLE("IBC CPU Assembler Module")
;
IBC_ASM  MODULE
;
PUBLIC  ibcBusInitialize        ; Initialize ibc bus timeout function
PUBLIC  ibcBusReadByte          ; IBC Bus Byte Read Routine with bus timeout
PUBLIC  ibcBusWriteByte         ; IBC Bus Byte Write Routine with bus timeout
PUBLIC  ibcBusReadWord          ; IBC Bus Word Read Routine with bus timeout
PUBLIC  ibcBusWriteWord         ; IBC Bus Word Write Routine with bus timeout
PUBLIC  NMI_isr                 ; IBC Bus timeout causes NMI interrupt
PUBLIC  ext_int_isr             ; External Interrupt for IBC Bus Interrupts
;
EXTRN   PIC_isr:ENTRY           ; Interrupt Controller Service Routine
EXTRN   PLMREG:WORD             ; Temporary registers used by C and PLM
EXTRN   PIC_intFuncTable:NULL   ; Pointers to PIC interrupt service functions

R0              EQU 00H:WORD    ; R/W ZERO REGISTER
INT_MASK        EQU 08H:BYTE    ; R/W Interrupt Mask Register
INT_PEND        EQU 09H:BYTE    ; R/W Interrupt Pending Register
IOPORT2         EQU 10H:BYTE    ; R/W Input/Output Port 2
INT_MASK1       EQU 13H:BYTE    ; R/W Interrupt Mask Register 1
SP              EQU 18H:WORD    ; R/W Stack Pointer

TI_INT_MASK     EQU 01H:BYTE    ; Transmit Interrupt Enable Mask
RI_INT_MASK     EQU 02H:BYTE    ; Receive Interrupt Enable Mask
EXTINT_MASK     EQU 80H:BYTE    ; External interrupt enable mask

IBC_BUS_ADDR_BASE EQU 1800H             ; IBC Bus base address

PIC_BASE_ADDR     EQU 1000H             ; 82C59A Interrupt Controller Base
PIC_OCW2          EQU PIC_BASE_ADDR     ; 82C59A OSW Register address
PIC_OCW3          EQU PIC_BASE_ADDR
PIC_IRR           EQU PIC_BASE_ADDR
PIC_ISTR          EQU PIC_BASE_ADDR
PIC_INT_ACK_ADDR  EQU 1200H             ; 82C59A Interrupt Acknowledge address

PIC_NON_SPEC_EOI  EQU 20H               ; Non-specific EOI command

;*****************************************************************************
; push_cregs - macro to save the C context for Interrupt Service Routines
;
push_cregs  MACRO
        PUSH    PLMREG+0
        PUSH    PLMREG+2
        PUSH    PLMREG+4
        PUSH    PLMREG+6
        PUSH    PLMREG+8
        ENDM
;
;*****************************************************************************
; pop_cregs - macro to restore the C context for Interrupt Service Routines
;
pop_cregs   MACRO
        POP     PLMREG+8
        POP     PLMREG+6
        POP     PLMREG+4
        POP     PLMREG+2
        POP     PLMREG+0
        ENDM
;
;****************************************************************************

        RSEG

IBC_TIMEOUTS:     dsw 1         ; IBC Bus timeout counter
PIC_VECTOR:       dsw 1         ; register for reading vector from PIC
PIC_FUNCTION:     dsw 1         ; PIC Interrupt level function pointer

;****************************************************************************

        CSEG                    ; Code segment starts here

;*****************************************************************************
;
;   Void ibcBusInitialize( Void );
;
ibcBusInitialize:
    CLR   IBC_TIMEOUTS                  ; Ste IBC Bus timeout counter to 0
    RET

;*****************************************************************************
;
;   Int16 ibcBusReadByte(Byte *addr);
;
ibcBusReadByte:
    LD    PLMREG, 2[SP]                 ; Fetch address off the stack
    LD    PLMREG+2, IBC_TIMEOUTS        ; Copy timeout counter
                                        ; Read a byte from IBC Bus
    LDBZE PLMREG, IBC_BUS_ADDR_BASE[PLMREG]
    NOP                                 ; Delay for NMI interrupt

                                        ; If a bus timeout occurs
                                        ; NMI isr increments IBC_TIMEOUTS
    CMP   PLMREG+2, IBC_TIMEOUTS        ; Test for Bus Timeout
    JNE   ibcReadTimeout
    RET

ibcReadTimeout:
    DEC   IBC_TIMEOUTS                  ; Adjust timeout counter
    LD    PLMREG, #0FFFFH               ; Bus Timeout so return 0xffff
    RET

;*****************************************************************************
;
;     Int16 ibcBusWriteByte(Byte *addr, Byte value);
;
ibcBusWriteByte:
    LD   PLMREG,   2[SP]                ; Fetch address off the stack
    LDB  PLMREG+2, 4[SP]                ; Fetch byte value from stack
    LD   PLMREG+4, IBC_TIMEOUTS         ; Copy timeout counter
                                        ; Write byte to IBC Bus
    STB  PLMREG+2, IBC_BUS_ADDR_BASE[PLMREG]
    NOP                                 ; Delay for NMI interrupt

                                        ; If a bus timeout occurs
                                        ; NMI isr increments IBC_BUS_TIMEOUTS
    CMP  PLMREG+4, IBC_TIMEOUTS         ; Test for Bus Timeout
    JNE  ibcWriteTimeout

    CLR  PLMREG                         ; No Timeout so return 0
    RET

ibcWriteTimeout:
    DEC  IBC_TIMEOUTS                   ; Adjust timeout counter
    LD   PLMREG, #0FFFFH                ; Bus Timeout so return 0xffff
    RET

;*****************************************************************************
;
;     Nat32 ibcBusReadWord(Word *addr);
;
ibcBusReadWord:
    LD    PLMREG, 2[SP]                 ; Fetch address off the stack
    LD    PLMREG+4, IBC_TIMEOUTS        ; Copy timeout counter
                                        ; Read a byte from IBC Bus
    LD    PLMREG+2, IBC_BUS_ADDR_BASE[PLMREG]
    NOP                                 ; Delay for NMI interrupt

                                        ; If a bus timeout occurs
                                        ; NMI isr increments IBC_TIMEOUTS
    CMP   PLMREG+4, IBC_TIMEOUTS        ; Test for Bus Timeout
    JNE   ibcReadTimeout

    CLR   PLMREG                        ; No Bus Timeout so set low word to 0
    RET

;*****************************************************************************
;
;     Int16 ibcBusWriteWord(Word *addr, Word value);
;
ibcBusWriteWord:
    LD   PLMREG,   2[SP]                ; Fetch address off the stack
    LDB  PLMREG+2, 4[SP]                ; Fetch byte value from stack
    LD   PLMREG+4, IBC_TIMEOUTS         ; Copy timeout counter
                                        ; Write byte to IBC Bus
    ST   PLMREG+2, IBC_BUS_ADDR_BASE[PLMREG]
    NOP                                 ; Delay for NMI interrupt

                                        ; If a bus timeout occurs
                                        ; NMI isr increments IBC_BUS_TIMEOUTS
    CMP  PLMREG+4, IBC_TIMEOUTS         ; Test for Bus Timeout
    JNE  ibcWriteTimeout

    CLR  PLMREG                         ; No Timeout so return 0
    RET

;****************************************************************************
;* Function    : NMI_isr                                                    *
;* Purpose     : IBC Bus timeout Service Routine                            *
;* Inputs      : None                                                       *
;* Outputs     : None                                                       *
;****************************************************************************
;
NMI_isr:
    INC IBC_TIMEOUTS                    ; Increment timeout counter
    RET

;****************************************************************************
;* Function    : ext_int_isr                                                *
;* Purpose     : 82C59 Interrupt Controller Service Routine                 *
;* Inputs      : None                                                       *
;* Outputs     : None                                                       *
;****************************************************************************
;
ext_int_isr:
    PUSHA                               ; Save PSW and INT_MASK1
    PUSH PIC_FUNCTION                   ; Save register used for function
    PUSH PIC_VECTOR                     ; Save register used for vector read

    EI                                  ; Re-enable '196 Global Interrupts
    LDB PIC_VECTOR, 5[SP]               ; Fetch saved INT_MASK1 from stack
                                        ; Re-enable Serial Port Interrupts
    ANDB INT_MASK1, PIC_VECTOR, #RI_INT_MASK + TI_INT_MASK

pic_int_pend:
    LDB INT_MASK, #EXTINT_MASK          ; Re-enable PIC Interrupt to '196

    LDBZE PIC_VECTOR, PIC_INT_ACK_ADDR[R0]  ; Pulse INTA\ signal
    LDBZE PIC_VECTOR, PIC_INT_ACK_ADDR[R0]  ; Pulse INTA\ signal & read vector

    AND  PIC_VECTOR, #07                ; Calculate function addr from vector
    SHL  PIC_VECTOR, #2                 ; Each entry is 4 bytes multiply by 4
    ADD  PIC_VECTOR, #PIC_intFuncTable  ; Add function table base address
    LD   PIC_FUNCTION, [PIC_VECTOR]+    ; Fetch function pointer from table
                                        ; & point PIC_VECTOR to func parameter

    CMP  PIC_FUNCTION, R0               ; Check for NULL func pointer
    JE   pic_eoi                        ; Jump over func call if null pointer

    push_cregs                          ; Save C Context

    PUSH [PIC_VECTOR]                   ; Push Function Parameter
    PUSH #pic_isrRet                    ; Push Program Counter for return
    BR  [PIC_FUNCTION]                  ; Call function with no parameters

pic_isrRet:
    ADD SP, #2                          ; Pop Function Parameter
    pop_cregs                           ; Restore C Context

pic_eoi:
    LDB PIC_VECTOR, #PIC_NON_SPEC_EOI   ; Load EOI command into a register
    STB PIC_VECTOR, PIC_OCW2[R0]        ; Issue Non-specific EOI to PIC
                                        ; Enable intrs of same/lower priority

    CLRB INT_MASK                       ; Disable PIC Interrupt
    JBC IOPORT2,  2, pic_rti            ; Check if Ext Int still high
    JBC INT_PEND, 7, pic_int_pend       ; If '196 missed PIC interrupt
                                        ; then process the missed interrupt

pic_rti:
    POP PIC_VECTOR                      ; Restore register used for vector
    POP PIC_FUNCTION                    ; Restore register used for function
    POPA                                ; Restore PSW and INT_MASK1
    RET

;*****************************************************************************
    END

