/* SDHC card controller SD bus mode 2024/02/18 */ %i "ram_8x512.h" circuit SDHCcard_ctrl_SDmode { output CLK; // SD Card Clock output CMD_en; // SD Card CMD Enable output CMD; // SD Card Command input RES; // SD Card Response input DAT<4>; // SD Card Data reg_ws CLK_reg, CMD_reg; reg_wr CMD_en_reg; instrin read(radrs); input radrs<41>; // 32 + 9 reg_ws radrs_reg<41>; output rdata<8>; reg_ws reset; instrself base_clk; output ack, err; reg_wr err_reg, crc_err; reg_ws send_data<8>; reg_wr cmd_index<6>, cmd_arg<32>, crc<7>; reg_wr resp_count<5>, recv_data<8>; reg_wr status_initcomp, RCA_H<8>, RCA_L<8>; ram_8x512 ram; stage_name init { task do(); } stage_name send_cmd { task do(cmd_index, cmd_arg); } stage_name acc { task send(send_data); task recv(); } stage_name get_block { task do(radrs_reg); } stage_name recv_block { task do(); } if(reset){ generate init.do(); reset := 0; } CLK = CLK_reg; CMD = CMD_reg; CMD_en = CMD_en_reg; // 初期化中はCLK400kHzとする reg_wr count_800k<6>; count_800k++; // <6>781250Hz if(init.do){ // CLK 約400kHz if(/&count_800k) base_clk(); } else{ // CLK 25MHz base_clk(); } ack = ^(init.do | get_block.do); err = err_reg | crc_err; rdata = ram.dout; instruct read par{ if(radrs<40:9>==radrs_reg<40:9>){ // すでに取得しているセクタであればデータを返す ram.read(radrs<8:0>); } else generate get_block.do(radrs); } stage init { first_state power_on; state power_on par{ // 電源立ち上げ1msウエイト reg_wr pon_count<16>; if(base_clk) pon_count++; if(pon_count<10>) goto dummy; // 800kHzで800カウント以上 } state dummy if(^acc.send){ // ダミー74clk以上 generate acc.send(0xFF); reg_wr dummy_count<4>; dummy_count++; if(/&dummy_count) goto cmd0; } state cmd0 if(^acc.send){ // リセット // CSn_reg := 0b1; // 1でSDモードのまま generate send_cmd.do(0, 0x00000000); goto cmd8; } state cmd8 if(^send_cmd.do){ generate send_cmd.do(8, 0x000001AA); goto cmd55_41; } state cmd55_41 if(^send_cmd.do){ // 初期RCAは0x0000 generate send_cmd.do(55, 0x00000000); goto acmd41; } state acmd41 if(^send_cmd.do){ // bit30 HCS 1:SDHC,SDXC support host, 0:SDSC only host // bit23-8 OCR<23:8> Voltage window 3.6-3.0 generate send_cmd.do(41, 0x40FC0000); goto acmd41w; } state acmd41w if(^send_cmd.do){ // R3 48bit // bit31 Busy 1:init_complete // bit30 CCS 1:SDHC,SDXC if(status_initcomp) goto cmd2; else goto cmd55_41; } state cmd2 if(^send_cmd.do){ generate send_cmd.do(2, 0x00000000); goto cmd3; } state cmd3 if(^send_cmd.do){ // RCA読み出し generate send_cmd.do(3, 0x00000000); goto cmd7; } state cmd7 if(^send_cmd.do){ // TransferStateへ移行 generate send_cmd.do(7, RCA_H || RCA_L || 0x0000); goto cmd55_6; // goto cmd16; } /* state cmd16 if(^send_cmd.do){ // ブロックサイズ512 // SDHC,SDXCは不要 generate send_cmd.do(16, 512); goto cmd55_6; } */ state cmd55_6 if(^send_cmd.do){ generate send_cmd.do(55, RCA_H || RCA_L || 0x0000); goto acmd6; } state acmd6 if(^send_cmd.do){ // 4bit bus mode generate send_cmd.do(6, 0x00000002); goto acmd6w; } state acmd6w if(^send_cmd.do){ finish; } } stage get_block { first_state st_cmd17; state st_cmd17 par{ generate send_cmd.do(17, radrs_reg<40:9>); goto st_recv; } state st_recv if(^send_cmd.do){ generate recv_block.do(); goto st_read_end; } state st_read_end if(^recv_block.do){ ram.read(radrs_reg<8:0>); goto st_cmd17; finish; } } // 512バイトの読み込み stage recv_block { reg_wr pre_DAT<4>, rec_dat, bf, recv_count<9>; first_state st_init; state st_init par{ CMD_en_reg := 0; pre_DAT := 0xF; rec_dat := 0b0; bf := 0b0; recv_count := 0; goto st_read; } state st_read par{ if(CLK_reg){ } else{ // 立ち上がりでデータ取得 if((pre_DAT==0xF) & (DAT==0x0)) rec_dat := 0b1; pre_DAT := DAT; if(rec_dat) any{ bf==0b0 : bf := 0b1; bf==0b1 : par{ bf := 0b0; ram.write(recv_count, pre_DAT || DAT); recv_count++; if(recv_count==511) goto st_crc; } } } CLK_reg := ^CLK_reg; } state st_crc par{ if(CLK_reg){ } else{ // 立ち上がりでデータ取得 recv_count++; if(recv_count==15){ // CRC読み捨て goto st_init; finish; } } CLK_reg := ^CLK_reg; } } stage send_cmd { instrself cmd_end; first_state st_cmd; state st_cmd if(^(acc.send | acc.recv)){ crc := 0; generate acc.send(0b01 || cmd_index); goto st_arg1; } state st_arg1 if(^acc.send){ generate acc.send(cmd_arg<31:24>); goto st_arg2; } state st_arg2 if(^acc.send){ generate acc.send(cmd_arg<23:16>); goto st_arg3; } state st_arg3 if(^acc.send){ generate acc.send(cmd_arg<15:8>); goto st_arg4; } state st_arg4 if(^acc.send){ generate acc.send(cmd_arg<7:0>); goto st_crc; } state st_crc if(^acc.send){ generate acc.send(crc || 0b1); goto st_recv; } state st_recv if(^acc.send){ if(cmd_index==0){ // レスポンス無し goto st_resp; } else{ // コマンドレスポンス generate acc.recv(); // first resp 0b00_xxxxxx goto st_recv_wait; } } state st_recv_wait if(^acc.recv){ if(recv_data<7>) goto st_recv; // 0xFF=busy, retry. else goto st_resp; } state st_resp if(^acc.recv){ if( ((cmd_index== 0) & (resp_count== 0)) | // なし ((cmd_index== 2) & (resp_count==16)) | // R2 ((cmd_index== 3) & (resp_count== 5)) | // R6 ((cmd_index== 6) & (resp_count== 5)) | // R1 ((cmd_index== 7) & (resp_count== 5)) | // R1b ((cmd_index== 8) & (resp_count== 5)) | // R7 // ((cmd_index==16) & (resp_count== 5)) | // R1 ((cmd_index==17) & (resp_count== 5)) | // R1 ((cmd_index==41) & (resp_count== 5)) | // R3 ((cmd_index==55) & (resp_count== 5)) // R1 ){ cmd_end(); } if(cmd_index==3) any{ resp_count==1 : RCA_H := recv_data; resp_count==2 : RCA_L := recv_data; } if(cmd_index==41) any{ resp_count==1 : status_initcomp := recv_data<7>; } if(cmd_end){ // R1 5 resp_count := 0; generate acc.send(0xFF); // dummy goto st_end; } else{ // R1 0,1,2,3,4 -> 1,2,3,4,5 resp_count++; generate acc.recv(); } } state st_end if(^acc.send){ goto st_cmd; finish; } } stage acc { reg_ws pre_RES; first_state st_init; state st_init par{ any{ acc.send : CMD_en_reg := 1; acc.recv : CMD_en_reg := 0; } pre_RES := 0b1; goto st_acc; } state st_acc par{ if(base_clk){ if(CLK_reg){ if(acc.send) CMD_reg := send_data<7>; send_data := send_data<6:0> || 0b1; // CRC7 crc := crc<5:3> || (crc<2>@crc<6>@send_data<7>) || crc<1:0> || (crc<6>@send_data<7>); } else{ reg_wr acc_count<3>; if(acc.recv){ if(((resp_count==0) & (pre_RES==0b1) & (RES==0b0)) | (acc_count!=0) | (resp_count!=0)){ recv_data := recv_data<6:0> || RES; acc_count++; if(acc_count==7){ goto st_init; finish; } } pre_RES := RES; } else{ // acc.send acc_count++; if(acc_count==7){ goto st_init; finish; } } } CLK_reg := ^CLK_reg; } } } }