	TTL IOLIB IOCOMASM - common assembly routines
	PAGE
********************************************************************************
*
*       COPYRIGHT (C) 1985, 1985 BY HEWLETT-PACKARD COMPANY
*
********************************************************************************
*
*
*       IOLIB     IOCOMASM
*
*
********************************************************************************
*
*
*
*       Library - IOLIB
*       Module  - IOCOMASM
*       Author  - Tim Mikkelsen
*       Phone   - 303-226-3800  ext. 2910
*
*       Purpose - This set of assembly language
*                 code is intended to be used as
*                 a support module for I/O drivers
*
*       Date    - 08/18/81
*       Update  - 03/25/85
*       Release -  7/12/85
*
*
*       Source  - IOLIB:COMASM.TEXT
*       Object  - IOLIB:COMASM.CODE
*
*
********************************************************************************
*
*
*        RELEASED
*       VERSION         3.1
*
*
********************************************************************************
	  PAGE
********************************************************************************
*
*       PASCAL DEFINITION OF MODULE
*
********************************************************************************
	  MNAME IOCOMASM
	  SRC MODULE IOCOMASM;
	  SRC IMPORT iodeclarations;
	  SRC EXPORT
	  SRC     FUNCTION  dma_request ( temp   : ANYPTR ) : INTEGER;
	  SRC     PROCEDURE dma_release ( temp   : ANYPTR );
	  SRC     FUNCTION  bit_set     ( v : INTEGER ;
	  SRC                             b : INTEGER ) : BOOLEAN ;
	  SRC     FUNCTION  binand      ( x : INTEGER ;
	  SRC                             y : INTEGER ) : INTEGER ;
	  SRC     FUNCTION  binior      ( x : INTEGER ;
	  SRC                             y : INTEGER ) : INTEGER ;
	  SRC     FUNCTION  bineor      ( x : INTEGER ;
	  SRC                             y : INTEGER ) : INTEGER ;
	  SRC     FUNCTION  bincmp      ( x : INTEGER ) : INTEGER ;
	  SRC     FUNCTION binasr ( Object : INTEGER ;
	  SRC                        Amount_of_shift : INTEGER ) : INTEGER ;
	  SRC     FUNCTION binasl ( Object : INTEGER ;
	  SRC                        Amount_of_shift : INTEGER ) : INTEGER ;
	  SRC     FUNCTION binlsr ( Object : INTEGER ;
	  SRC                        Amount_of_shift : INTEGER ) : INTEGER ;
	  SRC     FUNCTION binlsl ( Object : INTEGER ;
	  SRC                        Amount_of_shift : INTEGER ) : INTEGER ;
	  SRC END; { IOCOMASM }
	  SPC 5
	  DEF IOCOMASM_iocomasm
	  DEF IOCOMASM_dma_request
	  DEF IOCOMASM_dma_release
	  DEF IOCOMASM_bit_set
	  DEF IOCOMASM_binand
	  DEF IOCOMASM_binior
	  DEF IOCOMASM_bineor
	  DEF IOCOMASM_bincmp
	  DEF IOCOMASM_binasr
	  DEF IOCOMASM_binasl
	  DEF IOCOMASM_binlsr
	  DEF IOCOMASM_binlsl
	  PAGE
********************************************************************************
*
*       SYMBOLS FOR EXPORT - COMMON ASSEMBLY LANGUAGE ROUTINES
*
*       THE SYMBOLS DO NOT HAVE PASCAL ENTRY
*       POINTS SINCE THEY ARE ONLY USED BY
*       ASSEMBLY LANGUAGE MODULES OR WITH EXTERNAL DECLARATIONS
*
********************************************************************************
	  DEF  DROPDMA
	  DEF  GETDMA
	  DEF  TESTDMA
	  DEF  LOGINT
	  DEF  LOGEOT
	  DEF  STBSY
	  DEF  STCLR
	  DEF  DMA_STBSY
	  DEF  ITXFR
	  DEF  ABORT_IO
	  DEF  WAIT_TFR
	  DEF  CHECK_TFR
	  DEF  TIMEREXISTS    USED AS PASCAL EXTERNAL PROC
	  DEF  TIMED_OUT      USED AS PASCAL EXTERNAL PROC
	  SPC  3
*
*****************************************************************************
*
*          IMPORTED SYMBOLS
*
*****************************************************************************
*
	  REFA   CHECK_TIMER    USED TO GET AT TIMER ROUTINE IN POWERUP
	  REFA   ASM_FLUSH_ICACHE   USED TO FLUSH 68020 AFTER DMA XFR
*  JWH  9/24/90 :
	  LMODE  CHECK_TIMER
	  LMODE  ASM_FLUSH_ICACHE
	  LMODE  save_dtt1          jwh 9/24/90
	  TTL IOLIB IOCOMASM - pascal binary functions
	  PAGE
*
*       module initialization
*
IOCOMASM_IOCOMASM EQU *
	  RTS
*
*       bit test
*
IOCOMASM_BIT_SET  EQU *
	  MOVEA.L (SP)+,A0              save return address
	  MOVE.L  (SP)+,D0              get bit #
	  MOVE.L  (SP)+,D1              get numeric value
	  CLR.B   D2                    clear indicator
	  BTST    D0,D1                 test bit in value
	  BEQ.S   BITT_EXIT
	  MOVEQ   #1,D2                 if bit set set indicator
