マイペースなプログラミング日記

DTMやプログラミングにお熱なd-kamiがマイペースに書くブログ

カーネル/VM Advent Calendar 2012 2日目! Boot Sector Brainfuck

今年もやって来ましたカーネル/VM Advent Calendar!今日は2日目で私の番でございます。それで今回やる内容は『Boot Sector Brainfuck』!...あれ?2年前にも同じようなことをやったぞ?って感じだけど、ちょっと違います。2年前のやつはブートローダとメインプログラムとBrainfuckソースコードから構成されていて、Brainfuckソースコードを修正するたびにブートローダとメインプログラムをくっつけなければいけなかった!でも今回のやつはブートセクタ内で全てを終わらせるので、くっつける必要がないのです。

それでBrainfuckソースコードはどうするのか?ということですが、『Boot Sector Brainfuck』起動後にキーボード入力を受け付けるようにしてるので、そこでソースコード入力してね!ということです。

それで、ちょっと『Boot Sector Brainfuck』プログラムの解説をします。キーボード入力に関してですが、AHレジスタを0にしてINT 0x16を呼び出すと、キー入力を待ちます。そこで1文字入力が来ると、ALレジスタ文字コードが入ります。ただそれだけだと画面に文字が表示されなくて困るので、INT 0x10で入力された文字を表示します。ついでに入力された文字をBrainfuckソースコードアリア(自分で勝手に定義)にコピーします。Enterが押されたらBrainfuckインタプリタに移ります。あとはKernel/VM Advent Calendar 15日目: リアルモード Brainfuckとほぼ同じ。ただコードサイズの最適化を少しかけてバイナリのサイズが少し小さくなっています。やったのは『ADD AL, 1』みたいなのを『INC AL』にしたり、0チェックを『AND AX, AX』に変えたこと。

次に『Boot Sector Brainfuck』の使い方。qemuを準備して以下のファイルをダウンロードして

qemu -fda bf

と入力するだけ。起動後はBrainfuckソースコードを入力していきましょう!バックスペースは無効になってるので注意。見た目上直せるところもあるけど、メモリ上では変なコードになります。
bf 直

以下ソースコード

[BITS 16]
    mov ax, 0x7C00
    mov ds, ax
    xor ah, ah
    mov al, 0x03
    int 0x10
    mov di, 0x200

input:
    xor ah, ah
    int 0x16

    call printc

    cmp al, 0x0d
    je input_end
    mov byte [di], al
    inc di
    
    jmp input

input_end:
    mov al, 0x0a
    call printc
    mov byte [di], 0x00
    jmp bf_start

printc:
    mov ah, 0x0E
    mov bx, 0x15
    int 0x10
    ret

bf_start:
    mov si, 0x200

    call memset
    mov di, 0x8000

main:
    mov al, [si]
    inc si

    cmp al, '>'
    je incdi

    cmp al, '<'
    je decdi

    cmp al, '+'
    je incmem

    cmp al, '-'
    je decmem

    cmp al, '.'
    je dischar

    cmp al, '['
    je loopstart

    cmp al, ']'
    je loopend

    jmp bfend

incdi:
    inc di
    jmp main

decdi:
    dec di
    jmp main

incmem:
    inc byte [di]
    jmp main

decmem:
    dec byte [di]
    jmp main

dischar:
    mov al, [di]
    call printc
    jmp main

loopstart:
    mov al, [di]
    and al, al
    jne main

    mov bp, 1

toend:
    and bp, bp
    je main

    mov al, [si]
    inc si

    cmp al, '['
    je incnestfs
    cmp al, ']'
    je decnestfs

    jmp toend

loopend:
    mov bp, 1
    dec si

tostart:
    and bp, bp
    je main

    dec si
    mov al, [si]

    cmp al, ']'
    je incnestfe
    cmp al, '['
    je decnestfe

    jmp tostart

tomain:
    inc si
    jmp main

incnestfs:
    inc bp
    jmp toend

decnestfs:
    dec bp
    jmp toend

incnestfe:
    inc bp
    jmp tostart

decnestfe:
    dec bp
    jmp tostart

memset:
    mov di, 0x8000
    mov ax, 0
    mov cx, 30000

    rep stosb
    ret

bfend:
    jmp bfend

    times 510 - ($ - $$) db 0
    db 0x55, 0xAA