;; ------------------------------------------------ ;; mysprintf.s for Mac OS X (PowerPC 32bit) ;; % as -o dk_sprintf.o dk_sprintf.s ;; ------------------------------------------------ .machine ppc .globl _dk_sprintf ;; typedef union dk_va { ;; char *sval; ;; int ival; ;; float fval; ;; } dk_va, *dk_va_list_t; ;; ;; int dk_sprintf(char *dest, const char *format, dk_va_list_t args) ;; r3: char *dest ;; r4: const char *format ;; r5: dk_va_list_t args ;; ;; r7(buf): dest の書き込み用コピー ;; r8(c): スキャンする文字 ;; r9(flag): 前の文字が % なら 1 _dk_sprintf: ;; 初期化 mr r7, r3 li r9, 0 _scan: ;; format から一文字読み込む lbz r8, 0(r4) ; c = *format ;; ディレクティブ cmpli cr7, r9, 1 ; flag == 1 beq cr7, _scan_directive cmpli cr7, r8, 37 ; c == '%' beq cr7, _switch_directive ;; format から読み込んだ文字を書き込む stb r8, 0(r7) ; *buf = c addi r7, r7, 1 ; buf++ ;; 文字列の終端 cmpli cr7, r8, 0 ; c == 0 beq cr7, _dk_sprintf_return ;; 繰り返し addi r4, r4, 1 ; format++ b _scan _switch_directive: li r9, 1 ; flag = 1 addi r4, r4, 1 ; format++ b _scan _scan_directive: li r9, 0 ; flag = 0 ;; %% cmpli cr7, r8, 37 ; c == '%' beq cr7, _write_escape ;; %s cmpli cr7, r8, 115 ; c == 's' beq cr7, _write_s ;; %d cmpli cr7, r8, 100 ; c == 'd' beq cr7, _write_d ;; %f cmpli cr7, r8, 102 ; c == 'f' beq cr7, _write_f ;; 未定義のディレクティブ li r10, 37 ; '%' stb r10, 0(r7) ; *buf = '%' stb r8, 1(r7) ; *(buf+1) = c addi r7, r7, 2 ; buf += 2 addi r4, r4, 1 ; format++ b _scan ;; %% _write_escape: li r10, 37 ; '%' stb r10, 0(r7) ; *buf = '%' addi r7, r7, 1 ; buf++ addi r4, r4, 1 ; format++ b _scan ;; %s _write_s: lwz r10, 0(r5) ; args->sval addi r5, r5, 4 addi r4, r4, 1 ; format++ __write_s: lbz r11, 0(r10) ; s = args->sval cmpli cr7, r11, 0 beq cr7, _scan stb r11, 0(r7) ; *buf = s addi r7, r7, 1 ; buf++ addi r10, r10, 1 ; args->sval++ b __write_s ;; %d _write_d: lwz r10, 0(r5) ; i = args->ival addi r5, r5, 4 addi r4, r4, 1 ; format++ mflr r16 ; リンクレジスタをスタックに退避 bl _write_digit mtlr r16 ; リンクレジスタをスタックから復帰 b _scan ;; %f ;; r17: 精度 ;; f0: 元の数値 ;; f1: 整数部 ;; f5: 0 ;; f6: 10 _write_f: ;; 定数の準備など lis r13, hi16(zero) addi r13, r13, lo16(zero) lfs f5, 0(r13) ; 0 lis r13, hi16(ten) addi r13, r13, lo16(ten) lfs f6, 0(r13) ; 10 li r17, 6 ; 精度 lfs f0, 0(r5) ; f = args->fval addi r5, r5, 4 addi r4, r4, 1 ; format++ ;; 整数部 fctiwz f1, f0 ; (int)f, ビットは整数表現になる stfd f1, -8(r1) ; スタックを通して lwz r10, -4(r1) ; 汎用レジスタに入れる mflr r16 bl _write_digit mtlr r16 ;; 区切り li r14, 46 ; '.' stb r14, 0(r7) ; *buf = '.' addi r7, r7, 1 ; buf++ fabs f2, f0 li r11, 10 ;; 小数部 _write_fpointpart: fmuls f2, f2, f6 fctiwz f3, f2 stfd f3, -8(r1) lwz r10, -4(r1) divwu r12, r10, r11 mullw r12, r12, r11 sub r10, r10, r12 addi r10, r10, 48 ; ASCII stb r10, 0(r7) addi r7, r7, 1 ; buf++ subi r17, r17, 1 cmpli cr7, r17, 0 bgt cr7, _write_fpointpart b _scan ;; 整数を10進数で書き込む ;; r10: 書き込む整数 _write_digit: li r11, 25000 ; fig, 桁 mulli r11, r11, 4 li r14, 10 ; 桁の除算用 li r15, 0 ; 残りを数字をすべて表示するか ;; 負の数 cmpi cr7, r10, 0 bgt cr7, _write_each_digit li r12, 45 ; '-' stb r12, 0(r7) ; *buf = '-' addi r7, r7, 1 ; buf++ mulli r10, r10, -1 ; i = -i ;; 上の桁から順に出力する _write_each_digit: divw r12, r10, r11 ; d = i / fig mullw r13, r11, r12 ; rem = i - fig * d sub r10, r10, r13 divw r11, r11, r14 ; fig /= 10 cmpli cr7, r15, 0 cmpli cr6, r12, 0 ; d == 0 crand 2, 30, 26 ; cr0[eq] = cr7[eq] && cr6[eq] beq cr0, _write_each_digit li r15, 1 addi r12, r12, 48 ; ASCIIコードにする stb r12, 0(r7) ; *buf = s addi r7, r7, 1 ; buf++ ;; 最後の桁 cmpli cr7, r11, 1 ; fig = 1 bgt cr7, _write_each_digit mr r12, r10 addi r12, r12, 48 ; ASCIIコードにする stb r12, 0(r7) ; *buf = s addi r7, r7, 1 ; buf++ blr ; 終了 _dk_sprintf_return: sub r3, r7, r3 ; return buf - dest subi r3, r3, 1 blr .data .align 2 zero: .single 0.0 .align 2 ten: .single 10 .align 2