BITT_EXIT MOVE.B  D2,(SP)               push result
	  JMP     (A0)                  return
*
*       binary and
*
IOCOMASM_BINAND   EQU *
	  MOVEA.L (SP)+,A0              save return address
	  MOVE.L  (SP)+,D0              get last param
	  MOVE.L  (SP)+,D1              get first param
	  AND.L   D0,D1                 perform AND
	  MOVE.L  D1,(SP)               push result
	  JMP     (A0)                  return
*
*       binary inclusive or
*
IOCOMASM_BINIOR   EQU *
	  MOVEA.L (SP)+,A0              save return address
	  MOVE.L  (SP)+,D0              get last param
	  MOVE.L  (SP)+,D1              get first param
	  OR.L    D0,D1                 perform OR
	  MOVE.L  D1,(SP)               push result
	  JMP     (A0)                  return
*
*       binary exclusive or
*
IOCOMASM_BINEOR   EQU *
	  MOVEA.L (SP)+,A0              save return address
	  MOVE.L  (SP)+,D0              get last param
	  MOVE.L  (SP)+,D1              get first param
	  EOR.L   D0,D1                 perform XOR
	  MOVE.L  D1,(SP)               push result
	  JMP     (A0)                  return
*
*       binary complement
*
IOCOMASM_BINCMP   EQU *
	  MOVEA.L (SP)+,A0              save return address
	  MOVE.L  (SP)+,D0              get param
	  NOT.L   D0                    perform complement
	  MOVE.L  D0,(SP)               push result
	  JMP     (A0)                  return
	  SPC     5
	  TTL IOLIB IOCOMASM - common equates and definitions
	  PAGE
	  INCLUDE IOLIB:COMDCL
	  TTL IOLIB IOCOMASM - error escape
	  PAGE
********************************************************************************
*
*       Error escapes
*
********************************************************************************
CTMO_ERR  MOVEQ  #TMO_ERR,D0            timeout
	  BRA.S  ESC_ERR
TERR_C    MOVEQ  #TCNTERR,D0            bad transfer specification
	  BRA.S  ESC_ERR
TERR_B    MOVEQ  #TFR_ERR,D0            bad transfer specification
	  BRA.S  ESC_ERR
TERR_D    MOVEQ  #NO_DMA,D0             DMA not installed
*         BRA.S  ESC_ERR
	  SPC    4
ESC_ERR   EXT.L  D0
	  MOVE.L D0,IOE_RSLT(A5)        save io error
	  MOVE.B IO_SC(A2),D0           \ get sc for error
	  MOVE.L D0,IOE_SC(A5)          /
	  MOVE.W #IOE_ERROR,ESC_CODE(A5)  give i/o error
	  TRAP   #10                    escape
	  TTL IOLIB IOCOMASM - transfer support
	  PAGE
********************************************************************************
*
*       ABORT_IO
*
*         USED DURING INITIALIZATION/RESET TO MAKE SURE THERE
*                IS NO ACTIVE BUFFER LEFT AROUND.
*
*         ENTRY:  A2.L = TEMP POINTER
*
*         USES:   D1,D2,D3  AND ROUTINE DROPDMA (WHICH USES A0)
*
*         HPL ROUTINE ( MODIFIED )
*
********************************************************************************
ABORT_IO  TRAP  #11                     GET INTO SUPERVISOR MODE, SAVE SR  scs
* scs     MOVE    SR,-(SP)              \ PREVENT INTERRUPTS FOR A MOMENT.
	  ORI     #$2700,SR             /
ABORT_IO3 BSR     ITXFR                 IS THERE A TRANSFER IN PROGRESS?
	  BEQ.S   ABORT_IO2             IF NOT, DO NOTHING
	  CMP.B   #TT_DMA,D1            ELSE IS IT A DMA?
	  BEQ.S   ABORT_IO1             IF NOT, SKIP
	  BSR     DROPDMA               ELSE FREE UP THE DMA CH, GET COUNT
	  MOVE.L  D4,TCNT_OFF(A3)       fix up count
	  SUB.L   D4,D3                 fix up actual count
	  TST.B   TDIR_OFF(A3)
	  BNE.S   AB_OUT
	  ADD.L   D3,TFIL_OFF(A3)       if input then update fill
	  BRA.S   ABORT_IO1
AB_OUT    ADD.L   D3,TEMP_OFF(A3)       if output then update empty
ABORT_IO1 MOVE.B  #255,T_SC_OFF(A3)     UNBUSY THE BUFFER
	  CLR.B   TACT_OFF(A3)          SET TRANSFER TYPE TO NONE
	  CLR.L   (A4)                  clear buffer ptr
	  BRA     ABORT_IO3             see if there is another
ABORT_IO2 MOVE  (SP)+,SR                RESTORE USER MODE               scs
	  RTS                                                           scs
* scs     RTE                           RESTORE INTERRUPT LEVEL & RETURN
	  PAGE
