PIC32MXで作るMZ80エミュレータ(VGA出力)の製作 2022.7.25


    1.はじめに
    以前に製作したエミュレータです。
    NTSCで映像出力します。

     約9年前(2013.11.3)にMZ-80エミュレータを製作しました。 この時は、ブラウン管式のアナログTVに映し出せるようにNTSC信号で映像を出力しました。

     現在では、アナログ放送も終了しブラウン管TVも無くなってしまいました。そこで、パソコンのディスプレーに映し出せるように、VGA(640x480ドット)で映像出力するエミュレータを製作してみました。

     前回はランニングエレクトロニクスで販売されている'SBDBT32'マイコン基板を使いましたが、マイコンのピン割り当ての都合で、'REPIC32SD'という別の基板を使いました。こちらの基板は、 簡易ドライブレコーダの製作で一度使ったことがあります。


    今回製作したVGA出力版
    前回と同じプラケースに収めています
    VGAコネクタは中古のビデオカードからの流用です。
    基板やコネクタが大きいのでマイクロスピーカー(写真右上)を採用しました。
    USBキーボードは無線式です。
    4GBのSDカードを使いました。
    ケース裏側です。

    2.使い方

     前回製作したエミュレータと同様、SDカードにエミュレータの動作に必要なモニターROMやCGーROMのファイルを格納しておきます。

     エミュレータとディスプレーをDサブミニ15ピンのVGAケーブルで接続します。USBコネクタにUSBキーボードを差し込み、+5VのACアダプタをVGAコネクタの横にある電源ジャックに接続します。

     本体が正常に動作すると、ディスプレーに、モニターの起動開始画面が表示されます。左右上下の表示位置がずれている場合にはディスプレー側で調整を行います。

     これ以降の操作については、前回製作のエミュレータと同じです。詳細は、前回の製作記事を参考にしてください。


    3.製 作

    3−1 回路

     回路は右の通りです。'REPIC32SD'基板の回路そのものではなくそれと等価な回路で描いています。

     基板は異なるもののマイコンチップは前回と同じ'PIC32MX695H512H'です。回路やピン割り当てはほとんど前と同じです。PICのファームウエアも映像出力を除いて前の物をそのまま流用しています。

     NTSCの出力では、水平同期信号と垂直同期信号は複合されているので1ピンの割り当てで済みましたが、VGAの出力では、水平同期信号と垂直同期信号は分離されているので2ピンの割り当てが必要となりました。

     ビデオの映像信号については、VGAでは、本来、RED(赤),GREEN(緑),BLUE(青)の3色を必要とするのですが、MZ-80ではモノクロ表示ですので、RGBのG(緑)だけ出力することにします。これにより、映像信号の出力処理は、VGAにおいてもNTSCの時と同じ考えで製作出来ます。

     ファームウエアは、MPLAB IDE で c32 Cコンパイラーで作成しました。プロジェクトファイル一式はこちらです。


    3−2 VGA信号の生成

     VGAの信号は次のように作成しました。タイマー2(T2)と出力比較モジュール1(OC1)を使って同期信号を生成、映像信号は SPI3 で出力しました。

     タイマー2のクロックを40MHzに設定します。水平同期信号は、31.469KHz ですので、その周期は、40MHzクロックで換算すると1271クロック(40MHz/31.469KHz=1271)となります。

     水平同期パルスのパルス幅は4μsec ですので クロック換算で160クロックです。タイマー2と出力比較モジュール1(OC1)の設定を次のように行って、その出力ピン RD0 から水平同期信号を出力しました。

    
        // timing parameter
        #define H_LINE_CPS     1271   // 40MHz/31.469KHz=1271
                                      // 40MHz/1271=31.471KHz
                                      // (1/40MHz)*1271=31.775usec
        #define H_SYNC_CPS     160    // (1/40MHz)*160=4usec
    
        // set Timer2
        T2CON = 0x0010; // prescale 1:2 40MHz
        TMR2 = 0;
        PR2 = H_LINE_CPS-1;
    
        // set OC1(RD0) for Horizontal sync signal
        OC1CON = 0;
        OC1R = H_SYNC_CPS;
        OC1RS = PR2;
        OC1CONbits.OCM = 0b101; // continues pulse 
    
    

     次に垂直同期信号ですが、こちらはタイマー2の割込み処理で、出力ピン RD10 をトグルすることで生成しました。水平走査1回毎に割込みが発生しますので水平走査線数 525 本毎に垂直同期信号を作ります。

     具体的には フロントポーチ区間、垂直同期パルス区間、バックポーチ区間、映像表示区間、の4区間(ステート)に分割して、VGA信号全体の生成を行っています。

     映像表示区間においては、OC2Rをクロックカウンターとして動かし、OC2Rの割込み処理の中でSPI3の送信割込みを許可し、映像信号を出力するようにしています。、

    
        // 垂直同期ステートにより分岐
        switch(VState){
        case ST_V_BP:            // バックポーチ区間
        case ST_V_FP:            // フロントポーチ区間					
            V_SYNC_OUT = 1;
            break;
    
        case ST_V_SYNC:          // 垂直同期パルス区間
            V_SYNC_OUT = 0;
            break;
    
        case ST_V_SIGNAL:        // 映像表示区間
    	if(v_gate){
                OC2R = H_SYNC_CPS; // + H_BP_CPS; // 映像開始までの遅延(SPI3の送信開始遅延を考慮)
                OC2CON = 0x8001;   // ワンショット L->H
            }
    
            if((Line & 0xF) == 0){
                Lptr = VPtr; // saved begin address of line
                LrvsPtr = VrvsPtr;
            }else{      
                VPtr = Lptr; // restore begin address of line
                VrvsPtr = LrvsPtr;
            }
            cgrom=cgROM[((Line++)>>1)&0x7]; // set read line
            break;
        }
    
    

     解像度についてです。VGAは 640x480ドットですが、MZ-80は、320x200ドットです。640ドット表示の映像信号のクロック周波数は25.175MHzですが、この約半分の13.333MHzのクロックでSPI3を動かし、320ドット表示にしています。、

     縦は水平走査2ラインで文字の縦1ドットを表示するようにしました。これで縦25行の文字表示に水平走査 400ラインを使います。残りの80ラインは、フロントポーチ、バックポーチに含めました。

     詳細は、ソースコードvideo_vga.cを参照ください。

     VGA出力の確認は、ディスプレーの調整画面にて確認しました。その時の様子が下の写真です。

     
    VGA出力の確認
    VGA出力テスト中
    ディスプレーの調整画面
    640x480 31.5KHz/59.9Hz
    の出力が確認出来ました。

    3−3 VGA表示例

     実際にVGAで表示したのが下記の写真となります。

    VGAでの表示
    ROM-モニター起動画面
    SDカードのファイル一覧表示
    枠も綺麗に表示出来ている
    スペースインベーダー
    スターウォーズ

     MZ-80のカセットテープ読み出しのエミュレートではSDカードに格納されているファイル一覧をメニュー表示するのですが、前回の製作ではメニューの枠の表示がずれる不具合がありましたが今回は修正しています。