SSブログ
English Version

レトロマイコンZ80ボードの構想(その10)CP/M80 BIOS検討2 [Z80]

 ebayで注文していたブレッドボード用接続ケーブルが届いたので実験を再開しました。
 届いたケーブルはメッチャ安いのですが、ブレッドボードに差し込むピンにボンドが付いた状態だったので接触不良を防ぐために1本ずつピンセットで挟んでボンドを取り除きながらの接続作業でした^^;;
 自分で接続ケーブルを作るよりは全然楽なのですがさすがに安いだけあって品質が・・・

 最初にやりたかった実験は NMI や RESET 以外で HALT 状態を抜ける実験です。

 HALT状態では内部でNOPを実行しているということがマニュアルに書いてあったので、アドレスはインクリメントせずにHALTをNOPに置き換えてフェッチを繰り返しているものと想像していました。
 であればバスをPIC制御にし、HALTコードをNOPに変更後、バスを開放すれば、Z80は何事もなかったようにHALT状態を抜けるのではないかと考えたわけです。

 実験のソースとロジアナ波形は以下のとおりです。
 Z80の動作としては0000hのアドレスのHALTコード(76H)でHALT状態になった後は0001h番地のNOPコード(00h)をフェッチしています。

 従ってNOP書換えによるHALT脱出はできないという結論になりました。^^;

 ロジアナ波形でresetがhighになった後RD/がlowの部分で命令コードをフェッチしています。
 RD/の最初のlowでは(AD1,AD0)=(0,0)でアドレス0000hのコード(76h)をフェッチしています。(なので(D1,D0)=(1,0))
 その後HALT状態(HALT/がlowに遷移)し、(ad1,ad0)=(0,1)なので0001hのメモリのコード(00h:NOP)をフェッチする動作が繰り返されます。

 マーカーはRD/がアクティブになってからメモリからデータが出てくるまでの時間を示していて62.5nsでした。(この時ロジアナのサンプリング周波数は32MHzなので解像度は30ns程度です)
 使用しているメモリはHM628128D(DIPタイプ、128KBytes)でアクセスタイムは70nsなのでアクセスタイムにはあまり余裕はありませんが問題なく動作しているようです。
 Z80はPIC側から供給している16MHzで動作しています。(Z80は20MHz対応のチップを使用)

 NOP書換えではHALTから抜けれないことが判ったのでBIOSではNMIかRESETを使用することになりそうですが、PIC側で使用するI/O数を節約するために RESET方式にしようかと考えています(NMI方式にした場合でもRESETはPICから制御したいからねぇ)

 また、BUSREQ/はマシンサイクルの最後でチェックされ(Z80のマニュアルより:BUSREQ is always recognized at the end of the current machine cycle.)NMIよりも優先されるのでBUSACK/のチェックは省略可能と考えています。(SDカードの装着信号?を入力しておかないと起動後に抜き差しできなくなるのでI/O節約検討中なのですw)

HALT実験ソース(picle言語)
1:# HALT test by skyriver 2018/02/27 2: 3:use LibCpm; 4: 5:proc main() { 6: init(); 7: initPmp(); 8: 9: PmpOn(); 10: 11: PmpSetAdr( 0 ); 12: MemWr( $76 ); # HALT 13: MemWr( $00 ); # NOP 14: 15: PmpOff(); 16: 17: LATC[0] = $0008; # reset on 18: BusRelease(); 19: LATC[0] = $0009; # reset off 20:}


HALTコード実行時のZ80の挙動



 お遊びでZ80の全メモリをNOP(00h)に書き換えるプログラムを動かしてみました。
 このコードなら今でもそらで機械語を言えます ^^

 ロジアナ波形を見ると左側1/3くらいからデータバスがlowに貼り付き、WR/はhighに貼り付きます。
 Z80は全メモリNOPコードの中、アドレス(PC)を進めるのみの動作になります。
 昔のマイコンはメモリ空間上にVRAMがあったのでVRAM上での命令実行時に画面にノイズが載ってZ80の走行状態を目視できたんだよねぇw

