SSブログ

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

16ビット演算器

前回まで、8ビットの演算器を作ってきましたが、10倍の倍増器などを実験していると、すぐに上限値である256を超えてしまいます。 そこで、今回は、データパスをもう一つ追加して、16ビットの演算器を作ります。

8ビットから16ビットへ

16ビット倍増器のデータフロー

ここでは、例として16ビットの10倍増器を作ります。 データフローを見て分かるように、二組のデータパスを使って、演算を行います。 二つのデータパスには、 "_a" と "_b" のサフィックスが付いていて、順番に下位 (LSB) と上位 (MSB) を表しています。

そして、二つのデータパスの間には、繰上りを表現するための "Carry" とデータパスをまたぐビットシフトを表現するための "SIO" が配置されています。 これらのデータパスは、お互いを信号線で結ぶことから、物理的に近くに割り当てる必要があります。 PSoC Creator の論理合成では、二組のデータパスを確保する "cy_psoc3_dp16" を使うと、連続するデータパスを割り当ててくれるます。 このため、合わせて16ビットのデータパスとして使用することができるようになります。

しかしながら、二つのデータパスは、独立して設定できますので、連続したデータパスであったとしても、全く別の動作を行わせることも出来ます。

16ビット対応の設定

今回作成する10倍増器は、二つのデータパスを使いますが、それぞれのデータパスの設定は8ビットの時とほぼ同じです。 異なっているのは、上位 ("_b") 側の Carry/SIO 入力の部分です。

下位の設定

下位 ("_a") のデータパスの設定


上位の設定

上位 ("_b") のデータパスの設定


キャリー信号を下位から取り入れるために、 "CI SELA" の設定を "ARITH" から "CHAIN" に変更しています。 また、シフト信号を下位から取り入れるために、 "SI SELA" の設定を "DEFSI" から "CHAIN" に変更しています。 これで、二つの ALU が16ビットの ALU として動作するようになります。

Verilog 記述

Verilog 記述は、前回の倍増器とほぼ同じですが、データパスが二つになったために、一部の制御信号が2本になっています。

//`#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/25/2013 at 18:50
// Component: Times10
module Times10 (
	input   clock,
	input   en,
	input   reset
);

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

// State code declaration
localparam      ST_IDLE     = 3'b000;
localparam      ST_GET      = 3'b001;
localparam      ST_STEP1    = 3'b010;
localparam      ST_STEP2    = 3'b011;
localparam      ST_STEP3    = 3'b100;
localparam      ST_WAIT     = 3'b101;
localparam      ST_PUT      = 3'b110;

// Datapath function declaration
localparam      CS_IDLE     = 3'b000;
localparam      CS_CLEAR    = 3'b001;
localparam      CS_SL0      = 3'b100;
localparam      CS_SL1      = 3'b101;
localparam      CS_ADD0     = 3'b110;
localparam      CS_ADD1     = 3'b111;

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

// Pseudo register
reg[2:0]        addr;           // Datapath function
reg             d0_load;        // LOAD D0 from F0
reg             f1_load;        // LOAD F1

// State machine behavior
reg [2: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[1] & ~f0_empty[0]) begin
                state_reg <= ST_GET;
            end
        ST_GET:
                state_reg <= ST_STEP1;
        ST_STEP1:
                state_reg <= ST_STEP2;
        ST_STEP2:
                state_reg <= ST_STEP3;
        ST_STEP3:
                state_reg <= ST_WAIT;
        ST_WAIT:
            if (~f1_full[1] & ~f1_full[0]) 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;
            d0_load = 1'b0;
            f1_load = 1'b0;
        end
        ST_GET: begin
            addr    = CS_CLEAR;
            d0_load = 1'b1;
            f1_load = 1'b0;
        end
        ST_STEP1: begin
            addr    = CS_SL1;
            d0_load = 1'b0;
            f1_load = 1'b0;
        end
        ST_STEP2: begin
            addr    = CS_SL0;
            d0_load = 1'b0;
            f1_load = 1'b0;
        end
        ST_STEP3: begin
            addr    = CS_SL1;
            d0_load = 1'b0;
            f1_load = 1'b0;
        end
        ST_WAIT: begin
            addr    = CS_IDLE;
            d0_load = 1'b0;
            f1_load = 1'b0;
        end
        /*ST_PUT*/ default: begin
            addr    = CS_IDLE;
            d0_load = 1'b0;
            f1_load = 1'b1;
        end
    endcase
end

