目次

GBC処理変更

 従来のGameBoyCamera処理は、全画面データを入力後
 必要な内容を抽出していました。

 これで、どの程度の時間が必要になっていたのかを
 大まかに計算してみます。

 18秒近くかかっていては、マシンを止めて動かさない限り
 移動できません。
 また、16kバイトのメモリを外部に用意するのは面倒です。

 この処理時間を短縮する検討を始めます。

 目標設定しないと、効果も期待できないので、3つのゴールを考えます。

 ゴールを一つ一つクリアしていくプロセスを説明します。


メモリを1kバイトに制限

 GBCから出力されるデータは、128x128(16kbyte)です。  計算で、出力されてくるデータ1/16にすれば達成できます。  移動しながら、画像データを取得するので、画像データの  全ライン中、偶数ラインだけを抽出し、128x64(8kbyte)に  します。  1ラインは128ピクセルあるので、偶数ピクセルだけを抽出し  64x64(4kbyte)にします。  これまでの処理で、1/4までにデータが圧縮されます。  実際の画像は、どんな具合に見えるのかをTcl/Tkを利用し  テストしました。  元画像は、以下のものを利用しました。  圧縮すると、以下の画像になります。  肉眼で見る限り、充分認識できる画像になります。  1ピクセルを8ビットで扱うので、4kbyteになっていますが  1ピクセルを1ビットに変換すると、512バイトになります。  これで、ゴールを達成できます。  1ピクセルを8ビットから1ビットに変換すると、次の画像  になります。(見やすいよう、少し拡大)  実際に利用した画像データは、PGM形式なので、Tcl/Tkでこの  変換フィルタプログラムを作成し、検証しました。  128x128を64x64のPGM形式に変換するコードです。  (UNIX、WindowsのGUIアプリケーションにしました。) #!/bin/sh wm title . "PGM converter" # clear file names set fname "" set pname "" set tname "" # add menu on TopLevel . configure -menu .mnuTop menu .mnuTop # add sub form .mnuTop add cascade -label File -underline 0 -menu .mnuTop.file menu .mnuTop.file -tearoff no # add sub menu "Open" .mnuTop.file add command -label "Open" -command {OpenText} # add sub menu "Save" .mnuTop.file add command -label "Save" -command {SaveImage} # add sub menu "Quit" .mnuTop.file add command -label "Quit" -command {exit} # set window size set w 1000 set h 1000 label .lblTxt -textvariable fname label .lblPgm -textvariable pname pack .lblTxt pack .lblPgm ####################### # Open Text procedure ####################### proc OpenText { } { global fname pname tname # set file types set ftype {{ "pgm Files" .pgm} { "All Files" * }} # get file name from built-in tool set fname [tk_getOpenFile -filetypes $ftype -parent . ] # create file name set xlist [split $fname "."] set xlist [split $xlist "/"] set xlist [lindex $xlist end] set pname [lindex $xlist 0] set ext "r" # text file name set tname "$pname$ext.txt" # pgm file name set pname "$pname$ext.pgm" } ####################### # Save Image procedure ####################### proc SaveImage { } { global fname pname tname # open files set fd_in [open $fname "r"] set fd_out [open $pname "w"] set fd_out_txt [open $tname "w"] # handling header (mode) gets $fd_in sbuf puts $fd_out "P2" # handling header (size) gets $fd_in sbuf puts $fd_out "64 64" # handling header (mode) gets $fd_in sbuf puts $fd_out "255" # handling context set line 0 while { [gets $fd_in sbuf] >= 0 } { # judge even line set sbuf [string trim $sbuf " "] # judge even line if { [expr $line & 1] == 0 } { # initialize set xbuf "" set i 0 # get even pixel foreach e $sbuf { # judge and store if { [expr $i & 1] == 0 } { set xbuf "$xbuf $e" } # increment incr i } # store puts $fd_out $xbuf puts $fd_out_txt $xbuf } # increment incr line } # close close $fd_in close $fd_out close $fd_out_txt # message tk_messageBox -type ok -message "reduce pgm_file pgm_file(text_file)" }  64x64のテキストデータを、2値化画像に変換するコードです。  2値化したままでは、画像表示できないので、0と255に変換  した値をPGM形式で保存します。  (UNIX、WindowsのGUIアプリケーションにしました。) #!/bin/sh wm title . "PGM generator extended" # clear file names set fname "" set pname "" set fd_in "" set fd_out "" # add menu on TopLevel . configure -menu .mnuTop menu .mnuTop # add sub form .mnuTop add cascade -label File -underline 0 -menu .mnuTop.file menu .mnuTop.file -tearoff no # add sub menu "Open" .mnuTop.file add command -label "Open" -command {OpenText} # add sub menu "Save" .mnuTop.file add command -label "Save" -command {SaveImage} # add sub menu "Quit" .mnuTop.file add command -label "Quit" -command {exit} # declare image file image create photo input_image -file $fname # set window size set w 1000 set h 1000 label .lblTxt -textvariable fname label .lblPgm -textvariable pname pack .lblTxt pack .lblPgm ####################### # Open Text procedure ####################### proc OpenText { } { global fname pname # set file types set ftype {{ "text Files" .txt} { "All Files" * }} # get file name from built-in tool set fname [tk_getOpenFile -filetypes $ftype -parent . ] # create file name set xlist [split $fname "."] set xlist [split $xlist "/"] set xlist [lindex $xlist end] set fname [lindex $xlist 0] set ext "_r" set pname "$fname$ext.pgm" set fname "$fname.txt" } ####################### # Save Image procedure ####################### proc SaveImage { } { global fname pname # open files set fd_in [open $fname "r"] set fd_out [open $pname "w"] # save header puts $fd_out "P2" puts $fd_out "64 64" puts $fd_out "255" # justify context while { [gets $fd_in sbuf] >= 0 } { # trim set tmp [string trimright $sbuf " "] # get maximum and minimum set max 0 set min 255 foreach e $sbuf { # trim set val [string trimleft $e "0"] # compare if { $val > $max } { set max $val } if { $val < $min } { set min $val } } # calculate average set avr [expr ($max + $min) / 2] # generate code set obuf "" foreach e $sbuf { # trim set val [string trimleft $e "0"] # compare if { $val < $avr } { set obuf "$obuf 0" } else { set obuf "$obuf 255" } } puts $fd_out $obuf } # close close $fd_in close $fd_out # message tk_messageBox -type ok -message "convert text_file pgm_file" }

