;
;  $VER: port.asm 1.1 (20 Aug 1995)
;
;  magplip.device - Parallel Line Internet Protocol
;
;  Assembler routines for efficient port handling.
;
;  Original code written by Oliver Wagner and Michael Balzer.
;
;  This version has been completely reworked by Marius Gröger, introducing
;  slight protocol changes. The new source is a lot better organized and
;  maintainable.
;
;  Additional changes and code cleanup by Jan Kratochvil and Martin Mares.
;  The new source is significantly faster and yet better maintainable.
;
;  (C) Copyright 1993-1994 Oliver Wagner & Michael Balzer
;  (C) Copyright 1995 Marius Gröger
;  (C) Copyright 1995 Jan Kratochvil & Martin Mares
;      All Rights Reserved
;
;  $HISTORY:
;
;  20 Aug 1995 : 001.001 :  + removed need for conditional compiling, as we
;                             we want a generic, symmetrical code
;                           + in interrupt handlers, A6 points already to
;                             SysBase
;                           + using JSRLIB/JMPLIB macros
;                           + removed implicit some assumptions on the values
;                             behind symbolic names
;  13 Feb 1995 : 001.000 :  created (in fact manually compiled from 'C'-
;                           original) (jk/mm)
;
      section "text",code

      IFND HARDARE_CIA_I
      include "hardware/cia.i"
      ENDC

      IFND EXEC_MACROS_I
      include "exec/macros.i"
      ENDC

      IFND MAGPLIP_I
      include "magplip.i"
      ENDC

ciaa     equ     $bfe001
ciab     equ     $bfd000
BaseA5   equ     ciab+ciapra

      xref    _CRC16

      xdef    _interrupt
      xdef    _hwsend
      xdef    _hwrecv

;----------------------------------------------------------------------------
;
; NAME
;     interrupt() - ICR FLG interrupt handler
;
; SYNOPSIS
;     void interrupt(struct PLIPBase *)
;                    A1
;
; FUNCTION
;     This is called from the CIA resource on the receipt of an Flag-
;     interrupt. This is the case if the other side starts transmission
;     and writes the first byte to our port.
;     We recognise this here and propagate the information to the server
;     task by Signal()ing it and by setting the PLIPB_RECEIVING bit
;     in the flags field.
;
_interrupt:
        btst    #PLIPB_RECEIVING,pb_Flags(a1)
        bne     skipint
        move.b  pb_HandshakeBit+HS_LINE(a1),d0
        btst    d0,ciab+ciapra
        beq     skipint
        bset    #PLIPB_RECEIVING,pb_Flags(a1)
        move.l  pb_IntSigMask(a1),d0
        move.l  pb_Server(a1),a1
        JMPLIB  Signal
skipint rts

;----------------------------------------------------------------------------
;
; NAME
;     hwsend() - low level send routine
;
; SYNOPSIS
;     void hwsend(struct PLIPBase *)
;                  A0
;
; FUNCTION
;     This routine sends the PLIPBase->pb_SendFrame to the other side. It
;     cares for CRC encoding, if wanted.
;
_hwsend:
         movem.l  d2-d7/a2-a3/a5-a6,-(sp)
         move.l   a0,a2                               ; a2 = PLIPBase
         pea      FALSE                               ; (sp) = return value
         moveq    #0,d3
         move.l   d3,d4
         move.b   pb_HandshakeBit+HS_REQUEST(a2),d3   ; d3 = HS_REQUEST
         move.b   pb_HandshakeBit+HS_LINE(a2),d4      ; d4 = HS_LINE

         ;
         ; CRC wanted ?
         ;
         btst     #PLIPB_SENDCRC,pb_Flags(a2)
         beq      hww_NoCRC
         ; yes
         move.w   #SYNCWORD_CRC,pb_SendFrame+pf_Sync(a2)
         lea      pb_SendFrame+pf_data(a2),a0
         move.w   pb_SendFrame+pf_Size(a2),d0
         subq.w   #PKTFRAMESIZE_2,d0
         jsr      _CRC16(pc)
         move.w   d0,pb_SendFrame+pf_CRC(a2)
         bra.s    hww_CRC

hww_NoCRC:
         move.w   #SYNCWORD_NOCRC,pb_SendFrame+pf_Sync(a2)

