home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / DRI-archive / roche / lllfp_roche.asm < prev    next >
Assembly Source File  |  2009-12-11  |  43KB  |  1,623 lines

  1. ; LLLFPODT.ASM
  2. ; ---------
  3. ;
  4. ; Lawrence Livermore Laboratories Floating-Point package
  5. ;
  6. ; 1973: Floating-Point Package for the MCS8 by David Mead
  7. ; 1974: 24-bit mantissa and I/O by Hal Brand
  8. ; 1975: Under/overflow bug fixed by Frank Olken
  9. ; Sept-Oct 2006: Disassembled by Emmanuel ROCHE
  10. ;
  11. ;--------------------------------
  12.     ORG    0900H        ; Special case
  13. ;--------------------------------
  14. ; Octal Debugger Tool (ODT) TTY routines
  15. ;
  16. outr    EQU    0030H        ; Output char in ?
  17. inp    EQU    00DBH        ; Input  char from ?
  18. ;
  19. ; Characteristics with sign extended
  20. ;
  21. minch    EQU    192        ; Minimum
  22. maxch    EQU     63        ; Maximum
  23. ;
  24. ;--------------------------------
  25. ; Divide subroutine.
  26. ;
  27. ldiv:    CALL    csign        ; Compute sign of result
  28.     CALL    zchk        ; Check if dividend = zero
  29.     JNZ    dtst2        ; If dividend <> 0, check divisor
  30.     CALL    bchk        ; Check for zero/zero
  31.     JZ    indfc        ; Zero/zero = indefinite
  32.     JMP    wzerc        ; Zero/non-zero = zero
  33. ;
  34. dtst2:    CALL    bchk        ; Come here if dividend <> 0
  35.     JZ    oflwc        ; Non-zero/zero = overflow
  36.                 ; If we get here, things look okay
  37.     MOV    E,L        ; Save base in E
  38.     MOV    L,C        ; Base 6 to L
  39.     CALL    dclr        ; Clear quotient mantissa slot
  40.     MOV    L,E        ; Restore base in L
  41.     CALL    ent1        ; Do first cycle
  42.     MOV    L,C        ; Base 6 to L
  43.     CALL    dlst        ; Move quotient over one place
  44.     MVI    D,23        ; Number of iterations to D
  45. rep3:    MOV    L,E        ;
  46.     CALL    ent2        ;
  47.     DCR    D        ; Decrement D
  48.     JZ    goon        ;
  49.     MOV    A,L        ;
  50.     MOV    L,C        ; Base 6 to L
  51.     MOV    C,A        ;
  52.     CALL    dlst        ; Move quotient mantissa over
  53.     MOV    A,L        ; C-ptr to A
  54.     MOV    E,C        ; L-ptr to E
  55.     MOV    C,A        ; C-ptr to C
  56.     JMP    rep3        ;
  57. ;
  58. goon:    CALL    aors        ; Check if result is normalized
  59.     JM    crin        ;
  60.     MOV    A,L        ; L-ptr to A
  61.     MOV    L,C        ; C-ptr to L
  62.     MOV    C,A        ; L-ptr to C
  63.     CALL    dlst        ; Shift quotient left
  64.     MOV    C,L        ;
  65.     MOV    L,E        ;
  66.     CALL    ldcp        ; Compute the characteristic of result
  67.     RET            ;
  68. ;
  69. crin:    CALL    cfche        ; Get A=char(HL), E=char(H,B)
  70.     SUB    E        ; New char = char(dividend) - char(divisor)
  71.     CPI    7FH        ; Check max positive number
  72.     JZ    oflwc        ; Jump on overflow
  73.     ADI    01H        ; Add 1, since we did not left shift
  74.     CALL    cchk        ; Check and store chraracteristic
  75.     RET            ;
  76. ;
  77. ;--------------------------------
  78. ; Addition subroutine.
  79. ;
  80. ladd:    XRA    A        ; Set up to add
  81.     JMP    lads        ; Now, do it
  82. ;
  83. ;--------------------------------
  84. ; Subtraction subroutine.
  85. ;
  86. lsub:    MVI    A,128        ; Set up to subtract
  87. ;
  88. ; Subroutine LADS.
  89. ;
  90. ; Floating-Point add or sub
  91. ; A = 128 on entry to SUB
  92. ; A = 0 on entry to ADD
  93. ; F-S F, first operand destroyed
  94. ; Base 11 used for scatch
  95. ;
  96. lads:    CALL    acpr        ; Save entry point at base 6
  97.     CALL    bchk        ; Check addend/subtrahend = zero
  98.     RZ            ; If so, result=arg, so return
  99.                 ; This will prevent underflow
  100.                 ;   indication on zero + or - zero.
  101.     CALL    ccmp        ;
  102.     JZ    eq02        ; If equal, go on
  103.     MOV    D,A        ; Save L-ptr char in D
  104.     JC    lltb        ;
  105.     SUB    E        ; L > D if here
  106.     ANI    127        ;
  107.     MOV    D,A        ; Difference to D
  108.     MOV    E,L        ; Save base in E
  109.     MOV    L,C        ; C-ptr to L
  110.     INR    L        ; C-ptr 1 to L
  111.     MOV    M,E        ; Save base in C ptr 1
  112.     MOV    L,B        ; B-ptr to L
  113.     JMP    nchk        ;
  114. ;
  115. lltb:    MOV    A,E        ; L < B if here, B-ptr to A
  116.     SUB    D        ; Subtract L-ptr char from B-ptr char
  117.     ANI    127        ;
  118.     MOV    D,A        ; Difference to D
  119. nchk:    MVI    A,24        ;
  120.     CMP    D        ;
  121.     JNC    sh10        ;
  122.     MVI    D,24        ;
  123. sh10:    ORA    A        ;
  124.     CALL    drst        ;
  125.     DCR    D        ;
  126.     JNZ    sh10        ;
  127.     MOV    A,L        ;
  128.     CMP    B        ;
  129.     JNZ    eq02        ; F > S if L <> B
  130.     MOV    L,C        ; C-ptr to L
  131.     INR    L        ; C-ptr 1 to L
  132.     MOV    L,M        ; Restore L
  133. eq02:    CALL    lasd        ; Check what to
  134.     CALL    acpr        ; Save answer
  135.     CPI    02H        ; Test for zero answer
  136.     JNZ    not0        ;
  137.     JMP    wzer        ; Write floating zero and return
  138. ;
  139. not0:    MVI    D,01H        ; Will test for sub
  140.     ANA    D        ;
  141.     JZ    addz        ; LSB 1 implies sub
  142.     CALL    tstr        ; Check normal/reverse
  143.     JZ    subz        ; If normal, go SUBZ
  144.     MOV    A,L        ; Otherwise, reverse
  145.     MOV    L,B        ;   roles
  146.     MOV    B,A        ;   of L and B.
  147. subz:    CALL    dsub        ; Subtract smaller from bigger
  148.     CALL    mant        ; Set up sign of result
  149.     CALL    tstr        ; See if we need to interchange B-ptr and L-ptr
  150.     JZ    norm        ; No interchange nexessary, so normalize
  151.                 ;   and return.
  152.     MOV    A,L        ; Interchange
  153.     MOV    L,B        ;   L
  154.     MOV    B,A        ;   and B.
  155.     MOV    A,C        ; C-ptr to A
  156.     MOV    C,B        ; B-ptr to C
  157.     MOV    E,L        ; L-ptr to E
  158.     MOV    B,A        ; C-ptr to B
  159.     CALL    lxfr        ; Move B-ptr> to L-ptr>
  160.     MOV    A,B        ;
  161.     MOV    B,C        ;
  162.     MOV    C,A        ;
  163.     MOV    L,E        ;
  164.     JMP    norm        ; Normalize result and return
  165. ;
  166. ; Copy the larger characteristic to the result.
  167. ;
  168. addz:    CALL    ccmp        ; Compare the characteristic
  169.     JNC    add2        ; If char(HL) > char(H,B) continue
  170.     CALL    bctl        ; If char(HL) < char(H,B), then copy
  171.                 ;   char(H,B) to char(HL).
  172. add2:    CALL    mant        ; Compute sign of result
  173.     CALL    dadd        ; Add mantissas
  174.     JNC    sccfg        ; If there is no overflow: done
  175.     CALL    drst        ; If overflow, shift right
  176.     CALL    incr        ;   and increment characteristic.
  177.     RET            ; All done, so return
  178. ;
  179. ; This routine stores the mantissa sign in the result.
  180. ; The sign has previously been computed by LASD.
  181. ;
  182. mant:    MOV    E,L        ; Save L-ptr
  183.     MOV    L,C        ; C-ptr to L
  184.     MOV    A,M        ; Load index word
  185.     ANI    128        ; Scarf sign
  186.     MOV    L,E        ; Restore L-ptr
  187.     INR    L        ; L-ptr 2
  188.     INR    L        ;
  189.     INR    L        ; To L
  190.     MOV    E,A        ; Save sign in E
  191.     MOV    A,M        ;
  192.     ANI    127        ; Scarf char
  193.     ADD    E        ; Add sign
  194.     MOV    M,A        ; Store it
  195.     DCR    L        ; Restore
  196.     DCR    L        ;
  197.     DCR    L        ; L-ptr
  198.     RET            ;
  199. ;
  200. ; Subroutine LASD.
  201. ;
  202. ; Utility routine for LADS.
  203. ; Calculates true operand and sign.
  204. ; Returns answer in
  205. ;
  206. lasd:    CALL    msfh        ; Fetch mantissa signs, F in A,D
  207.     CMP    E        ; Compare signs
  208.     JC    abch        ; F, S- means go to A branch
  209.     JNZ    bbch        ; F-, S means go to B branch
  210.     ADD    E        ; Same sign if here: add signs
  211.     JC    bmin        ; If both minus, will overflow
  212.     CALL    aors        ; Both positive if here
  213.     JP    L000        ; If an add, load 0
  214. com1:    CALL    dcmp        ; Compare F sign S
  215.     JC    L131        ; S > F, so load 131
  216.     JNZ    L001        ; F > S, so load 1
  217. L002:    MVI    A,02H        ; Error condition: zero answer
  218.     RET            ;
  219. ;
  220. bmin:    CALL    aors        ; Check for add or sub
  221.     JP    L128        ; Add, so load 128
  222. com2:    CALL    dcmp        ; Compare F with S
  223.     JC    L003        ; S > F, so load 3
  224.     JNZ    L129        ; F > S, so load 129
  225.     JMP    L002        ; Error
  226. ;
  227. abch:    CALL    aors        ; FT, S-, so test for A/S
  228.     JM    L000        ; Subtract, so load 0
  229.     JMP    com1        ; Add, so go to DCMP
  230. ;
  231. bbch:    CALL    aors        ; F-, S, so test for A/S
  232.     JM    L128        ; Sub
  233.     JMP    com2        ; Add
  234. ;
  235. L000:    XRA    A        ; 0
  236.     RET            ;
  237. ;
  238. L001:    MVI    A,1        ; 1 
  239.     RET            ;
  240. ;
  241. L003:    MVI    A,3        ; 3 
  242.     RET            ;
  243. ;
  244. L128:    MVI    A,128        ; 128
  245.     RET            ;
  246. ;
  247. L129:    MVI    A,129        ; 129
  248.     RET            ;
  249. ;
  250. L131:    MVI    A,131        ; 131
  251.     RET            ;
  252. ;
  253. ;--------------------------------
  254. ; Subroutine LMCM.
  255. ;
  256. ; Compares the magnitude of two floating-point numbers.
  257. ; Z 1 if, C 1 if F < S
  258. ;
  259. lmcm:    CALL    ccmp        ; Check chars
  260.     RNZ            ; Return if not equal
  261.     CALL    dcmp        ; If equal, check mantissas
  262.     RET            ;
  263. ;
  264. ;--------------------------------
  265. ; Multiply subroutine.
  266. ;
  267. ; L-ptr * B-ptr to C-ptr
  268. ;
  269. lmul:    CALL    csign        ; Compute sign of result and store it
  270.     CALL    zchk        ; Check first operand for zero
  271.     JZ    wzerc        ; Zero * anything = zero
  272.     CALL    bchk        ; Check second operand for zero
  273.     JZ    wzerc        ; Anything * zero = zero
  274.     MOV    E,L        ; Save L-ptr
  275.     MOV    L,C        ; C-ptr to L
  276.     CALL    dclr        ; Clear product mantissa locations
  277.     MOV    L,E        ; L-ptr to L
  278.     MVI    D,24        ; Load number of iterations
  279.     CALL    dclr        ; Shift L-ptr right
  280.     JC    dclr        ; Will add B-ptr if C < 1
  281.     MOV    A,L        ; Interchange
  282.     MOV    L,C        ;   L and
  283.     MOV    C,A        ;   C ptrs.
  284. intr:    CALL    dclr        ; Shift product over
  285.     MOV    A,L        ; Interchange
  286.     MOV    L,C        ;   L and C ptrs back to
  287.     MOV    C,A        ;   original>.
  288.     DCR    D        ;
  289.     JNZ    dclr        ; More cycles if Z < 0
  290.     CALL    dclr        ; Test if result is normalized
  291.     JM    dclr        ; If normalized, go compute char
  292.     MOV    E,L        ; Save L-ptr in E
  293.     MOV    L,C        ; Set L=C-ptr
  294.     CALL    dclr        ; Left shift result to normalize
  295.     MOV    L,E        ; Restore L-ptr
  296.     CALL    dclr        ; Otherwise, set A=char(HL), E=char(H,B)
  297.     ADD    E        ; Char(result) = char(HL) + char(H,B)
  298.     CPI    32        ; Check for smallest negative number
  299.     JZ    dclr        ; If so, then underflow
  300.     SUI    01H        ; Subtract 1 to compensate for normalize
  301.     CALL    dclr        ; Check characteristic and store it
  302.     RET            ; Return
  303. ;
  304. madd:    MOV    A,L        ; Interchange
  305.     MOV    L,C        ;   L and
  306.     MOV    C,A        ;   C ptrs.
  307.     CALL    dclr        ; Accumulate product
  308.     JMP    intr        ;
  309. ;
  310. ;--------------------------------
  311. ; Subroutine NORM.
  312. ;
  313. ; This subroutine will normalize a floating-point number,
  314. ; preserving its original sign.
  315. ; We check for underflow, and set the condition flag appropriately.
  316. ; (See "Error returns".)
  317. ; There is an entry point to float a signed integer (FLOAT),
  318. ; and an entry point to float an unsigned integer.
  319. ;
  320. ; Entry points:
  321. ; NORM  -- Normalize floating-point number at (HL)
  322. ; FLOAT -- Float triple-precision integer at (HL),
  323. ;       preserving sign bit in (HL)+3.
  324. ; DFXL  -- Float unsigned (positive) triple-precision integer at (HL).
  325. ;
  326. ; Registers on exit:
  327. ; A = condition flag (see "Error returns".)
  328. ; D,E = garbage
  329. ; B,C,H,L = same as on entry
  330. ;
  331. norm:    MOV    E,L        ; Save L in E
  332.     CALL    gchar        ; Get char(HL) in A with sign extended
  333.     MOV    D,A        ; Save char in D
  334.     MOV    L,E        ; Restore L
  335. fxl2:    CALL    zmchk        ; Check for zero mantissa
  336.     JZ    wzer        ; If zero mantissa, then zero result
  337. rep6:    MOV    A,M        ; Get MSByte of mantissa
  338.     ORA    A        ; Set flags
  339.     JM    schar        ; If MSB=1, then number is normalized
  340.                 ;   and we go to store the characteristic.
  341.     MOV    A,D        ; Otherwise, check for underflow
  342.     CPI    minch        ; Compare with minimum char
  343.     JZ    wund        ; If equal, then underflow
  344.     CALL    dlst        ; Shift mantissa left
  345.     DCR    D        ; Decrement characteristic
  346.     JMP    rep6        ; Loop and test next bit
  347. schar:    JMP    incr3        ; Store the charactersitic, using
  348.                 ;   the same code as the increment.
  349. ;
  350. dfxl:    MOV    E,L        ; Enter here to float unsigned integer
  351.                 ; First, save L in E
  352.     INR    L        ; Make (HL) point to char
  353.     INR    L        ; Make (HL) point to char
  354.     INR    L        ; Make (HL) point to char
  355.     XRA    A        ; Zero Accumulator
  356.     MOV    M,A        ; Store a plus (+) sign
  357.     MOV    L,E        ; Restore L
  358. float:    MVI    D,24        ; Enter here to float integer,
  359.                 ;   preserving original sign in (HL)+3.
  360.     JMP    fxl2        ; Go float the number
  361. ;
  362. ;--------------------------------
  363. ; Subroutine ZCHK.
  364. ;
  365. ; This routine sets the Zero flag if it detects a floating zero at (HL).
  366. ;
  367. ; Subroutine ZMCHK.
  368. ;
  369. ; This routine sets the Zero flag if it detects a zero mantissa at (HL).
  370. ;
  371. zchk:
  372. zmchk:
  373.     INR    L        ; Set L to point to last byte of mantissa
  374.     INR    L        ; Set L to point to last byte of mantissa
  375.     MOV    A,M        ; Load least significant byte
  376.     DCR    L        ; L points to middle byte
  377.     ORA    M        ; OR with LSByte
  378.     DCR    L        ; L points to MSByte of mantissa (org val)
  379.     ORA    M        ; OR in MSByte
  380.     RET            ; Returns with Zero flag set appropriately
  381. ;
  382. ;--------------------------------
  383. ; Subroutine BCHK.
  384. ;
  385. ; This routine checks (H,B) for floating-point zero.
  386. ;
  387. bchk:    MOV    E,L        ; Save L-ptr in E
  388.     MOV    L,B        ; Set L=B-ptr
  389.     CALL    zchk        ; Check for zero
  390.     MOV    L,E        ; Restore L=L-ptr
  391.     RET            ; Return
  392. ;
  393. ;--------------------------------
  394. ; Subroutine DLST.
  395. ;
  396. ; Shifts double word one place left.
  397. ;
  398. dlst:    INR    L        ;
  399.     INR    L        ; TP
  400.     MOV    A,M        ; Load it
  401.     ORA    A        ; Kill Carry
  402.     RAL            ; Shift if left
  403.     MOV    M,A        ; Store it
  404.     DCR    L        ;
  405.     MOV    A,M        ; Load it
  406.     RAL            ; Shift if left
  407. ; If Carry set by first shift, it will be in LSB of second word.
  408.     MOV    M,A        ;
  409.     DCR    L        ; TP extension
  410.     MOV    A,M        ;
  411.     RAL            ;
  412.     MOV    M,A        ; All done TP
  413.     RET            ;
  414. ;
  415. ;--------------------------------
  416. ; Subroutine DRST.
  417. ;
  418. ; Shifts double word one place to the right.
  419. ; Does not affect D.
  420. ;
  421. drst:    MOV    E,L        ; TP modified right shift TP
  422.     MOV    A,M        ; Load first word
  423.     RAR            ; Rotate it right
  424.     MOV    M,A        ; Store it
  425.     INR    L        ; TP
  426.     MOV    A,M        ; Load second word
  427.     RAR            ; Shift it right
  428.     MOV    M,A        ; Store it
  429.     INR    L        ; TP extension
  430.     MOV    A,M        ;
  431.     RAR            ;
  432.     MOV    M,A        ;
  433.     MOV    L,E        ; TP -- All done TP
  434.     RET            ;
  435. ;
  436. ;--------------------------------
  437. ; Subroutine DADD.
  438. ;
  439. ; Adds two double precision words, C 1 if there is overflow.
  440. ;
  441. dadd:    MOV    E,L        ; Save base in E
  442.     MOV    L,B        ; Base 3 to L
  443.     INR    L        ; Base 4 to L
  444.     INR    L        ; TP
  445.     MOV    A,M        ; Load S mantB
  446.     MOV    L,E        ; Base to L
  447.     INR    L        ; Base+1 to L
  448.     INR    L        ; TP
  449.     ADD    M        ; Add two mantBs
  450.     MOV    M,A        ; Store answer
  451.     MOV    L,B        ; TP extension
  452.     INR    L        ;
  453.     MOV    A,M        ;
  454.     MOV    L,E        ;
  455.     INR    L        ;
  456.     ADC    M        ;
  457.     MOV    M,A        ; TP -- All done
  458.     MOV    L,B        ; Base 3 to L
  459.     MOV    A,M        ; MantA of S to A
  460.     MOV    L,E        ; Base to L
  461.     ADC    M        ; Add with Carry
  462.     MOV    M,A        ; Store answer
  463.     RET            ;
  464. ;
  465. ;--------------------------------
  466. ; Subroutine DCLR.
  467. ;
  468. ; Clears two successive locations of memory.
  469. ;
  470. dclr:    XRA    A        ;
  471.     MOV    M,A        ;
  472.     INR    L        ;
  473.     MOV    M,A        ;
  474.     INR    L        ; TP extension
  475.     MOV    M,A        ; TP zero 3
  476.     DCR    L        ; TP -- All done
  477.     DCR    L        ;
  478.     RET            ;
  479. ;
  480. ;--------------------------------
  481. ; Subroutine DSUB.
  482. ;
  483. ; Double precision subtract.
  484. ;
  485. dsub:    MOV    E,L        ; Save base in E
  486.     INR    L        ; TP extension
  487.     INR    L        ; Start with lows
  488.     MOV    A,M        ; Get arg
  489.     MOV    L,B        ; Now, set up to subtract
  490.     INR    L        ;
  491.     INR    L        ;
  492.     SUB    M        ; Now, do it
  493.     MOV    L,E        ; Now, must put it back
  494.     INR    L        ;
  495.     INR    L        ;
  496.     MOV    M,A        ; Put back
  497.     DCR    L        ; TP -- All done
  498.     MOV    A,M        ; Get low of L-op
  499.     MOV    L,B        ; Set to B-op
  500.     INR    L        ; Set to B-op low
  501.     SBB    M        ; Get difference of lows
  502.     MOV    L,E        ; Save in L-op low
  503.     INR    L        ; To L-op low
  504.     MOV    M,A        ; Into RAM
  505.     DCR    L        ; Back up to L-op high
  506.     MOV    A,M        ; Get L-op high
  507.     MOV    L,B        ; Set to B-op high
  508.     SBB    M        ; Subtract with Carry
  509.     MOV    L,E        ; Save in L-op high
  510.     MOV    M,A        ; Into RAM
  511.     RET            ; All done
  512. ;
  513. ;--------------------------------
  514. ; Subroutine GCHAR.
  515. ;
  516. ; This subroutine returns the characteristic of the floating-point
  517. ; number pointed to by (HL) in the A-register, with its sign extended
  518. ; into the leftmost bit.
  519. ;
  520. ; Registers on exit:
  521. ; A = characteristic of (HL) with sign extended
  522. ; L = (original L)+3
  523. ; B,C,D,E,H = same as on entry
  524. ;
  525. gchar:    INR    L        ; Make (HL) point to char
  526.     INR    L        ; Make (HL) point to char
  527.     INR    L        ; Make (HL) point to char
  528.     MOV    A,M        ; Set A=char + mantissa sign
  529.     ANI    7FH        ; Get rid of mantissa sign bit
  530.     ADI    64        ; Propagate char sign into leftmost bit
  531.     XRI    64        ; Restore original sign bit
  532.     RET            ;
  533. ;
  534. ; Return with (HL) pointing to the char = original (HL)+3
  535. ; Someone else will clean up
  536. ;--------------------------------
  537. ; Subroutine CFCHE.
  538. ;
  539. ; This subroutine returns the characteristic of the floating-point numbers
  540. ; pointed to by (HL) and (HB) in the A and E registers, respectively, with
  541. ; their signs extended into the leftmost bit.
  542. ;
  543. ; Registers on exit:
  544. ; A = characteristic of (HL) with sign extended
  545. ; C = characteristic of (HB) with sign extended
  546. ; B,C,H,L = same as on entry
  547. ; D = A
  548. ;
  549. cfche:    MOV    E,L        ; Save L-ptr in E
  550.     MOV    L,B        ; Set L=B-ptr
  551.     CALL    gchar        ; Get char(HB) with sign extended in A
  552.     MOV    L,E        ; Restore L=L-ptr
  553.     MOV    E,A        ; Set E=char(HB) with sign extended
  554.     CALL    gchar        ; Set A=char(HL) with sign extended
  555.     DCR    L        ; Restore L=L-ptr
  556.     DCR    L        ; Restore L=L-ptr
  557.     DCR    L        ; Restore L=L-ptr
  558.     MOV    D,A        ; Set D=A=char(HL) with sign extended
  559.     RET            ;
  560. ;
  561. ;--------------------------------
  562. ; Subroutine CCMP.
  563. ;
  564. ; This subroutine compares the charactersitic of floating-point numbers
  565. ; pointed to by (HL) and (HB).
  566. ; The Zero  flag is set if char(HL) equals char(HB).
  567. ; The Carry flag is set if char(HL) is less than char(HB).
  568. ;
  569. ; Registers on exit:
  570. ; A = characteristic of (HL) with sign extended
  571. ; E = charactersitic of (HB) with sign extended
  572. ; D = A
  573. ; B,C,H,L = same as on entry
  574. ;
  575. ccmp:    CALL    cfche        ; Fetch characteristic with sign extended
  576.                 ;   into A (char(HL)) and E (char(HB)) regs.
  577.     MOV    D,A        ; Save char (HL)
  578.     SUB    E        ; Subtract E (char(HB))
  579.     RAL            ; Rotate sign bit into Carry bit
  580.     MOV    A,D        ; Restore A=char(HL)
  581.     RET            ; Return
  582. ;
  583. ;--------------------------------
  584. ; Error returns.
  585. ;
  586. ; The following code is used to return various error conditions.
  587. ; In each case, a floating point number is stored in the four words
  588. ; pointed to by (HL), and a flag is stored in the Accumulator.
  589. ;
  590. ; Condition    Flag   Result  (+)    Result  (-)
  591. ; ---------    ----   -----------    -----------
  592. ; Underflow     FF    00 00 00 40    00 00 00 C0
  593. ; Overflow      7F    FF FF FF 3F    FF FF FF BF
  594. ; Indefinite    3F    FF FF FF 3F    FF FF FF BF
  595. ; Normal num.   00    xx xx xx xx    xx xx xx xx
  596. ; Normal zero   00    00 00 00 40    (always returns +0)
  597. ;
  598. ; Entry points:
  599. ; WUND -- Write UNDerflow
  600. ; WOVR -- Write OVeRflow
  601. ; WIND -- Write INDefinite
  602. ; WZER -- Write normal ZERo
  603. ;
  604. ; (WFLT = Write FLoaTing-point number)
  605. ;
  606. wflt    MACRO    vmant,vchar,vflag,label
  607.     MVI    D,vchar        ;; Load charactersitic into D-register
  608.     CALL    wchar        ;; Write characteristic
  609. label:    MVI    A,vmant        ;; Load mantissa value
  610. ;; We assume here that all bytes of mantissa are the same
  611.     CALL    wmant        ;; Write the mantissa
  612.     MVI    A,vflag        ;; Set Accumulator to flag
  613.     ORA    A        ;; Set flags properly
  614.     RET            ;; Return (WMANT restored (HL))
  615.     ENDM
  616. ;
  617. ; Write underflow, using WFLT macro.
  618. ;
  619. wund:    wflt    00H,40H,0FFH,uflw1
  620. ;
  621. ; Write overflow, using WFLT macro.
  622. ;
  623. wovr:    wflt    0FFH,3FH,7FH,oflw1
  624. ;
  625. ; Write indefinite, using WFLT macro.
  626. ;
  627. wind:    wflt    0FFH,3FH,3FH,indf1
  628. ;
  629. ; Write normal zero (not a macro).
  630. ;
  631. wzer:    INR    L        ;
  632.     INR    L        ;
  633.     INR    L        ;
  634.     MVI    M,40H        ; Store characteristic for zero
  635.     XRA    A        ; Zero Accumulator
  636.     CALL    wmant        ; Store zero mantissa
  637.     ORA    A        ; Set flags properly
  638.     RET            ; Return
  639. ;
  640. ;--------------------------------
  641. ; Routine to write mantissa for "error returns".
  642. ;
  643. wmant:    DCR    L        ; Point LSByte of mantissa
  644.     MOV    M,A        ; Store LSByte of mantissa
  645.     DCR    L        ; Point to next LSByte of mantissa
  646.     MOV    M,A        ; Store next LSByte of mantissa
  647.     DCR    L        ; Point to MSByte of mantissa
  648.     MOV    M,A        ; Store MSByte of mantissa
  649.     RET            ; Floating-point result
  650. ;
  651. ;--------------------------------
  652. ; Routine to write characteristic for "error returns".
  653. ;
  654. wchar:    INR    L        ; Set (HL) to point to characteristic
  655.     INR    L        ; Idem
  656.     INR    L        ; Idem
  657.     MOV    A,M        ; Load characteristic in A
  658.     ANI    80H        ; Just keep mantissa sign
  659.     ORA    D        ; OR in new characteristic
  660.     MOV    M,A        ; Store it back
  661.     RET            ;
  662. ;
  663. ; Return with (HL) pointing to characteristic of result
  664. ; Someone else will fix up (HL)
  665. ;--------------------------------
  666. ; Subroutine INDFC.
  667. ;
  668. ; This routine writes a floating-point indefinite at (HC),
  669. ; sets the condition flag, and returns.
  670. ;
  671. indfc:    MOV    E,L        ; Save L-ptr in E
  672.     MOV    L,C        ; Set L=C-ptr, so (HL)=addr of result
  673.     CALL    wind        ; Write indefinite
  674.     MOV    L,E        ; Restore L=L-ptr
  675.     RET            ; Return
  676. ;
  677. ;--------------------------------
  678. ; Subroutine WZERC.
  679. ;
  680. ; This routine writes a normal floating-point zero at (HC),
  681. ; sets the condition flag, and returns.
  682. ;
  683. wzerc:    MOV    E,L        ; Save L-ptr in E
  684.     MOV    L,C        ; Set L=C-ptr, so (HL)=addr of result
  685.     CALL    wzer        ; Write normal zero
  686.     MOV    L,E        ; Restore L=L-ptr
  687.     RET            ; Return
  688. ;
  689. ;--------------------------------
  690. ; Subroutine INCR.
  691. ;
  692. ; This subroutine increments the characteristic of the floating-point
  693. ; number pointed to by (HL).
  694. ; We test for overflow, and set appropriate flag (see "Error returns").
  695. ;
  696. ; Registers on exit:
  697. ; A = condition flag (see "Error returns")
  698. ; D = clobbered
  699. ; B,C,H,L = same as on entry
  700. ;
  701. incr:    CALL    gchar        ; Get char with sign extended
  702.     CPI    maxch        ; Compare with max char permitted
  703.     JZ    oflw1        ; Increment would cause overflow
  704.     MOV    D,A        ; Save it in D
  705.     INR    D        ; Increment it
  706.     JMP    incr2        ; Jump around alternate entry point
  707. ;
  708. incr3:    INR    L        ; Come here to store characteristic
  709.     INR    L        ; Point (HL) to char
  710.     INR    L        ; Point (HL) to char
  711. incr2:    MVI    A,127        ;
  712.     ANA    D        ; Kill sign bit
  713.     MOV    D,A        ; Back to D
  714.     MOV    A,M        ; Now, sign it
  715.     ANI    128        ; Get mantissa sign
  716.     ORA    D        ; Put together
  717.     MOV    M,A        ; Store it back
  718.     DCR    L        ; Now, back to base
  719.     DCR    L        ; TP
  720.     DCR    L        ;
  721. sccfg:    XRA    A        ; Set success flag
  722.     RET            ;
  723. ;
  724. ;--------------------------------
  725. ; Subroutine DECR.
  726. ;
  727. ; This subroutine decrements the characteristic of the floating-point
  728. ; number pointed to by (HL).
  729. ; We test for underflow and set appropriate flag (see "Error returns").
  730. ;
  731. ; Registers on exit:
  732. ; A = condition flag (see "Error returns")
  733. ; D = clobbered
  734. ; B,C,H,L = same as on entry
  735. ;
  736. decr:    CALL    gchar        ; Get char with sign extended
  737.     CPI    minch        ; Compare with min char permitted
  738.     JZ    uflw1        ; Decrement would cause underflow
  739.     MOV    D,A        ; Save characteristic in D
  740.     DCR    D        ; Decrement characteristic
  741.     JMP    incr2        ; Go store it back
  742. ;
  743. ;--------------------------------
  744. ; Subroutine AORS.
  745. ;
  746. ; Return S=1 if base \6 has a 1 in MSB.
  747. ;
  748. aors:    MOV    E,L        ; Save base
  749.     MOV    L,C        ; Base \6 to L
  750.     MOV    A,M        ; Load it
  751.     ORA    A        ; Set flags
  752.     MOV    L,E        ; Restore base
  753.     RET            ;
  754. ;
  755. ;--------------------------------
  756. ; Subroutine TSTR.
  757. ;
  758. ; Checks C-ptr, to see if next LSB=1.
  759. ; Returns Z=1 if not.
  760. ; Destroys F, D.
  761. ;
  762. tstr:    MOV    E,L        ; Save base
  763.     MOV    L,C        ; C-ptr to L
  764.     MVI    D,02H        ; Mask to D
  765.     MOV    A,M        ; Load value
  766.     MOV    L,E        ; Restore base
  767.     ANA    D        ; AND value with mask
  768.     RET            ;
  769. ;
  770. ;--------------------------------
  771. ; Subroutine ACPR.
  772. ;
  773. ; Stores A in location of C-ptr.
  774. ; L-ptr in E.
  775. ;
  776. acpr:    MOV    E,L        ; Save L-ptr
  777.     MOV    L,C        ; C-ptr to L
  778.     MOV    M,A        ; Store A
  779.     MOV    L,E        ; Restore base
  780.     RET            ;
  781. ;
  782. ;--------------------------------
  783. ; Subroutine DCMP.
  784. ;
  785. ; Compares two double length words.
  786. ;
  787. dcmp:    MOV    A,M        ; Number mantissa to A
  788.     MOV    E,L        ; Save base in E
  789.     MOV    L,B        ; Base 3 to L
  790.     CMP    M        ; Compare with den (?) mantissa
  791.     MOV    L,E        ; Return base to L
  792.     RNZ            ; Return if not the same
  793.     INR    L        ; L to number mantissa B (?)
  794.     MOV    A,M        ; Load it
  795.     MOV    L,B        ; Den (?) mantissa B (?) add to L
  796.     INR    L        ; Base 4 to L
  797.     CMP    M        ;
  798.     MOV    L,E        ;
  799.     RNZ            ; TP extension
  800.     INR    L        ; Now, check byte 3
  801.     INR    L        ;
  802.     MOV    A,M        ; Get for compare
  803.     MOV    L,B        ;
  804.     INR    L        ;
  805.     INR    L        ; Byte 3 now
  806.     CMP    M        ; Compare
  807.     MOV    L,E        ; TP -- All done
  808.     RET            ;
  809. ;
  810. ;--------------------------------
  811. ; Subroutine DIVC.
  812. ;
  813. ; Performs one cycle of double precision floating-point divide.
  814. ; Enter at ENT1 on first cycle.
  815. ; Enter at ENT2 all thereafter.
  816. ;
  817. ent2:    CALL    dlst        ; Shift moving dividend
  818.     JC    over        ; If Carry=1, number > D (?)
  819. ent1:    CALL    dcmp        ; Compare number with Den(ormalized?)
  820.     JNC    over        ; If Carry not set, number > Den (?)
  821.     RET            ;
  822. ;
  823. over:    CALL    dsub        ; Call double subtract
  824.     MOV    E,L        ; Save base in E
  825.     MOV    L,C        ; Base 6 to L
  826.     INR    L        ; Base 7 to L
  827.     INR    L        ; TP
  828.     MOV    A,M        ;
  829.     ADI    01H        ; Add 1
  830.     MOV    M,A        ; Put it back
  831.     MOV    L,E        ; Restore base to L
  832.     RET            ;
  833. ;
  834. ;--------------------------------
  835. ; Subroutine LXFR.
  836. ;
  837. ; Moves C-ptr to E-ptr.
  838. ; Moves 3 words if enter at LXFR.
  839. ;
  840. lxfr:    MVI    D,04H        ; Move 4 words
  841. rep5:    MOV    L,C        ; C-ptr to L
  842.     MOV    A,M        ; C-ptr> to A
  843.     MOV    L,E        ; E-ptr to L
  844.     MOV    M,A        ;
  845.     INR    C        ; Increment C
  846.     INR    E        ; Increment E to next
  847.     DCR    D        ; Test for done
  848.     JNZ    rep5        ; Go for til D=0
  849.     MOV    A,E        ; Now, reset C and E
  850.     SUI    04H        ; Reset back by 4
  851.     MOV    E,A        ; Put back in E
  852.     MOV    A,C        ; Now, reset C
  853.     SUI    04H        ;   by 4.
  854.     MOV    C,A        ; Back to C
  855.     RET            ; Done
  856. ;
  857. ;--------------------------------
  858. ; Subroutine LDCP.
  859. ;
  860. ; This subroutine computes the characteristic for the floating-point
  861. ; divide routine.
  862. ;
  863. ; Registers on exit:
  864. ; A = condition flag (see "Error returns")
  865. ; D,E = garbage
  866. ; B,C,H,L = same as on entry
  867. ;
  868. ; Registers on entry:
  869. ; (H,B) = address of divisor
  870. ; (H,C) = address of quotient
  871. ; (HL) = address of dividend
  872. ;
  873. ldcp:    CALL    cfche        ; Set E=char(H,B), A=char(HL)
  874.     SUB    E        ; Subtract to get new characteristic
  875.     JMP    cchk        ; Go check for over/underflow
  876.                 ;   and store characteristic.
  877. ;
  878. ;--------------------------------
  879. ; Subroutine LMCP.
  880. ;
  881. ; This subroutine computes the characteristic for the floating-point
  882. ; multiply routine.
  883. ;
  884. ; Registers on exit:
  885. ; A = condition flag (see "Error returns")
  886. ; D,F = garbage
  887. ; B,C,H,L = same as on entry
  888. ;
  889. ; Registers on entry:
  890. ; (H,B) = address of multiplicand
  891. ; (H,C) = address of product
  892. ; (HL) = address of multiplier
  893. ;
  894. lmcp:    CALL    cfche        ; Set E=char(H,B), A=char(HL)
  895.     ADD    E        ; Add to get new characteristic
  896. ;
  897. ; Now, fall into the routine which checks for over/underflow,
  898. ; and store characteristic.
  899. ;
  900. ; Subroutine CCHK.
  901. ;
  902. ; This subroutine checks a characteristic in the Accumulator for
  903. ; overflow or underflow.
  904. ; It then stores the characteristic, preserving the previously
  905. ; computed mantissa sign.
  906. ;
  907. ; Registers on entry:
  908. ; (HL) = address of one operand
  909. ; (H,B) = address of other operand
  910. ; (H,C) = address of result
  911. ; A = new characteristic of result
  912. ;
  913. ; Registers on exit:
  914. ; A = condition flag (see "Error returns")
  915. ; D,E = garbage
  916. ; B,C,H,L = same as on entry
  917. ;
  918. cchk:    CPI    64        ; Check for 0 to +63
  919.     JC    storc        ; Jump if okay
  920.     CPI    128        ; Check for +64 to +127
  921.     JC    oflwc        ; Jump if overflow
  922.     CPI    192        ; Check for -128 to -65
  923.     JC    uflwc        ; Jump if underflow
  924. storc:    MOV    E,L        ; Save L in E
  925.     MOV    L,C        ; Let L point to result
  926.     MOV    D,A        ; Save characteristic in D
  927.     CALL    incr3        ; Store characteristic
  928.     MOV    L,E        ; Restore L
  929.     RET            ; Return
  930. ;
  931. ;--------------------------------
  932. ; Subroutine OFLWC.
  933. ;
  934. ; This routine writes a floating-point overflow at (H,C),
  935. ; sets the condition flag, and returns.
  936. ;
  937. oflwc:    MOV    E,L        ; Save L in E
  938.     MOV    L,C        ; Set L=C-ptr, so (HL)=addr of result
  939.     CALL    wovr        ; Write out overflow
  940.     MOV    L,E        ; Restore L
  941.     RET            ; Return
  942. ;
  943. ;--------------------------------
  944. ; Subroutine UFLWC.
  945. ;
  946. ; This routine writes a floating-point underflow at (H,C),
  947. ; sets the condition flag, and returns.
  948. ;
  949. uflwc:    MOV    E,L        ; Save L in E
  950.     MOV    L,C        ; Set L=C-ptr, so (HL)=addr of result
  951.     CALL    wund        ; Write out underflow
  952.     MOV    L,E        ; Restore L
  953.     RET            ; Return
  954. ;
  955. ;--------------------------------
  956. ; Subroutine CSIGN.
  957. ;
  958. ; This subroutine computes and store the mantissa sign for the
  959. ; floating-point multiply and divide routines.
  960. ;
  961. ; Registers on entry:
  962. ; (HL) = address of one operand
  963. ; (H,B) = address of other operand
  964. ; (H,C) = address of result
  965. ;
  966. ; Registers on exit:
  967. ; A,D,E = garbage
  968. ; B,C,H,L = same as on entry
  969. ;
  970. csign:    CALL    msfh        ; Set A=sign(HL), E=sign(H,B)
  971.     XRA    E        ; Exclusive-OR signs, to get new sign
  972.     CALL    cstr        ; Store sign into result
  973.     RET            ; Return
  974. ;
  975. ;--------------------------------
  976. ; Subroutine CSTR.
  977. ;
  978. ; Stores value in A in C-ptr\2.
  979. ; Puts L-ptr in E.
  980. ;
  981. cstr:    MOV    E,L        ; Save L-ptr in E
  982.     MOV    L,C        ; C-ptr to L
  983.     INR    L        ; C-ptr\2
  984.     INR    L        ; To L
  985.     INR    L        ; TP
  986.     MOV    M,A        ; Store answer
  987.     MOV    L,E        ; L-ptr back to L
  988.     RET            ;
  989. ;
  990. ;--------------------------------
  991. ; Subroutine MSFH.
  992. ;
  993. ; This subroutine fetches the signs of the mantissas of the floating-point
  994. ; numbers pointed to by (HL) and (H,B) into the A and E registers,
  995. ; respectively.
  996. ;
  997. ; Registers on exit:
  998. ; A = sign of mantissa of (HL)
  999. ; E = sign of mantissa of (H,B)
  1000. ; B,C,D,H,L = same as on entry
  1001. ;
  1002. msfh:    MOV    E,L        ; Save L-ptr
  1003.     MOV    L,B        ; B-ptr to L
  1004.     INR    L        ; B-ptr\2
  1005.     INR    L        ; TP
  1006.     INR    L        ; To L
  1007.     MOV    A,M        ; B-ptr\2> to A
  1008.     ANI    128        ; Save mantissa sign
  1009.     MOV    L,E        ; L-ptr back to L
  1010.     MOV    E,A        ; Store B-ptr mantissa sign
  1011.     INR    L        ; L-ptr\2
  1012.     INR    L        ; TP
  1013.     INR    L        ; To L
  1014.     MOV    A,M        ; L-ptr\2> to A
  1015.     ANI    128        ; Save L-ptr mantissa sign
  1016.     DCR    L        ; L-ptr back
  1017.     DCR    L        ; To L
  1018.     DCR    L        ; LP
  1019.     RET            ;
  1020. ;
  1021. ;--------------------------------
  1022. ; Subroutine BCTL.
  1023. ;
  1024. ; Moves B-ptr char to L-ptr char.
  1025. ; Destroys E.
  1026. ;
  1027. bctl:    MOV    E,L        ; L-ptr to E
  1028.     MOV    L,B        ; B-ptr to L
  1029.     INR    L        ; B-ptr \2
  1030.     INR    L        ; TP
  1031.     INR    L        ; To L
  1032.     MOV    A,M        ; B-ptr to A
  1033.     MOV    L,E        ; L-ptr to L
  1034.     INR    L        ; L-ptr \2
  1035.     INR    L        ; To L
  1036.     INR    L        ; TP
  1037.     MOV    M,A        ; Store B-ptr char in L-ptr char
  1038.     MOV    L,E        ; L-ptr to L
  1039.     RET            ;
  1040. ;
  1041. ;--------------------------------
  1042. ; Square root.
  1043. ;
  1044. ; The L register points to the ? to be operated on.
  1045. ; The B register points to the location where the result is to be stored.
  1046. ; The C register points to a 17-byte scratch area, where:
  1047. ;
  1048. ; C = iteration count
  1049. ; C+1 = L register
  1050. ; C+2 = B register
  1051. ; C+3 to C+6 = internal register 1
  1052. ; C+7 to C+10 = internal register 2
  1053. ; C+11 to C+14 = internal register 3
  1054. ; C+15 = ?
  1055. ;
  1056. dsqrt:    MOV    A,L        ; Store L in
  1057.     MOV    L,C        ;   2nd word scratch.
  1058.     MVI    M,00H        ; Initialize iterative count
  1059.     INR    L        ;
  1060.     MOV    M,A        ;
  1061.     INR    L        ; Store B in 3rd
  1062.     MOV    M,B        ;   word of scratch.
  1063.     INR    L        ; Set C to internal
  1064.     MOV    C,L        ;   register 1.
  1065.     MOV    L,A        ; Set L ptr at (?)
  1066.     MOV    A,H        ; Set registers for copy
  1067.     CALL    copy        ; Copy (?) to internal register 1
  1068.     CALL    gchr        ; Put char in A
  1069.     MOV    B,A        ; Make copy
  1070.     ANI    128        ; Check negative
  1071.     JNZ    ersq        ;
  1072.     MOV    A,B        ;
  1073.     ANI    64        ; Check negative exponent
  1074.     MOV    A,B        ;
  1075.     JZ    epos        ;
  1076.     RAR            ; Divide by 2
  1077.     ANI    7FH        ;
  1078.     ORI    64        ; Set Sign bit
  1079.     MOV    M,A        ; Save first approximation
  1080.     JMP    agn4        ;
  1081. ;
  1082. epos:    RAR            ; Divide by 2
  1083.     ANI    7FH        ;
  1084.     MOV    M,A        ; Save first approximation
  1085. agn4:    MOV    L,C        ; Set registers
  1086.     MOV    A,C        ;   to copy
  1087.     ADI    04H        ;   first approximation
  1088.     MOV    C,A        ;   into internal register 2
  1089.     MOV    A,H        ;   from internal register 1.
  1090.     CALL    copy        ;
  1091.     MOV    A,C        ;
  1092.     SUI    04H        ; Multiply internal register 1
  1093.     MOV    L,A        ;
  1094.     MOV    B,C        ; Times internal register 2
  1095.     ADI    08H        ; Place result in
  1096.     MOV    C,A        ;   internal register 3.
  1097.     CALL    lmul        ;
  1098.     MOV    A,C        ;
  1099.     SUI    08H        ; Copy original into
  1100.     MOV    C,A        ;   internal register 1.
  1101.     SUI    02H        ;
  1102.     MOV    L,A        ;
  1103.     MOV    L,M        ;
  1104.     MOV    A,H        ;
  1105.     CALL    copy        ;
  1106.     MOV    A,C        ;
  1107.     ADI    08H        ; Add 
  1108.     MOV    L,A        ;   internal register 3
  1109.     MOV    B,C        ;   to internal register 1.
  1110.     ADI    04H        ; Answer to
  1111.     MOV    C,A        ;   internal register 3
  1112.     CALL    ladd        ;
  1113.     MOV    A,L        ;
  1114.     SUI    04H        ; Divide internal register 3
  1115.     MOV    B,A        ;   by internal register 2.
  1116.     SUI    04H        ; Put answer in
  1117.     MOV    C,A        ;   internal register 1.
  1118.     CALL    ldiv        ;
  1119.     CALL    gchr        ;
  1120.     SUI    01H        ;
  1121.     ANI    7FH        ;
  1122.     MOV    M,A        ;
  1123.     MOV    A,C        ;
  1124.     SUI    03H        ; C points to internal register 1
  1125.     MOV    L,A        ; Get iteration count
  1126.     MOV    B,M        ;
  1127.     INR    B        ; Increment it
  1128.     MOV    M,B        ;
  1129.     MOV    A,B        ;
  1130.     CPI    05H        ; If = 5, return answer
  1131.     JNZ    agn4        ; Otherwise, continue
  1132.     MOV    L,C        ;
  1133. aldn:    DCR    L        ; Copy answer into
  1134.     MOV    C,M        ;   location requested.
  1135.     INR    L        ;
  1136.     MOV    A,H        ;
  1137.     CALL    copy        ;
  1138.     RET            ;
  1139. ;
  1140. ersq:    MOV    L,C        ;
  1141.     CALL    wzer        ; Write a floating zero
  1142.     JMP    aldn        ; C+1 = L register
  1143. ;
  1144. ;--------------------------------
  1145. ; 5-digit floating-point output.
  1146. ;
  1147. ; Routine to convert floating-point numbers to ASCII, and
  1148. ; output them via a subroutine called OUTR.
  1149. ;
  1150. cvrt:    CALL    zchk        ; Check for new zero
  1151.     JNZ    nnzro        ; Not zero
  1152.     INR    C        ; It was, offset C by 2
  1153.     INR    C        ;
  1154.     MOV    L,C        ;
  1155.     CALL    wzer        ; Write zero
  1156.     CALL    sign        ; Send space on positive zero
  1157.     INR    L        ; Point to decimal exponent
  1158.     INR    L        ;
  1159.     INR    L        ;
  1160.     INR    L        ;
  1161.     XRA    A        ; Set it to zero
  1162.     MOV    M,A        ;
  1163.     JMP    mdskp        ; Output it
  1164. ;
  1165. nnzro:    MOV    D,M        ; Get the number to convert
  1166.     INR    L        ;
  1167.     MOV    B,M        ;
  1168.     INR    L        ;
  1169.     MOV    E,M        ;
  1170.     INR    L        ; 4 word TP
  1171.     MOV    A,M        ;
  1172.     INR    C        ; Offset scratch pointer by 2
  1173.     INR    C        ;
  1174.     MOV    L,C        ; L not needed anymore
  1175.     MOV    M,D        ; Save number in scratch
  1176.     INR    L        ;
  1177.     MOV    M,B        ;
  1178.     INR    L        ;
  1179.     MOV    M,E        ; TP
  1180.     INR    L        ; TP
  1181.     MOV    B,A        ; Save copy of char & sign
  1182.     ANI    7FH        ; Get only char
  1183.     MOV    M,A        ; Save ABS(number)
  1184.     CPI    64        ; Check for zero
  1185.     JZ    nzro        ;
  1186.     SUI    01H        ; Get sign of decimal exponent
  1187.     ANI    64        ; Get sign of char
  1188. nzro:    RLC            ; Move it to sign position
  1189.     INR    L        ; Move to decimal exponent
  1190.     MOV    M,A        ; Save sign of exponent
  1191.     MOV    A,B        ; Get mantissa sign back
  1192.     CALL    sign        ; Output sign
  1193.     MVI    L,(ten5 AND 255)  ; Try mult. or div. by 100.000 first
  1194.     CALL    copt        ; Make a copy in RAM
  1195. tstb:    CALL    gchr        ; Get char of number
  1196.     MOV    B,A        ; Save a copy
  1197.     ANI    64        ; Get absolute value of char
  1198.     MOV    A,B        ; In case plus
  1199.     JZ    gotv        ; Already plus
  1200.     MVI    A,128        ; Make minus into plus
  1201.     SUB    B        ; Plus = 128 - char
  1202. gotv:    CPI    18        ; Test for use of 100.000
  1203.     JM    try1        ; Wont go
  1204.     CALL    mord        ; Will go, so do it
  1205.     ADI    05H        ; Increment decimal exponent by 5
  1206.     MOV    M,A        ; Update memory
  1207.     JMP    tstb        ; Go try again
  1208. ;
  1209. try1:    MVI    L,(ten AND 255) ; Now, use just TEN
  1210.     CALL    copt        ; Put it in RAM
  1211. tst1:    CALL    gchr        ; Get characteristic
  1212.     CPI    01H        ; Must get in range 1 to 6
  1213.     JP    ok1        ; At least it is 1 or bigger
  1214. mdgn:    CALL    mord        ; Must mult. or div. by 10
  1215.     ADI    01H        ; Increment decimal exponent
  1216.     MOV    M,A        ; Update memory
  1217.     JMP    tst1        ; Now, try again
  1218. ;
  1219. ok1:    CPI    07H        ; Test for less than 7
  1220.     JP    mdgn        ; Nope -- 7 or greater
  1221. mdskp:    MOV    L,C        ; Set up digit count
  1222.     DCR    L        ;
  1223.     DCR    L        ;   in first word of scratch.
  1224.     MVI    M,05H        ; 5 digits
  1225.     MOV    E,A        ; Save char as left shift count
  1226.     CALL    lsft        ; Shift left proper number
  1227.     CPI    10        ; Test for 2 digits here
  1228.     JP    twod        ; Jump if 2 digits to output
  1229.     CALL    digo        ; Output first digit
  1230. popD:    CALL    multt        ; Multiply the number by 10
  1231. inpop:    CALL    digo        ; Print digit in A
  1232.     JNZ    popD        ; More digits?
  1233.     MVI    A,197        ; No, so print E
  1234.     CALL    outr        ; Basic call to output
  1235.     CALL    getex        ; Get decimal exponent
  1236.     MOV    B,A        ; Save a copy
  1237.     CALL    sign        ; Output sign
  1238.     MOV    A,B        ; Get exponent back
  1239.     ANI    3FH        ; Get good bits
  1240.     CALL    ctwo        ; Go convert 2 digits
  1241. digo:    ADI    0B0H        ; Make A into ASCII
  1242.     CALL    outr        ; Output digit
  1243.     MOV    L,C        ; Get digit count
  1244.     DCR    L        ; Back up to digit count
  1245.     DCR    L        ;
  1246.     MOV    A,M        ; Test for decimal point
  1247.     CPI    05H        ; Print "." after first digit
  1248.     MVI    A,0AEH        ; Just in case
  1249.     CZ    outr        ; Output "." if first digit
  1250.     MOV    D,M        ; Now, decrement digit count
  1251.     DCR    D        ;
  1252.     MOV    M,D        ; Update memory, and leave flops set
  1253.     RET            ; Serves as terminator for DIGO & CVRT
  1254. ;
  1255. multt:    MVI    E,01H        ; Multiply by 10 (start with *2)
  1256.     CALL    lsft        ; Left shift 1 = *2
  1257.     MOV    L,C        ; Save *2 in "result"
  1258.     DCR    L        ; Set to top of number
  1259.     MOV    A,C        ; Set C to result
  1260.     ADI    09H        ;
  1261.     MOV    C,A        ; Now, C set right
  1262.     MOV    A,H        ; Show RAM-to-RAM transfer
  1263.     CALL    copy        ; Save *2 finally
  1264.     MOV    A,C        ; Must reset C
  1265.     SUI    09H        ; Back to normal
  1266.     MOV    C,A        ;
  1267.     MVI    E,02H        ; Now, get (*2)*4 = *8
  1268.     MOV    L,C        ; But must save overflow
  1269.     DCR    L        ;
  1270.     CALL    tlp2        ; Get *8
  1271.     MOV    L,C        ; Set up to call DADD
  1272.     MOV    A,C        ; Set B to *2
  1273.     ADI    0AH        ; To *2
  1274.     MOV    B,A        ;
  1275.     CALL    dadd        ; Add 2 low words
  1276.     DCR    L        ; Back up to overflow
  1277.     MOV    A,M        ; Get it
  1278.     MOV    L,B        ; Now, set to *2 overflow
  1279.     DCR    L        ; It is a B-1
  1280.     ADC    M        ; Add with carry -- Carry was preserved
  1281.     RET            ; All done, return overflow in A
  1282. ;
  1283. lsft:    MOV    L,C        ; Set ptr for left shift of number
  1284.     DCR    L        ; Back up to overflow
  1285.     XRA    A        ; Overflow = zero the first time
  1286. tloop:    MOV    M,A        ; Save overflow
  1287. tlp2:    DCR    E        ; Test for done
  1288.     RM            ; Done when E minus
  1289.     INR    L        ; Move to low
  1290.     INR    L        ;
  1291.     INR    L        ; TP extension
  1292.     MOV    A,M        ; Shift left 4 bytes
  1293.     RAL            ;
  1294.     MOV    M,A        ; Put back
  1295.     DCR    L        ; TP -- All done
  1296.     MOV    A,M        ; Get low
  1297.     RAL            ; Shift left 1
  1298.     MOV    M,A        ; Restore it
  1299.     DCR    L        ; Back up to high
  1300.     MOV    A,M        ; Get high
  1301.     RAL            ; Shift it left with Carry
  1302.     MOV    M,A        ; Put it back
  1303.     DCR    L        ; Back up to overflow
  1304.     MOV    A,M        ; Get overflow
  1305.     RAL            ; Shift it left
  1306.     JMP    tloop        ; Go for more
  1307. ;
  1308. sign:    ANI    80H        ; Get sign bit
  1309.     MVI    A,0A0H        ; Space, instead of plus
  1310.     JZ    plsv        ; Test for +
  1311.     MVI    A,0ADH        ; Negative
  1312. plsv:    CALL    outr        ; Output sign
  1313.     RET            ;
  1314. ;
  1315. gchr:    MOV    L,C        ; Get characteristic
  1316. geta:    INR    L        ; Move to it
  1317.     INR    L        ;
  1318.     INR    L        ; TP
  1319.     MOV    A,M        ; Fetch into A
  1320.     RET            ; Done
  1321. ;
  1322. mord:    CALL    getex        ; Mult. or div. depending on exponent
  1323.     MOV    E,A        ; Save decimal exponent
  1324.     MOV    B,L        ; Set up to mult. or div.
  1325.     INR    B        ; Now, increments pointer set
  1326.     MOV    L,C        ; L points to number to convert
  1327.     MOV    A,C        ; Point C at "result" area
  1328.     ADI    09H        ; In scratch
  1329.     MOV    C,A        ; Now, C set right
  1330.     MOV    A,E        ; Now, test for mult.
  1331.     ANI    80H        ; Test negative decimal exponent
  1332.     JZ    divit        ; If exponent is +, then divide
  1333.     CALL    lmul        ; Multiply
  1334. finup:    MOV    A,C        ; Save location of result
  1335.     MOV    C,L        ; C = location of number (it was destroyed)
  1336.     MOV    L,A        ; Set L to location of result
  1337.     MOV    A,H        ; Show RAM-to-RAM transfer
  1338.     CALL    copy        ; Move result to number
  1339. getex:    MOV    L,C        ; Now, get decimal exponent
  1340.     INR    L        ;
  1341.     JMP    geta        ; Use part og GCHR
  1342. ;
  1343. divit:    CALL    ldiv        ; Divide
  1344.     JMP    finup        ;
  1345. ;
  1346. twod:    CALL    ctwo        ; Convert to 2 digits
  1347.     MOV    B,A        ; Save ones digit
  1348.     CALL    getex        ; Get decimal exponent
  1349.     MOV    E,A        ; Save a copy
  1350.     ANI    80H        ; Test for negative
  1351.     JZ    add1        ; Bump exponent by 1, since 2 digits
  1352.     DCR    E        ; Decrement negative exponent, since 2 digits
  1353. finit:    MOV    M,E        ; Restore exponent with new value
  1354.     MOV    A,B        ; Now, do second digit
  1355.     JMP    inpop        ; Go out second, and rest fo (?) digits
  1356. ;
  1357. add1:    INR    E        ; Compensate for 2 digits
  1358.     JMP    finit        ;
  1359. ;
  1360. ctwo:    MVI    E,0FFH        ; Convert 2 digit bin to BCD
  1361. loop:    INR    E        ; Add up tens digit
  1362.     SUI    0AH        ; Subtract 10
  1363.     JP    loop        ; Till negative result
  1364.     ADI    0AH        ; Restore ones digit
  1365.     MOV    B,A        ; Save ones digit
  1366.     MOV    A,E        ; Get tens digit
  1367.     CALL    digo        ; Output it
  1368.     MOV    A,B        ; Set A to second digit
  1369.     RET            ;
  1370. ;
  1371. copt:    MOV    A,C        ; Copy from 10 N to RAM
  1372.     ADI    05H        ;
  1373.     MOV    C,A        ; Set C to place to put
  1374.     MVI    A,(ten5 / 256)    ;
  1375.     CALL    copy        ; Copy it
  1376.     MOV    A,C        ; Now, reset C
  1377.     SUI    05H        ;
  1378.     MOV    C,A        ; It is reset
  1379.     RET            ;
  1380. ;
  1381. copy:    MOV    B,H        ; Save RAM H
  1382.     MOV    H,A        ; Set to source H
  1383.     MOV    A,M        ; Get 4 words into the registers
  1384.     INR    L        ;
  1385.     MOV    D,M        ;
  1386.     INR    L        ;
  1387.     MOV    E,M        ;
  1388.     INR    L        ;
  1389.     MOV    L,M        ; Last one erases L
  1390.     MOV    H,B        ; Set to destination RAM
  1391.     MOV    B,L        ; Save 4th word in B
  1392.     MOV    L,C        ; Set to destination
  1393.     MOV    M,A        ; Save first word
  1394.     INR    L        ;
  1395.     MOV    A,M        ; Save this word in A (input saves C here)
  1396.     MOV    M,D        ; Now, put second word
  1397.     INR    L        ;
  1398.     MOV    M,E        ;
  1399.     INR    L        ;
  1400.     MOV    M,B        ; All 4 copied, now
  1401.     RET            ; All done
  1402. ;
  1403. ;--------------------------------
  1404. ten5    DB    0C3H,50H,00H,11H ; = 100000.
  1405. ten    DB    0A0H,00H,00H,04H ; = 10
  1406. ;--------------------------------
  1407. ; Scratch map for I/O conversion routines.
  1408. ;
  1409. ; Relative to (C+2)    Use
  1410. ; -----------------    ---
  1411. ;        C-2        Digit count
  1412. ;     C-1        Overflow
  1413. ;     C        High number -- Mantissa
  1414. ;     C+1        Low number
  1415. ;     C+2        Characteristic
  1416. ;     C+3        Decimal exponent (sign & magnitude)
  1417. ;     C+4        Ten ** N
  1418. ;     C+5        Ten ** N
  1419. ;     C+6        Ten ** N
  1420. ;     C+7        Result of multiplication and division
  1421. ;     C+8          and temporary for *2.
  1422. ;     C+9        (idem)
  1423. ;     C+10        L for number to go into (input only)
  1424. ;     C+11        Digit just input (input only)
  1425. ;
  1426. err:    MVI    A,0BFH        ; Error in input
  1427.     CALL    outr        ; Send a ? (space)
  1428.     MVI    A,0A0H        ;
  1429.     CALL    outr        ; Output a space
  1430.     JMP    prmt        ; Go prompt user, and restart
  1431. ;
  1432. ;--------------------------------
  1433. ; 4-1/2 digit input routine.
  1434. ;
  1435. ; L points to where to put input number
  1436. ; C points to 13 words of scratch
  1437. ;
  1438. input:    MOV    B,L        ; Save address where data
  1439.     MOV    A,C        ;   is to go in scratch.
  1440.     ADI    0FH        ; Compute location in scratch
  1441.     MOV    L,A        ;
  1442.     MOV    M,B        ; Put it
  1443.     INR    C        ; Offset scratch pointer
  1444.     INR    C        ;   by 2.
  1445. prmt:    MVI    A,0BAH        ; Prompt user with ":"
  1446.     CALL    outr        ; Output ":"
  1447.     CALL    zroit        ; Zero number
  1448.     INR    L        ;   and zero
  1449.     MOV    M,A        ;   decimal exponent.
  1450.     CALL    gnum        ; Get integer part of number
  1451.     CPI    0FEH        ; Terminator = "." ?
  1452.     JZ    decpt        ; Yes
  1453. tstex:    CPI    15H        ; Test for E
  1454.     JZ    inexp        ; Yes: Handle exponent
  1455.     CPI    0F0H        ; Test for space terminator
  1456.     JNZ    err        ; Not legal terminator
  1457.     CALL    fltsgn        ; Float and sign it
  1458. scale:    CALL    getex        ; Get decimal exponent
  1459.     ANI    7FH        ; Get good bits
  1460.     MOV    E,A        ; Save copy
  1461.     ANI    40H        ; Get sign of exponent
  1462.     RLC            ;   into sign bit.
  1463.     ORA    A        ; Set flops
  1464.     MOV    B,A        ; Save sign
  1465.     MOV    A,E        ; Get exponent back
  1466.     JZ    apls        ; Jump is +
  1467.     MVI    A,80H        ; Make minus
  1468.     SUB    E        ; Now, it is +
  1469. apls:    ADD    B        ; Sign number
  1470.     MOV    M,A        ; Save exponent (sign & magnitude)
  1471.     MVI    L,(ten5 AND 255)  ; Try MORD with 10**5 first
  1472.     CALL    copt        ; Transfer to RAM
  1473.     CALL    getex        ; Get decimal exponent
  1474. int5:    ANI    3FH        ; Get magnitude of exponent
  1475.     CPI    05H        ; Test for use of 10**5
  1476.     JM    trytn        ; Wont go: Try 10
  1477.     CALL    mord        ; Will go, so do it
  1478.     SUI    05H        ; Magnitude = magnitude - 5
  1479.     MOV    M,A        ; Update decimal exponent in RAM
  1480.     JMP    int5        ; Go try again
  1481. ;
  1482. trytn:    MVI    L,(ten AND 255)    ; Put ten in RAM
  1483.     CALL    copt        ;
  1484.     CALL    getex        ; Set up for loop
  1485. int1:    ANI    3FH        ; Get magnitude
  1486.     ORA    A        ; Test for 0
  1487.     JZ    saven        ; Done, move number out, and get out
  1488.     CALL    mord        ; Not done: do 10
  1489.     SUI    01H        ; Exponent = exponent - 1
  1490.     MOV    M,A        ; Update memory
  1491.     JMP    int1        ; Try again
  1492. ;
  1493. decpt:    MOV    L,C        ; Zero digit count,
  1494.     DCR    L        ;   since it is necessary
  1495.     DCR    L        ;   to compute exponent.
  1496.     MVI    M,00H        ; Zeroed
  1497.     CALL    ep1        ; GNUM in middle
  1498.     MOV    E,A        ; Save terminator
  1499.     MOV    L,C        ; Move digit count to exponent
  1500.     DCR    L        ; Back up to digit count
  1501.     DCR    L        ;
  1502.     MOV    B,M        ; Got digit count
  1503.     CALL    getex        ; Set L to decimal exponent
  1504.     MOV    M,B        ; Put exponent
  1505.     MOV    A,E        ;   terminator back to A.
  1506.     JMP    tstex        ; Test for E+or-XX
  1507. ;
  1508. inexp:    CALL    fltsgn        ; Float and sign number
  1509.     CALL    saven        ; Save number in (L) temporarily
  1510.     CALL    zroit        ; Zero out number for inputting exponent
  1511.     CALL    gnum        ; Now, input exponent
  1512.     CPI    0F0H        ; Test for space terminator
  1513.     JNZ    err        ; Not legal: Try again
  1514.     MOV    L,C        ; Get exponent out of memory
  1515.     INR    L        ; TP
  1516.     INR    L        ; Exponent limited to 5 bits
  1517.     MOV    A,M        ; Get lowest 8 bits
  1518.     ANI    1FH        ; Get good bits
  1519.     MOV    B,A        ; Save them
  1520.     INR    L        ; Set sign of exponent
  1521.     MOV    A,M        ;   into A.
  1522.     ORA    A        ; Set flops
  1523.     MOV    A,B        ; In case nothing to do
  1524.     JM    useit        ; If negative, use as +
  1525.     MVI    A,00H        ; If +, make -
  1526.     SUB    B        ; 0-X = -X
  1527. useit:    INR    L        ; Point at exponent
  1528.     ADD    M        ; Get real decimal exponent
  1529.     MOV    M,A        ; Put in memory
  1530.     MOV    A,C        ; Now, get number back
  1531.     ADI    0DH        ; Get add of L
  1532.     MOV    L,A        ; L points to L of number
  1533.     MOV    L,M        ; Now, L points to number
  1534.     MOV    A,H        ; RAM-to-RAM copy
  1535.     CALL    copy        ; Copy it back
  1536.     JMP    scale        ; Now, adjust for exponent
  1537. ;
  1538. gnum:    CALL    inp        ; Get a character
  1539.     CPI    0A0H        ; Ignore leading spaces
  1540.     JZ    gnum        ;
  1541.     CPI    0ADH        ; Test for -
  1542.     JNZ    tryp        ; Not minus
  1543.     MOV    L,C        ; Minus, so set sign
  1544.     INR    L        ;   in char location.
  1545.     INR    L        ; TP
  1546.     INR    L        ;
  1547.     MVI    M,80H        ; Set - sign
  1548.     JMP    gnum        ;
  1549. ;
  1550. tryp:    CPI    0ABH        ; Ignore +
  1551.     JZ    gnum        ;
  1552. tstn:    SUI    0B0H        ; Strip ASCII
  1553.     RM            ; Return if terminator
  1554.     CPI    0AH        ; Test for number
  1555.     RP            ; Illegal
  1556.     MOV    E,A        ; Save digit
  1557.     CALL    getn        ; Location of digit storage to L
  1558.     MOV    M,E        ; Save digit
  1559.     CALL    multt        ; Multiply number by 10
  1560.     ORA    A        ; Test for too many digits
  1561.     RNZ            ; Too many digits
  1562.     CALL    getn        ; Get digit
  1563.     MOV    L,C        ; Set L to number
  1564.     INR    L        ;
  1565.     INR    L        ; TP
  1566.     ADD    M        ; Add in the digit
  1567.     MOV    M,A        ; Put result back
  1568.     DCR    L        ; Now, do high
  1569.     MOV    A,M        ; Get high to add in Carry
  1570.     ACI    00H        ; Add in Carry
  1571.     MOV    M,A        ; Update high
  1572.     DCR    L        ; TP extension
  1573.     MOV    A,M        ;
  1574.     ACI    00H        ; Add in Carry
  1575.     MOV    M,A        ; TP -- All done
  1576.     RC            ; Overflow error
  1577.     DCR    L        ; Bump digit count now
  1578.     DCR    L        ;
  1579.     MOV    B,M        ; Get digit count
  1580.     INR    B        ; Bump digit count
  1581.     MOV    M,B        ; Update digit count
  1582. ;
  1583. ep1:    CALL    inp        ; Get next char
  1584.     JMP    tstn        ; Must be number or terminator
  1585. ;
  1586. fltsgn:    MOV    L,C        ; Point L at number to float
  1587.     JMP    float        ; Go float it
  1588. ;
  1589. saven:    MOV    A,C        ; Put number in (L)
  1590.     ADI    0DH        ; Get add of L
  1591.     MOV    L,A        ;
  1592.     MOV    E,M        ; Get L of result
  1593.     MOV    L,E        ; Point L at (L)
  1594.     INR    L        ; Set to second word to save C
  1595.     MOV    M,C        ; Save C in (L)+1, since it will be destroyed
  1596.     MOV    L,C        ; Set up to call copy
  1597.     MOV    C,E        ; Now, L & C set
  1598.     MOV    A,H        ; RAM-to-RAM copy
  1599.     CALL    copy        ; Copy to L
  1600.     MOV    C,A        ; (L)+1 returned here, so set as C
  1601.     RET            ; Now, everything hunky-dorry
  1602. ;
  1603. getn:    MOV    A,C        ; Get digit
  1604.     ADI    0EH        ; Last location in scratch
  1605.     MOV    L,A        ; Put in L
  1606.     MOV    A,M        ; Get digit
  1607.     RET            ;
  1608. ;
  1609. zroit:    MOV    L,C        ; Zero number
  1610.     XRA    A        ;
  1611.     MOV    M,A        ; TP
  1612.     INR    L        ; TP
  1613.     MOV    M,A        ;
  1614.     INR    L        ;
  1615.     MOV    M,A        ;
  1616.     INR    L        ; Now, set sign to +
  1617.     MOV    M,A        ;
  1618.     RET            ; Done
  1619. ;
  1620. ;--------------------------------
  1621. ;
  1622.     END
  1623.