雑記帳
ここはhideyosiの雑記帳です。テケトーに書き散らしてるだけなので間違っていたりとは普通にしてます。信用度は相当低いことをあらかじめご了承を。またご覧のようにWikiを使ってますが、hideyosi意外は書き込めません。

FDを読んでみる実験2

えーっと。最初に言えるのは、

キタ━━━━(゚∀゚)━━━━ anchor.png Edit

ってことでしょう。エミュ上ではありますが、FDが読めました。以下のコードで、とりあえずセクター19の内容(バイナリエディタでイメージを開くと、0X004800付近ですな)を表示してくれた。

void cmd_fdtest(struct CONSOLE *cons)
{
 char s[30];
 char counter = 3;
 int p;
 char reza;

   struct FIFO32 timerfifox;
   struct TIMER *timerx;
   int timerbuf[128];

   fifo32_init(&timerfifox,128,timerbuf,0);

   timerx = timer_alloc();
   timer_init(timerx,&timerfifox,128);
   timer_settime(timerx,100);

  

 //3秒待ち
     for(;;){
       io_cli();
     p = fifo32_get(&timerfifox);
     if (counter == 0){break;}

     if( p == 128 ){
		sprintf(s, "Wait %dSec...\n",counter);
		cons_putstr0(cons, s);
	counter--;
	timer_settime(timerx,100);
   }
         io_sti();
 }
 
       io_sti();

 //0x03f4のチェック
     sprintf(s, "Check 0x03f4");
     cons_putstr0(cons, s);
     cons_newline(cons);

 char a;
 a = io_in8(0x03f4);a = a & 0x11;
 if ( a == 0 ) {
     sprintf(s, "OK! 0x03f4 & 0x11 is 0!");
     cons_putstr0(cons, s);
     cons_newline(cons);
 }

 //コマンドの送信
     sprintf(s, "Start command send...");
     cons_putstr0(cons, s);
     cons_newline(cons);


     while(io_in8(0x03f4) & 0xC0 != 0x80 ){}
     io_out8(0x03f5, 0x07);
     sprintf(s, "Send 0x03f5 [0x07]\n");
     cons_putstr0(cons, s);

     while(io_in8(0x03f4) & 0xC0 != 0x80 ){}

     io_out8(0x03f5, 0x00);
     sprintf(s, "Send 0x03f5 [0x00]\n");
     cons_putstr0(cons, s);
     //---------------------------------------


     //DMAの初期化
     io_out8(0x00d6, 0xc0); /* マスタのch0をカスケードモードに */
     io_out8(0x00c0, 0x00); /* スレーブのDMAを許可 */
     io_out8(0x000a, 0x06); /* マスタのch2のDMAをマスク */      

     //読み込み用にセットアップ
     //モード設定:デマンド・アドレス増加方向・メモリへの書き込み・ch2
     io_out8(0x000b, 0x06);
     // バイト数の設定 
     io_out8(0x0005, 0xff);
     io_out8(0x0005, 1 * 2 - 1);


     /* メモリ番地の設定 */
     io_out8(0x0004, 0x000a0000 & 0xff);
     io_out8(0x0004, (0x000a0000 >> 8) & 0xff); 
     io_out8(0x0081, (0x000a0000 >> 16) & 0xff);


     io_out8(0x000a, 0x02); /* マスタのch2のDMAをマスク解除 */

     //読み込み用のFDCコマンド発行!
     //  (FDCへのコマンド送信開始)(FATの情報を)
     
     //E6] [H<<2] [C] [H] [S] [02] [12] [01] [FF] (INT)
     //: [ST0] [ST1] [ST2] [C] [H] [S] [02]

     while(io_in8(0x03f4) & 0xC0 != 0x80 ){}
     io_out8(0x03f5, 0xE6);
     sprintf(s, "Send [E6],");
     cons_putstr0(cons, s);

     while(io_in8(0x03f4) & 0xC0 != 0x80 ){}
     io_out8(0x03f5, 0x00<<2);
     sprintf(s, "[0x00<<2],");
     cons_putstr0(cons, s);

     while(io_in8(0x03f4) & 0xC0 != 0x80 ){}
     io_out8(0x03f5, 0x01);
     sprintf(s, "[0x01],");
     cons_putstr0(cons, s);

     while(io_in8(0x03f4) & 0xC0 != 0x80 ){}
     io_out8(0x03f5, 0x00);
     sprintf(s, "[0x00],");
     cons_putstr0(cons, s);

     while(io_in8(0x03f4) & 0xC0 != 0x80 ){}
     io_out8(0x03f5, 0x01);
     sprintf(s, "[0x01],");
     cons_putstr0(cons, s);

     while(io_in8(0x03f4) & 0xC0 != 0x80 ){}
     io_out8(0x03f5, 0x02);
     sprintf(s, "[0x02],");
     cons_putstr0(cons, s);

     while(io_in8(0x03f4) & 0xC0 != 0x80 ){}
     io_out8(0x03f5, 0x12);
     sprintf(s, "[0x12],");
     cons_putstr0(cons, s);

     while(io_in8(0x03f4) & 0xC0 != 0x80 ){}
     io_out8(0x03f5, 0x01);
     sprintf(s, "[0x01],");
     cons_putstr0(cons, s);

     while(io_in8(0x03f4) & 0xC0 != 0x80 ){}
     io_out8(0x03f5, 0xFF);
     sprintf(s, "[0xFF]\n");
     cons_putstr0(cons, s);

     //  (FDCが実行)

 //3秒待ち
     counter=3;
     for(;;){
       io_cli();
     p = fifo32_get(&timerfifox);
     if (counter == 0){break;}

     if( p == 128 ){
		sprintf(s, "Wait %dSec...\n",counter);
		cons_putstr0(cons, s);
	counter--;
	timer_settime(timerx,100);
   }
         io_sti();
 }
 
       io_sti();


     //  (FDCからのINT)
		sprintf(s, "Come on! INT!\n");
		cons_putstr0(cons, s);

     //  (FDCからリザルトステータス読み取り)

     while(io_in8(0x03f4) & 0xC0 != 0xC0 ){}
     reza = io_in8(0x03f5);
     sprintf(s, "[ST0]&0xC0=%X,",reza & 0xC0);
     cons_putstr0(cons, s);

     while(io_in8(0x03f4) & 0xC0 != 0xC0 ){}
     reza = io_in8(0x03f5);
     sprintf(s, "ST1=%X,",reza);
     cons_putstr0(cons, s);

     while(io_in8(0x03f4) & 0xC0 != 0xC0 ){}
     reza = io_in8(0x03f5);
     sprintf(s, "ST2=%X,",reza);
     cons_putstr0(cons, s);

     while(io_in8(0x03f4) & 0xC0 != 0xC0 ){}
     reza = io_in8(0x03f5);
     sprintf(s, "[C]=%X,",reza);
     cons_putstr0(cons, s);

     while(io_in8(0x03f4) & 0xC0 != 0xC0 ){}
     reza = io_in8(0x03f5);
     sprintf(s, "[H]=%X,",reza);
     cons_putstr0(cons, s);

     while(io_in8(0x03f4) & 0xC0 != 0xC0 ){}
     reza = io_in8(0x03f5);
     sprintf(s, "[S]=%X\n",reza);
     cons_putstr0(cons, s);

     while(io_in8(0x03f4) & 0xC0 != 0xC0 ){}
     reza = io_in8(0x03f5);
     sprintf(s, "Last Code =  %X\n",reza);
     cons_putstr0(cons, s);
   //-------------------------------------------

   //マスタのch2のDMAをマスク */
   io_out8(0x000a, 0x06);



       char *vvv;
       vvv = 0x000a0000;

	for(;;){
	  vvv++;
	  if (vvv == 0x000a002f){break;}
	  sprintf(s,"%02x,",*vvv);
	  cons_putstr0(cons, s);
	}

     sprintf(s, "End...\n");
     cons_putstr0(cons, s);


 
      	timer_free(&timerx);
	return;
}
/*---------------------*/

