SSブログ

PSoC 3 で、 FIFO バッファを作った [PSoC]このエントリーを含むはてなブックマーク#

FIFO実験の回路図

データパスには、4段の FIFO が二本入っています。 今回は、この二本の FIFO を接続して8段の FIFO を構成します。

FIFO の使い方

FIFO の概略図

データパスが内蔵している FIFO は、原則として、 CPU などが接続されるバスとデータパスのレジスタを仲介します。 CPU がデータを書込んでデータパスのレジスタに引き渡すものを "Input mode" と、データパスで生成されたデータを CPU に引き渡すものを "Output mode" と呼んでいます。 前回のジェネレータで使用したのは、 "Output mode" の FIFO です。


Input mode

"Input mode" では、 CPU などを使ってバスから FIFO に書き込んだデータをアキュムレータ (Ax) またはデータレジスタ (Dx) に引き渡します。 アキュムレータに渡す場合には、データパスの設定 "Ax WR SRC" で FIFO (Fx) を指定します。 また、データレジスタに渡す場合には、外部制御信号 dx_load の立ち上がりを使用します。

このモードでは、二つのフラグ fx_bus_stat と fx_blk_stat が出力されます。 fx_bus_stat は、 CPU などのバス側の制御に通知を行うための信号で、 FIFO が FULL である時にアサートされます。 このフラグのネゲートにより、新たな値を書込むことが可能である事を示します。 また、 fx_blk_stat は、データパス側の制御に通知を行うための信号で、 FIFO が EMPTY である時にアサートされます。 このフラグのネゲートにより、次のデータを取り出すことが可能である事を示します。

Output mode

"Output mode" では、アキュムレータまたは ALU の出力の値を FIFO の入力とします。 どの値を入力するかは、データパスの設定 "Fx INSEL" で指定します。 データを取り込むタイミングは、外部制御信号 fx_load の立ち上がりを使います。

このモードでも、二つのフラグ fx_bus_stat と fx_blk_stat が出力されますが、 "Input mode" の時とは意味が逆になっています。 fx_bus_stat は、 CPU などのバス側の制御に通知を行うための信号で、 FIFO が EMPTY である時にアサートされます。 また、 fx_blk_stat は、データパス側の制御に通知を行うための信号で、 FIFO が FULL である時にアサートされます。

8段 FIFO の実装

今回の実験では、 FIFO0 を "Input mode" で使用し、 FIFO1 を "Output mode" で使用します。 そして、これらの FIFO の制御を行うステートマシンで FIFO 間のデータ転送を行います。

//`#start header` -- edit after this line, do not edit this line
// ========================================
//
// Copyright noritan.org, 2013
// All Rights Reserved
// UNPUBLISHED, LICENSED SOFTWARE.
//
// CONFIDENTIAL AND PROPRIETARY INFORMATION
// WHICH IS THE PROPERTY OF NORITAN.ORG.
//
// ========================================
`include "cypress.v"
//`#end` -- edit above this line, do not edit this line
// Generated on 05/05/2013 at 21:01
// Component: Fifo8Ntan01
module Fifo8Ntan01 (
	input   clock,
	input   en,
	input   reset
);

//`#start body` -- edit after this line, do not edit this line

// State code declaration
localparam      ST_IDLE = 2'b00;
localparam      ST_GET  = 2'b01;
localparam      ST_WAIT = 2'b11;
localparam      ST_PUT  = 2'b10;

// Datapath function declaration
localparam      CS_IDLE = 3'b000;
localparam      CS_FEED = 3'b001;

// Wire declaration
wire[1:0]       state;          // State code
wire            f0_empty;       // F0 is EMPTY
wire            f1_full;        // F1 is FULL

// Pseudo register
reg[2:0]        addr;           // Datapath function
reg             f1_load;        // LOAD control to F1

// State machine behavior
reg [1:0]       state_reg;
always @(posedge reset or posedge clock) begin
    if (reset) begin
                state_reg <= ST_IDLE;
    end else casez (state)
        ST_IDLE:
            if (en & !f0_empty) begin
                state_reg <= ST_GET;
            end
        ST_GET:
                state_reg <= ST_WAIT;
        ST_WAIT:
            if (!f1_full) begin
                state_reg <= ST_PUT;
            end
        /*ST_PUT*/ default:
                state_reg <= ST_IDLE;
    endcase
end
assign      state = state_reg;

