SSブログ

PSoC 3 で、 8-bit 加算器を作った [PSoC]このエントリーを含むはてなブックマーク#

タイトルを見ても、何を言っているのか分からないでしょうが、そういう事です。 作成したのは、 カスタムロジックで作成した二つの8-bit入力と一つの8-bit出力を持つ「コ・プロセッサ」です。

Verilog で書いた加算器

Verilog による実装

まずは、 Verilog で記述しています。 テストに使ったのは、こんな回路図です。 二つの Control Reg の出力をカスタム部品 AdderUDB に入力し、その出力を Status Reg で受け取ることにより、 CPU とのインターフェイスを可能にします。 Verilog で記述すると、簡単にカスタム部品の入出力の関係を定義できます。

//`#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 04/27/2013 at 15:30
// Component: AdderUDB
module AdderUDB (
	output [7:0] s,
	input  [7:0] a,
	input  [7:0] b
);

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

    assign s = a + b;

//`#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

PSoC Creator の場合、 Symbol Wizard で入出力を指定してシンボルを作成し、 Generate Verilog でひな形を作成し、 assign ステートメントを追加するだけです。

以下のようなテストプログラムを作成しました。 入力のすべての組み合わせについて結果を検証し、すべて正しければ二つの LED が同時に点滅し、一つでも間違っていれば LED が交互に点滅します。

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

uint16      rega;
uint16      regb;
uint8       sum;
CYBIT       good = 1;

void main()
{
    /* Place your initialization/startup code here (e.g. MyInst_Start()) */

    /* CyGlobalIntEnable; */ /* Uncomment this line to enable global interrupts. */
    for (rega = 0; rega < 256; rega++) {
        CR1_Write(rega);
        for (regb = 0; regb < 256; regb++) {
            CR2_Write(regb);
            sum = SR1_Read();
            if (sum != ((uint8)rega + (uint8)regb)) {
                good = 0;
            }
        }
    }
    // Specify LED status as the inspection results.
    if (good) {
        LED3_Write(0);
        LED4_Write(0);
    } else {
        LED3_Write(0);
        LED4_Write(1);
    }
    // Blink LEDs
    for(;;)
    {
        LED3_Write(!LED3_Read());
        LED4_Write(!LED4_Read());
        CyDelay(200);
    }
}

/* [] END OF FILE */

データパスで書いた加算器

データパスによる実装

単純に Verilog で加算器を書くと、多くの Look Up Table (LUT) を使ってしまいます。 これでは、すぐに資源を喰いつくしてしまいます。 そこで、 LUT の代わりにデータパスを使用して加算器を実装します。

//`#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 04/27/2013 at 15:55
// Component: AdderDp
module AdderDp (
	input   clock,
	input   reset
);

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

