FC2カウンター FPGAの部屋 NSL

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

キャラクタ・ディスプレイ・コントローラをNSLで書こう5(シミュレーション1)

PlanAhead12.4でCharDispCtler のNSLコードのデバック”の続き。

前回、PlanAheadのプロジェクトを作成して、ある程度のデバックができた。今回はISimでシミュレーションを行う。Top_wDCM_tb.vというテストベンチを用意した。このテストベンチは、”キャラクタ・ディスプレイ・コントローラのシミュレーション”のテストベンチを改造して使った。*キャラクタを使用して文字を描画するテストベンチだ。テストベンチを下に示す。

// Top Module is Top_wDCM

`timescale 1ns/1ps

module Top_wDCM_tb;
    `include "disp_timing_parameters.vh"

    reg m_clock = 1'b0;
    reg p_reset = 1'b1;
    wire [3:0] VGA_RED;
    wire [3:0] VGA_GREEN;
    wire [3:0] VGA_BLUE;
    wire VGA_HSYNC;
    wire VGA_VSYNC;
    integer i, j, k, m, n;

    parameter PERIOD = 20;
    parameter real DUTY_CYCLE = 0.5;
    parameter OFFSET = 0;

    initial    // Clock process for m_clock
    begin
        #OFFSET;
        forever
        begin
            m_clock = 1'b0;
            #(PERIOD-(PERIOD*DUTY_CYCLE)) m_clock = 1'b1;
            #(PERIOD*DUTY_CYCLE);
        end
    end

    Top_wDCM UUT (
        .m_clock(m_clock),
        .p_reset(p_reset),
        .VGA_RED(VGA_RED),
        .VGA_GREEN(VGA_GREEN),
        .VGA_BLUE(VGA_BLUE),
        .VGA_HSYNC(VGA_HSYNC),
        .VGA_VSYNC(VGA_VSYNC));

    initial begin // キャラクタを*で表示する
        
        #(PERIOD*10);
        p_reset = 1'b0;
        
        @(posedge VGA_VSYNC); // 垂直同期の立ち上がりまでWAIT
        
        for(i=0; i<= V_FRONT_PORCH-1-10; i=i+1) // V_FRONT_PORCHの10ライン前まで数える(表示範囲を広げるため)
            @(posedge VGA_HSYNC); // 水平同期の立ち上がりまでWAIT
            
        for(j=0; j<= H_FRONT_PORCH-1-10; j=j+1) // H_FRONT_PORCHの10ピクセルクロック前まで数える(表示範囲を広げるため)
            @(posedge m_clock);
            
        for(k=0; k<(8*5); k=k+1) begin // 8行(1キャラクタ)*5行
            for(m=0; m<(8*12); m=m+1) begin // 8ピクセル(1キャラクタ)*12列
                #1; // wait
                if(VGA_RED>0 || VGA_GREEN>0 || VGA_BLUE>0)
                    $write("*");
                else
                    $write(" ");
                @(posedge m_clock); // 次のクロックへ
            end
            $write("\n");
            
            @(posedge VGA_HSYNC) ; // 水平同期の立ち上がりまでWAIT
            for(n=0; n<= H_FRONT_PORCH-1-10; n=n+1) // H_FRONT_PORCHの10ピクセルクロック前まで数える(表示範囲を広げるため)
                @(posedge m_clock);
        end
        $stop; // 終了
    end

endmodule


次に、ISim用のプロジェクトファイルを作成した。下に示す。

verilog work ../char_gen_rom.v
verilog work ../dcm_inst.v
verilog work ../Papyrus_work/CharDispCntrler/CharDispCntrler.v
verilog work Top_wDCM_tb.v
verilog work K:\HDL\Xilinx\12.4\ISE_DS\ISE\verilog\src\glbl.v


最後に、ISimシミュレーション用のバッチファイルを下に示す。

del Top_wDCM_tb.exe
K:\HDL\Xilinx\12.4\ISE_DS\ISE\bin\nt\fuse work.Top_wDCM_tb work.glbl -incremental -L unisims_ver=K:\HDL\Xilinx\12.4\ISE_DS\ISE\verilog\hdp\nt\unisims_ver -o Top_wDCM_tb.exe -prj Top_wDCM_tb.prj
Top_wDCM_tb.exe -gui