********************************************************************************
*
*       CHECK_TFR
*
*         ROUTINE TO CHECK FOR ACTIVE TRANSFER IN THE OPPOSITE DIRECTION.
*               ( this is called by a tfr routine on cards
*                 that can't do bi-directional tfrs )
*               ( gpio and hpib modules use this routine )
*               ( with a timeout wait )
*
*         ENTRY:  A2.L = TEMP POINTER
*                 A3.L = BUF CTL BLK POINTER
*
*         EXIT :  IF NOT TRANSFER, RETURN
*                 IF     TRANSFER, THEN wait until finished
*                                       or   until timeout ( if any )
*
********************************************************************************
CHECK_TFR TST.B   TDIR_OFF(A3)          base test on direction
	  BNE.S   CHKT_IN               ( if this is in , check out )
CHKT_OUT  LEA     BUFO_OFF(A2),A4       IS THERE  AN output  BUFFER ACTIVE?
	  MOVE.L  (A4),D1
	  BRA.S   CHKWAIT               IF SO , THEN WAIT
	  SPC     2
CHKT_IN   LEA     BUFI_OFF(A2),A4       is there an input  tfr
	  MOVE.L  (A4),D1
*         BRA.S   CHKWAIT
	  SPC     3
CHKWAIT   BEQ.S   CHKEXIT               exit if no tfr
	  MOVE.L  TIMEOUT(A2),D2        get timeout value
	  BEQ.S   CHECK_TFR             if timeout = 0 then try forever
	  BTST    #TIMER_PRESENT,SYSFLAG2   CHECK IF TIMER PRESENT   JS 8/3/83
	  BEQ.S   CHKT_TIM              IF SO THEN USE IT            JS 8/3/83
	  LSL.L   #8,D2
CHKLOOP   MOVE.L  (A4),D1               check the buffer again
	  BEQ.S   CHKEXIT               if finished in time then return
	  SUBQ.L  #1,D2                 decrement
	  BNE.S   CHKLOOP
	  BRA     CTMO_ERR
CHKEXIT   RTS
	  SPC     3
CHKT_TIM  MOVE.B  #1,-(SP)              SET UP TIMER RECORD          JS 8/3/83
	  MOVE.L  D2,-(SP)                                           JS 8/3/83
CHKT_TIM1 MOVE.L  (A4),D1               TRANSFER ACTIVE ?            JS 8/3/83
	  BEQ.S   CHKT_TIM2             NO -- EXIT                   JS 8/3/83
	  PEA     (SP)                  ELSE CHECK TIMER             JS 8/3/83
	  JSR     CHECK_TIMER                                        JS 8/3/83
	  BPL     CHKT_TIM1             BRANCH IF NOT TIMED OUT      JS 8/3/83
	  BRA     CTMO_ERR              ELSE DO TIMEOUT ESCAPE       JS 8/3/83
CHKT_TIM2 ADDQ.L  #6,SP                 CLEAN TIMER RECORD FROM STACK JS 8/3/83
	  RTS                           AND RETURN                   JS 8/3/83
	  PAGE
********************************************************************************
*
*       WAIT_TFR
*
*         ROUTINE TO CHECK FOR ACTIVE TRANSFER.
*               ( with a timeout wait )
*
*         ENTRY:  A2.L = TEMP POINTER
*
*         EXIT :  IF NOT TRANSFER, RETURN
*                 IF     TRANSFER, THEN wait until finished
*                                       or   until timeout ( if any )
*
*         USES:   NO REGS OTHER THAN RETURN VALUES.
*
*
********************************************************************************
WAIT_TFR  BSR    ITXFR                  quick check for tfr
	  BEQ.S  WT_DONE                and exit
	  MOVE.L TIMEOUT(A2),D6         get timeout value
	  BEQ.S  WAIT_TFR               if timeout = 0 then try forever
	  BTST   #TIMER_PRESENT,SYSFLAG2 IF TIMER PRESENT USE IT   JS 8/3/83
	  BEQ.S  WT_TIM                  BRANCH IF WE HAVE IT      JS 8/3/83
	  LSL.L  #5,D6
WT_LOOP   BSR.S  ITXFR                  try
	  BEQ.S  WT_DONE                if finished in time then return
	  SUBQ.L #1,D6                  decrement
	  BNE.S  WT_LOOP
	  BRA    CTMO_ERR
WT_DONE   RTS
	  SPC    3
WT_TIM    MOVE.B #1,-(SP)              SET UP TIMER RECORD          JS 8/3/83
	  MOVE.L D6,-(SP)                                           JS 8/3/83
WT_TIM1   BSR.S  ITXFR                 CHECK FOR ACTIVE TRANSFER    JS 8/3/83
	  BEQ.S  WT_TIM2               NONE -- EXIT                 JS 8/3/83
	  PEA    (SP)                  CHECK TIMER                  JS 8/3/83
	  JSR    CHECK_TIMER                                        JS 8/3/83
	  BPL    WT_TIM1               LOOK AGAIN IF NOT TIMED OUT  JS 8/3/83
	  BRA    CTMO_ERR              ELSE DO TIMEOUT ESCAPE       JS 8/3/83
WT_TIM2   ADDQ.L #6,SP                 CLEAN UP TIMER RECORD        JS 8/3/83
	  RTS                          AND RETURN                   JS 8/3/83
	  PAGE
********************************************************************************
*
*       ITXFR
*
*         ROUTINE TO CHECK FOR ACTIVE TRANSFER.
*
*         ENTRY:  A2.L = TEMP POINTER
*
*         EXIT :  IF NOT TRANSFER, RET with zero flag  set
*                 IF     TRANSFER, RET with not zero
*                    D1.W = ACTUAL TFR TYPE
*                    D2.W = TERMINATING CHAR FROM TEMPS
*                    D3.L = TRANSFER COUNT FROM TEMPS
*                    A0.L = DATA POINTER FROM TEMPS ( either emtpy or fill )
*                    A3.L = BUF CTL BLK POINTER FROM TEMPS
*
*         HPL ROUTINE ( MODIFIED )
*
********************************************************************************
ITXFR     LEA     BUFI_OFF(A2),A4       IS THERE  AN input  BUFFER ACTIVE?
	  MOVE.L  (A4),D1
	  BNE.S   ITXFR3                IF NOT, SKIP
	  LEA     BUFO_OFF(A2),A4       is there an output tfr
	  MOVE.L  (A4),D1
	  BEQ.S   ITXFR1                   -no
ITXFR3    MOVEA.L D1,A3                 \
	  CLR.L   D1                      ELSE GET BUFFER TYPE WORD
	  MOVE.B  TACT_OFF(A3),D1       /
	  CLR.L   D2
	  MOVE.W  TCHR_OFF(A3),D2       GET TERMINATING CHAR
	  MOVE.L  TCNT_OFF(A3),D3       GET COUNT
	  MOVEA.L TEMP_OFF(A3),A0       GET EMPTY POINTER
	  TST.B   TDIR_OFF(A3)          check direction
	  BNE.S   ITXFR2                \ IF INPUT
	  MOVEA.L TFIL_OFF(A3),A0       /    THEN GET FILL POINTER
ITXFR2    MOVEQ   #1,D5                 set not zero
STCLR1    EQU     *
ITXFR1    RTS
	  PAGE
********************************************************************************
*
*       STCLR
*
*         ROUTINE TO SET A BUFFER & SELECT CODE NOT BUSY
*
*         ENTRY:  gets buf ptr from ITXFR routine
*
*                 assumes only one tfr per select code
*
*         USES:   A3,D0
*
*         HPL ROUTINE ( MODIFIED )
*
********************************************************************************
STCLR     BSR     ITXFR                 GET BUFFER POINTER FROM TEMPS
	  BEQ.S   STCLR1                IF ALREADY CLEAR, SKIP
	  MOVE.B  #255,T_SC_OFF(A3)     CLEAR S.C. INDICATOR IN THE BUF CTL BLK
	  CLR.B   TACT_OFF(A3)          clear tfr type
	  CLR.L   (A4)                  CLEAR BUF POINTER    IN SC TEMPS
*RTS
	  SPC     5
********************************************************************************
*
*       LOGEOT
*
*         CALL THE USER PROC AT END OF TRANSFER
*
*         PASCAL ROUTINE
*
*         modified to pass a user parameter:  JPC  02/22/82
*
********************************************************************************
LOGEOT    LEA     T_PR_OFF(A3),A0       point to procedure/static link/parameter

H_EOT1    MOVE.L  (A0),D0               is there a proc?
	  BEQ.S   H_EOT3                skip if not

	  MOVEM.L A1-A4,-(SP)           save dedicated regs      (8/10/82 JPC)
	  MOVE.L  8(A0),-(SP)           push the parameter
	  MOVE.L  4(A0),D1              is there a static link?
	  BEQ.S   H_EOT2                Roger Ison says it is okay to try
	  MOVE.L  D1,-(SP)                    and call proc with static link
H_EOT2    MOVEA.L D0,A0                 procedure address
	  JSR     (A0)                  call it
	  MOVEM.L (SP)+,A1-A4           restore dedicated regs   (8/10/82 JPC)

H_EOT3    RTS

	  PAGE
********************************************************************************
*
*       LOGINT
*
*         THIS ROUTINE WAS CALLED H_LOG
*
*         CALL THE USER PROC WHEN AN ISR SAYS TO
*
*         PASCAL ROUTINE
*
*         modified to pass a user parameter:  JPC  02/22/82
*
********************************************************************************
LOGINT    LEA     H_ISR_PR(A2),A0       point to procedure/static link/parameter
	  BRA     H_EOT1                call it (if it exists)
	  PAGE
********************************************************************************
*
*       DMA_STBSY
*
*         ROUTINE TO SET A BUFFER BUSY
*
*         ENTRY:
*                 D0.W = TRANSFER COUNT TO BE PUT IN TCNT_OFF(A2)
*                        AND TO BE ADDED TO E/F COUNT.
*                 A0.L = pointer to DMA temps
*                 A2.L = POINTER TO DRIVER TEMPS
*                 A3.L = POINTER TO BUFFER CTL BLOCK
*                 A4.L = POINTER TO TERMINATION ROUTINE
*
*         HPL ROUTINE ( MODIFIED )
*
********************************************************************************
DMA_STBSY MOVE.L A4,DMAISR(A0)          SAVE THE TERMINATION ROUTINE
	  CLR.L  DMASL(A0)              CLEAR THE STATIC LINK
*         BRA.S  STBSY                  SET THE BUFFER BUSY
	  SPC    5
********************************************************************************
*
*       STBSY
*
*         ROUTINE TO SET A BUFFER BUSY
*
*         ENTRY:
*                 D0.W = TRANSFER COUNT TO BE PUT IN TCNT_OFF(A2)
*                        AND TO BE ADDED TO E/F COUNT.
*                 A2.L = POINTER TO DRIVER TEMPS
*                 A3.L = POINTER TO BUFFER CTL BLOCK
*
*         HPL ROUTINE ( MODIFIED )
*
********************************************************************************
STBSY     MOVE.L D0,TCNT_OFF(A3)        COPY TFR COUNT INTO TEMPS.
	  TST.B  TDIR_OFF(A3)           \
	  BNE.S  STBSY1                  \
	  MOVE.L A3,BUFI_OFF(A2)           MAKE SELECT CODE BUSY
	  BRA.S  STBSY2                  /
STBSY1    MOVE.L A3,BUFO_OFF(A2)        /
STBSY2    MOVE.B IO_SC(A2),T_SC_OFF(A3) SET UP BUFFER ACTIVE SELECT CODE
	  RTS                           DONE!
	  TTL IOLIB IOCOMASM - dma support
	  PAGE
********************************************************************************
*
*       DMA RESOURCE MANAGEMENT ROUTINES
*
*
********************************************************************************
	  SPC 3
********************************************************************************
*
*       DMA RESOURCE temporaries
*
*         These resource temporaries need to be aligned with the offsets
*         generated by the main Pascal library.  This is not an automatic
*         operation - it must be done by hand if ANY new declarations are
*         added in the iodeclarations in front of the dma resource temps.
*
********************************************************************************
DMAFLAG   EQU    iodeclarations-61      boolean indicating presence of dma hardware
	  SPC    2
DMA0      EQU    iodeclarations-8
DMAISR_0  EQU    iodeclarations-8       \
DMASL_0   EQU    iodeclarations-4         channel 0 temps
DMA_SC_0  EQU    iodeclarations-9       /
	  SPC    2
DMA1      EQU    iodeclarations-18
DMAISR_1  EQU    iodeclarations-18      \
DMASL_1   EQU    iodeclarations-14        channel 1 temps
DMA_SC_1  EQU    iodeclarations-19      /
	  SPC    2
DMAISR    EQU    0                      isr pointer
DMASL     EQU    4                      static link
DMA_SC    EQU    -1                     allocated s.c.
	  SPC    2
DMACH0    EQU    $500000                address of dma channel 0
DMACH1    EQU    $500008                address of dma channel 1
********************************************************************************
*
*       ADDRESS CONSTANTS
*
********************************************************************************
H_INT_CA  EQU    $478000                ADDRESS OF INTERNAL HPIB INTERFACE
	  TTL IOLIB IOCOMASM - pascal dma procedures
	  PAGE
*
*       request a dma channel
*
IOCOMASM_DMA_REQUEST EQU *
	  MOVEA.L (SP)+,A4              save return address
	  MOVEA.L (SP)+,A2              get sc temp
	  MOVEA.L C_ADR(A2),A1          get card ptr
	  TRAP  #11                     GET INTO SUPERVISOR MODE        scs
* scs     MOVE    SR,-(SP)              JUST IN CASE CALLER DIDN'T DISABLE
	  ORI     #$2700,SR             INTERRUPTS, I WILL.
	  BSR     TESTDMA               SEE IF DMA IS INSTALLED
	  BEQ.S   DR_FAIL               IF NOT, return -1
	  SUBQ.W  #1,D3                 turn $82/$81 to $81/$80
	  ANDI.W  #1,D3                 determine channel
	  EXT.L   D3
	  MOVE.B  IO_SC(A2),DMA_SC(A0)     ELSE CLAIM THIS CHANNEL FOR CALLER
* following 3 lines for 68040 support JWH 2/15/91
	  btst  #3,SYSFLAG2
	  bne   no_40
	  jsr    WRITE_68040
	  jsr    ASM_FLUSH_ICACHE
no_40     BRA.S   DR_GOOD
DR_FAIL   MOVE.L  #-1,D3                return -1
DR_GOOD   MOVE    (SP)+,SR              restore int. state
	  MOVE.L  D3,(SP)               assign return value - channel ( or -1 )
	  JMP     (A4)                  return addr
	  SPC     4
*
*       release a dma channel
*
IOCOMASM_DMA_RELEASE EQU *
	  MOVEA.L (SP)+,A0              save return address
	  MOVEA.L (SP)+,A2              get sc temp
	  MOVEA.L C_ADR(A2),A1          get card ptr
	  PEA     (A0)                  push return address
	  BRA     DROPDMA               release it
	  SPC     4
	  TTL IOLIB IOCOMASM - assembly dma procedures
	  PAGE
********************************************************************************
*
*       GETDMA
*
*         ROUTINE TO OBTAIN CONTROL OF A DMA CHANNEL
*         GET EITHER DMA CHANNEL, TRYING FOR CH 1 FIRST.
*
*         ENTR:   CONDITIONS ARE THE SAME AS FOR THE tfr DRIVER ENTRY POINT.
*
*         EXIT:   IF DMA IS NOT INSTALLED, 'no dma' escape is generated.
*                 IF DMA IS INSTALLED, THE ALGORITHM WAITS FOR A CHANNEL TO
*                 BECOME AVAILABLE AND THEN:
*                    LOGS USE OF DMA CHANNEL
*                    SETS UP ADDRESS AND COUNT REGISTERS.
*                    CONSTRUCTS CARD ARM AND DMA ARM MASKS AS FOLLOWS:
*                           D2.W = DMA ARM BYTE WITH BITS 1, 2 DEFINED BY
*                                  CONTENTS OF D1 AND BIT 0 = 1.
*                           D3.B = CARD ENABLE BYTE WITH BITS 0, 1 DEFINED BY
*                                  WHICH DMA CHANNEL WAS GRANTED AND BIT 7=1.
*                    A4.L = ADDRESS OF DMA CHANNEL ARM WORD.
*
*         NOTE:   IF THE REQUEST IS FOR INTERNAL HP-IB AS INDICATED BY A1,
*                 ONLY CHANNEL 0 WILL BE GRANTED.
*
*         HPL ROUTINE ( MODIFIED )
*
********************************************************************************
GETDMA    TRAP  #11                     GET INTO SUPERVISOR MODE        scs
* scs     MOVE   SR,-(SP)               JUST IN CASE CALLER DIDN'T DISABLE
	  ORI    #$2700,SR              INTERRUPTS, I WILL.
	  CMPI.L #$010001,D0            \ make sure count <=65536
	   BPL   TERR_C                 /
	  BSR.S  TESTDMA                SEE IF DMA IS INSTALLED
	   BEQ   TERR_D                 IF NOT, GIVE ERROR
	  MOVE.B IO_SC(A2),DMA_SC(A0)      ELSE CLAIM THIS CHANNEL FOR CALLER
* added for 68040 support JWH 2/15/91
	  btst   #3,SYSFLAG2
	  bne    not_40
	  jsr  WRITE_68040
	  jsr  ASM_FLUSH_ICACHE
not_40    MOVEA.L D2,A4                 A4 = ADDRESS OF DMA CHANNEL HARDWARE.
	  SPC    1
	  MOVE.L TEMP_OFF(A3),D2        \
	  TST.B  TDIR_OFF(A3)            \
	  BNE.S  GETDMA1                   SET UP ADDRESS
	  MOVE.L TFIL_OFF(A3),D2         /
GETDMA1   MOVE.L D2,(A4)+               /
	  SPC    1
	  SUBQ.L #1,D0                     COUNT REGISTERS (COUNT REG
	  MOVE.W D0,(A4)+                  MUST BE COUNT-1)
	  ADDQ.L #1,D0
	  SPC    2
	  CLR.W  D2
	  MOVE.B TDIR_OFF(A3),D2        MOVE DIRECTION BIT INTO B2 OF D2
	  LSL    #2,D2                  IN ORDER TO CONSTRUCT DMA ARM
	  SPC    2
	  TST.B  T_BW_OFF(A3)           IF BYTE TRANSFER
	  BEQ.S  GETDMA2                THEN SKIP
	  ADDQ.W #2,D2                  ELSE SET BIT 1 OF DMA ARM.
