パスワードを忘れた? アカウント作成

kitune-sanさんのトモダチの日記みんなの日記も見てね。 みんなの日記はここから一覧を見ることができます。

15449860 journal
日記

kitune-sanの日記: 8086マイクロコードの読み方 6

日記 by kitune-san

8086のマイクロコードってどうなんているんだろうと思って調べていたら、メタルレイヤの画像から読み出している人がいてびっくり。
せっかくなのでマイクロコードを読めるように少しだけ調べてみた。
まだ少しだけしか読めていないけれど、自分の備忘録として残しておく。

読んでくれる人がいるかどうか微妙だが…もしも間違いなどを見つけたら忌憚なく教えてほしい。でも優しく教えてね。

理解するのに重要な資料はUS patent 4363091。ここに必要なこと全て書いてあると思う。
ただし、ここに書いてあることが8086/88と完全に一致していない可能性があることを考慮に入れておく必要がある。

前半はCPUのハードウェア的な説明と一部命令の説明が延々と続く。レジスタ、ALU、フラグの関係を理解していれば読む必要がないと思う。最終ページにあるFig.1〜3を必要に応じて参照する。
マイクロコードに関する詳細な記述は、27ページ目(PDFで15ページ目)のTABLE 7の上の「The microcode routines for〜」からである。

マイクロコードは21ビットで構成されている。この21ビットには前半10ビットと後半11ビットとで2種類の操作命令が格納できるようになっている。
ただし今回の説明では、実際のコードやビット配置については追求しない。自分もまだよくわかっていない。
なのでニーモニックから読み取ることを目標とする。

マイクロコードの構成は次のようになっている。
S/D: レジスタやALUとの転送操作を行う。
Typ/a/b/F: 転送以外の操作(ALU操作やアドレスジャンプ)を行う。
つまり、データ転送動作とALU操作(他、操作命令)を同時に行うことができる。

さて、ここまで来たところで実際にマイクロコードを読んでみよう。
読み取る内容はAAA/AAS命令のマイクロコード列である。

 AR  X 7 6 5 4 3 2 1 0 CR S    D      Typ  a    b     F
 ------------------------------------------------------
 AAA 0 0 0 1 1 X 1 1 1 0  A    tempaL  1   XI   tempa
 AAS                   1  ONES tempb   1
                       2  Σ    A       1   DEC  tempb F
                       3               0   XΦ   5
                       4               1   INC  tempb
                       5  X    tempb   0   NCY  7
                       6  Σ    X       4   none RNI
                       7               4   none RNI

うまく表示できないので、等幅のメモ帳に貼り付けるか、US patent 4363091の「TABLE 7」を見てほしい。
テーブルが使えないっぽい。

表のARは外部のROMから読み取られた(ARレジスタに格納された)命令とそのビット列を示している。このARレジスタの値を元にマイクロコードが記述されたアドレスをデコードする。
CRはマイクロコードを進めるたびにインクリメントされるレジスタの値を示している。ジャンプ先の指定などで使用する。結果として相対アドレスに近い感じになっている。

では、いってみよう。

まず最初の命令(CR=0)を読んでみる。S=A, D=tempalとあり、Aレジスタの内容をtempaの下位へコピーする。
次にa=XI, b=tmpaとある。これは、1stオペランドにtmpaを指定したXI操作をALUに指定する。これはType1の指示である。なお、Fig.1bより、ALUの第二オペランドはtempb固定であることがわかる。
(実は、資料の方ではb=temp2と記載があったのだが、temp2なぞここ以外見当たらなかった。リバースエンジニアされた方の資料にはtempaと書かれていたためこちらに差し替えた)

A->tempaL

tempa -> ALU(XI) -> Σ
tempb --/

注意する点として、ALUの操作指示は指示後次のコード読み取りに入ったとしても、別のALU操作指示(TYPE1指示)がくるまではその指示状態が維持されるということがある。これを頭に入れておかないと後のINC/DECで混乱する。

XI命令のALU動作は、Fig.2に示されている。AASの場合のマイナスはどこで指定されるのか記載がなく、実は私の中で疑問が残っているが、とりあえず今回は無視して読み進める。