全メモリクリアソース(picle言語)
:l 1:# all memory clear with Z80 by skyriver 2018/02/28 2: 3:use LibCpm; 4: 5:proc main() { 6: init(); 7: initPmp(); 8: 9: PmpOn(); 10: PmpSetAdr( 0 ); 11: MemWr( $21 ); # LD HL,0001h 12: MemWr( $01 ); 13: MemWr( $00 ); 14: MemWr( $36 ); # LD (HL),0e9h 15: MemWr( $e9 ); 16: MemWr( $2b ); # DEC HL 17: MemWr( $f9 ); # LD SP,HL 18: MemWr( $36 ); # LD (HL),0e5h 19: MemWr( $e5 ); 20: MemWr( $e9 ); # JP (HL) 21: 22: PmpOff(); 23: LATC[0] = $0008; # reset on 24: BusRelease(); 25: LATC[0] = $0009; # reset off 26: Timer_ = 50; 27: while ( Timer_ ); 28: dump( 0 ); 29:} :run 0000 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0010 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0020 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0030 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0040 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0050 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0060 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0070 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :

★2018/02/28 変更 メモリクリア部を1byte短縮w


全メモリクリアで永遠にNOPを実行し続ける


[TOP] [ 前へ ] 連載記事 [ 次へ ]

nice!(0)  コメント(4) 
共通テーマ:趣味・カルチャー

レトロマイコンZ80ボードの構想(その9)CP/M80 BIOS検討 [Z80]

 ebayで注文したブレッドボード用の接続コードがまだ届かず Z80 と PIC24FJ64GA004 のインターフェース部分の実験ができず待ちの状態なのでCP/MのBIOS部分の検討を少しやってみました。

 インテル系のニーモニックはあまり好きじゃないのでザイログ系のニーモニックがフルに使えるMACRO-80(m80.com)をCP/Mエミュ上で使うことに決めました。

 何十年かぶりの m80・・・^^
 avrCPM用のbios.asmを基にしてザイログニーモニックへの変換はすぐにできましたが、ディスクパラメータ生成のためのmac.com用のマクロがそのままでは動かず、自力でm80用に変換しようかとも思ったけどネットで探したら見つかった^^

bios.macの先頭部分抜粋
MSIZE EQU 62 ;size of available RAM in k BIAS EQU (MSIZE-20) * 1024 CCP EQU 3400H+BIAS ;base of cpm ccp BDOS EQU CCP+806H ;base of bdos BIOS EQU CCP+1600H ;base of bios CDISK EQU 0004H ;current disk number (0 ... 15) IOBYTE EQU 0003H ;intel iobyte BUFF EQU 0080H ;default buffer address RETRY EQU 3 ;max retries on disk i/o before error CR EQU 13 LF EQU 10 NSECTS EQU ($-CCP)/128 ;warm start sector count ASEG ORG 100H .PHASE BIOS .Z80 JP BOOT WBOOTE: JP WBOOT JP CONST JP CONIN JP CONOUT JP LIST JP PUNCH JP READER JP HOME JP SELDSK JP SETTRK JP SETSEC JP SETDMA JP READ JP WRITE JP LISTST JP SECTRAN SIGNON: DB CR,LF DB MSIZE/10+'0' DB (MSIZE mod 10) + '0' DB 'k CP/M Version 2.2 COPYRIGHT (C) 1979, DIGITAL RESEARCH' DB CR,LF,0 BOOT: LD SP,BUFF LD HL,SIGNON CALL PRMSG XOR A LD (IOBYTE),A LD (CDISK),A JP GOCPM


 あちこちいじっていますが、アセンブルが通りました。

超久々にm80でザイログニーモニックソースのアセンブル

 ディスクパラメータも想定通りに展開されています。^^

