FC2カウンター FPGAの部屋 VGAコントローラ
fc2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

キャラクタ描画テスト回路のインプリメント1(TIG制約)

前回、キャラクタ描画テスト回路のシミュレーションを行ったので、今度はインプリメントをしてみた。
最初にDDR2 SDRAMのバーストテストの時のUCFを貼りつけて、VGA出力などの足りないところはSpartan3A Starter Kitのユーザーズガイドから持ってきてUCFを完成させた。それでインプリメントしたところ、最初にVGA信号用のDCMとDDR2 SDRAM用のDCMを同じクロック入力パッドから入力していたので、片方のクロック配線が一般配線に回ってしまうというエラーが出てしまった。これは、DDR2 SDRAM用のDCM出力 (BUFG出力) からVGA信号用のDCMのクロック入力につなぐくことにして問題解決。
次に入力クロックの周期だが、20nsecでは到底メットしないとのエラーが出て、Place & Route(以下P&Rと省略)でエラーで止まってしまう。幾つか値を入れたところ100nsecでやっと通って、インプリメントが成功した。全くもっておかしいので、P&R後のタイミング解析結果を見てみたところ、非同期FIFO のclk_vga(65MHz予定クロック)ロジックからclk_ddr2(150MH予定クロック)ロジックまでの非同期FIFO のパスを解析してしまっている。
Bitmap_VGAC_implement_1_100213.png

これは、2つのクロックを使用するロジック間のパスのTIG制約を加える必要がある。以前に、”UCFの書き方3”で説明したことがあるが、今度はConstraints EditorからTIG制約を追加してみようと思う。それでは制約を追加しよう。
Project NavigatorのProcessesペインのUser ConstraintsからCreate Timing Constraints をダブルクリックする。
Bitmap_VGAC_implement_2_100213.png

Constraints EditorがProject Navigator上に表示されるので、左のConstraints TypeからGroup ConstraintsのBy DCM Outputsを選択して、DCM/PLL/MMCM 出力ピンごとの制約のグループ化を行うことにする。double click to add a new constraints... をダブルクリックすると、Group Constraints by DCM/PLL/MMCM Outputs (TNM)ダイアログが出てくる。
Bitmap_VGAC_implement_3_100213.png

ダイアログのTime name を入力して、VGAクロック用のDCMを選択する。Available output net pins: リストからCLKFXをクリックで選択して、AddボタンでOutput net pin targets: リストに追加する。(VGA用クロックはCLKFXで作っている)Createボタンをクリックして、制約を生成する。
Bitmap_VGAC_implement_4_100213.png

同様にDDR2_CLKの制約を生成する。
Bitmap_VGAC_implement_5_100213.png

2つのグループ制約が生成できた。
Bitmap_VGAC_implement_6_100213.png

次にTIG制約を生成しよう。
左のConstraints TypeからTiming ConstraintsのExceptionsのPathsを選択する。右の1ライン目を右クリックして、右クリックメニューからCreate Constraints を選択する。
Bitmap_VGAC_implement_7_100213.png

Path Exceptionsダイアログが表示される。TIMESPEC nameにTS_VGA2DDR2_CLK_TIGを入力して、Time groupsにFrom group:にVGA_CLK_OUTPUTを選択し、To groups:にDDR2_CLK_OUTPUTを選択する。Constraint typeでMark as false pathsのラジオボタンをクリックする。Createボタンをクリックする。これでVGA_clkで動作するロジックからDDR2_clkで動作するロジックへのパスを無視する設定をすることができた。
Bitmap_VGAC_implement_8_100213.png

次に、DDR2_clkで動作するロジックからVGA_clkで動作するロジックへのパスを無視する設定をする。これが出来上がり図。
Bitmap_VGAC_implement_9_100213.png

これでセーブして、UCFファイルを見てみると、下のような制約が付加された。

PIN "dcm_DDR2_VGA_clk_i/dcm_VGA_clk_dcm.CLKFX" TNM = VGA_CLK_OUTPUT;
PIN "ddr2_sdram_cont_i/dcm_module_inst/DCM_INST1.CLK0" TNM = DDR2_CLK_OUTPUT;
TIMESPEC TS_VGA2DDR2_CLK_TIG = FROM "VGA_CLK_OUTPUT" TO "DDR2_CLK_OUTPUT" TIG;
TIMESPEC TS_DDR22VGA_CLK_TIG = FROM "DDR2_CLK_OUTPUT" TO "VGA_CLK_OUTPUT" TIG;


