Commits

spencercw committed 61faaef

Add preliminary support for displaying values for variables stored in registers. Doesn't yet work properly for use of 8-bit registers.

Comments (0)

Files changed (3)

GbDebuggerMsvs/stack_frame.cpp

 using std::hex;
 using std::setfill;
 using std::setw;
+using std::string;
 using std::uppercase;
 using std::vector;
 using std::wostringstream;
 	f << "CGbVsStackFrame::EnumProperties\n";
 	f.close();
 
-	if (nRadix != 10 && nRadix != 16)
-	{
-		return E_INVALIDARG;
-	}
-
 	if (guidFilter == guidFilterRegisters || guidFilter == guidFilterAutoRegisters)
 	{
 		// Create register categories
 					}
 					break;
 
+				case CdbFile::REGISTER_SPACE:
+					{
+						unsigned size = (*variable)->type->size;
+						if (size != 1 && size != 2)
+						{
+							// Only support single register values at the moment. Not sure if values
+							// can use more than one register anyway
+							value = L"Variable uses more than one register; this is not supported.";
+							attributes |= DBG_ATTRIB_VALUE_ERROR;
+							break;
+						}
+						if ((*variable)->registers.empty())
+						{
+							value = L"Value has been optimised out.";
+							attributes |= DBG_ATTRIB_VALUE_ERROR;
+							break;
+						}
+
+						assert(size == 1 ? (*variable)->registers.size() == 1 :
+							(*variable)->registers.size() == 2);
+						
+						// Find the register
+						const string &regName1 = (*variable)->registers[0];
+						uint16_t reg;
+						if (regName1 == "a" || regName1 == "f")
+						{
+							reg = frame_.registers.af;
+						}
+						else if (regName1 == "b" || regName1 == "c")
+						{
+							reg = frame_.registers.bc;
+						}
+						else if (regName1 == "d" || regName1 == "e")
+						{
+							reg = frame_.registers.de;
+						}
+						else if (regName1 == "h" || regName1 == "l")
+						{
+							reg = frame_.registers.hl;
+						}
+						else
+						{
+							value = L"Unknown register referenced.";
+							attributes |= DBG_ATTRIB_VALUE_ERROR;
+							break;
+						}
+
+						// Check the second register entry refers to the same as the first if
+						// necessary (16-bit registers are referred to by defining both of the 8-bit
+						// components separately; for example, BC is indicated by "b" and "c")
+						if (size == 2)
+						{
+							const string &regName2 = (*variable)->registers[1];
+							if (regName1 == regName2 ||
+								(regName1 == "a" && regName2 != "f") ||
+								(regName1 == "f" && regName2 != "a") ||
+								(regName1 == "b" && regName2 != "c") ||
+								(regName1 == "c" && regName2 != "b") ||
+								(regName1 == "d" && regName2 != "e") ||
+								(regName1 == "e" && regName2 != "d") ||
+								(regName1 == "h" && regName2 != "l") ||
+								(regName1 == "l" && regName2 != "h"))
+							{
+								value = L"Unknown register referenced.";
+								attributes |= DBG_ATTRIB_VALUE_ERROR;
+								break;
+							}
+						}
+
+						// TODO: Handle signedness
+						// TODO: Correctly handle single-byte registers (i.e., show the correct
+						// byte)
+
+						// Format the value
+						wostringstream oss;
+						if (nRadix == 16)
+						{
+							oss << hex << setfill(L'0') << L"0x" << setw(2 * size);
+						}
+						oss << static_cast<unsigned>(reg);
+						value = oss.str();
+					}
+
+					break;
+
 				default:
 					value = L"Unsupported storage type.";
 					attributes |= DBG_ATTRIB_VALUE_ERROR;

gb_emulator/include/gb_emulator/gb_debugger.h

 class Gb;
 class GbCpu;
 