GETDMA2   TST.B  T_DMAPRI(A3)           check for dma priority requested
	  BEQ.S  GETDMA3
	  ADDQ.W #8,D2                    if set  then set pri bit
GETDMA3   ADDQ.W #1,D2                  SET BIT0 OF DMA ARM
	  MOVE  (SP)+,SR                                                scs
	  RTS                                                           scs
* scs     RTE
	  SPC    6
********************************************************************************
*
*       TESTDMA
*
*         THIS ROUTINE TESTS FOR PRESENCE OF DMA HARDWARE AND WAITS FOR
*         A CHANNEL TO BECOME AVAILABLE.
*
*         ENTRY:  A1 = CARD ADDRESS
*
*         EXIT:   IF NO DMA IS INSTALLED, RET with zero flag set
*                 IF    DMA IS INSTALLED, RET with not zero set
*                      A0.L = ADDRESS OF DMA FLAG FOR AVAILABLE CHANNEL
*                      D2.L = ADDRESS OF AVAILABLE DMA CHANNEL
*                      D3.B = CARD ENABLE BYTE FOR AVAILABLE CHANNEL
*
*         HPL ROUTINE ( MODIFIED )
*
********************************************************************************
TESTDMA   LEA    DMAFLAG(A5),A0         \
	  TST.B  (A0)                    DO RET 1 IF NO DMA
	  BEQ.S  TESTDMA_C              /
	  CMPA.L #H_INT_CA,A1           IF THIS IS A REQUEST FOR THE INTERNAL
	  BEQ.S  TESTDMA_A              HP-IB, THEN CAN'T TRY FOR CH 1 SO SKIP.
	  LEA    DMA1(A5),A0            ELSE ASSUME WE CAN GET CH 1
	  MOVE.L #DMACH1,D2
