K氏のheboOSをまねてみる

81:割り込み処理
-- K 10/14 23:52
 おめでとうございます!

>これを実行し、「一回目」のキーボタンがAなら、ちゃんとAを表示していますが、それ以降は無反応になってしまいます。

 いや、それでよいのです。なぜ無反応になってしまったかというと、割り込み処理が完了したことを、CPUにしか知らせてないからです。

 くわしいことは、

  http://community.osdev.info/index.php?(PIC)8259A

をじっくりと見てください(特に最後の「ものぐさなあなたのために」を見逃さないように)。

82:Re: 割り込み処理
hideyosi 10/16 15:45
ふむ!?

Kタンのhttp://community.osdev.info/index.php?(PIC)8259Aをジックリと読んでみた。
・・・むずかしくてわかりません・・・(T∀T)

しかし、そんなぼくらのために(ヲレだけかも)「ものぐさ」というセクションがあった。

ようするにはこういうことらしい。
●割り込みは、CPUの機能だが、その割り込みの発生・CPUへの発注・関所を行うLSIがあるらしい。
●このLSIは、キーボードなどから信号が来ると、割り込み信号を作って、CPUに「おい!割り込みがきたぞー!」と知らせ、CPUでは割り込みが発生する。
●CPU(アセンブラのプログラム部)では、割り込み時に必要な処理は行う。で、その処理が終わったら、IRETで戻ってくる。(つまり、CPUとしては、割り込みは終了している)
●問題は、さっきのLSI。この時点では、まだ、「割り込みがキタゾー!」のまんま。つまり、次の割り込みは待たされている
●つまり、このLSIにも、「CPUとしては、割り込み処理はもう終わったよ。次の割り込みを受け付けていいよ。たのむね」と、教えてあげなくてはいけないらしい。

そのためのコードが、これらしい。

AL = 割り込み番号 + 0x60; OUT(0x20, AL);

83:Re: 割り込み処理
hideyosi 10/16 16:15
うーーーん・・・
AL = 割り込み番号 + 0x60; OUT(0x20, AL);
これはどういうことだろう。こういうことなのかな???

-----------------------------------------

[BITS 16]
[OPTIMIZE 1]
[OPTION 1]
[INSTRSET "8086"]
[FORMAT "BIN"]
ORG 0x100
;-----------------------------------------------------
;--- こっから上は、MS-DOSの.COMを作る時の ------------
;----おまじないだと思ってくれい!     ------------
;-----------------------------------------------------


;-------- 実験部分 ----------------------

;BIOSのキー入力を乗っ取る
MOV AX,0
MOV ES,AX ; ESを0にする。
MOV WORD[ES:0x09*4+0],IINT09
MOV WORD[ES:0x09*4+2],CS
MOV AX,DS
MOV ES,AX ; ESをもとにもどす。


JMP MAINLLP ;メインループへジャンプ


;メインのループ部分
MAINLLP:


JMP MAINLLP



;乗っ取ったキーボード割り込み部分
IINT09:
;押されたキーは何かを調べる
;IN命令で、押されたキーの値を取得
MOV DX,0x60
IN AL,DX

;持ってきた値の7ビットだけを抽出
AND AL,0x7F ;二進数 01111111 でANDSする

;もしその値が1Eだったら、Aボタンが押されている
CMP AL,0x1E

;上のCPM命令によってキャリーフラブが変化している。
;同じならZFが1,CFが0になっている
;もしそうなら、文字表示ルーチンをコールする

JE MOJIPRINT

;そうでなかったら、割り込みから戻る
JMP INTEND


;文字を表示するルーチン
MOJIPRINT:
MOV AL,0x41
MOV AH,0x0e
INT 0x10

JMP INTEND


;割り込み後は、この処理をしないと戻れない
INTEND:
MOV AL,0x09
ADD AL,0x60
MOV DX,0x20
OUT DX,AL

IRET

;-----------------------------------------------------
;---- これがないと、暴走しちゃうぞ! -------------
;-----------------------------------------------------
;MS-DOS終了
INT 0x20

-----------------------------------------

・・・ところが、これだとうまくいかないんだよねぇ。なんでだろう????


84:Re: 割り込み処理
hideyosi 10/16 16:22
っはっはぁぁぁぁ。
なるほどぉ!
この場合の「割り込み番号」って、IRQ番号を使うんだぁ!
えーっと、キーボードのIRQって・・・・1か!

つまり、こうするわけか?

-----------------------------------------