バッチファイルを実行して、ISimが起動したので、信号を波形ウインドウに入れて、シミュレーションを試みた。下の波形は少しデバックをしたところなのだが、まだ'X'の信号が多い。
CDCont_NSL_10_110215.png

シミュレーションでデバックを進めていくことにする。

(追加)
NSLはmodule内でregを宣言するが、リセットの記述を書かないので、regのところで初期化しないと初期化されない。分かってみると当たり前のことだけど気がつかなかった。

regtemp_pointer[13];


と宣言すると、NSLからVerilogに変換したコードは、

always @(posedge m_clock)
  begin
if ((_u_disp_timing_v_sync)|(_net_12)) 
      temp_pointer <= ((_u_disp_timing_v_sync) ?13'b0000000000000:13'b0)|
    ((_net_12) ?display_addr:13'b0);

end


で、p_resetの記述が入っていない。

regtemp_pointer[13] = 0;


と宣言すると、NSLからVerilogに変換したコードは、

always @(posedge m_clock or posedge p_reset)
  begin
if (p_reset)
     temp_pointer <= 13'b0000000000000;
else if ((_u_disp_timing_v_sync)|(_net_12)) 
      temp_pointer <= ((_u_disp_timing_v_sync) ?13'b0000000000000:13'b0)|
    ((_net_12) ?display_addr:13'b0);

end


で、p_resetの記述が入っている。regの値は初期化する必要があるようだ。初期値が0で実機動作だったら動くと思うが、少なくともシミュレーションの時には初期化は必須だ。

<教訓> NSLでregを宣言したら初期化を忘れないこと。

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

PlanAhead12.4でCharDispCtler のNSLコードのデバック

今回の目的は、NSLで作ったCharDispCtler.vがきちんと論理合成出来て、インプリメントすることができるか?を確かめることだ。インプリメント出来たら、シミュレーションをしてうまく動いていることを確認してから、ビットファイルをSpartan-3A Starter Kitにダウンロードして動作させてみようと思っている。

さて前回で、プロジェクトが完成したが、UCFファイルは生成しただけで、まだピンの配置や動作周波数を設定してない。PlanAheadのプロジェクトからどうやってConstraints Editorやピン配置用の設定画面(これは、PlanAheadでやるのだが。。。)を出すかが良くわからない?

とりあえず、論理合成はUCFが必要ないので、論理合成をしてみよう。FlowメニューからSynthesis Settings を選択するとSynthesis Settings ダイアログが表示される。
PlanAhead124_13_110212.png

Options の... ボタンをクリックして、オプションを見てみる。
PlanAhead124_14_110212.png

-netlist_hierarchy はrebuiltになっている。
ダイアログをすべて閉じて、Project ManagerのSynthesizeをクリックして、論理合成を行う。
PlanAhead124_15_110211.png

Top Module Nameを尋ねるダイアログがでる。トップモジュールの名前。Top_wDCMを入れて、OKボタンをクリックする。
PlanAhead124_16_110211.png

そうすると、しまった。。。エラーが出てしまった。PlanAheadのチュートリアルのつもりだったのに。。。
PlanAhead124_17_110211.png

エラーを見てみると、temp_colorのレンジを超えているそうだ。temp_colorは、temp_color[3]で宣言している。temp_color[9]は当然ながら、インデックス値がout of rangeだ。Verilogを見ながら直したので、Verilogのこの部分がどうなっているかを見ると、

parameter RED_DOT_POS = 9; // 9ビット目がRED
parameter GREEN_DOT_POS = 8; // 8ビット目がGREEN
parameter BLUE_DOT_POS = 7; // 7ビット目がBLUE

に対して、

reg [RED_DOT_POS:BLUE_DOT_POS] temp_color;


で宣言しているので、reg[9:7] temp_color; で宣言していた。これではエラーですね。
元のNSLの下の部分を

if (char_data_node && display_on_d2) {
  red_node := temp_color[RED_DOT_POS];
  green_node := temp_color[GREEN_DOT_POS];
  blue_node := temp_color[BLUE_DOT_POS];


これに変更した。

if (char_data_node && display_on_d2) {
  red_node := temp_color[2];
  green_node := temp_color[1];
  blue_node := temp_color[0];



これで、もう一度、Project ManagerのSynthesizeをクリックして、論理合成を行ったところ、m_clockでエラー発生。
PlanAhead124_18_110211.png

今回、Top_wDCMがトップモジュールで、Verilog ソースファイルのdcm_inst.vをinterface文で接続して、クロックを入力し、そのクロックを下のモジュールに供給している。
これは、NSLから変換したVerilogファイルを見ると、下のように、u_charDispCtrlerTestのm_clockにm_clockが入っている。これは、clkdvが入っているはずなのだ。
PlanAhead124_19_110211.png

対応するNSLソースを下に示す。

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;
    
}


u_charDispCtrlerTest.m_clock = clkdv;と書いてあるが、そうなっていない。これはどれが原因かというと、

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


にinterfaceが入っていないのが問題だと思う。また、m_clock, m_reset入力定義も追加して、下の記述に変更した。

declareCharDispCtrlerTest interface {

inputm_clock;
inputp_reset;

// -- CharDispCtrlerTest --
outputVGA_RED[4];
outputVGA_GREEN[4];
outputVGA_BLUE[4];
outputVGA_HSYNC;
outputVGA_VSYNC;

}


これで、Verilog ソースに変換し、もう一度Project Manager で論理合成してみた。論理合成は正常終了した。これで取り敢えず大丈夫みたいだ。
PlanAhead124_20_110211.png
  1. 2011年02月12日 14:17 |
  2. NSL
  3. | トラックバック:0
  4. | コメント:0

キャラクタ・ディスプレイ・コントローラをNSLで書こう4(NSLを書いたがエラーだったがVerilogに変換)

キャラクタ・ディスプレイ・コントローラをNSLで書いているが、エラーが出ている。原因が良くわからない。 (Verilogに変換できました。(2011/2/10:追記)を参照)
NSL Coreのエラー表示は200行と320行。(他にもエラーがあると思う)
CDCont_NSL_9_110209.png

(NSL Coreもエラーの行が見えない部分があるが、見る方法がないのが残念だ。スクロールも出来ないし、ウインドウの拡大もできない)

200行目を下に示す。

display_dout = u_frame_buffer.fb_read(display_address).display_dout;


display_addr はないのだが? fb_read(display_addr)の定義の方を言っているのかな?
320行目のrom_addrも定義してあるはず?(でも、ちょっとした間違いの可能性があるね?)

とりあえず、全部のソースを貼っておく。

// 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  {
    
    // -- 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    char_gen_rom_nsl  {
    
    // -- char_gen_rom_nsl  --
    input    char_addr[7];
    input    row_addr[3];
    output    dout[8];
}

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 rom_addr[3];
    output dout[8];
}

module    CharDispCtrlerTest {
    
    // -- CharDispCtrlerTest  --
    reg    char_addr[13];
    reg    char_we;
    reg    count_200ms[23];
    reg    char_code[7] = 7'h21;
    reg color_data[3] = 1;
    wire    char_data[10];
    
    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_code_inc(); // キャラクタをインクリメント
                color_data_inc(); // カラーをインクリメント
            } else : {
                count_200ms++;
            }
        }
                
    }

    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];
    reg    temp_pointer[13];
    reg    page_start;
    reg    display_address[13];
    wire    char_data[8];
    wire    display_out[10];
    reg display_on_d1, display_on_d2;
    reg h_sync_1, v_sync_1;
    reg h_sync_2, v_sync_2;
    reg h_sync_3, v_sync_3;
    wire    display_dout[10];
    reg    temp_color[3];
    reg red_node, green_node, blue_node;
    frame_buffer    u_frame_buffer;
    char_gen_rom_nsl    u_char_gen_rom_nsl;
    disp_timing    u_disp_timing;

    /* common operations */
    {
        u_frame_buffer.display_addr = display_address;
        
        u_char_gen_rom_nsl.char_addr = u_frame_buffer.display_dout[6:0];
        u_char_gen_rom_nsl.row_addr = u_disp_timing.v_addr[2:0];
        
        char_data = u_char_gen_rom_nsl.dout;
        display_dout = u_frame_buffer.fb_read(display_address).display_dout;
        
        any {
            u_disp_timing.display_on : {
                if (u_disp_timing.h_addr[2:0] == 3'd7) {
                    display_address++;
                }
            }
            u_disp_timing.v_sync : {
                display_address := 0;
                temp_pointer := 0;
            }
            u_disp_timing.h_sync_pulse : {
                if (u_disp_timing.v_addr[2:0] == 3'd7)
                    temp_pointer := display_address;
                else
                    display_address := 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) {
                    red_node := temp_color[RED_DOT_POS];
                    green_node := temp_color[GREEN_DOT_POS];
                    blue_node := temp_color[BLUE_DOT_POS];
                } 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_3;
        
        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_data);
    }
        
}

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    char_gen_rom_nsl {
    char_gen_rom u_char_gen_rom;

    u_char_gen_rom.clk    = m_clock;
    u_char_gen_rom.reset = p_reset;
    u_char_gen_rom.char_addr = char_addr;
    u_char_gen_rom.row_addr = row_addr;
    dout = u_char_gen_rom.dout;
        
}
module    disp_timing {
    reg h_point, h_addr_node[11]; // 1024までOK
    reg v_point, v_addr_node[11]; // 1024までOK
    reg page_start_node;
    reg display_on_node;
    reg h_sync_node;
    reg v_sync_node;
    reg h_sync_pulse_node;
    
    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 :
            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;
    
}