* tm      MOVEQ  #$82,D3
	  MOVE.B #$82,D3
	  CMPI.B #255,DMA_SC(A0)        CAN WE?
	  BEQ.S  TESTDMA_B              IF SO, THEN RET 3
TESTDMA_A LEA    DMA0(A5),A0            ELSE ASSUME WE CAN GET CH 0
	  MOVE.L #DMACH0,D2
* tm      MOVEQ  #$81,D3
	  MOVE.B #$81,D3
	  CMPI.B #255,DMA_SC(A0)        CAN WE?
	  BEQ.S  TESTDMA_B     IF HARDWARE PRESENT BUT BUSY,same as not there
	  CLR    D5
	  RTS
TESTDMA_B MOVEQ  #1,D5                  ELSE WE GOT A CH
TESTDMA_C RTS
	  SPC    6
********************************************************************************
*
*       DROPDMA
*
*         ROUTINE TO FREE UP A DMA CHANNEL
*
*         ENTRY:  A2.L = POINTER TO DRIVER TEMPS
*
*         EXIT:   D4.W = FINAL DMA CHANNEL COUNT
*                 CHANNEL IS DISARMED.
*
*         USES:   A0
*
*         HPL ROUTINE ( MODIFIED )
*
********************************************************************************
DROPDMA   EQU *
	  TRAP #11                                                      scs