2つめの命令(CR=1)へ進む。S=ONES, D=tempbとあり、ONESをtempbへコピーする。ONESというのは資料を見た感じでは6のようだ。つまりXI命令の第二オペランドはここで設定される。

ONES(6) -> tempb

tempa -> ALU(XI) -> Σ
tempb --/

3つめの命令(CR=2)へ進む。S=Σ, D=Aとある。これはALU(XI)の演算結果をAレジスタへ格納することを示している。
また、Fのフラグが立っていることが確認できる。これは、ALU(XI)の演算で生じたフラグ変化を記録することを示している。

tempa -> ALU(XI) -> Σ -> A
tempb --/       \-> Σ(F) -> flags

同時に、a=DEC, b=tempbの指示がある。これはtempbのデクリメントを指示する。これによりALUはXIからDECへ切り替わる。

tempb -> ALU(DEC) -> Σ

4つめの命令(CR=3)へ進む。a=XΦ, b=5とある。これはMレジスタの下位ビット---ARレジスタの3ビット目を検査し真であればCR=5まで移動させるというタイプ5の指示である。
3ビット目は一体何かというと、このビットによってAAA/AAS命令のどちらであるかを決定している。

ではまずAAAの場合(XΦの結果が偽であった場合)を考える。

5つめの命令(CR=4)では、a=INC, b=tempbが指定されている。これによりALUはDECからINCへ切り替わる。

tempb -> ALU(INC) -> Σ

6つめの命令(CR=5)では、S=X, D=tempbとある。これは、Xレジスタの内容をtempbの下位へコピーする。

X -> tempb
tempb -> ALU(INC) -> Σ

また同時にキャリーフラグの検査を行う。キャリーフラグは3つめの命令(CR=2)のときに格納したflagsで立つことがある。ざっくり条件を書くと、6を足した(AAAの場合)計算結果が9を超えた場合である。
キャリーフラグが立っていない場合はCR=7まで移動する。CR=7の命令はRNI(Run Next Instruction)となっておりマイクロコードの終了を示す。そうでなければ次の命令へ進む。

7つめの命令(CR=6)では、S=Σ, D=Xとある。これは、これはALU(INC)の演算結果をXレジスタへ格納することを示している。

tempb -> ALU(INC) -> Σ -> X

同時にRNI司令が入り、マイクロコードの実行を終了する。

次に、AASの場合(XΦの結果が真であった場合)を考える。

飛び先の6つめの命令(CR=5)では、S=X, D=tempbとある。これは、Xレジスタの内容をtempbの下位へコピーする。注目する点は、AAAと違いALCがDECの状態が継続していることである。

X -> tempb
tempb -> ALU(DEC) -> Σ

また同時にキャリーフラグの検査を行う。キャリーフラグは3つめの命令(CR=2)のときに格納したflagsで立つことがある。ざっくり条件を書くと、6を引いた(AASの場合)計算結果が9を超えた場合である。
キャリーフラグが立っていない場合はCR=7まで移動する。CR=7の命令はRNI(Run Next Instruction)となっておりマイクロコードの終了を示す。そうでなければ次の命令へ進む。

7つめの命令(CR=6)では、S=Σ, D=Xとある。これは、これはALU(DEC)の演算結果をXレジスタへ格納することを示している。

tempb -> ALU(DEC) -> Σ -> X

同時にRNI司令が入り、マイクロコードの実行を終了する。

以上がAAA/AAS命令のマイクロコードである。他の命令も読めそうな気がしてこない? 読める・・・読めるぞ・・・!

15437636 journal
日記

kitune-sanの日記: SDRAMコントローラをSystemVerilogで書いてみる

日記 by kitune-san

FPGA内部のRAMブロックだけでは今後容量が不足してくると思えるため、DE0-CVに実装されているSDRAM(IS42S16320F-7TL (32Mx16))へアクセスするコントローラを作ることにした。

最初は、CPU側からのアクセスのみを考えていて、シングルモードの読み書きで問題ないと考えていた。
しかし途中でビデオメモリとの共用をしたくなってきた。共用すると速度の問題からVRAM用のキャッシュが必要となり、複数バイトの連続読み出しが必要になった。
出てきた案は、
1. バースト書き込み, バースト読み出しモードを使用する。
2. シングル書き込み, バースト読み出しモードを使用する。
3. シングルの読み書きモードとし、ACK後にREAD/WRITEコマンドを連続して送信する。(毎回バンクとCOLアドレスを指定)