これで、入力クロックの周期制約をもう一度、20nsecにしてインプリメント。P&Rの途中でけられることはなくなった。良かった。やはり、上記のパスが原因だった。しかし、タイミングエラーはまだある。
  1. 2010年02月13日 10:00 |
  2. VGAコントローラ
  3. | トラックバック:0
  4. | コメント:0

キャラクタ描画テスト回路のシミュレーション

大体、キャラクタ描画テスト回路のシミュレーションが終了した。
キャラクタ描画テスト回路の構成図を下に示す。
Char_Draw_Test_1_100201.png

関連する資料
Spartan3A Starter KitのビットマップVGAコントローラの仕様1
Spartan3A Starter KitのビットマップVGAコントローラの仕様2
キャラクタ生成コントローラの仕様
キャラクタ生成コントローラの仕様2



キャラクタ描画テスト回路の主なモジュールのシミュレーション波形を下に示す。
Bitmap_VGAC_debug_2_100211.png

ビットマップVGAコントローラについては、”ビットマップVGAコントローラのデバック1”で説明済みだ。
DDR2 SDRAMはDDR2 SDRAMコントローラの出力だ。上に書いてあるREADがビットマップVGAコントローラのDDR2 SDRAMのRead、WRITEがキャラクタ生成コントローラのWriteを表す。Writeを見ると間が空いているのがわかると思うが、これは、キャラクタを描画する際のドットの行が変わるときに、VRAMアドレスが不連続となるためだ。WRITEの時に下のChar_Graphic_Processorを見ると、動作しているのが確認できる。よく見ると間が空いているのがわかると思う。これは非同期FIFOにDDR2 SDRAMへのWriteを積んでいくが、ビットマップVGAコントローラがDDR2 SDRAMを使用しているため、非同期FIFOがFULLになるとWaitするためだ。ビットマップVGAコントローラがDDR2 SDRAMの使用を終了すると、アービタからのGRANTがアクティブとなって、キャラクタのビットをDDR2 SDRAMに書き込んでいく。この後のキャラクタの書き込みは、1秒間に20キャラクタ書く予定なので、50ms後となり、現在のシミュレーション時間では見ることが出来ない。

本当はもっとCとのインターフェースを作って、表示を確認するシミュレーションをすれば良いのだろうが、シミュレーション時間も半端ないだろうし、これで大体、シミュレーションは終了として、次はインプリメントに移ることにする。
  1. 2010年02月11日 19:21 |
  2. VGAコントローラ
  3. | トラックバック:0
  4. | コメント:0

ビットマップVGAコントローラのデバック1

ビットマップVGAコントローラをデバックしている。大体動作してきたと思う。
下にシミュレーション波形を示す。
Bitmap_VGAC_debug_1_100209.png

vram_addressが読んでくるVRAM(DDR2 SDRAM)のアドレスを示す。読んでくる時にカウントアップされている。vram_req_weはアービタへのVRAMのリクエストを書き込む信号。リクエストしたVRAMアドレスのデータがvram_data_inにでてきて、その有効はvram_data_validによって示される。
cs_rdgステートマシがビットマップVGAコントローラの描画データの読み込み状態を示す。最初にidle_rdgになっているが、リセットが外れたら、init_full_modeになって、描画データを貯めておくpixel_async_fifoをFULL状態になるまで、アービタにリクエストを出す。リクエストがDDR2 SDRAMコントローラに届いて、VRAMにある描画データを読み込みpixel_async_fifoがFULLになったら、cs_rdgステートマシンはwait_half_full状態に移行し、pixel_async_fifoが描画データを吐き出して、半分になるのを待つ。半分になったら、cs_rdgステートマシはreq_vram_burstステートに移行し、pixel_async_fifoの容量半分をアービタにリクエストをだして、描画データを読んでくる。
最初に、pixel_async_fifoがFULLになってから、描画もスタートする。これは、cs_rdgステートマシがinit_full_modeからwait_half_full状態に移行したときにh_countのカウントが始まることでわかると思う。今のところ、動作的にはうまく行っているようだ。ちなみにDDR2 SDRAMから読んでくるデータはまだ、書き込んでいないのでXとなってしまっている。
pixel_async_fifoがFULLから半分になるのが2.672usec、req_vram_burstステートに移行して描画データを読んでから、もう一度req_vram_burstステートに移行するまでの時間は1.541usecだった。最初は描画が止まっているので、長い時間になっている。req_vram_burstステートでは、ちょうどpixel_async_fifoの容量の半分のデータをアービタにリクエストしているが、もう少し増やそうと思う。
  1. 2010年02月09日 05:44 |
  2. VGAコントローラ
  3. | トラックバック:0
  4. | コメント:0

