FC2カウンター FPGAの部屋 キャラクタ・ディスプレイ・コントローラをNSLで書こう6(Spartan-3A Starter Kitにダウンロード)
FC2ブログ

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

FPGAの部屋

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

キャラクタ・ディスプレイ・コントローラをNSLで書こう6(Spartan-3A Starter Kitにダウンロード)

キャラクタ・ディスプレイ・コントローラをNSLで書こう5(シミュレーション1)”の続きなのだが、やったことは、”PlanAhead12.4でCreate New Projectしてみる3(Program and Debug)”に書いてしまった。
まだバグがあって、下の写真の様に、字がおかしくなっている。
PlanAhead124_40_110218.jpg

これをデバックしてみた。これは、キャラクタ・ジェネレータのキャラクタ・パターンをRGB値に直すところでおかしいはずなので、NSLファイルと以前書いたVerilogファイルを見比べてみた。下にNSLの問題の部分を示す。

        any {
            u_disp_timing.h_addr[2:0] == 3'd2 : {
                char_data_node := char_data[7:1];
                temp_color := display_dout[RED_DOT_POS : BLUE_DOT_POS]; 
                if (char_data[0] && display_on_d2) {
                    red_node := display_dout[RED_DOT_POS];
                    green_node := display_dout[GREEN_DOT_POS];
                    blue_node := display_dout[BLUE_DOT_POS];
                } else {
                    red_node := 1'b0;
                    green_node := 1'b0;
                    blue_node := 1'b0;
                }
            }
            else : {
                char_data_node := { 1'b0, char_data_node[6:1] };
                // if (char_data_node && display_on_d2) {
                if (char_data_node[0] && display_on_d2) {
                    red_node := temp_color[2];
                    green_node := temp_color[1];
                    blue_node := temp_color[0];
                } else {
                    red_node := 1'b0;
                    green_node := 1'b0;
                    blue_node := 1'b0;
                }
            }
        }            


上のNSLソースで、コメントしてある、// if (char_data_node && display_on_d2) { の部分が間違っていたところだ。これはキャラクタ・ジェネレータから出てきたキャラクタ・パターンをシフトレジスタに入れて、LSBの0晩ビットの値でRGB値を決めるところなので、char_data_node[0]でなければおかしい。その後、キャラクタ・パターンは1ビット右シフトされる。
これを修正して、論理合成、Implement、実機にダウンロードしたところ、下の写真のように動作した。
PlanAhead124_41_110218.jpg

なんか、少し、ちらついている感があるのだが、これで終了とする。
キャラクタ・ディスプレイ・コントローラとかはIPとしてVerilogやVHDLで書いて、NSLは、もう少し上のレベルを書いたほうが良い気がした。

最後にNSLの全ソースを載せておく。

// UML2NSL converter Ver. 2010-03-28 Copyright (c) 2009-2010 IP ARCH, Inc. All rights reserved.
// xmi  --- version 2.1 --- 

#define    C200MS_SECOND    ( 23'd230000 - 23'd1)
#define    H_ACTIVE_VIDEO 640
#define    H_FRONT_PORCH 16
#define    H_SYNC_PULSE 96
#define    H_BACK_PORCH 48
#define    H_SUM H_ACTIVE_VIDEO+H_FRONT_PORCH+H_SYNC_PULSE+H_BACK_PORCH

#define    V_ACTIVE_VIDEO 480
#define    V_FRONT_PORCH 11
#define    V_SYNC_PULSE 2
#define    V_BACK_PORCH 31
#define    V_SUM V_ACTIVE_VIDEO+V_FRONT_PORCH+V_SYNC_PULSE+V_BACK_PORCH

#define    H_DISPLAY_SIZE H_ACTIVE_VIDEO/8 // 横80桁
#define    V_DISPLAY_SIZE V_ACTIVE_VIDEO/8 // 縦60行
    
#define    RED_DOT_POS 9 // 9ビット目がRED
#define    GREEN_DOT_POS 8 // 8ビット目がGREEN
#define    BLUE_DOT_POS 7 // 7ビット目がBLUE

declare    CharDispCtrlerTest interface {
    
    input    m_clock;
    input    p_reset;
    
    // -- CharDispCtrlerTest  --
    output    VGA_RED[4];
    output    VGA_GREEN[4];
    output    VGA_BLUE[4];
    output    VGA_HSYNC;
    output    VGA_VSYNC;
    
}

declare    CharDispCtrler  {
    
    // -- CharDispCtrler  --
    output    VGA_RED[4];
    output    VGA_GREEN[4];
    output    VGA_BLUE[4];
    output    VGA_HSYNC;
    output    VGA_VSYNC;
    input    char_addr[13];
    input    char_din[10];
    
    // -- CharDispCtrler  --
    func_in    char_write(char_addr,char_din);

}

declare    Top_wDCM  {
    
    // -- Top_wDCM  --
    output    VGA_RED[4];
    output    VGA_GREEN[4];
    output    VGA_BLUE[4];
    output    VGA_HSYNC;
    output    VGA_VSYNC;
    
}

