/XMODEM RECEIVE OS/8 DEVICE HANDLER VERS. 1.01 /************************************************************** /THIS 2-PAGE OS/8 DEVICE HANDLER RECEIVES BINARY DATA VIA /A KL8-E-TYPE SERIAL PORT, USING THE XMODEM PROTOCOL. /LIMITATIONS: / 1. CRC ERROR CHECKING IS NOT SUPPORTED / 2. NO LIMIT ON RETRIES. BUT THE USER CAN ^C FROM THE CONSOLE. /************************************************************** /FOR DEVICE HANDLER DOCUMENTATION, SEE THE FOLLOWING: / OS/8 SOFTWARE SUPPORT MANUAL (DEC-S8-OSSMB-A-D), / CHAPTER 4: USING DEVICE HANDLERS / SECTION 5.1: WRITING DEVICE HANDLERS / OS/8 HANDBOOK, APRIL 1974 (DEC-S8-0SHBA-A-D) / PAGES 2-56 TO 2-61: BUILD HANDLER DEVICE FORMAT /************************************************************** /REVISION HISTORY / 1.01 27 SEPTEMBER 2023 M. EBERHARD / COMMENT CORRECTIONS ONLY / 1.00 23 AUGUST 2020 M. EBERHARD / CREATED /************************************************************** /LIMIATIONS: / 1. XMODEM-CRC IS NOT SUPPORTED / 2. THE BUFFER SIZE MUST BE AN EVEN NUMBER OF 128-WORD / OS/8 RECORDS. (ODD WILL GENERATE A FATAL ERROR RETURN) / 3. RETRIES ARE UNLIMITED. (THE XMODEM SPEC SAYS TO ABORT / AFTER 10 RETRIES OF ANY RECORD. THE USER CAN ALWAYS / ABORT WITH ^C) /************************************************************** XMRVERSION=0100 /OCTAL VERSION DEVTYPE=0560 /DEVICE TYPE, 0NN0, /NN BETWEEN 40 AND 77 /(SEE DEC-S8-0SHBA-A-D PAGE 2-59) /-------------------------------- /TRANSFER PORT DEFINITIONS /DTPORT MUST BE OF THE FORM 0NN0, /WHERE N IS AN OCTAL DIGIT /-------------------------------- /DTPORT=0030 /OS/8 CONSOLE DTPORT=0300 /2ND KL8-E /DTPORT=0400 /2ND "TELETYPE" ON THE PDP-8 SIMULATOR /CALCULATE THE SPECIFIED KL8-E IOT'S FOR THE TRANSFER PORT DTPKSF=6001+DTPORT /SKIP ON INPUT FLAG DTPKCC=6002+DTPORT /CLEAR INPUT FLAG DTPKRB=6006+DTPORT /READ INPUT BUFFER, CLEAR FLAG DTPTFL=6010+DTPORT /SET OUTPUT FLAG DTPTSF=6011+DTPORT /SKIP ON OUTPUT FLAG DTPTLS=6016+DTPORT /WRITE TO OUTPUT, CLEAR FLAG /********************************** /* DEVICE HANDLER HEADER BLOCK * /* SEE DEC-S8-0SHBA-A-D PAGE 2-57 * /********************************** *0 -1 /-NUMBER OF DEVICE HANDLERS HERE DEVICE XMR /DEVICE GROUP NAME DEVICE XMR /OS/8 DEVICE NAME DEVTYPE+1000 /DCB WORD: NOT FILE-STRUC'D, /WRITE-ONLY,DEVICE TYPE XMR&177+4000 /ENTRY POINT (MUST BE>24) /4000 INDICATES 2-PAGE HANDLER /(SEE DEC-S8-0SHBA-A-D PAGE 2-60) ZBLOCK 2 /2 WORDS MUST BE 0 /*********************** /* DEVICE HANDLER BODY * /*********************** *200 /(SEE DEC-S8-0SHBA-A-D PAGE 2-57) /VARIABLES BUFADR, 0 /BUFFER ADDRESS BPTRA, 0 /BUFPTR ADDRESS B123A, 0 /BUF123 ADDRESS SPTRA, 0 /BUFPTR ADDRESS S123A, 0 /BUF123 ADDRESS PRVREC, 0 /PREVIOUS XMODEM RECORD NUMBER XRECCNT,0 /NUMBER OF XWINDOW RECORDS THAT FIT /CONSTANTS CTLZ, 232 /OS/8 EOF MARK CTLZH, 4400 /CTLZ<0:3> IN <0:3> /CTLZL, 5000 /CTLZ<4:7> IN <0:3> CZLMCZ, 5000-232 /CTLZL - CTLZ BWCMSK, 3700 /MASK FOR BUFFER WORD COUNT CIFCDF, CDF CIF 0 /PROTOTYPE CDF CIF INSTRUCTION /*** INITIALIZATION *** /ON ENTRY: / AC=0 /********************** DELTA, NEWREC-IRET /BE POSITION-INDEPENDENT TEMP1, /(REUSE) INIT, 0 /INITIALIZE THE SERIAL PORT DTPKCC /CLEAR INPUT FLAG DTPTFL /SET OUTPUT FLAG /INITIALIZE PAGE 1 VARIABLES DCA PRVREC /COMPUTE & REMEMBER ADDRESSES OF PAGE 2 VARIABLES /INITALIZE PAGE 2 VARIABLES TOO TAD INIT /GET PAGE ADDRESS TAD DELTA /POINT TO NEWREC DCA S123A /TEMP USE S123A AS POINTER CMA DCA I S123A /INITIALIZE TO -1 FOR INIT NAKS ISZ S123A /POINT TO BUFPTR TAD S123A DCA BPTRA /CREATE LINK TO BUFPTR ISZ S123A /POINT BUF123 TAD S123A DCA B123A /CREATE LINK TO BUF123 ISZ S123A /POINT TO SAVPTR TAD S123A DCA SPTRA /CREATE LINK TO SAVPTR ISZ S123A /FINALLY BECOMES LINK TO SAV123 JMP I INIT /RETURN /*** EXIT ************************************************* /RECEIVED THE EOT. INSTALL A ^Z AND FILL THE REST OF THE /BUFFER WITH 0'S, THEN INDICATE THE END OF FILE VIA A SOFT- /ERROR RETURN (RETURN1 WITH AC=0). /(SEE DEC-S8-OSSMB-A-D PAGE 5-1 AND 5-3 ITEM 11) /NOTE THAT THE BUFFER CAN'T BE COMPLETELY FULL WHEN THE EOT /ARRIVES, BECAUSE WE HAD NO IDEA THAT THE NEXT RECORD WOULD /IN FACT BE THE EOT - SO MUST HAVE ROOM FOR A RECORD. / /ON ENTRY: / DATA FIELD IS FIELD 0 (WHERE WE ARE RUNNING) / AC=0 / BUFADR = -(LAST BUFFER ADDRESS+1) / BUFPTR = NEXT BUFFER ADDRESS TO WRITE / (SPECIAL CASE IF BUF123=-1, FOR BYTE 3) / BUF123 = NEXT BYTE 1-2-3 POSITION / 0 FOR BYTE 1 / 1 FOR BYTE 2 / -1 FOR BYTE 3 (MEANING THE ^Z MUST BE SPLIT) / BPTRA POINTS TO BUFPTR IN FIELD 0 / B123A POINTS TO BUF123 IN FIELD 0 /********************************************************** GOTEOT, TAD I BPTRA /GET BUFPTR, THE FINAL ADDRESS DCA BPTRA /..MOVED TO THIS PAGE TAD I B123A /WHICH 1-OF-3 BYTES? XMCDF2, HLT /(GETS OVERWRITTEN) /SET DATA FIELD FOR BUFFER /AC=0 FOR BYTE 1, 1 FOR BYTE 2 NEXT, -1 FOR BYTE3 /AS THE NEXT BUFFER 8-BIT BYTE. IF THE NEXT BYTE /IS BYTE 3, THEN THE TERMINATING ^Z MUST BE SPLIT /ACROSS THE LAST TWO 12-BIT BUFFER WORDS. SMA CLA /IS IT -1? JMP GEOT1 /N: BYTE 1 OR 2 STA /-1 TAD BPTRA /AC=-1: BACK UP TO WORD 1 DCA TEMP1 TAD I TEMP1 /INSTALL CTLZ<0:3> TAD CTLZH /IN BITS <0:3> DCA I TEMP1 TAD I BPTRA /GET LAST BUFFER WORD TO INSTALL /..CTLZ<4:7> IN BITS <0:3> TAD CZLMCZ /THIS WILL BECOME CTLZL COMBINED /..WITH THE LAST BYTE OF DATA /JUMP HERE IF BYTE 1 OR BYTE 2 IS NEXT: /INSTALL A ^Z IN THE BYTE 1 OR BYTE 2 LOCATION GEOT1, TAD CTLZ /INSTALL ^Z THERE /AC=CTLZ OR CTLZL COMBINED WITH THE LAST BYTE OF DATA. /INSTALL THIS IN THE BUFFER, AND FILL THE REST OF THE /BUFFER WITH 0'S. CLRLUP, DCA I BPTRA /0 ISZ BPTRA /NEXT ADDRESS C0070, 0070 /A HARMLESS "AND" INSTRUCTION /SINCE BPTRA CAN WRAP TAD BPTRA /NEXT ADDRESS TO WRITE TAD BUFADR /-(LAST BUFFER ADDRESS +1) SZA CLA /END YET? JMP CLRLUP /N: KEEP CLEARING /RETURN1 FROM HANDLER, WITH AC=0 INDICATING EOF JMP EOTEXT /RETURN1 FROM HANDLER /*********************** /* HANDLER ENTRY POINT * /*********************** XMR, XMRVERSION /THIS CODE'S VERSION NUMBER /..IN ITS RETURN ADDRESS SLOT /------------------------------- /PARSE HANDLER INPUT PARAMETERS /(SEE DEC-S8-OSSMB-A-D PAGE 5-1) /------------------------------- STL CLA RAR /AC=4000 TAD I XMR /GET FUNCTION WORD, R/W BIT TO LINK AND BWCMSK /EXTRACT MAX # OF RECORDS TO TRANSFER BSW /BITS 1-5 INTO BITS 7-11 DCA XRECCNT /OS/8 128-WORD RECORD COUNT FOR NOW RDF /FIND OUT THE USER'S INSTR. FIELD TAD CIFCDF /FORM OUR EXIT CIF CDF DCA RSTFLD /STORE AWAY FOR EXIT ROUTINE TAD I XMR /GET FUNCTION WORD AGAIN AND C0070 /ISOLATE FIELD OF BUFFER TAD CDFOP /FORM CDF TO BUFFER'S FIELD DCA XMCDF1 /STORE WHERE IT WILL BE USEFUL TAD XMCDF1 /..TWO PLACES DCA XMCDF2 ISZ XMR /POINT TO BUFFER ADDRESS TAD I XMR /GET BUFFER ADDRESS DCA BUFADR /AND SAVE IT IN PAGE 1 ISZ XMR /POINT TO OS/8 RECORD NUMBER SZL CLA /LINK=1 MEANS OUTPUT JMP ERREXT /OUTPUT IS AN ERROR: ERROR RETURN /------------------------------------------------------ /SET UP FOR NEW TRANSFER IF STARTING WITH 0S/8 RECORD 0 /(SEE DEC-S8-OSSMB-A-D PAGE 5-1 ITEM 2) /ON ENTRY: / AC=0 / L=0 / XMT POINTS TO OS/8 RECORD NUMBER /------------------------------------------------------ TAD I XMR /GET OS/8 RECORD NUMBER CDFOP, CDF 0 /THE FOLLOWING OPS ARE IN FIELD 0 /ALSO PROTOTYPE FOR CDF NN SNA CLA /RECORD 0 MEANS INITIALIZE 1ST JMS INIT IRET, /-------------------------------------------------- /INITIALIZE VARIABLES FOR EACH CALL TO THIS HANDLER /-------------------------------------------------- TAD BUFADR DCA I BPTRA /PUT BUFFER ADDRESS INTO PAGE 2 DCA I B123A /INITIALIZE 1-2-3 BYTE COUNTER /------------------------------------------------- /COMPUTE AND REMEMBER THE LAST BUFFER ADDRESS. /ALSO TEST XRECCNT FOR BITS 1-5 & 9-11 ALL 0, /WHICH MEANS CLOSE. (WE DON'T ACTUALLY CHECK /BITS 9-11 HERE. ONLY 0 IS MEANINGFUL ANYWAY.) /ON ENTRY: / AC=0 / XRECCNT<7:11> = # OF 128-WORD RECORDS IN BUFFER / BUFADR = FIRST BUFFER ADDRESS /ON EXIT: / AC=0 / BUFADR = -(LAST BUFFER ADDRESS+1) /------------------------------------------------- TAD XRECCNT /NUMBER OF 128-WORD RECORDS SNA JMP NRMEXT /XRECCNT=0 MEANS CLOSE (DO NOTHING) BSW /BITS <7:11> INTO BITS <1:5> CLL RAL /..AND THEN INTO <0:4>, TO BE THE /..NUMBER OF 12-BIT WORDS IN BUFFER TAD BUFADR /+ 1ST BUFFER ADDRESS CIA /MAKE IT NEGATIVE FOR COMPARING DCA BUFADR /-(LAST BUFFER ADDRESS+1) /----------------------------------------------------------- /COMPUTE XMODEM RECORD COUNT = -(OS/8 RECORD COUNT)*3/2 /ALSO CHECK FOR ILLEGAL ODD NUMBER OF OS/8 RECORDS. /(ONE OS/8 BLOCK COMPRISES TWO 128-WORD RECORDS) /(SEE DEC-S8-OSSMB-A-D PAGE 4-3 ITEM 5 AND PAGE 5-3 ITEM 12) /ON ENTRY: / AC=0 / XRECCNT=NUMBER OF 0S/8 128-WORD RECORDS /ON EXIT: / AC=0 / XRECCNT=-(NUMBER OF 128-BYTE XMODEM RECORDS) /----------------------------------------------------------- TAD XRECCNT /OS/8 128-WORD RECORD COUNT CLL RAR /DIVIDE BY 2, REMAINDER TO L SZL JMP ERREXT /ODD IS AN ERROR: FATAL ERROR RETURN TAD XRECCNT /(OS/8 RECORD COUNT)*3/2 CIA /MAKE IT NEGATIVE FOR COUNTER DCA XRECCNT /--------------------------------------------------- /RECEIVE AND VALIDATE AN XMODEM RECORD /ON ENTRY: / ACHCHR=NAK THE FIRST TIME, ACK THEREAFTER / PRVREC=PREVIOUS XMODEM RECORD NUMBER / BUFPTR=ADDRESS OF NEXT BUFFER WORD / BUF123=STARTING 8-BIY BYTE LOCATION / 0 FOR 1ST BYTE / 1 FOR 2ND BYTE / -1 FOR 3RD BYTE /--------------------------------------------------- RECLUP, /------------------------------------- /SAVE BUFFER LOCATION FOR XMODEM RETRY /ON ENTRY: / AC=0 /------------------------------------- TAD I BPTRA DCA I SPTRA TAD I B123A DCA I S123A /------------------------------------------------------ /GO TO PAGE 2 TO RECEIVE THE ENTIRE NEXT XMODEM RECORD. /GETREC RETURNS WITH DATA FIELD=0 /------------------------------------------------------ GOGETR, /ENTRY FOR IGNORING REPEATED REC XMCDF1, HLT /(GETS OVERWRITTEN) /SET DATA FIELD FOR BUFFER JMS GETREC /GET RECORD DATA JMP ERREXT /RETURN1 MEANS FATAL ERROR JMP GOTEOT /RETURN2 MEANS EOT RECEIVED /RETURN3 MEANS GOOD RECORD /AC=NEW RECORD NUMBER /----------------------------------------- /GOT AN ERROR-FREE RECORD. SEE IF IT'S THE /RIGHT RECORD NUMBER. ABORT IF NOT. /ON ENTRY: / AC=NEWREC > 0 /----------------------------------------- CIA /SUBTRACT NEWREC TAD PRVREC /..FROM PREVIOUS RECORD SNA /SAME RECORD? JMP GOGETR /Y: IGNORE IT /AC=PRVREC - NEWREC <> 0 IAC /TEST AND BMASK1 /BOTTOM 8 BITS ONLY SZA CLA JMP ERREXT /LOST RECORD FATAL ERROR /CORRECT (NEXT SEQUENTIAL) RECORD RECEIVED WITHOUT ERRORS. /UPDATE PRVREC ISZ PRVREC /WON'T WRAP UNTIL 4K RECORDS... BMASK1, 0377 /BYTE MASK /ALSO HARMLESS "AND" INSTRUCTION /SINCE PRVREC COULD POSSIBLY WRAP /MORE ROOM FOR RECORDS? LOOP TO GET THEM /AC=0 ISZ XRECCNT /ROOM FOR ANOTHER? JMP RECLUP /----------------------------------------------------------- /EXITS FROM HANDLER / NRMEXT IS THE NORMAL EXIT FOR A FULL BUFFER / ON ENTRY: / AC=0 / ON EXIT VIA RETURN2 / AC=0 / ERREXT INIDCATES A FATAL ERROR: / -HANDLER CALL FOR OUTPUT / -HANDLER CALL WITH ODD NUMBER OF 128-WORD RECORDS / -TIMEOUT WAITING FOR THE SENDER / -A LOST XMODEM RECORD / ON EXIT VIA RETURN1 / AC=-1 / EOTEXT INDICATES END OF FILE; THE EOT WAS ENCOUNTERED / ON ENTRY: / AC=0 / ON EXIT VIA RETURN1 / AC=0 / A ^Z HAS BEEN INSALLED IN THE BUFFER AFTER THE LAST / WORD, AND THE REMAINDER OF THE BUFFER IS ZEROED. /----------------------------------------------------------- NRMEXT, ISZ XMR /POINT TO NORMAL RETURN2 JMP EOTEXT /SKIP OVER ERROR ERREXT, STA /AC=-1 FOR FATAL ERROR EOTEXT, ISZ XMR /FATAL ERROR OR EOF RETURN1 RSTFLD, HLT /(GETS OVERWRITTEN) RESTORE FIELDS JMP I XMR /AND RETURN /*** SUBROUTINE ************************************** /RECEIVE A COMPLETE XMODEM RECORD, WRITING ITS DATA /INTO THE OS/8 BUFFER, WITH RETRIES ON CHECKSUM ERRORS /AND TIMEOUTS ON RECEIVED CHARACTERS / /THIS SUBROUTINE CROSSES THE PAGE BOUNDARY / /ON ENTRY: / AC=0 / BUFPTR=ADDRESS OF NEXT BUFFER WORD / BUF123=0 FOR BYTE 1 / 1 FOR BYTE 2 / -1 FOR BYTE 3 / SAVPTR=BUFPTR / SAV123=BUF123 / NEWREC = 0 ON FIRST CALL /ON EXIT: / RETURN1 (FATAL TIMEOUT): / AC=0 / DATA FIELD IS 0 / RETURN2 (EOT RECEIVED): / AC=0 / BUF123=NEXT 1-OF-3 POSITION: / 0: BYTE 1, 1: BYTE 2, -1: BYTE 3 / IF BUF123=0: BUFPTR=NEXT BUFFER ADDRESS TO WRITE / OTHERWISE BUFPTR=LAST BUFFER ADDRESS WRITTEN / DATA FIELD IS 0 / RETURN3(SUCCESS): / AC=0 / NEWREC=RECEIVED RECORD NUMBER / BUF123=NEXT 1-OF-3 POSITION: / 0: BYTE 1, 1: BYTE 2, -1: BYTE 3 / IF BUF123=-1, BUFPTR=LAST BUFFER ADDRESS WRITTEN / OTHERWISE BUFPTR=NEXT BUFFER ADDRESS TO WRITE / DATA FIELD IS 0 /***************************************************** *376 /MAKE ALIGNMENT MAGIC GETREC, 0 /RETURN ADDRESS TAD GETREC /RETURN ADDRESS /---PAGE BREAK HERE--- DCA GRRET /CREATE RETURN ADDRESS /---------------------------------------------- /ACK THE PREVIOUS RECORD (OR NAK IF ERROR) /ON ENTRY: / AC=0 / NEWREC<0 TO START THE TRANSFER (WITH NAKS) /ON ENTRY AT XRETRY: / AC=0 /---------------------------------------------- TAD NEWREC /1ST RECORD? SPA CLA /<0 MEANS YES, SO SEND NAK XRETRY, TAD NAKMAK /Y: SEND NAK INSTEAD JMS SNDACK /SEND NAK OR ACK /BACK UP IF THIS IS A RETRY TAD SAVPTR /BACK UP THE BUFFER POINTERS DCA BUFPTR TAD SAV123 DCA BUF123 /------------------------------- /SET UP FOR RECEIVING ONE RECORD /------------------------------- DCA CHKSUM /INITIALIZE CHECKSUM TAD XBYTES /-BYTES PER XMODEM RECORD DCA XBCOUNT /SET UP BYTE COUNT /-------------------------------- /GET THE RECORD HEADER / RECORD HEADER: / SOH / RECORD NUMBER / COMPLEMENTED RECORD NUMBER /ON ENTRY: / AC=0 /-------------------------------- TAD SOHTO /SOH TIMEOUT VALUE DCA RXTMRH TAD NEWREC /FIRST RECORD (NEWREC<0)? JMS TPIN /GET TRANSFER PORT BYTE WITH TIMEOUT TAD NSOH /RECEIVED AN SOH? (-1 IF TIMEOUT) SNA JMP GOTSOH /NOT AN SOH. WAS IT THE EOT? /WE WILL FALL THROUGH HERE ON INITIAL NAK TIMEOUT TAD SOHMEOT /EOT? SNA CLA JMP GOTEOH /Y: DONE WITH TRANSFER /NEITHER SOH NOR EOT, OR FAILED RECORD NUMBER. IT IS /GARBAGE. WAIT UNTIL LINE IS QUIET FOR 1 SECOND, AND /THEN SEND A NAK TO TRY AGAIN PURGE, STA /TELL TPIN TO RETURN HERE IF TIMEOUT JMS TPIN /RETURN HERE IF TIMEOUT SMA CLA /<0 MEANS TIMEOUT JMP PURGE />=0 NO TIMEOUT, EAT MORE GARBAGE JMP XRETRY /LINE IS QUIET, TRY AGAIN /Y: ACK THE EOT AND RETURN GOTEOH, JMS SNDACK JMP GRRET2 /RETURN2 /GOT AN SOH. NOW GET AND VALIDATE THE RECORD NUMBER /AC=0 HERE GOTSOH, JMS TPIN /GET RECORD NUMBER DCA NEWREC /AC=RECORD NUMBER JMS TPIN /GET INVERTED RECORD NUMBER IAC /AC=NEGATIVE RECORD NUMBER TAD NEWREC /COMPARE TO POSITIVE AND BMASK2 /8-BITS PLEASE SZA CLA /CORRECT INVERTED RECORD NUMBER? JMP PURGE /N: PURGE GARBAGE /--------------------------------------------------------- /LOOP TO RECEIVE THE NEXT 128 8-BIT XMODEM BYTES, AND SAVE /THEM IN THE NEXT 128*2/3 12-BIT BUFFER WORDS, COMPUTING /THE CHECKSUM AS WE GO. EACH 3 XMODEM BYTES BECOMES TWO /12-BIT BUFFER WORDS, ENCODED AS FOLLOWS /(DEC-S8-OSSMB-A-D PAGE 5-3, ITEM 11): / / 0 3 4 11 / ------------ ---------------------------- / WORD 1 |BYTE 3 <0:3>| BYTE 1 <0:7> | / ------------ ---------------------------- / WORD 2 |BYTE 3 <4:7>| BYTE 2 <0:7> | / ------------ ---------------------------- /ON ENTRY: / AC=0 / CHKSUM=0 / XBCOUNT=-128 / BUFPTR=ADDRESS OF NEXT BUFFER WORD / BUF123=0 FOR BYTE 1 / 1 FOR BYTE 2 / -1 FOR BYTE 3 /ON EXIT: / (SEE ABOVE COMMENT) /--------------------------------------------------------- XRDLUP, JMS TPIN /GET BYTE INTO AC AND RXBYTE TAD CHKSUM DCA CHKSUM /ENQUEUE RXBYTE, PACKING IT INTO THE BUFFER /THE WAY OS/8 LIKES IT TAD BUF123 ISZ BUF123 /WHICH 8-BIT BYTE NEXT? JMP XRD1 /WAS -1: ENQUEUE AS BYTE 3 /BUF123 WAS -1: ENQUEUE RXBYTE AS BYTE 3, SPLIT ACROSS 2 /BUFFER WORDS. SINCE THIS MIGHT BE THE FIRST BYTE OF A /RETRIED XMODEM RECORD, WE CAN'T ASSUME THAT THE T0P 4 /BITS OF THESE 2 BUFFER WORDS ARE 0. /AC=-1 HERE TAD BUFPTR /DECREMENT BUFPTR DCA TEMP2 /POINT TO 1ST OF 2 BUFFER WORDS TAD I TEMP2 /CLEAR WORD 1<0:3> AND BMASK2 DCA I TEMP2 TAD I BUFPTR /CLEAR WORD 2<0:3> AND BMASK2 DCA I BUFPTR TAD RXBYTE /MOVE RECEIVED BYTE<0:7> CLL RTL /..FROM RXBYTE<4:11> CLL RTL /..TO RXBYTE<0:7> AND C7400 /AC<0:3>=RECEIVED BYTE<0:3> TAD I TEMP2 /COMBINE INTO 1ST BUFFER WORD DCA I TEMP2 TAD RXBYTE /NOW FOR RECEIVED BYTE<4:7> BSW RTL /..INTO BITS <0:3> AND C7400 /AC<0:3>=RECEIVED BYTE<4:7> TAD I BUFPTR /COMBINE INTO 2ND BUFFER WORD DCA RXBYTE /AND A=0 NOW /AC=0 FOR BYTE 1 OR BYTE 3 /AC=1 FOR BYTE 2, AND BUF123=2 (WHICH MUST BE SET TO -1) /WORD TO WRITE I IN RXBYTE XRD1, CLL CML CMA IAC /L=0 AND AC=0 IF BYTE 1 OR BYTE 3 /L=1 AND AC=-1 IF BYTE 2 SZA /BYTE 2? DCA BUF123 /WAS BYTE 2: BUF123=-1 TAD RXBYTE DCA I BUFPTR /ENQUEUE BYTE 1 OR 2 SNL /DON'T BUMP BUFPTR IF BYTE 2 ISZ BUFPTR /POINT TO NEXT 12-BIT WORD SOHTO, /8-SECOND TIMEOUT TO RECEIVE SOH C7400, 7400 /HARMLESS "NOP" INSTRUCTION /IN CASE BUFFER WRAPS /NEXT XMODEM BYTE, UNLESS WE'RE DONE XRD4, ISZ XBCOUNT JMP XRDLUP /LOOP FOR ALL DATA WORDS /GET AND VERIFY THE RECORD CHECKSUM JMS TPIN /GET CHECKSUM AT END OF RECORD CIA TAD CHKSUM /COMPARE TO COMPUTED CHECKSUM AND BMASK2 /STRIP THE HIGH BITS SZA CLA /CHECKSUM MATCH? JMP XRETRY /N: NAK IT AND TRY AGAIN TAD NEWREC /NEW RECORD NUMBER FOR RETURN3 /FALL INTO RETURN3 FOR SUCCESSFUL RETURN /------------------------------------- /RETURNS FROM GETREC WITH DATA FIELD=0 /ON ENTRY: / AC=NEWREC FOR RETURN3, 0 OTHERWISE / GRRET POINTS TO RETURN1 FROM GETREC /------------------------------------- ISZ GRRET /RETURN3 (SUCCESS) GRRET2, ISZ GRRET /RETURN2 (EOT RECEIVED) GRRET1, /RETURN1 (FATAL ERROR) CDF 0 /BACK TO FIELD 0 JMP I GRRET GRRET, 0 /PAGE-JUMPING RETURN ADDRESS /*** SUBROUTINE ********************** / SEND NAK OR ACK TO THE TRANSFER PORT /ON ENTRY: / AC=0 TO SEND AN ACK / AC=NAKMAK TO SEND NK /ON EXIT: / AC=0 /TRASHES CHKSUM /************************************* CHKSUM, /(REUSE) XMODEM CHECKSUM SNDACK, 0 TAD ACK /FORM ACK OR NAK DTPTSF /DEVICE READY? JMP .-1 /N: KEEP WAITING DTPTLS /SEND AC TO DEVICE ABORT, /EXIT TO MONITOR AT 7600 IN PAGE 0 XBYTES, -200 /7600=-200=-BYTES PER XMODEM RECORD /ALSO ALTERNATE "CLA" JMP I SNDACK /RETURN /*** SUBROUTINE *************************************** /RECEIVE A TRANSFER PORT BYTE WITH TIMEOUT AND TEST FOR /USER ^C. (SEE DEC-S8-OSSMB-A-D OS8 PAGE 5-2 ITEM 4) /SOME RXTMRH TIMEOUT VALUES: / 1-SECOND TIMEOUT: 7741 / 2-SECOND TIMEOUT: 7700 / 5-SECOND TIMEOUT: 7545 / 8-SECOND TIMEOUT: 7400 / 10-SECOND TIMEOUT: 7312 / 30-SECOND TIMEOUT: 6136 / 60-SECOND TIMEOUT: 4274 /ON ENTRY: / AC>=0 IF TIMEOUT ABORTS / AC<0 IF TIMEOUT RETURNS / RXTMRH=TIMEOUT VALUE (>0) / RXTMRL IS RANDOM. (WHO CARES?) /ON SUCCESS RETURN: / AC=RXBYTE=RECEIVED BYTE >=0 / RXTMRH=DATATO /ON TIMEOUT RETURN / AC=AC VALUE FROM ENTRY / RXBYTE<0 /HARD JUMP TO GRRET1 WITH AC=0 IF NOT TIMEOUT RETURN /TRASHES TEMP2 /****************************************************** TEMP2, /(REUSE) TPIN, 0 /RETURN ADDRESS DCA RXBYTE /<0 MEANS RETURN ON ERROR /7.6 US PER INNER-LOOP PASS. /AC=0 THROUGHOUT THE LOOP UNTIL A BYTE ARRIVES /TEST FOR TRANSFER PORT BYTE, KEEP WAITING IF NOT, /WITH TIMEOUT TPILUP, DTPKSF /(2,6)TEST FOR BYTE JMP TPIWAT /(1.2)WAIT FOR INPUT DTPKRB /GET TRANSFER PORT BYTE DCA RXBYTE /STASH IT FOR A MOMENT TPIRET, TAD DATATO /RESET TIMEOUT TIMER DCA RXTMRH TAD RXBYTE /RECOVER BYTE FOR RETURN JMP I TPIN /RETURN WITH AC=BYTE /NO BYTE YET. BUMP TIMER AND CHECK FOR TIMEOUT /TEST FOR ^C FROM USER, AND ABORT FROM GETREC IF SO. TPIWAT, ISZ RXTMRL /(2.6)INNER LOOP JMP TPILUP /(1.2) /EVERY 32 MSEC, TEST FOR ^C FROM USER, /AND ABORT FROM GETREC IF SO. KRS /READ STATIC FROM KEYBOARD TAD NCTRLC /^C ABORT? SNA CLA JMP I ABORT /YES - EXIT TO MONITOR /BUMP HIGH TIMER WORD, TEST FOR TIMEOUT. ISZ RXTMRH /TIMEOUT? JMP TPILUP /N: KEEP WAITING /TIMEOUT. ABORT OR RETURN? /AC=0 TAD RXBYTE /RETURN ON TIMEOUT? DATATO, SMA CLA /OPCODE=7700, FOR 2-SECOND TIMEOUT JMP GRRET1 /N: ABORT GETREC VIA ITS RETURN1 JMP TPIRET /Y:TIMEOUT RETURN, AC<0 /CONSTANTS BMASK2, 0377 /BYTE MASK ACK, 6 /XMODEM ACK NAKMAK, 25-6 /XMODEM NAK - XMODEM ACK M0001, NSOH, -1 /-XMODEM SOH NCTRLC, /-ASCII ^C=-3 SOHMEOT,-3 /XMODEM SOH - XMODEM EOT = 1-4 = -3 /VARIABLES XBCOUNT,0 /-XMODEM BYTE COUNT RXBYTE, 0 /RECEIVED BYTE RXTMRH, 0 /TIMEOUT TIMER HIGH WORD RXTMRL, 0 /TIMEOUT TIMER LOW WORD /THESE 5 MUST STAY IN THIS ORDER NEWREC, 0 /NEW RECORD NUMBER BUFPTR, 0 /POINTER INTO OS/8 BUFFER BUF123, 0 /3-BYTE COUNTER SAVPTR, 0 /BUFPTR FOR XMODEM RETRY SAV123, 0 /BUF123 FOR XMODEM RETRY $