hww_CRC  move.l   pb_CIAABase(a2),a6
         moveq    #CIAICRF_FLG,d0
         JSRLIB   AbleICR                             ; DISABLEINT
         lea      BaseA5,a5
         st       ciaa+ciaddrb-BaseA5(a5)             ; SETCIAOUTPUT
         move.b   (a5),d7                             ; SAMPLEINPUT, d7 = State
         lea      pb_SendFrame(a2),a3
         move.w   pb_SendFrame+pf_Size(a2),d6
         addq.w   #PKTFRAMESIZE_1-2,d6
         move.l   pb_Timeout(a2),d5
         move.b   (a3)+,ciaa+ciaprb-BaseA5(a5)        ; WRITECIA *p++
         move.l   d5,d2                               ; initially we wait
         add.l    d2,d2                               ; 2*Timeout
         move.w   d2,d1
         swap     d2
hww_LoopShake1:
         move.b   (a5),d0                             ; ciab+ciapra
         eor.b    d7,d0
         btst     d4,d0                               ; WAITINPUTTOGGLE
         dbne     d1,hww_LoopShake1
         dbne     d2,hww_LoopShake1
         beq      hww_TimedOut
         eor.b    d0,d7

hww_MainLoop:
         move.b   (a3)+,ciaa+ciaprb-BaseA5(a5)        ; WRITECIA *p++
         bchg     d3,(a5)                             ; OUTPUTTOGGLE
         move.l   d5,d2
         move.w   d2,d1
         swap     d2
hww_LoopShake2:
         move.b   (a5),d0                             ; ciab+ciapra
         eor.b    d7,d0
         btst     d4,d0                               ; WAITINPUTTOGGLE
         dbne     d1,hww_LoopShake2
         dbne     d2,hww_LoopShake2
         beq      hww_TimedOut
         eor.b    d0,d7
         dbra     d6,hww_MainLoop
         move.l   #TRUE,(sp)                          ; rc = TRUE
hww_TimedOut:
         sf       ciaa+ciaddrb-BaseA5(a5)             ; SETCIAINPUT
         bclr     d3,(a5)                             ; CLEARREQUEST ciab+ciapra
         moveq    #CIAICRF_FLG,d0
         JSRLIB   SetICR                              ; CLEARINT
         move.w   #CIAICRF_FLG|CIAICRF_SETCLR,d0
         JSRLIB   AbleICR                             ; ENABLEINT

         move.l   (sp)+,d0                            ; return rc
         movem.l  (sp)+,d2-d7/a2-a3/a5-a6
Return   rts


;----------------------------------------------------------------------------
;
; NAME
;     hwrecv() - low level receive routine
;
; SYNOPSIS
;     void hwrecv(struct PLIPBase *)
;                 A0
;
; FUNCTION
;     This routine receives a magPLIP frame and stores it into
;     PLIPBase->pb_ReceiveFrame. It cares for CRC decoding, if the incoming
;     packet is encoded.
;
_hwrecv:
         movem.l  d2-d7/a2-a6,-(sp)
         move.l   a0,a2                               ; a2 = PLIPBase
         pea      FALSE                               ; (sp) = return value
         move.l   pb_CIAABase(a2),a6                  ; a6 = CIABase
         move.l   pb_Timeout(a2),a4                   ; a4 = Timeout
         moveq    #0,d3
         move.l   d3,d5
         move.b   pb_HandshakeBit+HS_REQUEST(a2),d3   ; d3 = HS_REQUEST
         move.b   pb_HandshakeBit+HS_LINE(a2),d5      ; d5 = HS_LINE
         lea      BaseA5,a5                           ; a5 = ciab+ciapra

         moveq    #CIAICRF_FLG,d0
         JSRLIB   AbleICR                             ; DISABLEINT

         move.b   (a5),d7                             ; SAMPLEINPUT
         cmp.b    #SYNCBYTE_HEAD,ciaa+ciaprb-BaseA5(a5) ; READCIABYTE
         bne      hwr_TimedOut

         bchg     d3,(a5)                             ; OUTPUTTOGGLE
         move.l   a4,d2
         move.w   d2,d1
         swap     d2