declare    frame_buffer  {
    
    // -- frame_buffer  --
    input    char_addr[13];
    input    char_din[10];
    input    char_we;
    input    display_addr[13];
    output    display_dout[10];
    
    // -- frame_buffer  --
    func_in fb_write(char_addr, char_din);
    func_in    fb_read(display_addr) ;

}

declare    disp_timing  {
    
    // -- disp_timing  --
    output    page_start;
    output    display_on;
    output    h_addr[10];
    output    v_addr[10];
    output    h_sync;
    output    h_sync_pulse;
    output    v_sync;
    
}

declare dcm_inst interface {
    input clkin;
    input reset;
    output clkout;
    output clkfx;
    output clkdv;
    output locked;
}

declare char_gen_rom interface {
    input clk;
    input reset;
    input char_addr[7];
    input row_addr[3];
    output dout[8];
}

module    CharDispCtrlerTest {
    
    // -- CharDispCtrlerTest  --
    reg    char_addr[13] = 0;
    reg    count_200ms[23] = 0;
    reg    char_code[7] = 7'h21;
    reg color_data[3] = 1;
    wire    char_data[10];
    
    func_self    char_addr_inc();
    func_self    char_code_inc();
    func_self    color_data_inc();
    
    CharDispCtrler    u_charDispCtrler;

    /* common operations */
    {
        VGA_RED = u_charDispCtrler.VGA_RED;
        VGA_GREEN = u_charDispCtrler.VGA_GREEN;
        VGA_BLUE = u_charDispCtrler.VGA_BLUE;
        VGA_HSYNC = u_charDispCtrler.VGA_HSYNC;
        VGA_VSYNC = u_charDispCtrler.VGA_VSYNC;
        
        char_data = { color_data, char_code };
        
        any {
            count_200ms == C200MS_SECOND : {
                count_200ms := 0;
                u_charDispCtrler.char_write(char_addr, char_data); // キャラクタを描画
                char_addr_inc(); // キャラクタのアドレスをインクリメント
                char_code_inc(); // キャラクタをインクリメント
                color_data_inc(); // カラーをインクリメント
            } else : {
                count_200ms++;
            }
        }
                
    }
    
    function char_addr_inc {
        if (char_addr == 13'd4799) { // 終了
            char_addr := 0;
        } else {
            char_addr++;
        }
    }

    function char_code_inc {
        if (char_code == 7'h7E) {
            char_code := 7'h21;
        } else {
            char_code++;
        }
    }
    
    function color_data_inc {
        if (color_data == 3'h7) {
            color_data := 3'h1;
        } else {
            color_data ++;
        }
    }
        
}

module    CharDispCtrler {
    
    // -- CharDispCtrler  --
    wire    h_sync_pulse;
    reg    char_data_node[7] = 0;
    reg    temp_pointer[13] = 0;
    reg    page_start = 0;
    reg    display_addr[13] = 0;
    wire    char_data[8];
    wire    display_out[10];
    reg display_on_d1 = 0, display_on_d2 = 0;
    reg h_sync_1 = 0, v_sync_1 = 0;
    reg h_sync_2 = 0, v_sync_2 = 0;
    reg h_sync_3 = 0, v_sync_3 = 0;
    wire    display_dout[10];
    reg    temp_color[3] = 0;
    reg red_node = 0, green_node = 0, blue_node = 0;
    frame_buffer    u_frame_buffer;
    char_gen_rom    u_char_gen_rom;
    disp_timing    u_disp_timing;