1の案は、バーストの読み出し回数が固定の上、書き込みは1回としたいため、廃案にした。
2の案は、当初最有力であったが、バーストの連続読み出し回数が最大8回であることと、後に3のアクセス方法を見つけたため、廃案とした。
3の案は、読み書き回数が都度指定可能で、さらに8回以上(最大1023回)連続読み出しができるのでこれを採用した。なんかデメリットがあるかもしれないけど、とりあえずこれで進めた。

で、作ったのがこれ
まだ実際にFPGAに書き込んで動作は見ていない。どうやって確認しようか考え中。シュミレータで信号の確認はした。

使い方は次のようにした、
1. アクセスをしたいアドレス(address)、連続アクセス回数(access_num)、(書き込みの場合は)1バイト目の書き込みデータ(data_in)をセットする。
2. 読み書きどちらかの要求フラグ(write_request/read_request)を立てる。

書き込みの場合
3. 書き込み確認フラグ(write_flag)が立ったことを確認したら、要求フラグを下げ、次の書き込みデータをdata_inにセットする。
4. write_flagが下がるまで、次の書き込みデータをdata_inにセットし続ける。

読み取りの場合
3. 読み取り確認フラグ(read_flag)が立ったことを確認したら、要求フラグを下げ、data_outからデータを取得する。
4. read_flagが下がるまで、次の読み取りデータをdata_outからデータを取得する。

注意点として、colアドレス(IS42S16320Fの場合アドレス末尾10バイト)と書き込み回数とを足した結果が、colアドレスのアドレス表現を超える場合には、
書き込み/読み取り途中でアクセス先が折り返される。
また、読み書き処理中に、address, access_numは、変更禁止である。

---

CPU(XTバス)からの読み書き要求とビデオコントローラからの読み取り要求の調停処理は、このコントローラより上のレイヤで作製しようと思う。

15432398 journal
日記

kitune-sanの日記: PC/XTのREADY信号 2

日記 by kitune-san

PC/XTの回路図SystemBord(2/10)は、ざっくり分けると
1. READY信号の生成(nRDY/WAIT, RDYTODMA)
2. DMA要求発生時の信号生成 (HLDA, AENBRD, /AEN, DMAWAIT, /DMAEN)
3. NMI信号生成
4. I/OCHECK信号生成
5. DMA用クロック信号生成(H幅の伸張) (DCLK)
に分かれると思うのだけれど、この内「1. READY信号の生成」がわかりにくくて理解するのに時間がかかってしまったため忘れる前にメモする。というか今でもあれ?となる。

まず、nRDY/WAIT信号は8284のnAEN1に入力される信号で、CPUへ送信するREADY信号を生成するために使用される。nRDY/WAIT=HでREADYはLOW(CPUはT3->Twステート)となる。
nRDY/WAIT信号は一つのフリップフロップから出力される。このFFのトリガはクロックではなく下記のの信号の論理の組み合わせとなっている。
¬/XIOW + ¬/XIOR + (/DACK0BRD ・ ¬/XMEMR ・ AENBRD)
※ AENBRDはLのときアドレスイネーブルとなることに注意
上記の入力がL->Hとなると、nRDY/WAIT=Lとなる。ただし、後述のCLR信号により、CPUクロックの立ち上がりエッジでHにもどる。
FFのPRにはI/OCHRDYが、CLRにはnRDY/WAITを入力としたもう一つのFF(クロック立ち上がりエッジ)の出力/Qが接続されている。
I/OCHRDY信号はバスを通して外部から制御でき、適切なアクセスタイミングでLOWに落とすことで外部のカードからREADY信号を要求することができる。

以上の情報から、nRDY/WAIT信号が発生する条件は以下のタイミングとなる。
1. I/Oアクセス直後 (/XIOWまたは/XIORが、H->Lとなった時)
2. 外部のカードがREADY要求している。
3. DACK0以外のDMAアクセス発生時 (・・・多分)