[BITS 16]
[OPTIMIZE 1]
[OPTION 1]
[INSTRSET "8086"]
[FORMAT "BIN"]
ORG 0x100
;-----------------------------------------------------
;--- こっから上は、MS-DOSの.COMを作る時の ------------
;----おまじないだと思ってくれい!     ------------
;-----------------------------------------------------


;-------- 実験部分 ----------------------

;BIOSのキー入力を乗っ取る
MOV AX,0
MOV ES,AX ; ESを0にする。
MOV WORD[ES:0x09*4+0],IINT09
MOV WORD[ES:0x09*4+2],CS
MOV AX,DS
MOV ES,AX ; ESをもとにもどす。


JMP MAINLLP ;メインループへジャンプ


;メインのループ部分
MAINLLP:


JMP MAINLLP



;乗っ取ったキーボード割り込み部分
IINT09:
;押されたキーは何かを調べる
;IN命令で、押されたキーの値を取得
MOV DX,0x60
IN AL,DX

;持ってきた値の7ビットだけを抽出
AND AL,0x7F ;二進数 01111111 でANDSする

;もしその値が1Eだったら、Aボタンが押されている
CMP AL,0x1E

;上のCPM命令によってキャリーフラブが変化している。
;同じならZFが1,CFが0になっている
;もしそうなら、文字表示ルーチンをコールする

JE MOJIPRINT

;そうでなかったら、割り込みから戻る
JMP INTEND


;文字を表示するルーチン
MOJIPRINT:
MOV AL,0x41
MOV AH,0x0e
INT 0x10

JMP INTEND


;割り込み後は、この処理をしないと戻れない
INTEND:
MOV AL,0x01 ;キーボードの割り込み(IRQ)
ADD AL,0x60 ;その番号に、60を足した値
MOV DX,0x20
OUT DX,AL

IRET

;-----------------------------------------------------
;---- これがないと、暴走しちゃうぞ! -------------
;-----------------------------------------------------
;MS-DOS終了
INT 0x20

-----------------------------------------

おぉぉ!!! うまくいったぞ!!!!
逆にKタンの懸念どおり、一回押せば2回Aが出てしまうってのもちゃんと?再現。

よぉぉぉぉし!!!!!!!うまくいったぞ!!!


85:Re: 割り込み処理
hideyosi 10/16 19:16
さてさて。この実験用のショボイコードも、けっこういろいろと
できるようになってきた。
これを、とにもかくにもOSっぱく見えるところまで仕上げてみよう。
そのためには、

1、プロンプトを表示してみよう
2、例の、一回押すと二個文字がでる現象をなんとかする
3、キーボードからの文字をちゃんと認識できるようにする
4、一個ぐらい、コマンドを実装したいなぁ(clsとか)

そんなわけで、まずは2から手をつけよう。


86:Re: 割り込み処理
hideyosi 10/16 22:04
まず、キーボードからやってくる、「押されたキー信号」は、
0〜6までがキーを示す値。で、最後の7bit目が、「押したのか・離したのか」をあらわします。
今現在、私のコードでは、押して一回、離して一回と割り込みを処理してしまっていますので、一回キーを押すと二回「A」が表示されます。
「キーが離されたときだけ」という反応をすれば、OKなのではと考えました。

今現在はこういうコード。

---------------------------------------------------
IINT09:
;押されたキーは何かを調べる
;IN命令で、押されたキーの値を取得
MOV DX,0x60
IN AL,DX

;持ってきた値の7ビットだけを抽出
AND AL,0x7F ;二進数 01111111 でANDSする

;もしその値が1Eだったら、Aボタンが押されている
CMP AL,0x1E

;上のCPM命令によってキャリーフラブが変化している。
;同じならZFが1,CFが0になっている
;もしそうなら、文字表示ルーチンをコールする

JE MOJIPRINT

;そうでなかったら、割り込みから戻る
JMP INTEND
-----------------------------------------------------

これを、こうしてみたらどうだろ?

------------------------------------------------------
IINT09:
;押されたキーは何かを調べる
;IN命令で、押されたキーの値を取得
MOV DX,0x60
IN AL,DX

;持ってきた値を一時、AHに複製する
MOV AH,AL
;AHに複製した値の7ビット目だけを摘出
AND AH,0x80
;もし、この結果の値が00000000すなわち0x0なら、
;キーは「押された」となるはず。ここで条件分岐
CMP AH,0x0

;なにもせずに割り込みを終了する
JE INTEND

;違うなら、キーは「離されて」いる。
;持ってきた値の7ビットだけを抽出
AND AL,0x7F ;二進数 01111111 でANDSする

