FC2カウンター FPGAの部屋 PS/2キーボードインターフェース用テストベンチ(task使用)
FC2ブログ

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

FPGAの部屋

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

PS/2キーボードインターフェース用テストベンチ(task使用)

PS/2キーボードインターフェース用テストベンチ(procedure使用)でVHDLの procedure 文を使って、PS/2キーボードインターフェースをシミュレーションしてみた。
今度はVerilog2001で task 文を使ってシミュレーションしてみた。task もprocedure 同様サブプログラムとして使用できるようだ。Verilog は、VHDLと違って、出力信号を定義せずに直接信号を変更できるようだ。これは私としては、信号がグローバルになっているようであまり好きではない。便利なことはいろいろあるのだけど。。。
ps2read.v は、日曜デジタルさんのコードを丸写しで直しても芸がないので、自分で作ってみた。ずっとコード量は多いし、回路も複雑になると思うが、シリアルデータ受信のすべてのフェーズを1つ1つのステートにした。
さらにステートを見やすいように、MAIN_STATEにステート文字をアサインした。
Verilogを書くのは久しぶりなので、大分苦労してしまったが、何とか完成。

// ps2read Verilog2001

`default_nettype none
`timescale 1ns / 1ps

module ps2read(clk, reset, ps2clk, ps2data, scandata);
    input clk, reset, ps2clk, ps2data;
    output [7:0] scandata;
    
    wire clk, reset, ps2clk, ps2data;
    reg [7:0] scandata;
    reg [10:0] c_state, n_state;
    reg ps2clk_b1, ps2clk_b2;
    reg ps2data_b;
    reg [7:0] c_scandata, n_scandata;
    
    parameter IDLE=11'b00000000001, BIT0=11'b00000000010, BIT1=11'b00000000100, BIT2=11'b00000001000, BIT3=11'b00000010000, BIT4=11'b00000100000, BIT5=11'b00001000000, BIT6=11'b00010000000, BIT7=11'b00100000000, PARITY=11'b01000000000, STOP=11'b10000000000;
    
    always @(posedge reset, posedge clk) begin
        if (reset) begin
            ps2clk_b1 <= 1'b0;
            ps2clk_b2 <= 1'b0;
            ps2data_b <= 1'b0;
        end else begin
            ps2clk_b1 <= ps2clk;
            ps2clk_b2 <= ps2clk_b1;
            ps2data_b <= ps2data;
        end
    end
            
    always @(posedge reset, posedge clk) begin
        if (reset) begin
            c_state <= IDLE;
            c_scandata <= 0;
        end else begin
            c_state <= n_state;
            c_scandata <= n_scandata;
        end
    end
    
    always @* begin
        case (c_state)
            IDLE : begin
                n_scandata <= c_scandata;
                if (ps2clk_b2 && !ps2clk_b1)
                    n_state <= BIT0;
                else
                    n_state <= IDLE;
            end
            BIT0 : 
                if (ps2clk_b2 && !ps2clk_b1) begin
                    n_state <= BIT1;
                    n_scandata <= {ps2data_b, c_scandata[7:1]};
                end else begin
                    n_state <= BIT0;
                    n_scandata <= c_scandata;
                end
            BIT1 : 
                if (ps2clk_b2 && !ps2clk_b1) begin
                    n_state <= BIT2;
                    n_scandata <= {ps2data_b, c_scandata[7:1]};
                end else begin
                    n_state <= BIT1;
                    n_scandata <= c_scandata;
                end
            BIT2 : 
                if (ps2clk_b2 && !ps2clk_b1) begin
                    n_state <= BIT3;
                    n_scandata <= {ps2data_b, c_scandata[7:1]};
                end else begin
                    n_state <= BIT2;
                    n_scandata <= c_scandata;
                end
            BIT3 : 
                if (ps2clk_b2 && !ps2clk_b1) begin
                    n_state <= BIT4;
                    n_scandata <= {ps2data_b, c_scandata[7:1]};
                end else begin
                    n_state <= BIT3;
                    n_scandata <= c_scandata;
                end
            BIT4 : 
                if (ps2clk_b2 && !ps2clk_b1) begin
                    n_state <= BIT5;
                    n_scandata <= {ps2data_b, c_scandata[7:1]};
                end else begin
                    n_state <= BIT4;
                    n_scandata <= c_scandata;
                end
            BIT5 : 
                if (ps2clk_b2 && !ps2clk_b1) begin
                    n_state <= BIT6;
                    n_scandata <= {ps2data_b, c_scandata[7:1]};
                end else begin
                    n_state <= BIT5;
                    n_scandata <= c_scandata;
                end
            BIT6 :
                if (ps2clk_b2 && !ps2clk_b1) begin
                    n_state <= BIT7;
                    n_scandata <= {ps2data_b, c_scandata[7:1]};
                end else begin
                    n_state <= BIT6;
                    n_scandata <= c_scandata;
                end
            BIT7 :
                if (ps2clk_b2 && !ps2clk_b1) begin
                    n_state <= PARITY;
                    n_scandata <= {ps2data_b, c_scandata[7:1]};
                end else begin
                    n_state <= BIT7;
                    n_scandata <= c_scandata;
                end
            PARITY : begin
                n_scandata <= c_scandata;
                if (ps2clk_b2 && !ps2clk_b1)
                    n_state <= STOP;
                else
                    n_state <= PARITY;
            end
            STOP : begin
                n_scandata <= c_scandata;
                if (ps2clk_b2 && !ps2clk_b1)
                    n_state <= IDLE;
                else
                    n_state <= STOP;
            end
        endcase
    end
    
    always @(posedge reset, posedge clk) begin
        if (reset)
            scandata <= 0;
        else
            if (c_state == STOP)
                scandata <= c_scandata;
    end
    
    // synthesis translate_off

    reg [20*8:1] MAIN_STATE; 
    
    always @(c_state) begin
        case(c_state)
            IDLE: MAIN_STATE <= "IDLE";
            BIT0: MAIN_STATE <= "BIT0";
            BIT1: MAIN_STATE <= "BIT1";
            BIT2: MAIN_STATE <= "BIT2";
            BIT3: MAIN_STATE <= "BIT3";
            BIT4: MAIN_STATE <= "BIT4";
            BIT5: MAIN_STATE <= "BIT5";
            BIT6: MAIN_STATE <= "BIT6";
            BIT7: MAIN_STATE <= "BIT7";
            PARITY: MAIN_STATE <= "PARITY";
            STOP: MAIN_STATE <= "STOP";
        endcase
    end
    // synthesis translate_on
     