1,2はわかりやすいと思うのだけれども、3についてはわかりにくいと思う。そもそも、DMAの信号でも、/XIOWか/XIORどちらかがLとなるから(/DACK0BRD ・ ¬/XMEMR ・ AENBRD)いらなくね?と1日中考えていた。
それで、8237のデータシートを見ていたら、8237の書き込み信号は拡張設定をしなければ読み取り信号が出力されるタイミングよりも1クロックずれるということに気がついた。
つまりこの設定がなければ、/XMEMR=L, /XIOW=LのDMA動作の場合に本来8237がほしいタイミングでREADY信号(REDYTODACK)が来ないことになる。これを回避したかったのだろう。…ということで納得することにした。
DACK0を除いたのは、DACK0はDRAMリフレッシュですでに使用されており、不要だったのだろう。

で、これをFPGAで動かせるように実装してみたいと思ったのだが、FFのトリガがクロック以外であることに気が付き困ってしまった。
FPGAを最初に触った時、クロック以外の信号をトリガに入れまくってよくわからなくなったトラウマがあるため避けたい。少なくとも(どっちのエッジでもいいからとりあえず)クロック同期にしたかった。
で、アイディアとして8284内部の立ち上がりエッジのFFを取り出し(イメージ的にはこれをCLR信号のFFと統合して)、オリジナルのnRDY/WAIT信号生成FFを置き換えできないかと考えた。
で、作ったのがこれ。シュミレータで見た感じは思い通りになっている・・・と思う。

15425876 journal
日記

kitune-sanの日記: 8237をSystemVerilogで書いてみる #2 (終)

日記 by kitune-san

前回から、新しく2つのブロックを追加した。
KF8237_Address_And_Count_Registers.sv - アドレスレジスタと現在カウントレジスタの計算を行うブロック。
KF8237_Timing_And_Control.sv - DMA制御のための信号出力を行うブロック。
これらを配線し、KF8237.svを作成した。
実のところ、すべての実装が完了しているわけではなくメモリ間転送については未実装のままとなっている。途中まで忘れていた。現状欲しい機能は実装できているのでとりあえず終了する。

・・・これでPC/XTを構成する主要なチップを、CPUを除いてFPGAで実装することができた。次はラスボス(8088)だ。
mod r/wとかややこしいし、8080からやったほうがいいのかなぁ。

15416473 journal
日記

kitune-sanの日記: 8237をSystemVerilogで書いてみる #1

日記 by kitune-san

8237AはDMAのチップだ。

ここまでで2つのブロックを作成した。
KF8237_Bus_Control_Logic.svは、内部バスの書き込み/読み取り信号を生成するブロック。
KF8237_Priority_Encoder.svは、DMA要求の優先度解決と優先度の回転を行うブロック。

優先度の回転処理は、KF8259と同じで、
ビット右回転→優先度解決→ビット左回転 という手順となっているが、もっといい方法があるような気がする。

オリジナルのデータシートのブロック図は自分にはわかりにくくて、そのまま真似して実装できそうになかった。
「PRIORITY ENCODER AND ROTATING PRIORITY LOGIC」からは、外部信号としてDACQ0-3、HLDA、HRQ、DACK0-3が出ているけど、
今回のKF8237_Priority_Encoder.svでは、DACQ0-3入力以外の信号処理は作らなかった。

次は、ステートマシンとモードに応じた信号の出力ブロックを作っていいこうと思うが、どんな構成にしようかな・・・。

15393402 journal
日記

kitune-sanの日記: PC/XTのDMAとDRAMリフレッシュ 4

日記 by kitune-san

8237AをSystemVerilogで書き始めるにあたって、
理解がおざなりになっていたDMAとDRAMについて調べた。
回路図とデータシートを眺めてわかってきたことのメモ。

PC/XTのDMAには8237Aが使われている。
DMA0がDRAMリフレッシュに割り当てられており、その他のDMA1-DMA3はXTバスを通して外部から使用できるようになっている。
8237Aへのクロックは8284AのCLKから直接接続されておらず、ディレイラインと若干ややこしいゲートを通って供給されている。これはクロックのHIGH時間を長くするように働く。
調べていくうちに、どうやら8237Aの制約によるものらしいことがわかった。8237Aへ供給するクロックのTCHおよびTCLはそれぞれ80nsと67ns以上にする必要があり、
4.77MHzの周期の1/3の時間の69.88nsのHIGH出力では、使用条件を満たすことができないからである。