;もしその値が1Eだったら、Aボタンが押されている
CMP AL,0x1E

;上のCPM命令によってキャリーフラブが変化している。
;同じならZFが1,CFが0になっている
;もしそうなら、文字表示ルーチンをコールする

JE MOJIPRINT

;そうでなかったら、割り込みから戻る
JMP INTEND
---------------------------------------------------------

さて。これでうまくいくかな???



87:Re: 割り込み処理
hideyosi 10/16 22:09
うはははは! いよーし!! うまくいったぞ!! (^^)

次は、A以外のキーも反応できるようにしょう!

88:Re: 割り込み処理
hideyosi 10/16 23:50
うーーーん・・・・
押されたキーと、ASCIIのキーコード。なんらかの法則性があるかと思って眺めていたんだけど、まったく関連性がないや・・・
なんらかの計算ルーチンでなんとかなるかと思っていたが、甘かった・・・・
やっぱ、基本的には「絨毯爆撃」で分岐を書くしかないのかなぁ・・・


89:Re: 割り込み処理
hideyosi 10/18 01:01
いろいろと考えてみたんだけど、やっぱほかにいい方法がみつからないや。もういいや!絨毯爆撃で!

・・・ってなわけで、キーボードの割り込み部分はこういうふうになった。

-------------------------------------------
;もしその値が1Eだったら、Aボタンが押されている
CMP AL,0x1E

;上のCPM命令によってキャリーフラブが変化している。
;同じならZFが1,CFが0になっている
;もしそうなら、文字表示ルーチンをコールする
JE APRINT


CMP AL,0x30 ;Bが押されている
JE BPRINT

CMP AL,0x2E ;Cが押されている
JE CPRINT




CMP AL,0x15 ;Yが押されている
JE YPRINT

CMP AL,0x2C ;Zが押されている
JE ZPRINT


;そうでなかったら、割り込みから戻る
JMP INTEND




;文字ごとにコードをセットする
APRINT:
MOV AL,0x41
JMP MOJIPRINT

BPRINT:
MOV AL,0x42
JMP MOJIPRINT



YPRINT:
MOV AL,0x59
JMP MOJIPRINT

ZPRINT:
MOV AL,0x5A
JMP MOJIPRINT




;文字を表示するルーチン
MOJIPRINT:
MOV AH,0x0e
INT 0x10

JMP INTEND
----------------------------------------------

で、コンパイル。
おぉぉ!!! 文字がいろいろと表示できる!けっこうたのしいぞ!!

今回はとりあえず、ABC・・・XYZまでだけにしておこう。他のキーやShiftとかはちょっと後回し。

・・・でも、ENTERキーだけは、なんとかそれらしく動作させたいなぁ。




90:キーコード変換
-- K 10/18 14:04
>おぉぉ!!! 文字がいろいろと表示できる!けっこうたのしいぞ!!

 おめでとうございます。

>いろいろと考えてみたんだけど、やっぱほかにいい方法がみつからないや。もういいや!絨毯爆撃で!

 ちょっとだけヒントを書くことにしようかな。

 アセンブラでもCでも同じことですが、この手のコードをifのかたまりやswitchのかたまりで書くのは良くないことです。C言語であれば、

 static char table[] = {
  0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', '\b', '\t',
  'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', '\n', 0, 'A', 'S',
  'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':', 0, 0, ']', 'Z', 'X', 'C', 'V',
  'B', 'N', 'M', ',', '.', '/', 0, '*'
     (以下略)
 };

とやっておいて、 j = table[i]; とでもすれば、一発でキーコードから文字コードにできます。

 おなじことをnaskですることもちろんできて、

; ALには0x1eなどのコードが既に入っているとする。

  MOV BH,0
  MOV BL,AL
  MOV AL,[BX+table]

; これでもうALには文字コードが入っている。たくさんのCMP+JEにさようなら。

; 以下はプログラムではなくデータなので間違って実行しないような位置におく

table:
  DB 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 8, 9
  DB 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', 10, 0, 'A', 'S'
  DB 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':', 0, 0, ']', 'Z', 'X', 'C', 'V'
  DB 'B', 'N', 'M', ',', '.', '/', 0, '*'
     (以下略)

 僕の書いた意味が理解できたら使ってみてください。
理解できなければ今のままCMP+JEで書くほうがいいと思います。
MOVしか使ってないので、努力すれば理解できるのではないかと思って書いてみました。

 ちなみに、'A'などの表現が見慣れないかもしれませんが、これは0x41のことです。 MOV AL,'A' とかもできます。


1-

BluesBB ©Sting_Band