cy_psoc3_dp16 #(.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 : Do nothing*/
    `CS_ALU_OP__XOR, `CS_SRCA_A0, `CS_SRCB_A0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM1: CLEAR : A0 <= ALU <= (A0 XOR A0);*/
    `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___SL, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM4: SL0 : A0 <= ALU <= (A0) << 1;*/
    `CS_ALU_OP__ADD, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP___SL, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM5: SL1 : A0<= ALU <= (A0 + D0) << 1;*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM6: ADD0 : A0 <= ALU <= (A0);*/
    `CS_ALU_OP__ADD, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM7: ADD1 : A0 <= ALU <= (A0 + D0);*/
    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_ALU, `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: */
}
), .cy_dpconfig_b(
{
    `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 : Do nothing*/
    `CS_ALU_OP__XOR, `CS_SRCA_A0, `CS_SRCB_A0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM1: CLEAR : A0 <= ALU <= (A0 XOR A0);*/
    `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___SL, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM4: SL0 : A0 <= ALU <= (A0) << 1;*/
    `CS_ALU_OP__ADD, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP___SL, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM5: SL1 : A0 <= ALU <= (A0 + D0) << 1;*/
    `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM6: ADD0 : A0 <= ALU <= (A0);*/
    `CS_ALU_OP__ADD, `CS_SRCA_A0, `CS_SRCB_D0,
    `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE,
    `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
    `CS_CMP_SEL_CFGA, /*CFGRAM7: ADD1 : A0 <= ALU <= (A0 + D0);*/
    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_CHAIN, `SC_C1_MASK_DSBL, `SC_C0_MASK_DSBL,
    `SC_A_MASK_DSBL, `SC_DEF_SI_0, `SC_SI_B_DEFSI,
    `SC_SI_A_CHAIN, /*CFG13-12: */
    `SC_A0_SRC_ACC, `SC_SHIFT_SL, 1'h0,
    1'h0, `SC_FIFO1_ALU, `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[2:0]),
        /*  input           */  .route_si(1'b0),
        /*  input           */  .route_ci(1'b0),
        /*  input           */  .f0_load(1'b0),
        /*  input           */  .f1_load(f1_load),
        /*  input           */  .d0_load(d0_load),
        /*  input           */  .d1_load(1'b0),
        /*  output  [01:00] */  .ce0(),
        /*  output  [01:00] */  .cl0(),
        /*  output  [01:00] */  .z0(),
        /*  output  [01:00] */  .ff0(),
        /*  output  [01:00] */  .ce1(),
        /*  output  [01:00] */  .cl1(),
        /*  output  [01:00] */  .z1(),
        /*  output  [01:00] */  .ff1(),
        /*  output  [01:00] */  .ov_msb(),
        /*  output  [01:00] */  .co_msb(),
        /*  output  [01:00] */  .cmsb(),
        /*  output  [01:00] */  .so(),
        /*  output  [01:00] */  .f0_bus_stat(),
        /*  output  [01:00] */  .f0_blk_stat(f0_empty[1:0]),
        /*  output  [01:00] */  .f1_bus_stat(),
        /*  output  [01:00] */  .f1_blk_stat(f1_full[1:0])
);

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

FIFO は、それぞれのデータパスに8ビットずつ配置されています。 そのため、双方のデータパスの 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()
{
    uint16          a;
    uint16          a10;
    volatile uint16 w = 0;
    CYBIT           good;
        
    LCD_Start();

    CR1_Write(1);
    good = 1;
    for (a = 0; a < 6554; a++) {
        CY_SET_REG16(Times10_dp_u0__F0_REG, a);
        a10 = a * 10;
        w = CY_GET_REG16(Times10_dp_u0__F1_REG);
        if (a10 != w) {
            good = 0;
            break;
        }
    }
    
    LCD_Position(0, 0);
    if (good) {
        LCD_PrintString("GOOD");
    } else {
        LCD_PrintString("BAD");
        LCD_Position(1, 0);
        LCD_PrintNumber(a);
        LCD_Position(1, 8);
        LCD_PrintNumber(w);
    }

    a = 0;
    CY_SET_REG16(Times10_dp_u0__F0_REG, a++);
    CY_SET_REG16(Times10_dp_u0__F0_REG, a++);

    /* CyGlobalIntEnable; */ /* Uncomment this line to enable global interrupts. */
    for(;;)
    {
        CY_SET_REG16(Times10_dp_u0__F0_REG, a++);
        w = CY_GET_REG16(Times10_dp_u0__F1_REG);
    }
}

/* [] END OF FILE */

データを入れるための FIFO0 には、下位 (u0) 側の F0 レジスタのアドレスを指定して、16ビットのアクセスをしています。

        CY_SET_REG16(Times10_dp_u0__F0_REG, a);

上位のデータパスは、下位の隣に配置されています。 そのため、上位データパスの F0 レジスタは、この次のアドレスに配置されています。 このような構造のために、下位の F0 レジスタのアドレスが、16ビットレジスタへのアドレスとして使用できるのです。

また、読み出し側のアドレス指定も同様に下位側のアドレスを指定します。

        w = CY_GET_REG16(Times10_dp_u0__F1_REG);

計算結果が、すべて正しければ、 "GOOD" が表示されます。 また、計算結果が合わなかった場合には、 "BAD" の表示とともに、与えた値と計算結果が表示されて、デバッグを支援するようになっています。

プロジェクトアーカイブ

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

関連文献


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

nice! 0

コメント 0

コメントを書く

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

トラックバック 0

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