* scs     MOVE   SR,-(SP)               JUST IN CASE CALLER DIDN'T DISABLE
	  ORI    #$2700,SR              INTERRUPTS, I WILL.
	  BTST   #GOT_68020,SYSFLAG2    CHECK IF WE HAVE 68020
	  BEQ.S  DODROP                 IF NOT THEN SKIP
	  JSR    ASM_FLUSH_ICACHE       FLUSH ICACHE ON 68020
	  MOVE   CACHE_CTL,D4           GET EXT. CACHE CONTROL WORD
	  ANDI   #$63,D4                SET DISABLE
	  MOVE   D4,CACHE_CTL           TURN CACHE OFF
	  BSET   #2,D4                  SET ENABLE BIT
	  MOVE   D4,CACHE_CTL           TURN CACHE  BACK ON
DODROP    MOVEQ  #0,D4                  ASSUME DMA CHA ALREADY DROPPED...
	  MOVE.B DMA_SC_0(A5),D0        \
	  CMP.B  IO_SC(A2),D0           / IS IT CH 0?
	  BNE.S  DROPDMA0               IF NOT, SKIP
	  LEA    DMA0(A5),A4            GET A POINTER TO THE CHANNEL R/W
	  LEA    DMACH0,A0              POINT A0 TO CH 0
	  BRA.S  DROPDMA1               GO DO IT
	  SPC    2