かなり元のVerilogに近くなってしまった。それが反省点だ。でもまだ、Verilogにコンバートが出来ない。
大分デバックで疲れたが、こんな時は、別のテーマにチャレンジしてから、もう一度やってみるのが良いと思う。
という訳で、次はSpartan-3A Starter Kitの拡張コネクタに接続する基板をKicadで書いて、作ってみたい。

忘れていたがdcm_inst.v とchar_gen_rom.vを載せておく。
まずは、dcm_inst.v。

// DCM module

`default_nettype none
`timescale 1ns / 1ps

module dcm_inst(clkin, reset, clkout, clkfx, clkdv, locked);
    input clkin;
    input reset;
    output clkout;
    output clkfx;
    output clkdv;
    output locked;
    
    wire clkin;
    wire reset;
    wire clkout;
    wire clkfx;
    wire clkdv;
    wire locked;
    
    wire clk_ibuf;
    wire clkfb, clkfx_node;
    wire gnd, clk_node;
    wire clkdv_node, clkdv_bufg;
    
    assign gnd = 1'b0;
    
    IBUFG IBUFG_inst (
        .I(clkin),
        .O(clk_ibuf)
    );
    
    DCM DCM_INST1 (
        .CLKIN(clk_ibuf),
        .CLKFB(clkfb),
        .DSSEN(gnd),
        .PSINCDEC(gnd),
        .PSEN(gnd),
        .PSCLK(gnd),
        .RST(gnd), // リセットごとにDCMのロックが外れないようにgndにしておく
        .CLK0(clk_node),
        .CLK90(),
        .CLK180(),
        .CLK270(),
        .CLK2X(),
        .CLK2X180(),
        .CLKDV(clkdv_node),
        .CLKFX(clkfx_node),
        .CLKFX180(),
        .LOCKED(locked),
        .PSDONE(),
        .STATUS()
    );
    defparam DCM_INST1.CLKIN_PERIOD = 20.0;
    defparam DCM_INST1.DLL_FREQUENCY_MODE = "LOW";
    defparam DCM_INST1.DUTY_CYCLE_CORRECTION = "TRUE";
    defparam DCM_INST1.CLKDV_DIVIDE = 2.0;
    defparam DCM_INST1.PHASE_SHIFT = 0;
    defparam DCM_INST1.CLKOUT_PHASE_SHIFT = "NONE";
    defparam DCM_INST1.STARTUP_WAIT = "FALSE";
    defparam DCM_INST1.FACTORY_JF = 16'hFFFF;
    
    BUFG BUFG_inst(
        .I(clk_node),
        .O(clkfb)
    );
    
    BUFG BUFG_clkfx(
        .I(clkfx_node),
        .O(clkfx)
    );
    
    BUFG BUFG_clkdv(
        .I(clkdv_node),
        .O(clkdv_bufg)
    );
    assign clkout = clkdv_bufg;
    assign clkdv = clkdv_bufg;