// Internal control signals
always @(state) begin
    casez (state)
        ST_IDLE: begin
            addr = CS_IDLE;
            f1_load = 1'b0;
        end
        ST_GET: begin
            addr = CS_FEED;
            f1_load = 1'b0;
        end
        ST_WAIT: begin
            addr = CS_IDLE;
            f1_load = 1'b0;
        end
        /*ST_PUT*/ default: begin
            addr = CS_IDLE;
            f1_load = 1'b1;
        end
    endcase
end

cy_psoc3_dp8 #(.cy_dpconfig_a(
{
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM0: IDLE*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC___F0, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM1: FEED: A0:=F0*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM2: */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM3: */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM4: */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM5: */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM6: */
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM7: */
    8'hFF, 8'h00,  /*CFG9: */
    8'hFF, 8'hFF,  /*CFG11-10: */
    `SC_CMPB_A1_D1, `SC_CMPA_A1_D1, `SC_CI_B_ARITH,
    `SC_CI_A_ARITH, `SC_C1_MASK_DSBL, `SC_C0_MASK_DSBL,
    `SC_A_MASK_DSBL, `SC_DEF_SI_0, `SC_SI_B_DEFSI,
    `SC_SI_A_DEFSI, /*CFG13-12: */
    `SC_A0_SRC_ACC, `SC_SHIFT_SL, 1'h0,
    1'h0, `SC_FIFO1__A0, `SC_FIFO0_BUS,
    `SC_MSB_DSBL, `SC_MSB_BIT0, `SC_MSB_NOCHN,
    `SC_FB_NOCHN, `SC_CMP1_NOCHN,
    `SC_CMP0_NOCHN, /*CFG15-14: */
    10'h00, `SC_FIFO_CLK__DP,`SC_FIFO_CAP_AX,
    `SC_FIFO_LEVEL,`SC_FIFO__SYNC,`SC_EXTCRC_DSBL,
    `SC_WRK16CAT_DSBL /*CFG17-16: */
}
)) dp(
        /*  input                   */  .reset(reset),
        /*  input                   */  .clk(clock),
        /*  input   [02:00]         */  .cs_addr(addr),
        /*  input                   */  .route_si(1'b0),
        /*  input                   */  .route_ci(1'b0),
        /*  input                   */  .f0_load(1'b0),
        /*  input                   */  .f1_load(f1_load),
        /*  input                   */  .d0_load(1'b0),
        /*  input                   */  .d1_load(1'b0),
        /*  output                  */  .ce0(),
        /*  output                  */  .cl0(),
        /*  output                  */  .z0(),
        /*  output                  */  .ff0(),
        /*  output                  */  .ce1(),
        /*  output                  */  .cl1(),
        /*  output                  */  .z1(),
        /*  output                  */  .ff1(),
        /*  output                  */  .ov_msb(),
        /*  output                  */  .co_msb(),
        /*  output                  */  .cmsb(),
        /*  output                  */  .so(),
        /*  output                  */  .f0_bus_stat(),
        /*  output                  */  .f0_blk_stat(f0_empty),
        /*  output                  */  .f1_bus_stat(),
        /*  output                  */  .f1_blk_stat(f1_full)
);

//`#end` -- edit above this line, do not edit this line
endmodule
//`#start footer` -- edit after this line, do not edit this line
//`#end` -- edit above this line, do not edit this line

ステートマシンは、四つの状態で構成されています。

IDLE
f0_empty (f0_blk_stat) を監視して、 FIFO0 にデータが入るのを待ちます。 ALU は、何もしません。
GET
ALU を駆動して、 FIFO0 の値をアキュムレータ A0 に取り出します。
WAIT
f1_full (f1_blk_stat) を監視して、 FIFO1 に空きができるのを待ちます。 アキュムレータ A0 には、 GET で FIFO0 から取り出した値が入ったままになっています。
PUT
f1_load をアサートして、アキュムレータ A0 の値を FIFO1 に転送します。
FIFO 動作のタイミング図

これら一連の動作を経て、1バイトのデータが FIFO0 から FIFO1 に転送されていきます。 FIFO1 が FULL の状態で FIFO0 にデータが到着した場合には、状態 WAIT で待ち合わせを行います。

データパスの設定

データパスの設定

データパスは、 Reg0 と Reg1 をそれぞれ IDLE と FEED に割り当てています。 IDLE は何もしない状態、 FEED は FIFO0 から A0 にデータを取り出す状態です。

FIFO1 の入力選択

FIFO1 へは、アキュムレータ A0 の値が送り込まれます。 この設定を行うのが、 "F1 INSEL" です。 データパスの設定で、変更されたのは、以上の二点です。

FIFO へアクセスするテストプログラム

動作試験のために作成されたテストプログラムは、今回も、最初の16バイトの出力を LCD に表示させるものとしました。

/* ========================================
 *
 * Copyright noritan.org, 2013
 * All Rights Reserved
 * UNPUBLISHED, LICENSED SOFTWARE.
 *
 * CONFIDENTIAL AND PROPRIETARY INFORMATION
 * WHICH IS THE PROPERTY OF NORITAN.ORG.
 *
 * ========================================
*/
#include <device.h>

void main()
{
    uint8           i = 0;
    uint8           v[16];
    volatile uint8  w;
    
    CR1_Write(1);
    CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
    CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
    CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
    CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
    CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
    CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
    CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
    CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
    v[ 0] = CY_GET_REG8(Fifo_dp_u0__F1_REG);    // =0
    v[ 1] = CY_GET_REG8(Fifo_dp_u0__F1_REG);    // =1
    v[ 2] = CY_GET_REG8(Fifo_dp_u0__F1_REG);    // =2
    v[ 3] = CY_GET_REG8(Fifo_dp_u0__F1_REG);    // =3
    v[ 4] = CY_GET_REG8(Fifo_dp_u0__F1_REG);    // =4
    v[ 5] = CY_GET_REG8(Fifo_dp_u0__F1_REG);    // =5
    v[ 6] = CY_GET_REG8(Fifo_dp_u0__F1_REG);    // =6
    v[ 7] = CY_GET_REG8(Fifo_dp_u0__F1_REG);    // =7
    v[ 8] = CY_GET_REG8(Fifo_dp_u0__F1_REG);    // =4
    v[ 9] = CY_GET_REG8(Fifo_dp_u0__F1_REG);    // =4
    CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
    v[10] = CY_GET_REG8(Fifo_dp_u0__F1_REG);    // =8
    CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
    CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
    v[11] = CY_GET_REG8(Fifo_dp_u0__F1_REG);    // =9
    CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
    CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
    v[12] = CY_GET_REG8(Fifo_dp_u0__F1_REG);    // =10
    CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
    v[13] = CY_GET_REG8(Fifo_dp_u0__F1_REG);    // =11
    v[14] = CY_GET_REG8(Fifo_dp_u0__F1_REG);    // =12
    v[15] = CY_GET_REG8(Fifo_dp_u0__F1_REG);    // =13
    
    LCD_Start();
    LCD_Position(0, 0);
    for (i = 0; i < 8; i++) {
        LCD_PrintInt8(v[i]);
    }
    LCD_Position(1, 0);
    for (i = 8; i < 16; i++) {
        LCD_PrintInt8(v[i]);
    }

    CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
    CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
    CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
    CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
        
    /* CyGlobalIntEnable; */ /* Uncomment this line to enable global interrupts. */
    for(;;)
    {
        CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
        CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
        CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
        CY_SET_REG8(Fifo_dp_u0__F0_REG, i++);
        w = CY_GET_REG8(Fifo_dp_u0__F1_REG);
        w = CY_GET_REG8(Fifo_dp_u0__F1_REG);
        w = CY_GET_REG8(Fifo_dp_u0__F1_REG);
        w = CY_GET_REG8(Fifo_dp_u0__F1_REG);
    }
}

/* [] END OF FILE */

初期化を終えたら、まず、 0 から 7 までの値を FIFO に書き込みます。 書込まれたデータは、 0 から 3 までが FIFO1 に、 4 から 7 までが FIFO0 に格納されます。

次にデータを10回読み出します。 FIFO には、8個しか値が入っていませんので、 0 から 7 までの値が出て行ったあとは、ゴミデータが読み出されます。 この例では、 4 という値が出ています。 本来は、 EMPTY フラグ (f1_blk_stat) を実装して、フラグを見ながら値を読み出していくのが、正しい使い方になります。

その後は、数個ずつ FIFO への書き込みと読み出しを行って、順番通りの値が読み出されている事を確認しています。

メインループでは、4個ずつデータの書き込みと読み出しを行っています。 デバッガのステップ動作で、読み出された値を確認することができます。

プロジェクトアーカイブ

この記事を書くために作成したプロジェクトは、このファイルの拡張子を ZIP に変更して展開すると再現できます。

関連文献


nice!(0)  コメント(0)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。