ディスクパラメータ生成
; Name spt bls dks dir cks off dpb dpb_A, 64, 2048, 972, 256, 0, 1 F38B + dpb_A: ddw %64,<;sec per track> F38B 0040 + dw 64 ;sec per track F38D 04 + db 4 ;block shift F38E 0F + db 15 ;block mask F38F 00 + db 0 ;extnt mask F390 03CB + dw 971 ;disk size-1 F392 00FF + dw 255 ;directory max F394 F0 + db 240 ;alloc0 F395 00 + db 0 ;alloc1 F396 0000 + dw 0 ;check size F398 0001 + dw 1 ;offset dpb dpb_B, 64, 2048, 976, 256, 0, 244 F39A + dpb_B: ddw %64,<;sec per track> F39A 0040 + dw 64 ;sec per track F39C 04 + db 4 ;block shift F39D 0F + db 15 ;block mask F39E 00 + db 0 ;extnt mask F39F 03CF + dw 975 ;disk size-1 F3A1 00FF + dw 255 ;directory max F3A3 F0 + db 240 ;alloc0 F3A4 00 + db 0 ;alloc1 F3A5 0000 + dw 0 ;check size F3A7 00F4 + dw 244 ;offset


 Z80とPIC24FJ64GA004とのインターフェースに関してはこれから細かく考えますが、boot時のシステム読込みはSDカードからではなく、PIC内のフラッシュから展開した方が良さそう。

 あと、Z80とPIC間のインターフェースでZ80側のNMIもリセットも使わない方法を実験予定です。うまく行けばI/Oが1bit節約できる ^^


[TOP] [ 前へ ] 連載記事 [ 次へ ]
nice!(0)  コメント(0) 
共通テーマ:趣味・カルチャー

レトロマイコンZ80ボードの構想(その8)パラレルマスターポート機能 [Z80]

 前回の記事「レトロマイコンZ80ボードの構想(その7)SDカード2」でSDカードのアクセス方法が確認できたので外部メモリ制御のためにPIC24FJ64GAのパラレルマスターポート(PMP)機能について実験してみました。

 PICに実装されているPMP機能については「レトロマイコンZ80ボードの構想(その2)」の記事でも少し書いていますがPIC24FJ64GA004では外部メモリ制御のためのアドレス信号はPMA10(アドレス信号合計で11本)までです。
 PICのピンアサインに関しては「レトロマイコンZ80ボードの構想(その5)ピンアサイン」を参照してください。

 今回使用したメモリは HM628128で128KBytesのDIPパッケージの5V動作のスタティックRAMです(アクセスタイム:70ns)。
 今回の評価実験回路については
  • アドレス線
     Z80のメモリ空間は64KBytesなのA16はGNDに固定。またCS2は5Vに接続

  • チップセレクト(CS1/)
     Z80からのバス切替時などにlowになると最悪メモリ内容が破壊される可能性もあるので5Vにプルアップし、PIC側のPMCS1はオープンドレインに設定

  • アドレスの上位ビット
     A14、A15はとりあえず、PIC側のAD13に接続

  • PMWR
     実験的にPIC内でプルアップ設定

としています。

 メモリ書込み時のロジアナ波形が下図です。
 PMPではメモリアクセス時のタイミングをPMMODE(パラレルマスタポート モードレジスタ)で設定でき、今回は
  • WAITB : 0
  • WAITM : 1
  • WAITE : 0

で設定しています(パラメータ名の末尾はそれぞれ Begin,Middle,End の意味だと思う)

 ライトストローブの後にCS1/がdisableになるまでの時間が長め(WAITEで調整)ですが最短設定にしています。

 データ線は読込み時にPIC側が入力状態になりますが、一部5Vトレラントでないポートがあります。時間的には一瞬なのでこのために壊れることはまずないと思いますが抵抗を入れる等、考慮した方がいいかも。
 アドレス線など、他の信号に関してはPIC側からの出力信号であり、3.3V駆動のPIC側の信号でもメモリ側の規格範囲内(Input high voltage Min 2.2V)です。

メモリ書込み波形


 メモリ書込み/読込み時の波形が下図です。
 0x0000アドレスから開始(アドレスは自動インクリメント)して0xa5と0x5aの2つのデータを書込んだだ後、書込んだデータを読み出している波形です。

 読み出し時にデータ線がバタついている部分がありますが、PIC側もメモリ側も入力状態なのでフローティング状態のためです。  バタつくのは良くないのでデータ線に関してはPIC側でプルアップ設定することでバタツキ対処をする予定です
★2018/02/13 修正 {
 3.3V電源が2.9Vの状態でした^^; 3.3Vにするとデータリード時のバタツキは発生しなくなりました(電源電圧が低くスレッショルド付近であったためバタツキ易くなっていたものと思います)。ロジアナのキャプチャも3.3Vのものに差し換えました。
}

メモリ書込み/読込み波形


★2018/02/12 追記
 メモリテスト中のロジアナ波形を追加しておきます。数十分間連続動作させましたがエラーは検出されませんでした。

