BIOSを使用しないでテキストを表示させる

# VRAMに直書きする
自分の前回の投稿（[自作OS（1）: ブートローダ](http://qiita.com/Wanwannodao/items/19830459606eedc46812)）では、BIOSの割り込み```0x10```のテレタイプモードでテキストを表示したが今回はBIOSを使用せずにVRAMに直接書き込むことでテキストを表示させる
※とりあえず今回はリアルモードでの話

NASMを使用します

### VRAMの領域は```0xb800:0x0000```
2byteが色を含めた1文字分に相当する
具体的には、

* 1byte目: キャラクタコード
* 2byte目: 0-3bit 文字色, 4-8bit 背景色

といった具合
また、80文字x25行なので、1行は**160byte**となる

基本的に知っておくことはこれだけで、適切なオフセットを計算して2byteを書き込むということを繰り返す操作となる

## コード
### 各種初期化

まず、```stosw```命令はアキュムレータレジスタ(AX)をエクストラセグメント(ES)のディスティネーションインデックス(DI)に書き込むので、ESにはVRAMのセグメントアドレス```0xb800```を入れておく

ソースインデックス(SI)には目的のテキストのアドレスを入れておく

```nasm
[bits 16]
[org 0x7c00]

start:
        ;; initialize segment registers                                                                                                      
        xor     ax, ax
        mov     ds, ax
        mov     ss, ax
        ;; initialize stack                                                                                                                  
        mov     sp, 0x7c00

        mov     ax, 0xb800      ; VRAM segment                                                                                               
        mov     es, ax          ; segment reg for stosw  
        mov     si, msg

        jmp     println
```

### メインの処理
汎用レジスタの使い方は以下のような感じ

* アキュムレータレジスタ(AX): ALは文字、AHは色情報
* カウンターレジスタ(CX): 行内オフセット 
* ベースレジスタ(BX): 行オフセット (160 byte/line), 25行あるので2byte使いました

大まかな処理の流れ

1. SIレジスタから```lodsb```でALに次の文字を格納
2. 終端なら１行分インクリメントして、とりあえず```hang```ヘ
3. AHに文字色と背景色の情報を格納
4. BXにオフセット値を乗せる
5. オフセットアドレス DI = CX + BX
6. ES:DIにAXの内容を書き込む
7. CXを1文字分(2byte)インクリメントして次の文字へ

```nasm
println:
        xor     cx, cx          ; cx = 0                                                                                                     
print_char:
        lodsb                   ; load a char to AL                                                                                          
        or      al, al          ; if \0                                                                                                      

        jnz     print
        add     word [line], 160 ; 1 line = 80 chars x 2 bytes                                                                               
        jmp     hang
print:
        mov     ah, 0x0f        ; char:white, back:black                                                                                     

        ;; set offset                                                                                                                        
        mov     bx, word [line]
        xor     di, di          ; di = 0 (beginning of VRAM)                                                                                 
        add     di, cx          ; x-offset                                                                                                   
        add     di, bx          ; y-offset                                                                                                   
        ;; write                                                                                                                             
        stosw                   ; stor ax to ES:DI, and di -= 2                                                                              

        add     cx, 2           ; char/attr = 2byte                                                                                          
        jmp     print_char

hang:
        hlt
        jmp     hang

line    dw      0               ; = line num x ( 80 x 2 )                                                                                    
msg     db      "Hello World", 0
        times   510-($-$$) db 0
        dw      0xaa55
```

## 参考
[OSDev](http://wiki.osdev.org/Babystep4)
[OS Wiki](http://community.osdev.info/index.php?VGA%2Ftext)