home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Netzwerk / parbench.lha / Extras / ParPC.lha / ParPC / PCFiles / parkern.asm < prev    next >
Encoding:
Assembly Source File  |  1993-06-25  |  19.9 KB  |  802 lines

  1. ; Lowlevel routines for PARnet
  2. ; 03-JUN-93 <S.A.Pechler@bdk.tue.nl>
  3.  
  4.     .MODEL MEMMOD,C
  5.     LOCALS
  6.     %MACS
  7.     .LALL
  8.  
  9.     .DATA
  10. _ParNetAddr    db 1        ; default network address
  11. _LPTData    dw 0378h    ; LPT data port address (default)
  12. _LPTStatus    dw 0379h    ; LPT status port address (default)
  13. _LPTControl    dw 037ah    ; LPT control port address (default)
  14.  
  15. _ParLLTimeout   dw 65535
  16.     ;dl 983025 ; default timeout value (about 1 second?)
  17. _DestAddress db 5
  18. _DebugBytes dw 255
  19. _DummyBuf db 0            ; dummy buffer
  20.       db 0            ; dummy buffer
  21.       db 0,0        ; padding
  22.  
  23.     .CODE
  24.         PUBLIC paraddress,pardataready,parread,parwrite
  25.  
  26. ; Parnet interface truth table
  27. ;
  28. ; 0 = line is 0V
  29. ; 1 = line is 5V
  30. ; X = don't care
  31. ;
  32. ;SELIN  D3 STROBE | RD RC WD WC | Function
  33. ;-----------------+-------------+---------------
  34. ; 0      0    X   | 0  1  1  1    | Read Data
  35. ; 0      1    X   | 1  1  1  0    | Write Control
  36. ; 1      X    0   | 1  1  0  1    | Write Data
  37. ; 1      X    1   | 1  0  1  1    | Read Control
  38. ;
  39.  
  40. ; Put the interface in a stable mode by switching it into
  41. ; 'Read Control' mode.
  42. ;
  43. stable: push ax
  44.     push dx
  45.     mov dx,_LPTControl    ;control register 2 (to clock in data & Read Control)
  46.  
  47.     mov al,14h    ;all outputs to 1 (INIT is not inverted!), enable IRQ7
  48.     out dx,al    ;STROBE=1 & SELIN=1 -> read control (stable mode).
  49.     pop dx
  50.     pop ax
  51.     ret
  52.  
  53. ; Set the datalines to 'input' by setting all lines to high.
  54. ; (Open collector outputs not active).
  55. ;
  56. data_input:
  57.     push ax
  58.     push dx
  59.     mov dx,_LPTData    ;data register
  60.     mov al,0ffh    ;datalines high, so
  61.     out dx,al    ;open collector drivers not active.
  62.     mov dx,_LPTControl    ;control register 2 (to set data)
  63.  
  64.     mov al,15h    ;SELIN=1 & STROBE=0 Enable IRQ7
  65.     out dx,ax    ;write data
  66.     call Stable    ;be sure to CLOCK it in.
  67.     pop dx
  68.     pop ax
  69.     ret
  70.  
  71. ; Set the control-lines to 'input' by setting all lines to high.
  72. ; (Open collector outputs not active).
  73. ;
  74. control_input:
  75.     push ax
  76.     push dx
  77.     mov dx,_LPTData    ;data register
  78.     mov al,0ffh    ;d3=1, rest don't care
  79.     out dx,ax
  80.     mov dx,_LPTControl ;Control register
  81.  
  82.     mov al,1ch    ;all outputs to 1, SELIN to 0 (INIT is not inverted!)
  83.     out dx,al    ;d3=1 & SELIN=0 -> write control
  84.     call Stable    ;be sure to CLOCK it in.
  85.     pop dx
  86.     pop ax
  87.     ret
  88.  
  89. ; read data from the cable
  90. read_data:        ;buffers must be in stable & data_input mode.
  91.     push ax
  92.     push bx
  93.     push dx
  94.     mov dx,_LPTData    ;data register
  95.     mov al,00    ;d3=0
  96.     out dx,al    ;all datalines to zero.
  97.     mov dx,_LPTControl ;Control register
  98.  
  99.     mov al,1ch    ;SELIN=0, rest high (INIT is not inverted!).
  100.     out dx,al    ;d3=0 & SELIN=0 -> Read Data.
  101.     mov dx,_LPTStatus ;status register
  102.     in al,dx    ;read it
  103.     mov bl,al    ;save it to BL (AL will be changed)
  104.     mov dx,_LPTControl    ;control register 2
  105.     in al,dx    ;read it
  106.     mov cl,al    ;save it to CL
  107.     call stable    ;put all buffers in tri-state mode.
  108.     call data_input ;a bug, the change from RD->RC could activate WD.
  109.     call translate_data ; put data into 8 bit CL.
  110.     pop dx
  111.     pop bx
  112.     pop ax
  113.     ret
  114.  
  115. ; Translation incomming data via control lines.
  116. ; (some lines are inverted, and I can't read 8 bits at once)
  117. ;
  118. ; Let's say, all datalines on the cable are high:
  119. ;
  120. ; databits: 7654 3210
  121. ; value:    1111 1111
  122. ;
  123. ; Then the input from the control registers would look like this:
  124. ;
  125. ; CL: data read from control register 2
  126. ;
  127. ; CL bits: 7654 3210  centronics  corresponding
  128. ; value:   XXXX X100   keyword:    databits:
  129. ;          |||| |||`- strobe         d0
  130. ;          |||| ||`-- auto LF        d1
  131. ;          |||| |`--- init           d2
  132. ;          |||| `---- invalid        x
  133. ;          ````------ invalid        x
  134. ;
  135. ; BL: data read from control register 1
  136. ;
  137. ; BL bits: 7654 3210  centronics  corresponding
  138. ; value:   0111 1XXX   keyword:     databits:
  139. ;          |||| |```- invalid          x
  140. ;          |||| `---- error           d3
  141. ;          |||`------ select          d4
  142. ;          ||`------- paper empty     d5
  143. ;          |`-------- ack             d6
  144. ;          `--------- busy            d7
  145. ;
  146. translate_data:
  147.     xor cl,03h    ;invert bits 0 and 1
  148.     and cl,07h    ;discards bits not needed in CL.
  149.     xor bl,80h    ;invert bit 7 in BL (busy).
  150.     and bl,0f8h    ;discard bits not needed in BL.
  151.     or cl,bl    ;merge them together (high bits in BL, lower in CL)
  152.     ret        ;ready, translated data in CL.
  153.  
  154.  
  155. ; Read the controlbits from the cable (busy, pout & sel)
  156. ;
  157. ; BL: control read from control register 1, represents the REAL line
  158. ;     status.
  159. ;
  160. ; BL bits: 7654 3210  centronics:    cable:  parnet:
  161. ; value:   0111 1XXX   
  162. ;          |||| |```- invalid          x
  163. ;          |||| `---- error            x
  164. ;          |||`------ select          busy    ack
  165. ;          ||`------- paper empty     pout    req
  166. ;          |`-------- ack             sel     ctl
  167. ;          `--------- busy             x
  168. ;
  169. ;Output: BL, but shifted 4 bits to the right.
  170. ;
  171. read_control:            ;control lines must be set to input first.
  172.     push ax
  173.     push cx
  174.     push dx
  175.     call Stable        ;Stable mode = Read_Control mode.
  176.     mov dx,_LPTStatus    ;Status register
  177.     in al,dx        ;read it
  178.     mov cl,04        ;need CL to shift AL
  179.     shr al,cl        ;shift 4 bits to the right.
  180.     mov bl,al        ;save it to BL
  181.     and bl,07        ;discard bits not needed.
  182.     pop dx
  183.     pop cx
  184.     pop ax
  185.     ret            ;ready, controlbits in BL.
  186.  
  187. ;-----------------------------------------------------------------------------
  188. ; Clear the parnet ack-bit. Leave other control lines high.
  189. ; Warning: I can't read my own control-lines back!
  190. ;
  191. clear_ack_only:
  192.     push bx
  193.     push cx
  194.     mov bl,0feh        ; set parnet ack-bit to 0
  195.     call write_control    ; write control
  196.     pop cx
  197.     pop bx
  198.     ret
  199.  
  200. ;-----------------------------------------------------------------------------
  201. ; Set the parnet ack-bit. Leave other control lines high.
  202. ; Warning: I can't read my own control-lines back!
  203. ;
  204. Set_ack_all:
  205.     push bx
  206.     push cx
  207.     mov bl,0fh        ; set all bits to 1 (including ACK)
  208.     call write_control    ; write control
  209.     pop cx
  210.     pop bx
  211.     ret
  212.  
  213. ; Write control
  214. ;
  215. ; BL: controlbits to be written
  216. ;
  217. ; BL bits: 7654 3210                centronics
  218. ; value:   XXXX X100  controlbits:  keyword:
  219. ;          |||| |||`-    ack        strobe
  220. ;          |||| ||`--    req        auto LF
  221. ;          |||| |`---    ctl        init
  222. ;          |||| `----     x         selin
  223. ;          ````------     x         invalid
  224. ;
  225. ; !The value in BL represents the REAL LINE STATUS, so a bit=0 means the
  226. ; !line is on low voltage.
  227. ;
  228. ; The INIT output is on the parallel card not inverted. This bit will be
  229. ; inverted in this procedure, so you don't have to care about it.
  230. ;
  231. write_control:        ; Interface must be in stable mode!
  232.     push ax
  233.     push dx
  234.     mov dx,_LPTData    ; data register
  235.     mov al,0ffh    ; d3=1, rest don't care.
  236.     out dx,al    ;
  237.     mov dx,_LPTControl ; control register
  238.     mov al,bl    ; move control bits to AL (for OUT-instruction)
  239.     xor al,0bh    ; invert all lines except for INIT (=ctl)
  240.     or al,08h    ; SELIN = 0 (inverted!)
  241.     out dx,al    ; SELIN = 0 & d3=1 -> write control.
  242.     call Stable
  243.     pop dx
  244.     pop ax
  245.     ret
  246.  
  247. ; Write DATA
  248. ;
  249. ; CL: data to be written.
  250. ;
  251. write_data:            ; interface must be in stable mode!
  252.     push ax
  253.     push dx
  254.     mov dx,_LPTData        ; data register
  255.     mov al,cl        ; move data to AL for OUT-instruction.
  256.     out dx,al        ; put it on (not on cable yet).
  257.     mov dx,_LPTControl    ; control register
  258.     mov al,15h        ; SELIN=1, strobe=0, enable IRQ7
  259.     out dx,al        ; write data
  260.     call Stable        ; be sure to 'CLOCK' it in.
  261.     pop dx
  262.     pop ax
  263.     ret
  264.  
  265.  
  266. ; (void) paraddress(int16 myaddr,int16 LPTAddress)
  267. ;
  268. ; Set my ParNet address (1-254) and LPT port address (0378h,03bch or 0278h)
  269. ;
  270. ; ParNet addresses 0 and 255 are reserved!
  271. ;
  272. paraddress    PROC
  273.         ARG myad:word,lptad:word
  274.  
  275.     mov ax,myad        ; my parnet address
  276.     mov _ParNetAddr,al    ; store address
  277.     mov ax,lptad        ; LPT port address
  278.     mov _LPTData,ax        ; Place data port address
  279.     inc ax            ; next register is status port
  280.     mov _LPTStatus,ax
  281.     inc ax            ; next register is control port
  282.     mov _LPTControl,ax
  283.     call data_input        ; data lines high
  284.     call control_input    ; control lines high
  285.     ret
  286.  
  287. paraddress     ENDP
  288.  
  289. ; int  = pardataready(void)
  290. ;
  291. ; Check for data present (e.g. after an IRQ7).
  292. ;
  293. ; Returns:  1 if packet is probably pending for you
  294. ;           0 if line is currently idle
  295. ;          -1 if packet isn't for you
  296. ;
  297. ; If line has been aquired but no control address has been
  298. ; put on it yet, pardataready() will wait for a control
  299. ; address.  Thus, after a signal, a single call to
  300. ; pardataready() should suffice.
  301. ;
  302. pardataready    PROC
  303.     call data_input        ; be sure all lines
  304.     call control_input    ; are set to input.    
  305. .pdstable:
  306.     call read_control    ; read control in BL
  307.     mov al,bl        ; save it
  308.     call read_data        ; read data in CL
  309.     call read_control    ; read control in BL
  310.     cmp al,bl
  311.     jne .pdstable
  312.  
  313.     ;   Now, pardataready might be called after the sending machine
  314.     ;   has aquired but before it can assert REQ.  However, the
  315.     ;   sending machine has already (guarenteed) placed its address
  316.     ;   on the data port.  So while the address matches, loop while
  317.     ;   REQ not asserted.
  318.  
  319.     test bl,02        ; ~REQ asserted?
  320.     jz .pd10        ; yes
  321.     cmp  [_ParNetAddr],cl    ; no, does data match anyway?
  322.     je .pdstable        ; YES, loop until get ~REQ or
  323.     jmp .pdfail        ; data bad.
  324.  
  325. .pd10:
  326.     test bl,04        ; yes, CTL?
  327.     jz .pdrn        ; no, middle of some packet.
  328.     cmp [_ParNetAddr],cl    ; yes, my address?
  329.     jne .pdrn        ; nope
  330.     mov al,1        ; yes, packet (probably) for us.
  331.     ret
  332.  
  333. .pdfail:
  334.     test bl,04        ; fail due to ~REQ not asserted.
  335.     jz .pdrn        ; CTL=0, line busy
  336.     mov al,0        ; line idle.
  337.     ret
  338.  
  339. .pdrn:
  340.  
  341.     mov al,-1        ; line busy, packet not for me.
  342.     ret
  343.  
  344. pardataready    ENDP
  345.  
  346. ;n = parread (unsigned char *buf,int16 bytes)
  347. ;
  348. ;Read a pending packet.
  349. ;
  350. ;Returns: n = -1 (1 second timeout, no packet pending)
  351. ;       n = 0 to bytes-1 (1 second timeout after transmission interrupted)
  352. ;      n = bytes (success), or n > bytes (transmitting machine's packet
  353. ;          was larger than we can handle, extra bytes thrown out)
  354. ;
  355. ;NOTE:    Requesting an odd number of bytes is O.K. but if you request N where
  356. ;    N is odd and the writer sends N + 1 you will never know (N will be
  357. ;    returned). See also parwrite() below.
  358. ;
  359. parread    PROC
  360.     ARG buf:ptr, byts:word
  361.  
  362.     if    @Datasize NE 0
  363.                 uses es,di
  364.                 les     di,buf  ; ds:di = buf
  365.     else
  366.         uses di
  367.         mov di,buf    ; ds:di = buf (ds already set)
  368.     endif
  369.  
  370.     mov ax,byts        ; max. number of bytes to read.
  371.     mov _Debugbytes,ax    ; can't do a direct move to _DebugBytes.
  372.  
  373.     call data_input        ; ensure all
  374.     call control_input    ; are inputs.
  375.     call Stable        ; ensure line not asserted.
  376.     mov DX,[_ParLLTimeout]    ; DX = timeout load
  377.  
  378.     ;  Wait loop for address mark
  379.     ;  Ctl = 1, ~DReq = 0
  380. .rmstab:
  381.     call read_control    ; read control in BL
  382.     mov al,bl        ; save it
  383.     call read_data        ; read data in CL
  384.     call read_control    ; read control in BL
  385.     cmp al,bl        ; control lines stable?
  386.     jne .rmstab        ; nope
  387.     test al,04        ; expect CTL=1
  388.     jz .rms1        ; nope
  389.     test al,02        ; expect ~REQ=0
  390.     jz .rms2        ; yes
  391.  
  392. .rms1:
  393.     dec dx            ; decrement timeout count
  394.     jnz .rmstab        ; no timeout.
  395.     jmp .rmend        ; no address mark!
  396.  
  397. .rms2:
  398.     cmp [_ParNetAddr],CL    ; My address?
  399.     jne .rms1        ; no, timeout loop
  400.  
  401.     ; Got my address, ~Ack byte.
  402.  
  403.     mov DX,[_ParLLTimeout]    ; reset timeout
  404.     call Clear_Ack_Only    ; set ~Ack to 0
  405.  
  406. .rms4:  call read_control    ; get control
  407.     test bl,02        ; wait for ~REQ to go away
  408.     jnz .rms5
  409.     dec dx            ; decrement timeout count
  410.     jnz .rms4
  411.     mov bl,-2        ;~REQ not released?
  412.     jmp .rmend
  413.  
  414. .rms5:  call Set_Ack_All    ; release ~ACK
  415.  
  416.     mov ax,0        ; set # of bytes read to 0
  417.     jmp .rms10        ; skip past move
  418.  
  419.  
  420.     ; MAIN READ LOOP
  421.     ;
  422.     ; AX holds count (number of bytes read).
  423.     ; DI buffer pointer (place to store data).
  424.  
  425. .rms10loop:
  426. ;        es:
  427.         mov es:[di],cl             ; store data
  428.     inc di            ; next address
  429.                 ; (can't do this with a STOSB)
  430.  
  431. .rms10:
  432.     call Read_Control
  433.     test bl,02        ; wait for ~REQ asserted
  434.     jz .rms20
  435.     call Read_control
  436.     test bl,02        ; again
  437.     jz .rms20
  438.     mov DX,[_ParLLTimeout]    ; reset timeout
  439.  
  440. .rms11: call Read_Control
  441.     test bl,02        ; wait for ~REQ asserted with timeout
  442.     jz .rms20
  443.     dec dx            ; decrement timeout count
  444.     jnz .rms11
  445.     jmp .rmend        ; timeout
  446.  
  447. .rms20: call read_data        ; get data in CL and
  448.     call Clear_Ack_Only    ; assert ~ACK
  449.  
  450.     ; note on CTL = 1 end sequence this data item is a dummy
  451.  
  452. ;        es:
  453.         mov es:[di],cl             ; store data
  454.     inc di            ; next address
  455.     inc ax            ; optimized, but not quite true,
  456.     inc ax            ; we've only written one 1 sf.
  457.  
  458.     call Read_Control
  459.     test bl,02        ; wait for ~REQ released
  460.     jnz .rms30
  461.     call Read_Control
  462.     test bl,02        ; again
  463.     jnz .rms30
  464.     mov DX,[_ParLLTimeout]    ; reset timeout
  465. .rms21:
  466.     call Read_Control
  467.     test bl,02        ; wait for ~REQ released with timeout
  468.     jnz .rms30
  469.     dec dx            ; decrement timeout count
  470.     jnz .rms21        ; no timeout yet?
  471.     jmp .rmendsub        ; sub because D6 is 2 ahead
  472.  
  473.  
  474. .rms30:
  475.     call read_data        ; get data in CL
  476.     call Read_Control    ; get CTL status in BL
  477.     call Set_Ack_All    ; release ~ACK    
  478.     test bl,04        ; EOP if CTL=1
  479.     jnz .rmeop
  480.  
  481.     ; CANNOT STORE DATA HERE! In case odd # bytes requested,
  482.     ; second byte would overflow buffer (each handshake sequence ALWAYS
  483.     ; transfers 2 bytes of information)
  484.  
  485.     sub _DebugBytes,2    ; # bytes remaining
  486.     jz  .rmste        ; reached zero
  487.     jno .rms10loop        ; continue if >0.
  488.     jnz .rmnlb        ; always true?
  489.  
  490. .rmste:
  491. ;        es:
  492.         mov es:[di],CL             ; if _DebugBytes = 0, its's even and we
  493.                 ; should only store the last byte.
  494.  
  495. .rmnlb: cmp _DebugBytes,-1    ; -1 = was odd #
  496.     jne .rmeven        ; fixup count
  497.     dec ax
  498.  
  499. .rmeven:
  500. .rmsev0:
  501.     jmp .rmovflow
  502.  
  503. .rmovflow:
  504.     mov di,OFFSET _DummyBuf    ; overflow, use dummy buffer
  505.     jmp .rms10
  506.  
  507. .rmeop:
  508.     cmp CL,0        ; EOP data better be 0!
  509.     je .rmendsub
  510.     mov bx,-3        ; bad protocol
  511.     jmp .rmend
  512.  
  513. .rmendsub:
  514.     dec ax            ; because we were two ahead
  515.     dec ax
  516. .rmend:
  517.     call data_input
  518.     call Set_Ack_All    ; setting ~ACK to input
  519.     call Stable
  520.     ret            ; return value in AL
  521.  
  522. parread    ENDP
  523.  
  524. ;n = parwrite(int16 destadr, unsigned char *buf, int16 bytes)
  525. ;
  526. ;Write a packet.
  527. ;
  528. ;Returns: n = -2    Cannot write anything, a packet is pending
  529. ;            (instantanious)
  530. ;      n = -1    Destination machine does not respond (1 sec to)
  531. ;      n = N        N bytes written ok (success if n == bytes)
  532. ;
  533. ; NOTE: sending an odd number of bytes is O.K. but if you write N where
  534. ;    N is odd and the reader requests N + 1 he will get N + 1 the last
  535. ;    byte being garbage.
  536. ;
  537. parwrite    PROC
  538.         ARG dest:word, buf:ptr, byts:word
  539.  
  540.     if @Datasize NE 0
  541.                 uses es,si
  542.                 les si,buf      ; ds:si = source-buffer to be written
  543.     else
  544.         uses si
  545.         mov si,buf    ; ds:si = buf (ds already set)
  546.     endif
  547.  
  548.     mov ax,dest        ; destination address.
  549.     mov _DestAddress,al    ; can't do a direct move to _DestAddress.
  550.     mov ax,byts        ; number of bytes to write.
  551.     mov _DebugBytes,ax    ; can't do a direct move to _DebugBytes.
  552.  
  553.     call data_input        ; ensure all
  554.     call control_input    ; are inputs.
  555.     call Stable        ; ensure line not asserted.
  556.     mov DX,[_ParLLTimeout]    ; DX = timeout load
  557.  
  558. .wmstab:
  559.     cli            ; disable interrupts
  560.     call Read_Control
  561.     mov al,bl
  562.     call read_data    
  563.     call Read_Control    ; get stable control
  564.     cmp al,bl
  565.     je .wmstab1
  566.     sti            ; set interrupts
  567.     jmp .wmstab
  568.  
  569.     ; Interrupts still disabled
  570.     ; BX holds ~ACK ~REQ and CTL status
  571.  
  572. .wmstab1:
  573.     mov ax,-2        ; number of bytes written yet (=none).
  574.     cmp bl,07h        ; ~ACK=1, ~REQ=1, CTL=1 ?
  575.     je .wm02
  576.  
  577.     ; if CTL=1, ~REQ=0 and CL=my address then
  578.     ; return with -2
  579.  
  580.     test bl,02h        ; ~REQ = 0?
  581.     jne .wm01        ; nope
  582.     test bl,04h        ; CTL = 1?
  583.     je .wm01        ; nope
  584.     cmp [_ParNetAddr],cl    ; somebody is calling me?
  585.     jne .wm01        ; nope
  586.  
  587.     sti            ; enable interrupts
  588.     jmp .wmend
  589.  
  590. .wm01:
  591.     sti            ; enable interrupts
  592.     dec dx            ; decrement timeout count
  593.     jnz .wmstab
  594.     jmp .wmend
  595.  
  596.     ; interrupts still disabled
  597.     ; we almost own the line
  598.  
  599. .wm02:
  600.     call Read_Control
  601.     call Clear_Ack_Only    ; assert ~ACK
  602.     test bl,01
  603.     jne .wm05        ; ACK was released before, have line!
  604.  
  605.     call Set_Ack_All    ; release ~ACK
  606.     jmp .wm01
  607.  
  608.     ; Line now aquired.
  609.  
  610. .wm05:
  611.     sti            ; enable interrupts
  612.     mov cl,_DestAddress
  613.     call Write_Data        ; set destination address on datalines.
  614.  
  615.     ; Before asserting ~REQ, pulse CTL to cause interrupt on remote
  616.     ; machines. Note that our address is already on the datalines.
  617.  
  618.     mov bl,02h        ; leave ~ACK=0 and ~REQ=1, but CTL->0
  619.     call Write_Control
  620.     mov bl,06h        ; leave ~ACK=0 and ~REQ=1, but CTL->1
  621.     call Write_Control
  622.     mov bl,04h        ; leave ~ACK=0 and CTL=1, but ~REQ->0  
  623.     call Write_Control    ; assert REQ
  624.     mov bl,05h        ; leave CTL=1 and ~REQ=0, but ~ACK->1
  625.     call Write_Control    ; release ACK
  626.                 ; (note that REQ->0 before ACK->released)
  627.  
  628.     mov ax,-1        ; number of bytes written yet (none).
  629.  
  630.     ; interrupts enabled for transfer (fully handshaked)
  631.     ;
  632.     ; Address mark ~ACK, wait for ~ACK asserted.
  633. .wm10:
  634.     call Read_Control
  635.     test bl,01        ; ~ACK asserted?
  636.     jz .wm15        ; yes, remote machine got my address mark
  637.     mov DX,[_ParLLTimeout]    ; DX = timeout count
  638. .wm11:
  639.     call Read_Control
  640.     test bl,01
  641.     jz .wm15
  642.     dec dx            ; decrement timeout count
  643.     jnz .wm11        ; timeout?
  644.     jmp .wmend        ; yes.
  645.  
  646.     ; got ack, now set CTL = 0 (leaves at least one line 0 so
  647.     ; nobody else thinks the bus is idle!)
  648.     ;
  649.     ; note:  Since this is the address mark, and is sampled by
  650.     ;     the reader before it asserts ~ACK, I can set CTL
  651.     ;     = 0 now instead of waiting till after ~ACK is
  652.     ;     released.
  653.  
  654. .wm15:
  655.     mov bl,01h        ; leave ACK=1, REQ=0, but CTL->0
  656.     call Write_Control    ; set CTL = 0 for duration of packet
  657.     mov bl,03h        ; leave ACK=1, CTL=0, but REQ->1
  658.     call Write_Control    ; release ~REQ
  659.  
  660.     mov ax,0        ; number of bytes written (none).
  661.  
  662.     ; Data transfer loop
  663.     ;
  664.     ; wait for ~ACK to be released (-> 1). If no more bytes to
  665.     ; write, then skip to .wm50
  666.  
  667. .wm20:
  668.     cmp _DebugBytes,0    ; more data in this buffer?
  669.     jz .wm50        ; nope
  670.  
  671.     call Read_Control
  672.     test bl,01        ; wait for ~ACK to be released
  673.     jnz .wm30
  674.     mov DX,[_ParLLTimeout]    ; DX = timeout countdown
  675. .wm21:
  676.     call Read_Control
  677.     test bl,01
  678.     jnz .wm30        ; need the timeout here?
  679.     call Read_control
  680.     test bl,01        ; check ACK again
  681.     jnz .wm30
  682.     dec dx
  683.     jnz .wm21
  684.     jmp .wmend        ; timeout
  685.  
  686.     ; Assert ~REQ for this data byte and wait for ~ACK
  687.  
  688. .wm30:
  689. ;        es:
  690.         mov cl,es:[si]             ; get next data byte.
  691.     inc si
  692.     call Write_Data        ; store data and ..
  693.     mov bl,01h        ; leave ACK=1, CTL=0, but REQ->0
  694.     call Write_Control    ; .. assert ~REQ
  695.  
  696. ;        es:
  697.         mov cl,es:[si]             ; get next data bytes
  698.     inc si
  699.     inc ax            ; number of bytes written (this only)
  700.                 ; (not valid until we get ACK which
  701.                 ;  is why the wmendsub is included)
  702.  
  703.     call Read_Control
  704.     test bl,01        ; wait for ACKasserted
  705.     jz .wm40
  706.     call Read_Control
  707.     test bl,01        ; look again
  708.     jz .wm40
  709.     mov DX,[_ParLLTimeout]    ; DX = timeout count
  710. .wm31:
  711.     call Read_Control
  712.     test bl,01        ; wait for ACK asserted with timeout
  713.     jz .wm40
  714.     dec dx            ; decrement timeout count
  715.     jnz .wm31
  716.     jmp .wmendsub        ; timeout, no bytes written!
  717.  
  718.     ; have ~ACK, so byte transmitted. increment bytes written,
  719.     ; decr. of bytes left was already done before.
  720.     ; now send second byte and loop back.
  721.  
  722. .wm40:    call Write_Data        ; data was loaded in CL before.
  723.     mov bl,03h        ; leave ACK=1, CTL=0, but REQ->1
  724.     call Write_Control    ; release ~REQ
  725.     inc ax            ; increment number of bytes written
  726.  
  727.     sub _DebugBytes,2    ; two less bytes
  728.     jo .wm50        ; these were the last bytes(s)
  729.  
  730.     jmp .wm20        ; loop back
  731.  
  732.     ; Last byte in buffer has been transmitted.
  733.     ;
  734.     ; Get next buffer in vector (not yet implemented).
  735.  
  736. .wm50:    jmp .wm50a
  737.  
  738. .wm50a:
  739.     ;   Last byte has been transmitted,
  740.     ;
  741.     ;   Wait for ~ACK to be released and then assert ~REQ with
  742.     ;   EOP & CTL = 1
  743.     ;
  744.     ;   (timing on read is that CTL is sampled when ~REQ is
  745.     ;   RELEASED so no timing window here)
  746.  
  747.     call Read_Control    ; Wait ~ACK released
  748.     test bl,01
  749.     jz .wm50
  750.  
  751.     mov cl,0
  752.     call Write_Data        ; EOP mark (=0)
  753.     mov bl,01h        ; leave ACK=1 and CTL=0, but REQ->0
  754.     call Write_Control    ; assert ~REQ
  755.  
  756.     ; Wait for ~ACK asserted
  757.  
  758.     call Read_Control
  759.     test bl,01        ; ACK asserted?
  760.     jz .wm60        ; yes
  761.     mov DX,[_ParLLTimeout]    ; DX = timeout count
  762. .wm51:
  763.     call Read_Control
  764.     test bl,01        ; wait for ACK asserted with timeout
  765.     jz .wm60
  766.     dec dx            ; decrement timeout count
  767.     jnz .wm51
  768.     mov al,-3        ; EOP failed
  769.     jmp .wmend
  770.  
  771.     ; Set CTL=1 then release ~REQ, then wait for ~ACK released
  772. .wm60:
  773.     mov bl,05h        ; leave ACK=1, REQ=0, but CTL->1
  774.     call Write_Control    ; release CTL
  775.     mov bl,07h        ; leave ACK=1, CTL=1, but REQ->1
  776.     call Write_Control    ; release ~REQ
  777.     
  778.     ; Wait ~ACK released ?
  779.  
  780. .wm61:    call Read_Control
  781.     test bl,01
  782.     jz .wm61
  783.  
  784.     ; Add _DebugBytes to AX. This handles fixup if an odd number of bytes
  785.     ; were requested written, _DebugBytes will be -1 (odd) or 0 (even) and
  786.     ; AX will be one too large (odd) or perfect (even)
  787.  
  788.     add ax,[_DebugBytes]
  789.  
  790.     jmp .wmend
  791.  
  792. .wmendsub:
  793.     dec ax            ; was ahead in count
  794. .wmend:
  795.     call data_input        ; set data port to input
  796.     call control_input    ; set control lines to input
  797.     ret            ; return value in AL
  798.  
  799. parwrite    ENDP
  800.  
  801.     END
  802.