まえおき
以前 投稿しました「Spartan6でmicroblaze mcs を動かす①②③」にて、FPGA上でCPUを動作させることが可能になりました。
今後ハードウェアアクセラレータもどきを増築していきたいと思います。
#ハードウェアアクセラレータとは
ハードウェアアクセラレータとはCPUのバスにぶら下がっている専用の演算回路です。
特徴としては以下のようなメリットがあります。
- 特定の演算処理をCPUに代わって行うハードウェア
- CPUはアクセラレータに指示を投げて、結果だけをもう
- アクセラレータが演算中、CPUは他の処理を行うことができる
- 演算を並列処理できる(作り方次第)
構成
モジュールを以下のように構成します
- BUS I/F(バス信号のI/F)
- メモリ(BlockRAM)のリードライトを行う
- DualPortMEM
- データを貯めるデュアルポートメモリ
- AポートはCPUから読み書きできる
- BポートはLogic部から読み書きできる
- AポートとBポートは非同期クロック
- Logic部(演算処理回路)
- CPUからアクセスできる演算命令用のレジスタを実装する
- 演算命令に応じてBRAMからデータを取り出し、演算結果をBRAMに書き戻す
今回作る回路
今回はBUS/Fとメモリの部分までを作成することとし、CPUからメモリに読み書きできることを目標にします。
(演算ロジック部分は次回の投稿にします)
CPU バス I/F
Microblaze_MCSのポート名 | 図中の略称 | 機能 | 説明 |
---|---|---|---|
IO_Addr_Strobe | a_stb | アドレスストローブ | Hのときアドレスが有効 |
IO_Read_Strobe | r_stb | リードストローブ | Hでリードを要求 |
IO_Write_Strobe | w_stb | ライトストローブ | Hのときライトデータが有効 |
IO_Address | adr | アドレス | アクセス先のアドレスを示す Microblaze_mcsは0xC000_0000がバス空間の先頭アドレス |
IO_Byte_Enable | be | バイトイネーブル | 32bitバス(4Byte)のうちアクセス対象Byteを示す。 intでアクセス⇒1111 shortでアクセス⇒0011 or 1100 charでアクセス⇒0001 or 0010 or 0100 or 1000 |
IO_Write_Data | w_dat | ライトデータ | 書き込みデータです |
IO_Read_Data | r_dat | リードデータ | リードストローブが来たらレディがHになる間だけ出力します。 そのほかはL固定(他のモジュールとワイヤーORで共有するので) |
IO_Ready | rdy | レディ応答 | リード時:有効なリードデータとともにアサート ライト時:処理完了後アサート<※>Microblazeはレディが帰ってこないとハングアップするので要注意!! |
RTL図
ブロック | 概要 |
---|---|
入力FF | バスの信号を一度叩くFFです |
WriteContlorl | ブロックRAMのライトイネーブル信号を生成します 上位アドレスがヒットしているBRAMに対してバイトイネーブルとライトストローブのANDを通します。 |
ReadContlorl | 上位アドレスがヒットしているBRAMの出力を後段のセレクタでセレクトするための制御信号を生成します |
BRAM | メモリ本体です、BRAMを3面インスタンスしています。 |
VHDLコード
バスの信号を1つづつ毎回記述すると、回路を複製するときに記述が多くなるのは嫌です。
バスの信号はパッケージにユーザー定義型(C言語でいう構造体みたいなもの)に定義して記述しました。
-----------------------------------------------------------
-- 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;
--------------------------------------------------------------------
-- CPUバスにぶら下げるワークメモリ
-- DualPortRAM(32bit×512)を2面インスタンスしている
--
-- ※今後RAMのデータを演算するロジックを追加して演算アクセラレータにする
-- ------------+--------------------
-- BA + 0x0800 |ワークメモリA面
-- : |
-- BA + 0x07FF |
-- ------------+--------------------
-- BA + 0x0800 |ワークメモリB面
-- : |
-- BA + 0x0FFF |
-- ------------+--------------------
-- BA + 0x1000 |ワークメモリC面
-- : |
-- 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);
--BRAM出力データのアレイ型
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なので下位2bitは捨て)
addra(8 downto 0) <=adr(10 downto 2);
--BRAMライトデータ:32bitそのまま接続
dina(31 downto 0) <=w_dat(31 downto 0);
--2KByte(32bit×512)デュアルポートメモリ(2面インスタンス)
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のはずだけど本当か?
BRAM3面分の初期値を読みだす|書き込む前の値を確認する
RAM-A面にcharでインクリメントデータを書き込む|1Byte毎にインクリメントしているはず
RAM-B面にshortでインクリメントデータを書き込む|2Byte毎にインクリメントしているはず
RAM-C面にintでインクリメントデータを書き込む|4Byte毎にインクリメントしているはず
3つのRAMをすべてcharで読みだす|上記3つの「~Byte毎にインクリメントしているはず」が正しいか確認
#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
今後は、演算処理を追加してゆきたいと思います。