endmodule


次にテストベンチを作成した。task 文を使用してVHDL の procedure 文の時と同様に書いてみた。
PS/2のクロック間隔は、'1'の期間が40us、'0'の期間が40us のクロックと、VHDLと同じとした。task 文には入力8ビット幅のスキャンコードだけがアサインされている。出力は直接信号に出力される。

`default_nettype none
`timescale 1ns / 1ps

module ps2read_tb;

    parameter CYCLE=20;

    reg clk, reset, ps2clk, ps2data;
    wire [7:0] scandata;
    
    ps2read ps2read_inst (
        .clk(clk),
        .reset(reset),
        .ps2clk(ps2clk),
        .ps2data(ps2data),
        .scandata(scandata)
    );
    
    initial begin
        clk <= 1'b1;
    end
    always #(CYCLE/2)
        clk <= ~clk;
    
    initial begin
        reset <= 1'b1;
        ps2clk <= 1'b1;
        ps2data <= 1'b1;
        
        #80; // リセット
        reset <= 1'b0; // リセット解除
        PS2_SigGen(8'h1C);
        PS2_SigGen(8'h32);
        #500;
        $stop;
    end
    
    task PS2_SigGen;
        input [7:0] input_code;
        integer i;
        begin
            ps2clk <= 1'b1;
            ps2data <= 1'b0; // Stop bit
            
            #40000;
            ps2clk <= 1'b0; // 立ち下がりエッジ
            #40000;
            
            for(i=0; i<=7; i=i+1) begin
                ps2clk <= 1'b1; // 立ち上がりエッジ
                ps2data <= input_code[i]; // シリアルデータ出力
                
                #40000;
                ps2clk <= 1'b0; // 立下りエッジ
                #40000;
            end
        
            ps2clk <= 1'b1;
            ps2data <= !(^input_code);
        
            #40000;
            ps2clk <= 1'b0; // 立ち下がりエッジ
            #40000;
        
            ps2clk <= 1'b1;
            ps2data <= 1'b1; // Stop bit
        
            #40000;
            ps2clk <= 1'b0; // 立ち下がりエッジ
            #40000;
            ps2clk <= 1'b1; // 1に戻す
        end
    endtask
endmodule


ModelSimでシミュレーションしてみた。
wave表示で、MAIN_STATE表示するときには、そこを右クリックして、Radix -> ASCII を選択するとステート名で表示することができる。
keyboard_verilog_2_071008.png

さらにVeritak でも確かめてみた。
keyboard_verilog_1_071008.png


2007/10/13 : PS/2インターフェースのパリティが偶数パリティだったので、奇数パリティに変更しました。
2007/10/15 : ps2clkの1クロック遅延で比較していたので、ps2dataも1クロック遅延しました。ここでは、50MHzでサンプリングしているので大して変わりませんが、もっとサインプリングレートを低くしたときに効いてきます。
  1. 2007年10月08日 13:02 |
  2. 入門Verilog
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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