FC2カウンター FPGAの部屋 2010年02月03日
FC2ブログ

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

FPGAの部屋

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

キャラクタ描画テスト回路の経過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