1*2041Swnj /* @(#)doprnt.c 4.1 (Berkeley) 12/21/80 */ 2*2041Swnj # C library -- conversions 3*2041Swnj 4*2041Swnj .globl __doprnt 5*2041Swnj .globl __flsbuf 6*2041Swnj 7*2041Swnj #define vbit 1 8*2041Swnj #define flags r10 9*2041Swnj #define ndfnd 0 10*2041Swnj #define prec 1 11*2041Swnj #define zfill 2 12*2041Swnj #define minsgn 3 13*2041Swnj #define plssgn 4 14*2041Swnj #define numsgn 5 15*2041Swnj #define caps 6 16*2041Swnj #define blank 7 17*2041Swnj #define gflag 8 18*2041Swnj #define dpflag 9 19*2041Swnj #define width r9 20*2041Swnj #define ndigit r8 21*2041Swnj #define llafx r7 22*2041Swnj #define lrafx r6 23*2041Swnj #define fdesc -4(fp) 24*2041Swnj #define exp -8(fp) 25*2041Swnj #define sexp -12(fp) 26*2041Swnj #define nchar -16(fp) 27*2041Swnj #define sign -17(fp) 28*2041Swnj .set ch.zer,'0 # cpp doesn't like single appostrophes 29*2041Swnj 30*2041Swnj .align 2 31*2041Swnj strtab: # translate table for detecting null and percent 32*2041Swnj .byte 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 33*2041Swnj .byte 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 34*2041Swnj .byte ' ,'!,'",'#,'$, 0,'&,'','(,'),'*,'+,',,'-,'.,'/ 35*2041Swnj .byte '0,'1,'2,'3,'4,'5,'6,'7,'8,'9,':,';,'<,'=,'>,'? 36*2041Swnj .byte '@,'A,'B,'C,'D,'E,'F,'G,'H,'I,'J,'K,'L,'M,'N,'O 37*2041Swnj .byte 'P,'Q,'R,'S,'T,'U,'V,'W,'X,'Y,'Z,'[,'\,'],'^,'_ 38*2041Swnj .byte '`,'a,'b,'c,'d,'e,'f,'g,'h,'i,'j,'k,'l,'m,'n,'o 39*2041Swnj .byte 'p,'q,'r,'s,'t,'u,'v,'w,'x,'y,'z,'{,'|,'},'~,127 40*2041Swnj .byte 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143 41*2041Swnj .byte 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159 42*2041Swnj .byte 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175 43*2041Swnj .byte 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191 44*2041Swnj .byte 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207 45*2041Swnj .byte 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223 46*2041Swnj .byte 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239 47*2041Swnj .byte 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 48*2041Swnj 49*2041Swnj strfoo: 50*2041Swnj clrl r4 # fix interrupt race 51*2041Swnj jbr strok # and try again 52*2041Swnj strmore: 53*2041Swnj movzbl (r1)+,r2 # one char 54*2041Swnj tstb (r3)[r2] # translate 55*2041Swnj jeql stresc2 # bad guy in disguise (outbuf is full) 56*2041Swnj strout2: # enter here to force out r2; r0,r1 must be set 57*2041Swnj pushr $3 # save input descriptor 58*2041Swnj pushl fdesc # FILE 59*2041Swnj pushl r2 # the char 60*2041Swnj calls $2,__flsbuf # please empty the buffer and handle 1 char 61*2041Swnj tstl r0 # successful? 62*2041Swnj jgeq strm1 # yes 63*2041Swnj jbcs $31,nchar,strm1 # turn on sign bit of nchar to signify error 64*2041Swnj strm1: 65*2041Swnj incl nchar # count the char 66*2041Swnj popr $3 # get input descriptor back 67*2041Swnj strout: # enter via bsb with (r0,r1)=input descriptor 68*2041Swnj movab strtab,r3 # table address 69*2041Swnj movq *fdesc,r4 # output descriptor 70*2041Swnj jbs $31,r4,strfoo # negative count is a no no 71*2041Swnj strok: 72*2041Swnj addl2 r0,nchar # we intend to move this many chars 73*2041Swnj movtuc r0,(r1),$0,(r3),r4,(r5) 74*2041Swnj movpsl r2 # squirrel away condition codes 75*2041Swnj movq r4,*fdesc # update output descriptor 76*2041Swnj subl2 r0,nchar # some chars not moved 77*2041Swnj jbs $vbit,r2,stresc # terminated by escape? 78*2041Swnj sobgeq r0,strmore # no; but out buffer might be full 79*2041Swnj stresc: 80*2041Swnj rsb 81*2041Swnj stresc2: 82*2041Swnj incl r0 # fix the length 83*2041Swnj decl r1 # and the addr 84*2041Swnj movl $1<vbit,r2 # fake condition codes 85*2041Swnj rsb 86*2041Swnj 87*2041Swnj errdone: 88*2041Swnj jbcs $31,nchar,prdone # set error bit 89*2041Swnj prdone: 90*2041Swnj movl nchar,r0 91*2041Swnj ret 92*2041Swnj 93*2041Swnj .align 1 94*2041Swnj __doprnt: 95*2041Swnj .word 0xfc0 # uses r11-r6 96*2041Swnj movab -256(sp),sp # work space 97*2041Swnj movl 4(ap),r11 # addr of format string 98*2041Swnj movl 12(ap),fdesc # output FILE ptr 99*2041Swnj movl 8(ap),ap # addr of first arg 100*2041Swnj clrl nchar # number of chars transferred 101*2041Swnj loop: 102*2041Swnj movzwl $65535,r0 # pseudo length 103*2041Swnj movl r11,r1 # fmt addr 104*2041Swnj bsbw strout # copy to output, stop at null or percent 105*2041Swnj movl r1,r11 # new fmt 106*2041Swnj jbc $vbit,r2,loop # if no escape, then very long fmt 107*2041Swnj tstb (r11)+ # escape; null or percent? 108*2041Swnj jeql prdone # null means end of fmt 109*2041Swnj 110*2041Swnj movl sp,r5 # reset output buffer pointer 111*2041Swnj clrq r9 # width; flags 112*2041Swnj clrq r6 # lrafx,llafx 113*2041Swnj longorunsg: # we can ignore both of these distinctions 114*2041Swnj short: 115*2041Swnj L4a: 116*2041Swnj movzbl (r11)+,r0 # so capital letters can tail merge 117*2041Swnj L4: caseb r0,$' ,$'x-' # format char 118*2041Swnj L5: 119*2041Swnj .word space-L5 # space 120*2041Swnj .word fmtbad-L5 # ! 121*2041Swnj .word fmtbad-L5 # " 122*2041Swnj .word sharp-L5 # # 123*2041Swnj .word fmtbad-L5 # $ 124*2041Swnj .word fmtbad-L5 # % 125*2041Swnj .word fmtbad-L5 # & 126*2041Swnj .word fmtbad-L5 # ' 127*2041Swnj .word fmtbad-L5 # ( 128*2041Swnj .word fmtbad-L5 # ) 129*2041Swnj .word indir-L5 # * 130*2041Swnj .word plus-L5 # + 131*2041Swnj .word fmtbad-L5 # , 132*2041Swnj .word minus-L5 # - 133*2041Swnj .word dot-L5 # . 134*2041Swnj .word fmtbad-L5 # / 135*2041Swnj .word gnum0-L5 # 0 136*2041Swnj .word gnum-L5 # 1 137*2041Swnj .word gnum-L5 # 2 138*2041Swnj .word gnum-L5 # 3 139*2041Swnj .word gnum-L5 # 4 140*2041Swnj .word gnum-L5 # 5 141*2041Swnj .word gnum-L5 # 6 142*2041Swnj .word gnum-L5 # 7 143*2041Swnj .word gnum-L5 # 8 144*2041Swnj .word gnum-L5 # 9 145*2041Swnj .word fmtbad-L5 # : 146*2041Swnj .word fmtbad-L5 # ; 147*2041Swnj .word fmtbad-L5 # < 148*2041Swnj .word fmtbad-L5 # = 149*2041Swnj .word fmtbad-L5 # > 150*2041Swnj .word fmtbad-L5 # ? 151*2041Swnj .word fmtbad-L5 # @ 152*2041Swnj .word fmtbad-L5 # A 153*2041Swnj .word fmtbad-L5 # B 154*2041Swnj .word fmtbad-L5 # C 155*2041Swnj .word decimal-L5 # D 156*2041Swnj .word capital-L5 # E 157*2041Swnj .word fmtbad-L5 # F 158*2041Swnj .word capital-L5 # G 159*2041Swnj .word fmtbad-L5 # H 160*2041Swnj .word fmtbad-L5 # I 161*2041Swnj .word fmtbad-L5 # J 162*2041Swnj .word fmtbad-L5 # K 163*2041Swnj .word fmtbad-L5 # L 164*2041Swnj .word fmtbad-L5 # M 165*2041Swnj .word fmtbad-L5 # N 166*2041Swnj .word octal-L5 # O 167*2041Swnj .word fmtbad-L5 # P 168*2041Swnj .word fmtbad-L5 # Q 169*2041Swnj .word fmtbad-L5 # R 170*2041Swnj .word fmtbad-L5 # S 171*2041Swnj .word fmtbad-L5 # T 172*2041Swnj .word unsigned-L5 # U 173*2041Swnj .word fmtbad-L5 # V 174*2041Swnj .word fmtbad-L5 # W 175*2041Swnj .word hex-L5 # X 176*2041Swnj .word fmtbad-L5 # Y 177*2041Swnj .word fmtbad-L5 # Z 178*2041Swnj .word fmtbad-L5 # [ 179*2041Swnj .word fmtbad-L5 # \ 180*2041Swnj .word fmtbad-L5 # ] 181*2041Swnj .word fmtbad-L5 # ^ 182*2041Swnj .word fmtbad-L5 # _ 183*2041Swnj .word fmtbad-L5 # ` 184*2041Swnj .word fmtbad-L5 # a 185*2041Swnj .word fmtbad-L5 # b 186*2041Swnj .word charac-L5 # c 187*2041Swnj .word decimal-L5 # d 188*2041Swnj .word scien-L5 # e 189*2041Swnj .word float-L5 # f 190*2041Swnj .word general-L5 # g 191*2041Swnj .word short-L5 # h 192*2041Swnj .word fmtbad-L5 # i 193*2041Swnj .word fmtbad-L5 # j 194*2041Swnj .word fmtbad-L5 # k 195*2041Swnj .word longorunsg-L5 # l 196*2041Swnj .word fmtbad-L5 # m 197*2041Swnj .word fmtbad-L5 # n 198*2041Swnj .word octal-L5 # o 199*2041Swnj .word fmtbad-L5 # p 200*2041Swnj .word fmtbad-L5 # q 201*2041Swnj .word fmtbad-L5 # r 202*2041Swnj .word string-L5 # s 203*2041Swnj .word fmtbad-L5 # t 204*2041Swnj .word unsigned-L5 # u 205*2041Swnj .word fmtbad-L5 # v 206*2041Swnj .word fmtbad-L5 # w 207*2041Swnj .word hex-L5 # x 208*2041Swnj fmtbad: 209*2041Swnj movb r0,(r5)+ # print the unfound character 210*2041Swnj jeql errdone # dumb users who end the format with a % 211*2041Swnj jbr prbuf 212*2041Swnj capital: 213*2041Swnj bisl2 $1<caps,flags # note that it was capitalized 214*2041Swnj xorb2 $'a^'A,r0 # make it small 215*2041Swnj jbr L4 # and try again 216*2041Swnj 217*2041Swnj string: 218*2041Swnj movl ndigit,r0 219*2041Swnj jbs $prec,flags,L20 # max length was specified 220*2041Swnj mnegl $1,r0 # default max length 221*2041Swnj L20: movl (ap)+,r2 # addr first byte 222*2041Swnj locc $0,r0,(r2) # find the zero at the end 223*2041Swnj movl r1,r5 # addr last byte +1 224*2041Swnj movl r2,r1 # addr first byte 225*2041Swnj jbr prstr 226*2041Swnj 227*2041Swnj htab: .byte '0,'1,'2,'3,'4,'5,'6,'7,'8,'9,'a,'b,'c,'d,'e,'f 228*2041Swnj Htab: .byte '0,'1,'2,'3,'4,'5,'6,'7,'8,'9,'A,'B,'C,'D,'E,'F 229*2041Swnj 230*2041Swnj octal: 231*2041Swnj movl $30,r2 # init position 232*2041Swnj movl $3,r3 # field width 233*2041Swnj movab htab,llafx # translate table 234*2041Swnj jbr L10 235*2041Swnj 236*2041Swnj hex: 237*2041Swnj movl $28,r2 # init position 238*2041Swnj movl $4,r3 # field width 239*2041Swnj movab htab,llafx # translate table 240*2041Swnj jbc $caps,flags,L10 241*2041Swnj movab Htab,llafx 242*2041Swnj L10: mnegl r3,r6 # increment 243*2041Swnj clrl r1 244*2041Swnj addl2 $4,r5 # room for left affix (2) and slop [forced sign?] 245*2041Swnj movl (ap)+,r0 # fetch arg 246*2041Swnj L11: extzv r2,r3,r0,r1 # pull out a digit 247*2041Swnj movb (llafx)[r1],(r5)+ # convert to character 248*2041Swnj L12: acbl $0,r6,r2,L11 # continue until done 249*2041Swnj clrq r6 # lrafx, llafx 250*2041Swnj clrb (r5) # flag end 251*2041Swnj skpc $'0,$11,4(sp) # skip over leading zeroes 252*2041Swnj jbc $numsgn,flags,prn3 # easy if no left affix 253*2041Swnj tstl -4(ap) # original value 254*2041Swnj jeql prn3 # no affix on 0, for some reason 255*2041Swnj cmpl r3,$4 # were we doing hex or octal? 256*2041Swnj jneq L12a # octal 257*2041Swnj movb $'x,r0 258*2041Swnj jbc $caps,flags,L12b 259*2041Swnj movb $'X,r0 260*2041Swnj L12b: movb r0,-(r1) 261*2041Swnj movl $2,llafx # leading 0x for hex is an affix 262*2041Swnj L12a: movb $'0,-(r1) # leading zero for octal is a digit, not an affix 263*2041Swnj jbr prn3 # omit sign (plus, blank) massaging 264*2041Swnj 265*2041Swnj unsigned: 266*2041Swnj lunsigned: 267*2041Swnj bicl2 $1<plssgn|1<blank,flags # omit sign (plus, blank) massaging 268*2041Swnj extzv $1,$31,(ap),r0 # right shift logical 1 bit 269*2041Swnj cvtlp r0,$10,(sp) # convert [n/2] to packed 270*2041Swnj movp $10,(sp),8(sp) # copy packed 271*2041Swnj addp4 $10,8(sp),$10,(sp) # 2*[n/2] in packed, at (sp) 272*2041Swnj blbc (ap)+,L14 # n was even 273*2041Swnj addp4 $1,pone,$10,(sp) # n was odd 274*2041Swnj jbr L14 275*2041Swnj 276*2041Swnj patdec: # editpc pattern for decimal printing 277*2041Swnj .byte 0xAA # eo$float 10 278*2041Swnj .byte 0x01 # eo$end_float 279*2041Swnj .byte 0 # eo$end 280*2041Swnj 281*2041Swnj decimal: 282*2041Swnj cvtlp (ap)+,$10,(sp) # 10 digits max 283*2041Swnj jgeq L14 284*2041Swnj incl llafx # minus sign is a left affix 285*2041Swnj L14: editpc $10,(sp),patdec,8(sp) # ascii at 8(sp); r5=end+1 286*2041Swnj skpc $' ,$11,8(sp) # skip leading blanks; r1=first 287*2041Swnj 288*2041Swnj prnum: # r1=addr first byte, r5=addr last byte +1, llafx=size of signs 289*2041Swnj # -1(r1) vacant, for forced sign 290*2041Swnj tstl llafx 291*2041Swnj jneq prn3 # already some left affix, dont fuss 292*2041Swnj jbc $plssgn,flags,prn2 293*2041Swnj movb $'+,-(r1) # needs a plus sign 294*2041Swnj jbr prn4 295*2041Swnj prn2: jbc $blank,flags,prn3 296*2041Swnj movb $' ,-(r1) # needs a blank sign 297*2041Swnj prn4: incl llafx 298*2041Swnj prn3: jbs $prec,flags,prn1 299*2041Swnj movl $1,ndigit # default precision is 1 300*2041Swnj prn1: subl3 r1,r5,lrafx # raw width 301*2041Swnj subl2 llafx,lrafx # number of digits 302*2041Swnj subl2 lrafx,ndigit # number of leading zeroes needed 303*2041Swnj jleq prstr # none 304*2041Swnj addl2 llafx,r1 # where current digits start 305*2041Swnj pushl r1 # movcx gobbles registers 306*2041Swnj # check bounds on users who say %.300d 307*2041Swnj movab 32(r5)[ndigit],r2 308*2041Swnj subl2 fp,r2 309*2041Swnj jlss prn5 310*2041Swnj subl2 r2,ndigit 311*2041Swnj prn5: 312*2041Swnj # 313*2041Swnj movc3 lrafx,(r1),(r1)[ndigit] # make room in middle 314*2041Swnj movc5 $0,(r1),$ch.zer,ndigit,*(sp) # '0 fill 315*2041Swnj subl3 llafx,(sp)+,r1 # first byte addr 316*2041Swnj addl3 lrafx,r3,r5 # last byte addr +1 317*2041Swnj 318*2041Swnj prstr: # r1=addr first byte; r5=addr last byte +1 319*2041Swnj # width=minimum width; llafx=len. left affix 320*2041Swnj # ndigit=<avail> 321*2041Swnj subl3 r1,r5,ndigit # raw width 322*2041Swnj subl3 ndigit,width,r0 # pad length 323*2041Swnj jleq padlno # in particular, no left padding 324*2041Swnj jbs $minsgn,flags,padlno 325*2041Swnj # extension for %0 flag causing left zero padding to field width 326*2041Swnj jbs $zfill,flags,padlz 327*2041Swnj # this bsbb needed even if %0 flag extension is removed 328*2041Swnj bsbb padb # blank pad on left 329*2041Swnj jbr padnlz 330*2041Swnj padlz: 331*2041Swnj movl llafx,r0 332*2041Swnj jleq padnlx # left zero pad requires left affix first 333*2041Swnj subl2 r0,ndigit # part of total length will be transferred 334*2041Swnj subl2 r0,width # and will account for part of minimum width 335*2041Swnj bsbw strout # left affix 336*2041Swnj padnlx: 337*2041Swnj subl3 ndigit,width,r0 # pad length 338*2041Swnj bsbb padz # zero pad on left 339*2041Swnj padnlz: 340*2041Swnj # end of extension for left zero padding 341*2041Swnj padlno: # remaining: root, possible right padding 342*2041Swnj subl2 ndigit,width # root reduces minimum width 343*2041Swnj movl ndigit,r0 # root length 344*2041Swnj p1: bsbw strout # transfer to output buffer 345*2041Swnj p3: jbc $vbit,r2,padnpct # percent sign (or null byte via %c) ? 346*2041Swnj decl r0 # yes; adjust count 347*2041Swnj movzbl (r1)+,r2 # fetch byte 348*2041Swnj movq *fdesc,r4 # output buffer descriptor 349*2041Swnj sobgeq r4,p2 # room at the out [inn] ? 350*2041Swnj bsbw strout2 # no; force it, then try rest 351*2041Swnj jbr p3 # here we go 'round the mullberry bush, ... 352*2041Swnj p2: movb r2,(r5)+ # hand-deposit the percent or null 353*2041Swnj incl nchar # count it 354*2041Swnj movq r4,*fdesc # store output descriptor 355*2041Swnj jbr p1 # what an expensive hiccup! 356*2041Swnj padnpct: 357*2041Swnj movl width,r0 # size of pad 358*2041Swnj jleq loop 359*2041Swnj bsbb padb 360*2041Swnj jbr loop 361*2041Swnj 362*2041Swnj padz: 363*2041Swnj movb $'0,r2 364*2041Swnj jbr pad 365*2041Swnj padb: 366*2041Swnj movb $' ,r2 367*2041Swnj pad: 368*2041Swnj subl2 r0,width # pad width decreases minimum width 369*2041Swnj pushl r1 # save non-pad addr 370*2041Swnj movl r0,llafx # remember width of pad 371*2041Swnj subl2 r0,sp # allocate 372*2041Swnj movc5 $0,(r0),r2,llafx,(sp) # create pad string 373*2041Swnj movl llafx,r0 # length 374*2041Swnj movl sp,r1 # addr 375*2041Swnj bsbw strout 376*2041Swnj addl2 llafx,sp # deallocate 377*2041Swnj movl (sp)+,r1 # recover non-pad addr 378*2041Swnj rsb 379*2041Swnj 380*2041Swnj pone: .byte 0x1C # packed 1 381*2041Swnj 382*2041Swnj charac: 383*2041Swnj movl (ap)+,r0 # word containing the char 384*2041Swnj movb r0,(r5)+ # one byte, that's all 385*2041Swnj 386*2041Swnj prbuf: 387*2041Swnj movl sp,r1 # addr first byte 388*2041Swnj jbr prstr 389*2041Swnj 390*2041Swnj space: bisl2 $1<blank,flags # constant width e fmt, no plus sign 391*2041Swnj jbr L4a 392*2041Swnj sharp: bisl2 $1<numsgn,flags # 'self identifying', please 393*2041Swnj jbr L4a 394*2041Swnj plus: bisl2 $1<plssgn,flags # always print sign for floats 395*2041Swnj jbr L4a 396*2041Swnj minus: bisl2 $1<minsgn,flags # left justification, please 397*2041Swnj jbr L4a 398*2041Swnj gnum0: jbs $ndfnd,flags,gnum 399*2041Swnj jbs $prec,flags,gnump # ignore when reading precision 400*2041Swnj bisl2 $1<zfill,flags # leading zero fill, please 401*2041Swnj gnum: jbs $prec,flags,gnump 402*2041Swnj moval (width)[width],width # width *= 5; 403*2041Swnj movaw -ch.zer(r0)[width],width # width = 2*witdh + r0 - '0'; 404*2041Swnj jbr gnumd 405*2041Swnj gnump: moval (ndigit)[ndigit],ndigit # ndigit *= 5; 406*2041Swnj movaw -ch.zer(r0)[ndigit],ndigit # ndigit = 2*ndigit + r0 - '0'; 407*2041Swnj gnumd: bisl2 $1<ndfnd,flags # digit seen 408*2041Swnj jbr L4a 409*2041Swnj dot: clrl ndigit # start on the precision 410*2041Swnj bisl2 $1<prec,flags 411*2041Swnj bicl2 $1<ndfnd,flags 412*2041Swnj jbr L4a 413*2041Swnj indir: 414*2041Swnj jbs $prec,flags,in1 415*2041Swnj movl (ap)+,width # width specified by parameter 416*2041Swnj jgeq gnumd 417*2041Swnj xorl2 $1<minsgn,flags # parameterized left adjustment 418*2041Swnj mnegl width,width 419*2041Swnj jbr gnumd 420*2041Swnj in1: 421*2041Swnj movl (ap)+,ndigit # precision specified by paratmeter 422*2041Swnj jgeq gnumd 423*2041Swnj mnegl ndigit,ndigit 424*2041Swnj jbr gnumd 425*2041Swnj 426*2041Swnj float: 427*2041Swnj jbs $prec,flags,float1 428*2041Swnj movl $6,ndigit # default # digits to right of decpt. 429*2041Swnj float1: bsbw fltcvt 430*2041Swnj addl3 exp,ndigit,r7 431*2041Swnj movl r7,r6 # for later "underflow" checking 432*2041Swnj bgeq fxplrd 433*2041Swnj clrl r7 # poor programmer planning 434*2041Swnj fxplrd: cmpl r7,$31 # expressible in packed decimal? 435*2041Swnj bleq fnarro # yes 436*2041Swnj movl $31,r7 437*2041Swnj fnarro: subl3 $17,r7,r0 # where to round 438*2041Swnj ashp r0,$17,(sp),$5,r7,16(sp) # do it 439*2041Swnj bvc fnovfl 440*2041Swnj # band-aid for microcode error (spurious overflow) 441*2041Swnj # clrl r0 # assume even length result 442*2041Swnj # jlbc r7,fleven # right 443*2041Swnj # movl $4,r0 # odd length result 444*2041Swnj #fleven: cmpv r0,$4,16(sp),$0 # top digit zero iff true overflow 445*2041Swnj # bneq fnovfl 446*2041Swnj # end band-aid 447*2041Swnj aobleq $0,r6,fnovfl # if "underflow" then jump 448*2041Swnj movl r7,r0 449*2041Swnj incl exp 450*2041Swnj incl r7 451*2041Swnj ashp r0,$1,pone,$0,r7,16(sp) 452*2041Swnj ashl $-1,r7,r0 # displ to last byte 453*2041Swnj bisb2 sign,16(sp)[r0] # insert sign 454*2041Swnj fnovfl: 455*2041Swnj movab 16(sp),r1 # packed source 456*2041Swnj movl r7,r6 # packed length 457*2041Swnj pushab prnum # goto prnum after fall-through call to fedit 458*2041Swnj 459*2041Swnj 460*2041Swnj # enter via bsb 461*2041Swnj # r1=addr of packed source 462*2041Swnj # 16(r1) used to unpack source 463*2041Swnj # 48(r1) used to construct pattern to unpack source 464*2041Swnj # 48(r1) used to hold result 465*2041Swnj # r6=length of packed source (destroyed) 466*2041Swnj # exp=# digits to left of decimal point (destroyed) 467*2041Swnj # ndigit=# digits to right of decimal point (destroyed) 468*2041Swnj # sign=1 if negative, 0 otherwise 469*2041Swnj # stack will be used for work space for pattern and unpacked source 470*2041Swnj # exits with 471*2041Swnj # r1=addr of punctuated result 472*2041Swnj # r5=addr of last byte +1 473*2041Swnj # llafx=1 if minus sign inserted, 0 otherwise 474*2041Swnj fedit: 475*2041Swnj pushab 48(r1) # save result addr 476*2041Swnj movab 48(r1),r3 # pattern addr 477*2041Swnj movb $0x03,(r3)+ # eo$set_signif 478*2041Swnj movc5 $0,(r1),$0x91,r6,(r3) # eo$move 1 479*2041Swnj clrb (r3) # eo$end 480*2041Swnj editpc r6,(r1),48(r1),16(r1) # unpack 'em all 481*2041Swnj subl3 r6,r5,r1 # addr unpacked source 482*2041Swnj movl (sp),r3 # punctuated output placed here 483*2041Swnj clrl llafx 484*2041Swnj jlbc sign,f1 485*2041Swnj movb $'-,(r3)+ # negative 486*2041Swnj incl llafx 487*2041Swnj f1: movl exp,r0 488*2041Swnj jgtr f2 489*2041Swnj movb $'0,(r3)+ # must have digit before decimal point 490*2041Swnj jbr f3 491*2041Swnj f2: cmpl r0,r6 # limit on packed length 492*2041Swnj jleq f4 493*2041Swnj movl r6,r0 494*2041Swnj f4: subl2 r0,r6 # eat some digits 495*2041Swnj subl2 r0,exp # from the exponent 496*2041Swnj movc3 r0,(r1),(r3) # (most of the) digits to left of decimal point 497*2041Swnj movl exp,r0 # need any more? 498*2041Swnj jleq f3 499*2041Swnj movc5 $0,(r1),$'0,r0,(r3) # '0 fill 500*2041Swnj f3: movl ndigit,r0 # # digits to right of decimal point 501*2041Swnj jgtr f5 502*2041Swnj jbs $numsgn,flags,f5 # no decimal point unless forced 503*2041Swnj jbcs $dpflag,flags,f6 # no decimal point 504*2041Swnj f5: movb $'.,(r3)+ # the decimal point 505*2041Swnj f6: mnegl exp,r0 # "leading" zeroes to right of decimal point 506*2041Swnj jleq f9 507*2041Swnj cmpl r0,ndigit # cant exceed this many 508*2041Swnj jleq fa 509*2041Swnj movl ndigit,r0 510*2041Swnj fa: subl2 r0,ndigit 511*2041Swnj movc5 $0,(r1),$'0,r0,(r3) 512*2041Swnj f9: movl ndigit,r0 513*2041Swnj cmpl r0,r6 # limit on packed length 514*2041Swnj jleq f7 515*2041Swnj movl r6,r0 516*2041Swnj f7: subl2 r0,ndigit # eat some digits from the fraction 517*2041Swnj movc3 r0,(r1),(r3) # (most of the) digits to right of decimal point 518*2041Swnj movl ndigit,r0 # need any more? 519*2041Swnj jleq f8 520*2041Swnj # check bounds on users who say %.300f 521*2041Swnj movab 32(r3)[r0],r2 522*2041Swnj subl2 fp,r2 523*2041Swnj jlss fb 524*2041Swnj subl2 r2,r0 # truncate, willy-nilly 525*2041Swnj movl r0,ndigit # and no more digits later, either 526*2041Swnj fb: 527*2041Swnj # 528*2041Swnj subl2 r0,ndigit # eat some digits from the fraction 529*2041Swnj movc5 $0,(r1),$'0,r0,(r3) # '0 fill 530*2041Swnj f8: movl r3,r5 # addr last byte +1 531*2041Swnj popr $1<1 # [movl (sp)+,r1] addr first byte 532*2041Swnj rsb 533*2041Swnj 534*2041Swnj patexp: .byte 0x03 # eo$set_signif 535*2041Swnj .byte 0x44,'e # eo$insert 'e 536*2041Swnj .byte 0x42,'+ # eo$load_plus '+ 537*2041Swnj .byte 0x04 # eo$store_sign 538*2041Swnj .byte 0x92 # eo$move 2 539*2041Swnj .byte 0 # eo$end 540*2041Swnj 541*2041Swnj scien: 542*2041Swnj incl ndigit 543*2041Swnj jbs $prec,flags,L23 544*2041Swnj movl $7,ndigit 545*2041Swnj L23: bsbw fltcvt # get packed digits 546*2041Swnj movl ndigit,r7 547*2041Swnj cmpl r7,$31 # expressible in packed decimal? 548*2041Swnj jleq snarro # yes 549*2041Swnj movl $31,r7 550*2041Swnj snarro: subl3 $17,r7,r0 # rounding position 551*2041Swnj ashp r0,$17,(sp),$5,r7,16(sp) # shift and round 552*2041Swnj bvc snovfl 553*2041Swnj # band-aid for microcode error (spurious overflow) 554*2041Swnj # clrl r0 # assume even length result 555*2041Swnj # jlbc ndigit,sceven # right 556*2041Swnj # movl $4,r0 # odd length result 557*2041Swnj #sceven: cmpv r0,$4,16(sp),$0 # top digit zero iff true overflow 558*2041Swnj # bneq snovfl 559*2041Swnj # end band-aid 560*2041Swnj incl exp # rounding overflowed to 100... 561*2041Swnj subl3 $1,r7,r0 562*2041Swnj ashp r0,$1,pone,$0,r7,16(sp) 563*2041Swnj ashl $-1,r7,r0 # displ to last byte 564*2041Swnj bisb2 sign,16(sp)[r0] # insert sign 565*2041Swnj snovfl: 566*2041Swnj jbs $gflag,flags,gfmt # %g format 567*2041Swnj movab 16(sp),r1 568*2041Swnj bsbb eedit 569*2041Swnj eexp: 570*2041Swnj movl r1,r6 # save fwa from destruction by cvtlp 571*2041Swnj subl3 $1,sexp,r0 # 1P exponent 572*2041Swnj cvtlp r0,$2,(sp) # packed 573*2041Swnj editpc $2,(sp),patexp,(r5) 574*2041Swnj movl r6,r1 # fwa 575*2041Swnj jbc $caps,flags,prnum 576*2041Swnj xorb2 $'e^'E,-4(r5) 577*2041Swnj jbr prnum 578*2041Swnj 579*2041Swnj eedit: 580*2041Swnj movl r7,r6 # packed length 581*2041Swnj decl ndigit # 1 digit before decimal point 582*2041Swnj movl exp,sexp # save from destruction 583*2041Swnj movl $1,exp # and pretend 584*2041Swnj jbr fedit 585*2041Swnj 586*2041Swnj gfmt: 587*2041Swnj addl3 $3,exp,r0 # exp is 1 more than e 588*2041Swnj jlss gfmte # (e+1)+3<0, e+4<=-1, e<=-5 589*2041Swnj subl2 $3,r0 # exp [==(e+1)] 590*2041Swnj cmpl r0,ndigit 591*2041Swnj jgtr gfmte # e+1>n, e>=n 592*2041Swnj gfmtf: 593*2041Swnj movl r7,r6 594*2041Swnj subl2 r0,ndigit # n-e-1 595*2041Swnj movab 16(sp),r1 596*2041Swnj bsbw fedit 597*2041Swnj g1: jbs $numsgn,flags,g2 598*2041Swnj jbs $dpflag,flags,g2 # dont strip if no decimal point 599*2041Swnj g3: cmpb -(r5),$'0 # strip trailing zeroes 600*2041Swnj jeql g3 601*2041Swnj cmpb (r5),$'. # and trailing decimal point 602*2041Swnj jeql g2 603*2041Swnj incl r5 604*2041Swnj g2: jbc $gflag,flags,eexp 605*2041Swnj jbr prnum 606*2041Swnj gfmte: 607*2041Swnj movab 16(sp),r1 # packed source 608*2041Swnj bsbw eedit 609*2041Swnj jbsc $gflag,flags,g1 # gflag now means "use %f" [hence no exponent] 610*2041Swnj 611*2041Swnj general: 612*2041Swnj jbs $prec,flags,gn1 613*2041Swnj movl $6,ndigit # default precision is 6 significant digits 614*2041Swnj gn1: tstl ndigit # cannot allow precision of 0 615*2041Swnj jgtr gn2 616*2041Swnj movl $1,ndigit # change 0 to 1, willy-nilly 617*2041Swnj gn2: jbcs $gflag,flags,L23 618*2041Swnj jbr L23 # safety net 619*2041Swnj 620*2041Swnj # convert double-floating at (ap) to 17-digit packed at (sp), 621*2041Swnj # set 'sign' and 'exp', advance ap. 622*2041Swnj fltcvt: 623*2041Swnj clrb sign 624*2041Swnj movd (ap)+,r5 625*2041Swnj jeql fzero 626*2041Swnj bgtr fpos 627*2041Swnj mnegd r5,r5 628*2041Swnj incb sign 629*2041Swnj fpos: 630*2041Swnj extzv $7,$8,r5,r2 # exponent of 2 631*2041Swnj movab -0200(r2),r2 # unbias 632*2041Swnj mull2 $59,r2 # 59/196: 3rd convergent continued frac of log10(2) 633*2041Swnj jlss eneg 634*2041Swnj movab 196(r2),r2 635*2041Swnj eneg: 636*2041Swnj movab -98(r2),r2 637*2041Swnj divl2 $196,r2 638*2041Swnj bsbw expten 639*2041Swnj cmpd r0,r5 640*2041Swnj bgtr ceil 641*2041Swnj incl r2 642*2041Swnj ceil: movl r2,exp 643*2041Swnj mnegl r2,r2 644*2041Swnj cmpl r2,$29 # 10^(29+9) is all we can handle 645*2041Swnj bleq getman 646*2041Swnj muld2 ten16,r5 647*2041Swnj subl2 $16,r2 648*2041Swnj getman: addl2 $9,r2 # -ceil(log10(x)) + 9 649*2041Swnj bsbb expten 650*2041Swnj emodd r0,r4,r5,r0,r5 # (r0+r4)*r5; r0=int, r5=frac 651*2041Swnj fz1: cvtlp r0,$9,16(sp) # leading 9 digits 652*2041Swnj ashp $8,$9,16(sp),$0,$17,4(sp) # as top 9 of 17 653*2041Swnj emodd ten8,$0,r5,r0,r5 654*2041Swnj cvtlp r0,$8,16(sp) # trailing 8 digits 655*2041Swnj # if precision >= 17, must round here 656*2041Swnj movl ndigit,r7 # so figure out what precision is 657*2041Swnj pushab scien 658*2041Swnj cmpl (sp)+,(sp) 659*2041Swnj jleq gm1 # who called us? 660*2041Swnj addl2 exp,r7 # float; adjust for exponent 661*2041Swnj gm1: cmpl r7,$17 662*2041Swnj jlss gm2 663*2041Swnj cmpd r5,$0d0.5 # must round here; check fraction 664*2041Swnj jlss gm2 665*2041Swnj bisb2 $0x10,8+4(sp) # increment l.s. digit 666*2041Swnj gm2: # end of "round here" code 667*2041Swnj addp4 $8,16(sp),$17,4(sp) # combine leading and trailing 668*2041Swnj bisb2 sign,12(sp) # and insert sign 669*2041Swnj rsb 670*2041Swnj fzero: clrl r0 671*2041Swnj movl $1,exp # 0.000e+00 and 0.000 rather than 0.000e-01 and .000 672*2041Swnj jbr fz1 673*2041Swnj 674*2041Swnj .align 2 675*2041Swnj lsb: .long 0x00010000 # lsb in the crazy floating-point format 676*2041Swnj 677*2041Swnj # return 10^r2 as a double float in r0||r1 and 8 extra bits of precision in r4 678*2041Swnj # preserve r2, r5||r6 679*2041Swnj expten: 680*2041Swnj movd $0d1.0,r0 # begin computing 10^exp10 681*2041Swnj clrl r4 # bit counter 682*2041Swnj movad ten1,r3 # table address 683*2041Swnj tstl r2 684*2041Swnj bgeq e10lp 685*2041Swnj mnegl r2,r2 # get absolute value 686*2041Swnj jbss $6,r2,e10lp # flag as negative 687*2041Swnj e10lp: jbc r4,r2,el1 # want this power? 688*2041Swnj muld2 (r3),r0 # yes 689*2041Swnj el1: addl2 $8,r3 # advance to next power 690*2041Swnj aobleq $5,r4,e10lp # through 10^32 691*2041Swnj jbcc $6,r2,el2 # correct for negative exponent 692*2041Swnj divd3 r0,$0d1.0,r0 # by taking reciprocal 693*2041Swnj cmpl $28,r2 694*2041Swnj jneq enm28 695*2041Swnj addl2 lsb,r1 # 10**-28 needs lsb incremented 696*2041Swnj enm28: mnegl r2,r2 # original exponent of 10 697*2041Swnj el2: addl3 $5*8,r2,r3 # negative bit positions are illegal? 698*2041Swnj jbc r3,xlsbh-5,eoklsb 699*2041Swnj subl2 lsb,r1 # lsb was too high 700*2041Swnj eoklsb: 701*2041Swnj movzbl xprec[r2],r4 # 8 extra bits 702*2041Swnj rsb 703*2041Swnj 704*2041Swnj # powers of ten 705*2041Swnj .align 2 706*2041Swnj ten1: .word 0x4220,0,0,0 707*2041Swnj ten2: .word 0x43c8,0,0,0 708*2041Swnj ten4: .word 0x471c,0x4000,0,0 709*2041Swnj ten8: .word 0x4dbe,0xbc20,0,0 710*2041Swnj ten16: .word 0x5b0e,0x1bc9,0xbf04,0 711*2041Swnj ten32: .word 0x759d,0xc5ad,0xa82b,0x70b6 712*2041Swnj 713*2041Swnj # whether lsb is too high or not 714*2041Swnj .byte 1:0,1:0,1:0,1:0,1:1,1:0,1:1,1:0 # -40 thru -33 715*2041Swnj .byte 1:0,1:1,1:0,1:0,1:0,1:0,1:1,1:0 # -32 thru -25 716*2041Swnj .byte 1:0,1:0,1:1,1:1,1:1,1:1,1:0,1:0 # -24 thru -17 717*2041Swnj .byte 1:0,1:1,1:0,1:0,1:1,1:1,1:1,1:1 # -16 thru -9 718*2041Swnj .byte 1:1,1:1,1:1,1:0,1:0,1:0,1:0,1:1 # -8 thru -1 719*2041Swnj xlsbh: 720*2041Swnj .byte 1:0,1:0,1:0,1:0,1:0,1:0,1:0,1:0 # 0 thru 7 721*2041Swnj .byte 1:0,1:0,1:0,1:0,1:0,1:0,1:0,1:0 # 8 thru 15 722*2041Swnj .byte 1:0,1:0,1:0,1:0,1:0,1:0,1:0,1:0 # 16 thru 23 723*2041Swnj .byte 1:0,1:1,1:1,1:0,1:1,1:1,1:1,1:1 # 24 thru 31 724*2041Swnj .byte 1:1,1:1,1:1,1:1,1:1,1:1,1:1 # 32 thru 38 725*2041Swnj 726*2041Swnj # bytes of extra precision 727*2041Swnj .byte 0x56,0x76,0xd3,0x88,0xb5,0x62 # -38 thru -33 728*2041Swnj .byte 0xba,0xf5,0x32,0x3e,0x0e,0x48,0xdb,0x51 # -32 thru -25 729*2041Swnj .byte 0x53,0x27,0xb1,0xef,0xeb,0xa5,0x07,0x49 # -24 thru -17 730*2041Swnj .byte 0x5b,0xd9,0x0f,0x13,0xcd,0xff,0xbf,0x97 # -16 thru -9 731*2041Swnj .byte 0xfd,0xbc,0xb6,0x23,0x2c,0x3b,0x0a,0xcd # -8 thru -1 732*2041Swnj xprec: 733*2041Swnj .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 # 0 thru 7 734*2041Swnj .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 # 8 thru 15 735*2041Swnj .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 # 16 thru 23 736*2041Swnj .byte 0x00,0xa0,0xc8,0x3a,0x84,0xe4,0xdc,0x92 # 24 thru 31 737*2041Swnj .byte 0x9b,0x00,0xc0,0x58,0xae,0x18,0xef # 32 thru 38 738