home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 12: Textmags & Docs / nf_archive_12.iso / MAGS / SOURCES / ATARI_SRC.ZIP / atari source / HDX_BACK / HDXPCH / ACSI.S < prev    next >
Encoding:
Text File  |  2001-02-09  |  11.7 KB  |  451 lines

  1.  
  2. .include    "defs.h"
  3. .include    "sysvar.h"
  4. .include    "mfp.h"
  5. .include    "acsi.h"
  6. .include    "68030.s"
  7.  
  8.  
  9. ;+
  10. ;  Tunable (delay) values for ACSI
  11. ;-
  12. ACLTMOUT    equ    600        ; long-timeout (3 S)
  13. ACSTMOUT    equ    20        ; short-timeout (100 mS)
  14. SLWACLTO    equ    5000        ; long-timeout (25 S) for slow ACSI
  15. SLWACSTO    equ    42        ; short-timeout (205 mS) for slow ACSI
  16.  
  17.  
  18. ;+
  19. ; Declarations
  20. ;-
  21. lastacstm:    dc.l    0        ; controller last accessed time
  22. control:    dc.b    0        ; flag for sending control byte
  23.         .globl    _slwacsi
  24. _slwacsi:    dc.b    0        ; assume not doing slow ACSI
  25. .even
  26.  
  27. .extern        _cmdblk
  28.  
  29.  
  30. ;+
  31. ; LONG _qdone() - Wait for command byte handshake
  32. ; LONG _fdone() - Wait for operation complete
  33. ; Passed:    nothing
  34. ;
  35. ; Returns:    EQ: no timeout
  36. ;        MI: timeout condition
  37. ;
  38. ; Uses:        D0
  39. ;
  40. ;-
  41.  
  42. .if    !DRIVER
  43. _slwfdone:                ; fdone for slow response
  44.     move.l    #SLWACLTO,d0
  45.     bra.s    qd0
  46. .endif
  47.  
  48. _fdone:    move.l    #ACLTMOUT,d0
  49.     bra.s    qd0
  50.  
  51. .if    !DRIVER
  52. _slwqdone:                ; qdone for slow response
  53.     moveq    #SLWACSTO,d0    
  54.     bra.s    qd0
  55. .endif
  56.  
  57. _qdone:    moveq    #ACSTMOUT,d0
  58.  
  59. qd0:    tst.b    _slwacsi        ; talking to slow ACSI device?
  60.     beq.s    qd1            ; if not, go wait for interrupt
  61.                     ; else
  62.     move.l    d0,-(sp)        ; save timeout value
  63.     moveq    #2,d0            ; busy-wait delay for slow ACSI
  64. sdelay:    add.l    _hz_200,d0        ; minimum 20 microsec.
  65.     cmp.l    _hz_200,d0
  66.     bge.s    sdelay
  67.     move.l    (sp)+,d0        ; restore timeout value
  68.  
  69. qd1:    add.l    _hz_200,d0
  70. qd2:    cmp.l    _hz_200,d0        ; timeout?
  71.     bcs.s    qdq            ; (i give up, return NE)
  72.     btst    #5,GPIP        ; interrupt?
  73.     bne.s    qd2            ; (not yet)
  74.  
  75.     moveq    #0,d0            ; return EQ (no timeout)
  76.     rts
  77.  
  78. qdq:    moveq    #-1,d0
  79.     rts
  80.  
  81.  
  82. ;+
  83. ; Wait for end of SASI command
  84. ;
  85. ; Passed:    d1 value to be written to wdl
  86. ;
  87. ; Returns:    EQ: success (error code in D0.W)
  88. ;        MI: timeout (-1 in D0.W)
  89. ;        NE: failure (SASI error code in D0.W)
  90. ;
  91. ; Uses:        d0
  92. ;
  93. ; Comments: (12/05/89)
  94. ;    The flushing of D cache is necessary per Jim Tittsler.  For
  95. ; detail, refer to mail sent by jwt on 12/04/89 about ACSI DMA.
  96. ;-
  97. .if    !DRIVER
  98.     .globl    _cachexst
  99. _cachexst:    dc.b    0
  100.  
  101. _slwendcmd:
  102.     bsr    _slwfdone        ; wait for operation complete
  103.     bra.s    end0
  104. .else
  105.     .extern    _cachexst
  106. .endif
  107.  
  108. _endcmd:
  109.     bsr    _fdone            ; wait for operation complete
  110. end0:    bmi.s    endce            ; (timed-out, so complain)
  111.  
  112. cmdcmp:    tst.b    _cachexst        ; '030 cache exists
  113.     beq.s    end1            ; if not, fine
  114.                     ; else, dump D cache
  115.     move.w    sr,-(sp)        ; go to IPL 7
  116.     ori.w    #$700,sr        ; no interrupts right now kudasai
  117.     movecacrd0            ; d0 = (cache control register)
  118.     ori.w    #$800,d0        ; dump the D cache
  119.     moved0cacr            ; update cache control register
  120.     move.w    (sp)+,sr        ; restore interrupt state
  121.  
  122. end1:    move.w    d1,WDL
  123.     move.w    WDC,d0            ; get the result
  124.     and.w    #$00ff,d0        ; (clean it up), if non-zero should
  125.                     ; do a ReadSense command to learn more
  126. endce:    move.l    _hz_200,lastacstm    ; update controller last accessed time
  127.     addq.l    #2,lastacstm        ; lastacstm = _hz_200 + 2;
  128.     rts                
  129.  
  130.  
  131. ;+
  132. ;  Unlock DMA chip and return completion status;
  133. ;-
  134.     .globl    _hdone
  135. _hdone:    move.w    #$180,WDL    ; reset the chip for floppy
  136.     bsr    rstdelay
  137.     move.w    #$80,WDL    ; Landon's code seems to presume we put 
  138.                 ;  $80 there
  139.     clr    flock        ; NOW, signal that we are done
  140.     rts
  141.  
  142.  
  143. ;+
  144. ; delay()
  145. ;    5 - 10ms kludge delay for message byte sent back by controller.
  146. ;-
  147. _delay:    move.l    d0,-(sp)        ; preserve d0
  148.     move.l    lastacstm,d0        ; d0 = controller last accessed time
  149. wait:    cmp.l    _hz_200,d0        ; while (_hz_200 <= lastacstm)
  150.     bcc.s    wait            ;    wait()
  151.     move.l    (sp)+,d0        ; restore d0
  152.     rts
  153.  
  154.  
  155. ;+
  156. ; smplacsi() - send a simple ACSI command (ie. no DMA involved)
  157. ;
  158. ;    d0.w = physical unit number
  159. ;    d1.l = transfer length (in bytes)
  160. ;    d2.w = command length (NCMD or LCMD)
  161. ;    a0.l = buffer address
  162. ;-
  163.     .globl    _smplacsi
  164. _smplacsi:
  165.     st    flock            ; lock FIFO
  166.     bsr    _delay            ; delay if necessary
  167.     movea.l    #WDC,a1            ; a1 = pointer to DMA chip
  168.     andi.w    #7,d0            ; mask off the flags to get unit num
  169.     moveq    #0,d1            ; no DMA
  170.     bsr    sblkacsi        ; send command block
  171.     bra    _hdone            ; cleanup after IRQ
  172.  
  173.  
  174. ;+
  175. ; rcvacsi() - send a ACSI command which receives data back.
  176. ;
  177. ; Passed:
  178. ;    d0.w = physical unit number
  179. ;    d1.l = transfer length (in bytes)
  180. ;    d2.w = command length (NCMD or LCMD)
  181. ;    a0.l = buffer address
  182. ;
  183. ; Comments:
  184. ;    This routine assumes that if you are transferring more than 512
  185. ; bytes, the transfer length must be a multiple of 16 bytes.  It also 
  186. ; assumes the allocation length byte is always at byte 4 in the command
  187. ; block. (Therefore, it won't work with Receive Diagnostic ($1c) if data
  188. ; length is not a multiple of 16 bytes.  But Receive Diagnostic has never
  189. ; been used.)
  190. ;    The transfer length in register D1 MUST be greater than 0.
  191. ;-
  192.     .globl    _rcvacsi
  193. _rcvacsi:
  194.     st    flock            ; lock FIFO
  195.     move.w    d3,-(sp)        ; preserve d3
  196.     bsr    _delay            ; delay if necessary
  197.     movea.l    #WDC,a1            ; a1 = pointer to DMA chip
  198.  
  199.     bsr    setadma            ; set DMA pointer
  200.     move.w    #$190,XWDL(a1)    ;WDL    ; toggle DMA chip for "receive"
  201.     bsr    rstdelay        ; delay
  202.     move.w    #$090,XWDL(a1)    ;WDL
  203.     bsr    rstdelay        ; delay
  204.  
  205. .if    RDWDL
  206.     tst.w    XWDL(a1)        ; to point MMU to correct direction
  207. .endif    ;RDWDL
  208.  
  209.     bsr    setacnt            ; set DMA count
  210.  
  211.     andi.w    #7,d0            ; mask off the flags to get unit num
  212.                     ; find # times need to send it
  213.     cmpi.l    #512,d1            ; transferring < 512 bytes?
  214.     bcs.s    .0            ; if so, go find # times to send
  215.     moveq    #0,d1            ; else assume it's 16*n, send once
  216.     bra.s    .4
  217.  
  218. .0:    move.w    d1,d3            ; d3 = transfer length
  219.     cmpi.w    #16,d1            ; transferring < 16 bytes?
  220.     bcs.s    .1            ; if so, find # times to make 16 bytes
  221.  
  222.     andi.w    #$0f,d1            ; else, is it multiple of 16 bytes?
  223.     beq.s    .4            ; if so, just do once (d1.w = 0)
  224.     moveq    #1,d1            ; else, need to do twice
  225.     bra.s    .4
  226.  
  227. .1:    moveq    #16,d1            ; find # times to make 16 bytes
  228.     divu    d3,d1            ; d1.w = 16 / transfer length
  229.     subq.w    #1,d1            ; dbra likes one less
  230.  
  231. .2:    swap    d1            ; d1.w = remainder
  232.     tst.w    d1            ; any remainder?
  233.     bne.s    .3            ; if yes, go add one to the quotient
  234.     swap    d1            ; if no, # times to send = quotient
  235.     bra.s    .4
  236.  
  237. .3:    swap    d1            ; d1.w    = # times to send command
  238.     addq.w    #1,d1            ;    = quotient + 1
  239.  
  240. .4:    lea    _cmdblk,a0        ; a0 = address of command block
  241. .5:    movem.l    d0-d2/a0,-(sp)        ; save d0 through d2 and a0
  242.     moveq    #0,d1            ; direction of DMA is IN
  243.     bsr    _delay            ; delay if necessary
  244.     bsr    sblkacsi        ; send the command block
  245.     tst.w    d0            ; successful?
  246.     bne.s    .7            ; if not, quit
  247.     movem.l    (sp)+,d0-d2/a0        ; else restore d0 through d2 and a0
  248.     dbra    d1,.6            ; done yet?
  249.     moveq    #0,d0            ; command block sent successfully
  250.     bra.s    raend            ; phone home...
  251.  
  252. .6:    moveq    #-1,d0            ; unit number already in command block
  253.     move.b    d3,4(a0)        ; modify transfer length
  254.     bra.s    .5            ; send it enough times
  255.  
  256. .7:    adda    #16,sp            ; cleanup stack
  257. raend:    move.w    (sp)+,d3        ; restore d3
  258.     bra    _hdone            ; cleanup after IRQ
  259.  
  260.  
  261. ;+
  262. ; wrtacsi() - send an ACSI command which will write data to the target
  263. ;
  264. ; Passed:
  265. ;    d0.w = physical unit number
  266. ;    d1.l = transfer length (in bytes)
  267. ;    d2.w = command length (NCMD or LCMD)
  268. ;    a0.l = buffer address
  269. ;-
  270.     .globl    _wrtacsi
  271. _wrtacsi:
  272.     st    flock            ; lock FIFO
  273.     bsr    _delay
  274.     movea.l    #WDC,a1            ; a1 = pointer to DMA chip
  275.  
  276.     bsr    setadma            ; set DMA pointer
  277.     move.w    #$90,XWDL(a1)    ;WDL    ; toggle DMA chip for "send"
  278.     bsr    rstdelay        ; delay 
  279.     move.w    #$190,XWDL(a1)    ;WDL
  280.     bsr    rstdelay        ; delay
  281.  
  282. .if    RDWDL
  283.     tst.w    XWDL(a1)        ; to point MMU to correct direction
  284. .endif    ;RDWDL
  285.  
  286.     bsr    setacnt            ; set DMA count
  287.     
  288.     andi.w    #7,d0            ; mask off the flags to get unit num
  289.     move.l    #$0100,d1        ; d1 = direction of DMA is OUT
  290.     bsr    sblkacsi        ; send the command block
  291.  
  292. waend:    bra    _hdone            ; cleanup after IRQ
  293.  
  294.  
  295. ;+
  296. ; sblkacsi() - set DMA pointer and count and send command block
  297. ;
  298. ; Passed:
  299. ;    d0.w = physical unit number
  300. ;    d1.l = direction of DMA ($0000 for IN or $0100 for OUT)
  301. ;    d2.w = command length (NCMD or LCMD)
  302. ;    a1.l = pointer to DMA chip
  303. ;
  304. ; Returns:
  305. ;    d0.l =  0 if successful
  306. ;    d0.l = -1 if timeout
  307. ;
  308. ; Trashes:
  309. ;    d0, d1, d2, a2
  310. ;-
  311. sblkacsi:
  312.     move.b    #$88,d1            ; next byte is the opcode
  313.     move.w    d1,XWDL(a1)    ;WDL
  314.  
  315.     move.b    #$8a,d1            ; following bytes are operands
  316.     lea    _cmdblk,a2        ; a2 = address of command block
  317.  
  318.     tst.w    d0            ; is unit # already in command block
  319.     bmi.s    .0            ; if yes, just send command block
  320.                     ; else integrate unit # into cmd blk
  321.     lsl.b    #5,d0            ; shift unit number into place
  322.     or.b    d0,(a2)            ; first command byte = unit # | opcode
  323.                     ; control byte is sent seperately
  324. .0:    subq.w    #2,d2            ; and dbra likes one less 
  325. .1:    swap    d1            ; d1.hw = operand
  326.     move.b    (a2)+,d1        ; d1.lw = tells controller next byte
  327.     swap    d1            ;      is an operand
  328.     move.l    d1,(a1)        ;WDCWDL
  329.     bsr    _qdone
  330.     bmi.s    sbaend            ; if timeout, returns
  331.     dbra    d2,.1            ; else send rest of command block
  332.  
  333.     move.w    d1,XWDL(a1)    ;WDL    ; else get ready to send control byte
  334.     move.b    #0,d1            ; signal sending control byte
  335.     swap    d1            ; d1.hw = operand
  336.     move.b    (a2),d1            ; d1.lw = tells controller it's end
  337.     swap    d1            ;      of command
  338.     move.l    d1,(a1)            ; send it
  339.  
  340.     move.b    #$8a,d1            ; d1 = wdl value
  341.     bsr    _endcmd            ; wait for command completion
  342. sbaend: rts                ; heading home
  343.  
  344.  
  345. ;+
  346. ; setadma() - set the ACSI DMA pointer
  347. ;
  348. ; Passed:
  349. ;    a0.l = buffer address
  350. ;-
  351.     .globl    setadma
  352. setadma:
  353.     move.l    a0,-(sp)        ; move it on stack
  354.     move.b    3(sp),DMALOW        ; set low-byte of address
  355.     move.b    2(sp),DMAMID        ; set mid-byte of address
  356.     move.b    1(sp),DMAHI        ; set high-byte of address
  357.     addq.l    #4,sp            ; clean up stack
  358.     rts
  359.  
  360.  
  361. ;+
  362. ; setacnt() - set the ACSI DMA counter
  363. ;
  364. ; Passed:
  365. ;    d1.l = transfer length (in bytes)
  366. ;    a1.l = pointer to DMA chip
  367. ;-
  368.     .globl    setacnt
  369. setacnt:
  370.     cmpi.l    #512,d1            ; transferring more than 512 bytes?
  371.     bhi.s    .0            ; if so, find transfer len in blocks
  372.     move.w    #1,(a1)        ;WDC    ; else set DMA count to 1 block
  373.     bra.s    sacend
  374. .0:    movem.l    d1-d2,-(sp)        ; save d1 and d2
  375.     move.l    d1,d2            ; d2 = transfer length (in bytes)
  376.     lsr.l    #8,d1            ; find transfer length (in blocks)
  377.     lsr.l    #1,d1            ; d1 >>= 9 = transfer len (in blocks)
  378.     andi.l    #$1ff,d2        ; multiples of 512?
  379.     beq.s    .1            ; if so, go set count
  380.     add.w    #1,d1            ; else increment count by one    
  381. .1:    move.w    d1,(a1)        ;WDC    ; set DMA count
  382.     movem.l    (sp)+,d1-d2        ; restore d1 and d2
  383. sacend:    rts
  384.  
  385.  
  386.  
  387. .if    !DRIVER                ; not to be included in driver
  388.  
  389.  
  390. ;+
  391. ; stacsi() - start/stop an ACSI unit
  392. ;
  393. ;    d0.w = physical unit number
  394. ;    d2.w = command length (NCMD or LCMD)
  395. ;-
  396.     .globl    _stacsi
  397.     .extern    _cmdblk
  398. _stacsi:
  399.     st    flock            ; lock FIFO
  400.     bsr    _delay            ; delay if necessary
  401.     movea.l    #WDC,a1            ; a1 = pointer to DMA chip
  402.     andi.w    #7,d0            ; mask off the flags to get unit num
  403.     moveq    #0,d1            ; clear d1
  404.     move.b    #$88,d1            ; next byte is the opcode
  405.     move.w    d1,XWDL(a1)    ;WDL
  406.  
  407.     move.b    #$8a,d1            ; following bytes are operands
  408.     lea    _cmdblk,a2        ; a2 = address of command block
  409.                     ; integrate unit # into cmd blk
  410.     lsl.w    #5,d0            ; shift unit number into place
  411.     or.b    d0,(a2)            ; first command byte = unit # | opcode
  412.                     ; control byte is sent seperately
  413.     subq.w    #2,d2            ; and dbra likes one less 
  414. .0:    swap    d1            ; d1.hw = operand
  415.     move.b    (a2)+,d1        ; d1.lw = tells controller next byte
  416.     swap    d1            ;      is an operand
  417.     move.l    d1,(a1)        ;WDCWDL
  418.     bsr    _slwqdone        ; needs a longer short timeout
  419.     beq.s    .1            ; if successful, go on
  420.     rts                ; else it timed-out, returns
  421. .1:    dbra    d2,.0            ; send rest of command block
  422.  
  423.     move.w    d1,XWDL(a1)    ;WDL    ; else get ready to send control byte
  424.     move.b    #0,d1            ; signal sending control byte
  425.     swap    d1            ; d1.hw = operand
  426.     move.b    (a2),d1            ; d1.lw = tells controller it's end
  427.     swap    d1            ;      of command
  428.     move.l    d1,(a1)            ; send it
  429.  
  430.     move.b    #$8a,d1            ; d1 = wdl value
  431.     bsr    _slwendcmd        ; wait for command completion
  432.     bra    _hdone            ; cleanup after IRQ
  433.  
  434. .endif    ;!DRIVER
  435.  
  436.  
  437. ;+
  438. ; Rstdelay()
  439. ;    After talking to the DMA chip in a way that may reset it, 
  440. ; we need a 8 8Mhz clocks (ie. 1 microsec) delay, before we can
  441. ; talk to the chip again.
  442. ;-
  443.     .globl    rstdelay
  444. rstdelay:
  445.     tst.b    GPIP            ; delay for 1 microsec
  446.     tst.b    GPIP            ; this amounts to 16 16Mhz clocks
  447.     tst.b    GPIP
  448.     tst.b    GPIP
  449.     rts
  450.  
  451.