目次

落ち葉ひろい

 mugen2013マシンは、ARM+FPGAのコラボレーションで
 制御を実現しました。

 ARMは32ビットプロセッサなので、ネットサーフィン
 すれば、必要情報の入手は比較的楽でした。

 FPGAはデジタル回路を設計し、それを封入するのが
 前提です。動作確認に、3つのVHDLコードを作成した
 ので、備忘録として残しておきます。

 作成VHDLコードのリストは、以下です。

 上のVHDLコードのテストに利用したFPGAは
 mugen2013で使った基板です。



 クロックは48MHz、Spartan3の200kゲートタイプ
 大阪のヒューマンデータから入手しました。

 FPGA基板にマザーボードを用意し、マザーボード
 からコネクタ、ケーブルを介してマイコン、他の
 基板に接続できるようにしてあります。

 FPGAの内部状態確認のため、スイッチとLEDが
 ついたモニタ基板を使います。



 ARMとFPGAは、10ピンケーブルで接続します。



 各VHDLコードに関して説明していきます。


DualPortMemory動作テスト  OV7670が出力してくる画像データを保存するため  FPGA内部にあるDualPortMemoryを使いました。  DualPortMemoryは、A、Bの2ポートをもつので  Aポートを入力、Bポートを出力にしています。  使い方は、AポートにOV7670を接続し、Bポートに  ARMを接続しますが、動作確認では2ポートともに  ARMに接続します。  動作テストは、ARMからAポートを使いメモリに  データを書込み、Bポートからメモリデータを  読出す処理としました。  動作テストは、ARMからAポートを使いメモリに  データを書込み、Bポートからメモリデータを  読出す処理としました。  ARMのファームウエアに、次の機能を用意します。  ARMとPCは、シリアルケーブルで接続し  端末ソフトで、コマンドを与えながら  上の機能を実現します。  ARMとFPGAは、8ビットバスを2ポート利用し  接続します。1ポートは、データバスとして  他のポートは制御バスに使います。  コマンドは、次のように決めました。  アドレスに関連するコマンドは、すべて'A'コマンドに  集約します。コマンドに続けるパラメータで、処理と  ポートを指定します。  データ書込みは'W'コマンドを使い、続けるパラメータを  16進2バイトとします。  データ読込みは'R'コマンドを使います。  A、Bポートの現在のアドレスを表示することで  データライト時のアドレス確認が楽になるように  しました。  仕様を決めたので、PCとARM間の通信関係パラメータを  以下のようにまとめます。  ARMファームウエアは、以下のように定義しました。 #include <ADuC7026.h> #define OFF 0 #define ON OFF+1 /* data definitions */ typedef unsigned char UBYTE ; typedef signed char SBYTE ; typedef unsigned short UWORD ; typedef signed short SWORD ; typedef unsigned long ULONG ; typedef signed long SLONG ; void IRQ_Handler(void) __irq; void init_usr(void); #define MASKFF 0xFF #define MASK0F 0x0F #define MASKF0 0xF0 #define MASK80 0x80 #define MASK40 0x40 #define MASK20 0x20 #define MASK10 0x10 #define MASK08 0x08 #define MASK04 0x04 #define MASK02 0x02 #define MASK01 0x01 #define ASFT 16 #define WSFT 17 #define RSFT 18 #define ATRG 1 #define WTRG 2 ULONG timcnt ; void rs_putchar(UBYTE x); void crlf(void); void rs_puts(UBYTE *x); UBYTE get_hex(UBYTE x); void show_help(void); void delay_100us(UWORD x); void read_loop(void); void put_fpga(UWORD x); UBYTE get_fpga(void); void show_memory_address(void); /* global variables */ volatile UBYTE uflag ; volatile UBYTE sbuf[16] ; volatile UBYTE sindex ; volatile UBYTE cmd ; volatile UBYTE asc_hex[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; volatile UBYTE oflag ; volatile UBYTE dat ; volatile UWORD madra ; volatile UWORD madrb ; #define ALAST 160 int main(void) { UBYTE tmp ; /* initialize user */ init_usr(); /* endless loop */ while(ON) { /* opening message */ if ( oflag == ON ) { /* clear flag */ oflag = OFF ; /* show message */ rs_puts("Hello"); crlf(); } /* command interrpreter */ if ( uflag == ON ) { /* clear flag */ uflag = OFF ; /* new line */ crlf(); /* judge */ cmd = *(sbuf+0) ; if ( cmd == '?' ) { show_help(); } /* address */ if ( cmd == 'A' ) { /* get parameter */ tmp = get_hex( *(sbuf+1) ); /* send command */ put_fpga( (ATRG << 8) | tmp ) ; /* update local address */ if ( tmp == 0 ) { madra = 0 ; } if ( tmp == 2 ) { madrb = 0 ; } if ( tmp == 1 ) { madra++ ; } if ( tmp == 3 ) { madrb++ ; } } /* show memory address */ if ( cmd == 'M' ) { show_memory_address() ; } /* store data from A port */ if ( cmd == 'W' ) { /* get data */ dat = get_hex( *(sbuf+1) ); /* get upper nibble */ dat <<= 4 ; dat |= get_hex( *(sbuf+2) ); /* concatenate lower nibble */ /* send data */ put_fpga( (WTRG << 8) | dat ) ; } /* read B port data */ if ( cmd == 'R' ) { read_loop(); } } } /* dummy return */ return (0); } void IRQ_Handler(void) __irq { volatile UBYTE ch ; /* judge UART receive interruption */ if ( (IRQSTA & UART_BIT) == UART_BIT ) { /* judge */ if ( COMSTA0 & 1 ) { /* clear flag */ ch = COMRX ; *(sbuf+sindex) = ch ; sindex++ ; if ( ch == '\r' ) { sindex = 0 ; uflag = ON ; } } } /* judge timer3 interruption (1ms) */ if ( (IRQSTA & WATCHDOG_TIMER_BIT) == WATCHDOG_TIMER_BIT ) { /* clear timer3 interrupt flag */ T3CLRI = 0xff ; /* increment */ timcnt++ ; /* blink */ if ( (timcnt & 0x3ff) == 1000 ) { GP4DAT ^= (1 << 23); } } } void init_usr(void) { /* select clock 10.44MHz initialized in start up routine */ PLLKEY1 = 0xaa ; PLLCON = 0x01 ; PLLKEY2 = 0x55 ; /* power control initialized in start up routine */ /* initialize flag */ uflag = OFF ; oflag = ON ; /* clear counter */ timcnt = 0 ; /* initialize UART */ { /* set baud rate 19200 bps CD = 2 */ COMCON0 = 0x80 ; /* select COMDIV1 and COMDIV0 */ COMDIV0 = 0x11 ; COMDIV1 = 0x00 ; /* set conditions */ COMCON0 = 0x03 ; /* select COMRX and COMTX , 8bit data , 1 stop bit , no parity */ /* enable interrupt */ COMIEN0 = 0x01 ; /* ERBFI */ } /* P0 */ { /* */ GP0DAT = 0xDF000000 ; } /* P1 */ { /* use UART */ GP1CON = 0x00000011 ; /* */ GP1DAT = 0xfef00000 ; } /* P2 */ { /* all bits outputs */ GP2DAT = 0xff000000 ; } /* P3 */ { /* all bits outputs */ GP3DAT = 0xff000000 ; } /* P4 */ { GP4DAT = 0xff000000 ; } /* */ madra = 0 ; madrb = 0 ; dat = 0 ; /* initialize timer 3 (1s) */ { T3LD = 33 ; /* (32.768kHz / 33) = about 1kHz */ T3CON = 0xc0 ; /* enable , cyclic , 1/1 */ } /* enable timer 3 interrupt and UART interrupt */ IRQEN = WATCHDOG_TIMER_BIT | UART_BIT ; } /* UART putchar */ void rs_putchar(UBYTE x) { /* ? transmmit buffer empty */ while( (COMSTA0 & 0x40) == 0 ) ; /* set value */ COMTX = x ; } /* carriage return and line feed */ void crlf(void) { rs_putchar('\r'); rs_putchar('\n'); } /* UART puts */ void rs_puts(UBYTE *x) { while ( *x != '\0' ) { rs_putchar( *x ) ; x++ ; } } /* convert ASCII to number */ UBYTE get_hex(UBYTE x) { UBYTE result ; /* default */ result = 0 ; /* judge */ if ( '0' <= x && x <= '9' ) { result = x - '0' ; } if ( 'A' <= x && x <= 'F' ) { result = x - 'A' + 10 ; } if ( 'a' <= x && x <= 'f' ) { result = x - 'a' + 10 ; } return result ; } /* show help */ void show_help(void) { rs_puts("? help") ; crlf(); rs_puts("A handling address") ; crlf(); rs_puts(" A0 clear A port address") ; crlf(); rs_puts(" A1 increase A port address") ; crlf(); rs_puts(" A2 clear B port address") ; crlf(); rs_puts(" A3 increase B port address") ; crlf(); rs_puts("W write value to A port ") ; crlf(); rs_puts("R read B port data") ; crlf(); rs_puts("M show memory address") ; crlf(); } void delay_100us(UWORD x) { ULONG last ; /* calculate */ last = timcnt + x ; /* wait */ while ( timcnt < last ) ; } void read_loop(void) { UBYTE result ; UBYTE madr[6] ; UBYTE i ; /* default */ *(madr+4) = ':'; *(madr+5) = '\0'; /* clear address */ put_fpga((ATRG < 8) | 0x02); /* loop */ for ( i = 0 ; i < ALAST ; i++ ) { /* show address */ if ( (i & MASK0F) == 0 ) { /* calculate address */ *(madr+0) = ((i >> 12) & MASK0F) ; *(madr+1) = ((i >> 8) & MASK0F) ; *(madr+2) = ((i >> 4) & MASK0F) ; *(madr+3) = (i & MASK0F) ; /* convert */ *(madr+0) = asc_hex[*(madr+0)] ; *(madr+1) = asc_hex[*(madr+1)] ; *(madr+2) = asc_hex[*(madr+2)] ; *(madr+3) = asc_hex[*(madr+3)] ; /* show */ rs_puts( madr ); } /* get data */ result = get_fpga() ; /* show */ rs_putchar(asc_hex[(result >> 4) & MASK0F]); rs_putchar(asc_hex[result & MASK0F]); rs_putchar(' '); /* judge new line */ if ( (i & MASK0F) == 15 ) { crlf(); } /* address increment */ put_fpga((ATRG << 8) | 0x03); } /* clear address */ put_fpga((ATRG << 8) | 0x02); /* new line */ crlf(); } void put_fpga(UWORD x) { UBYTE xcmd ; UBYTE xsft ; /* impress data to GP3 */ GP3DAT &= 0xFF00FFFF ; GP3DAT |= ((x & MASKFF) << 16) ; /* judge trigger */ xcmd = (x >> 8) & MASKFF ; if ( xcmd == ATRG ) { xsft = ASFT ; } if ( xcmd == WTRG ) { xsft = WSFT ; } /* trigger */ GP2DAT &= 0xFF00FFFF ; GP2DAT |= (1 << xsft) ; GP2DAT &= 0xFF00FFFF ; } UBYTE get_fpga(void) { UBYTE result ; /* change GP3 input */ GP3DAT &= 0x00FFFFFF ; /* enable OE */ GP2DAT &= 0xFF00FFFF ; GP2DAT |= (1 << RSFT) ; /* delay */ delay_100us(2); /* get data */ result = GP3DAT & MASKFF ; /* disable OE */ GP2DAT &= 0xFF00FFFF ; /* change GP3 output */ GP3DAT |= 0xFF000000 ; return result ; } void show_memory_address(void) { UBYTE madr[6] ; UBYTE loop ; UWORD tmp ; /* default */ *(madr+4) = ':'; *(madr+5) = '\0'; /* loop */ for ( loop = 0 ; loop < 2 ; loop++ ) { /* get address */ tmp = madra ; if ( loop ) { tmp = madrb ; } /* calculate address */ *(madr+0) = ((tmp >> 12) & MASK0F) ; *(madr+1) = ((tmp >> 8) & MASK0F) ; *(madr+2) = ((tmp >> 4) & MASK0F) ; *(madr+3) = (tmp & MASK0F) ; /* convert */ *(madr+0) = asc_hex[*(madr+0)] ; *(madr+1) = asc_hex[*(madr+1)] ; *(madr+2) = asc_hex[*(madr+2)] ; *(madr+3) = asc_hex[*(madr+3)] ; /* show */ rs_puts( madr ); /* new line */ crlf(); } }  FPGA内のDualPortMemoryを操作するVHDLコードは  次のように定義してあります。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; Library UNISIM; use UNISIM.vcomponents.all; entity dpmtsty is port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- trigger ATRG : in std_logic ; WTRG : in std_logic ; RTRG : in std_logic ; -- data BUS ADBUS : inout std_logic_vector(7 downto 0) ; -- address monitor SEL : in std_logic ; ROUT : out std_logic_vector(7 downto 0) ; GOUT : out std_logic_vector(2 downto 0) ; MCLKX : out std_logic -- ; ); end dpmtsty; architecture Behavioral of dpmtsty is -- clock (input) signal iCLK0_OUT : std_logic ; signal iCLKFX : std_logic ; signal iCLKFB_IN : std_logic ; signal iCLKIN_IBUFG : std_logic ; signal iCLKFX_OUT : std_logic ; -- trigger signal iATRG_SFT : std_logic_vector(2 downto 0) ; signal iWTRG_SFT : std_logic_vector(2 downto 0) ; signal iATRG : std_logic ; signal iWTRG : std_logic ; -- address sequencer signal iASTATE : std_logic_vector(1 downto 0) ; signal iAREG : std_logic_vector(1 downto 0) ; -- data sequencer signal iWSTATE : std_logic_vector(1 downto 0) ; -- internal registers (A port) signal iADRA : std_logic_vector(10 downto 0) ; signal iDIA : std_logic_vector( 7 downto 0) ; signal iWEA : std_logic ; -- internal registers (Bport) signal iDOB : std_logic_vector( 7 downto 0) ; signal iADRB : std_logic_vector(10 downto 0) ; begin -- input clock buffer handling IBUFG_inst : IBUFG generic map (IOSTANDARD => "DEFAULT") port map ( O => iCLKIN_IBUFG, -- Clock buffer output I => CLOCK -- Clock buffer input (connect directly to top-level port) ); -- output clock buffer handling BUFG_inst : BUFG port map ( O => iCLKFB_IN, -- Clock buffer output I => iCLK0_OUT -- Clock buffer input ); -- output clock buffer handling BUFG_instX : BUFG port map ( O => iCLKFX_OUT , -- Clock buffer output I => iCLKFX -- Clock buffer input ); -- DCM (48MHz/4 = 12MHz) -- MULTIPLY 2 -- DIVIDE 8 -- (2 / 4) * 24 = (1 / 2) * 24 = 12 DCM_inst : DCM generic map ( CLKDV_DIVIDE => 2.0, -- Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5 -- 7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0 CLKFX_DIVIDE => 4, -- Can be any integer from 1 to 32 CLKFX_MULTIPLY => 2, -- Can be any integer from 2 to 32 CLKIN_DIVIDE_BY_2 => TRUE, -- TRUE/FALSE to enable CLKIN divide by two feature CLKIN_PERIOD => 20.833, -- Specify period of input clock CLKOUT_PHASE_SHIFT => "FIXED", -- Specify phase shift of NONE, FIXED or VARIABLE CLK_FEEDBACK => "1X", -- Specify clock feedback of NONE, 1X or 2X DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS", -- SOURCE_SYNCHRONOUS, SYSTEM_SYNCHRONOUS or -- an integer from 0 to 15 DFS_FREQUENCY_MODE => "LOW", -- HIGH or LOW frequency mode for frequency synthesis DLL_FREQUENCY_MODE => "LOW", -- HIGH or LOW frequency mode for DLL DUTY_CYCLE_CORRECTION => TRUE, -- Duty cycle correction, TRUE or FALSE FACTORY_JF => X"C080", -- FACTORY JF Values PHASE_SHIFT => 0, -- Amount of fixed phase shift from -255 to 255 SIM_MODE => "SAFE", -- Simulation: "SAFE" vs "FAST", see "Synthesis and Simulation -- Design Guide" for details STARTUP_WAIT => FALSE) -- Delay configuration DONE until DCM LOCK, TRUE/FALSE port map ( CLK0 => iCLK0_OUT, -- 0 degree DCM CLK ouptput CLK180 => open, -- 180 degree DCM CLK output CLK270 => open, -- 270 degree DCM CLK output CLK2X => open, -- 2X DCM CLK output CLK2X180 => open, -- 2X, 180 degree DCM CLK out CLK90 => open, -- 90 degree DCM CLK output CLKDV => open, -- Divided DCM CLK out (CLKDV_DIVIDE) CLKFX => iCLKFX, -- DCM CLK synthesis out (M/D) CLKFX180 => open, -- 180 degree CLK synthesis out LOCKED => open, -- DCM LOCK status output PSDONE => open, -- Dynamic phase adjust done output STATUS => open, -- 8-bit DCM status bits output CLKFB => iCLKFB_IN, -- DCM clock feedback CLKIN => iCLKIN_IBUFG, -- Clock input (from IBUFG, BUFG or DCM) PSCLK => '0', -- Dynamic phase adjust clock input PSEN => '0', -- Dynamic phase adjust enable input PSINCDEC => '0', -- Dynamic phase adjust increment/decrement RST => '0' -- DCM asynchronous reset input ); RAMB16_S9_S9_instA : RAMB16_S9_S9 generic map ( INIT_A => X"000", -- Value of output RAM registers on Port A at startup INIT_B => X"000", -- Value of output RAM registers on Port B at startup SRVAL_A => X"000", -- Port A ouput value upon SSR assertion SRVAL_B => X"000", -- Port B ouput value upon SSR assertion WRITE_MODE_A => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE WRITE_MODE_B => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE SIM_COLLISION_CHECK => "ALL", -- "NONE", "WARNING", "GENERATE_X_ONLY", "ALL" -- The following INIT_xx declarations specify the initial contents of the RAM -- Address 0 to 511 INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 512 to 1023 INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1024 to 1535 INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1536 to 2047 INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000", -- The next set of INITP_xx are for the parity bits -- Address 0 to 511 INITP_00 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_01 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 512 to 1023 INITP_02 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_03 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1024 to 1535 INITP_04 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_05 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1536 to 2047 INITP_06 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_07 => X"0000000000000000000000000000000000000000000000000000000000000000") port map ( DOA => open, -- Port A 8-bit Data Output DOB => iDOB, -- Port B 8-bit Data Output DOPA => open, -- Port A 1-bit Parity Output DOPB => open, -- Port B 1-bit Parity Output ADDRA => iADRA, -- Port A 11-bit Address Input ADDRB => iADRB, -- Port B 11-bit Address Input CLKA => iCLKFX_OUT, -- Port A Clock CLKB => iCLKFX_OUT, -- Port B Clock DIA => iDIA, -- Port A 8-bit Data Input DIB => X"FF", -- Port B 8-bit Data Input DIPA => "1", -- Port A 1-bit parity Input DIPB => "1", -- Port B 1-bit parity Input ENA => '1', -- Port A RAM Enable Input ENB => '1', -- Port B RAM Enable Input SSRA => '0', -- Port A Synchronous Set/Reset Input SSRB => '0', -- Port B Synchronous Set/Reset Input WEA => iWEA, -- Port A Write Enable Input WEB => '0' -- Port B Write Enable Input ); -- monitor output MCLKX <= not iCLKFX_OUT ; ROUT <= (not iADRB(7 downto 0)) when ( SEL = '1' ) else (not iADRA(7 downto 0)) ; GOUT <= (not iADRB(10 downto 8)) when ( SEL = '1' ) else (not iADRA(10 downto 8)) ; -- output ADBUS <= iDOB when ( RTRG = '1' ) else (others => 'Z'); -- trigger process (nRESET,iCLKFX_OUT) begin if ( nRESET = '0' ) then iATRG_SFT <= "000" ; iWTRG_SFT <= "000" ; elsif rising_edge(iCLKFX_OUT) then iATRG_SFT <= iATRG_SFT(1 downto 0) & ATRG ; iWTRG_SFT <= iWTRG_SFT(1 downto 0) & WTRG ; end if ; end process ; iATRG <= '1' when ( iATRG_SFT = "011" or iATRG_SFT = "001" ) else '0' ; iWTRG <= '1' when ( iWTRG_SFT = "011" or iWTRG_SFT = "001" ) else '0' ; -- sequencer (address handling) process (nRESET,iCLKFX_OUT) begin if ( nRESET = '0' ) then iASTATE <= "00" ; iADRA <= (others => '0') ; iADRB <= (others => '0') ; elsif rising_edge(iCLKFX_OUT) then case conv_integer(iASTATE) is -- wait trigger when 0 => if ( iATRG = '1' ) then iASTATE <= "01" ; else iASTATE <= "00" ; end if ; -- transfer when 1 => iASTATE <= "11" ; iAREG <= ADBUS(1 downto 0) ; -- decode when 3 => iASTATE <= "10" ; -- clear A port address if ( iAREG = "00" ) then iADRA <= (others => '0') ; end if ; -- increase A port address if ( iAREG = "01" ) then iADRA <= iADRA + '1' ; end if ; -- clear B port address if ( iAREG = "10" ) then iADRB <= (others => '0') ; end if ; -- increase B port address if ( iAREG = "11" ) then iADRB <= iADRB + '1' ; end if ; -- return first state when 2 => iASTATE <= "00" ; -- default when others => iASTATE <= "00" ; end case ; end if ; end process ; -- sequencer (write handling) process (nRESET,iCLKFX_OUT) begin if ( nRESET = '0' ) then iWSTATE <= "00" ; iDIA <= (others => '0') ; elsif rising_edge(iCLKFX_OUT) then case conv_integer(iWSTATE) is -- wait trigger when 0 => if ( iWTRG = '1' ) then iWSTATE <= "01" ; else iWSTATE <= "00" ; end if ; -- get data when 1 => iWSTATE <= "11" ; iDIA <= ADBUS ; -- send trigger when 3 => iWSTATE <= "10" ; -- return first state when 2 => iWSTATE <= "00" ; -- default when others => iWSTATE <= "00" ; end case ; end if ; end process ; iWEA <= '1' when ( iWSTATE = "11" ) else '0' ; end Behavioral;  DCMを利用し48MHzから12MHzを生成し、このクロックで  内部回路を動かします。12MHzを選択したのは、ARMが  約11MHzで動作しているので、このクロックに近づける  意図があります。  2ポートのアドレス処理、データライトにそれぞれ  シーケンサを用意して、単純な動作になるように  回路を分けています。  メモリからのデータ取得は、8ビットバスを入力から  出力の方向切替えで対応しています。  バスは通常、入力としておき、信号RTRGにより  出力に切替えます。  ピンアサインは、以下。 # system NET "CLOCK" LOC = "P55" | IOSTANDARD = LVCMOS33 ; NET "nRESET" LOC = "P73" | IOSTANDARD = LVCMOS33 ; # G0 NET "ADBUS<0>" LOC = "P1" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<1>" LOC = "P2" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<2>" LOC = "P4" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<3>" LOC = "P5" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<4>" LOC = "P6" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<5>" LOC = "P7" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<6>" LOC = "P8" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<7>" LOC = "P10" | IOSTANDARD = LVCMOS33 ; # G1 NET "ATRG" LOC = "P11" | IOSTANDARD = LVCMOS33 ; NET "WTRG" LOC = "P12" | IOSTANDARD = LVCMOS33 ; NET "RTRG" LOC = "P13" | IOSTANDARD = LVCMOS33 ; # G0B NET "ROUT<0>" LOC = "P141" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<1>" LOC = "P140" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<2>" LOC = "P137" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<3>" LOC = "P135" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<4>" LOC = "P132" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<5>" LOC = "P131" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<6>" LOC = "P130" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<7>" LOC = "P129" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; # G1B NET "GOUT<0>" LOC = "P116" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "GOUT<1>" LOC = "P113" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "GOUT<2>" LOC = "P119" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "MCLKX" LOC = "P124" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; # G2B NET "SEL" LOC = "P103" | IOSTANDARD = LVCMOS33 ;
閾値計算  DualPortMemoryにデータを入力できると  OV7670から取得したデータとみなし、その  最大値、最小値を求め、閾値を計算できます。  元となるデータをFPGA内部のメモリに転送しなければ  動作試験ができないので、ARMの中に配列を用意して  その内容をFPGAに転送します。  ARMの配列中にデータを設定するために  コマンドを考え、次のようにします。  ARMの配列内のデータをFPGAに転送、計算、取得  するためのコマンドも必要です。  次のように、決めました。  コマンドを決めたので、ファームウエアを定義します。 #include <ADuC7026.h> #define OFF 0 #define ON OFF+1 /* data definitions */ typedef unsigned char UBYTE ; typedef signed char SBYTE ; typedef unsigned short UWORD ; typedef signed short SWORD ; typedef unsigned long ULONG ; typedef signed long SLONG ; void IRQ_Handler(void) __irq; void init_usr(void); #define MASKFF 0xFF #define MASK0F 0x0F #define MASKF0 0xF0 #define MASK80 0x80 #define MASK40 0x40 #define MASK20 0x20 #define MASK10 0x10 #define MASK08 0x08 #define MASK04 0x04 #define MASK02 0x02 #define MASK01 0x01 #define ASFT 16 #define WSFT 17 #define CSFT 18 #define BSFT 19 #define RSFT 20 #define ATRG 1 #define WTRG 2 #define CTRG 4 #define BTRG 8 ULONG timcnt ; void rs_putchar(UBYTE x); void crlf(void); void rs_puts(UBYTE *x); UBYTE get_hex(UBYTE x); void show_help(void); void delay_100us(UWORD x); void read_loop(void); void write_loop(void); void put_fpga(UWORD x); UBYTE get_fpga(UBYTE x); void show_memory_address(void); void dump_array(void); void fill_array(UBYTE x); void read_binary(void); /* global variables */ volatile UBYTE uflag ; volatile UBYTE sbuf[16] ; volatile UBYTE sindex ; volatile UBYTE cmd ; volatile UBYTE asc_hex[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; volatile UBYTE oflag ; volatile UBYTE dat ; volatile UWORD madra ; volatile UWORD madrb ; #define ALAST 160 volatile UBYTE gdat[ALAST] ; int main(void) { UBYTE tmp ; /* initialize user */ init_usr(); /* endless loop */ while(ON) { /* opening message */ if ( oflag == ON ) { /* clear flag */ oflag = OFF ; /* show message */ rs_puts("Hello"); crlf(); } /* command interrpreter */ if ( uflag == ON ) { /* clear flag */ uflag = OFF ; /* new line */ crlf(); /* judge */ cmd = *(sbuf+0) ; if ( cmd == '?' ) { show_help(); } /* address */ if ( cmd == 'A' ) { /* get parameter */ tmp = get_hex( *(sbuf+1) ); /* send command */ put_fpga( (ATRG << 8) | tmp ) ; /* update local address */ if ( tmp == 0 ) { madra = 0 ; } if ( tmp == 2 ) { madrb = 0 ; } if ( tmp == 1 ) { madra++ ; } if ( tmp == 3 ) { madrb++ ; } } /* show memory address */ if ( cmd == 'M' ) { show_memory_address() ; } /* transfer data to A port */ if ( cmd == 'T' ) { write_loop() ; } /* send calculate trigger */ if ( cmd == 'C' ) { put_fpga( (CTRG << 8) | 0x00 ); } /* dump SRAM contents */ if ( cmd == 'D' ) { dump_array(); } /* store data to SRAM */ if ( cmd == 'E' ) { /* get address */ tmp = get_hex( *(sbuf+1) ); /* get upper nibble */ tmp <<= 4 ; tmp |= get_hex( *(sbuf+2) ); /* concatenate lower nibble */ /* get data */ dat = get_hex( *(sbuf+3) ); /* get upper nibble */ dat <<= 4 ; dat |= get_hex( *(sbuf+4) ); /* concatenate lower nibble */ /* store */ *(gdat+tmp) = dat ; } /* fill SRAM */ if ( cmd == 'F' ) { /* get data */ dat = get_hex( *(sbuf+1) ); /* get upper nibble */ dat <<= 4 ; dat |= get_hex( *(sbuf+2) ); /* concatenate lower nibble */ /* store */ fill_array(dat); } /* send binary conversion trigger */ if ( cmd == 'B' ) { put_fpga( (BTRG << 8) | 0x00 ); } /* show binary data */ if ( cmd == 'X' ) { read_binary() ; } /* store data from A port */ if ( cmd == 'W' ) { /* get data */ dat = get_hex( *(sbuf+1) ); /* get upper nibble */ dat <<= 4 ; dat |= get_hex( *(sbuf+2) ); /* concatenate lower nibble */ /* send data */ put_fpga( (WTRG << 8) | dat ) ; } /* read B port data */ if ( cmd == 'R' ) { read_loop(); } } } /* dummy return */ return (0); } void IRQ_Handler(void) __irq { volatile UBYTE ch ; /* judge UART receive interruption */ if ( (IRQSTA & UART_BIT) == UART_BIT ) { /* judge */ if ( COMSTA0 & 1 ) { /* clear flag */ ch = COMRX ; *(sbuf+sindex) = ch ; sindex++ ; if ( ch == '\r' ) { sindex = 0 ; uflag = ON ; } } } /* judge timer3 interruption (1ms) */ if ( (IRQSTA & WATCHDOG_TIMER_BIT) == WATCHDOG_TIMER_BIT ) { /* clear timer3 interrupt flag */ T3CLRI = 0xff ; /* increment */ timcnt++ ; /* blink */ if ( (timcnt & 0x3ff) == 1000 ) { GP4DAT ^= (1 << 23); } } } void init_usr(void) { /* select clock 10.44MHz initialized in start up routine */ PLLKEY1 = 0xaa ; PLLCON = 0x01 ; PLLKEY2 = 0x55 ; /* power control initialized in start up routine */ /* initialize flag */ uflag = OFF ; oflag = ON ; /* clear counter */ timcnt = 0 ; /* initialize UART */ { /* set baud rate 19200 bps CD = 2 */ COMCON0 = 0x80 ; /* select COMDIV1 and COMDIV0 */ COMDIV0 = 0x11 ; COMDIV1 = 0x00 ; /* set conditions */ COMCON0 = 0x03 ; /* select COMRX and COMTX , 8bit data , 1 stop bit , no parity */ /* enable interrupt */ COMIEN0 = 0x01 ; /* ERBFI */ } /* P0 */ { /* */ GP0DAT = 0xDF000000 ; } /* P1 */ { /* use UART */ GP1CON = 0x00000011 ; /* */ GP1DAT = 0xfef00000 ; } /* P2 */ { /* all bits outputs */ GP2DAT = 0xff000000 ; } /* P3 */ { /* all bits outputs */ GP3DAT = 0xff000000 ; } /* P4 */ { GP4DAT = 0xff000000 ; } /* */ madra = 0 ; madrb = 0 ; dat = 0 ; fill_array( 0x00 ); /* initialize timer 3 (1s) */ { T3LD = 33 ; /* (32.768kHz / 33) = about 1kHz */ T3CON = 0xc0 ; /* enable , cyclic , 1/1 */ } /* enable timer 3 interrupt and UART interrupt */ IRQEN = WATCHDOG_TIMER_BIT | UART_BIT ; } /* UART putchar */ void rs_putchar(UBYTE x) { /* ? transmmit buffer empty */ while( (COMSTA0 & 0x40) == 0 ) ; /* set value */ COMTX = x ; } /* carriage return and line feed */ void crlf(void) { rs_putchar('\r'); rs_putchar('\n'); } /* UART puts */ void rs_puts(UBYTE *x) { while ( *x != '\0' ) { rs_putchar( *x ) ; x++ ; } } /* convert ASCII to number */ UBYTE get_hex(UBYTE x) { UBYTE result ; /* default */ result = 0 ; /* judge */ if ( '0' <= x && x <= '9' ) { result = x - '0' ; } if ( 'A' <= x && x <= 'F' ) { result = x - 'A' + 10 ; } if ( 'a' <= x && x <= 'f' ) { result = x - 'a' + 10 ; } return result ; } /* show help */ void show_help(void) { rs_puts("? help") ; crlf(); rs_puts("A handling address") ; crlf(); rs_puts(" A0 clear A port address") ; crlf(); rs_puts(" A1 increase A port address") ; crlf(); rs_puts(" A2 clear B port address") ; crlf(); rs_puts(" A3 increase B port address") ; crlf(); rs_puts("W write value to A port ") ; crlf(); rs_puts("R read B port data") ; crlf(); rs_puts("M show memory address") ; crlf(); rs_puts("T transfer data") ; crlf(); rs_puts("C calculate") ; crlf(); rs_puts("D dump SRAM contents") ; crlf(); rs_puts("F fill SRAM") ; crlf(); rs_puts("E store data to SRAM") ; crlf(); rs_puts("B binary convert") ; crlf(); rs_puts("X read binary data") ; crlf(); } void delay_100us(UWORD x) { ULONG last ; /* calculate */ last = timcnt + x ; /* wait */ while ( timcnt < last ) ; } void dump_array(void) { UBYTE result ; UBYTE madr[4] ; UBYTE i ; /* default */ *(madr+2) = ':'; *(madr+3) = '\0'; /* loop */ for ( i = 0 ; i < ALAST ; i++ ) { /* show address */ if ( (i & MASK0F) == 0 ) { /* calculate address */ *(madr+0) = ((i >> 4) & MASK0F); *(madr+1) = (i & MASK0F) ; /* convert */ *(madr+0) = asc_hex[*(madr+0)] ; *(madr+1) = asc_hex[*(madr+1)] ; /* show */ rs_puts( madr ); } /* get data */ result = *(gdat+i) ; /* show */ rs_putchar(asc_hex[(result >> 4) & MASK0F]); rs_putchar(asc_hex[result & MASK0F]); rs_putchar(' '); /* judge new line */ if ( (i & MASK0F) == 15 ) { crlf(); } } /* new line */ crlf(); } void fill_array(UBYTE x) { UBYTE i ; /* loop */ for ( i = 0 ; i < ALAST ; i++ ) { *(gdat+i) = x ; } } void read_loop(void) { UBYTE result ; UBYTE madr[6] ; UBYTE i ; /* default */ *(madr+4) = ':'; *(madr+5) = '\0'; /* clear B port address */ put_fpga((ATRG << 8) | 0x02); /* loop */ for ( i = 0 ; i < ALAST ; i++ ) { /* show address */ if ( (i & MASK0F) == 0 ) { /* calculate address */ *(madr+0) = ((i >> 12) & MASK0F) ; *(madr+1) = ((i >> 8) & MASK0F) ; *(madr+2) = ((i >> 4) & MASK0F) ; *(madr+3) = (i & MASK0F) ; /* convert */ *(madr+0) = asc_hex[*(madr+0)] ; *(madr+1) = asc_hex[*(madr+1)] ; *(madr+2) = asc_hex[*(madr+2)] ; *(madr+3) = asc_hex[*(madr+3)] ; /* show */ rs_puts( madr ); } /* get data */ result = get_fpga(0) ; /* show */ rs_putchar(asc_hex[(result >> 4) & MASK0F]); rs_putchar(asc_hex[result & MASK0F]); rs_putchar(' '); /* judge new line */ if ( (i & MASK0F) == 15 ) { crlf(); } /* address increment */ put_fpga((ATRG << 8) | 0x03); } /* new line */ crlf(); /* clear address */ put_fpga((ATRG << 8) | 0x02); /* minimum */ { result = get_fpga(1) ; rs_puts("Minimum = "); rs_putchar(asc_hex[(result >> 4) & MASK0F]); rs_putchar(asc_hex[result & MASK0F]); crlf(); } /* maximum */ { result = get_fpga(2) ; rs_puts("Maximum = "); rs_putchar(asc_hex[(result >> 4) & MASK0F]); rs_putchar(asc_hex[result & MASK0F]); crlf(); } /* threshold */ { result = get_fpga(3) ; rs_puts("Threshold = "); rs_putchar(asc_hex[(result >> 4) & MASK0F]); rs_putchar(asc_hex[result & MASK0F]); crlf(); } } void write_loop(void) { UBYTE tmp ; UBYTE i ; /* clear A port address */ put_fpga((ATRG << 8) | 0x00); /* loop */ for ( i = 0 ; i < ALAST ; i++ ) { /* get data */ tmp = *(gdat+i) ; /* send */ put_fpga((WTRG << 8) | tmp) ; /* A port address increment */ put_fpga((ATRG << 8) | 0x01); } /* clear A port address */ put_fpga((ATRG << 8) | 0x00); /* new line */ crlf(); } void put_fpga(UWORD x) { UBYTE xcmd ; UBYTE xsft ; /* impress data to GP3 */ GP3DAT &= 0xFF00FFFF ; GP3DAT |= ((x & MASKFF) << 16) ; /* judge trigger */ xcmd = (x >> 8) & MASKFF ; if ( xcmd == ATRG ) { xsft = ASFT ; } if ( xcmd == WTRG ) { xsft = WSFT ; } if ( xcmd == CTRG ) { xsft = CSFT ; } if ( xcmd == BTRG ) { xsft = BSFT ; } /* trigger */ GP2DAT &= 0xFF00FFFF ; GP2DAT |= (1 << xsft) ; GP2DAT &= 0xFF00FFFF ; } UBYTE get_fpga(UBYTE x) { UBYTE result ; /* change GP3 input */ GP3DAT &= 0x00FFFFFF ; /* enable OE */ GP2DAT &= 0xFF00FFFF ; GP2DAT |= ((x << 21) | (1 << RSFT)); /* RSEL2 RSEL1 RSEL0 RTRG = 23 22 21 20 */ /* delay */ delay_100us(2); /* get data */ result = GP3DAT & MASKFF ; /* disable OE */ GP2DAT &= 0xFF00FFFF ; /* change GP3 output */ GP3DAT |= 0xFF000000 ; return result ; } void show_memory_address(void) { UBYTE madr[6] ; UBYTE loop ; UWORD tmp ; /* default */ *(madr+4) = ':'; *(madr+5) = '\0'; /* loop */ for ( loop = 0 ; loop < 2 ; loop++ ) { /* get address */ tmp = madra ; if ( loop ) { tmp = madrb ; } /* calculate address */ *(madr+0) = ((tmp >> 12) & MASK0F) ; *(madr+1) = ((tmp >> 8) & MASK0F) ; *(madr+2) = ((tmp >> 4) & MASK0F) ; *(madr+3) = (tmp & MASK0F) ; /* convert */ *(madr+0) = asc_hex[*(madr+0)] ; *(madr+1) = asc_hex[*(madr+1)] ; *(madr+2) = asc_hex[*(madr+2)] ; *(madr+3) = asc_hex[*(madr+3)] ; /* show */ rs_puts( madr ); /* new line */ crlf(); } } void read_binary(void) { UBYTE result ; UBYTE madr[4] ; UBYTE i ; /* default */ *(madr+2) = ':'; *(madr+3) = '\0'; /* clear shift register address address */ put_fpga((ATRG << 8) | 0x04); /* loop */ for ( i = 0 ; i < 20 ; i++ ) { /* show address */ if ( (i % 8) == 0 ) { /* calculate address */ *(madr+0) = ((i >> 4) & MASK0F); *(madr+1) = (i & MASK0F) ; /* convert */ *(madr+0) = asc_hex[*(madr+0)] ; *(madr+1) = asc_hex[*(madr+1)] ; /* show */ rs_puts( madr ); } /* get data */ result = get_fpga(4) ; /* show */ rs_putchar( ((result >> 7) & 1) + '0' ); rs_putchar( ((result >> 6) & 1) + '0' ); rs_putchar( ((result >> 5) & 1) + '0' ); rs_putchar( ((result >> 4) & 1) + '0' ); rs_putchar( ((result >> 3) & 1) + '0' ); rs_putchar( ((result >> 2) & 1) + '0' ); rs_putchar( ((result >> 1) & 1) + '0' ); rs_putchar( (result & 1) + '0' ); /* judge new line */ if ( (i % 8) == 7 ) { crlf(); } /* shift register increment */ put_fpga((ATRG << 8) | 0x05); } /* new line */ crlf(); /* clear shift register address address */ put_fpga((ATRG << 8) | 0x04); }  HyperTerminalを利用し、ARMだけで完結する動作を  テストしました。  'D'(dump)コマンドのテスト。  'F'(fill)、'D'(dump)、'E'(enter)コマンドのテスト。  'E'(enter)、'D'(dump)コマンドのテスト。  FPGAを接続し、'C'(calcualte)、'R'(read)コマンドのテスト。  最大値、最小値、閾値を求める処理は、正しく動いて  いることを確認できました。  FPGA内部にあるトリガーを与えて、最大値、最小値、閾値を  求めるためのシーケンサは、以下のように定義。 process (nRESET,iCLKFX_OUT) begin if ( nRESET = '0' ) then iCSTATE <= 0 ; iCREG <= "00" ; iCMAX <= (others => '0') ; iCMIN <= (others => '0') ; iCCOUNT <= 0 ; iCTHV <= 0 ; elsif rising_edge(iCLKFX_OUT) then case iCSTATE is -- wait trigger when 0 => if ( iCTRG = '1' ) then iCSTATE <= 1 ; else iCSTATE <= 0 ; end if ; -- clear B port address when 1 => iCSTATE <= 2 ; iCREG <= "10" ; -- send trigger when 2 => iCSTATE <= 3 ; -- delay when 3 => iCSTATE <= 4 ; -- wait complete when 4 => if ( iASTATE = "00" ) then iCSTATE <= 5 ; -- next else iCSTATE <= 4 ; -- stay end if ; -- set MAX and MIN when 5 => iCSTATE <= 6 ; -- next iCMAX <= iDOB ; -- maximum iCMIN <= iDOB ; -- minimum iCCOUNT <= 0 ; -- increse B port address when 6 => iCSTATE <= 7 ; iCREG <= "11" ; iCCOUNT <= iCCOUNT + 1 ; -- send trigger when 7 => iCSTATE <= 8 ; -- delay when 8 => iCSTATE <= 9 ; -- wait complete when 9 => if ( iASTATE = "00" ) then iCSTATE <= 10 ; -- next else iCSTATE <= 9 ; -- stay end if ; -- compare when 10 => iCSTATE <= 11 ; if ( conv_integer(iCMAX) < conv_integer(iDOB) ) then iCMAX <= iDOB ; end if ; if ( conv_integer(iCMIN) > conv_integer(iDOB) ) then iCMIN <= iDOB ; end if ; -- judge when 11 => if ( iCCOUNT = PIXEL_LAST ) then iCSTATE <= 12 ; -- exit else iCSTATE <= 6 ; -- loop end if ; -- return first state when 12 => iCSTATE <= 0 ; iCTHV <= (conv_integer(iCMAX)+conv_integer(iCMIN)) / 2 ; -- default when others => iCSTATE <= 0 ; end case ; end if ; end process ; iAXTRG <= '1' when ( iCSTATE = 2 or iCSTATE = 7 ) else '0' ; iCTHVX <= conv_std_logic_vector(iCTHV,8) ;  トリガーを与えられたなら、Bポートからアドレス0のデータを  取出して、仮の最大値、最小値とします。残り159個のデータを  取出しては、比較し、最大値、最小値を求めます。  すべて比較し終えたなら、閾値を求めます。  DualPortMemoryのA、Bポートのアドレスを操作するため  アドレス処理シーケンサを、定義し直しました。 process (nRESET,iCLKFX_OUT) begin if ( nRESET = '0' ) then iASTATE <= "00" ; iADRA <= (others => '0') ; iADRB <= (others => '0') ; iASEL <= "00" ; iBPTR <= 0 ; elsif rising_edge(iCLKFX_OUT) then case conv_integer(iASTATE) is -- wait trigger when 0 => if ( iATRG = '1' ) then iASTATE <= "01" ; elsif ( iAXTRG = '1' ) then iASTATE <= "01" ; iASEL <= "01" ; elsif ( iAYTRG = '1' ) then iASTATE <= "01" ; iASEL <= "10" ; else iASTATE <= "00" ; end if ; -- transfer when 1 => iASTATE <= "11" ; if ( iASEL(0) = '1' ) then iAREG <= '0' & iCREG ; elsif ( iASEL(1) = '1' ) then iAREG <= '0' & iBREG ; else iAREG <= ADBUS(2 downto 0) ; end if ; -- decode when 3 => iASTATE <= "10" ; -- clear A port address if ( iAREG = "000" ) then iADRA <= (others => '0') ; end if ; -- increase A port address if ( iAREG = "001" ) then iADRA <= iADRA + '1' ; end if ; -- clear B port address if ( iAREG = "010" ) then iADRB <= (others => '0') ; end if ; -- increase B port address if ( iAREG = "011" ) then iADRB <= iADRB + '1' ; end if ; -- clear shift register pointer if ( iAREG = "100" ) then iBPTR <= 0 ; end if ; -- increase shift register pointer if ( iAREG = "101" ) then iBPTR <= iBPTR + 1 ; end if ; -- return first state when 2 => iASTATE <= "00" ; iASEL <= "00" ; -- default when others => iASTATE <= "00" ; end case ; end if ; end process ;  A、Bポートのアドレスをクリア、+1する指示を  ARMマイコンから与える他、最大値、最小値、閾値  を計算させるシーケンサから、Bポートアドレスを  クリア、+1する処理を加えました。  さらに、2値化を担当するシーケンサから、Bポート  のアドレスを操作する処理も加えました。  トリガーを加えFPGAから読み出すデータが  増えたので、8ビットの制御ピンの扱いを  次のように変更しました。
2値化  最大値、最小値、閾値を求められたなら  閾値を使い、データを2値化します。  2値化を担当するシーケンサを定義します。 process (nRESET,iCLKFX_OUT) begin if ( nRESET = '0' ) then iBSTATE <= 0 ; iBCOUNT <= 0 ; iBREG <= "00" ; iBDAT <= (others => '0') ; elsif rising_edge(iCLKFX_OUT) then case iBSTATE is -- wait trigger when 0 => if ( iBTRG = '1' ) then iBSTATE <= 1 ; else iBSTATE <= 0 ; end if ; -- clear counter when 1 => iBSTATE <= 2 ; iBCOUNT <= 0 ; -- set B port address zero when 2 => iBSTATE <= 3 ; iBREG <= "10" ; -- send trigger when 3 => iBSTATE <= 4 ; -- delay when 4 => iBSTATE <= 5 ; -- wait complete when 5 => if ( iASTATE = "00" ) then iBSTATE <= 6 ; else iBSTATE <= 5 ; end if ; -- get memory data when 6 => iBSTATE <= 7 ; iBDAT <= iDOB ; -- compare and store when 7 => iBSTATE <= 8 ; if ( conv_integer(iBDAT) > iCTHV ) then iBSFT(iBCOUNT) <= '1' ; else iBSFT(iBCOUNT) <= '0' ; end if ; -- counter increment when 8 => iBSTATE <= 9 ; iBCOUNT <= iBCOUNT + 1 ; -- judge complete when 9 => if ( iBCOUNT = PIXEL_MAX ) then iBSTATE <= 10 ; -- exit else iBSTATE <= 3 ; -- loop iBREG <= "11" ; -- increse B port address end if ; -- set B port address zero when 10 => iBSTATE <= 11 ; iBREG <= "10" ; -- send trigger when 11 => iBSTATE <= 12 ; -- return first state when 12 => iBSTATE <= 0 ; -- default when others => iBSTATE <= 0 ; end case ; end if ; end process ; iAYTRG <= '1' when ( iBSTATE = 3 or iBSTATE = 11 ) else '0' ;  トリガーで動作開始を指示されると、Bポートアドレスを  クリア、+1しながら、閾値とデータを比較します。  比較の結果で1か0を確定し、結果をレジスタに保存します。  レジスタのビット数は、160とします。  160ビットのレジスタ値を8ビットに区切って出力する  ように、バス出力を次のようにしました。 iBSFTV <= iBSFT(8*iBPTR to 8*iBPTR+7); ADBUS <= iDOB when ( RTRG = '1' and RSEL = "000" ) else -- B port data iCMIN when ( RTRG = '1' and RSEL = "001" ) else -- min iCMAX when ( RTRG = '1' and RSEL = "010" ) else -- max iCTHVX when ( RTRG = '1' and RSEL = "011" ) else -- threshold iBSFTV when ( RTRG = '1' and RSEL = "100" ) else -- binary data (others => 'Z');  iBPTRの値は、アドレスを扱う回路でクリアと+1するように  定義してあります。  ファームウエアからの指示で、動作を確認しました。  端末では、次の操作をしました。
  1. 'R'コマンドで、DualPortMemoryの内容確認
  2. 'C'コマンドで、最大値、最小値、閾値を計算
  3. 'B'コマンドで、2値化しレジスタに保存
  4. 'X'コマンドで、2値化した値を表示
 FPGAに入れたVHDLコードは、以下です。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; Library UNISIM; use UNISIM.vcomponents.all; entity dpmtsty is generic ( PIXEL_MAX : integer := 160 ; PIXEL_LAST : integer := 159 --; ) ; port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- trigger ATRG : in std_logic ; WTRG : in std_logic ; RTRG : in std_logic ; CTRG : in std_logic ; BTRG : in std_logic ; RSEL : in std_logic_vector(2 downto 0) ; -- data BUS ADBUS : inout std_logic_vector(7 downto 0) ; -- address monitor SEL : in std_logic ; ROUT : out std_logic_vector(7 downto 0) ; GOUT : out std_logic_vector(2 downto 0) ; MCLKX : out std_logic -- ; ); end dpmtsty; architecture Behavioral of dpmtsty is -- clock (input) signal iCLK0_OUT : std_logic ; signal iCLKFX : std_logic ; signal iCLKFB_IN : std_logic ; signal iCLKIN_IBUFG : std_logic ; signal iCLKFX_OUT : std_logic ; -- trigger signal iATRG_SFT : std_logic_vector(2 downto 0) ; signal iWTRG_SFT : std_logic_vector(2 downto 0) ; signal iCTRG_SFT : std_logic_vector(2 downto 0) ; signal iBTRG_SFT : std_logic_vector(2 downto 0) ; signal iATRG : std_logic ; signal iWTRG : std_logic ; signal iCTRG : std_logic ; signal iBTRG : std_logic ; -- address sequencer signal iASTATE : std_logic_vector(1 downto 0) ; signal iAREG : std_logic_vector(2 downto 0) ; signal iASEL : std_logic_vector(1 downto 0) ; -- data sequencer signal iWSTATE : std_logic_vector(1 downto 0) ; -- calculate sequencer signal iCSTATE : integer range 0 to 12 ; signal iCREG : std_logic_vector(1 downto 0) ; signal iAXTRG : std_logic ; signal iCMAX : std_logic_vector( 7 downto 0) ; signal iCMIN : std_logic_vector( 7 downto 0) ; signal iCCOUNT : integer range 0 to PIXEL_LAST ; signal iCTHV : integer range 0 to 255 ; signal iCTHVX : std_logic_vector( 7 downto 0) ; -- binary conversion sequencer signal iBSTATE : integer range 0 to 12 ; signal iBREG : std_logic_vector(1 downto 0) ; signal iBDAT : std_logic_vector(7 downto 0) ; signal iAYTRG : std_logic ; signal iBCOUNT : integer range 0 to PIXEL_LAST ; signal iBSFT : std_logic_vector(0 to PIXEL_LAST) ; signal iBPTR : integer range 0 to 21 ; signal iBSFTV : std_logic_vector(0 to 7) ; -- internal registers (A port) signal iADRA : std_logic_vector(10 downto 0) ; signal iDIA : std_logic_vector( 7 downto 0) ; signal iWEA : std_logic ; -- internal registers (Bport) signal iDOB : std_logic_vector( 7 downto 0) ; signal iADRB : std_logic_vector(10 downto 0) ; begin -- input clock buffer handling IBUFG_inst : IBUFG generic map (IOSTANDARD => "DEFAULT") port map ( O => iCLKIN_IBUFG, -- Clock buffer output I => CLOCK -- Clock buffer input (connect directly to top-level port) ); -- output clock buffer handling BUFG_inst : BUFG port map ( O => iCLKFB_IN, -- Clock buffer output I => iCLK0_OUT -- Clock buffer input ); -- output clock buffer handling BUFG_instX : BUFG port map ( O => iCLKFX_OUT , -- Clock buffer output I => iCLKFX -- Clock buffer input ); -- DCM (48MHz/4 = 12MHz) -- MULTIPLY 2 -- DIVIDE 8 -- (2 / 4) * 24 = (1 / 2) * 24 = 12 DCM_inst : DCM generic map ( CLKDV_DIVIDE => 2.0, -- Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5 -- 7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0 CLKFX_DIVIDE => 4, -- Can be any integer from 1 to 32 CLKFX_MULTIPLY => 2, -- Can be any integer from 2 to 32 CLKIN_DIVIDE_BY_2 => TRUE, -- TRUE/FALSE to enable CLKIN divide by two feature CLKIN_PERIOD => 20.833, -- Specify period of input clock CLKOUT_PHASE_SHIFT => "FIXED", -- Specify phase shift of NONE, FIXED or VARIABLE CLK_FEEDBACK => "1X", -- Specify clock feedback of NONE, 1X or 2X DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS", -- SOURCE_SYNCHRONOUS, SYSTEM_SYNCHRONOUS or -- an integer from 0 to 15 DFS_FREQUENCY_MODE => "LOW", -- HIGH or LOW frequency mode for frequency synthesis DLL_FREQUENCY_MODE => "LOW", -- HIGH or LOW frequency mode for DLL DUTY_CYCLE_CORRECTION => TRUE, -- Duty cycle correction, TRUE or FALSE FACTORY_JF => X"C080", -- FACTORY JF Values PHASE_SHIFT => 0, -- Amount of fixed phase shift from -255 to 255 SIM_MODE => "SAFE", -- Simulation: "SAFE" vs "FAST", see "Synthesis and Simulation -- Design Guide" for details STARTUP_WAIT => FALSE) -- Delay configuration DONE until DCM LOCK, TRUE/FALSE port map ( CLK0 => iCLK0_OUT, -- 0 degree DCM CLK ouptput CLK180 => open, -- 180 degree DCM CLK output CLK270 => open, -- 270 degree DCM CLK output CLK2X => open, -- 2X DCM CLK output CLK2X180 => open, -- 2X, 180 degree DCM CLK out CLK90 => open, -- 90 degree DCM CLK output CLKDV => open, -- Divided DCM CLK out (CLKDV_DIVIDE) CLKFX => iCLKFX, -- DCM CLK synthesis out (M/D) CLKFX180 => open, -- 180 degree CLK synthesis out LOCKED => open, -- DCM LOCK status output PSDONE => open, -- Dynamic phase adjust done output STATUS => open, -- 8-bit DCM status bits output CLKFB => iCLKFB_IN, -- DCM clock feedback CLKIN => iCLKIN_IBUFG, -- Clock input (from IBUFG, BUFG or DCM) PSCLK => '0', -- Dynamic phase adjust clock input PSEN => '0', -- Dynamic phase adjust enable input PSINCDEC => '0', -- Dynamic phase adjust increment/decrement RST => '0' -- DCM asynchronous reset input ); RAMB16_S9_S9_instA : RAMB16_S9_S9 generic map ( INIT_A => X"000", -- Value of output RAM registers on Port A at startup INIT_B => X"000", -- Value of output RAM registers on Port B at startup SRVAL_A => X"000", -- Port A ouput value upon SSR assertion SRVAL_B => X"000", -- Port B ouput value upon SSR assertion WRITE_MODE_A => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE WRITE_MODE_B => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE SIM_COLLISION_CHECK => "ALL", -- "NONE", "WARNING", "GENERATE_X_ONLY", "ALL" -- The following INIT_xx declarations specify the initial contents of the RAM -- Address 0 to 511 INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 512 to 1023 INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1024 to 1535 INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1536 to 2047 INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000", -- The next set of INITP_xx are for the parity bits -- Address 0 to 511 INITP_00 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_01 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 512 to 1023 INITP_02 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_03 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1024 to 1535 INITP_04 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_05 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1536 to 2047 INITP_06 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_07 => X"0000000000000000000000000000000000000000000000000000000000000000") port map ( DOA => open, -- Port A 8-bit Data Output DOB => iDOB, -- Port B 8-bit Data Output DOPA => open, -- Port A 1-bit Parity Output DOPB => open, -- Port B 1-bit Parity Output ADDRA => iADRA, -- Port A 11-bit Address Input ADDRB => iADRB, -- Port B 11-bit Address Input CLKA => iCLKFX_OUT, -- Port A Clock CLKB => iCLKFX_OUT, -- Port B Clock DIA => iDIA, -- Port A 8-bit Data Input DIB => X"FF", -- Port B 8-bit Data Input DIPA => "1", -- Port A 1-bit parity Input DIPB => "1", -- Port B 1-bit parity Input ENA => '1', -- Port A RAM Enable Input ENB => '1', -- Port B RAM Enable Input SSRA => '0', -- Port A Synchronous Set/Reset Input SSRB => '0', -- Port B Synchronous Set/Reset Input WEA => iWEA, -- Port A Write Enable Input WEB => '0' -- Port B Write Enable Input ); -- monitor output MCLKX <= not iCLKFX_OUT ; ROUT <= (not iADRB(7 downto 0)) when ( SEL = '1' ) else (not iADRA(7 downto 0)) ; GOUT <= (not iADRB(10 downto 8)) when ( SEL = '1' ) else (not iADRA(10 downto 8)) ; -- output ADBUS <= iDOB when ( RTRG = '1' and RSEL = "000" ) else -- B port data iCMIN when ( RTRG = '1' and RSEL = "001" ) else -- min iCMAX when ( RTRG = '1' and RSEL = "010" ) else -- max iCTHVX when ( RTRG = '1' and RSEL = "011" ) else -- threshold iBSFTV when ( RTRG = '1' and RSEL = "100" ) else -- binary data (others => 'Z'); -- trigger process (nRESET,iCLKFX_OUT) begin if ( nRESET = '0' ) then iATRG_SFT <= "000" ; iWTRG_SFT <= "000" ; iCTRG_SFT <= "000" ; iBTRG_SFT <= "000" ; elsif rising_edge(iCLKFX_OUT) then iATRG_SFT <= iATRG_SFT(1 downto 0) & ATRG ; iWTRG_SFT <= iWTRG_SFT(1 downto 0) & WTRG ; iCTRG_SFT <= iCTRG_SFT(1 downto 0) & CTRG ; iBTRG_SFT <= iBTRG_SFT(1 downto 0) & BTRG ; end if ; end process ; iATRG <= '1' when ( iATRG_SFT = "011" or iATRG_SFT = "001" ) else '0' ; iWTRG <= '1' when ( iWTRG_SFT = "011" or iWTRG_SFT = "001" ) else '0' ; iCTRG <= '1' when ( iCTRG_SFT = "011" or iCTRG_SFT = "001" ) else '0' ; iBTRG <= '1' when ( iBTRG_SFT = "011" or iBTRG_SFT = "001" ) else '0' ; -- sequencer (address handling) process (nRESET,iCLKFX_OUT) begin if ( nRESET = '0' ) then iASTATE <= "00" ; iADRA <= (others => '0') ; iADRB <= (others => '0') ; iASEL <= "00" ; iBPTR <= 0 ; elsif rising_edge(iCLKFX_OUT) then case conv_integer(iASTATE) is -- wait trigger when 0 => if ( iATRG = '1' ) then iASTATE <= "01" ; elsif ( iAXTRG = '1' ) then iASTATE <= "01" ; iASEL <= "01" ; elsif ( iAYTRG = '1' ) then iASTATE <= "01" ; iASEL <= "10" ; else iASTATE <= "00" ; end if ; -- transfer when 1 => iASTATE <= "11" ; if ( iASEL(0) = '1' ) then iAREG <= '0' & iCREG ; elsif ( iASEL(1) = '1' ) then iAREG <= '0' & iBREG ; else iAREG <= ADBUS(2 downto 0) ; end if ; -- decode when 3 => iASTATE <= "10" ; -- clear A port address if ( iAREG = "000" ) then iADRA <= (others => '0') ; end if ; -- increase A port address if ( iAREG = "001" ) then iADRA <= iADRA + '1' ; end if ; -- clear B port address if ( iAREG = "010" ) then iADRB <= (others => '0') ; end if ; -- increase B port address if ( iAREG = "011" ) then iADRB <= iADRB + '1' ; end if ; -- clear shift register pointer if ( iAREG = "100" ) then iBPTR <= 0 ; end if ; -- increase shift register pointer if ( iAREG = "101" ) then iBPTR <= iBPTR + 1 ; end if ; -- return first state when 2 => iASTATE <= "00" ; iASEL <= "00" ; -- default when others => iASTATE <= "00" ; end case ; end if ; end process ; -- sequencer (write handling) process (nRESET,iCLKFX_OUT) begin if ( nRESET = '0' ) then iWSTATE <= "00" ; iDIA <= (others => '0') ; elsif rising_edge(iCLKFX_OUT) then case conv_integer(iWSTATE) is -- wait trigger when 0 => if ( iWTRG = '1' ) then iWSTATE <= "01" ; else iWSTATE <= "00" ; end if ; -- get data when 1 => iWSTATE <= "11" ; iDIA <= ADBUS ; -- send trigger when 3 => iWSTATE <= "10" ; -- return first state when 2 => iWSTATE <= "00" ; -- default when others => iWSTATE <= "00" ; end case ; end if ; end process ; iWEA <= '1' when ( iWSTATE = "11" ) else '0' ; -- sequencer (calculate) process (nRESET,iCLKFX_OUT) begin if ( nRESET = '0' ) then iCSTATE <= 0 ; iCREG <= "00" ; iCMAX <= (others => '0') ; iCMIN <= (others => '0') ; iCCOUNT <= 0 ; iCTHV <= 0 ; elsif rising_edge(iCLKFX_OUT) then case iCSTATE is -- wait trigger when 0 => if ( iCTRG = '1' ) then iCSTATE <= 1 ; else iCSTATE <= 0 ; end if ; -- clear B port address when 1 => iCSTATE <= 2 ; iCREG <= "10" ; -- send trigger when 2 => iCSTATE <= 3 ; -- delay when 3 => iCSTATE <= 4 ; -- wait complete when 4 => if ( iASTATE = "00" ) then iCSTATE <= 5 ; -- next else iCSTATE <= 4 ; -- stay end if ; -- set MAX and MIN when 5 => iCSTATE <= 6 ; -- next iCMAX <= iDOB ; -- maximum iCMIN <= iDOB ; -- minimum iCCOUNT <= 0 ; -- increse B port address when 6 => iCSTATE <= 7 ; iCREG <= "11" ; iCCOUNT <= iCCOUNT + 1 ; -- send trigger when 7 => iCSTATE <= 8 ; -- delay when 8 => iCSTATE <= 9 ; -- wait complete when 9 => if ( iASTATE = "00" ) then iCSTATE <= 10 ; -- next else iCSTATE <= 9 ; -- stay end if ; -- compare when 10 => iCSTATE <= 11 ; if ( conv_integer(iCMAX) < conv_integer(iDOB) ) then iCMAX <= iDOB ; end if ; if ( conv_integer(iCMIN) > conv_integer(iDOB) ) then iCMIN <= iDOB ; end if ; -- judge when 11 => if ( iCCOUNT = PIXEL_LAST ) then iCSTATE <= 12 ; -- exit else iCSTATE <= 6 ; -- loop end if ; -- return first state when 12 => iCSTATE <= 0 ; iCTHV <= (conv_integer(iCMAX)+conv_integer(iCMIN)) / 2 ; -- default when others => iCSTATE <= 0 ; end case ; end if ; end process ; iAXTRG <= '1' when ( iCSTATE = 2 or iCSTATE = 7 ) else '0' ; iCTHVX <= conv_std_logic_vector(iCTHV,8) ; -- sequencer (binary conversion) process (nRESET,iCLKFX_OUT) begin if ( nRESET = '0' ) then iBSTATE <= 0 ; iBCOUNT <= 0 ; iBREG <= "00" ; iBDAT <= (others => '0') ; elsif rising_edge(iCLKFX_OUT) then case iBSTATE is -- wait trigger when 0 => if ( iBTRG = '1' ) then iBSTATE <= 1 ; else iBSTATE <= 0 ; end if ; -- clear counter when 1 => iBSTATE <= 2 ; iBCOUNT <= 0 ; -- set B port address zero when 2 => iBSTATE <= 3 ; iBREG <= "10" ; -- send trigger when 3 => iBSTATE <= 4 ; -- delay when 4 => iBSTATE <= 5 ; -- wait complete when 5 => if ( iASTATE = "00" ) then iBSTATE <= 6 ; else iBSTATE <= 5 ; end if ; -- get memory data when 6 => iBSTATE <= 7 ; iBDAT <= iDOB ; -- compare and store when 7 => iBSTATE <= 8 ; if ( conv_integer(iBDAT) > iCTHV ) then iBSFT(iBCOUNT) <= '1' ; else iBSFT(iBCOUNT) <= '0' ; end if ; -- counter increment when 8 => iBSTATE <= 9 ; iBCOUNT <= iBCOUNT + 1 ; -- judge complete when 9 => if ( iBCOUNT = PIXEL_MAX ) then iBSTATE <= 10 ; -- exit else iBSTATE <= 3 ; -- loop iBREG <= "11" ; -- increse B port address end if ; -- set B port address zero when 10 => iBSTATE <= 11 ; iBREG <= "10" ; -- send trigger when 11 => iBSTATE <= 12 ; -- return first state when 12 => iBSTATE <= 0 ; -- default when others => iBSTATE <= 0 ; end case ; end if ; end process ; iAYTRG <= '1' when ( iBSTATE = 3 or iBSTATE = 11 ) else '0' ; iBSFTV <= iBSFT(8*iBPTR to 8*iBPTR+7); end Behavioral;  160ビットのレジスタを、DualPortMemoryをもう1ブロック  利用して実現した方が、内部デジタル回路を入れる領域を  消費しないのでよいかも知れませんが、動作するか否かを  チェックするので、ここまでとしています。  最終ピンアサインは、以下です。 # system NET "CLOCK" LOC = "P55" | IOSTANDARD = LVCMOS33 ; NET "nRESET" LOC = "P73" | IOSTANDARD = LVCMOS33 ; # G0 NET "ADBUS<0>" LOC = "P1" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<1>" LOC = "P2" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<2>" LOC = "P4" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<3>" LOC = "P5" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<4>" LOC = "P6" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<5>" LOC = "P7" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<6>" LOC = "P8" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<7>" LOC = "P10" | IOSTANDARD = LVCMOS33 ; # G1 NET "ATRG" LOC = "P11" | IOSTANDARD = LVCMOS33 ; NET "WTRG" LOC = "P12" | IOSTANDARD = LVCMOS33 ; NET "CTRG" LOC = "P13" | IOSTANDARD = LVCMOS33 ; NET "BTRG" LOC = "P14" | IOSTANDARD = LVCMOS33 ; NET "RTRG" LOC = "P15" | IOSTANDARD = LVCMOS33 ; NET "RSEL<0>" LOC = "P17" | IOSTANDARD = LVCMOS33 ; NET "RSEL<1>" LOC = "P18" | IOSTANDARD = LVCMOS33 ; NET "RSEL<2>" LOC = "P20" | IOSTANDARD = LVCMOS33 ; # G0B NET "ROUT<0>" LOC = "P141" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<1>" LOC = "P140" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<2>" LOC = "P137" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<3>" LOC = "P135" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<4>" LOC = "P132" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<5>" LOC = "P131" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<6>" LOC = "P130" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<7>" LOC = "P129" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; # G1B NET "GOUT<0>" LOC = "P116" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "GOUT<1>" LOC = "P113" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "GOUT<2>" LOC = "P119" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "MCLKX" LOC = "P124" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; # G2B NET "SEL" LOC = "P103" | IOSTANDARD = LVCMOS33 ;
