環境 ・ホスト OS windows 作成したブートローダーから第二ブートローダーまで(内容はプロテクトモードへ移行してからVRAMへ書き込むまで) そのプロフラムをVirtualbox上で動かしています。 縦: 480ドット 横: 640ドット
リアルモードからプロテクトモードへ移行させて文字を表示させたかったのですが
思うようにいきません。
FONT: は16bitアドレスの範囲に設置しています。
FILE boot.s
s
1push FONT 2call get_font_adr 3add sp,2 4 5 6FONT: 7.seg: dw 0 8.off: dw 0 9 10; 11; 12;省略・・・ 13; 14; 15 16mov esi,'a' 17shl esi,4 18add esi,[FONT] 19 20mov edi,0xA_0000 21 22mov ecx,16 23 24.10L: 25 26movsb 27add edi,80 - 1 28 29loop .10L 30
FILE get_font_adr
s
1get_font_adr: 2 3push bp 4mov bp,sp 5 6;/_/_/_/_/_/_/_/ 7; 8;bx 9;ax 10;bp (bp) 11;リターンアドレス 12;フォントアドレス格納位置(si) 13; 14;/_/_/_/_/_/_/_/ 15 16push ax 17push bx 18push si 19push es 20push bp 21 22mov si,[bp + 4] 23 24mov ax,0x1130 25mov bh,0x06 ;8×16 26int 10h ;ES:BPにフォントアドレスが設定される。 27 28mov [si + 0],es ;低位アドレスに上位を格納。 29mov [si + 2],bp ;高位アドレスに下位を格納。 30 31pop bp 32pop es 33pop si 34pop bx 35pop ax 36 37mov sp,bp 38pop bp 39 40ret 41
画面左上に'a'を表示させたいのですが
このように表示されてしまいます。
・まず、左上に'a'ではないけど なんか写っているので
VRAM領域への書き込み自体はうまくいっている。
・縦横連続的に写っているので改行処理はうまくいっている。
s
1add edi,80 - 1
以上のことを踏まえるとフォントアドレスを正しく受け取れていない
または
フォントアドレスを格納場所(FONT:)に入れられていない。
のどちらか(たぶん)
①
push FONT
call get_font_adr
add sp,2
関数 get_font_adr には引数としてFONTを
FONT: ・・・ BIOSコールで手に入れたフォントアドレス
スタックに積みます。
②
get_font_adr: push bp mov bp,sp ;/_/_/_/_/_/_/_/ ; ;bx ;ax ;bp (bp) ;リターンアドレス ;フォントアドレス格納位置(si) ; ;/_/_/_/_/_/_/_/ push ax push bx push si push es push bp mov si,[bp + 4] mov ax,0x1130 mov bh,0x06 ;8×16 int 10h ;ES:BPにフォントアドレスが設定される。 mov [si + 0],es ;低位アドレスに上位を格納。 mov [si + 2],bp ;高位アドレスに下位を格納。 pop bp pop es pop si pop bx pop ax mov sp,bp pop bp ret
③
s
1mov esi,'a' 2shl esi,4 ;1文字16バイトなので ×16をしてオフセットを求める。 3add esi,[FONT] ;ベース + オフセット これでアドレスを手に入れる。 4 5mov edi,0xA_0000 6 7mov ecx,16 ;縦16bitなので16回改行を入れる。 8 9.10L: 10 11movsb ;esiレジスタに入っているアドレスに入ってい値からediレジスタに入っているアドレスへ値を入れる。 12add edi,80 - 1 ;改行 よこ680bit 80バイト だから +79 13 14loop .10L
どこが間違えているのか見つけられないのですが
どこが間違えているのでしょうか?
###追記
自分でフォントデーターを作成し、それを映し出すことを目標にします。
メモリ:0x0000:0x0500にフォントデーターを配置させます。
s
1mov ax,0x0000 2mov [FONT.seg],ax 3mov ax,0x0500 4mov [FONT.off],ax 5
[es:bp]にフォントデータを配置するアドレスを配置しました。
es=0x0000
bp=0x0500
また、
s
1FONT: 2.seg: dw 0 3.off: dw 0 4
こっちにも
.seg=0x0000
.off=0x0500
を格納します。
s
1mov ax,0b1111111111111111 2mov [es:bp],ax 3add bp,2 4mov [es:bp],ax 5add bp,4 6mov [es:bp],ax 7add bp,6 8mov [es:bp],ax 9 10mov ax,0b0000000000000000 11add bp,8 12mov [es:bp],ax 13add bp,10 14mov [es:bp],ax 15add bp,12 16mov [es:bp],ax 17add bp,14 18mov [es:bp],ax 19
このコードで0x0000:0x0500で表させる先頭アドレスから最初の8バイトを11111・・・で埋め尽くし
最初の8バイトから16バイトまでを0000・・・で埋め尽くします。
フォントデータ 1文字16バイト。1文字 縦16ドット 横8ドット
これを表示させると
■■■■■■■■
■■■■■■■■
■■■■■■■■
■■■■■■■■
■■■■■■■■
■■■■■■■■
■■■■■■■■
■■■■■■■■
□□□□□□□□
□□□□□□□□
□□□□□□□□
□□□□□□□□
□□□□□□□□
□□□□□□□□
□□□□□□□□
□□□□□□□□
このように表示されることを期待しています。
実際に、0x0000:0x0500の領域にデータが書き込まれたか確認をします。
s
1mov ax,[es:bp] 2push 0b0100;これは気にしないでください。 3push 2 ;2進数で表示させたいから基数2をプッシュ 4push 16 ;0 or 1を16文字ASCIIで表示させるから16バイト 5push .font_data2 ;font_data2にASCIIに変換した数値を格納 6push ax;変換したい数値 7call itoa;ASCII変換関数を呼び出す 8add sp,10 9 10push .font_data2 ;表示させたい文字をプッシュ(さっきASCIIに変換した数値) 11call puts ;出力関数 12add sp,19 13 14.font_data2 db "----------------",0x0A,0x0D,0 ;16バイト分 0x0A,0x0Dは画面出力させるとき改行するため 0は文字列の終わりを示す。 15
以下、ASCII変換関数
s
1itoa: 2 3;/_/_/_/_/_/_/_/_/_/_/_/ 4; 5;bp (bp) 6;リターンアドレス 7;num 変換する値 (ax) 8;buff 保存先アドレス(si) 9;size 保存先バッファさきサイズ(cx) 10;radix 基数(2、8,10または16を設定する。) 11;flags B2:空白を0で埋める B1:+/-符号をつける B0:値を符号付変数として扱う(bx) 12; 13;/_/_/_/_/_/_/_/_/_/_/_/ 14 15push bp 16mov bp,sp 17 18push ax 19push bx 20push cx 21push dx 22push si 23push di 24 25mov ax,[bp + 4] ;変換する値 26mov si,[bp + 6] ;保存先アドレス 27 28mov cx,[bp + 8] ;cx=バッファサイズ 29 30mov di,si 31add di,cx 32dec di ;di=バッファの最後尾 33 34mov bx,word [bp + 12] ;flags 35 36test bx,0b0001 ;値を符号付変数として扱う AND演算 結果が0なら ZFを立てる。 37 38.10Q: 39je .10E ;IF ZF=1 40 41cmp ax,0 42 43.12Q: 44jge .12E 45or bx,0b0010 46 47.12E: 48.10E: 49 50test bx,0b0010 51 52.20Q: 53je .20E ;IF ZF==1 54cmp ax,0 55 56.22Q: 57jge .22F 58neg ax 59mov [si],byte '-' 60 61jmp .22E 62 63.22F: 64 65mov [si],byte '+' 66 67.22E: 68dec cx 69 70.20E: 71 72;/_/_/_/_/_/_/ 73;ASCII変換 74;/_/_/_/_/_/_/ 75 76mov bx,[bp + 10] ;基数 77 78.30L: 79 80mov dx,0 81div bx 82;DX=DX:AX % 基数 83;AX=DX:AX / 基数 84 85mov si,dx 86mov dl,byte [.ascii + si] 87 88mov [di],dl 89dec di 90 91cmp ax,0 ;割った商が0か確認 92 93loopnz .30L ;CX を -1 し cx != 0 かつ ZF == 0 94 95.30E: 96 97; 98;空白を埋める。 99; 100 101;cmp cx,0 102;.40Q: 103;je .40E ;IF ZF==1 104;mov al,' ' 105 106;cmp [bp + 12],word 0b0100 107 108;.42Q: 109;jne .42E ;IF ZF==0 110mov al,'0' 111 112.42E: 113std ;デクリメント 114rep stosb ;al→di ecx=回数 115 116.40E: 117 118pop di 119pop si 120pop dx 121pop cx 122pop bx 123pop ax 124 125mov sp,bp 126pop bp 127 128ret 129 130.ascii db "0123456789ABCDEF" 131
以下、出力関数
s
1puts: 2 3;/_/_/_/_/_/_/ 4; 5;bx 6;ax 7;bp←bp 8;リターンアドレス 9;文字コード 10; 11;/_/_/_/_/_/_/ 12 13push bp 14mov bp,sp 15push ax 16push bx 17push si 18 19mov si,[bp + 4] 20mov ah,0x0E ;固定 21 22mov bx,0x0000 ;固定 23 24cld ;DFを0にする。 25 26.10L: 27 28lodsb ;si=文字列 DF=0ならインクリメントする。 29cmp al,0 30je .10E ;IF ZF==1 31 32int 0x10 33 34jmp .10L 35 36.10E: 37 38pop si 39pop bx 40pop ax 41mov sp,bp 42pop bp 43 44ret 45
数値をそのまま画面に出力できないので
数値をASCIIに変換してから表示させます。
0x0000:0x0500から先頭の2バイトを表示させています。
さっきそこには1111...を格納したので
1111...が2バイト分つまり
16個 '1'が表示させるはずなのですが。。。
なぜ、書き換えがうまくいっていないのでしょうか?
s
1mov ax,0b1111111111111111 2mov [0xA_0000],ax 3mov [0xA_0050],ax 4mov [0xA_00A0],ax 5mov [0xA_00F0],ax 6mov [0xA_0140],ax 7
試しに直接VRAMへ書き込みをおこなったところ
書き込めさえすればしっかり写してくれているので
VRAMへデータを適切に移せていないのが
文字が出ない原因のようです。
次は、0x0_0500にフォントデータ(全部1)を設置してから
VRAMへ書き込むプログラムを書いてみました。
s
1mov ax,0b1111111111111111 2mov [0x0_0500],ax 3mov [0x0_0502],ax 4mov [0x0_0504],ax 5mov [0x0_0506],ax 6mov [0x0_0508],ax 7 8 9mov ax,[0x0_0500] 10mov [0xA_0000],ax 11mov ax,[0x0_0502] 12mov [0xA_0050],ax 13mov ax,[0x0_504] 14mov [0xA_00A0],ax 15mov ax,[0x0_506] 16mov [0xA_00F0],ax 17mov ax,[0x0_508] 18mov [0xA_0140],ax
画面には何も出力されませんでした。
なぜなんでしょうか?
回答3件
あなたの回答
tips
プレビュー