さて、じゃ、なんで前はうまくいかなかったのか?ってことだけど、

    • 送信コマンドを間違えていた <バカ
    • DMAの設定をイマイチ理解していない

まず、送信コマンド。2のコード見てもらえばわかるよね?。間違ってます・・・orz

さて、次にもう一個。DMACの設定部分。

Kタンのサンプルで一番解らなかったのが、

io_out8(0x0005, 0xff); io_out8(0x0005, セクタ数 * 2 - 1); /* バイト数の設定 */
io_out8(0x0004, 番地 & 0xff); io_out8(0x0004, (番地 >> 8) & 0xff); 
io_out8(0x0081, (番地 >> 16) & 0xff); /* メモリ番地の設定 */

この、セクタ数や番地のこと。

これ、よーく考えてみて初めて意味がわかった。まず、io_out8ってことは、全てのデータは8bitだということ!

そう。8bit。0x00〜0xFF(十進数で256) までしか設定できないわけ。

「え?それじゃ、セクター(512)を設定したり、バッファのメモリ番地を0x000a0000に設定したりはできないの!?」

と、こういう話になりますね?。

ここらへんのレジスタは特殊で、同じレジスタに連続で2回とか書き込むと16bitや20bitと解釈してくれるという。エラク特殊な形なんですねぇ〜。(なーーんだ!)

