$TITLE ('New Bubble Device Driver 11/19/82')
$DEBUG

NAME BubbleXfer

DGROUP GROUP DATA
CGROUP GROUP CODE

;DATE : August 3, 1982
;AUTHOR : Kathy Wheeler
;REVISION DATE : 1) September 7, 1982
;                2) September 8, 1982
;                3) September 10, 1982
;                4) September 15, 1982
;                5) September 15, 1982
;                6) September 15, 1982
;                7) September 16, 1982
;                8) September 16, 1982
;                9) November 19, 1982
;               10) November 19, 1982
;               11) March 11, 1983
;REVISION AUTHOR : Kathy Wheeler
;REASON: 1) error recovery routines (watchdog ti-
; mer 2) took out watchdog timer routines and put in code
; to just check status common from bubble controller.
; 3) remove error checking because bigbubbles.plm does it.
; 4) change design to do one wait and one signal for a com-
; plete 256 byte transfer to improve or solve the hanging
; problem.  5) scush the primethepump loop to save code.
; 6) revert back to (4) version.  This is the best working
; version.  7) take out the check on status from the read/
; write loops - status is not valid till the busy bit is
; low.  8) fix underflow problem in read loop  9) the enable
; register value which is set in new.bigbubbles.plm was 
; changed from 4aH to 28H - Read Corrected Data was enabled
; and interrupt on error was disabled for everything but
; uncorrectable errror and timing error.  11) Replace the Os
; calls with Cp calls for compatibility with rest of os.

;GRiD CORPORATION, PROPRIETOR

;Bubble Transfer Assembly Language Program Overview:

;This module reads and writes blocks of data from the bubble
;memory on the COMPASS.

;The module is called from the Big Bubble Driver and has the
;following procedural interface:
;
; BubbleXfer: PROCEDURE(osCommand,pData,length,SIDcode,
;                       errPtr) WORD EXTERNAL;
;	DCL osCommand WORD,
;	    pData     PTR,
;	    length    WORD,
;	    SIDcode   WORD,
;	    errPtr    PTR;
; END BubbleXfer;
;
;The routine returns the number of bytes transferred to/from
;the bubbles, as well as an errorcode.  The parameters are
;located on the stack following the data segment and the 
;calling address (CS:IP).

;The primary difference between this new version of the
;bubble driver and the old is the implementation of inter-
;rupts to facilitate the transfer of data.  The buffer of
;the bubble memory controller is forty bytes long.  When 22
;bytes can be read from or written to the controller, the
;DMA request line is enabled.  This causes a BubbleInt (num-
;ber 2 on the 8259 controller).

;The BubbleXfer program consists of two main routines: The
;Interrupt Service Routine and The Transfer Loop.
;Semaphores are used to suspend the Transfer
;Loop until the 22 byte event.  That event causes an inter-
;rupt and while system interrupts are off, the bytes are 
;transferred.  When the operation is complete, the Transfer
;Loop is Signalled via a semaphore and the Interrupt Service
;Routine is exited.  The cycle is continued until the entire
;block is transferred.  The length of that transfer is re-
;turned when BubbleXfer is exited and returns to Big Bubble
;Driver.
$EJ
; *********************************************************
; ***  START OF CODE  *************************************
; *********************************************************


; *** BubbleXfer EXTERNALS ********************************

EXTRN	CpWait:FAR
EXTRN	CpSignal:FAR
EXTRN  CpEnableInterrupt:FAR
EXTRN  CpDisableInterrupt:FAR
EXTRN  CpEndOfInterrupt:FAR

;Procedural and functional interfaces to the above OS calls:

;CpWait: PROCEDURE(SIDcode,timeout,errPtr) WORD EXTERNAL;
;	DCL SIDcode WORD,
;	    timeout WORD,
;	    errPtr  PTR;
;END CpWait;

