### 6-10　フラッシュメモリの読み書き

フラッシュメモリへの書き込み、読み込み、ベリファイを行い、各フェーズが終了するごとに“SEGA”の文字を順次表示します。

60〜78行目は、フラッシュメモリに書き込むデータをRAMに準備します。データは0〜128の値で、間接アドレスレジスタを用いてRAMバンク1のアドレス10H〜8FHにセットします。データの準備フェーズを終えると、LCDに“S”の文字を表示します。

91〜102行目では、システムBIOSを呼び出すためにそのパラメータをセットし、ローバッテリ自動検出を禁止します。

104〜115行目では、システムBIOSを呼び出す前にシステムクロックをRC発振の6分周に切り換えています。システムBIOS呼び出し後は、元のクロック（水晶発振）に切り換えています。

クロック切り換え後は、ローバッテリ自動検出を有効にして、LCDに“E”を表示します。

フラッシュメモリにアクセス中は、ベースタイマーを含めすべての割り込みを禁止してください。ベースタイマーは内蔵の時計機能が利用していますので、できる限り割り込み禁止時間を短くしてください。時計が遅れる原因になります。 また、フラッシュメモリへの書き込みの際は、システムクロックを1/6分周のRC発振にしてください。読み込みの際は、1/12分周でかまいません。

128〜146行目は、フラッシュメモリに書き込んだデータと、RAMのデータをシステムBIOSのベリファイ機能を使って比較します。完全に同一であれば、LCDに“G”を表示します。データが一致せずシステムBIOSがエラーを返した場合は“G”の文字を表示せず次のフェーズを実行します。

159〜173行目では、フラッシュメモリに書き込んだデータをRAMに読み出しています。読み出したデータは、172行目以降にある自前の比較ルーチンでデータを検証しています。データが完全に一致した場合は“A”の文字を表示しプログラムを終了します。もし、一致しなかった場合は“A”の文字を表示せずに終了します。

“G”や“A”の文字が表示されなかった場合は、それ以前に行ったフラッシュメモリへのアクセスでデータが化けていることになります。

357行目以降のデータは、データの書き込み先（フラッシュメモリ）です。

フラッシュメモリに書き込みを行う場合は、必ずアプリケーション自身内に書き込む領域を用意します。アプリケーション外のフラッシュメモリへの書き込みは禁止されています。

フラッシュメモリのアクセスは、常に128バイト単位で行われますので、364行目のORGで128バイトのアライメントを行っています。

フラッシュメモリの領域確保には、アセンブラ疑似命令のDSコマンドは利用できません。DSコマンドは、RAM領域に対してのみ有効です。

