I have ported my old project “pNesX” game console emulator to the nucleo.

Dependencies:   SDFileSystem mbed

Intro

I have ported my old project “pNesX” to the STM32 Nucleo. The pNesX is a NES emulator for the PlayStation that I have created 16 years ago!

Emulation part was almost without change, the sound part was newly added.

Parts

STM32 Nucleo F446RE
QVGA 2.2 TFT SPI (with the SD card slot)
Audio jack(TS or TRS)
USB Connector
Register 100k, 10k, 4.7k, 100
Capacitor 0.01uF, 2.2uF
Breadboard
Wires
Computer Speakers
USB GamePad

Wiring diagram

/media/uploads/beaglescout007/nucleo_ex06_emu.png

TFT J2Nucleo
VCC3V3
GNDGND
CSPB_5(D4)
ResetPA_10(D2) Pull Up(100k)
D/CPA_8(D7)
MOSIPA_7(D11)
SCKPA_5(D13)
LEDLED-100ohm-3V3
MISOPA_6(D12)
TFT J4Nucleo
SD_CSPA_9
SD_MOSIPB_15
SD_MISOPB_14
SD_SCKPB_13
AudioNucleo
TIPPA_4(A2)
USB con.Nucleo
GNDGND
+PA_12
-PA_11
5V5V

https://youtu.be/jL24IjT6LnI

Limitations

  • Since the rest of the RAM is about 50kbyte, maximum capacity of the game ROM is about 50kbyte.
  • The length of the file name up to 32 characters.
  • The number of files in the folder is up to 100.

Used Library

Files at this revision

API Documentation at this revision

Comitter:
beaglescout007
Date:
Sun Apr 03 07:45:29 2016 +0000
Commit message:
Release

Changed in this revision

