.enable subsitution .disable display ; VQDRV.BLD - Build file for Peritek VRG-Q driver/ACP ; Copyright (C) 1994 John Otis Lene Comeau ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; .; You should have received a copy of the GNU General Public License .; along with this program; if not, write to the Free Software .; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. .; .; A copy of the GNU General Public License is appended to the end of .; this command file. .; .; John Lene-Comeau, ICT, POB 100632, Ft. Lauderdale, FL 33310-0632 .; jcomeau@world.std.com or CompuServe: 70641,57 .; .parse ":].;" cmddev cmduic cmdnam cmdext cmdver .iff ;'cmdnam' -- Must have privileges to build this file .iff .exit .sets cmduic cmduic+"]" !replace what .PARSE chopped .sets uic !so we can return to it later .gosub credvs !go create driver source .gosub creacs !go create ACP source .gosub credvl !make the driver link file .gosub creacl !make the ACP link file .gosub mac vqdrv .if ne status&7 .exit .gosub mac vqacp .if ne status&7 .exit .;if we made it this far, switch to system UIC to link them... set /uic='' .gosub link @'uic'vqdrv.tkb .if eq &7 .gosub link @'uic'vqacp.tkb set /uic='uic' .if ne status&7 .exit ;VQDRV was successfully built. INStall ''VQACP, then LOAd VQ:. .exit .mac: .parse comman " " filnam junk .sett macins !assume it's installed .ifnins mac .if ne "DCL" .setf macins .ifnins mac .if ne "DCL" ins $mac .sets mac "mac" .sets mac mac+" "+filnam .if ne "DCL" .sets mac mac+"="+filnam 'mac' .setn status .iff macins rem mac .return .link: .parse comman " " filnam junk .sett tkbins !assume it's installed .ifnins tkb .if ne "DCL" .setf tkbins .ifnins tkb .if ne "DCL" ins $tkb .sets tkb "tkb" .if eq "DCL" .sets tkb "link" .sets tkb tkb+" "+filnam 'tkb' .setn status .iff tkbins rem tkb .return .; .credvs: ;Building driver source... .open vqdrv.mac .enable data .title VQDRV ;Peritek VRG-Q graphics interface driver ;*** NOTE: DO NOT MODIFY THIS FILE. CREATED BY VQDRV.BLD *** ;debug=1 ;define when debugging (of course) attdet=1 ;define when you want to be able to attach Peritek terminal ; Assumed no alphanumeric ROM included on VRG board. ; This was originally written as a stand-alone driver, but the time-intensive ; character output routines, particularly when scrolling, caused problems with ; the real-time machine control running as the computer''s primary purpose. So ; this is now a "shell" driver with all the real work being done by the ACP ; in user state rather than kernel mode. ; .library "lb:[1,1]exemc.mlb" .mcall abodf$,hwddf$,pktdf$,tcbdf$ ;define globals for target system m$$mup=1 ;multi-user protection m$$mge=1 ;memory management enabled abodf$ ;define task abort codes hwddf$ ;define hardware register symbols pktdf$ ;define I/O packet offsets tcbdf$ ;define task control block offsets ; .macro push arg mov arg,-(sp) .endm push ; .macro pop arg mov (sp)+,arg .endm pop ; ;Task-specific and device-specific equates ; vrgcsr=174140 ;=17774140 on 22-bit machine vrgdat=174000 vg0=40 cram=10 memloa=4 blank=100000 ; ;Driver dispatch table ; acptnm: .rad50 /VQACP / ;name of associated ACP .even ;ensure we''re on a word boundary ucbsav: .blkw 1 ;for debugging .if df debug pktcnt: .blkw 1 ;packet count for debugging abocnt: .blkw 1 ;cancel I/O count for debugging .endc $vqtbl:: .word vqini ;device initiator entry point .word vqcan ;cancel I/O entry point .word vqout ;device timeout entry point .word vqpwf ;powerfail entry point ; ;Begin VRG-Q QIO service routine. ; ;Initiator: entered when I/O request is queued. ; ;Input: ; ; R5=address of the UCB of the controller to be initiated ; ;Output: ; ; If the I/O request dequeues OK, then ; the I/O is performed. ; vqini: .iif df debug, inc pktcnt ;bump packet count if debugging call $gtpkt ;attempt to dequeue a packet bcc 10$ ;continue if OK return ;abort if controller busy or no request ; ; ;The following args are returned by $GTPKT: ; ; R1=address of i/o request packet ; R2=physical unit number of request UCB ; R3=controller index ; R4=address of the status control block ; R5=UCB address of the controller ; ;VRG-Q request packet format: ; ; Byte Symbol Description ; ; 2 I.TCB TCB address of requesting task ; 10 I.UCB Address of redirect UCB ; 12 I.FCN Function code of I/O request in high-order byte ; 13 The low-order byte holds any modifiers ; 24 I.PRM Device-dependent parameters ; For the VRG-Q, we use the same as for TT devices ; ;Only two transfer functions passed to driver are IO.WLB and IO.WVB, which are ;treated the same. So no need to check which function it is. ; 10$: ;don''t clear controller busy bit, we need it for synchronization bit #vg0,@#vrgcsr ;has VRGINI been run? beq vqcn1 ;if not, quit with "Device Not Ready" status movb s.itm(r4),s.ctm(r4) ;setup for timeout 12$: mov u.vacp(r5),r0 ;don''t use U.ACP, file system might need it bne 14$ ;if NE the ACP was already started mov #acptnm,r3 ;else get taskname and try to start it call $srstd ;see if it''s installed bcs vqcn1 ;skip if not, return device not ready ;unlike example code in Guide, we don''t care if it''s built as ACP or not mov r0,u.vacp(r5) ;store TCB address for later reference 14$: cmp t.nam(r0),#^rVQA ;is it *really* our ACP? beq 30$ ;go for it if so clr u.vacp(r5) ;otherwise, assume ACP crapped out br vqcn1 ;finish I/O with DNR code 30$: callr $exrqp ;jump to queue the packet to ACP ; ;Power Failure entry is called at system state with the following registers: ; R5 = UCB address ; R4 = SCB address ; R3 = Controller Index vqpwf: mov r5,ucbsav ;save UCB address for debugging mov #acptnm,r3 ;else get taskname and try to start it call $srstd ;see if it''s installed bcs 20$ ;skip if not, clear U.VACP mov r0,u.vacp(r5) ;store TCB address for later reference cmp t.nam(r0),#^rVQA ;is it *really* our ACP? bne 20$ ;skip ahead if not ; .if df debug mov #t.nlup,r0 ;show "link up" for debugging call $dvmsg ;use TKTN service .endc ; return ;otherwise we''re done initialization 20$: clr u.vacp(r5) ;assume ACP crapped out mov #t.nrct,r0 ;show "control task not installed" for debugging call $dvmsg ;use TKTN service return ; ;Timeout is called at device priority with the following registers set: ; R5 = UCB address ; R4 = SCB address ; R3 = Controller Index ; R2 = Address of device CSR ; R0 = I/O status code IE.DNR vqout: mov #t.ndnr,r0 ;set message number for TKTN movb s.itm(r4),s.ctm(r4) ;reset the timeout count callr $dvmsg ;send the "device not ready" message ; ;Cancel I/O is called at device priority with the following registers set: ; R5 = UCB address ; R4 = SCB address ; R3 = Controller Index ; R1 = Address of TCB of current task ; R0 = Address of active I/O packet ; .enabl lsb ;local symbol block for cancel code ;9/24/94 VQCAN no longer will cancel the I/O, just signal to VQACP to do so... ; Alternate entry point VQCN1 will still clear out the packets. vqcan: cmp r1,i.tcb(r0) ;;;request for current task? bne 20$ ;;;if not, ignore it .iif df debug, inc abocnt ;;;if debugging enabled, inc IO.KIL count br 12$ ;;;else skip, don''t kill the packet vqcn1: mov #,r0 ;;;device not ready mov s.pkt(r4),r3 ;;;packet address into R3 call $ioalt ;;;finish I/O for this packet ;9/24/94 Don't bother ACP with something that doesn't concern it... br 14$ ;;;skip past ACP notification 12$: mov u.vacp(r5),r0 ;;;get TCB address of ACP beq 14$ ;;;return if not there mov #-1,u.cnt(r5) ;;;let ACP know about the IO.KIL call $exrqu ;;;make sure it wakes up to see it ; 14$: .if df debug mov #t.nldn,r0 ;show "link down" for debugging call $dvmsg ;use TKTN service .endc ; 20$: return ;;;that''s all .dsabl lsb ;end of local symbol block ; .sbttl vqtab ;loadable data table for Peritek VRG-Q device driver vrgcsr=174140 $vqdat:: ;;only for loadable drivers vqdcb: .word 0 ;link to next DCB .word .vq0 ;pointer to first (and only) UCB .ascii /VQ/ .byte 0,0 ;lowest and highest unit numbers .word vqnd-vqst ;length of each UCB in bytes .word $vqtbl ;pointer to driver dispatch table .word 140033 ;legal function mask 0-15. .if df attdet ;control function mask 0-15. .word 30 ;here to allow attach-detach .iff .word 0 ;here if desired to make them no-op .ift ;now for no-op mask... .word 140000 ;attach-detach is performed, "access" funtions ignored .iff ;otherwise... .word 140030 ;attach-detach ignored .endc ;attdet .word 0 ;ACP function mask codes 0-15. .word 5 ;high words of above function masks, deaccess and WVB .word 0 ;no control functions .word 1 ;deaccess is no-op .word 0 ;no ACP functions ; ;VRG-Q UCB ; .mcall ucbdf$ ucbdf$ ;define Unit Control Block offsets vqst=. .word 0 ;u.mup .word 0 ;u.luic .word 0 ;u.own .vq0:: .word vqdcb ;back pointer to DCB .word .-2 ;pointer to redirect unit UCB .byte uc.kil!uc.pwf,0 ;control processing flag, unit status .byte 0,0 ;physical unit number, unit status extension .word dv.rec!dv.ccl ;first of 4 device characteristics words u.vacp==u.cw2 .word 0 ;using for TCB address of our special ACP .word 0 .word 80. ;default buffer size in bytes .word vqscb ;pointer to SCB .word 0 ;TCB address of attached task .word 0,0 ;relocation bias/buffer address of current I/O request .word 0 ;byte count of current I/O request .word 0 ;address of TCB of mounted ACP .word 0 ;address of Volume Control Block vqnd=. ; ;no interrupt vector for VRG-Q ; ; ;VRG-Q status control block ; vqscb: .word 0 ;controller i/o queue listhead, first entry .word .-2 ; pointer to last entry .byte 0,0 ;no interrupt generated ;good LONG timeouts allowed while realtime tasks are hogging processor .byte 0,15. ;current and initial timeout counts .byte 0,0 ;controller index and status .word vrgcsr ;address of CSR .word 0 ;address of current i/o packet .blkw 4 ;fork block allocation .blkw 6 ;UMR work area, not needed ; but LOA rejects SCB if this not present??? $vqend:: ;;only for loadable drivers .end .disable data .close .return .; .creacs: ;Building ACP source... .open vqacp.mac .enable data .title VQACP ;Peritek VRG-Q graphics interface driver ACP ;*** NOTE: DO NOT MODIFY THIS FILE. CREATED BY VQDRV.BLD *** ;debug=1 ;comment out when debugged ; Assumed no alphanumeric ROM included. Simulated here. ; 1/4/92 rewritten as normal task which waits for use via SDAT$ directives ; from client tasks, and takes a line of text passed in the command line. ; ; Send error messages to CO: using TKB ; ; 1/19/93 making conditional code for use as Device Driver ; 3/6/93 added code for saving and restoring cursor position ; 5/10/93 changed PARLOA routine to accept chars between and "/" as ; being within parameter range, due to problem with 7 I ; Also fixed bug in multiplication routine at termination of sixel state. ; 5/21/93 started modifying for hardware scrolling, to eliminate bus timeouts ; during L-O-N-G scroll routine currently used. So as not to break the ; existing code, am using conditional code symbol HWSCRL ; 11/15/93 Forget hardware scrolling. Its limitation to every 16. lines makes ; it altogether too tedious to program correctly, even if it is ; possible, of which I have my doubts. Will rewrite as driver/ACP combo. ; 4/12/94 Starting concerted effort at driver-ACP combination, the only ; worthwhile method of getting this idea to work ; 9/5/94 Finally got driver-ACP combination working, except for newlines ; 9/9/94 Attempting to find the bug that crashes RSX after I/O abort ; 10/1/94 Simplified IOKIL operation to where it seems to behave now... ; .enable mcl ;so we don''t have to declare every doggone macro ; .library "lb:[1,1]exemc.mlb" .mcall abodf$,hwddf$,pktdf$,tcbdf$ abodf$ ;define task abort codes hwddf$ ;define hardware register symbols pktdf$ ;define I/O packet offsets tcbdf$ ;define task control block offsets ; .macro push arg mov arg,-(sp) .endm push ; .macro pop arg mov (sp)+,arg .endm pop ; .macro swstk$ label ;in case macro not in system MLB''s emt 376 ;trap to $EMSST in DRDSP .word label .endm swstk$ ; .macro print string,p1,p2,p3,p4,p5,p6,p7,p8,p9,?msg,?endstr br endstr msg: .asciz |VQACP -- string| .even ;ensure word boundary, this is code space endstr: push r0 ;save registers used by this proc push r1 push r2 c=0 ;arg count .irp arg, .if nb arg push arg ;push any parameters c=c+1 .endc .endr mov sp,r2 ;save parameter list location mov #msg,r1 ;str address add #-80.,sp ;output buffer mov sp,r0 ;place address in r0 call $edmsg ;call system formatting routine mov #write,r0 ;get previously set-up qio for standard output mov sp,q.iopl(r0) ;address of text mov r1,q.iopl+2(r0) ;store length dir$ r0 ;send message to screen add #80.,sp ;adjust SP for output buffer add #,sp ;and for parameter list pop r2 pop r1 pop r0 .endm print ; ;Task-specific and device-specific equates ; vrgcsr=174140 ;=17774140 on 22-bit machine vrgdat=174000 vg0=40 cram=10 memloa=4 blank=100000 bs=8. ;backspace ht=9. ;horizontal tab, ^I lf=10. ;line feed vt=11. ;vertical tab ff=12. ;form feed cr=13. ;carriage return sub=26. ;substitution char, or ^Z esc=27. ;escape space=32. dcs=144. ;device control string csi=155. ;control string introducer st=156. ;string terminator ; states: .word 0,0,0 ;state stack, 3 words deep. States are: s.text=0 ; 0 - text mode s.esc=1 ; 1 - escape sequence s.csi=2 ; 2 - csi sequence s.dcs=3 ; 3 - dcs sequence s.sxl=4 ; 4 - sixel sequence s.prm=5 ; 5 - parameter processing (substate of CSI or DCS states) s.sxlr=6 ; 6 - sixel repeat sequence s.unkn=7 ; 7 - unknown device control string (waiting for ST) curstk: .word 0,0,0 ;cursor location stack curstp: .word 0 ;pointer for above stack, goes from 0 to 3 params: .word 0,0,0,0,0,0,0,0,0,0 ;10 parameters allowed, any more get trashed parcnt: .word 0 ;count of parameters stored xloc: .word 0 ;storage for X and Y screen coordinates yloc: .word 0 rptcnt: .word 1 ;sixel repeat count, defaults to 1 glm: .word 0 ;graphic left margin ucbsav: .word 0 ;saved VQ UCB ; .even sstvec: .word 0,0,0,0,reserved ;specify SST vector for reserved intructions write: qiow$ io.wvb,5,1,,,,<,,40> inbuf: .blkw 256. ;allow buffer size up to 512. ; ;State table ; .even stabl: .word text ;normal text mode .word escseq ;escape sequence .word csiseq ;CSI sequence .word dcsseq ;DCS sequence .word sxlseq ;sixel sequence .word parloa ;parameter load .word sxlrep ;sixel repeat .word waitst ;waiting for ST (unknown DCS sequence) ; .psect code,ro,i vqacp:: call init ;initialize connection to VQDRV 5$: call getpkt ;get packet from driver 25$: call getbyte ;get the next byte ;into r0 beq 5$ ;wait for another packet if this one empty mov states,r2 ;get current state asl r2 ;multiply by 2 for word offset call @stabl(r2) ;and jump to routine from state table br 25$ ;continue, whether or not there were errors ; text: jmp 1$ 101$: .byte 1,bs,1,ht,1,vt,1,lf,1,ff,1,cr,1,esc,1,dcs,1,csi,1,st .byte 8.,31.,5,126.,8.,159.,5,255.,0 .even 110$: .word bsrou,htrou,lfrou,lfrou,ffrou,crrou,escrou,dcsrou .word csirou,strou ; 1$: mov #101$,r1 call bounds beq 5$ ;match on control char, jump bvc 10$ ;if not recognized control char, see if text clc ;clear error flag return ;any other case, ignore it 5$: jmp @110$(r1) ;else jump to routine 10$: cmp r0,#126. ;in 7-bit ASCII range? blos 20$ ;if so, print it return ;else exit 20$: call sendchar ;send the character add #6.,xloc ;update X global return ; sendsixel: sub #63.,r0 ;remove SIXEL offset beq 30$ ;if zero, skip manipulations mov r0,r4 ;save character value mov #6,r3 ;count mov #1,r5 ;bit pointer mov xloc,r0 mov yloc,r1 ash #6,r1 ;shift into position 10$: bitb r5,r4 ;test if this bit is set or reset beq 20$ ;if reset, just skip it call pixel ;set the pixel 20$: add #100,r1 asl r5 ;next more signficant bit to test sob r3,10$ ;loop till done 30$: inc xloc ;and point to next location on X axis return ;(carry clear) sendchar: ;send the character in R0 to screen position (X,Y) ;1/3/93 The need to compress the table forced me to make this routine less ;straightforward, as now we must scan the table until we reach the desired ;character, then decompress it... sub #31.,r0 ;make offset into table, 1-based (space=1) mov #chrtbl,r4 10$: movb (r4)+,r2 bpl 10$ ;keep skipping until negative number hit sob r0,10$ ;count down until reached mov #10.,r3 ;row count neg r2 ;number of preceding nulls sub r2,r3 ;move down one row for each null mov xloc,r0 mov yloc,r1 ;otherwise just get Y coordinate add r2,r1 ;corresponds to ADD R2,YLOC in old routine ash #6,r1 21$: movb (r4)+,r2 bmi 90$ ;if negative, no more data push r2 ;do it on the stack, leave r4 for pointer bic #177637,(sp) ;clear all but bits 5 & 6 bic (sp),r2 ;now clear those bits in data word if set 22$: mov #1,r5 ;bit pointer tst r3 ;are we done 10 rows? beq 99$ ;then quit 25$: bit r5,r2 ;is this bit set? beq 30$ ;skip if not call pixel ;else set it on the screen 30$: inc r0 asl r5 ;next higher bit cmp r5,#40 ;end of the character? blt 25$ ;loop until reached sub #5,r0 add #100,r1 dec r3 tst (sp) bne 80$ tst (sp)+ 80$: beq 21$ ;if none, next outer loop sub #40,(sp) br 22$ 90$: 99$: clc ;clear error flag return ; escseq: br 1$ ;skip past tabular data 100$: .byte 1,''P,1,''[,1,''\,1,''7,1,''8,8.,31.,5,''/,8.,255.,0 101$: .byte 8.,31.,5,126.,8.,159.,5,255.,0 .even ;make sure it''s aligned on word boundary ;routines corresponding to match characters 111$: .word dcsrou,csirou,strou,decsc,decrc 1$: mov #100$,r1 ;load address of valid char table call bounds ;do bounds check bcs 99$ ;return on error bvs 10$ ;if control char or unrec. escseq, back to text mode beq 20$ ;if valid, skip ahead 99$: return ;non-terminating character, ignore 10$: mov #101$,r1 ;now check which it is,... call bounds ;control char or terminating char bvc 12$ ;if terminating, just switch states and return clr states ;back to text mode jmp text ;and jump to its routine 12$: clr states ;to text mode return ;quit, ignoring this char 20$: jmp @111$(r1) ;and branch to corresponding routine ; csiseq: br 1$ ;skip past tabular data 100$: .byte 1,''H,1,''J,2,''/,2,''?,8.,31.,5,126.,8.,159.,5,255.,0 .even 111$: .word 90$,92$,70$,80$ ;routines corresponding to rec''d chars 1$: mov #100$,r1 ;list address into r1 call bounds ;see if character is out of range bcs 70$ ;quit on program error beq 10$ ;if in range, continue ;if control char or unrecognized final char, quit ;if escape char, we should process it... if unrecognized ;final char, we will ignore it bvc 20$ ;final char, skip to RETURN clr states jmp text ;else process in text mode 10$: jmp @111$(r1) ;jump to appropriate routine 20$: clr states 70$: return ;return and get new char, this one ignored 80$: mov states,states+2 ;else push current state mov #s.prm,states ;enter parameter state jmp parloa ;and jump to its routine 90$: call csicup ;call cursor positioning routine jmp 20$ ;clear state before returning 92$: call csi.ed ;call clear-screen routine jmp 20$ ; dcsseq: br 1$ ;skip past tabular data 100$: .byte 1,''q,4,cr,4,lf,8.,31.,5,126.,8.,159.,5,255.,0 101$: .byte 5,''/,2,''?,5,255.,0 .even ;make sure it''s aligned on word boundary 1$: mov #100$,r1 ;set table address call bounds ;and see if this char is acceptable bcs 99$ ;quit on program error bvs 10$ ;if control char, terminate CSI sequence processing bne 30$ ;if not recognized DCS sequence,process again mov #s.sxl,states mov xloc,glm ;set graphic left margin to current X coordinate return ;SIXEL is the only DCS mode recognized by this driver 10$: clr states jmp text ;and process in text mode 30$: mov #101$,r1 ;now test for parameter setting call bounds bne 99$ mov states,states+2 ;push current state mov #s.prm,states ;and set parameter mode jmp parloa ;process parameters 99$: return ; sxlseq: br 1$ 101$: .byte 1,sub,1,''!,1,''$,1,''-,4,cr,4,lf,8.,31.,5,''>,2,126. .byte 4,127.,8.,159.,5,190.,2,254.,4,255.,0 .even 110$: .word 50$,60$,70$,80$ ;routines for above received chars ;Don''t choke on GR characters, ignore the high bit and pass to the SIXEL decode ;mechanism. All C1 and C0 control characters, however, immediately terminate ;SIXEL mode and cause TEXT mode to be re-entered. (except CR, SUB, and LF) 1$: mov #101$,r1 ;check for special characters call bounds bcs 99$ ;quit on program error bvs 90$ ;quit sixel mode on receipt of control char beq 10$ ;process SIXEL char return ;else return, ignoring this char 10$: cmp r1,#6 ;was it a special character? bhi 20$ ;jump to process normal SIXEL char jmp @110$(r1) ;go to special routine 20$: tst rptcnt ;is repeat count 0? beq 29$ ;then we''re done push r0 ;save value call sendsixel ;send it to screen pop r0 ;restore char value dec rptcnt ;dec count jmp 20$ 29$: inc rptcnt ;reset repeat count to 1 clc ;clear error flag return 50$: mov #''?,r0 ;replace SUB with SIXEL zero jmp sxlseq ;and try again 60$: mov #s.sxlr,states ;begin repeat mode clr rptcnt ;clear count prior to calculations return 70$: mov glm,xloc ;graphic CR return 80$: mov glm,xloc ;graphic CRLF add #6.,yloc cmp #503.,yloc ;past last SIXEL row? bcc 99$ ;if not, just return call scrl10 ;else scroll 10 lines, one character height bcs 99$ ;catch error sub #10.,yloc ;set relative pointer back where it was return 90$: ;terminate SIXEL mode, and leave screen position aligned on character cell mov xloc,r3 ;get X axis location clr r2 ;clear most significant bits div #6,r2 ;calc X position tst r3 ;was there a remainder? beq 91$ ;skip if not inc r2 ;else move to next char position 91$: mul #6,r2 ;now update XLOC... mov r3,xloc mov yloc,r3 ;do the same for Y position clr r2 div #10.,r2 tst r3 beq 92$ inc r2 92$: mul #10.,r2 mov r3,yloc clr states ;back to TEXT state jmp text 99$: return ; parloa: br 1$ 101$: .byte 8.,31.,2,''?,5,126.,8.,159.,5,255.,0 103$: .byte 1,'';,2,''9,5,255.,0 .even 110$: .word 50$,60$,70$ ;Convert any non-numeric chars in the parameter range to a negative integer ;using NEG two''s complement conversion. This may make the program incompatible ;with some numeric parameters, but most I''ve seen are small values, generally ;no higher than 255. 1$: mov #101$,r1 ;table address call bounds ;do boundary check bvs 20$ ;control char? back to text mode beq 30$ ;valid parameter range, skip ahead jmp 40$ ;terminator, pop previous mode and jump to it 20$: clr states jmp text ;to text mode 30$: mov #103$,r1 ;find out what to do with this char call bounds jmp @110$(r1) ;jump to appropriate routine 40$: inc parcnt ;inc parameter count before leaving... mov states+2,r1 ;pop previous state mov r1,states asl r1 ;get routine offset jmp @stabl(r1) ;and jump to it 50$: inc parcnt ;next parameter cmp parcnt,#10. ;past max? bhis 99$ ;then quit mov parcnt,r1 ;let''s index to it asl r1 ;by making word index clr params(r1) ;and clear it jmp 99$ ;done for now 60$: cmp parcnt,#10. ;parameter list full? bhis 99$ ;if so, quit sub #48.,r0 ;else convert to binary mov parcnt,r1 ;get current parameter count asl r1 ;make it an index mov params(r1),r3 mul #10.,r3 ;multiply whatever''s there by 10 add r0,r3 mov r3,params(r1) ;and merge in this digit br 99$ ;if carry set, will exit 70$: neg r0 ;convert to negative number and store as parameter mov parcnt,r1 ;get parameter count asl r1 ;make it a word offset mov r0,params(r1) ;and store it jmp 50$ ;inc parcount and return 99$: return ; sxlrep: br 1$ 100$: .byte 4,lf,4,cr,8.,31.,5,''/,2,''9,5,126.,8.,159.,5,255.,0 101$: .byte 1,lf,1,cr,2,''>,5,255.,0 ;ignore CRLF and non-SIXEL chars .even 1$: mov #100$,r1 call bounds ;check character against above list bcs 99$ ;quit on program error beq 10$ ;if a decimal digit, process as repeat count bvs 5$ ;if control char, terminate SIXEL processing mov #101$,r1 ;now check for innocuous characters call bounds bcs 99$ ;error? beq 99$ ;ignore CRLF or non-SIXEL mov #s.sxl,states ;no longer repeat mode jmp sxlseq ;if not a number, process as normal SIXEL char 5$: clr states ;else back to TEXT mode jmp text 10$: mov rptcnt,r1 ;get current repeat count mul #10.,r1 ;move over one decimal place sub #''0,r0 ;convert ASCII digit to binary add r0,r1 ;merge in with current count word mov r1,rptcnt ;store in memory location 99$: return ;error (carry) flag should be clear ; waitst: br 10$ 1$: .byte 1,lf,1,cr,8.,31.,2,126.,8.,159.,2,255.,0,0 .even ;This state was entered upon receipt of an unrecognized DCS sequence. So we ;just wait for any control character other than CR or LF ;then go back to TEXT mode. 10$: mov #1$,r1 ;address of table into r1 call bounds ;do bounds check bcs 99$ ;return if error bvs 20$ ;enter text mode on receipt of control character 99$: return 20$: clr states ;enter text mode jmp text ; bsrou: ;backspace routine sub #6.,xloc ;back up one space bcs 10$ ;if went below 0, adjust return ;otherwise return 10$: clr xloc ;leave at zero if trying to BS from leftmost position clc ;make sure carry clear return ; htrou: ;horizontal tab routine mov xloc,r1 ;current X position clr r0 ;clear most significant bits of longword div #48.,r0 ;divide X by 8 char widths, ignoring remainder inc r0 ;and add one tab width cmp r0,#8. ;are we past max? blo 10$ ;if not, set new X loc clr xloc ;else issue CRLF jmp lfrou 10$: mul #48.,r0 ;expand position to pixel location mov r1,xloc ;and store in local variables return lfrou: ;linefeed routine add #10.,yloc ;update Y location cmp #510.,yloc ;are we at max? bhi 10$ ;if not, just return call scrl10 ;and scroll the screen 10 lines (1 character height) sub #10.,yloc 10$: return ; scrl10: mov #10.,r3 10$: jmp scroll ; scroll: ;When using 10. as the number of raster lines, moves line 10. to line 0, line ;11. to line 1, etc, up to line 510. to line 500., for a total of 501. lines. ;Then it clears the ten lines from 501. to 510.; line 511. should always be ;blank anyway, since this program does not use it. ;1/31/93 changed it... even though THIS doesn''t use line 511., some other ; program MAY have, and we should clear it, too. mov r3,r4 ;number of raster lines to scroll ash #6,r4 ;shift over to match address bits of VRGCSR bic #77700,@#vrgcsr ;clear address lines mov #511.,r2 ;outer loop count sub r3,r2 ;subtract number of scroll lines, we gotta blank them 5$: mov #vrgdat,r0 ;point to data access area mov #32.,r1 ;inner loop count 10$: add r4,@#vrgcsr ;point to "next line down" bmi 98$ ;jump if high bit set by add push (r0) ;save the data at that location sub r4,@#vrgcsr ;now back to current line pop (r0)+ ;and store that data here, incrementing pointer sob r1,10$ ;loop for one line add #100,@#vrgcsr ;make following line the current line bmi 98$ ;catch overflow sob r2,5$ ;and loop for entire screen 15$: mov #vrgdat,r0 ;now clear the bottom lines mov #32.,r1 ;number of words to clear 20$: clr (r0)+ ;do it... sob r1,20$ ;and loop till done add #100,@#vrgcsr bmi 98$ sob r3,15$ return 98$: sec ;error flag set return ; csicup: ;cursor positioning routine clr yloc ;assume no parameters clr xloc ;assume no column specified tst parcnt ;assumption correct? beq 99$ ;then quit early mov params,r1 ;get row number mul #10.,r1 ;ten raster lines per row mov r1,yloc ;store it cmp parcnt,#2 ;was column specified? blo 99$ ;if not, we''re done mov params+2,r1 ;else get column number mul #6,r1 ;make into pixel offset mov r1,xloc ;and store it 99$: return csi.ed: ;[J ffrou: ;form feed routine ;Form Feed will clear the screen and home the cursor call clrperitek ;clear screen clr xloc ;clear X loc... clr yloc ;and Y return crrou: ;carriage return routine ;This routine will only be entered from a state that uses it, since the DCS ;processor can screen it out without calling this. clr xloc ;clear X location return escrou: ;escape routine mov #s.esc,states ;now in ESC state return dcsrou: ;dcs routine mov #s.dcs,states ;make DCS the current state clr parcnt ;clear parameter count clr params ;and clear first parameter return csirou: ;csi routine mov #s.csi,states ;terminate existing state and replace with CSI clr parcnt ;clear parameter count in case another escape sequence ;was in progress... clr params ;and clear first parameter return strou: ;string terminator routine mov #s.text,states ;set state to TEXT return ; decsc: ;DEC save cursor routine, won''t accept ANSI s cmp curstp,#3 ;are we at max stack depth? bhis 10$ ;if so, forget it mov curstp,r0 ;else get cursor stack pointer asl r0 ;make word index mov xloc,r3 ;get X axis location clr r2 ;clear most significant bits div #6,r2 ;calc X position movb r2,curstk(r0) ;save it mov yloc,r3 ;do the same for Y position clr r2 div #10.,r2 movb r2,curstk+1(r0) inc curstp ;inc cursor position stack pointer 10$: clr states ;terminate escape sequence return ; decrc: ;DEC restore cursor, won''t recognize ANSI u tst curstp ;see if stack is empty beq 10$ ;quit if so dec curstp ;get current saved coordinates mov curstp,r0 asl r0 ;make word index... movb curstk(r0),r1 ;get X character position bic #177400,r1 ;make sure it''s a byte value mul #6,r1 ;make into absolute (pixel) coordinate mov r1,xloc ;and store it movb curstk+1(r0),r1 ;get Y value bic #177400,r1 ;process same as X above mul #10.,r1 mov r1,yloc 10$: clr states ;end of escape mode return ; bounds: ;bounds_check routine is passed a character in r0 and a table address ;in r1. The table consists of word entries, each with the low byte containing ;an action code and the high byte a character code. The action codes are: ; 0 - end of table ; 1 - char is legal ; 2 - chars less than or equal to this are legal ; 3 - chars greater than this are legal ; 4 - char is ignored ; 5 - chars <= are ignored ; 6 - chars > are ignored ; 7 - char is illegal ; 8 - <= is illegal ; 9 - > is illegal ;returns V set if char is illegal ;Z set if char is legal ;C set if passed bad parameters (program error) or reached end of table ;no flags if char is to be ignored ;Doesn''t mess with R0, but R1 is returned as word pointer to entry where ;match occurred. R2 is destroyed. push r1 1$: cmpb #9.,(r1) ;illegal action code? bcs 96$ ;if so, exit with error flag set movb (r1)+,r2 ;else get the code asl r2 ;make word pointer cmpb r0,(r1)+ ;make the comparison jmp @4$(r2) ;and branch to appropriate action routine 4$: .word 96$ ;end of table is error... shouldn''t happen. .word 10$ .word 20$ .word 30$ .word 40$ .word 50$ .word 60$ .word 70$ .word 80$ .word 90$ 10$: beq 97$ ;char is legal br 1$ ;else loop back and try again 20$: blos 97$ ;less or equal is legal br 1$ ;else loop 30$: bhi 97$ ;higher is legal br 1$ ;loop 40$: beq 95$ ;char is ignored br 1$ 50$: blos 95$ ;lower or same chars are ignored br 1$ 60$: bhi 95$ ;higher chars are ignored br 1$ 70$: beq 98$ ;char is illegal br 1$ 80$: blos 98$ ;less or equal is illegal br 1$ 90$: bhi 98$ ;higher is illegal br 1$ 95$: sub (sp)+,r1 ;make r1 into pointer to match sub #2,r1 ccc ;clear all codes, ignore character return 96$: sub (sp)+,r1 ;make r1 into pointer to match sub #2,r1 sec ;set carry flag to indicate program error return 97$: sub (sp)+,r1 ;make r1 into pointer to match sub #2,r1 ccc ;clear condition codes sez ;and set zero flag return 98$: sub (sp)+,r1 ;make r1 into pointer to match sub #2,r1 ccc ;only one flag to be set sev ;set overflow flag return ; pixel: cmp #511.,r0 blo 99$ ;quit if past limit push r1 ;r1 contains Y, shifted, adjusted for HWSCRL if used bic #77700,@#vrgcsr ;clear existing line select bits bic #100077,r1 ;make sure r1 is clean of dangerous bits bis r1,@#vrgcsr ;now merge in our own line select ;the Y is taken care of, now let''s get X push r0 ash #-3,r0 ;make it into a word address, first divide by 8... bic #1,r0 ;then chop low bit off add #vrgdat,r0 ;make it an absolute address into hardware buffer pop r1 ;get original r0 into r1 push r1 ;and save it again bic #177760,r1 ;clear all but low nybble push r1 mov #1,r1 ash (sp)+,r1 ;move that #1 to the correct bit position bis r1,(r0) ;and set the bit in the display address pop r0 ;get original r0 back pop r1 ;and get original r1 back clc ;clear error flag return 99$: sec ;set error flag return ; clrperitek: ;can''t use MEMLOAD function because character RAM (CRAM) is not installed ; mov #0,r1 ;start line mov #512.,r0 ;number of lines to clear call clrline ;do it... return ; clrline: bit #vg0,@#vrgcsr ;has VRGINIT been run? beq 99$ ;if not, quit now push @#vrgcsr ;push current CSR value bic #77707,@#vrgcsr ;clear addr lines, MEMLOAD, RVEN, DMAEN bic #177000,r1 ;get modulo 512 of r1 value ash #6,r1 ;move start line into bit positions 6-14 bis r1,@#vrgcsr ;set our chosen start line 10$: mov #32.,r2 ;32 words/line (32*16 bits=512 pixels) mov #vrgdat,r3 ;point to access window 20$: clr (r3)+ ;do it now... sob r2,20$ ;loop for the line add #100,@#vrgcsr ;inc line pointer bmi 98$ ;if we set bit 15, quit sob r0,10$ ;loop for selected number of lines pop @#vrgcsr ;restore previous CSR value clc ;clear error flag return 98$: pop @#vrgcsr ;restore previous CSR value 99$: sec ;indicate error return ; reserved: dec (sp) ;point to instruction that caused the trap dec (sp) cmp #76040,@(sp) ;was it the LOCC instruction? beq 10$ ;if so, process it bpt ;else break execution 10$: inc (sp) ;restore PC inc (sp) 20$: tst r0 ;empty string? beq 30$ ;then return cmpb r4,(r1) ;compare search char to current string position beq 29$ inc r1 ;adjust regs and loop dec r0 br 20$ 29$: bic #4,2(sp) ;return with Z clear if match rtt 30$: bis #4,2(sp) ;return with Z set if no match rtt ;return from trap ; getpkt: clr r1 ;clear for packet location swstk$ 20$ ;enter system state mov $tktcb,r0 ;get address of this task''s TCB ;(must be ours since we have the floor) add #t.rcvl,r0 ;point to receive queue listhead call $qrmvf ;try to get a packet from queue bcc 10$ ;skip if successful callr $stpct ;else stop ourselves 10$: mov r1,4(sp);store packet address in user state R1 return ;back to user state 20$: ;.iif df debug, print ,r1 mov r1,r3 ;did we get anything? beq getpkt ;loop back, wait for more packets ;The driver will only pass transfer packets to us, so no need to check. ; Of course if that changes, we''ll need to add some code here mov i.ucb(r3),r5 ;get UCB address ;.iif df debug, print ,r5 mov r5,ucbsav ;store UCB address for cleanup code .if df lclbuf ;if using a local buffer tst u.cnt(r5) ;is VQDRV telling us to empty the queue? bmi 30$ ;skip if so mov u.buf(r5),r1 ;APR mapping mov u.buf+2(r5),r2 ;displacement swstk$ 30$ ;back to system stack again mov #inbuf,r0 ;location of our local buffer call $reloc ;convert to address doubleword mov r1,r3 ;and store in destination pointers mov r2,r4 ;... mov 4(sp),r1 ;restore r1 mov 6(sp),r2 ;and R2 from stack sub #20000,r2 ;change R2 to APR5 displacement from APR6 mov u.cnt(r5),r0 ;byte count call $blxio ;transfer to our buffer mov #inbuf,u.buf+2(r5) ;location of current character ;no need to worry about mapping base, from now on ;only this task will be referencing it... return ;to task state .endc 30$: clc ;clear error flag return ; init: svtk$s #sstvec,#5 ;process certain SSTs bcs 10$ srex$s #unbusy ;make sure to unbusy units before aborting 10$: return ; ;Exit AST, clean up before we quit unbusy: mov ucbsav,r5 ;get our UCB address beq 10$ ;quit if no link ever established with driver swstk$ 10$ ;go to system state... bicb #us.bsy,u.sts(r5) ;first the unit... mov u.scb(r5),r5 ;then get controller block clrb s.sts(r5) ;unbusy controller as well clr u.vacp(r5) ;let driver know ACP is gone mov $tktcb,r5 ;get our TCB address callr $drext ;exit without possibility of a race condition 10$: exit$s ;just exit the task ; getbyte: ;must be at system state to synchronize with driver... mov ucbsav,r5 ;restore UCB pointer swstk$ 200$ ;go to system state... 50$: mov u.cnt(r5),2(sp) ;any chars left? bgt 100$ ;continue if so bmi 60$ ;special if negative mov #is.suc,r0 ;completed successfully br 70$ ;join common code ;negative if driver, on IO.KIL, put -1 there 60$: mov #,r0 ;show aborted 70$: call $ioalt ;finish I/O and clear busy bit bicb #us.bsy,u.sts(r5) ;just the unit, controller cleared by VQDRV clr u.cnt(r5) ;clear -1 if there return ;to task state, at 200$ 100$: ;now get one character .if ndf lclbuf ;if not using local buffer push @#kisar6 ;save APR6 mapping mov u.buf(r5),@#kisar6 ;point it to user''s buffer .iftf ;get char, in either case... movb @u.buf+2(r5),r0 ;load character into return register .ift ;and if not using local buffer, restore APR6 pop @#kisar6 .endc ;lclbuf ;we got it, now... bic #177400,r0 ;clear sign-extended bits if any inc u.buf+2(r5) ;update pointer dec u.cnt(r5) ;and count mov r0,2(sp) ;store in return register 0 beq 50$ ;loop if null character return 200$: tst r0 ;set Z flag if nothing, S if aborted bgt 310$ ;just return if valid character bmi 210$ ;clear if I/O aborted tst states ;are we in text processing state? bne 300$ ;don''t CRLF if not call crrou ;otherwise advance to next line call lfrou ;when we get around to it, we can process 3rd parameter ;in the I/O packet, which indicates desired CRLF mode 210$: clr r0 ;clear the register now 300$: tst r0 ;set flags again before returning 310$: return ; chrtbl: ;characters from 32. (space) to 126. (~) in 5*9 (6*10 total) dot matrix ;bit 0 is at the top of each dot column; top and right are clear ;Coded as follows, to shrink storage space: ;First byte is the two''s complement of the number of leading zeroes. The ;trailing zeroes can be determined by the next negative byte, indicating ;the start of the next character. ;Bits 5 and 6 are not needed for pixel storage, so we will use them for ;repeat count: 01=2 times, 10=3, and 11=4 times2=40 times3=100 times4=140 .byte -10. ;space, ten zeroes .byte -1,4!times4,4,0,4 ;! .byte -1,12!times3 ;" .byte -1,12!times2,37,12,37,12!times2 ;# .byte -1,4,16,5,16,24,16,4 ;$ .byte -1,23!times2,10,4,2,31!times2 ;% .byte -1,2,5,2,6,31,11,26 ;& .byte -1,14,4,2 ;'' .byte -1,10,4,2!times3,4,10 ;( .byte -1,2,4,10!times3,4,2 ;) .byte -2,12,4,37,4,12 ;* .byte -1,4!times3,37,4!times3 ;+ .byte -7,14,4,2 ;, .byte -4,37 ;- .byte -7,4 ;. .byte -1,20!times2,10,4,2,1!times2 ;/ .byte -1,4,12,21!times3,12,4 ;0 .byte -1,4,6,4!times4,16 ;1 .byte -1,16,21,20,10,4,2,37 ;2 .byte -1,37,10,4,16,20,21,16 ;3 .byte -1,10,14,12,11,37,10!times2 ;4 .byte -1,37,1,17,21,20,21,17 ;5 .byte -1,14,2,1,17,23,21,16 ;6 .byte -1,37,20!times2,10,4,2!times2 ;7 .byte -1,16,21!times2,16,21!times2,16 ;8 .byte -1,16,21,31,36,20,10,6 ;9 .byte -2,6!times2,0!times2,6!times2 ;: .byte -2,6,6,0!times2,6,2,1 ;; .byte -1,10,4,2,1,2,4,10 ;< .byte -3,37,0,37 ;= .byte -1,2,4,10,20,10,4,2 ;> .byte -1,16,21,10,4!times2,0,4 ;? .byte -1,16,21,31,25,31,1,16 ;@ .byte -1,4,12,21!times2,37,21!times2 ;A .byte -1,17,62,16,62,17 ;B .byte -1,14,22,1!times3,22,14 ;C .byte -1,7,12,22!times3,12,7 ;D .byte -1,37,41,17,41,37 ;E .byte -1,37,41,17,1!times3 ;F .byte -1,14,22,41,31,22,14 ;G .byte -1,21!times3,37,21!times3 ;H .byte -1,16,4!times4,4,16 ;I .byte -1,34,10!times4,11,6 ;J .byte -1,21,11,5,3,5,11,21 ;K .byte -1,1,1,1,1,1,1,37 ;L .byte -1,21,33,25!times2,21!times3 ;M .byte -1,21,23!times2,25,31!times2,21 ;N .byte -1,16,21!times4,21,16 ;O .byte -1,17,21!times2,17,1,1,1 ;P .byte -1,16,21!times3,25,11,36 ;Q .byte -1,17,21!times2,17,5,11,21 ;R .byte -1,16,21,1,16,20,21,16 ;S .byte -1,37,4!times3,4!times3 ;T .byte -1,21!times3,21!times3,16 ;U .byte -1,21!times3,12!times3,4 ;V .byte -1,21!times3,25!times2,37,12 ;W .byte -1,21!times2,12,4,12!times2,21 ;X .byte -1,21!times2,12,4!times4 ;Y .byte -1,37,20,10,4,2,1,37 ;Z .byte -1,34,4!times4,4,34 ;[ .byte -1,1!times2,2,4,10,20!times2 ;\ .byte -1,7,4!times4,4,7 ;] .byte -1,4,12,21 ;^ .byte -8.,37 ;_ .byte -1,6,4,10 ;` .byte -3,16,20,36,21,36 ;a .byte -1,41,17,23,21,23,17 ;b .byte -3,16,21,1!times2,36 ;c .byte -1,20!times2,36,31,21,31,36 ;d .byte -3,16,21,37,1,16 ;e .byte -1,10,24,4,16,4!times3 ;f .byte -3,26,11,6,1,16,21,16 ;g .byte -1,1!times2,17,21!times4 ;h .byte -1,4,0,6,4!times3,16 ;i .byte -1,10,0,10!times4,11!times2,6 ;j .byte -1,1!times2,11,5,3,11,21 ;k .byte -1,6,4!times4,4,16 ;l .byte -3,13,25!times3,21 ;m .byte -3,15,23,21!times3 ;n .byte -3,16,21!times3,16 ;o .byte -3,15,23,21,17,1!times3 ;p .byte -3,26,31,21,36,20!times3 ;q .byte -3,15,22,2!times3 ;r .byte -3,16,1,16,20,17 ;s .byte -1,4!times2,16,4!times2,24,10 ;t .byte -3,11!times4,26 ;u .byte -3,21!times2,12!times2,4 ;v .byte -3,21!times2,25,37,12 ;w .byte -3,21,12,4,12,21 ;x .byte -3,11!times3,16,10,11,6 ;y .byte -3,37,10,4,2,37 ;z .byte -1,30,4,10,6,10,4,30 ;{ .byte -1,4!times4,4!times3,0,0 ;| .byte -1,3,4,2,14,2,4,3 ;} .byte -1,26,11,-1 ;~ .even ; .end vqacp .disable data .close .return .; .credvl: ;Building driver link file... .open vqdrv.tkb .enable data ''vqdrv/-hd/-mm,,''vqdrv= 'uic'vqdrv ''rsx11m.stb/ss [1,1]exelib/lb / stack=0 par=drvpar:120000:20000 // .disable data .close .return .; .creacl: ;Building ACP link file... .open vqacp.tkb .enable data ''vqacp/ac/-cp='uic'vqacp ''rsx11m.stb/ss ''vqdrv.stb/ss [1,1]exelib/lb / task=vqacp // .disable data .close .return .; GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.