;CpSignal: PROCEDURE(SIDcode,mode,note,errPtr) EXTERNAL;
;	DCL SIDcode WORD,
;	    mode    WORD,
;	    note    WORD,
;	    errPtr  PTR;
;END CpSignal;

; *** BubbleXfer PUBLICS **********************************

PUBLIC	BubbleXfer
PUBLIC BubbleInt
PUBLIC semaphorebuba
PUBLIC semaphorebubb
$EJ
; *********************************************************
; *** DATA SEGMENT DECLARATIONS ***************************
; *********************************************************

DATA SEGMENT PUBLIC 'DATA'

; Create a structure in order to easily reference the param-
; eters from the STACK:

Bubble_Params STRUC

  ErrorPtr	DD	?
  SIDxfer	DW	?
  dataLength	DW	?
  dataBuffer	DD	?
  request	DW	?
  OrigBuffPtr  DW      ?
  OrigCount	DW	?

Bubble_Params ENDS

; allocate space in the data segment for the structure:

BuB Bubble_Params <>

;
DATA	ENDS
;
; *** END OF DATA SEGMENT *********************************
$EJ
; *********************************************************
; *** START OF STACK SEGMENT ******************************
; *********************************************************

; Stack allocated at run time.

STACK SEGMENT STACK 'STACK'
;
STACK ENDS
;
; *** END OF STACK SEGMENT ********************************
; *********************************************************

; *********************************************************
; *** Entry to BigBubbleDriver Semaphore Declaration ******
;
SEMAbubsegA SEGMENT PARA 'DATA'
;
semaphorebuba DB 16 DUP (?)
;
SEMAbubsegA ENDS
;
; *********************************************************

; *********************************************************
; *** Data Semaphore Declaration for BigBubbleDriver ******
;
SEMAbubsegB SEGMENT PARA 'DATA'
;
semaphorebubb DB 16 DUP (?)
;
SEMAbubsegB ENDS
;
; *********************************************************
$EJ
; *********************************************************
; *** START OF CODE SEGMENT *******************************
; *********************************************************

CODE SEGMENT PUBLIC 'CODE'
     ASSUME CS:CGROUP, DS:DGROUP, SS:STACK

;
; *** MODULE EQUATES **************************************
;

; Interrupt Controller - 80130:

INTbubID	EQU	5	;interruptID for os call
INTbubMODE	EQU	0	;mode for interrupt

; Bubble Controller - 7220-1:

BUBread	EQU	12h	;ok to read
BUBwrite	EQU	13h	;ok to write
BUBbusy	EQU	80h	;controller busy
BUBfifo	EQU	01h	;fifo ready
BUBdma		EQU	0fbh	;dma enable
BUBdmaoff	EQU	04h	;dma disable
OPFAIL		EQU	20h	;operation failed
OPCOMPLETE	EQU	40h	;operation complete
;
BubbleSEG	EQU	0dfe8h	;segment of bubble controller
BubbleSTAT	EQU	02h	;offset to status register
BubbleCTRL	EQU	02h	;offset to control register
BubbleENAB	EQU	0dh	;offset to enable register
BubbleDATA	EQU	00h	;offset to data port

; WatchDog Timer Equates:

WDenable	EQU	106h	;enable watchdog timer
WDdisable	EQU	06h	;disable watchdog timer
WDinterval	EQU	11	;set timeout interval
WDtimeout	EQU	064h	;timeout interval

; Error Codes:

eOK		EQU	0
eBuBTimeout	EQU	451
eOutofMem	EQU	453
eNotSupport	EQU	23
eDeviceNotReady EQU	107

; Other Useful Parameters:

TRUE		EQU	0
FALSE		EQU	0ffffh
ddRead		EQU	4
ddWrite	EQU	5
Timeout	EQU	01388h  ;five seconds
Mode		EQU	01h

