示例#1
0
/**	---------------------------------------------------------------------------
	\brief	calculate instruction length of Addr 

	\param	
	\return			
	\code
	\endcode		
-----------------------------------------------------------------------------*/
int GetInstructionLength(BYTE* Addr)
{

#ifdef _USE_LIBDASM_LIB		
	
	INSTRUCTION instr = {0};	
	int Len = get_instruction(&instr, 
						Addr,
						MODE_32);
	// check illegal opcode
	if (0 == Len)
	{
		_ASSERTE(!"get_instruction");
		return -1;
	}

	#ifdef _DEBUG
	char string[256] = {0};
	get_instruction_string(&instr, FORMAT_INTEL, 0, string, sizeof(string));
	_tprintf(TEXT("%s\n"), string);
	#endif
	
	return Len;		

#else

	DISASSEMBLER   Disassembler;
	INSTRUCTION *  Instruction = NULL;	
	if (TRUE != InitDisassembler(&Disassembler, ARCH_X86))
	{
		_ASSERTE(!"InitDisassembler");
		return -1;
	}

	ULONG Flags = DISASM_DISASSEMBLE | DISASM_DECODE | DISASM_STOPONERROR | 
					DISASM_STOPONANOMALY | DISASM_STOPONRETURN;
	Instruction = GetInstruction(&Disassembler, 
							(ULONG)Addr, 
							(PBYTE)Addr,
							Flags);
	if (!Instruction) 
	{
		_ASSERTE(!"GetInstruction");
		CloseDisassembler(&Disassembler);

		return -1;
	}

	#ifdef _DEBUG 
	DumpInstruction(Instruction, TRUE, TRUE);
	#endif
	

	int Len = Instruction->Length;
	CloseDisassembler(&Disassembler);
	return Len;

#endif//_USE_LIBDASM_LIB
}
void DumpExecuteBuffer(LPDIRECT3DEXECUTEBUFFER executeBuffer)
{
	std::ostringstream str;

	D3DEXECUTEDATA data = {};
	data.dwSize = sizeof(D3DEXECUTEDATA);

	D3DEXECUTEBUFFERDESC desc = {};
	desc.dwSize = sizeof(D3DEXECUTEBUFFERDESC);

	executeBuffer->GetExecuteData(&data);
	executeBuffer->Lock(&desc);

	LogObjObject(data.dwInstructionOffset, data.dwInstructionLength, desc.dwBufferSize);

	str << "\tExecute Buffer: ";

	LPD3DTLVERTEX pVertex = (LPD3DTLVERTEX)((char*)desc.lpData + data.dwVertexOffset);

	for (DWORD index = 0; index < data.dwVertexCount; index++)
	{
		LogObjVertex(pVertex->sx, pVertex->sy, pVertex->sz);

		str << std::endl;
		str << "\t" << index << ":";
		str << "\t( " << (int)pVertex->sx << "\t; " << (int)pVertex->sy << "\t; " << (int)pVertex->sz << " )";
		str << "\t" << pVertex->rhw;
		str << "\t " << (void*)pVertex->color;
		str << "\t " << (void*)pVertex->specular;
		str << "\t( " << pVertex->tu << "\t; " << pVertex->tv << " )";

		pVertex++;
	}

	char* pData = (char*)desc.lpData + data.dwInstructionOffset;
	char* pDataEnd = pData + data.dwInstructionLength;
	DWORD instructionIndex = 0;

	while (pData < pDataEnd)
	{
		LPD3DINSTRUCTION instruction = (LPD3DINSTRUCTION)pData;

		str << std::endl;
		str << "\t" << instructionIndex << ":";

		DumpInstruction(str, instruction);

		pData += sizeof(D3DINSTRUCTION) + instruction->bSize * instruction->wCount;
		instructionIndex++;
	}

	executeBuffer->Unlock();

	LogText(str.str());
}
void DumpExecuteBuffer(IDirect3DExecuteBuffer* executeBuffer)
{
	std::ostringstream str;

	D3DEXECUTEDATA data;
	data.dwSize = sizeof(D3DEXECUTEDATA);

	D3DEXECUTEBUFFERDESC desc;
	desc.dwSize = sizeof(D3DEXECUTEBUFFERDESC);

	executeBuffer->GetExecuteData(&data);
	executeBuffer->Lock(&desc);

	str << "\tExecute Buffer:";

	if (DumpExecuteBufferHasTriangling(data, desc))
	{
		str << " triangling";
	}

	LPD3DTLVERTEX pVertex = (LPD3DTLVERTEX)((char*)desc.lpData + data.dwVertexOffset);

	for (DWORD index = 0; index < data.dwVertexCount; index++)
	{
		D3DTLVERTEX v = *pVertex;
		pVertex++;

		v.sx = v.sx;
		v.sy = v.sy;
		v.sz = 1.0f - v.sz;
		v.rhw = 1.0f;

		str << std::endl;
		str << "\t" << index << ":";
		str << "\t( " << v.sx << "\t; " << v.sy << "\t; " << v.sz << " )";
		str << "\t" << v.rhw;
		str << "\t " << (void*)v.color;
		str << "\t " << (void*)v.specular;
		str << "\t( " << v.tu << "\t; " << v.tv << " )";
	}

	char* pData = (char*)desc.lpData + data.dwInstructionOffset;
	char* pDataEnd = pData + data.dwInstructionLength;
	DWORD instructionIndex = 0;

	while (pData < pDataEnd)
	{
		LPD3DINSTRUCTION instruction = (LPD3DINSTRUCTION)pData;

		str << std::endl;
		str << "\t" << instructionIndex << ":";

		DumpInstruction(str, instruction);

		pData += sizeof(D3DINSTRUCTION) + instruction->bSize * instruction->wCount;
		instructionIndex++;
	}

	executeBuffer->Unlock();

	LogText(str.str());
}
示例#4
0
int main( int numArgs, char ** args )
{
	Chip8 chip8;
	Api api;
	api.Initialise( );

	FILE * fh = NULL;
	if ( fopen_s( &fh, "Pong.ch8", "rb" ) == 0 )
	{
		fseek( fh, 0L, SEEK_END );
		size_t fileSize = ftell( fh );
		fseek( fh, 0L, SEEK_SET );
		assert( sizeof( chip8.Memory ) - 0x200 >= fileSize );
		int numRead = fread( &chip8.Memory[ 0x200 ], fileSize, 1, fh );
		assert( numRead == 1 );
		fclose( fh );
	}
	else
	{
		assert( 0 );
		return -1;
	}

	// Previous instruction (for debugging).
	address lastInstruction = 0x0000;

	// Last time we did our 60Hz update.
	Uint32 last60HzTime = SDL_GetTicks( );

	// Instructions processed since last 60hz interval.
	Uint8 instructionsProcessedSinceLastUpdate = 0;

	// Loop forever.
	for ( ; ; )
	{
		// Get time (in milliseconds).
		Uint32 timeNow = SDL_GetTicks( );

		if ( instructionsProcessedSinceLastUpdate >= 15 )
		{
			while ( timeNow - last60HzTime <= 1000.f / 60.f )
			{
				SDL_Delay( 0 );
				timeNow = SDL_GetTicks( );
			}

			instructionsProcessedSinceLastUpdate = 0;
		}

		// If it has been 60Hz since our last update...
		if ( timeNow - last60HzTime > 1000.f / 60.f )
		{
			// Decrement delay register.
			if ( chip8.Cpu.Regs.delay > 0 )
				chip8.Cpu.Regs.delay--;

			// Decrement sound register.
			if ( chip8.Cpu.Regs.sound > 0 )
				chip8.Cpu.Regs.sound--;

			// Update to know when next 60Hz timer should be issued.
			last60HzTime = timeNow;

			// Update API (render to screen, process keys, etc.)
			api.Tick( );
		}

		// Play bleeping sound.
		api.SetSound( chip8.Cpu.Regs.sound > 0 );

		Uint16 instruction = ( ( ( address )chip8.Memory[ chip8.Cpu.Regs.pc ] ) << 8 ) | ( address )chip8.Memory[ chip8.Cpu.Regs.pc + 1 ];

		switch ( instruction )
		{
		case 0x00e0:
			DumpInstruction( "Screen clear" );
			api.ClearScreen( );
			break;

		case 0x00ee:
			DumpInstruction( "Return from sub routine" );

			// Pop current PC from stack.
			assert( chip8.Cpu.StackLevel );
			chip8.Cpu.Regs.pc = chip8.Cpu.Stack[ --chip8.Cpu.StackLevel ];

			break;

		default:
			switch ( instruction & 0xf000 )
			{
			case 0x0000:
				{
					address addr = instruction & 0x0fff;
					DumpInstruction( "Calls RCA 1802 program at address 0x%x", addr );

					// http://devernay.free.fr/hacks/chip8/C8TECH10.HTM#0nnn
					// This instruction is only used on the old computers on which Chip-8 was originally implemented. It is ignored by modern interpreters.

				}
				break;
			case 0x1000:
				{
					address addr = instruction & 0x0fff;
					DumpInstruction( "Jump to 0x%x", addr );

					// Set PC, we do -2 as PC is incremented by two after each instruction.
					chip8.Cpu.Regs.pc = addr - 2;
				}
				break;
			case 0x2000:
				{
					address addr = instruction & 0x0fff;
					DumpInstruction( "Call sub routine to 0x%x", addr );

					// Store current PC on stack.
					chip8.Cpu.Stack[ chip8.Cpu.StackLevel++ ] = chip8.Cpu.Regs.pc;
					assert( chip8.Cpu.StackLevel < 16 );

					// Set PC, we do -2 as PC is incremented by two after each instruction.
					chip8.Cpu.Regs.pc = addr - 2;
				}
				break;
			case 0x3000:
				{
					int reg = ( instruction & 0x0f00 ) >> 8;
					int val = instruction & 0x00ff;
					DumpInstruction( "Skips next instruction if v%02d equals %d", reg, val );

					if ( chip8.Cpu.Regs.v[ reg ] == val )
					{
						chip8.Cpu.Regs.pc += 2;
					}
				}
				break;
			case 0x4000:
				{
					int reg = ( instruction & 0x0f00 ) >> 8;
					int val = instruction & 0x00ff;
					DumpInstruction( "Skips next instruction if v%02d does not equals %d", reg, val );

					if ( chip8.Cpu.Regs.v[ reg ] != val )
					{
						chip8.Cpu.Regs.pc += 2;
					}
				}
				break;
			case 0x5000:
				{
					int reg1 = ( instruction & 0x0f00 ) >> 8;
					int reg2 = ( instruction & 0x00f0 ) >> 4;
					DumpInstruction( "Skips next instruction if v%02d equals v%02d", reg1, reg2 );

					if ( chip8.Cpu.Regs.v[ reg1 ] == chip8.Cpu.Regs.v[ reg2 ] )
					{
						chip8.Cpu.Regs.pc += 2;
					}
				}
				break;
			case 0x6000:
				{
					int reg = ( instruction & 0x0f00 ) >> 8;
					int val = instruction & 0x00ff;
					DumpInstruction( "Set v%02d to %d", reg, val );

					chip8.Cpu.Regs.v[ reg ] = val;
				}
				break;
			case 0x7000:
				{
					int reg = ( instruction & 0x0f00 ) >> 8;
					int val = instruction & 0x00ff;
					DumpInstruction( "Add %d to v%02d", val, reg );

					chip8.Cpu.Regs.v[ reg ] += val;
				}
				break;
			case 0x8000:
				{
					int reg1 = ( instruction & 0x0f00 ) >> 8;
					int reg2 = ( instruction & 0x00f0 ) >> 4;

					switch ( instruction & 0x000f )
					{
					case 0:
						DumpInstruction( "Sets v%02d to v%02d", reg1, reg2 );
						chip8.Cpu.Regs.v[ reg1 ] = chip8.Cpu.Regs.v[ reg2 ];
						break;
					case 1:
						DumpInstruction( "Sets v%02d to v%02d OR v%02d", reg1, reg1, reg2 );
						chip8.Cpu.Regs.v[ reg1 ] = chip8.Cpu.Regs.v[ reg1 ] | chip8.Cpu.Regs.v[ reg2 ];
						break;
					case 2:
						DumpInstruction( "Sets v%02d to v%02d AND v%02d", reg1, reg1, reg2 );
						chip8.Cpu.Regs.v[ reg1 ] = chip8.Cpu.Regs.v[ reg1 ] & chip8.Cpu.Regs.v[ reg2 ];
						break;
					case 3:
						DumpInstruction( "Sets v%02d to v%02d XOR v%02d", reg1, reg1, reg2 );
						chip8.Cpu.Regs.v[ reg1 ] = chip8.Cpu.Regs.v[ reg1 ] ^ chip8.Cpu.Regs.v[ reg2 ];
						break;
					case 4:
						{
							DumpInstruction( "Sets v%02d to v%02d + v%02d [VF = 1 when there is a carry, 0 when not]", reg1, reg1, reg2 );
							unsigned __int16 result = chip8.Cpu.Regs.v[ reg1 ] + chip8.Cpu.Regs.v[ reg2 ];
							chip8.Cpu.Regs.v[ reg1 ] = result & 0xff;
							chip8.Cpu.Regs.v[ 0xf ] = ( result > 0xff ) ? 1 : 0;
						}
						break;
					case 5:
						DumpInstruction( "Sets v%02d to v%02d - v%02d [VF = 0 when there is a borrow, 1 when not]", reg1, reg1, reg2 );
						chip8.Cpu.Regs.v[ 0xf ] = ( chip8.Cpu.Regs.v[ reg1 ] >= chip8.Cpu.Regs.v[ reg2 ] ) ? 1 : 0;
						chip8.Cpu.Regs.v[ reg1 ] = chip8.Cpu.Regs.v[ reg1 ] - chip8.Cpu.Regs.v[ reg2 ];
						break;
					case 6:
						DumpInstruction( "Shift v%02d right by one [VF is set to the least significant bit of v%02d before the shift]", reg1, reg1 );
						chip8.Cpu.Regs.v[ 0xf ] = chip8.Cpu.Regs.v[ reg1 ] & 0x1;
						chip8.Cpu.Regs.v[ reg1 ] >>= 1;
						break;
					case 7:
						DumpInstruction( "Sets v%02d to v%02d - v%02d [VF = 0 when there is a borrow, 1 when not]", reg1, reg2, reg1 );
						chip8.Cpu.Regs.v[ 0xf ] = ( chip8.Cpu.Regs.v[ reg2 ] >= chip8.Cpu.Regs.v[ reg1 ] ) ? 1 : 0;
						chip8.Cpu.Regs.v[ reg1 ] = chip8.Cpu.Regs.v[ reg2 ] - chip8.Cpu.Regs.v[ reg1 ];
						break;
					case 0xe:
						DumpInstruction( "Shift v%02d left by one [VF is set to the most significant bit of v%02d before the shift]", reg1, reg1 );
						chip8.Cpu.Regs.v[ 0xf ] = ( chip8.Cpu.Regs.v[ reg1 ] & 0x80 ) ? 1 : 0;
						chip8.Cpu.Regs.v[ reg1 ] <<= 1;
						break;

					default:
						assert( 0 );
					}
				}
				break;
			case 0x9000:
				{
					int reg1 = ( instruction & 0x0f00 ) >> 8;
					int reg2 = ( instruction & 0x00f0 ) >> 4;
					DumpInstruction( "Skips next instruction if v%02d does not equals v%02d", reg1, reg2 );

					if ( chip8.Cpu.Regs.v[ reg1 ] != chip8.Cpu.Regs.v[ reg2 ] )
					{
						chip8.Cpu.Regs.pc += 2;
					}
				}
				break;
			case 0xa000:
				{
					address addr = instruction & 0x0fff;
					DumpInstruction( "Set i to 0x%x", addr );

					chip8.Cpu.Regs.i = addr;
				}
				break;
			case 0xb000:
				{
					address addr = instruction & 0x0fff;
					DumpInstruction( "Jump to address 0x%x plus v0", addr );

					// Set PC, we do -2 as PC is incremented by two after each instruction.
					chip8.Cpu.Regs.pc = chip8.Cpu.Regs.v[ 0 ] + addr - 2;
				}
				break;
			case 0xc000:
				{
					int reg = ( instruction & 0x0f00 ) >> 8;
					int val = instruction & 0x00ff;
					DumpInstruction( "Set v%02d to random number and %d", reg, val );

					chip8.Cpu.Regs.v[ reg ] = ( rand( ) % 255 ) & val;
				}
				break;
			case 0xd000:
				{
					int reg1 = ( instruction & 0x0f00 ) >> 8;
					int reg2 = ( instruction & 0x00f0 ) >> 4;
					int val = instruction & 0x000f;
					DumpInstruction( "Draw sprite at v%02d,v%02d width 8, height %d", reg1, reg2, val );

					if ( api.DrawAt( chip8.Cpu.Regs.v[ reg1 ], chip8.Cpu.Regs.v[ reg2 ], val, &chip8.Memory[ chip8.Cpu.Regs.i ] ) )
					{
						chip8.Cpu.Regs.v[ 0xf ] = 1;
					}
					else
					{
						chip8.Cpu.Regs.v[ 0xf ] = 0;
					}

					// Each row drawn from address in i register (a bit rows are 8 bits in i register, MSB on left).
					// If any pixels are turned off from this v[15] is set to 1, otherwise v[15] is set to 0.
				}
				break;
			case 0xe000:
				{
					int reg = ( instruction & 0x0f00 ) >> 8;

					switch ( instruction & 0x00ff )
					{
					case 0x9e:
						DumpInstruction( "Skip next instruction if key stored in v%02d is pressed", reg );

						if ( api.IsKeyDown( chip8.Cpu.Regs.v[ reg ] ) )
						{
							chip8.Cpu.Regs.pc += 2;
						}

						break;
					case 0xa1:
						DumpInstruction( "Skip next instruction if key stored in v%02d is not pressed", reg );

						if ( ! api.IsKeyDown( chip8.Cpu.Regs.v[ reg ] ) )
						{
							chip8.Cpu.Regs.pc += 2;
						}

						break;

					default:
						assert( 0 );
					}
				}
				break;
			case 0xf000:
				{
					int reg = ( instruction & 0x0f00 ) >> 8;

					switch ( instruction & 0x00ff )
					{
					case 0x7:
						DumpInstruction( "Set v%02d to value of the delay timer", reg );
						chip8.Cpu.Regs.v[ reg ] = chip8.Cpu.Regs.delay;
						break;
					case 0xa:
						DumpInstruction( "Key press awaited and then stored in v%02d", reg );
						assert( 0 );
						break;
					case 0x15:
						DumpInstruction( "Set delay timer to v%02d", reg );
						chip8.Cpu.Regs.delay = chip8.Cpu.Regs.v[ reg ];
						break;
					case 0x18:
						DumpInstruction( "Set sound timer to v%02d", reg );
						chip8.Cpu.Regs.sound = chip8.Cpu.Regs.v[ reg ];
						break;
					case 0x1e:
						DumpInstruction( "Sets i to i + v%02d", reg );
						chip8.Cpu.Regs.i += chip8.Cpu.Regs.v[ reg ];
						break;
					case 0x29:
						// Characters 0-F (in hexadecimal) are represented by a 4x5 font.
						DumpInstruction( "Sets i to the location of the sprite for the character in v%02d", reg );
						chip8.Cpu.Regs.i = chip8.Cpu.Regs.v[ reg ] * 5;
						break;
					case 0x33:
						{
							// With the most significant of three digits at the address in I, the middle digit at I plus 1, and the least significant digit at I plus 2.
							// In other words, take the decimal representation of VX, place the hundreds digit in memory at location in I, the tens digit at location I+1, and the ones digit at location I+2.
							DumpInstruction( "Stores Binary-coded decimal representation of v%02d in i", reg );
							int hundreds = chip8.Cpu.Regs.v[ reg ] / 100;
							int tens = ( chip8.Cpu.Regs.v[ reg ] / 10 ) % 10;
							int units = chip8.Cpu.Regs.v[ reg ] % 10;

							chip8.Memory[ chip8.Cpu.Regs.i + 0 ] = hundreds;
							chip8.Memory[ chip8.Cpu.Regs.i + 1 ] = tens;
							chip8.Memory[ chip8.Cpu.Regs.i + 2 ] = units;
						}
						break;
					case 0x55:
						DumpInstruction( "Stores v0 to v%02d in memory starting at i", reg );
						for ( int ix = 0; ix < reg + 1; ++ix )
						{
							chip8.Memory[ chip8.Cpu.Regs.i + ix ] = chip8.Cpu.Regs.v[ ix ];
						}
						break;
					case 0x65:
						DumpInstruction( "Fills v0 to v%02d with memory starting at i", reg );
						for ( int ix = 0; ix < reg + 1; ++ix )
						{
							chip8.Cpu.Regs.v[ ix ] = chip8.Memory[ chip8.Cpu.Regs.i + ix ];
						}
						break;

					default:
						assert( 0 );
					}
				}
				break;

			default:
				assert( 0 );
			}
		}

		// Update last instruction (for debugging).
		lastInstruction = instruction;

		// Jump forward to next instruction.
		chip8.Cpu.Regs.pc += 2;

		// Increment instruction counter.
		instructionsProcessedSinceLastUpdate++;
	}

	api.Destroy( );

	return 0;
}