メモリは内蔵

 128ピクセルx128ラインを64ピクセルx64ラインに変換すると  64ピクセルを2値化して、8バイトx64ラインになります。  計算すると、512バイトになるので1kバイトの配列がある  マイコン内蔵SRAMに保存できます。  2kバイト以上のSRAMをもつマイコンであれば、GBCの制御  を含め、対応できると考えられます。

データ取得時間2秒以内

 マイコン内蔵A/Dコンバータを利用する限り、GBCが出力する  Voutをアナログからデジタルの2値変換する処理は、高速に  ならないと判断し、FPGAを利用することにしました。  利用したFPGAは、XilinxのSpartan3、200kゲートです。  大阪のヒューマンデータから購入しました。  GBCで利用している人工網膜チップのアナログ出力電圧Voutは  最大で2Vです。上のボードは、3.3VのI/Oインタフェースを  もつので、Voutを直結することにします。  Voutは、アナログ値なのでデジタル2値に変換するために  可変抵抗器とシリコンダイオードを利用します。  可変抵抗器のトリマーを回し、スレショルドレベルを調整します。  FPGAとGBC、マイクロコンピュータのインタフェースを考えます。  GBCは、+5Vを電源電圧としていますが、入力電圧は2.2V以上をHと  認識するので、FPGAの出力を直結します。  GBCの出力は、Hレベルを4.5V以上としているので、抵抗による分圧  で、3.0Vまで引き下げます。  マイクロコンピュータからの信号で、GBCに対しての制御信号を  出力します。3つのトリガー信号を使います。  GBCの出力した画像データを2値化するとして、保存している  16384ビットのデータを、シリアルインタフェースで出力させます。  この機能のために必要な信号を定義します。  FPGAが、どういう状態であるのかを示すSTATUS信号を  用意します。  入出力信号が確定したので、VHDLコードを記述します。  entityは、以下とします。 entity gbcx is generic ( TOPX : integer := 3 ; RMAX : integer := 6 ; TOPY : integer := 13 ; YMAX : integer := 5000 --; ); port( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- trigger RTRG : in std_logic ; PTRG : in std_logic ; GTRG : in std_logic ; -- status STATUS : out std_logic_vector(1 downto 0) ; -- input from GBC GREAD : in std_logic ; VOUT : in std_logic ; -- Game Boy Camera control XRST : out std_logic ; XCK : out std_logic ; SIN : out std_logic ; LOAD : out std_logic ; START : out std_logic ; -- serial interface STRG : in std_logic ; STxD : out std_logic --; ); end gbcx;  FPGAの内部を考えます。  GBC、シリアルインタフェースを利用する場合、クロックが必要です。  この2クロックは、異なる周波数としたいので、クロックジェネレータ  を定義して、それを使い回します。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity clkgenx is generic ( TOPX : integer ; RMAX : integer --; ); port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- output CLKOUT : out std_logic -- ; ); end clkgenx; architecture Behavioral of clkgenx is signal iSCNT : std_logic_vector(TOPX-1 downto 0); signal iCLK : std_logic ; begin -- output CLKOUT <= iCLK ; -- divider process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iSCNT <= (others => '0') ; iCLK <= '0' ; elsif rising_edge(CLOCK) then if ( conv_integer(iSCNT) = RMAX ) then iSCNT <= (others => '0') ; iCLK <= not iCLK ; else iSCNT <= iSCNT + '1' ; end if ; end if ; end process ; end Behavioral;  利用しているボードにあるマスタークロックは48MHzなので  GBCを動かすために4MHzを生成し、それから500kHzを作ります。 CLKX : clkgenx generic map (TOPX,RMAX) port map (nRESET,CLOCK,iMCLK);  iMCLKは、4MHzとなるので、Johnsonカウンタを利用し500kHzを作ります。 process (nRESET,iMCLK) begin if ( nRESET = '0' ) then iSTATE <= "00" ; elsif rising_edge(iMCLK) then case conv_integer(iSTATE) is when 0 => iSTATE <= "01" ; when 1 => iSTATE <= "11" ; when 3 => iSTATE <= "10" ; when 2 => iSTATE <= "00" ; when others => iSTATE <= "00" ; end case ; end if ; end process ;  Johnsonカウンタを利用すると、iSTATEのどちらのビットも  500kHzを生成します。  Johnsonカウンタの2ビットを利用し、他ブロックでも使える  信号を作っておきます。  iSTATE(1)は、iXCKそのものに出来ます。  GBCにリセット信号やパラメータを与える場合は、XCKの  立上りエッジを使うので、セットアップタイムを満たす  ように、論理値を出力するタイミングをiVALIDで指定  します。また、Voutを捕まえるためのトリガーをiLTRG  で生成します。 iVALID <= '1' when ( iSTATE = "01" ) else '0' ; iLTRG <= '1' when ( iSTATE = "11" ) else '0' ;  マイクロコンピュータからの指示で、リセット、パラメータ  設定、画像取得を制御したいので、シンクロナイザをつけて  対応します。  シンクロナイザは、シフトレジスタを利用します。 process (nRESET,iMCLK) begin if ( nRESET = '0' ) then iRTRG_SFT <= "000" ; iPTRG_SFT <= "000" ; iGTRG_SFT <= "000" ; iSTRG_SFT <= "000" ; elsif rising_edge(iMCLK) then iRTRG_SFT <= iRTRG_SFT(1 downto 0) & RTRG ; iPTRG_SFT <= iPTRG_SFT(1 downto 0) & PTRG ; iGTRG_SFT <= iGTRG_SFT(1 downto 0) & GTRG ; iSTRG_SFT <= iSTRG_SFT(1 downto 0) & STRG ; end if ; end process ; iRTRG <= '1' when ( iRTRG_SFT = "011" or iRTRG_SFT = "001" ) else '0' ; iPTRG <= '1' when ( iPTRG_SFT = "011" or iPTRG_SFT = "001" ) else '0' ; iGTRG <= '1' when ( iGTRG_SFT = "011" or iGTRG_SFT = "001" ) else '0' ; iSTRG <= '1' when ( iSTRG_SFT = "011" or iSTRG_SFT = "001" ) else '0' ;  外部信号をシフトレジスタに順次入れていき、立上がりの  エッジをつかまえます。  各々信号の機能は、以下とします。  これらのトリガー信号を利用してシーケンサ(ステートマシン)を  動かします。各シーケンサを動かすための同期信号に別途設けます。  リセット、パラメータ設定、画像入力は、これらの監督シーケンサ  (マスターシーケンサ)を用意し、サブシーケンサで対応します。  トリガーを検出すると、マスターは、サブに  トリガーを与え、終了フラグを待ちます。  マスターシーケンサは、以下としました。 process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iMSTATE <= 0 ; elsif rising_edge(CLOCK) then case iMSTATE is -- wait trigger when 0 => if ( iRTRG = '1' ) then -- reset iMSTATE <= 1 ; elsif ( iPTRG = '1' ) then -- set parameters iMSTATE <= 3 ; elsif ( iGTRG = '1' ) then -- get image iMSTATE <= 5 ; else -- stay iMSTATE <= 0 ; end if ; -- enable reset action when 1 => iMSTATE <= 2 ; -- exit reset action when 2 => iMSTATE <= 7 ; -- enable parameter set sequencer when 3 => iMSTATE <= 4 ; -- wait parameter set sequencer complete flag when 4 => if ( iPFLAG = '1' ) then iMSTATE <= 7 ; end if ; -- enable get image sequencer when 5 => iMSTATE <= 6 ; -- wait get image sequencer when 6 => if ( iGFLAG = '1' ) then iMSTATE <= 7 ; end if ; -- return first state when 7 => iMSTATE <= 0 ; when others => iMSTATE <= 0 ; end case ; end if ; end process ;  リセットシーケンサは、トリガーを受けたなら  XCKの立上がエッジの前に、信号を出力します。  内部は、正論理で動かします。 process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iRSTATE <= "00" ; iXRST <= '0' ; elsif rising_edge(CLOCK) then case conv_integer(iRSTATE) is -- wait trigger when 0 => iXRST <= '0' ; if ( iRTRGX = '1' ) then iRSTATE <= "01" ; else iRSTATE <= "00" ; end if ; -- judge wait trigger when 1 => if ( iVALID = '1' ) then -- enable reset signal iXRST <= '1' ; iRSTATE <= "11" ; else iRSTATE <= "01" ; end if ; -- judge wait trigger when 3 => if ( iVALID = '1' ) then -- disable iXRST <= '0' ; iRSTATE <= "10" ; else iRSTATE <= "11" ; end if ; -- return first state when 2 => iRSTATE <= "00" ; when others => iXRST <= '0' ; iRSTATE <= "00" ; end case ; end if ; end process ;  iXCK、iXRST信号は、バッファとインバータを介して出力します。 XCK <= iSTATE(1) ; -- iXCK XRST <= not iXRST ;  使いやすくするため、別のVHDLコードにしました。 ------------------------------------------------------------ library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity rstx is port( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- trigger TRG : in std_logic ; -- enable ENABLE : in std_logic ; -- output XRST : out std_logic -- ; ); end rstx; architecture Behavioral of rstx is signal iRSTATE : std_logic_vector(1 downto 0) ; signal iXRST : std_logic ; begin -- reset sequencer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iRSTATE <= "00" ; iXRST <= '0' ; elsif rising_edge(CLOCK) then case conv_integer(iRSTATE) is -- wait trigger when 0 => iXRST <= '0' ; if ( TRG = '1' ) then iRSTATE <= "01" ; else iRSTATE <= "00" ; end if ; -- judge wait trigger when 1 => if ( ENABLE = '1' ) then -- enable reset signal iXRST <= '1' ; iRSTATE <= "11" ; else iRSTATE <= "01" ; end if ; -- judge wait trigger when 3 => if ( ENABLE = '1' ) then -- disable reset signal iXRST <= '0' ; iRSTATE <= "10" ; else iRSTATE <= "11" ; end if ; -- return first state when 2 => iRSTATE <= "00" ; when others => iXRST <= '0' ; iRSTATE <= "00" ; end case ; end if ; end process ; XRST <= iXRST ; end Behavioral; ------------------------------------------------------------  GBCに渡すパラメータは、FPGA内部にメモリ領域を定義し  リセット時に設定します。  マスターシーケンサからのトリガーで、順次パラメータを  出力します。  メモリ領域の指定は、以下とします。 type PARAMP is array(0 to 8) of std_logic_vector(10 downto 0); signal iPARAMS : PARAMP ;  アドレス3ビット、パラメータ8ビットなので、11ビット幅の  メモリ領域を用意し、9個の配列としておきます。  メモリ領域最終ブロックを常に出力するよう、シーケンサを  回します。この処理を別のVHDLコードで定義し、呼び出して  使います。  パラメータ設定シーケンサは、以下となります。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity psetx is port( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- trigger TRG : in std_logic ; -- enable ENABLE : in std_logic ; -- flag FLAG : out std_logic ; -- output SIN : out std_logic ; LOAD : out std_logic -- ; ); end psetx; architecture Behavioral of psetx is signal iPSTATE : integer range 0 to 14 ; signal iPPTR : integer range 0 to 8 ; signal iSIN : std_logic ; signal iLOAD : std_logic ; signal iFLAG : std_logic ; type PARAMP is array(0 to 7) of std_logic_vector(10 downto 0); signal iPARAMS : PARAMP ; signal iPARAMSX : std_logic_vector(10 downto 0) ; begin -- output SIN <= iSIN ; LOAD <= iLOAD ; FLAG <= iFLAG ; -- sequencer process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iPSTATE <= 0 ; iPPTR <= 0 ; -- set paramters iPARAMS(0) <= "000" & X"80" ; -- register #0 iPARAMS(1) <= "001" & X"03" ; -- register #1 iPARAMS(2) <= "010" & X"00" ; -- register #2 iPARAMS(3) <= "011" & X"30" ; -- register #3 iPARAMS(4) <= "100" & X"01" ; -- register #4 iPARAMS(5) <= "101" & X"00" ; -- register #5 iPARAMS(6) <= "110" & X"01" ; -- register #6 iPARAMS(7) <= "111" & X"21" ; -- register #7 iPARAMSX <= "000" & X"FF" ; -- temporary elsif rising_edge(CLOCK) then case iPSTATE is -- wait trigger when 0 => if ( TRG = '1' ) then iPSTATE <= 1 ; end if ; -- judge pointer when 1 => if ( iPPTR > 7 ) then iPSTATE <= 14 ; else iPSTATE <= 2 ; iPARAMSX <= iPARAMS(iPPTR) ; end if ; -- set data) when 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 => if ( ENABLE = '1' ) then iPSTATE <= iPSTATE + 1 ; end if ; -- update pointer when 13 => iPPTR <= iPPTR + 1 ; iPSTATE <= 1 ; -- return first state when 14 => iPSTATE <= 0 ; iPPTR <= 0 ; when others => iPSTATE <= 0 ; iPPTR <= 0 ; end case ; end if ; end process ; iSIN <= iPARAMSX(10) when ( iPSTATE = 2 ) else iPARAMSX(9) when ( iPSTATE = 3 ) else iPARAMSX(8) when ( iPSTATE = 4 ) else iPARAMSX(7) when ( iPSTATE = 5 ) else iPARAMSX(6) when ( iPSTATE = 6 ) else iPARAMSX(5) when ( iPSTATE = 7 ) else iPARAMSX(4) when ( iPSTATE = 8 ) else iPARAMSX(3) when ( iPSTATE = 9 ) else iPARAMSX(2) when ( iPSTATE = 10 ) else iPARAMSX(1) when ( iPSTATE = 11 ) else iPARAMSX(0) when ( iPSTATE = 12 ) else '0' ; iLOAD <= '1' when ( iPSTATE = 12 ) else '0' ; iFLAG <= '1' when ( iPSTATE = 14 ) else '0' ; end Behavioral;  GBCから送られてくる画像データは、アナログ出力でVoutを使います。  2値化処理を外部回路でやるとして、内部には16384ビットのメモリを  用意して、格納しておきたいもの。  そこで、DualPortMemoryを利用することに。  DualPortMemoryは、2つのポートをもち、各ポートでランダムアクセス  が可能になります。GBCから入力したデータを使う場合、GBCとのデータ  処理を気にせずに、画像データを取りだして処理できるようにします。  利用するSpartan3の中には、DualPortMemoryのライブラリが用意されて  いるので、Aポートを1ビットごとにアドレスを付けたメモリとして  Bポートを4ビットごとにアドレスを付けたメモリとしてアクセスできる  記述を選びました。  XilinxのISEWebPackのLanguage Templateから必要な記述を  見つけて、次のように信号を定義しました。 signal iGPTR : std_logic_vector(14 downto 0) ; signal iGDO : std_logic_vector(0 downto 0); signal iGDI : std_logic_vector(0 downto 0); signal iGEN : std_logic ; signal iGSSR : std_logic ; signal iGWE : std_logic ; signal iTPTR : std_logic_vector(12 downto 0) ; signal iTDO : std_logic_vector(3 downto 0); signal iTDI : std_logic_vector(3 downto 0); signal iTEN : std_logic ; signal iTSSR : std_logic ; signal iTWE : std_logic ; RAMB16_S1_S4_inst : RAMB16_S1_S4 port map ( DOA => iGDO , -- Port A 1-bit Data Output DOB => iTDO , -- Port B 4-bit Data Output ADDRA => iGPTR(13 downto 0) , -- Port A 14-bit Address Input ADDRB => iTPTR(11 downto 0) , -- Port B 12-bit Address Input CLKA => iMCLK , -- Port A Clock CLKB => iTCLK , -- Port B Clock DIA => iGDI , -- Port A 1-bit Data Input DIB => iTDI , -- Port B 4-bit Data Input ENA => iGEN , -- Port A RAM Enable Input ENB => iTEN , -- PortB RAM Enable Input SSRA => iGSSR , -- Port A Synchronous Set/Reset Input SSRB => iTSSR , -- Port B Synchronous Set/Reset Input WEA => iGWE , -- Port A Write Enable Input WEB => iTWE -- Port B Write Enable Input );  DualPortMemoryのAポートを使って、GBCからの画像データを  メモリ領域に保存します。  単純なシーケンサ処理でまとめました。 process (nRESET,iMCLK) begin if ( nRESET = '0' ) then iGSTATE <= 0 ; iSTART <= '0' ; iGPTR <= (others => '0') ; elsif rising_edge(iMCLK) then case iGSTATE is -- wait trigger when 0 => iSTART <= '0' ; if ( iGTRGX = '1' ) then iGSTATE <= 1 ; end if ; -- enable START when 1 => if ( iVALID = '1' ) then iSTART <= '1' ; iGSTATE <= 2 ; end if ; -- disable START when 2 => if ( iVALID = '1' ) then iGSTATE <= 3 ; iGPTR <= (others => '0') ; end if ; -- judge READ = '1' when 3 => if ( GREAD = '1' ) then iGSTATE <= 4 ; end if ; -- store when 4 => if ( iSTATE = "10" ) then iGSTATE <= 5 ; end if ; -- judge and increment when 5 => if ( iGPTR > 16383 ) then iGSTATE <= 6 ; else iGPTR <= iGPTR + '1' ; iGSTATE <= 4 ; end if ; -- return frist state when 6 => iGSTATE <= 0 ; -- default when others => iGSTATE <= 0 ; end case ; end if ; end process ;  Aポートからのデータは、バッファiGDI(0)経由でクロックiMCLKに  同期してメモリ領域に書き込まれていきます。  ライブラリ仕様にのっとって、他の信号の論理値を決めます。 iGEN <= '1' ; -- Port A RAM Enable Input iGSSR <= '1' ; -- Port A Synchronous Set/Reset Input iGWE <= '1' ; -- Port A Write Enable Input  Bポートからのデータは、シリアルインタフェースで出力します。  トリガーを与えられたなら、16384ビットのデータを4ビットずつ  '0'〜'9'、'A'〜'F'に変換して出力することに決めました。  4ビットの数値を1文字のASCIIコードに変換する  VHDLコードを定義します。  4入力8出力の組合せ回路で、単純に定義しました。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity ascdecx is port( -- input Din : in std_logic_vector(3 downto 0) ; -- output Dout : out std_logic_vector(7 downto 0) -- ; ); end ascdecx; architecture Behavioral of ascdecx is begin -- decoder Dout <= X"30" when ( Din = "0000" ) else -- 0 X"31" when ( Din = "0001" ) else -- 1 X"32" when ( Din = "0010" ) else -- 2 X"33" when ( Din = "0011" ) else -- 3 X"34" when ( Din = "0100" ) else -- 4 X"35" when ( Din = "0101" ) else -- 5 X"36" when ( Din = "0110" ) else -- 6 X"37" when ( Din = "0111" ) else -- 7 X"38" when ( Din = "1000" ) else -- 8 X"39" when ( Din = "1001" ) else -- 9 X"41" when ( Din = "1010" ) else -- A X"42" when ( Din = "1011" ) else -- B X"43" when ( Din = "1100" ) else -- C X"44" when ( Din = "1101" ) else -- D X"45" when ( Din = "1110" ) else -- E X"46" when ( Din = "1111" ) else -- F X"20" ; end Behavioral;  トリガーを与えられたなら、一気にデータを出力する仕様で  シーケンサを定義します。 process (nRESET,iTCLK) variable iTPTRX : integer ; begin if ( nRESET = '0' ) then iTSTATE <= 0 ; iTPTR <= (others => '0') ; iGSDATN <= X"0" ; iTDAT <= X"FF" ; elsif rising_edge( iTCLK ) then iTPTRX := conv_integer(iTPTR) ; case iTSTATE is -- wait trigger when 0 => if ( iSTRG = '1' ) then iTSTATE <= 1 ; iTPTR <= (others => '0') ; end if ; -- judge counter when 1 => if ( iTPTR > 4095 ) then iTSTATE <= 10 ; else iTSTATE <= 2 ; -- get data iGSDATN <= iTDO; end if ; -- convert ASCII code (both upper nibble) when 2 => iTSTATE <= 3 ; -- latch when 3 => iTSTATE <= 4 ; iTDAT <= iGSUPDN ; -- enable trigger when 4 => iTSTATE <= 5 ; iTPTR <= iTPTR + 1 ; -- judge complete flag when 5 => if ( iTTFLAG = '1' ) then iTSTATE <= 6 ; iGSDATN <= iTDO ; end if ; -- latch when 6 => iTSTATE <= 7 ; iTDAT <= iGSUPDN ; -- enable trigger when 7 => iTSTATE <= 8 ; -- judge complete flag when 8 => if ( iTTFLAG = '1' ) then iTSTATE <= 9 ; end if ; -- loop when 9 => iTSTATE <= 1 ; iTPTR <= iTPTR + 1 ; -- set delimiter when 10 => iTSTATE <= 11 ; iTDAT <= X"0D" ; -- enable trigger when 11 => iTSTATE <= 12 ; -- judge complete flag when 12 => if ( iTTFLAG = '1' ) then iTSTATE <= 13 ; end if ; -- return first state when 13 => iTSTATE <= 0 ; -- default when others => iTSTATE <= 0 ; end case ; end if ; end process ; iTTRG <= '1' when ( iTSTATE = 4 ) else '1' when ( iTSTATE = 7 ) else '1' when ( iTSTATE = 11 ) else '0' ; iTFLAG <= '1' when ( iTSTATE = 13 ) else '0' ;  DualPortMemoryのBポートから、4ビットデータを順次  取得して出力します。  8ビットデータをTxDに出力する処理は、別のVHDLコードで  実現しました。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity stxdx is port( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- trigger TRG : in std_logic ; -- flag FLAG : out std_logic ; -- input Din : in std_logic_vector(7 downto 0) ; -- output TxD : out std_logic -- ; ); end stxdx; architecture Behavioral of stxdx is signal iTxSTATE : integer range 0 to 11 ; begin process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iTxSTATE <= 0 ; elsif rising_edge(CLOCK) then case iTxSTATE is -- wait trigger when 0 => if ( TRG = '1' ) then iTxSTATE <= 1 ; end if ; -- start bit when 1 => iTxSTATE <= iTxSTATE + 1 ; -- data when 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 => iTxSTATE <= iTxSTATE + 1 ; -- set flag when 10 => iTxSTATE <= iTxSTATE + 1 ; -- return first state when 11 => iTxSTATE <= 0 ; -- default when others => iTxSTATE <= 0 ; end case ; end if ; end process ; TxD <= '0' when ( iTxSTATE = 1 ) else Din(0) when ( iTxSTATE = 2 ) else Din(1) when ( iTxSTATE = 3 ) else Din(2) when ( iTxSTATE = 4 ) else Din(3) when ( iTxSTATE = 5 ) else Din(4) when ( iTxSTATE = 6 ) else Din(5) when ( iTxSTATE = 7 ) else Din(6) when ( iTxSTATE = 8 ) else Din(7) when ( iTxSTATE = 9 ) else '1' ; FLAG <= '1' when ( iTxSTATE = 11 ) else '0' ; end Behavioral;  8ビットのデータを入れて、トリガーを与えると  スタートビットとストップビットで挟んだ8ビット  を出力します。  全体では、10ビットとしておき、転送終了後フラグで  呼出し側に通知します。  GBCから出力されるVoutの2値化のために使ったVHDLコード  は単純で、次のように短いものです。 ------------------------------------------------------------ library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity gbctst is Port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- input GVOUT : in std_logic ; -- output LEDOUT : out std_logic_vector(3 downto 0) --; ); end gbctst; architecture Behavioral of gbctst is signal iCNT : integer range 0 to 18000 ; signal iLEDOUT : std_logic_vector(3 downto 0) ; signal iGVOUT : std_logic ; begin -- input iGVOUT <= GVOUT ; -- output LEDOUT <= not iLEDOUT ; -- divider process (nRESET,CLOCK) begin if ( nRESET = '0' ) then iCNT <= 0 ; iLEDOUT <= "0000" ; elsif rising_edge( CLOCK ) then if ( iCNT = 18000 ) then iCNT <= 0 ; iLEDOUT <= iLEDOUT(2 downto 0) & iGVOUT ; else iCNT <= iCNT + 1 ; end if ; end if ; end process ; end Behavioral; ------------------------------------------------------------  動作は、単純で1HzでVOUTに相当する電圧をキャッチし  LEDに点灯するだけですが、この電圧値をOPアンプで  作った可変電圧出力装置でいろいろ変えました。  この実験で得られたデータは、3.3VのCMOSデバイスでは  0.8V前後にHとLの境界がありました。1.0V以上であれば  CPLD/FPGAは、Hと判定します。  0.6V以下では、Lと判定します。  実験には、CPLDのCoolRunnerIIを載せたCPLDボードを使いました。
目次

inserted by FC2 system