.TITLE ALVSB5 Alvin Subroutines - Level 5 .Psect Alvin,GBL,CON .Ident /LVL51 / .MCALL $ALVIN .Globl PutByte ;; ;;********************************************************************** ;; THESE SUBROUTINES EXTEND ALVIN PROCESSING CAPABILITIES. ;; THEY CONSTITUTE THE PRIMARY PRIMITIVES ASSOCIATED WITH ;; THE ABILITY TO PROCESS ALVIN BUFFERS, COMMAND STRINGS, AND ;; DATA AREAS IN EASILY EXECUTED RE-ENTRANT SUBROUTINE CALLS. ;; ;; VERSION 2 ;; LATEST REVISION: 5-15-79 - ADDED BUFSTRING TO BUFFER STRINGS. ;; 20-DEC-79 - LINKED TO ALVIN LEVEL 4 BASE ;; 22-Nov-83 - Adapted to Alvin Version 5. ;; 10-Jul-84 DVJ removed SPAN, GETBYTE, PUTBYTE, PRESS, CMDMAT, ;; and CMDCOPY - separate PSECTS. ;;********************************************************************** $ALVIN DEL=177 ;RUBOUT/DELETE CHARACTER (ALTERNATE BACK SPACE) ;+ ;;********************************************************************** ;; SUBROUTINE TO CONVERT BINARY DATA WORD(S) TO HEX CHARACTERS. ;; HIGHORDER DATA BITS ARE PROCESSED FIRST. ;; PROVIDES TWO MODES DETERMINED BY THE DATA BLOCKSIZE: ;; (1) DATA BLOCKSIZE=(N>0)=CONVERT N SEQUENTIAL DATA WORDS TO ;; HEX AND OUTPUT TO THE BUFFER, CALCULATE A 16-BIT CHECKSUM ;; AND CONVERT THE CHECKSUM TO HEX, UPDATE THE DATA ;; DESCRIPTOR, TAKE NORMAL EXIT WHEN A BLOCK HAS PROCESSED ;; (MAY BE PADDED WITH ZEROES ON RIGHT OF DATA AND TO LEFT OF ;; CHECKSUM IF INSUFFICIENT DATA FOR A FULL BLOCK), TAKE ;; DONE_EXIT IF ON ENTRY THERE ARE NO LONGER ANY WORDS TO BE ;; PROCESSED. (THE DONE_EXIT IS ALSO TAKEN IF A BUFFER FULL ;; CONDITION OCURRS ON THE CHARACTER BUFFER, IN WHICH CASE ;; THE DATA DESCRIPTOR IS NOT UPDATED. ;; NORMAL DONE = DATA START ADR > DATA END ADR, ELSE ERROR.) ;; ALL BLOCKS ARE OF A FIXED LENGTH=(DATA BLOCKSIZE*4)+4 FOR ;; THE CHECKSUM. THE USER CAN MANIPULATE THE BLOCKSIZE TO ;; GENERATE VARIABLE LENGTH BLOCKS AND/OR TO PREVENT PADDING ;; WITH ZEROES. EXPECTS CALLS OF THE FORM: ;; JSR R5,FORMH ;; .WORD (ADDRESS OF AN ALVIN CURCULAR BUFFER DESC) ;; .WORD (ADDRESS OF THE DATA DESCRIPTOR) ;; .WORD (# DATA WORDS PER BLOCK = DATA BLOCKSIZE > 0) ;; BR (DONE WITH DATA AREA, BUFFER FULL OR ERROR) ;; ; WHERE A DATA DESCRIPTOR IS TWO WORDS: THE DATA START ;; ; ADDRESS (WHICH IS MODIFIED AS THE BLOCKS ARE ;; ; COMPLETED) FOLLOWED BY THE DATA END ADDRESS WHICH ;; ; IS NOT MODIFIED. IE. ;; DATA.DESC: .WORD (ADDRESS OF START OF DATA BLOCK) ;; .WORD (ADDRESS OF END OF DATA) ;; (2) DATA BLOCKSIZE = 0 = CONVERT ONE WORD OF DATA TO HEX AND ;; OUTPUT TO THE BUFFER. (THE DATA WORD IS NOT MODIFIED NOR ;; IS THE POINTER TO THE DATA WORD; NO CHECKSUM GENERATED.) ;; DESIGNED TO BE USED FOR CUSTOM FORMATING, IE. BYTES ;; REVERSED, PREFIX DATA ON A BLOCK SUCH AS ADDRESS AND ;; BLOCKSIZE, ETC. EXPECTS CALLS OF THE FORM: ;; JSR R5,FORMH ;; .WORD (ADDRESS OF AN ALVIN CIRCULAR BUFFER DESC) ;; .WORD (ADDRESS OF THE DATA WORD) ;; .WORD 0 ;BLOCKSIZE MUST EQUAL ZERO ;; BR ERROR ;PROBABLE BUFFER FULL ;; (3) DATA BLOCKSIZE=NEGATIVE=ERROR EXIT TAKEN (PROGRAM ERROR) ;; THERE IS NO EASY WAY TO RECOVER FROM A BUFFER FULL ERROR; ;; IT IS A CONDITION TO BE AVOIDED. THE ERROR EXIT FACILITY IS ;; PROVIDED TO DETECT PROGRAMMING ERRORS THAT WOULD OTHERWISE BE ;; DIFFICULT TO LOCATE. THE DONE_EXIT IS THE INTENDED USE OF THIS ;; RESERVED BRANCH WORD. "DONE" CAN BE DETERMINED BY THE USER ;; PRIOR TO THE FINAL SUBROUTINE ENTRY, IN WHICH CASE THE SPECIAL ;; EXIT COULD ENTIRELY BE TREATED AS AN ERROR EXIT. ;; YOU THE USER MAY CHOOSE HOW TO USE THE OPTIONS. ;- FORMH:: ;SUBROUTINE TO FORMAT HEX BLOCKS FROM DATA WORDS MOV R4,-(SP) ;SAVE REGISTERS ON STACK MOV R3,-(SP) MOV R2,-(SP) MOV R1,-(SP) MOV R0,-(SP) MOV (R5)+,R4 ;GET ALVIN BUFFER DESCRIPTOR ADDRESSARM MOV (R5)+,R2 ;GET DATA POINTER/DESC ADDRESS MOV (R2)+,R0 ;GET DATA/DATA START PTR TO REG 0 ;SEE OPTIONS ABOVE: IF DESC, R2 NOW POINTS TO END ADR MOV R0,R3 ;PUT DATA/DATA POINTER IN REG 3 MOV R2,-(SP) ;SAVE DATA DESC ADR ON THE STACK CLR -(SP) ;CLEAR THE CHECKSUM WORK AREA MOV (R5)+,-(SP) ;GET DATA BLOCKSIZE TO THE TOP OF THE STACK BMI FORMHDONE ;INVALID IF NEGATIVE BEQ FORMH2 ;PROCESS SINGLE WORD IF BLOCKSIZE=0 ;PROCESS DATA BLOCK MODE - CHECK FOR DONE EXIT CMP (R2),R3 ;IS DATA END ADR < DATA START ADR? BLO FORMHDONE ;YES, TAKE THE DONE EXIT FORMH1: MOV (R3)+,R0 ;GET NEXT DATA WORD AND INCR DATA PTR ADD R0,2(SP) ;CALCULATE CHECKSUM FORMH2: CLR R1 ;CLEAR R1 FOUR-WAY SWITCH FOR 4 HEX DIGITS FORMH3: SWAB R0 ;RE-POSITION BYTES (HIGH THEN LOW BYTE) FORMH8: MOV R0,R2 ;SAVE CURRENT BYTE POSITION ROR R0 ROR R0 ;SHIFT FOR HIGH HEX DIGIT IN LOW BYTE ROR R0 ROR R0 FORMH6: BIC #177760,R0 ;EXTRACT THE 4-BIT BYTE ADD #260,R0 ;FORCE PARITY BIT & CONVERT TO CHAR 0-9 CMP #271,R0 BGE FORMH4 ADD #7,R0 ;CONVERT FOR CHARS A-F FORMH4: JSR PC,PARITE ;GENERATE EVEN PARITY ON LOW BYTE IN REG 0 JSR R5,PUTBYTE ;MOVE CHAR IN R0 TO BUFFER AND UPDATE DESC .WORD 0 ;BUFFER DESCRIPTOR ADDRESS IS IN REG 4 BR FORMHDONE ;BUFFER FULL - QUIT IMMEDIATELY MOV R2,R0 ;RESTORE SWAPPED BYTES COM R1 ;COMPLEMENT SWITCH VALUE BMI FORMH6 ;LOOP FOR LOW HEX DIGIT IN LOW BYTE BNE FORMH7 ;WORD DONE - EXIT LOOP INC R1 ;SET SWITCH FOR SECOND BYTE IN WORD BR FORMH3 ;LOOP FOR OTHER BYTE IN WORD ;; FORMH7: DEC (SP) ;COUNT DOWN THE BLOCK SIZE COUNTER BMI FORMHX ;IF MINUS THEN DONE BEQ FORMH5 ;IF ZERO THEN NEED TO PROCESS THE CHECKSUM CMP @4(SP),R3 ;IS THERE MORE DATA TO PUT IN THE BLOCK? BHIS FORMH1 ;YES CLR R0 ;NO, PAD REST OF BLOCK WITH ZEROES BR FORMH2 FORMH5: MOV 2(SP),R0 ;PROCESS CHECKSUM NEG R0 ;TWO'S COMPLEMENT OF BLOCKSUM BR FORMH2 ;CONVERT & EXIT ;; FORMHX: TST (R5)+ ;SUCCESSFULL EXIT - INCR RETURN ADDRESS FORMHDONE: CMP (SP)+,(SP)+ ;POP THE STACK BY 2 WORDS MOV (SP)+,R2 ;GET THE DATA DESC PTR OFF THE STACK MOV R3,-(R2) ;UPDATE DATA DESC START ADDRESS ;(THIS REWRITES THE ORIGINAL VALUE FOR WORD MODE) ;; NOTE: IF THE BUFFER DESCRIPTOR ABSOLUTE ADDRESS IS ZERO, THEN ;; THIS ADDRESS IS ASSUMED TO ALREADY BE IN REGISTER 4. MOV (SP)+,R0 ;RESTORE REGISTERS MOV (SP)+,R1 MOV (SP)+,R2 MOV (SP)+,R3 MOV (SP)+,R4 RTS R5 ;RETURN ;+ ;;********************************************************************** ;; SUBROUTINE TO GENERATE EVEN PARITY ON LOW-ORDER BYTE IN REG 0. ;; REGISTER 0 IS NOT OTHERWISE MODIFIED; HIGH-ORDER BYTE IS SAFE. ;; EXPECTS CALLS OF THE FORM: JSR PC,PARITE ;- PARITE:: MOV R4,-(SP) ;STACK REGISTERS USED MOV R3,-(SP) MOV R2,-(SP) MOV R1,-(SP) MOV #7,R3 ;COUNT NUMBER BITS IN ASCII CHAR MOV R0,R1 ;COPY CHAR TO WORK IN REG 1 CLR R2 ;INIT FOR SUMMING BITS IN REG 2 PARITLP: ASL R1 ;SHIFT NEXT HIGH BIT TO BIT POSITION 7 MOV R1,R4 ;SAVE CURRENT SHIFTED CONDITION BIC #177577,R1 ;CLEAR ALL BITS EXCEPT BIT 7 ADD R1,R2 ;SUM BITS IN CHAR MOV R4,R1 ;RESTORE REG 1 DEC R3 ;COUNT DOWN FOR 7 BITS BGT PARITLP ;LOOP FOR ALL POSSIBLE BITS MOV #200,R1 BIC R1,R0 ;FORCE PARITY BIT OFF BIT R1,R2 ;WAS THE SUM EVEN? BEQ PARITOK ;YES, PARITY IS OK BIS R1,R0 ;NO, FORCE THE PARITY BIT ON PARITOK: MOV (SP)+,R1 ;RESTORE REGS MOV (SP)+,R2 MOV (SP)+,R3 MOV (SP)+,R4 RTS PC ;RETURN ;+ ;;********************************************************************** ;; SUBROUTINE TO COPY THE CONTENTS OF AN ALVIN BUFFER TO ANOTHER. ;; PROCESSES UNTIL THE BUFFER BEING COPIED FROM IS ENTIRELY ;; COPYIED OR UNTIL THE BUFFER BEING COPIED TO IS FULL, ;; WHICH EVER COMES FIRST. ;; EXPECTS CALLS OF THE FORM: ;; JSR R5,BUFCOPY ;; .WORD (ADDRESS OF BUFFER DESCRIPTOR TO COPY FROM) ;; .WORD (ADDRESS OF BUFFER DESCRIPTOR TO COPY TO) ;- BUFCOPY:: MOV R4,-(SP) ;STACK REGISTERS USED MOV R3,-(SP) MOV R2,-(SP) MOV R0,-(SP) ;REG 0 IS THE GETBYTE/PUTBYTE RETURN REG. MOV (R5)+,R3 ;GET BUF DESC TO COPY FROM MOV (R5)+,R4 ;GET BUF DESC TO COPY TO JSR R5,BUFRESET ;RESET BUFFER COPYING TO TO NULL .Word 0 ; (BUF DESC IS IN REG 4) MOV 2(R3),R2 ;GET OUTPUT POINTER OF BUF COPYING FROM BUFCLP: CMP R2,(R3) ;IS COPY-FROM BUFFER EMPTY? BEQ BUFCX ;YES, EXIT MOVB (R2),R0 ;NO, GET BYTE FROM COPY-FROM BUF JSR R5,PUTBYTE ;PUT BYTE IN REG 0 INTO THE BUFFER .WORD 0 ;(BUF DESC IS IN REG 4) BR BUFCX ;EXIT WHEN FULL INC R2 ;INCR COPY-FROM BUFFER POINTER CMP R2,6(R3) ;AT END OF BOPY-FROM BUFFER? BLOS BUFCLP ;NO, LOOP MOV 4(R3),R2 ;YES, WRAP-AROUND TO BEGINNING BR BUFCLP ;LOOP UNTIL EMPTY OR FULL ;; BUFCX: MOV (SP)+,R0 ;RESTORE REGISTERS USED MOV (SP)+,R2 MOV (SP)+,R3 MOV (SP)+,R4 RTS R5 ;RETURN ;+ ;;********************************************************************** ;; SUBROUTINE TO TERMINATE THE SPECIFIED BUFFER WITH THE STANDARD ;; END-OF-LINE CHARACTER "EOL1". IF THE LAST CHARACTER IN THE ;; BUFFER IS "EOL1" THEN THE BUFFER IS NOT MODIFIED. ;; IF THE LAST CHAR IS "EOL2", IT WILL BE OVERRIDDEN TO "EOL1". ;; ELSE AN ATTEMPT WILL BE MADE TO ADD "EOL1" TO THE END OF THE ;; BUFFER. IF THE BUFFER IS FULL, THE LAST BYTE IN THE BUFFER ;; WILL BE OVERRIDDEN TO "EOL1". ;; EXPECTS CALLS OF THE FORM: ;; JSR R5,BUFEOL ;; .WORD (ADDRESS OF BUFFER DESCRIPTOR) ;; BUFEOL:: MOV R4,-(SP) ;SAVE REGISTERS USED MOV R3,-(SP) MOV R0,-(SP) MOV (R5)+,R4 ;GET ADDRESS OF BUFFER DESC MOV #EOL1,R0 ;GET STANDARD END-OF-LINE CHAR MOV (R4),R3 ;GET CURRENT BUFFER INPUT POINTER CMP R3,2(R4) ;IS THE BUFFER EMPTY? BEQ BUFEOIN ;YES, PUT IN AN EOL DEC R3 ;BACKUP INPUT POINTER BY 1 CMP R3,4(R4) ;WRAP BACK? BHIS BUFEOGO ;NO MOV 6(R4),R3 ;YES, GET END-OF-BUFFER ADDRESS BUFEOGO: CMPB (R3),R0 ;IS LAST CHAR STANDARD EOL? BEQ BUFEOX ;YES, EXIT CMPB #EOL2,(R3) ;IS LAST CHAR ALTERNATE EOL? BEQ BUFEOR ;YES, OVER-RIDE TO EOL1 BUFEOIN: JSR R5,PUTBYTE ;TRY TO ADD EOL1 TO BUFFER .WORD 0 ;BUF DESC ADR IS ALREADY IN REG 4 BR BUFEOR ;BUFFER FULL - OVER-RIDE LAST CHAR TO EOL1 BR BUFEOX ;EXIT BUFEOR: MOVB R0,(R3) ;OVER-RIDE LAST CHAR TO EOL1 BUFEOX: MOV (SP)+,R0 ;RESTORE REGISTERS USED MOV (SP)+,R3 MOV (SP)+,R4 RTS R5 ;AND RETURN ;+ ;;********************************************************************** ;; SUBROUTINE TO BUFFER THE CONTENTS OF A STRING DESCRIPTOR ;; FOR THE LENGTH SPECIFIED OR UNTIL THE STRING IS EXHAUSTED. ;; NULL STRINGS OR EXHAUSTED STRINGS BUFFER NOTHING. ;; EVEN PARITY IS GENERATED BY DEFAULT. IF THE LENGTH HAS THE ;; HIGH ORDER BIT SET (NOPARITY BIT) THEN BYTES ARE MOVED AS IS. ;; THIS CAN BE USED TO BUFFER PURE DATA AREAS AS LONG AS ;; THE STRING DESCRIPTOR DOES NOT SPECIFY ONE ZERO BYTE, ;; FOR THIS IS THE NULL STRING AND IT WILL NOT BE BUFFERED. ;; A LENGTH OF ZERO WILL BUFFER FOR THE LENGTH OF THE STRING ;; OR UNTIL BUFFER FULL, WHICH EVER COMES FIRST. ;; A COUNT OF THE BYTES BUFFERED IS RETURNED IN REGISTER 0. ;; IF THE BUFFER LIMIT IS EXCEEDED THE BUFFER FULL EXIT IS TAKEN. ;; EXPECTS CALLS OF THE FORM: ;; JSR R5,BUFSTRING ;(CAN BE SHORTENED TO BUFSTR) ;; .WORD (BUFFER DESCRIPTOR ADDRESS) ;; .WORD (STATIC STRING DESCRIPTOR) ;NOT MODIFIED ;; .WORD (MAX # BYTES TO BUFFER) ;IF BIT-15 SET THEN NOPARITY ;; (IF ZERO, THEN MOVE FOR LENGTH OF STRING) ;; BR (BUFFER LIMIT EXCEEDED) ;; ;; NOTE-1: IF THE ALVIN BUFFER DESCRIPTOR ADDRESS IS ZERO, THEN ;; THIS ADDRESS IS ASSUMED TO BE IN REGISTER 4. ;; NOTE-2: IF THE STRING DESCRIPTOR ADDRESS IS ZERO, THEN ;; THIS ADDRESS IS ASSUMED TO BE IN REGISTER 3. ;; NOPARITY=100000 ;CONTROL BIT TO PREVENT GENERATION OF EVEN PARITY ;- BUFSTRING:: MOV R4,-(SP) ;STACK REGISTERS USED MOV R3,-(SP) MOV R2,-(SP) MOV R1,-(SP) MOV (R5)+,R2 ;GET BUFFER DESC ADR PARM BEQ BUFS10 ;IF ZERO, THEN IT IS ALREADY IN REG 4 MOV R2,R4 ;ELSE PUT IT IN REG 4 BUFS10: MOV (R5)+,R2 ;GET STRING DESC ADR PARM BEQ BUFS20 ;IF ZERO, THEN IT IS ALREADY IN REG 3 MOV R2,R3 ;ELSE PUT IT IN REG 3 BUFS20: MOV (R5),-(SP) ;PUT LENGTH ON TOP OF STACK BIC #NOPARITY,(SP) ;GUARANTEE POSITIVE COUNT CLR R1 ;CLEAR COUNT TO ZERO MOV (R3)+,R2 ;GET STARTING ADDRESS OF STRING CMP R2,(R3) ;COMPARE TO END ADDRESS BLO BUFSTLP ;IF LOW THEN PROCEED BHI BUFSTX ;IF HIGH THEN ASSUME EXHAUSTED STRING TSTB (R2) ;IS THIS A NULL BYTE - NULL STRING? BEQ BUFSTX ;YES, BRANCH BUFSTLP: MOVB (R2)+,R0 ;GET A BYTE FROM THE STRING TST (R5) ;SHOULD PARITY BE GENERATED? BMI BUFSTIT ;NO, BRANCH JSR PC,PARITE ;GENERATE EVEN PARITY BUFSTIT: JSR R5,PUTBYTE ;BUFFER THE BYTE .WORD 0 ;THE BUF DESC ADR IS IN REG 4 BR BUFSTF ;BUFFER FULL - TAKE ERROR EXIT INC R1 ;COUNT THIS BYTE DEC (SP) ;COUNT DOWN REQUESTED LENGTH BEQ BUFSTX ;IF ZERO THEN DONE CMP R2,(R3) ;IS THE STRING ALL BUFFERED? BLOS BUFSTLP ;NO, LOOP BUFSTX: TST (R5)+ ;INCR RETURN ADDRESS FOR SUCCESS BUFSTF: MOV R1,R0 ;RETURN COUNT IN REG 0 TST (SP)+ ;POP THE COUNT FROM THE TOP OF THE STACK TST (R5)+ ;INCR PAST LENGTH/CONTROL PARM MOV (SP)+,R1 ;RESTORE REGISTERS USED MOV (SP)+,R2 MOV (SP)+,R3 MOV (SP)+,R4 RTS R5 ;RETURN WITH COUNT IN REGISTER 0. ;;********************************************************************** ;; SUBROUTINE TO RESET THE INPUT AND OUTPUT BUFFER POINTERS ;; IN AN ALVIN BUFFER DESCRIPTOR TO THE START OF THE BUFFER. ;; EXPECTS CALLS OF THE FORM: ;; JSR R5,BufReset ;; .WORD (ADDRESS OF BUFFER DESCRIPTOR) ;; NOTE: IF THE BUFFER DESCRIPTOR ADDRESS IS ZERO, THEN ;; THIS ADDRESS IS ASSUMED TO ALREADY BE IN RGISTER 4. ;; BufReset:: MOV R4,-(SP) ;STACK THE WORK REG MOV (R5)+,R4 ;GET THE BUF DESC ADDRESS BNE RESETGO ;BRANCH IF DESC DEFINED MOV (SP),R4 ;ELSE ASSUME BUF DESC ADR WAS IN REG 4 RESETGO: MOV BSTART(R4),BIN(R4) ;SET INPUT PTR TO START OF BUFFER MOV BSTART(R4),BOUT(R4) ;SET OUTPUT PTR TO START OF BUFFER MOV (SP)+,R4 RTS R5 ;RETURN ;;********************************************************************** .END