ORG 001#000 FPCONT: CAL CRLF2 ;DISPLAY A FEW CR & LF'S FOR I/0 DEVICE CAL DINPUT ;LET OPERATOR ENTER A FP DECIMAL NUMBER CAL SPACES ;DISPLAY A FEW SPACES AFTER NUMBER LLI 124 ;SET PWTR TO LSW OF FPACC LDH ;SET D = 0 POR SURE LEI 170 ;SET PNTR TO TEMP # STORAGE AREA LBI 004 ;SET PRECISION COUNTER CAL MOVEIT ;MOVE FPACC TO TEMP STORAGE AREA NVALID: CAL INPUT ;FETCH "OPERATOR" FROM INPUT DEVICE LBI 000 ;CLEAR REGISTER "B" CPI 253 ;TEST FOR "+" SIGN JTZ OPERA1 ;GO SET UP FOR "+" SIGN CPI 255 ;IF NOT"+", TEST FOR "-" SIGN JTZ OPERA2 ;GO SET UP FOR "-" SIGN CPI 330 ;IF NOT ABOVE, TEST FOR "X" (MULT) SIGN JTZ OPERA3 ;GO SET UP FOR "X" SIGN CPI 257 ;IF NOT ABOVE, TEST FOR "/" (DIV) SIGN JTZ OPERA4 ;GO SET UP FOR "/" SIGN CPI 377 ;IF NOT ABOVE, TEST FOR "RUBOUT" JFZ NVALID ;IF NONE OF ABOVE, IGNORE INPUT JMP FPCONT ;IF "RUBOUT" START NEW INPUT SEQUENCE OPERA1: DCB ;SET UP REGISTER "B" BASED ON ABOVE DCB ; " " " " " " " OPERA2: DCB ; " " " " " " " DCB ; " " " " " " " OPERA3: DCB ; " " " " " " " DCB ; " " " " " " " OPERA4: LCA ;SAVE "OPERATOR" CHARACTER IN REG "C" LAI 242 ;*** = NEXT TO LAST LOC IN "LOOKUP" TABLE ADB ;MODIFY ,"***" BY CONTENTS 0F "B" LLI 110 ;SET PNTR TO "LOOKUP" TABLE ADDR STORAGE LMA ;PLACE "LOOKUP" ADDR IN STOftAGE LOCATION LAC ;RESTORE "OPERATOR" CHARACTER TO ACC CAL ECHO ;DISPLAY THE "OPERATOR" SIGN CAL SPACES ;DISPLAY FEW SPACES AFTER "OPERATOR" SIGN CAL DINPUT ;LET OPERATOR ENTER 2ND FP DECIMAL NUMBER CAL SPACES ;PROVIDE FEW SPACES APTER 2ND NUMBER LAI 275 ;PLACE ASCII CODE FOR "=" IN ACCUMULATOR CAL ECHO ;DISPLAY "." SIGN CAL SPACES ;DISPLAY FEW SPACES AFTER "=" SIGN LLI 170 ;SET POINTER TO TEMP NUMBER STORAGE ARFA LDH ;SET D =0 FOR SURE LEI 134 ;SET ANOTHER POINTER TO LSW FPOP LBI 004 ;SET PRECISION COUNTER CAL MOVEIT ;MOVE 1ST NUMBER INPUTTED TO FPOP LLI 110 ;SET PNTR TO "LOOKUP" TABLE ADDR STORAGE LLM ;BRING IN LOW ORDER ADDR OF "LOOKUP" TABLE LHI 001 ;XXX = PAGE THIS PROGRAM LOCATED ON LEM ;BRING IN AN ADDR STORED IN "LOOKUP" TABLE INL ;RESIDING ON THIS PAGE (XXX) AT LOCATIONS LDM ;"*** + B" AND "*** + B + 1" AND PLACE IT LLI 224 ;IN REGS "D & E" THEN CHANGE PNTR TO ADDR LME ;PART OF INSTRUCTION LABELED "RESULT" BE- INL ;LOW AND TRANSFER THE "LOOKUP" TABLE CON- LMD ;TENTS TO BEOMCE THE ADDRESS FOR THE IN- LHI 000 ;STRUCTION LABELED "RESULT." THEN RESTORE LDH ;REGISTERS "D" AND "H" BACK TO "0" JMP RESULT ;NOW JUMP TO COMMAND LABELED "RESULT" CRLF2: LAI 215 ;SUBRTN TO PROVIDE CR & LF'S CAL ECHO ;PLACE ASCII CODE FOR CR IN ACC & DISPLAY LAI 212 ;PLACE ASCII CODE FOR LINE FEED IN ACC CAL ECHO ;AND DISPLAY LAI 215 ;DO IT AGAIN - CODE FOR CR IN ACC CAL ECHO ;DISPLAY. IT LAI 212 ;CODE FOR LF CAL ECHO ;DISPLAY IT RET ;RETURN TO CALLING ROUTINE SPACES: LAI 240 ;SET UP ASCII CODE FOR SPACE IN ACC CAL ECHO ;DISPLAY A SPAC E LAI 240 ;DO IT AGAIN - CODE FOR SPACE IN ACC CAL ECHO ;DISPLAY SPACE RET ;RETURN TO CALLING ROUTINE RESULT: CAL DUMMY ;CAL RTN AT ADDRESS IN NEXT TWO BYTES1 CAL FPOUT ;DISPLAY RESULT JMP FPCONT ;GO BACK'AND GET NEXT PROBLEM I ; ; TABLE OF OPERATIONS ; ;LOOKUP: ; DATA \LB\FPADD ;LOW address for start of FPADD subroutine ; DATA \HB\FPADD ;PAGE address for start of FPADD subroutine ; DATA \LB\FSUB ;LOW address for start of FPSUB subroutine ; DATA \HB\FSUB ;PAGE address for start of FPSUB subroutine ; DATA \LB\FPMULT ;LOW address for start of FPMULT subroutine ; DATA \HB\FPMULT ;PAGE address for start of FPMULT subroutine ;ENDLOOKUP: ; DATA \LB\FPDIV ;LOW address for start of FPDIV subroutine ; DATA \HB\FPDIV ;PAGE address for start of FPDIV subroutine DATA 240 DATA 004 DATA 115 DATA 005 DATA 127 DATA 005 DATA 022 DATA 006 FPOUT: LLI 157 ;Set pointer to decimal exponent storage location LMI 000 ;Initialize storage location to zero LLI 126 ;Change pointer to FPACC (number to be outputted) LAM ;And fetch MSW of FPACC NDA ;Test the contents of MSW of FPACC JTS OUTNEG ;If most significant bit of MSW is a one, have a minus nr. LAI 253 ;Else number is positive set ASCII code for space for a JMP AHEAD1 ;Positive number and go display a space OUTNEG: LLI 124 ;If number in FPACC is negative must negate in orde LBI 003 ;To display. Set pntr to LSW of FPACC & set prec. cntr. CAL COMPLM ;Negate the number in the FPACC to make it positive LAI 255 ;But load ACC with ASCII code for minus sign AHEAD1: CAL ECHO ;Call user display driver to output space or minus sign LAI 260 ;Load ASCII code for '0' into accumulato CAL ECHO ;Call user display driver to output '0' as first characte LAI 256 ;Number string. Now load ASCII code for decimal point. CAL ECHO ;Call user display driver to output '.'as second character. LLI 127 ;Set pointer to FPACC Exponent LAI 377 ;Load accumulator with minus one ADM ;Add value in FPACC Exponent LMA ;Restore compensated exponent value DECEXT: JFS DECEXD ;If compen exp is zero or positive, multip MANT by 0.1 LAI 004 ;If compensated exponent is negative ADM ;Add '4' (decimal) to exponent value JFS DECOUT ;If exponent now zero or positive, output MANTISSA CAL FPX10 ;Otherwise, multiply MANTISSA by 10 DECREP: LLI 127 ;Reset pointer to FPACC Exponent LAM ;Fetch value in exponent NDA ;Test value JMP DECEXT ;Repeat process as required DECEXD: CAL FPD10 ;Multiply FPACC by 0.1 JMP DECREP ;Repeat process as required ;The next section outputs the mantissa ;(or fixed point number) by converting the value remaining ;in the FPACC (after the decimal exponent equivalent has ;been extracted from the original value if required by the ;previous routines) to a string of decirnal digits. DECOUT: LEI 164 ;Set pointer to LSW of output working registe LDH ;Set D to same page value as H LLI 124 ;Set pointer to LSW of FPACC LBI 003 ;Set precision counte CAL MOVEIT ;Move value in FPACC to output working registe LLI 167 ;Set pointer to MSW plus one of output working registe LMI 000 ;Clear that location to 0 LLI 164 ;Set pointer to LSW of output working registe LBI 003 ;Set precision counte CAL ROTATL ;Rotate register left once to compensate for sign bit CAL OUTX10 ;Multiply output register by 10, overflow into N4SW+ 1 COMPEN: LLI 127 ;Set pointer back to FPACC Exponent LBM ;Compensate for any remainder in the binary exponent INB ;By performing a rotate right on the output working LMB ;Register until the binary exponent becomes zero JTZ OUTDIG ;Go output decimal digits when this loop is finished LLI 167 ;Binary exponent compensating loop. Setpointe'r to LBI 004 ;Working register MSW+L. Set precision counter. CAL ROTATR ;Rotate working register to the right. JMP COMPEN ;Repeat loop as required. OUTDIG: LLI 107 ;Set pointer to output digit counter storage location LMI 007 ;Initialize to value of seven LLI 167 ;Change pointer to output working register MSW+L LAM ;Fetch MSW+L byte containing BCD of digit to be NDA ;Displayed. Test the contents of this byte. JTZ ZERODG ;If zero jump to ZERODG routine. OUTDGS: LLI 167 ;Reset pointer to working register MSW+L LAI 260 ADM CAL ECHO DECRDG: LLI 107 ;Set pointer to FIXED/FLOAT indicator storage CAL CNTDWN JTZ EXPOUT CAL OUTX10 JMP OUTDGS ZERODG: LLI 157 ;If first digit of floating point number is a zero, set CAL CNTDWN ;Decrement the value to compensate for skipping LLI 166 ;Change pointer to MSW of output working registe LAM ;Fetch MSW of output working registe NDA ;Test the contents JFZ DECRDG ;If non-zero, continue outputting DCL ;Else decrement pointer to next byte in working registe LAM ;Fetch its contents NDA ;Test JFZ DECRDG ;If non-zero, continue outputting DCL ;Else decrement pointer to LSW of working registe LAM ;Fetch its contents NDA ;Test JFZ DECRDG ;If non-zero, continue outputting LLI 157 ;If decimal mantissa is zero, set pointer to decirnal LMA ;Exponent storage and clear it JMP DECRDG ;Finish outputting ;Following routine multiplies the binary number in the ;output working register by ten to push the most signifi- ;cant digit out to the MSW+L byte. OUTX10: LLI 167 ;Set pointer to work ing register M SW+ 1 LMI 000 ;Clear it in preparation for receiving next digit pushed LLI 164 ;Into it. Change pointer to working register LSW. LDH ;Set up register D to same page as H. LEI 160 ;Set second pointer to LSW of second working registe LBI 004 ;Set precision counte CAL MOVEIT ;Move first working register into second LLI 164 ;Reset pointer to LSW of first working registe LBI 004 ;Set precision counte CAL ROTATL ;Rotate contents of first working register left (X 2) LLI 164 ;Reset pointer to LSW LBI 004 ;Reset precision counte CAL ROTATL ;Rotate contents left again (X 4) LLI 160 ;Set pointer to LSW of original value in 2'nd registe LEI 164 ;Set pointer to LSW of rotated value LBI 004 ;Set precision counte CAL ADDER ;Add rotated value to original value (X 5) LLI 164 ;Reset pointer to LSW of first working registe LBI 004 ;Set precision counte CAL ROTATL ;Rotate contents left again (X 10) RET ;Exit to calling routine EXPOUT: LAI 305 ;Else, load ACC with ASCII code for letter E. CAL ECHO ;Display E for Exponent via user's display driver rtn LLI 157 LAM ;Get decimal exponent value back into ACC NDA ;Test again JTS EXOUTN ;If value is negative, skip ahead LAI 253 ;If positive, load ASCII code for + sign JMP AHEAD2 ;Jump to display the + sign EXOUTN: XRI 377 ;When decimal exponent is negative, must negate ADI 001 ;Value for display purposes. Perform two's complement LMA ;And restore the negated value to storage location LAI 255 ;Load ASCII code for minus sign AHEAD2: CAL ECHO ;Display the ASCII character in ACC LBI 000 ;Clear register B LAM ;Fetch the decimal exponent value back into ACC SUB12: SUI 012 ;Subtract 10 (decimal) from value in ACC JTS TOMUCH ;Break out of loop when accumulator goes negative LMA ;Else restore value to storage location INB ;Increment register B as a counte JMP SUB12 ;Repeat loop to form tens value of decimal exponent TOMUCH: LAI 260 ;Load base ASCII value for digit into the accumulato ADB ;Add to the count in B to forin tens digit of decimal CAL ECHO ;Exponent. Display via user's driver subroutine LAM ;Fetch remainder of decimal exponent value ADI 260 ;Add in ASCII base value to form final digit CAL ECHO ;Display second digit of decirnal exponent RET ;Finished outputting. Return to caller. DINPUT: LHI 000 ;** Set H to page of floating point working registers LLI 150 ;Set L to start of decirnal-to-binary working area XRA ;Clear the accumulato LBI 010 ;Set up a loop counte CLRNX2: LMA ;Deposit zero in working area to initialize INL ;Advance the memory pointe DCB ;Decrement the loop counte JFZ CLRNX2 ;Clear working area until loop counter is zero LLI 103 ;Set pointer to floating point temporary registers and LBI 004 ;Indicators working area. Set up a loop counter. CLRNX3: LMA ;Deposit zero in working area to initialize INL ;Advance the memory pointe DCB ;Decrement the loop counte JFZ CLRNX3 ;Clear working area until loop counter is zero CAL INPUT ;Fetch a character from the ASCII chax string buffe CPI 253 ;(Typically the SYMBOL/TOKEN buffer). See if it is JTZ SECHO ;Code for + sign. Jump ahead if code for + sign. CPI 255 ;See if code for minus (-) sign. JFZ NOTPLM ;Jump ahead if not code for minus sign. If code fo LLI 103 ;Minus sign, set pointer to MINUS flag storage location. LMA ;Set the MINUS flag to indicate a minus numbe ;Following subroutine is used ;to convert decimal charac- ;ters to binary fixed point forinat ;in a triple-precision format. SECHO: CAL ECHO NINPUT: CAL INPUT ;Fetch another character from the ASCII char string NOTPLM: CPI 377 ;See if character represents a period (decimal point) in JTZ ERASE ;Input string. Jump ahead if yes. CPI 256 JTZ PERIOD CPI 305 ;If not period, see if code for E as in Exponent JTZ FNDEXP ;Jump ahead if yes. CPI 260 ;Else see if code for space. JTS ENDINP ;Ignore space character, go fetch another character. CPI 272 ;If none of the above see if zero byte JFS ENDINP ;Indicating end of input char string. If yes, jumn ahead. LLI 156 ;For valid digit, set pointer to MSW of temporary LBA ;Decimal to binary holding registers. Save character in C. LAI 370 ;Form mask for sizing in accumulator. Now see if NDM ;Holding register has enough room for the conversion of JFZ NINPUT ;Another digit. Ignore the input if no more room. LAB CAL ECHO LLI 105 ;If have room in register then set pointer to input digit LCM ;Counter location. Fetch the present value. INC ;Increment it to account for incoming digit. LMC ;Restore updated count to storage location. CAL DECBIN ;Call the DECimal to BINary conversion routine to add JMP NINPUT ;In the new digit in holding registers. Continue inputting. PERIOD: LBA ;Save character code in register B LLI 106 ;Set pointer to PERIOD indicator storage location LAM ;Fetch value in PERIOD indicato NDA ;Exercise CPU flags JFZ ENDINP ;If already have a period then display error message LLI 105 ;If not, change pointer to digit counter storage location LMA ;Clear the digit counter back to zero INL ;Advance pointer to PERIOD indicato LMB ;Set the PERIOD indicato LAB CAL ECHO JMP NINPUT ;Continue processing the input character string ERASE: LAI 274 CAL ECHO LAI 240 CAL ECHO CAL ECHO JMP DINPUT FNDEXP: CAL ECHO CAL INPUT ;Get next character in Exponent CPI 253 ;See if it is code for + sign JTZ EXECHO ;Jump ahead if yes. CPI 255 ;If not + sign, see if minus sign JFZ NOEXPS ;If not minus sign then jump ahead LLI 104 ;For minus sign, set pointer to EXP SIGN indicato LMA ;Set the EXP SIGN indicator for a minus exponent EXECHO: CAL ECHO EXPINP: CAL INPUT ;Fetch the next character in the decimal exponent NOEXPS: CPI 377 ;Exercise the CPU flags JTZ ERASE ;If character inputted was zero, then end of input string CPI 260 ;If not end of string, check to see JTS ENDINP ;If character represents CPI 272 ;A valid decimal number (0 to 9) JFS ENDINP ;Display error message if not a valid digit at this point! NDI 017 ;Else trim the ASCII code to BCD LBA ;And save in register B LLI 157 ;Set pointer to input exponent storage location LAI 003 ;Set accumulator equal to three CPM ;See if any previous digit in exponent greater than three JTS EXPINP ;Display error message if yes LCM ;Else save any previous value in register C LAM ;And also place any previous value in accumulato NDA ;Clear the carry bit with this instruction RAL RAL ;Single precision multiply by ten algorithm ADC RAL ;Two rotate lefts equals times fou ADB ;Adding in the digit makes total times five LMA ;Rotating left again equals times ten LAI 260 ADB ;now add in digit just inputted JMP EXECHO ;Go get any additional exponent int)ut ENDINP: LLI 103 ;Set pointer to mantissa SIGN indicato LAM ;Fetch the SIGN indicator to the acclimulato NDA ;Exercise the CPU flags JTZ FININP ;If SIGN indicator is zero, go finish up as nr is positive LLI 154 ;But, if indicator is non-zero, number is negative LBI 003 ;Set pntr to LSW of storage registers, set precision ent CAL COMPLM ;Negate the triple-precision number in holding registers FININP: LLI 153 ;Set pointer to input storage LS~V minus one XRA ;Clear the accumulato LDA ;Clear the LSW minus one location LMA ;Set register D to floating point working page LEI 123 ;Set E to address of FPACC LSW minus one LBI 004 ;Set precision counte CAL MOVEIT ;Move number from input register to FPACC LBI 027 CAL FPNORM ;Now convert the binary fixed point to floating point LLI 104 ;Set pointer to Exponent SIGN indicator location LAM ;Fetch the value of the EXP SIGN indicato NDA ;Exercise the CPU flags LLI 157 ;Reset pointer to input exponent storage location JTZ POSEXP ;If EXP SIGN indicator zero, exponent is positive LAM ;Else, exponent is negative so must negate XRI 377 ;The value in the input exponent storage location ADI 001 ;By performing this two's complement LMA ;Restore the negated value to exponent storage location POSEXP: LLI 106 ;Set pointer to PERIOD indicator storage location LAM ;Fetch the contents of the PERIOD indicato NDA ;Exercise the CPU flags JTZ EXPOK ;If PERIOD indicator clear, no decimal point involved LLI 105 ;If have a decimal point, set pointer to digit counte XRA ;Storage location. Clear the accumulator. SUM ;And get a negated value of the digit counter in ACC EXPOK: LLI 157 ;Change pointer to input exponent storage location ADM ;Add this value to negated digit counter value LMA ;Restore new value to storage location JTS MINEXP ;If new value is minus, skip over next subroutine RTZ ;If new value is zero, no further processing required EXPFIX: CAL FPX10 ;Compensated decimal exponent is positive, multiply JFZ EXPFIX ;FPACC by 10, loop until decimal exponent is zero RET ;Exit with converted value in FP ACC ;Following subroutine will multiply the floating point ;binary number stored in FPACC by ten tirnes the ;value stored in the deciinal exponent storage location. FPX10: LEI 134 ;Multiply FPACC by 10 subroutine, set pointer to LDH ;FPOP LSW, then set D = zero for sure LLI 124 ;Set pointer to FP ACC LSW LBI 004 ;Set precision counter CAL MOVEIT ;Move FPACC to FPOP (including exponents) LLI 127 ;Set pointer to FP ACC exponent LMI 004 ;Place FP form of 10 (decimal) in FPACC DCL ;Place FP form of 10 (decimal) in FPACC LMI 120 ;Place FP form of 10 (decimal) in FPACC DCL ;Place FP form of 10 (decimal) in FPACC XRA ;Place FP form of 10 (decimal) in FPACC LMA ;Place FP form of 10 (decimal) in FPACC DCL ;Place FP form of 10 (decimal) in FPACC LMA ;Place FP form of 10 (decimal) in FPACC CAL FPMULT ;Now multiply original binary number (in FPOP) by ten LLI 157 ;Set pointer to decimal exponent storage CAL CNTDWN ;Decrement decimal exponent value RET ;Return to calling program ;Following subroutine will multiply the floating point ;binary number stored in PPACC by 0.1 times the value ;(negative) stored in the decimal exponent storage location MINEXP: CAL FPD10 ;Compensated decimal exponent is minus, multiply JFZ MINEXP ;FPACC by 0.1, loop until decimal exponent is zero RET ;Exit with converted value in FP ACC FPD10: LEI 134 ;Multiply FPACC by 0.1 routine, pointer to FPOP LSW LDH ;Set D = '0 ' for sure LLI 124 ;Set pointer to FP ACC LBI 004 ;Set pointer to FP ACC CAL MOVEIT ;Set precision counter LLI 127 ;Move FPACC to FPOP (including exponent) LMI 375 ;Set pointer to FPACC exponent DCL ;Place FP form of 0.1 (decimal) in FPACC LMI 146 ;Place FP form of 0 .1 (decimal) in FPACC DCL ;Place FP form of 0.1 (decimal) in FPACC LMI 146 ;Place FP form of 0 .1 (decimal) in FPACC DCL ;Place FP form of 0.1 (decimal) in FPACC LMI 147 ;Place FP form of 0.1 (decimal) in FPACC CAL FPMULT ;Place FP form of 0 .1 (decimal) in FPACC LLI 157 ;Now multiply original binary number (in FPOP) by 0.1 LBM ;Set pointer to decimal exponent storage INB ;Fetch value LMB ;Increment it RET ;Restore it to memory DECBIN: LLI 153 ;Set pointer to temporary storage location LAB ;Restore character inputted to accumulato NDI 017 ;Trim ASCII code to BCD LMA ;Store temporarily LEI 150 ;Set pointer to working area LSW of multi-byte registe LLI 154 ;Set another pointer to LSW of conversion registe LDH ;Make sure D set to page of working area LBI 003 ;Set precision counte CAL MOVEIT ;Move original value of conversion register to working LLI 154 ;Register. Reset pointer to LSW of conversion register. LBI 003 ;Set precision counte CAL ROTATL ;Rotate register left, (Multiplies value by two.) LLI 154 ;Reset pointer to LSW. LBI 003 ;Set precision counte CAL ROTATL ;Multiply by two again (total now times four). LEI 154 ;Set pointer to LSW of conversion register. LLI 150 ;Set pointer to LSW of working register (original value). LBI 003 ;Set precision counter. CAL ADDER ;Add original value to rotated value (now times five). LLI 154 ;Reset pointer to LSW LBI 003 ;Set precision counte CAL ROTATL ;Multiply by two once more (total now times ten). LLI 152 ;Set pointer to clear working register locatiotis XRA ;Clear the accumulato LMA ;Clear MSW of working registe DCL ;Decrement pointe LMA ;Clear next byte LLI 153 ;Set pointer to current digit storage location LAM ;Fetch the current digit LLI 150 ;Change pointer to LSW of working registe LMA ;Deposit the current digit in LSW of working registe LEI 154 ;Set pointer to conversion register LSW LBI 003 ;Set precision counte CAL ADDER ;Add current digit to conversion register to complete RET FPNORM: LAB ;Get CPU register B into ACC to check for special case NDA JTZ NOEXCO LLI 127 ;Set L to FPACC Exponent byte LMB ;Else set Exponent of FPACC to 23 decimal NOEXCO: LLI 126 LAM ;Fetch MSW of FPACC into accumulato LLI 100 ;Change pointer to SIGN indicator storage location NDA JTS ACCMIN XRA LMA ;Place the MSW of FPACC there for future reference JMP ACZERT ;If sign bit not set then jump ahead to do next test ACCMIN: LMA LBI 004 ;If sign bit set, number in FPACC is negative. Set up LLI 123 ;For two's complement operation CAL COMPLM ;And negate the value in the FPACC to make it positive ACZERT: LLI 126 ;Reset pointer to MSW of FPACC LBI 004 ;Set precision counter to number of bytes in FPACC LOOK0: LAM ;Plus one. Fetch a byte of the FPACC. NDA ;Set CPU flags JFZ ACNONZ ;If find anything then FPACC is not zero DCL ;Else decrement pointer to NSW of FPACC DCB ;Decrement precision counte JFZ LOOK0 ;Continue checking to see if FPACC contains anything LLI 127 ;Until precision counter is zero. If reach here then XRA ;Reset pointer to FPACC Exponent. Clear the ACC and LMA ;Clear out the FPACC Exponent. Value of FPACC is zip! RET ;Exit to calling routine ACNONZ: LLI 123 ;If FPACC has any value set pointer to LSW minus one LBI 004 ;Set precision counter to number of bytes in FPACC CAL ROTATL ;Plus one for special cases. Rotate the contents of the LAM ;FPACC to the LEFT. Pointer will be set to MSW afte NDA ;Rotate ops. Fetch MSW and see if have anything in JTS ACCSET ;Most significant bit position. If so, have rotated enough INL ;If not, advance pointer to FPACC Exponent. Fetch CAL CNTDWN JMP ACNONZ ;Continue rotating ops to normalize the FPACC ACCSET: LLI 126 ;Set pntr to FPACC MSW. Now must provide room fo LBI 003 ;Sign bit in nonnalized FPACC. Set precision counter. CAL ROTATR ;Rotate the FPACC once to the right now. LLI 100 ;Set the pointer to SIGN indicator storage location LAM ;Fetch the original sign of the FPACC NDA ;Set CPU flags RFS ;If original sign of FPACC was positive, can exit now. LLI 124 ; However, if original sign was negative, must now restore LBI 003 ;The FPACC to negative by performing two's comple- CAL COMPLM ;Ment on FPACC. Return to caring rtn via COMPLM. RET FPADD: LLI 126 ;Set pointer to MSW of FP ACC LBI 003 ;Set loop counter CKZACC: LAM ;Fetch part of FPACC NDA ;Set flags after loading operation JFZ NONZAC ;Finding anything means FPACC not zero DCB ;If that part equals zero, decrement loop counter JTZ MOVOP ;If FPACC equals zero , move FPOP into FPACC DCL ;Not finished checking, decrement pointer JMP CKZACC ;And test next part of FPACC MOVOP: CAL SWITCH ;Save pointer to LSW of FPACC LHD ;Set H equal to zero for sure LLI 134 ;Set pointer to LSW of FPOP LBI 004 ;Set a loop counter CAL MOVEIT ;Move FPOP into FPACC as answer RET ;Exit FP ADD subroutine NONZAC: LLI 136 ;Set pointer to MSW of FPOP LBI 003 ;Set loop counter CKZOP: LAM ;Set flags after load operation NDA ;If not zero then have a number JFZ CKEQEX ;If zero, decrement loop counter DCB ;Exit subroutine if FPOP equals zero RTZ ;Else decreme nt pointer to next part of FPOP DCL ;And continue testing for zero FPOP JMP CKZOP ;Check for equal expo nents CKEQEX: LLI 127 ;Get FPACC exponent LAM ;Change pointer to FPOP exponent LLI 137 ;Compare exponents CPM ;If same can setup for ADD operation JTZ SHACOP XRI 377 ;If not same, then two 's complement ADI 001 ;The value of the FP ACC exponent ADM ;And add in FPOP exponent JFS SKPNEG ;If + then go directly to alignment test XRI 377 ;If negative perform two's complement ADI 001 ;On the result SKPNEG: CPI 030 ;N ow see if result greater than 27 octal JTS LINEUP ;If not can perform alignment LAM ;If not alignable, get FPOP exponent LLI 127 ;Set pointer to FPACC exponent SUM ;Subtract FPACC exponent from FPOP exponent RTS ;FPACC exponent greater so just exit routine LLI 124 ;FPOP was greater, set pointer to FPACC LSW JMP MOVOP ;Go put FPOP into FPACC and then exit routine LINEUP: LAM ;Align FPACC and FPOP, get FPOP exponent LLI 127 ;Change pointer to FPACC exponent SUM ;Subtract FPACC exponent from FPOP exponent JTS SHIFTO ;FPACC greater so go to shift operand LCA ;FPOP greater so save difference MORACC: LLI 127 ;Pointer to FP ACC exponent CAL SHLOOP ;Call shift loop subroutine DCC ;Decrement difference counter JFZ MORACC ;Continue aligning if not done JMP SHACOP ;Setup for ADD operation SHIFTO: LCA ;Shift FPOP routine, save difference count (negative) MOROP: LLI 137 ;Set pointer to FPOP exponent CAL SHLOOP ;Call shift loop subroutine INC ;Increment difference counter JFZ MOROP ;Shift again if not done SHACOP: LLI 123 ;First clear out extra room, setup pointer LMI 000 ;to FP A CC LSW + 1 and set it to zero LLI 127 ;N ow prepare to shift FP ACC right once CAL SHLOOP ;Set pointer and then call shift loop routine LLI 137 ;Shift FPOP right once, first set pointer CAL SHLOOP ;Call shift loop subroutine LDH ;Setup pointers, set T) equal to zero for sure LEI 123 ;Pointer to LSW of FPACC LBI 004 ;Set precision counter CAL ADDER ;Add FPACC to FPOP using quad-precision LBI 000 ;Set B for standard normalization procedure CAL FPNORM ;Normalize the result of the addition RET ;Exit FP ADD subroutine with result in FP ACe SHLOOP: LBM ;Sh ifting loop for alignment INB ;Fetch exponent into B and increment LMB ;Return increment value to memory DCL ;Decrement the pointer LBI 004 ;Set a counter FSHIFT: LAM ;Get MSW of floating point number NDA ;Set flags after loading operation JTS BRING1 ;If number is minus, need to shift in a '1 ' CAL ROTATR ;Otherwise perform N'th-precision rotate RET ;Exit FSHIFT subroutine BRING1: RAL ;Save '1 ' in carry bit CAL ROTR ;Do ROT ATE RIGHT without clearing carry bit RET ;Exit FSHIFT SUbroutine MOVEIT: LAM ;Fetch a word from memory string' A' INL ;Advance 'A' string pointer CAL SWITCH ;Switch pointer to string 'B' LMA ;Put word from string 'A' into 'B' INL ;Advance B string pointer CAL SWITCH ;Switch pointer back to string 'A' DCB ;Decrement counter RTZ ;Return to calling routine when counter is zero JMP MOVEIT ;Otherwise continue moving operation FSUB: LLI 124 ;Set pointer to LSW of FPACC LBI 003 ;Set precision counter CAL COMPLM ;Perform two's complement on FPACC JMP FPADD ;Subtraction accomplished now by adding! ;The first part of the FLOATING POINT MULTIPLI- ;CATION subroutine calls a subroutine to check the ;original signs of the numbers that are to be multi- ;plied and perform working register clearing functions. ;Next the exponents of the numbers to be multiplied ;are added together. FPMULT: CAL CKSIGN ;Call routine to set up registers & ck signs of numbers ADDEXP: LLI 137 ;Set pointer to FPOP Exponent LAM ;Fetch FPOP Exponent into the accumulato LLI 127 ;Change pointer to FPACC Exponent ADM ;Add FPACC Exponent to FPOP Exponent ADI 001 ;Add one more to total for algorithm compensation LMA ;Store result in FPACC Exponent location SETMCT: LLI 102 ;Change pointer to bit counter storage location LMI 027 ;Initialize bit counter to 23 decimal ;Next portion of the FPMULT routine is the iinplernen- ;tation of the algorithm illustrated in the flow chart ;above. This portion multiplies the values of the two ;mantissas. The final value is rounded off to leave the ;23 most significant bits as the answer that is stored ;back in the FPACC. MULTIP: LLI 126 ;Set pointer to MSW of FPACC mantissa LBI 003 ;Set precision counte CAL ROTATR ;Rotate FPACC (multiplier) RIGHT into carry bit CTC ADOPPP ;If carry is a one, add multiplicand to partial-product LLI 146 ;Set pointer to partial-product most significant byte LBI 006 ;Set precision counter (p-p register is double length) CAL ROTATR ;Shift partial-product RIGHT LLI 102 ;Set pointer to bit counter storage location CAL CNTDWN JFZ MULTIP ;If have not multiplied for 23 (deciinal) bits, keep going LLI 146 ;If have done 23 (decimal) bits, set pntr to p-p MSW LBI 006 ;Set precision counter (for double length) CAL ROTATR ;Shift partial-product once more to the RIGHT LLI 143 ;Set pointer to access 24'th bit in partial-product LAM ;Fetch the byte containing the 24'th bit RAL ;Position the 24'th bit to be MSB in the accumulato LAA NDA ;Set the CPU flags after to rotate operation and test to CTS MROUND ;See if 24'th bit of p-p is a ONE. If so, must round-off LLI 123 ;Now set up pointers CAL SWITCH LHD LLI 143 ;From the partial-product location LBI 004 ;To the FPACC EXMLDV: CAL MOVEIT ;Perform the transfer from p-p to FPACC LBI 000 ;Set up CPU register B to indicate regular normalization CAL FPNORM ;Normalize the result of multiplication LLI 101 ;Now set the pointer to the original SIGNS indicato LAM ;Fetch the indicato NDA ;Exercise the CPU flags RFZ ;If indicator is non-zero, answer is positive can exit he LLI 124 LBI 003 CAL COMPLM RET ;The following portions of the FPMULT ;routine set up working locations in memory by clearing ;locations for an expanded FPOP area and the partial-produc ;area. Next, the signs of the two numbers to be multiplied ;are examined. Negative numbers are negated ;in preparation for the multiplication ;algorithm. A SIGNS indicator register is set up during ;this process to indicate whether the final result of the ;multiplication should be positive or negative. (Negative ;if original signs of the two numbers to be multiplied are ;different.) CKSIGN: CAL CLRWRK LLI 101 ;Set pointer to start of partial-product working area LMI 001 ;** Set H to proper page LLI 126 LAM NDA JTS NEGFPA OPSGNT: LLI 136 ;Set pointer to MSW of FPOP LAM ;Fetch MSW of mantissa into accumulato NDA ;Test flags RFS ;Return to caller if number in FPOP is positive LLI 101 ;Else change pointer to M/D SIGNS indicato CAL CNTDWN LLI 134 ;Set pointer to LSW of FPOP LBI 003 ;Set precision counte CAL COMPLM ;Two's complement value of FPOP & return to calle RET NEGFPA: LLI 101 ;Set pointer to M/D SIGNS indicato CAL CNTDWN LLI 124 ;Set pointer to LSW of FPACC LBI 003 ;Set precision counte CAL COMPLM ;Two's complement value of FPACC JMP OPSGNT ;Proceed to check sign of FPOP CLRWRK: LLI 140 LBI 010 XRA CLRNEX: LMA ;Now clear out locations for the partial-product DCB JTZ CLROPL INL ;Working registers JMP CLRNEX CLROPL: LBI 004 ;Set a loop counte LLI 130 ;Set up pointe CLRNX1: LMA ;Clear out some extra registers so that the DCB ;Perform clearing ops until loop counte RTZ INL JMP CLRNX1 ;Is zero ;The following subroutine adds the double length (six regis ;multiplicand in FPOP to the partial-product register when ;called on by the multiplication algorithm. ADOPPP: LEI 141 ;Pointer to LSW of partial-product LDH ;On same page as FPOP LLI 131 ;LSIV of FPOP which contains extended multiplicand LBI 006 ;Set precision counter (double length working registers) CAL ADDER ;Add multiplicand to partial-product & return to calle RET MROUND: LBI 003 ;Set up precision counte LAI 100 ;Prepare to add one to 24'th bit of partial-product ADM ;Add one to the 24'th bit of the partial-product CROUND: LMA ;Restore the updated byte to memory INL ;Advance the memory pointer to next most significant LAI 000 ;Byte of partial-product, then clear ACC without ACM ;Disturbing carry bit. Now perform add with carry to DCB ;Propagate any rounding in the partial-product registers. JFZ CROUND ;If cotinter is not zero continue propagating any carry LMA ;Restore final byte to memory RET ;Exit to calling routine FPDIV: CAL CKSIGN ;Call routine to set up registers & ck signs of numbers LLI 126 ;Set pointer to MSW of FPACC (divisor) LAI 000 ;Fetch MSW of FPACC to accumulato CPM JFZ SUBEXP DCL CPM JFZ SUBEXP DCL CPM JTZ DERROR ;If MSW of FPACC is zero go display 'DZ' error message SUBEXP: LLI 137 ;Set pointer to FPOP (dividend) Exponent LAM ;Get FPOP Exponent into accumulato LLI 127 ;Change pointer to FPACC (divisor) Exponent SUM ;Subtract divisor exponent from dividend exponent ADI 001 ;Add one for algorithm compensation LMA ;Place result in FPACC Exponent SETDCT: LLI 102 ;Set pointer to bit counter storage location LMI 027 ;Initialize bit counter to 23 decimal ;Main division algorithm for mantissas DIVIDE: CAL SETSUB ;Go subtmct divisor from dividend JTS NOGO ;If result is negative then place a zero bit in quotient LEI 134 ;If result zero or positive then move remainder afte LLI 131 ;Subtraction from working area to become new dividend LBI 003 ;Set up moving pointers and initialize precision counte CAL MOVEIT ;Perform the transfe LAI 001 ;Place a one into least significant bit of accumulato RAR ;And rotate it out into the carry bit JMP QUOROT ;Proceed to rotate the carry bit into the current quotient NOGO: LAI 000 ;When result is negative, put a zero in the carry bit, then RAR QUOROT: LLI 144 ;Set up pointer to LSW of quotient registe LBI 003 ;Set precision counte CAL ROTL ;Rotate carry bit into quotient by using special entry to LLI 134 ;ROTATL subroutine. Now set up pointer to dividend LBI 003 ;LSW and set precision counte CAL ROTATL ;Rotate the current dividend to the left LLI 102 ;Set pointer to bit counter storage location CAL CNTDWN JFZ DIVIDE ;If bit counter is not zero, continue division process CAL SETSUB ;After 23 (decimal) bits, do subtraction once more fo JFS DVEXIT ;Possible rounding. Jump ahead if no rounding required. LLI 144 ;If rounding required set pointer to LSW of quotient LAM ;Fetch LSW of quotient to accumulato ADI 001 ;Add one to 23rd bit of quotient LMA ;Restore updated LSW of quotient LAI 000 ;Clear accumulator without disturbing carry bit INL ;Advance pointer to next significant byte of quotient ACM ;Propagate any carry as part of rounding process LMA ;Restore the updated byte of quotient LAI 000 ;Clear ACC again without disturbing carry bit INL ;Advance pointer to MSW of quotient ACM ;Propagate any carry to finish rounding process LMA ;Restore the updated byte of quotient JFS DVEXIT ;If most significant bit of quotient is zero, go finish up LBI 003 ;If not, set precision counte CAL ROTATR ;And rotate quotient to the right to clear the sign bit LLI 127 ;Set pointer to FPACC Exponent LBM ;Fetch FPACC exponent INL ;Increment the value to compensate for the rotate right LMB ;Restore the updated exponent value DVEXIT: LLI 144 ;Set up pointers LEI 124 ;To transfer the quotient into the FPACC LBI 003 ;Set precision counte ;THIS IS A CORRECTION FOUND IN THE NOTES JMP EXMLDV ;And exit through FPMULT routine at EXMLDV ;Subroutine to subtract divisor from dividend. Used by ;main DIVIDE subroutine. SETSUB: LLI 131 ;Set pointer to LSW of working area CAL SWITCH LHD ;On same page as FPACC LLI 124 ;Set pointer to LSW of FPACC (divisor) LBI 003 ;Set precision counte CAL MOVEIT ;Perform transfe LEI 131 ;Reset pointer to LSW of working area (now divisor) LLI 134 ;Reset pointer to LSW of FPOP (dividend) LBI 003 ;Set precision counte CAL SUBBER ;Subtract divisor from dividend LAM ;Get MSW of the result of the subtraction operations NDA ;Exercise CPU flags RET ;Return to caller with status DERROR: CAL DERMSG JMP USERDF ADDER: NDA ;Initialize the carry bit to zero upon entry ADDMOR: LAM ;Fetch byte from register group A CAL SWITCH ;Switch memory pointer to register group B ACM ;Add byte from A to byte from B with carry LMA ;Leave result in register group B DCB ;Decrement number of bytes (precision) counte RTZ ;Return to caller when all bytes in group processed INL ;Else advance pointer for register group B CAL SWITCH ;Switch memory pointer back to register group A INL ;Advance the pointer for register group A JMP ADDMOR ;Continue the multi-byte addition operation ;Subroutine to exchange the contents of H & L with ;D & E. SWITCH: LCH ;Transfer register H to C temporarily LHD ;Place value of D into H LDC ;Now put former H from C into D LCL ;Transfer register L to C temporarily LLE ;Place value of E into L LEC ;Now put former L from C into E RET ;Exit to calling routine CNTDWN: LCM ;Fetch counter DCC ;Decrement value LMC ;Return counter to storage RET ;Exit subroutine ;N'th precision two's complement (negate) ;subroutine. Performs a two's complement on the multi-byte ;registers tarting at the address pointed ; to by H & L (least significant byte) upon entry. COMPLM: LAM ;Fetch the least significant byte of the number to ACC XRI 377 ;Exclusive OR to complement the byte ADI 001 ;Add one to form two's complement of byte MORCOM: LMA ;Restore the negated byte to memory RAR ;Save the carry bit LDA ;In CPU register D DCB ;Decrement number of bytes (precision) counte RTZ ;Return to caller when all bytes in number processed INL ;Else advance the pointe LAM ;Fetch the next byte of the number to ACC XRI 377 ;Exclusive OR to complement the byte LEA ;Save complemented value in register E temporarily LAD ;Restore previous carry status to ACC RAL ;And rotate it out to the carry bit LAI 000 ;Clear ACC without disturbing carry status ACE ;Add in any carry to complemented value JMP MORCOM ;Continue the two's complement procedure as req'd ;N'th precision subtraction subroutine. ;Number starting at location pointed to by D & E (least ;significant byte) is subtracted from number starting at ;address specified by contents of H & L. ROTATL: NDA ;CLEAR CARRY FLAG AT THIS ENTRY POINT ROTL: LAM ;FETCH WORD FROM MEMORY RAL ;ROTATE LEFT (WITH CARRY) LMA ;RESTORE ROTATED WORD TO MEMORY DCB ;DECREMENT "PRECISION" COUNTER RTZ ;RETURN TO CALLING ROUTINE WHEN DONE INL ;OTHERWISE ADVANCE PNTR TO NEXT WORD JMP ROTL ;AND ROTATE ACROSS THE HEM WORD STRING ROTATR: NDA ;CLEAR CARRY FLAG AT THIS ENTRY POINT ROTR: LAM ;FETCH WORD FROM MEMORY RAR ;ROTATE RIGHT (WITH CARRY) LMA ;RESTORE ROTATED WORD TO MEMORY DCB ;DECREMENT "PRECISION" COUNTER RTZ ;RETURN TO CALLING ROUTINE WHEN DONE DCL ;GOING OTHER WAY SO DECREMENT MEM PNTR JMP ROTR ;AND ROTATE ACROSS THE MEM WORD STRING SUBBER: NDA ;Initialize the carry bit to zero upon entry SUBTRA: LAM ;Fetch byte from register group A CAL SWITCH ;Switch memory pointer to register group B SBM ;Subtract byte from group B ftom that in group A LMA ;Leave result in register group B DCB ;Decrement number of bytes (precision) counte RTZ ;Return to caller when all bytes in group processed INL ;Else advance pointer for register group B CAL SWITCH ;Switch memory pointer back to register group A INL ;Advance the pointer for register group A JMP SUBTRA ;Continue the multi-byte subtraction operation DERMSG: ORG 007#100 ;Attempted divide by zero error message HLT USERDF: ORG 007#160 ;Direct program flow after above error HLT ;;; HERE IS THE USER DEFINED CHARACTER INPUT TO READ FROM SERIAL PORT ; Returns Character in A, destroys B, C, and D ; WAIT for start bit INPORT: EQU 5 OUTPORT: EQU 016 INPUT: ORG 007#200 ;ASCII input routine ; DATA 101 ; LBI 0 ; LCI 0 ; LDI 0 ; LEI 0 ; RET INP INPORT NDA ; 5 JTS INPUT ; 9/11 ; found - delay 1 1/2 bit times LCI 322 ; 8 /2400 or 322/110 TIMER: ; DCC ; 5 JFZ TIMER ; 9/11 ;grab 8 bits LDI 8 ; 8 ; get 1 bit ; MSB of port contains input stream ; read and move to carry ; shift into MS bit position ; and maintain in B register DATAIN: INP INPORT ; 8 RAL ; 5 LAB ; 5 RAR ; 5 LBA ; 5 ; delay 1 bit time LCI 214 ; 8 214(o) 110 or 3/2400 baud BITTIMER: ; DCC ; 5 JFZ BITTIMER ; 9/11 LAA ; 5 delay to make timing better DCD ; 5 JFZ DATAIN ; 9/11 ; ; result goes to a and return ; LAB ; ORI 200 ; set MSB RET ;;; HERE IS THE USER DEFINED PRINT ROUTINE FOR A SERIAL PORT ; input in A ; destroys D ECHO: ORG 007#300 ;ASCII Output routine ; DATA 131 ; LDI 0 ; RET NDI 177 ; mask MSbit RAL OUT OUTPORT RAR LAA ; delay to make timing work LAA LDI 151 ; delay counter 2/2400 baud CAL MORE2 CAL BITOUT ; LSB CAL BITOUT ; 1 CAL BITOUT ; 2 CAL BITOUT ; 3 CAL BITOUT ; 4 CAL BITOUT ; 5 CAL BITOUT ; 6 CAL BITOUT ; MSB LDA ; timing delay LAI 001 OUT OUTPORT ; stop bit LDI 200 ; 5 2400 baud 200/110 JMP MORE2 BITOUT: OUT OUTPORT RRC ; shift to get next bit LDI 152 ; 3 2400 or 152/110 MORE2: LAA ; nop to delay 5 states to make timing work DCD JFZ MORE2 LDI 0 ; delay 8 states RET DUMMY: RET CNTUP: LCM ;Fetch CNTR indicated by H & L INC ;In crement value of the counter in reg C LMC ;Restore new counter value t o memory RET ;Exit subroutine