1*26694Sdonn #ifdef LIBC_SCCS 222154Smckusick .data 322154Smckusick _sccsid: 4*26694Sdonn .asciz "@(#)doprnt.c 5.4 (Berkeley) 03/09/86" 522154Smckusick .text 6*26694Sdonn #endif LIBC_SCCS 722154Smckusick 82041Swnj # C library -- conversions 92041Swnj 1024426Smckusick #include "DEFS.h" 1124426Smckusick 122041Swnj .globl __doprnt 132041Swnj .globl __flsbuf 142041Swnj 152041Swnj #define vbit 1 162041Swnj #define flags r10 172041Swnj #define ndfnd 0 182041Swnj #define prec 1 192041Swnj #define zfill 2 202041Swnj #define minsgn 3 212041Swnj #define plssgn 4 222041Swnj #define numsgn 5 232041Swnj #define caps 6 242041Swnj #define blank 7 252041Swnj #define gflag 8 262041Swnj #define dpflag 9 272041Swnj #define width r9 282041Swnj #define ndigit r8 292041Swnj #define llafx r7 302041Swnj #define lrafx r6 312041Swnj #define fdesc -4(fp) 322041Swnj #define exp -8(fp) 332041Swnj #define sexp -12(fp) 342041Swnj #define nchar -16(fp) 352041Swnj #define sign -17(fp) 362041Swnj .set ch.zer,'0 # cpp doesn't like single appostrophes 372041Swnj 382041Swnj .align 2 392041Swnj strtab: # translate table for detecting null and percent 402041Swnj .byte 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 412041Swnj .byte 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 422041Swnj .byte ' ,'!,'",'#,'$, 0,'&,'','(,'),'*,'+,',,'-,'.,'/ 432041Swnj .byte '0,'1,'2,'3,'4,'5,'6,'7,'8,'9,':,';,'<,'=,'>,'? 442041Swnj .byte '@,'A,'B,'C,'D,'E,'F,'G,'H,'I,'J,'K,'L,'M,'N,'O 452041Swnj .byte 'P,'Q,'R,'S,'T,'U,'V,'W,'X,'Y,'Z,'[,'\,'],'^,'_ 462041Swnj .byte '`,'a,'b,'c,'d,'e,'f,'g,'h,'i,'j,'k,'l,'m,'n,'o 472041Swnj .byte 'p,'q,'r,'s,'t,'u,'v,'w,'x,'y,'z,'{,'|,'},'~,127 482041Swnj .byte 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143 492041Swnj .byte 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159 502041Swnj .byte 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175 512041Swnj .byte 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191 522041Swnj .byte 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207 532041Swnj .byte 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223 542041Swnj .byte 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239 552041Swnj .byte 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 562041Swnj 5724426Smckusick ENTRY(_doprnt, R6|R7|R8|R9|R10|R11) 585071Smckusic jbr doit 595071Smckusic 602041Swnj strfoo: 612041Swnj clrl r4 # fix interrupt race 622041Swnj jbr strok # and try again 632041Swnj strout2: # enter here to force out r2; r0,r1 must be set 6417342Sralph # do some tricks with line buffering (_IOLBF) first 6517342Sralph movl fdesc,r3 6617342Sralph jbc $7,16(r3),0f # not line buffered (unbuffered) 6717342Sralph addl3 12(r3),8(r3),r4 # fdesc->_base+fdesc->_bufsiz 6817342Sralph cmpl 4(r3),r4 # buffer full? 6917342Sralph jgeq 0f # yes 7017342Sralph cmpl r2,$10 # c == '\n'? 7117342Sralph jeql 0f # yes 7217342Sralph movb r2,*4(r3) # line buffered and not buffer full 7317342Sralph incl 4(r3) # and not newline 7417342Sralph clrl (r3) # just stuff it and fix _cnt 7517342Sralph incl nchar # count the char 7617342Sralph jbr strout # skip __flsbuf 7717342Sralph 0: pushr $3 # save input descriptor 782041Swnj pushl fdesc # FILE 792041Swnj pushl r2 # the char 802041Swnj calls $2,__flsbuf # please empty the buffer and handle 1 char 812041Swnj tstl r0 # successful? 822041Swnj jgeq strm1 # yes 832041Swnj jbcs $31,nchar,strm1 # turn on sign bit of nchar to signify error 842041Swnj strm1: 852041Swnj incl nchar # count the char 862041Swnj popr $3 # get input descriptor back 872041Swnj strout: # enter via bsb with (r0,r1)=input descriptor 882041Swnj movab strtab,r3 # table address 892041Swnj movq *fdesc,r4 # output descriptor 902041Swnj jbs $31,r4,strfoo # negative count is a no no 912041Swnj strok: 922041Swnj addl2 r0,nchar # we intend to move this many chars 933358Swnj /******* Start bogus movtuc workaround *****/ 943358Swnj clrl r2 953358Swnj tstl r0 963358Swnj bleq movdon 973358Swnj movlp: 983358Swnj tstl r4 993358Swnj bleq movdon 1003358Swnj movzbl (r1)+,r3 1013358Swnj tstb strtab[r3] 1023358Swnj bneq 1f 1033358Swnj mnegl $1,r2 1043358Swnj decl r1 1053358Swnj brb movdon 1063358Swnj 1: 1073358Swnj movb r3,(r5)+ 1083358Swnj decl r4 1093358Swnj sobgtr r0,movlp 1103358Swnj /******* End bogus movtuc workaround *** 1112041Swnj movtuc r0,(r1),$0,(r3),r4,(r5) 1123358Swnj movpsl r2 /* squirrel away condition codes */ 1133358Swnj /******* End equally bogus movtuc ****/ 1143358Swnj movdon: movq r4,*fdesc /* update output descriptor */ 1152041Swnj subl2 r0,nchar # some chars not moved 1162041Swnj jbs $vbit,r2,stresc # terminated by escape? 1172041Swnj sobgeq r0,strmore # no; but out buffer might be full 1182041Swnj stresc: 1192041Swnj rsb 12017342Sralph strmore: 12117342Sralph movzbl (r1)+,r2 # one char 12217342Sralph tstb strtab[r2] # translate 12317342Sralph jneq strout2 # bad guy in disguise (outbuf is full) 12417342Sralph incl r0 # fix the length 12517342Sralph decl r1 # and the addr 1262041Swnj movl $1<vbit,r2 # fake condition codes 1272041Swnj rsb 1282041Swnj 1292041Swnj errdone: 1302041Swnj jbcs $31,nchar,prdone # set error bit 1312041Swnj prdone: 1322041Swnj movl nchar,r0 1332041Swnj ret 1342041Swnj 1355071Smckusic doit: 1362041Swnj movab -256(sp),sp # work space 1372041Swnj movl 4(ap),r11 # addr of format string 1382041Swnj movl 12(ap),fdesc # output FILE ptr 1392041Swnj movl 8(ap),ap # addr of first arg 1402041Swnj clrl nchar # number of chars transferred 1412041Swnj loop: 1422041Swnj movzwl $65535,r0 # pseudo length 1433358Swnj movl r11,r1 # fmt addr 1443357Swnj # comet sucks. 1453357Swnj movq *fdesc,r4 1463357Swnj subl3 r1,r5,r2 1473357Swnj jlss lp1 1483357Swnj cmpl r0,r2 1493357Swnj jleq lp1 1503357Swnj movl r2,r0 1513357Swnj lp1: 1523357Swnj # 1532041Swnj bsbw strout # copy to output, stop at null or percent 1542041Swnj movl r1,r11 # new fmt 1552041Swnj jbc $vbit,r2,loop # if no escape, then very long fmt 1562041Swnj tstb (r11)+ # escape; null or percent? 1572041Swnj jeql prdone # null means end of fmt 1582041Swnj 1592041Swnj movl sp,r5 # reset output buffer pointer 1602041Swnj clrq r9 # width; flags 1612041Swnj clrq r6 # lrafx,llafx 1622041Swnj longorunsg: # we can ignore both of these distinctions 1632041Swnj short: 1642041Swnj L4a: 1652041Swnj movzbl (r11)+,r0 # so capital letters can tail merge 1662041Swnj L4: caseb r0,$' ,$'x-' # format char 1672041Swnj L5: 1682041Swnj .word space-L5 # space 1692041Swnj .word fmtbad-L5 # ! 1702041Swnj .word fmtbad-L5 # " 1712041Swnj .word sharp-L5 # # 1722041Swnj .word fmtbad-L5 # $ 1732041Swnj .word fmtbad-L5 # % 1742041Swnj .word fmtbad-L5 # & 1752041Swnj .word fmtbad-L5 # ' 1762041Swnj .word fmtbad-L5 # ( 1772041Swnj .word fmtbad-L5 # ) 1782041Swnj .word indir-L5 # * 1792041Swnj .word plus-L5 # + 1802041Swnj .word fmtbad-L5 # , 1812041Swnj .word minus-L5 # - 1822041Swnj .word dot-L5 # . 1832041Swnj .word fmtbad-L5 # / 1842041Swnj .word gnum0-L5 # 0 1852041Swnj .word gnum-L5 # 1 1862041Swnj .word gnum-L5 # 2 1872041Swnj .word gnum-L5 # 3 1882041Swnj .word gnum-L5 # 4 1892041Swnj .word gnum-L5 # 5 1902041Swnj .word gnum-L5 # 6 1912041Swnj .word gnum-L5 # 7 1922041Swnj .word gnum-L5 # 8 1932041Swnj .word gnum-L5 # 9 1942041Swnj .word fmtbad-L5 # : 1952041Swnj .word fmtbad-L5 # ; 1962041Swnj .word fmtbad-L5 # < 1972041Swnj .word fmtbad-L5 # = 1982041Swnj .word fmtbad-L5 # > 1992041Swnj .word fmtbad-L5 # ? 2002041Swnj .word fmtbad-L5 # @ 2012041Swnj .word fmtbad-L5 # A 2022041Swnj .word fmtbad-L5 # B 2032041Swnj .word fmtbad-L5 # C 2042041Swnj .word decimal-L5 # D 2052041Swnj .word capital-L5 # E 2062041Swnj .word fmtbad-L5 # F 2072041Swnj .word capital-L5 # G 2082041Swnj .word fmtbad-L5 # H 2092041Swnj .word fmtbad-L5 # I 2102041Swnj .word fmtbad-L5 # J 2112041Swnj .word fmtbad-L5 # K 2122041Swnj .word fmtbad-L5 # L 2132041Swnj .word fmtbad-L5 # M 2142041Swnj .word fmtbad-L5 # N 2152041Swnj .word octal-L5 # O 2162041Swnj .word fmtbad-L5 # P 2172041Swnj .word fmtbad-L5 # Q 2182041Swnj .word fmtbad-L5 # R 2192041Swnj .word fmtbad-L5 # S 2202041Swnj .word fmtbad-L5 # T 2212041Swnj .word unsigned-L5 # U 2222041Swnj .word fmtbad-L5 # V 2232041Swnj .word fmtbad-L5 # W 22418326Sralph .word capital-L5 # X 2252041Swnj .word fmtbad-L5 # Y 2262041Swnj .word fmtbad-L5 # Z 2272041Swnj .word fmtbad-L5 # [ 2282041Swnj .word fmtbad-L5 # \ 2292041Swnj .word fmtbad-L5 # ] 2302041Swnj .word fmtbad-L5 # ^ 2312041Swnj .word fmtbad-L5 # _ 2322041Swnj .word fmtbad-L5 # ` 2332041Swnj .word fmtbad-L5 # a 2342041Swnj .word fmtbad-L5 # b 2352041Swnj .word charac-L5 # c 2362041Swnj .word decimal-L5 # d 2372041Swnj .word scien-L5 # e 2382041Swnj .word float-L5 # f 2392041Swnj .word general-L5 # g 2402041Swnj .word short-L5 # h 2412041Swnj .word fmtbad-L5 # i 2422041Swnj .word fmtbad-L5 # j 2432041Swnj .word fmtbad-L5 # k 2442041Swnj .word longorunsg-L5 # l 2452041Swnj .word fmtbad-L5 # m 2462041Swnj .word fmtbad-L5 # n 2472041Swnj .word octal-L5 # o 2482041Swnj .word fmtbad-L5 # p 2492041Swnj .word fmtbad-L5 # q 2502041Swnj .word fmtbad-L5 # r 2512041Swnj .word string-L5 # s 2522041Swnj .word fmtbad-L5 # t 2532041Swnj .word unsigned-L5 # u 2542041Swnj .word fmtbad-L5 # v 2552041Swnj .word fmtbad-L5 # w 2562041Swnj .word hex-L5 # x 2572041Swnj fmtbad: 2582041Swnj movb r0,(r5)+ # print the unfound character 2592041Swnj jeql errdone # dumb users who end the format with a % 2602041Swnj jbr prbuf 2612041Swnj capital: 2622041Swnj bisl2 $1<caps,flags # note that it was capitalized 2632041Swnj xorb2 $'a^'A,r0 # make it small 2642041Swnj jbr L4 # and try again 2652041Swnj 2662041Swnj string: 2672041Swnj movl ndigit,r0 2682041Swnj jbs $prec,flags,L20 # max length was specified 2692041Swnj mnegl $1,r0 # default max length 2702041Swnj L20: movl (ap)+,r2 # addr first byte 2712041Swnj locc $0,r0,(r2) # find the zero at the end 2722041Swnj movl r1,r5 # addr last byte +1 2732041Swnj movl r2,r1 # addr first byte 2742041Swnj jbr prstr 2752041Swnj 2762041Swnj htab: .byte '0,'1,'2,'3,'4,'5,'6,'7,'8,'9,'a,'b,'c,'d,'e,'f 2772041Swnj Htab: .byte '0,'1,'2,'3,'4,'5,'6,'7,'8,'9,'A,'B,'C,'D,'E,'F 2782041Swnj 2792041Swnj octal: 2802041Swnj movl $30,r2 # init position 2812041Swnj movl $3,r3 # field width 2822041Swnj movab htab,llafx # translate table 2832041Swnj jbr L10 2842041Swnj 2852041Swnj hex: 2862041Swnj movl $28,r2 # init position 2872041Swnj movl $4,r3 # field width 2882041Swnj movab htab,llafx # translate table 2892041Swnj jbc $caps,flags,L10 2902041Swnj movab Htab,llafx 2912041Swnj L10: mnegl r3,r6 # increment 2922041Swnj clrl r1 2932041Swnj addl2 $4,r5 # room for left affix (2) and slop [forced sign?] 2942041Swnj movl (ap)+,r0 # fetch arg 2952041Swnj L11: extzv r2,r3,r0,r1 # pull out a digit 2962041Swnj movb (llafx)[r1],(r5)+ # convert to character 2972041Swnj L12: acbl $0,r6,r2,L11 # continue until done 2982041Swnj clrq r6 # lrafx, llafx 2992041Swnj clrb (r5) # flag end 3002041Swnj skpc $'0,$11,4(sp) # skip over leading zeroes 3012041Swnj jbc $numsgn,flags,prn3 # easy if no left affix 3022041Swnj tstl -4(ap) # original value 3032041Swnj jeql prn3 # no affix on 0, for some reason 3042041Swnj cmpl r3,$4 # were we doing hex or octal? 3052041Swnj jneq L12a # octal 3062041Swnj movb $'x,r0 3072041Swnj jbc $caps,flags,L12b 3082041Swnj movb $'X,r0 3092041Swnj L12b: movb r0,-(r1) 3102041Swnj movl $2,llafx # leading 0x for hex is an affix 3112041Swnj L12a: movb $'0,-(r1) # leading zero for octal is a digit, not an affix 3122041Swnj jbr prn3 # omit sign (plus, blank) massaging 3132041Swnj 3142041Swnj unsigned: 3152041Swnj lunsigned: 3162041Swnj bicl2 $1<plssgn|1<blank,flags # omit sign (plus, blank) massaging 3172041Swnj extzv $1,$31,(ap),r0 # right shift logical 1 bit 3182041Swnj cvtlp r0,$10,(sp) # convert [n/2] to packed 3192041Swnj movp $10,(sp),8(sp) # copy packed 3202041Swnj addp4 $10,8(sp),$10,(sp) # 2*[n/2] in packed, at (sp) 3212041Swnj blbc (ap)+,L14 # n was even 3222041Swnj addp4 $1,pone,$10,(sp) # n was odd 3232041Swnj jbr L14 3242041Swnj 3252041Swnj patdec: # editpc pattern for decimal printing 3262041Swnj .byte 0xAA # eo$float 10 3272041Swnj .byte 0x01 # eo$end_float 3282041Swnj .byte 0 # eo$end 3292041Swnj 3302041Swnj decimal: 3312041Swnj cvtlp (ap)+,$10,(sp) # 10 digits max 3322041Swnj jgeq L14 3332041Swnj incl llafx # minus sign is a left affix 3342041Swnj L14: editpc $10,(sp),patdec,8(sp) # ascii at 8(sp); r5=end+1 3352041Swnj skpc $' ,$11,8(sp) # skip leading blanks; r1=first 3362041Swnj 3372041Swnj prnum: # r1=addr first byte, r5=addr last byte +1, llafx=size of signs 3382041Swnj # -1(r1) vacant, for forced sign 3392041Swnj tstl llafx 3402041Swnj jneq prn3 # already some left affix, dont fuss 3412041Swnj jbc $plssgn,flags,prn2 3422041Swnj movb $'+,-(r1) # needs a plus sign 3432041Swnj jbr prn4 3442041Swnj prn2: jbc $blank,flags,prn3 3452041Swnj movb $' ,-(r1) # needs a blank sign 3462041Swnj prn4: incl llafx 3472041Swnj prn3: jbs $prec,flags,prn1 3482041Swnj movl $1,ndigit # default precision is 1 3492041Swnj prn1: subl3 r1,r5,lrafx # raw width 3502041Swnj subl2 llafx,lrafx # number of digits 3512041Swnj subl2 lrafx,ndigit # number of leading zeroes needed 3522041Swnj jleq prstr # none 3532041Swnj addl2 llafx,r1 # where current digits start 3542041Swnj pushl r1 # movcx gobbles registers 3552041Swnj # check bounds on users who say %.300d 3562041Swnj movab 32(r5)[ndigit],r2 3572041Swnj subl2 fp,r2 3582041Swnj jlss prn5 3592041Swnj subl2 r2,ndigit 3602041Swnj prn5: 3612041Swnj # 3622041Swnj movc3 lrafx,(r1),(r1)[ndigit] # make room in middle 3632041Swnj movc5 $0,(r1),$ch.zer,ndigit,*(sp) # '0 fill 3642041Swnj subl3 llafx,(sp)+,r1 # first byte addr 3652041Swnj addl3 lrafx,r3,r5 # last byte addr +1 3662041Swnj 3672041Swnj prstr: # r1=addr first byte; r5=addr last byte +1 3682041Swnj # width=minimum width; llafx=len. left affix 3692041Swnj # ndigit=<avail> 3702041Swnj subl3 r1,r5,ndigit # raw width 3712041Swnj subl3 ndigit,width,r0 # pad length 3722041Swnj jleq padlno # in particular, no left padding 3732041Swnj jbs $minsgn,flags,padlno 3742041Swnj # extension for %0 flag causing left zero padding to field width 3752041Swnj jbs $zfill,flags,padlz 3762041Swnj # this bsbb needed even if %0 flag extension is removed 3772041Swnj bsbb padb # blank pad on left 3782041Swnj jbr padnlz 3792041Swnj padlz: 3802041Swnj movl llafx,r0 3812041Swnj jleq padnlx # left zero pad requires left affix first 3822041Swnj subl2 r0,ndigit # part of total length will be transferred 3832041Swnj subl2 r0,width # and will account for part of minimum width 3842041Swnj bsbw strout # left affix 3852041Swnj padnlx: 3862041Swnj subl3 ndigit,width,r0 # pad length 3872041Swnj bsbb padz # zero pad on left 3882041Swnj padnlz: 3892041Swnj # end of extension for left zero padding 3902041Swnj padlno: # remaining: root, possible right padding 3912041Swnj subl2 ndigit,width # root reduces minimum width 3922041Swnj movl ndigit,r0 # root length 3932041Swnj p1: bsbw strout # transfer to output buffer 3942041Swnj p3: jbc $vbit,r2,padnpct # percent sign (or null byte via %c) ? 3952041Swnj decl r0 # yes; adjust count 3962041Swnj movzbl (r1)+,r2 # fetch byte 3972041Swnj movq *fdesc,r4 # output buffer descriptor 3982041Swnj sobgeq r4,p2 # room at the out [inn] ? 3992041Swnj bsbw strout2 # no; force it, then try rest 4002041Swnj jbr p3 # here we go 'round the mullberry bush, ... 4012041Swnj p2: movb r2,(r5)+ # hand-deposit the percent or null 4022041Swnj incl nchar # count it 4032041Swnj movq r4,*fdesc # store output descriptor 4042041Swnj jbr p1 # what an expensive hiccup! 4052041Swnj padnpct: 4062041Swnj movl width,r0 # size of pad 4072041Swnj jleq loop 4082041Swnj bsbb padb 4092041Swnj jbr loop 4102041Swnj 4112041Swnj padz: 4122041Swnj movb $'0,r2 4132041Swnj jbr pad 4142041Swnj padb: 4152041Swnj movb $' ,r2 4162041Swnj pad: 4172041Swnj subl2 r0,width # pad width decreases minimum width 4182041Swnj pushl r1 # save non-pad addr 4192041Swnj movl r0,llafx # remember width of pad 4202041Swnj subl2 r0,sp # allocate 4212041Swnj movc5 $0,(r0),r2,llafx,(sp) # create pad string 4222041Swnj movl llafx,r0 # length 4232041Swnj movl sp,r1 # addr 4242041Swnj bsbw strout 4252041Swnj addl2 llafx,sp # deallocate 4262041Swnj movl (sp)+,r1 # recover non-pad addr 4272041Swnj rsb 4282041Swnj 4292041Swnj pone: .byte 0x1C # packed 1 4302041Swnj 4312041Swnj charac: 4322041Swnj movl (ap)+,r0 # word containing the char 4332041Swnj movb r0,(r5)+ # one byte, that's all 4342041Swnj 4352041Swnj prbuf: 4362041Swnj movl sp,r1 # addr first byte 4372041Swnj jbr prstr 4382041Swnj 4392041Swnj space: bisl2 $1<blank,flags # constant width e fmt, no plus sign 4402041Swnj jbr L4a 4412041Swnj sharp: bisl2 $1<numsgn,flags # 'self identifying', please 4422041Swnj jbr L4a 4432041Swnj plus: bisl2 $1<plssgn,flags # always print sign for floats 4442041Swnj jbr L4a 4452041Swnj minus: bisl2 $1<minsgn,flags # left justification, please 4462041Swnj jbr L4a 4472041Swnj gnum0: jbs $ndfnd,flags,gnum 4482041Swnj jbs $prec,flags,gnump # ignore when reading precision 4492041Swnj bisl2 $1<zfill,flags # leading zero fill, please 4502041Swnj gnum: jbs $prec,flags,gnump 4512041Swnj moval (width)[width],width # width *= 5; 4522041Swnj movaw -ch.zer(r0)[width],width # width = 2*witdh + r0 - '0'; 4532041Swnj jbr gnumd 4542041Swnj gnump: moval (ndigit)[ndigit],ndigit # ndigit *= 5; 4552041Swnj movaw -ch.zer(r0)[ndigit],ndigit # ndigit = 2*ndigit + r0 - '0'; 4562041Swnj gnumd: bisl2 $1<ndfnd,flags # digit seen 4572041Swnj jbr L4a 4582041Swnj dot: clrl ndigit # start on the precision 4592041Swnj bisl2 $1<prec,flags 4602041Swnj bicl2 $1<ndfnd,flags 4612041Swnj jbr L4a 4622041Swnj indir: 4632041Swnj jbs $prec,flags,in1 4642041Swnj movl (ap)+,width # width specified by parameter 4652041Swnj jgeq gnumd 4662041Swnj xorl2 $1<minsgn,flags # parameterized left adjustment 4672041Swnj mnegl width,width 4682041Swnj jbr gnumd 4692041Swnj in1: 4702041Swnj movl (ap)+,ndigit # precision specified by paratmeter 4712041Swnj jgeq gnumd 4722041Swnj mnegl ndigit,ndigit 4732041Swnj jbr gnumd 4742041Swnj 4752041Swnj float: 4762041Swnj jbs $prec,flags,float1 4772041Swnj movl $6,ndigit # default # digits to right of decpt. 4782041Swnj float1: bsbw fltcvt 4792041Swnj addl3 exp,ndigit,r7 4802041Swnj movl r7,r6 # for later "underflow" checking 4812041Swnj bgeq fxplrd 4822041Swnj clrl r7 # poor programmer planning 4832041Swnj fxplrd: cmpl r7,$31 # expressible in packed decimal? 4842041Swnj bleq fnarro # yes 4852041Swnj movl $31,r7 4862041Swnj fnarro: subl3 $17,r7,r0 # where to round 4872041Swnj ashp r0,$17,(sp),$5,r7,16(sp) # do it 4882041Swnj bvc fnovfl 4892041Swnj # band-aid for microcode error (spurious overflow) 4902041Swnj # clrl r0 # assume even length result 4912041Swnj # jlbc r7,fleven # right 4922041Swnj # movl $4,r0 # odd length result 4932041Swnj #fleven: cmpv r0,$4,16(sp),$0 # top digit zero iff true overflow 4942041Swnj # bneq fnovfl 4952041Swnj # end band-aid 4962041Swnj aobleq $0,r6,fnovfl # if "underflow" then jump 4972041Swnj movl r7,r0 4982041Swnj incl exp 4992041Swnj incl r7 5002041Swnj ashp r0,$1,pone,$0,r7,16(sp) 5012041Swnj ashl $-1,r7,r0 # displ to last byte 5022041Swnj bisb2 sign,16(sp)[r0] # insert sign 5032041Swnj fnovfl: 5042041Swnj movab 16(sp),r1 # packed source 5052041Swnj movl r7,r6 # packed length 5062041Swnj pushab prnum # goto prnum after fall-through call to fedit 5072041Swnj 5082041Swnj 5092041Swnj # enter via bsb 5102041Swnj # r1=addr of packed source 5112041Swnj # 16(r1) used to unpack source 5122041Swnj # 48(r1) used to construct pattern to unpack source 5132041Swnj # 48(r1) used to hold result 5142041Swnj # r6=length of packed source (destroyed) 5152041Swnj # exp=# digits to left of decimal point (destroyed) 5162041Swnj # ndigit=# digits to right of decimal point (destroyed) 5172041Swnj # sign=1 if negative, 0 otherwise 5182041Swnj # stack will be used for work space for pattern and unpacked source 5192041Swnj # exits with 5202041Swnj # r1=addr of punctuated result 5212041Swnj # r5=addr of last byte +1 5222041Swnj # llafx=1 if minus sign inserted, 0 otherwise 5232041Swnj fedit: 5242041Swnj pushab 48(r1) # save result addr 5252041Swnj movab 48(r1),r3 # pattern addr 5262041Swnj movb $0x03,(r3)+ # eo$set_signif 5272041Swnj movc5 $0,(r1),$0x91,r6,(r3) # eo$move 1 5282041Swnj clrb (r3) # eo$end 5292041Swnj editpc r6,(r1),48(r1),16(r1) # unpack 'em all 5302041Swnj subl3 r6,r5,r1 # addr unpacked source 5312041Swnj movl (sp),r3 # punctuated output placed here 5322041Swnj clrl llafx 5332041Swnj jlbc sign,f1 5342041Swnj movb $'-,(r3)+ # negative 5352041Swnj incl llafx 5362041Swnj f1: movl exp,r0 5372041Swnj jgtr f2 5382041Swnj movb $'0,(r3)+ # must have digit before decimal point 5392041Swnj jbr f3 5402041Swnj f2: cmpl r0,r6 # limit on packed length 5412041Swnj jleq f4 5422041Swnj movl r6,r0 5432041Swnj f4: subl2 r0,r6 # eat some digits 5442041Swnj subl2 r0,exp # from the exponent 5452041Swnj movc3 r0,(r1),(r3) # (most of the) digits to left of decimal point 5462041Swnj movl exp,r0 # need any more? 5472041Swnj jleq f3 5482041Swnj movc5 $0,(r1),$'0,r0,(r3) # '0 fill 5492041Swnj f3: movl ndigit,r0 # # digits to right of decimal point 5502041Swnj jgtr f5 5512041Swnj jbs $numsgn,flags,f5 # no decimal point unless forced 5522041Swnj jbcs $dpflag,flags,f6 # no decimal point 5532041Swnj f5: movb $'.,(r3)+ # the decimal point 5542041Swnj f6: mnegl exp,r0 # "leading" zeroes to right of decimal point 5552041Swnj jleq f9 5562041Swnj cmpl r0,ndigit # cant exceed this many 5572041Swnj jleq fa 5582041Swnj movl ndigit,r0 5592041Swnj fa: subl2 r0,ndigit 5602041Swnj movc5 $0,(r1),$'0,r0,(r3) 5612041Swnj f9: movl ndigit,r0 5622041Swnj cmpl r0,r6 # limit on packed length 5632041Swnj jleq f7 5642041Swnj movl r6,r0 5652041Swnj f7: subl2 r0,ndigit # eat some digits from the fraction 5662041Swnj movc3 r0,(r1),(r3) # (most of the) digits to right of decimal point 5672041Swnj movl ndigit,r0 # need any more? 5682041Swnj jleq f8 5692041Swnj # check bounds on users who say %.300f 5702041Swnj movab 32(r3)[r0],r2 5712041Swnj subl2 fp,r2 5722041Swnj jlss fb 5732041Swnj subl2 r2,r0 # truncate, willy-nilly 5742041Swnj movl r0,ndigit # and no more digits later, either 5752041Swnj fb: 5762041Swnj # 5772041Swnj subl2 r0,ndigit # eat some digits from the fraction 5782041Swnj movc5 $0,(r1),$'0,r0,(r3) # '0 fill 5792041Swnj f8: movl r3,r5 # addr last byte +1 5802041Swnj popr $1<1 # [movl (sp)+,r1] addr first byte 5812041Swnj rsb 5822041Swnj 5832041Swnj patexp: .byte 0x03 # eo$set_signif 5842041Swnj .byte 0x44,'e # eo$insert 'e 5852041Swnj .byte 0x42,'+ # eo$load_plus '+ 5862041Swnj .byte 0x04 # eo$store_sign 5872041Swnj .byte 0x92 # eo$move 2 5882041Swnj .byte 0 # eo$end 5892041Swnj 5902041Swnj scien: 5912041Swnj incl ndigit 5922041Swnj jbs $prec,flags,L23 5932041Swnj movl $7,ndigit 5942041Swnj L23: bsbw fltcvt # get packed digits 5952041Swnj movl ndigit,r7 5962041Swnj cmpl r7,$31 # expressible in packed decimal? 5972041Swnj jleq snarro # yes 5982041Swnj movl $31,r7 5992041Swnj snarro: subl3 $17,r7,r0 # rounding position 6002041Swnj ashp r0,$17,(sp),$5,r7,16(sp) # shift and round 6012041Swnj bvc snovfl 6022041Swnj # band-aid for microcode error (spurious overflow) 6032041Swnj # clrl r0 # assume even length result 6042041Swnj # jlbc ndigit,sceven # right 6052041Swnj # movl $4,r0 # odd length result 6062041Swnj #sceven: cmpv r0,$4,16(sp),$0 # top digit zero iff true overflow 6072041Swnj # bneq snovfl 6082041Swnj # end band-aid 6092041Swnj incl exp # rounding overflowed to 100... 6102041Swnj subl3 $1,r7,r0 6112041Swnj ashp r0,$1,pone,$0,r7,16(sp) 6122041Swnj ashl $-1,r7,r0 # displ to last byte 6132041Swnj bisb2 sign,16(sp)[r0] # insert sign 6142041Swnj snovfl: 6152041Swnj jbs $gflag,flags,gfmt # %g format 6162041Swnj movab 16(sp),r1 6172041Swnj bsbb eedit 6182041Swnj eexp: 6192041Swnj movl r1,r6 # save fwa from destruction by cvtlp 6202041Swnj subl3 $1,sexp,r0 # 1P exponent 6212041Swnj cvtlp r0,$2,(sp) # packed 6222041Swnj editpc $2,(sp),patexp,(r5) 6232041Swnj movl r6,r1 # fwa 6242041Swnj jbc $caps,flags,prnum 6252041Swnj xorb2 $'e^'E,-4(r5) 6262041Swnj jbr prnum 6272041Swnj 6282041Swnj eedit: 6292041Swnj movl r7,r6 # packed length 6302041Swnj decl ndigit # 1 digit before decimal point 6312041Swnj movl exp,sexp # save from destruction 6322041Swnj movl $1,exp # and pretend 6332041Swnj jbr fedit 6342041Swnj 6352041Swnj gfmt: 6362041Swnj addl3 $3,exp,r0 # exp is 1 more than e 6372041Swnj jlss gfmte # (e+1)+3<0, e+4<=-1, e<=-5 6382041Swnj subl2 $3,r0 # exp [==(e+1)] 6392041Swnj cmpl r0,ndigit 6402041Swnj jgtr gfmte # e+1>n, e>=n 6412041Swnj gfmtf: 6422041Swnj movl r7,r6 6432041Swnj subl2 r0,ndigit # n-e-1 6442041Swnj movab 16(sp),r1 6452041Swnj bsbw fedit 6462041Swnj g1: jbs $numsgn,flags,g2 6472041Swnj jbs $dpflag,flags,g2 # dont strip if no decimal point 6482041Swnj g3: cmpb -(r5),$'0 # strip trailing zeroes 6492041Swnj jeql g3 6502041Swnj cmpb (r5),$'. # and trailing decimal point 6512041Swnj jeql g2 6522041Swnj incl r5 6532041Swnj g2: jbc $gflag,flags,eexp 6542041Swnj jbr prnum 6552041Swnj gfmte: 6562041Swnj movab 16(sp),r1 # packed source 6572041Swnj bsbw eedit 6582041Swnj jbsc $gflag,flags,g1 # gflag now means "use %f" [hence no exponent] 6592041Swnj 6602041Swnj general: 6612041Swnj jbs $prec,flags,gn1 6622041Swnj movl $6,ndigit # default precision is 6 significant digits 6632041Swnj gn1: tstl ndigit # cannot allow precision of 0 6642041Swnj jgtr gn2 6652041Swnj movl $1,ndigit # change 0 to 1, willy-nilly 6662041Swnj gn2: jbcs $gflag,flags,L23 6672041Swnj jbr L23 # safety net 6682041Swnj 6692041Swnj # convert double-floating at (ap) to 17-digit packed at (sp), 6702041Swnj # set 'sign' and 'exp', advance ap. 6712041Swnj fltcvt: 6722041Swnj clrb sign 6732041Swnj movd (ap)+,r5 6742041Swnj jeql fzero 6752041Swnj bgtr fpos 6762041Swnj mnegd r5,r5 6772041Swnj incb sign 6782041Swnj fpos: 6792041Swnj extzv $7,$8,r5,r2 # exponent of 2 6802041Swnj movab -0200(r2),r2 # unbias 6812041Swnj mull2 $59,r2 # 59/196: 3rd convergent continued frac of log10(2) 6822041Swnj jlss eneg 6832041Swnj movab 196(r2),r2 6842041Swnj eneg: 6852041Swnj movab -98(r2),r2 6862041Swnj divl2 $196,r2 6872041Swnj bsbw expten 6882041Swnj cmpd r0,r5 6892041Swnj bgtr ceil 6902041Swnj incl r2 6912041Swnj ceil: movl r2,exp 6922041Swnj mnegl r2,r2 6932041Swnj cmpl r2,$29 # 10^(29+9) is all we can handle 6942041Swnj bleq getman 6952041Swnj muld2 ten16,r5 6962041Swnj subl2 $16,r2 6972041Swnj getman: addl2 $9,r2 # -ceil(log10(x)) + 9 6983357Swnj jsb expten 6992041Swnj emodd r0,r4,r5,r0,r5 # (r0+r4)*r5; r0=int, r5=frac 7002041Swnj fz1: cvtlp r0,$9,16(sp) # leading 9 digits 7012041Swnj ashp $8,$9,16(sp),$0,$17,4(sp) # as top 9 of 17 7022041Swnj emodd ten8,$0,r5,r0,r5 7032041Swnj cvtlp r0,$8,16(sp) # trailing 8 digits 7042041Swnj # if precision >= 17, must round here 7052041Swnj movl ndigit,r7 # so figure out what precision is 7062041Swnj pushab scien 7072041Swnj cmpl (sp)+,(sp) 7082041Swnj jleq gm1 # who called us? 7092041Swnj addl2 exp,r7 # float; adjust for exponent 7102041Swnj gm1: cmpl r7,$17 7112041Swnj jlss gm2 7122041Swnj cmpd r5,$0d0.5 # must round here; check fraction 7132041Swnj jlss gm2 7142041Swnj bisb2 $0x10,8+4(sp) # increment l.s. digit 7152041Swnj gm2: # end of "round here" code 7162041Swnj addp4 $8,16(sp),$17,4(sp) # combine leading and trailing 7172041Swnj bisb2 sign,12(sp) # and insert sign 7182041Swnj rsb 7192041Swnj fzero: clrl r0 7202041Swnj movl $1,exp # 0.000e+00 and 0.000 rather than 0.000e-01 and .000 7212041Swnj jbr fz1 7222041Swnj 7232041Swnj .align 2 7242041Swnj lsb: .long 0x00010000 # lsb in the crazy floating-point format 7252041Swnj 7262041Swnj # return 10^r2 as a double float in r0||r1 and 8 extra bits of precision in r4 7272041Swnj # preserve r2, r5||r6 7282041Swnj expten: 7292041Swnj movd $0d1.0,r0 # begin computing 10^exp10 7302041Swnj clrl r4 # bit counter 7312041Swnj movad ten1,r3 # table address 7322041Swnj tstl r2 7332041Swnj bgeq e10lp 7342041Swnj mnegl r2,r2 # get absolute value 7352041Swnj jbss $6,r2,e10lp # flag as negative 7362041Swnj e10lp: jbc r4,r2,el1 # want this power? 7372041Swnj muld2 (r3),r0 # yes 7382041Swnj el1: addl2 $8,r3 # advance to next power 7392041Swnj aobleq $5,r4,e10lp # through 10^32 7402041Swnj jbcc $6,r2,el2 # correct for negative exponent 7412041Swnj divd3 r0,$0d1.0,r0 # by taking reciprocal 7422041Swnj cmpl $28,r2 7432041Swnj jneq enm28 7442041Swnj addl2 lsb,r1 # 10**-28 needs lsb incremented 7452041Swnj enm28: mnegl r2,r2 # original exponent of 10 7462041Swnj el2: addl3 $5*8,r2,r3 # negative bit positions are illegal? 7472041Swnj jbc r3,xlsbh-5,eoklsb 7482041Swnj subl2 lsb,r1 # lsb was too high 7492041Swnj eoklsb: 7502041Swnj movzbl xprec[r2],r4 # 8 extra bits 7512041Swnj rsb 7522041Swnj 7532041Swnj # powers of ten 7542041Swnj .align 2 7552041Swnj ten1: .word 0x4220,0,0,0 7562041Swnj ten2: .word 0x43c8,0,0,0 7572041Swnj ten4: .word 0x471c,0x4000,0,0 7582041Swnj ten8: .word 0x4dbe,0xbc20,0,0 7592041Swnj ten16: .word 0x5b0e,0x1bc9,0xbf04,0 7602041Swnj ten32: .word 0x759d,0xc5ad,0xa82b,0x70b6 7612041Swnj 7622041Swnj # whether lsb is too high or not 7632041Swnj .byte 1:0,1:0,1:0,1:0,1:1,1:0,1:1,1:0 # -40 thru -33 7642041Swnj .byte 1:0,1:1,1:0,1:0,1:0,1:0,1:1,1:0 # -32 thru -25 7652041Swnj .byte 1:0,1:0,1:1,1:1,1:1,1:1,1:0,1:0 # -24 thru -17 7662041Swnj .byte 1:0,1:1,1:0,1:0,1:1,1:1,1:1,1:1 # -16 thru -9 7672041Swnj .byte 1:1,1:1,1:1,1:0,1:0,1:0,1:0,1:1 # -8 thru -1 7682041Swnj xlsbh: 7692041Swnj .byte 1:0,1:0,1:0,1:0,1:0,1:0,1:0,1:0 # 0 thru 7 7702041Swnj .byte 1:0,1:0,1:0,1:0,1:0,1:0,1:0,1:0 # 8 thru 15 7712041Swnj .byte 1:0,1:0,1:0,1:0,1:0,1:0,1:0,1:0 # 16 thru 23 7722041Swnj .byte 1:0,1:1,1:1,1:0,1:1,1:1,1:1,1:1 # 24 thru 31 7732041Swnj .byte 1:1,1:1,1:1,1:1,1:1,1:1,1:1 # 32 thru 38 7742041Swnj 7752041Swnj # bytes of extra precision 7762041Swnj .byte 0x56,0x76,0xd3,0x88,0xb5,0x62 # -38 thru -33 7772041Swnj .byte 0xba,0xf5,0x32,0x3e,0x0e,0x48,0xdb,0x51 # -32 thru -25 7782041Swnj .byte 0x53,0x27,0xb1,0xef,0xeb,0xa5,0x07,0x49 # -24 thru -17 7792041Swnj .byte 0x5b,0xd9,0x0f,0x13,0xcd,0xff,0xbf,0x97 # -16 thru -9 7802041Swnj .byte 0xfd,0xbc,0xb6,0x23,0x2c,0x3b,0x0a,0xcd # -8 thru -1 7812041Swnj xprec: 7822041Swnj .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 # 0 thru 7 7832041Swnj .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 # 8 thru 15 7842041Swnj .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 # 16 thru 23 7852041Swnj .byte 0x00,0xa0,0xc8,0x3a,0x84,0xe4,0xdc,0x92 # 24 thru 31 7862041Swnj .byte 0x9b,0x00,0xc0,0x58,0xae,0x18,0xef # 32 thru 38 787