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