$EJ
; *********************************************************
; *** Bubble Transfer Loop Module *************************
; ***
; *** This module takes the request to read or write bytes
; *** to the bubble memory and does, essentially, three
; *** things:
; ***
; *** 1. Initializes the transfer process by enabling bubble
; ***    interrupts, reseting dma enable (ready for data
; ***    transfer interrupt mode), issueing the read or 
; ***    write command, and flagging the interrupt routine
; ***    that this is the first transfer (send or get 40
; ***    bytes instead of 22 bytes).
; *** 2. Waits on a timed semaphore in a looped manner un-
; ***    til the count of bytes transferred is zero.
; *** 3. Finishes the transfer process by disabling bubble
; ***    interrupts, setting dma enable and sending the
; ***    appropriate error code.
; ***
; *********************************************************

BubbleXfer 	PROC	FAR

               push	DS	;save calls segment
               push	BP
               mov	BP,SP
               mov	AX,DATA	;get this data segment
               mov	DS,AX	;
               mov	BX,Offset Bub ;get offset of struc
               mov	SI,2	;for double word moves
               pop	DI	;stack pointer
               pop	AX	;data seg
               pop	CX	;CS of calling program
               pop	DX	;IP of calling program
               pop	Word Ptr [BX].ErrorPtr
               pop	Word Ptr [BX][SI].ErrorPtr
               pop	[BX].SIDxfer
               pop	[BX].datalength
               pop	Word Ptr [BX].databuffer
               pop	Word Ptr [BX][SI].databuffer
               pop	[BX].request
               push	DX
               push	CX
               push	AX
               push	DI

; completion of PLM interface environment retrieval ych.

               call	RSTint		;reset int

               mov	AX,BubbleSEG	;get seg of bubb ctrl
               mov	ES,AX
               push	DS
               lds	SI,[BX].databuffer ;save orig ptr
               pop	DS
               mov	[BX].OrigBuffPtr,SI
               mov	DX,[BX].datalength ;get count
               mov	[BX].OrigCount,DX  ;save it
               mov	AX,[BX].request	;see what op to do
               cmp	AX,ddRead	;is it a read?
               je	BubbleRead	;yes
               cmp	AX,ddWrite	;is it a write?
               je	BubbleWrite	;yes
               mov	AX,eNotSupport	;no, flag error
               jmp	BubbleEnd

BubbleRead:    mov	AL,BUBread	;send read command
               jmp	BubbleBusy	;go wait for busy=0

BubbleWrite:   mov	AL,BUBwrite	;send write command
               
BubbleBusy:    mov	ES:Byte Ptr BubbleCTRL,AL ;send cmd
               mov	CX,0ffffh	;timeout
BusyLoop:      mov	AL,ES:Byte Ptr BubbleSTAT
               test	AL,BUBbusy	;accepted command?
               loopz	BusyLoop	;no
               jcxz	BubbleTO	;yes
               jmp	BubbleRDWT	;continue
BubbleTO:      mov	AX,eBuBTimeout	;timeout on busy
               jmp	BubbleEnd	;go tell driver

BubbleRDWT:    mov	AX,[BX].request
               cmp	AX,ddWrite
               jne	BubXferLoop
               call	primethepump
ShortCount:    or	AX,AX
               jnz	BubbleEnd
               mov	CX,[BX].datalength ;get current count
               or	CX,CX		;done?
               jz	BubbleEnd	;yes
               cmp	CX,22		;count less than 22?
               jae	BubXferLoop	;no, continue
               call	primethepump
               jmp	ShortCount	;make sure done
               
BubXferLoop:   push	BX
               
               call	SETint

               mov	AX,Timeout	;timeout for WAIT
               push	[BX].SIDxfer	;push SID code
               push	AX		;push timeout
               les	DI,[BX].ErrorPtr ;push ptr to error
               push	ES		;segment
               push	DI		;offset
               call	CpWait		;wait for transfer

               pop	BX
               