だから、もう一度上のサンプルを良く見ると、こんなふうに割れませんか?

/* バイト数の設定 */
io_out8(0x0005, 0xff);
io_out8(0x0005, セクタ数 * 2 - 1);

/* メモリ番地の設定 */
io_out8(0x0004, 番地 & 0xff);
io_out8(0x0004, (番地 >> 8) & 0xff); 
io_out8(0x0081, (番地 >> 16) & 0xff); 

そう。こうやって、一見無意味に複数回書き込んでいるのがまさにそれなんです。

さらに!!。セクタ数や番地の後ろにあるヘンテコな計算式。これは、8bit以上になる各数値を自動的に8bitに切り出してくれる計算式なんですねぇ〜。

じゃ、たとえば、セクターを一つだけ。DMAバッファを0x000a0000番地にして読み込みを行いたいとしましょう。

セクター1個は通常512バイト。16進数にすると、0x0200になるよね。で、OS-Wikiの資料によると、

データ転送はDMAのTC(ターミナルカウント)に依存しており、この仕様のために、カウント値は実際の転送量-1をセットする。

とのことなので、ここは 0x0200 - 1 = 0x01FF をセットします。

ほらね!!!

io_out8(0x0005, 0xFF);
io_out8(0x0005, 0x01);  <-  セクタ数(1個) * 2 - 1 = 1なので。

同じくDMAバッファのメモリ番地の設定。DMAバッファは仕様上、0x00ffffff以下でないと設置できません。よーく見て。最大は0xffffffでしょ? つまり、8bit三回分だよね?

今回の例。0x0a0000を設置したいとした場合、こうなる!

io_out8(0x0004, 0x00);   <- 0x0a0000 & 0xff = 0
io_out8(0x0004, 0x00);   <- (0x0a0000 >> 8) & 0xff = 0
io_out8(0x0081, 0x0a);   <- (0x0a0000 >> 16) & 0xff = 0a 

ほらね。こういう書式になるわけ。ちょっと値を複雑にしてみるともっと解るよ。

例:0xa1b2c3 番地を設定したい場合

io_out8(0x0004, 0xc3);   <- 0xa1b2c3 & 0xff = c3
io_out8(0x0004, 0xb2);   <- (0xa1b2c3 >> 8) & 0xff = b2
io_out8(0x0081, 0xa1);   <- (0xa1b2c3 >> 16) & 0xff = a1 

これでもう、解ったでしょ〜? (^^


最終更新: 2024-01-06 (土) 22:39:09 (JST) (110d) by