キャラクタ描画テスト回路の経過1(エラー出まくり)

キャラクタ描画テスト回路を一応、Verilogコーディングし終えて、デバックをしているがエラー出まくり。
現在のProject Navigatorの様子を下に示す。こんな感じの階層になっている。
Char_Draw_Test_2_100203.png

今出来なくて悩んでいることがある。それはparameterでビット幅を定義することだ。defineでビット幅を定義できることは知っているのだけど、parameter ではできないのだろうか?

parameter DECODE_ADDRESS_LENGTH = 4; // デーコードするアドレス長、上のビットから何ビットデーコードするか。

parameter CHAR_GEN_CONTROLLER_ADDR = DECODE_ADDRESS_LENGTH'hF; // キャラクタ生成コントローラのアドレスマップ
parameter DDR2_SDRAM_ADDR = DECODE_ADDRESS_LENGTH'h0;

cpu_address <= {CHAR_GEN_CONTROLLER_ADDR, (DECODE_ADDRESS_LENGTH-8)'d4, 4'd0};
cpu_address <= {CHAR_GEN_CONTROLLER_ADDR, (32-(DECODE_ADDRESS_LENGTH+4))'d4, 4'd0};


上の例がエラーになってしまう。どうやって書くかを検索中。

(たっくさんの最初のコメント後に修正)
上に書き写したVerilogソースが間違っていたので修正しました。すみません。
つまり、DECODE_ADDRESS_LENGTH, CHAR_GEN_CONTROLLER_ADDR, DDR2_SDRAM_ADDRのパラメータを別のインクルードファイルにしておいて、お手軽にすべてのVerilogソースのアドレスデコードのビット幅を変化させたいということです。やってみたのですが、DECODE_ADDRESS_LENGTH'hFとかは書けないみたいです。つまりビット幅の所にパラメータで定義した値を書けないのかな?ということです。
これだと上の3行のシンタックスチェックが通るのはやってあります。(cpu_address = ... は確かめていない)

`define DCODE_ADDRESS_LENGTH 4 // デーコードするアドレス長、上のビットから何ビットデーコードするか。

parameter CHAR_GEN_CONTROLLER_ADDR = `DECODE_ADDRESS_LENGTH'hF; // キャラクタ生成コントローラのアドレスマップ
parameter DDR2_SDRAM_ADDR = `DECODE_ADDRESS_LENGTH'h0;

cpu_address <= {CHAR_GEN_CONTROLLER_ADDR, (32-(`DECODE_ADDRESS_LENGTH+4))'d4, 4'd0};


#今度は大丈夫かな?心配になってきた。。。

(2010/02/04追記)
上の最後の行はエラーになると、たっくさんに教えていただいた。たっくさん、ありがとうございました。
結局、このように書き直した。

parameter DECODE_ADDRESS_LENGTH = 4; // デーコードするアドレス長、上のビットから何ビットデーコードするか。

parameter CHAR_GEN_CONTROLLER_ADDR = 4'hF; // キャラクタ生成コントローラのアドレスマップ
parameter DDR2_SDRAM_ADDR = 4'h0;

cpu_address[31:31-(DECODE_ADDRESS_LENGTH-1)] <= CHAR_GEN_CONTROLLER_ADDR;
cpu_address[31-(DECODE_ADDRESS_LENGTH):4] <= 4;
cpu_address[3:0] <= 4'd0;


ついでに、アドレスマップを定義するAddress_Map_Define.vhを下に示す。

