「手探りでCUI OS作成に挑む」連載
この記事は「手探りでCUI OS作成に挑む」連載の一部です。
全体の目次は「手探りでCUI OS作成に挑む」連載目次を御覧下さい。
目的
CUIのOSを開発しています。
全てアセンブリで書いています。
デバッグを便利にする為、画面左上にレジスタの値を表示する機能を実装しました。
ソース
boot.asm
org 0x7C00
start:
; セグメント初期化
xor ax, ax
mov ds, ax
mov es, ax
; スタック設定
mov ss, ax
mov sp, 0x7C00
; ディスクから第2セクタ(LBA=1)を 0x8000 に読み込む
mov ah, 0x02 ; INT 13h サービス 2: 読み込み
mov al, 1 ; 読み込むセクタ数 = 1
mov ch, 0 ; シリンダ = 0
mov cl, 2 ; セクタ番号 = 2(1始まり)
mov dh, 0 ; ヘッド = 0
mov dl, 0 ; ドライブ番号(通常フロッピーは 0x00)
mov bx, 0x7E00 ; 読み込み先アドレス
int 0x13
jc disk_error ; エラー時に無限ループ
; 読み込んだコードへジャンプ(第2セクタ)
jmp 0x0000:0x7E00
disk_error:
jmp $ ; 無限ループ(エラー時に停止)
times 510-($-$$) db 0
dw 0xAA55
kernel.asm
org 0x7E00
start:
; レジスタ初期化
xor ax, ax
mov ds, ax
mov es, ax
; スタック設定
mov ss, ax
mov sp, 0x7C00
; 画面クリア
mov ax, 0x0003
int 0x10
mov bx, 0xABCD
mov ax, bx
call print_ax_hex
cli
hlt
ret
%include "debug.asm"
debug.asm
print_ax_hex:
pusha
push ds
push es
mov dx, ax ; AXの値を退避(DL=下位, DH=上位)
; DI = 0(VRAMオフセット、文字2バイト単位)
mov di, 0
; ES = 0xB800(VRAM)
mov ax, 0xB800
mov es, ax
; DS = CS(hex_table参照用)
mov ax, cs
mov ds, ax
; --- DHの上位4bit ---
mov al, dh
shr al, 4
and al, 0x0F
mov bl, al
mov bh, 0
mov al, [hex_table + bx]
mov [es:di], al
mov byte [es:di+1], 0xE0
add di, 2
; --- DHの下位4bit ---
mov al, dh
and al, 0x0F
mov bl, al
mov bh, 0
mov al, [hex_table + bx]
mov [es:di], al
mov byte [es:di+1], 0xE0
add di, 2
; --- DLの上位4bit ---
mov al, dl
shr al, 4
and al, 0x0F
mov bl, al
mov bh, 0
mov al, [hex_table + bx]
mov [es:di], al
mov byte [es:di+1], 0xE0
add di, 2
; --- DLの下位4bit ---
mov al, dl
and al, 0x0F
mov bl, al
mov bh, 0
mov al, [hex_table + bx]
mov [es:di], al
mov byte [es:di+1], 0xE0
add di, 2
pop es
pop ds
popa
ret
hex_table:
db '0123456789ABCDEF'
nasm -f bin boot.asm -o boot.bin
nasm -f bin kernel.asm -o kernel.bin
cat boot.bin kernel.bin > os-image.bin
qemu-system-i386 -fda os-image.bin
使い方
例えばBXの値(0xBCBC)を表示したい場合はAXにその値を入れてprint_ax_hex関数を呼び出します。
mov bx, 0xABCD
mov ax, bx
call print_ax_hex
仕組み
AX,BX,CX,DXレジスタの大きさはそれぞれ16ビット
16進数は4ビット毎に0〜Fまでを使って表示するので合計4文字を画面上に表示することになります。
以下のような処理を4回繰り返します。
; --- DHの上位4bit ---
mov al, dh
shr al, 4
and al, 0x0F
mov bl, al
mov bh, 0
mov al, [hex_table + bx]
mov [es:di], al
mov byte [es:di+1], 0xE0
add di, 2
例:AX = 0011110011110011として説明します。
まずはDHの値をALに入れます。
9文字目から始まる1111が表示したい値です。
shrを使って右に4ビットずらして表示した値が下位4ビットにくるようにします。
AX = 0000001111001111
この時点でAL=11001111となっており先頭の11が邪魔です。
11001111及び00001111(0x0F)の論理積(AND)を取ることで残し上位4ビットを0にします。
AL=00001111
BLに格納して添字とします。BHは影響しないように0で埋めます。
そしてmov al, [hex_table + bx]のようにすることで、16進数の値に対応した文字がALに入ります。
例えば今回の例ではBL=00001111(10進数の15に相当)
[hex_table + bx]の結果はFとなる。
参考
hex_table:
db '0123456789ABCDEF'