endmodule


次に、char_gen_rom.vを示す。

// キャラクタジェネレータ用ROM

`default_nettype none
`timescale 1ns / 1ps

module char_gen_rom(clk, reset, char_addr, row_addr, dout);
    input clk;
    input reset;
    input [6:0] char_addr;
    input [2:0] row_addr;
    output [7:0] dout;
    
    wire clk;
    wire reset;
    wire [6:0] char_addr;
    wire [2:0] row_addr;
    wire [7:0] dout;
    
    wire [10:0] addr;
    
    assign addr = {1'b0, char_addr, row_addr};
    
    RAMB16_S9 #(
        .INIT_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_07(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_08(256'h0014147F147F1414000000000012243600080008080808080000000000000000), // #,",!, 
        .INIT_09(256'h0000000000081018004C322254081408002152240812254200083E483E093E08), // ',&,%,$
        .INIT_0A(256'h000808087F08080800492A1C7F1C2A4900040810101008040020100808081020), // +,*,),(
        .INIT_0B(256'h00010204081020400006060000000000000000007F0000000002040600000000), // /,.,-,,
        .INIT_0C(256'h001C22201820221C003E02041820221C001C080808080C080018244242422418), // 3,2,1,0
        .INIT_0D(256'h001010202040407E003C42423E02423C001E20201E02023E0020207E22242830), // 7,6,5,4
        .INIT_0E(256'h0004080C00000C000000000C00000C00003C42407C42423C003C42423C42423C), // ;,:,9,8
        .INIT_0F(256'h000800081020221C00040810201008040000003E003E00000020100804081020), // ?,>,=,<
        .INIT_10(256'h001C22010101221C003F41413F41413F0041417F2236141C005C2A155549221E), // C,B,A,@
        .INIT_11(256'h001C22710101221C000101013F01017F007F01013F01017F001F21414141211F), // G,F,E,D
        .INIT_12(256'h0022120A060A1222000E11101010103E001C08080808081C004141417F414141), // K,J,I,H
        .INIT_13(256'h001C22414141221C00416151494543410041414149556341003E020202020202),// O,N,M,L
        .INIT_14(256'h003C42403C02423C002111093F41413F005C26594141221C000101013F41413F), // S,R,Q,P
        .INIT_15(256'h00225555554949490008141422224141001C224141414141000808080808087F), // W,V,U,T
        .INIT_16(256'h0038080808080838003F02040810203F00080808081422410041221408142241), // [,Z,Y,X
        .INIT_17(256'h007F0000000000000000000000221408001C10101010101C0008083E083E1422), // _,^,],\
        .INIT_18(256'h0038040438000000001E22221E020200003C223C201C00000000000000180810), // c,b,a,`
        .INIT_19(256'h001C221C0C122C00000808081C081000001C021E221C0000003C22223C202000), // g,f,e,d
        .INIT_1A(256'h0024140C14240400000C1210100010000008080800080000002424241C040400), // k,j,i,h
        .INIT_1B(256'h0018242424180000002828282814000000545454542A00000018080808080800), // o,n,m,l
        .INIT_1C(256'h0018201804180000000404040C34000000202038243800000004041C241C0000), // s,r,q,p
        .INIT_1D(256'h00142A2A2A2200000008141422220000001824242424000000180808081C0800), // w,v,u,t
        .INIT_1E(256'h001008080C080810003E0408103E000000020408142200000022140814220000), // {,z,y,x
        .INIT_1F(256'h0000000000000000000000000000142800040808180808040008080808080808), //  ,~,},|
        .INIT_20(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_21(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_22(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_23(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_24(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_25(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_26(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_27(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_28(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_29(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_2A(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_2B(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_2C(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_2D(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_2E(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_2F(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_31(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_32(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_33(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_34(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_35(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_36(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_37(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_38(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_39(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_3A(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_3B(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_3C(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_3D(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_3E(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_3F(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_07(256'h0000000000000000000000000000000000000000000000000000000000000000)
    ) CHAR_GEN_ROM_INST (
        .DO(dout),
        .DOP(),
        .ADDR(addr),
        .CLK(clk),
        .DI(8'd0),
        .DIP(1'b0),
        .EN(1'b1),
        .SSR(reset),
        .WE(1'b0)
    );
endmodule



なお、”Notepad++でNSLのキーワードの色を変える”のNSL_define.xmlはちょこちょこ書き換えているので、もし使っている方がいらっしゃったら、もう一度コピペしてImportしてください。

(2011/2/10:追記)
Verilogに変換できました!!嬉しいです。ここ2,3日NSLが書けなくてストレスを貯めていましたが、一挙に解放されました。ヤッター!
display_addrのコンフリクトの問題がわからなかったのですが、

u_frame_buffer.display_addr = display_address;



display_dout = u_frame_buffer.fb_read(display_address).display_dout


がコンフリクトしていました。上の文とfb_readで同じdisplay_addrに値を入れています。NSLだとこういう間違いが多くなるような気がします。安易にインスタンスの下のメンバを使わずにfunctionで呼び出すということに徹した方が良い気がします。

reg h_point, h_addr_node[11];


もだめでした。

reg h_point[11], h_addr_node[11];


が正解みたいです。

続けてやってみることにします。おおきさんありがとうございました。
  1. 2011年02月09日 05:40 |
  2. NSL
  3. | トラックバック:0
  4. | コメント:2

キャラクタ・ディスプレイ・コントローラをNSLで書こう3(NSLを作成中)

キャラクタ・ディスプレイ・コントローラをNSLで書こう2(Papyrusでクラス図を作成)”でクラス図が書けて、NSLのスケルトンが出力できたので、今度はNSLを書いている。
元のVerilogファイルを見ながら、NSLに書きなおしているのだが、フレーム・バッファもキャラクタ・ジェネレータもBlockRAMで実装していて、BlockRAMのアドレスに入れてもデータが出てくるには1クロックかかるといった条件が気になって、うまく高位言語に変換が難しい。どうしてもクロックを考える必要が出てきて、泥臭くなってしまう。特にピクセルを出力するReadがやはりクロックを考える必要が出てきてしまう。キャラクタを0.2secごとに書きこむWriteはメソッドで素直に書くことができた。
色々迷いながら書いている。新しい言語を勉強するときはいつもこんなもんだと思う。本当はこの辺りはIPとしてVerilogで作っておいて、もっと上の層をNSLで作るのが良さそうだ。
キャラクタ・ディスプレイ・コントローラのNSLを書き上げるのにもう少し時間がかかりそうだ。下が書いている様子だ。
CDCont_NSL_8_110207.png

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

キャラクタ・ディスプレイ・コントローラをNSLで書こう2(Papyrusでクラス図を作成)

キャラクタ・ディスプレイ・コントローラのクラス図をPapyrusで書いている。
下の図が書きかけのクラス図だ。Top_wDCMのトップ階層を新たに設けた(VerilogとVHDLバージョには無い)が、これは、CharDispCtrlerTestには、CharDispCtrlerを動作させるためのロジックが入っている。ロジックが入っていると、同じ階層でDCMでクロックを変換することが出来ないと思ったからだ。
CDCont_NSL_3_110203.png

CharDispCtrlerTestはすべてreg やwireを書いたのだが、CharDispCtler はinput, outputは全て書いたが、reg やwire は途中でやめてしまった。Verilogで書けばコピペが出来るし、いちいちtypeをダイアログを出して選択するのが面倒だ。やはりここはNSLのスケルトンを生成するのだから、input, outputだけを書いたクラス図で良い気がする。
CharDispCtrlerTestとCharDispCtler のreg, wireはすべて削除したのが、下の図だ。
CDCont_NSL_4_110203.png

クラス図としては、これのほうが良い気がする。NSLのスケルトンを生成するしてから、reg, wire は作ることにする。
Top_wDCMを設けたのは、CharDispCtrlerTestではロジックが入っているので、DCMを接続してクロックを帰るので、トップにクロックを使用するロジックがあってはまずいのでは?と思ったからだ。dcm_instはinterface文を使うか?して、クロックを明示して接続するつもりだ。

そうかメソッドを作成する場合に、reg, wire がないとだめなのかな?早速やってみた。
メソッドを作成していく。
CDCont_NSL_5_110203.png

次はインスタンスだが、これは迷うところ。順当に行けば、CharDispCtler からframe_buffer, char_gen_rom, disp_timing がインスタンスされるんだろうと思う。だが、下のブロック図を見ると、イベント駆動と考えると、disp_timingがタイミングを管理しているので、そこからframe_bufferを駆動して、char_gen_romを駆動するというのが自然のような気がする。しかし、frame_bufferは、キャラクタを書きこむのに、CharDispCtrlerからも駆動されるので、やはり、順当にインスタンスすることになるのだろか?しかし、他のインスタンスのメソッドも使えるんだろうか?考えていても、わからないので、やってることにする。
char_disp_ctler_3_070524.png

色々と構成を考えてみたが、結局、クラス図は下図になった。
CDCont_NSL_6_110204.png

dcm_instは空だが、後で、Verilogファイルを接続するつもりだ。
次に、UMLtoNSLでUMLをNSLのスケルトンに変換した。NSLのスケルトンを下図に示す。
CDCont_NSL_7_110204.png

後は、NSLを書いていくことにする。
  1. 2011年02月03日 05:45 |
  2. NSL
  3. | トラックバック:0
  4. | コメント:0

キャラクタ・ディスプレイ・コントローラをNSLで書こう1(メモリの生成テスト)

キャラクタ・ディスプレイ・コントローラをNSLで書きなおしてみようと思っている。キャラクタ・ディスプレイ・コントローラに関しては、”キャラクタ・ディスプレイ・コントローラの詳しい説明”と”キャラクタ・ディスプレイ・コントローラのまとめ”参照。使用したISEはISE12.4 。

最初にキャラクタ・ジェネレータROMやフレーム・バッファRAMをどうやって書こうか?を考えた。NSLでは、チュートリアルの”8.メモリ”にメモリの生成と初期化方法が書いてある。でも、こう書いた場合にBlockRAMを使ってくれるかどうか?という不安がある。それではということで、実際にやってみた。チュートリアルに載っていたサンプルを少し加工させていただいて下に引用する。

declare memtest {
   input in[8], adr[8] ;
   output f[8] ;

   func_in write ;
   func_in read ;
}
module memtest {
   mem m[256][8] ;

   function write m[adr] := in ;
   function read  f = m[adr] ;
}


これをNSL CoreでVerilogに落とす(Optimizeオプションをチェックしてある)。落としたVerilogファイルを下に示す。

/*
 Produced by NSL Core(version=20110119), IP ARCH, Inc. Sat Jan 29 05:42:47 2011
 Licensed to :LIMITED EVALUATION USER:
*/

module memtest ( p_reset , m_clock , in , adr , f , write , read );
  input p_reset, m_clock;
  input [7:0] in;
  input [7:0] adr;
  output [7:0] f;
  input write;
  input read;
  reg [7:0] m [0:255];

   assign  f = m[adr];
always @(posedge m_clock)
  begin
   if (write )
     m[adr] <= in;
end
endmodule
/*
 Produced by NSL Core(version=20110119), IP ARCH, Inc. Sat Jan 29 05:42:48 2011
 Licensed to :LIMITED EVALUATION USER:
*/


多分これだと、BlockRAMには割り当てられないで、SLICEMに割り当てられると思う。実際にSpartan-3A Starter Kit 用にインプリメントしてFPGA Editorで見てみた。やはりSLICEMが割り当てられている。
CDCont_NSL_1_110129.png

選択されたSLICEMをダブルクリックして中身を見てみると、やはりRAMとして使用されていた。
CDCont_NSL_2_110129.png

やはり、assign f = m[adr]; が always @(posedge m_clock) の中にはっていないとBlockRAMにアサインされない。
この場合は、やはり、Verilogのプリミティブ記述をInterface文で付けたほうが良さそうだ。

ということで一度諦めたんですが、もしかして、Readにregを設定して、それにメモリのデータを一度コピーして出力すればどうだろう?ということで、やってみました。それにフレーム・バッファRAMを想定すると、デュアルポートRAMになっているので、NSLファイルを書きなおしてみた。そのNSLソースを下に示す。

// BlockRAM
declare memtest {
   input in[8], adr_w[8], adr_r[8] ;
   output f[8] ;

   func_in write(adr_w) ;
   func_in read(adr_r) ;
}
module memtest {
   mem m[256][8] ;
   reg ReadData[8];

   func write{
    m[adr_w] := in ;
   }
   func read{
    ReadData := m[adr_r] ;
    f = ReadData;
   }    
}


これをNSL CoreでVerilogに落とす(Optimizeオプションをチェックしてある)。落としたVerilogファイルを下に示す。

/*
 Produced by NSL Core(version=20110119), IP ARCH, Inc. Sat Jan 29 19:12:22 2011
 Licensed to :LIMITED EVALUATION USER:
*/

module memtest ( p_reset , m_clock , in , adr_w , adr_r , f , write , read );
  input p_reset, m_clock;
  input [7:0] in;
  input [7:0] adr_w;
  input [7:0] adr_r;
  output [7:0] f;
  input write;
  input read;
  reg [7:0] m [0:255];
  reg [7:0] ReadData;

   assign  f = ReadData;
always @(posedge m_clock)
  begin
   if (write )
     m[adr_w] <= in;
end
always @(posedge m_clock)
  begin
if ((read)) 
      ReadData <= m[adr_r];
end
endmodule
/*
 Produced by NSL Core(version=20110119), IP ARCH, Inc. Sat Jan 29 19:12:22 2011
 Licensed to :LIMITED EVALUATION USER:
*/


インプリメントして、FPGA Editorで見てみた。BlockRAMが使用されていた。
CDCont_NSL_3_110129.png

これで、大丈夫かな?と思う。キャラクタ・ジェネレータROMも生成してみよう。

(2011/01/30:追加)
分散RAMのデュアルポートRAMのNSL記述について追加しておく。

// 分散RAM
declare memtest {
   input in[8], adr_w[8], adr_r[8] ;
   output f[8] ;

   func_in write(adr_w) ;
   func_in read(adr_r) ;
}
module memtest {
   mem m[256][8] ;

   func write{
    m[adr_w] := in ;
   }
   func read{
    f = m[adr_r] ;
    }    
}


これをNSL CoreでVerilogに落とす(Optimizeオプションをチェックしてある)。落としたVerilogファイルを下に示す。

/*
 Produced by NSL Core(version=20110119), IP ARCH, Inc. Sun Jan 30 04:40:30 2011
 Licensed to :LIMITED EVALUATION USER:
*/

module memtest ( p_reset , m_clock , in , adr_w , adr_r , f , write , read );
  input p_reset, m_clock;
  input [7:0] in;
  input [7:0] adr_w;
  input [7:0] adr_r;
  output [7:0] f;
  input write;
  input read;
  reg [7:0] m [0:255];

   assign  f = m[adr_r];
always @(posedge m_clock)
  begin
   if (write )
     m[adr_w] <= in;
end
endmodule
/*
 Produced by NSL Core(version=20110119), IP ARCH, Inc. Sun Jan 30 04:40:30 2011
 Licensed to :LIMITED EVALUATION USER:
*/


  1. 2011年01月29日 19:24 |
  2. NSL
  3. | トラックバック:0
  4. | コメント:0
»