mirror of
https://github.com/open-develop/xenoborg.git
synced 2025-04-02 13:21:42 -04:00
347 lines
No EOL
8 KiB
C
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;
|
|
} |