BubbleEnd:     
               mov	CX,[BX].OrigCount  ;full transfer
               mov	[BX].datalength,CX ;restore orig cnt
               mov	SI,[BX].OrigBuffPtr ;get original ptr
               mov	DI,Word Ptr[BX].databuffer ;get ptr
               mov	Word Ptr[BX].databuffer,SI ;restore
               sub	DI,SI		;get actual count

               mov	AX,DI		;put xfer len in AX
               pop	BP
               pop	DS
               ret

RSTint		PROC	NEAR

               push	BX
               mov	AX,INTbubID
               push	AX
               call	CpDisableInterrupt
               pop	BX
               ret

RSTint		ENDP

SETint		PROC	NEAR

               push	BX
               mov	AX,INTbubID
               push	AX
               mov	AX,INTbubMODE
               push	AX
               call	CpEnableInterrupt
               pop	BX
               ret

SETint		ENDP

primethepump	PROC	NEAR

               push	DS
               mov	CX,[BX].datalength ;get count
               mov	DX,[BX].request ;get operation
               lds	SI,[BX].databuffer ;ptr to xfer
               mov	AX,BubbleSEG
               mov	ES,AX
               cmp	DX,ddWrite
               jne	intRead
               
intWrite:      mov	AL,ES:Byte Ptr BubbleSTAT
               test	AL,BubBusy
               jnz	intWrite2
               jmp	BubIntDone2
intWrite2:     test	AL,BuBfifo
               jz	BubIntDone
               mov	AL,[SI]
               mov	ES:Byte Ptr BubbleData,AL
               inc	SI
               dec	CX
               jnz	intWrite

BubIntDone:    xor	AX,AX
BubIntDone2:   pop	DS
               mov	Word Ptr[BX].databuffer,SI ;save ptr
               mov	[BX].datalength,CX ;save count
               ret

intRead:       mov	AL,ES:Byte Ptr BubbleSTAT
               test	AL,BubBusy	;op done?
               jnz	intRead2	;no
               test	AL,BuBfifo	;still bytes in fifo?
               jnz	intRead3	;yes
               jmp	BubIntDone2	;no, done with error
intRead2:      test	AL,BuBfifo
               jz	BubIntDone
intRead3:      mov	AL,ES:Byte Ptr BubbleDATA
               mov	[SI],AL
               inc	SI
               dec	CX
               jnz	intRead
               jmp	BubIntDone

primethepump   ENDP

$EJ
; *********************************************************
; *** Bubble Interrupt Service Routine ********************
; ***
; *********************************************************

BubbleInt	PROC	NEAR

               push	AX
               push	BX
               push	CX
               push	DX
               push	SI
               push	DI
               push	DS
               push	ES
               push	BP
               mov	AX,DATA
               mov	DS,AX
               mov	BX,Offset BuB
               push	BX
               mov	AX,INTbubID
               push	AX
               call	CpEndOfInterrupt
               pop	BX

               call	primethepump
               or	AX,AX
               jnz	FakeBubbleXferEnd

ChkTheCount:   mov	CX,[BX].datalength ;get current count
               or	CX,CX		;done?
               jz	FakeBubbleXferEnd	;yes
               cmp	CX,22		;count less than 22?
               jae	BubbleIntEnd	;no, continue
               call	primethepump
               or	AX,AX
               jnz	FakeBubbleXferEnd
               jmp	ChkTheCount	;make sure done

FakeBubbleXferEnd: NOP
BubbleXferEnd: call	RSTint		;mask out int for bub
               push	BX
               mov	AX,MODE		;mode
               xor	CX,CX		;note
               push	[BX].SIDxfer    ;sidcode
               push	AX
               push	CX
               les	DI,[BX].ErrorPtr
               push	ES
               push	DI
               call	CpSignal	;done with transfer
               pop	BX
               
BubbleIntEnd:  pop	BP
               pop	ES
               pop	DS
               pop	DI
               pop	SI
               pop	DX
               pop	CX
               pop	BX
               pop	AX
               iret

BubbleInt      ENDP

; *********************************************************
; 
BubbleXfer	ENDP

CODE	ENDS
		END
