8086 で FizzBuzz!

さあ!すっかり 8086 のアセンブリプログラミングにハマってしまいました。いや、ハマったというのは過言ですが。

ともかく、8086 で FizzBuzz に挑戦してみました。が、2560 で止まってしまいます…。

fizzbuzz

# vim:set syntax=gas:

/* fizzbuzz.S
 * https://linuxshugendo.wordpress.com/?p=1486
 * 2015-02-16
 */

        .code16
        .global _start
_start:
        xor     %ax, %ax
        movw    %ax, %es
        movw    $0xffff, %sp

        xor     %bx, %bx        # カウンタ

next:
        /* カウンタの更新 */
        inc     %bx

        /* 停止条件 */
        movw    %bx, %ax
        xor     $0xfff, %ax
        jz      end

        xor     %di, %di        # Fizz か Buzz だったことを示すフラグ

        /* Fizz */
        movw    %bx, %ax
        xor     %dx, %dx
        movw    $3, %cx
        div     %cx
        xor     $0, %dx
        jnz     buzz

        movw    $1, %di
        movw    $(fizzstr), %si
        call    puts

buzz:
        /* Buzz */
        movw    %bx, %ax
        xor     %dx, %dx
        movw    $5, %cx
        div     %cx
        xor     $0, %dx
        jnz     else

        movw    $1, %di
        movw    $(buzzstr), %si
        call    puts

else:
        /* フラグチェック */
        xor     $1, %di
        jz      printspc

        /* カウンタを表示します */
        movw    $(string), %di
        call    to_s
        call    puts
printspc:
        movw    $(space), %si
        call    puts

        jmp     next
end:
        hlt
        jmp     end

string: .string "Test!"
space:  .string " "
fizzstr:.string "Fizz"
buzzstr:.string "Buzz"

/* puts
 *
 * 入力
 *   %si ヌル終端文字列の開始アドレス
 */
puts:
        push    %ax
        push    %si
        movb    $0xe, %ah
        cld
sub_puts:
        lodsb
        xor     $0, %al
        jz      end_puts
        int     $0x10
        jmp     sub_puts
end_puts:
        pop     %si
        pop     %ax
        ret

/* to_s
 *
 * 入力
 *   %bx 数値
 *   %di 保存先のアドレス (5 バイト長)
 *
 * 出力
 *   %si 新しいアドレス
 */
to_s:
        push    %ax
        push    %bx
        push    %cx
        push    %di

        movw    %di, %si

        /* 空白文字で埋めます */
        cld
        movb    $0x20, %al
        movw    $4, %cx
        rep
        stosb

        std
        movw    %bx, %ax
        movb    $10, %bl
sub_to_s:
        div     %bl
        addb    $0x30, %ah      # ASCII 文字に変換します
        xchg    %ah, %al
        stosb
        xchg    %ah, %al
        xor     %ah, %ah
        xor     $0, %al
        jnz     sub_to_s

        movw    %si, %cx
        xor     %bx, %bx        # 空白文字数カウンタ
        cld
cnt_spaces:
        inc     %bx
        lodsb
        xor     $0x20, %al      # 空白文字と比較
        jz      cnt_spaces
        dec     %bx
        movw    %cx, %si
        addw    %bx, %si

        pop     %di
        pop     %cx
        pop     %bx
        pop     %ax

        ret

いやー難しい!パズル大好きな人ならハマるかも知れませんね。

(コウヅ)

広告