PSoC 3 で、かけ算器を作った [PSoC]
全国一千万人のデータパスファンの皆様、お待たせいたしました。 すっかり、公開を忘れていましたが、ついに、かけ算器までたどり着きました。 といっても、まだまだ、チューニングが必要ですね。 ひとまず、公開。
かけ算器の考え方
以前、「PSoC 3 で、16ビット演算器を作った」で定数倍のかけ算器を作りました。 このデータフローでは、アキュムレータのデータをシフトしながら、時々、データレジスタの値を足しこむことで、10倍の値を生成していました。 この「データレジスタの値を足しこむ」タイミングを制御すると、任意の倍数の「かけ算器」に改造することができます。
そのタイミングの制御の方法ですが、三つ目のデータパスを追加してシフトレジスタとして使い、その MSB の値にしたがって、データレジスタの値を足すか足さないかを決定します。 dp1 の A0 をシフトレジスタとして使用し、 dp0 の D0 レジスタに入った値を10倍にして dp0 の A0 に求める計算を行っています。
実際には、 dp1 に8ビットの値を入れてかけ算を行うため、かけ算の手順は、 STEP1 から STEP8 までが必要です。 このデータフローでは、下位4ビットの STEP5 から STEP8 までを記述しています。
シフトレジスタ部分の構成
シフトレジスタ dp1 で使用する機能そのものは、 dp0 の機能と揃えました。 そのため、ステートマシンと機能コードデコーダは、 dp0 と dp1 で同じものが使えます。
Verilog の記述
Verilog 記述は、一つの Verilog ファイルに三つのデータパスを記述しているので、かなり長くなってしまいました。 また、 dp0 で使用される機能コードの最下位ビットには、 dp1 の MSB を直接取り入れて、機能コードデコーダを簡略化しています。
//`#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 06/08/2013 at 16:32 // Component: Multiply16 module Multiply16 ( output drq, input clock, input en, input reset ); //`#start body` -- edit after this line, do not edit this line // State code declaration localparam ST_IDLE = 4'b0000; localparam ST_GET = 4'b0001; localparam ST_STEP1 = 4'b1000; localparam ST_STEP2 = 4'b1001; localparam ST_STEP3 = 4'b1010; localparam ST_STEP4 = 4'b1011; localparam ST_STEP5 = 4'b1100; localparam ST_STEP6 = 4'b1101; localparam ST_STEP7 = 4'b1110; localparam ST_STEP8 = 4'b1111; localparam ST_WAIT = 4'b0011; localparam ST_PUT = 4'b0010; // MSB part of Datapath function localparam CS_IDLE = 2'b00; localparam CS_CLEAR = 2'b01; localparam CS_SL = 2'b10; localparam CS_ADD = 2'b11; // Wire declaration wire[3:0] state; // State code wire f0_empty; // DP1.F0 is EMPTY wire[1:0] f1_full; // DP0.F1 is FULL wire[1:0] so; // Shift out of DP0_A wire[1:0] co; // Carry out of DP0_A wire dp1_msb; // MSB of DP1 // Pseudo register reg[1:0] addr; // MSB part of Datapath function reg d0_load; // LOAD D0 from F0 reg f1_load; // LOAD F1 // State machine behavior reg [3: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_STEP1; ST_STEP1: state_reg <= ST_STEP2; ST_STEP2: state_reg <= ST_STEP3; ST_STEP3: state_reg <= ST_STEP4; ST_STEP4: state_reg <= ST_STEP5; ST_STEP5: state_reg <= ST_STEP6; ST_STEP6: state_reg <= ST_STEP7; ST_STEP7: state_reg <= ST_STEP8; ST_STEP8: 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, ST_STEP2, ST_STEP3, ST_STEP4, ST_STEP5, ST_STEP6, ST_STEP7: begin addr = CS_SL; d0_load = 1'b0; f1_load = 1'b0; end ST_STEP8: begin addr = CS_ADD; 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 reg drq_reg; always @(posedge clock) begin casez (state) ST_PUT: drq_reg <= 1'b1; default: drq_reg <= 1'b0; endcase end assign drq = drq_reg; 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: IDLE0 : Do nothing*/ `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: IDLE1 : 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, /*CFGRAM2: CLEAR0 : A0 <= ALU <= (A0 XOR A0);*/ `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, /*CFGRAM3: CLEAR1 : A0 <= ALU <= (A0 XOR A0);*/ `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: IDLE0 : Do nothing*/ `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: IDLE1 : 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, /*CFGRAM2: CLEAR0 : A0, A1 <= ALU <= (A0 XOR A0);*/ `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, /*CFGRAM3: CLEAR1 : A0, A1 <= ALU <= (A0 XOR A0);*/ `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 + A1) << 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 + A1);*/ 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: */ } )) dp0( /* input */ .reset(reset), /* input */ .clk(clock), /* input [02:00] */ .cs_addr({addr[1:0], dp1_msb}), /* 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(), /* output [01:00] */ .f1_bus_stat(), /* output [01:00] */ .f1_blk_stat(f1_full[1:0]) ); 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: IDLE0 : Do nothing*/ `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: IDLE1 : Do nothing*/ `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, /*CFGRAM2: CLEAR0 : A0 <= F0;*/ `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, /*CFGRAM3: CLEAR1 : A0 <= F0;*/ `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 <= (A0 << 1);*/ `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, /*CFGRAM5: SL1 : A0 <= (A0 << 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 <= A0;*/ `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, /*CFGRAM7: ADD1 : A0 <= A0;*/ 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: */ } )) dp1( /* input */ .reset(reset), /* input */ .clk(clock), /* input [02:00] */ .cs_addr({addr[1:0], 1'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(dp1_msb), /* output */ .f0_bus_stat(), /* output */ .f0_blk_stat(f0_empty), /* 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
かけ算器の使い方
これまでのかけ算器は、 dp0 の FIFO にデータが入ったら、それをトリガにして計算を開始していました。 今回は、 dp1 の FIFO への書き込みをトリガにしています。 そのため、かけ算器に値を書き込むときには、 dp0 への書き込みの後、 dp1 への書き込みをおこないます。
for (i = 0; i < N_BATCH; i++) { CY_SET_REG16(Multiply16_INPUT_PTR, alub[i]); CY_SET_REG8(Multiply16_MULTIPLIER_PTR, alua[i]); }
かけ算の結果は、前回の「PSoC 3 で、 DMA 対応倍増器を作った」と同様に DMA で自動的に取り出されます。 プログラムの部分は、前回同様、計算結果を自動的に検証して、検証結果を LCD に表示させるようにしています。
プロジェクトアーカイブ
この記事を書くために作成したプロジェクトは、このファイルの拡張子を ZIP に変更して展開すると再現できます。
関連文献
シリーズ最強!PSoC 3ボード+デバッグ・ボード: あのPSoCが生まれ変わった!アナログもディジタルも一新 (トライアルシリーズ)
- 作者: 古平 晃洋
- 出版社/メーカー: CQ出版
- 発売日: 2012/10/23
- メディア: 単行本
トランジスタ技術増刊 基板付き体験編ARM PSoCで作るMyスペシャル・マイコン 2013年 12月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2013/11/21
- メディア: 雑誌
開発編 ARM PSoCで作るMyスペシャル・マイコン (トライアルシリーズ)
- 作者: 圓山 宗智
- 出版社/メーカー: CQ出版
- 発売日: 2013/12/24
- メディア: 単行本
コメント 0