メモリ試験中の波形



 今回の実験で作ったソースを末尾に貼っておきます。
 PMCS1はPMA14(アドレス線)と兼用なのでネット上で見つかる例はチップセレクトとしてPIC24FJ64GA004には無いPMCS2を使うものが殆どで、今回のようにPMCS1を使っている例は見つかりませんでした(海外等をじっくり探せば例があると思うけど探すより試した方が面白い)。

 メモリライトを2回行った後、メモリリードを2回行っていますが、最初のリードはPMPがメモリリードシーケンスを開始するためのトリガなので読込んだデータは前回のリード動作で読んだ値になっています。(n個のデータを読むためには(n+1)回の、PMDIN1レジスタの読込みが必要)

 また、init()の最後で実験的にPMWRをプルアップ設定してみたところ予想通り、PMPをdisableにした後も信号レベルはhighを保持する(ポート入力機能以外でもPullUp設定は有効)ようになりました。

PMP機能の実験用に作ったソース(picle言語)
:l 1:# PMP test for PIC24FJ64004 2:# ver 0.01 2018/02/10 by skyriver 3: 4:var REG,_REG; 5:var PMCON,PMMODE,PMADDR,PMDAT,PMAEN,PMSTAT; 6:var Pmcon, Pmmode; 7: 8:# print value 9:proc PrnVal( str, val ) { 10: PrnStr_( str ); 11: PrnHex_( val ); 12:} 13: 14: 15:proc ChkBsy() { 16: while ( PMMODE[0] & $8000 ) {} 17:} 18: 19: 20:proc SetAdr( adr ) { 21: ChkBsy(); 22: PMADDR[0] = adr | $4000; 23:} 24: 25: 26:proc MemWr( dat ) { 27: ChkBsy(); 28: PMDAT[0] = dat; 29:} 30: 31: 32:func MemRd() { 33: ChkBsy(); 34: return = PMDAT[0]; 35:} 36: 37: 38:proc init() { 39: var pre,cen,post; 40: PMCON = $0600; # PMMODE[1], PMADDR[2] 41: PMMODE = $0602; 42: PMADDR = $0604; 43: PMDAT = $0608; 44: PMAEN = $060c; 45: PMSTAT = $060e; 46:# PADCFG1 = $02fc; 47: 48: Pmcon = $8380; # 1000 0011 1000 0000 49: PMCON[0] = Pmcon; 50: 51: pre = 0; # 2bit 52: cen = 1; # 4 bit 0:31.25ns 1:62.5ns 2:125ns 53: post = 0; # 2bit 54: Pmmode = $0a00|(pre*64)|(cen*4)|(post); # 00xx x010 xxxx xxxx 55: PMMODE[0] = Pmmode; 56: 57: PMAEN[0] = $47ff; # PMAEN 0100 0111 1111 1111 58:# PADCFG1[0] = $0000; # default 59: 60: asm_( $A8E2CF ); # bset ODCB,#15 61: REG = $02c8; # TRISB 62: REG[2] = 0; # LATB 63: REG[0] = $fff8; # AD11-13 64: 65: REG = $0068; # CNPU1 66: REG[0] = $1000; # pull up CN16 PMWR 67:} 68: 69: 70:proc main() { 71: var dat; 72: init(); 73: 74: SetAdr( 0 ); # set addr 75: MemWr( $a5 ); 76: MemWr( $5A ); 77: 78: SetAdr( 0 ); # set addr 79: dat = MemRd(); 80: dat = MemRd(); 81: 82: PMCON[0] = $0380; # PMP disable 83: PrnVal( "\npmcon : ", Pmcon ); 84: PrnVal( "\npmode : ", Pmmode ); 85:} 86: :run pmcon : 8380 pmode : 0A04 :


[TOP] [ 前へ ] 連載記事 [ 次へ ]
nice!(0)  コメント(0) 
共通テーマ:趣味・カルチャー

