.mcall .MODULE .MODULE MX,comment=,release=X08,version=05 ;**************************************************************; ; ; ; Copyright (c) 1987, 88 Bob Schor ; ; Eye and Ear Hospital ; ; 230 Lothrop St. ; ; Pittsburgh, PA 15213 ; ; ; ; All rights reserved. May not be copied without this notice. ; ; ; ;**************************************************************; ;device handler for Matrox QC-640 ;b schor august, 1987 ;modifications -- ; aug, 1987 SET FORK/NOFORK added (fork not working yet) ; oct, 1987 Single queue system ; Fork works, SET FORK removed ; may, 1988 Cold-reset .SPFUN added ; .READ runs without interrupts, null-fills if needed ; jun, 1988 Initial .WRITE does cold reset ; .READ has internal delay before null-filling ; Cold reset made SET option (COLD/NOCOLD) ;uses SUMAC for structured macro code .library /lib:sumac/ ;use external macro definition file .mcall SUMAC SUMAC .dsabl gbl ;if undefined symbol, force error .sbttl Macros and Definitions .iif ndf rte$m rte$m = 0 .iif ndf tim$it tim$it = 0 .iif ndf mmg$t mmg$t = 0 .iif ndf mx$pri mx$pri = 4 .iif ne rte$m rte$m = 1 .iif ne tim$it tim$it = 1 .iif ne mmg$t mmg$t = 1 .mcall .DRDEF, .MTPS, .INTEN .DRDEF mx, 375, spfun$, 0, 160400, 240 .DRPTR .DREST class=dvc.uk .DRSPF <201> clrmtx = 201 ; SPFUN code to do cold reset HEAD st.bits, st.emp = 1 ; Fifo empty st.ful = 2 ; Fifo full st.haf = 4 ; Fifo half empty st.out = 10 ; Output full st.dat = 20 ; Data if bit set st.err = 20 ; Error if bit clear HEAD co.bits, co.emp = 1 ; Interrupt on fifo empty co.ful = 2 ; Interrupt on fifo full co.haf = 4 ; Interrupt on fifo half empty co.out = 10 ; Interrupt on output present co.wrm = 20 ; Do warm reset (must clear bit by hand) co.cld = 200 ; Do cold reset (must clear bit by hand) HEAD const, delay = 0 ; Build in wait for input to succeed HEAD MXINT, .macro MXINT mov intmsk, @mx.com ; move interrupt mask to command register tst @mx.com ; read register to activate interrupts .endm MXINT HEAD MXOFF, .macro MXOFF clr @mx.com ; clear command register tst @mx.com ; read register to activate interrupts .endm MXOFF .sbttl Set option parameter table .DRSET csr, 160000, o.csr, oct .DRSET vector, 477, o.vec, oct .DRSET cold,nop,o.cold,NO .sbttl Set option processing routines PROCED o.csr, mov r0, mx.com ; set command register mov r0, mx.sta ; set status register add #4, mx.sta mov r0, mx.fif ; set fifo register add #10, mx.fif mov r0, mx.dat ; set data register add #14, mx.dat cmp r0, r3 ; error if address too low ENDPROC PROCED o.vec, mov r0, mxstrt ; save vector bit #3, r0 ; check for valid address IF ne ; if lower two bits set OR r0, gt, r3 ; or above upper bound, sec ; return with carry set ENDIF ENDPROC PROCED o.cold, mov (pc)+, r3 ;get next instruction br nocold-o$cold+. ;branch offset mov r3, o$cold ;modify instruction ENDPROC .sbttl driver entry .DRBEG mx mov mxcqe, r4 ; point to current queue movb q$func(r4), r5 ; get special function code (if any) bne spfun ; handle as appropriate asl q$wcnt(r4) ; convert word to byte count IF cs ; negative, write bis #, intmsk ; enable interrupts ELSIF ne ; positive, read br getdat ; handle read immediately ELSE ; zero, seek br mxfin ; can just exit ENDIF MXINT ; set interrupts rts pc ; exit back to user PROCED spfun, cmpb r5, #clrmtx ; check for "clear matrox" function IF eq INVOKE coldr ; do a cold reset ENDIF ENDPROC .sbttl interrupt service routine .DRAST mx, mx$pri, mxdone MXOFF ; forbid interrupts mov @mx.sta, r5 ; get status bit #st.haf, r5 ; see if fifo half-empty IF eq ; 0 = half-empty br tofifo ; fill the fifo ENDIF mov mxcqe, r4 ; point to top of queue IF q$wcnt(r4), ne ; if more to come, MXINT ; re-enable interrupts rts pc ; go wait for it ENDIF LABEL mxdone, clr intmsk ; clear all interrupts clr mxfblk+2 ; clear fork block LABEL mxfin, ; MXINT ; enable/disable interrupts .DRFIN mx .sbttl output interrupt servicer LABEL tofifo, mov mxcqe, r4 ; get output queue element .FORK mxfblk ; run at system state 0 o$cold: ; nop ;COLD, cold reset on block 0 br nocold ;NOCOLD, skip it IF q$blkn(r4), eq ; if .WRITE to block 0, INVOKE coldr ; do a cold reset inc q$blkn(r4) ; and change block to 1 ENDIF nocold: mov #400, r5 ; set half-fifo counter .if eq mmg$t add #q$wcnt, r4 ; get byte count WHILE (r4), ne ; while bytes present AND r5, gt ; and room in fifo inc (r4) ; count byte movb @-(r4), @mx.fif ; send byte to fifo inc (r4)+ ; bump buffer dec r5 ; count down fifo ENDWHILE .iff WHILE q$wcnt(r4), ne ; if bytes present, AND r5, gt ; and room in fifo inc q$wcnt(r4) ; count byte INVOKE @$gtbyt ; get byte from buffer mov (sp)+, @mx.fif ; send to fifo dec r5 ; count down fifo ENDWHILE .endc mov mxcqe, r4 ; point to top of queue IF q$wcnt(r4), ne ; if more to come, MXINT ; re-enable interrupts rts pc ; go wait for it ENDIF br mxdone ; done with i/o LABEL mxfblk, .word 0, 0, 0, 0 .sbttl input interrupt servicer LABEL getdat, mov mxcqe, r4 ; get output queue element .if eq mmg$t add #q$wcnt, r4 ; get byte count ;can test for errors WHILE (r4), gt ; while room in buffer, bit #st.out, @mx.sta ; see if data from matrox IF ne movb @mx.dat, @-(r4) ; save data in buffer ELSE .if gt delay FOR r5, #1, #delay ; wait a bit ENDFOR bit #st.out, @mx.sta ; try again IF ne movb @mx.dat, @-(r4) ; save data in buffer ELSE clrb @-(r4) ; clear buffer if no data ENDIF .iff clrb @-(r4) ; clear buffer if no data .endc ENDIF inc (r4)+ ; bump buffer dec (r4) ; decrease byte count ENDWHILE .iff WHILE q$wcnt(r4), gt ; while room in buffer, bit #st.out, @mx.sta ; see if data from matrox IF ne PUSHB @mx.dat ; get character ELSE PUSHB ; clear if no data ENDIF INVOKE @$ptbyt ; give to user dec q$wcnt(r4) ; decrease byte count ENDWHILE .endc MXINT ; set interrupts br mxfin ; and dismiss queue element .sbttl miscellaneous routines and tables PROCED coldr, PUSH r4 ; save register mov #co.cld, @mx.com ; do cold reset tst @mx.com ; force an execute FOR r4, #1, #10000 ; wait ENDFOR MXOFF ; turn all bits off tst @mx.dat ; clear out data register POP r4 ; restore register ENDPROC HEAD QC-640, mx.com: .word mx$csr mx.sta: .word mx$csr+4 mx.fif: .word mx$csr+10 mx.dat: .word mx$csr+14 LABEL intmsk, .word 0 ENDEND .DREND mx .end