// Address_Map_Define.vh
// アドレスマップを定義する

    parameter DECODE_ADDRESS_LENGTH = 4; // デーコードするアドレス長、上のビットから何ビットデーコードするか。
    
    parameter CHAR_GEN_CONTROLLER_ADDR = 4'hF; // キャラクタ生成コントローラのアドレスマップ
    parameter DDR2_SDRAM_ADDR = 4'h0;


次に、キャラクタ生成コントローラのコマンド、ステータスレジスタのマップを表すCommand_Status_Define.vhを示す。

// Command_Status_Define.vh

    // Command Registers
    
    // 0番地の割り当て
    parameter CHAR_CODE_UPPER_HIGH        = 31; // キャラクタ・コードの上位バイト
    parameter CHAR_CODE_UPPER_LOW        = 24;
    parameter CHAR_CODE_LOWER_HIGH        = 23; // キャラクタ・コードの下位バイト
    parameter CHAR_CODE_LOWER_LOW        = 16;
    parameter NOT_PAINTED_BACKGROUND    = 15; // 0 - 文字の背景を塗りつぶす, 1 - 文字の背景を塗りつぶさない
    parameter DRAW_IMMEDIATELY            = 14; // 0 - 8番地の書き込みを待つ, 1 - 0番地の書き込みだけで描画
    parameter RED_FEILD_HIGH            = 11;
    parameter RED_FEILD_LOW                = 8;
    parameter GREEN_FEILD_HIGH            = 7;
    parameter GREEN_FEILD_LOW            = 4;
    parameter BLUE_FEILD_HIGH            = 3;
    parameter BLUE_FEILD_LOW            = 0;
    
    // 4番地の割り当て
    parameter MAGNIFICATION_HIGH        = 15; // 拡大倍率
    parameter MAGNIFICATION_LOW            = 11;
    // Red, Green, Blue の割り当ては0番地と同じ
    
    // 8番地の割り当て
    parameter VRAM_START_ADDRESS_HIGH    = 31;
    parameter VRAM_START_ADDRESS_LOW    = 0;
    
    // Status Register
    parameter FIFO_COUNT_HIGH            = 4;
    parameter FIFO_COUNT_LOW            = 0;
    
    // 各領域のビット幅
    `define CHAR_CODE_UPPER_WIDTH 8
    `define CHAR_CODE_LOWER_WIDTH 8
    `define RED_FEILD_WIDTH 4
    parameter RED_FEILD_WIDTH = 4;
    `define GREEN_FEILD_WIDTH 4
    parameter GREEN_FEILD_WIDTH = 4;
    `define BLUE_FEILD_WIDTH 4
    parameter BLUE_FEILD_WIDTH = 4;
    `define MAGNIFICATION_WIDTH 5
    `define VRAM_START_ADDRESS_WIDTH 32
    `define FIFO_COUNT_WIDTH 5


最後に、今回問題のあった記述のあるプロセッサの代わりをするステートマシン、Char_Draw_for_Test.v

// テスト用キャラクタ描画モジュール
// Char_Draw_for_Test.v
// 
// グラフィックメモリの先頭からキャラクタを描画する。0~9まで、A~Zまで描画したら元に戻る。背景色は黒とする
// Char_Gen_Controller.v のCPUのインターフェースを操作する。
// DDR2 SDRAMは64Mbytes, よって先頭を0x0とすると0x3FF_FFFFまで。
// グラフィックメモリは1024X768X2bytes = 1,572,864 bytes = 0x18_0000
// グラフィックメモリは0x300_0000からとする
// キャラクタは128X96文字 = 12,288文字を1画面に描画できる