レトロマイコンZ80ボードの構想(その7)SDカード2 [Z80]

 前回の記事「レトロマイコンZ80ボードの構想(その6)SDカード」でSDカードとのSPI通信のロジアナ波形を掲載しましたが、ブロック読込み時に読込みデータ間にクロックが停止する隙間がでるのが嫌なのでSPI通信の処理を見直しました。

  • リード時の隙間
     SPI通信でデータリード時にデータ間にクロックの停止する隙間が発生するのはやはりもったいない。SPIモジュール(ハード)自体の制約によるものではないので隙間なく受信するように変更しました。

  • CSをhighに変更後のクロック提供
     web上の情報ではCSをhighにしてから1バイト(0xff)を送信する必要があるという情報を見かけましたが、波形を見てみるとSDカードからの応答の最後のバイトのLSBがlowの場合、その後のクロック提供がないと、DOをlowに引っ張り続けることがあるけどクロック入力によりパラ-シリ変換がシフトされる(ゴミが残った場合吐き出される)とDOがhighに復帰するので供給するクロックは1クロック以上であればいいように思えます。
     今回はわざわざ1バイトの0xffを送らないでSPI受信処理時のクロック提供のための0xff送信でバッファを使うようにしました。
     受信完了後にバッファ内の0xffデータが送信されるのでSDカード側のごみ吐出しはできるものと思います。

 改良版でのSPI波形を参考に貼っておきます。今回はブロックライトとブロックリードの波形も付けました。

★2018/02/10 追記 {
 SDカード初期化時のクロックは333kHzです。初期化後クロック切替えの実験をしたところ、SPI1CON1のプリスケーラの再設定だけではクロックが変わらず、一旦、SPIをdisableにしてからプリスケーラを設定後、SPIをイネーブルにする必要がありました。
 picleソースで書くと

    SPISTAT[0] = $0000;
#   SPISTAT[1] = $7a;    # SPI1CON1 prescale2:1,prescale4:1  = 8:1  2M NG
    SPISTAT[1] = $7d;    # SPI1CON1 prescale1:1,prescale16:1 = 16:1 1M OK
    SPISTAT[0] = $8000;

 こんな感じです。
 コメントに書いたようにブロック書込み/読込み動作が2MHzではNG(DIのデータを取りこぼす)で1MHzではokでした。(PIC24FJのクロックは内蔵の32MHz)
}


CMD0波形

CMD8波形

ACMD41波形(アイドル状態なのでリトライ)

ACMD41波形(0x00のレスポンス(OK))

CMD58波形

CMD24(ブロックライト)波形

CMD24(ブロックライト:データ送信後wait)波形

CMD24(ブロックライト:wait解除され終了)波形

CMD17(ブロックリード)波形

CMD17(ブロックリード:SDカードがパケット送信開始)波形

CMD17(ブロックリード:パケット受信完了)波形


 今回の実験で作成した picleソースは次のとおりです。SRAM上にソースが入りきらなくなってきたのでmain()部分と関数部分を分離し、main()側でフラッシュメモリにセーブした関数ソースをインクルードしています。


