/* PlayStation PAD Controller 2008/8/25 SCPH-1010 ノーマル SCPH-1080 ノーマル(ノイズフィルタ付き) SCPH-1150 アナログコントローラ(キー入力のみ) SCPH-1200 デュアルショック SCPH-110 デュアルショック(PSone) SCPH-10010 デュアルショック2 */ //#define enable_DUALSHOCK %d m_READ_DATA_ONLY 0b0000 %d m_READ_DATA_AND_VIBRATE_MN 0b0001 %d m_CONFIG_MODE_ENTER 0b0010 %d m_QUERY_MODEL_AND_MODE 0b0011 %d m_SET_MODE_AND_LOCK 0b0100 %d m_VIBRATION_ENABLE 0b0101 %d m_CONFIG_MODE_EXIT 0b0110 %d m_READ_DATA_AND_VIBRATE_EX 0b0111 %d m_PRESSURE_ENABLE 0b1000 %d m_PRES_TRANS_START 0b1001 module PSPAD_ctrl { output seln, clk, cmd; input ackn, data; instrin clock_500k, key_get; reg_ws seln_reg; reg_ws ackn_reg, data_reg; // cur : 左|下|右|上|St| 1| 1|Sl // ref : □|×|○|△|R1|L1|R2|L2 output data_cur<8>, data_ref<8>; // DUALSHOCK対応 instrin vibrate(vib_length); input vib_length<8>; reg_wr vib_count<8>; // スティック 左00-FF右 上00-FF下 output stick_RH<8>, stick_RV<8>; output stick_LH<8>, stick_LV<8>; // DUALSHOCK2 感圧 無00-FF有 output press_curR<8>, press_curL<8>, press_curU<8>, press_curD<8>; output press_Tri<8>, press_Cir<8>, press_Bad<8>, press_Rect<8>; output press_L1<8>, press_R1<8>, press_L2<8>, press_R2<8>; reg_wr rcv_data<8>; reg_wr mode<8>, status<8>, DAmode; sel cmd0<8>, cmd1<8>, cmd2<8>, cmd3<8>, cmd4<8>; sel cmd5<8>, cmd6<8>, cmd7<8>, cmd8<8>; instrself cmds(cmd0, cmd1, cmd2, cmd3, cmd4, cmd5, cmd6, cmd7, cmd8); instrself send(sendbyte), ack; sel sendbyte<8>; reg_wr command<4>; reg_wr err, f_pressure, gen_comex, gen_comex2; stage_name ds_set { task do(); } stage_name snd_cmd { task do(); } #ifdef enable_DUALSHOCK stage_name snd_cmd_ex { task do(); } stage_name snd_cmd_ex2 { task do(); } #endif stage_name snd_rcv { task do(); } par{ seln = seln_reg; ackn_reg := ackn; data_reg := data; } instruct key_get par{ seln_reg := 0b0; } instruct vibrate par{ // バイブレート長さ指定 vib_count := vib_length; } instruct clock_500k par{ if(seln_reg==0b0){ any{ #ifdef enable_DUALSHOCK gen_comex : generate snd_cmd_ex.do(); gen_comex2 : generate snd_cmd_ex2.do(); #endif else : generate snd_cmd.do(); } generate snd_rcv.do(); } } instruct send any{ // 速度最適化のためここはselのみにすること command==m_READ_DATA_ONLY : par{ cmds(0x01, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); } #ifdef enable_DUALSHOCK command==m_READ_DATA_AND_VIBRATE_MN : par{ if(/|vib_count){ cmds(0x01, 0x42, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00); } else{ cmds(0x01, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); } // cmd3 = 0x40; // MM の上位2ビットが 01 かつ // cmd4 = 0x01; // NN の下位1ビットが 1 -> 小モータオン } command==m_CONFIG_MODE_ENTER : par{ cmds(0x01, 0x43, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00); } command==m_QUERY_MODEL_AND_MODE : par{ cmds(0x01, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); } command==m_SET_MODE_AND_LOCK : par{ // cmds(0x01, 0x44, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00); cmds(0x01, 0x44, 0x00, 0b0000000||DAmode, 0x00, 0x00, 0x00, 0x00, 0x00); // cmd3 = 0b0000000 || DAmode; // モード 0x01:アナログ 0x00:デジタル // cmd4 = 0x03; // 0x03:モード固定 else:ボタン切り替え可能 } command==m_VIBRATION_ENABLE : par{ cmds(0x01, 0x4D, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF); // 後半は0xFFとすること } command==m_CONFIG_MODE_EXIT : par{ cmds(0x01, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); } command==m_READ_DATA_AND_VIBRATE_EX : par{ if(/|vib_count){ cmds(0x01, 0x42, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x00, 0x00); } else{ cmds(0x01, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); } // cmd3 = 0x01; // 小モータ // cmd4 = 0xFF; // 大モータ } command==m_PRESSURE_ENABLE : par{ cmds(0x01, 0x4F, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00); } command==m_PRES_TRANS_START : par{ cmds(0x01, 0x43, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); } #endif } // コマンドプロトコルDUALSHOCK2対応 stage ds_set { state_name init,initb,conf,//qmod,qmodb,readmn,setm, vibe,prese,prts,confe,readex; first_state init; finish; state init par{ command := m_READ_DATA_ONLY; #ifdef enable_DUALSHOCK goto initb; } state initb par{ if(^err) goto conf; } state conf par{ command := m_CONFIG_MODE_ENTER; // goto qmod; // goto setm; goto vibe; } /* state qmod par{ command := m_QUERY_MODEL_AND_MODE; // goto qmodb; goto setm; } state qmodb par{ if(mode==0xF3) goto setm; else goto readmn; } state readmn par{ command := m_READ_DATA_AND_VIBRATE_MN; if(/|vib_count) vib_count--; if((status==0x00) | err) goto init; } state setm par{ command := m_SET_MODE_AND_LOCK; goto vibe; } */ state vibe par{ command := m_VIBRATION_ENABLE; // goto confe; goto prese; } state prese par{ command := m_PRESSURE_ENABLE; goto prts; } state prts par{ command := m_PRES_TRANS_START; f_pressure := 0b1; goto confe; } state confe par{ command := m_CONFIG_MODE_EXIT; goto readex; } state readex par{ command := m_READ_DATA_AND_VIBRATE_EX; if(/|vib_count) vib_count--; if((status==0x00) | err) goto init; #endif } } // CMD 0〜4 stage snd_cmd { reg_wr data_cur_reg<8>, data_ref_reg<8>; state_name st0,st1,st2,st3,st4,st5,st6,st7; first_state st0; par{ data_cur = data_cur_reg; data_ref = data_ref_reg; finish; } state st0 par{ generate ds_set.do(); goto st1; } state st1 par{ // パッドセレクト err := 0b0; send(0x01); // send(cmd0); if(ack) goto st2; } state st2 par{ // コマンド send(cmd1); if(ack){ mode := rcv_data; // パッドモードID goto st3; } } state st3 par{ /* if(^( (mode==0x41) // デジタルモード | (mode==0x53) // ジョイスティック アナログモード | (mode==0x73) // DUALSHOCK互換アナログモード | (mode==0x79) // DUALSHOCK2 native アナログモード | (mode==0xE3) // ジョグコンモード (ジョグコンのみ) | (mode==0xF3) // コンフィギュレーションモード // | (mode==0xFF) // リセット中 )){ err := 0b1; // errでもコマンドの途中で打ち切るべきではない } */ send(cmd2); if(ack){ status := rcv_data; // パッドステータス goto st4; } } state st4 par{ /* if(^( (status==0x5A) // モード切替なし | (status==0x00) // モード切替あり | (status==0xB4) // DUALSHOCK2のデジタルモードREAD_DATAのとき? | (status==0xB5) // DUALSHOCK2のアナログモードREAD_DATAのとき? )){ err := 0b1; } */ if(status==0xFF) err := 0b1; send(cmd3); if(ack) goto st5; } state st5 par{ if( ( (command==m_READ_DATA_ONLY) | (command==m_READ_DATA_AND_VIBRATE_MN) | (command==m_READ_DATA_AND_VIBRATE_EX) ) & (^err) ){ data_cur_reg := ^rcv_data; } goto st6; } state st6 par{ send(cmd4); if(ack) goto st7; } state st7 par{ if( ( (command==m_READ_DATA_ONLY) | (command==m_READ_DATA_AND_VIBRATE_MN) | (command==m_READ_DATA_AND_VIBRATE_EX) ) & (^err) ){ data_ref_reg := ^rcv_data; } #ifndef enable_DUALSHOCK seln_reg := 0b1; #endif #ifdef enable_DUALSHOCK gen_comex := 0b1; #endif goto st0; } } #ifdef enable_DUALSHOCK // CMD 5〜8 DUALSHOCKアナログモード時のコマンド延長 stage snd_cmd_ex { reg_wr stick_RH_reg<8>, stick_RV_reg<8>; reg_wr stick_LH_reg<8>, stick_LV_reg<8>; state_name st10,st11,st12,st13; first_state st10; par{ stick_RH = stick_RH_reg; stick_RV = stick_RV_reg; stick_LH = stick_LH_reg; stick_LV = stick_LV_reg; finish; } state st10 par{ send(cmd5); if(ack){ if(command==m_QUERY_MODEL_AND_MODE){ DAmode := rcv_data<0>; } if(command==m_READ_DATA_AND_VIBRATE_EX){ stick_RH_reg := rcv_data; } goto st11; } } state st11 par{ send(cmd6); if(ack){ if(command==m_READ_DATA_AND_VIBRATE_EX){ stick_RV_reg := rcv_data; } goto st12; } } state st12 par{ send(cmd7); if(ack){ if(command==m_READ_DATA_AND_VIBRATE_EX){ stick_LH_reg := rcv_data; } goto st13; } } state st13 par{ send(cmd8); if(ack){ if(command==m_READ_DATA_AND_VIBRATE_EX){ stick_LV_reg := rcv_data; } if((command==m_READ_DATA_AND_VIBRATE_EX) & f_pressure){ gen_comex2 := 0b1; } else{ seln_reg := 0b1; } gen_comex := 0b0; goto st10; } } } // CMD 9〜20 stage snd_cmd_ex2 { reg_wr press_curR_reg<8>, press_curL_reg<8>, press_curU_reg<8>, press_curD_reg<8>; reg_wr press_Tri_reg<8>, press_Cir_reg<8>, press_Bad_reg<8>, press_Rect_reg<8>; reg_wr press_L1_reg<8>, press_R1_reg<8>, press_L2_reg<8>, press_R2_reg<8>; state_name stp0s,stp1s,stp2s,stp3s, stp4s,stp5s,stp6s,stp7s, stp8s,stp9s,stpAs,stpBs,sted; first_state stp0s; par{ press_curR = press_curR_reg; press_curL = press_curL_reg; press_curU = press_curU_reg; press_curD = press_curD_reg; press_Tri = press_Tri_reg; press_Cir = press_Cir_reg; press_Bad = press_Bad_reg; press_Rect = press_Rect_reg; press_L1 = press_L1_reg; press_R1 = press_R1_reg; press_L2 = press_L2_reg; press_R2 = press_R2_reg; finish; } state stp0s par{ send(0x00); if(ack){ press_curR_reg := rcv_data; goto stp1s; } } state stp1s par{ send(0x00); if(ack){ press_curL_reg := rcv_data; goto stp2s; } } state stp2s par{ send(0x00); if(ack){ press_curU_reg := rcv_data; goto stp3s; } } state stp3s par{ send(0x00); if(ack){ press_curD_reg := rcv_data; goto stp4s; } } state stp4s par{ send(0x00); if(ack){ press_Tri_reg := rcv_data; goto stp5s; } } state stp5s par{ send(0x00); if(ack){ press_Cir_reg := rcv_data; goto stp6s; } } state stp6s par{ send(0x00); if(ack){ press_Bad_reg := rcv_data; goto stp7s; } } state stp7s par{ send(0x00); if(ack){ press_Rect_reg := rcv_data; goto stp8s; } } state stp8s par{ send(0x00); if(ack){ press_L1_reg := rcv_data; goto stp9s; } } state stp9s par{ send(0x00); if(ack){ press_R1_reg := rcv_data; goto stpAs; } } state stpAs par{ send(0x00); if(ack){ press_L2_reg := rcv_data; goto stpBs; } } state stpBs par{ send(0x00); if(ack){ press_R2_reg := rcv_data; goto sted; } } state sted par{ gen_comex2 := 0b0; seln_reg := 0b1; goto stp0s; } } #endif // コマンド-データ送受信部 stage snd_rcv { reg_ws clk_reg, cmd_reg; reg_wr cmd_data<8>, timing<8>; state_name sts,stw,stc,sta; first_state sts; par{ clk = clk_reg; cmd = cmd_reg; finish; } state sts par{ clk_reg := 0b1; timing := 0xF0; cmd_data := sendbyte; if(send) goto stw; } state stw par{ // SELイネーブル後とコマンド間に20us以上のウェイトが必要 timing := timing<6:0> || 0b0; if(timing<7>==0b0) goto stc; } state stc par{ // 250kHz=4us 1コマンド=32us if(clk_reg){ // down コマンド出力 cmd_reg := cmd_data<0>; cmd_data := 0b0 || cmd_data<7:1>; timing := timing<6:0> || 0b1; } else{ // up データ取り込み rcv_data := data_reg || rcv_data<7:1>; } clk_reg := ^clk_reg; if(timing<7>) goto sta; } state sta par{ ack(); goto sts; } } }