cy_psoc3_dp8 #(.cy_dpconfig_a(
{
    `CS_ALU_OP__ADD, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC__ALU,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM0: Add A0 and D0 into A1*/
    `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, /*CFGRAM1: */
    `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_BUS, `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(3'b0),
        /*  input                   */  .route_si(1'b0),
        /*  input                   */  .route_ci(1'b0),
        /*  input                   */  .f0_load(1'b0),
        /*  input                   */  .f1_load(1'b0),
        /*  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(),
        /*  output                  */  .f1_bus_stat(),
        /*  output                  */  .f1_blk_stat()
);

//`#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

多くの記述があるように見えますが、中身はデータパスモジュール "cy_psoc3_dp8" のインスタンス "dp" だけです。 しかも、この記述は、 Datapath Config Tool で自動的に生成されたものを "reset" と "clk" の二つの入力を追加したものです。

データパスの設定

データパスの設定のうち使用しているのは、 CFGRAM の一行目 "Reg0" だけです。 この設定では、 A0D0 の内容を足して A1 に格納する動作をクロックごとに繰り返します。 クロックには、 BUS_CLK を与えているため、 CPU と無関係に高速で加算動作を行います。 ただし、データを出し入れしているのは、 CPU なんですけどね。

以下のようなテストプログラムを作成しました。 変更箇所は、レジスタに対する読み書きだけです。

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

uint16      rega;
uint16      regb;
uint8       sum;
CYBIT       good = 1;

void main()
{
    /* Place your initialization/startup code here (e.g. MyInst_Start()) */

    /* CyGlobalIntEnable; */ /* Uncomment this line to enable global interrupts. */
    for (rega = 0; rega < 256; rega++) {
        CY_SET_REG8(Adder_dp_u0__A0_REG, rega);
        for (regb = 0; regb < 256; regb++) {
            CY_SET_REG8(Adder_dp_u0__D0_REG, regb);
            sum = CY_GET_REG8(Adder_dp_u0__A1_REG);
            if (sum != ((uint8)rega + (uint8)regb)) {
                good = 0;
            }
        }
    }
    // Specify LED status as the inspection results.
    if (good) {
        LED3_Write(0);
        LED4_Write(0);
    } else {
        LED3_Write(0);
        LED4_Write(1);
    }
    // Blink LEDs
    for(;;)
    {
        LED3_Write(!LED3_Read());
        LED4_Write(!LED4_Read());
        CyDelay(200);
    }
}

/* [] END OF FILE */

カスタム部品を作るときには、専用の API を作成して、配置配線後の違いを吸収するのが定石です。 今回は、横着をして、 API を作成せずにレジスタのアドレスを直接与えて、アクセスをしています。 このレジスタアドレスは、 "cyfitter.h" というファイルの中で宣言されています。

消費資源の比較

加算器をデータパスで実現した動機は、消費する資源を減らすためです。 上で作成したシステムのそれぞれの消費資源を比較してみました。

Verilog での実装
Resource Type                 : Used : Free :  Max :  % Used
============================================================
Digital domain clock dividers :    0 :    8 :    8 :   0.00%
Analog domain clock dividers  :    0 :    4 :    4 :   0.00%
Pins                          :    5 :   67 :   72 :   6.94%
UDB Macrocells                :    8 :  184 :  192 :   4.17%
UDB Unique Pterms             :   16 :  368 :  384 :   4.17%
UDB Total Pterms              :   16 :      :      : 
UDB Datapath Cells            :    0 :   24 :   24 :   0.00%
UDB Status Cells              :    1 :   23 :   24 :   4.17%
             Status Registers :    1 
UDB Control Cells             :    2 :   22 :   24 :   8.33%
            Control Registers :    2 
DMA Channels                  :    0 :   24 :   24 :   0.00%
Interrupts                    :    0 :   32 :   32 :   0.00%
データパスでの実装
Resource Type                 : Used : Free :  Max :  % Used
============================================================
Digital domain clock dividers :    0 :    8 :    8 :   0.00%
Analog domain clock dividers  :    0 :    4 :    4 :   0.00%
Pins                          :    5 :   67 :   72 :   6.94%
UDB Macrocells                :    0 :  192 :  192 :   0.00%
UDB Unique Pterms             :    0 :  384 :  384 :   0.00%
UDB Datapath Cells            :    1 :   23 :   24 :   4.17%
UDB Status Cells              :    0 :   24 :   24 :   0.00%
UDB Control Cells             :    0 :   24 :   24 :   0.00%
DMA Channels                  :    0 :   24 :   24 :   0.00%
Interrupts                    :    0 :   32 :   32 :   0.00%

このように、単純な Verilog での実装の場合はマクロセルを8個消費していましたが、データパスの実装の場合はデータパスがセル一個だけで済んでいます。 データパスは、多機能な ALU の機能とそれに付随するレジスタから構成されていますので、資源の消費を少なくできます。 とはいえ、データパスを使って、これだけの事しかできないのではさみしいので、次回は、もっと違う事をしてみましょう。

プロジェクトアーカイブ

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

関連書籍


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

nice! 0

コメント 0

コメントを書く

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

トラックバック 0

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

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