FPGAでハードウェアアクセラレータを作る：①ワークメモリを作る

# まえおき
以前 投稿しました「Spartan6でmicroblaze mcs を動かす[①](https://qiita.com/cyebu1103/items/be327836084940eed003)[②](https://qiita.com/cyebu1103/items/28128b21875495d04b03)[③](https://qiita.com/cyebu1103/items/683e3a2fb6b65b4a7c1a)」にて、FPGA上でCPUを動作させることが可能になりました。

今後ハードウェアアクセラレータもどきを増築していきたいと思います。



#ハードウェアアクセラレータとは
ハードウェアアクセラレータとはCPUのバスにぶら下がっている専用の演算回路です。
特徴としては以下のようなメリットがあります。

* 特定の演算処理をCPUに代わって行うハードウェア
* CPUはアクセラレータに指示を投げて、結果だけをもう
* アクセラレータが演算中、CPUは他の処理を行うことができる
* 演算を並列処理できる（作り方次第）



# 構成
モジュールを以下のように構成します

![IP_1.jpg](https://qiita-image-store.s3.amazonaws.com/0/204268/6131798a-9e80-5bda-3bbc-70bce9000f14.jpeg)


* BUS I/F（バス信号のI/F）
 * メモリ（BlockRAM）のリードライトを行う
* DualPortMEM
 * データを貯めるデュアルポートメモリ
 * AポートはCPUから読み書きできる
 * BポートはLogic部から読み書きできる
 * AポートとBポートは非同期クロック
* Logic部（演算処理回路）
 * CPUからアクセスできる演算命令用のレジスタを実装する
 * 演算命令に応じてBRAMからデータを取り出し、演算結果をBRAMに書き戻す


# 今回作る回路
今回はBUS/Fとメモリの部分までを作成することとし、CPUからメモリに読み書きできることを目標にします。
（演算ロジック部分は次回の投稿にします）

# CPU バス I/F
CPUバスからのシングルリード/ライトアクセスの概要
![IP_2.jpg](https://qiita-image-store.s3.amazonaws.com/0/204268/7dd0154e-9e99-ed6a-cb88-fdf878eadbdf.jpeg)






Microblaze_MCSのポート名|図中の略称|機能|説明
-------|---------|----|----
IO_Addr_Strobe|a_stb|アドレスストローブ|Hのときアドレスが有効
IO_Read_Strobe|	r_stb|リードストローブ|Hでリードを要求
IO_Write_Strobe|w_stb|ライトストローブ|Hのときライトデータが有効
IO_Address|adr|アドレス|アクセス先のアドレスを示す<br>Microblaze_mcsは0xC000_0000がバス空間の先頭アドレス
IO_Byte_Enable|be|バイトイネーブル|32bitバス（4Byte）のうちアクセス対象Byteを示す。<br>intでアクセス⇒1111<br>shortでアクセス⇒0011 or 1100 <br> charでアクセス⇒0001 or 0010 or 0100 or 1000
IO_Write_Data|w_dat|ライトデータ|書き込みデータです
IO_Read_Data|r_dat|リードデータ|リードストローブが来たらレディがHになる間だけ出力します。<br>そのほかはL固定（他のモジュールとワイヤーORで共有するので）
IO_Ready|rdy|レディ応答|リード時：有効なリードデータとともにアサート<br>ライト時：処理完了後アサート<※>Microblazeはレディが帰ってこないとハングアップするので要注意！！


# RTL図


![IP_3.jpg](https://qiita-image-store.s3.amazonaws.com/0/204268/65fe9b9e-b0b1-ef18-5a8f-ca7a2744efcf.jpeg)

ブロック|概要
---|---
入力FF|バスの信号を一度叩くFFです
WriteContlorl|ブロックRAMのライトイネーブル信号を生成します<br>上位アドレスがヒットしているBRAMに対してバイトイネーブルとライトストローブのANDを通します。
ReadContlorl|上位アドレスがヒットしているBRAMの出力を後段のセレクタでセレクトするための制御信号を生成します
BRAM|メモリ本体です、BRAMを３面インスタンスしています。

# VHDLコード

バスの信号を１つづつ毎回記述すると、回路を複製するときに記述が多くなるのは嫌です。
バスの信号はパッケージにユーザー定義型（C言語でいう構造体みたいなもの）に定義して記述しました。

```vhdl:BUS_IF_package.vhd
-----------------------------------------------------------
-- Microblaze_MCSのバス信号 型定義
-----------------------------------------------------------
library	ieee;
use	ieee.std_logic_1164.all;
	
package	BUS_IF_package is
	
	-------------------------------------------------------
	--バス リクエスト（CPU => IP）
	-------------------------------------------------------
	--型定義
	type t_BUS_REQ is record
		a_stb	:std_logic						;--Address Strobe
		adr		:std_logic_vector(31 downto 0)	;--Address
		w_stb	:std_logic						;--Write Strobe
		w_dat	:std_logic_vector(31 downto 0)	;--Write Data
		be		:std_logic_vector(3 downto 0)	;--Byte Enable
		r_stb	:std_logic						;--Read Strobe
	end record;
	
	--配列
	type ta_BUS_REQ
		is array(integer range <>) of t_BUS_REQ;
		
	--初期値
	constant t_BUS_REQ_ini	:t_BUS_REQ:=('0',x"00000000",'0',x"00000000","0000",'0');
		
	-------------------------------------------------------
	--バス レスポンス（COU <= IP）
	-------------------------------------------------------
	--型定義
	type t_BUS_RES is record
		rdy		:std_logic						;--Ready
		r_dat	:std_logic_vector(31 downto 0)	;--Read Data
	end record;
	
	--配列
	type ta_BUS_RES
		is array(integer range <>) of t_BUS_RES; 
	
	--初期値
	constant t_BUS_RES_ini	:t_BUS_RES	:=('0',x"00000000");
	
end package;
```


```vhdl:BUS_IF.vhd
--------------------------------------------------------------------
-- CPUバスにぶら下げるワークメモリ
-- DualPortRAM(32bit×512)を２面インスタンスしている
-- 
-- ※今後RAMのデータを演算するロジックを追加して演算アクセラレータにする
--	------------+--------------------
--	BA + 0x0800	|ワークメモリＡ面
--		:		|
--	BA + 0x07FF	|
--	------------+--------------------
--	BA + 0x0800	|ワークメモリＢ面
--		:		|
--	BA + 0x0FFF	|
--	------------+--------------------
--	BA + 0x1000	|ワークメモリＣ面
--		:		|
--	BA + 0x17FF	|
--	------------+--------------------
--	BA + 0x1000	|ロジック領域
--		:		|(演算命令レジスタ)
--	BA + 0x17FF	|※今後追加
--------------------------------------------------------------------
library	ieee;
use	ieee.std_logic_1164.all;
use	ieee.std_logic_unsigned.all;

use	work.BUS_IF_package.all;--CPUバスをまとめたType宣言を読み込む
	
	entity BUS_IF is
		generic(
		BASE_ADR	:std_logic_vector(31 downto 0)		);--ベースアドレス
		port(
		i_rst		:in		std_logic					;--リセット
		i_bus_clk	:in		std_logic					;--クロック
		i_bus		:in		t_BUS_REQ					;--CPU_BUS
		o_bus		:out	t_BUS_RES					);--CPU_BUS
	end	entity;
	
architecture rtl of BUS_IF is
	constant	N	:integer	:=2;--メモリインスタンス数-1
	-----------------------------------------------------------------
	-- Type
	-----------------------------------------------------------------
	--ライトイネーブルをアレイにした型定義
	type typ_WEA is 
		array(integer range <>) of std_logic_vector(3 downto 0);
	--ＢＲＡＭ出力データのアレイ型
	type typ_DOUT is 
		array(integer range <>) of std_logic_vector(31 downto 0);
	-----------------------------------------------------------------
	-- Signal
	-----------------------------------------------------------------
	--入力FF
	signal	be		:std_logic_vector(3 downto 0)	:=(others=>'0')	;
	signal	adr		:std_logic_vector(31 downto 0)	:=(others=>'0')	;
	signal	w_stb	:std_logic						:='0'			;
	signal	w_dat	:std_logic_vector(31 downto 0)	:=(others=>'0')	;
	signal	r_stb	:std_logic						:='0'			;
	--
	signal	rd_cnt	:std_logic_vector(0 to N)		:=(others=>'0')	;
	signal	r_valid	:std_logic_vector(0 to N)		:=(others=>'0')	;
	--
	signal	rdy_or	:std_logic										;
	signal	rdy		:std_logic						:='0'			;
	signal	r_dat	:std_logic_vector(31 downto 0)	:=(others=>'0')	;
	signal	hit_mem	:std_logic_vector(0 to N)						;
	--Memory I/F
	signal	rsta	:std_logic_vector(N downto 0)	:=(others=>'0')	;
	--Memory I/F(A side)
	signal	wea		:typ_WEA(0 to N)				:=(others=>x"0");
	signal	addra	:std_logic_vector(8 downto 0)					;
	signal	dina	:std_logic_vector(31 downto 0)					;
	signal	douta	:typ_DOUT(0 to N)							;
	--Memory I/F(B side)
	signal	web		:std_logic_vector(3 downto 0)	:=(others=>'0')	;
	signal	addrb	:std_logic_vector(8 downto 0)	:=(others=>'0')	;
	signal	dinb	:std_logic_vector(31 downto 0)	:=(others=>'0')	;
	signal	doutb	:typ_DOUT(0 to N)								;
	
begin	
	
	---------------------------------------
	--CPUバスインターフェース
	---------------------------------------
	process(i_bus_clk)begin
		if(Rising_edge(i_bus_clk))then
			------------------------
			--Stage1：入力信号受けFF
			------------------------
			--アドレス
			if(i_bus.a_stb='1')then
				adr	<=i_bus.adr;
			end if;
			--バイトイネーブル
			be(0)	<=i_bus.be(0);
			be(1)	<=i_bus.be(1);
			be(2)	<=i_bus.be(2);
			be(3)	<=i_bus.be(3);
			--ライトストローブ
			w_stb	<=i_bus.w_stb;
			--ライトデータ
			if(i_bus.w_stb='1')then
				w_dat	<=i_bus.w_dat;
			end if;
			--リードストローブ
			r_stb	<=i_bus.r_stb;
			
			--------------------------
			--Stage2：
			--------------------------
			--メモリリードデータ有効
			r_valid	<=rd_cnt;
			
			--------------------------
			--Stage3
			--------------------------
			--読み出しデータ
			case(r_valid)is
				when "100"	=>r_dat	<=douta(0);--A面
				when "010"	=>r_dat	<=douta(1);--B面
				when "001"	=>r_dat	<=douta(2);--C面
				when others	=>r_dat	<=(others=>'0');--応答時以外0固定
			end case;
			
			--レディ応答
			rdy		<=rdy_or;
		end if;
	end process;
	
	---------------------------------------
	--メモリアクセス制御
	---------------------------------------
	MEM_CONTLORL:for i in 0 to N generate
		--アドレス上位ヒット判定
		hit_mem(i)	<='1' when (adr(31 downto 11)=BASE_ADR(31 downto 11)+i)else '0';
		
		--ライトコントロール
		wea(i)	<=be when (hit_mem(i)='1') and (w_stb='1') else "0000";
		
		--リードコントロール
		rd_cnt(i)	<='1' when (hit_mem(i)='1') and (r_stb='1') else '0';
	end generate;
	
	--レディ応答条件
	rdy_or	<='1' when 
		(r_valid/="000" ) or
		(wea(0) /="0000") or
		(wea(1) /="0000") or
		(wea(2) /="0000") else '0';

	--BRAM物理アドレス：512word =>9bit分接続 (1word = 4Byteなので下位２bitは捨て)
	addra(8 downto 0)	<=adr(10 downto 2);
	
	--BRAMライトデータ：32bitそのまま接続
	dina(31 downto 0)	<=w_dat(31 downto 0);
	
	--2KByte（32bit×512）デュアルポートメモリ（２面インスタンス）
	MEM:for i in 0 to N generate
		mWORK_MEM:entity work.WORK_MEM
		port map
		--A port(CPU side)-------
		(clka	=>i_bus_clk
		,rsta	=>rsta(i)	
		,wea	=>wea(i)	
		,addra	=>addra		
		,dina	=>dina		
		,douta	=>douta(i)	
		--B port(Logic side)-----
		,clkb	=>i_bus_clk		--未使用
		,web	=>"0000"		--未使用
		,addrb	=>"000000000"	--未使用
		,dinb	=>x"00000000"	--未使用
		,doutb	=>doutb(i)		--未使用
		);
	end generate;
	
	--Output Port
	o_bus.rdy	<=rdy	;
	o_bus.r_dat	<=r_dat	;
	
end architecture;
```


# 検証用ソフト

検証用のCのコードを作成します。


検証内容|検証目的
---|---|---
char,short,int型のサイズを調べる| 32bbitバスなのでint=4Byteのはずだけど本当か？
BRAM３面分の初期値を読みだす|書き込む前の値を確認する
RAM-A面にcharでインクリメントデータを書き込む|1Byte毎にインクリメントしているはず
RAM-B面にshortでインクリメントデータを書き込む|2Byte毎にインクリメントしているはず
RAM-C面にintでインクリメントデータを書き込む|4Byte毎にインクリメントしているはず
３つのRAMをすべてcharで読みだす|上記３つの「～Byte毎にインクリメントしているはず」が正しいか確認


```c:main.c
#include "platform.h"		//とりあえず必要
#include "mb_interface.h"	//とりあえず必要
#include "ADR_MAP.h"		//自前のヘッダファイル

//ASCIIコードのバイナリ定義
	#define	BS		0x08	//バックスペース
	#define	CR		0x0D	//復帰
	#define	LF		0x0A	//改行
	#define	ESC		0x1B	//エスケープ

//-----------------------------
//グローバル変数
//-----------------------------
	unsigned char g_led=0x7F;

//-------------------------------------------------------------------------------
//割込みハンドラ
//-------------------------------------------------------------------------------
void Int_Handl(void) {
	unsigned char msg;
	int i;
	unsigned char p=0;
	unsigned char n;
	
	//割り込みフラグ落とす
	IRQ_ACK = 0xFFFFFFFF;

	//受信文字を持ってくる
	msg=UART_RX;

	//エコーバック
	xil_printf("%c",msg);
	
	//受信文字に応じた処理
	switch(msg){
		case CR://エンター
			//LEDをインクリメント
			g_led++;
			GPO1=g_led;
			break;
		case BS://バックスペース
			//LEDをデクリメント
			g_led--;
			GPO1=g_led;
			break;
		default://
			//なにもしない
			break;
	}//switch
}
//============================================================
//256Byte読み出し：char型
//============================================================
void ReaderChar(unsigned char* StartPoint){
	unsigned int	i , j;
	unsigned char*	pt;

	pt = StartPoint;
	xil_printf("----------------------------------------------------------\r");
	xil_printf(" Char Read : Start Addres = 0x%08X\r",pt);
	xil_printf("----------------------------------------------------------\r");
	xil_printf("  Address |+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F\r");
	for(i=0; i<16; i++){
		xil_printf("0x%04X|",pt);
		for(j=0; j<16; j++){
			xil_printf("%02X ",*pt);
			pt++;
		}
		xil_printf("\r");
	}
}
//============================================================
//256Byte読み出し：short型
//============================================================
void ReaderShort(unsigned short* StartPoint){
	unsigned int	i , j;
	unsigned short*	pt;

	pt = StartPoint;
	xil_printf("--------------------------------------------------\r");
	xil_printf(" Short Read : Start Addres = 0x%08X\r",pt);
	xil_printf("--------------------------------------------------\r");
	xil_printf("  Address | +0   +2   +4   +6   +8   +A   +C   +E \r");
	for(i=0; i<16; i++){
		xil_printf("0x%04X|",pt);
		for(j=0; j<8; j++){
			xil_printf("%04X ",*pt);
			pt++;
		}
		xil_printf("\r");
	}
}
//============================================================
//256Byte読み出し：int型
//============================================================
void ReaderInt(unsigned int* StartPoint){
	unsigned int	i , j;
	unsigned int*	pt;

	pt = StartPoint;
	xil_printf("----------------------------------------------\r");
	xil_printf(" Int Read : Start Addres = 0x%08X\r",pt);
	xil_printf("----------------------------------------------\r");
	xil_printf("  Address |   +0       +4       +8       +C\r");
	for(i=0; i<16; i++){
		xil_printf("0x%04X|",pt);
		for(j=0; j<4; j++){
			xil_printf("%08X ",*pt);
			pt++;
		}
		xil_printf("\r");
	}
}
//============================================================
//256Byteゼロフィル
//============================================================
void ZeroClear(unsigned int* StartPoint){
	unsigned int	i;
	unsigned int*	pt;
	pt = StartPoint;
	xil_printf("-----------------------------------------\r");
	xil_printf(" Zero clear : Start Addres = 0x%08X\r",pt);
	xil_printf("-----------------------------------------\r");
	for(i=0; i<256; i++){
		*pt=0;
		pt++;
	}
}
//============================================================
//メインループ
//============================================================
void main()
{
	unsigned int*		start_adr=0;
	unsigned int		i=0;
	unsigned char* 		pt_c;//
	unsigned short* 	pt_s;//
	unsigned int* 		pt_i;//

	//================================================
	//ハードの初期化
    	init_platform();
    //割込みハンドラの登録
    	microblaze_register_handler((XInterruptHandler)Int_Handl,(void*)0);
	//使用する割込み選択(bit[2]⇒UART割り込み)
    	IRQ_ENABLE = 0x00000004;
    //割り込みを有効にする
    	microblaze_enable_interrupts();
    //================================================
	
	xil_printf("*******************\r");
	xil_printf("Start!!\r");
	xil_printf("Size of char =%d\r",sizeof(unsigned char));
	xil_printf("Size of short=%d\r",sizeof(unsigned short));
	xil_printf("Size of int  =%d\r",sizeof(unsigned int));
	xil_printf("Size of long =%d\r",sizeof(unsigned long));
	xil_printf("*******************\r");

	//初期値読み出し
	start_adr=0xC0000000;
		ReaderChar(0xC0000000);		//A面
		ReaderShort(0xC0000800);	//B面
		ReaderInt(0xC0001000);		//C面
	///////////////////////////////////////
	//メモリAにキャラで書き込み
	xil_printf("Write increment　dta\r");
	pt_c=0xC0000000;
	pt_s=0xC0000800;
	pt_i=0xC0001000;

	for(i=0; i<256; i++){
		*pt_c = (unsigned char)i;
		pt_c++;
	}
	//メモリBにショート型で書き込み
	for(i=0; i<128; i++){
		*pt_s = (unsigned short)i;
		pt_s++;
	}
	//メモリCにイントき込み
	for(i=0; i<64; i++){
		*pt_i = (unsigned int)i;
		pt_i++;
	}
	///////////////////////////////////////

	//読み出し（あえて全部キャラで読む）
		ReaderChar(0xC0000000);	//A面
		ReaderChar(0xC0000800);	//B面
		ReaderChar(0xC0001000);	//C面

	//--------------------------------------------
	//メインループ
	//--------------------------------------------
    while(1){

    }
	
}
```



# 実機検証結果
ターミナルのログを確認しました。
* intは4byte、shortは2byteでした想定通りの動作でした。
* charで読みだした結果、Byte単位でLSBファーストでした。

```
*******************
Start!!
Size of char =1
Size of short=2
Size of int  =4
Size of long =4
*******************
----------------------------------------------------------
 Char Read : Start Addres = 0xC0000000
----------------------------------------------------------
  Address |+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
0xC0000000|00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xC0000010|00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xC0000020|00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xC0000030|00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xC0000040|00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xC0000050|00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xC0000060|00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xC0000070|00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xC0000080|00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xC0000090|00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xC00000A0|00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xC00000B0|00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xC00000C0|00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xC00000D0|00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xC00000E0|00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xC00000F0|00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
--------------------------------------------------
 Short Read : Start Addres = 0xC0000800
--------------------------------------------------
  Address | +0   +2   +4   +6   +8   +A   +C   +E
0xC0000800|0000 0000 0000 0000 0000 0000 0000 0000
0xC0000810|0000 0000 0000 0000 0000 0000 0000 0000
0xC0000820|0000 0000 0000 0000 0000 0000 0000 0000
0xC0000830|0000 0000 0000 0000 0000 0000 0000 0000
0xC0000840|0000 0000 0000 0000 0000 0000 0000 0000
0xC0000850|0000 0000 0000 0000 0000 0000 0000 0000
0xC0000860|0000 0000 0000 0000 0000 0000 0000 0000
0xC0000870|0000 0000 0000 0000 0000 0000 0000 0000
0xC0000880|0000 0000 0000 0000 0000 0000 0000 0000
0xC0000890|0000 0000 0000 0000 0000 0000 0000 0000
0xC00008A0|0000 0000 0000 0000 0000 0000 0000 0000
0xC00008B0|0000 0000 0000 0000 0000 0000 0000 0000
0xC00008C0|0000 0000 0000 0000 0000 0000 0000 0000
0xC00008D0|0000 0000 0000 0000 0000 0000 0000 0000
0xC00008E0|0000 0000 0000 0000 0000 0000 0000 0000
0xC00008F0|0000 0000 0000 0000 0000 0000 0000 0000
----------------------------------------------
 Int Read : Start Addres = 0xC0001000
----------------------------------------------
  Address |   +0       +4       +8       +C
0xC0001000|00000000 00000000 00000000 00000000
0xC0001010|00000000 00000000 00000000 00000000
0xC0001020|00000000 00000000 00000000 00000000
0xC0001030|00000000 00000000 00000000 00000000
0xC0001040|00000000 00000000 00000000 00000000
0xC0001050|00000000 00000000 00000000 00000000
0xC0001060|00000000 00000000 00000000 00000000
0xC0001070|00000000 00000000 00000000 00000000
0xC0001080|00000000 00000000 00000000 00000000
0xC0001090|00000000 00000000 00000000 00000000
0xC00010A0|00000000 00000000 00000000 00000000
0xC00010B0|00000000 00000000 00000000 00000000
0xC00010C0|00000000 00000000 00000000 00000000
0xC00010D0|00000000 00000000 00000000 00000000
0xC00010E0|00000000 00000000 00000000 00000000
0xC00010F0|00000000 00000000 00000000 00000000
Write increment　dta
----------------------------------------------------------
 Char Read : Start Addres = 0xC0000000
----------------------------------------------------------
  Address |+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
0xC0000000|00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
0xC0000010|10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
0xC0000020|20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
0xC0000030|30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
0xC0000040|40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
0xC0000050|50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
0xC0000060|60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
0xC0000070|70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
0xC0000080|80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
0xC0000090|90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
0xC00000A0|A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
0xC00000B0|B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
0xC00000C0|C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
0xC00000D0|D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
0xC00000E0|E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
0xC00000F0|F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
----------------------------------------------------------
 Char Read : Start Addres = 0xC0000800
----------------------------------------------------------
  Address |+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
0xC0000800|00 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00
0xC0000810|08 00 09 00 0A 00 0B 00 0C 00 0D 00 0E 00 0F 00
0xC0000820|10 00 11 00 12 00 13 00 14 00 15 00 16 00 17 00
0xC0000830|18 00 19 00 1A 00 1B 00 1C 00 1D 00 1E 00 1F 00
0xC0000840|20 00 21 00 22 00 23 00 24 00 25 00 26 00 27 00
0xC0000850|28 00 29 00 2A 00 2B 00 2C 00 2D 00 2E 00 2F 00
0xC0000860|30 00 31 00 32 00 33 00 34 00 35 00 36 00 37 00
0xC0000870|38 00 39 00 3A 00 3B 00 3C 00 3D 00 3E 00 3F 00
0xC0000880|40 00 41 00 42 00 43 00 44 00 45 00 46 00 47 00
0xC0000890|48 00 49 00 4A 00 4B 00 4C 00 4D 00 4E 00 4F 00
0xC00008A0|50 00 51 00 52 00 53 00 54 00 55 00 56 00 57 00
0xC00008B0|58 00 59 00 5A 00 5B 00 5C 00 5D 00 5E 00 5F 00
0xC00008C0|60 00 61 00 62 00 63 00 64 00 65 00 66 00 67 00
0xC00008D0|68 00 69 00 6A 00 6B 00 6C 00 6D 00 6E 00 6F 00
0xC00008E0|70 00 71 00 72 00 73 00 74 00 75 00 76 00 77 00
0xC00008F0|78 00 79 00 7A 00 7B 00 7C 00 7D 00 7E 00 7F 00
----------------------------------------------------------
 Char Read : Start Addres = 0xC0001000
----------------------------------------------------------
  Address |+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
0xC0001000|00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00
0xC0001010|04 00 00 00 05 00 00 00 06 00 00 00 07 00 00 00
0xC0001020|08 00 00 00 09 00 00 00 0A 00 00 00 0B 00 00 00
0xC0001030|0C 00 00 00 0D 00 00 00 0E 00 00 00 0F 00 00 00
0xC0001040|10 00 00 00 11 00 00 00 12 00 00 00 13 00 00 00
0xC0001050|14 00 00 00 15 00 00 00 16 00 00 00 17 00 00 00
0xC0001060|18 00 00 00 19 00 00 00 1A 00 00 00 1B 00 00 00
0xC0001070|1C 00 00 00 1D 00 00 00 1E 00 00 00 1F 00 00 00
0xC0001080|20 00 00 00 21 00 00 00 22 00 00 00 23 00 00 00
0xC0001090|24 00 00 00 25 00 00 00 26 00 00 00 27 00 00 00
0xC00010A0|28 00 00 00 29 00 00 00 2A 00 00 00 2B 00 00 00
0xC00010B0|2C 00 00 00 2D 00 00 00 2E 00 00 00 2F 00 00 00
0xC00010C0|30 00 00 00 31 00 00 00 32 00 00 00 33 00 00 00
0xC00010D0|34 00 00 00 35 00 00 00 36 00 00 00 37 00 00 00
0xC00010E0|38 00 00 00 39 00 00 00 3A 00 00 00 3B 00 00 00
0xC00010F0|3C 00 00 00 3D 00 00 00 3E 00 00 00 3F 00 00 00

```

今後は、演算処理を追加してゆきたいと思います。