Annotation of 3BSD/libc/stdio/doprnt.s, revision 1.1.1.1

1.1       root        1:        # C library -- conversions
                      2: 
                      3: .globl __doprnt
                      4: .globl __strout
                      5: 
                      6: #define flags r10
                      7: #define literb 0
                      8: #define liter 1
                      9: #define ndfndb 0
                     10: #define ndfnd 1
                     11: #define ljustb 1
                     12: #define ljust 2
                     13: #define zfillb 2
                     14: #define zfill 4
                     15: #define precb 3
                     16: #define prec 8
                     17: #define psignb 4
                     18: #define psign 16
                     19: #define gflagb 5
                     20: #define gflag 32
                     21: #define width r9
                     22: #define ndigit r8
                     23: #define fdesc -4(fp)
                     24: #define exp -8(fp)
                     25: #define sign -9(fp)
                     26:        .set one,010                    # 1.0 in floating immediate
                     27:        .set ch.zer,'0                  # cpp doesn't like single appostrophes
                     28: 
                     29:        .align  1
                     30: __doprnt:
                     31:        .word   0xfc0                   # uses r11-r6
                     32:        subl2 $128,sp
                     33:        movl 4(ap),r11                  # addr of format string
                     34:        movl 12(ap),fdesc               # output FILE ptr
                     35:        movl 8(ap),ap                   # addr of first arg
                     36: loop:
                     37:        movl r11,r0                     # current point in format
                     38:        bicl2 $liter,flags              # no literal characters yet
                     39: L1:    movb (r11)+,width               # next character of format
                     40:        beql L2                         # end of format string
                     41:        cmpb width,$'%
                     42:        beql L2                         # warning character
                     43:        bisl2 $liter,flags              # literal character
                     44:        jbr L1
                     45: L2:    blbc flags,L3                   # bbc $literb,flags,L3 # no literals in format
                     46:        pushl fdesc                     # file pointer
                     47:        pushl $0                        # no left/right adjust
                     48:        pushl r0                        # addr
                     49:        subl3 r0,r11,r1                 # length
                     50:        subl3 $1,r1,-(sp)               # % or null not part of literal
                     51:        calls $4,__strout               # dump the literal
                     52: L3:
                     53:        blbs width,L4                   # % is odd; end of format?
                     54:        ret                             # yes
                     55: 
                     56:        # htab overlaps last 16 characters of ftab
                     57: ftab:  .byte    0, 0, 0,'c,'d,'e,'f,'g, 0, 0, 0,'+,'l,'-,'.,'o
                     58: htab:  .byte   '0,'1,'2,'3,'4,'5,'6,'7,'8,'9,'a,'b,'c,'d,'e,'f
                     59: 
                     60: L4:    movl sp,r5                      # reset output buffer pointer
                     61:        clrq r9                         # width; flags ljustb,ndfndb,zfillb
                     62: L4a:   movzbl (r11)+,r0                # supposed format
                     63:        extzv $0,$5,r0,r1                # bottom 5 bits
                     64: L4b:   cmpb r0,ftab[r1]                # good enough?
                     65:        jneq L6                         # no
                     66: L4c:   casel r1,$3,$22                 # yes
                     67: L5:    .word charac-L5                 # c
                     68:        .word decimal-L5                # d
                     69:        .word scien-L5                  # e
                     70:        .word float-L5                  # f
                     71:        .word general-L5                # g
                     72:        .word L6-L5                     # h
                     73:        .word L6-L5                     # i
                     74:        .word L6-L5                     # j
                     75:        .word plus-L5                   # +
                     76:        .word longorunsg-L5             # l
                     77:        .word minus-L5                  # -
                     78:        .word dot-L5                    # .
                     79:        .word octal-L5                  # o
                     80:        .word gnum0-L5                  # 0
                     81:        .word gnum-L5                   # 1
                     82:        .word gnum-L5                   # 2
                     83:        .word gnum-L5                   # 3
                     84:        .word gnum-L5                   # 4
                     85:        .word gnum-L5                   # 5
                     86:        .word gnum-L5                   # 6
                     87:        .word gnum-L5                   # 7
                     88:        .word gnum-L5                   # 8
                     89:        .word gnum-L5                   # 9
                     90: 
                     91: L6:    jbcs $5,r0,L4b                  # capitals same as small
                     92:        cmpb r0,$'s
                     93:        jeql string
                     94:        cmpb r0,$'x
                     95:        jeql hex
                     96:        cmpb r0,$'u
                     97:        jeql unsigned
                     98:        cmpb r0,$'r
                     99:        jeql remote
                    100:        movzbl -1(r11),r0               # orginal "format" character
                    101:        cmpb r0,$'*
                    102:        jeql indir
                    103: L9:    movb r0,(r5)+                   # print the unfound character
                    104:        jbr prbuf
                    105: 
                    106: nulstr:
                    107:        .byte '(,'n,'u,'l,'l,'),0
                    108: 
                    109: string:
                    110:        movl ndigit,r0
                    111:        jbs $precb,flags,L20            # max length was specified
                    112:        mnegl $1,r0                     # default max length
                    113: L20:   movl (ap)+,r2                   # addr first byte
                    114:        bneq L21
                    115:        movab nulstr,r2
                    116: L21:   locc $0,r0,(r2)                 # find the zero at the end
                    117:        movl r1,r5                      # addr last byte +1
                    118:        movl r2,r1                      # addr first byte
                    119:        jbr prstr
                    120: 
                    121: 
                    122: longorunsg:
                    123:        movb (r11)+,r0
                    124:        cmpb r0,$'o
                    125:        jeql loct
                    126:        cmpb r0,$'x
                    127:        jeql lhex
                    128:        cmpb r0,$'d
                    129:        jeql long
                    130:        cmpb r0,$'u
                    131:        jeql lunsigned
                    132:        decl r11
                    133:        jbr unsigned
                    134: 
                    135: loct:
                    136: octal:
                    137:        movl $30,r2                     # init position
                    138:        movl $3,r3                      # field width
                    139:        movl $10,r4                     # result length -1
                    140:        jbr L10
                    141: 
                    142: lhex:
                    143: hex:
                    144:        movl $28,r2                     # init position
                    145:        movl $4,r3                      # field width
                    146:        movl $7,r4                      # result length -1
                    147: L10:   mnegl r3,r6                     # increment
                    148:        clrl r1
                    149:        movl (ap)+,r0                   # fetch arg
                    150: L11:   extzv r2,r3,r0,r1               # pull out a digit
                    151:        movb htab[r1],(r5)+             # convert to character
                    152: L12:   acbl $0,r6,r2,L11               # continue until done
                    153:        clrb (r5)                       # flag end
                    154:        skpc $'0,r4,(sp)                # skip over leading zeroes
                    155:        jbr prstr
                    156: 
                    157: patdec:                                        # editpc pattern for decimal printing
                    158:        .byte 0xA9                      # eo$float 9
                    159:        .byte 0x01                      # eo$end_float
                    160:        .byte 0x91                      # eo$move 1
                    161:        .byte 0                         # eo$end
                    162: 
                    163: long:
                    164: decimal:
                    165:        cvtlp (ap)+,$10,(sp)            # 10 digits max
                    166: L14:   editpc $10,(sp),patdec,8(sp)    # ascii at 8(sp); r5=end+1
                    167:        skpc $' ,$10,8(sp)              # skip leading blanks; r1=first
                    168: 
                    169: prstr:                 # r1=addr first byte; r5=addr last byte +1
                    170:        cvtbl $' ,-(sp)                 # blank fill
                    171:        jbc $zfillb,flags,L15
                    172:        cvtbl $'0,(sp)                  # zero fill
                    173: L15:   pushl fdesc                     # FILE
                    174:        subl2 r1,r5                     # r5=actual length=end+1-first
                    175:        subl3 r5,width,r0               # if >0, how much to fill
                    176:        bgeq L24
                    177:        clrl r0                         # no fill
                    178: L24:   jbs $ljustb,flags,L25
                    179:        mnegl r0,r0
                    180: L25:   pushl r0                        # fill count
                    181:        pushl r1                        # addr first byte
                    182:        pushl r5                        # length
                    183:        calls $5,__strout
                    184:        jbr     loop
                    185: 
                    186: pone:  .byte   0x1C                    # packed 1
                    187:        
                    188: unsigned:
                    189: lunsigned:
                    190:        extzv $1,$31,(ap),r0            # right shift logical 1 bit
                    191:        cvtlp r0,$10,(sp)               # convert [n/2] to packed
                    192:        movp $10,(sp),8(sp)             # copy packed
                    193:        addp4 $10,8(sp),$10,(sp)        # 2*[n/2] in packed, at (sp)
                    194:        blbc (ap)+,L14                  # n was even
                    195:        addp4 $1,pone,$10,(sp)          # n was odd
                    196:        jbr L14
                    197: 
                    198: charac:
                    199:        movl $4,r0                      # chars per word
                    200: L18:   movb (ap)+,(r5)+                # transfer char
                    201:        bneq L19
                    202:        decl r5                         # omit null characters
                    203: L19:   sobgtr r0,L18
                    204: 
                    205: prbuf:
                    206:        movl sp,r1                      # addr first byte
                    207:        jbr prstr
                    208: 
                    209: plus:  bisl2 $psign,flags              # always print sign for floats
                    210:        jbr L4a
                    211: minus: bisl2 $ljust,flags              # left justification, please
                    212:        jbr L4a
                    213: gnum0: jbs $ndfndb,flags,gnum
                    214:        jbs $precb,flags,gnump          # ignore when reading precision
                    215:        bisl2 $zfill,flags              # leading zero fill, please
                    216: gnum:  jbs $precb,flags,gnump
                    217:        moval (width)[width],width      # width *= 5;
                    218:        movaw -ch.zer(r0)[width],width  # width = 2*witdh + r0 - '0';
                    219:        jbr gnumd
                    220: gnump: moval (ndigit)[ndigit],ndigit   # ndigit *= 5;
                    221:        movaw -ch.zer(r0)[ndigit],ndigit # ndigit = 2*ndigit + r0 - '0';
                    222: gnumd: bisl2 $ndfnd,flags              # digit seen
                    223:        jbr L4a
                    224: dot:   clrl ndigit                     # start on the precision
                    225:        bisl2 $prec,flags
                    226:        bicl2 $ndfnd,flags
                    227:        jbr L4a
                    228: indir: movl (ap)+,ndigit               # width specified by parameter
                    229:        jbr gnumd
                    230: remote:        movl (ap)+,ap
                    231:        movl (ap)+,r11
                    232:        jbr loop
                    233: 
                    234: float:
                    235:        bsbw fltcvt
                    236: fltg:  jbs $ndfndb,flags,float1
                    237:        movl $6,ndigit                  # default # digits to right of decpt.
                    238: float1:        addl3 exp,ndigit,r7
                    239:        movl r7,r6                      # for later "underflow" checking
                    240:        bgeq fxplrd
                    241:        clrl r7                         # poor programmer planning
                    242: fxplrd:        cmpl r7,$31                     # expressible in packed decimal?
                    243:        bleq fnarro                     # yes
                    244:        movl $31,r7
                    245: fnarro:        subl3 $17,r7,r0                 # where to round
                    246:        ashp r0,$17,(sp),$5,r7,16(sp)   # do it
                    247:        bvc fnovfl
                    248:        # band-aid for microcode error (spurious overflow)
                    249:        clrl r0                         # assume even length result
                    250:        jlbc r7,fleven                  # right
                    251:        movl $4,r0                      # odd length result
                    252: fleven:        cmpv r0,$4,16(sp),$0            # top digit zero iff true overflow
                    253:        bneq fnovfl
                    254:        # end band-aid
                    255:        aobleq $0,r6,fnovfl             # if "underflow" then jump
                    256:        movl r7,r0
                    257:        incl exp
                    258:        incl r7
                    259:        ashp r0,$1,pone,$0,r7,16(sp)
                    260:        ashl $-1,r7,r0                  # displ to last byte
                    261:        bisb2 sign,16(sp)[r0]           # insert sign
                    262: fnovfl:
                    263:        movc3 $4,patsci,(sp)
                    264:        clrl r6                         # # digits moved so far
                    265:        movl exp,r0
                    266:        bleq fexpng
                    267:        bsbb patmov                     # digits to left of decpt.
                    268: fexpng:        tstl ndigit
                    269:        jeql fnodp
                    270:        movc3 $2,fpatdp,(r3)
                    271:        tstl exp
                    272:        bgeq fxppos
                    273:        addl3 exp,ndigit,r6
                    274:        bgeq  flfakl
                    275:        clrl r6                         # it's all fill
                    276: flfakl:        subl3 r6,$31,r6                 # fake length for patmov
                    277: flfill:        movc3 $2,fpatzf,(r3)            # zero fill to right of dec.pt
                    278: fxppos:        movl ndigit,r0
                    279:        bsbb patmov
                    280: fnodp: sobgeq r6,fledit                # must move at least 1 digit
                    281:        movl $31,r6                     # none moved; fake it
                    282:        aobleq $1,ndigit,flfill         # with a one-character zero fill
                    283: fledit:        editpc r7,16(sp),(sp),32(sp)
                    284:        jbr prflt
                    285: 
                    286: patexp:        .byte   0x03                    # eo$set_signif
                    287:        .byte   0x44,'e                 # eo$insert 'e
                    288:        .byte   0x42,'+                 # eo$load_plus '+
                    289:        .byte   0x04                    # eo$store_sign
                    290:        .byte   0x92                    # eo$move 2
                    291:        .byte   0                       # eo$end
                    292: patsci:        .byte   0x42,'+                 # eo$load_plus '+
                    293:        .byte   0x03                    # eo$set_signif
                    294:        .byte   0x04                    # eo$store_sign
                    295:        .byte   0x91                    # eo$move 1
                    296: fpatdp:        .byte   0x44,'.                 # eo$insert '.
                    297: fpatzf:        .byte   0x40,'0                 # eo$load_fill '0
                    298: 
                    299:        # construct pattern at (r3) to move  r0  digits in  editpc;
                    300:        #  r6  digits already moved for this number
                    301: patmov:
                    302:        movb $0x90,r2                   # eo$move
                    303:        subl3 r6,$31,r1                 # # digits remaining in packed
                    304:        addl2 r0,r6
                    305:        cmpl r0,r1                      # enough digits remaining?
                    306:        bleq patsml                     # yes
                    307:        tstl exp                        # zero 'fill'; before or after rest?
                    308:        bgeq pataft                     # after
                    309:        pushl r1                        # # digits remaining
                    310:        movb $0x80,r2                   # eo$fill
                    311:        subl3 $31,r6,r0                 # number of fill bytes
                    312:        bsbb patsml                     # recursion!
                    313:        movl (sp)+,r0
                    314:        movb $0x90,r2                   # eo$move
                    315:        jbr patsml
                    316: pataft:        movl r1,r0                      # last of the 31
                    317:        bsbb patsml                     # recursion!
                    318:        subl3 $31,r6,r0                 # number of fill bytes
                    319:        movb $0x80,r2                   # eo$fill
                    320: patsml:        tstl r0
                    321:        bleq patzer                     # DEC doesn't like repetition counts of 0
                    322:        mnegl $15,r1                    # 15 digits at a time
                    323:        subl2 r1,r0                     # counteract acbl
                    324:        jbr pattst
                    325: patmlp:        bisb3 r2,$15,(r3)+              # 15
                    326: pattst:        acbl $16,r1,r0,patmlp           # until <= 15 left
                    327:        bisb3 r2,r0,(r3)+               # rest
                    328: patzer:        clrb (r3)                       # eo$end
                    329:        rsb
                    330: 
                    331: scien:
                    332:        bsbw fltcvt                     # get packed digits
                    333: scig:  incl ndigit
                    334:        jbs $ndfndb,flags,L23
                    335:        movl $7,ndigit
                    336: L23:   subl3 $17,ndigit,r0             # rounding position
                    337:        ashp r0,$17,(sp),$5,ndigit,16(sp) # shift and round
                    338:        bvc snovfl
                    339:        # band-aid for microcode error (spurious overflow)
                    340:        clrl r0                         # assume even length result
                    341:        jlbc ndigit,sceven              # right
                    342:        movl $4,r0                      # odd length result
                    343: sceven:        cmpv r0,$4,16(sp),$0            # top digit zero iff true overflow
                    344:        bneq snovfl
                    345:        # end band-aid
                    346:        incl exp                        # rounding overflowed to 100...
                    347:        subl3 $1,ndigit,r0
                    348:        ashp r0,$1,pone,$0,ndigit,16(sp)
                    349:        ashl $-1,ndigit,r0              # displ to last byte
                    350:        bisb2 sign,16(sp)[r0]           # insert sign
                    351: snovfl:
                    352:        jbc $gflagb,flags,enotg         # not %g format
                    353:  # find trailing zeroes in packed number
                    354:        ashl $-1,ndigit,r0
                    355:        addl2 r3,r0                     # addr of l.s.digit and sign
                    356:        movl $4,r1                      # bit position of digit
                    357:        movl ndigit,r7                  # current length of packed
                    358:        jbr gtz
                    359: gtz1:  xorl2 $4,r1                     # position of next digit
                    360:        bneq gtz                        # same byte
                    361:        decl r0                         # different byte
                    362: gtz:   cmpv r1,$4,(r0),$0              # a trailing zero?
                    363:        jneq gntz
                    364:        sobgtr r7,gtz1
                    365:        incl r7
                    366: gntz:                                  # r7: minimum width of fraction
                    367:        cmpl exp,$-4
                    368:        jleq eg                         # small exponents use %e
                    369:        subl3 r7,exp,r0
                    370:        cmpl $5,r0
                    371:        jleq eg                         # so do (w+5) <= exp
                    372:        tstl r0                         # rest use %f
                    373:        jleq fg                         # did we trim too many trailing zeroes?
                    374:        movl exp,r7                     # yes
                    375: fg:    subl3 ndigit,r7,r0
                    376:        ashp r0,ndigit,16(sp),$0,r7,(sp)
                    377:        movp r7,(sp),16(sp)
                    378:        subl3 exp,r7,ndigit             # correct ndigit for %f
                    379:        jbr fnovfl
                    380: eg:    subl3 ndigit,r7,r0
                    381:        ashp r0,ndigit,16(sp),$0,r7,(sp)
                    382:        movp r7,(sp),16(sp)
                    383:        movl r7,ndigit                  # packed number has been trimmed
                    384: enotg:
                    385:        movc3 $7,patsci,(sp)
                    386:        movl $1,r6                      # 1P
                    387:        subl3 $1,ndigit,r0              # digits after dec.pt
                    388:        bsbw patmov
                    389:        editpc ndigit,16(sp),(sp),32(sp)        # 32(sp)->result, r5->(end+1)
                    390:        decl exp                        # compensate: 1 digit left of dec.pt
                    391:        cvtlp exp,$2,(sp)               # exponent
                    392:        editpc $2,(sp),patexp,(r5)
                    393: prflt: movab 32(sp),r1
                    394:        jbs $psignb,flags,prflt1
                    395:        cmpb (r1)+,$'+
                    396:        beql prflt1
                    397:        decl r1
                    398: prflt1:        skpc $' ,$63,(r1)
                    399:        jbr prstr
                    400: 
                    401: general:
                    402:        jbcs $gflagb,flags,scien
                    403:        jbr scien                       # safety net
                    404: 
                    405:        # convert double-floating at (ap) to 17-digit packed at (sp),
                    406:        # set 'sign' and 'exp', advance ap.
                    407: fltcvt:
                    408:        clrb sign
                    409:        movd (ap)+,r5
                    410:        jeql fzero
                    411:        bgtr fpos
                    412:        mnegd r5,r5
                    413:        incb sign
                    414: fpos:
                    415:        extzv $7,$8,r5,r2               # exponent of 2
                    416:        movaw -0600(r2)[r2],r2          # unbias and mult by 3
                    417:        bgeq epos
                    418:        subl2 $9,r2
                    419: epos:  divl2 $10,r2
                    420:        bsbb expten
                    421:        cmpd r0,r5
                    422:        bgtr ceil
                    423:        incl r2
                    424: ceil:  movl r2,exp
                    425:        mnegl r2,r2
                    426:        cmpl r2,$29                     # 10^(29+9) is all we can handle
                    427:        bleq getman
                    428:        muld2 ten16,r5
                    429:        subl2 $16,r2
                    430: getman:        addl2 $9,r2                     # -ceil(log10(x)) + 9
                    431:        bsbb expten
                    432:        emodd r0,r4,r5,r0,r5            # (r0+r4)*r5; r0=int, r5=frac
                    433: fz1:   cvtlp r0,$9,16(sp)              # leading 9 digits
                    434:        ashp $8,$9,16(sp),$0,$17,4(sp)  # as top 9 of 17
                    435:        emodd ten8,$0,r5,r0,r5
                    436:        cvtlp r0,$8,16(sp)              # trailing 8 digits
                    437:        addp4 $8,16(sp),$17,4(sp)       # combine leading and trailing
                    438:        bisb2 sign,12(sp)               # and insert sign
                    439:        rsb
                    440: fzero: clrl r0
                    441:        movl $1,exp             # 0.000e+00 and 0.000 rather than 0.000e-01 and .000
                    442:        jbr fz1
                    443: 
                    444:        # return 10^r2 as a double float in r0||r1 and 8 extra bits of precision in r4
                    445:        # preserve r2, r5||r6
                    446: expten:
                    447:        movd $one,r0                    # begin computing 10^exp10
                    448:        clrl r4                         # bit counter
                    449:        movad ten1,r3                   # table address
                    450:        tstl r2
                    451:        bgeq e10lp
                    452:        mnegl r2,r2                     # get absolute value
                    453:        jbss $6,r2,e10lp                # flag as negative
                    454: e10lp: jbc r4,r2,el1                   # want this power?
                    455:        muld2 (r3),r0                   # yes
                    456: el1:   addl2 $8,r3                     # advance to next power
                    457:        aobleq $5,r4,e10lp              # through 10^32
                    458:        jbcc $6,r2,el2                  # correct for negative exponent
                    459:        divd3 r0,$one,r0                # by taking reciprocal
                    460:        mnegl r2,r2
                    461: el2:   clrl r4                         # 8 extra bits of precision
                    462:        rsb
                    463: 
                    464:        # powers of ten
                    465:        .align  3
                    466: ten1:  .word   0x4220,0,0,0
                    467: ten2:  .word   0x43c8,0,0,0
                    468: ten4:  .word   0x471c,0x4000,0,0
                    469: ten8:  .word   0x4dbe,0xbc20,0,0
                    470: ten16: .word   0x5b0e,0x1bc9,0xbf04,0
                    471: ten32: .word   0x759d,0xc5ad,0xa82b,0x70b6

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.