DROPDMA0  MOVE.B DMA_SC_1(A5),D0        \
	  CMP.B  IO_SC(A2),D0           / IS IT CH 1?
	  BNE.S  DROPDMA2               IF NOT, DO NOTHING
	  LEA    DMA1(A5),A4            GET A POINTER TO THE CHANNEL R/W
	  LEA    DMACH1,A0              POINT A0 TO CH 1
DROPDMA1  equ   *
* next 3 lines for 68040 support JWH 2/15/91
	  btst   #3,SYSFLAG2
	  bne    same_old
	  jsr    copy_68040
same_old  MOVE.B #255,DMA_SC(A4)        clear s.c.
	  CLR.L  DMASL(A4)              clear static link
	  CLR.L  DMAISR(A4)             clear isr pointer
	  MOVE.L (A0)+,D4               DISARM CH BY READING ADDRESS
	  CLR.L  D4
	  MOVE.W (A0),D4                GET FINAL COUNT INTO D0
	  ADD.W  #1,D4                  FIX UP COUNT TO INDICATE LEFT OVER TFR'S
DROPDMA2  MOVE  (SP)+,SR                                                scs
	  RTS                                                           scs
* scs     RTE
	  PAGE
*
*******************************************************************************
*         WRITE_68040                             JEFF HENDERSHOT 2/15/91.
*
*         THIS ROUTINE IS CALLED IN CASE WE HAVE A 68040 AND WE HAVE ACTUALLY
*         CLAIMED A DMA CHANNEL. BASICALLY, ONCE A DMA CHANNEL HAS ACTUALLY
*         BEEN ASSIGNED, WE HAVE TO FORCE WRITETHROUGH CACHING MODE AND
*         FLUSH CACHES. WHEN ALL DMA CHANNELS ARE RELEASED WE CAN RESTORE
*         COPYBACK MODE IF THAT WAS THE MODE WE ENCOUNTERED HERE.
*
*         CALLED BY : DMA_REQUEST and GETDMA, right after a DMA channel has
*                     actually been claimed. Note - we do not call this from
*                     TESTDMA because TESTDMA does not assign channels
*
*         ALGORITHM:    ASSUMES 68040 (PUT TEST BEFORE CALLING)
*
*                       IF DTT1 CONTAINS SOMETHING NON-ZERO
*                          SAVE CONTENTS OF DTT1 (IN SAVE_DTT1)
*                          PUT 0 (WRITETHROUGH MODE) IN DTT1
*                       EXIT
********************************************************************************
SAVE_DTT1 DC.L   $00000000              save place for DTT1
*
WRITE_68040  trap #11                  supervisor mode
	     move.l d0,-(sp)           save d0
	     movec  DTT1,d0            grab DTT1
	     cmpi.l #$00000000,d0      if 0 don't ...
	     beq    bag_it             bother, already in writethrough
	     move.l d0,SAVE_DTT1       else saveit
	     move.l #0,d0              and force ...
	     movec  d0,DTT1            writethrough mode
bag_it       move.l (sp)+,d0           restore d0
	     move   (sp)+,SR           and SR also
	     RTS