DRAMリフレッシュは、インターバルタイマ8253のタイマ1で生成される周期で実施される。インターバルタイマのOUT1はDMAのDREQ0に接続されている。
DMA0を受け付けるとDACK0が出力される。DACK0信号は、DRAMの/CAS=H,/RAS=L(アクティブ)にする。
webを巡回して、Wikipediaのメモリリフレッシュの項目を見つけた。どうやらRAS only リフレッシュというものっぽい。
RAS onlyリフレッシュである場合、行アドレスを与える必要がある。おそらくブロック転送モード/読み取り転送モードで動作するようになっていると思う。
最初はベリファイ転送モードで動作するかと思ったが、/XMEMRか/XMEMWをLOWにしないとアドレス選択信号ADDRSELが出力されない。DRAMへアドレスを入力する必要があるならば、読み取り転送モードにしなければならないように思う。
なお、DMA転送中(HRQ=H)は、/AEN=Hとなるため/IOWがLOWとなってもメインボード上のIOが書き込まれる心配はない。
ただまあ、ここらへんの動作や設定が実際どうなっているか答え合わせをするにはBIOSのコードを見てみないとわからない。

2021/8/25 追記
ADDRSELを出力しなければいけないと書いたが、列アドレスを指定する必要がないため不要だった。
/XMEMRをアクティブにすることが読み取り転送モードにする理由だろう。
nekopon様のコメントにある資料より、新しいことが分かった。
まず、ブロック転送モードではなく、シングル転送を15usの周期で行っているようだ。
そして転送毎にアドレスをインクリメントしており、リフレッシュをするDRAMの行アドレスが0,1,2…255,0,1…と切り替わるようになっている。
転送アドレス自体は、0H~FFFFHであるが、行アドレスは8ビットのため0~255を繰り返す。FFFFHをロールオーバーすると自動初期化設定により再度0から始まる。
(/XMEMRをアクティブにするため、上位8ビットも行アドレスとして送信されるように思えるが、特に問題ないのだろう)

15355475 journal
日記

kitune-sanの日記: MMCへのアクセスをSystemVerilogで書いてみる #4

日記 by kitune-san

前回の続き
BotWやり始めたら止まらなくなってしまい、2.5周間ぶりの更新。

ついに書き込みができるようになった!

前回から変更したコードは主にKFMMC_Controller.sv
書き込み用のステートと各ステートでの信号処理を追加した。あとバグ修正を少々。

動作確認としてSDカードに次のような2ブロック(1024バイト)の書き込み処理を行い、実行。
その後書き込んだカードを前回作成したブロック読み取りを使って読み出しを行った。結果「01 02 03 ・・・ FE FF 00」と意図通り、書き込んだデータが出力されたことを確認した。

とりあえずカードへのアクセスはできるようになったので、8bit-ISAからアクセスできるようにするというフェーズへ進む。
構想は#1に書いたとおり、uPD765ライクなアクセス方法を描いている。

ところで、eMMCをmicroSDのスロットに変換する基板でいいのないかな。
digi-keyにいいのあった!と思ったけどICモジュールのほうが在庫なしなんだよね・・・。BGAなんてはんだ付けしたくないしなぁ。
ウォッチ用メモ
https://www.digikey.jp/product-detail/ja/seeed-technology-co-ltd/103990443/1597-103990443-ND/10385089
https://www.digikey.jp/product-detail/ja/seeed-technology-co-ltd/112990087/1597-112990087-ND/10385091

15336368 journal
日記

kitune-sanの日記: MMCへのアクセスをSystemVerilogで書いてみる #3

日記 by kitune-san

以前の続き

512バイトごとのブロックリードができるようになった。
主な変更はKFMMC_Controller.svにCMD17以降の動作と制御信号を追加した。
他、細かい修正をしている。

確認としてテストコードを作成し、ラズパイに入っていたSDカードの先頭1024バイトを読み出してみた。
読み出し結果の出力は以前作成したKFTVGAを使用する。