実験で使用したソース:関数部分(picle言語)
#LibSpi SPI test to connect SD card for PIC24FJ64GA004 with picle # Ver 0.02 by skyriver 2018/02/08 var SPISTAT,SPIBUF; var _RPINR20,RPOR0; var _REG,AD1PCFG; var TRISA,LATA; var ByteTimer,SdhcFlg; var SpiDat,_Buf; proc init() { SPISTAT = $0240; # SPI1 status SPIBUF = $0248; RPOR0 = $06c0; AD1PCFG = $032c; AD1PCFG[0] = $ffff; # I/O TRISA = $02c0; LATA = TRISA + 4; SPISTAT[1] = $0075; # SPI1CON1 pre 2:3,Post 1:16 = 48:1 333k SPISTAT[2] = 0; # SPI1CON2 SPISTAT[0] = $8000; _RPINR20 = $06a8; _RPINR20[0] = 2; # SDI -> RP2 RPOR0[0] = $0708; # CLK -> RP0, SDO ->RP1 TRISA[0] = TRISA[0] & $fffb; LATA[0] = $0004; _Buf = Array_(0); ByteTimer = 30; } proc SpiCheck() { if ( SPISTAT[0]&1 ) { SpiDat = SPIBUF[0]; } } # wait about 1.8us * n proc TmWait( n ) { for (; n ; n=n-1) { SpiCheck(); } } proc SpiSnd( dat ) { do { SpiCheck(); } while ( SPISTAT[0]&2 ); SPIBUF[0] = dat; } func SpiRcv() { do { if ( (SPISTAT[0]&2) = 0 ) { SPIBUF[0] = $ff; } } while ( (SPISTAT[0]&1) = 0 ); return = SPIBUF[0]; } func SpiRcvAns() { do { return = SpiRcv(); } while ( return = $ff ); } proc SpiRcvN( n ) { var i; for ( i=0; i < n; i=i+1 ) { _Buf[i] = SpiRcv(); } } proc SetCsDisable() { LATA[0] = $0004; TmWait( ByteTimer ); } proc PrnVal( str, val ) { PrnStr_( str ); PrnHex_( val ); } # return 0:NG, 1:OK func BlkRead( sec ) { var ans; LATA[0] = 0; SpiSnd( $51 ); # CMD17 SpiSnd( 0 ); SpiSnd( 0 ); SpiSnd( sec / 256 ); SpiSnd( sec & $ff ); SpiSnd( $ff ); # dummy CRC ans = SpiRcvAns(); if ( ans = 0 ) { ans = SpiRcvAns(); # Data Token if ( ans = $fe ) { var i; for ( i=0; i<128; i=i+1 ) { SpiRcvN( 512 / 128 ); } } SpiRcvN( 2 ); } SetCsDisable(); return = ans = $e5; } # return 0:NG, 1:OK func BlkWrite( sec ) { var i; LATA[0] = 0; SpiSnd( $58 ); # CMD24 SpiSnd( 0 ); SpiSnd( 0 ); SpiSnd( sec / 256 ); SpiSnd( sec & $ff ); SpiSnd( $ff ); # dummy CRC if ( SpiRcvAns() = 0 ) { SpiSnd( $fe ); # send token for ( i = 0; i<512; i=i+1 ) { SpiSnd( i & $ff ); } SpiSnd( $ff ); # dummy CRC SpiSnd( $ff ); return = SpiRcvAns() = $e5; while ( SpiRcv() = 0 ) {} } SetCsDisable(); }


実験で使用したソース:main()部分(picle言語)
# SPI test to connect SD card for PIC24FJ64GA004 with picle # Ver 0.02 by skyriver 2018/02/08 use LibSpi; proc main() { var ans,i; init(); LATA[0] = $0004; for ( i=0; i<10; i=i+1 ) { SpiSnd( $ff ); } TmWait( ByteTimer * 2 ); LATA[0] = 0; SpiSnd( $40 ); # CMD0 SpiSnd( 0 ); SpiSnd( 0 ); SpiSnd( 0 ); SpiSnd( 0 ); SpiSnd( $95 ); ans = SpiRcvAns(); SetCsDisable(); if ( ans <> 1 ) { PrnVal( "Cmd0Res:", ans ); } else { LATA[0] = 0; SpiSnd( $48 ); # CMD8 SpiSnd( 0 ); SpiSnd( 0 ); SpiSnd( 1 ); SpiSnd( $aa ); SpiSnd( $87 ); ans = SpiRcvAns(); SpiRcvN( 4 ); # 16M:00 00 01 aa SetCsDisable(); if ( ans <> 1 ) { PrnVal( "CMD8 err:", ans ); } else { if ( (_Buf[2] <> $01) | (_Buf[3] <> $aa ) ) { PrnStr_("SDC not v2" ); } else { SdhcFlg = 1; do { LATA[0] = 0; SpiSnd( $77 ); # CMD55 SpiSnd( 0 ); SpiSnd( 0 ); SpiSnd( 0 ); SpiSnd( 0 ); SpiSnd( $65 ); ans = SpiRcvAns(); if ( ans = 1 ) { SpiSnd( $69 ); # ACMD41 SpiSnd( $40 ); SpiSnd( $ff ); SpiSnd( $80 ); SpiSnd( $00 ); SpiSnd( $17 ); ans = SpiRcvAns(); } SetCsDisable(); } while ( ans <> 0 ); LATA[0] = 0; SpiSnd( $7a ); # CMD58 SpiSnd( 0 ); SpiSnd( 0 ); SpiSnd( 0 ); SpiSnd( 0 ); SpiSnd( $fd ); ans = SpiRcvAns(); SpiRcvN( 4 ); # 16MB:c0 ff 80 00 SetCsDisable(); if ( ans <> 0 ) { PrnVal( "CMD58 err:", ans ); } if ( BlkWrite( 4 ) ) { if ( BlkRead( 4 ) ) { PrnStr_( "Ok" ); } } } } } LATA[0] = $0004; }