hwr_LoopShake1:
         move.b   (a5),d0                             ; ciab+ciapra
         eor.b    d7,d0
         btst     d5,d0                               ; WAITINPUTTOGGLE
         dbne     d1,hwr_LoopShake1
         dbne     d2,hwr_LoopShake1
         beq      hwr_TimedOut
         eor.b    d0,d7
         move.b   ciaa+ciaprb-BaseA5(a5),d4           ; READCIABYTE
         bchg     d3,(a5)                             ; OUTPUTTOGGLE
         move.b   d4,d0
         subq.b   #SYNCBYTE_CRC,d0
         subq.b   #SYNCBYTE_NOCRC,d0
         bcc      hwr_TimedOut
         lea      pb_ReceiveFrame+pf_Size(a2),a3

         ; Read 1st length byte
         ;
         move.l   a4,d2
         move.w   d2,d1
         swap     d2
hwr_LoopShake2
         move.b   (a5),d0                             ; ciab+ciapra
         eor.b    d7,d0
         btst     d5,d0                               ; WAITINPUTTOGGLE
         dbne     d1,hwr_LoopShake2
         dbne     d2,hwr_LoopShake2
         beq      hwr_TimedOut
         eor.b    d0,d7
         move.b   ciaa+ciaprb-BaseA5(a5),(a3)+        ; READCIABYTE
         bchg     d3,(a5)                             ; OUTPUTTOGGLE

         ; Read 2nd length byte
         ;
         move.l   a4,d2
         move.w   d2,d1
         swap     d2
hwr_LoopShake3:
         move.b   (a5),d0                             ; ciab+ciapra
         eor.b    d7,d0
         btst     d5,d0                               ; WAITINPUTTOGGLE
         dbne     d1,hwr_LoopShake3
         dbne     d2,hwr_LoopShake3
         beq      hwr_TimedOut
         eor.b    d0,d7
         move.b   ciaa+ciaprb-BaseA5(a5),(a3)+        ; READCIABYTE
         bchg     d3,(a5)                             ; OUTPUTTOGGLE ciab+ciapra

         move.w   -2(a3),d6                           ; = length
         subq.w   #PKTFRAMESIZE_2,d6
         bcs      hwr_TimedOut
         cmp.w    pb_MTU+2(a2),d6
         bhi      hwr_TimedOut
         addq.w   #PKTFRAMESIZE_2-1,d6

         ; Read main packet body
         ;
hwr_MainLoop:
         move.l   a4,d2
         move.w   d2,d1
         swap     d2
hwr_LoopShake4:
         move.b   (a5),d0                             ; ciab+ciapra
         eor.b    d7,d0
         btst     d5,d0
         dbne     d1,hwr_LoopShake4
         dbne     d2,hwr_LoopShake4
         beq      hwr_TimedOut
         eor.b    d0,d7
         move.b   ciaa+ciaprb-BaseA5(a5),(a3)+        ; READCIABYTE
         bchg     d3,(a5)                             ; OUTPUTTOGGLE ciab+ciapra
         dbra     d6,hwr_MainLoop

hwr_DoneRead:
         subq.b   #SYNCBYTE_CRC,d4
         bne      hwr_ReadOkay
         lea      pb_ReceiveFrame+pf_data(a2),a0
         move.w   pb_ReceiveFrame+pf_Size(a2),d0
         subq.w   #PKTFRAMESIZE_2,d0
         jsr      _CRC16(pc)
         cmp.w    pb_ReceiveFrame+pf_CRC(a2),d0
         bne      hwr_TimedOut

hwr_ReadOkay:
         move.l   #TRUE,(sp)
hwr_TimedOut:
         bclr     #PLIPB_RECEIVING,pb_Flags(a2)
         sf       ciaa+ciaddrb-BaseA5(a5)             ; SETCIAINPUT
         bclr     d3,(a5)                             ; CLEARREQUEST ciab+ciapra
         moveq    #CIAICRF_FLG,d0
         JSRLIB   SetICR                              ; CLEARINT
         move.w   #CIAICRF_FLG|CIAICRF_SETCLR,d0
         JSRLIB   AbleICR                             ; ENABLEINT

         move.l   (sp)+,d0                            ; return value
         movem.l  (sp)+,d2-d7/a2-a6
         rts

         end