    /* common operations */
    {
        u_char_gen_rom.clk    = m_clock;
        u_char_gen_rom.reset = p_reset;
        u_char_gen_rom.char_addr = u_frame_buffer.display_dout[6:0];
        u_char_gen_rom.row_addr = u_disp_timing.v_addr[2:0];
        
        char_data = u_char_gen_rom.dout;
        display_dout = u_frame_buffer.fb_read(display_addr).display_dout;
        
        any {
            u_disp_timing.display_on : {
                if (u_disp_timing.h_addr[2:0] == 3'd7) {
                    display_addr++;
                }
            }
            u_disp_timing.v_sync : {
                display_addr := 0;
                temp_pointer := 0;
            }
            u_disp_timing.h_sync_pulse : {
                if (u_disp_timing.v_addr[2:0] == 3'd7)
                    temp_pointer := display_addr;
                else
                    display_addr := temp_pointer;
            }
        }
    
        any {
            u_disp_timing.h_addr[2:0] == 3'd2 : {
                char_data_node := char_data[7:1];
                temp_color := display_dout[RED_DOT_POS : BLUE_DOT_POS]; 
                if (char_data[0] && display_on_d2) {
                    red_node := display_dout[RED_DOT_POS];
                    green_node := display_dout[GREEN_DOT_POS];
                    blue_node := display_dout[BLUE_DOT_POS];
                } else {
                    red_node := 1'b0;
                    green_node := 1'b0;
                    blue_node := 1'b0;
                }
            }
            else : {
                char_data_node := { 1'b0, char_data_node[6:1] };
                // if (char_data_node && display_on_d2) {
                if (char_data_node[0] && display_on_d2) {
                    red_node := temp_color[2];
                    green_node := temp_color[1];
                    blue_node := temp_color[0];
                } else {
                    red_node := 1'b0;
                    green_node := 1'b0;
                    blue_node := 1'b0;
                }
            }
        }            
        VGA_RED = {4{red_node}};
        VGA_GREEN = {4{green_node}};
        VGA_BLUE = {4{blue_node}};
        
        display_on_d1 := u_disp_timing.display_on;
        display_on_d2 := display_on_d1;
        
        h_sync_1 := u_disp_timing.h_sync;
        v_sync_1 := u_disp_timing.v_sync;
        h_sync_2 := h_sync_1;
        v_sync_2 := v_sync_1;
        h_sync_3 := h_sync_2;
        v_sync_3 := v_sync_2;
        
        VGA_HSYNC = ~h_sync_3;
        VGA_VSYNC = ~v_sync_3;
    }

    
    /* func_in char_write(char_addr,char_dout) operation */
    function    char_write {
        u_frame_buffer.fb_write(char_addr, char_din);
    }
        
}

module    Top_wDCM {
    dcm_inst    u_dcm_inst;
    CharDispCtrlerTest    u_charDispCtrlerTest;
    wire    clkdv;
    wire    locked;
    
    u_dcm_inst.clkin = m_clock;
    u_dcm_inst.reset = p_reset;
    clkdv = u_dcm_inst.clkdv;
    locked = u_dcm_inst.locked;
    
    u_charDispCtrlerTest.m_clock = clkdv;
    u_charDispCtrlerTest.p_reset = ~locked;
    VGA_RED = u_charDispCtrlerTest.VGA_RED;
    VGA_GREEN = u_charDispCtrlerTest.VGA_GREEN;
    VGA_BLUE = u_charDispCtrlerTest.VGA_BLUE;
    VGA_HSYNC = u_charDispCtrlerTest.VGA_HSYNC;
    VGA_VSYNC = u_charDispCtrlerTest.VGA_VSYNC;
    
}

module    frame_buffer {
    mem m[8192][10] ;
    reg ReadData[10];
    
    /* common operations */
    {
        display_dout = ReadData;    
    }

    /* func_in fb_read(display_addr) operation */
    function    fb_read {
        ReadData := m[display_addr] ;
    }
        
    /* function fb_write(char_addr,char_din) operation */
    function    fb_write {
        m[char_addr] := char_din ;
    }
        
}
        
module    disp_timing {
    reg h_point[11] = 0, h_addr_node[11] = 0; // 1024までOK
    reg v_point[11] = 0, v_addr_node[11] = 0; // 1024までOK
    reg page_start_node = 0;
    reg display_on_node = 0;
    reg h_sync_node = 0;
    reg v_sync_node = 0;
    reg h_sync_pulse_node = 0;
    
    any {
        h_point == H_SUM-1 :
            h_point := 0;
        else :
            h_point++;
    }
    h_addr_node := h_point;
    h_addr = h_addr_node[9:0];
    
    any {
        v_point == V_SUM-1 :
            v_point := 0;
        else : {
            if (h_point == H_SUM-1)
                v_point++;
        }
    }
    v_addr_node := v_point;
    v_addr = v_addr_node[9:0];
    
    any {
        h_point<H_ACTIVE_VIDEO && v_point<V_ACTIVE_VIDEO :
            display_on_node := 1'b1;
        else : 
            display_on_node := 1'b0;
    }
    display_on = display_on_node;
    
    any {
        h_point==0 : 
            page_start_node := 1'b1;
        else :
            page_start_node := 1'b0;
    }
    page_start = page_start_node;

    any {
        (h_point>=(H_ACTIVE_VIDEO + H_FRONT_PORCH)) && (h_point < (H_SUM-H_BACK_PORCH)) :
            h_sync_node := 1'b1;
        else :
            h_sync_node := 1'b0;
    }
    h_sync = h_sync_node;
    
    any {
        h_point==(H_ACTIVE_VIDEO+H_FRONT_PORCH) :
            h_sync_pulse_node := 1'b1;
        else :
            h_sync_pulse_node := 1'b0;
    }
    h_sync_pulse = h_sync_pulse_node;
    
    any {
        (v_point>=(V_ACTIVE_VIDEO + V_FRONT_PORCH)) && (v_point<(V_SUM-V_BACK_PORCH)) :
            v_sync_node := 1'b1;
        else :
            v_sync_node := 1'b0;
    }
    v_sync = v_sync_node;
    
}


  1. 2011年02月18日 05:56 |
  2. NSL
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
http://marsee101.blog.fc2.com/tb.php/1723-fa4f483a
この記事にトラックバックする(FC2ブログユーザー)