結果はこんな感じ
フォントが詰めっつめで見にくい。機会があれば直す。

細かいデータの確認は眠たくて、まだできてていない。明日やる。511,512バイト目の0x55 0xAAが読めてるので多分できてるんじゃないかな。(雑

次はブロック読み出しだ。

15331974 journal
日記

kitune-sanの日記: MMCへのアクセスをSystemVerilogで書いてみる #2 2

日記 by kitune-san

以前の続き。
とりあえず、ネイティブモードでカードを認識して、ブロック読み取り/書き込み直前の状態まで持っていくことができた。

ChaNさんのMMC/SDCの使いかたとねむいさんのSTM32F7を使ってみる10 -いにしえのマルチメディアカードを動かす(うごかす編)-と公開コードがすごく参考になりました。感謝。

追加したモジュール
- KFMMC_Command_IO.sv - コマンドの送信とレスポンスの受信
- KFMMC_Data_IO.sv - データの送受信
- KFMMC_Controller.sv - MMCへのアクセス制御(途中)
- KFMMC_Drive.sv - 上記のモジュール達や以前作成したモジュールを配線したもの

エラー処理とかいろいろ雑なところがあると思うけど、とりあえず置いておいて、
次のようなTOPモジュールを作成しSDカードを挿したDE0-CVに制作物を書き込み、tran状態まで進むことができた。
次はブロック読み取りの実装の予定。

15304583 journal
日記

kitune-sanの日記: MMCへのアクセスををSystemVerilogで書いてみる #1

日記 by kitune-san

8bitのISAのインターフェースからから身近にある記録媒体ににアクセスしてみたいと思い、
比較的簡単そうな、MMCやその互換カードへのアクセスをするデバイスを実装してみることにした。

まずは、MMCと通信する部分を作成した。
最初SPIで実装してカードの初期化まで行けたが、今後eMMCへのアクセスをすることを考えネイティブモードで再度作成した。
ネイティブモードで作成する上で課題となったのは以下の点
1. SPIモードと違い、8ビットごとの通信でなくスタートビットを起点として送受信を行う。
2. DATラインの先頭/末尾データは、スタート/ストップビットを含めると9ビットとなる。
3. CMDのレスポンス受信処理と、DATのデータ受信処理が同時に行われる。
4. 通信データにCRCを付加する必要がある。

これを解決するために、以下の動作とした。
1. 停止中にstart_communication=1のパルスを入力すると通信を開始する。
2. 〜_ioで送受信方向を設定する。1で受信、0で送信。
3. check_〜start_bit=1で受信開始すると、スタートビットの検出を開始する。クロックの立ち上がり時にCMD=0でコマンド受信を開始する。クロックの立ち上がり時にDAT=0でデータ受信を開始する。
4. set_send_〜=1で送信開始すると、送信データに格納されたデータの送信を開始する。
5. 送信/受信どちらかのイベントが発生するとそれに対応したイベントの〜_interrupt=1が発生し、通信を停止する。start_communication=1パルスの入力でイベントを解除し、続きの動作を行う。
6. コマンドの送受信データ8ビットには、ストップビットとデータビットが含まれる。
7. データの送受信データ8ビットには、ストップビットとデータビットが含まない。最初の送信データに0xFE(スタートビット), 最後の送信データに0xFF(ストップビット)を付加する。
8. 送受信中に各データのCRC計算を行い、読み出せるようにする。clear_〜_crc=1でCRCを0にクリアする。

次の目標はこのモジュールを使用して、MMCの初期化を行う。

また、読み書きの命令は、uPD765的な方法(コマンドー>実行(割り込みorDMA)ー>ステータス読み取り)でできないか考え中。
ただし、uPD765と全く互換にはせずに以下のようにすることを想定
- CHS的なアクセスだと計算が面倒な上にアクセスできる領域に制限がかかるためLBAアクセスに変更する。
- アクセスコマンドは、write,readのみ。
- アクセスできるブロックサイズは512バイト固定にする。DMA転送で途中にT/Cが入る場合には。割り込み転送に切り替えるようにする。

typodupeerror

「毎々お世話になっております。仕様書を頂きたく。」「拝承」 -- ある会社の日常

読み込み中...