`default_nettype none

module Char_Draw_for_Test (clk_vga, reset_vga, cpu_address, cpu_write_data, cpu_read_data, cpu_data_we);

    input wire clk_vga; // VGAのクロック、65MHzの予定
    input wire reset_vga; // clk_vga用リセット
    output reg [31:0] cpu_address; // CPUのアドレス
    output wire [31:0] cpu_write_data; // CPUのWrite データ
    input wire [31:0] cpu_read_data; // CPUのRead データ
    output reg cpu_data_we; // CPUのデータ入力のWrite Enable
    
    `include "Address_Map_Define.vh"
    `include "Command_Status_Define.vh"
    
    parameter idle_char                = 6'b000001;
    parameter CGC_first_cmd0_set    = 6'b000010;
    parameter CGC_cmd4_set            = 6'b000100;
    parameter CGC_cmd8_set            = 6'b001000;
    parameter Wait_CGC_cmd0            = 6'b010000;
    parameter CGC_cmd0_loop            = 6'b100000;
    reg [5:0] cs_char;
    reg [7:0] char_code_count; // キャラクタのカウンタ
    reg [RED_FEILD_HIGH:RED_FEILD_LOW] red_count;
    reg [GREEN_FEILD_HIGH:GREEN_FEILD_LOW] green_count;
    reg [BLUE_FEILD_HIGH:BLUE_FEILD_LOW] blue_count;
    wire op_ena;
    reg [13:0] vram_disp_count;
    reg [31:0] cmd_data;

    // 周波数分周
    freqdiv #(.DIVISOR(3250000)) // 65MHzを20Hzにする
    freqdiv_inst (
        .clk(clk_vga),
        .reset(reset_vga),
        .op_ena(op_ena)
    );
    
    // キャラクタを書きまくるステートマシン
    always @(posedge clk_vga) begin
        if (reset_vga)
            cs_char <= idle_char;
        else begin
            case (cs_char)
                idle_char :
                    cs_char <= CGC_first_cmd0_set;
                CGC_first_cmd0_set : // キャラクタ生成コントローラの0番地に最初のキャラクタと色をセット
                    cs_char <= CGC_cmd4_set;
                CGC_cmd4_set : // キャラクタ生成コントローラの4番地背景色、倍率をセット
                    cs_char <= CGC_cmd8_set;
                CGC_cmd8_set : // キャラクタ生成コントローラの8番地アドレスをセットして1キャラクタ描画
                    cs_char <= Wait_CGC_cmd0;
                Wait_CGC_cmd0 : // 次のキャラクタを書くまでのWait
                    if ((cpu_read_data[FIFO_COUNT_HIGH:FIFO_COUNT_LOW]<5'h01110) && op_ena)
                        cs_char <= CGC_cmd0_loop;
                CGC_cmd0_loop : // ループしながらキャラクタと色を+1しながら
                    if (vram_disp_count>14'd12287) // 1画面描画済み
                        cs_char <= CGC_first_cmd0_set;
                    else
                        cs_char <= Wait_CGC_cmd0;
            endcase
        end
    end
    
    
    // キャラクタ生成コントローラのコマンドデータの用意
    always @(posedge clk_vga) begin
        if (reset_vga) begin
            cpu_address <= 32'd0;
            cmd_data <= 32'd0;
            cpu_data_we <= 1'b0;
        end else begin
            case (cs_char)
                idle_char :begin
                    cpu_address <= 32'd0;
                    cmd_data <= 32'd0;
                    cpu_data_we <= 1'b0;
                end
                CGC_first_cmd0_set : begin
                    cpu_address[31:31-(DECODE_ADDRESS_LENGTH-1)] <= CHAR_GEN_CONTROLLER_ADDR;
                    cpu_address[31-(DECODE_ADDRESS_LENGTH):4] <= 0;
                    cpu_address[3:0] <= 4'd0;
                    
                    cmd_data[CHAR_CODE_UPPER_HIGH:CHAR_CODE_UPPER_LOW] <= 0;
                    cmd_data[CHAR_CODE_LOWER_HIGH:CHAR_CODE_LOWER_LOW] <= `CHAR_CODE_LOWER_WIDTH'h30; // 0x30
                    cmd_data[NOT_PAINTED_BACKGROUND] <= 1'b0; // 背景を塗りつぶす
                    cmd_data[DRAW_IMMEDIATELY] <= 1'b0; // アドレスの書き込みを待つ
                    cmd_data[DRAW_IMMEDIATELY-1 : RED_FEILD_HIGH+1] <= 0;
                    cmd_data[RED_FEILD_HIGH:RED_FEILD_LOW] <= red_count;
                    cmd_data[GREEN_FEILD_HIGH:GREEN_FEILD_LOW] <= green_count;
                    cmd_data[BLUE_FEILD_HIGH:BLUE_FEILD_LOW] <= blue_count;
                    
                    cpu_data_we <= 1'b1;
                end
                CGC_cmd4_set : begin
                    cpu_address[31:31-(DECODE_ADDRESS_LENGTH-1)] <= CHAR_GEN_CONTROLLER_ADDR;
                    cpu_address[31-(DECODE_ADDRESS_LENGTH):4] <= 0;
                    cpu_address[3:0] <= 4'd4;
                    
                    cmd_data[31:MAGNIFICATION_HIGH+1] <= 0;
                    cmd_data[MAGNIFICATION_HIGH:MAGNIFICATION_LOW] <= 0; // 倍率1倍
                    cmd_data[RED_FEILD_HIGH:RED_FEILD_LOW] <= `RED_FEILD_WIDTH'd0;
                    cmd_data[GREEN_FEILD_HIGH:GREEN_FEILD_LOW] <= `GREEN_FEILD_WIDTH'd0;
                    cmd_data[BLUE_FEILD_HIGH:BLUE_FEILD_LOW] <= `BLUE_FEILD_WIDTH'd0;
                    
                    cpu_data_we <= 1'b1;
                end
                CGC_cmd8_set : begin
                    cpu_address[31:31-(DECODE_ADDRESS_LENGTH-1)] <= CHAR_GEN_CONTROLLER_ADDR;
                    cpu_address[31-(DECODE_ADDRESS_LENGTH):4] <= 0;
                    cpu_address[3:0] <= 4'd8;
                    
                    cmd_data <= VRAM_START_ADDRESS;
                    cpu_data_we <= 1'b1;
                end
                Wait_CGC_cmd0 : begin
                    cpu_address[31:31-(DECODE_ADDRESS_LENGTH-1)] <= CHAR_GEN_CONTROLLER_ADDR;
                    cpu_address[31-(DECODE_ADDRESS_LENGTH):4] <= 0;
                    cpu_address[3:0] <= 4'd0;
                    
                    cmd_data[CHAR_CODE_UPPER_HIGH:CHAR_CODE_UPPER_LOW] <= 0;
                    cmd_data[CHAR_CODE_LOWER_HIGH:CHAR_CODE_LOWER_LOW] <= char_code_count;
                    cmd_data[NOT_PAINTED_BACKGROUND] <= 1'b0; // 背景を塗りつぶす
                    cmd_data[DRAW_IMMEDIATELY] <= 1'b1; // アドレスの書き込みを待つ
                    cmd_data[DRAW_IMMEDIATELY-1 : RED_FEILD_HIGH+1] <= 0;
                    cmd_data[RED_FEILD_HIGH:RED_FEILD_LOW] <= red_count;
                    cmd_data[GREEN_FEILD_HIGH:GREEN_FEILD_LOW] <= green_count;
                    cmd_data[BLUE_FEILD_HIGH:BLUE_FEILD_LOW] <= blue_count;
                    
                    cpu_data_we <= 1'b0;
                end
                CGC_cmd0_loop : begin
                    cpu_address[31:31-(DECODE_ADDRESS_LENGTH-1)] <= CHAR_GEN_CONTROLLER_ADDR;
                    cpu_address[31-(DECODE_ADDRESS_LENGTH):4] <= 0;
                    cpu_address[3:0] <= 4'd0;
                    
                    cmd_data[CHAR_CODE_UPPER_HIGH:CHAR_CODE_UPPER_LOW] <= 0;
                    cmd_data[CHAR_CODE_LOWER_HIGH:CHAR_CODE_LOWER_LOW] <= char_code_count;
                    cmd_data[NOT_PAINTED_BACKGROUND] <= 1'b0; // 背景を塗りつぶす
                    cmd_data[DRAW_IMMEDIATELY] <= 1'b1; // アドレスの書き込みを待つ
                    cmd_data[DRAW_IMMEDIATELY-1 : RED_FEILD_HIGH+1] <= 0;
                    cmd_data[RED_FEILD_HIGH:RED_FEILD_LOW] <= red_count;
                    cmd_data[GREEN_FEILD_HIGH:GREEN_FEILD_LOW] <= green_count;
                    cmd_data[BLUE_FEILD_HIGH:BLUE_FEILD_LOW] <= blue_count;
                    
                    cpu_data_we <= 1'b1;
                end
            endcase
        end
    end
    assign cpu_write_data = cmd_data;
    
    // vram_disp_count の処理
    always @(posedge clk_vga) begin
        if (reset_vga)
            vram_disp_count <= 14'd0;
        else
            if (cs_char==CGC_cmd8_set || cs_char==CGC_cmd0_loop) begin
                if (vram_disp_count>14'd12287)
                    vram_disp_count <= 14'd0;
                else
                    vram_disp_count <= vram_disp_count + 14'd0;
            end
    end
            
    // キャラクタのカウンタ
    always @(posedge clk_vga) begin
        if (reset_vga)
            char_code_count <= 8'h30;
        else begin
            if (cs_char==CGC_cmd8_set || cs_char==CGC_cmd0_loop) begin
                if (char_code_count==8'h39) // 9
                    char_code_count <= 8'h41; // A
                else if (char_code_count==8'h5A) // Z
                    char_code_count <= 8'h61; // a
                else if (char_code_count==8'h7A) // z
                    char_code_count <= 8'h30; // 0
                else
                    char_code_count <= char_code_count + 8'd1;
            end
        end
    end
    
    // Red のカウント
    always @(posedge clk_vga) begin
        if (reset_vga)
            red_count <= {RED_FEILD_WIDTH{1'b1}};
        else
            if (cs_char==CGC_cmd8_set || cs_char==CGC_cmd0_loop)
                red_count <= red_count - `RED_FEILD_WIDTH'd1;
    end
    
    // Green のカウント
    always @(posedge clk_vga) begin
        if (reset_vga)
            green_count <= {GREEN_FEILD_WIDTH{1'b1}};
        else
            if ((cs_char==CGC_cmd8_set || cs_char==CGC_cmd0_loop) && red_count==`RED_FEILD_WIDTH'd0) // Redが0の時に-1
                green_count <= green_count - `GREEN_FEILD_WIDTH'd1;
    end
    
    // Blue のカウント
    always @(posedge clk_vga) begin
        if (reset_vga)
            blue_count <= {BLUE_FEILD_WIDTH{1'b1}};
        else
            if ((cs_char==CGC_cmd8_set || cs_char==CGC_cmd0_loop) && green_count==`GREEN_FEILD_WIDTH'd0) // Greenが0の時に-1
                blue_count <= blue_count - `BLUE_FEILD_WIDTH'd1;
    end
    
endmodule


なお、まだシミュレーションしていないので、変更する可能性があります。(というか、絶対に変更になるでしょう?)

(2010/02/05:追記)
上のChar_Draw_for_Test.vを書き換えました。ブロック文とノンブロック文が混在していました。どうもRubyを書いていてVerilogを書くと混在になってしまいます。。。

(2010/02/07:追記)
Command_Status_Define.vhの各領域のビット幅を下のように修正しました。

// 各領域のビット幅
`define CHAR_CODE_UPPER_WIDTH 8
`define CHAR_CODE_LOWER_WIDTH 8
`define RED_FEILD_WIDTH 4
`define GREEN_FEILD_WIDTH 4
`define BLUE_FEILD_WIDTH 4
`define MAGNIFICATION_WIDTH 5
`define VRAM_START_ADDRESS_WIDTH 32
`define FIFO_COUNT_WIDTH 5
parameter RED_FEILD_WIDTH = `RED_FEILD_WIDTH;
parameter GREEN_FEILD_WIDTH = `GREEN_FEILD_WIDTH;
parameter BLUE_FEILD_WIDTH = `BLUE_FEILD_WIDTH;


  1. 2010年02月03日 06:14 |
  2. VGAコントローラ
  3. | トラックバック:0
  4. | コメント:11

キャラクタ描画テスト回路の構成

頑張って作ってきたキャラクタ描画テスト回路もだいぶ出来てきた。今はトップモジュールを作っている。
ここで、キャラクタ描画テスト回路の構成図を作ったので、下に示す。
Char_Draw_Test_1_100201.png

以前との違いは、CPUがキャラクタを書きまくるステートマシンに変わったことだ。これで一旦、テストしてみることにする。白い四角の中は、矢印元のファイルの内部のVerilogファイル構成を示している。現状では、トップモジュールのChar_Draw_Test_Top.v 以外は書けている。トップモジュールを書いて、テストベンチを書けばシミュレーションをすることができる。テストベンチは、クロックを生成して、リセットの処理、DDR2 SDRAMモデルとの接続程度でかけるはず。やっとゴールが近くなってきたが、全くコンパイルしていないので、エラーがぼろぼろ出そうだ。

X-festでSecureIPをシミュレーションするのにISimが重要だとわかったので、後でもう少し使ってみたいと思っている。
  1. 2010年02月01日 06:08 |
  2. VGAコントローラ
  3. | トラックバック:0
  4. | コメント:0

キャラクタ生成コントローラをVerilogコーディング中

現在、キャラクタ生成コントローラをVerilogコーディング中だ。ステートマシンをどう構成するかを悩んでしまって、遅れている。やはり倍率があると1段階面倒になって、すぐにできなかった。次に改訂する場合には、今度はフォントをバッファリングするつもりなので、今ちゃんと作っておかないと更に面倒になる。
こんな感じでFIFOはCORE Generator にお任せだ。VerilogコーディングはNotepad++ で書いている。19インチのディスプレイで書いているが、もう少し横幅が欲しい。Verilogソースを2つ並べて余裕があると良いな。。。
現在は右のソースを参照して、左で書いている。include したparameter を見ながら書くと便利。また、Verilogソースが長くなると右のソースを左に複製して、右で書きながら、左でregやwire の定義を書いていたりする。また右で書いているときに、前後のソースを参照したいときは、左で表示しながら右で書くこともある。2画面にしないと、Verilogコーディングができなくなってしまった。。。
Char_Gen_Controller_5_100126.png
  1. 2010年01月26日 06:00 |
  2. VGAコントローラ
  3. | トラックバック:0
  4. | コメント:2

キャラクタ生成コントローラの仕様2

前回、”キャラクタ生成コントローラの仕様”で、キャラクタ生成コントローラ全体の仕様を考えて、ブロック図を書いてみたが、今度はその下のモジュールのブロック図を書いてみた。
まずはコマンド用FIFOのブロック図を下に示す。
Char_Gen_Controller_3_100117.png

CPUのアドレスはアドレスデコーダに入って、アドレスがデコードされる。自分のアドレスで、最下位の番地が0番地の場合は、0番地用FFにデータバスを貯めておく。8番地を書き込んだ時や、0番地のbit14を1にして書き込んだ場合に、0番地用から8番地用FIFOに各番地のFFの内容を一斉に書き込む。書き込まれたコマンドはキャラクタグラフィックプロセッサに送られる。
次は、キャラクタグラフィックプロセッサだが、キャラクタグラフィックプロセッサ、キャラクタジェネレータROM、画像データ書き込み用FIFOを一緒のブロック図に書くことにする。そのブロック図を下に示す。
Char_Gen_Controller_4_100117.png

主に8番地の”キャラクタを書くVRAMの先頭番地”からVRAMアドレスカウンタに入力される。0番地のbit14が1だと、キャラクタを並べて書くので、8番地の内容は無視して、単に4番地のフォントの倍率を掛けたアドレスを計算してVRAMアドレスカウンタにロードする。VRAMアドレスカウンタの出力はアドレス用FIFOに入力されてアービタに出力される。
0番地のキャラクタコードはキャラクタコードアドレスカウンタにロードされ、行方向のカウンタのアドレスと一緒にキャラクタジェネレータROMのアドレスに入力される。キャラクタジェネレータROMから出力された8ビットのフォントデータは、キャラクタデータ判定回路で判定されて、キャラクタの色データか背景データかをMUXで選択される。その後、Write用データ非同期FIFOに入力されて、アービタに出力される。
背景色を書かない設定になっている場合の背景色の時には、アドレス用非同期FIFOにもWrite用データ非同期FIFOにも書かない。
フォントの倍率が1倍でないときは、倍数に応じて、VRAMアドレスカウンタを進めてアドレス用非同期FIFOに出力する。また、キャラクタデータシフトレジスタは進めずにWrite用データ非同期FIFOに同じデータを書き込んで行くことにする。

大体、仕様が決まったので、次はVerilogコードを書いて行こうと思う。

(2010/01/19:追記)CPUとアービタのクロックドメインが異なるを忘れていたので、書き換えました。
  1. 2010年01月18日 05:13 |
  2. VGAコントローラ
  3. | トラックバック:0
  4. | コメント:0