xref: /csrg-svn/lib/libc/vax/stdio.old/doprnt.c (revision 26694)
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