OCTAL "Double-word math subs" $PRINT CRLF ; updated 8/1/04 to include decimal string conversion ; ; n1high n1low n2high n2low DADD pushes high,low of n1 + n2 ; high low D2CPL pushes high,low of cmp(high/low)+1 (2's complement) ; n1 n2 EMUL - pushes high,low of n1(16)*n2(16) ; n1high n1low n2 EDIV - pushes result, remainder of n1(32)/n2(16) ; n1high n1low n2high n2low DSWAP - makes stack n2high n2low n1high n1low ; "decimal" $DVAL - converts decimal number string to high,low on stack ; high low $DSTR - converts high,low to decimal number string ; "Loading DADD" $PRINT CRLF ; n1high n1low n2high n2low DADD pushes high,low of n1 + n2 CREATE DADD JSB ZSPOP,I pop n2low STA OP2LO JSB ZSPOP,I pop n2high STA OP2HI JSB ZSPOP,I pop n1low STA OP1LO JSB ZSPOP,I pop n1high STA OP1HI JSB ADD32 call add sub STA TMP4 save low result in tmp STB 0 save high result in A JSB ZSPSH,I push result high LDA TMP4 JSB ZSPSH,I push result low JMP ZNXT,I * math subs... * 32 bit add... compute OP1 + OP2 * OP1HI OP1LO OP2HI OP2LO hold operands * result low left in A, high in B ADD32 NOP CLE CLO LDA OP1LO ADA OP2LO LDB OP1HI SEZ INB ADB OP2HI JMP ADD32,I * 2's complement OP2 - for doing subtractions NEG32 NOP CLE CLO LDA OP2LO LDB OP2HI CMA,INA CMB,SEZ INB STA OP2LO STB OP2HI JMP NEG32,I OP1HI OCT 0 used by math subs... OP1LO OCT 0 OP2HI OCT 0 OP2LO OCT 0 END "Loading D2CPL" $PRINT CRLF ; high low D2CPL pushes high,low of cmp(high/low)+1 (2's complement) CREATE D2CPL /KEEP JSB ZSPOP,I pop low STA OP2LO JSB ZSPOP,I pop high STA OP2HI JSB NEG32 call negate sub LDA OP2HI JSB ZSPSH,I push high LDA OP2LO JSB ZSPSH,I push low END "Loading EMUL" $PRINT CRLF ; n1 n2 EMUL - pushes high,low of n1(16)*n2(16) CREATE EMUL JSB ZSPOP,I get n2 STA TMP4 put in tmp4 JSB ZSPOP,I get n1 in A MPY DEF TMP4 multiply n1 by n2 STA TMP4 save low word in tmp4 LDA 1 put high word in A JSB ZSPSH,I push high word LDA TMP4 get low word JSB ZSPSH,I push low word END "Loading EDIV" $PRINT CRLF ; n1high n1low n2 EDIV - pushes result, remainder of n1(32)/n2(16) CREATE EDIV JSB ZSPOP,I get n2 STA TMP4 put n2 in tmp4 JSB ZSPOP,I get low word of n1 STA TMP3 put n1low in tmp3 JSB ZSPOP,I get high word of n1 STA 1 put n1high in B LDA TMP3 put n1low in A DIV DEF TMP4 divide n1 by n2 STB TMP4 store remainder in tmp4 JSB ZSPSH,I push result LDA TMP4 get remainder JSB ZSPSH,I push remainder END ; "Loading DSWAP" $PRINT CRLF ;a b c d becomes c d a b DEFINE DSWAP S>Z S>Z ;save op2 S>Y S>Y ;save op1 Z>S Z>S ;push op2 Y>S Y>S ;push op1 END ; "Loading $DVAL" $PRINT CRLF OCTAL DEFINE $DVAL ; programmed 7/28/04 ; $DVAL pops string from X and pushes high,low value on stack ; decimal only (don't have to be running in decimal mode) ; embedded commas are ignored ;---- optional sanitize code ---- remove for lean and mean ;with this code can tolerate spaces and pick out the first ;number it finds in a string, "the answer is 42.125" returns 42 $LEN DUP IFZ DROP ;don't need to do anything if empty ELSE ;if non-empty string scan for digits #0 S>Z ;control on Z #0 SWAP DEC +DO ;loop thru string 0 to len-1 INDEX $GET ;push char n CASE ;check character = 55 #1 ; "-" is ok = 54 #1 ; "," is ok < 60 #0 ;less than "0" not ok > 71 #0 ;greater than "9" not ok DEFAULT #1 ; anything else ok ENDCASE IFZ ;if not ok INDEX 40 $PUT ;replace junk with space Z>S DUP S>Z IFNZ ;if good digits Z>S DROP 2 S>Z ;make 2 to mean junk on end ENDIF ELSE Z>S DUP S>Z IFZ Z>S DROP #1 S>Z ENDIF ;mark run of good characters Z>S DUP S>Z 2 SUB IFZ INDEX 40 $PUT ENDIF ;erase extra numeric or not ENDIF +LOOP Z>S DROP ;drop control $TRIM ;eliminate surrounding spaces ENDIF ;---- end sanitize code ---- ;convert string to double... #0 #0 ;double result and multiplier on stack #0 #1 ;push multiplier DO ;until string is empty $LEN IFZ #1 ;terminate when string empty ELSE $TAIL ;push ascii digit DUP 55 SUB IFZ ;if "-" DROP DSWAP D2CPL DSWAP ;make result negative ELSE DUP 54 SUB IFZ ;if "," DROP ;ignore commas ELSE ;hopefully it's a digit 60 SUB ;convert to decimal ;add multiplier to result n times DUP IFNZ #1 SWAP +DO ;loop n times OVER OVER S>Y S>Y ;save multiplier DADD ;double add to result Y>S Y>S ;put back multiplier +LOOP ELSE DROP ;the 0 ENDIF ;multiply multiplier by 10 OVER OVER DADD ;multiply by 2 OVER OVER S>Y S>Y ;save it OVER OVER DADD ;multiply by 2 again (4) OVER OVER DADD ;multiply by 2 again (8) Y>S Y>S DADD ;add in results from x2 (10) ENDIF ENDIF #0 ;keep going for next digit ENDIF UNTIL ;string is empty $DROP ;empty string DROP DROP ;multiplier ;result high,low on stack END ; "Loading $DSTR" $PRINT CRLF OCTAL DEFINE $DSTR ;programmed 8/1/04 ;pops dword and pushes string containing decimal equivalent SWAP DUP S>Z SWAP Z>S 100000 AND IFNZ ;if negative "-" ;push a minus sign D2CPL ;2-compliment the dword to convert as positive ELSE "" ;positive number, push an empty string ENDIF #0 S>Z ;put a 0-suppression flag on the Z stack #1 12 +DO ;loop 10 times for the 10 decimal places OVER OVER ;duplicate number to display INDEX CASE ;get inverted divisor = 000001 142145 033000 ;"-1000000000" = 000002 175012 017400 ;"-100000000" = 000003 177547 064600 ;"-10000000" = 000004 177760 136700 ;"-1000000" = 000005 177776 074540 ;"-100000" = 000006 177777 154360 ;"-10000" = 000007 177777 176030 ;"-1000" = 000010 177777 177634 ;"-100" = 000011 177777 177766 ;"-10" = 000012 177777 177777 ;"-1" ENDCASE S>Z S>Z ;keep on Z to avoid recomputing #0 S>Y ;count on Y, will become digit DO ;until negative Z>S Z>S OVER OVER S>Z S>Z ;push inverted divisor DADD ;really subtract divisor OVER 100000 AND ;push 0 if not negative DUP IFZ ;if positive Y>S INC S>Y ;increment ENDIF UNTIL ;loop until negative DROP DROP ;don't negative number anymore ;S stack = (remainder of) number to display high,low ;X stack = "result" ;Y stack = digit count ;Z stack = leading 0 flag, high,low inverted divisor Z>S Z>S ;get inverted divisor back on stack Y>S ;get count DUP ;duplicate for later DUP IFZ ;if zero DROP ;drop the 0 count Z>S DUP S>Z IFNZ ;if 0-suppress not 0 60 $APPEND ;add "0" to result string ENDIF ELSE ;non-zero digit Z>S INC S>Z ;set 0-suppress flag 60 ADD $APPEND ;add digit to result string ENDIF ;inv. div. high, low, digit on stack ;subtract digit * divisor from number to make remainder DUP IFZ ;if digit = 0 DROP ;drop digit, nothing to subtract ELSE ;if digit > 0 SWAP ROT S>Z S>Z ;stash inverted divisor #1 SWAP +DO ;loop digit times Z>S Z>S OVER OVER S>Z S>Z DADD ;subtract divisor +LOOP Z>S Z>S ENDIF DROP DROP ;inverted divisor +LOOP ;loop until done Z>S DROP ;drop 0-suppression flag DROP DROP ;now empty remainder $LEN IFZ 60 $APPEND ENDIF ;make "0" if empty string END ; "Done" $PRINT CONSOLE