FLTPT IDT TITL 'T.I. 99/4A FLOATING POINT & CASSETTE' * * HIGH ROM >0FF4 TO >1FFF * * * MEMORY ALLOCATION: * 0 - >1FFF INTERNAL ROM * >2000 - >3FFF MEMORY EXPANSION PERIPHERAL * >4000 - >5FFF PERIPHERAL EXPANSION ( DECODED TO I/O CON) * >6000 - >7FFF CARTRIDGE ROM/RAM (GROM CONNECTOR) * >8000 - >83FF INTERNAL RAM (ONLY 8300 - 83FF USED) * >8300 - >83FF SCRATCH PAD RAM * >8400 SOUND * >8800 VDP READ DATA * >8802 VDP READ STATUS * >8C00 VDP WRITE DATA * >8C02 VDP WRITE ADDRESS * >9000 SPEECH READ * >9400 SPEECH WRITE * >9800 GROM READ DATA * >9802 GROM READ ADDRESS * >9C00 GROM WRITE DATA * >9C02 GROM WRITE ADDRESS * >A000 - >FFFF MEMORY EXPANSION PERIPHERAL * * CRU ALLOCATION * 0000-0FFE INTERNAL USE * 1000-10FE UNASSIGNED * 1100-11FE DISK CONTROLLER CARD * 1200-12FE MODEMS * 1300-13FE RS232 (PRIMARY) * 1400-14FE UNASSIGNED * 1500-15FE RS232 (SECONDARY) * 1600-16FE UNASSIGNED * 1700-17FE HEX-BUS * 1800-18FE THERMAL PRINTER * 1900-19FE EPROM PROGRAMMER * 1A00-1BFE UNASSIGNED * 1C00-1CFE VIDEO CONTROLLER CARD * 1D00-1DFE IEE 488 CONTROLLER CARD * 1E00-1EFE UNASSIGNED * 1F00-1FFE P-CODE CARD * * 9901 CRU BIT ALLOCATIONS * 0 CONTROL * 1 EXTERNAL INTERRUPT * 2 VDP VERT. SYNC INTERRUPT * 3 9901 INTERNAL TIMER INTERRUPT * KEYBOARD '=' LINE * JOYSTICK 'FIRE' * 4 KEYBOARD 'SPACE' LINE * JOYSTICK 'LEFT' * 5 KEYBOARD 'ENTER' LINE * JOYSTICK 'RIGHT' * 6 KEYBOARD '0' LINE * JOYSTICK 'DOWN' * 7 KEYBOARD 'FCTN' LINE * JOYSTICK 'UP' * 8 KEYBOARD 'SHIFT' LINE * 9 KEYBOARD 'CTRL' LINE * 10 KEYBOARD 'Z' LINE * 11 NOT USED AS INTERRUPT * 12 RESERVED, HIGH LEVEL * 13-15 NOT USED AS INTERRUPT * * 16 RESERVED * 17 RESERVED * 18 BIT 2 OF KEYBOARD SELECT * 19 BIT 1 OF KEYBOARD SELECT * 20 BIT 0 (MSB) OF KEYBOARD SELECT * 21 KEYBOARD ALPHA LOCK * 22 CASSETTE CONTROL 1 (MOTOR CONTROL) * 23 CASSETTE CONTROL 2 (MOTOR CONTROL) * 24 AUDIO GATE * 25 MAG TAPE OUT * 26 RESERVED * 27 MAG TAPE INPUT * 28-31 NOT USED IN I/O MAPPING * ************************************* * DEFINITIONS FOR BASIC INTERPRETER * DEF CSNGR,SADD,SCOMPB,SSUB,SDIV,CFI,SMULT * * DEFINITIONS FOR GPL INTERPRETER * DEF XTAB,WRITE,TIMER,VERIFY,READ * * REFERENCES INTO GPL ROM FROM FPT ROM * HX0020 EQU S+>0032 NEXT EQU S+>0070 SROM EQU S+>0AC0 SGROM EQU S+>0B24 * * REFERENCES INTO BASIC ROM FROM FPT ROM * SYMB EQU S+>1648 SMBB EQU S+>164E ASSGNV EQU S+>1642 FBSYMB EQU S+>15D6 VPUSHG EQU S+>163C VPOP EQU S+>1F2E PGMCH EQU S+>1868 POPSTK EQU S+>1FA8 GETCH EQU S+>1FC8 GETCHG EQU S+>1FDA * * EQUATES * VWDOFF EQU -2 VDP WRITE DATA OFFSET (FROM R15) GRAOFF EQU 2 GROM READ ADDRESS OFFSET (FROM R13) GWDOFF EQU >400 GROM WRITE DATA OFFSET (FROM R13) VRSOFF EQU ->400 VDP READ STATUS OFFSET (FROM R15) GWAOFF EQU >402 WRITE ADDRESS OFFSET(FROM R13) VRDOFF EQU ->402 VDP READ DATA OFFSET (FROM R15) SGCADR EQU >8400 SOUND CHIP * * RAM EQUATES * PAD EQU >8300 FAC EQU PAD+>4A FDVSR EQU FAC+10 DIVISOR STORE DURING DIVISION ARG EQU PAD+>5C PLAYER EQU PAD+>74 SIGN EQU PAD+>75 EXP EQU PAD+>76 STATUS EQU PAD+>7C ERRCD EQU STATUS GROMFG EQU PAD+>89 * WKSC EQU PAD+>C0 INT. 1 WORKSPACE WKSE EQU PAD+>E0 MAIN WORKSPACE R0LSB EQU WKSE+R0+R0+1 R1LSB EQU WKSE+R1+R1+1 R2LSB EQU WKSE+R2+R2+1 R3LSB EQU WKSE+R3+R3+1 R6LSB EQU WKSE+R6+R6+1 R7LSB EQU WKSE+R7+R7+1 R8LSB EQU WKSE+R8+R8+1 R9LSB EQU WKSE+R9+R9+1 R10LSB EQU WKSE+R10+R10+1 * VDPREG EQU >8000 * GR EQU >9800 GROM READ (DATA) VRD EQU >8800 VDP READ DATA VRS EQU >8802 VDP READ STATUS VWD EQU >8C00 VDP WRITE DATA VWA EQU >8C02 VDP WRITE ADDRESS * * MISC. EQUATES HIBYTE EQU >0100 OFERR EQU >0100 OVERFLOW ERROR CODE DZERR EQU >0200 DIVIDE BY ZERO ERROR CODE SGNBIT EQU >8000 * S EQU 0 AORG S+>0D1A * FLTTAB DATA 0,ROUND,ROUNU,STEXIT,OVEXP,OV,FADD,FSUB DATA FMULT,FDIV,FCOMP,SADD,SSUB,SMULT,SDIV,SCOMP * * FLOATING COMPARE * * = BR TABLE FCOMP MOV R11,R10 LI R3,STEX01 LOAD EXIT FOR GPL COMPARE JMP FCOMP1 * * STACK COMPARE ENTRY FOR BASIC * * = BL SCOMPB MOV R11,R3 DON'T USE STEX01 FOR BASIC JMP SCOMP1 * * STACK COMPARE ENTRY FOR GPL * SCOMP LI R3,STEX01 EXIT FOR GPL COMPARE MOV R11,R10 SCOMP1 BL @POPSTK STACK COMPARE FCOMP1 LI R7,ARG LI R5,FAC C *R7,*R5+ COMPARE THE 1ST WORDS JNE FCOMRT DONE COMPARING IF NOT EQ MOV *R7+,R6 SIGN OF NUMBERS JEQ FCOMRT NUMBERS ARE ZERO AND EQ JGT FCOM01 BOTH NEGATIVE MOV R5,R6 MOV R7,R5 MOV R6,R7 FCOM01 C *R7+,*R5+ BOTH +VE JNE FCOMRT CONTINUE COMP'G UNTIL UNEQUAL C *R7+,*R5+ OR END OF NUMBER JNE FCOMRT C *R7,*R5 THE LAST ENVELOPE! FCOMRT B *R3 EXIT AS SPECIFIED * * FLOATING ADDITION AND SUBTRACTION * THE TOP 2 STACK ELEMENTS ARE POPPED, ADDED (OR SUBT'D) * AND THE RESULT PUSHED ONTO THE STACK * = BL *R2 SSUB MOV R11,R10 SAVE RTN ADR BL @POPSTK STACK SUBTRACTION MOV R10,R11 FSUB NEG @FAC NEGATE THE RH ARGUMENT FADD MOV R11,R10 SAVE RTN JMP FADD1 * = BL *R2 SADD MOV R11,R10 SAVE RTN BL @POPSTK FADD1 MOV @ARG,R7 IS ARG. ZERO? JEQ FADD02 YES, NO CHANGE TO FAC MOV @FAC,R8 IS FAC ZERO? JNE FADD03 NO, GO ADD FAC TO ARG LI R1,-8 YES, MOVE ARG TO FAC FADD01 MOV @ARG+8(R1),@FAC+8(R1) INCT R1 JLT FADD01 FADD02 B @STEX EXIT TO GLI WITH STATUS FADD03 XOR R8,R7 SIGN DIFFERENCE ABS @FAC TAKE ABSOLUTE VAL OF FAC ABS @ARG AND ARG LI R3,-8 ENSURE THAT THE LARGEST NO. * IS IN FAC FADD20 C @FAC+8(R3),@ARG+8(R3) JGT FADD05 TRUE INITIALLY JLT FADD21 NEED TO SWAY THIS WORD & FOLLOWING INCT R3 JNE FADD20 COMPARE ALL 4 WORDS JMP FADD05 FAC = ARG FADD21 MOV @ARG+8(R3),R0 MOV @FAC+8(R3),@ARG+8(R3) MOV R0,@FAC+8(R3) INCT R3 JNE FADD21 CONTINUE THE SWAP XOR R7,R8 FADD05 CLR R5 HANDY ZERO CLR @FAC+8 CLEAR GUARD DIGITS FOR FAC CLR @ARG+8 AND ARG MOVB R8,@SIGN SAVE RESULT SIGN CLR R6 CLEAR HIGH BYTE OF EXP DIFF MOVB @FAC,@R6LSB FAC EXP TO R6 LSB MOV R6,@EXP USE FAC EXP AS RESULT EXP MOVB R5,@FAC CLEAR HIGH BYTE OF FAC TO CHECK * FOR OVERFLOW SB @ARG,@R6LSB SUBTRACT SMALLER EXPONENT CI R6,7 SMALLER NUMBER TOO SMALL TO * AFFECT THE SUM? JGT FADD15 YES, RTN WITH LARGER NO. IN FAC MOV R6,R0 EXPONENT DIFFERENCE LI R8,HIBYTE 1 FOR BYTE OPERATIONS LI R9,100*HIBYTE 100 FOR BYTE OPERATIONS LI R5,FAC+9 POINTER TO LOW BYTE OF BIG NO. LI R6,ARG+9 AND LOW BYTE OF SMALL NO. S R0,R6 ADJ ARG POINTER TO ALIGN RADIX MOV R0,R4 ADD/SUB LOOP COUNT IS AI R4,-9 BYTES LEFT IN SMALL NUMBER MOV R7,R1 2 NO'S HAVE SAME SIGN? JLT FADD11 NO, SUB THEN, YES ADD THEM FADD06 AB *R6,*R5 ADD A BYTE OF SMALL TO LARGER CB *R5,R9 IF SUM LT RADIX JL FADD07 THEN CONTINUE TO NEXT BYTE SB R9,*R5 SUBTACT RADIX FROM THIS BYTE AB R8,@-1(R5) AND ADD CARRY TO NEXT BYTE FADD07 DEC R5 TO NEXT HIGHER BIG NO. BYTE DEC R6 AND NEXT HIGHER SMALL BYTE INC R4 IF NOT ALL SIGN IF BYTES OF SMALL JLT FADD06 ADDED, THEN CONTINUE JMP FADD09 ELSE PROPAGATE CARRY FADD08 DEC R5 WAS LARGER, POINT TO NEXT BYTE AB R8,*R5 ADD CARRY TO NEXT BYTE FADD09 SB R9,*R5 SUB RADIX FROM NEXT BYTE JGT FADD08 DONE IF REACHED ONE BYTE * SMALLER THAN RADIX JEQ FADD08 CONTINUE IF RESULT = RADIX AB R9,*R5 RADIX SUB'S ONCE TOO OFTEN MOVB @FAC,R1 CARRY OUT OF HIGH ORDER RESULT? JEQ FADD10 NO, ROUND RESULT INC @EXP LI R1,FAC+8 LI R2,9 FADD30 MOVB *R1,@1(R1) SHIFT FAC RIGHT ONE BYTE HX01 EQU $-1 DEC R1 DEC R2 JNE FADD30 FADD10 JMP ROUN1 * FADD11 SB *R6,*R5 SUB A BYTE OF SMALL FROM BIG JGT FADD12 JEQ FADD12 AB R9,*R5 SB R8,@-1(R5) FADD12 DEC R5 DEC R6 INC R4 JLT FADD11 JMP FADD14 FADD13 AB R9,*R5 DEC R5 SB R8,*R5 FADD14 MOVB *R5,R4 JLT FADD13 JMP NORMAL FADD15 B @PACKUP * * FLATING MULTIPLICATION FAC:= ARG * FAC * * ENTRY NOT KNOWN FMULT MOV R11,R10 SAVE RTN JMP FMULT1 * = BL *R2 SMULT MOV R11,R10 STACK MULTIPLICATION BL @POPSTK FMULT1 LI R3,FAC IF FAC IS ZERO LI R5,ARG MOV *R3,R8 IF FAC IS ZERO JEQ FMULZR THEN RESULT IS ZERO XOR *R5,R8 COMPUTE SIGN RESULT ABS *R5 IF ARG IS ZERO JEQ FMULZR THEN ZERO FAC AND RTN ABS *R3 TAKE ABS VALUE OF FAC CLR R9 TO ZERO LOW BYTE OF RESULT EXP MOVB *R3,R9 RESULT EXP = FAC EXP AB *R5,R9 +ARG EXP SWPB R9 AI R9,-63 - BIAS MOV R9,@EXP MOVB R8,@SIGN SAVE TILL NORMAL, ROUND LI R5,FAC+8 LOW ORDER DIGITS FMCLR CLR *R5+ WILL BE CI R5,FAC+16 FORMED JNE FMCLR HERE * * R0-R1 WORK REGISTERS FOR MPY, DIV * R2 CURRENT RESULT DIGIT * R3 CURRENT FAC DIGIT * R4 REGISTER NUMBER LOOP COUNT * R5 FAC LOOP COUNT * R6 POINTER TO RESULT IN FAC * R7 NUMBER OF SIGNIF. BYTES IN ARG FRACTION * R8 RB(R0) POINTER * R9 RADIX 100 VALUE LI R5,FAC+8 BYTES IN FAC +1 FMUL02 DEC R5 CHANGE SIGNIF. BYTE COUNT MOVB *R5,R0 IF NEXT FAC BYTE IS ZERO CECE JEQ FMUL02 THEN DECREMENT COUNT FOR IT LI R7,8 COUNT SIGNIF. BYTES IN ARG FMUL03 DEC R7 DEC. FOR ZERO BYTE MOVB @ARG(R7),R0 IF THIS BYTE OF ARG IS ZERO JEQ FMUL03 THEN DEC. COUNT CLR R0 MPY, DIV WORK REGR MPY R0,R2 CURRENT RESULT IN HIGH BYTE MOV R5,R6 LI R8,R0LSB RB (R0) LI R9,100 RADIX FMUL04 MOV R7,R4 INNER LOOP CTR = BYTES IN ARG A R7,R6 RESULT PTR TO END OF NEXT PARTIAL * PRODUCT MOVB *R5,@R3LSB RB(R3) IS NEXT DIGIT OF FAC MOVB R3,*R5 CLEAR FAC DIGIT FOR NEXT PARTIAL FMUL05 MOVB @ARG(R4),*R8 GET NEXT DIGIT OF ARG MPY R3,R0 AND MPY IT MOVB *R6,@R2LSB TO CORRESPONDING PARTIAL PRODUCT * DIGIT IN RB (R2) A R2,R1 ADD IN NEXT PARTIAL PROD DIGIT DIV R9,R0 CONVERT PRODUCT TO RADIX DIGIT * AND CARRY MOVB @R1LSB,*R6 STORE NEW RESULT DIGIT IN FAC DEC R6 POINT TO NEXT HIGHER BYTE OF RESULT AB *R8,*R6 ADD IN CARRY TO NEXT HIGHER BYTE * OF RESULT DEC R4 IF ALL ARG DIGITS NOT DONE, JGT FMUL05 THEN CONTINUE DEC R6 POINT TO START OF NEXT PARTIAL PROD DEC R5 IF FAC DIGITS REMAIN CI R5,FAC JGT FMUL04 THEN CONTINUE FMEND CLR @FAC+10 CLEAR ERROR INDICATOR * * SIGN DESTROYS R0 - R2 * NORMAL LI R1,-9 NUMBER OF BYTES IN FAC INCLUDING * GUARD BYTES NORM01 MOVB @FAC+10(R1),R2 IS NEXT BYTE OF FAC NON-ZERO? JNE NORM02 YES, SHIFT REST LEFT INC R1 NO, ALL BYTES ZERO? JLT NORM01 YES, LOOK AT NEXT BYTE * * ZERO FAC, SETS FAC =0 * FMULZR CLR @FAC INSTALL FLOATING ZERO CLR @FAC+2 CLEAR POSSIBLE BASIC TYPE CODE JMP STEX AND EXIT WITH STATUS NORM02 MOV R1,R0 NUMBER OF NON-ZERO BYTES AI R0,9 FIRST BYTE NON-ZERO? JEQ ROUN1 YES, FINISH S R0,@EXP NO, ADJUST EXPONENT FOR SHIFT LI R2,FAC+1 POINT TO FIRST BYTE OF FAC NORM03 MOVB @FAC+10(R1),*R2+ MOVE NON-ZERO BYTE * TO FAC FIRST DIGIT INC R1 IF NON-ZERO BYTES REMAIN JLT NORM03 THEN MOVE ANOTHER BYTE NORM04 MOVB R1,*R2+ MOVE A ZERO DEC R0 LAST BYTE DONE? JGT NORM04 NO, CONTINUE * YES, ROUND THE NO. IN FAC AND FINISH * * ROUND THE NUMBER IN THE FAC USING THE GUARD DIGITS * DESTROYS R0-R2 * ENTRY NOT KNOWN JMP ROUN1 SKIP SAVE IF INTERNAL CALL ROUND MOV R11,R10 SAVE RTN ROUN1 LI R0,50*HIBYTE C @FAC+8,R0 IS ROUNDING NECESSARY? JLT PACKUP NO, PUT EXPONENT BACK LI R1,7 ROUND UP, GET NO. OF FAC BYTES ROUNUP LI R2,1*HIBYTE 1 (FOR BYTE INSTN) LI R0,100*HIBYTE 100 (SAME) ROUN02 AB R2,@FAC(R1) ADD ONE TO A BYTE OF FAC CB @FAC(R1),R0 IF BYTE NOT GREATER THAN RADIX JL PACKUP THEN PUT EXPONENT IN FAC SB R0,@FAC(R1) BRING DIGIT BACK IN RANGE DEC R1 IF CARRY PAST HIGH BYTE OF FAC JGT ROUN02 THEN CARRY TO NEXT HIGHER BYTE INC @EXP FRACTION HAS OVERFLOWED (WAS ALL 9'S) * SHIFT NO. BY ADDING 1 TO EXP MOVB R2,@FAC+1 MAKE THE HIGH BYTE A 1 * * PUT SIGN AND EXPONENT IN FAC * PACKUP MOV @EXP,R3 CI R3,128 JHE OVEXP1 MOVB @R3LSB,@FAC PUT EXPONENT IN FAC MOVB @SIGN,R2 INV R2 IF SIGN IS -VE JLT PACK01 NEG @FAC THEN INVERT 1ST WORD PACK01 JMP STEX SKIP SAVE IF INTERNAL CALL * ENTRY NOT KNOWN STEXIT MOV R11,R10 SAVE RETURN ADR STEX MOV @FAC,R1 SET STATUS ON FAC STEX01 STST R2 AND PUT IT MOVB R2,@STATUS IN THE STATUS REGISTER B *R10 THEN RETURN TO GLI * ROUND FAC BEGINING AT DIGIT SPECIFIED IN ARG * ENTRY NOT KNOWN ROUNU MOV R11,R10 SAVE RTN MOVB @FAC+10,R1 PICK UP OFFSET SRL R1,8 JMP ROUNUP AND DO IT * * ERROR ROUTINE EXITS * * DIVIDE BY ZERO EXIT * * ENTRY NOT KNOWN DIVZER LI R9,DZERR DIVIDE BY ZERO CODE FOR USER JMP BIGFLT LARGEST MAGNITUDE WITH SIGN * ----- OVER/UNDERFLOW ----- * ENTRY NOT KNOWN OVEXP MOV R11,R10 SAVE RTN OVEXP1 MOVB @EXP,R2 IS EXPONENT -VE? JLT FMULZR YES, RETURN ZERO JMP OV1 SKIP SAVE IF INTERNAL CALL * ENTRY NOT KNOWN OV MOV R11,R10 SAVE RTN OV1 LI R9,OFERR * SUPPLY THE LARGEST MAGNITUDE VALUE WITH PROPER SIGN BIGFLT LI R0,->7F63 HIGH WORD OF LARGEST VALUE MOVB @SIGN,R2 IS FAC -VE JLT BIGF01 YES, PUT HIGH WORD IN FAC NEG R0 BIGF01 LI R2,FAC GET PRT TO FAC MOV R0,*R2+ PUT APPROPRIATE HIGH WORD IN FAC LI R0,>6363 GET 99'S MOV R0,*R2+ PUT IN FAC TO GIVE LARGEST POS MOV R0,*R2+ OR MOST NEG NUMBER MOV R0,*R2 MOVB R9,@FAC+10 PLACE ERROR CODE IN RAM JMP STEX NO ROUTINE SPECIFIED, RETURN * * FLOATING DIVISION FAC = ARG / FAC * * = BR TABLE FDIV MOV R11,R10 JMP FDIV1 SDIV MOV R11,R10 SVE RTN BL @POPSTK STACK DIVISION FDIV1 LI R3,FAC PTR TO FAC MOV *R3,R8 GET DIVISOR 1ST WORD LI R0,ARG PTR TO ARG XOR *R0,R8 NO, COMPUTE SIGN OF QUOTIENT MOVB R8,@SIGN SAVE SAME ABS *R3 ABS OF DIVISOR D010 JEQ DIVZER CAN'T BE ZERO ABS *R0 IS DIVIDEND ZERO? JEQ FMULZR YES, RESULT IS ZERO MOVB *R0,R9 GET DIVIDENT EXP SB *R3,R9 SUB EXP'S TO GET QUOTIENT EXP SRA R9,8 GET DIFF IN LOW BYTE AI R9,64 ADD BIAS TO EXPONENT MOV R9,@EXP AND SAVE FOR RESULT LI R4,4 LI R5,ARG+8 FDV01 MOV *R3+,@10-2(R3) CLR *R5+ DEC R4 JGT FDV01 LOOP TILL 4 BYTE MOVED MOVB R4,@ARG CLEAR EXTRA HIGH BYTE OF DIVIDEND * * REFS FOR DIVISION ALGORITHM: * DONALD E. KNUTH, THE ART OF COMPUTER PROGRAMMING, VOLUME 2 * SEMINUMERICAL ALGORITHMS, ADDISON-WESLEY, 1969, P 235 FF * * THE DIVIDEND IS THE SERIES OF RADIX DIGITS: * U0,U1,U2 .... U7 (IN ARG) * THE DIVISOR IS THE SERIES OF RADIX DIGITS: * V1,V2,V3 .... V7 (IN FAC+8 OR FDVSR) * (U0 IS THE EXTRA HIGH BYTE OF THE DIVIDEND) * * NORMALIZE DIVISOR AND DIVIDEND SO V1 GT 50 * IF V1 LT 50, MULTIPLY DIVISOR AND DIVIDEND BY * INT(100/(V1+1)) * * R0-R1 MPY, DIV WORK REGS * R2 CARRY * R3 MULTIPLIER * R4 LOOP COUNT * R5 PTR TO RB (R0) * R6 PRT TO RB(R1) * R77 100 * LI R5,R0LSB GET POINTERS INTO MULTIPLY LI R6,R1LSB WORK AREA LI R7,100 RADIX HX0064 EQU $-2 D045 EQU $-1 CLR R2 CLEARR HIGH BYTE OF WHERE V1 WILL BE MOVB @FDVSR+1,@R2LSB GET V1 IN RB(R2) CI R2,49 IS V1 ALREADY NORMALIZED? JGT FDIV06 YES, PROCEED WITH DIVISION INC R2 NO, COMPUTE V1+1 CLR R3 GET RADIX IN 2 REGS FOR DIV MOV R7,R4 GET RADIX DIV R2,R3 COMPUTE MULTIPLIER =INT(100/V1+1)) LI R9,FDVSR+8 FDVLP LI R4,8 GET NO. OF BYTES IN DIVIDEND+1 FDIV04 DEC R4 IGNORE ZERO BYTES AT END DEC R9 MOVB *R9,R0 IS NEXT HIGHER ORDER BYTE ZERO? JEQ FDIV04 YES, KEEP LOOKING FOR NON-ZERO CLR R0 NO, LEAR CARRY INTO LOW ORDER BYTE FDIV05 MOV R0,R2 SAVE CARRY FROM LAST BYTE MOVB *R9,*R5 GET NEXT BYTE OF DIVIDEND MPY R3,R0 MULTIPLY THIS BYTE BY MULTIPLIER A R2,R1 ADD IN CARRY FROM PREVIOUS BYTE DIV R7,R0 CNVRT TO A RADIX DIGIT AND A CARRY MOVB *R6,*R9 PUT RESULT BYTE IN DIVIDEND DEC R9 DEC R4 LOOP UNTIL ALL DIVIDEND BYTES JGT FDIV05 NO, CONTINUE MULTIPLYING CI R9,FDVSR JNE FDVLPA LI R9,ARG+8 JMP FDVLP FDVLPA MOVB *R5,@ARG YES, PUT CARRY OUT OF HIGH ORDER * IN HIGHEST BYTE * * DIVIDE LOOP: * U(J) IS THE HIGHEST ORDER BYTE OF WHAT IS LEFT OF THE DIVIDEND * EACH QUOTIENT DIGIT IS ESTIMATED AS FOLLOWS: * IF U(J) = V1 THEN Q := 99 * ELSE Q:= INT((100*U(J)+U(J+1))/V1) * IF V2*Q GT (100*U(J)+U(J+1)-Q*V1)*100+U(J+2) * THEN Q := Q-1 ADN THE TEST IS REPEATED. * THIS WILL ENSURE THAT Q-1 LE NEXT-QUOTIENT-DIGIT LE Q. * NOTE THAT 100*U(J)+U(J+1)-Q*V1 = * REMAINDER ((100*U(J)+U(J+1))/V1 * Q*V IS THEN SUBTRACTED FROM U * IF THE RESULT IS -VE, V IS ADDED BACK IN AND A:= Q-1 (THE PROB * -ABILITY OF ADDING BACK IS APPROX .03) * * R0-R1 TEMPORARY * R2 NEXT QUOTIENT DIGIT * R3-R4 TEMPORARY * R5 QUOTIENT BYTE LOOP COUNT * R6 NUMBER OF SIGNIFICANT BYTES IN DIVISOR * R7 V1 * R8 V2 * R9 100*V1+V2 * R11 POINTER INTO DIVIDEND (USUALLY POINTS TO U(J) * FDIV06 LI R6,8 NUMBER OF DIVISOR BYTES +1 FDIV07 DEC R6 COMPUTE NO. OF SIG BYTES IN * DIVISOR MOVB @FDVSR(R6),R0 GET NEXT HIGHER ORDER BYTE JEQ FDIV07 IGNORE IF ZERO CLR R7 CLR HIGH BYTE OF WHERE V1 WILL BE MOVB @FDVSR+1,@R7LSB RB(R7) IS V1 MOV R7,R8 COPY V1 TO COMPUTE 100*V1 MPY @HX0064,R8 COMPUTE 100*V1 MOVB @FDVSR+2,@R8LSB GET V2 (HIGH BYTE IS ZERO) A R8,R9 COMPUTE 100*V1+V2 LI R5,-9 COMPUTE 9 BYTES OF QUOTIENT LI R11,ARG PTR TO HIGH BYTE OF DIVIDEND FDIV08 CLR R2 CLEAR HIGH BYTE OF WHERE U(J) WILL BE MOVB *R11,@R2LSB RB(R2) IS U(J) MPY @HX0064,R2 COMPUTE 100*U(J) CLR R0 WHERE U(J+1) WILL BE MOVB @1(R11),@R0LSB GET U(J+1) A R0,R3 100*U(J)+U(J+1) DIV R7,R2 GET Q AND REMAINDER MPY @HX0064,R3 100* REMAINDER MOVB @2(R11),@R0LSB U(J+2) A R0,R4 100*REM + U(J+2) MOV R2,R0 GET Q FOR THE TEST MPY R8,R0 COMPUTE V2*Q C R2,@HX0064 DOES Q=100? JEQ FDIV09 YES, MAKE Q=99 S R4,R1 NO, COMPUTE V2*Q-(100*REM+U(J+2) JMP FDIV11 GO CHECK IF IT IS IN RANGE FDIV09 S R4,R1 COMPUTE V2*Q-(100*REM+U(J+2)) FDIV10 DEC R2 DECREMENT Q S R9,R1 COMPUTE ABOVE FOR NEW Q FDIV11 JGT FDIV10 IF Q TOO BIG, MAKE IT SMALLER MOV R2,R2 IS Q ZERO? JEQ FDIV16 YES, DO NOTHING * NO, SUBTRACT Q*V FROM U * * R0-R1 TEMPORARY * R2 NEXT QUOTIENT DIGIT * R3 CARRY * R4 LOOP COUNT * R5 QUOTIENT BYTE LOOP COUNT * R6 NUMBER OF SIGNIFICANT BYTES IN DIVISOR * R7 V1 * R8 V2 * R9 100*V1+V2 * R11 POINTER INTO DIVIDEND (USUALLY POINTS TO U(J) * CLR R3 CLEAR CARRY INTO 1ST BYTE MOV R6,R4 GET DIVISOR LOOP COUNT A R6,R11 TO LOW BYTE OF DIVID. OF INTEREST FDIV12 MOV R0,R3 SAVE CARRY FROM PREV. BYTE MOVB @FDVSR(R4),@R0LSB GET NXT BYTE DIVISOR MPY R2,R0 MPY BYTE OF DIVSR BY QUOTIENT A R3,R1 ADD IN CARRY FROM LAST DVSR BYTE DIV @HX0064,R0 CONVERT TO A RADIX 100 DIGIT SB @R1LSB,*R11 SUB. PRODUCT BYTE FROM DIVIDEND JGT FDIV13 IS RESULT +VE? JEQ FDIV13 OR ZERO ? AB @HX0064+1,*R11 NO, ADD RADIX BACK INC R0 INC PRODUCT CARRY TO BORROW FROM * NEXT BYTE FDIV13 DEC R11 POINT TO NEXT HIGHER BYTE OF DVDND DEC R4 SUB'D ALL BYTES OF DIVISOR? JGT FDIV12 NO, CONTINUE SUBTRACTING SB @R0LSB,*R11 YES, SUB CARRY FROM DIVISOR PRODUCT JGT FDIV16 HIGH ORDER FROM HIGHEST ORDER JEQ FDIV16 DIVIDEND BYTE. -VE RESULT? * YES, ADD DIVIDEND BACK IN, Q WAS * ONE TOO BIG DEC R2 DEC Q, WAS ONE TOO BIG MOV R6,R4 GET ADD-BACK LOOP COUNT A R6,R11 PNT TO LOW ORDER BYTE OF DVDND * OF INTEREST FDIV14 AB @FDVSR(R4),*R11 ADD BYTE OF DVSR TO DVDND CB *R11,@HX0064+1 RESULT LARGER THAN RADIX? JL FDIV15 NO, RESULT IS CORRECT SB @HX0064+1,*R11 YES, SUBTRACT RADIX AB @HX01,@-1(R11) ADD 1 FOR CARRY TO HIGHER BYTE FDIV15 DEC R11 TO NEXT HIGHER BYTE OF DIVIDEND DEC R4 DONE ADDING IN ALL BYTES OF DVDND? JGT FDIV14 NO, ADD IN THE NEXT ONE FDIV16 MOVB @R2LSB,@FDVSR(R5) PUT AWAY NEXT QUOT BYTE INC R11 HIGH ORDER OF NEXT SIGNIF DVDND INC R5 COMPUTED ALL NECESS. BYTES OF QUO? JLT FDIV08 NO, CONTINUE B @FMEND YES, NORMALIZE AND FINISH UP * * STRING TO NUMBER CONVERSIONS * R0 POINTER * R1 EXPONENT SIGN * R2 TP1 (SAVED TEXT POINTER) * R3 ADR. OF GETCH (FOR BL) * R4 ACCUMULATOR FOR CSINT * R5 ACCUMULATOR FOR CSINT * R6 TEXT POINTER * R7 RELATIVE POSITION COUNTER * R8 CURRENT CHARACTER (LSBYTE) * R9 UNUSED * R10 SAVED LINK * R11 LINK * R12 NON-ZERO CHARACTER POINTER * * CALLED WITH FAX = ADR. OF STRING * RETURNS WITH CONTAINING NUMBER * * RPOS-RELATIVE POSITION OF FIRST NONZERO DIGIT * WRT ONE'S DIGIT * EG. 10,+1; 1,+0; .1,-1; .01,-2 * * * CONVERT STRING TO INTEGER, VALUE RETURNED IN R4 * HX3203 DATA >3203 * = BL, REQUIRES R3 SET UP ON ENTRY CSINT CLR R4 CLR R0 CHAR COUNTER FOR EXPONENT MOV R11,R9 JMP CSI02 CSI01 MPY @HX000A,R4 MOV R4,R4 TEST FOR OVERFLOW JNE CSI05 YES, OVERFLOW INC R0 COUNT THE CHAR A R8,R5 MOV R5,R4 IS INTEGER >32767 JLT CSI05 YES, TOO BIG CSI02 BL *R3 GET NEXT DIGIT AI R8,-'0' ASCII TO BINARY CI R8,10 COMPARE TO TEN HX000A EQU $-2 JL CSI01 CHAR OK MOV R0,R0 ANY CHARS? JEQ CSNZ10 NO - ERROR B *R9 RETURN GOOD CSI05 LI R9,CSNOFL SET RTN ADR. TO ERROR JMP CSI02 CONTINUE WITH STRING CSNZER B @FMULZR CSNZ10 B *R10 RETURN * = B *R9 CSNOFL DEC R6 MOV R6,@FAC+12 C R12,R2 IS MANTISSA ZERO? JEQ CSNZER YES, NUMBER IS ZERO MOV R1,@EXP SET EXPONENT SIGN B @OVEXP1 GO TO ERROR ROUTINE * * CONVERT STRING TO NUMBER GROM ENTRY * * =BL CSNGR MOVB @GROMFG,R3 TEST FOR GROM JEQ CSN LI R3,GETCHG ROUTINE TO GET GROM CHAR JMP CSN01 CSN LI R3,GETCH ADDR OF GETCH ROUTINE CSN01 MOV R11,R10 MOV @>8356,R6 INIT TEXT POINTER BL *R3 GET CHAR CLR R7 SIGN MOV R6,R2 SAVE REQUIRED DIGIT POINTER CI R8,'+' IS CHAR A PLUS? JEQ CSN02 YES, IGNORE CI R8,'-' IS IT A MINUS? JNE CSN04 NO SETO R7 NEGATIVE CSN02 INC R2 CSN03 BL *R3 GET NEXT CHAR CSN04 CI R8,'0' ZERO? JEQ CSN03 YES MOVB R7,@SIGN SAVE S[GO MOV R6,R12 DEC R12 FIRST NON-ZERO CHARR SETO R7 INIT RELATIVE POSN JMP CSN06 CSN05 INC R7 INC RELATIVE POSN BL *R3 CSN06 CI R8,'0' LESS THAN A ZERO? JL CSN07 YES CI R8,'9' LESS THAN 9? JLE CSN05 YES CSN07 CI R8,'.' END OF INTEGER PART? JNE CSNG LOOK FOR EXPONENT OR END * * COVERT A FLOATING POINT NUMBER * INC R2 MOVE DIGIT POINTER PAST DEC. POINT MOV R7,R7 JLT CSNF03 NO SIGNIF DIGIT TO LEFT OF JMP CSNF04 LOOK FOR LAST DIGIT CSNF02 DEC R7 CSNF03 BL *R3 GET NEXT CHAR CI R8,'0' IGNORE LEADING ZEROS JEQ CSNF02 DEC R6 * THIS IS FIRST SIGNIFICANT DIGIT OF THE END OF THE NUMBER, * POINT BACK TO FIRST NON-ZERO CHAR. MOV R6,R12 CSNF04 BL *R3 CI R8,'0' JL CSNF05 TOO SMALL FOR DIGIT CI R8,'9' JLE CSNF04 IN RANGE, KEEP LOOKING CSNF05 C R6,R2 JEQ CSNZER NUMBER HAS NO DIGITS **BAD** * --- LOOK FOR EXPONENT OR END OF NUMBER CSNG MOV R6,R2 POINTER TO LAST CHAR +2 CLR R4 DEC R2 CLR R1 CI R8,'E' IS NEXT CHAR AN 'E' JNE CSNH NO, EXP. DEFAULT = 0 BL *R3 CI R8,'+' GET A PLUS JEQ CSNG03 IGNORE PLUS SIGN CI R8,'-' GET A MINUS JNE CSNG02 NOT MINUS SIGN D23C DEC R1 CHANGE SIGN TO NEGATIVE JMP CSNG03 * CSNG02 DEC R6 BACK UP CSNG03 BL @CSINT GET INTEGER VALUE MOVB R1,R1 JEQ CSNH NEG R4 * ------ PACK FRACTION INTO FAC CSNH DEC R6 POINT TO 1ST CHAR AFTER MOV R6,@FAC+12 STORE FIRST NON CONVERTED POSN C R12,R2 WAS THE FRACTION ZERO? JEQ CSNZER YES AI R4,128 CLR R1 CLEAR WORK REGISTER A R7,R4 COPY EXPONENT FOR PLACE FLAG MOV R4,R7 SRA R4,1 BASE 100 MOV R4,@EXP SRC R7,1 LI R5,8 INIT LOOP LI R0,FAC+1 MOV R12,R6 CSNH01 C R6,R2 END OF FRACTION JEQ CSNH03 YES ZERO UNUSED FRACTION BL *R3 GET NEXT CHAR CI R8,'.' IGNORE DECIMAL POINT JEQ CSNH01 AI R8,-'0' ASCII TO BINARY INV R7 JLT CSNH02 1'S DIGIT MPY @HX000A,R8 MOVB @R9LSB,R1 SAVE JMP CSNH01 GET ONE'S DIGIT CSNH02 AB @R8LSB,R1 ADD ONES AND TENS DIGIT CSNH03 MOVB R1,*R0+ STORE DIGIT CLR R1 IN CASE NUMBER ENDS DEC R5 MORE? JNE CSNH01 YES B @ROUN1 RETURN * BRANCH TABLE, REF NOT KNOWN XTAB DATA CSN DATA CSNGR DATA CFI DATA SYMB DATA SMBB DATA ASSGNV DATA FBSYMB DATA VPUSHG DATA VPOP DATA SROM DATA SGROM DATA PGMCH * * FLOATING TO INTEGER CONVERSION * FAC HAS FLOATING NUMBER, RETURNS WITH INTEGER IN FAC'S FIRST * INTEGER IS 16 BIT TWO'S COMPLEMENT * = BL CFI MOV @FAC,R4 IS FAC ZERO? JEQ CFISI1 YES, ALL DONE CLR R0 ZERO RESULT IN CASE FAC = 0 LI R2,FAC+1 GET PTR R0 HIGH ORDER BYTE OF FAC CLR R3 CLEAR HI BYTE OF CURRENT FRACTION D ABS @FAC MAKE SURE 1ST DIGIT IS +VE CLR R5 CLR LOW BYTE OF WHERE EXPONENT WILL BE MOVB @FAC,R5 GET EXPONENT CI R5,>3F00 IS NUMBER LESS THAN ONE? JLT CFIRI YES RESULT IS <.01, RESULT =0 JEQ CFI03 .014100 IS NUMBER LESS THAN 100000 JLT CFI02 IT IS BETWEEN 1 AND 100 JEQ CFI01 IT IS BETWEEN 100 AND 10000 CI R5,>4200 IS NUMBER TOO BIG TO CONVERT JH CFI08 TOO BIG, ERROR MOVB *R2+,@R0LSB GET DIGIT MPY @DEC100,R0 MPY BY RADIX TO CONVERT TO BI MOV R1,R0 GET RESULT OF MPY FOR NEXT DIGIT CFI01 MOVB *R2+,@R3LSB GET NEXT DIGIT A R3,R0 ADD TO PREVIOUS RESULT MPY @DEC100,R0 MULTIPLY BY RADIX MOV R0,R0 TEST FOR OVERFLOW JNE CFI08 YES, ERROR MOV R1,R0 NO - GET RESULT FOR LAST DIGIT JLT CFI08 OVERFLOW IF HI BIT SET CFI02 MOVB *R2+,@R3LSB GET LAST RADIX DIGIT TO LEFT OF PO A R3,R0 ADD IT TO RESULT CFI03 CB *R2+,@HX3203 IS ROUNDING NECESSARY JLT CFI06 NO PUT ON PROPER SIGN JGT CFI05 YES ADD A 1 TO IT MOV R4,R4 MAYBE -- ?????? JGT CFI05 NONZERO ROUND UP CFI04 MOVB *R2+,R3 GET NEXT RADIX DIGIT JNE CFI05 NON ZERO, ROUND UP CI R2,FAC+8 LOOK AT REST OF DIGITS JL CFI04 NO LOOK AT NEXT ONE JMP CFI06 ROUND DOWN DEC100 DATA 100 CFI05 INC R0 ROUND UP CFI06 CI R0,SGNBIT IS RESULT 32768? JL CFIRSI NO PUT ON THE PROPER SIGN JH CFI08 NO IT IS GREATER -- OVERFLOW MOV R4,R4 IS NUMBER NEGATIVE? JLT CFIRS2 YES, PUT ON CORRECT SIGN CFI08 MOVB @HX3203+1,@FDVSR OVERFLOW RTN TO ERROR LCN RT (ERROR CODE) CFIRSI INV R4 IS NUMBER -VE? JLT CFIRI NO RETURN +VE NUMBER CFIRS2 NEG R0 RTN -VE NO. CFIRI MOV R0,@FAC RTN NO. IN FAC CFISI1 RT * * THIS IS A SET OF ROUTINES DEFINED FOR AUDIO CASSETTE * COMMUNICATION. THEY ARE ENTERED THROUGH A GRAPHICS * LANGUAGE PROGRAM, WHICH GIVES INFORMATION LIKE THE NO. * OF BLOCKS (=64 BYTES) TO BE WRITTEN, OR THE NUMBER OF * FREE BLOCKS IN CASE OF READ MODE; THE VDP START ADR. * AND THE BAUD RATE. * THE ROUTINES TAKE CARE OF THE NECESSARY ENCODING/ * DECODING AND THE ERROR CHECKING. * * THE BIPHASE FORMAT, USED IN THIS SET OF ROUTINES, HAS * THE FOLLOWING REPRESENTATIONS FOR THE BINARY DIGITS: * * --------------- --------- ---- * | | | | | * --- --- --- ------- * <-----"0"-----> <---- "1"---------> * * REPRESENTATIONS OF THE BITS MAY BE CHANGED IN PHASE BY * 180 DEGREES, DEPENDING UPON THE VALUE OF THE BIT STREAM * AFTER THE PREVIOUS BIT. * * PRINCIPLES OF OPERATION * * WRITING * THE ACTUAL IMPLEMENTATION OF THE BIPHASE RECORDING SCHEME * IS RELATIVELY SIMPLE. THE VALUE FOR THE DATA RATE, AS INDICATED * BY THE GRAPHICS LANGUAGE PROGRAM, IS USED AS A TIMER VALUE FOR * THE INTERNAL TMS9985 TIMER/COUNTER. IT IS USED AS A TIMER VALUE * FOR HALF A BIT CELL. * * ------------ ------ ---- * | | | | | * --- --- --- ------ * |<----><----> <-----><-----> * DRATE DRATE * * EACH BIT CELL THUS CONSISTS OF TWO TIMER INTERVALS. THE TIMER * INTERRUPT AT THE BEGINING OF EACH BIT CELL CAUSES THE OUTPUT LINE * TO CHANGE VALUE. THE NEXT TIMER INTERRUPT, IN THE MIDDLE OF THE * BIT CELL, ONLY CHANGES THE VALUE OF THE OUTPUT LINE IF THE BIT TO * BE OUTPUT EQUALS A BINARY "1". * * READING * ON READING BACK, THE BASIC TIMER INTERVAL TIME IS SET TO 1.5 * TIMES THE DRATE OF THE WRITE SECTION. THE TIMER IS SYYNCHRONIZED * ON THE FLUX CHANGE AT THE BEGINING OF THE BIT CELL. AFTER THE TIMER * HAS GIVEN AN INTERRUPT, THE CURRENT INPUT LINE VALUE IS COMPARED TO * THE VALUE AT THE BEGINING OF THE BIT CELL. IF THIS VALUE HAS * CHANGED, THE BIT VALUE IS ASSUMED TO BE "1" IF NOT, IT WILL BE * A "0" * TO PROVIDE A TIME-OUT MECHANISM THE TIMER AUTOMATICALLY * RESTARTS ITSELF WITH THE SAME RATE. IF THE TIMER TIMES OUT BEFORE * THE NEXT FLUX CHANGE, AN ILLEGAL BIT LENGTH IS ASSUMED, AND AN * ERROR RETURN CODE IS PRODUCED. * ********************************************************************* * * CASSETTE WRITE ROUTINE * * WRITES N BLOCKS OF 64 BYTES TO THE AUDIO CASSETTE. * * THE OUTPUT FORMAT USED IS: * - ZERO LEADER CONSISTING OF LDCNT ZEROES * - SYNC BYTE (8 "1" BITS) * - NUMBER OF BLOCKS TO FOLLOW (8 BITS) * - CHECKSUM (8 BITS) * - 2*N BLOCKS, CONSISTING OF: * - 8 BYTES OF ZERO * - 1 BYTE OF ONES * - 64 BYTES OF INFORMATION * - CHECKSUM (8 BITS) * - EACH BLOCK IS REPEATED TWICE. THE LEADING ZEROES AND * ONES ARE USED FOR TIMING AND TO R * - TRAILER OF EIGHT "1" BITS * * REGISTER DEFINITION * * R0 TEMPORARY * R1 PHASE FLAG REGISTER * R2 COUNTER/BYTE COUNTER * R3 DATA RATE COUNTER * R4 BYTE * R5 BLOCK COUNT * R6 LOOP COUNT * R7 CHECKSUM * R8 SET/RESET OUTPUT INSTRUCTION * R12 CRU BASE REGISTER = TIMER CRU * ********************************************************************* * THE GRAPHICS LANGUAGE PROGRAM PROVIDES THE FOLLOWING * INFORMATION: * (R1) DATA LENGTH IN BYTES * (R1) +2 VDP RAM START ADDRESS * * THE DATA SHOULD BE READ BACK AT THE SAME BAUD RATE AT WHICH * IT WAS WRITTEN. * HX0010 DATA >0010 * = BR TABLE * * WRITE ROUTINE * WRITE CLR R0 NO OFFSET FOR VIDEO ADR. LI R2,>0300 LOAD LEADER COUNT FIRST LI R8,>1E19 LOAD SBZ INSTN LI R3,>0023 SET DATA RATE AT 1500 BAUD BL @INIT INIT. FURTHER LI R0,BOUT SAVE BYTES HX0300 LIMI 1 LABEL IS NASTY! WRITE0 CLR R4 BL *R0 WRITE BYTE OF LEADER DEC R2 COMPLETE LEADER JNE WRITE0 AND RTN IF NOT COMPLETED SETO R4 BYTE =>FFFF (SYNC BYTE) BL *R0 MOV R5,R4 WRITE BLOCKCOUNT TO TAPE SWPB R4 BL *R0 AND OUTPUT AGAIN MOV R5,R4 TWICE (ONE CHECKSUM) SWPB R4 BL *R0 CLR R9 USED TO SEE IF 2ND RECD. WAS WRITTEN REWRI LI R2,8 WRITE 8 BYTES OF ZERO LEAD CLR R4 ZERO BL *R0 WRITE THEM DEC R2 MORE? JNE LEAD YES SETO R4 WRITE ALL ONES BYTE BL *R0 WRITE IT MOVB @R10LSB,*R15 RESTORE VDP ADR. LI R2,64 LOAD COUNT WITH ONE BLOCK MOVB R10,*R15 CLR R7 CLEAR CHECKSUM WRBYT CLR R4 MOVB @VRDOFF(R15),R4 VDP DATA TO R4 MSB A R4,R7 ADD BYTE TO CHEKCSUM BL *R0 OUTPUT BYTE TO TAPE DEC R2 DEC. BYTE COUNTER JNE WRBYT WRITE ALL 64 BYTES MOV R7,R4 OUTPUT CHECKSUM BL *R0 INV R9 2ND TIME RECORD WRITTEN? JNE REWRI REWRITE AI R10,64 BUMP ADR. TO NEXT RECD DEC R5 DONE ALL BLOCKS? JNE REWRI NO... NOT YET, CONTINUE SPIN WAIT FOR COMPLETION OF LAST CYCLE B @STTIM STOP TIMER AND EXIT * * INITIALIZATION ROUTINE * INIT MOV *R1+,R5 COPY NO. OF BLOCKS IN BLKCNT AI R5,63 COMPUTE IN BLOCKS OF 64 BYTES SRL R5,6 DIVIDE BY 2**6=64 SOC *R1,R0 COPY ADR. + OFFSET IN R0 MOV R0,R10 SAVE ADR FOR WRITING DUPLICATES MOVB @R0LSB,*R15 COPY IN VIDEO ADR CLR R1 INIT THE ERROR FLAG CLR R12 CRU BASE MOVB R0,*R15 COPIED... SOC @HX0020,R14 SET TIMER INTPT FLAG SBZ 2 TURN OFF VDP INTPT SBZ 12 TURN OFF ??? INTPUT LDCR R3,15 LOAD TIMER SBZ 0 ENABLE INTS SBZ 1 TURN OFF EXTERNAL INT. SBO 3 ENABLE CLOCK INTPT RT AND RTN * * BYTE OUTPUT ROUTINE * BOUT LI R6,8 LOAD LOOP COUNTER INV R4 INVERT FOR ENABLING "0" BIT JUMP BOUT0 SPIN IDLE AROUND UNTIL LAST CYCLE OF X R8 ALWAYS FLIP AT START OF BIT XOR @HX0300,R8 HXSPIN EQU $ D3F0 SPIN PREVIOUS BYTE+1ST OF THIS BYTE MOV R4,R4 TEST HIGHEST BIT FOR NEW FLIP CHECK JLT BOUT1 BIT SET MEANS NO FLIP (SEE INV) X R8 FLIP OUTPUT LINE XOR @HX0300,R8 REVERSE INSTN BOUT1 SLA R4,1 GET NEXT BIT READY FOR OUTPUT DEC R6 HAS BEEN COMPLETED... THEN LOOP JNE BOUT0 UNTIL BYTE COMPLETED RT RETURN IF BYTE COMPLETED * * TIMER INTERRUPT ROUTINE * TIMER SBZ 0 MAKE SURE WE'RE IN INTPT MODE SBO 3 CLEAR DECREMENTER INTPT MOV R1,R1 TEST FLAG REGISTER JLT TIMER1 FLAG SET -> ERROR EXIT LWPI WKSC BACK TO REGULAR WORKSPACE C *R14,@HXSPIN DOING A SPIN? JNE TIMER1 NO, DON'T INC ADR. INCT R14 BYPASS SPIN TIMER2 RTWP AND RETURN TIMER1 LWPI WKSC MOV @WKSE+R6+R6,R14 GET EXIT ADDRESS JMP TIMER2 AND EXIT * * READ REGISTER DEFINITIONS * * R0 TEMPORARY * R1 ERROR EXIT/INPUT LEVEL FLAG * R2 COUNTER/BYTE COUNTER * R3 DATA RATE COUNTER * R4 BYTE * R5 BLOCK COUNT * R6 BIT LENGTH ERROR EXIT ADR * R7 CHECKSUM * R8 RETRY COUNT/BYTE COUNT * R12 CRU BASE REGISTER = TIMER CRU * * * CASSETTE READ ROUTINES * HX2100 BYTE >21,0 * * DEVIATION OF UP TO -25 TO +50 PERCENT OF THE * NOMINAL BAUD RATE IS PERMITTED * VERIFY SOC @HX0010,R14 SET VERIFY BIT CLR R0 SET ADR BIT TO READ FROM VDP JMP READA * = BR TABLE READ SZC @HX0010,R14 RESET VERIFY BIT LI R0,>4000 SET ADR. BIT TO WRITE TO VDP READA LI R3,>002B SET BAUDRATE IN HX002B EQU $-2 BL @INIT AND INIT MOV R10,R7 SAVE VDP ADR. CLR R0 INDICATE FIRST RECORD HX20 MOVB @HX20+1,@ERRCD ASSUME TIME OUT ERROR READ12 LI R8,30000 LOAD RETRY COUNT FOR 10 SECS LIMI 1 ALLOW TIMER INTPTS LI R6,READ0 LOAD TIME-OUT RETRY ADR READ00 LI R3,>2B IF FALSE START READ0 ANDI R1,>FF CLEAR FLAG TO PREVENT ERROR HANG UP HX00FF EQU $-2 DEC R8 COUNT FOR ONE RETRY JEQ STTIM RETRY ERROR LI R2,48 COUNT AT LEAST 48 ZEROES MOV R0,R0 AM I IN THE MIDDLE? JNE READ1 YES LOOK FOR 48 ZEROES A R2,R2 NO LOOK FOR MORE READ1 BL @RDBIT GET A BIT ** TIME OUT GIVES RETRY JMP READ15 JMP READ0 "1" RETURN READ15 DEC R2 DETECTED A "0" BIT, COUNT IT JNE READ1 AND CONTINUE TILL DONE * --- CALCULATE ACTUAL BIT RATE BASED ON 8 ZERO BIT TIMES --- LI R9,>7FFF BIG COUNT FOR TIMER LI R8,8 NUMBER OF BITS TO AVERAGE LDCR R9,15 SET TIMER SBZ 0 TURN ON 9901 INTPTS SBO 3 ENABLE CLOCK INTPT LOOP BL @FLUXC FIND BIT JMP ENDL CHANGE-DEC NO. OF BITS JMP LOOP NO CHANGE, KEEP LOOKING ENDL DEC R8 LOOK FOR MORE ??? JNE LOOP YES SBO 0 SET 9901 TO CLOCK STCR R3,15 READ TIMER S R3,R9 HOW MUCH TIME USED? MOV R9,R3 SAVE CELL TIME SLA R9,2 CELL TIME * 4 A R9,R3 MAKE NEW 3/4 BIT TIME SRL R3,6 5/8 CELL TIME/2 ORI R3,>0001 SET 9901 TO CLOCK LI R10,READ5 RTN ADR FOR SUBSUBROUTINE CI R3,>001F MAKE SURE FREQ. NOT TOO SMALL JLT READ00 TOO SMALL, LOOK FOR REAL ZEROS B @RDBIT2 LOAD NEW BIT TIME * READ5 BL @RDBIT AGAIN READ BIT INPUT JMP READ5 "0" IS STILL OK * ENTRY NOT KNOWN D4B6 LI R2,7 SHOULD BE "ALL ONE" BYTE READ3 BL @RDBIT NEXT BIT PHASE JMP READ0 FALSE ALARM-NOT A REAL LEADER DEC R2 ALL SYNC BYTE DONE? JNE READ3 NO...KEEP ACCEPTING "1" BITS LI R6,ERROR1 GET SET FOR ERROR EXIT * AT THIS POINT WE ARE SYNCHRONIZED ON THE DATA STREAM * COMING IN FROM THE CASSETTE, BOTH ON BIT AND R4 LEVEL * ALL DATA COMING IN NOW SHOULD BE CORRECT. IF NOT WE * TAKE THE ERROR EXIT MOV R0,R0 DO I READ BLOCK COUNTS? JNE DUMP3 I ALREADY READ THEM MOVB @HX2100,@ERRCD ASSUME NOT ENOUGH BLOCKS MOV R7,R0 CLR R7 INIT CHECK SUM BL @RDBYTE CALL READ BYTE ROUTINE C R5,R4 ENOUGH SPACE AVAILABLE?? JL STTIM ** ERROR ** NOT ENOUGH SPACE MOV R4,R5 READ NO. OF BLOCKS ON TAPE INC R5 AND INC FOR EASE OF PROGRAMMING NEG R7 PREPARE FOR BLOCK COUNT CHECK BL @RDBYTE READ CHECK SUM JNE STTIM BAD BLOCK COUNT DATA JMP DUMP4 LOOP AROUND TO FIRST READ RDLOOP ANDI R7,>FF USE ONLY LOWER BYTE OF CHKSUM NEG R7 NEGATTE FOR ZERO RESULT BL @RDBYTE READ RECORDED CHKSUM JEQ DUMP **NO ERROR** CHKSUM CORRECT ERROR1 MOV R5,R5 ERROR ON 2ND RECORD JLT STTIM YES, FLAG ERROR MOVB @R0LSB,*R15 RESTORE VDP ADR. NEG R5 NO, TRY 2ND READING MOVB R0,*R15 JMP READ12 READ AGAIN DUMP MOV R5,R5 HAS 2ND RECORD BEEN READ? JLT DUMP2 YES, SO DON'T READ AGAIN LI R2,73 SKIP NEXT RECORD DUMP1 LI R6,DUMPX BL @RDBYTE WAIT FOR A BYTE DUMPX DEC R2 MORE TO READ? JNE DUMP1 READ SOME MORE DUMP2 AI R0,64 BUMP RECORD ADR. IN VDP MOVB @R0LSB,*R15 OUTPUT ADR. TO VDP ABS R5 SET FLAG FOR 1ST RECORD MOVB R0,*R15 DUMP4 CLR R7 CLEAR CHKSUM AFTER DUMPING DEC R5 REDUCE NO. OF BLOCKS TO READ JNE READ12 READY...MORE BLOCKS TO GO JMP DONE NO MORE TO READ DUMP3 LI R2,64 START OUT FOR 128 BYTES CLR R7 ZERO CHKSUM FOR NEXT RECORD RDL0 BL @RDBYTE READ ONE BYTE SWPB R4 SWAP TO UPPER BYTE COC @HX0010,R14 IS IT A VERIFY JNE STO NO, SO STORE IT SB @VRDOFF(R15),R4 IS IT RIGHT? JEQ STO1 YES, CONTINUE CI R5,1 LAST RECORD? JEQ STO1 YYES, IGNORE BAD COMPARISONS JMP ERROR1 NO, TRY READING 2ND RECORD STO MOVB R4,@VWDOFF(R15) WRITE DATA TO VDP STO1 DEC R2 SEE IF DONE JNE RDL0 NO.. NOT YET JMP RDLOOP COMPLETE READ LOOP DONE MOVB @HX002B,@ERRCD CLEAR ERROR CODE * ------ ALSO ERROR EXIT -------- STTIM SZC @HX0010,R14 FREE UP BIT SZC @HX0020,R14 TURN OFF TIMER INTPT FLAG SBZ 3 TURN OFF TIMER INTPT MASK BIT SBO 12 ENABLE INTERRUPT SBO 1 ENABLE EXT INTPT SBO 2 ENABLE VDP INTPT B @NEXT * * BIT INPUT ROUTINE * * READ ONE BIT FROM THE INPUT STREAM. RETURN TO CALLER+2 * IF BIT READ IS "1" * THE VALUE OF THE BIT CELL IS COMPUTED BY DETERMINING * THE INPUT LINE VALUE AT 3/4 OF THE BIT CELL LENGTH. IF THE * INPUT LINE LEVEL HAS CHANGED DURING THAT PERIOD, THE BIT * READ = "1"; IF NOT, THE BIT READ = "0" * THE NEXT FLUX CHANGE SHOULD COME WITHIN 3/4 OF A BIT * CELL, IN ORDER TO ACCEPT THE BIT * RDBIT MOV R11,R10 SAVE RTN ADR. IN LEVEL 2 SPIN WAIT FOR END OF CYCLE BL @FLUXC SEE IF WE HAD A FLUX CHANGE INCT R10 IF SO... UPDATE RTN ADR ORI R1,>FF00 SET FLAG FOR ERROR EXIT RDBIT2 CZC @HX00FF,R1 WHICH WAY IS CHANGED FLUX? JEQ F2 INPUT IS A ZERO F1 TB 27 WAIT FOR A CHANGE JNE RDBIT1 CHANGED JMP F1 NO CHANGE F2 TB 27 WAIT FOR A CHANGE JNE F2 NO CHANGE, WAIT SOME MORE RDBIT1 LDCR R3,15 AN ERROR EXIT SBZ 0 ENABLE INTPTS SBO 3 ENABLE CLOCK INTPT ANDI R1,>FF RESET ERROR FLAG TO PREVENT CHANGE XOR @HX00FF,R1 RECORD FLUX CHANGE B *R10 TIMER... THEN EXIT ON LEVEL 2 * ----- BYTE READ ROUTINE ------ * THE R4 READ ROUTINE IS SIMPLE AND STRAIGHT FORWARD. * ONLY REMEMBER THAT WE ARE DEALING WITH THREE LEVELS * OF SUBROUTINES HERE, SO WE MUST SAVE THE RTN ADR IN R9 * RDBYTE LI R8,8 LOAD BYTE COUNTER CLR R4 CLEAR RESULT MOV R11,R9 SAVE RTN ADR. IN LEVEL 3 RDBYT0 SLA R4,1 RESULT ONE BIT TO THE LEFT BL @RDBIT READ ONE BIT JMP RDBYT1 AVOID COUNTING ZEROS INC R4 IF IT'S A "1", INC. BYTE RDBYT1 DEC R8 CONTINUE?? JNE RDBYT0 YEP... A R4,R7 UPDATE CHKSUM *** CONDITION CODES B *R9 RTN FROM BYTE READING (LEVEL 3) * FLUX CHANGE CONTROL ROUTINE * RETURNS TO (R11) IF FLUX HAS CHANGED, (R11) +2 IF FLUX * HASN'T CHANGED SINCE LAST OUTPUT VALUE. * FLUXC TB 27 CONTROL VALUE OF INPUT LINE JEQ FLUXC1 INPUT LINE SET CZC @HX00FF,R1 WAS INPUT LINE HIGH LAST TIME? JEQ FLUXC2 INPUT LINE WAS LOW FLUXC0 XOR @HX00FF,R1 FLIP FLAG(INPUT LINE CHANGED) RT & RETURN FLUXC1 CZC @HX00FF,R1 INPUT LINE HIGH AGAIN? JEQ FLUXC0 INPUT LINE WAS LOW -> CHANGE FLUXC2 INCT R11 UPDATE RTN ADR, NO CHANGE RT