特異点抽出  2値化ができたなら、0→1、1→0の特異点が  ピクセル中のどこにあるのかを求められます。  特異点を求めるVHDLコードは、次のように定義しました。 process (nRESET,iCLKFX) begin if ( nRESET = '0' ) then iSSTATE <= "000" ; iSCOUNT <= 0 ; iSPLH <= 255 ; iSPHL <= 255 ; iSPLHOUT <= (others => '1') ; iSPHLOUT <= (others => '1') ; elsif rising_edge(iCLKFX) then case conv_integer(iSSTATE) is -- wait trigger when 0 => if ( iSTRG = '1' ) then iSSTATE <= "001" ; else iSSTATE <= "000" ; end if ; -- initialize when 1 => iSSTATE <= "011" ; iSCOUNT <= 0 ; iSTMP <= iBSFT(0 to 1); iSPLH <= 255 ; iSPHL <= 255 ; iSPLHOUT <= (others => '1') ; iSPHLOUT <= (others => '1') ; -- compare when 3 => iSSTATE <= "111" ; if ( iSTMP = SLHV ) then iSPLH <= iSCOUNT ; end if ; if ( iSTMP = SHLV ) then iSPHL <= iSCOUNT ; end if ; -- counter increment when 7 => iSSTATE <= "110" ; iSCOUNT <= iSCOUNT + 1 ; -- judge when 6 => if ( iSCOUNT = PIXEL_LAST ) then iSSTATE <= "100" ; else iSSTATE <= "011" ; iSTMP <= iSTMP(0) & iBSFT(iSCOUNT+1) ; end if ; -- return first state when 4 => iSSTATE <= "000" ; iSPLHOUT <= conv_std_logic_vector(iSPLH,8) ; iSPHLOUT <= conv_std_logic_vector(iSPHL,8) ; -- default when others => iSSTATE <= "000" ; end case ; end if ; end process ;  トリガーが来たら、カウンタ、特異点位置を初期化し  2値化されたレジスタの値を2ビットずつ"01"と"10"  照合します。  ビットバターンが一致したとき、カウンタ値を特異点  の位置として更新します。  高速動作が可能になるよう、ジョンソンカウンタで  状態遷移させます。2値化された値を格納している  レジスタから、2ビットずつシフトレジスタに入れ  照合します。照合が終わると、レジスタの1ビット  を取り出して、対象となる2ビットを更新です。  ARMが読出しやすいよう、特異点位置を出力バッファに  保存してから、終了にしました。  特異点位置を見つけるシーケンサの動作開始には  トリガーを使います。2値化担当のシーケンサが  開始トリガーを出力することに。  トリガーは、2値化担当シーケンサのステート値  をデコードして生成できるます。 iSTRG <= '1' when ( iBSTATE = 11 ) else '0' ;  ARMから画像データに相当する値を、DualPortMemoryに  転送したなら、計算開始トリガーを出し特異点位置まで  一気に求めた方が楽です。そこで、3つのシーケンサが  ドミノ倒しの要領で動くように、トリガーを決めます。  計算開始トリガーを与えてから、どのくらいの時間で  処理完了になるのかを計測できるように、カウンタを  使います。 -- measure calcualte time sequencer process (nRESET,iCLKFX) begin if ( nRESET = '0' ) then iTSTATE <= "00" ; iTCOUNT <= (others => '0') ; elsif rising_edge(iCLKFX) then case conv_integer(iTSTATE) is -- wait start (iCTRG) trigger when 0 => if ( iCTRG = '1' ) then iTSTATE <= "01" ; else iTSTATE <= "00" ; end if ; -- initialize counter when 1 => iTSTATE <= "11" ; iTCOUNT <= (others => '0') ; -- wait exit (iSEXIT) trigger when 3 => if ( iSEXIT = '1' ) then iTSTATE <= "10" ; else iTSTATE <= "11" ; iTCOUNT <= iTCOUNT + '1' ; end if ; -- return first state when 2 => iTSTATE <= "00" ; -- default when others => iTSTATE <= "00" ; end case ; end if ; end process ;  計算開始トリガーと終了フラグを使い、その間の  カウントで、時間を等価カウントに置き換えます。  実際に計算開始トリガーを与えて計測すると  等価カウントは、897でした。  12MHzで動かしたので、所要時間は約74usです。  1ラインで約100usの所要時間とすると、3ライン  では、300us程度になります。  OV7570は、30フレーム程度の画像データ更新が最高  なので、1フレームの取得時間は33ms。3ライン分  の画像データを処理して、特異点を見つけたとして  34msごとに、新しい特異点を取得できます。  これがFPGAのもつ高速性と言えるでしょう。  特異点と等価カウントを求める処理を入れた  VHDLコードは、以下です。 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; Library UNISIM; use UNISIM.vcomponents.all; entity dpmtsty is generic ( PIXEL_MAX : integer := 160 ; PIXEL_LAST : integer := 159 ; ADRACLR : std_logic_vector(2 downto 0) := "000" ; ADRAINC : std_logic_vector(2 downto 0) := "001" ; ADRBCLR : std_logic_vector(2 downto 0) := "010" ; ADRBINC : std_logic_vector(2 downto 0) := "011" ; SFTACLR : std_logic_vector(2 downto 0) := "100" ; SFTAINC : std_logic_vector(2 downto 0) := "101" ; SHLV : std_logic_vector(1 downto 0) := "10" ; SLHV : std_logic_vector(1 downto 0) := "01" --; ) ; port ( -- system nRESET : in std_logic ; CLOCK : in std_logic ; -- trigger ATRG : in std_logic ; WTRG : in std_logic ; CTRG : in std_logic ; RTRG : in std_logic ; RSEL : in std_logic_vector(2 downto 0) ; -- data BUS ADBUS : inout std_logic_vector(7 downto 0) ; -- address monitor SEL : in std_logic ; ROUT : out std_logic_vector(7 downto 0) ; GOUT : out std_logic_vector(7 downto 0) ; MCLKX : out std_logic -- ; ); end dpmtsty; architecture Behavioral of dpmtsty is -- clock (input) signal iCLK0_OUT : std_logic ; signal iCLKFX : std_logic ; signal iCLKFB_IN : std_logic ; signal iCLKIN_IBUFG : std_logic ; -- trigger signal iATRG_SFT : std_logic_vector(2 downto 0) ; signal iWTRG_SFT : std_logic_vector(2 downto 0) ; signal iCTRG_SFT : std_logic_vector(2 downto 0) ; signal iATRG : std_logic ; signal iWTRG : std_logic ; signal iCTRG : std_logic ; signal iBTRG : std_logic ; -- address sequencer signal iASTATE : std_logic_vector(1 downto 0) ; signal iAREG : std_logic_vector(2 downto 0) ; signal iASEL : std_logic_vector(1 downto 0) ; -- data sequencer signal iWSTATE : std_logic_vector(1 downto 0) ; -- calculate sequencer signal iCSTATE : integer range 0 to 12 ; signal iCREG : std_logic_vector(1 downto 0) ; signal iAXTRG : std_logic ; signal iCMAX : std_logic_vector(7 downto 0) ; signal iCMIN : std_logic_vector(7 downto 0) ; signal iCCOUNT : integer range 0 to PIXEL_LAST ; signal iCTHV : integer range 0 to 255 ; signal iCTHVX : std_logic_vector(7 downto 0) ; -- binary conversion sequencer signal iBSTATE : integer range 0 to 12 ; signal iBREG : std_logic_vector(1 downto 0) ; signal iBDAT : std_logic_vector(7 downto 0) ; signal iAYTRG : std_logic ; signal iBCOUNT : integer range 0 to PIXEL_LAST ; signal iBSFT : std_logic_vector(0 to PIXEL_LAST) ; signal iBPTR : integer range 0 to 21 ; signal iBSFTV : std_logic_vector(0 to 7) ; -- internal registers (A port) signal iADRA : std_logic_vector(10 downto 0) ; signal iDIA : std_logic_vector( 7 downto 0) ; signal iWEA : std_logic ; -- internal registers (Bport) signal iDOB : std_logic_vector( 7 downto 0) ; signal iADRB : std_logic_vector(10 downto 0) ; -- scan sequencer signal iSSTATE : std_logic_vector(2 downto 0) ; signal iSTRG : std_logic ; signal iSEXIT : std_logic ; signal iSTMP : std_logic_vector(1 downto 0) ; signal iSCOUNT : integer range 0 to PIXEL_LAST ; signal iSPLH : integer range 0 to 255 ; signal iSPHL : integer range 0 to 255 ; signal iSPLHOUT : std_logic_vector(7 downto 0) ; signal iSPHLOUT : std_logic_vector(7 downto 0) ; -- measure time sequencer signal iTSTATE : std_logic_vector( 1 downto 0) ; signal iTCOUNT : std_logic_vector(15 downto 0) ; begin -- input clock buffer handling IBUFG_inst : IBUFG generic map (IOSTANDARD => "DEFAULT") port map ( O => iCLKIN_IBUFG, -- Clock buffer output I => CLOCK -- Clock buffer input (connect directly to top-level port) ); -- output clock buffer handling BUFG_inst : BUFG port map ( O => iCLKFB_IN, -- Clock buffer output I => iCLK0_OUT -- Clock buffer input ); -- DCM (48MHz/4 = 12MHz) -- MULTIPLY 2 -- DIVIDE 8 -- (2 / 4) * 24 = (1 / 2) * 24 = 12 DCM_inst : DCM generic map ( CLKDV_DIVIDE => 2.0, -- Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5 -- 7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0 CLKFX_DIVIDE => 4, -- Can be any integer from 1 to 32 CLKFX_MULTIPLY => 2, -- Can be any integer from 2 to 32 CLKIN_DIVIDE_BY_2 => TRUE, -- TRUE/FALSE to enable CLKIN divide by two feature CLKIN_PERIOD => 20.833, -- Specify period of input clock CLKOUT_PHASE_SHIFT => "FIXED", -- Specify phase shift of NONE, FIXED or VARIABLE CLK_FEEDBACK => "1X", -- Specify clock feedback of NONE, 1X or 2X DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS", -- SOURCE_SYNCHRONOUS, SYSTEM_SYNCHRONOUS or -- an integer from 0 to 15 DFS_FREQUENCY_MODE => "LOW", -- HIGH or LOW frequency mode for frequency synthesis DLL_FREQUENCY_MODE => "LOW", -- HIGH or LOW frequency mode for DLL DUTY_CYCLE_CORRECTION => TRUE, -- Duty cycle correction, TRUE or FALSE FACTORY_JF => X"C080", -- FACTORY JF Values PHASE_SHIFT => 0, -- Amount of fixed phase shift from -255 to 255 SIM_MODE => "SAFE", -- Simulation: "SAFE" vs "FAST", see "Synthesis and Simulation -- Design Guide" for details STARTUP_WAIT => FALSE) -- Delay configuration DONE until DCM LOCK, TRUE/FALSE port map ( CLK0 => iCLK0_OUT, -- 0 degree DCM CLK ouptput CLK180 => open, -- 180 degree DCM CLK output CLK270 => open, -- 270 degree DCM CLK output CLK2X => open, -- 2X DCM CLK output CLK2X180 => open, -- 2X, 180 degree DCM CLK out CLK90 => open, -- 90 degree DCM CLK output CLKDV => open, -- Divided DCM CLK out (CLKDV_DIVIDE) CLKFX => iCLKFX, -- DCM CLK synthesis out (M/D) CLKFX180 => open, -- 180 degree CLK synthesis out LOCKED => open, -- DCM LOCK status output PSDONE => open, -- Dynamic phase adjust done output STATUS => open, -- 8-bit DCM status bits output CLKFB => iCLKFB_IN, -- DCM clock feedback CLKIN => iCLKIN_IBUFG, -- Clock input (from IBUFG, BUFG or DCM) PSCLK => '0', -- Dynamic phase adjust clock input PSEN => '0', -- Dynamic phase adjust enable input PSINCDEC => '0', -- Dynamic phase adjust increment/decrement RST => '0' -- DCM asynchronous reset input ); RAMB16_S9_S9_instA : RAMB16_S9_S9 generic map ( INIT_A => X"000", -- Value of output RAM registers on Port A at startup INIT_B => X"000", -- Value of output RAM registers on Port B at startup SRVAL_A => X"000", -- Port A ouput value upon SSR assertion SRVAL_B => X"000", -- Port B ouput value upon SSR assertion WRITE_MODE_A => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE WRITE_MODE_B => "WRITE_FIRST", -- WRITE_FIRST, READ_FIRST or NO_CHANGE SIM_COLLISION_CHECK => "ALL", -- "NONE", "WARNING", "GENERATE_X_ONLY", "ALL" -- The following INIT_xx declarations specify the initial contents of the RAM -- Address 0 to 511 INIT_00 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 512 to 1023 INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1024 to 1535 INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1536 to 2047 INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000", -- The next set of INITP_xx are for the parity bits -- Address 0 to 511 INITP_00 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_01 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 512 to 1023 INITP_02 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_03 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1024 to 1535 INITP_04 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_05 => X"0000000000000000000000000000000000000000000000000000000000000000", -- Address 1536 to 2047 INITP_06 => X"0000000000000000000000000000000000000000000000000000000000000000", INITP_07 => X"0000000000000000000000000000000000000000000000000000000000000000") port map ( DOA => open, -- Port A 8-bit Data Output DOB => iDOB, -- Port B 8-bit Data Output DOPA => open, -- Port A 1-bit Parity Output DOPB => open, -- Port B 1-bit Parity Output ADDRA => iADRA, -- Port A 11-bit Address Input ADDRB => iADRB, -- Port B 11-bit Address Input CLKA => iCLKFX, -- Port A Clock CLKB => iCLKFX, -- Port B Clock DIA => iDIA, -- Port A 8-bit Data Input DIB => X"FF", -- Port B 8-bit Data Input DIPA => "1", -- Port A 1-bit parity Input DIPB => "1", -- Port B 1-bit parity Input ENA => '1', -- Port A RAM Enable Input ENB => '1', -- Port B RAM Enable Input SSRA => '0', -- Port A Synchronous Set/Reset Input SSRB => '0', -- Port B Synchronous Set/Reset Input WEA => iWEA, -- Port A Write Enable Input WEB => '0' -- Port B Write Enable Input ); -- monitor output MCLKX <= not iCLKFX ; ROUT <= (not iTCOUNT(7 downto 0)) when ( SEL = '0' ) else (not iADRB(7 downto 0)); GOUT <= (not iTCOUNT(15 downto 8)) when ( SEL = '0') else (not ("00000" & iADRB(10 downto 8))) ; -- output ADBUS <= iDOB when ( RTRG = '1' and RSEL = "000" ) else -- B port data iCMIN when ( RTRG = '1' and RSEL = "001" ) else -- min iCMAX when ( RTRG = '1' and RSEL = "010" ) else -- max iCTHVX when ( RTRG = '1' and RSEL = "011" ) else -- threshold iBSFTV when ( RTRG = '1' and RSEL = "100" ) else -- binary data iSPLHOUT when ( RTRG = '1' and RSEL = "101" ) else -- position LH iSPHLOUT when ( RTRG = '1' and RSEL = "110" ) else -- position HL (others => 'Z'); -- trigger process (nRESET,iCLKFX) begin if ( nRESET = '0' ) then iATRG_SFT <= "000" ; iWTRG_SFT <= "000" ; iCTRG_SFT <= "000" ; elsif rising_edge(iCLKFX) then iATRG_SFT <= iATRG_SFT(1 downto 0) & ATRG ; iWTRG_SFT <= iWTRG_SFT(1 downto 0) & WTRG ; iCTRG_SFT <= iCTRG_SFT(1 downto 0) & CTRG ; end if ; end process ; iATRG <= '1' when ( iATRG_SFT = "011" or iATRG_SFT = "001" ) else '0' ; iWTRG <= '1' when ( iWTRG_SFT = "011" or iWTRG_SFT = "001" ) else '0' ; iCTRG <= '1' when ( iCTRG_SFT = "011" or iCTRG_SFT = "001" ) else '0' ; -- sequencer (address handling) process (nRESET,iCLKFX) begin if ( nRESET = '0' ) then iASTATE <= "00" ; iADRA <= (others => '0') ; iADRB <= (others => '0') ; iASEL <= "00" ; iBPTR <= 0 ; elsif rising_edge(iCLKFX) then case conv_integer(iASTATE) is -- wait trigger when 0 => if ( iATRG = '1' ) then iASTATE <= "01" ; elsif ( iAXTRG = '1' ) then iASTATE <= "01" ; iASEL <= "01" ; elsif ( iAYTRG = '1' ) then iASTATE <= "01" ; iASEL <= "10" ; else iASTATE <= "00" ; end if ; -- transfer when 1 => iASTATE <= "11" ; if ( iASEL(0) = '1' ) then iAREG <= '0' & iCREG ; elsif ( iASEL(1) = '1' ) then iAREG <= '0' & iBREG ; else iAREG <= ADBUS(2 downto 0) ; end if ; -- decode when 3 => iASTATE <= "10" ; -- clear A port address if ( iAREG = ADRACLR ) then iADRA <= (others => '0') ; end if ; -- increase A port address if ( iAREG = ADRAINC ) then iADRA <= iADRA + '1' ; end if ; -- clear B port address if ( iAREG = ADRBCLR ) then iADRB <= (others => '0') ; end if ; -- increase B port address if ( iAREG = ADRBINC ) then iADRB <= iADRB + '1' ; end if ; -- clear shift register pointer if ( iAREG = SFTACLR ) then iBPTR <= 0 ; end if ; -- increase shift register pointer if ( iAREG = SFTAINC ) then iBPTR <= iBPTR + 1 ; end if ; -- return first state when 2 => iASTATE <= "00" ; iASEL <= "00" ; -- default when others => iASTATE <= "00" ; end case ; end if ; end process ; -- sequencer (write handling) process (nRESET,iCLKFX) begin if ( nRESET = '0' ) then iWSTATE <= "00" ; iDIA <= (others => '0') ; elsif rising_edge(iCLKFX) then case conv_integer(iWSTATE) is -- wait trigger when 0 => if ( iWTRG = '1' ) then iWSTATE <= "01" ; else iWSTATE <= "00" ; end if ; -- get data when 1 => iWSTATE <= "11" ; iDIA <= ADBUS ; -- send trigger when 3 => iWSTATE <= "10" ; -- return first state when 2 => iWSTATE <= "00" ; -- default when others => iWSTATE <= "00" ; end case ; end if ; end process ; iWEA <= '1' when ( iWSTATE = "11" ) else '0' ; -- sequencer (calculate) process (nRESET,iCLKFX) begin if ( nRESET = '0' ) then iCSTATE <= 0 ; iCREG <= "00" ; iCMAX <= (others => '0') ; iCMIN <= (others => '0') ; iCCOUNT <= 0 ; iCTHV <= 0 ; elsif rising_edge(iCLKFX) then case iCSTATE is -- wait trigger when 0 => if ( iCTRG = '1' ) then iCSTATE <= 1 ; else iCSTATE <= 0 ; end if ; -- clear B port address when 1 => iCSTATE <= 2 ; iCREG <= "10" ; -- send trigger when 2 => iCSTATE <= 3 ; -- delay when 3 => iCSTATE <= 4 ; -- wait complete when 4 => if ( iASTATE = "00" ) then iCSTATE <= 5 ; -- next else iCSTATE <= 4 ; -- stay end if ; -- set MAX and MIN when 5 => iCSTATE <= 6 ; -- next iCMAX <= iDOB ; -- maximum iCMIN <= iDOB ; -- minimum iCCOUNT <= 0 ; -- increse B port address when 6 => iCSTATE <= 7 ; iCREG <= "11" ; iCCOUNT <= iCCOUNT + 1 ; -- send trigger when 7 => iCSTATE <= 8 ; -- delay when 8 => iCSTATE <= 9 ; -- wait complete when 9 => if ( iASTATE = "00" ) then iCSTATE <= 10 ; -- next else iCSTATE <= 9 ; -- stay end if ; -- compare when 10 => iCSTATE <= 11 ; if ( conv_integer(iCMAX) < conv_integer(iDOB) ) then iCMAX <= iDOB ; end if ; if ( conv_integer(iCMIN) > conv_integer(iDOB) ) then iCMIN <= iDOB ; end if ; -- judge when 11 => if ( iCCOUNT = PIXEL_LAST ) then iCSTATE <= 12 ; -- exit else iCSTATE <= 6 ; -- loop end if ; -- return first state when 12 => iCSTATE <= 0 ; iCTHV <= (conv_integer(iCMAX)+conv_integer(iCMIN)) / 2 ; -- default when others => iCSTATE <= 0 ; end case ; end if ; end process ; iAXTRG <= '1' when ( iCSTATE = 2 or iCSTATE = 7 ) else '0' ; iCTHVX <= conv_std_logic_vector(iCTHV,8) ; iBTRG <= '1' when ( iCSTATE = 12 ) else '0' ; -- sequencer (binary conversion) process (nRESET,iCLKFX) begin if ( nRESET = '0' ) then iBSTATE <= 0 ; iBCOUNT <= 0 ; iBREG <= "00" ; iBDAT <= (others => '0') ; elsif rising_edge(iCLKFX) then case iBSTATE is -- wait trigger when 0 => if ( iBTRG = '1' ) then iBSTATE <= 1 ; else iBSTATE <= 0 ; end if ; -- clear counter when 1 => iBSTATE <= 2 ; iBCOUNT <= 0 ; -- set B port address zero when 2 => iBSTATE <= 3 ; iBREG <= "10" ; -- send trigger when 3 => iBSTATE <= 4 ; -- delay when 4 => iBSTATE <= 5 ; -- wait complete when 5 => if ( iASTATE = "00" ) then iBSTATE <= 6 ; else iBSTATE <= 5 ; end if ; -- get memory data when 6 => iBSTATE <= 7 ; iBDAT <= iDOB ; -- compare and store when 7 => iBSTATE <= 8 ; if ( conv_integer(iBDAT) > iCTHV ) then iBSFT(iBCOUNT) <= '1' ; else iBSFT(iBCOUNT) <= '0' ; end if ; -- counter increment when 8 => iBSTATE <= 9 ; iBCOUNT <= iBCOUNT + 1 ; -- judge complete when 9 => if ( iBCOUNT = PIXEL_MAX ) then iBSTATE <= 10 ; -- exit else iBSTATE <= 3 ; -- loop iBREG <= "11" ; -- increse B port address end if ; -- set B port address zero when 10 => iBSTATE <= 11 ; iBREG <= "10" ; -- send trigger when 11 => iBSTATE <= 12 ; -- return first state when 12 => iBSTATE <= 0 ; -- default when others => iBSTATE <= 0 ; end case ; end if ; end process ; iAYTRG <= '1' when ( iBSTATE = 3 or iBSTATE = 11 ) else '0' ; iBSFTV <= iBSFT(8*iBPTR to 8*iBPTR+7); iSTRG <= '1' when ( iBSTATE = 11 ) else '0' ; -- sequencer (scan) process (nRESET,iCLKFX) begin if ( nRESET = '0' ) then iSSTATE <= "000" ; iSCOUNT <= 0 ; iSPLH <= 255 ; iSPHL <= 255 ; iSPLHOUT <= (others => '1') ; iSPHLOUT <= (others => '1') ; elsif rising_edge(iCLKFX) then case conv_integer(iSSTATE) is -- wait trigger when 0 => if ( iSTRG = '1' ) then iSSTATE <= "001" ; else iSSTATE <= "000" ; end if ; -- initialize when 1 => iSSTATE <= "011" ; iSCOUNT <= 0 ; iSTMP <= iBSFT(0 to 1); iSPLH <= 255 ; iSPHL <= 255 ; iSPLHOUT <= (others => '1') ; iSPHLOUT <= (others => '1') ; -- compare when 3 => iSSTATE <= "111" ; if ( iSTMP = SLHV ) then iSPLH <= iSCOUNT ; end if ; if ( iSTMP = SHLV ) then iSPHL <= iSCOUNT ; end if ; -- counter increment when 7 => iSSTATE <= "110" ; iSCOUNT <= iSCOUNT + 1 ; -- judge when 6 => if ( iSCOUNT = PIXEL_LAST ) then iSSTATE <= "100" ; else iSSTATE <= "011" ; iSTMP <= iSTMP(0) & iBSFT(iSCOUNT+1) ; end if ; -- return first state when 4 => iSSTATE <= "000" ; iSPLHOUT <= conv_std_logic_vector(iSPLH,8) ; iSPHLOUT <= conv_std_logic_vector(iSPHL,8) ; -- default when others => iSSTATE <= "000" ; end case ; end if ; end process ; iSEXIT <= '1' when ( iSSTATE = "100" ) else '0' ; -- measure calcualte time sequencer process (nRESET,iCLKFX) begin if ( nRESET = '0' ) then iTSTATE <= "00" ; iTCOUNT <= (others => '0') ; elsif rising_edge(iCLKFX) then case conv_integer(iTSTATE) is -- wait start (iCTRG) trigger when 0 => if ( iCTRG = '1' ) then iTSTATE <= "01" ; else iTSTATE <= "00" ; end if ; -- initialize counter when 1 => iTSTATE <= "11" ; iTCOUNT <= (others => '0') ; -- wait exit (iSEXIT) trigger when 3 => if ( iSEXIT = '1' ) then iTSTATE <= "10" ; else iTSTATE <= "11" ; iTCOUNT <= iTCOUNT + '1' ; end if ; -- return first state when 2 => iTSTATE <= "00" ; -- default when others => iTSTATE <= "00" ; end case ; end if ; end process ; end Behavioral;  ピン配置は、次のように変更しました。 # system NET "CLOCK" LOC = "P55" | IOSTANDARD = LVCMOS33 ; NET "nRESET" LOC = "P73" | IOSTANDARD = LVCMOS33 ; # G0 NET "ADBUS<0>" LOC = "P1" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<1>" LOC = "P2" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<2>" LOC = "P4" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<3>" LOC = "P5" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<4>" LOC = "P6" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<5>" LOC = "P7" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<6>" LOC = "P8" | IOSTANDARD = LVCMOS33 ; NET "ADBUS<7>" LOC = "P10" | IOSTANDARD = LVCMOS33 ; # G1 NET "ATRG" LOC = "P11" | IOSTANDARD = LVCMOS33 ; NET "WTRG" LOC = "P12" | IOSTANDARD = LVCMOS33 ; NET "CTRG" LOC = "P13" | IOSTANDARD = LVCMOS33 ; NET "RTRG" LOC = "P15" | IOSTANDARD = LVCMOS33 ; NET "RSEL<0>" LOC = "P17" | IOSTANDARD = LVCMOS33 ; NET "RSEL<1>" LOC = "P18" | IOSTANDARD = LVCMOS33 ; NET "RSEL<2>" LOC = "P20" | IOSTANDARD = LVCMOS33 ; # G0B NET "ROUT<0>" LOC = "P141" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<1>" LOC = "P140" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<2>" LOC = "P137" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<3>" LOC = "P135" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<4>" LOC = "P132" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<5>" LOC = "P131" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<6>" LOC = "P130" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "ROUT<7>" LOC = "P129" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; # G1B NET "GOUT<0>" LOC = "P116" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "GOUT<1>" LOC = "P113" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "GOUT<2>" LOC = "P119" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "GOUT<3>" LOC = "P118" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "GOUT<4>" LOC = "P123" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "GOUT<5>" LOC = "P122" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "GOUT<6>" LOC = "P125" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; NET "GOUT<7>" LOC = "P124" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; # G2B NET "SEL" LOC = "P103" | IOSTANDARD = LVCMOS33 ; NET "MCLKX" LOC = "P100" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;  計算処理開始のトリガーをひとつにしたので  ARMのファームウエアもコマンドを次のように  絞りこみます。  変更したファームウエアで、FPGA内部のデジタル回路に  データ転送、計算させると、次のようになります。  'R'コマンドで、DualPortMemoryの内容表示。  'F'コマンドで、ARM内部の配列に値設定。  'E'コマンドで、配列の1バイトの内容変更。  'T'コマンドで、ARMからFPGAにデータ転送。  'C'コマンドで、特異点まで計算。  'X'コマンドで、2値化データと特異点位置を表示。  変更したファームウエアのソースコードは、以下です。 #include <ADuC7026.h> #define OFF 0 #define ON OFF+1 /* data definitions */ typedef unsigned char UBYTE ; typedef signed char SBYTE ; typedef unsigned short UWORD ; typedef signed short SWORD ; typedef unsigned long ULONG ; typedef signed long SLONG ; void IRQ_Handler(void) __irq; void init_usr(void); #define MASKFF 0xFF #define MASK0F 0x0F #define MASKF0 0xF0 #define MASK80 0x80 #define MASK40 0x40 #define MASK20 0x20 #define MASK10 0x10 #define MASK08 0x08 #define MASK04 0x04 #define MASK02 0x02 #define MASK01 0x01 #define ASFT 16 #define WSFT 17 #define CSFT 18 #define RSFT 20 #define ATRG 1 #define WTRG 2 #define CTRG 4 ULONG timcnt ; void rs_putchar(UBYTE x); void crlf(void); void rs_puts(UBYTE *x); UBYTE get_hex(UBYTE x); void show_help(void); void delay_100us(UWORD x); void read_loop(void); void write_loop(void); void put_fpga(UWORD x); UBYTE get_fpga(UBYTE x); void dump_array(void); void fill_array(UBYTE x); void read_binary(void); void show_hex(UBYTE x,UBYTE chx); /* global variables */ volatile UBYTE uflag ; volatile UBYTE sbuf[8] ; volatile UBYTE sindex ; volatile UBYTE cmd ; volatile UBYTE asc_hex[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; volatile UBYTE oflag ; volatile UBYTE dat ; volatile UWORD madra ; volatile UWORD madrb ; #define ALAST 160 volatile UBYTE gdat[ALAST] ; int main(void) { UBYTE tmp ; /* initialize user */ init_usr(); /* endless loop */ while(ON) { /* opening message */ if ( oflag == ON ) { /* clear flag */ oflag = OFF ; /* show message */ rs_puts("Hello"); crlf(); } /* command interrpreter */ if ( uflag == ON ) { /* clear flag */ uflag = OFF ; /* new line */ crlf(); /* judge */ cmd = *(sbuf+0) ; if ( cmd == '?' ) { show_help(); } /* address */ if ( cmd == 'A' ) { /* get parameter */ tmp = get_hex( *(sbuf+1) ); /* send command */ put_fpga( (ATRG << 8) | tmp ) ; /* update local address */ if ( tmp == 0 ) { madra = 0 ; } if ( tmp == 2 ) { madrb = 0 ; } if ( tmp == 1 ) { madra++ ; } if ( tmp == 3 ) { madrb++ ; } } /* transfer data to A port */ if ( cmd == 'T' ) { write_loop(); /* show internal array context */ dump_array(); /* show FPGA dual port memory context */ read_loop(); } /* send calculate trigger */ if ( cmd == 'C' ) { put_fpga( (CTRG << 8) | 0x00 ); /* delay */ delay_100us(100); /* show FPGA dual port memory context */ read_loop(); } /* dump SRAM contents */ if ( cmd == 'D' ) { dump_array(); } /* store data to SRAM */ if ( cmd == 'E' ) { /* get address */ tmp = get_hex( *(sbuf+1) ); /* get upper nibble */ tmp <<= 4 ; tmp |= get_hex( *(sbuf+2) ); /* concatenate lower nibble */ /* get data */ dat = get_hex( *(sbuf+3) ); /* get upper nibble */ dat <<= 4 ; dat |= get_hex( *(sbuf+4) ); /* concatenate lower nibble */ /* store */ *(gdat+tmp) = dat ; /* show internal array context */ dump_array(); } /* fill SRAM */ if ( cmd == 'F' ) { /* get data */ dat = get_hex( *(sbuf+1) ); /* get upper nibble */ dat <<= 4 ; dat |= get_hex( *(sbuf+2) ); /* concatenate lower nibble */ /* store */ fill_array(dat); /* show */ dump_array(); } /* show binary data */ if ( cmd == 'X' ) { read_binary() ; } /* store data from A port */ if ( cmd == 'W' ) { /* get data */ dat = get_hex( *(sbuf+1) ); /* get upper nibble */ dat <<= 4 ; dat |= get_hex( *(sbuf+2) ); /* concatenate lower nibble */ /* send data */ put_fpga( (WTRG << 8) | dat ) ; } /* read B port data */ if ( cmd == 'R' ) { read_loop(); } } } /* dummy return */ return (0); } void IRQ_Handler(void) __irq { volatile UBYTE ch ; /* judge UART receive interruption */ if ( (IRQSTA & UART_BIT) == UART_BIT ) { /* judge */ if ( COMSTA0 & 1 ) { /* clear flag */ ch = COMRX ; *(sbuf+sindex) = ch ; sindex++ ; if ( ch == '\r' ) { sindex = 0 ; uflag = ON ; } } } /* judge timer3 interruption (1ms) */ if ( (IRQSTA & WATCHDOG_TIMER_BIT) == WATCHDOG_TIMER_BIT ) { /* clear timer3 interrupt flag */ T3CLRI = 0xff ; /* increment */ timcnt++ ; /* blink */ if ( (timcnt & 0x3ff) == 1000 ) { GP4DAT ^= (1 << 23); } } } void init_usr(void) { /* select clock 10.44MHz initialized in start up routine */ PLLKEY1 = 0xaa ; PLLCON = 0x01 ; PLLKEY2 = 0x55 ; /* power control initialized in start up routine */ /* initialize flag */ uflag = OFF ; oflag = ON ; /* clear counter */ timcnt = 0 ; /* initialize UART */ { /* set baud rate 19200 bps CD = 2 */ COMCON0 = 0x80 ; /* select COMDIV1 and COMDIV0 */ COMDIV0 = 0x11 ; COMDIV1 = 0x00 ; /* set conditions */ COMCON0 = 0x03 ; /* select COMRX and COMTX , 8bit data , 1 stop bit , no parity */ /* enable interrupt */ COMIEN0 = 0x01 ; /* ERBFI */ } /* P0 */ { /* */ GP0DAT = 0xDF000000 ; } /* P1 */ { /* use UART */ GP1CON = 0x00000011 ; /* */ GP1DAT = 0xfef00000 ; } /* P2 */ { /* all bits outputs */ GP2DAT = 0xff000000 ; } /* P3 */ { /* all bits outputs */ GP3DAT = 0xff000000 ; } /* P4 */ { GP4DAT = 0xff000000 ; } /* */ madra = 0 ; madrb = 0 ; dat = 0 ; fill_array( 0x00 ); /* initialize timer 3 (1s) */ { T3LD = 33 ; /* (32.768kHz / 33) = about 1kHz */ T3CON = 0xc0 ; /* enable , cyclic , 1/1 */ } /* enable timer 3 interrupt and UART interrupt */ IRQEN = WATCHDOG_TIMER_BIT | UART_BIT ; } /* UART putchar */ void rs_putchar(UBYTE x) { /* ? transmmit buffer empty */ while( (COMSTA0 & 0x40) == 0 ) ; /* set value */ COMTX = x ; } /* carriage return and line feed */ void crlf(void) { rs_putchar('\r'); rs_putchar('\n'); } /* UART puts */ void rs_puts(UBYTE *x) { while ( *x != '\0' ) { rs_putchar( *x ) ; x++ ; } } /* convert ASCII to number */ UBYTE get_hex(UBYTE x) { UBYTE result ; /* default */ result = 0 ; /* judge */ if ( '0' <= x && x <= '9' ) { result = x - '0' ; } if ( 'A' <= x && x <= 'F' ) { result = x - 'A' + 10 ; } if ( 'a' <= x && x <= 'f' ) { result = x - 'a' + 10 ; } return result ; } /* show help */ void show_help(void) { rs_puts("? help") ; crlf(); rs_puts("A handling address") ; crlf(); rs_puts(" A0 clear A port address") ; crlf(); rs_puts(" A1 increase A port address") ; crlf(); rs_puts(" A2 clear B port address") ; crlf(); rs_puts(" A3 increase B port address") ; crlf(); rs_puts("W write value to A port ") ; crlf(); rs_puts("R read B port data") ; crlf(); rs_puts("T transfer data") ; crlf(); rs_puts("C calculate") ; crlf(); rs_puts("D dump SRAM contents") ; crlf(); rs_puts("F fill SRAM") ; crlf(); rs_puts("E store data to SRAM") ; crlf(); rs_puts("X read binary data") ; crlf(); } void delay_100us(UWORD x) { ULONG last ; /* calculate */ last = timcnt + x ; /* wait */ while ( timcnt < last ) ; } void dump_array(void) { UBYTE result ; UBYTE madr[4] ; UBYTE i ; /* default */ *(madr+2) = ':'; *(madr+3) = '\0'; /* loop */ for ( i = 0 ; i < ALAST ; i++ ) { /* show address */ if ( (i & MASK0F) == 0 ) { /* calculate address */ *(madr+0) = ((i >> 4) & MASK0F); *(madr+1) = (i & MASK0F) ; /* convert */ *(madr+0) = asc_hex[*(madr+0)] ; *(madr+1) = asc_hex[*(madr+1)] ; /* show */ rs_puts( madr ); } /* get data */ result = *(gdat+i) ; /* show */ show_hex( result , ' ' ) ; /* judge new line */ if ( (i & MASK0F) == 15 ) { crlf(); } } /* new line */ crlf(); } void fill_array(UBYTE x) { UBYTE i ; /* loop */ for ( i = 0 ; i < ALAST ; i++ ) { *(gdat+i) = x ; } } void read_loop(void) { UBYTE result ; UBYTE madr[6] ; UBYTE i ; /* default */ *(madr+4) = ':'; *(madr+5) = '\0'; /* clear B port address */ put_fpga((ATRG << 8) | 0x02); /* loop */ for ( i = 0 ; i < ALAST ; i++ ) { /* show address */ if ( (i & MASK0F) == 0 ) { /* calculate address */ *(madr+0) = ((i >> 12) & MASK0F) ; *(madr+1) = ((i >> 8) & MASK0F) ; *(madr+2) = ((i >> 4) & MASK0F); *(madr+3) = (i & MASK0F) ; /* convert */ *(madr+0) = asc_hex[*(madr+0)] ; *(madr+1) = asc_hex[*(madr+1)] ; *(madr+2) = asc_hex[*(madr+2)] ; *(madr+3) = asc_hex[*(madr+3)] ; /* show */ rs_puts( madr ); } /* get data */ result = get_fpga(0) ; /* show */ show_hex( result , ' ' ) ; /* judge new line */ if ( (i & MASK0F) == 15 ) { crlf(); } /* address increment */ put_fpga((ATRG << 8) | 0x03); } /* new line */ crlf(); /* clear address */ put_fpga((ATRG << 8) | 0x02); /* minimum */ { result = get_fpga(1) ; rs_puts("Minimum = "); show_hex( result , '\n' ) ; } /* maximum */ { result = get_fpga(2) ; rs_puts("Maximum = "); show_hex( result , '\n' ) ; } /* threshold */ { result = get_fpga(3) ; rs_puts("Threshold = "); show_hex( result , '\n' ) ; } } void write_loop(void) { UBYTE tmp ; UBYTE i ; /* clear A port address */ put_fpga((ATRG << 8) | 0x00); /* loop */ for ( i = 0 ; i < ALAST ; i++ ) { /* get data */ tmp = *(gdat+i) ; /* send */ put_fpga((WTRG << 8) | tmp) ; /* A port address increment */ put_fpga((ATRG << 8) | 0x01); } /* clear A port address */ put_fpga((ATRG << 8) | 0x00); /* new line */ crlf(); } void put_fpga(UWORD x) { UBYTE xcmd ; UBYTE xsft ; /* impress data to GP3 */ GP3DAT &= 0xFF00FFFF ; GP3DAT |= ((x & MASKFF) << 16) ; /* judge trigger */ xcmd = (x >> 8) & MASKFF ; if ( xcmd == ATRG ) { xsft = ASFT ; } if ( xcmd == WTRG ) { xsft = WSFT ; } if ( xcmd == CTRG ) { xsft = CSFT ; } /* trigger */ GP2DAT &= 0xFF00FFFF ; GP2DAT |= (1 << xsft) ; GP2DAT &= 0xFF00FFFF ; } UBYTE get_fpga(UBYTE x) { UBYTE result ; /* change GP3 input */ GP3DAT &= 0x00FFFFFF ; /* enable OE */ GP2DAT &= 0xFF00FFFF ; GP2DAT |= ((x << 21) | (1 << RSFT)); /* RSEL2 RSEL1 RSEL0 RTRG = 23 22 21 20 */ /* delay */ delay_100us(2); /* get data */ result = GP3DAT & MASKFF ; /* disable OE */ GP2DAT &= 0xFF00FFFF ; /* change GP3 output */ GP3DAT |= 0xFF000000 ; return result ; } void read_binary(void) { UBYTE result ; UBYTE madr[4] ; UBYTE i ; /* default */ *(madr+2) = ':'; *(madr+3) = '\0'; /* clear shift register address address */ put_fpga((ATRG << 8) | 0x04); /* loop */ for ( i = 0 ; i < 20 ; i++ ) { /* show address */ if ( (i % 8) == 0 ) { /* calculate bit address */ result = (i << 3); *(madr+0) = ((result >> 4) & MASK0F); *(madr+1) = (result & MASK0F) ; /* convert */ *(madr+0) = asc_hex[*(madr+0)] ; *(madr+1) = asc_hex[*(madr+1)] ; /* show */ rs_puts( madr ); } /* get data */ result = get_fpga(4) ; /* show */ rs_putchar( ((result >> 7) & 1) + '0' ); rs_putchar( ((result >> 6) & 1) + '0' ); rs_putchar( ((result >> 5) & 1) + '0' ); rs_putchar( ((result >> 4) & 1) + '0' ); rs_putchar( ((result >> 3) & 1) + '0' ); rs_putchar( ((result >> 2) & 1) + '0' ); rs_putchar( ((result >> 1) & 1) + '0' ); rs_putchar( (result & 1) + '0' ); rs_putchar('_'); /* judge new line */ if ( (i % 8) == 7 ) { crlf(); } /* shift register increment */ put_fpga((ATRG << 8) | 0x05); } /* new line */ crlf(); /* clear shift register address address */ put_fpga((ATRG << 8) | 0x04); /* position L -> H */ { result = get_fpga(5) ; rs_puts("location(0->1) : "); show_hex( result , '\n' ) ; } /* position H -> L */ { result = get_fpga(6) ; rs_puts("location(1->0) : "); show_hex( result , '\n' ) ; } } void show_hex(UBYTE x,UBYTE chx) { rs_putchar(asc_hex[(x >> 4) & MASK0F]); rs_putchar(asc_hex[x & MASK0F]); if ( chx == '\n' ) { crlf(); } else { rs_putchar(chx) ;} }
目次

inserted by FC2 system