xenoborg/alpha/source/xbox_emu.c
blueshogun96@gmail.com e140504ee8
2012-01-05 00:09:50 +00:00

347 lines
No EOL
8 KiB
C

#include "win32.h"
#include "gl_drv.h"
#include "xbox_emu.h"
#include "xbox\\xbe.h"
/* LibEmu (x86) includes */
#include <emu/emu.h>
#include <emu/emu_memory.h>
#include <emu/emu_cpu.h>
struct xbox_emu_t xbox;
int launch_bios = No;
int enable_debugger = No;
void emulation_uninit();
extern void show_debugger();
/* Sets the current state of the emulator */
void set_emulator_state( enum emu_state es )
{
xbox.state = es;
}
/* Opens the bios file and determine it's size */
int open_bios( char* filename, int preload )
{
struct _iobuf* f = NULL;
int ret = 1;
/* sanity check(s) */
if( xbox.bios.ptr )
free( xbox.bios.ptr );
/* Open the bios file, get it's file size, validate that the file size is correct
and if we're not preloading it, then read it into a buffer */
f = fopen( filename, "rb" );
if(!f)
{
msg_box( "Could not open BIOS file!", MB_OK );
ret = 0;
goto stop;
}
fseek(f, 0, SEEK_END);
xbox.bios.size = ftell(f);
/* Xbox bioses are always 256kb, 512kb or 1mb */
/* TODO: Verify that only Chihiro has a 512kb bios */
if( xbox.bios.size != 1024*256 && xbox.bios.size != 1024*512 && xbox.bios.size != 1024*1024 )
{
msg_box( "BIOS file size is incorrect!", MB_OK );
ret = 0;
goto stop;
}
/* If we're preloading, stop here */
if( preload )
goto stop;
/* Put it into a buffer */
xbox.bios.ptr = malloc( xbox.bios.size );
fread( xbox.bios.ptr, xbox.bios.size, 1, f );
/* TODO: Do a CRC check to determine what version this BIOS is unless the version
number is somewhere in the BIOS itself. I haven't checked so I don't know... */
stop:
fclose(f);
return ret;
}
/* Closes the bios */
void close_bios()
{
printf( "Closing BIOS...\n" );
if( xbox.bios.ptr )
free( xbox.bios.ptr );
memset( &xbox.bios, 0, sizeof( struct xbox_bios_t ) );
}
/* */
int open_xbe( char* filename )
{
/* sanity check */
if( xbox.xbe.m_bXbeHasBeenOpened )
xbe_unload( &xbox.xbe );
/* Load .xbe file */
if( !xbe_load( filename, &xbox.xbe ) )
return 0;
return 1;
}
/* Uninitialize xbe resources */
void close_xbe()
{
xbe_unload( &xbox.xbe );
}
/* Setup memory handlers before emulation begins */
void setup_memory_handlers()
{
struct emu_memory_handler m;
/* NV2A (framebuffer)*/
memset( &m, 0, sizeof( m ) );
m.mem_start = fb_start;
m.mem_end = fb_start + ( 640 * 480 * 4 );
m.read_only_access = 0;
m.executable = 0;
m.read8 = nv2a_read8;
m.write8 = nv2a_write8;
m.read16 = nv2a_read16;
m.write16 = nv2a_write16;
m.read32 = nv2a_read32;
m.write32 = nv2a_write32;
emu_memory_add_handler( emu_memory_get(xbox.e), &m );
m.mem_start = fb_start2;
m.mem_end = fb_start2 + ( 640 * 480 * 4 );
emu_memory_add_handler( emu_memory_get(xbox.e), &m );
}
/* Initializes the emulator components */
int emulation_init()
{
uint32_t i = 0;
/* Is the emulator already running? */
if( xbox.state != emu_state_stopped )
return 0;
/* Verify that the .xbe was loaded first */
if( launch_bios == No && !xbox.xbe.m_bXbeHasBeenOpened )
{
msg_box( "No xbe loaded!", MB_OK );
return 0;
}
/* Get parent window */
if( !w32_get_parent_window( &xbox.wnd ) )
return 0;
/* Initialize OpenGL */
if( !enable_ogldrv( &xbox.wnd ) )
{
disable_ogldrv();
msg_box( "Error initializing OpenGL!", MB_OK );
return 0;
}
/* Clear the screen once */
ogl_clear_colour_buffer();
ogl_swap_buffers();
/* Create a new instance of the x86 emulator */
xbox.e = emu_new();
if(!xbox.e)
{
char string[128];
sprintf( string, "emu_new(): %s", emu_strerror(xbox.e) );
msg_box( string, MB_OK );
emu_free(xbox.e);
return 0;
}
/* Set up memory handlers for memory mapped I/O devices */
setup_memory_handlers();
/* Set up the default register values */
emu_cpu_reg32_set( emu_cpu_get(xbox.e), eax, 0 );
emu_cpu_reg32_set( emu_cpu_get(xbox.e), ecx, 0 );
emu_cpu_reg32_set( emu_cpu_get(xbox.e), edx, 0x00000600 );
emu_cpu_reg32_set( emu_cpu_get(xbox.e), ebx, 0 );
emu_cpu_reg32_set( emu_cpu_get(xbox.e), esp, 1024 ); /* TODO */
emu_cpu_reg32_set( emu_cpu_get(xbox.e), ebp, 0 );
emu_cpu_reg32_set( emu_cpu_get(xbox.e), esi, 0 );
emu_cpu_reg32_set( emu_cpu_get(xbox.e), edi, 0 );
emu_cpu_eflags_set( emu_cpu_get(xbox.e), 0x00000002 );
if( launch_bios )
{
/* Set EIP to 0xFFFFFFF0 */
emu_cpu_eip_set( emu_cpu_get(xbox.e), 0xFFFFFFF0 );
/* Write bios contents to 0xFF000000 and mirror as many times as appropriate */
while( i < 1024*1024*16 )
{
emu_memory_write_block( emu_memory_get(xbox.e), 0xFF000000+i, xbox.bios.ptr, xbox.bios.size );
i += xbox.bios.size;
}
}
else
{
/* Set EIP to entry point */
emu_cpu_eip_set( emu_cpu_get(xbox.e), xbox.xbe.m_dwActualEntryPoint );
/* Write .xbe contents starting at the base address */
emu_memory_write_block( emu_memory_get(xbox.e), xbox.xbe.m_XbeHeader.dwBaseAddr,
xbox.xbe.m_pXbeData, xbox.xbe.m_lXbeFileSize );
}
#if 0
/* TODO: Create patch system */
if( xbox.xbe.crc == 0x5C524785 )
{
/* NOPs placed over jbe short 0x11070 @ [0x11074] */
printf( "Applying patches...\n" );
emu_memory_write_byte( emu_memory_get(xbox.e), 0x11074, 0x90 );
emu_memory_write_byte( emu_memory_get(xbox.e), 0x11075, 0x90 );
emu_memory_write_byte( emu_memory_get(xbox.e), 0x1107A, 0x90 );
emu_memory_write_byte( emu_memory_get(xbox.e), 0x1107B, 0x90 );
}
#endif
/* Initialize fake kernel thunk */
init_kernel_thunk();
/* Set uninitialization function to go off at exit */
//atexit( (void (__cdecl *)(void)) emulation_uninit );
xbox.state = emu_state_running;
return 1;
}
/* Uninitialize emulator components */
void emulation_uninit()
{
/* Close the xbe */
close_xbe();
/* Uninitialize cpu */
emu_free(xbox.e);
/* Uninitialize OpenGL */
disable_ogldrv();
}
/* Executes the CPU core */
void execute_cpu()
{
/* Attempt to parse the instruction EIP points to */
if( emu_cpu_parse( emu_cpu_get(xbox.e) ) )
{
printf( "emu_cpu_parse(): %s", emu_strerror(xbox.e) );
//msg_box( string, MB_OK );
}
else
{
/* Now actually emulate the instruction */
if( emu_cpu_step( emu_cpu_get(xbox.e) ) )
{
printf( "emu_cpu_step(): %s", emu_strerror(xbox.e) );
//msg_box( string, MB_OK );
}
}
}
/* Emulator starts executing here */
void* emulation_thread( void* params )
{
/* Initialize emulator */
if( !emulation_init() )
return NULL;
/* Reset the timer */
timer_reset();
/* Emulation loop */
while( TRUE )
{
/* Handle emulator states */
if( xbox.state == emu_state_stopped ) break;
if( xbox.state == emu_state_halted ) {}
/* Execute CPU */
execute_cpu();
/* Update screen based on the timer value */
if( (((float) timer_get_current_time()) / ( 1000.0f * 1000.0f ) ) >= XBOX_CPU_SPEED )
{
/* Update frame buffer */
ogl_update_fb();
ogl_swap_buffers();
/* Reset timer */
timer_reset();
}
/* Update HLEd tick count */
impl_KeTickCount = GetTickCount();
}
/* Uninitialize emulator */
emulation_uninit();
msg_box( "Emulation thread terminated!", MB_OK );
/* Exit thread */
// pthread_exit(NULL);
return NULL;
}
void populate_debugger_list( HWND hwnd, uint32_t list )
{
char string[128];
void* mem = xbox.e->memory->mem;
uint32_t i = 0;
for( i = 0; i < (xbox.xbe.m_lXbeFileSize); i++ )
{
sprintf( string, "0x%X: 0x%.02X", i+0x10000, /*((uint8_t*)mem)[i+0x11000]*/ xbox.xbe.m_pXbeData[i] );
SendDlgItemMessage( hwnd, list, LB_ADDSTRING, 0, (LPARAM) string );
}
}
/* Initialize the emulation thread */
int initialize_emulation_thread()
{
/* Initialize the emulation thread */
int ret = pthread_create( &xbox.emulation_thread_handle, NULL, emulation_thread, NULL );
if( ret )
{
msg_box( "Error creating POSIX thread!", MB_OK );
return 0;
}
/* Enable the debugger if desired */
if( enable_debugger )
{
/* Small delay */
Sleep( 500 );
show_debugger();
}
return 1;
}