K6502.cpp Show annotated file Show diff for this revision Revisions of this file
K6502.h Show annotated file Show diff for this revision Revisions of this file
K6502_rw.h Show annotated file Show diff for this revision Revisions of this file
Racoon_logo.cpp Show annotated file Show diff for this revision Revisions of this file
SDFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
TFT/spidma.cpp Show annotated file Show diff for this revision Revisions of this file
TFT/spidma.h Show annotated file Show diff for this revision Revisions of this file
TFT/tft.cpp Show annotated file Show diff for this revision Revisions of this file
TFT/tft.h Show annotated file Show diff for this revision Revisions of this file
USBHost/IUSBEnumerator.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBDeviceConnected.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBDeviceConnected.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBEndpoint.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHALHost.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHALHost2_F401RE.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHALHost_F401RE.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHALHost_F401RE.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHost.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHost.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHostConf.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHostGamepad.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHostGamepad.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHostHub.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHostTypes.h Show annotated file Show diff for this revision Revisions of this file
USBHost/dbg.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mydebug.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mymap.h Show annotated file Show diff for this revision Revisions of this file
USBHost/myvector.h Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
pNesX.cpp Show annotated file Show diff for this revision Revisions of this file
pNesX.h Show annotated file Show diff for this revision Revisions of this file
pNesX_Apu.cpp Show annotated file Show diff for this revision Revisions of this file
pNesX_Filer.cpp Show annotated file Show diff for this revision Revisions of this file
pNesX_Mapper.cpp Show annotated file Show diff for this revision Revisions of this file
pNesX_Mapper.h Show annotated file Show diff for this revision Revisions of this file
pNesX_System.h Show annotated file Show diff for this revision Revisions of this file
pNesX_System_Nucleo.cpp Show annotated file Show diff for this revision Revisions of this file
pNesX_Types.h Show annotated file Show diff for this revision Revisions of this file
pNesX_logo.cpp Show annotated file Show diff for this revision Revisions of this file
pspad.cpp Show annotated file Show diff for this revision Revisions of this file
pspad.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 3dac1f1bc9e0 K6502.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/K6502.cpp	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,1058 @@
+/*===================================================================*/
+/*                                                                   */
+/*  K6502.cpp : 6502 Emulator                                        */
+/*                                                                   */
+/*  1999/10/19  Racoon  New preparation                              */
+/*                                                                   */
+/*===================================================================*/
+
+/*-------------------------------------------------------------------*/
+/*  Include files                                                    */
+/*-------------------------------------------------------------------*/
+#include "K6502.h"
+
+/*-------------------------------------------------------------------*/
+/*  Operation Macros                                                 */
+/*-------------------------------------------------------------------*/
+
+// Clock Op.
+#define CLK(a)   g_wPassedClocks += (a);
+
+// Addressing Op.
+// Address
+// (Indirect,X)
+#define AA_IX    K6502_ReadZpW( K6502_Read( PC++ ) + X )
+// (Indirect),Y
+#define AA_IY    K6502_ReadZpW( K6502_Read( PC++ ) ) + Y
+// Zero Page
+#define AA_ZP    K6502_Read( PC++ )
+// Zero Page,X
+#define AA_ZPX   (BYTE)( K6502_Read( PC++ ) + X )
+// Zero Page,Y
+#define AA_ZPY   (BYTE)( K6502_Read( PC++ ) + Y )
+// Absolute
+#define AA_ABS   ( K6502_Read( PC++ ) | (WORD)K6502_Read( PC++ ) << 8 )
+// Absolute2 ( PC-- )
+#define AA_ABS2  ( K6502_Read( PC++ ) | (WORD)K6502_Read( PC ) << 8 )
+// Absolute,X
+#define AA_ABSX  AA_ABS + X
+// Absolute,Y
+#define AA_ABSY  AA_ABS + Y
+
+// Data
+// (Indirect,X)
+#define A_IX    K6502_Read( AA_IX )
+// (Indirect),Y
+#define A_IY    K6502_ReadIY()
+// Zero Page
+#define A_ZP    K6502_ReadZp( AA_ZP )
+// Zero Page,X
+#define A_ZPX   K6502_ReadZp( AA_ZPX )
+// Zero Page,Y
+#define A_ZPY   K6502_ReadZp( AA_ZPY )
+// Absolute
+#define A_ABS   K6502_Read( AA_ABS )
+// Absolute,X
+#define A_ABSX  K6502_ReadAbsX()
+// Absolute,Y
+#define A_ABSY  K6502_ReadAbsY()
+// Immediate
+#define A_IMM   K6502_Read( PC++ )
+
+// Flag Op.
+#define SETF(a)  F |= (a)
+#define RSTF(a)  F &= ~(a)
+#define TEST(a)  RSTF( FLAG_N | FLAG_Z ); SETF( g_byTestTable[ a ] )
+
+// Load & Store Op.
+#define STA(a)    K6502_Write( (a), A );
+#define STX(a)    K6502_Write( (a), X );
+#define STY(a)    K6502_Write( (a), Y );
+#define LDA(a)    A = (a); TEST( A );
+#define LDX(a)    X = (a); TEST( X );
+#define LDY(a)    Y = (a); TEST( Y );
+
+// Stack Op.
+#define PUSH(a)   K6502_Write( BASE_STACK + SP--, (a) )
+#define PUSHW(a)  PUSH( (a) >> 8 ); PUSH( (a) & 0xff )
+#define POP(a)    a = K6502_Read( BASE_STACK + ++SP )
+#define POPW(a)   POP(a); a |= ( K6502_Read( BASE_STACK + ++SP ) << 8 )
+
+// Logical Op.
+#define ORA(a)  A |= (a); TEST( A )
+#define AND(a)  A &= (a); TEST( A )
+#define EOR(a)  A ^= (a); TEST( A )
+#define BIT(a)  byD0 = (a); RSTF( FLAG_N | FLAG_V | FLAG_Z ); SETF( ( byD0 & ( FLAG_N | FLAG_V ) ) | ( ( byD0 & A ) ? 0 : FLAG_Z ) );
+#define CMP(a)  wD0 = (WORD)A - (a); RSTF( FLAG_N | FLAG_Z | FLAG_C ); SETF( g_byTestTable[ wD0 & 0xff ] | ( wD0 < 0x100 ? FLAG_C : 0 ) );
+#define CPX(a)  wD0 = (WORD)X - (a); RSTF( FLAG_N | FLAG_Z | FLAG_C ); SETF( g_byTestTable[ wD0 & 0xff ] | ( wD0 < 0x100 ? FLAG_C : 0 ) );
+#define CPY(a)  wD0 = (WORD)Y - (a); RSTF( FLAG_N | FLAG_Z | FLAG_C ); SETF( g_byTestTable[ wD0 & 0xff ] | ( wD0 < 0x100 ? FLAG_C : 0 ) );
+  
+// Math Op. (A D flag isn't being supported.)
+#define ADC(a)  byD0 = (a); \
+                wD0 = A + byD0 + ( F & FLAG_C ); \
+                byD1 = (BYTE)wD0; \
+                RSTF( FLAG_N | FLAG_V | FLAG_Z | FLAG_C ); \
+                SETF( g_byTestTable[ byD1 ] | ( ( ~( A ^ byD0 ) & ( A ^ byD1 ) & 0x80 ) ? FLAG_V : 0 ) | ( wD0 > 0xff ) ); \
+                A = byD1;
+
+#define SBC(a)  byD0 = (a); \
+                wD0 = A - byD0 - ( ~F & FLAG_C ); \
+                byD1 = (BYTE)wD0; \
+                RSTF( FLAG_N | FLAG_V | FLAG_Z | FLAG_C ); \
+                SETF( g_byTestTable[ byD1 ] | ( ( ( A ^ byD0 ) & ( A ^ byD1 ) & 0x80 ) ? FLAG_V : 0 ) | ( wD0 < 0x100 ) ); \
+                A = byD1;
+
+#define DEC(a)  wA0 = a; byD0 = K6502_Read( wA0 ); --byD0; K6502_Write( wA0, byD0 ); TEST( byD0 )
+#define INC(a)  wA0 = a; byD0 = K6502_Read( wA0 ); ++byD0; K6502_Write( wA0, byD0 ); TEST( byD0 )
+
+// Shift Op.
+#define ASLA    RSTF( FLAG_N | FLAG_Z | FLAG_C ); SETF( g_ASLTable[ A ].byFlag ); A = g_ASLTable[ A ].byValue 
+#define ASL(a)  RSTF( FLAG_N | FLAG_Z | FLAG_C ); wA0 = a; byD0 = K6502_Read( wA0 ); SETF( g_ASLTable[ byD0 ].byFlag ); K6502_Write( wA0, g_ASLTable[ byD0 ].byValue )
+#define LSRA    RSTF( FLAG_N | FLAG_Z | FLAG_C ); SETF( g_LSRTable[ A ].byFlag ); A = g_LSRTable[ A ].byValue 
+#define LSR(a)  RSTF( FLAG_N | FLAG_Z | FLAG_C ); wA0 = a; byD0 = K6502_Read( wA0 ); SETF( g_LSRTable[ byD0 ].byFlag ); K6502_Write( wA0, g_LSRTable[ byD0 ].byValue ) 
+#define ROLA    byD0 = F & FLAG_C; RSTF( FLAG_N | FLAG_Z | FLAG_C ); SETF( g_ROLTable[ byD0 ][ A ].byFlag ); A = g_ROLTable[ byD0 ][ A ].byValue 
+#define ROL(a)  byD1 = F & FLAG_C; RSTF( FLAG_N | FLAG_Z | FLAG_C ); wA0 = a; byD0 = K6502_Read( wA0 ); SETF( g_ROLTable[ byD1 ][ byD0 ].byFlag ); K6502_Write( wA0, g_ROLTable[ byD1 ][ byD0 ].byValue )
+#define RORA    byD0 = F & FLAG_C; RSTF( FLAG_N | FLAG_Z | FLAG_C ); SETF( g_RORTable[ byD0 ][ A ].byFlag ); A = g_RORTable[ byD0 ][ A ].byValue 
+#define ROR(a)  byD1 = F & FLAG_C; RSTF( FLAG_N | FLAG_Z | FLAG_C ); wA0 = a; byD0 = K6502_Read( wA0 ); SETF( g_RORTable[ byD1 ][ byD0 ].byFlag ); K6502_Write( wA0, g_RORTable[ byD1 ][ byD0 ].byValue )
+
+// Jump Op.
+#define JSR     wA0 = AA_ABS2; PUSHW( PC ); PC = wA0; 
+#define BRA(a)  if ( a ) { wA0 = PC; PC += (signed char)K6502_Read( PC ); CLK( 3 + ( ( wA0 & 0x0100 ) != ( PC & 0x0100 ) ) ); ++PC; } else { ++PC; CLK( 2 ); }
+#define JMP(a)  PC = a;
+
+/*-------------------------------------------------------------------*/
+/*  Global valiables                                                 */
+/*-------------------------------------------------------------------*/
+
+// 6502 Register
+WORD PC;
+BYTE SP;
+BYTE F;
+BYTE A;
+BYTE X;
+BYTE Y;
+
+// The state of the IRQ pin
+BYTE IRQ_State;
+
+// Wiring of the IRQ pin
+BYTE IRQ_Wiring;
+
+// The state of the NMI pin
+BYTE NMI_State;
+
+// Wiring of the NMI pin
+BYTE NMI_Wiring;
+
+// The number of the clocks that it passed
+WORD g_wPassedClocks;
+
+// A table for the test
+BYTE g_byTestTable[ 256 ];
+
+// Value and Flag Data
+struct value_table_tag
+{
+  BYTE byValue;
+  BYTE byFlag;
+};
+
+// A table for ASL
+struct value_table_tag g_ASLTable[ 256 ];
+
+// A table for LSR
+struct value_table_tag g_LSRTable[ 256 ];
+
+// A table for ROL
+struct value_table_tag g_ROLTable[ 2 ][ 256 ];
+
+// A table for ROR
+struct value_table_tag g_RORTable[ 2 ][ 256 ];
+
+/*===================================================================*/
+/*                                                                   */
+/*                K6502_Init() : Initialize K6502                    */
+/*                                                                   */
+/*===================================================================*/
+void K6502_Init()
+{
+/*
+ *  Initialize K6502
+ *
+ *  You must call this function only once at first.
+ */
+
+  BYTE idx;
+  BYTE idx2;
+
+  // The establishment of the IRQ pin
+  NMI_Wiring = NMI_State = 1;
+  IRQ_Wiring = IRQ_State = 1;
+
+  // Make a table for the test
+  idx = 0;
+  do
+  {
+    if ( idx == 0 )
+      g_byTestTable[ 0 ] = FLAG_Z;
+    else
+    if ( idx > 127 )
+      g_byTestTable[ idx ] = FLAG_N;
+    else
+      g_byTestTable[ idx ] = 0;
+
+    ++idx;
+  } while ( idx != 0 );
+
+  // Make a table ASL
+  idx = 0;
+  do
+  {
+    g_ASLTable[ idx ].byValue = idx << 1;
+    g_ASLTable[ idx ].byFlag = 0;
+
+    if ( idx > 127 )
+      g_ASLTable[ idx ].byFlag = FLAG_C;
+
+    if ( g_ASLTable[ idx ].byValue == 0 )
+      g_ASLTable[ idx ].byFlag |= FLAG_Z;
+    else
+    if ( g_ASLTable[ idx ].byValue & 0x80 )
+      g_ASLTable[ idx ].byFlag |= FLAG_N;
+
+    ++idx;
+  } while ( idx != 0 );
+
+  // Make a table LSR
+  idx = 0;
+  do
+  {
+    g_LSRTable[ idx ].byValue = idx >> 1;
+    g_LSRTable[ idx ].byFlag = 0;
+
+    if ( idx & 1 )
+      g_LSRTable[ idx ].byFlag = FLAG_C;
+
+    if ( g_LSRTable[ idx ].byValue == 0 )
+      g_LSRTable[ idx ].byFlag |= FLAG_Z;
+
+    ++idx;
+  } while ( idx != 0 );
+
+  // Make a table ROL
+  for ( idx2 = 0; idx2 < 2; ++idx2 )
+  {
+    idx = 0;
+    do
+    {
+      g_ROLTable[ idx2 ][ idx ].byValue = ( idx << 1 ) | idx2;
+      g_ROLTable[ idx2 ][ idx ].byFlag = 0;
+
+      if ( idx > 127 )
+        g_ROLTable[ idx2 ][ idx ].byFlag = FLAG_C;
+
+      if ( g_ROLTable[ idx2 ][ idx ].byValue == 0 )
+        g_ROLTable[ idx2 ][ idx ].byFlag |= FLAG_Z;
+      else
+      if ( g_ROLTable[ idx2 ][ idx ].byValue & 0x80 )
+        g_ROLTable[ idx2 ][ idx ].byFlag |= FLAG_N;
+
+      ++idx;
+    } while ( idx != 0 );
+  }
+
+  // Make a table ROR
+  for ( idx2 = 0; idx2 < 2; ++idx2 )
+  {
+    idx = 0;
+    do
+    {
+      g_RORTable[ idx2 ][ idx ].byValue = ( idx >> 1 ) | ( idx2 << 7 );
+      g_RORTable[ idx2 ][ idx ].byFlag = 0;
+
+      if ( idx & 1 )
+        g_RORTable[ idx2 ][ idx ].byFlag = FLAG_C;
+
+      if ( g_RORTable[ idx2 ][ idx ].byValue == 0 )
+        g_RORTable[ idx2 ][ idx ].byFlag |= FLAG_Z;
+      else
+      if ( g_RORTable[ idx2 ][ idx ].byValue & 0x80 )
+        g_RORTable[ idx2 ][ idx ].byFlag |= FLAG_N;
+
+      ++idx;
+    } while ( idx != 0 );
+  }
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*                K6502_Reset() : Reset a CPU                        */
+/*                                                                   */
+/*===================================================================*/
+void K6502_Reset()
+{
+/*
+ *  Reset a CPU
+ *
+ */
+
+  // Reset Registers
+  PC = K6502_ReadW( VECTOR_RESET );
+  SP = 0xFF;
+  A = X = Y = 0;
+  F = FLAG_Z | FLAG_R;
+
+  // Set up the state of the Interrupt pin.
+  NMI_State = NMI_Wiring;
+  IRQ_State = IRQ_Wiring;
+
+  // Reset Passed Clocks
+  g_wPassedClocks = 0;
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*    K6502_Set_Int_Wiring() : Set up wiring of the interrupt pin    */
+/*                                                                   */
+/*===================================================================*/
+void K6502_Set_Int_Wiring( BYTE byNMI_Wiring, BYTE byIRQ_Wiring )
+{
+/*
+ * Set up wiring of the interrupt pin
+ *
+ */
+
+  NMI_Wiring = byNMI_Wiring;
+  IRQ_Wiring = byIRQ_Wiring;
+}
+
+int dbgstep = 0;
+int check_userbutton();
+
+/*===================================================================*/
+/*                                                                   */
+/*  K6502_Step() :                                                   */
+/*          Only the specified number of the clocks execute Op.      */
+/*                                                                   */
+/*===================================================================*/
+void K6502_Step( WORD wClocks )
+{
+/*
+ *  Only the specified number of the clocks execute Op.
+ *
+ *  Parameters
+ *    WORD wClocks              (Read)
+ *      The number of the clocks
+ */
+
+  BYTE byCode;
+
+  WORD wA0;
+  BYTE byD0;
+  BYTE byD1;
+  WORD wD0;
+
+  // Dispose of it if there is an interrupt requirement
+  if ( NMI_State != NMI_Wiring )
+  {
+    // NMI Interrupt
+    CLK( 7 );
+
+    PUSHW( PC );
+    PUSH( F & ~FLAG_B );
+
+    RSTF( FLAG_D );
+
+    PC = K6502_ReadW( VECTOR_NMI );
+  }
+  else
+  if ( IRQ_State != IRQ_Wiring )
+  {
+    // IRQ Interrupt
+    // Execute IRQ if an I flag isn't being set
+    if ( !( F & FLAG_I ) )
+    {
+      CLK( 7 );
+
+      PUSHW( PC );
+      PUSH( F & ~FLAG_B );
+
+      RSTF( FLAG_D );
+      SETF( FLAG_I );
+    
+      PC = K6502_ReadW( VECTOR_IRQ );
+    }
+  }
+
+  NMI_State = NMI_Wiring;
+  IRQ_State = IRQ_Wiring;
+
+  // It has a loop until a constant clock passes
+  while ( g_wPassedClocks < wClocks )
+  {
+    // Read an instruction
+    byCode = K6502_Read( PC++ );
+ 
+    //if (dbgstep % 10000 == 0)
+    //{
+    //    printf("%8d PC:%4x Code:%2x SP:%2x F:%2x A:%2x X:%2x Y:%2x\r\n", dbgstep, PC - 1, byCode, SP, F, A, X, Y);
+    //    while (check_userbutton() != 0) ;
+    //    wait(0.1);
+    //}
+    //dbgstep++;
+    
+    // Execute an instruction.
+    switch ( byCode )
+    {
+      case 0x00:  // BRK
+        ++PC; PUSHW( PC ); SETF( FLAG_B ); PUSH( F ); SETF( FLAG_I ); RSTF( FLAG_D ); PC = K6502_ReadW( VECTOR_IRQ ); CLK( 7 );
+        break;
+
+      case 0x01:  // ORA (Zpg,X)
+        ORA( A_IX ); CLK( 6 );
+        break;
+
+      case 0x05:  // ORA Zpg
+        ORA( A_ZP ); CLK( 3 );
+        break;
+
+      case 0x06:  // ASL Zpg
+        ASL( AA_ZP ); CLK( 5 );
+        break;
+
+      case 0x08:  // PHP
+        PUSH( F ); CLK( 3 );
+        break;
+
+      case 0x09:  // ORA #Oper
+        ORA( A_IMM ); CLK( 2 );
+        break;
+
+      case 0x0A:  // ASL A
+        ASLA; CLK( 2 );
+        break;
+
+      case 0x0D:  // ORA Abs
+        ORA( A_ABS ); CLK( 4 );
+        break;
+
+      case 0x0e:  // ASL Abs 
+        ASL( AA_ABS ); CLK( 6 );
+        break;
+
+      case 0x10: // BPL Oper
+        BRA( !( F & FLAG_N ) );
+        break;
+
+      case 0x11: // ORA (Zpg),Y
+        ORA( A_IY ); CLK( 5 );
+        break;
+
+      case 0x15: // ORA Zpg,X
+        ORA( A_ZPX ); CLK( 4 );
+        break;
+
+      case 0x16: // ASL Zpg,X
+        ASL( AA_ZPX ); CLK( 6 );
+        break;
+
+      case 0x18: // CLC
+        RSTF( FLAG_C ); CLK( 2 );
+        break;
+
+      case 0x19: // ORA Abs,Y
+        ORA( A_ABSY ); CLK( 4 );
+        break;
+
+      case 0x1D: // ORA Abs,X
+        ORA( A_ABSX ); CLK( 4 );
+        break;
+
+      case 0x1E: // ASL Abs,X
+        ASL( AA_ABSX ); CLK( 7 );
+        break;
+
+      case 0x20: // JSR Abs
+        JSR; CLK( 6 );
+        break;
+
+      case 0x21: // AND (Zpg,X)
+        AND( A_IX ); CLK( 6 );
+        break;
+
+      case 0x24: // BIT Zpg
+        BIT( A_ZP ); CLK( 3 );
+        break;
+
+      case 0x25: // AND Zpg
+        AND( A_ZP ); CLK( 3 );
+        break;
+
+      case 0x26: // ROL Zpg
+        ROL( AA_ZP ); CLK( 5 );
+        break;
+
+      case 0x28: // PLP
+        POP( F ); SETF( FLAG_R ); CLK( 4 );
+        break;
+
+      case 0x29: // AND #Oper
+        AND( A_IMM ); CLK( 2 );
+        break;
+
+      case 0x2A: // ROL A
+        ROLA; CLK( 2 );
+        break;
+
+      case 0x2C: // BIT Abs
+        BIT( A_ABS ); CLK( 4 );
+        break;
+
+      case 0x2D: // AND Abs 
+        AND( A_ABS ); CLK( 4 );
+        break;
+
+      case 0x2E: // ROL Abs
+        ROL( AA_ABS ); CLK( 6 );
+        break;
+
+      case 0x30: // BMI Oper 
+        BRA( F & FLAG_N );
+        break;
+
+      case 0x31: // AND (Zpg),Y
+        AND( A_IY ); CLK( 5 );
+        break;
+
+      case 0x35: // AND Zpg,X
+        AND( A_ZPX ); CLK( 4 );
+        break;
+
+      case 0x36: // ROL Zpg,X
+        ROL( AA_ZPX ); CLK( 6 );
+        break;
+
+      case 0x38: // SEC
+        SETF( FLAG_C ); CLK( 2 );
+        break;
+
+      case 0x39: // AND Abs,Y
+        AND( A_ABSY ); CLK( 4 );
+        break;
+
+      case 0x3D: // AND Abs,X
+        AND( A_ABSX ); CLK( 4 );
+        break;
+
+      case 0x3E: // ROL Abs,X
+        ROL( AA_ABSX ); CLK( 7 );
+        break;
+
+      case 0x40: // RTI
+        POP( F ); SETF( FLAG_R ); POPW( PC ); CLK( 6 );
+        break;
+
+      case 0x41: // EOR (Zpg,X)
+        EOR( A_IX ); CLK( 6 );
+        break;
+
+      case 0x45: // EOR Zpg
+        EOR( A_ZP ); CLK( 3 );
+        break;
+
+      case 0x46: // LSR Zpg
+        LSR( AA_ZP ); CLK( 5 );
+        break;
+
+      case 0x48: // PHA
+        PUSH( A ); CLK( 3 );
+        break;
+
+      case 0x49: // EOR #Oper
+        EOR( A_IMM ); CLK( 2 );
+        break;
+
+      case 0x4A: // LSR A
+        LSRA; CLK( 2 );
+        break;
+
+      case 0x4C: // JMP Abs
+        JMP( AA_ABS ); CLK( 3 );
+        break;
+
+      case 0x4D: // EOR Abs
+        EOR( A_ABS ); CLK( 4 );
+        break;
+
+      case 0x4E: // LSR Abs
+        LSR( AA_ABS ); CLK( 6 );
+        break;
+
+      case 0x50: // BVC
+        BRA( !( F & FLAG_V ) );
+        break;
+
+      case 0x51: // EOR (Zpg),Y
+        EOR( A_IY ); CLK( 5 );
+        break;
+
+      case 0x55: // EOR Zpg,X
+        EOR( A_ZPX ); CLK( 4 );
+        break;
+
+      case 0x56: // LSR Zpg,X
+        LSR( AA_ZPX ); CLK( 6 );
+        break;
+
+      case 0x58: // CLI
+        byD0 = F;
+        RSTF( FLAG_I ); CLK( 2 );
+        if ( ( byD0 & FLAG_I ) && IRQ_State == 0 )
+        {
+          // IRQ Interrupt
+          // Execute IRQ if an I flag isn't being set
+          if ( !( F & FLAG_I ) )
+          {
+            CLK( 7 );
+
+            PUSHW( PC );
+            PUSH( F & ~FLAG_B );
+
+            RSTF( FLAG_D );
+            SETF( FLAG_I );
+    
+            PC = K6502_ReadW( VECTOR_IRQ );
+          }
+        }
+        break;
+
+      case 0x59: // EOR Abs,Y
+        EOR( A_ABSY ); CLK( 4 );
+        break;
+
+      case 0x5D: // EOR Abs,X
+        EOR( A_ABSX ); CLK( 4 );
+        break;
+
+      case 0x5E: // LSR Abs,X
+        LSR( AA_ABSX ); CLK( 7 );
+        break;
+
+      case 0x60: // RTS
+        POPW( PC ); ++PC; CLK( 6 );
+        break;
+
+      case 0x61: // ADC (Zpg,X)
+        ADC( A_IX ); CLK( 6 );
+        break;
+
+      case 0x65: // ADC Zpg
+        ADC( A_ZP ); CLK( 3 );
+        break;
+
+      case 0x66: // ROR Zpg
+        ROR( AA_ZP ); CLK( 5 );
+        break;
+
+      case 0x68: // PLA
+        POP( A ); TEST( A ); CLK( 4 );
+        break;
+
+      case 0x69: // ADC #Oper
+        ADC( A_IMM ); CLK( 2 );
+        break;
+
+      case 0x6A: // ROR A
+        RORA; CLK( 2 );
+        break;
+
+      case 0x6C: // JMP (Abs)
+        JMP( K6502_ReadW( AA_ABS ) ); CLK( 5 );
+        break;
+
+      case 0x6D: // ADC Abs
+        ADC( A_ABS ); CLK( 4 );
+        break;
+
+      case 0x6E: // ROR Abs
+        ROR( AA_ABS ); CLK( 6 );
+        break;
+
+      case 0x70: // BVS
+        BRA( F & FLAG_V );
+        break;
+
+      case 0x71: // ADC (Zpg),Y
+        ADC( A_IY ); CLK( 5 );
+        break;
+
+      case 0x75: // ADC Zpg,X
+        ADC( A_ZPX ); CLK( 4 );
+        break;
+
+      case 0x76: // ROR Zpg,X
+        ROR( AA_ZPX ); CLK( 6 );
+        break;
+
+      case 0x78: // SEI
+        SETF( FLAG_I ); CLK( 2 );
+        break;
+
+      case 0x79: // ADC Abs,Y
+        ADC( A_ABSY ); CLK( 4 );
+        break;
+
+      case 0x7D: // ADC Abs,X
+        ADC( A_ABSX ); CLK( 4 );
+        break;
+
+      case 0x7E: // ROR Abs,X
+        ROR( AA_ABSX ); CLK( 7 );
+        break;
+
+      case 0x81: // STA (Zpg,X)
+        STA( AA_IX ); CLK( 6 );
+        break;
+      
+      case 0x84: // STY Zpg
+        STY( AA_ZP ); CLK( 3 );
+        break;
+
+      case 0x85: // STA Zpg
+        STA( AA_ZP ); CLK( 3 );
+        break;
+
+      case 0x86: // STX Zpg
+        STX( AA_ZP ); CLK( 3 );
+        break;
+
+      case 0x88: // DEY
+        --Y; TEST( Y ); CLK( 2 );
+        break;
+
+      case 0x8A: // TXA
+        A = X; TEST( A ); CLK( 2 );
+        break;
+
+      case 0x8C: // STY Abs
+        STY( AA_ABS ); CLK( 4 );
+        break;
+
+      case 0x8D: // STA Abs
+        STA( AA_ABS ); CLK( 4 );
+        break;
+
+      case 0x8E: // STX Abs
+        STX( AA_ABS ); CLK( 4 );
+        break;
+
+      case 0x90: // BCC
+        BRA( !( F & FLAG_C ) );
+        break;
+
+      case 0x91: // STA (Zpg),Y
+        STA( AA_IY ); CLK( 6 );
+        break;
+
+      case 0x94: // STY Zpg,X
+        STY( AA_ZPX ); CLK( 4 );
+        break;
+
+      case 0x95: // STA Zpg,X
+        STA( AA_ZPX ); CLK( 4 );
+        break;
+
+      case 0x96: // STX Zpg,Y
+        STX( AA_ZPY ); CLK( 4 );
+        break;
+
+      case 0x98: // TYA
+        A = Y; TEST( A ); CLK( 2 );
+        break;
+
+      case 0x99: // STA Abs,Y
+        STA( AA_ABSY ); CLK( 5 );
+        break;
+
+      case 0x9A: // TXS
+        SP = X; CLK( 2 );
+        break;
+
+      case 0x9D: // STA Abs,X
+        STA( AA_ABSX ); CLK( 5 );
+        break;
+
+      case 0xA0: // LDY #Oper
+        LDY( A_IMM ); CLK( 2 );
+        break;
+
+      case 0xA1: // LDA (Zpg,X)
+        LDA( A_IX ); CLK( 6 );
+        break;
+
+      case 0xA2: // LDX #Oper
+        LDX( A_IMM ); CLK( 2 );
+        break;
+
+      case 0xA4: // LDY Zpg
+        LDY( A_ZP ); CLK( 3 );
+        break;
+
+      case 0xA5: // LDA Zpg
+        LDA( A_ZP ); CLK( 3 );
+        break;
+
+      case 0xA6: // LDX Zpg
+        LDX( A_ZP ); CLK( 3 );
+        break;
+
+      case 0xA8: // TAY
+        Y = A; TEST( A ); CLK( 2 );
+        break;
+
+      case 0xA9: // LDA #Oper
+        LDA( A_IMM ); CLK( 2 );
+        break;
+
+      case 0xAA: // TAX
+        X = A; TEST( A ); CLK( 2 );
+        break;
+
+      case 0xAC: // LDY Abs
+        LDY( A_ABS ); CLK( 4 );
+        break;
+
+      case 0xAD: // LDA Abs
+        LDA( A_ABS ); CLK( 4 );
+        break;
+
+      case 0xAE: // LDX Abs
+        LDX( A_ABS ); CLK( 4 );
+        break;
+
+      case 0xB0: // BCS
+        BRA( F & FLAG_C );
+        break;
+
+      case 0xB1: // LDA (Zpg),Y
+        LDA( A_IY ); CLK( 5 );
+        break;
+
+      case 0xB4: // LDY Zpg,X
+        LDY( A_ZPX ); CLK( 4 );
+        break;
+
+      case 0xB5: // LDA Zpg,X
+        LDA( A_ZPX ); CLK( 4 );
+        break;
+
+      case 0xB6: // LDX Zpg,Y
+        LDX( A_ZPY ); CLK( 4 );
+        break;
+
+      case 0xB8: // CLV
+        RSTF( FLAG_V ); CLK( 2 );
+        break;
+
+      case 0xB9: // LDA Abs,Y
+        LDA( A_ABSY ); CLK( 4 );
+        break;
+
+      case 0xBA: // TSX
+        X = SP; TEST( X ); CLK( 2 );
+        break;
+
+      case 0xBC: // LDY Abs,X
+        LDY( A_ABSX ); CLK( 4 );
+        break;
+
+      case 0xBD: // LDA Abs,X
+        LDA( A_ABSX ); CLK( 4 );
+        break;
+
+      case 0xBE: // LDX Abs,Y
+        LDX( A_ABSY ); CLK( 4 );
+        break;
+
+      case 0xC0: // CPY #Oper
+        CPY( A_IMM ); CLK( 2 );
+        break;
+
+      case 0xC1: // CMP (Zpg,X)
+        CMP( A_IX ); CLK( 6 );
+        break;
+
+      case 0xC4: // CPY Zpg
+        CPY( A_ZP ); CLK( 3 );
+        break;
+
+      case 0xC5: // CMP Zpg
+        CMP( A_ZP ); CLK( 3 );
+        break;
+
+      case 0xC6: // DEC Zpg
+        DEC( AA_ZP ); CLK( 5 );
+        break;
+
+      case 0xC8: // INY
+        ++Y; TEST( Y ); CLK( 2 );
+        break;
+
+      case 0xC9: // CMP #Oper
+        CMP( A_IMM ); CLK( 2 );
+        break;
+
+      case 0xCA: // DEX
+        --X; TEST( X ); CLK( 2 );
+        break;
+
+      case 0xCC: // CPY Abs
+        CPY( A_ABS ); CLK( 4 );
+        break;
+
+      case 0xCD: // CMP Abs
+        CMP( A_ABS ); CLK( 4 );
+        break;
+
+      case 0xCE: // DEC Abs
+        DEC( AA_ABS ); CLK( 6 );
+        break;
+
+      case 0xD0: // BNE
+        BRA( !( F & FLAG_Z ) );
+        break;
+
+      case 0xD1: // CMP (Zpg),Y
+        CMP( A_IY ); CLK( 5 );
+        break;
+
+      case 0xD5: // CMP Zpg,X
+        CMP( A_ZPX ); CLK( 4 );
+        break;
+
+      case 0xD6: // DEC Zpg,X
+        DEC( AA_ZPX ); CLK( 6 );
+        break;
+
+      case 0xD8: // CLD
+        RSTF( FLAG_D ); CLK( 2 );
+        break;
+
+      case 0xD9: // CMP Abs,Y
+        CMP( A_ABSY ); CLK( 4 );
+        break;
+
+      case 0xDD: // CMP Abs,X
+        CMP( A_ABSX ); CLK( 4 );
+        break;
+
+      case 0xDE: // DEC Abs,X
+        DEC( AA_ABSX ); CLK( 7 );
+        break;
+
+      case 0xE0: // CPX #Oper
+        CPX( A_IMM ); CLK( 2 );
+        break;
+
+      case 0xE1: // SBC (Zpg,X)
+        SBC( A_IX ); CLK( 6 );
+        break;
+
+      case 0xE4: // CPX Zpg
+        CPX( A_ZP ); CLK( 3 );
+        break;
+
+      case 0xE5: // SBC Zpg
+        SBC( A_ZP ); CLK( 3 );
+        break;
+
+      case 0xE6: // INC Zpg
+        INC( AA_ZP ); CLK( 5 );
+        break;
+
+      case 0xE8: // INX
+        ++X; TEST( X ); CLK( 2 );
+        break;
+
+      case 0xE9: // SBC #Oper
+        SBC( A_IMM ); CLK( 2 );
+        break;
+
+      case 0xEA: // NOP
+        CLK( 2 );
+        break;
+
+      case 0xEC: // CPX Abs
+        CPX( A_ABS ); CLK( 4 );
+        break;
+
+      case 0xED: // SBC Abs
+        SBC( A_ABS ); CLK( 4 );
+        break;
+
+      case 0xEE: // INC Abs
+        INC( AA_ABS ); CLK( 6 );
+        break;
+
+      case 0xF0: // BEQ
+        BRA( F & FLAG_Z );
+        break;
+
+      case 0xF1: // SBC (Zpg),Y
+        SBC( A_IY ); CLK( 5 );
+        break;
+
+      case 0xF5: // SBC Zpg,X
+        SBC( A_ZPX ); CLK( 4 );
+        break;
+
+      case 0xF6: // INC Zpg,X
+        INC( AA_ZPX ); CLK( 6 );
+        break;
+
+      case 0xF8: // SED
+        SETF( FLAG_D ); CLK( 2 );
+        break;
+
+      case 0xF9: // SBC Abs,Y
+        SBC( A_ABSY ); CLK( 4 );
+        break;
+
+      case 0xFD: // SBC Abs,X
+        SBC( A_ABSX ); CLK( 4 );
+        break;
+
+      case 0xFE: // INC Abs,X
+        INC( AA_ABSX ); CLK( 7 );
+        break;
+
+      default:   // Unknown Instruction
+        CLK( 2 );
+        break;
+        
+    }  /* end of switch ( byCode ) */
+
+  }  /* end of while ... */
+
+  // Correct the number of the clocks
+  g_wPassedClocks -= wClocks;
+}
+
+// Addressing Op.
+// Data
+// Absolute,X
+static inline BYTE K6502_ReadAbsX(){ WORD wA0, wA1; wA0 = AA_ABS; wA1 = wA0 + X; CLK( ( wA0 & 0x0100 ) != ( wA1 & 0x0100 ) ); return K6502_Read( wA1 ); };
+// Absolute,Y
+static inline BYTE K6502_ReadAbsY(){ WORD wA0, wA1; wA0 = AA_ABS; wA1 = wA0 + Y; CLK( ( wA0 & 0x0100 ) != ( wA1 & 0x0100 ) ); return K6502_Read( wA1 ); };
+// (Indirect),Y
+static inline BYTE K6502_ReadIY(){ WORD wA0, wA1; wA0 = K6502_ReadZpW( K6502_Read( PC++ ) ); wA1 = wA0 + Y; CLK( ( wA0 & 0x0100 ) != ( wA1 & 0x0100 ) ); return K6502_Read( wA1 ); };
+
+/*===================================================================*/
+/*                                                                   */
+/*                  6502 Reading/Writing Operation                   */
+/*                                                                   */
+/*===================================================================*/
+#include "K6502_rw.h"
+
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 K6502.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/K6502.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,82 @@
+/*===================================================================*/
+/*                                                                   */
+/*  K6502.h : Header file for K6502                                  */
+/*                                                                   */
+/*  1999/10/19  Racoon  New preparation                              */
+/*                                                                   */
+/*===================================================================*/
+
+#ifndef K6502_H_INCLUDED
+#define K6502_H_INCLUDED
+
+// Type definition
+#ifndef DWORD
+typedef unsigned long  DWORD;
+//typedef unsigned int  DWORD;
+#endif
+
+#ifndef WORD
+typedef unsigned short WORD;
+//typedef unsigned short WORD;
+#endif
+
+#ifndef BYTE
+typedef unsigned char  BYTE;
+//typedef char  BYTE;
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* 6502 Flags */
+#define FLAG_C 0x01
+#define FLAG_Z 0x02
+#define FLAG_I 0x04
+#define FLAG_D 0x08
+#define FLAG_B 0x10
+#define FLAG_R 0x20
+#define FLAG_V 0x40
+#define FLAG_N 0x80
+
+/* Stack Address */
+#define BASE_STACK   0x100
+
+/* Interrupt Vectors */
+#define VECTOR_NMI   0xfffa
+#define VECTOR_RESET 0xfffc
+#define VECTOR_IRQ   0xfffe
+
+// NMI Request
+#define NMI_REQ  NMI_State = 0;
+
+// IRQ Request
+#define IRQ_REQ  IRQ_State = 0;
+
+// Emulator Operation
+void K6502_Init();
+void K6502_Reset();
+void K6502_Set_Int_Wiring( BYTE byNMI_Wiring, BYTE byIRQ_Wiring );
+void K6502_Step( register WORD wClocks );
+
+// I/O Operation (User definition)
+static inline BYTE K6502_Read( WORD wAddr);
+static inline WORD K6502_ReadW( WORD wAddr );
+static inline BYTE K6502_ReadZp( BYTE byAddr );
+static inline WORD K6502_ReadZpW( BYTE byAddr );
+static inline BYTE K6502_ReadAbsX();
+static inline BYTE K6502_ReadAbsY();
+static inline BYTE K6502_ReadIY();
+
+static inline void K6502_Write( WORD wAddr, BYTE byData );
+static inline void K6502_WriteW( WORD wAddr, WORD wData );
+
+// The state of the IRQ pin
+extern BYTE IRQ_State;
+
+// The state of the NMI pin
+extern BYTE NMI_State;
+
+#endif /* !K6502_H_INCLUDED */
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 K6502_rw.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/K6502_rw.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,363 @@
+/*===================================================================*/
+/*                                                                   */
+/*  K6502_RW.h : 6502 Reading/Writing Operation for NES              */
+/*               This file is included in K6502.cpp                  */
+/*                                                                   */
+/*  1999/11/03  Racoon  New preparation                              */
+/*                                                                   */
+/*===================================================================*/
+
+#ifndef K6502_RW_H_INCLUDED
+#define K6502_RW_H_INCLUDED
+
+/*-------------------------------------------------------------------*/
+/*  Include files                                                    */
+/*-------------------------------------------------------------------*/
+
+#include "pNesX.h"
+#include "pNesX_System.h"
+
+/*===================================================================*/
+/*                                                                   */
+/*            K6502_ReadZp() : Reading from the zero page            */
+/*                                                                   */
+/*===================================================================*/
+static inline BYTE K6502_ReadZp( BYTE byAddr )
+{
+/*
+ *  Reading from the zero page
+ *
+ *  Parameters
+ *    BYTE byAddr              (Read)
+ *      An address inside the zero page
+ *
+ *  Return values
+ *    Read Data
+ */
+
+  return RAM[ byAddr ];
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*               K6502_Read() : Reading operation                    */
+/*                                                                   */
+/*===================================================================*/
+static inline BYTE K6502_Read( WORD wAddr )
+{
+/*
+ *  Reading operation
+ *
+ *  Parameters
+ *    WORD wAddr              (Read)
+ *      Address to read
+ *
+ *  Return values
+ *    Read data
+ *
+ *  Remarks
+ *    0x0000 - 0x1fff  RAM ( 0x800 - 0x1fff is mirror of 0x0 - 0x7ff )
+ *    0x2000 - 0x3fff  PPU
+ *    0x4000 - 0x5fff  Sound
+ *    0x6000 - 0x7fff  SRAM ( Battery Backed )
+ *    0x8000 - 0xffff  ROM
+ *
+ */
+  BYTE byRet;
+
+  switch ( wAddr & 0xe000 )
+  {
+    case 0x0000:  /* RAM */
+      return RAM[ wAddr & 0x7ff ];
+
+    case 0x2000:  /* PPU */
+      if ( wAddr <= 0x2006 )  /* PPU Status */
+      {
+        // Set return value
+        byRet = PPU_R2;
+
+        // Reset a V-Blank flag
+        PPU_R2 &= ~R2_IN_VBLANK;
+
+        // Reset address latch
+        PPU_Latch_Flag = 0;
+
+        // Make a Nametable 0 in V-Blank
+        if ( PPU_Scanline >= SCAN_VBLANK_START && !( PPU_R0 & R0_NMI_VB ) )
+        {
+          PPU_R0 &= ~R0_NAME_ADDR;
+          PPU_NameTableBank = NAME_TABLE0;
+        }
+        return byRet;
+      }
+      else
+      if ( wAddr == 0x2007 )  /* PPU Memory */
+      {
+        // Set return value;
+        byRet = PPU_R7;
+
+        // Read PPU Memory
+        PPU_R7 = PPUBANK[ PPU_Addr >> 10 ][ PPU_Addr & 0x3ff ];
+
+        // Increment PPU Address
+        PPU_Addr += PPU_Increment;
+        PPU_Addr &= 0x3fff;
+
+        return byRet;
+      }
+      break;
+
+    case 0x4000:  /* Sound */
+      if ( wAddr < 0x4016 )
+      {
+        // Return APU Register
+        //return APU_Reg[ wAddr & 0x1f ];
+        return ApuRead( wAddr & 0x1f );
+      }
+      else
+      if ( wAddr == 0x4016 )
+      {
+        // Set Joypad1 data
+        byRet = (BYTE)( ( PAD1_Latch >> PAD1_Bit ) & 1 ) | 0x40;
+        PAD1_Bit = ( PAD1_Bit == 23 ) ? 0 : ( PAD1_Bit + 1 );
+        return byRet;
+      }
+      else
+      if ( wAddr == 0x4017 )
+      {
+        // Set Joypad2 data
+        byRet = (BYTE)( ( PAD2_Latch >> PAD2_Bit ) & 1 ) | 0x40;
+        PAD2_Bit = ( PAD2_Bit == 23 ) ? 0 : ( PAD2_Bit + 1 );
+        return byRet;
+      }
+      break;
+
+    case 0x6000:  /* SRAM */
+      return SRAM[ wAddr & 0x1fff ];
+
+    case 0x8000:  /* ROM BANK 0 */
+      return ROMBANK0[ wAddr & 0x1fff ];
+
+    case 0xa000:  /* ROM BANK 1 */
+      return ROMBANK1[ wAddr & 0x1fff ];
+
+    case 0xc000:  /* ROM BANK 2 */
+      return ROMBANK2[ wAddr & 0x1fff ];
+
+    case 0xe000:  /* ROM BANK 3 */
+      return ROMBANK3[ wAddr & 0x1fff ];
+  }
+
+  return 0;
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*               K6502_Write() : Writing operation                    */
+/*                                                                   */
+/*===================================================================*/
+static inline void K6502_Write( WORD wAddr, BYTE byData )
+{
+/*
+ *  Writing operation
+ *
+ *  Parameters
+ *    WORD wAddr              (Read)
+ *      Address to write
+ *
+ *    BYTE byData             (Read)
+ *      Data to write
+ *
+ *  Remarks
+ *    0x0000 - 0x1fff  RAM ( 0x800 - 0x1fff is mirror of 0x0 - 0x7ff )
+ *    0x2000 - 0x3fff  PPU
+ *    0x4000 - 0x5fff  Sound
+ *    0x6000 - 0x7fff  SRAM ( Battery Backed )
+ *    0x8000 - 0xffff  ROM
+ *
+ */
+
+  switch ( wAddr & 0xe000 )
+  {
+    case 0x0000:  /* RAM */
+      RAM[ wAddr & 0x7ff ] = byData;
+      break;
+
+    case 0x2000:  /* PPU */
+      switch ( wAddr & 0x7 )
+      {
+        case 0:    /* 0x2000 */
+          PPU_R0 = byData;
+          PPU_Increment = ( PPU_R0 & R0_INC_ADDR ) ? 32 : 1;
+          PPU_NameTableBank = NAME_TABLE0 + ( PPU_R0 & R0_NAME_ADDR );
+          PPU_BG_Base = ( PPU_R0 & R0_BG_ADDR ) ? ChrBuf + 256 * 64 : ChrBuf;
+          PPU_SP_Base = ( PPU_R0 & R0_SP_ADDR ) ? ChrBuf + 256 * 64 : ChrBuf;
+          PPU_SP_Height = ( PPU_R0 & R0_SP_SIZE ) ? 16 : 8;
+          break;
+
+        case 1:   /* 0x2001 */
+          PPU_R1 = byData;
+          break;
+
+        case 2:   /* 0x2002 */
+          PPU_R2 = byData;
+          break;
+
+        case 3:   /* 0x2003 */
+          // Sprite RAM Address
+          PPU_R3 = byData;
+          break;
+
+        case 4:   /* 0x2004 */
+          // Write data to Sprite RAM
+          SPRRAM[ PPU_R3++ ] = byData;
+          break;
+
+        case 5:   /* 0x2005 */
+          // Set Scroll Register
+          if ( PPU_Latch_Flag )
+          {
+            // V-Scroll Register
+            PPU_Scr_V_Next = ( byData > 239 ) ? 0 : byData;
+            PPU_Scr_V_Byte_Next = PPU_Scr_V_Next >> 3;
+            PPU_Scr_V_Bit_Next = PPU_Scr_V_Next & 7;
+          }
+          else
+          {
+            // H-Scroll Register
+            PPU_Scr_H_Next = byData;
+            PPU_Scr_H_Byte_Next = PPU_Scr_H_Next >> 3;
+            PPU_Scr_H_Bit_Next = PPU_Scr_H_Next & 7;
+          }
+          PPU_Latch_Flag ^= 1;
+          break;
+
+        case 6:   /* 0x2006 */
+          // Set PPU Address
+          if ( PPU_Latch_Flag )
+          {
+            // Low
+            PPU_Addr |= byData;
+          }
+          else
+          {
+            // High
+            PPU_Addr = ( byData & 0x3f ) << 8;
+          }
+          PPU_Latch_Flag ^= 1;
+          break;
+
+        case 7:   /* 0x2007 */
+          // Write to PPU Memory
+          if ( PPU_Addr < 0x2000 && NesHeader.byVRomSize == 0 )
+          {
+            // Pattern Data
+            ChrBufUpdate |= ( 1 << ( PPU_Addr >> 10 ) );
+            PPURAM[ PPU_Addr ] = byData;
+          }
+          else
+          if ( PPU_Addr < 0x3f00 )  /* 0x2000 - 0x3eff */
+          {
+            // Name Table
+            PPUBANK[ PPU_Addr >> 10 ][ PPU_Addr & 0x3ff ] = byData;
+          }
+          else
+          if ( !( PPU_Addr & 0xf ) )  /* 0x3f00 or 0x3f10 */
+          {
+            // Palette mirror
+            PPURAM[ 0x3f10 ] = PPURAM[ 0x3f14 ] = PPURAM[ 0x3f18 ] = PPURAM[ 0x3f1c ] = 
+            PPURAM[ 0x3f00 ] = PPURAM[ 0x3f04 ] = PPURAM[ 0x3f08 ] = PPURAM[ 0x3f0c ] = byData;
+            PalTable[ 0x00 ] = PalTable[ 0x04 ] = PalTable[ 0x08 ] = PalTable[ 0x0c ] =
+            PalTable[ 0x10 ] = PalTable[ 0x14 ] = PalTable[ 0x18 ] = PalTable[ 0x1c ] = NesPalette[ byData ]; // | 0x8000;
+          }
+          else
+          if ( PPU_Addr & 3 )
+          {
+            // Palette
+            PPURAM[ PPU_Addr ] = byData;
+            PalTable[ PPU_Addr & 0x1f ] = NesPalette[ byData ];
+          }
+
+          // Increment PPU Address
+          PPU_Addr += PPU_Increment;
+          PPU_Addr &= 0x3fff;
+          break;
+      }
+      break;
+
+    case 0x4000:  /* Sound */
+      switch ( wAddr & 0x1f )
+      {
+        case 0x14:  /* 0x4014 */
+          // Sprite DMA
+          switch ( byData >> 5 )
+          {
+            case 0x0:  /* RAM */
+              pNesX_MemoryCopy( SPRRAM, &RAM[ ( (WORD)byData << 8 ) & 0x7ff ], SPRRAM_SIZE );
+              break;
+
+            case 0x3:  /* SRAM */
+              pNesX_MemoryCopy( SPRRAM, &SRAM[ ( (WORD)byData << 8 ) & 0x1fff ], SPRRAM_SIZE );
+              break;
+
+            case 0x4:  /* ROM BANK 0 */
+              pNesX_MemoryCopy( SPRRAM, &ROMBANK0[ ( (WORD)byData << 8 ) & 0x1fff ], SPRRAM_SIZE );
+              break;
+
+            case 0x5:  /* ROM BANK 1 */
+              pNesX_MemoryCopy( SPRRAM, &ROMBANK1[ ( (WORD)byData << 8 ) & 0x1fff ], SPRRAM_SIZE );
+              break;
+
+            case 0x6:  /* ROM BANK 2 */
+              pNesX_MemoryCopy( SPRRAM, &ROMBANK2[ ( (WORD)byData << 8 ) & 0x1fff ], SPRRAM_SIZE );
+              break;
+
+            case 0x7:  /* ROM BANK 3 */
+              pNesX_MemoryCopy( SPRRAM, &ROMBANK3[ ( (WORD)byData << 8 ) & 0x1fff ], SPRRAM_SIZE );
+              break;
+          }
+          APU_Reg[ 0x14 ] = byData;          
+          break;
+
+        case 0x16:  /* 0x4016 */
+          // Reset joypad
+          if ( !( APU_Reg[ 0x16 ] & 1 ) && ( byData & 1 ) )
+          {
+            PAD1_Bit = 0;
+            PAD2_Bit = 0;
+          }
+          APU_Reg[ 0x16 ] = byData;
+          break;
+          
+        default:
+          if ( wAddr <= 0x4017 )
+          {
+            // Write to APU Register
+            ApuWrite( wAddr & 0x1f, byData );
+          }
+          break;
+      }
+      break;
+
+    case 0x6000:  /* SRAM */
+      SRAM[ wAddr & 0x1fff ] = byData;
+      break;
+
+    case 0x8000:  /* ROM BANK 0 */
+    case 0xa000:  /* ROM BANK 1 */
+    case 0xc000:  /* ROM BANK 2 */
+    case 0xe000:  /* ROM BANK 3 */
+      // Write to Mapper
+      MapperWrite( wAddr, byData );
+      break;
+  }
+}
+
+// Reading/Writing operation (WORD version)
+static inline WORD K6502_ReadW( WORD wAddr ){ return K6502_Read( wAddr ) | (WORD)K6502_Read( wAddr + 1 ) << 8; };
+static inline void K6502_WriteW( WORD wAddr, WORD wData ){ K6502_Write( wAddr, wData & 0xff ); K6502_Write( wAddr + 1, wData >> 8 ); };
+static inline WORD K6502_ReadZpW( BYTE byAddr ){ return K6502_ReadZp( byAddr ) | ( K6502_ReadZp( byAddr + 1 ) << 8 ); };
+
+#endif /* !K6502_RW_H_INCLUDED */
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 Racoon_logo.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Racoon_logo.cpp	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,54 @@
+/*===================================================================*/
+/*                                                                   */
+/*  Racoon_logo.cpp : Racoon Logo image data(4bit bmp)               */
+/*                                                                   */
+/*  2016/1/20  Racoon                                                */
+/*                                                                   */
+/*===================================================================*/
+
+extern const unsigned char Racoon_logo[];
+
+const unsigned char Racoon_logo[]=
+{
+	0x42,0x4D,0x6E,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x6E,0x00,0x00,0x00,0x28,0x00,
+	0x00,0x00,0x3D,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0xF8,0xF8,0x00,0xF5,0xF5,0xF5,0x00,0xEF,0xEF,
+	0xEF,0x00,0xE3,0xE3,0xE3,0x00,0xD2,0xD2,0xD2,0x00,0xC2,0xC2,0xC2,0x00,0xAC,0xAC,
+	0xAC,0x00,0x9E,0x9E,0x9E,0x00,0x80,0x80,0x80,0x00,0x68,0x68,0x68,0x00,0x4D,0x4D,
+	0x4D,0x00,0x2E,0x2E,0x2E,0x00,0x17,0x17,0x17,0x00,0x09,0x09,0x09,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x27,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
+	0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x73,0x00,0x00,0x00,0x00,0x00,
+	0x5C,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
+	0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xC6,0x10,0x00,0x00,0x00,0x00,
+	0x26,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
+	0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x63,0x10,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x04,0x97,0x22,0x69,0x84,0x8A,0x97,0x94,0x14,0x8A,0xA7,0x33,0x8A,0xA7,
+	0x31,0x26,0x9A,0x94,0x24,0x97,0x13,0x96,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x06,0xCA,0x35,0xBC,0x68,0xCA,0x9C,0xD6,0x4A,0xCA,0xAA,0x59,0xCA,0xAD,
+	0x93,0x7C,0xB9,0xCB,0x46,0xDA,0x15,0xCA,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x06,0xCA,0x4A,0xD9,0x28,0xC8,0x39,0xD6,0x7C,0xA3,0x34,0x6B,0xA4,0x4B,
+	0xC6,0xAC,0x52,0x9D,0x76,0xDB,0x05,0xCA,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x06,0xCC,0xBD,0xB5,0x04,0xAB,0xBC,0xD6,0x8D,0x91,0x01,0x6C,0xA3,0x3A,
+	0xD6,0xBC,0x30,0x8D,0x86,0xDA,0x25,0xC9,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x06,0xCB,0x9B,0xC9,0x22,0x56,0x6B,0xD6,0x6C,0xB4,0x46,0x6B,0xB4,0x5B,
+	0xB5,0xAC,0x63,0xAD,0x76,0xDB,0x57,0xC9,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x06,0xCA,0x45,0xBC,0x43,0xAB,0xBC,0xA4,0x39,0xCB,0xBA,0x48,0xCB,0xBC,
+	0x82,0x6B,0xBB,0xC9,0x36,0xCC,0xBB,0xC7,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x06,0xCB,0x78,0xDC,0x32,0x68,0x88,0x41,0x02,0x68,0x85,0x21,0x57,0x85,
+	0x20,0x04,0x78,0x62,0x13,0x66,0x58,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x06,0xCD,0xDD,0xB8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x02,0x33,0x33,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 SDFileSystem.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem.lib	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/neilt6/code/SDFileSystem/#3fa5eaf48e81
diff -r 000000000000 -r 3dac1f1bc9e0 TFT/spidma.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TFT/spidma.cpp	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,107 @@
+/*===================================================================*/
+/*                                                                   */
+/*  spidma.cpp : SPI DMA function                                    */
+/*                                                                   */
+/*  2016/1/20  Racoon                                                */
+/*                                                                   */
+/*===================================================================*/
+
+#include "mbed.h"
+#include "stm32f4xx_hal.h"
+
+SPI_HandleTypeDef SpiHandle;
+
+/*-------------------------------------------------------------------*/
+/*  callback                                                         */
+/*-------------------------------------------------------------------*/
+extern "C" {
+    void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
+    {
+        static DMA_HandleTypeDef hdma_tx;
+
+        GPIO_InitTypeDef GPIO_InitStruct;
+
+        __HAL_RCC_GPIOA_CLK_ENABLE();
+        __HAL_RCC_SPI1_CLK_ENABLE();
+        __HAL_RCC_DMA2_CLK_ENABLE();
+
+        GPIO_InitStruct.Pin       = GPIO_PIN_5;
+        GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
+        GPIO_InitStruct.Pull      = GPIO_PULLUP;
+        GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;
+        GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
+        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+        GPIO_InitStruct.Pin = GPIO_PIN_6;
+        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+        GPIO_InitStruct.Pin = GPIO_PIN_7;
+        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+        hdma_tx.Instance                 = DMA2_Stream3;
+        hdma_tx.Init.Channel             = DMA_CHANNEL_3;
+        hdma_tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;
+        hdma_tx.Init.PeriphInc           = DMA_PINC_DISABLE;
+        hdma_tx.Init.MemInc              = DMA_MINC_ENABLE;
+        hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
+        hdma_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
+        hdma_tx.Init.Mode                = DMA_NORMAL;
+        hdma_tx.Init.Priority            = DMA_PRIORITY_HIGH;
+        hdma_tx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
+        hdma_tx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
+        hdma_tx.Init.MemBurst            = DMA_MBURST_SINGLE;
+        hdma_tx.Init.PeriphBurst         = DMA_PBURST_SINGLE;
+
+        HAL_DMA_Init(&hdma_tx);
+
+        __HAL_LINKDMA(hspi, hdmatx, hdma_tx);
+
+        HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 0, 1);
+        HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
+    }
+
+    void DMA2_Stream3_IRQHandler(void)
+    {
+        HAL_DMA_IRQHandler(SpiHandle.hdmatx);
+    }
+
+} // extern "C"
+
+/*-------------------------------------------------------------------*/
+/*  Write a byte data                                                */
+/*-------------------------------------------------------------------*/
+void spi_write(uint8_t data)
+{
+    HAL_SPI_Transmit(&SpiHandle, &data, 1, 100);
+}
+
+/*-------------------------------------------------------------------*/
+/*  Write a word data                                                */
+/*-------------------------------------------------------------------*/
+void spi_writew(uint16_t data)
+{
+    HAL_SPI_Transmit(&SpiHandle, (uint8_t *)&data, 2, 100);
+}
+
+/*-------------------------------------------------------------------*/
+/*  Initialize SPI DMA                                               */
+/*-------------------------------------------------------------------*/
+void spi_init()
+{
+    SpiHandle.Instance               = SPI1;
+    SpiHandle.Init.Mode              = SPI_MODE_MASTER;
+    SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
+    SpiHandle.Init.Direction         = SPI_DIRECTION_2LINES;
+    SpiHandle.Init.CLKPhase          = SPI_PHASE_1EDGE;
+    SpiHandle.Init.CLKPolarity       = SPI_POLARITY_HIGH;
+    SpiHandle.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLE;
+    SpiHandle.Init.CRCPolynomial     = 7;
+    SpiHandle.Init.DataSize          = SPI_DATASIZE_8BIT;
+    SpiHandle.Init.FirstBit          = SPI_FIRSTBIT_MSB;
+    SpiHandle.Init.NSS               = SPI_NSS_SOFT;
+    SpiHandle.Init.TIMode            = SPI_TIMODE_DISABLE;
+
+    if (HAL_SPI_Init(&SpiHandle) != HAL_OK)
+        while(1);
+}
+
diff -r 000000000000 -r 3dac1f1bc9e0 TFT/spidma.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TFT/spidma.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,19 @@
+/*===================================================================*/
+/*                                                                   */
+/*  spidma.h : SPI DMA function header                               */
+/*                                                                   */
+/*  2016/1/20  Racoon                                                */
+/*                                                                   */
+/*===================================================================*/
+
+#ifndef SPIDMA_H_INCLUDED
+#define SPIDMA_H_INCLUDED
+
+void spi_init();
+void spi_write(uint8_t data);
+void spi_writew(uint16_t data);
+
+extern SPI_HandleTypeDef SpiHandle;
+
+#endif
+
diff -r 000000000000 -r 3dac1f1bc9e0 TFT/tft.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TFT/tft.cpp	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,273 @@
+/*===================================================================*/
+/*                                                                   */
+/*  tft.cpp : TFT(ILI9341) function                                  */
+/*                                                                   */
+/*  2016/1/20  Racoon                                                */
+/*                                                                   */
+/*===================================================================*/
+
+#include "mbed.h"
+#include "tft.h"
+
+DigitalOut cs(PB_5, PullUp); // TFT chipselect pin
+DigitalOut dc(PA_8, PullUp); // TFT data command select pin
+DigitalOut rst(PA_10,PullUp); // TFT reset pin
+
+/*-------------------------------------------------------------------*/
+/*  Write command                                                    */
+/*-------------------------------------------------------------------*/
+void write_cmd(uint8_t cmd)
+{
+    dc = 0;
+    spi_write(cmd);
+}
+  
+/*-------------------------------------------------------------------*/
+/*  Write data                                                       */
+/*-------------------------------------------------------------------*/
+void write_data(uint8_t data)
+{
+    dc = 1;
+    spi_write(data);
+}
+
+/*-------------------------------------------------------------------*/
+/*  TFT reset                                                        */
+/*-------------------------------------------------------------------*/
+void tft_reset()
+{
+    wait_ms(200);
+    cs = 1;
+    dc = 1;
+    rst = 1;
+    wait_ms(200);
+    rst = 0;
+    wait_us(10);
+    rst = 1;
+    wait_ms(120);
+    cs = 0;
+    wait_ms(10);
+        
+    write_cmd(0x3A); // Pixel Format    
+    write_data(0x55); // 16bit Color
+    
+    write_cmd(0xB1); // Frame Control    
+    write_data(0);
+    write_data(0x1f);
+        
+    write_cmd(0x36); // Memory Access Control 
+    write_data(0xE8); // MY MX MV BGR
+
+    write_cmd(0x11); // Sleep Out
+    wait_ms(5);
+        
+    write_cmd(0x29); // Display On    
+}
+
+/*-------------------------------------------------------------------*/
+/*  Set windows size, start memory write                             */
+/*-------------------------------------------------------------------*/
+void tft_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
+{
+  write_cmd(0x2A); // Column Address Set
+  write_data(x0 >> 8);
+  write_data(x0);
+  write_data(x1 >> 8);
+  write_data(x1);
+
+  write_cmd(0x2B); // Page Address Set
+  write_data(y0 >> 8);
+  write_data(y0);
+  write_data(y1 >> 8);
+  write_data(y1);
+
+  write_cmd(0x2C); // Memory Write
+  
+  wait_us(20);
+  
+  dc = 1;
+}
+
+/*-------------------------------------------------------------------*/
+/*  Clear screen                                                     */
+/*-------------------------------------------------------------------*/
+void tft_clear(uint16_t color)
+{
+    tft_set_window(0, 0, TFT_WIDTH, TFT_HEIGHT);
+
+    for (int i = 0; i < TFT_WIDTH * TFT_HEIGHT; ++i)
+    {
+        spi_writew(color);
+    }    
+}
+
+/*-------------------------------------------------------------------*/
+/*  Put char                                                         */
+/*-------------------------------------------------------------------*/
+void tft_put_char(int x, int y, char chr, uint16_t color, uint16_t bgcolor)
+{
+    if (chr < 0x20 || chr > 0x7f)
+    {
+        chr = 0x3f;
+    }
+    else
+    {
+        chr = (chr < 0x60) ? chr - 0x20 : chr - 0x40;
+    }
+        
+    tft_set_window(x, y, x + 7, y + 6);
+    
+    for (int dy = 0; dy < 7; ++dy)
+    {
+        unsigned char img = chrimg[chr][dy];
+        for ( int dx = 0; dx < 8; ++dx)
+        {
+            if (img & 0x80)
+            {
+                spi_writew(color);
+            }
+            else
+            {
+                spi_writew(bgcolor);                
+            }
+            img <<= 1;
+        }
+    }    
+    
+}
+ 
+/*-------------------------------------------------------------------*/
+/*  Text out                                                         */
+/*-------------------------------------------------------------------*/
+void tft_text(int x, int y, char *text, uint16_t color, uint16_t bgcolor)
+{
+    while (*text != 0)
+    {
+        tft_put_char(x, y, *text, color, bgcolor);
+        x += 8;
+        text++;
+    }
+}
+
+/*-------------------------------------------------------------------*/
+/*  Horizontal Line                                                        */
+/*-------------------------------------------------------------------*/
+void tft_hline(int x1, int y, int x2, uint16_t color)
+{
+    tft_set_window(x1, y, x2, y);
+    
+    for (;x1 < x2; ++x1)
+    {
+        spi_writew(color);
+    }
+}
+
+/*-------------------------------------------------------------------*/
+/*  Vertical Line                                                        */
+/*-------------------------------------------------------------------*/
+void tft_vline(int x, int y1, int y2, uint16_t color)
+{
+    tft_set_window(x, y1, x, y2);
+    
+    for (;y1 < y2; ++y1)
+    {
+        spi_writew(color);
+    }
+}
+
+/*-------------------------------------------------------------------*/
+/*  Box                                                              */
+/*-------------------------------------------------------------------*/
+void tft_box(int x1, int y1, int x2, int y2, uint16_t color)
+{
+    tft_hline(x1, y1, x2, color);
+    tft_vline(x1, y1, y2, color);
+    tft_vline(x2, y1, y2, color);
+    tft_hline(x1, y2, x2, color);
+}
+
+/*-------------------------------------------------------------------*/
+/*  Box Fill                                                        */
+/*-------------------------------------------------------------------*/
+void tft_boxfill(int x1, int y1, int x2, int y2, uint16_t color)
+{
+    tft_set_window(x1, y1, x2, y2);
+    
+    for (int i = 0; i < (x2 - x1 + 1) * (y2 - y1 + 1); ++i)
+    {
+        spi_writew(color);
+    }
+}
+
+/*-------------------------------------------------------------------*/
+/*  Draw 4bit BMP                                                    */
+/*-------------------------------------------------------------------*/
+bool draw_bmp_4bpp(const unsigned char *imgdata, int x, int y)
+{
+    BITMAPFILEHEADER *bf = (BITMAPFILEHEADER *)imgdata;
+    BITMAPINFOHEADER *bi = (BITMAPINFOHEADER *)(imgdata + sizeof(BITMAPFILEHEADER));
+       
+    if (bi->biBitCount != 4)
+    {
+        return false;
+    }
+
+    unsigned char *pRGBPal = (unsigned char*)imgdata + sizeof(BITMAPFILEHEADER) + bi->biSize;
+    unsigned short palette[16];
+
+    for (int i = 0; pRGBPal < imgdata + bf->bfOffBits && i < 16; ++i)
+    {
+        unsigned short r,g,b;  
+        b = *pRGBPal++ >> 3;
+        g = *pRGBPal++ >> 2;
+        r = *pRGBPal++ >> 3;
+        pRGBPal++;
+        palette[i] = ((g & 7) << 13) | (b << 8) | (r << 3) | (g >> 3);
+    }
+
+    unsigned short HLine[320];
+    int linesize = (bi->biWidth / 2 + 3) & 0xfffc;
+        
+    tft_set_window(x, y, x + bi->biWidth - 1, y + bi->biHeight - 1);
+    
+    unsigned char *bmp;
+    
+    for (int y = bi->biHeight - 1; y >= 0; --y)
+    {
+        bmp = (unsigned char *)imgdata + bf->bfOffBits + y * linesize; 
+        
+        for (int x = 0; x < bi->biWidth; ++x)
+        {
+            char pal;
+            if (x & 1)
+            {
+                pal = *bmp & 0xf;
+                bmp++;
+            }
+            else
+            {
+                pal = *bmp >> 4;
+            }
+                
+            HLine[x] = palette[pal];
+        }
+    
+        HAL_SPI_Transmit(&SpiHandle, (uint8_t *)HLine, bi->biWidth * 2, 100);
+    }
+
+    return true;
+}
+  
+/*-------------------------------------------------------------------*/
+/*  Initialize TFT                                                   */
+/*-------------------------------------------------------------------*/
+void tft_init(void)
+{
+    spi_init();
+        
+    tft_reset();
+}
+
+
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 TFT/tft.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TFT/tft.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,273 @@
+/*===================================================================*/
+/*                                                                   */
+/*  tft.h : TFT(ILI9341) function header                             */
+/*                                                                   */
+/*  2016/1/20  Racoon                                                */
+/*                                                                   */
+/*===================================================================*/
+
+#ifndef TFT_H
+#define TFT_H
+
+#include "stm32f4xx_hal.h"
+#include "spidma.h"
+
+#define TFT_WIDTH   320
+#define TFT_HEIGHT  240
+
+#define TFT_WHITE 0xFFFF
+#define TFT_WHITESMOKE 0xBFFF
+#define TFT_GHOSTWHITE 0xDFFF
+#define TFT_ALICEBLUE 0xDFF7
+#define TFT_LAVENDAR 0x5FEF
+#define TFT_AZURE 0xFFF7
+#define TFT_LIGHTCYAN 0xFFE7
+#define TFT_MINTCREAM 0xFFFF
+#define TFT_HONEYDEW 0xFEF7
+#define TFT_IVORY 0xFEFF
+#define TFT_BEIGE 0xBCFF
+#define TFT_LIGHTYELLOW 0xFCFF
+#define TFT_LIGHTGOLDENRODYELLOW 0xFAFF
+#define TFT_LEMONCHIFFON 0xFAFF
+#define TFT_FLORALWHITE 0xFEFF
+#define TFT_OLDLACE 0xBDFF
+#define TFT_CORNSILK 0xDCFF
+#define TFT_PAPAYAWHITE 0x9BFF
+#define TFT_BLANCHEDALMOND 0x7AFF
+#define TFT_BISQUE 0x39FF
+#define TFT_SNOW 0xFFFF
+#define TFT_LINEN 0x9DFF
+#define TFT_ANTIQUEWHITE 0x7BFF
+#define TFT_SEASHELL 0xBEFF
+#define TFT_LAVENDERBLUSH 0x9FFF
+#define TFT_MISTYROSE 0x3CFF
+#define TFT_GAINSBORO 0xFCE6
+#define TFT_LIGHTGRAY 0xBAD6
+#define TFT_LIGHTSTEELBLUE 0x3CB6
+#define TFT_LIGHTBLUE 0xDDB6
+#define TFT_LIGHTSKYBLUE 0x9F8E
+#define TFT_POWDERBLUE 0x1DB7
+#define TFT_PALETURQUOISE 0x9EB7
+#define TFT_SKYBLUE 0x9D8E
+#define TFT_MEDIUMAQUAMARINE 0x756E
+#define TFT_AQUAMARINE 0xFB87
+#define TFT_PALEGREEN 0xF39F
+#define TFT_LIGHTGREEN 0x9297
+#define TFT_KHAKI 0x52F7
+#define TFT_PALEGOLDENROD 0x55F7
+#define TFT_MOCCASIN 0x37FF
+#define TFT_NAVAJOWHITE 0x16FF
+#define TFT_PEACHPUFF 0xF7FE
+#define TFT_WHEAT 0x16FF
+#define TFT_PINK 0x19FE
+#define TFT_LIGHTPINK 0xD8FD
+#define TFT_THISTLE 0x1BDE
+#define TFT_PLUM 0x1CE5
+#define TFT_SILVER 0x18C6
+#define TFT_DARKGRAY 0x55AD
+#define TFT_LIGHTSLATEGRAY 0x537C
+#define TFT_SLATEGRAY 0x1274
+#define TFT_SLATEBLUE 0xFA6A
+#define TFT_STEELBLUE 0x374C
+#define TFT_MEDIUMSLATEBLUE 0x5E7B
+#define TFT_ROYALBLUE 0x5C43
+#define TFT_BLUE 0x1F00
+#define TFT_DODGERBLUE 0x9F24
+#define TFT_CORNFLOWERBLUE 0xBE6C
+#define TFT_DEEPSKYBLUE 0x1F06
+#define TFT_CYAN 0xFF07
+#define TFT_AQUA 0xFF07
+#define TFT_TURQUOISE 0x1A47
+#define TFT_MEDIUMTURQUOISE 0x9A4E
+#define TFT_DARKTURQUOISE 0x9A06
+#define TFT_LIGHTSEAGREEN 0xB525
+#define TFT_MEDIUMSPRINGGREEN 0xF307
+#define TFT_SPRINGGREEN 0xF007
+#define TFT_LIME 0xE007
+#define TFT_LIMEGREEN 0x6636
+#define TFT_YELLOWGREEN 0x669E
+#define TFT_LAWNGREEN 0xE087
+#define TFT_CHARTREUSE 0xE087
+#define TFT_GREENYELLOW 0xE6B7
+#define TFT_YELLOW 0xE0FF
+#define TFT_GOLD 0xC0FE
+#define TFT_ORANGE 0x20FD
+#define TFT_DARKORANGE 0x60FC
+#define TFT_GOLDENROD 0x24DD
+#define TFT_BURLYWOOD 0xD1E5
+#define TFT_TAN 0xB2D5
+#define TFT_SANDYBROWN 0x2CFD
+#define TFT_DARKSALMON 0xCFEC
+#define TFT_LIGHTCORAL 0x10F4
+#define TFT_SALMON 0xEFC
+#define TFT_LIGHTSALMON 0xFFD
+#define TFT_CORAL 0xAFC
+#define TFT_TOMATO 0x29FB
+#define TFT_ORANGERED 0x20FA
+#define TFT_RED 0xF8
+#define TFT_DEEPPINK 0xB2F8
+#define TFT_HOTPINK 0x57FB
+#define TFT_PALEVIOLETRED 0x92DB
+#define TFT_VIOLET 0x3EF4
+#define TFT_ORCHID 0x9BDB
+#define TFT_MAGENTA 0x1FF8
+#define TFT_FUCHSIA 0x1FF8
+#define TFT_MEDIUMORCHID 0xBABA
+#define TFT_DARKORCHID 0xBA99
+#define TFT_DARKVIOLET 0x1A98
+#define TFT_BLUEVIOLET 0x7C89
+#define TFT_MEDIUMPURPLE 0x9B93
+#define TFT_GRAY 0x1084
+#define TFT_MEDIUMBLUE 0x1A00
+#define TFT_DARKCYAN 0x7104
+#define TFT_CADETBLUE 0x1465
+#define TFT_DARKSEAGREEN 0xF295
+#define TFT_MEDIUMSEAGREEN 0xAE45
+#define TFT_TEAL 0x1004
+#define TFT_FORESTGREEN 0x6424
+#define TFT_SEAGREEN 0x6B34
+#define TFT_DARKKHAKI 0xCDC5
+#define TFT_PERU 0x28D4
+#define TFT_CRIMSON 0xA8E0
+#define TFT_INDIANRED 0xECD2
+#define TFT_ROSYBROWN 0x92C4
+#define TFT_MEDIUMVIOLETRED 0xB1C8
+#define TFT_DIMGRAY 0x4D6B
+#define TFT_BLACK 0x0
+#define TFT_MIDNIGHTBLUE 0xCE18
+#define TFT_DARKSLATEBLUE 0xF149
+#define TFT_DARKBLUE 0x1100
+#define TFT_NAVY 0x1000
+#define TFT_DARKSLATEGRAY 0x8A32
+#define TFT_GREEN 0x4
+#define TFT_DARKGREEN 0x2003
+#define TFT_DARKOLIVEGREEN 0x665B
+#define TFT_OLIVEDRAB 0x846C
+#define TFT_OLIVE 0x84
+#define TFT_DARKGOLDENROD 0x41BC
+#define TFT_CHOCOLATE 0x44D3
+#define TFT_SIENNA 0xA6A2
+#define TFT_SADDLEBROWN 0x228A
+#define TFT_FIREBRICK 0x24B1
+#define TFT_BROWN 0x65A9
+#define TFT_MAROON 0x80
+#define TFT_DARKRED 0x88
+#define TFT_DARKMAGENTA 0x1188
+#define TFT_PURPLE 0x1080
+#define TFT_INDIGO 0x1048
+
+const unsigned char chrimg[][7] =
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 20h SP
+  0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, // 21h !
+  0x00, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, // 22h "
+  0x00, 0x28, 0x7c, 0x28, 0x7c, 0x28, 0x00, // 23h #
+  0x10, 0x3c, 0x50, 0x38, 0x14, 0x78, 0x10, // 24h $
+  0x00, 0x32, 0x54, 0x68, 0x16, 0x2a, 0x4c, // 25h %
+  0x18, 0x24, 0x14, 0x38, 0x4e, 0x44, 0x3a, // 26h &
+  0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, // 27h '
+  0x04, 0x08, 0x10, 0x10, 0x10, 0x08, 0x04, // 28h (
+  0x40, 0x20, 0x10, 0x10, 0x10, 0x20, 0x40, // 29h )
+  0x10, 0x54, 0x38, 0xfe, 0x38, 0x54, 0x10, // 2Ah *
+  0x10, 0x10, 0x10, 0xfe, 0x10, 0x10, 0x10, // 2Bh +
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, // 2Ch ,
+  0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, // 2Dh -
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, // 2Eh .
+  0x00, 0x08, 0x08, 0x10, 0x20, 0x20, 0x00, // 2Fh /
+
+  0x38, 0x44, 0x4c, 0x54, 0x64, 0x44, 0x38, // 30h 0
+  0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x38, // 31h 1
+  0x38, 0x44, 0x04, 0x18, 0x20, 0x40, 0x7c, // 32h 2
+  0x38, 0x44, 0x04, 0x18, 0x04, 0x44, 0x38, // 33h 3
+  0x08, 0x18, 0x28, 0x48, 0x7c, 0x08, 0x08, // 34h 4
+  0x7c, 0x40, 0x78, 0x04, 0x04, 0x44, 0x38, // 35h 5
+  0x38, 0x44, 0x40, 0x78, 0x44, 0x44, 0x38, // 36h 6
+  0x7c, 0x44, 0x04, 0x08, 0x08, 0x10, 0x10, // 37h 7
+  0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, // 38h 8
+  0x38, 0x44, 0x44, 0x3c, 0x04, 0x44, 0x38, // 39h 9
+  0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, // 3Ah :
+  0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x20, // 3Bh ;
+  0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, // 3Ch <
+  0x00, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x00, // 3Dh =
+  0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, // 3Eh >
+  0x38, 0x44, 0x44, 0x08, 0x10, 0x00, 0x10, // 3Fh >
+
+  0x7c, 0x82, 0xba, 0xa6, 0xbc, 0x80, 0x7c, // 40h @
+  0x38, 0x44, 0x44, 0x44, 0x7c, 0x44, 0x44, // 41h A
+  0x78, 0x44, 0x44, 0x78, 0x44, 0x44, 0x78, // 42h B
+  0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, // 43h C
+  0x70, 0x48, 0x44, 0x44, 0x44, 0x48, 0x70, // 44h D
+  0x7c, 0x40, 0x40, 0x78, 0x40, 0x40, 0x7c, // 45h E
+  0x7c, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, // 46h F
+  0x38, 0x44, 0x40, 0x4c, 0x44, 0x44, 0x38, // 47h G
+  0x44, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x44, // 48h H
+  0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, // 49h I
+  0x3c, 0x08, 0x08, 0x08, 0x08, 0x48, 0x30, // 4Ah J
+  0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, // 4Bh K
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7c, // 4CH L
+  0x44, 0x6c, 0x54, 0x54, 0x44, 0x44, 0x44, // 4DH M
+  0x44, 0x64, 0x54, 0x54, 0x4c, 0x44, 0x44, // 4EH N
+  0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, // 4FH O
+
+  0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, // 50h P
+  0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, // 51h Q
+  0x78, 0x44, 0x44, 0x78, 0x44, 0x44, 0x44, // 52h R
+  0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, // 53h S
+  0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, // 54h T
+  0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, // 55h U
+  0x44, 0x44, 0x44, 0x44, 0x28, 0x28, 0x10, // 56h V
+  0x44, 0x44, 0x54, 0x54, 0x54, 0x54, 0x28, // 57h W
+  0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, // 58h X
+  0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, // 59h Y
+  0x7c, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7c, // 5Ah Z
+  0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1c, // 5Bh [
+  0x00, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, // 5Ch back slash
+  0x70, 0x10, 0x10, 0x10, 0x10, 0x10, 0x70, // 5Dh ]
+  0x00, 0x10, 0x28, 0x00, 0x00, 0x00, 0x00, // 5Eh ^
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c  // 5Fh _
+};
+
+#pragma pack(2)
+typedef struct tagBITMAPFILEHEADER {
+  unsigned short bfType;
+  unsigned long  bfSize;
+  unsigned short bfReserved1;
+  unsigned short bfReserved2;
+  unsigned long  bfOffBits;
+} BITMAPFILEHEADER;
+
+typedef struct tagBITMAPINFOHEADER{
+    unsigned long  biSize;
+    long           biWidth;
+    long           biHeight;
+    unsigned short biPlanes;
+    unsigned short biBitCount;
+    unsigned long  biCompression;
+    unsigned long  biSizeImage;
+    long           biXPixPerMeter;
+    long           biYPixPerMeter;
+    unsigned long  biClrUsed;
+    unsigned long  biClrImporant;
+} BITMAPINFOHEADER;
+#pragma pack()
+
+#pragma pack(1)
+typedef struct tagBMP24{
+    unsigned char B;
+    unsigned char G;
+    unsigned char R;
+} BMP24;
+#pragma pack()
+
+void tft_init();
+void tft_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
+void tft_clear(uint16_t color);
+void tft_put_char(int x, int y, char chr, uint16_t color, uint16_t bgcolor);
+void tft_text(int x, int y, char *text, uint16_t color, uint16_t bgcolor);
+void tft_hline(int x1, int y, int x2, uint16_t color);
+void tft_vline(int x, int y1, int y2, uint16_t color);
+void tft_box(int x1, int y1, int x2, int y2, uint16_t color);
+void tft_boxfill(int x1, int y1, int x2, int y2, uint16_t color);
+bool draw_bmp_4bpp(const unsigned char *imgdata, int x, int y);
+
+#endif
+
diff -r 000000000000 -r 3dac1f1bc9e0 USBHost/IUSBEnumerator.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/IUSBEnumerator.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,37 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IUSBENUMERATOR_H_
+#define IUSBENUMERATOR_H_
+
+#include "stdint.h"
+#include "USBEndpoint.h"
+
+/*
+Generic interface to implement for "smart" USB enumeration
+*/
+
+class IUSBEnumerator
+{
+public:
+    virtual void setVidPid(uint16_t vid, uint16_t pid) = 0;
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) = 0; //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) = 0; //Must return true if the endpoint will be used
+};
+
+#endif /*IUSBENUMERATOR_H_*/
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 USBHost/USBDeviceConnected.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBDeviceConnected.cpp	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,90 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBDeviceConnected.h"
+#include "dbg.h"
+
+USBDeviceConnected::USBDeviceConnected() {
+    init();
+}
+
+void USBDeviceConnected::init() {
+    port = 0;
+    vid = 0;
+    pid = 0;
+    nb_interf = 0;
+    enumerated = false;
+    device_class = 0;
+    device_subclass = 0;
+    proto = 0;
+    lowSpeed = false;
+    hub_parent = NULL;
+}
+
+bool USBDeviceConnected::addInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) {
+    USB_DBG("intf_nb=%d", intf_nb);
+    if (intf.count(intf_nb) > 0) {
+        return false;
+    }
+    intf[intf_nb] = new INTERFACE(intf_class, intf_subclass, intf_protocol);
+    return true;
+}
+
+bool USBDeviceConnected::addEndpoint(uint8_t intf_nb, USBEndpoint * ept) {
+    if (intf.count(intf_nb) > 0) {
+        intf[intf_nb]->ep.push_back(ept);
+        return true;
+    }
+    return false;
+}
+
+void USBDeviceConnected::init(USBDeviceConnected* parent, uint8_t port_, bool lowSpeed_) {
+    USB_DBG("init dev: %p", this);
+    init();
+    hub_parent = parent;
+    port = port_;
+    lowSpeed = lowSpeed_;
+}
+
+void USBDeviceConnected::disconnect() {
+    //for(int i = 0; i < MAX_INTF; i++) {
+    //    intf[i].detach.call();
+    //}
+    //init();
+}
+
+
+USBEndpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index) {
+    USB_DBG("intf_nb=%d", intf_nb);
+    USB_TEST_ASSERT(intf.count(intf_nb) > 0);
+    INTERFACE* inter = intf[intf_nb];
+    for (int i = 0; i < inter->ep.size(); i++) {
+        if ((inter->ep[i]->getType() == type) && (inter->ep[i]->getDir() == dir)) {
+            if(index) {
+                index--;
+            } else {
+                return inter->ep[i];
+            }
+        }
+    }
+    return NULL;
+}
+
+USBEndpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, uint8_t index) {
+    USB_TEST_ASSERT(intf.count(intf_nb) > 0);
+    return intf[intf_nb]->ep[index];
+}
+
diff -r 000000000000 -r 3dac1f1bc9e0 USBHost/USBDeviceConnected.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBDeviceConnected.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,134 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "USBEndpoint.h"
+#include "USBHostConf.h"
+#include "myvector.h"
+#include "mymap.h"
+
+class USBEndpoint;
+
+struct INTERFACE {
+    INTERFACE(uint8_t _class, uint8_t _subclass, uint8_t _protocol) {
+        intf_class = _class;
+        intf_subclass = _subclass;
+        intf_protocol = _protocol;
+    }
+    uint8_t intf_class;
+    uint8_t intf_subclass;
+    uint8_t intf_protocol;
+    myvector<USBEndpoint*>ep; 
+}; 
+
+/**
+* USBDeviceConnected class
+*/
+class USBDeviceConnected {
+public:
+
+    /**
+    * Constructor
+    */
+    USBDeviceConnected();
+
+    /**
+    * Attach an USBEndpoint to this device
+    *
+    * @param intf_nb interface number
+    * @param ep pointeur on the USBEndpoint which will be attached
+    * @returns true if successful, false otherwise
+    */
+    bool addEndpoint(uint8_t intf_nb, USBEndpoint * ep);
+
+    /**
+    * Retrieve an USBEndpoint by its TYPE and DIRECTION
+    *
+    * @param intf_nb the interface on which to lookup the USBEndpoint
+    * @param type type of the USBEndpoint looked for
+    * @param dir direction of the USBEndpoint looked for
+    * @param index the index of the USBEndpoint whitin the interface
+    * @returns pointer on the USBEndpoint if found, NULL otherwise
+    */
+    USBEndpoint * getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index = 0);
+
+    /**
+    * Retrieve an USBEndpoint by its index
+    *
+    * @param intf_nb interface number
+    * @param index index of the USBEndpoint
+    * @returns pointer on the USBEndpoint if found, NULL otherwise
+    */
+    USBEndpoint * getEndpoint(uint8_t intf_nb, uint8_t index);
+
+    /**
+    * Add a new interface to this device
+    *
+    * @param intf_nb interface number
+    * @param intf_class interface class
+    * @param intf_subclass interface subclass
+    * @param intf_protocol interface protocol
+    * @returns true if successful, false otherwise
+    */
+    bool addInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol);
+
+    /**
+    * Disconnect the device by calling a callback function registered by a driver
+    */
+    void disconnect();
+
+    void init(USBDeviceConnected* parent, uint8_t _port, bool _lowSpeed);
+    void setAddress(uint8_t addr_) { addr = addr_; };
+    void setVid(uint16_t vid_) { vid = vid_; };
+    void setPid(uint16_t pid_) { pid = pid_; };
+    void setClass(uint8_t device_class_) { device_class = device_class_; }
+    void setSubClass(uint8_t device_subclass_) { device_subclass = device_subclass_; };
+    void setProtocol(uint8_t pr) { proto = pr; };
+    void setEnumerated() { enumerated = true; };
+    void setNbIntf(uint8_t nb_intf) {nb_interf = nb_intf; };
+    void setSpeed(bool _lowSpeed) { lowSpeed = _lowSpeed; }
+    void setName(const char * name_, uint8_t intf_nb) { return; };
+    void setEpCtl(USBEndpoint* ep) { ep_ctl = ep; }
+
+    static int getNewAddress() {
+        static int addr = 1;
+        return addr++;
+    }
+    uint8_t getAddress() { return addr; };
+    uint16_t getVid() { return vid; };
+    uint16_t getPid() { return pid; };
+    uint8_t getClass() { return device_class; };
+    bool getSpeed() { return lowSpeed; }
+    bool isEnumerated() { return enumerated; };
+    USBEndpoint* getEpCtl() { return ep_ctl; }
+
+private:
+    USBDeviceConnected* hub_parent;
+    mymap<int,INTERFACE*>intf;
+    uint8_t port;
+    uint16_t vid;
+    uint16_t pid;
+    uint8_t addr;
+    uint8_t device_class;
+    uint8_t device_subclass;
+    uint8_t proto;
+    bool lowSpeed;
+    bool enumerated;
+    uint8_t nb_interf;
+    USBEndpoint* ep_ctl;
+    void init();
+};
+
diff -r 000000000000 -r 3dac1f1bc9e0 USBHost/USBEndpoint.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBEndpoint.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,168 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+#pragma once
+#include "FunctionPointer.h"
+#include "USBHostTypes.h"
+#include "USBDeviceConnected.h"
+
+class USBDeviceConnected;
+
+/**
+* USBEndpoint class
+*/
+class USBEndpoint {
+public:
+    /**
+    * Constructor
+    */
+    USBEndpoint(USBDeviceConnected* _dev) {
+        init(CONTROL_ENDPOINT, IN, 8, 0);
+        dev = _dev;
+        pData = NULL;
+    }
+
+    /**
+    * Initialize an endpoint
+    *
+    * @param type endpoint type
+    * @param dir endpoint direction
+    * @param size endpoint size
+    * @param ep_number endpoint number
+    */
+    void init(ENDPOINT_TYPE _type, ENDPOINT_DIRECTION _dir, uint32_t size, uint8_t ep_number) {
+        setState(USB_TYPE_FREE);
+        setType(_type);
+        dir = _dir;
+        MaxPacketSize = size;
+        address = ep_number;
+        data01_toggle = DATA0;
+    }
+
+    void ohci_init(uint8_t frameCount, uint8_t queueLimit) {
+        ohci.frameCount = frameCount;
+        ohci.queueLimit = queueLimit;
+    }
+
+    /**
+     *  Attach a member function to call when a transfer is finished
+     *
+     *  @param tptr pointer to the object to call the member function on
+     *  @param mptr pointer to the member function to be called
+     */
+    template<typename T>
+    inline void attach(T* tptr, void (T::*mptr)(void)) {
+        if((mptr != NULL) && (tptr != NULL)) {
+            rx.attach(tptr, mptr);
+        }
+    }
+
+    /**
+     * Attach a callback called when a transfer is finished
+     *
+     * @param fptr function pointer
+     */
+    inline void attach(void (*fptr)(void)) {
+        if(fptr != NULL) {
+            rx.attach(fptr);
+        }
+    }
+
+    /**
+    * Call the handler associted to the end of a transfer
+    */
+    inline void call() {
+        rx.call();
+    };
+
+    void setType(ENDPOINT_TYPE _type) { type = _type; }
+    void setState(USB_TYPE st) { state = st; }
+    void setDevice(USBDeviceConnected* _dev) { dev = _dev; }
+    void setBuffer(uint8_t* buf, int size) { buf_start = buf, buf_size = size; }
+    void setLengthTransferred(int len) { transferred = len; };
+    void setAddress(int addr) { address = addr; }
+    void setSize(int size) { MaxPacketSize = size; }
+    void setData01(uint8_t data01) { data01_toggle = data01; }
+    void setNextEndpoint(USBEndpoint* ep) { nextEp = ep; };
+    template<class T>
+    void setHALData(T data) { pData = data; }
+
+    USBDeviceConnected* getDevice() { return dev; }
+    ENDPOINT_TYPE getType() { return type; };
+    USB_TYPE getState() { return state; }
+    int getLengthTransferred() { return transferred; }
+    uint8_t *getBufStart() { return buf_start; }
+    int getBufSize() { return buf_size; }
+    uint8_t getAddress(){ return address; };
+    int getSize() { return MaxPacketSize; }
+    ENDPOINT_DIRECTION getDir() { return dir; }
+    uint8_t getData01() { return data01_toggle; }
+    void toggleData01() {
+        data01_toggle = (data01_toggle == DATA0) ? DATA1 : DATA0;
+    }
+    USBEndpoint* nextEndpoint() { return nextEp; };
+    template<class T>
+    T getHALData() { return reinterpret_cast<T>(pData); }
+
+    struct {
+        uint8_t queueLimit;
+        uint8_t frameCount; // 1-8
+    } ohci;
+private:
+    USBEndpoint(){}
+    ENDPOINT_TYPE type;
+    USB_TYPE state;
+    ENDPOINT_DIRECTION dir;
+    USBDeviceConnected* dev;
+    uint8_t data01_toggle; // DATA0,DATA1
+    uint8_t address;
+    int transferred;
+    uint8_t * buf_start;
+    int buf_size;
+    FunctionPointer rx;
+    int MaxPacketSize;
+    USBEndpoint* nextEp;
+    void* pData;
+};
+
+class EndpointQueue {
+public:
+    EndpointQueue():head(NULL),tail(NULL) {}
+    void push(USBEndpoint* ep) {
+        if (head) {
+            tail->setNextEndpoint(ep);
+        } else {
+            head = ep;
+        }
+        tail = ep;
+        ep->setNextEndpoint(NULL);
+    }
+    USBEndpoint* pop() {
+        USBEndpoint* ep = head;
+        if (ep) {
+            head = ep->nextEndpoint();
+        }
+        return ep;
+    }
+    bool empty() { return head == NULL; }
+
+private:
+    USBEndpoint* head;
+    USBEndpoint* tail;
+};
+
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 USBHost/USBHALHost.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHALHost.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,35 @@
+#include "mbed.h"
+
+struct SETUP_PACKET {
+    uint8_t bmRequestType;
+    uint8_t bRequest;
+    uint16_t wValue;
+    uint16_t wIndex;
+    uint16_t wLength;
+    SETUP_PACKET(uint8_t RequestType, uint8_t Request, uint16_t Value, uint16_t Index, uint16_t Length) {
+        bmRequestType = RequestType;
+        bRequest = Request;
+        wValue = Value;
+        wIndex = Index;
+        wLength = Length;
+    }
+};
+
+#if defined(TARGET_NUCLEO_F401RE)||defined(TARGET_NUCLEO_F411RE)||defined(TARGET_NUCLEO_F446RE)
+#include "USBHALHost_F401RE.h"
+#elif defined(TARGET_KL46Z)||defined(TARGET_KL25Z)||defined(TARGET_K64F)
+#include "USBHALHost_KL46Z.h"
+#elif defined(TARGET_LPC4088)||defined(TARGET_LPC1768)
+#include "USBHALHost_LPC4088.h"
+#else
+#error "target error"
+#endif
+
+#ifndef  CTASSERT
+template <bool>struct CtAssert;
+template <>struct CtAssert<true> {};
+#define CTASSERT(A) CtAssert<A>();
+#endif // CTASSERT
+
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 USBHost/USBHALHost2_F401RE.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHALHost2_F401RE.cpp	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,540 @@
+#if defined(TARGET_NUCLEO_F401RE)||defined(TARGET_NUCLEO_F411RE)||defined(TARGET_NUCLEO_F446RE)
+#include "USBHALHost.h"
+
+// usbh_conf.c
+HCD_HandleTypeDef hhcd_USB_OTG_FS;
+
+static void HAL_HCD_IRQHandler(HCD_HandleTypeDef *hhcd);
+
+// stm32f4xx_it.c
+extern "C" {
+void OTG_FS_IRQHandler(void)
+{
+  HAL_NVIC_ClearPendingIRQ(OTG_FS_IRQn);
+  HAL_HCD_IRQHandler(&hhcd_USB_OTG_FS);
+}
+}
+
+// stm32f4xx_hal_hcd.c
+static void HCD_HC_IN_IRQHandler(HCD_HandleTypeDef *hhcd, uint8_t chnum);
+static void HCD_HC_OUT_IRQHandler(HCD_HandleTypeDef *hhcd, uint8_t chnum); 
+static void HCD_RXQLVL_IRQHandler(HCD_HandleTypeDef *hhcd);
+static void HCD_Port_IRQHandler(HCD_HandleTypeDef *hhcd);
+
+/**
+  * @brief  This function handles HCD interrupt request.
+  * @param  hhcd: HCD handle
+  * @retval none
+  */
+static void HAL_HCD_IRQHandler(HCD_HandleTypeDef *hhcd)
+{
+  USB_OTG_GlobalTypeDef *USBx = hhcd->Instance;
+  uint32_t i = 0 , interrupt = 0;
+  
+  /* ensure that we are in device mode */
+  if (USB_GetMode(hhcd->Instance) == USB_OTG_MODE_HOST)
+  {
+    /* avoid spurious interrupt */
+    if(__HAL_HCD_IS_INVALID_INTERRUPT(hhcd)) 
+    {
+      return;
+    }
+    
+    if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_PXFR_INCOMPISOOUT))
+    {
+     /* incorrect mode, acknowledge the interrupt */
+      __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_PXFR_INCOMPISOOUT);
+    }
+    
+    if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_IISOIXFR))
+    {
+     /* incorrect mode, acknowledge the interrupt */
+      __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_IISOIXFR);
+    }
+
+    if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_PTXFE))
+    {
+     /* incorrect mode, acknowledge the interrupt */
+      __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_PTXFE);
+    }   
+    
+    if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_MMIS))
+    {
+     /* incorrect mode, acknowledge the interrupt */
+      __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_MMIS);
+    }     
+    
+    /* Handle Host Disconnect Interrupts */
+    if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_DISCINT))
+    {
+      
+      /* Cleanup HPRT */
+      USBx_HPRT0 &= ~(USB_OTG_HPRT_PENA | USB_OTG_HPRT_PCDET |\
+        USB_OTG_HPRT_PENCHNG | USB_OTG_HPRT_POCCHNG );
+       
+      /* Handle Host Port Interrupts */
+      HAL_HCD_Disconnect_Callback(hhcd);
+       USB_InitFSLSPClkSel(hhcd->Instance ,HCFG_48_MHZ );
+      __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_DISCINT);
+    }
+    
+    /* Handle Host Port Interrupts */
+    if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_HPRTINT))
+    {
+      HCD_Port_IRQHandler (hhcd);
+    }
+    
+    /* Handle Host SOF Interrupts */
+    if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_SOF))
+    {
+      HAL_HCD_SOF_Callback(hhcd);
+      __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_SOF);
+    }
+          
+    /* Handle Host channel Interrupts */
+    if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_HCINT))
+    {
+      
+      interrupt = USB_HC_ReadInterrupt(hhcd->Instance);
+      for (i = 0; i < hhcd->Init.Host_channels ; i++)
+      {
+        if (interrupt & (1 << i))
+        {
+          if ((USBx_HC(i)->HCCHAR) &  USB_OTG_HCCHAR_EPDIR)
+          {
+            HCD_HC_IN_IRQHandler (hhcd, i);
+          }
+          else
+          {
+            HCD_HC_OUT_IRQHandler (hhcd, i);
+          }
+        }
+      }
+      __HAL_HCD_CLEAR_FLAG(hhcd, USB_OTG_GINTSTS_HCINT);
+    } 
+    
+        /* Handle Rx Queue Level Interrupts */
+    if(__HAL_HCD_GET_FLAG(hhcd, USB_OTG_GINTSTS_RXFLVL))
+    {
+      USB_MASK_INTERRUPT(hhcd->Instance, USB_OTG_GINTSTS_RXFLVL);
+      
+      HCD_RXQLVL_IRQHandler (hhcd);
+      
+      USB_UNMASK_INTERRUPT(hhcd->Instance, USB_OTG_GINTSTS_RXFLVL);
+    }
+    
+  }
+}
+/**
+  * @brief  This function handles Host Channel IN interrupt requests.
+  * @param  hhcd: HCD handle
+  * @param  chnum : Channel number
+  *         This parameter can be a value from 1 to 15
+  * @retval none
+  */
+static void HCD_HC_IN_IRQHandler   (HCD_HandleTypeDef *hhcd, uint8_t chnum)
+{
+  USB_OTG_GlobalTypeDef *USBx = hhcd->Instance;
+    
+  if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_AHBERR)
+  {
+    __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_AHBERR);
+    __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
+  }  
+  else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_ACK)
+  {
+    __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_ACK);
+  }
+  
+  else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_STALL)  
+  {
+    __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
+    hhcd->hc[chnum].state = HC_STALL;
+    __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);
+    __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_STALL);    
+    USB_HC_Halt(hhcd->Instance, chnum);    
+  }
+  else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_DTERR)
+  {
+    __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
+    USB_HC_Halt(hhcd->Instance, chnum);  
+    __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);    
+    hhcd->hc[chnum].state = HC_DATATGLERR;
+    __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_DTERR);
+  }    
+  
+  if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_FRMOR)
+  {
+    __HAL_HCD_UNMASK_HALT_HC_INT(chnum); 
+    USB_HC_Halt(hhcd->Instance, chnum);  
+    __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_FRMOR);
+  }
+  
+  else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_XFRC)
+  {
+    
+    if (hhcd->Init.dma_enable)
+    {
+      hhcd->hc[chnum].xfer_count = hhcd->hc[chnum].xfer_len - \
+                               (USBx_HC(chnum)->HCTSIZ & USB_OTG_HCTSIZ_XFRSIZ);
+    }
+    
+    hhcd->hc[chnum].state = HC_XFRC;
+    __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_XFRC);
+    
+    
+    if ((hhcd->hc[chnum].ep_type == EP_TYPE_CTRL)||
+        (hhcd->hc[chnum].ep_type == EP_TYPE_BULK))
+    {
+      __HAL_HCD_UNMASK_HALT_HC_INT(chnum); 
+      USB_HC_Halt(hhcd->Instance, chnum); 
+      __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);
+      
+    }
+    else if(hhcd->hc[chnum].ep_type == EP_TYPE_INTR)
+    {
+      USBx_HC(chnum)->HCCHAR |= USB_OTG_HCCHAR_ODDFRM;
+      __HAL_HCD_UNMASK_HALT_HC_INT(chnum); 
+      USB_HC_Halt(hhcd->Instance, chnum); 
+      __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);
+    }
+    else if(hhcd->hc[chnum].ep_type == EP_TYPE_ISOC)
+    {
+      USBx_HC(chnum)->HCCHAR |= USB_OTG_HCCHAR_ODDFRM;
+      hhcd->hc[chnum].urb_state = URB_DONE; 
+      HAL_HCD_HC_NotifyURBChange_Callback(hhcd, chnum, hhcd->hc[chnum].urb_state);
+    }
+    hhcd->hc[chnum].toggle_in ^= 1;
+    
+  }
+  else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_CHH)
+  {
+    __HAL_HCD_MASK_HALT_HC_INT(chnum); 
+    
+    if(hhcd->hc[chnum].state == HC_XFRC)
+    {
+      hhcd->hc[chnum].urb_state  = URB_DONE;      
+    }
+
+    else if (hhcd->hc[chnum].state == HC_NAK)
+    {
+      hhcd->hc[chnum].urb_state  = URB_DONE;
+    }
+    
+    else if (hhcd->hc[chnum].state == HC_STALL) 
+    {
+      hhcd->hc[chnum].urb_state  = URB_STALL;
+    }   
+    
+    else if (hhcd->hc[chnum].state == HC_XACTERR)
+    {
+        hhcd->hc[chnum].urb_state = URB_NOTREADY;
+    }
+
+    else if (hhcd->hc[chnum].state == HC_DATATGLERR)
+    {
+        hhcd->hc[chnum].urb_state = URB_ERROR;
+    }
+
+    __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_CHH);
+    HAL_HCD_HC_NotifyURBChange_Callback(hhcd, chnum, hhcd->hc[chnum].urb_state);
+  }  
+  
+  else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_TXERR)
+  {
+    __HAL_HCD_UNMASK_HALT_HC_INT(chnum); 
+     hhcd->hc[chnum].state = HC_XACTERR;
+     USB_HC_Halt(hhcd->Instance, chnum);     
+     __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_TXERR);
+  }
+  else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_NAK)
+  {  
+    if(hhcd->hc[chnum].ep_type == EP_TYPE_INTR)
+    {
+      __HAL_HCD_UNMASK_HALT_HC_INT(chnum); 
+      USB_HC_Halt(hhcd->Instance, chnum);  
+    }
+    else if (hhcd->hc[chnum].ep_type == EP_TYPE_CTRL)
+    {
+      /* re-activate the channel  */
+      USBx_HC(chnum)->HCCHAR &= ~USB_OTG_HCCHAR_CHDIS;         
+      USBx_HC(chnum)->HCCHAR |= USB_OTG_HCCHAR_CHENA;
+   
+    }
+    
+    else if (hhcd->hc[chnum].ep_type == EP_TYPE_BULK)
+    {
+      __HAL_HCD_UNMASK_HALT_HC_INT(chnum); 
+      USB_HC_Halt(hhcd->Instance, chnum); 
+    }
+
+    hhcd->hc[chnum].state = HC_NAK;
+     __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);
+  }
+}
+
+/**
+  * @brief  This function handles Host Channel OUT interrupt requests.
+  * @param  hhcd: HCD handle
+  * @param  chnum : Channel number
+  *         This parameter can be a value from 1 to 15
+  * @retval none
+  */
+static void HCD_HC_OUT_IRQHandler  (HCD_HandleTypeDef *hhcd, uint8_t chnum)
+{
+  USB_OTG_GlobalTypeDef *USBx = hhcd->Instance;
+  
+  if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_AHBERR)
+  {
+    __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_AHBERR);
+    __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
+  }  
+  else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_ACK)
+  {
+    __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_ACK);
+    
+    if( hhcd->hc[chnum].do_ping == 1)
+    {
+      hhcd->hc[chnum].state = HC_NYET;     
+      __HAL_HCD_UNMASK_HALT_HC_INT(chnum); 
+      USB_HC_Halt(hhcd->Instance, chnum); 
+      hhcd->hc[chnum].urb_state  = URB_NOTREADY;
+    }
+  }
+  
+  else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_NYET)
+  {
+    hhcd->hc[chnum].state = HC_NYET;
+    __HAL_HCD_UNMASK_HALT_HC_INT(chnum); 
+    USB_HC_Halt(hhcd->Instance, chnum);      
+    __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NYET);
+    
+  }  
+  
+  else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_FRMOR)
+  {
+    __HAL_HCD_UNMASK_HALT_HC_INT(chnum); 
+    USB_HC_Halt(hhcd->Instance, chnum);  
+    __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_FRMOR);
+  }
+  
+  else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_XFRC)
+  {
+    __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
+    USB_HC_Halt(hhcd->Instance, chnum);   
+    __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_XFRC);
+    hhcd->hc[chnum].state = HC_XFRC;
+
+  }  
+
+  else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_STALL)  
+  {
+    __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_STALL);  
+    __HAL_HCD_UNMASK_HALT_HC_INT(chnum);
+    USB_HC_Halt(hhcd->Instance, chnum);   
+    hhcd->hc[chnum].state = HC_STALL;    
+  }
+
+  else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_NAK)
+  {  
+    __HAL_HCD_UNMASK_HALT_HC_INT(chnum); 
+    USB_HC_Halt(hhcd->Instance, chnum);   
+    hhcd->hc[chnum].state = HC_NAK;
+    __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);
+  }
+
+  else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_TXERR)
+  {
+    __HAL_HCD_UNMASK_HALT_HC_INT(chnum); 
+    USB_HC_Halt(hhcd->Instance, chnum);      
+    hhcd->hc[chnum].state = HC_XACTERR;  
+     __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_TXERR);
+  }
+  
+  else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_DTERR)
+  {
+    __HAL_HCD_UNMASK_HALT_HC_INT(chnum); 
+    USB_HC_Halt(hhcd->Instance, chnum);      
+    __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);
+    __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_DTERR);    
+    hhcd->hc[chnum].state = HC_DATATGLERR;
+  }
+  
+  
+  else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_CHH)
+  {
+    __HAL_HCD_MASK_HALT_HC_INT(chnum); 
+    
+    if(hhcd->hc[chnum].state == HC_XFRC)
+    {
+      hhcd->hc[chnum].urb_state  = URB_DONE;
+      if (hhcd->hc[chnum].ep_type == EP_TYPE_BULK)
+      {
+        hhcd->hc[chnum].toggle_out ^= 1; 
+      }      
+    }
+    else if (hhcd->hc[chnum].state == HC_NAK) 
+    {
+      hhcd->hc[chnum].urb_state  = URB_NOTREADY;
+    }  
+    
+    else if (hhcd->hc[chnum].state == HC_NYET) 
+    {
+      hhcd->hc[chnum].urb_state  = URB_NOTREADY;
+      hhcd->hc[chnum].do_ping = 0;
+    }   
+    
+    else if (hhcd->hc[chnum].state == HC_STALL) 
+    {
+      hhcd->hc[chnum].urb_state  = URB_STALL;
+    } 
+    
+    else if(hhcd->hc[chnum].state == HC_XACTERR)
+    {
+      hhcd->hc[chnum].urb_state = URB_NOTREADY;
+    }
+    
+    else if (hhcd->hc[chnum].state == HC_DATATGLERR)
+    {
+      hhcd->hc[chnum].urb_state = URB_ERROR;
+    }
+
+    __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_CHH);
+    HAL_HCD_HC_NotifyURBChange_Callback(hhcd, chnum, hhcd->hc[chnum].urb_state);  
+  }
+} 
+
+/**
+  * @brief  This function handles Rx Queue Level interrupt requests.
+  * @param  hhcd: HCD handle
+  * @retval none
+  */
+static void HCD_RXQLVL_IRQHandler  (HCD_HandleTypeDef *hhcd)
+{
+  USB_OTG_GlobalTypeDef *USBx = hhcd->Instance;  
+  uint8_t                       channelnum =0;  
+  uint32_t                      pktsts;
+  uint32_t                      pktcnt; 
+  uint32_t                      temp = 0;
+  
+  temp = hhcd->Instance->GRXSTSP ;
+  channelnum = temp &  USB_OTG_GRXSTSP_EPNUM;  
+  pktsts = (temp &  USB_OTG_GRXSTSP_PKTSTS) >> 17;
+  pktcnt = (temp &  USB_OTG_GRXSTSP_BCNT) >> 4;
+    
+  switch (pktsts)
+  {
+  case GRXSTS_PKTSTS_IN:
+    /* Read the data into the host buffer. */
+    if ((pktcnt > 0) && (hhcd->hc[channelnum].xfer_buff != (void  *)0))
+    {  
+      
+      USB_ReadPacket(hhcd->Instance, hhcd->hc[channelnum].xfer_buff, pktcnt);
+     
+      /*manage multiple Xfer */
+      hhcd->hc[channelnum].xfer_buff += pktcnt;           
+      hhcd->hc[channelnum].xfer_count  += pktcnt;
+        
+      if((USBx_HC(channelnum)->HCTSIZ & USB_OTG_HCTSIZ_PKTCNT) > 0)
+      {
+        /* re-activate the channel when more packets are expected */
+        USBx_HC(channelnum)->HCCHAR &= ~USB_OTG_HCCHAR_CHDIS; 
+        USBx_HC(channelnum)->HCCHAR |= USB_OTG_HCCHAR_CHENA;
+        hhcd->hc[channelnum].toggle_in ^= 1;
+      }
+    }
+    break;
+
+  case GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
+    break;
+  case GRXSTS_PKTSTS_IN_XFER_COMP:
+  case GRXSTS_PKTSTS_CH_HALTED:
+  default:
+    break;
+  }
+}
+
+/**
+  * @brief  This function handles Host Port interrupt requests.
+  * @param  hhcd: HCD handle
+  * @retval none
+  */
+static void HCD_Port_IRQHandler  (HCD_HandleTypeDef *hhcd)
+{
+  USB_OTG_GlobalTypeDef *USBx = hhcd->Instance;  
+  __IO uint32_t hprt0, hprt0_dup;
+  
+  /* Handle Host Port Interrupts */
+  hprt0 = USBx_HPRT0;
+  hprt0_dup = USBx_HPRT0;
+  
+  hprt0_dup &= ~(USB_OTG_HPRT_PENA | USB_OTG_HPRT_PCDET |\
+                 USB_OTG_HPRT_PENCHNG | USB_OTG_HPRT_POCCHNG );
+  
+  /* Check wether Port Connect Detected */
+  if((hprt0 & USB_OTG_HPRT_PCDET) == USB_OTG_HPRT_PCDET)
+  {  
+    if((hprt0 & USB_OTG_HPRT_PCSTS) == USB_OTG_HPRT_PCSTS)
+    {
+      USB_MASK_INTERRUPT(hhcd->Instance, USB_OTG_GINTSTS_DISCINT);
+      HAL_HCD_Connect_Callback(hhcd);
+    }
+    hprt0_dup  |= USB_OTG_HPRT_PCDET;
+    
+  }
+  
+  /* Check whether Port Enable Changed */
+  if((hprt0 & USB_OTG_HPRT_PENCHNG) == USB_OTG_HPRT_PENCHNG)
+  {
+    hprt0_dup |= USB_OTG_HPRT_PENCHNG;
+    
+    if((hprt0 & USB_OTG_HPRT_PENA) == USB_OTG_HPRT_PENA)
+    {    
+      if(hhcd->Init.phy_itface  == USB_OTG_EMBEDDED_PHY)
+      {
+        if ((hprt0 & USB_OTG_HPRT_PSPD) == (HPRT0_PRTSPD_LOW_SPEED << 17))
+        {
+          USB_InitFSLSPClkSel(hhcd->Instance ,HCFG_6_MHZ );
+        }
+        else
+        {
+          USB_InitFSLSPClkSel(hhcd->Instance ,HCFG_48_MHZ );
+        }
+      }
+      else
+      {
+        if(hhcd->Init.speed == HCD_SPEED_FULL)
+        {
+          USBx_HOST->HFIR = (uint32_t)60000;
+        }
+      }
+      HAL_HCD_Connect_Callback(hhcd);
+      
+      if(hhcd->Init.speed == HCD_SPEED_HIGH)
+      {
+        USB_UNMASK_INTERRUPT(hhcd->Instance, USB_OTG_GINTSTS_DISCINT); 
+      }
+    }
+    else
+    {
+      /* Cleanup HPRT */
+      USBx_HPRT0 &= ~(USB_OTG_HPRT_PENA | USB_OTG_HPRT_PCDET |\
+        USB_OTG_HPRT_PENCHNG | USB_OTG_HPRT_POCCHNG );
+      
+      USB_UNMASK_INTERRUPT(hhcd->Instance, USB_OTG_GINTSTS_DISCINT); 
+    }    
+  }
+  
+  /* Check For an overcurrent */
+  if((hprt0 & USB_OTG_HPRT_POCCHNG) == USB_OTG_HPRT_POCCHNG)
+  {
+    hprt0_dup |= USB_OTG_HPRT_POCCHNG;
+  }
+
+  /* Clear Port Interrupts */
+  USBx_HPRT0 = hprt0_dup;
+}
+
+#endif
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 USBHost/USBHALHost_F401RE.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHALHost_F401RE.cpp	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,534 @@
+#if defined(TARGET_NUCLEO_F401RE)||defined(TARGET_NUCLEO_F411RE)||defined(TARGET_NUCLEO_F446RE)
+#include "USBHALHost.h"
+#include <algorithm>
+
+#ifdef _USB_DBG
+extern RawSerial pc;
+//RawSerial pc(USBTX,USBRX);
+#include "mydebug.h"
+#define USB_DBG(...) do{pc.printf("[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);pc.printf(__VA_ARGS__);pc.puts("\n");} while(0);
+#define USB_DBG_HEX(A,B) debug_hex<RawSerial>(pc,A,B)
+
+#else
+#define USB_DBG(...) while(0)
+#define USB_DBG_HEX(A,B) while(0)
+#endif
+
+#undef USB_TEST_ASSERT
+void usb_test_assert_internal(const char *expr, const char *file, int line);
+#define USB_TEST_ASSERT(EXPR) while(!(EXPR)){usb_test_assert_internal(#EXPR,__FILE__,__LINE__);}
+
+#define USB_TRACE1(A) while(0)
+
+#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");}while(0);
+
+__IO bool attach_done = false;
+
+void delay_ms(uint32_t t)
+{
+    HAL_Delay(t);
+}
+
+// usbh_conf.c
+extern HCD_HandleTypeDef hhcd_USB_OTG_FS;
+
+void HAL_HCD_MspInit(HCD_HandleTypeDef* hhcd)
+{
+  GPIO_InitTypeDef GPIO_InitStruct;
+  if(hhcd->Instance==USB_OTG_FS)
+  {
+    /* Peripheral clock enable */
+    __USB_OTG_FS_CLK_ENABLE();
+  
+    /**USB_OTG_FS GPIO Configuration    
+    PA11     ------> USB_OTG_FS_DM
+    PA12     ------> USB_OTG_FS_DP 
+    */
+    GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
+    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
+    GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
+    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+    /* Peripheral interrupt init*/
+    /* Sets the priority grouping field */
+    HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);
+    HAL_NVIC_SetPriority(OTG_FS_IRQn, 0, 0);
+    HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
+  }
+}
+
+// stm32f4xx_it.c
+extern "C" {
+void HAL_HCD_Connect_Callback(HCD_HandleTypeDef *hhcd)
+{
+    USB_TRACE1(hhcd);
+    attach_done = true;
+}
+
+} // extern "C"
+
+USBHALHost* USBHALHost::instHost;
+
+USBHALHost::USBHALHost() {
+    instHost = this;
+}
+
+void USBHALHost::init() {
+    hhcd_USB_OTG_FS.Instance = USB_OTG_FS;
+    hhcd_USB_OTG_FS.Init.Host_channels = 8;
+    hhcd_USB_OTG_FS.Init.speed = HCD_SPEED_FULL;
+    hhcd_USB_OTG_FS.Init.dma_enable = DISABLE;
+    hhcd_USB_OTG_FS.Init.phy_itface = HCD_PHY_EMBEDDED;
+    hhcd_USB_OTG_FS.Init.Sof_enable = DISABLE;
+    hhcd_USB_OTG_FS.Init.low_power_enable = ENABLE;
+    hhcd_USB_OTG_FS.Init.vbus_sensing_enable = DISABLE;
+    hhcd_USB_OTG_FS.Init.use_external_vbus = DISABLE;
+
+    HAL_HCD_Init(&hhcd_USB_OTG_FS);
+    HAL_HCD_Start(&hhcd_USB_OTG_FS);
+
+    bool lowSpeed = wait_attach();
+    delay_ms(200);
+    HAL_HCD_ResetPort(&hhcd_USB_OTG_FS);
+    delay_ms(100); // Wait for 100 ms after Reset
+    addDevice(NULL, 0, lowSpeed);
+}
+
+bool USBHALHost::wait_attach() {
+    Timer t;
+    t.reset();
+    t.start();
+    while(!attach_done) {
+        if (t.read_ms() > 5*1000) {
+            t.reset();
+            USB_INFO("Please attach USB device.");
+        }
+    }
+    wait_ms(100);
+    return HAL_HCD_GetCurrentSpeed(&hhcd_USB_OTG_FS) == USB_OTG_SPEED_LOW;
+}
+
+int USBHALHost::token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength) {
+    const uint8_t ep_addr = 0x00;
+    HC hc;
+    USBDeviceConnected* dev = ep->getDevice();
+    hc.Init(ep_addr, 
+        dev->getAddress(),
+        dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
+        EP_TYPE_CTRL, ep->getSize());
+
+    setup->wLength = wLength;
+    hc.SubmitRequest((uint8_t*)setup, 8, true); // PID_SETUP
+    while(hc.GetURBState() == URB_IDLE);
+
+    switch(hc.GetURBState()) {
+        case URB_DONE:
+            LastStatus = ACK;
+            break;
+        default:
+            LastStatus = 0xff;
+            break;
+    }
+    ep->setData01(DATA1);
+    return 8;
+}
+
+int USBHALHost::token_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit) {
+    switch(ep->getType()) {
+        case CONTROL_ENDPOINT:
+            return token_ctl_in(ep, data, size, retryLimit);
+        case INTERRUPT_ENDPOINT:
+            return token_int_in(ep, data, size);
+        case BULK_ENDPOINT:
+            return token_blk_in(ep, data, size, retryLimit);
+    }
+    return -1;
+}
+
+int USBHALHost::token_ctl_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit) {
+    const uint8_t ep_addr = 0x80;
+    HC hc;
+    USBDeviceConnected* dev = ep->getDevice();
+    hc.Init(ep_addr, 
+        dev->getAddress(),
+        dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
+        EP_TYPE_CTRL, ep->getSize());
+
+    hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
+
+    hc.SubmitRequest(data, size);
+    while(hc.GetURBState() == URB_IDLE);
+
+    switch(hc.GetURBState()) {
+        case URB_DONE:
+            LastStatus = ACK;
+            break;
+        default:
+            LastStatus = 0xff;
+            return -1;
+    }
+    ep->toggleData01();
+    return hc.GetXferCount();
+}
+
+int USBHALHost::token_int_in(USBEndpoint* ep, uint8_t* data, int size) {
+    HC hc;
+    USBDeviceConnected* dev = ep->getDevice();
+    hc.Init(
+        ep->getAddress(),
+        dev->getAddress(),
+        dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
+        EP_TYPE_INTR, ep->getSize());
+
+    hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
+
+    hc.SubmitRequest(data, size);
+    while(hc.GetURBState() == URB_IDLE);
+    switch(hc.GetURBState()) {
+        case URB_DONE:
+            switch(hc.GetState()) {
+                case HC_XFRC:
+                    LastStatus = ep->getData01();
+                    ep->toggleData01();
+                    return hc.GetXferCount();
+                case HC_NAK:
+                    LastStatus = NAK;
+                    return -1;
+            }
+            break;
+    }
+    LastStatus = STALL;
+    return -1;
+}
+
+int USBHALHost::token_blk_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit) {
+    HC hc;
+    USBDeviceConnected* dev = ep->getDevice();
+    hc.Init(
+        ep->getAddress(),
+        dev->getAddress(),
+        HCD_SPEED_FULL,
+        EP_TYPE_BULK, ep->getSize());
+
+    hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
+
+    int retry = 0;
+    do {
+        hc.SubmitRequest(data, size);
+        while(hc.GetURBState() == URB_IDLE);
+
+        switch(hc.GetURBState()) {
+            case URB_DONE:
+                switch(hc.GetState()) {
+                    case HC_XFRC:
+                        LastStatus = ep->getData01();
+                        ep->toggleData01();
+                        return hc.GetXferCount();
+                    case HC_NAK:
+                        LastStatus = NAK;
+                        if (retryLimit > 0) {
+                            delay_ms(1 + 10 * retry);
+                        }
+                        break;
+                    default:
+                        break;
+                }
+                break;
+            case URB_STALL:
+                LastStatus = STALL;
+                return -1;
+            default:
+                LastStatus = STALL;
+                delay_ms(500 + 100 * retry);
+                break;
+        }
+    }while(retry++ < retryLimit);
+    return -1;
+}
+
+int USBHALHost::token_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit) {
+    switch(ep->getType()) {
+        case CONTROL_ENDPOINT:
+            return token_ctl_out(ep, data, size, retryLimit);
+        case INTERRUPT_ENDPOINT:
+            return token_int_out(ep, data, size);
+        case BULK_ENDPOINT:
+            return token_blk_out(ep, data, size, retryLimit);
+    }
+    return -1;
+}
+
+int USBHALHost::token_ctl_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit) {
+    const uint8_t ep_addr = 0x00;
+    HC hc;
+    USBDeviceConnected* dev = ep->getDevice();
+    hc.Init(ep_addr, 
+        dev->getAddress(),
+        dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
+        EP_TYPE_CTRL, ep->getSize());
+
+    hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
+
+    do {
+        hc.SubmitRequest((uint8_t*)data, size);
+        while(hc.GetURBState() == URB_IDLE);
+
+        switch(hc.GetURBState()) {
+            case URB_DONE:
+                LastStatus = ACK;
+                ep->toggleData01();
+                return size;
+
+            default:
+                break;
+        }
+        delay_ms(1);
+    }while(retryLimit-- > 0); 
+    return -1;
+}
+
+int USBHALHost::token_int_out(USBEndpoint* ep, const uint8_t* data, int size) {
+    HC hc;
+    USBDeviceConnected* dev = ep->getDevice();
+    hc.Init(
+        ep->getAddress(),
+        dev->getAddress(),
+        dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
+        EP_TYPE_INTR, ep->getSize());
+
+    hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
+
+    hc.SubmitRequest((uint8_t*)data, size);
+    while(hc.GetURBState() == URB_IDLE);
+    if (hc.GetURBState() != URB_DONE) {
+        return -1;
+    }
+    ep->toggleData01();
+    return size;
+}
+
+int USBHALHost::token_blk_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit) {
+    HC hc;
+    USBDeviceConnected* dev = ep->getDevice();
+    hc.Init(
+        ep->getAddress(), dev->getAddress(),
+        HCD_SPEED_FULL, EP_TYPE_BULK, ep->getSize());
+
+    hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
+
+    int retry = 0;
+    do {
+        hc.SubmitRequest((uint8_t*)data, size);
+        while(hc.GetURBState() == URB_IDLE);
+
+        switch(hc.GetURBState()) {
+            case URB_DONE:
+                switch(hc.GetState()) {
+                    case HC_XFRC: // ACK
+                        LastStatus = ep->getData01();
+                        ep->toggleData01();
+                        return size;
+                    default:
+                        break;
+                }
+                break;
+            case URB_NOTREADY: // HC_NAK
+                LastStatus = NAK;
+                delay_ms(100 * retry);
+                break;
+            default:
+                LastStatus = STALL;
+                return -1;
+        }
+    } while(retry++ < retryLimit);
+    return -1;
+}
+
+int USBHALHost::token_iso_in(USBEndpoint* ep, uint8_t* data, int size) {
+    HC* hc = ep->getHALData<HC*>();
+    if (hc == NULL) {
+        hc = new HC;
+        ep->setHALData<HC*>(hc);
+        USBDeviceConnected* dev = ep->getDevice();
+        hc->Init(
+            ep->getAddress(), dev->getAddress(),
+            HCD_SPEED_FULL, EP_TYPE_ISOC, ep->getSize());
+    }
+    hc->SubmitRequest(data, size);
+    while(hc->GetURBState() == URB_IDLE);
+    return hc->GetXferCount();
+}
+
+int USBHALHost::multi_token_in(USBEndpoint* ep, uint8_t* data, size_t total, bool block) {
+    if (total == 0) {
+        return token_in(ep);
+    }
+    int retryLimit = block ? 10 : 0;
+    int read_len = 0;
+    for(int n = 0; read_len < total; n++) {
+        int size = std::min((int)total-read_len, ep->getSize());
+        int result = token_in(ep, data+read_len, size, retryLimit);
+        if (result < 0) {
+            if (block) {
+                return -1;
+            }
+            if (LastStatus == NAK) {
+                if (n == 0) {
+                    return -1;
+                }
+                break;
+            }
+            return result;
+        }
+        read_len += result;
+        if (result < ep->getSize()) {
+            break;
+        }
+    }
+    return read_len;
+}
+
+int USBHALHost::multi_token_out(USBEndpoint* ep, const uint8_t* data, size_t total) {
+    if (total == 0) {
+        return token_out(ep);
+    }
+    int write_len = 0;
+    for(int n = 0; write_len < total; n++) {
+        int size = std::min((int)total-write_len, ep->getSize());
+        int result = token_out(ep, data+write_len, size);
+        if (result < 0) {
+            if (LastStatus == NAK) {
+                if (n == 0) {
+                    return -1;
+                }
+                break;
+            }
+            USB_DBG("token_out result=%d %02x", result, LastStatus);
+            return result;
+        }
+        write_len += result;
+        if (result < ep->getSize()) {
+            break;
+        }
+    }
+    return write_len;
+}
+void USBHALHost::multi_token_inNB(USBEndpoint* ep, uint8_t* data, int size) {
+    USB_TRACE1(size);
+    USB_TEST_ASSERT(ep->getState() != USB_TYPE_PROCESSING);
+    ep->setBuffer(data, size);
+    ep->setState(USB_TYPE_PROCESSING);
+}
+
+USB_TYPE USBHALHost::multi_token_inNB_result(USBEndpoint* ep) {
+    USB_TEST_ASSERT(ep->getState() == USB_TYPE_PROCESSING);
+    uint8_t* buf = ep->getBufStart();
+    int size = ep->getBufSize();
+    int result = multi_token_in(ep, buf, size, false);
+    USB_TRACE1(result);
+    if (result < 0) {
+        return USB_TYPE_PROCESSING;
+    }
+    ep->setLengthTransferred(result);
+    ep->setState(USB_TYPE_IDLE);
+    return USB_TYPE_OK;
+
+}
+
+void USBHALHost::setToggle(USBEndpoint* ep, uint8_t toggle) {
+    USB_TEST_ASSERT(toggle == 1);
+    ep->setData01(toggle == 0 ? DATA0 : DATA1);
+}
+
+uint8_t HC::slot = 0x00;
+
+HC::HC() {
+    static const int start = 1;
+    uint8_t mask = (1<<start);
+    for(int i = start; i < 8; i++, mask <<= 1) {
+        if (!(slot & mask)) {
+            slot |= mask;
+            _ch = i;
+            return;
+        }
+    }
+    _ch = 0; // ERROR!!!
+}
+
+HC::HC(int ch) {
+    _ch = ch;
+    slot |= (1<<_ch);
+}
+
+HC::~HC() {
+    slot &= ~(1<<_ch);
+}
+
+HAL_StatusTypeDef HC::Init(uint8_t epnum, uint8_t dev_address, uint8_t speed, uint8_t ep_type, uint16_t mps) {
+    _ep_addr = epnum;
+    _ep_type = ep_type;
+    return HAL_HCD_HC_Init(&hhcd_USB_OTG_FS, _ch,
+                           epnum, dev_address, speed, ep_type, mps);
+}
+
+HAL_StatusTypeDef HC::SubmitRequest(uint8_t* pbuff, uint16_t length, bool setup) {
+    uint8_t direction = (_ep_addr & 0x80) ? DIR_IN : DIR_OUT;
+    if (_ep_type == EP_TYPE_CTRL) {
+        HCD_HCTypeDef* hc = &hhcd_USB_OTG_FS.hc[_ch];
+        if (setup) {
+            hc->data_pid = HC_PID_SETUP;
+            hc->toggle_out = 0;
+        } else {
+            if (direction == DIR_IN) {
+                if (hc->toggle_in == 0) {
+                    hc->data_pid = HC_PID_DATA0;
+                } else {
+                    hc->data_pid = HC_PID_DATA1;
+                }
+            } else { // OUT
+                if (hc->toggle_out == 0) {
+                    hc->data_pid = HC_PID_DATA0;
+                } else {
+                    hc->data_pid = HC_PID_DATA1;
+                }
+            }
+        }
+        hc->xfer_buff = pbuff;
+        hc->xfer_len  = length;
+        hc->urb_state = URB_IDLE;
+        hc->xfer_count = 0;
+        hc->ch_num = _ch;
+        hc->state = HC_IDLE;
+  
+        return USB_HC_StartXfer(hhcd_USB_OTG_FS.Instance, hc, 0);
+    }
+    return HAL_HCD_HC_SubmitRequest(&hhcd_USB_OTG_FS, _ch,
+                                    direction, _ep_type, 0, pbuff, length, 0);
+}
+
+HCD_URBStateTypeDef HC::GetURBState() {
+    return HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, _ch);
+}
+
+HCD_HCStateTypeDef HC::GetState() {
+    return HAL_HCD_HC_GetState(&hhcd_USB_OTG_FS, _ch);
+}
+
+uint32_t HC::GetXferCount() {
+    return HAL_HCD_HC_GetXferCount(&hhcd_USB_OTG_FS, _ch);
+}
+
+void HC::SetToggle(uint8_t toggle) {
+    if (_ep_addr & 0x80) { // IN
+        hhcd_USB_OTG_FS.hc[_ch].toggle_in = toggle;
+    } else { // OUT
+        hhcd_USB_OTG_FS.hc[_ch].toggle_out = toggle;
+    }
+}
+
+#endif
+
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 USBHost/USBHALHost_F401RE.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHALHost_F401RE.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,59 @@
+#pragma once
+#include "mbed.h"
+#include "USBHostTypes.h"
+#include "USBEndpoint.h"
+
+class HC {
+    static const uint8_t DIR_IN  = 1;
+    static const uint8_t DIR_OUT = 0;
+
+public:
+    HC();
+    HC(int ch);
+    ~HC();
+    HAL_StatusTypeDef Init(uint8_t epnum, uint8_t dev_address, uint8_t speed, uint8_t ep_type, uint16_t mps);
+    HAL_StatusTypeDef SubmitRequest(uint8_t* pbuff, uint16_t length, bool setup = false);
+    HCD_URBStateTypeDef GetURBState();
+    HCD_HCStateTypeDef GetState();
+    uint32_t GetXferCount();
+    void SetToggle(uint8_t toggle);
+
+    static uint8_t slot;
+
+private:
+    int _ch;
+    uint8_t _ep_addr;
+    uint8_t _ep_type;
+};
+
+class USBHALHost {
+public:
+    uint8_t LastStatus;
+    uint8_t prev_LastStatus;
+
+protected:
+    USBHALHost();
+    void init();
+    virtual bool addDevice(USBDeviceConnected* parent, int port, bool lowSpeed) = 0;
+    int token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength = 0);
+    int token_iso_in(USBEndpoint* ep, uint8_t* data, int size);
+    int multi_token_in(USBEndpoint* ep, uint8_t* data = NULL, size_t total = 0, bool block = true);
+    int multi_token_out(USBEndpoint* ep, const uint8_t* data = NULL, size_t total = 0);
+    void multi_token_inNB(USBEndpoint* ep, uint8_t* data, int size);
+    USB_TYPE multi_token_inNB_result(USBEndpoint* ep);
+    void setToggle(USBEndpoint* ep, uint8_t toggle);
+
+private:
+    int token_in(USBEndpoint* ep, uint8_t* data = NULL, int size = 0, int retryLimit = 10);
+    int token_out(USBEndpoint* ep, const uint8_t* data = NULL, int size = 0, int retryLimit = 10);
+    int token_ctl_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit);
+    int token_int_in(USBEndpoint* ep, uint8_t* data, int size);
+    int token_blk_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit);
+    int token_ctl_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit);
+    int token_int_out(USBEndpoint* ep, const uint8_t* data, int size);
+    int token_blk_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit);
+    bool wait_attach();
+    static USBHALHost * instHost;
+};
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 USBHost/USBHost.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost.cpp	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,352 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBHost.h"
+
+#define USB_TRACE1(A) while(0)
+#undef USB_TEST_ASSERT
+void usb_test_assert_internal(const char *expr, const char *file, int line);
+#define USB_TEST_ASSERT(EXPR) while(!(EXPR)){usb_test_assert_internal(#EXPR,__FILE__,__LINE__);}
+
+USBHost* USBHost::inst = NULL;
+
+USBHost* USBHost::getHostInst() {
+    if (inst == NULL) {
+        inst = new USBHost();
+        inst->init();
+    }
+    return inst;
+}
+
+void USBHost::poll()
+{
+    if (inst) {
+        inst->task();
+    }
+}
+
+USBHost::USBHost() {
+}
+
+/* virtual */ bool USBHost::addDevice(USBDeviceConnected* parent, int port, bool lowSpeed) {
+    USBDeviceConnected* dev = new USBDeviceConnected;
+    USBEndpoint* ep = new USBEndpoint(dev);
+    dev->init(0, port, lowSpeed);
+    dev->setAddress(0);
+    dev->setEpCtl(ep);
+    uint8_t desc[18];
+    wait_ms(100);
+
+    int rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, 8);
+    USB_TEST_ASSERT(rc == USB_TYPE_OK);
+    if (rc != USB_TYPE_OK) {
+        USB_ERR("ADD DEVICE FAILD");
+    }
+    USB_DBG_HEX(desc, 8);
+    DeviceDescriptor* dev_desc = reinterpret_cast<DeviceDescriptor*>(desc);
+    ep->setSize(dev_desc->bMaxPacketSize);
+
+    int new_addr = USBDeviceConnected::getNewAddress();
+    rc = controlWrite(dev, 0x00, SET_ADDRESS, new_addr, 0, NULL, 0);
+    USB_TEST_ASSERT(rc == USB_TYPE_OK);
+    dev->setAddress(new_addr);
+    wait_ms(100);
+
+    rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, sizeof(desc));
+    USB_TEST_ASSERT(rc == USB_TYPE_OK);
+    USB_DBG_HEX(desc, sizeof(desc));
+
+    dev->setVid(dev_desc->idVendor);
+    dev->setPid(dev_desc->idProduct);
+    dev->setClass(dev_desc->bDeviceClass);
+    USB_INFO("parent:%p port:%d speed:%s VID:%04x PID:%04x class:%02x addr:%d",
+        parent, port, (lowSpeed ? "low " : "full"), dev->getVid(), dev->getPid(), dev->getClass(),
+        dev->getAddress());
+
+    DeviceLists.push_back(dev);
+
+    if (dev->getClass() == HUB_CLASS) {
+        const int config = 1;
+        int rc = controlWrite(dev, 0x00, SET_CONFIGURATION, config, 0, NULL, 0);
+        USB_TEST_ASSERT(rc == USB_TYPE_OK);
+        wait_ms(100);
+        Hub(dev);
+    }
+    return true;
+}
+
+// enumerate a device with the control USBEndpoint
+USB_TYPE USBHost::enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator)
+{
+    if (dev->getClass() == HUB_CLASS) { // skip hub class
+        return USB_TYPE_OK;
+    }
+    uint8_t desc[18];
+    USB_TYPE rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 1<<8, 0, desc, sizeof(desc));
+    USB_TEST_ASSERT(rc == USB_TYPE_OK);
+    USB_DBG_HEX(desc, sizeof(desc));
+    if (rc != USB_TYPE_OK) {
+        return rc;
+    }
+    DeviceDescriptor* dev_desc = reinterpret_cast<DeviceDescriptor*>(desc);
+    dev->setClass(dev_desc->bDeviceClass);
+    pEnumerator->setVidPid(dev->getVid(), dev->getPid());
+
+    rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 2<<8, 0, desc, 4);
+    USB_TEST_ASSERT(rc == USB_TYPE_OK);
+    USB_DBG_HEX(desc, 4);
+
+    int TotalLength = desc[2]|desc[3]<<8;
+    uint8_t* buf = new uint8_t[TotalLength];
+    rc = controlRead(dev, 0x80, GET_DESCRIPTOR, 2<<8, 0, buf, TotalLength);
+    USB_TEST_ASSERT(rc == USB_TYPE_OK);
+    //USB_DBG_HEX(buf, TotalLength);
+
+    // Parse the configuration descriptor
+    parseConfDescr(dev, buf, TotalLength, pEnumerator);
+    delete[] buf;
+    // only set configuration if not enumerated before
+    if (!dev->isEnumerated()) {
+        USB_DBG("Set configuration 1 on dev: %p", dev);
+        // sixth step: set configuration (only 1 supported)
+        int config = 1;
+        USB_TYPE res = controlWrite(dev, 0x00, SET_CONFIGURATION, config, 0, NULL, 0);
+        if (res != USB_TYPE_OK) {
+            USB_ERR("SET CONF FAILED");
+            return res;
+        }
+        // Some devices may require this delay
+        wait_ms(100);
+        dev->setEnumerated();
+        // Now the device is enumerated!
+        USB_DBG("dev %p is enumerated", dev);
+    }
+    return USB_TYPE_OK;
+}
+
+// this method fills the USBDeviceConnected object: class,.... . It also add endpoints found in the descriptor.
+void USBHost::parseConfDescr(USBDeviceConnected * dev, uint8_t * conf_descr, uint32_t len, IUSBEnumerator* pEnumerator)
+{
+    uint32_t index = 0;
+    uint32_t len_desc = 0;
+    uint8_t id = 0;
+    USBEndpoint * ep = NULL;
+    uint8_t intf_nb = 0;
+    bool parsing_intf = false;
+    uint8_t current_intf = 0;
+    EndpointDescriptor* ep_desc;
+
+    while (index < len) {
+        len_desc = conf_descr[index];
+        id = conf_descr[index+1];
+        USB_DBG_HEX(conf_descr+index, len_desc);
+        switch (id) {
+            case CONFIGURATION_DESCRIPTOR:
+                USB_DBG("dev: %p has %d intf", dev, conf_descr[4]);
+                dev->setNbIntf(conf_descr[4]);
+                break;
+            case INTERFACE_DESCRIPTOR:
+                if(pEnumerator->parseInterface(conf_descr[index + 2], conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7])) {
+                    intf_nb++;
+                    current_intf = conf_descr[index + 2];
+                    dev->addInterface(current_intf, conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7]);
+                    USB_DBG("ADD INTF %d on device %p: class: %d, subclass: %d, proto: %d", current_intf, dev, conf_descr[index + 5],conf_descr[index + 6],conf_descr[index + 7]);
+                    parsing_intf = true;
+                } else {
+                    parsing_intf = false;
+                }
+                break;
+            case ENDPOINT_DESCRIPTOR:
+                ep_desc = reinterpret_cast<EndpointDescriptor*>(conf_descr+index);
+                if (parsing_intf && (intf_nb <= MAX_INTF) ) {
+                    ENDPOINT_TYPE type = (ENDPOINT_TYPE)(ep_desc->bmAttributes & 0x03);
+                    ENDPOINT_DIRECTION dir = (ep_desc->bEndpointAddress & 0x80) ? IN : OUT;
+                    if(pEnumerator->useEndpoint(current_intf, type, dir)) {
+                        ep = new USBEndpoint(dev);
+                        ep->init(type, dir, ep_desc->wMaxPacketSize, ep_desc->bEndpointAddress);
+                        USB_DBG("ADD USBEndpoint %p, on interf %d on device %p", ep, current_intf, dev);
+                        dev->addEndpoint(current_intf, ep);
+                    }
+                }
+                break;
+            case HID_DESCRIPTOR:
+                //lenReportDescr = conf_descr[index + 7] | (conf_descr[index + 8] << 8);
+                break;
+            default:
+                break;
+        }
+        index += len_desc;
+    }
+}
+
+USB_TYPE USBHost::controlRead(USBDeviceConnected* dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
+    USBEndpoint* ep = dev->getEpCtl();
+    SETUP_PACKET setup(requestType, request, value, index, len);
+
+    int result = token_setup(ep, &setup, len); // setup stage
+    USB_TRACE1(result);
+    if (result < 0) {
+        return USB_TYPE_ERROR;
+    }
+
+    int read_len = multi_token_in(ep, buf, len); // data stage
+    USB_TRACE1(read_len);
+    if (read_len < 0) {
+        return USB_TYPE_ERROR;
+    }
+
+    setToggle(ep, 1); // DATA1
+    result = multi_token_out(ep); // status stage
+    USB_TRACE1(result);
+    if (result < 0) {
+        return USB_TYPE_ERROR;
+    }
+    ep->setLengthTransferred(read_len);
+    return USB_TYPE_OK;
+}
+
+USB_TYPE USBHost::controlWrite(USBDeviceConnected* dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
+    USBEndpoint* ep = dev->getEpCtl();
+    SETUP_PACKET setup(requestType, request, value, index, len);
+
+    int result = token_setup(ep, &setup, len); // setup stage
+    USB_TRACE1(result);
+    if (result < 0) {
+        return USB_TYPE_ERROR;
+    }
+    int write_len = 0;
+    if (buf != NULL) {
+        write_len = multi_token_out(ep, buf, len); // data stage
+        USB_TRACE1(write_len);
+        if (write_len < 0) {
+            return USB_TYPE_ERROR;
+        }
+    }
+
+    setToggle(ep, 1); // DATA1
+    result = multi_token_in(ep); // status stage
+    USB_TRACE1(result);
+    if (result < 0) {
+        return USB_TYPE_ERROR;
+    }
+    ep->setLengthTransferred(write_len);
+    return USB_TYPE_OK;
+}
+
+USB_TYPE USBHost::bulkRead(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) {
+    if (blocking == false) {
+        ep->setBuffer(buf, len);
+        ep_queue.push(ep);
+        multi_token_inNB(ep, buf, len);
+        return USB_TYPE_PROCESSING;
+    }
+    int result = multi_token_in(ep, buf, len);
+    USB_TRACE1(result);
+    if (result < 0) {
+        return USB_TYPE_ERROR;
+    }
+    ep->setLengthTransferred(result);
+    return USB_TYPE_OK;
+}
+
+USB_TYPE USBHost::bulkWrite(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) {
+    USB_TEST_ASSERT(blocking);
+    int result = multi_token_out(ep, buf, len);
+    USB_TRACE1(result);
+    if (result < 0) {
+        return USB_TYPE_ERROR;
+    }
+    ep->setLengthTransferred(result);
+    return USB_TYPE_OK;
+}
+
+USB_TYPE USBHost::interruptRead(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) {
+    if (blocking == false) {
+        ep->setBuffer(buf, len);
+        ep_queue.push(ep);
+        multi_token_inNB(ep, buf, len);
+        return USB_TYPE_PROCESSING;
+    }
+    int result = multi_token_in(ep, buf, len);
+    USB_TRACE1(result);
+    if (result < 0) {
+        return USB_TYPE_ERROR;
+    }
+    ep->setLengthTransferred(result);
+    return USB_TYPE_OK;
+}
+
+USB_TYPE USBHost::interruptWrite(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) {
+    USB_TEST_ASSERT(blocking);
+    int result = multi_token_out(ep, buf, len);
+    USB_TRACE1(result);
+    if (result < 0) {
+        return USB_TYPE_ERROR;
+    }
+    ep->setLengthTransferred(result);
+    return USB_TYPE_OK;
+}
+
+USB_TYPE USBHost::isochronousRead(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking) {
+    USB_TEST_ASSERT(blocking);
+    isochronousReadNB(ep, buf, len);
+    return USB_TYPE_OK;
+}
+
+int USBHost::interruptReadNB(USBEndpoint* ep, uint8_t* data, int size) {
+    USB_TRACE1(size);
+    if (ep->getState() != USB_TYPE_PROCESSING) {
+        ep->setState(USB_TYPE_PROCESSING);
+        ep->setBuffer(data, size);
+        multi_token_inNB(ep, data, size);
+    }
+    if (multi_token_inNB_result(ep) != USB_TYPE_PROCESSING) {
+        return ep->getLengthTransferred();
+    }
+    return -1;
+}
+
+int USBHost::bulkReadNB(USBEndpoint* ep, uint8_t* data, int size) {
+    USB_TRACE1(size);
+    return interruptReadNB(ep, data, size);
+}
+
+int USBHost::isochronousReadNB(USBEndpoint* ep, uint8_t* data, int size) {
+    USB_TRACE1(size);
+    int result = token_iso_in(ep, data, size);
+    if (result >= 0) {
+         ep->setLengthTransferred(result);
+    }
+    return result;
+}
+
+void USBHost::task() {
+    USBEndpoint* ep = ep_queue.pop();
+    if (ep) {
+        USB_TEST_ASSERT(ep->getDir() == IN);
+        if (multi_token_inNB_result(ep) != USB_TYPE_PROCESSING) {
+            ep->call();
+        } else {
+            ep_queue.push(ep);
+        }
+    }
+}
+
+void usb_test_assert_internal(const char *expr, const char *file, int line){
+    error("\n\n%s@%d %s ASSERT!\n\n", file, line, expr);
+}
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 USBHost/USBHost.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,195 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include "mbed.h"
+#include "USBHALHost.h"
+#include "USBDeviceConnected.h"
+#include "IUSBEnumerator.h"
+#include "USBHostConf.h"
+#include "dbg.h"
+#include "myvector.h"
+
+/**
+* USBHost class
+*   This class is a singleton. All drivers have a reference on the static USBHost instance
+*/
+class USBHost : public USBHALHost {
+public:
+    /**
+    * Static method to create or retrieve the single USBHost instance
+    */
+    static USBHost* getHostInst();
+
+    /**
+    * Control read: setup stage, data stage and status stage
+    *
+    * @param dev the control read will be done for this device
+    * @param requestType request type
+    * @param request request
+    * @param value value
+    * @param index index
+    * @param buf pointer on a buffer where will be store the data received
+    * @param len length of the transfer
+    *
+    * @returns status of the control read
+    */
+    USB_TYPE controlRead(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len);
+
+    /**
+    * Control write: setup stage, data stage and status stage
+    *
+    * @param dev the control write will be done for this device
+    * @param requestType request type
+    * @param request request
+    * @param value value
+    * @param index index
+    * @param buf pointer on a buffer which will be written
+    * @param len length of the transfer
+    *
+    * @returns status of the control write
+    */
+    USB_TYPE controlWrite(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len);
+
+    /**
+    * Bulk read
+    *
+    * @param dev the bulk transfer will be done for this device
+    * @param ep USBEndpoint which will be used to read a packet
+    * @param buf pointer on a buffer where will be store the data received
+    * @param len length of the transfer
+    * @param blocking if true, the read is blocking (wait for completion)
+    *
+    * @returns status of the bulk read
+    */
+    USB_TYPE bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
+
+    /**
+    * Bulk write
+    *
+    * @param dev the bulk transfer will be done for this device
+    * @param ep USBEndpoint which will be used to write a packet
+    * @param buf pointer on a buffer which will be written
+    * @param len length of the transfer
+    * @param blocking if true, the write is blocking (wait for completion)
+    *
+    * @returns status of the bulk write
+    */
+    USB_TYPE bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
+
+    /**
+    * Interrupt read
+    *
+    * @param dev the interrupt transfer will be done for this device
+    * @param ep USBEndpoint which will be used to write a packet
+    * @param buf pointer on a buffer which will be written
+    * @param len length of the transfer
+    * @param blocking if true, the read is blocking (wait for completion)
+    *
+    * @returns status of the interrupt read
+    */
+    USB_TYPE interruptRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
+
+    /**
+    * Interrupt write
+    *
+    * @param dev the interrupt transfer will be done for this device
+    * @param ep USBEndpoint which will be used to write a packet
+    * @param buf pointer on a buffer which will be written
+    * @param len length of the transfer
+    * @param blocking if true, the write is blocking (wait for completion)
+    *
+    * @returns status of the interrupt write
+    */
+    USB_TYPE interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
+
+    /**
+    * Isochronous read
+    *
+    * @param dev the isochronous transfer will be done for this device
+    * @param ep USBEndpoint which will be used to write a packet
+    * @param buf pointer on a buffer which will be written
+    * @param len length of the transfer
+    * @param blocking if true, the read is blocking (wait for completion)
+    *
+    * @returns status of the interrupt read
+    */
+    USB_TYPE isochronousRead(USBDeviceConnected* dev, USBEndpoint* ep, uint8_t* buf, uint32_t len, bool blocking = true);
+
+    /**
+    * Enumerate a device.
+    *
+    * @param dev device which will be enumerated
+    *
+    * @returns status of the enumeration
+    */
+    USB_TYPE enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator);
+
+    /**
+    * Get a device
+    *
+    * @param index index of the device which will be returned
+    *
+    * @returns pointer on the "index" device
+    */
+    USBDeviceConnected * getDevice(uint8_t index) {
+        return index < DeviceLists.size() ? DeviceLists[index] : NULL;
+    }
+
+    /**
+     *  register a driver into the host associated with a callback function called when the device is disconnected
+     *
+     *  @param dev device
+     *  @param intf interface number
+     *  @param tptr pointer to the object to call the member function on
+     *  @param mptr pointer to the member function to be called
+     */
+    template<typename T>
+    void registerDriver(USBDeviceConnected * dev, uint8_t intf, T* tptr, void (T::*mptr)(void)) {
+    }
+
+    // KL46Z-USBHost extensions
+    int interruptReadNB(USBEndpoint* ep, uint8_t* data, int size);
+    int bulkReadNB(USBEndpoint*ep, uint8_t* data, int size);
+    int isochronousReadNB(USBEndpoint*ep, uint8_t* data, int size);
+
+    /**
+     * non-blocking processing
+     */
+    static void poll();
+
+private:
+    USBHost();
+    static USBHost* inst;
+    virtual bool addDevice(USBDeviceConnected* parent, int port, bool lowSpeed);
+    void root_enumeration(USBDeviceConnected* dev);
+    void parseConfDescr(USBDeviceConnected* dev, uint8_t* conf_descr, uint32_t len, IUSBEnumerator* pEnumerator);
+    myvector<USBDeviceConnected*>DeviceLists;
+    void task();
+    EndpointQueue ep_queue;
+
+    // USB HUB
+    bool Hub(USBDeviceConnected* dev);
+    int SetPortPower(USBDeviceConnected* dev, int port);
+    int ClearPortPower(USBDeviceConnected* dev, int port);
+    int PortReset(USBDeviceConnected* dev, int port);
+    int SetPortFeature(USBDeviceConnected* dev, int feature, int index);
+    int ClearPortFeature(USBDeviceConnected* dev, int feature, int index);
+    int SetPortReset(USBDeviceConnected* dev, int port);
+    int GetPortStatus(USBDeviceConnected* dev, int port, uint32_t* status);
+};
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 USBHost/USBHostConf.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostConf.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,72 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOST_CONF_H
+#define USBHOST_CONF_H
+
+/*
+* Maximum number of devices that can be connected
+* to the usb host
+*/
+#define MAX_DEVICE_CONNECTED        5
+
+/*
+* Maximum of Hub connected to the usb host
+*/
+#define MAX_HUB_NB                  1
+
+/*
+* Maximum number of ports on a USB hub
+*/
+#define MAX_HUB_PORT                4
+
+/*
+* Enable USBHostMSD
+*/
+#define USBHOST_MSD                 0
+
+/*
+* Enable USBHostKeyboard
+*/
+#define USBHOST_KEYBOARD            0
+
+/*
+* Enable USBHostMouse
+*/
+#define USBHOST_MOUSE               0
+
+/*
+* Enable USBHostSerial or USBHostMultiSerial (if set > 1)
+*/
+#define USBHOST_SERIAL              0
+
+/*
+* Enable USB3Gmodule
+*/
+#define USBHOST_3GMODULE            0 
+
+/*
+* Maximum number of interfaces of a usb device
+*/
+#define MAX_INTF                    4
+
+/*
+* usb_thread stack size
+*/
+#define USB_THREAD_STACK            (256*4 + MAX_HUB_NB*256*4)
+
+#endif
+
diff -r 000000000000 -r 3dac1f1bc9e0 USBHost/USBHostGamepad.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostGamepad.cpp	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,119 @@
+/*
+ * mbed USBHost Gamepad driver sample
+ * Copyright (c) 2014 Yuuichi Akagawa
+ *
+ * modified from mbed USBHostMouse
+ *
+ * mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+#include "USBHostGamepad.h"
+//#if USBHOST_GAMEPAD
+
+USBHostGamepad::USBHostGamepad() {
+    host = USBHost::getHostInst();
+    init();
+}
+
+void USBHostGamepad::init() {
+    dev = NULL;
+    int_in = NULL;
+    dev_connected = false;
+    gamepad_device_found = false;
+    gamepad_intf = -1;
+}
+
+bool USBHostGamepad::connected() {
+    return dev_connected;
+}
+
+bool USBHostGamepad::connect() {
+    if (dev_connected) {
+        return true;
+    }
+
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if ((dev = host->getDevice(i)) != NULL) {
+
+            if(host->enumerate(dev, this))
+                break;
+
+            if (gamepad_device_found) {
+
+                int_in = dev->getEndpoint(gamepad_intf, INTERRUPT_ENDPOINT, IN);
+                if (!int_in)
+                    break;
+
+                USB_INFO("New Gamepad/Joystick device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, gamepad_intf);
+#if DEBUG > 3
+                //Parse HID Report Descriptor
+                parseHidDescr();
+#endif
+                dev->setName("Gamepad", gamepad_intf);
+                host->registerDriver(dev, gamepad_intf, this, &USBHostGamepad::init);
+
+                int_in->attach(this, &USBHostGamepad::rxHandler);
+                rxSize = int_in->getSize();
+                if (rxSize > sizeof(report))
+                    rxSize = sizeof(report);
+                host->interruptRead(dev, int_in, report, rxSize, false);
+
+                dev_connected = true;
+                return true;
+            }
+        }
+    }
+    init();
+    return false;
+}
+
+void USBHostGamepad::rxHandler() {
+    if (dev)
+        host->interruptRead(dev, int_in, report, rxSize, false);
+        
+    /* modified 2016 Racoon */
+        
+}
+
+/*virtual*/ void USBHostGamepad::setVidPid(uint16_t vid, uint16_t pid)
+{
+    // we don't check VID/PID for gamepad driver
+}
+
+/*virtual*/ bool USBHostGamepad::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+    if ((gamepad_intf == -1) &&
+        (intf_class == HID_CLASS) &&
+        (intf_subclass == 0x00) &&
+        (intf_protocol == 0x00)) {
+        gamepad_intf = intf_nb;
+        return true;
+    }
+    return false;
+}
+
+/*virtual*/ bool USBHostGamepad::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    if (intf_nb == gamepad_intf) {
+        if (type == INTERRUPT_ENDPOINT && dir == IN) {
+            gamepad_device_found = true;
+            return true;
+        }
+    }
+    return false;
+}
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 USBHost/USBHostGamepad.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostGamepad.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,90 @@
+/* 
+ * modified from
+ * mbed USBHost Gamepad driver sample
+ * Copyright (c) 2014 Yuuichi Akagawa
+ *
+ * modified from mbed USBHostMouse
+ *
+ * Copyright (c) 2014 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef USBHOSTGAMEPAD_H
+#define USBHOSTGAMEPAD_H
+
+#include "USBHostConf.h"
+
+//#if USBHOST_GAMEPAD
+
+#include "USBHost.h"
+//HID Class Request
+#define HID_GET_REPORT                                 0x01
+#define HID_GET_IDLE                                   0x02
+#define HID_GET_PROTOCOL                               0x03
+#define HID_GET_DESCRIPTOR                             0x06
+#define HID_SET_REPORT                                 0x09
+#define HID_SET_IDLE                                   0x0a
+#define HID_SET_PROTOCOL                               0x0b
+
+/** 
+ * A class to communicate a USB MIDI device
+ */
+class USBHostGamepad : public IUSBEnumerator {
+public:
+    /**
+     * Constructor
+     */
+    USBHostGamepad();
+
+    /**
+     * Try to connect a gamepad device
+     *
+     * @return true if connection was successful
+     */
+    bool connect();
+
+    /**
+    * Check if a gamepad is connected
+    *
+    * @returns true if a gamepad is connected
+    */
+    bool connected();
+
+    uint8_t report[8]; /* modified 2016 Racoon */
+    int rxSize;
+        
+protected:
+    //From IUSBEnumerator
+    virtual void setVidPid(uint16_t vid, uint16_t pid);
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+private:
+    USBHost * host;
+    USBDeviceConnected * dev;
+    USBEndpoint * int_in;
+
+    bool dev_connected;
+    bool gamepad_device_found;
+    int gamepad_intf;
+
+    void rxHandler();
+    void init();
+};
+
+#endif
+
diff -r 000000000000 -r 3dac1f1bc9e0 USBHost/USBHostHub.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostHub.cpp	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,113 @@
+#include "USBHost.h"
+
+#define PORT_CONNECTION   0
+#define PORT_ENABLE       1
+#define PORT_SUSPEND      2
+#define PORT_OVER_CURRENT 3
+#define PORT_RESET        4
+#define PORT_POWER        8
+#define PORT_LOW_SPEED    9
+
+#define C_PORT_CONNECTION   16
+#define C_PORT_ENABLE       17
+#define C_PORT_SUSPEND      18
+#define C_PORT_OVER_CURRENT 19
+#define C_PORT_RESET        20
+
+bool USBHost::Hub(USBDeviceConnected* dev) {
+    USB_INFO("New HUB: VID:%04x PID:%04x [dev: %p]", dev->getVid(), dev->getPid(), dev);
+    HubDescriptor hubdesc;
+    // get HUB descriptor
+    int rc = controlRead(dev, 
+                        USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS,
+                        GET_DESCRIPTOR,
+                        0x29 << 8, 0, reinterpret_cast<uint8_t*>(&hubdesc), 
+                        sizeof(HubDescriptor));
+    USB_TEST_ASSERT(rc == USB_TYPE_OK);
+    if (rc != USB_TYPE_OK) {
+        return false;
+    }
+    USB_DBG_HEX((uint8_t*)&hubdesc, sizeof(hubdesc));
+
+    uint32_t status;
+    rc = controlRead( dev,
+                      0xa0, 0, 0, 0, reinterpret_cast<uint8_t*>(&status), 4);
+    USB_TEST_ASSERT(rc == USB_TYPE_OK);
+    if (rc != USB_TYPE_OK) {
+        return false;
+    }
+    USB_DBG("HUB STATUS: %08X\n", status);
+
+    for(int i = 1; i <= hubdesc.bNbrPorts; i++) {
+        SetPortPower(dev, i); // power on
+        wait_ms(hubdesc.bPwrOn2PwrGood*2);
+        uint32_t status;
+        GetPortStatus(dev, i, &status);
+        USB_DBG("port: %d status: %08X\n", i, status);
+        if (status & 0x010000) { // Connect Status Change, has changed
+            USB_TEST_ASSERT(status & 0x000001);
+            ClearPortFeature(dev, C_PORT_CONNECTION, i);
+            int lowSpeed = 0;
+            if (status & 0x0200) {
+                lowSpeed = 1;
+            }
+            PortReset(dev, i);
+            if (!addDevice(dev, i, lowSpeed)) {
+                ClearPortPower(dev, i); // power off
+            }
+        } else {
+            ClearPortPower(dev, i); // power off
+        }
+    }
+    return false;
+}
+
+
+int USBHost::SetPortPower(USBDeviceConnected* dev, int port)
+{
+    return SetPortFeature(dev, PORT_POWER, port);
+}
+
+int USBHost::ClearPortPower(USBDeviceConnected* dev, int port)
+{
+    return ClearPortFeature(dev, PORT_POWER, port);
+}
+
+int USBHost::SetPortFeature(USBDeviceConnected* dev, int feature, int index)
+{
+    return controlWrite(dev, 0x23, SET_FEATURE,feature,index,0,0);
+}
+
+int USBHost::ClearPortFeature(USBDeviceConnected* dev, int feature, int index)
+{
+    return controlWrite(dev, 0x23, CLEAR_FEATURE,feature,index,0,0);
+}
+
+int USBHost::SetPortReset(USBDeviceConnected* dev, int port)
+{
+    return SetPortFeature(dev, PORT_RESET, port);
+}
+
+int USBHost::GetPortStatus(USBDeviceConnected* dev, int port, uint32_t* status)
+{
+    return controlRead(dev, 0xa3, GET_STATUS, 0, port, (uint8_t*)status, 4);
+}
+
+int USBHost::PortReset(USBDeviceConnected* dev, int port)
+{
+    USB_DBG("%p port=%d\n", this, port);
+    USB_TEST_ASSERT(port >= 1);
+    SetPortReset(dev, port);
+    // wait reset
+    for(int i = 0; i < 100; i++) {
+        uint32_t status;    
+        GetPortStatus(dev, port, &status);
+        USB_DBG("RESET port: %d status: %08X\n", port, status);
+        if (status & 0x100000) { // Reset change , Reset complete
+            return USB_TYPE_OK;
+        }
+        wait_ms(5);
+     }
+     return USB_TYPE_ERROR;
+}
+
diff -r 000000000000 -r 3dac1f1bc9e0 USBHost/USBHostTypes.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostTypes.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,168 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USB_INC_H
+#define USB_INC_H
+
+#include "mbed.h"
+#include "toolchain.h"
+
+enum USB_TYPE {
+    USB_TYPE_OK = 0,
+
+    // completion code
+    USB_TYPE_CRC_ERROR = 1,
+    USB_TYPE_BIT_STUFFING_ERROR = 2,
+    USB_TYPE_DATA_TOGGLE_MISMATCH_ERROR = 3,
+    USB_TYPE_STALL_ERROR = 4,
+    USB_TYPE_DEVICE_NOT_RESPONDING_ERROR = 5,
+    USB_TYPE_PID_CHECK_FAILURE_ERROR = 6,
+    USB_TYPE_UNEXPECTED_PID_ERROR = 7,
+    USB_TYPE_DATA_OVERRUN_ERROR = 8,
+    USB_TYPE_DATA_UNDERRUN_ERROR = 9,
+    USB_TYPE_RESERVED = 9,
+    USB_TYPE_RESERVED_ = 10,
+    USB_TYPE_BUFFER_OVERRUN_ERROR = 12,
+    USB_TYPE_BUFFER_UNDERRUN_ERROR = 13,
+
+    // general usb state
+    USB_TYPE_DISCONNECTED = 14,
+    USB_TYPE_FREE = 15,
+    USB_TYPE_IDLE = 16,
+    USB_TYPE_PROCESSING = 17,
+
+    USB_TYPE_ERROR = 18,
+};
+
+
+enum ENDPOINT_DIRECTION {
+    OUT = 1,
+    IN
+};
+
+enum ENDPOINT_TYPE {
+    CONTROL_ENDPOINT = 0,
+    ISOCHRONOUS_ENDPOINT,
+    BULK_ENDPOINT,
+    INTERRUPT_ENDPOINT
+};
+
+#define AUDIO_CLASS     0x01
+#define CDC_CLASS       0x02
+#define HID_CLASS       0x03
+#define MSD_CLASS       0x08
+#define HUB_CLASS       0x09
+#define SERIAL_CLASS    0x0A
+
+#define  DEVICE_DESCRIPTOR                     (1)
+#define  CONFIGURATION_DESCRIPTOR              (2)
+#define  INTERFACE_DESCRIPTOR                  (4)
+#define  ENDPOINT_DESCRIPTOR                   (5)
+#define  HID_DESCRIPTOR                        (33)
+
+//  ----------- Control RequestType Fields  ----------- 
+#define  USB_DEVICE_TO_HOST         0x80
+#define  USB_HOST_TO_DEVICE         0x00
+#define  USB_REQUEST_TYPE_CLASS     0x20
+#define  USB_REQUEST_TYPE_STANDARD  0x00
+#define  USB_RECIPIENT_DEVICE       0x00
+#define  USB_RECIPIENT_INTERFACE    0x01
+#define  USB_RECIPIENT_ENDPOINT     0x02
+
+// -------------- USB Standard Requests  -------------- 
+#define  GET_STATUS                 0x00
+#define  SET_FEATURE                0x03
+#define  SET_ADDRESS                0x05
+#define  GET_DESCRIPTOR             0x06
+#define  SET_CONFIGURATION          0x09
+#define  SET_INTERFACE              0x0b
+#define  CLEAR_FEATURE              0x01
+
+// -------------- USB Descriptor Length  -------------- 
+#define DEVICE_DESCRIPTOR_LENGTH            0x12
+#define CONFIGURATION_DESCRIPTOR_LENGTH     0x09
+
+// PID
+#define DATA0 0x03
+#define DATA1 0x0b
+#define ACK   0x02
+#define STALL 0x0e
+#define NAK   0x0a
+
+#pragma pack(push,1)
+typedef struct {
+    uint8_t bLength;            
+    uint8_t bDescriptorType;    
+    uint16_t bcdUSB;            
+    uint8_t bDeviceClass;       
+    uint8_t bDeviceSubClass;    
+    uint8_t bDeviceProtocol;    
+    uint8_t bMaxPacketSize;     
+    uint16_t idVendor;          
+    uint16_t idProduct;         
+    uint16_t bcdDevice;         
+    uint8_t iManufacturer;      
+    uint8_t iProduct;           
+    uint8_t iSerialNumber;      
+    uint8_t bNumConfigurations; 
+} PACKED DeviceDescriptor;
+
+typedef struct {
+    uint8_t bLength;               
+    uint8_t bDescriptorType;       
+    uint16_t wTotalLength;         
+    uint8_t bNumInterfaces;        
+    uint8_t bConfigurationValue;   
+    uint8_t iConfiguration;        
+    uint8_t bmAttributes;          
+    uint8_t bMaxPower;             
+} PACKED ConfigurationDescriptor; 
+
+typedef struct {
+    uint8_t bLength;                 
+    uint8_t bDescriptorType;   
+    uint8_t bInterfaceNumber;  
+    uint8_t bAlternateSetting; 
+    uint8_t bNumEndpoints;     
+    uint8_t bInterfaceClass;   
+    uint8_t bInterfaceSubClass;
+    uint8_t bInterfaceProtocol;
+    uint8_t iInterface;        
+} InterfaceDescriptor; 
+
+typedef struct {
+    uint8_t bLength;          
+    uint8_t bDescriptorType;  
+    uint8_t bEndpointAddress; 
+    uint8_t bmAttributes;     
+    uint16_t wMaxPacketSize;  
+    uint8_t bInterval;        
+} EndpointDescriptor;
+
+typedef struct {
+    uint8_t bDescLength;      
+    uint8_t bDescriptorType;  
+    uint8_t bNbrPorts;        
+    uint16_t wHubCharacteristics;
+    uint8_t bPwrOn2PwrGood;   
+    uint8_t bHubContrCurrent; 
+    uint8_t DeviceRemovable;  
+    uint8_t PortPweCtrlMak;   
+} HubDescriptor;              
+#pragma pack(pop)
+
+#endif
+
diff -r 000000000000 -r 3dac1f1bc9e0 USBHost/dbg.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/dbg.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,91 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USB_DEBUG_H
+#define USB_DEBUG_H
+
+//Debug is disabled by default
+#ifndef DEBUG
+//#define DEBUG 3 /*INFO,ERR,WARN*/
+#define DEBUG 0
+#endif
+#ifndef DEBUG2
+#define DEBUG2 0
+#endif
+#define DEBUG_TRANSFER 0
+#define DEBUG_EP_STATE 0
+#define DEBUG_EVENT 0
+
+#if (DEBUG > 3)
+#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0);
+//#define USB_DBG(x, ...) std::printf("[USB_DBG: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#define USB_DBG_HEX(A,B) debug_hex(A,B)
+extern void debug_hex(uint8_t* buf, int size);
+#define USB_DBG_ERRSTAT() report.print_errstat();
+#else
+#define USB_DBG(x, ...)
+#define USB_DBG_HEX(A,B) while(0)
+#define USB_DBG_ERRSTAT() while(0)
+#endif
+
+#if (DEBUG2 > 3)
+#define USB_DBG2(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0);
+#else
+#define USB_DBG2(...)  while(0);
+#endif
+
+#if (DEBUG > 2)
+#define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");}while(0);
+//#define USB_INFO(x, ...) std::printf("[USB_INFO: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_INFO(x, ...)
+#endif
+
+#if (DEBUG > 1)
+#define USB_WARN(x, ...) std::printf("[USB_WARNING: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_WARN(x, ...)
+#endif
+
+#if (DEBUG > 0)
+#define USB_ERR(x, ...) std::printf("[USB_ERR: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_ERR(x, ...)
+#endif
+
+#if (DEBUG_TRANSFER)
+#define USB_DBG_TRANSFER(x, ...) std::printf("[USB_TRANSFER: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_DBG_TRANSFER(x, ...)
+#endif
+
+#if (DEBUG_EVENT)
+#define USB_DBG_EVENT(x, ...) std::printf("[USB_EVENT: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_DBG_EVENT(x, ...)
+#endif
+
+#ifdef _USB_TEST
+#define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
+#define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A))
+#else
+#define USB_TEST_ASSERT(A) while(0)
+#define USB_TEST_ASSERT_FALSE(A) while(0)
+#endif
+
+#endif
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 USBHost/mydebug.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mydebug.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,14 @@
+#pragma once
+template<class SERIAL_T>
+void debug_hex(SERIAL_T& pc, const uint8_t* buf, int size)
+{
+    for(int i = 0; i < size; i++) {
+        pc.printf("%02x ", buf[i]);
+        if (i%16 == 15) {
+            pc.puts("\n");
+        }
+    }
+    pc.puts("\n");
+}
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 USBHost/mymap.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mymap.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,66 @@
+#pragma once
+
+template<class K,class T>
+class mymap {
+    struct mypair {
+        K first;
+        T second;
+    };
+public:
+    mymap() {
+        m_size = 0;
+    }
+    T& operator[](const K& key) {
+        int it;
+        if (count(key) == 0) {
+            it = insert(key, 0);
+        } else {
+            it = find(key);
+        }
+        return m_buf[it].second;
+    }
+    bool empty() { return m_size == 0 ? true : false; }
+    int size() { return m_size; }
+    void clear() { m_size = 0; }
+    int count(K key) {
+        for(int i = 0; i < m_size; i++) {
+            if (m_buf[i].first == key) {
+                return 1;
+            }
+        }
+        return 0;
+    }
+
+private:
+    int find(K key) {
+        for(int i = 0; i < m_size; i++) {
+            if (m_buf[i].first == key) {
+                return i;
+            }
+        }
+        return -1;
+    }
+    int insert(K key, T value) {
+        int it = find(key);
+        if (it != -1) {
+            m_buf[it].second = value;
+            return it;
+        }
+        mypair* new_buf = new mypair[m_size+1];
+        if (m_size > 0) {
+            for(int i = 0; i < m_size; i++) {
+                new_buf[i] = m_buf[i];
+            }
+            delete[] m_buf;
+        }
+        m_buf = new_buf;
+        it = m_size++;
+        m_buf[it].first = key;
+        m_buf[it].second = value;
+        return it;
+    }
+
+    int m_size;
+    mypair *m_buf;
+};
+
diff -r 000000000000 -r 3dac1f1bc9e0 USBHost/myvector.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/myvector.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,35 @@
+#pragma once
+
+template<class T>
+class myvector {
+public:
+    myvector() {
+        m_size = 0;
+        m_buf = NULL;
+    }
+    ~myvector() {
+        if (m_buf) {
+            delete[] m_buf;
+        }
+    }
+    void push_back(T v) {
+        T* new_buf = new T[m_size+1];
+        if (m_size > 0) {
+            for(int i = 0; i < m_size; i++) {
+                new_buf[i] = m_buf[i];
+            }
+            delete[] m_buf;
+        }
+        m_buf = new_buf;
+        m_buf[m_size++] = v;
+    }
+    T& operator[](const int index) {
+        return m_buf[index];
+    }
+    int size() { return m_size; }
+
+private:
+    int m_size;
+    T *m_buf;
+};
+
diff -r 000000000000 -r 3dac1f1bc9e0 mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/c0f6e94411f5
\ No newline at end of file
diff -r 000000000000 -r 3dac1f1bc9e0 pNesX.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pNesX.cpp	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,1065 @@
+/*===================================================================*/
+/*                                                                   */
+/*  pNesX.cpp : NES Emulator for PSX                                 */
+/*                                                                   */
+/*  1999/11/03  Racoon  New preparation                              */
+/*  2016/ 1/20  Racoon  Some optimization.                           */
+/*                                                                   */
+/*===================================================================*/
+
+/*-------------------------------------------------------------------
+ * File List :
+ *
+ * [NES Hardware]
+ *   pNesX.cpp
+ *   pNesX.h
+ *   K6502_rw.h
+ *   pNesX_Apu.cpp (Added)
+ *
+ * [Mapper function]
+ *   pNesX_Mapper.cpp
+ *   pNesX_Mapper.h
+ *
+ * [The function which depends on a system]
+ *   pNesX_System_ooo.cpp (ooo is a system name. psx, win, Nucleo...)
+ *   pNesX_System.h
+ *
+ * [CPU]
+ *   K6502.cpp
+ *   K6502.h
+ *
+ * [Others]
+ *   pNesX_Types.h
+ *
+ --------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------*/
+/*  Include files                                                    */
+/*-------------------------------------------------------------------*/
+
+#include "mbed.h"
+#include "pNesX.h"
+#include "pNesX_System.h"
+#include "pNesX_Mapper.h"
+#include "K6502.h"
+
+/*-------------------------------------------------------------------*/
+/*  NES resources                                                    */
+/*-------------------------------------------------------------------*/
+
+/* RAM */
+BYTE RAM[ RAM_SIZE ];
+
+/* SRAM */
+BYTE SRAM[ SRAM_SIZE ];
+
+/* ROM */
+BYTE *ROM;
+
+/* ROM BANK ( 8Kb * 4 ) */
+BYTE *ROMBANK0;
+BYTE *ROMBANK1;
+BYTE *ROMBANK2;
+BYTE *ROMBANK3;
+
+/*-------------------------------------------------------------------*/
+/*  PPU resources                                                    */
+/*-------------------------------------------------------------------*/
+
+/* PPU RAM */
+BYTE PPURAM[ PPURAM_SIZE ];
+
+/* VROM */
+BYTE *VROM;
+
+/* PPU BANK ( 1Kb * 16 ) */
+BYTE *PPUBANK[ 16 ];
+
+/* Sprite RAM */
+BYTE SPRRAM[ SPRRAM_SIZE ];
+
+/* PPU Register */
+BYTE PPU_R0;
+BYTE PPU_R1;
+BYTE PPU_R2;
+BYTE PPU_R3;
+BYTE PPU_R7;
+
+/* Flag for PPU Address and Scroll Latch */
+BYTE PPU_Latch_Flag;
+
+/* Vertical scroll value */
+BYTE PPU_Scr_V;
+BYTE PPU_Scr_V_Next;
+BYTE PPU_Scr_V_Byte;
+BYTE PPU_Scr_V_Byte_Next;
+BYTE PPU_Scr_V_Bit;
+BYTE PPU_Scr_V_Bit_Next;
+
+/* Horizontal scroll value */
+BYTE PPU_Scr_H;
+BYTE PPU_Scr_H_Next;
+BYTE PPU_Scr_H_Byte;
+BYTE PPU_Scr_H_Byte_Next;
+BYTE PPU_Scr_H_Bit;
+BYTE PPU_Scr_H_Bit_Next;
+
+/* PPU Address */
+WORD PPU_Addr;
+
+/* The increase value of the PPU Address */
+WORD PPU_Increment;
+
+/* Current Scanline */
+WORD PPU_Scanline;
+
+/* Scanline Table */
+//BYTE PPU_ScanTable[ 263 ];
+
+/* Name Table Bank */
+BYTE PPU_NameTableBank;
+
+/* BG Base Address */
+BYTE *PPU_BG_Base;
+
+/* Sprite Base Address */
+BYTE *PPU_SP_Base;
+
+/* Sprite Height */
+WORD PPU_SP_Height;
+
+/* Sprite #0 Scanline Hit Position */
+int SpriteHitPos;
+
+/*-------------------------------------------------------------------*/
+/*  Display and Others resouces                                      */
+/*-------------------------------------------------------------------*/
+
+/* Frame Skip */
+WORD FrameSkip;
+WORD FrameCnt;
+bool FrameDraw;
+
+/* Display Line Buffer */
+WORD LineData[2][ NES_DISP_WIDTH ];
+WORD *pDrawData;
+int LineDataIdx;
+
+/* Character Buffer */
+BYTE ChrBuf[ 256 * 2 * 8 * 8 ];
+
+/* Update flag for ChrBuf */
+BYTE ChrBufUpdate;
+
+/* Palette Table */
+WORD PalTable[ 32 ];
+
+/* Table for Mirroring */
+const BYTE PPU_MirrorTable[][ 4 ] =
+{
+  { NAME_TABLE0, NAME_TABLE0, NAME_TABLE1, NAME_TABLE1 },
+  { NAME_TABLE0, NAME_TABLE1, NAME_TABLE0, NAME_TABLE1 },
+  { NAME_TABLE1, NAME_TABLE1, NAME_TABLE1, NAME_TABLE1 },
+  { NAME_TABLE0, NAME_TABLE0, NAME_TABLE0, NAME_TABLE0 }
+};
+
+/*-------------------------------------------------------------------*/
+/*  APU and Pad resources                                            */
+/*-------------------------------------------------------------------*/
+
+/* APU Register */
+BYTE APU_Reg[ 0x18 ];
+
+/* Pad data */
+DWORD PAD1_Latch;
+DWORD PAD2_Latch;
+DWORD PAD_System;
+DWORD PAD1_Bit;
+DWORD PAD2_Bit;
+
+/*-------------------------------------------------------------------*/
+/*  Mapper Function                                                  */
+/*-------------------------------------------------------------------*/
+
+/* Initialize Mapper */
+void (*MapperInit)();
+/* Write to Mapper */
+void (*MapperWrite)( WORD wAddr, BYTE byData );
+/* Callback at VSync */
+void (*MapperVSync)();
+/* Callback at HSync */
+void (*MapperHSync)();
+
+/*-------------------------------------------------------------------*/
+/*  ROM information                                                  */
+/*-------------------------------------------------------------------*/
+
+/* .nes File Header */
+struct NesHeader_tag NesHeader;
+
+/* Mapper Number */
+BYTE MapperNo;
+
+/* Mirroring 0:Horizontal 1:Vertical */
+BYTE ROM_Mirroring;
+/* It has SRAM */
+BYTE ROM_SRAM;
+/* It has Trainer */
+BYTE ROM_Trainer;
+/* Four screen VRAM  */
+BYTE ROM_FourScr;
+
+/*===================================================================*/
+/*                                                                   */
+/*                pNesX_Init() : Initialize pNesX                    */
+/*                                                                   */
+/*===================================================================*/
+void pNesX_Init()
+{
+/*
+ *  Initialize pNesX
+ *
+ *  Remarks
+ *    Initialize K6502 and Scanline Table.
+ */
+
+  // Initialize 6502
+  K6502_Init();
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*                pNesX_Fin() : Completion treatment                 */
+/*                                                                   */
+/*===================================================================*/
+void pNesX_Fin()
+{
+/*
+ *  Completion treatment
+ *
+ *  Remarks
+ *    Release resources
+ */
+
+  // Release a memory for ROM
+  pNesX_ReleaseRom();
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*                  pNesX_Load() : Load a cassette                   */
+/*                                                                   */
+/*===================================================================*/
+int pNesX_Load( const char *pszFileName )
+{
+/*
+ *  Load a cassette
+ *
+ *  Parameters
+ *    const char *pszFileName            (Read)
+ *      File name of ROM image
+ *
+ *  Return values
+ *     0 : It was finished normally.
+ *    -1 : An error occurred.
+ *
+ *  Remarks
+ *    Read a ROM image in the memory. 
+ *    Reset pNesX.
+ */
+
+  // Release a memory for ROM
+  pNesX_ReleaseRom();
+
+  // Read a ROM image in the memory
+  if ( pNesX_ReadRom( pszFileName ) < 0 )
+    return -1;
+
+  // Reset pNesX
+  if ( pNesX_Reset() < 0 )
+    return -1;
+
+  // Successful
+  return 0;
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*                 pNesX_Reset() : Reset pNesX                       */
+/*                                                                   */
+/*===================================================================*/
+int pNesX_Reset()
+{
+/*
+ *  Reset pNesX
+ *
+ *  Return values
+ *     0 : Normally
+ *    -1 : Non support mapper
+ *
+ *  Remarks
+ *    Initialize Resources, PPU and Mapper.
+ *    Reset CPU.
+ */
+
+  int nIdx;
+
+  /*-------------------------------------------------------------------*/
+  /*  Get information on the cassette                                  */
+  /*-------------------------------------------------------------------*/
+
+  // Get Mapper Number
+  MapperNo = NesHeader.byInfo1 >> 4;
+
+  // Check bit counts of Mapper No.
+  for ( nIdx = 4; nIdx < 8 && NesHeader.byReserve[ nIdx ] == 0; ++nIdx )
+    ;
+
+  if ( nIdx == 8 )
+  {
+    // Mapper Number is 8bits
+    MapperNo |= ( NesHeader.byInfo2 & 0xf0 );
+  }
+
+  // Get information on the ROM
+  ROM_Mirroring = NesHeader.byInfo1 & 1;
+  ROM_SRAM = NesHeader.byInfo1 & 2;
+  ROM_Trainer = NesHeader.byInfo1 & 4;
+  ROM_FourScr = NesHeader.byInfo1 & 8;
+
+  /*-------------------------------------------------------------------*/
+  /*  Initialize resources                                             */
+  /*-------------------------------------------------------------------*/
+
+  // Clear RAM
+  pNesX_MemorySet( RAM, 0, sizeof RAM );
+
+  // Reset frame skip and frame count
+  FrameSkip = 2; // 0:full 1:half 2:2/3 3:1/3
+  FrameCnt = 0;
+  
+ 
+  // Reset update flag of ChrBuf
+  ChrBufUpdate = 0xff;
+
+  // Reset palette table
+  pNesX_MemorySet( PalTable, 0, sizeof PalTable );
+
+  // Reset APU register
+  pNesX_MemorySet( APU_Reg, 0, sizeof APU_Reg );
+
+  // Reset joypad
+  PAD1_Latch = PAD2_Latch = PAD_System = 0;
+  PAD1_Bit = PAD2_Bit = 0;
+
+  /*-------------------------------------------------------------------*/
+  /*  Initialize PPU                                                   */
+  /*-------------------------------------------------------------------*/
+
+  pNesX_SetupPPU();
+
+  /*-------------------------------------------------------------------*/
+  /*  Initialize Mapper                                                */
+  /*-------------------------------------------------------------------*/
+
+  // Get Mapper Table Index
+  for ( nIdx = 0; MapperTable[ nIdx ].nMapperNo != -1; ++nIdx )
+  {
+    if ( MapperTable[ nIdx ].nMapperNo == MapperNo )
+      break;
+  }
+
+  if ( MapperTable[ nIdx ].nMapperNo == -1 )
+  {
+    // Non support mapper
+    return -1;
+  }
+
+  // Set up a mapper initialization function
+  MapperTable[ nIdx ].pMapperInit();
+
+  /*-------------------------------------------------------------------*/
+  /*  Reset CPU                                                        */
+  /*-------------------------------------------------------------------*/
+
+  K6502_Reset();
+  
+  // Successful
+  return 0;
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*                pNesX_SetupPPU() : Initialize PPU                  */
+/*                                                                   */
+/*===================================================================*/
+void pNesX_SetupPPU()
+{
+/*
+ *  Initialize PPU
+ *
+ */
+  int nPage;
+
+  // Clear PPU and Sprite Memory
+  pNesX_MemorySet( PPURAM, 0, sizeof PPURAM );
+  pNesX_MemorySet( SPRRAM, 0, sizeof SPRRAM );
+
+  // Reset PPU Register
+  PPU_R0 = PPU_R1 = PPU_R2 = PPU_R3 = PPU_R7 = 0;
+
+  // Reset latch flag
+  PPU_Latch_Flag = 0;
+
+  // Reset Scroll values
+  PPU_Scr_V = PPU_Scr_V_Next = PPU_Scr_V_Byte = PPU_Scr_V_Byte_Next = PPU_Scr_V_Bit = PPU_Scr_V_Bit_Next = 0;
+  PPU_Scr_H = PPU_Scr_H_Next = PPU_Scr_H_Byte = PPU_Scr_H_Byte_Next = PPU_Scr_H_Bit = PPU_Scr_H_Bit_Next = 0;
+
+  // Reset PPU address
+  PPU_Addr = 0;
+
+  // Reset scanline
+  PPU_Scanline = 0;
+
+  // Reset hit position of sprite #0 
+  SpriteHitPos = 0;
+
+  // Reset information on PPU_R0
+  PPU_Increment = 1;
+  PPU_NameTableBank = NAME_TABLE0;
+  PPU_BG_Base = ChrBuf;
+  PPU_SP_Base = ChrBuf + 256 * 64;
+  PPU_SP_Height = 8;
+
+  // Reset PPU banks
+  for ( nPage = 0; nPage < 16; ++nPage )
+    PPUBANK[ nPage ] = &PPURAM[ nPage * 0x400 ];
+
+  /* Mirroring of Name Table */
+  pNesX_Mirroring( ROM_Mirroring );
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*       pNesX_Mirroring() : Set up a Mirroring of Name Table        */
+/*                                                                   */
+/*===================================================================*/
+void pNesX_Mirroring( int nType )
+{
+/*
+ *  Set up a Mirroring of Name Table
+ *
+ *  Parameters
+ *    int nType          (Read)
+ *      Mirroring Type
+ *        0 : Horizontal
+ *        1 : Vertical
+ *        2 : One Screen 0x2000
+ *        3 : One Screen 0x2400
+ */
+
+  PPUBANK[ NAME_TABLE0 ] = &PPURAM[ PPU_MirrorTable[ nType ][ 0 ] * 0x400 ];
+  PPUBANK[ NAME_TABLE1 ] = &PPURAM[ PPU_MirrorTable[ nType ][ 1 ] * 0x400 ];
+  PPUBANK[ NAME_TABLE2 ] = &PPURAM[ PPU_MirrorTable[ nType ][ 2 ] * 0x400 ];
+  PPUBANK[ NAME_TABLE3 ] = &PPURAM[ PPU_MirrorTable[ nType ][ 3 ] * 0x400 ];
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*              pNesX_Main() : The main loop of pNesX                */
+/*                                                                   */
+/*===================================================================*/
+void pNesX_Main()
+{
+/*
+ *  The main loop of pNesX
+ *
+ */
+
+  // Initialize pNesX
+  pNesX_Init();
+
+  // Main loop
+  while ( 1 )
+  {
+    /*-------------------------------------------------------------------*/
+    /*  To the menu screen                                               */
+    /*-------------------------------------------------------------------*/
+    if ( pNesX_Menu() == -1 )
+    {
+      break;  // Quit
+    }
+    
+    /*-------------------------------------------------------------------*/
+    /*  Start a NES emulation                                            */
+    /*-------------------------------------------------------------------*/
+    pNesX_Cycle();
+  }
+
+  // Completion treatment
+  pNesX_Fin();
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*              pNesX_Cycle() : The loop of emulation                */
+/*                                                                   */
+/*===================================================================*/
+void pNesX_Cycle()
+{
+/*
+ *  The loop of emulation
+ *
+ */
+
+  // Emulation loop
+  for (;;)
+  {
+    // Execute instructions
+    K6502_Step( 40 );
+
+    // Set a flag if a scanning line is a hit in the sprite #0
+    if ( ( SPRRAM[ SPR_Y ] + SpriteHitPos ) == PPU_Scanline &&
+         PPU_Scanline >= SCAN_ON_SCREEN_START && PPU_Scanline < SCAN_BOTTOM_OFF_SCREEN_START )
+         //PPU_ScanTable[ PPU_Scanline ] == SCAN_ON_SCREEN )
+    {
+      // Set a sprite hit flag
+      PPU_R2 |= R2_HIT_SP;
+
+      // NMI is required if there is necessity
+      if ( ( PPU_R0 & R0_NMI_SP ) && ( PPU_R1 & R1_SHOW_SP ) )
+        NMI_REQ;
+    }
+    
+    // Execute instructions
+    K6502_Step( 75 );
+
+    // A mapper function in H-Sync
+    MapperHSync();
+
+    // A function in H-Sync
+    if ( pNesX_HSync() == -1 )
+      return;  // To the menu screen
+  }
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*              pNesX_HSync() : A function in H-Sync                 */
+/*                                                                   */
+/*===================================================================*/
+int pNesX_HSync()
+{
+/*
+ *  A function in H-Sync
+ *
+ *  Return values
+ *    0 : Normally
+ *   -1 : Exit an emulation
+ */
+
+  /*-------------------------------------------------------------------*/
+  /*  Render a scanline                                                */
+  /*-------------------------------------------------------------------*/
+  if ( FrameDraw &&
+       PPU_Scanline >= SCAN_ON_SCREEN_START && PPU_Scanline < SCAN_BOTTOM_OFF_SCREEN_START )
+  {
+    pNesX_DrawLine();
+    pNesX_TransmitLinedata();
+  }
+
+  /*-------------------------------------------------------------------*/
+  /*  Set new scroll values                                            */
+  /*-------------------------------------------------------------------*/
+  PPU_Scr_V      = PPU_Scr_V_Next;
+  PPU_Scr_V_Byte = PPU_Scr_V_Byte_Next;
+  PPU_Scr_V_Bit  = PPU_Scr_V_Bit_Next;
+
+  PPU_Scr_H      = PPU_Scr_H_Next;
+  PPU_Scr_H_Byte = PPU_Scr_H_Byte_Next;
+  PPU_Scr_H_Bit  = PPU_Scr_H_Bit_Next;
+
+  /*-------------------------------------------------------------------*/
+  /*  Next Scanline                                                    */
+  /*-------------------------------------------------------------------*/
+  PPU_Scanline = ( PPU_Scanline == SCAN_VBLANK_END ) ? 0 : PPU_Scanline + 1;
+
+  /*-------------------------------------------------------------------*/
+  /*  Operation in the specific scanning line                          */
+  /*-------------------------------------------------------------------*/
+  switch ( PPU_Scanline )
+  {
+    case SCAN_ON_SCREEN_START:
+      // Reset a PPU status
+      PPU_R2 = 0;
+
+      // Set up a character data
+      if ( NesHeader.byVRomSize == 0 && FrameDraw )
+        pNesX_SetupChr();
+
+      // Get position of sprite #0
+      pNesX_GetSprHitY();
+      break;
+
+    case SCAN_VBLANK_START:
+      // Frame skip
+      FrameCnt = ++FrameCnt % 6;
+      switch (FrameSkip)
+      {
+        case 0: // full
+          FrameDraw = true;
+          break;
+          
+        case 1: // 1/2
+          FrameDraw = FrameCnt & 1;
+          break;
+          
+        case 2: // 2/3
+          FrameDraw = !(FrameCnt == 2 || FrameCnt == 5);
+          break;
+          
+        case 3: // 1/3
+          FrameDraw = FrameCnt == 0 || FrameCnt == 3;  
+      } 
+        
+      pNesX_LoadFrame();
+      
+      // Set a V-Blank flag
+      PPU_R2 = R2_IN_VBLANK;
+
+      // Reset latch flag
+      PPU_Latch_Flag = 0;
+
+      // A mapper function in V-Sync
+      MapperVSync();
+
+      // Get the condition of the joypad
+      pNesX_PadState( &PAD1_Latch, &PAD2_Latch, &PAD_System );
+      
+      // NMI on V-Blank
+      if ( PPU_R0 & R0_NMI_VB )
+        NMI_REQ;
+
+      // Exit an emulation if a QUIT button is pushed
+      static DWORD quitWait;
+      if (PAD_PUSH( PAD_System, PAD_SYS_QUIT ))
+      {
+        quitWait++;
+      }
+      else
+      {
+        if (quitWait > 10)
+        {
+          quitWait = 0;
+          return -1;  // Exit an emulation
+        }
+        quitWait = 0;
+      }
+      break;
+      
+    case SCAN_APU_CLK1: // 240Hz
+    case SCAN_APU_CLK3: // 240Hz    
+      pNesX_ApuClk_240Hz();
+      break;
+
+    case SCAN_APU_CLK2: // 240Hz 120Hz
+      pNesX_ApuClk_240Hz();
+      pNesX_ApuClk_120Hz();
+      break;
+
+    case SCAN_APU_CLK4: // 240Hz 120Hz 60Hz
+      pNesX_ApuClk_240Hz();
+      pNesX_ApuClk_120Hz();
+      pNesX_ApuClk_60Hz();   
+      break;
+        
+  }
+
+  // Successful
+  return 0;
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*              pNesX_DrawLine() : Render a scanline                 */
+/*                                                                   */
+/*===================================================================*/
+
+
+void pNesX_DrawLine()
+{
+/*
+ *  Render a scanline
+ *
+ */
+  int nX;
+  int nY;
+  int nY4;
+  int nYBit;
+  WORD *pPalTbl;
+  BYTE *pAttrBase;
+  WORD *pPoint;
+  int nNameTable;
+  BYTE *pbyNameTable;
+  BYTE *pbyChrData;
+  BYTE *pSPRRAM;
+  int nAttr;
+  int nSprCnt;
+  int nIdx;
+  BYTE bySprCol;
+  bool bMask[ NES_DISP_WIDTH ];
+  bool *pMask;
+  
+  // Pointer to the render position
+  pPoint = LineData[LineDataIdx];
+  LineDataIdx = LineDataIdx == 0 ? 1 : 0;
+  pDrawData = pPoint;
+  
+  // Clear a scanline if screen is off
+  if ( !( PPU_R1 & R1_SHOW_SCR ) )
+  {
+    pNesX_MemorySet( pPoint, 0, NES_DISP_WIDTH << 1 );
+    return;
+  }
+
+  nNameTable = PPU_NameTableBank;
+
+  nY = PPU_Scr_V_Byte + ( PPU_Scanline >> 3 );
+
+  nYBit = PPU_Scr_V_Bit + ( PPU_Scanline & 7 );
+
+  if ( nYBit > 7 )
+  {
+    ++nY;
+    nYBit &= 7;
+  }
+  nYBit <<= 3;
+
+  if ( nY > 29 )
+  {
+    // Next NameTable (An up-down direction)
+    nNameTable ^= NAME_TABLE_V_MASK;
+    nY -= 30;
+  }
+
+  nX = PPU_Scr_H_Byte;
+
+  nY4 = ( ( nY & 2 ) << 1 );
+
+  pMask = bMask;
+  
+  /*-------------------------------------------------------------------*/
+  /*  Rendering of the block of the left end                           */
+  /*-------------------------------------------------------------------*/
+
+  pbyNameTable = PPUBANK[ nNameTable ] + nY * 32 + nX;
+  pbyChrData = PPU_BG_Base + ( *pbyNameTable << 6 ) + nYBit;
+  pAttrBase = PPUBANK[ nNameTable ] + 0x3c0 + ( nY / 4 ) * 8;
+  pPalTbl =  &PalTable[ ( ( ( pAttrBase[ nX >> 2 ] >> ( ( nX & 2 ) + nY4 ) ) & 3 ) << 2 ) ];
+
+  for ( nIdx = PPU_Scr_H_Bit; nIdx < 8; ++nIdx )
+  {
+    *( pPoint++ ) = pPalTbl[ pbyChrData[ nIdx ] ];
+    *pMask++ = pbyChrData[ nIdx ] == 0;
+  }
+
+  ++nX;
+  ++pbyNameTable;
+
+  /*-------------------------------------------------------------------*/
+  /*  Rendering of the left table                                      */
+  /*-------------------------------------------------------------------*/
+
+  for ( ; nX < 32; ++nX )
+  {
+    pbyChrData = PPU_BG_Base + ( *pbyNameTable << 6 ) + nYBit;
+    pPalTbl = &PalTable[ ( ( ( pAttrBase[ nX >> 2 ] >> ( ( nX & 2 ) + nY4 ) ) & 3 ) << 2 ) ];
+
+    *pPoint++ = pPalTbl[ pbyChrData[ 0 ] ]; 
+    *pPoint++ = pPalTbl[ pbyChrData[ 1 ] ];
+    *pPoint++ = pPalTbl[ pbyChrData[ 2 ] ];
+    *pPoint++ = pPalTbl[ pbyChrData[ 3 ] ];
+    *pPoint++ = pPalTbl[ pbyChrData[ 4 ] ];
+    *pPoint++ = pPalTbl[ pbyChrData[ 5 ] ];
+    *pPoint++ = pPalTbl[ pbyChrData[ 6 ] ];
+    *pPoint++ = pPalTbl[ pbyChrData[ 7 ] ];
+
+    *pMask++ = pbyChrData[ 0 ] == 0;
+    *pMask++ = pbyChrData[ 1 ] == 0;
+    *pMask++ = pbyChrData[ 2 ] == 0;
+    *pMask++ = pbyChrData[ 3 ] == 0;
+    *pMask++ = pbyChrData[ 4 ] == 0;
+    *pMask++ = pbyChrData[ 5 ] == 0;
+    *pMask++ = pbyChrData[ 6 ] == 0;
+    *pMask++ = pbyChrData[ 7 ] == 0;
+
+    ++pbyNameTable;
+  }
+
+  // Holizontal Mirror
+  nNameTable ^= NAME_TABLE_H_MASK;
+
+  pbyNameTable = PPUBANK[ nNameTable ] + nY * 32;
+  pAttrBase = PPUBANK[ nNameTable ] + 0x3c0 + ( nY / 4 ) * 8;
+
+  /*-------------------------------------------------------------------*/
+  /*  Rendering of the right table                                     */
+  /*-------------------------------------------------------------------*/
+
+  for ( nX = 0; nX < PPU_Scr_H_Byte; ++nX )
+  {
+    pbyChrData = PPU_BG_Base + ( *pbyNameTable << 6 ) + nYBit;
+    pPalTbl = &PalTable[ ( ( ( pAttrBase[ nX >> 2 ] >> ( ( nX & 2 ) + nY4 ) ) & 3 ) << 2 ) ];
+
+    *pPoint++ = pPalTbl[ pbyChrData[ 0 ] ]; 
+    *pPoint++ = pPalTbl[ pbyChrData[ 1 ] ];
+    *pPoint++ = pPalTbl[ pbyChrData[ 2 ] ];
+    *pPoint++ = pPalTbl[ pbyChrData[ 3 ] ];
+    *pPoint++ = pPalTbl[ pbyChrData[ 4 ] ];
+    *pPoint++ = pPalTbl[ pbyChrData[ 5 ] ];
+    *pPoint++ = pPalTbl[ pbyChrData[ 6 ] ];
+    *pPoint++ = pPalTbl[ pbyChrData[ 7 ] ];
+
+    *pMask++ = pbyChrData[ 0 ] == 0;
+    *pMask++ = pbyChrData[ 1 ] == 0;
+    *pMask++ = pbyChrData[ 2 ] == 0;
+    *pMask++ = pbyChrData[ 3 ] == 0;
+    *pMask++ = pbyChrData[ 4 ] == 0;
+    *pMask++ = pbyChrData[ 5 ] == 0;
+    *pMask++ = pbyChrData[ 6 ] == 0;
+    *pMask++ = pbyChrData[ 7 ] == 0;
+
+    ++pbyNameTable;
+  }
+
+  /*-------------------------------------------------------------------*/
+  /*  Rendering of the block of the right end                          */
+  /*-------------------------------------------------------------------*/
+
+  pbyChrData = PPU_BG_Base + ( *pbyNameTable << 6 ) + nYBit;
+  pPalTbl = &PalTable[ ( ( ( pAttrBase[ nX >> 2 ] >> ( ( nX & 2 ) + nY4 ) ) & 3 ) << 2 ) ];
+  for ( nIdx = 0; nIdx < PPU_Scr_H_Bit; ++nIdx )
+  {
+    pPoint[ nIdx ] = pPalTbl[ pbyChrData[ nIdx ] ];
+    *pMask++ = pbyChrData[ nIdx ] == 0;
+  }
+
+  /*-------------------------------------------------------------------*/
+  /*  Render a sprite                                                  */
+  /*-------------------------------------------------------------------*/
+
+  if ( PPU_R1 & R1_SHOW_SP )
+  {
+    // Reset Scanline Sprite Count
+    PPU_R2 &= ~R2_MAX_SP;
+
+    // Render a sprite to the sprite buffer
+    pPoint = pDrawData;
+    nSprCnt = 0;
+    for ( pSPRRAM = SPRRAM + ( 63 << 2 ); pSPRRAM >= SPRRAM &&
+                                          nSprCnt < 8; pSPRRAM -= 4 )
+    {
+      nY = pSPRRAM[ SPR_Y ] + 1;
+      if ( nY > PPU_Scanline || nY + PPU_SP_Height <= PPU_Scanline )
+        continue;  // Next sprite
+
+     /*-------------------------------------------------------------------*/
+     /*  A sprite in scanning line                                        */
+     /*-------------------------------------------------------------------*/
+
+      // Holizontal Sprite Count +1
+      ++nSprCnt;
+      
+      nAttr = pSPRRAM[ SPR_ATTR ];
+      nYBit = PPU_Scanline - nY;
+      nYBit = ( nAttr & SPR_ATTR_V_FLIP ) ? ( PPU_SP_Height - nYBit - 1 ) << 3 : nYBit << 3;
+
+      if ( PPU_R0 & R0_SP_SIZE )
+      {
+        // Sprite size 8x16
+        if ( pSPRRAM[ SPR_CHR ] & 1 )
+        {
+          pbyChrData = ChrBuf + 256 * 64 + ( ( pSPRRAM[ SPR_CHR ] & 0xfe ) << 6 ) + nYBit;
+        }
+        else
+        {
+          pbyChrData = ChrBuf + ( ( pSPRRAM[ SPR_CHR ] & 0xfe ) << 6 ) + nYBit;
+        }
+      }
+      else
+      {
+        // Sprite size 8x8
+        pbyChrData = PPU_SP_Base + ( pSPRRAM[ SPR_CHR ] << 6 ) + nYBit;
+      }
+
+      bool bSprFront = !(nAttr & SPR_ATTR_PRI);
+      bySprCol = (( nAttr & SPR_ATTR_COLOR ) << 2) + 0x10;
+      nX = pSPRRAM[ SPR_X ];
+
+      if ( nAttr & SPR_ATTR_H_FLIP )
+      {
+        // Horizontal flip
+        if ( pbyChrData[ 0 ] && nX < 249 && (bSprFront || bMask[nX + 7]) )
+          pPoint[ nX + 7 ] = PalTable[ bySprCol | pbyChrData[ 0 ] ];
+        if ( pbyChrData[ 1 ] && nX < 250 && (bSprFront || bMask[nX + 6]) )
+          pPoint[ nX + 6 ] = PalTable[ bySprCol | pbyChrData[ 1 ] ];
+        if ( pbyChrData[ 2 ] && nX < 251 && (bSprFront || bMask[nX + 5]) )
+          pPoint[ nX + 5 ] = PalTable[ bySprCol | pbyChrData[ 2 ] ];
+        if ( pbyChrData[ 3 ] && nX < 252 && (bSprFront || bMask[nX + 4]) )
+          pPoint[ nX + 4 ] = PalTable[ bySprCol | pbyChrData[ 3 ] ];
+        if ( pbyChrData[ 4 ] && nX < 253 && (bSprFront || bMask[nX + 3]) )
+          pPoint[ nX + 3 ] = PalTable[ bySprCol | pbyChrData[ 4 ] ];
+        if ( pbyChrData[ 5 ] && nX < 254 && (bSprFront || bMask[nX + 2]) )
+          pPoint[ nX + 2 ] = PalTable[ bySprCol | pbyChrData[ 5 ] ];
+        if ( pbyChrData[ 6 ] && nX < 255 && (bSprFront || bMask[nX + 1]) )
+          pPoint[ nX + 1 ] = PalTable[ bySprCol | pbyChrData[ 6 ] ];
+        if ( pbyChrData[ 7 ] && (bSprFront || bMask[nX]) )
+          pPoint[ nX ] = PalTable[ bySprCol | pbyChrData[ 7 ] ];
+      }
+      else
+      {
+        // Non flip
+        if ( pbyChrData[ 0 ] && (bSprFront || bMask[nX]) )
+          pPoint[ nX ]     = PalTable[ bySprCol | pbyChrData[ 0 ] ];
+        if ( pbyChrData[ 1 ] && nX < 255 && (bSprFront || bMask[nX + 1]) )
+          pPoint[ nX + 1 ] = PalTable[ bySprCol | pbyChrData[ 1 ] ];
+        if ( pbyChrData[ 2 ] && nX < 254 && (bSprFront || bMask[nX + 2]) )
+          pPoint[ nX + 2 ] = PalTable[ bySprCol | pbyChrData[ 2 ] ];
+        if ( pbyChrData[ 3 ] && nX < 253 && (bSprFront || bMask[nX + 3]) )
+          pPoint[ nX + 3 ] = PalTable[ bySprCol | pbyChrData[ 3 ] ];
+        if ( pbyChrData[ 4 ] && nX < 252 && (bSprFront || bMask[nX + 4]) )
+          pPoint[ nX + 4 ] = PalTable[ bySprCol | pbyChrData[ 4 ] ];
+        if ( pbyChrData[ 5 ] && nX < 251 && (bSprFront || bMask[nX + 5]) )
+          pPoint[ nX + 5 ] = PalTable[ bySprCol | pbyChrData[ 5 ] ];
+        if ( pbyChrData[ 6 ] && nX < 250 && (bSprFront || bMask[nX + 6]) )
+          pPoint[ nX + 6 ] = PalTable[ bySprCol | pbyChrData[ 6 ] ];
+        if ( pbyChrData[ 7 ] && nX < 249 && (bSprFront || bMask[nX + 7]) )
+          pPoint[ nX + 7 ] = PalTable[ bySprCol | pbyChrData[ 7 ] ];
+      }
+    }
+
+    if ( nSprCnt == 8 )
+      PPU_R2 |= R2_MAX_SP;  // Set a flag of maximum sprites on scanline
+  }
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*   pNesX_GetSprHitY() : Get a position of scanline hits sprite #0  */
+/*                                                                   */
+/*===================================================================*/
+void pNesX_GetSprHitY()
+{
+/*
+ * Get a position of scanline hits sprite #0
+ *
+ */
+
+  int nYBit;
+  DWORD *pdwChrData;
+  int nOff;
+
+  if ( SPRRAM[ SPR_ATTR ] & SPR_ATTR_V_FLIP )
+  {
+    // Vertical flip
+    nYBit = ( PPU_SP_Height - 1 ) << 3;
+    nOff = -2;
+  }
+  else
+  {
+    // Non flip
+    nYBit = 0;
+    nOff = 2;
+  }
+
+  if ( PPU_R0 & R0_SP_SIZE )
+  {
+    // Sprite size 8x16
+    if ( SPRRAM[ SPR_CHR ] & 1 )
+    {
+      pdwChrData = (DWORD *)( ChrBuf + 256 * 64 + ( ( SPRRAM[ SPR_CHR ] & 0xfe ) << 6 ) + nYBit );
+    }
+    else
+    {
+      pdwChrData = (DWORD * )( ChrBuf + ( ( SPRRAM[ SPR_CHR ] & 0xfe ) << 6 ) + nYBit );
+    } 
+  }
+  else
+  {
+    // Sprite size 8x8
+    pdwChrData = (DWORD *)( PPU_SP_Base + ( SPRRAM[ SPR_CHR ] << 6 ) + nYBit );
+  }
+
+  for ( SpriteHitPos = 1; SpriteHitPos < PPU_SP_Height + 1; ++SpriteHitPos )
+  {
+    if ( pdwChrData[ 0 ] | pdwChrData[ 1 ] )
+      return;  // Scanline hits sprite #0
+
+    pdwChrData += nOff;
+  }
+
+  // Scanline didn't hit sprite #0
+  SpriteHitPos = SCAN_VBLANK_END;
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*            pNesX_SetupChr() : Develop character data              */
+/*                                                                   */
+/*===================================================================*/
+void pNesX_SetupChr()
+{
+/*
+ *  Develop character data
+ *
+ */
+
+  BYTE *pbyBGData;
+  BYTE byData1;
+  BYTE byData2;
+  int nIdx;
+  int nY;
+  int nOff;
+  static BYTE *pbyPrevBank[ 8 ];
+  int nBank;
+
+  for ( nBank = 0; nBank < 8; ++nBank )
+  {
+    if ( pbyPrevBank[ nBank ] == PPUBANK[ nBank ] && !( ( ChrBufUpdate >> nBank ) & 1 ) )
+      continue;  // Next bank
+
+    /*-------------------------------------------------------------------*/
+    /*  An address is different from the last time                       */
+    /*    or                                                             */
+    /*  An update flag is being set                                      */
+    /*-------------------------------------------------------------------*/
+
+    for ( nIdx = 0; nIdx < 64; ++nIdx )
+    {
+      nOff = ( nBank << 12 ) + ( nIdx << 6 );
+
+      for ( nY = 0; nY < 8; ++nY )
+      {
+        pbyBGData = PPUBANK[ nBank ] + ( nIdx << 4 ) + nY;
+
+        byData1 = ( ( pbyBGData[ 0 ] >> 1 ) & 0x55 ) | ( pbyBGData[ 8 ] & 0xAA );
+        byData2 = ( pbyBGData[ 0 ] & 0x55 ) | ( ( pbyBGData[ 8 ] << 1 ) & 0xAA );
+
+        ChrBuf[ nOff++ ] = ( byData1 >> 6 ) & 3;
+        ChrBuf[ nOff++ ] = ( byData2 >> 6 ) & 3;
+        ChrBuf[ nOff++ ] = ( byData1 >> 4 ) & 3;
+        ChrBuf[ nOff++ ] = ( byData2 >> 4 ) & 3;
+        ChrBuf[ nOff++ ] = ( byData1 >> 2 ) & 3;
+        ChrBuf[ nOff++ ] = ( byData2 >> 2 ) & 3;
+        ChrBuf[ nOff++ ] = byData1 & 3;
+        ChrBuf[ nOff++ ] = byData2 & 3;
+      }
+    }
+    // Keep this address
+    pbyPrevBank[ nBank ] = PPUBANK[ nBank ];
+  }
+
+  // Reset update flag
+  ChrBufUpdate = 0;
+}
+
diff -r 000000000000 -r 3dac1f1bc9e0 pNesX.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pNesX.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,285 @@
+/*===================================================================*/
+/*                                                                   */
+/*  pNesX.h : NES Emulator for PSX                                   */
+/*                                                                   */
+/*  1999/11/03  Racoon  New preparation                              */
+/*                                                                   */
+/*===================================================================*/
+
+#ifndef PNESX_H_INCLUDED
+#define PNESX_H_INCLUDED
+
+/*-------------------------------------------------------------------*/
+/*  Include files                                                    */
+/*-------------------------------------------------------------------*/
+
+#include "pNesX_Types.h"
+
+/*-------------------------------------------------------------------*/
+/*  NES resources                                                    */
+/*-------------------------------------------------------------------*/
+
+#define RAM_SIZE     0x2000
+#define SRAM_SIZE    0x2000
+#define PPURAM_SIZE  0x4000
+#define SPRRAM_SIZE  256
+
+/* RAM */
+extern BYTE RAM[];
+
+/* SRAM */
+extern BYTE SRAM[];
+
+/* ROM */
+extern BYTE *ROM;
+
+/* ROM BANK ( 8Kb * 4 ) */
+extern BYTE *ROMBANK0;
+extern BYTE *ROMBANK1;
+extern BYTE *ROMBANK2;
+extern BYTE *ROMBANK3;
+
+/*-------------------------------------------------------------------*/
+/*  PPU resources                                                    */
+/*-------------------------------------------------------------------*/
+
+/* PPU RAM */
+extern BYTE PPURAM[];
+
+/* VROM */
+extern BYTE *VROM;
+
+/* PPU BANK ( 1Kb * 16 ) */
+extern BYTE *PPUBANK[];
+
+#define NAME_TABLE0  8
+#define NAME_TABLE1  9
+#define NAME_TABLE2  10
+#define NAME_TABLE3  11
+
+#define NAME_TABLE_V_MASK 2
+#define NAME_TABLE_H_MASK 1
+
+/* Sprite RAM */
+extern BYTE SPRRAM[];
+
+#define SPR_Y    0
+#define SPR_CHR  1
+#define SPR_ATTR 2
+#define SPR_X    3
+#define SPR_ATTR_COLOR  0x3
+#define SPR_ATTR_V_FLIP 0x80
+#define SPR_ATTR_H_FLIP 0x40
+#define SPR_ATTR_PRI    0x20
+
+/* PPU Register */
+extern BYTE PPU_R0;
+extern BYTE PPU_R1;
+extern BYTE PPU_R2;
+extern BYTE PPU_R3;
+extern BYTE PPU_R7;
+
+extern BYTE PPU_Scr_V;
+extern BYTE PPU_Scr_V_Next;
+extern BYTE PPU_Scr_V_Byte;
+extern BYTE PPU_Scr_V_Byte_Next;
+extern BYTE PPU_Scr_V_Bit;
+extern BYTE PPU_Scr_V_Bit_Next;
+
+extern BYTE PPU_Scr_H;
+extern BYTE PPU_Scr_H_Next;
+extern BYTE PPU_Scr_H_Byte;
+extern BYTE PPU_Scr_H_Byte_Next;
+extern BYTE PPU_Scr_H_Bit;
+extern BYTE PPU_Scr_H_Bit_Next;
+
+extern BYTE PPU_Latch_Flag;
+extern WORD PPU_Addr;
+extern WORD PPU_Increment;
+
+#define R0_NMI_VB      0x80
+#define R0_NMI_SP      0x40
+#define R0_SP_SIZE     0x20
+#define R0_BG_ADDR     0x10
+#define R0_SP_ADDR     0x08
+#define R0_INC_ADDR    0x04
+#define R0_NAME_ADDR   0x03
+
+#define R1_BACKCOLOR   0xe0
+#define R1_SHOW_SP     0x10
+#define R1_SHOW_SCR    0x08
+#define R1_CLIP_SP     0x04
+#define R1_CLIP_BG     0x02
+#define R1_MONOCHROME  0x01
+
+#define R2_IN_VBLANK   0x80
+#define R2_HIT_SP      0x40
+#define R2_MAX_SP      0x20
+#define R2_WRITE_FLAG  0x10
+
+#define SCAN_TOP_OFF_SCREEN_START       0 
+#define SCAN_ON_SCREEN_START            8
+#define SCAN_BOTTOM_OFF_SCREEN_START  232
+#define SCAN_POSTRENDER_START          240
+#define SCAN_VBLANK_START             245
+#define SCAN_VBLANK_END               261
+
+#define SCAN_APU_CLK1   45      // 240Hz
+#define SCAN_APU_CLK2   110     // 240Hz 120Hz
+#define SCAN_APU_CLK3   176     // 240Hz
+#define SCAN_APU_CLK4   241     // 240Hz 120Hz 60Hz
+
+/* Current Scanline */
+extern WORD PPU_Scanline;
+
+/* Scanline Table */
+extern BYTE PPU_ScanTable[];
+
+/* Name Table Bank */
+extern BYTE PPU_NameTableBank;
+
+/* BG Base Address */
+extern BYTE *PPU_BG_Base;
+
+/* Sprite Base Address */
+extern BYTE *PPU_SP_Base;
+
+/* Sprite Height */
+extern WORD PPU_SP_Height;
+
+/* NES display size */
+#define NES_DISP_WIDTH      256
+#define NES_DISP_HEIGHT     224
+
+/*-------------------------------------------------------------------*/
+/*  Display and Others resouces                                      */
+/*-------------------------------------------------------------------*/
+
+/* Frame Skip */
+extern WORD FrameSkip;
+extern WORD FrameCnt;
+
+//extern WORD DoubleFrame[ 2 ][ NES_DISP_WIDTH * NES_DISP_HEIGHT ];
+//extern WORD DoubleFrame[ 2 ][ NES_DISP_WIDTH ];
+extern WORD *WorkFrame;
+extern WORD WorkFrameIdx;
+
+extern BYTE ChrBuf[];
+
+extern BYTE ChrBufUpdate;
+
+extern WORD PalTable[];
+
+/*-------------------------------------------------------------------*/
+/*  APU and Pad resources                                            */
+/*-------------------------------------------------------------------*/
+
+extern BYTE APU_Reg[];
+
+extern DWORD PAD1_Latch;
+extern DWORD PAD2_Latch;
+extern DWORD PAD_System;
+extern DWORD PAD1_Bit;
+extern DWORD PAD2_Bit;
+
+#define PAD_SYS_QUIT   1
+#define PAD_SYS_OK     2
+#define PAD_SYS_CANCEL 4
+#define PAD_SYS_UP     8
+#define PAD_SYS_DOWN   0x10
+#define PAD_SYS_LEFT   0x20
+#define PAD_SYS_RIGHT  0x40
+
+#define PAD_PUSH(a,b)  ( ( (a) & (b) ) != 0 )
+
+/*-------------------------------------------------------------------*/
+/*  Mapper Function                                                  */
+/*-------------------------------------------------------------------*/
+
+/* Initialize Mapper */
+extern void (*MapperInit)();
+/* Write to Mapper */
+extern void (*MapperWrite)( WORD wAddr, BYTE byData );
+/* Callback at VSync */
+extern void (*MapperVSync)();
+/* Callback at HSync */
+extern void (*MapperHSync)();
+
+/*-------------------------------------------------------------------*/
+/*  ROM information                                                  */
+/*-------------------------------------------------------------------*/
+
+/* .nes File Header */
+struct NesHeader_tag
+{
+  BYTE byID[ 4 ];
+  BYTE byRomSize;
+  BYTE byVRomSize;
+  BYTE byInfo1;
+  BYTE byInfo2;
+  BYTE byReserve[ 8 ];
+};
+
+/* .nes File Header */
+extern struct NesHeader_tag NesHeader;
+
+/* Mapper No. */
+extern BYTE MapperNo;
+
+/* Other */
+extern BYTE ROM_Mirroring;
+extern BYTE ROM_SRAM;
+extern BYTE ROM_Trainer;
+extern BYTE ROM_FourScr;
+
+/*-------------------------------------------------------------------*/
+/*  Function prototypes                                              */
+/*-------------------------------------------------------------------*/
+
+/* Initialize pNesX */
+void pNesX_Init();
+
+/* Completion treatment */
+void pNesX_Fin();
+
+/* Load a cassette */
+int pNesX_Load( const char *pszFileName );
+
+/* Reset pNesX */
+int pNesX_Reset();
+
+/* Initialize PPU */
+void pNesX_SetupPPU();
+
+/* Set up a Mirroring of Name Table */
+void pNesX_Mirroring( int nType );
+
+/* The main loop of pNesX */ 
+void pNesX_Main();
+
+/* The loop of emulation */
+void pNesX_Cycle();
+
+/* A function in H-Sync */
+int pNesX_HSync();
+
+/* Render a scanline */
+void pNesX_DrawLine();
+
+/* Get a position of scanline hits sprite #0 */
+void pNesX_GetSprHitY();
+
+/* Develop character data */
+void pNesX_SetupChr();
+
+/* Apu */
+void ApuInit();
+void ApuWrite(WORD wAddr, BYTE byData);
+BYTE ApuRead(WORD wAddr);
+void pNesX_ApuClk_240Hz();
+void pNesX_ApuClk_120Hz();
+void pNesX_ApuClk_60Hz();
+
+#endif /* !PNESX_H_INCLUDED */
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 pNesX_Apu.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pNesX_Apu.cpp	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,674 @@
+/*===================================================================*/
+/*                                                                   */
+/*  pNesX_Apu.cpp : NES APU emulation (for Nucleo)                   */
+/*                                                                   */
+/*  2016/1/20  Racoon                                                */
+/*                                                                   */
+/*===================================================================*/
+
+#include "mbed.h"
+#include "SDFileSystem.h"
+
+#include "pNesX.h"
+#include "pNesX_System.h"
+
+//====================
+// DAC
+//====================
+AnalogOut DAC_Out(PA_4);
+WORD TrDac, P1Dac, P2Dac, NsDac, MixDac;
+#define DACFreq 24000
+// Pulse clock(8 steps) = 1789773 / 2 / DACFreq * 1000
+#define PuClock 37287
+// Triangle clock(32 steps) = 1789773 / DACFreq * 1000
+#define TrClock 74574
+
+//====================
+// DAC Timer
+//====================
+#define TIMx                TIM4
+#define TIMx_CLK_ENABLE     __HAL_RCC_TIM4_CLK_ENABLE
+#define TIMx_IRQn           TIM4_IRQn
+#define TIMx_IRQHandler     TIM4_IRQHandler
+TIM_HandleTypeDef TimHandle;
+
+//====================
+// Audio channel variables
+//====================
+
+const BYTE LengthTable[] = {10, 254, 20,  2, 40,  4, 80,  6, 160,  8, 60, 10, 14, 12, 26, 14,
+                            12, 16, 24, 18, 48, 20, 96, 22, 192, 24, 72, 26, 16, 28, 32, 30};
+
+// Minimum Volume
+#define MV 4096
+const WORD Pulse_Table[4][8] = { 0,MV, 0, 0, 0, 0, 0, 0,
+                                 0,MV,MV, 0, 0, 0, 0, 0,
+                                 0,MV,MV,MV,MV, 0, 0, 0,
+                                MV, 0, 0,MV,MV,MV,MV,MV};
+// Pulse1
+bool P1Enable;
+int P1Timer;
+int P1WaveLength;
+int P1WavePeriod;
+int P1Lapse;
+int P1Duty;
+int P1Vol;
+int P1LengthCounter;
+int P1EnvSeq;
+int P1EnvCnt;
+int P1Sweep;
+int P1SwCnt;
+int P1SwLevel;
+bool P1SwReloadFlag;
+bool P1SwOverflow;
+
+// Pulse2
+bool P2Enable;
+int P2Timer;
+int P2WaveLength;
+int P2WavePeriod;
+int P2Lapse;
+int P2Duty;
+int P2Vol;
+int P2LengthCounter;
+int P2EnvSeq;
+int P2EnvCnt;
+int P2Sweep;
+int P2SwCnt;
+int P2SwLevel;
+bool P2SwReloadFlag;
+bool P2SwOverflow;
+    
+// Triangle                   
+bool TrEnable;
+int TrTimer;
+const WORD Triangle_Table[] = {61440,57344,53248,49152,45056,40960,36864,32768,28672,24576,20480,16384,12288,8192,4096,0,
+                               0,4096,8192,12288,16384,20480,24576,28672,32768,36864,40960,45056,49152,53248,57344,61440};
+bool LinearCounterReloadFlag;
+int LinearCounter;
+int TrLengthCounter;
+int TrWaveLength;
+int TrWavePeriod;
+int TrLapse;
+
+// Noise
+bool NsEnable;
+const WORD Noise_Freq[] = {0,0,0,0,0,0,12000,11186,8860,7046,4710,3523,2349,1762,880,440};
+int NsFreq;
+int NsSum;
+int NsVol;
+int NsLengthCounter;
+int NsEnvSeq;
+int NsEnvCnt;
+
+// DMC
+int DmOutLevel;
+
+/*-------------------------------------------------------------------*/
+/*  DAC Timer callback                                               */
+/*-------------------------------------------------------------------*/
+extern "C" {
+void TIMx_IRQHandler(void)
+{
+  HAL_TIM_IRQHandler(&TimHandle);
+}
+
+void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
+{
+  TIMx_CLK_ENABLE();
+  
+  HAL_NVIC_SetPriority(TIMx_IRQn, 4, 0);
+  HAL_NVIC_EnableIRQ(TIMx_IRQn);
+}
+
+static void Error_Handler(void)
+{
+  while(1);
+}
+} // extern "C"
+
+/*-------------------------------------------------------------------*/
+/*  Randomize value (Noise channel)                                  */
+/*-------------------------------------------------------------------*/
+WORD ShiftReg = 1;
+
+WORD Rand96()
+{
+    ShiftReg |= ((ShiftReg ^ (ShiftReg >> 6)) & 1) << 15;
+    ShiftReg >>= 1;
+    return (ShiftReg & 1) ? MV : 0;    
+}
+
+WORD Rand32k()
+{
+    ShiftReg |= ((ShiftReg ^ (ShiftReg >> 1)) & 1) << 15;
+    ShiftReg >>= 1;
+    return (ShiftReg & 1) ? MV : 0;    
+}
+
+/*-------------------------------------------------------------------*/
+/*  DAC Timer Interrup                                               */
+/*-------------------------------------------------------------------*/
+void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
+{
+    // Pulse1
+    if (P1Enable && P1LengthCounter > 0 && !P1SwOverflow && P1Timer > 8)
+    {
+        P1Lapse += PuClock; 
+        P1Lapse %= P1WavePeriod;
+        P1Dac = Pulse_Table[P1Duty][P1Lapse / P1WaveLength] * P1Vol;           
+    }
+
+    // Pulse2
+    if (P2Enable && P2LengthCounter > 0 && !P2SwOverflow && P2Timer > 8)
+    {
+        P2Lapse += PuClock; 
+        P2Lapse %= P2WavePeriod;
+        P2Dac = Pulse_Table[P2Duty][P2Lapse / P2WaveLength] * P2Vol;   
+    }
+    
+    // Triangle
+    if (TrEnable && LinearCounter > 0 && TrLengthCounter > 0)
+    {
+        TrLapse += TrClock; 
+        TrLapse %= TrWavePeriod;
+        TrDac = Triangle_Table[TrLapse / TrWaveLength];        
+        TrDac -= (TrDac * DmOutLevel / 295);
+    }
+    
+    // Noise
+    if (NsEnable && NsLengthCounter > 0)
+    {
+        NsSum += NsFreq;
+        if (NsSum >= DACFreq)
+        {
+            NsSum %= DACFreq;
+
+            NsDac = ((APU_Reg[0xe] & 0x80) ? Rand96() : Rand32k()) * NsVol;
+            NsDac -= (NsDac * DmOutLevel / 295);            
+        }        
+    }
+        
+    // Mixing
+    MixDac = (P1Dac + P2Dac + TrDac + NsDac) / 4;
+        
+    // Output to DAC
+    DAC_Out.write_u16(MixDac);   
+}
+ 
+/*-------------------------------------------------------------------*/
+/*  Apu Initialize Function                                          */
+/*-------------------------------------------------------------------*/
+void ApuInit()
+{
+    // Setup DAC Timer  
+    TimHandle.Instance = TIMx;   
+    TimHandle.Init.Prescaler = (uint32_t) ((SystemCoreClock / 2) / 240000) - 1; // 240000Hz
+    TimHandle.Init.Period = 10 - 1; // 240000/10=24000Hz 
+    TimHandle.Init.ClockDivision = 0;
+    TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
+    
+    if(HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
+        Error_Handler();
+    
+    if(HAL_TIM_Base_Start_IT(&TimHandle) != HAL_OK)
+        Error_Handler();
+}
+
+/*-------------------------------------------------------------------*/
+/*  Apu Mute                                                         */
+/*-------------------------------------------------------------------*/
+void ApuMute(bool mute)
+{
+    if (mute)
+    {
+        if(HAL_TIM_Base_Stop_IT(&TimHandle) != HAL_OK)
+            Error_Handler();
+    }
+    else
+    {
+        if(HAL_TIM_Base_Start_IT(&TimHandle) != HAL_OK)
+            Error_Handler();
+    }    
+}
+      
+/*-------------------------------------------------------------------*/
+/*  Apu Write Function                                               */
+/*-------------------------------------------------------------------*/
+void ApuWrite( WORD wAddr, BYTE byData )
+{
+  APU_Reg[ wAddr ] = byData;
+
+  switch( wAddr )
+  {
+    //====================
+    // Pulse1
+    //====================
+    case 0:
+      P1Duty = (byData & 0xc0) >> 6;
+    
+      if (byData & 0x10)
+      {
+        // constant volume
+        P1Vol = byData & 0xf;
+      }
+      else
+      {
+        // envelope on
+        P1Vol = 15;
+        P1EnvCnt = (byData & 0xf) + 1;
+      }
+      break;
+
+    case 1:
+      P1SwReloadFlag = true;
+      P1SwLevel = (byData & 7);
+      break;
+  
+    case 2:
+    case 3:
+      P1Timer = APU_Reg[3] & 7;
+      P1Timer = (P1Timer << 8) | APU_Reg[2];
+      P1WaveLength = (P1Timer+1) * 1000;
+      P1WavePeriod = P1WaveLength * 8;               
+
+      if (wAddr == 3)
+      {
+        P1LengthCounter = LengthTable[(byData & 0xf8) >> 3];
+    
+        // Reset sequencer
+        P1Lapse = 0;
+        P1EnvSeq = P1EnvCnt;
+        P1Sweep = 0;
+        P1SwCnt = 0;
+        P1SwOverflow = false;
+      }
+      break;
+      
+    //====================
+    // Pulse2
+    //====================
+    case 4:
+      P2Duty = (byData & 0xc0) >> 6;
+    
+      if (byData & 0x10)
+      {
+        // constant volume
+        P2Vol = byData & 0xf;
+      }
+      else
+      {
+        // envelope on
+        P2Vol = 15;
+        P2EnvCnt = (byData & 0xf) + 1;
+      }
+      break;
+      
+    case 5:
+      P2SwReloadFlag = true;
+      P2SwLevel = (byData & 7);
+      break;
+  
+    case 6:
+    case 7:
+      P2Timer = APU_Reg[7] & 7;
+      P2Timer = (P2Timer << 8) | APU_Reg[6];
+      P2WaveLength = (P2Timer+1) * 1000;
+      P2WavePeriod = P2WaveLength * 8;         
+      if (wAddr == 7)
+      {
+        P2LengthCounter = LengthTable[(byData & 0xf8) >> 3];
+    
+        // Reset sequencer
+        P2Lapse = 0;
+        P2EnvSeq = P2EnvCnt;
+        P2Sweep = 0;
+        P2SwCnt = 0;
+        P2SwOverflow = false;
+      }
+      break;
+      
+    //====================
+    // Triangle
+    //====================
+    case 0x8:
+      LinearCounterReloadFlag = true;
+      break;
+      
+    case 0xA:
+    case 0xB:
+      TrTimer = APU_Reg[0xB] & 7;
+      TrTimer = (TrTimer << 8) | APU_Reg[0xA];
+      TrWaveLength = TrTimer * 1000;
+      TrWavePeriod = TrWaveLength * 32;          
+      
+      if (wAddr == 0xB)
+      {
+        TrLengthCounter = LengthTable[(byData & 0xf8) >> 3];
+        LinearCounterReloadFlag = true;
+      }
+      break;
+      
+    //====================
+    // Noise
+    //====================
+    case 0xC:
+      if (byData & 0x10)
+      {
+        // constant volume
+        NsVol = byData & 0xf;
+      }
+      else
+      {
+        // envelope on
+        NsVol = 15;
+        NsEnvCnt = (byData & 0xf) + 1;
+      }
+      break;
+        
+    case 0xF:
+      NsLengthCounter = LengthTable[(byData & 0xf8) >> 3];
+    
+      // Reset sequencer
+      NsEnvSeq = NsEnvCnt;
+      break;
+
+    case 0xE:
+      NsFreq = Noise_Freq[byData & 0xf];
+      break;
+  
+    //====================
+    // DMC(PCM)
+    //====================
+    case 0x11:
+      DmOutLevel = byData & 0x7f;
+      break;
+      
+    //====================
+    // Control
+    //====================
+    case 0x15:
+      if (byData & 1)
+      {
+        P1Enable = true;
+      }
+      else
+      {
+        P1Enable = false;
+        P1LengthCounter = 0;
+      }
+              
+      if (byData & 2)
+      {
+        P2Enable = true;
+      }
+      else
+      {
+        P2Enable = false;
+        P2LengthCounter = 0;
+      }
+      
+      if (byData & 4)
+      {
+        TrEnable = true;
+      }
+      else
+      {
+        TrEnable = false;
+        TrLengthCounter = 0;
+      }
+
+      if (byData & 8)
+      {
+        NsEnable = true;
+      }
+      else
+      {
+        NsEnable = false;
+        NsLengthCounter = 0;
+      }
+      break;
+  } // Switch( wAddr ) 
+}
+
+/*-------------------------------------------------------------------*/
+/*  240Hz Clock                                                      */
+/*-------------------------------------------------------------------*/
+void pNesX_ApuClk_240Hz()
+{
+  //====================
+  // Pulse1 Envelope
+  //====================
+  if (!(APU_Reg[0] & 0x10) && P1EnvSeq > 0)
+  {
+    P1EnvSeq--;
+    if (P1EnvSeq == 0)
+    {
+      if (P1Vol > 0)
+      {
+        --P1Vol;
+        P1EnvSeq = P1EnvCnt;
+      }
+      else
+      { 
+        if (APU_Reg[0] & 0x20)
+        {
+          P1Vol = 15;
+          P1EnvSeq = P1EnvCnt;
+        }
+      }
+    }    
+  }
+
+  //====================
+  // Pulse2 Envelope
+  //====================
+  if (!(APU_Reg[4] & 0x10) && P2EnvSeq > 0)
+  {
+    P2EnvSeq--;
+    if (P2EnvSeq == 0)
+    {
+      if (P2Vol > 0)
+      {
+        --P2Vol;
+        P2EnvSeq = P2EnvCnt;
+      }
+      else
+      { 
+        if (APU_Reg[4] & 0x20)
+        {
+          P2Vol = 15;
+          P2EnvSeq = P2EnvCnt;
+        }
+      }
+    }    
+  }
+    
+  //====================
+  // Triangle Linear Counter
+  //====================
+  if (LinearCounterReloadFlag)
+  {
+    LinearCounter = APU_Reg[0x8] & 0x7f;
+  }
+  else if (LinearCounter > 0)
+  {
+    LinearCounter--;
+  }
+  
+  if (!(APU_Reg[0x8] & 0x80))
+  {
+    LinearCounterReloadFlag = false;
+  }
+  
+  //====================
+  // Noise Envelope
+  //====================
+  if (!(APU_Reg[0xc] & 0x10) && NsEnvSeq > 0)
+  {
+    NsEnvSeq--;
+    if (NsEnvSeq == 0)
+    {
+      if (NsVol > 0)
+      {
+        --NsVol;
+        NsEnvSeq = NsEnvCnt;
+      }
+      else
+      { 
+        if (APU_Reg[0xc] & 0x20)
+        {
+          NsVol = 15;
+          NsEnvSeq = NsEnvCnt;
+        }
+      }
+    }    
+  }  
+}
+
+/*-------------------------------------------------------------------*/
+/*  120Hz Clock                                                      */
+/*-------------------------------------------------------------------*/
+void pNesX_ApuClk_120Hz()
+{
+  //====================
+  // Pulse1 Sweep
+  //====================
+  if (P1SwReloadFlag)
+  {
+    P1Sweep = ((APU_Reg[1] & 0x70) >> 4) + 1;
+    P1SwCnt = 0;
+    P1SwReloadFlag = false;    
+  }
+  else if (APU_Reg[1] & 0x80 && !P1SwOverflow)
+  {
+    P1SwCnt++;
+    if (P1SwCnt == P1Sweep)
+    {
+      P1SwCnt = 0;
+      
+      int sweep = P1Timer >> P1SwLevel;
+      int value = P1Timer;
+      if (APU_Reg[1] & 8)
+      {
+        value = value - sweep - 1;
+        if (value < 8)
+        {
+          P1SwOverflow = true;
+          return;
+        }
+      }
+      else
+      {
+        value = value + sweep;
+        if (value > 0x7ff)
+        {
+          P1SwOverflow = true;
+          return;
+        }
+      } 
+      P1Timer = value;
+      
+      APU_Reg[3] &= 7;
+      APU_Reg[3] |= value >> 8;
+      APU_Reg[2] = value & 0xff;
+       
+      P1WaveLength = (value + 1) * 1000;
+      P1WavePeriod = P1WaveLength * 8;         
+    }
+  }
+
+  //====================
+  // Pulse1 Sweep
+  //====================  
+  if (P2SwReloadFlag)
+  {
+    P2Sweep = ((APU_Reg[5] & 0x70) >> 4) + 1;
+    P2SwCnt = 0;
+    P2SwReloadFlag = false;    
+  }
+  else if (APU_Reg[5] & 0x80 && !P2SwOverflow)
+  {
+    P2SwCnt++;
+    if (P2SwCnt == P2Sweep)
+    {
+      P2SwCnt = 0;
+      
+      int sweep = P2Timer >> P2SwLevel;
+      int value = P2Timer;
+      if (APU_Reg[5] & 8)
+      {
+        value = value - sweep;
+        if (value < 8)
+        {
+          P2SwOverflow = true;
+          return;
+        }
+      }
+      else
+      {
+        value = value + sweep;
+        if (value > 0x7ff)
+        {
+          P2SwOverflow = true;
+          return;
+        }
+      } 
+      
+      P2Timer = value;
+      
+      APU_Reg[7] &= 7;
+      APU_Reg[7] |= value >> 8;
+      APU_Reg[6] = value & 0xff;
+       
+      P2WaveLength = (value + 1) * 1000;
+      P2WavePeriod = P2WaveLength * 8;         
+      
+    }
+  }
+}
+
+/*-------------------------------------------------------------------*/
+/*  60Hz Clock                                                       */
+/*-------------------------------------------------------------------*/
+void pNesX_ApuClk_60Hz()
+{
+  // Pulse1
+  if (!(APU_Reg[0] & 0x20) && P1LengthCounter > 0)
+  {
+    P1LengthCounter--;
+  }
+
+  // Pulse2
+  if (!(APU_Reg[4] & 0x20) && P2LengthCounter > 0)
+  {
+    P2LengthCounter--;
+  }
+
+  // Triangle
+  if (!(APU_Reg[0x8] & 0x80) && TrLengthCounter > 0)
+  {
+    TrLengthCounter--;
+  }
+  
+  // Noise
+  if (!(APU_Reg[0xc] & 0x20) && NsLengthCounter > 0)
+  {
+    NsLengthCounter--;
+  }
+  
+}
+
+/*-------------------------------------------------------------------*/
+/*  Status                                                           */
+/*-------------------------------------------------------------------*/
+BYTE ApuRead( WORD wAddr )
+{
+  if (wAddr == 0x15)
+  {
+    return (P1LengthCounter > 0) | (P2LengthCounter > 0) << 1 | (TrLengthCounter > 0) << 2 | (NsLengthCounter > 0) << 3;
+  }
+  
+  return APU_Reg[ wAddr ];  
+}
+
diff -r 000000000000 -r 3dac1f1bc9e0 pNesX_Filer.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pNesX_Filer.cpp	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,374 @@
+/*===================================================================*/
+/*                                                                   */
+/*  pNesX_Filer.cpp : ROM selection screen                           */
+/*                                                                   */
+/*  2016/1/20  Racoon                                                */
+/*                                                                   */
+/*===================================================================*/
+
+#include "mbed.h"
+#include "SDFileSystem.h"
+#include "tft.h"
+
+extern void pNesX_PadState( DWORD *pdwPad1, DWORD *pdwPad2, DWORD *pdwSystem );
+extern const unsigned char pNesX_logo[];
+extern const unsigned char Racoon_logo[];
+
+#define LOGO_BACKCOLOR 0x86fd
+
+#define FOLDER_FILE_MAX 100
+#define LIST_ROWS 20
+#define LIST_TOP 40
+#define LIST_LEFT 4
+
+int DispTop; // Top of the list
+int SelIdx; // Cursor index
+int FileCount; // Number of files in the folder
+
+// file information
+typedef struct tagLISTITEM{
+    char filename[33];
+    bool isDir;
+    long size;
+} LISTITEM;
+
+// folder file list
+LISTITEM *flist;
+
+char szRomFolder[256];
+char szPrevFolder[256];
+char szRomFilename[33];
+char szRomPath[256];
+
+/*-------------------------------------------------------------------*/
+/*  Get file extension                                               */
+/*-------------------------------------------------------------------*/
+char *get_ext(char *filename)
+{
+    int i;
+    for (i = strlen(filename) - 1; i >= 0; --i) {
+        if (filename[i] == '.') {
+            return &filename[i + 1];
+        }
+    }
+    return NULL;
+}
+
+/*-------------------------------------------------------------------*/
+/*  Get file path                                                    */
+/*-------------------------------------------------------------------*/
+char *get_filepath(char *path, char *filename)
+{
+    static char filepath[256];
+
+    if (strncmp(path, "/sd", 3) != 0)
+    {
+        filepath[0] = 0;
+        return filepath;
+    }
+    
+    int len = strlen(path);
+    if (len < 4) {
+        strcpy(filepath, filename);
+    } else {
+        sprintf(filepath, "%s/%s", &path[4], filename);
+    }
+
+    return filepath;
+}
+
+/*-------------------------------------------------------------------*/
+/*  Get file list in the folder                                     */
+/*-------------------------------------------------------------------*/
+int get_filelist(char *path)
+{
+    DIR *dir = opendir(path);
+    if ( dir == NULL ) {
+        return 0;
+    }
+
+    dirent *entry;
+    FILINFO fi;
+    fi.lfname = NULL;
+    fi.lfsize = 0;
+    int i = 0;
+
+    // not root
+    if (strcmp(path, "/sd") != 0) {
+        strcpy(flist[i].filename, "..");
+        flist[i].isDir = true;
+        i++;
+    }
+
+    // folder
+    while ((entry = readdir(dir)) != NULL && i < FOLDER_FILE_MAX) {
+        if (f_stat(get_filepath(path, entry->d_name), &fi) == FR_OK) {
+            int len = strlen(entry->d_name);
+            len = len > 32 ? 32 : len;
+            if (entry->d_name[0] == '.') continue;
+
+            memcpy(flist[i].filename, entry->d_name, len);
+            flist[i].filename[len] = 0;
+            flist[i].isDir = fi.fattrib & AM_DIR;
+            flist[i].size = fi.fsize;
+            ++i;
+        }
+    }
+
+    closedir(dir);
+
+    return i;
+}
+
+
+/*-------------------------------------------------------------------*/
+/*  Get file information string                                      */
+/*-------------------------------------------------------------------*/
+char* filedata(int idx)
+{
+    static char disptext[41];
+    
+    if (flist[idx].isDir) {
+        sprintf(disptext, "%-32s  <DIR>", flist[idx].filename);
+    } else {
+        sprintf(disptext, "%-32s %6d", flist[idx].filename, flist[idx].size);
+    }
+
+    return disptext;
+}
+
+/*-------------------------------------------------------------------*/
+/*  Draw file list                                                   */
+/*-------------------------------------------------------------------*/
+void draw_list()
+{
+    int i,y;
+
+    for (y = 0, i = DispTop; y < LIST_ROWS && i < FileCount; ++y, ++i) {
+        tft_text( LIST_LEFT, LIST_TOP + y * 8, filedata(i), TFT_WHITE, TFT_BLACK );
+    }
+
+    if (y < LIST_ROWS) {
+        tft_boxfill( 0, LIST_TOP + y * 8, 319, LIST_TOP + LIST_ROWS * 8 - 1, TFT_BLACK);
+    }
+}
+
+/*-------------------------------------------------------------------*/
+/*  Draw cursor                                                      */
+/*-------------------------------------------------------------------*/
+void draw_cursor(bool clear = false)
+{
+    int y = SelIdx - DispTop;
+    if (clear) {
+        tft_box( LIST_LEFT - 1, LIST_TOP + y * 8 - 1, LIST_LEFT + 39 * 8, LIST_TOP + y * 8 + 7, TFT_BLACK);
+        tft_text( LIST_LEFT, LIST_TOP + y * 8, filedata(SelIdx), TFT_WHITE, TFT_BLACK );
+    } else {
+        tft_box( LIST_LEFT - 1, LIST_TOP + y * 8 - 1, LIST_LEFT + 39 * 8, LIST_TOP + y * 8 + 7, TFT_YELLOW);
+        tft_text( LIST_LEFT, LIST_TOP + y * 8, filedata(SelIdx), TFT_BLACK, TFT_YELLOW );
+    }
+}
+
+/*-------------------------------------------------------------------*/
+/*  Draw back ground                                                 */
+/*-------------------------------------------------------------------*/
+void draw_frame()
+{
+        tft_boxfill( 0, 0, 319, 31, LOGO_BACKCOLOR);
+        tft_boxfill(0, 32, 319, 223, TFT_BLACK);
+        tft_boxfill( 0, 224, 319, 239, LOGO_BACKCOLOR);
+        
+        draw_bmp_4bpp(pNesX_logo, 8, 6);
+        tft_text( 200, 225, "L2:Emu<->Menu", TFT_BLACK, LOGO_BACKCOLOR );
+        tft_text( 200, 233, "R1+R2:Reset", TFT_BLACK, LOGO_BACKCOLOR );
+        draw_bmp_4bpp(Racoon_logo, 0, 224);
+}
+
+/*-------------------------------------------------------------------*/
+/*  Dialog window                                                    */
+/*-------------------------------------------------------------------*/
+void dialog(char *msg)
+{
+    if (msg)
+    {
+        tft_boxfill(0, 100, 319, 139, TFT_NAVY);
+        int len = strlen(msg);
+        len = len > 38 ? 38 : len;
+        msg[len] = 0;
+        int x = (40 - len) * 4;
+        tft_text(x, 116, msg, TFT_WHITE, TFT_NAVY);
+    }
+    else
+    {
+        tft_boxfill(0, 100, 319, 139, TFT_BLACK);
+    }
+}
+
+/*-------------------------------------------------------------------*/
+/*  Rom selection                                                    */
+/*-------------------------------------------------------------------*/
+//  return code:
+//   0 : File selected
+//   1 : Return to Emu
+//   2 : Reset
+//   -1: Error
+int pNesX_Filer()
+{
+    DWORD dwPad1, dwPad2, dwSystem;
+    DWORD prev_dwPad1 = 0;
+    
+    bool loadFolder;
+    int keyrepeat = 1;
+
+    // Draw back ground
+    draw_frame();
+    
+    // init
+    flist = (LISTITEM *)malloc(sizeof(LISTITEM) * FOLDER_FILE_MAX);
+    if (flist == NULL) {
+        return -1;
+    }
+    
+    loadFolder = true;
+    int ret;
+    
+    while(1) {
+        if (loadFolder) {
+            // Drawing of the files in the folder
+            FileCount = get_filelist(szRomFolder);
+            
+            if (FileCount > 0) {
+                if (strcmp(szRomFolder, szPrevFolder) != 0)
+                {
+                    DispTop = 0;
+                    SelIdx = 0;
+                    strcpy( szPrevFolder, szRomFolder);
+                }
+                draw_list();
+                draw_cursor();
+            }
+            loadFolder = false;
+        }
+
+        pNesX_PadState( &dwPad1, &dwPad2, &dwSystem );
+        
+        if (dwPad1 != prev_dwPad1) {
+            keyrepeat = 0;
+        }
+
+        if (keyrepeat == 0 || keyrepeat >= 10) {
+            // Down
+            if (dwPad1 & 0x20) {
+                if (SelIdx < FileCount - 1) {
+                    // clear cursor
+                    draw_cursor(true);
+                    
+                    if (SelIdx - DispTop == LIST_ROWS - 1) {
+                        DispTop++;
+                        draw_list();
+                    }
+    
+                    // draw new cursor
+                    SelIdx++;
+                    draw_cursor();
+                }                
+            }
+
+            // Up
+            if (dwPad1 & 0x10) {
+                if (SelIdx > 0) {
+                    // clear cursor
+                    draw_cursor(true);
+                    
+                    if (SelIdx - DispTop == 0) {
+                        DispTop--;
+                        draw_list();
+                    }
+
+                    // draw new cursor
+                    SelIdx--;
+                    draw_cursor();
+                }
+            }
+
+            // Select
+            if (dwPad1 & 0x01) {
+                // clear cursor
+                draw_cursor(true);
+
+                if (flist[SelIdx].isDir) {
+                    // folder
+                    if (strcmp(flist[SelIdx].filename, "..") != 0) {
+                        sprintf(szRomFolder, "%s/%s", szRomFolder, flist[SelIdx].filename);
+                    } else {
+                        // upper folder
+                        char *upper = strrchr(szRomFolder, '/');
+                        if (upper) {
+                            *upper = 0;
+                        }
+                    }
+
+                    loadFolder = true;
+                } else {
+                    char *ext = get_ext(flist[SelIdx].filename);
+                    if (ext != NULL && strcasecmp(ext, "nes") == 0)
+                    {
+                        strcpy(szRomFilename, flist[SelIdx].filename);
+    
+
+                        strcpy(szRomPath, get_filepath(szRomFolder, szRomFilename));
+                        
+                        ret = 0;
+                        break;
+                    }
+                    else
+                    {
+                        dialog("not a rom file!!");
+                        wait(1);
+                        dialog(NULL);
+                        draw_list();
+                        draw_cursor();
+                    }
+                }
+            }
+            
+            // Return to Emu
+            if (dwSystem & 0x01) {
+                if ( szRomFilename[0] != 0 ) {
+                    do {
+                        wait(0.08);
+                        pNesX_PadState( &dwPad1, &dwPad2, &dwSystem );
+
+                    } while (dwSystem & 0x01);
+                    
+                    ret = 1;
+                    break;
+                }
+            }
+
+            // Reset
+            if (dwSystem & 0x02) {
+                if ( szRomFilename[0] != 0 ) {
+                    do {
+                        wait(0.08);
+                        pNesX_PadState( &dwPad1, &dwPad2, &dwSystem );
+                    } while (dwSystem & 0x02);
+                    
+                    ret = 2;
+                    break;
+                }
+            }
+        }
+
+        keyrepeat++;
+
+        prev_dwPad1 = dwPad1;
+
+        wait(0.08);
+    }
+    
+    // release memory
+    free(flist);
+
+    return ret;
+}
+
diff -r 000000000000 -r 3dac1f1bc9e0 pNesX_Mapper.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pNesX_Mapper.cpp	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,589 @@
+/*===================================================================*/
+/*                                                                   */
+/*  pNesX_Mapper.cpp : pNesX Mapper Function                         */
+/*                                                                   */
+/*  1999/11/03  Racoon  New preparation                              */
+/*                                                                   */
+/*===================================================================*/
+
+/*-------------------------------------------------------------------*/
+/*  Include files                                                    */
+/*-------------------------------------------------------------------*/
+
+#include "pNesX.h"
+#include "pNesX_System.h"
+#include "pNesX_Mapper.h"
+#include "K6502.h"
+
+/*-------------------------------------------------------------------*/
+/*  Table of Mapper initialize function                              */
+/*-------------------------------------------------------------------*/
+
+struct MapperTable_tag MapperTable[] =
+{
+  { 0, Map0_Init },
+  { 1, Map1_Init },
+  { 2, Map2_Init },
+  { 3, Map3_Init },
+  { 4, Map4_Init },
+  { -1, NULL }
+};
+
+/*===================================================================*/
+/*                                                                   */
+/*                            Mapper 0                               */
+/*                                                                   */
+/*===================================================================*/
+
+/*-------------------------------------------------------------------*/
+/*  Initialize Mapper 0                                              */
+/*-------------------------------------------------------------------*/
+void Map0_Init()
+{
+  /* Initialize Mapper */
+  MapperInit = Map0_Init;
+
+  /* Write to Mapper */
+  MapperWrite = Map0_Write;
+
+  /* Callback at VSync */
+  MapperVSync = Map0_VSync;
+
+  /* Callback at HSync */
+  MapperHSync = Map0_HSync;
+
+  /* Set ROM Banks */
+  ROMBANK0 = ROMPAGE( 0 );
+  ROMBANK1 = ROMPAGE( 1 );
+  ROMBANK2 = ROMLASTPAGE( 1 );
+  ROMBANK3 = ROMLASTPAGE( 0 );
+
+  /* Set PPU Banks */
+  if ( NesHeader.byVRomSize > 0 )
+  {
+    for ( int nPage = 0; nPage < 8; ++nPage )
+      PPUBANK[ nPage ] = &VROM[ nPage * 0x400 ];
+
+    pNesX_SetupChr();
+  }
+
+  /* Set up wiring of the interrupt pin */
+  K6502_Set_Int_Wiring( 1, 1 ); 
+}
+
+/*-------------------------------------------------------------------*/
+/*  Mapper 0 Write Function                                          */
+/*-------------------------------------------------------------------*/
+void Map0_Write( WORD wAddr, BYTE byData )
+{
+/*
+ *  Dummy Write to Mapper
+ *
+ */
+}
+
+/*-------------------------------------------------------------------*/
+/*  Mapper 0 V-Sync Function                                         */
+/*-------------------------------------------------------------------*/
+void Map0_VSync()
+{
+/*
+ *  Dummy Callback at VSync
+ *
+ */
+}
+
+/*-------------------------------------------------------------------*/
+/*  Mapper 0 H-Sync Function                                         */
+/*-------------------------------------------------------------------*/
+void Map0_HSync()
+{
+/*
+ *  Dummy Callback at HSync
+ *
+ */
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*                            Mapper 1                               */
+/*                                                                   */
+/*===================================================================*/
+
+BYTE Map1_Reg[ 4 ];
+
+int Map1_Cnt;
+BYTE Map1_Latch;
+
+/*-------------------------------------------------------------------*/
+/*  Initialize Mapper 1                                              */
+/*-------------------------------------------------------------------*/
+void Map1_Init()
+{
+  int nPage;
+
+  /* Initialize Mapper */
+  MapperInit = Map1_Init;
+
+  /* Write to Mapper */
+  MapperWrite = Map1_Write;
+
+  /* Callback at VSync */
+  MapperVSync = Map0_VSync;
+
+  /* Callback at HSync */
+  MapperHSync = Map0_HSync;
+
+  pNesX_MemorySet( Map1_Reg, 0, sizeof Map1_Reg );
+  Map1_Cnt = Map1_Latch = 0;
+
+  /* Set ROM Banks */
+  ROMBANK0 = ROMPAGE( 0 );
+  ROMBANK1 = ROMPAGE( 1 );
+  ROMBANK2 = ROMLASTPAGE( 1 );
+  ROMBANK3 = ROMLASTPAGE( 0 );
+
+  /* Set PPU VROM Banks */
+  if ( NesHeader.byVRomSize > 0 )
+  {
+    for ( nPage = 0; nPage < 8; ++nPage )
+      PPUBANK[ nPage ] = &VROM[ nPage * 0x400 ];
+
+    pNesX_SetupChr();
+  }
+
+  /* Set up wiring of the interrupt pin */
+  K6502_Set_Int_Wiring( 1, 1 );
+}
+
+/*-------------------------------------------------------------------*/
+/*  Mapper 1 Write Function                                          */
+/*-------------------------------------------------------------------*/
+void Map1_Write( WORD wAddr, BYTE byData )
+{
+/*
+ * MMC1
+ */
+
+  int nReg;
+  int nROMPos;
+  int nBank;
+  int nVBank;
+  int nPage;
+
+  nReg = ( wAddr >> 13 ) - 4;
+
+  if ( byData & 0x80 )
+  {
+    // Reset
+    Map1_Reg[ 0 ] |= 0xc;
+    Map1_Cnt = 0;
+    Map1_Latch = 0;
+    return;
+  }
+  else
+  {
+    // Bit Data Set
+    Map1_Latch |= ( ( byData & 1 ) << Map1_Cnt );
+    ++Map1_Cnt;
+  }
+  
+  if ( Map1_Cnt < 5 )
+    return;
+
+  // 5Bits Latched
+  Map1_Reg[ nReg ] = ( nReg == 3 ) ? ( Map1_Latch & 0xf ) : Map1_Latch;
+  Map1_Cnt = 0;
+  Map1_Latch = 0;
+  
+  // Name Table Mirroring
+  pNesX_Mirroring( ( Map1_Reg[ 0 ] & 3 ) ^ 3 );
+    
+  // Select Program ROM Bank
+
+  // 256K ROM Position Selection
+  nROMPos = 0;
+  if ( NesHeader.byRomSize == 32 )
+  {
+    /* 512K Program ROM */
+    // 0 (First 256K) or 32 (Second 256K)
+    nROMPos = ( Map1_Reg[ 1 ] & 0x10 ) << 1;
+  }
+  else
+  if ( NesHeader.byRomSize == 64 )
+  {
+    /* 1024K Program ROM */
+    if ( Map1_Reg[ 0 ] & 0x10 )
+    {
+      // Acknowledge 256K selection register 1 
+      nROMPos = ( ( Map1_Reg[ 1 ] & 0x10 ) << 1 ) |
+               ( ( Map1_Reg[ 2 ] & 0x10 ) << 2 );
+    }
+    else 
+    {
+      // Ignore 256K selection register 1
+      // 0 (First 256K) or 64 (Third 256K)
+      nROMPos = ( Map1_Reg[ 1 ] & 0x10 ) << 2;
+    }
+  }
+    
+  // Set Program ROM Bank
+  if ( !( Map1_Reg[ 0 ] & 8 ) )
+  {
+    // 32K ROM Bank
+    /* Set ROM Banks */
+    nBank = ( ( Map1_Reg[ 3 ] << 2 ) + nROMPos ) % ( NesHeader.byRomSize << 1 );
+
+    ROMBANK0 = ROMPAGE( nBank );
+    ROMBANK1 = ROMPAGE( nBank + 1 );
+    ROMBANK2 = ROMPAGE( nBank + 2 );
+    ROMBANK3 = ROMPAGE( nBank + 3 );
+  }
+  else
+  if ( Map1_Reg[ 0 ] & 4 )
+  {
+    // 16K ROM Bank at 0x8000
+    nBank = ( ( Map1_Reg[ 3 ] << 1 ) + nROMPos ) % ( NesHeader.byRomSize << 1 );
+    ROMBANK0 = ROMPAGE( nBank );
+    ROMBANK1 = ROMPAGE( nBank + 1 );
+    ROMBANK2 = ROMLASTPAGE( 1 );
+    ROMBANK3 = ROMLASTPAGE( 0 );
+  }
+  else
+  {
+    // 16K ROM Bank at 0xc000
+    nBank = ( ( Map1_Reg[ 3 ] << 1 ) + nROMPos ) % ( NesHeader.byRomSize << 1 );
+    ROMBANK0 = ROMPAGE( 0 );
+    ROMBANK1 = ROMPAGE( 1 );
+    ROMBANK2 = ROMPAGE( nBank );
+    ROMBANK3 = ROMPAGE( nBank + 1 );
+  }
+
+  // Select PPU VROM Bank
+  if ( NesHeader.byVRomSize > 0 )
+  {
+    if ( Map1_Reg[ 0 ] & 0x10 )
+    {
+      // 4K VROM Switching
+      nVBank = Map1_Reg[ 1 ] % ( NesHeader.byVRomSize << 1 );
+      for ( nPage = 0; nPage < 4; ++nPage )
+        PPUBANK[ nPage ] = &VROM[ nVBank * 0x1000 + nPage * 0x400 ];
+
+      nVBank = Map1_Reg[ 2 ] % ( NesHeader.byVRomSize << 1 );
+      for ( nPage = 0; nPage < 4; ++nPage )
+        PPUBANK[ nPage + 4 ] = &VROM[ nVBank * 0x1000 + nPage * 0x400 ];
+    }
+    else
+    {
+      // 8K VROM Switching
+      nVBank = ( Map1_Reg[ 1 ] & 0xe ) % ( NesHeader.byVRomSize << 1 );
+      for ( nPage = 0; nPage < 8; ++nPage )
+        PPUBANK[ nPage ] = &VROM[ nVBank * 0x1000 + nPage * 0x400 ];
+    }
+
+    pNesX_SetupChr();
+  }
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*                        Mapper 2 (UNROM)                           */
+/*                                                                   */
+/*===================================================================*/
+
+/*-------------------------------------------------------------------*/
+/*  Initialize Mapper 2                                              */
+/*-------------------------------------------------------------------*/
+void Map2_Init()
+{
+  /* Initialize Mapper */
+  MapperInit = Map2_Init;
+
+  /* Write to Mapper */
+  MapperWrite = Map2_Write;
+
+  /* Callback at VSync */
+  MapperVSync = Map0_VSync;
+
+  /* Callback at HSync */
+  MapperHSync = Map0_HSync;
+
+  /* Set ROM Banks */
+  ROMBANK0 = ROMPAGE( 0 );
+  ROMBANK1 = ROMPAGE( 1 );
+  ROMBANK2 = ROMLASTPAGE( 1 );
+  ROMBANK3 = ROMLASTPAGE( 0 );
+
+  /* Set up wiring of the interrupt pin */
+  K6502_Set_Int_Wiring( 1, 1 ); 
+}
+
+/*-------------------------------------------------------------------*/
+/*  Mapper 2 Write Function                                          */
+/*-------------------------------------------------------------------*/
+void Map2_Write( WORD wAddr, BYTE byData )
+{
+  /* Set ROM Banks */
+  byData %= NesHeader.byRomSize;
+  byData <<= 1;
+
+  ROMBANK0 = ROMPAGE( byData );
+  ROMBANK1 = ROMPAGE( byData + 1 );
+}
+
+
+/*===================================================================*/
+/*                                                                   */
+/*                     Mapper 3 (VROM Switch)                        */
+/*                                                                   */
+/*===================================================================*/
+
+/*-------------------------------------------------------------------*/
+/*  Initialize Mapper 3                                              */
+/*-------------------------------------------------------------------*/
+void Map3_Init()
+{
+  int nPage;
+
+  /* Initialize Mapper */
+  MapperInit = Map3_Init;
+
+  /* Write to Mapper */
+  MapperWrite = Map3_Write;
+
+  /* Callback at VSync */
+  MapperVSync = Map0_VSync;
+
+  /* Callback at HSync */
+  MapperHSync = Map0_HSync;
+
+  /* Set ROM Banks */
+  ROMBANK0 = ROMPAGE( 0 );
+  ROMBANK1 = ROMPAGE( 1 );
+  ROMBANK2 = ROMLASTPAGE( 1 );
+  ROMBANK3 = ROMLASTPAGE( 0 );
+
+  /* Set PPU Banks */
+  if ( NesHeader.byVRomSize > 0 )
+  {
+    for ( nPage = 0; nPage < 8; ++nPage )
+      PPUBANK[ nPage ] = &VROM[ nPage * 0x400 ];
+    pNesX_SetupChr();
+  }
+
+  /* Set up wiring of the interrupt pin */
+  /* "DragonQuest" doesn't run if IRQ isn't made to occur in CLI */
+  K6502_Set_Int_Wiring( 1, 0 ); 
+}
+
+/*-------------------------------------------------------------------*/
+/*  Mapper 3 Write Function                                          */
+/*-------------------------------------------------------------------*/
+void Map3_Write( WORD wAddr, BYTE byData )
+{
+  int nPage;
+
+  /* Set PPU Banks */
+  byData %= NesHeader.byVRomSize;
+  for ( nPage = 0; nPage < 8; ++nPage )
+    PPUBANK[ nPage ] = &VROM[ byData * 0x2000 + nPage * 0x400 ];
+
+  pNesX_SetupChr();
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*                        Mapper 4 (MMC3)                            */
+/*                                                                   */
+/*===================================================================*/
+
+BYTE Map4_VROM_Base;
+BYTE Map4_ROM_Base;
+BYTE Map4_Cmd;
+BYTE Map4_Banks_Reg[ 8 ];
+BYTE Map4_IRQ_Cnt;
+BYTE Map4_IRQ_Set;
+BYTE Map4_IRQ_Enable;
+
+/*-------------------------------------------------------------------*/
+/*  Initialize Mapper 4                                              */
+/*-------------------------------------------------------------------*/
+void Map4_Init()
+{
+  /* Initialize Mapper */
+  MapperInit = Map4_Init;
+
+  /* Write to Mapper */
+  MapperWrite = Map4_Write;
+
+  /* Callback at VSync */
+  MapperVSync = Map4_VSync;
+
+  /* Callback at HSync */
+  MapperHSync = Map4_HSync;
+
+  Map4_VROM_Base = Map4_ROM_Base = Map4_Cmd = Map4_IRQ_Cnt = Map4_IRQ_Set = Map4_IRQ_Enable = 0;
+
+  Map4_Banks_Reg[ 0 ] = 0;
+  Map4_Banks_Reg[ 1 ] = 2;
+  Map4_Banks_Reg[ 2 ] = 4;
+  Map4_Banks_Reg[ 3 ] = 5;
+  Map4_Banks_Reg[ 4 ] = 6;
+  Map4_Banks_Reg[ 5 ] = 7;
+  Map4_Banks_Reg[ 6 ] = 0;
+  Map4_Banks_Reg[ 7 ] = 1;
+
+  Map4_Write( 0x8000, 0 );
+  Map4_Write( 0x8001, 0 );
+
+  /* Set up wiring of the interrupt pin */
+  K6502_Set_Int_Wiring( 1, 1 ); 
+}
+
+/*-------------------------------------------------------------------*/
+/*  Mapper 4 Write Function                                          */
+/*-------------------------------------------------------------------*/
+void Map4_Write( WORD wAddr, BYTE byData )
+{
+  WORD wMapAddr;
+
+  wMapAddr = wAddr & 0xe001;
+
+  switch ( wMapAddr )
+  {
+    case 0xa000:
+      // Name Table Mirroring
+      pNesX_Mirroring( ~byData & 1 );
+      break;
+
+    case 0xa001:
+      break;
+
+    case 0xc000:
+      Map4_IRQ_Cnt = byData;
+      break;
+
+    case 0xc001:
+      Map4_IRQ_Set = byData;
+      break;
+
+    case 0xe000:
+      Map4_IRQ_Cnt = Map4_IRQ_Set;
+      Map4_IRQ_Enable = 0;
+      break;
+
+    case 0xe001:
+      if ( Map4_IRQ_Cnt > 0 )
+        Map4_IRQ_Enable = 1;
+      break;
+
+    default:
+      if ( wMapAddr == 0x8000 )
+      {
+        Map4_VROM_Base = byData >> 7;
+        Map4_ROM_Base = ( byData >> 6 ) & 1;
+        Map4_Cmd = byData & 7;
+        return;
+      }
+      else
+      {
+        if ( Map4_Cmd >= 6 )
+          byData %= ( NesHeader.byRomSize << 1 );
+        else
+        if ( NesHeader.byVRomSize > 0 )
+        {
+          if ( Map4_Cmd < 2 )
+            byData = ( byData & 0xfe ) % ( NesHeader.byVRomSize << 3 );
+          else
+          if ( Map4_Cmd < 6 )
+            byData %= ( NesHeader.byVRomSize << 3 );
+        }
+
+        Map4_Banks_Reg[ Map4_Cmd ] = byData;
+      }
+
+      /* Set VROM Banks */
+      if ( NesHeader.byVRomSize > 0 )
+      {
+        if ( Map4_VROM_Base )
+        {
+          PPUBANK[ 0 ] = VROMPAGE( Map4_Banks_Reg[ 2 ] );
+          PPUBANK[ 1 ] = VROMPAGE( Map4_Banks_Reg[ 3 ] );
+          PPUBANK[ 2 ] = VROMPAGE( Map4_Banks_Reg[ 4 ] );
+          PPUBANK[ 3 ] = VROMPAGE( Map4_Banks_Reg[ 5 ] );
+          PPUBANK[ 4 ] = VROMPAGE( Map4_Banks_Reg[ 0 ] );
+          PPUBANK[ 5 ] = VROMPAGE( Map4_Banks_Reg[ 0 ] + 1 );
+          PPUBANK[ 6 ] = VROMPAGE( Map4_Banks_Reg[ 1 ] );
+          PPUBANK[ 7 ] = VROMPAGE( Map4_Banks_Reg[ 1 ] + 1 );
+        }
+        else
+        {
+          PPUBANK[ 0 ] = VROMPAGE( Map4_Banks_Reg[ 0 ] );
+          PPUBANK[ 1 ] = VROMPAGE( Map4_Banks_Reg[ 0 ] + 1 );
+          PPUBANK[ 2 ] = VROMPAGE( Map4_Banks_Reg[ 1 ] );
+          PPUBANK[ 3 ] = VROMPAGE( Map4_Banks_Reg[ 1 ] + 1 );
+          PPUBANK[ 4 ] = VROMPAGE( Map4_Banks_Reg[ 2 ] );
+          PPUBANK[ 5 ] = VROMPAGE( Map4_Banks_Reg[ 3 ] );
+          PPUBANK[ 6 ] = VROMPAGE( Map4_Banks_Reg[ 4 ] );
+          PPUBANK[ 7 ] = VROMPAGE( Map4_Banks_Reg[ 5 ] );
+        }
+
+        pNesX_SetupChr();
+      }
+
+      if ( Map4_ROM_Base )
+      {
+        ROMBANK0 = ROMLASTPAGE( 1 );
+        ROMBANK1 = ROMPAGE( Map4_Banks_Reg[ 7 ] );
+        ROMBANK2 = ROMPAGE( Map4_Banks_Reg[ 6 ] );
+        ROMBANK3 = ROMLASTPAGE( 0 );
+      }
+      else
+      {
+        ROMBANK0 = ROMPAGE( Map4_Banks_Reg[ 6 ] );
+        ROMBANK1 = ROMPAGE( Map4_Banks_Reg[ 7 ] );
+        ROMBANK2 = ROMLASTPAGE( 1 );
+        ROMBANK3 = ROMLASTPAGE( 0 );
+      }
+  }
+}
+
+/*-------------------------------------------------------------------*/
+/*  Mapper 4 V-Sync Function                                         */
+/*-------------------------------------------------------------------*/
+void Map4_VSync()
+{
+/*
+ *  Callback at VSync
+ *
+ */
+  Map4_IRQ_Cnt = Map4_IRQ_Set;
+}
+
+/*-------------------------------------------------------------------*/
+/*  Mapper 4 H-Sync Function                                         */
+/*-------------------------------------------------------------------*/
+void Map4_HSync()
+{
+/*
+ *  Callback at HSync
+ *
+ */
+
+  if ( Map4_IRQ_Enable &&
+       PPU_Scanline >= SCAN_ON_SCREEN_START && PPU_Scanline < SCAN_BOTTOM_OFF_SCREEN_START &&
+       //PPU_ScanTable[ PPU_Scanline ] == SCAN_ON_SCREEN &&
+       ( PPU_R1 & ( R1_SHOW_SCR | R1_SHOW_SP ) ) == ( R1_SHOW_SCR | R1_SHOW_SP ) &&
+       Map4_IRQ_Cnt > 0 )
+  {
+    --Map4_IRQ_Cnt;
+    if ( Map4_IRQ_Cnt == 0 )
+    {
+      Map4_IRQ_Cnt = Map4_IRQ_Set;
+      IRQ_REQ;
+    }
+  }
+}
+
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 pNesX_Mapper.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pNesX_Mapper.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,67 @@
+/*===================================================================*/
+/*                                                                   */
+/*  pNesX_Mapper.h : pNesX Mapper Function                           */
+/*                                                                   */
+/*  1999/11/03  Racoon  New preparation                              */
+/*                                                                   */
+/*===================================================================*/
+
+#ifndef PNESX_MAPPER_H_INCLUDED
+#define PNESX_MAPPER_H_INCLUDED
+
+/*-------------------------------------------------------------------*/
+/*  Include files                                                    */
+/*-------------------------------------------------------------------*/
+
+#include "pNesX_Types.h"
+
+/*-------------------------------------------------------------------*/
+/*  Macros                                                           */
+/*-------------------------------------------------------------------*/
+
+/* The address of 8Kbytes unit of the ROM */
+#define ROMPAGE(a)     &ROM[ (a) * 0x2000 ]
+/* From behind the ROM, the address of 8kbytes unit */
+#define ROMLASTPAGE(a) &ROM[ NesHeader.byRomSize * 0x4000 - ( (a) + 1 ) * 0x2000 ]
+
+/* The address of 1Kbytes unit of the VROM */
+#define VROMPAGE(a)    &VROM[ (a) * 0x400 ]
+
+/*-------------------------------------------------------------------*/
+/*  Table of Mapper initialize function                              */
+/*-------------------------------------------------------------------*/
+
+struct MapperTable_tag
+{
+  int nMapperNo;
+  void (*pMapperInit)();
+};
+
+extern struct MapperTable_tag MapperTable[];
+
+/*-------------------------------------------------------------------*/
+/*  Function prototypes                                              */
+/*-------------------------------------------------------------------*/
+
+void Map0_Init();
+void Map0_Write( WORD wAddr, BYTE byData );
+void Map0_VSync();
+void Map0_HSync();
+
+void Map1_Init();
+void Map1_Write( WORD wAddr, BYTE byData );
+
+void Map2_Init();
+void Map2_Write( WORD wAddr, BYTE byData );
+
+void Map3_Init();
+void Map3_Write( WORD wAddr, BYTE byData );
+
+void Map4_Init();
+void Map4_Write( WORD wAddr, BYTE byData );
+void Map4_VSync();
+void Map4_HSync();
+
+#endif /* !PNESX_MAPPER_H_INCLUDED */
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 pNesX_System.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pNesX_System.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,54 @@
+/*===================================================================*/
+/*                                                                   */
+/*  pNesX_System.h : The function which depends on a system          */
+/*                                                                   */
+/*  1999/11/03  Racoon  New preparation                              */
+/*                                                                   */
+/*===================================================================*/
+
+#ifndef PNESX_SYSTEM_H_INCLUDED
+#define PNESX_SYSTEM_H_INCLUDED
+
+/*-------------------------------------------------------------------*/
+/*  Include files                                                    */
+/*-------------------------------------------------------------------*/
+
+#include "pNesX_Types.h"
+
+/*-------------------------------------------------------------------*/
+/*  Palette data                                                     */
+/*-------------------------------------------------------------------*/
+extern const WORD NesPalette[];
+
+/*-------------------------------------------------------------------*/
+/*  Function prototypes                                              */
+/*-------------------------------------------------------------------*/
+
+/* Menu screen */
+int pNesX_Menu();
+
+/* Read ROM image file */
+int pNesX_ReadRom( const char *pszFileName );
+
+/* Release a memory for ROM */
+void pNesX_ReleaseRom();
+
+/* Transfer the contents of work frame on the screen */
+void pNesX_LoadFrame();
+void pNesX_TransmitLinedata();
+
+/* Get a joypad state */
+void pNesX_PadState( DWORD *pdwPad1, DWORD *pdwPad2, DWORD *pdwSystem );
+
+/* memcpy */
+void *pNesX_MemoryCopy( void *dest, const void *src, int count );
+
+/* memset */
+void *pNesX_MemorySet( void *dest, int c, int count );
+
+/* Print debug message */
+void pNesX_DebugPrint( char *pszMsg );
+
+#endif /* !PNESX_SYSTEM_H_INCLUDED */
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 pNesX_System_Nucleo.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pNesX_System_Nucleo.cpp	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,483 @@
+/*===================================================================*/
+/*                                                                   */
+/*  pNesX_System_Nucleo.cpp : The function which depends on a system */
+/*                         (for Nucleo F446RE)                       */
+/*                                                                   */
+/*  2016/1/20  Racoon                                                */
+/*                                                                   */
+/*===================================================================*/
+
+/*-------------------------------------------------------------------*/
+/*  Include files                                                    */
+/*-------------------------------------------------------------------*/
+
+#include "mbed.h"
+#include "SDFileSystem.h"
+#include "tft.h"
+
+//#define PS_GAMEPAD
+
+#if !defined(PS_GAMEPAD)
+#include "USBHostGamepad.h"
+USBHostGamepad *pad;
+#else
+#include "pspad.h"
+#endif
+
+#include "pNesX.h"
+#include "pNesX_System.h"
+
+extern int pNesX_Filer();
+extern void ApuMute(bool mute);
+
+SDFileSystem *sd; //(PB_15, PB_14, PB_13, PA_9, "sd", NC, SDFileSystem::SWITCH_NONE, 20000000);
+
+DigitalIn userbutton(USER_BUTTON);
+
+extern WORD LineData[][256];
+extern WORD *pDrawData;
+
+//#define SHOW_FPS
+
+#if defined(SHOW_FPS)
+Timer timer;
+int fps = 0;
+int dmawait;
+#endif
+
+/*-------------------------------------------------------------------*/
+/*  ROM image file information                                       */
+/*-------------------------------------------------------------------*/
+
+extern char szRomFolder[];
+extern char szRomFilename[];
+extern char szRomPath[];
+    
+char szRomName[ 256 ];
+char szSaveName[ 256 ];
+int nSRAM_SaveFlag;
+
+// Palette data
+const WORD NesPalette[ 64 ] =
+{
+    0xef7b,0x1f00,0x1700,0x5741,0x1090,0x04a8,0x80a8,0xa088,0x8051,0xc003,0x4003,0xc002,0x0b02,0x0000,0x0000,0x0000,
+    0xf7bd,0xdf03,0xdf02,0x3f6a,0x19d8,0x0be0,0xc0f9,0xe2e2,0xe0ab,0xc005,0x4005,0x4805,0x5104,0x0000,0x0000,0x0000,
+    0xdfff,0xff3d,0x5f6c,0xdf9b,0xdffb,0xd3fa,0xcbfb,0x08fd,0xc0fd,0xc3bf,0xca5e,0xd35f,0x5b07,0xcf7b,0x0000,0x0000,
+    0xffff,0x3fa7,0xdfbd,0xdfdd,0xdffd,0x38fd,0x96f6,0x15ff,0xcffe,0xcfdf,0xd7bf,0xdbbf,0xff07,0xdffe,0x0000,0x0000
+};
+
+/*-------------------------------------------------------------------*/
+/*  Function prototypes                                              */
+/*-------------------------------------------------------------------*/
+
+int LoadSRAM();
+int SaveSRAM();
+
+/*===================================================================*/
+/*                                                                   */
+/*           LoadSRAM() : Load a SRAM                                */
+/*                                                                   */
+/*===================================================================*/
+int LoadSRAM()
+{
+/*
+ *  Load a SRAM
+ *
+ *  Return values
+ *     0 : Normally
+ *    -1 : SRAM data couldn't be read
+ */
+
+  return 0;
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*           SaveSRAM() : Save a SRAM                                */
+/*                                                                   */
+/*===================================================================*/
+int SaveSRAM()
+{
+/*
+ *  Save a SRAM
+ *
+ *  Return values
+ *     0 : Normally
+ *    -1 : SRAM data couldn't be written
+ */
+
+
+  // Successful
+  return 0;
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*                  pNesX_Menu() : Menu screen                       */
+/*                                                                   */
+/*===================================================================*/
+int pNesX_Menu()
+{
+/*
+ *  Menu screen
+ *
+ *  Return values
+ *     0 : Normally
+ *    -1 : Exit pNesX
+ */
+
+#if defined(SHOW_FPS)
+    timer.stop();
+#endif
+
+    ApuMute(true);
+
+    switch (pNesX_Filer())
+    {
+        case 0:  // Selected a file
+            if ( pNesX_Load( szRomPath ) == 0 )
+            {
+                // Set a ROM image name
+                strcpy( szRomName, szRomFilename );
+        
+                // Load SRAM
+                LoadSRAM();
+            }
+            break;
+            
+        case 1:  // Return to Emu
+            break;
+            
+        case 2:  // Reset
+            if ( szRomName[ 0 ] != 0 )
+            {
+              // Reset pNesX
+              pNesX_Reset();
+            }                
+        
+            break;
+            
+        case -1:  // Error
+            printf("Filer Error\r\n");
+            while(1);
+    }
+
+    tft_clear(TFT_BLACK);
+    tft_set_window(32, 8, NES_DISP_WIDTH + 32 - 1, NES_DISP_HEIGHT + 8 - 1);        
+    
+    ApuMute(false);
+
+#if defined(SHOW_FPS)
+    timer.start();  
+#endif
+
+  return 0;
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*               pNesX_ReadRom() : Read ROM image file               */
+/*                                                                   */
+/*===================================================================*/
+int pNesX_ReadRom( const char *pszFileName )
+{
+/*
+ *  Read ROM image file
+ *
+ *  Parameters
+ *    const char *pszFileName          (Read)
+ *
+ *  Return values
+ *     0 : Normally
+ *    -1 : Error
+ */
+    FileHandle* file;
+    
+    /* Open ROM file */
+    file = sd->open(pszFileName, O_RDONLY);
+    if ( file == NULL )
+    {
+        printf("open error\r\n");
+        return -1;
+    }
+    
+    /* Read ROM Header */
+    file->read( &NesHeader, sizeof NesHeader);
+    if ( memcmp( NesHeader.byID, "NES\x1a", 4 ) != 0 )
+    {
+        /* not .nes file */
+        file->close();
+        return -1;
+    }
+
+    /* Clear SRAM */
+    memset( SRAM, 0, SRAM_SIZE );
+
+    /* If trainer presents Read Triner at 0x7000-0x71ff */
+    if ( NesHeader.byInfo1 & 4 )
+    {
+        printf("Read Trainer\r\n");
+        file->read( &SRAM[ 0x1000 ], 512 );
+    }
+
+    printf("RomSize: %d\r\n", NesHeader.byRomSize);
+    /* Allocate Memory for ROM Image */
+    ROM = (BYTE *)malloc( NesHeader.byRomSize * 0x4000 );
+    printf("ROM addr:%x\r\n", ROM);
+
+    /* Read ROM Image */
+    file->read( ROM, 0x4000 * NesHeader.byRomSize );
+
+    if ( NesHeader.byVRomSize > 0 )
+    {
+        /* Allocate Memory for VROM Image */
+        VROM = (BYTE *)malloc( NesHeader.byVRomSize * 0x2000 );
+        printf("VROM addr:%x\r\n", VROM);
+
+        /* Read VROM Image */
+        file->read( VROM, 0x2000 * NesHeader.byVRomSize );
+    }
+
+    /* File close */
+    file->close();
+    
+    /* Successful */
+    return 0;
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*           pNesX_ReleaseRom() : Release a memory for ROM           */
+/*                                                                   */
+/*===================================================================*/
+void pNesX_ReleaseRom()
+{
+/*
+ *  Release a memory for ROM
+ *
+ */
+  if ( ROM )
+  {
+    free( ROM );
+    ROM = NULL;
+  }
+
+  if ( VROM )
+  {
+    free( VROM );
+    VROM = NULL;
+  }
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*      pNesX_LoadFrame() :                                          */
+/*           Transfer the contents of work frame on the screen       */
+/*                                                                   */
+/*===================================================================*/
+void pNesX_LoadFrame()
+{
+/*
+ *  Transfer the contents of work frame on the screen
+ *
+ */
+#if defined(SHOW_FPS)
+    fps++;
+    
+    if (timer.read_ms() >= 1000)
+    {
+        timer.stop();
+        printf("%d %d %d\r\n", fps, timer.read_ms(), dmawait);
+        fps = 0;
+        timer.reset();
+        timer.start();
+    }
+    dmawait = 0;
+#endif
+}
+
+void pNesX_TransmitLinedata()
+{
+  while (SpiHandle.State != HAL_SPI_STATE_READY)
+  {
+#if defined(SHOW_FPS)
+    dmawait++;
+#endif
+  }
+  HAL_SPI_Transmit_DMA(&SpiHandle, (uint8_t *)pDrawData, 256 * 2);
+}
+
+#if !defined(PS_GAMEPAD)
+const BYTE UsbPadTable[] = {0x10, 0x90, 0x80, 0xa0, 0x20, 0x60, 0x40, 0x50}; 
+#endif
+
+/*===================================================================*/
+/*                                                                   */
+/*             pNesX_PadState() : Get a joypad state                 */
+/*                                                                   */
+/*===================================================================*/
+void pNesX_PadState( DWORD *pdwPad1, DWORD *pdwPad2, DWORD *pdwSystem )
+{
+/*
+ *  Get a joypad state
+ *
+ *  Parameters
+ *    DWORD *pdwPad1                   (Write)
+ *      Joypad 1 State  R L D U St Se B A 
+ *
+ *    DWORD *pdwPad2                   (Write)
+ *      Joypad 2 State
+ *
+ *    DWORD *pdwSystem                 (Write)
+ *      Input for pNesX
+ *
+ */
+
+#if !defined(PS_GAMEPAD)
+  *pdwPad1 = ((pad->report[4] & 0x20) >> 5) |
+             ((pad->report[4] & 0x10) >> 3) |
+             ((pad->report[5] & 0x30) >> 2);
+
+  if (!(pad->report[4] & 8))
+  {
+      *pdwPad1 |= UsbPadTable[pad->report[4] & 7];
+  }
+  
+  *pdwPad1 = *pdwPad1 | ( *pdwPad1 << 8 );
+    
+  *pdwPad2 = 0;
+  *pdwSystem = ((pad->report[5] & 0x4) >> 2) |
+               (((pad->report[5] & 0xa) == 0xa) << 1);
+                   
+  USBHost::poll();
+#else
+
+    unsigned short pad1, pad2;
+    pspad_read(&pad1, &pad2);
+                               // R L D U St Se B A 
+ 
+    // SE -- -- ST U R D L       L2 R2 L1 R1 TR O X SQ
+    *pdwPad1 = ((pad1 & 0x0400) >> 3) |
+               ((pad1 & 0x0100) >> 2) |
+               ((pad1 & 0x0200) >> 4) |
+               ((pad1 & 0x0800) >> 7) |
+               ((pad1 & 0x1000) >> 9) |
+               ((pad1 & 0x8000) >> 13) |
+               ((pad1 & 1) << 1) |
+               ((pad1 & 2) >> 1);
+
+    *pdwPad1 = *pdwPad1 | ( *pdwPad1 << 8 );
+
+    *pdwPad2 = 0;
+    
+    *pdwSystem = ((pad1 & 0x80) >> 7) |
+                 (((pad1 & 0x50) == 0x50) << 1);
+    
+#endif
+
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*             pNesX_MemoryCopy() : memcpy                           */
+/*                                                                   */
+/*===================================================================*/
+void *pNesX_MemoryCopy( void *dest, const void *src, int count )
+{
+/*
+ *  memcpy
+ *
+ *  Parameters
+ *    void *dest                       (Write)
+ *      Points to the starting address of the copied block to destination
+ *
+ *    const void *src                  (Read)
+ *      Points to the starting address of the block of memory to copy
+ *
+ *    int count                        (Read)
+ *      Specifies the size, in bytes, of the block of memory to copy
+ *
+ *  Return values
+ *    Pointer of destination
+ */
+
+  memcpy(dest, src, count );
+  return dest;
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*             pNesX_MemorySet() :                                   */
+/*                                                                   */
+/*===================================================================*/
+void *pNesX_MemorySet( void *dest, int c, int count )
+{
+/*
+ *  memset
+ *
+ *  Parameters
+ *    void *dest                       (Write)
+ *      Points to the starting address of the block of memory to fill
+ *
+ *    int c                            (Read)
+ *      Specifies the byte value with which to fill the memory block
+ *
+ *    int count                        (Read)
+ *      Specifies the size, in bytes, of the block of memory to fill
+ *
+ *  Return values
+ *    Pointer of destination
+ */
+
+  memset(dest, c, count); 
+  return dest;
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*                DebugPrint() : Print debug message                 */
+/*                                                                   */
+/*===================================================================*/
+void pNesX_DebugPrint( char *pszMsg )
+{
+}
+
+/*===================================================================*/
+/*                                                                   */
+/*                pNesX Initialise                                   */
+/*                                                                   */
+/*===================================================================*/
+int main()
+{
+    // TFT initialize    
+    tft_init();
+    tft_clear(TFT_BLACK);
+    tft_set_window(32, 8, NES_DISP_WIDTH + 32 - 1, NES_DISP_HEIGHT + 8 - 1);
+        
+    // SD card Initialize
+    sd = new SDFileSystem(PB_15, PB_14, PB_13, PA_9, "sd", NC, SDFileSystem::SWITCH_NONE, 20000000);
+    sd->crc(true);
+    sd->large_frames(true);
+    sd->write_validation(true);
+
+    strcpy(szRomFolder, "/sd");
+
+#if !defined(PS_GAMEPAD)
+    // USB Gmaepad Initialize
+    pad = new USBHostGamepad();
+    pad->connect();
+#else
+    pspad_init();
+#endif
+
+    // Apu Initialize
+    ApuInit();
+    
+    /*-------------------------------------------------------------------*/
+    /*  Start pNesX                                                      */
+    /*-------------------------------------------------------------------*/
+
+    pNesX_Main();    
+}
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 pNesX_Types.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pNesX_Types.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,37 @@
+/*===================================================================*/
+/*                                                                   */
+/*  pNesX_Types.h : Type definitions for pNesX                       */
+/*                                                                   */
+/*  1999/11/03  Racoon  New preparation                              */
+/*                                                                   */
+/*===================================================================*/
+
+#ifndef PNESX_TYPES_H_INCLUDED
+#define PNESX_TYPES_H_INCLUDED
+
+/*-------------------------------------------------------------------*/
+/*  Type definition                                                  */
+/*-------------------------------------------------------------------*/
+#ifndef DWORD
+typedef unsigned long  DWORD;
+#endif /* !DWORD */
+
+#ifndef WORD
+typedef unsigned short WORD;
+#endif /* !WORD */
+
+#ifndef BYTE
+typedef unsigned char  BYTE;
+#endif /* !BYTE */
+
+/*-------------------------------------------------------------------*/
+/*  NULL definition                                                  */
+/*-------------------------------------------------------------------*/
+#ifndef NULL
+#define NULL  0
+#endif /* !NULL */
+
+#endif /* !PNESX_TYPES_H_INCLUDED */
+
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 pNesX_logo.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pNesX_logo.cpp	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,99 @@
+/*===================================================================*/
+/*                                                                   */
+/*  pNesX_logo.cpp : pNesX Logo image data(4bit bmp)                 */
+/*                                                                   */
+/*  2016/1/20  Racoon                                                */
+/*                                                                   */
+/*===================================================================*/
+extern const unsigned char pNesX_logo[];
+
+const unsigned char pNesX_logo[] =
+{
+	0x42,0x4D,0x4A,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x6A,0x00,0x00,0x00,0x28,0x00,
+	0x00,0x00,0x63,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x30,0xB0,0xF8,0x00,0x2F,0xAD,0xF5,0x00,0x2D,0xA7,
+	0xEC,0x00,0x2A,0x9C,0xDD,0x00,0x26,0x8A,0xC3,0x00,0x22,0x7A,0xAC,0x00,0x1B,0x5B,
+	0x81,0x00,0x14,0x40,0x5A,0x00,0x0D,0x26,0x35,0x00,0x0B,0x18,0x20,0x00,0x09,0x11,
+	0x16,0x00,0x08,0x0D,0x0F,0x00,0x08,0x08,0x08,0x00,0x9C,0xCC,0xC5,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xCC,
+	0xC7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x5C,0xCC,0xC9,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x39,0xCC,0xCC,0x50,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0xCC,0xCC,0x70,0x24,0x54,
+	0x30,0x00,0x00,0x02,0x33,0x33,0x20,0x00,0x00,0x02,0x33,0x33,0x31,0x00,0x00,0x00,
+	0x24,0x45,0x54,0x31,0x00,0x00,0x00,0x00,0x23,0x45,0x54,0x43,0x00,0x00,0x23,0x33,
+	0x33,0x30,0x00,0x00,0x01,0x33,0x33,0x33,0x20,0x00,0x00,0x00,0x00,0x00,0x05,0xCC,
+	0xCC,0x94,0x8B,0xCC,0x97,0x30,0x00,0x06,0x99,0x99,0x82,0x00,0x00,0x06,0x99,0x99,
+	0x95,0x00,0x00,0x05,0x8A,0xCC,0xCB,0x98,0x62,0x00,0x00,0x15,0x8A,0xBC,0xCC,0xB9,
+	0x74,0x00,0x48,0x99,0x99,0x95,0x00,0x00,0x03,0x89,0x99,0x99,0x60,0x00,0x00,0x00,
+	0x00,0x00,0x03,0x9C,0xCC,0xCA,0xCC,0xCC,0xCC,0xA5,0x10,0x04,0xBC,0xCC,0xC5,0x00,
+	0x00,0x18,0xCC,0xCC,0xC7,0x00,0x01,0x6C,0xCC,0xCC,0xCC,0xCC,0xC9,0x51,0x00,0x5B,
+	0xCC,0xCC,0xCC,0xCC,0xCC,0x73,0x04,0x9C,0xCC,0xCA,0x41,0x00,0x05,0xCC,0xCC,0xCB,
+	0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xCC,0xCC,0xCC,0xCC,0xCC,0xCB,0x51,0x02,
+	0x8C,0xCC,0xC7,0x10,0x00,0x4A,0xCC,0xCC,0xC9,0x20,0x03,0x9C,0xCC,0xCA,0x88,0xCC,
+	0xCC,0xB6,0x10,0x7C,0xCC,0xCC,0x77,0x7B,0xCC,0xC7,0x20,0x49,0xCC,0xCC,0x94,0x00,
+	0x06,0xCC,0xCC,0xC8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x5C,0xCC,0xCC,0xC8,0x79,
+	0xCC,0xCC,0xA4,0x00,0x6C,0xCC,0xC9,0x10,0x00,0x6C,0xCC,0xCC,0xCC,0x50,0x04,0xCC,
+	0xCC,0xC5,0x22,0x59,0x99,0x87,0x30,0x69,0xCC,0xC8,0x20,0x15,0xBC,0xCC,0x60,0x04,
+	0xAC,0xCC,0xC9,0x40,0x28,0xCC,0xCC,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x29,
+	0xCC,0xCC,0x92,0x02,0x7C,0xCC,0xC8,0x10,0x4C,0xCC,0xCC,0x50,0x02,0x8C,0xCC,0xCC,
+	0xCC,0x71,0x05,0xCC,0xCC,0xA1,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x44,0x11,0x35,
+	0xAC,0xCC,0x91,0x00,0x49,0xCC,0xCC,0x94,0x3B,0xCC,0xCC,0xB4,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x17,0xCC,0xCC,0x80,0x00,0x39,0xCC,0xCB,0x40,0x28,0xCC,0xCC,0x70,
+	0x04,0xBC,0xCC,0xCC,0xCC,0x93,0x03,0xBC,0xCC,0xC6,0x66,0x66,0x66,0x66,0x65,0x00,
+	0x01,0x35,0x67,0x9C,0xCC,0xCC,0xC3,0x00,0x05,0x9C,0xCC,0xC8,0x6C,0xCC,0xCC,0x82,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xCC,0xCC,0x92,0x00,0x17,0xCC,0xCC,0x70,
+	0x16,0xCC,0xCC,0x92,0x06,0xCC,0xCC,0xCC,0xCC,0xC5,0x02,0x8C,0xCC,0xCC,0xCC,0xCC,
+	0xCC,0xCC,0xC7,0x10,0x06,0x9C,0xCC,0xCC,0xCC,0xCC,0xA2,0x00,0x00,0x5A,0xCC,0xCC,
+	0xCC,0xCC,0xCC,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x8C,0xCC,0xC5,0x00,
+	0x04,0xCC,0xCC,0x93,0x04,0xBC,0xCC,0xC5,0x18,0xCC,0xCC,0xCC,0xCC,0xC7,0x10,0x6C,
+	0xCC,0xCC,0x99,0x99,0x9C,0xCC,0xCB,0x30,0x4B,0xCC,0xCC,0xCC,0xCC,0xC9,0x50,0x00,
+	0x00,0x05,0x9C,0xCC,0xCC,0xCC,0xCC,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x7C,0xCC,0xC8,0x30,0x04,0xBC,0xCC,0xB3,0x02,0x8C,0xCC,0xC7,0x4C,0xCC,0xCC,0x8C,
+	0xCC,0xC9,0x30,0x39,0xCC,0xCA,0x53,0x33,0x39,0xCC,0xCC,0x40,0x5C,0xCC,0xCC,0xB9,
+	0x87,0x63,0x10,0x00,0x00,0x00,0x59,0xCC,0xCC,0xCC,0xC9,0x20,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x5C,0xCC,0xCC,0x74,0x16,0xCC,0xCC,0xC4,0x00,0x6C,0xCC,0xC8,
+	0x7C,0xCC,0xCB,0x5C,0xCC,0xCC,0x50,0x06,0xCC,0xCC,0x82,0x00,0x29,0xCC,0xCC,0x50,
+	0x4C,0xCC,0xC8,0x43,0x23,0x31,0x00,0x00,0x00,0x00,0x05,0xBC,0xCC,0xCC,0xC7,0x10,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x29,0xCC,0xCC,0xCC,0x9C,0xCC,0xCC,0xC4,
+	0x00,0x4C,0xCC,0xCC,0xBC,0xCC,0xC8,0x28,0xCC,0xCC,0x70,0x01,0x7C,0xCC,0xC8,0x54,
+	0x6C,0xCC,0xCC,0x40,0x07,0xCC,0xC8,0x42,0x38,0xCC,0x98,0x50,0x00,0x00,0x04,0xCC,
+	0xCC,0xCC,0xCB,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xCC,0xCC,0xAC,
+	0xCC,0xCC,0xCC,0x93,0x00,0x18,0xCC,0xCC,0xCC,0xCC,0xC6,0x16,0xCC,0xCC,0xA3,0x00,
+	0x26,0xBC,0xCC,0xCC,0xCC,0xCC,0xC8,0x20,0x04,0x9C,0xCC,0xA8,0x9C,0xCC,0xCB,0x40,
+	0x00,0x00,0x06,0xCC,0xCC,0xCC,0xCC,0xA5,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x05,0xCC,0xCC,0x77,0xCC,0xCC,0xCC,0x61,0x00,0x06,0xCC,0xCC,0xCC,0xCC,0xA4,0x03,
+	0xAC,0xCC,0xC5,0x00,0x01,0x58,0xCC,0xCC,0xCC,0xCC,0x94,0x10,0x01,0x37,0xCC,0xCC,
+	0xCC,0xCC,0xC7,0x20,0x00,0x00,0x08,0xCC,0xCC,0xCC,0xCC,0xCA,0x51,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x01,0x77,0x77,0x72,0x47,0x89,0x86,0x20,0x00,0x04,0xCC,0xCC,
+	0xCC,0xCC,0x81,0x02,0x7C,0xCC,0xC7,0x10,0x00,0x01,0x57,0x89,0x98,0x76,0x30,0x00,
+	0x00,0x00,0x46,0x79,0x99,0x87,0x62,0x00,0x00,0x00,0x3B,0xCC,0xCC,0x87,0xCC,0xCC,
+	0xB5,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x02,0x8C,0xCC,0xCC,0xCC,0x60,0x00,0x6C,0xCC,0xC9,0x30,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6C,0xCC,
+	0xCC,0x72,0x7C,0xCC,0xCA,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x01,0x6C,0xCC,0xCC,0xCC,0x30,0x00,0x4A,0xCC,0xCC,0x50,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x01,0x8C,0xCC,0xCC,0x50,0x38,0xCC,0xCC,0x94,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4B,0xCC,0xCC,0xC8,0x10,0x00,
+	0x08,0xCC,0xCC,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x03,0x9C,0xCC,0xCA,0x30,0x03,0x8C,0xCC,0xCA,0x40,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0xCC,
+	0xCC,0xC6,0x00,0x00,0x06,0xCC,0xCC,0x93,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0xCC,0xCC,0xC8,0x20,0x00,0x49,
+	0xCC,0xCC,0x94,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x06,0x88,0x88,0x83,0x00,0x00,0x03,0x88,0x88,0x84,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x88,0x88,
+	0x86,0x00,0x00,0x14,0x88,0x88,0x87,0x30,0x00,0x00
+};
+
+
diff -r 000000000000 -r 3dac1f1bc9e0 pspad.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pspad.cpp	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,44 @@
+/*===================================================================*/
+/*                                                                   */
+/*  pspad.cpp : PS Pad function                                      */
+/*                                                                   */
+/*  2016/1/20  Racoon                                                */
+/*                                                                   */
+/*===================================================================*/
+
+#include "mbed.h"
+#include "pspad.h"
+
+// SPI interface
+SPI pad_spi(PC_12, PC_11, PC_10);   // MOSI(should pullup), MISO, SCK
+DigitalOut pad1_cs(PD_2);
+
+// PS pad initialize
+void pspad_init()
+{
+    pad_spi.format(8, 3);
+    pad_spi.frequency(250000);
+}
+
+// Read PS Pad state
+// data1  SE -- -- ST U  R D L
+// data2  L2 R2 L1 R1 TR O X SQ
+void pspad_read(unsigned short *pad1, unsigned short *pad2)
+{
+    pad1_cs = 0;
+    wait_us(500);
+
+    pad_spi.write(0x80);
+    pad_spi.write(0x42);
+    pad_spi.write(0);
+    pad_spi.write(0);
+    int d1 = pad_spi.write(0);
+    int d2 = pad_spi.write(0);
+
+    pad1_cs = 1;
+    
+    *pad1 = (char)~d1 << 8 | (char)~d2;
+    
+    *pad2 = 0;
+}
+
diff -r 000000000000 -r 3dac1f1bc9e0 pspad.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pspad.h	Sun Apr 03 07:45:29 2016 +0000
@@ -0,0 +1,19 @@
+/*===================================================================*/
+/*                                                                   */
+/*  pspad.h : PS Pad function header file                            */
+/*                                                                   */
+/*  2016/1/20  Racoon                                                */
+/*                                                                   */
+/*===================================================================*/
+#ifndef PSPAD_H
+#define PSPAD_H
+
+// Initialize interface
+void pspad_init();
+
+// Read PS Pad state
+// SE -- -- ST U R D L L2 R2 L1 R1 TR O X SQ
+void pspad_read(unsigned short *pad1, unsigned short *pad2);
+
+#endif
+