*********************************************************************************
*         COPY_68040                             JEFF HENDERSHOT 2/15/91.
*
*         THIS ROUTINE IS CALLED IN CASE WE HAVE A 68040 AND WE ARE
*         DROPPING A DMA CHANNEL. BASICALLY, ONCE A DMA CHANNEL HAS ACTUALLY
*         BEEN ASSIGNED, WE HAVE TO FORCE WRITETHROUGH CACHING MODE AND
*         FLUSH CACHES. WHEN ALL DMA CHANNELS ARE RELEASED WE CAN RESTORE
*         COPYBACK MODE (IF THAT MODE WAS SAVED EARLIER)
*
*         CALLED BY : DROPDMA, right after the channel is released
*
*         ENTRY: A0 contains DMACH0 or DMACH1
*
*         ALGORITHM:    ASSUMES 68040 (PUT TEST BEFORE CALLING)
*
*                       IF SAVE_DTT1 HAS A NON-ZERO VALUE (COPYBACK MODE)
*                          IF CHANNEL 0 RELEASED
*                            IF CHANNEL 1 NOT IN USE
*                               RESTORE DTT1
*                               ZERO OUT SAVE_DTT1
*                               EXIT
*                          IF CHANNEL 1 RELEASED
*                            IF CHANNEL 0 NOT IN USE
*                               RESTORE DTT1
*                               ZERO OUT SAVE_DTT1
*                               EXIT
********************************************************************************
COPY_68040   equ   *
	  move.l  d0,-(sp)              save d0
	  move.l  SAVE_DTT1,d0
	  cmpi.l  #0,d0                 anything there ?
	  beq     OUTTA_HERE            bail out if not
	  move.l  a1,-(sp)              a1 needed in either case
	  cmpa.l  #DMACH0,a0            was it channel 0 released ?
	  bne     hadta_be_one          if not then one
	  lea    DMA1(A5),a1            see if ..
	  CMPI.B  #$FF,DMA_SC(a1)       channel 1 busy
	  BNE    DONT                   if so don't restore DTT1
	  BRA    PUT_IT                 otherwise do restore it
hadta_be_one  equ  *                    no other choice
	  lea    DMA0(A5),a1
	  CMPI.B  #$FF,DMA_SC(a1)       channel 0 busy ?
	  BNE    DONT                   if so don't restore DTT1
PUT_IT    trap #11                      otherwise do save it
	  movec  d0,DTT1                d0 has SAVE_DTT1
	  move.l  #0,SAVE_DTT1          clear save spot
	  move   (sp)+,SR               restore SR also
DONT      movea.l  (sp)+,a1             restore a1
OUTTA_HERE  move.l (sp)+,d0             restore d0
	   RTS
******************************************************************************
*
*         TIMEREXISTS:  PASCAL FUNCTION TO SEE IF TIMER EXISTS
*
*           FUNCTION TIMEREXISTS: BOOLEAN; EXTERNAL;
*
*           RETURNS TRUE IF TIMER PRESENT, ELSE FALSE
*
*           J SCHMIDT 8/2/83
*
*****************************************************************************
*
TIMEREXISTS EQU *
	  BTST   #TIMER_PRESENT,SYSFLAG2  CHECK BIT FOR TIMER PRESENT
	  SEQ    4(SP)                   SET FUNCTION RESULT 0=>TRUE
	  RTS                             AND RETURN
*
***************************************************************************
*
*         TIMED_OUT:   PASCAL FUNCTION TO SEE IF TIMEOUT HAS OCCURRED
*
*            FUNCTION TIMED_OUT(VAR REC: TIMEOUTREC): BOOLEAN; EXTERNAL;
*
*            TIMEOUTREC= PACKED RECORD
*                           COUNT: INTEGER { SET TO TIMEOUT IN MS }
*                           FIRSTTIME: BOOLEAN; {SET THIS TO TRUE FOR FIRST
*                                                 CALL }
*                         END;
*
*            RETURNS:  TRUE IF TIMEOUT PERIOD EXPIRED, ELSE FALSE
*
*            CAUTION: WILL SMASH BOTH PARTS OF TIMEOUTREC PARAMETER
*
*                J SCHMIDT 8/2/83
*
*                  REMOVED ADDQ.L #4,SP AFTER SMI   JWS 5/3/84
*****************************************************************************
*
TIMED_OUT      MOVEA.L   (SP)+,A0     SAVE RETURN ADDRESS
	       JSR       CHECK_TIMER  CALL CHECK_TIMER USING PARAMETER ON STK
	       SMI       (SP)        SET RESULT OF FUNCTION
	       JMP       (A0)         AND RETURN WITH SP POINTING TO RESULT




*
*****************************************************************************
*
*   Bit shifting routines
*
*****************************************************************************
*

IOCOMASM_binasr    equ     *
	movea.l (sp)+,a0        Save return address
	move.l  (sp)+,d0        Pop # of bits to shift
	move.l  (sp)+,d1        Pop the value to shift
	asr.l   d0,d1           Shift the value
	move.l  d1,(sp)         Push the resulting return value
	jmp     (a0)            Return

IOCOMASM_binlsr    equ     *
	movea.l (sp)+,a0        Save return address
	move.l  (sp)+,d0        Pop # of bits to shift
	move.l  (sp)+,d1        Pop the value to shift
	lsr.l   d0,d1           Shift the value
	move.l  d1,(sp)         Push the resulting return value
	jmp     (a0)            Return

IOCOMASM_binasl    equ     *
	movea.l (sp)+,a0        Save return address
	move.l  (sp)+,d0        Pop # of bits to shift
	move.l  (sp)+,d1        Pop the value to shift
	asl.l   d0,d1           Shift the value
	move.l  d1,(sp)         Push the resulting return value
	jmp     (a0)            Return

IOCOMASM_binlsl    equ     *
	movea.l (sp)+,a0        Save return address
	move.l  (sp)+,d0        Pop # of bits to shift
	move.l  (sp)+,d1        Pop the value to shift
	lsl.l   d0,d1           Shift the value
	move.l  d1,(sp)         Push the resulting return value
	jmp     (a0)            Return

	end