+struct GB_EMULATOR_API GbRegisters
+{
+	uint16_t af;
+	uint16_t bc;
+	uint16_t de;
+	uint16_t hl;
+	uint16_t sp;
+	uint16_t pc;
+	bool ime;
+};
+
 struct GB_EMULATOR_API GbStackFrame
 {
 	bool isRom;
 	uint16_t functionAddr;
 	uint16_t instructionAddr;
 	uint16_t returnAddr;
-};
 
-struct GB_EMULATOR_API GbRegisters
-{
-	uint16_t af;
-	uint16_t bc;
-	uint16_t de;
-	uint16_t hl;
-	uint16_t sp;
-	uint16_t pc;
-	bool ime;
+	GbRegisters registers;
 };
 
 class GB_EMULATOR_API GbDebugger
 	void doMemRead(uint16_t address, uint16_t len, uint8_t *data);
 
 	std::pair<boost::filesystem::path, uint32_t> getModule(bool *isRom = NULL);
+	GbRegisters getRegisters();
 
 	// Disabled operations
 	GbDebugger(const GbDebugger &);

gb_emulator/src/gb_debugger.cpp

 		GbStackFrame &frame = stack_.back();
 		frame.stackAddrMin = gb_.cpu_.sp;
 		frame.instructionAddr = gb_.cpu_.pc;
+		frame.registers = getRegisters();
 	}
 
 	// Create a new stack frame
 			GbStackFrame &frame = stack_.back();
 			frame.stackAddrMin = gb_.cpu_.sp;
 			frame.instructionAddr = gb_.cpu_.pc + 3;
+			frame.registers = getRegisters();
 		}
 
 		// Create a new stack frame
 		// the function being called
 		frame.stackAddrMin = gb_.cpu_.sp + 2;
 		frame.instructionAddr = gb_.cpu_.pc + 1;
+		frame.registers = getRegisters();
 
 		// Create a new stack frame
 		GbStackFrame newFrame;
 	GbStackFrame &frame = stack_.back();
 	frame.stackAddrMin = gb_.cpu_.sp;
 	frame.instructionAddr = gb_.cpu_.pc;
+	frame.registers = getRegisters();
 
 	// Get the source information for the stack frames
 	for (deque<GbStackFrame>::iterator frame = stack_.begin(), end = stack_.end();
 
 void GbDebugger::doRegisters()
 {
-	GbRegisters registers;
-	registers.af = gb_.cpu_.r.r16[AF];
-	registers.bc = gb_.cpu_.r.r16[BC];
-	registers.de = gb_.cpu_.r.r16[DE];
-	registers.hl = gb_.cpu_.r.r16[HL];
-	registers.sp = gb_.cpu_.sp;
-	registers.pc = gb_.cpu_.pc;
-
-	switch (gb_.cpu_.ime)
-	{
-	case IME_DISABLED:
-	case IME_ENABLING:
-		registers.ime = false;
-		break;
-
-	case IME_ENABLED:
-	case IME_DISABLING:
-		registers.ime = true;
-		break;
-
-	default:
-		assert(!"all ime types should have been handled");
-	}
-	
+	GbRegisters registers = getRegisters();
 	NOTIFY(registers, registers)
 }
 
 		return make_pair(gb_.biosFilename_, static_cast<uint32_t>(gb_.bios_.size()));
 	}
 }
+
+GbRegisters GbDebugger::getRegisters()
+{
+	GbRegisters registers;
+	registers.af = gb_.cpu_.r.r16[AF];
+	registers.bc = gb_.cpu_.r.r16[BC];
+	registers.de = gb_.cpu_.r.r16[DE];
+	registers.hl = gb_.cpu_.r.r16[HL];
+	registers.sp = gb_.cpu_.sp;
+	registers.pc = gb_.cpu_.pc;
+
+	switch (gb_.cpu_.ime)
+	{
+	case IME_DISABLED:
+	case IME_ENABLING:
+		registers.ime = false;
+		break;
+
+	case IME_ENABLED:
+	case IME_DISABLING:
+		registers.ime = true;
+		break;
+
+	default:
+		assert(!"all ime types should have been handled");
+	}
+
+	return registers;
+}