★2018/05/09 追記
 SDHCタイプのSDカードのブロックサイズは 512バイトでCP/Mのディスクリード/ライト時の最小サイズ(128バイト)より大きいため、ブロッキング/デブロッキング処理する必要があります。また、ブロッキング/デブロッキング処理のサンプルソースがCP/Mのディスク内に添付されているケースもあるようです。

 この処理を実施した場合、読込みは速くなる(1セクタの読込みで4個分読めるので)けど、書込みは一度該当セクタを読込み、書込み対象部分をアップデート後、セクタ書込みする必要があるので2倍程度遅くなります。
 ※BIOSへの書き込み要求時にC-regに下記情報が渡されるので単純に2倍遅くなるわけではない。
  C=0 - Write can be deferred
  C=1 - Write must be immediate
  C=2 - Write can be deferred, no pre-read is necessary.

 実際待ち時間が生じるのはHI-TECH Cでコンパイルする場合などのケースであり、この場合、読込みと同様に書込みも頻繁に行われているのでブロッキング/デブロッキングの処理で遅くしたくはありません。

 今回はSDHCカードのセクタの先頭の128バイトのみを使うことでブロッキング/デブロッキング処理を省略し、書込み時のパフォーマンス低下を防ぐことにしました。
(SDカードを無駄遣いしているようにも思えますが、CP/Mで使用できるのはSDカードの先頭部分のほんの少しだけなので無駄ということにはならない)

 SDHCのコマンドを眺めていたらブロックサイズを設定するコマンドがあったので試してみました。ブロックサイズを128にできれば未使用部分のセクタ先頭以外の3/4の読み/書きが不要になり高速化できるはずです。

 このブロックサイズ指定のコマンドへの対応はSDカードに依存するようなことがネット情報にあり、16GBのSDカードを用いた実験結果としては
  • ブロック指定コマンドに対してはOK応答を返してくるけど、ブロック読込みで128バイト読込み、再度ブロック読込みすると129バイト目からのデータを吐き出してくるように見える(下記キャプチャ)

  • ブロックサイズ設定がうまく行ったら二つ目のセクタの読み出し位置が先頭から129バイト目になるのではという期待もありましたが、読み出し位置はブロックサイズ指定後も変化しませんでした(指定対象サイズがセクタではなくブロックなので当然かも)

 下のキャプチャがブロックサイズ指定のコマンドを発行している時の波形でSDカードからは OK 応答が帰ってきています。(その後クロックを1MHzに上げている)

ブロックサイズ指定コマンド波形


 下のキャプチャは128バイト分のブロック読込み後、別のセクタのブロック読込みを開始している時の波形です。
 始めのブロックの最後の2バイトがCRCコードになっておらず、次のブロック読込みのコマンド発行中に129バイト目以降のデータが送られてきています(いずれもデータは0e5h)

ブロックサイズ指定後のブロック読み出し



[TOP] [ 前へ ] 連載記事 [ 次へ ]

nice!(0)  コメント(1) 
共通テーマ:趣味・カルチャー

迷惑コメント発生中 [日記]

 やったぁ~。本日のページビューは1千を超えました ^^

 というか、実は数日前から特定のページにアルファベット文字だけの内容でリンクが多数の何かの売込みのコメント書込みが多発しています。

 昨日まではその都度マニュアル操作で消していたんですがそれが気に入らなかった(気に入った?w)のか今朝から頻度が激増しました。

 そうなんです・・・ページビューのほとんどはこのカキコのアクセスが占めてします・・・

 書込み内容を変更しながら自動で書き込んでいるようです。

 このブログは「画像認証」機能があり、コメント書込みの際に画像に書かれた文字を正しく入力する必要があります。
 認証の文字列を読みづらい(と思われる)ものに変更してからは収まっているようですがもう少し様子を見たいと思います。(あまり反応すると増長しそうなのでしばらく放置)

 ん~ 明日のアクセスランキングが楽しみ・・w

nice!(0)  コメント(1) 
共通テーマ:趣味・カルチャー