test
Dependencies: SDFileSystem mbed-dev
Fork of Nucleo_Ex06_EMU by
Diff: pNesX_System_Nucleo.cpp
- Revision:
- 4:53ef91c87d74
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pNesX_System_Nucleo.cpp Sat May 27 02:17:37 2017 +0000 @@ -0,0 +1,788 @@ +/*===================================================================*/ +/* */ +/* pNesX_System_Nucleo.cpp : The function which depends on a system */ +/* (for Nucleo F446RE) */ +/* */ +/* 2016/1/20 Racoon */ +/* */ +/*===================================================================*/ + +#define USE_CAN (1) + +/*-------------------------------------------------------------------*/ +/* Include files */ +/*-------------------------------------------------------------------*/ + +#include "mbed.h" +#include "SDFileSystem.h" +#include "tft.h" +//#include "SWO.h" + +// added in for SD check +int get_filelist ( char *path ); + +// logo ptrs + +extern const unsigned char l1_Logo[]; +extern const unsigned char asg_logo[]; +extern const unsigned char adaptable_conn_logo[]; +extern const unsigned char hacker_stickers_logo[]; +extern const unsigned char nostarch_logo[]; +extern const unsigned char nslmini[]; +extern const unsigned char PRO_LG_K_500x200_1CRevGrey_noDSCR[]; +extern const unsigned char securitysnobs[]; +extern const unsigned char supplyFrame[]; +extern const unsigned char WallOfSheep_logo_200px[]; +extern const unsigned char tinder_logo[]; + +// ID that game pad data is sent on +#define CAN_SEND_ID (0x7e1) + +// ID that game pad data is received from +#define CAN_RECV_ID (0x7e0) + +// Memory interface +enum { + CAN_READ_BYTE = CAN_SEND_ID + 1, + CAN_READ_WORD, + CAN_READ_DWORD, + + CAN_WRITE_BYTE, + CAN_WRITE_WORD, + CAN_WRITE_DWORD +}; + +#ifdef USE_CAN + +CAN can1 ( PB_8, PB_9 ); + +//not usng second CAN yet., +//CAN can2(PB_5, PB_6); + +#endif + +//#define ORIGINAL_GAMEPAD +//#define PS_GAMEPAD +#define NES_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 ); + +// temporary store for joystick value +static DWORD canval2; + +#ifdef USE_CAN +// if there is a CAN msg available to read from +static bool msgAvailable = false; +#endif + +SDFileSystem *sd; //(PB_15, PB_14, PB_13, PA_9, "sd", NC, SDFileSystem::SWITCH_NONE, 20000000); + +DigitalIn SW1 ( PC_13 ); +DigitalIn SW2 ( PC_14 ); + +DigitalOut bLED1 ( PB_12 ) ; +DigitalOut bLED2 ( PB_13 ) ; + +extern WORD LineData[][256]; +extern WORD *pDrawData; + +//#define SHOW_FPS + +#if defined(SHOW_FPS) +Timer timer; +int fps = 0; +int dmawait; +#endif + +//SWO_Channel swo; + +/*-------------------------------------------------------------------*/ +/* ROM image file information */ +/*-------------------------------------------------------------------*/ + +extern char szRomFolder[]; +extern char szRomFilename[]; +extern char szRomPath[]; + +char szRomName[ 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(ORIGINAL_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(ORIGINAL_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(); + +#elif defined(NES_GAMEPAD) + + *pdwSystem = 0 ; + *pdwPad1 = 0 ; + /* + 01 02 03 04 05 06 07 08 + ----------------------- + 01 80 80 7f 7f 0f 00 00 + LEFT 00 + RIGHT FF + UP 00 + DOWN FF + SELECT 10 + START 20 + B 1F + A 2F + */ + + if ( pad->report[3] == 0x00 ) {*pdwPad1 |= KEYPAD_LEFT; *pdwSystem ^= PAD_SYS_LEFT;} + + if ( pad->report[3] == 0xFF ) {*pdwPad1 |= KEYPAD_RIGHT; *pdwSystem ^= PAD_SYS_RIGHT;} + + if ( pad->report[4] == 0x00 ) {*pdwPad1 |= KEYPAD_UP; *pdwSystem ^= PAD_SYS_UP;} + + if ( pad->report[4] == 0xFF ) {*pdwPad1 |= KEYPAD_DOWN; *pdwSystem ^= PAD_SYS_DOWN;} + + if ( pad->report[6] & 0x10 ) {*pdwPad1 |= KEYPAD_SELECT;} + + if ( pad->report[6] & 0x20 ) {*pdwPad1 |= KEYPAD_START;} + + if ( pad->report[5] & 0x10 ) {*pdwPad1 |= KEYPAD_B;} + + if ( pad->report[5] & 0x20 ) {*pdwPad1 |= KEYPAD_A;} + + if ( pad->report[6] == 0x30 ) { *pdwSystem = PAD_SYS_QUIT; } + +#ifdef USE_CAN + + { + static DWORD lastpad; + + if ( *pdwPad1 != lastpad ) { + can1.write ( CANMessage ( CAN_SEND_ID, ( char* ) pdwPad1, 4 ) ); + lastpad = *pdwPad1; + } + } + + if ( msgAvailable ) { + + *pdwPad2 = canval2; + + } else +#endif + { + // network ? + *pdwPad2 = 0; + } + + + 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 ) +{ +} + + +#ifdef USE_CAN + +/** + * @brief 'CAN receive-complete' interrup handler. + * @note Called on arrival of new CAN message. + * Keep it as short as possible. + * @param + * @retval + */ +void onMsgReceived() +{ + CANMessage msg; + + // address to read/wrte + WORD address; + + // default to SRAM + uint8_t *bank_ptr = &RAM[0]; + uint8_t bank = 0; + + memset ( &msg, 0, sizeof ( msg ) ); + + if ( can1.read ( msg ) ) { + + // less code + address = ( ( WORD ) msg.data[0] << 8 + ( WORD ) msg.data[1] ); + + // RAM,SRAM,ROM,ROMBANK0/1/2/3,PPURAM,VROM,PPUBANK + bank = msg.data[2]; + + // decide which bank + switch ( bank ) { + case 0: + //RAM + break; + + case 1: + bank_ptr = &SRAM[0]; + break; + + case 2: + bank_ptr = ROM; + break; + + case 3: + bank_ptr = &PPURAM[0]; + break; + + case 4: + bank_ptr = VROM; + break; + + case 5: + bank_ptr = ( uint8_t* ) &PPUBANK[0]; + break; + + case 6: + bank_ptr = ( uint8_t* ) &SPRRAM[0]; + break; + + } + + switch ( msg.id ) { + case CAN_RECV_ID : + + /// so far only mark it as available when its a gamepad message.. + msgAvailable = true; + + //memcpy(&canval2,(char*)&msg.data[0],4); + canval2 = ( unsigned long ) ( msg.data[3] << 24 ) + ( ( unsigned long ) msg.data[2] << 16 ) + ( ( unsigned long ) msg.data[1] << 8 ) + ( ( unsigned long ) msg.data[0] ); + break; + + case CAN_READ_BYTE: + break; + + case CAN_READ_WORD: + break; + + case CAN_READ_DWORD: + break; + + case CAN_WRITE_BYTE: + break; + + case CAN_WRITE_WORD: + break; + + case CAN_WRITE_DWORD: + break; + } + } +} + +#endif + + +const unsigned char * const logoPtrs[] = { + l1_Logo, + +//platinum + tinder_logo, + supplyFrame, + asg_logo, + nslmini, + +//gold + securitysnobs, + +//silver + PRO_LG_K_500x200_1CRevGrey_noDSCR, + adaptable_conn_logo, + WallOfSheep_logo_200px, + hacker_stickers_logo, + nostarch_logo +}; + +void draw_logos ( void ) +{ + static unsigned char counter = 0; + + unsigned short w; + unsigned char h; + const unsigned char *p; + + for ( float b = 1 ; b > 0 ; b -= 0.05f ) { + backlight ( b ); + HAL_Delay ( 20 ); + } + + backlight ( 0 ); + tft_clear ( TFT_BLACK ); + + p = logoPtrs[counter]; + + w = ( unsigned short ) ( p[18] ) + ( ( unsigned short ) p[19] << 8 ); + h = p[22]; + + draw_bmp_4bpp ( p, ( TFT_WIDTH / 2 ) - ( w / 2 ), ( ( TFT_HEIGHT / 2 ) - ( h / 2 ) ) ); + + for ( float b = 0 ; b < 1 ; b += 0.05f ) { + backlight ( b ); + HAL_Delay ( 20 ); + } + + + HAL_Delay ( 1000 ); + counter++ ; + + if ( counter >= sizeof ( logoPtrs ) / sizeof ( unsigned char * ) ) { counter = 0; } + +} + + +/*===================================================================*/ +/* */ +/* pNesX Initialise */ +/* */ +/*===================================================================*/ +int main() +{ + const unsigned char *p ; + bLED1 = 0; + bLED2 = 0; + +#ifdef USE_CAN + // can1.reset(); + can1.frequency ( 1000000 ); + can1.attach ( &onMsgReceived ); // attach 'CAN receive-complete' interrupt handler +#endif + + // TFT initialize + tft_init(); + + tft_set_window ( 32, 8, NES_DISP_WIDTH + 32 - 1, NES_DISP_HEIGHT + 8 - 1 ); + +// SD_CS = PB_2 +// SD_SCK = PB_10 +// SD_MISO = PC_2 +// SD_MOSI = PC_3 + + if ( sd == NULL ) + { + // SD card Initialize + bLED2 = 1; + + sd = new SDFileSystem ( PC_3, PC_2, PB_10, PB_2, "sd", NC, SDFileSystem::SWITCH_NONE, 20000000 ); + + + sd->crc ( true ); + sd->large_frames ( true ); + sd->write_validation ( true ); + + strcpy ( szRomFolder, "/sd" ); + + } + + for ( ;; ) { + draw_logos(); + + if ( get_filelist ( "/sd" ) ) { break; } + } + +#if !defined(PS_GAMEPAD) + tft_clear ( TFT_RED + TFT_BLUE ); + // USB Gamepad Initialize` + pad = new USBHostGamepad(); + pad->connect(); +#else + pspad_init(); +#endif + + // Apu Initialize + ApuInit(); + + /*-------------------------------------------------------------------*/ + /* Start pNesX */ + /*-------------------------------------------------------------------*/ + + bLED2 = 1; + bLED1 = 1; + + pNesX_Main(); + +} + +