>     001	; Tab width = 4
>     002
>     003	;----------------------------------------------------------------------------
>     004	; ** フラッシュメモリ使用サンプル1 **
>     005	;
>     006	; フラッシュメモリにデータを書き込み、ベリファイし、読み出し、検証する。
>     007	; 全てが良好に動作するとLCD上に「SEGA」の文字が揃って表示される。
>     008	;----------------------------------------------------------------------------
>     009	; 1.01 990208 SEGA Enterprises,LTD.
>     010	;----------------------------------------------------------------------------
>     011
>     012	chip	LC868700			; チップの種類をアセンブラに指定
>     013	world	external			; 外部メモリ用プログラム
>     014
>     015	public	main				; ghead.asm から参照されるシンボル
>     016
>     017	extern	_game_end			; ghead.asm への参照シンボル
>     018	extern	fm_wrt_ex, fm_vrf_ex, fm_prd_ex	; ghead.asm への参照シンボル
>     019
>     020
>     021	; **** システム定数の定義 ***************************************************
>     022
>     023								; OCR(発振制御レジスタ)設定値
>     024	osc_rc		equ 04dh		;	システムクロックに内蔵RC発振を指定(1/12)
>     025	osc_rcfw	equ 0cdh		;	システムクロックに内蔵RC発振を指定(1/6)
>     026	osc_xt		equ 0efh		;	システムクロックに水晶発振を指定
>     027
>     028	LowBattChk	equ 06eh		; ローバッテリ検出フラグ(RAMバンク0)
>     029
>     030	fmflag		equ 07ch		; フラッシュメモリ書き込み終了検出方式
>     031	fmbank		equ 07dh		; フラッシュメモリバンク切替え
>     032	fmadd_h		equ 07eh		; フラッシュメモリ上位アドレス
>     033	fmadd_l		equ 07fh		; フラッシュメモリ下位アドレス
>     034
>     035	fmbuff		equ 080h		; フラッシュメモリ読み書き用バッファ先頭
>     036
>     037	; *** データセグメント ******************************************************
>     038
>     039			dseg				; データセグメント開始
>     040
>     041	r0:		ds		1			; 間接アドレッシングレジスタ r0
>     042	r1:		ds		1			; 間接アドレッシングレジスタ r1
>     043	r2:		ds		1			; 間接アドレッシングレジスタ r2
>     044	r3:		ds		1			; 間接アドレッシングレジスタ r3
>     045			ds		12			; その他のシステム予約レジスタ
>     046
>     047	; *** コードセグメント ******************************************************
>     048
>     049			cseg				; コードセグメント開始
>     050
>     051	; *-------------------------------------------------------------------------*
>     052	; * ユーザープログラム														*
>     053	; *-------------------------------------------------------------------------*
>     054	main:
>     055			call	cls			; LCD表示イメージを消去する
>     056
>     057
>     058								; **** テスト書き込み用のデータを準備する ****
>     059								; fmbuff に 10h〜8fh の 128byte のデータを用意
>     060
>     061			push	PSW			; PSW値を退避
>     062			set1	PSW,1		; データRAMバンク1を選択
>     063
>     064			mov		#fmbuff,r0	; 読み書きバッファのアドレスを r0 に
>     065			mov		#128,c		; ループカウンタ(128回)
>     066			mov		#010h,b		; 書き込むデータの初期値
>     067	loop4:
>     068			ld		b			; データをバッファに置く
>     069			st		@r0			;
>     070
>     071			inc		b			; 書き込みテスト用データを変える
>     072
>     073			inc		r0			; バッファのアドレスをインクリメント
>     074
>     075			dec		c			; ループカウンタのデクリメント
>     076			ld		c
>     077			bnz		loop4		; 128回の繰り返し
>     078
>     079			pop		PSW			; PSW値を復帰
>     080
>     081
>     082								; **** 「S」を表示 ****
>     083
>     084			mov		#1,c		; 水平座標
>     085			mov		#1,b		; 垂直座標
>     086			mov		#0ah,acc	; キャラクタコード 'S'
>     087			call	putch		; 一文字表示
>     088
>     089
>     090								; **** フラッシュメモリへの書き込み ****
>     091
>     092			push	PSW			; PSW値を退避
>     093			set1	PSW,1		; データRAMバンク1を選択
>     094
>     095			mov		#0,fmbank	; フラッシュメモリのバンク指定 = 0
>     096			mov		#high(fmarea),fmadd_h	; 書き込み先アドレス(上位)
>     097			mov		#low(fmarea),fmadd_l	; 書き込み先アドレス(下位)
>     098
>     099			clr1	PSW,1		; データRAMバンク0を選択
>     100			mov		#0ffh,acc	; ローバッテリ検出をしない(0ffh)
>     101			st		LowBattChk	; ローバッテリ自動検出フラグ(RAMバンク0)
>     102
>     103			pop		PSW			; PSW値を復帰
>     104
>     105			push	OCR			; OCR値を退避
>     106			mov		#osc_rcfw,OCR ; システムクロックを指定(RC)
>     107			call	fm_wrt_ex	; BIOS「フラッシュメモリへの書き込み」
>     108			pop		OCR			; OCR値を復帰
>     109
>     110			push	PSW			; PSW値を退避
>     111			clr1	PSW,1		; データRAMバンク0を選択
>     112			mov		#0,acc		; ローバッテリ検出をする(0)
>     113			st		LowBattChk	; ローバッテリ自動検出フラグ(RAMバンク0)
>     114			pop		PSW			; PSW値を復帰
>     115
>     116
>     117								; **** 「E」を表示 ****
>     118
>     119			mov		#2,c		; 水平座標
>     120			mov		#1,b		; 垂直座標
>     121			mov		#0bh,acc	; キャラクタコード 'E'
>     122			call	putch		; 一文字表示
>     123
>     124
>     125								; **** フラッシュメモリとのベリファイ ****
>     126
>     127			push	PSW			; PSW値を退避
>     128			set1	PSW,1		; データRAMバンク1を選択
>     129
>     130			mov		#0,fmbank	; フラッシュメモリのバンク指定 = 0
>     131			mov		#high(fmarea),fmadd_h	; アドレス(上位)
>     132			mov		#low(fmarea),fmadd_l	; アドレス(下位)
>     133
>     134
>     135			push	OCR			; OCR値を退避
>     136			mov		#osc_rc,OCR ; システムクロックを指定(RC)
>     137			call	fm_vrf_ex	; BIOS「フラッシュメモリとのベリファイ」
>     138			pop		OCR			; OCR値を復帰
>     139
>     140			pop		PSW			; PSW値を復帰
>     141
>     142			bnz		vrt_bad		; 書き込み失敗分岐
>     143								; 成功時のみ「G」を表示する
>     144
>     145								; **** 「G」を表示 ****
>     146
>     147			mov		#3,c		; 水平座標
>     148			mov		#1,b		; 垂直座標
>     149			mov		#0ch,acc	; キャラクタコード 'G'
>     150			call	putch		; 一文字表示
>     151	vrt_bad:
>     152
>     153
>     154								; **** フラッシュメモリのページデータ読み出し ****
>     155
>     156			push	PSW			; PSW値を退避
>     157			set1	PSW,1		; データRAMバンク1を選択
>     158
>     159			mov		#0,fmbank	; フラッシュメモリのバンク指定 = 0
>     160			mov		#high(fmarea),fmadd_h	; アドレス(上位)
>     161			mov		#low(fmarea),fmadd_l	; アドレス(下位)
>     162
>     163			push	OCR			; OCR値を退避
>     164			mov		#osc_rc,OCR ; システムクロックを指定(RC)
>     165			call	fm_prd_ex	; BIOS「フラッシュメモリのページデータ読み出し」
>     166			pop		OCR			; OCR値を復帰
>     167
>     168			pop		PSW			; PSW値を復帰
>     169
>     170
>     171								; **** 読み込んだデータを検証する ****
>     172
>     173			push	PSW			; PSW値を退避
>     174			set1	PSW,1		; データRAMバンク1を選択
>     175
>     176			mov		#fmbuff,r0	; 読み書きバッファのアドレスを r0 に
>     177			mov		#128,c		; ループカウンタ(128回)
>     178			mov		#010h,b		; 比較用データの初期値
>     179	loop5:
>     180			ld		b			; データをバッファに置く
>     181			sub		@r0			; データを比較
>     182			bnz		read_bad	; 比較エラー.「A」を表示せず終了
>     183
>     184			inc		b			; 書き込みテスト用データを変える
>     185
>     186			inc		r0			; バッファのアドレスをインクリメント
>     187
>     188			dec		c			; ループカウンタのデクリメント
>     189			ld		c
>     190			bnz		loop5		; 128回の繰り返し
>     191
>     192			pop		PSW			; PSW値を復帰
>     193
>     194
>     195								; **** 「A」を表示 ****
>     196
>     197			mov		#4,c		; 水平座標
>     198			mov		#1,b		; 垂直座標
>     199			mov		#0dh,acc	; キャラクタコード 'A'
>     200			call	putch		; 一文字表示
>     201
>     202
>     203	read_bad:
>     204	loop6:						; ** [M](モード)ボタンチェック **
>     205			ld		P3
>     206			bn		acc,6,finish ; [M]ボタンが押されていたらアプリ終了
>     207
>     208			br		loop6		; [M]ボタンが押されるまで待つ
>     209
>     210	finish:						; ** アプリケーション終了処理 **
>     211			jmp		_game_end	; アプリケーション終了
>     212
>     213
>     214	; *-------------------------------------------------------------------------*
>     215	; * LCD表示イメージを消去する												*
>     216	; *-------------------------------------------------------------------------*
>     217	cls:
>     218			push	OCR			; OCR値を退避
>     219			mov		#osc_rc,OCR ; システムクロックを指定
>     220
>     221			mov		#0,XBNK		; 表示用RAMのバンクアドレスを指定(BANK0)
>     222			call	cls_s		; そのバンク内のデータをクリア
>     223
>     224			mov		#1,XBNK		; 表示用RAMのバンクアドレスを指定(BANK1)
>     225			call	cls_s		; そのバンク内のデータをクリア
>     226			pop		OCR			; OCR値を復帰
>     227
>     228			ret					; cls終わり
>     229
>     230	cls_s:						; *** 表示用RAM 1BANK分の消去 ***
>     231			mov		#80h,r2		; 間接アドレッシングレジスタを表示用RAMの先頭に
>     232			mov		#80h,b 		; ループカウンタbにループ数をセット
>     233	loop3:
>     234			mov		#0,@r2		; アドレスをインクリメントしながら0を書き込む
>     235			inc		r2			;
>     236			dbnz	b,loop3		; bが0になるまで繰り返す
>     237
>     238			ret					; cls_s終わり
>     239
>     240
>     241	; *-------------------------------------------------------------------------*
>     242	; * 指定位置に1キャラクタ表示する											*
>     243	; * 入力 acc : キャラクタコード												*
>     244	; *        c : 文字水平位置												  	*
>     245	; *        b : 文字垂直位置												  	*
>     246	; *-------------------------------------------------------------------------*
>     247	putch:
>     248			push	XBNK
>     249			push	acc
>     250			call	locate		; 座標から表示RAMのアドレスを計算
>     251			pop		acc
>     252			call	put_chara	; 1キャラクタ表示する
>     253			pop		XBNK
>     254
>     255			ret					; putch終わり
>     256
>     257
>     258	locate:	; **** 表示位置指定から表示用RAMのアドレスを計算 ****
>     259			; ** 入力 c: 水平位置(0〜5) b: 垂直位置(0〜3)
>     260			; ** 出力 r2: RAMアドレス XBNK: 表示用RAMバンク
>     261
>     262								; *** 表示用RAMバンクアドレスの判断 ***
>     263			ld		b			; b>=2 のとき next1 へ
>     264			sub		#2			;
>     265			bn		PSW,7,next1	;
>     266
>     267			mov		#00h,XBNK	; 表示用RAMのバンクアドレスを指定(BANK0)
>     268			br		next2
>     269	next1:
>     270			st		b
>     271			mov		#01h,XBNK	; 表示用RAMのバンクアドレスを指定(BANK1)
>     272	next2:
>     273
>     274								; *** 表示指定位置のRAMアドレス計算 ***
>     275			ld		b			; b * 40h + c + 80h
>     276			rol					;
>     277			rol					;
>     278			rol					;
>     279			rol					;
>     280			rol					;
>     281			rol					;
>     282			add		c			;
>     283			add		#80h		;
>     284			st		r2			; RAMアドレスをr2に格納
>     285
>     286			ret					; locate終わり
>     287
>     288
>     289	put_chara:
>     290			push	PSW			; PSW値を退避
>     291			set1	PSW,1		; データRAMバンク1を選択
>     292
>     293								; *** キャラクタデータアドレスの計算 ***
>     294			rol					; (TRH,TRL) = acc*8 + fontdata
>     295			rol					;
>     296			rol					;
>     297			add		#low(fontdata)	;
>     298			st		TRL				;
>     299			mov		#0,acc			;
>     300			addc	#high(fontdata)	;
>     301			st		TRH			;
>     302
>     303			push	OCR			; OCR値を退避
>     304			mov		#osc_rc,OCR ; システムクロックを指定
>     305
>     306			mov		#0,b		; キャラクタデータ読み出し用オフセット値
>     307			mov		#4,c		; ループカウンタ
>     308	loop1:
>     309			ld		b			; 1ライン目の表示データを読み出す
>     310			ldc					;
>     311			inc		b			; 読み出しデータのオフセットを +1
>     312			st		@r2			; 表示データを表示用RAMに転送
>     313			ld		r2			; 表示用RAMアドレス +6
>     314			add		#6			;
>     315			st		r2			;
>     316
>     317			ld		b			; 2ライン目の表示データを読み出す
>     318			ldc					;
>     319			inc		b			; 読み出しデータのオフセットを +1
>     320			st		@r2			; 表示データを表示用RAMに転送
>     321			ld		r2			; 表示用RAMアドレス +10
>     322			add		#10			;
>     323			st		r2			;
>     324
>     325			dec		c			; ループカウンタのデクリメント
>     326			ld		c			;
>     327			bnz		loop1		; 8ライン分(4回)繰り返し
>     328
>     329			pop		OCR			; OCR値を復帰
>     330			pop		PSW			; PSW値を復帰
>     331
>     332			ret					; put_chara終わり
>     333
>     334
>     335	; *-------------------------------------------------------------------------*
>     336	; * キャラクタのビットイメージデータ										*
>     337	; *-------------------------------------------------------------------------*
>     338	fontdata:
>     339			db 07ch, 0e6h, 0c6h, 0c6h, 0c6h, 0ceh, 07ch, 000h	;'0' 00
>     340			db 018h, 038h, 018h, 018h, 018h, 018h, 03ch, 000h	;'1' 01
>     341			db 07ch, 0c6h, 0c6h, 00ch, 038h, 060h, 0feh, 000h	;'2' 02
>     342			db 07ch, 0e6h, 006h, 01ch, 006h, 0e6h, 07ch, 000h	;'3' 03
>     343			db 00ch, 01ch, 03ch, 06ch, 0cch, 0feh, 00ch, 000h	;'4' 04
>     344			db 0feh, 0c0h, 0fch, 006h, 006h, 0c6h, 07ch, 000h	;'5' 05
>     345			db 01ch, 030h, 060h, 0fch, 0c6h, 0c6h, 07ch, 000h	;'6' 06
>     346			db 0feh, 0c6h, 004h, 00ch, 018h, 018h, 038h, 000h	;'7' 07
>     347			db 07ch, 0c6h, 0c6h, 07ch, 0c6h, 0c6h, 07ch, 000h	;'8' 08
>     348			db 07ch, 0c6h, 0c6h, 07eh, 006h, 00ch, 078h, 000h	;'9' 09
>     349
>     350			db 07ch, 0e6h, 076h, 038h, 0dch, 0ceh, 07ch, 000h	;'S' 0a
>     351			db 0feh, 0c0h, 0c0h, 0f8h, 0c0h, 0c0h, 0feh, 000h	;'E' 0b
>     352			db 07ch, 0e6h, 0c0h, 0dch, 0c6h, 0e6h, 07ch, 000h	;'G' 0c
>     353			db 01eh, 036h, 066h, 0c6h, 0c6h, 0feh, 0c6h, 000h	;'A' 0d
>     354
>     355
>     356	; *-------------------------------------------------------------------------*
>     357	; * データ保存用フラッシュメモリ領域										*
>     358	; *-------------------------------------------------------------------------*
>     359			org ((*-1) land 0ff80h) + 80h		; 128byte アライン
>     360	fmarea:
>     361			; 128byte フラッシュメモリ領域を確保する
>     362			db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
>     363			db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
>     364			db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
>     365			db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
>     366			db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
>     367			db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
>     368			db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
>     369			db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
>     370
>     371	end

[←] | [INDEX] | [→]