home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Misc / Vector18.lha / ParNetExample / pio.asm < prev    next >
Encoding:
Assembly Source File  |  1993-12-18  |  20.8 KB  |  771 lines

  1. ;
  2. ; $Header: DH0:SRC/asm/parallel/parnet/RCS/pio.asm,v 1.3 1993/03/25 01:40:55 barnard Exp $
  3. ;
  4. ;
  5.  
  6. ;/*
  7. ; * This code was originally written by Matthew Dillon and put into Public Domain
  8. ; *
  9. ; * All changes concerning the adaption of Matt's original code to the
  10. ; * Vector Connection I/O board are © 1991-1993 by Henning Schmiedehausen
  11. ; * All rights for this changes are reserved. The original code is Public Domain
  12. ; *
  13. ; * This code is distributed with the expressed written permission of Matthew
  14. ; * Dillon (Thank you very much, Matt)
  15. ; *
  16. ; */
  17.  
  18.  
  19.         ;   PARALLEL PORT NETWORK LOW LEVEL ROUTINES
  20.         ;
  21.         ;   CABLE:  Connect D7-D0,SEL,POUT, and BUSY across,
  22.         ;        Connect ACK to SEL locally:
  23.         ;        Connect GND lines indicated
  24.         ;
  25.         ;   (2-9)   D7-D0   ------------    D7-D0
  26.         ;   (12)    POUT    ------------    POUT
  27.         ;   (11)    BUSY    ------------    BUSY       PARALLEL PORT
  28.         ;   (13)    SEL     --+------+--    SEL
  29.         ;   (10)    ACK     -/        \-    ACK
  30.         ;   (18-22) GND     ------------    GND
  31.         ;
  32.         ;   WARNING: you cannot connect RI on the serial port to your
  33.         ;         modem because it interferes with the parallel
  34.         ;         port's SEL line in this configuration.
  35.         ;
  36.         ;   *    28K/sec bandwidth
  37.         ;   *    # machines depends on extra hardware for buffering,
  38.         ;    but 3 ought to work fine without any extra hardware.
  39.         ;
  40.         ;    (network protocol can now handle 254)
  41.         ;
  42.         ;   Data Line Definitions:
  43.         ;    CIAA PORTB :    D7-D0    used for byte data transfer
  44.         ;    CIAB PORTA :    D2-D0    used for line aquisition and
  45.         ;                handshaking (SEL,POUT,BUSY)
  46.         ;
  47.         ;   All lines pulled up.  Thus, asserted state is a 0.    Idle
  48.         ;   state is an undriven (1).  Protocol transfers a byte at
  49.         ;   a time.  Protocol is ethernet style with a small window
  50.         ;   of error in the line aquisition routine.
  51.         ;
  52.         ;   Note:   Timeouts should be set around a second.  Ideally
  53.         ;        defaults should be fixed on faster machines.
  54.         ;
  55.         ;   CIAB PORTA    D0  ~ACK    hand shake
  56.         ;        D1  ~REQ    hand shake
  57.         ;        D2   CTL    1 = special byte, 0 = data byte.
  58.         ;                (for address mark, valid when ~REQ
  59.         ;                 goes low.    For EOP mark, sample
  60.         ;                 when ~REQ goes high)
  61.         ;
  62.         ;                PROTOCOL
  63.         ;
  64.         ;   HandShake    (Reader <- Writer transfer).  A Handshake
  65.         ;        sequence transfers TWO bytes of information.
  66.         ;
  67.         ;        WRITER                READER
  68.         ;    |-> place data, ~REQ->0
  69.         ;    |                 wait for ~REQ->0
  70.         ;    |                 read data & store
  71.         ;    |                 set ~ACK->0
  72.         ;    |   wait ~ACK->0
  73.         ;    |   place data, ~REQ->1
  74.         ;    |                 wait for ~REQ->1
  75.         ;    |                 read data & store
  76.         ;    |                 set ~ACK->1
  77.         ;    |   wait ~ACK->1
  78.         ;    |<- LOOP  (2 bytes written)      LOOP  (2 bytes read)
  79.         ;
  80.         ;
  81.         ;   Read:   (1) Determine if your machine is being addressed
  82.         ;        (~REQ=0, data=myaddress, CTL=1)
  83.         ;        (1) set DDR for ~ACK to output and
  84.         ;        (2) Handshake sequence for the address mark, only
  85.         ;        first byte valid.
  86.         ;        (3) Handshake sequence for data util rcv byte
  87.         ;        with CTL = 1 (EOP), byte must == 0.
  88.         ;        (4) Set ~ACK (bit 0) to input
  89.         ;
  90.         ;   Write:  (1) AQUIRE THE NETWORK (see below)
  91.         ;        involves gaining control and then setting the
  92.         ;        DDR for CTL and ~REQ to outputs.
  93.         ;
  94.         ;        Also checks if somebody is writing to us,
  95.         ;        in which case -2 is returned instantaniously
  96.         ;        indicating we should do a ParRead().
  97.         ;
  98.         ;        (2) Handshake sequence for address mark, send dest
  99.         ;        address (second byte garbage).  Note that CTL->1
  100.         ;        *BEFORE* we set ~REQ->0
  101.         ;        (3) Handshake sequence for data bytes
  102.         ;        (4) Handshake sequence for EOP mark (Note that CTL->1
  103.         ;        *AFTER* we get the ~ACK->1 and before release
  104.         ;        ~REQ (->1).  Only firstbyte valid and set to 0.
  105.         ;
  106.         ;        (5) Set ~ACK and ~CTL to inputs
  107.         ;
  108.         ;   AQUIRE: Line aquisition prevents two people from writing to
  109.         ;        the net at the same time.
  110.         ;
  111.         ;        * A line is considered aquired if ANY of the 3
  112.         ;          control lines is 0.
  113.         ;        * If network is not aquired:
  114.         ;        - set ~ACK to output and 1
  115.         ;        - bclr ~ACK to 0 and bne success
  116.         ;          (else set ~ACK to input and try again)
  117.         ;        - set data lines to output and place my address
  118.         ;          (Must ]be done before CTL is glitched)
  119.         ;        - set ~CTL to output and 1
  120.         ;        - set CTL to 0 and then 1 (glitch it) to cause
  121.         ;          FLAG interrupt on all other machines
  122.         ;        - set ~REQ to output and 0 (beginning of handshake
  123.         ;          sequence)
  124.         ;        - lastly, release ~ACK by setting it to an input
  125.         ;
  126.         ;          Note that at all times at least one line is a 0
  127.         ;          so no other machine will attempt to aquire the net.
  128.         ;
  129.         ;   Note that the destination address is placed on the data
  130.         ;   lines after we have aquired the line but before we glitch
  131.         ;   the CTL line to cause an interrupt.  This allows the
  132.         ;   other machines to instantaniously determine who is being
  133.         ;   addressed.
  134.         ;
  135.         ;   Note that the CTL line gets glitched at the end of a packet
  136.         ;   too for the EOP mark.  In this case there is a 0 on the
  137.         ;   data lines so while an interrupt is generated, nobody
  138.         ;   thinks they are being addressed.
  139.  
  140.         INCLUDE "exec/types.i"
  141.         INCLUDE "exec/execbase.i"
  142.         INCLUDE "exec/io.i"
  143.         INCLUDE "devices/pio.i"
  144.         INCLUDE "devices/pio_hard.i"
  145.  
  146. PORTA        set    1
  147. ; PORTB        set    1
  148.  
  149.         ifd    PORTA
  150.  
  151. CTL_MASK    equ    %11010000        ; Kontrolleitungen für Port A
  152. PIOIntBit    equ    0
  153.  
  154.         BITDEF    PIO,ACK,6
  155.         BITDEF    PIO,REQ,7
  156.         BITDEF    PIO,CTL,4
  157.  
  158.         endc
  159.  
  160.         ifd    PORTB
  161.  
  162. CTL_MASK    equ    %00000111        ; Kontrolleitungen für Port B
  163. PIOIntBit    equ    2
  164.  
  165.         BITDEF  PIO,ACK,2
  166.         BITDEF  PIO,REQ,1
  167.         BITDEF  PIO,CTL,0
  168.  
  169.         endc
  170.  
  171.  
  172.         xdef    PIOIntBit
  173.         xdef    CTL_MASK
  174.  
  175.         XREF    _intena
  176.  
  177. DISABLE     MACRO
  178.         MOVE.W    #$04000,_intena     *(NOT IF_SETCLR)+IF_INTEN
  179.         ADDQ.B    #1,IDNestCnt(A6)
  180.         ENDM
  181.  
  182. ENABLE        MACRO
  183.         SUBQ.B    #1,IDNestCnt(A6)
  184.         BGE.S    ENABLE\@
  185.         MOVE.W    #$0C000,_intena     *IF_SETCLR+IF_INTEN
  186. ENABLE\@
  187.         ENDM
  188.  
  189.  
  190.         section __MERGED,DATA
  191.  
  192.         xdef    _ParLLTimeout
  193.         xdef    _ParCollision1
  194.         xdef    _ParCollision2
  195.         xdef    _ParDebug
  196.  
  197.         ;   Note, the timeout is set manually on init by using the
  198.         ;   timer.device to time one second.
  199.  
  200. _ParLLTimeout    dc.l    1000000     ; default timeout value (count). 1 second
  201. _ParNetAddr    dc.b    0        ; default network address (msb 4 bits)
  202. _DummyBuf    dc.b    0        ; dummy buffer
  203.         dc.b    0        ; dummy buffer
  204.         dc.b    0        ; pad
  205. _ParCollision1    dc.l    0        ; statistics
  206. _ParCollision2    dc.l    0        ;
  207. Null        dc.l    0        ; always 0
  208.         dc.l    0        ; always 0
  209.  
  210. _ParDebug    ds.l    16        ; 16 longword debug entries
  211.  
  212.         section text,code
  213.  
  214.         ;   (void) ParAddress(myaddr)
  215.         ;    Set my address to (1-254)
  216.         ;
  217.         ;    0 and 255 are reserved!
  218.         ;
  219.         ;   int  = ParDataReady()
  220.         ;    returns 1  if packet pending
  221.         ;    returns 0  if line is currently idle
  222.         ;    returns -1 if packet isn't for you
  223.         ;
  224.         ;    if line has been aquired but no control address has been
  225.         ;    put on it yet, ParDataReady() will wait for a control
  226.         ;    address.  Thus, after a signal, a single call to
  227.         ;    ParDataReady() should suffice.
  228.         ;
  229.         ;   n = ParReadV (buf1, bytes1, buf2, bytes2, ..., NULL, NULL);
  230.         ;    (buffer sizes must be even)
  231.         ;   n = ParRead (buf, bytes)
  232.         ;    read a pending packet.    Returns n = -1 (1 second timeout
  233.         ;    no packet pending), n = 0 to bytes -1 (1 second timeout
  234.         ;    after transmission interrupted), n = bytes (success),
  235.         ;    or n > bytes (transmitting machine's packet was larger
  236.         ;    than we can handle, extra bytes thrown out)
  237.         ;
  238.         ;    NOTE: requesting an odd number of bytes is O.K. but
  239.         ;          if you request N where N is odd and the writer
  240.         ;          sends N + 1 you will never know (N will be
  241.         ;          returned).  See ParWrite() below
  242.         ;
  243.         ;   n = ParWriteV (destadr, buf1, bytes1, buf2, bytes2, ..., NULL, NULL);
  244.         ;    (buffer sizes must be even)
  245.         ;   n = ParWrite(destadr, buf, bytes)
  246.         ;    write a packet.  Returns:
  247.         ;    n = -2    Cannot write anything, a packet is pending
  248.         ;        (instantanious)
  249.         ;    n = -1    Destination machine does not respond (1 sec to)
  250.         ;    n = N    N bytes written ok (success if n == bytes)
  251.         ;
  252.         ;    NOTE: sending an odd number of bytes is O.K. but if
  253.         ;    you write N where N is odd and the reader requests
  254.         ;    N + 1 he will get N + 1 the last byte being garbage.
  255.         ;
  256.         xdef    _ParRead
  257.         xdef    _ParReadV
  258.         xdef    _ParWrite
  259.         xdef    _ParWriteV
  260.         xdef    _ParAddress
  261.         xdef    _ParDataReady
  262.         xdef    _LongCheckSum
  263.         xdef    _Time10000
  264.  
  265.         xref    _UnitBase        ; Kommen von CMD_INACTIVE
  266.         xref    _PIOBase
  267.  
  268. _ParAddress:    move.l    4(sp),D0                ;   address 1-254
  269.         move.b    D0,_ParNetAddr        ;   store
  270.         rts
  271.  
  272.         ;   ParDataReady()
  273.         ;
  274.         ;   -1    packet isn't for you
  275.         ;   0    line is idle
  276.         ;   1    packet probably pending for you
  277.  
  278. _ParDataReady:    move.l    d2,-(a7)
  279.         move.l    _UnitBase,A0        ; Basis-Adresse des Kanals holen
  280.         lea    PIOR_PDR(A0),A0        ; a0 zeigt auf Port
  281.         move.l    _PIOBase,a1        ; Basis-Adresse der PIO holen
  282.         lea    PIO_PCDR(a1),a1        ; a1 zeigt auf den Port C
  283.  
  284. .pdstable    move.b    (A1),D0
  285.         and.b    #CTL_MASK,d0        ; Nur die Kontrolleitungen interessieren
  286.  
  287.         move.b    (A0),D1
  288.  
  289.         move.b    (A1),d2
  290.         and.b    #CTL_MASK,d2
  291.         cmp.b    d2,D0                  ;   control lines stable?
  292.         bne    .pdstable
  293.  
  294.         ;   Now, ParDataReady might be called after the sending machine
  295.         ;   has aquired but before it can assert REQ.  However, the
  296.         ;   sending machine has already (guarenteed) placed its address
  297.         ;   on the data port.  So while the address matches, loop while
  298.         ;   REQ not asserted.
  299.  
  300.         btst.l    #PIOB_REQ,D0        ;   ~Req asserted?
  301.         beq    .pd10            ;   beq yes
  302.         cmp.b    _ParNetAddr,D1        ;   no, does data match anyway?
  303.         beq    .pdstable        ;   YES, loop until get ~REQ or
  304.         bra    .pdfail         ;   data bad.
  305.  
  306. .pd10        btst.l    #PIOB_CTL,D0        ;   yes, Ctl ?
  307.         beq    .pdrn            ;   no, middle of some packet
  308.         cmp.b    _ParNetAddr,D1        ;   yes, my address?
  309.         bne    .pdrn
  310.         moveq.l #1,D0            ;   yes, packet (probably) for us
  311.         move.l    (a7)+,d2
  312.         rts
  313.  
  314. .pdfail     btst.l    #PIOB_CTL,D0        ;   fail due to ~Req not asserted
  315.         beq    .pdrn            ;   Ctl = 0, line busy
  316. .pdr0        moveq.l #0,D0            ;   line idle
  317.         move.l    (a7)+,d2
  318.         rts
  319. .pdrn        moveq.l #-1,D0            ;   line busy, packet not for me
  320.         move.l    (a7)+,d2
  321.         rts
  322.  
  323. _ParReadV:                    ;   Read Into Vector
  324.         movem.l D2-D7/A2-A5,-(sp)
  325.         lea    12+40(sp),A3
  326.         bra    .rm000
  327.  
  328. _ParRead:
  329.         movem.l D2-D7/A2-A5,-(sp)
  330.         lea    Null,A3         ;   Pointer to next vector
  331. .rm000        move.l    4+40(sp),A0             ;   A0 = buffer to read into
  332.         move.l    8+40(sp),D7             ;   D7 = # bytes to read (maximum)
  333.         move.l    _UnitBase,a1        ; A1 zeigt auf Unit
  334.         lea    PIOR_DDR(a1),a2        ; A2 zeigt auf DATA-DDR
  335.         lea    PIOR_PDR(a1),a1        ; A1 zeigt auf DATA
  336.  
  337.         move.l    _PIOBase,a4        ; A4 zeigt auf PIO
  338.         lea    PIO_PCDDR(a4),a5    ; A5 zeigt auf CTL-DDR
  339.         lea    PIO_PCDR(a4),a4        ; A4 zeigt auf CTL
  340.  
  341.         move.b    #0,(A2)                 ;   ensure all are inputs
  342.         bclr.b    #PIOB_ACK,(A5)
  343.         bclr.b    #PIOB_REQ,(A5)
  344.         bclr.b    #PIOB_CTL,(A5)
  345.  
  346.         move.l    _ParLLTimeout,D5    ;   D5 = timeout load
  347.         moveq.l #-1,D6            ;   D6 = # bytes read so far
  348.  
  349.         ;   WAIT LOOK FOR ADDRESS MARK
  350.         ;
  351.         ;   Ctl = 1, ~DReq = 0
  352.  
  353.         move.l    D5,D4            ;   D4 = timeout countdown
  354. .rmstab     move.b    (A4),D0                 ;   control data
  355.         and.b    #CTL_MASK,d0        ; Nur Kontrolleitungen
  356.         move.b    (A1),D1                 ;   data data (network addr)
  357.         move.b    (a4),d2
  358.         and.b    #CTL_MASK,d2
  359.         cmp.b    d2,D0
  360.         bne    .rmstab
  361.         btst.l    #PIOB_CTL,D0        ;   expect CTL = 1
  362.         beq    .rms1            ;   nope
  363.         btst.l    #PIOB_REQ,D0        ;   expect ~REQ = 0
  364.         beq    .rms2            ;   yes
  365. .rms1
  366.         add.l    #1,_ParDebug+0
  367.         subq.l    #1,D4            ;   timeout
  368.         bne    .rmstab
  369.         bra    .rmend            ;   no address mark!
  370.  
  371. .rms2        cmp.b    _ParNetAddr,D1        ;   my address?
  372.         bne    .rms1            ;   no, timeout loop
  373.  
  374.         ;   My address, ~Ack byte.
  375.  
  376.         bclr.b    #PIOB_ACK,(A4)           ;   set ~ACK to 0
  377.         bset.b    #PIOB_ACK,(A5)           ;   set to output
  378.  
  379.         move.l    D5,D4            ;   reset timeout
  380. .rms4        btst.b    #PIOB_REQ,(A4)           ;   wait for ~REQ to go away
  381.         bne    .rms5
  382.         add.l    #1,_ParDebug+4
  383.         subq.l    #1,D4
  384.         bne    .rms4
  385.         moveq.l #-2,D6            ;   ~REQ not released ?????
  386.         bra    .rmend
  387.  
  388. .rms5        bset.b    #PIOB_ACK,(A4)           ;   release ~ACK
  389.         moveq.l #0,D6            ;   set # bytes read to 0
  390.         bra    .rms10            ;   skip past move
  391.  
  392.         ;   MAIN READ LOOP
  393.         ;
  394.         ;   D6 holds cnt, A0 buffer ptr, D0-D4 free to allocate
  395.  
  396. .rms10loop
  397.         move.b    D0,(A0)                 ;   store data
  398.         addq.l    #1,A0            ;   next addr.
  399.  
  400. .rms10        btst.b    #PIOB_REQ,(A4)           ;   wait for ~REQ asserted
  401.         beq    .rms20
  402.         btst.b    #PIOB_REQ,(A4)
  403.         beq    .rms20
  404.         move.l    D5,D4            ;   load timeout
  405. .rms11        btst.b    #PIOB_REQ,(A4)           ;   wait for ~REQ asserted w/to
  406.         beq    .rms20
  407.         add.l    #1,_ParDebug+8
  408.         subq.l    #1,D4
  409.         bne    .rms11
  410.         bra    .rmend
  411.  
  412. .rms20        move.b    (A1),D0                 ;   get data and
  413.         bclr.b    #PIOB_ACK,(A4)           ;   assert ~ACK
  414.  
  415.         ;   note, on CTL = 1 end sequence this data item is a dummy
  416.  
  417.         move.b    D0,(A0)                 ;   store data
  418.         addq.l    #1,A0            ;   next addr.
  419.         addq.l    #2,D6            ;   optimized but not quite
  420.                         ;   true, we've only written 1 sf.
  421.         btst.b    #PIOB_REQ,(A4)           ;   wait for ~REQ released
  422.         bne    .rms30
  423.         btst.b    #PIOB_REQ,(A4)
  424.         bne    .rms30
  425.         move.l    D5,D4
  426. .rms21        btst.b    #PIOB_REQ,(A4)           ;   wait for ~REQ rel w/ to
  427.         bne    .rms30
  428.         add.l    #1,_ParDebug+12
  429.         subq.l    #1,D4
  430.         bne    .rms21
  431.         bra    .rmendsub        ;   sub because D6 is 2 ahead
  432.  
  433. .rms30        move.b    (A1),D0                 ;   get data
  434.         move.b    (A4),D1                 ;   get CTL status
  435.         bset.b    #PIOB_ACK,(A4)           ;   release ~ACK
  436.         btst.l    #PIOB_CTL,D1            ;   EOP if CTL = 1
  437.         bne    .rmeop
  438.  
  439.         ;   CANNOT STORE DATA HERE!  In case odd # bytes requested,
  440.         ;   second byte would overflow buffer
  441.  
  442.         subq.l    #2,D7            ;   # bytes remaining
  443.         bgt    .rms10loop
  444.         bne    .rmnlb
  445.         move.b    D0,(A0)                 ;   if D7 = 0 its even and we
  446.                         ;   should store the last byte
  447. .rmnlb        cmp.l    #-1,D7            ;   -1 = was odd #
  448.         bne    .rmeven         ;   fixup count
  449.         subq.l    #1,D6
  450.  
  451. .rmeven
  452. .rmsev0     tst.l    (A3)                    ;   if next buffer NULL
  453.         beq    .rmovflow
  454.         move.l    (A3)+,A0                ;   next buffer
  455.         move.l    (A3)+,D7
  456.         beq    .rmsev0         ;   0 bytes, goto next buffer
  457.         bra    .rms10            ;   loop, continue reading
  458.  
  459. .rmovflow
  460.         lea    _DummyBuf,A0        ;   overflow, dummy buffer
  461.         bra    .rms10
  462.  
  463. .rmeop        tst.b    D0            ;   EOP data better be 0!
  464.         beq    .rmendsub
  465.         moveq.l #-3,D6
  466.         bra    .rmend
  467.  
  468. .rmendsub    subq.l    #2,D6            ;   because we were two ahead
  469.  
  470. .rmend        bset.b    #PIOB_ACK,(A4)           ;   active pull up before (?)
  471.         bclr.b    #PIOB_ACK,(A5)           ;   setting ~ACK to input
  472.         move.l    D6,D0            ;   return value
  473.         movem.l (sp)+,D2-D7/A2-A5       ;   restore registers
  474.         rts
  475.  
  476. _ParWriteV:    movem.l D2-D7/A2-A6,-(sp)       ;   write vector
  477.         lea    16+44(sp),A3
  478.         bra    .wm000
  479.  
  480. _ParWrite:
  481.         movem.l D2-D7/A2-A6,-(sp)
  482.         lea    Null,A3
  483. .wm000        move.l    4+44(sp),D3             ;   D3 = destination address
  484.         move.l    8+44(sp),A0             ;   A0 = buffer to write
  485.         move.l    12+44(sp),D7            ;   D7 = # bytes to write
  486.  
  487.         move.l    _UnitBase,a1        ; A1 zeigt auf Unit
  488.         lea    PIOR_DDR(a1),a2        ; A2 zeigt auf DATA-DDR
  489.         lea    PIOR_PDR(a1),a1        ; A1 zeigt auf DATA
  490.  
  491.         move.l    _PIOBase,a4        ; A4 zeigt auf PIO
  492.         lea    PIO_PCDDR(a4),a5    ; A5 zeigt auf CTL-DDR
  493.         lea    PIO_PCDR(a4),a4        ; A4 zeigt auf CTL
  494.  
  495.         move.l    4,A6            ;   SYSBase
  496.  
  497.         move.b    #0,(A2)
  498.         and.b    #~CTL_MASK,(A5)
  499.  
  500.         move.l    _ParLLTimeout,D5    ;   D5 = timeout load
  501.  
  502.         move.l    D5,D4            ;   D4 = timeout countdown
  503.         moveq.l #-2,D6            ;   D6 = # bytes written
  504.  
  505.         ;   AQUIRE THE LINE USING ~ACK
  506.  
  507. .wmstab
  508.         bset.b    #PIOB_ACK,(A4)           ;   so is a 1 when we set it to w
  509.  
  510.         DISABLE
  511.  
  512.         move.b    (A4),D0                 ;   get stable data
  513.         and.b    #CTL_MASK,d0
  514.         move.b    (A1),D1
  515.         move.b    (a4),d2
  516.         and.b    #CTL_MASK,d2
  517.         cmp.b    d2,D0
  518.         beq    .wmstab1
  519.  
  520.         ENABLE
  521.  
  522.         bra    .wmstab
  523.  
  524.         ;   Ints still disabled
  525.         ;   D0 holds ~ACK ~REQ CTL status
  526.  
  527. .wmstab1    and.b    #CTL_MASK,D0        ;   ~ACK=1, ~REQ=1, CTL=1
  528.         cmp.b    #CTL_MASK,D0
  529.         beq    .wm02
  530.  
  531.         ;   no, if CTL = 1, ~REQ = 0, and D1 = my address then
  532.         ;   return w/ -2
  533.  
  534.         btst.l    #PIOB_REQ,D0
  535.         bne    .wm01
  536.         btst.l    #PIOB_CTL,D0
  537.         beq    .wm01
  538.         cmp.b    _ParNetAddr,D1        ;   somebody calling me?
  539.         bne    .wm01
  540.  
  541.         ENABLE
  542.         bra    .wmend
  543.  
  544. .wm01
  545.         ENABLE
  546.  
  547.         add.l    #1,_ParDebug+16
  548.         subq.l    #1,D4
  549.         bne    .wmstab
  550.         bra    .wmend
  551.  
  552.         ;   interrupts still disabled
  553.         ;   we almost own the line
  554.  
  555. .wm02        bset.b    #PIOB_ACK,(A5)                ;   set ~ACK to an output
  556.         nop
  557.         bclr.b    #PIOB_ACK,(A4)                ;   assert ~ACK
  558.         bne    .wm05            ;   was released before, have line!
  559.  
  560.                         ;   don't have line,
  561.         bclr.b    #PIOB_ACK,(A5)                ;   set back to input
  562.         bra    .wm01
  563.  
  564.         ;   Line now aquired.
  565.  
  566. .wm05
  567.         ENABLE
  568.  
  569.         move.b    #%11111111,(A2)         ;   set data ddr to outputs
  570.         move.b    D3,(A1)                 ;   set data lines to our addr
  571.  
  572.         ;   Before asserting ~REQ pulse CTL to cause interrupt on remote
  573.         ;   machines.  Note that our address is already on the data
  574.         ;   lines.
  575.  
  576.         bset.b    #PIOB_CTL,(A5)           ;   set CTL to output
  577.         bclr.b    #PIOB_CTL,(A4)           ;   pulse CTL to cause FLAG int
  578.         or.b    #CTL_MASK,(A4)          ;   set CTL = 1 and make sure
  579.                         ;   REQ will be one when we
  580.         bset.b    #PIOB_REQ,(A5)           ;   set ~REQ to output
  581.  
  582.         bclr.b    #PIOB_REQ,(A4)           ;   assert ~REQ
  583.  
  584.         bclr.b    #PIOB_ACK,(A5)           ;   make ~ACK an input
  585.                         ;   (note that REQ->0 before ACK->release)
  586.  
  587.         moveq.l #-1,D6            ;   D6 = # bytes written
  588.  
  589.         ;   INTERRUPTS ENABLED FOR TXFER (fully handshaked)
  590.         ;
  591.         ;   Address mark ~ACK, wait for ~ACK asserted
  592.  
  593. .wm10        btst.b    #PIOB_ACK,(A4)
  594.         beq    .wm15
  595.         move.l    D5,D4            ;   D4 = timeout countdown
  596. .wm11        btst.b    #PIOB_ACK,(A4)
  597.         beq    .wm15
  598.         add.l    #1,_ParDebug+20
  599.         subq.l    #1,D4
  600.         bne    .wm11
  601.         bra    .wmend
  602.  
  603.         ;   got ack, now set CTL = 0 (leaves at least one line 0 so
  604.         ;   nobody else thinks the bus is idle!)
  605.         ;
  606.         ;   note:   Since this is the address mark, and is sampled by
  607.         ;        the reader before it asserts ~ACK, I can set CTL
  608.         ;        = 0 now instead of waiting till after ~ACK is
  609.         ;        released.
  610.  
  611. .wm15        bclr.b    #PIOB_CTL,(A4)           ;   set CTL = 0 for duration of pkt
  612.         nop                ;   ???
  613.         bset.b    #PIOB_REQ,(A4)           ;   release ~REQ
  614.  
  615.  
  616.         moveq.l #0,D6            ;   # bytes written
  617.  
  618.         ;   DATA XFER LOOP
  619.         ;
  620.         ;   wait for ~ACK to be released (->1).  If no more bytes
  621.         ;   then skip to .wm50
  622.  
  623. .wm20
  624.         tst.l    D7            ;   more data in this buffer?
  625.         ble    .wm50            ;   nope.
  626.  
  627.         btst.b    #PIOB_ACK,(A4)           ;   wait ~ACK released
  628.         bne    .wm30
  629.         move.l    D5,D4            ;   D4 = timeout countdown
  630. .wm21        btst.b    #PIOB_ACK,(A4)
  631.         bne    .wm30            ;   need the timeout here?
  632.         btst.b    #PIOB_ACK,(A4)
  633.         bne    .wm30
  634.         add.l    #1,_ParDebug+24
  635.         subq.l    #1,D4
  636.         bne    .wm21
  637.         bra    .wmend
  638.  
  639.         ;   Assert ~REQ for this data byte and wait for ~ACK
  640.  
  641. .wm30
  642.         move.b    (A0)+,D0                ;   get next data byte
  643.         move.b    D0,(A1)                 ;   store data and
  644.         bclr.b    #PIOB_REQ,(A4)           ;   assert ~REQ
  645.  
  646.         move.b    (A0)+,D0                ;   get next data byte
  647.         subq.l    #2,D7            ;   one less byte (this and next)
  648.         addq.l    #1,D6            ;   # bytes written (this only)
  649.                         ;   (not valid until we get ACK
  650.                         ;    which is why the wmendsub
  651.  
  652.         btst.b    #PIOB_ACK,(A4)           ;   wait for ACK
  653.         beq    .wm40
  654.         btst.b    #PIOB_ACK,(A4)
  655.         beq    .wm40
  656.         move.l    D5,D4            ;   D4 = timeout countdown
  657. .wm31        btst.b    #PIOB_ACK,(A4)
  658.         beq    .wm40
  659.         add.l    #1,_ParDebug+28
  660.         subq.l    #1,D4
  661.         bne    .wm31
  662.         bra    .wmendsub
  663.  
  664.         ;   Have ~ACK, byte transmitted.  ++bytes written, --bytes left
  665.         ;   and loop
  666.  
  667. .wm40        move.b    D0,(A1)                 ;   store second byte
  668.         bset.b    #PIOB_REQ,(A4)           ;   release ~REQ
  669.  
  670.         addq.l    #1,D6            ;   # bytes written
  671.  
  672.         bra    .wm20
  673.  
  674.         ;   Last byte in buffer has been transmitted.
  675.         ;
  676.         ;   Get next buffer in vector
  677.  
  678. .wm50        tst.l    (A3)
  679.         beq    .wm50a
  680.         move.l    (A3)+,A0                ;   buffer ptr
  681.         move.l    (A3)+,D7                ;   # bytes
  682.         bra    .wm20            ;   loop to top
  683.  
  684. .wm50a
  685.         ;   Last byte has been transmitted,
  686.         ;
  687.         ;   Wait for ~ACK to be released and then assert ~REQ with
  688.         ;   EOP & CTL = 1
  689.         ;
  690.         ;   (timing on read is that CTL is sampled when ~REQ is
  691.         ;   RELEASED so no timing window here)
  692.  
  693.         btst.b    #PIOB_ACK,(A4)           ;   Wait ~ACK released
  694.         beq    .wm50
  695.  
  696.         move.b    #0,(A1)                 ;   EOP mark (0)
  697.         bclr.b    #PIOB_REQ,(A4)           ;   assert ~REQ
  698.  
  699.         ;   Wait for ~ACK asserted
  700.  
  701.         btst.b    #PIOB_ACK,(A4)
  702.         beq    .wm60
  703.         move.l    D5,D4
  704. .wm51        btst.b    #PIOB_ACK,(A4)
  705.         beq    .wm60
  706.         add.l    #1,_ParDebug+32
  707.         subq.l    #1,D4
  708.         bne    .wm51
  709.         moveq.l #-3,D6            ;   EOP failed
  710.         bra    .wmend
  711.  
  712.         ;   Set CTL = 1 then release ~REQ, then wait for ~ACK released
  713.  
  714. .wm60        or.b    #PIOF_CTL,(A4)          ;   set CTL = 1
  715.         or.b    #PIOF_CTL!PIOF_REQ,(A4) ;   release ~REQ
  716.  
  717.         ;   Wait ~ACK released ?
  718.  
  719. .wm61        btst.b    #PIOB_ACK,(A4)
  720.         beq    .wm61
  721.  
  722.         ;   Add D7 to D6.  This handles fixup if an odd number of bytes
  723.         ;   were requested written, D7 will be -1 (odd) or 0 (even) and
  724.         ;   D6 will be one too large (odd) or perfect (even)
  725.  
  726.         add.l    D7,D6
  727.  
  728.         bra    .wmend
  729.  
  730. .wmendsub    subq.l    #1,D6        ;   was ahead in count
  731.  
  732. .wmend        move.b    #0,(A2)         ;   set data port to input
  733.         and.b    #~CTL_MASK,(A5) ;   set data port for ctl lines to input
  734.  
  735.         move.l    D6,D0            ;   return value
  736.         movem.l (sp)+,D2-D7/A2-A6       ;   restore registers
  737.         rts
  738.  
  739.         ;   sum = LongCheckSum(buf, bytes)
  740.         ;   (buffer must be lw aligned and bytes must be multiples of 4)
  741.  
  742. _LongCheckSum:
  743.         moveq.l #0,D0            ;   D0 = accumulated checksum
  744.         move.l    4(sp),A0                ;   A0 = ptr
  745.         move.l    8(sp),D1                ;   D1 = bytes
  746.         beq    .pcrts
  747. .pc10        add.l    (A0)+,D0
  748.         subq.l    #4,D1
  749.         bgt    .pc10
  750.         tst.l    D1
  751.         bne    .pc20            ;   not multiple of 4 bytes!
  752. .pcrts        rts                ;   return checksum
  753. .pc20        illegal             ;   cause task-held msg
  754.         rts
  755.  
  756.         ;   Delays 10000 rough timeout loops, used to determine
  757.         ;   timeout on init
  758.  
  759. _Time10000:
  760.         move.l    #10000,D4
  761. t10        move.l    D4,D4
  762.         move.l    D4,D4
  763.         move.l    D4,D4
  764.         move.l    D4,D4
  765.         subq.l    #1,D4
  766.         bne    t10
  767.         rts
  768.  
  769.         END
  770.  
  771.