PSoC 3 で、16ビット演算器を作った [PSoC]
前回まで、8ビットの演算器を作ってきましたが、10倍の倍増器などを実験していると、すぐに上限値である256を超えてしまいます。 そこで、今回は、データパスをもう一つ追加して、16ビットの演算器を作ります。
8ビットから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 に変更して展開すると再現できます。
関連文献
シリーズ最強!PSoC 3ボード+デバッグ・ボード: あのPSoCが生まれ変わった!アナログもディジタルも一新 (トライアルシリーズ)
- 作者: 古平 晃洋
- 出版社/メーカー: CQ出版
- 発売日: 2012/10/23
- メディア: 単行本
コメント 0