1. spencercw
  2. gb_emulator

Commits

spencercw  committed f70bdea

#17 Add support for debugging large ROMs that have multiple ROM banks.

  • Participants
  • Parent commits 6029773
  • Branches default

Comments (0)

Files changed (8)

File gb_debugger_msvs/breakpoints/pending_breakpoint.cpp

View file
  • Ignore whitespace
 		documentContext->Init(breakpoint->sourceFile, breakpoint->line);
 
 		// Create the code context
-		// TODO: The address needs to be adjusted to handle switchable ROM banks
 		CComObject<CCodeContext> *codeContext;
 		CComObject<CCodeContext>::CreateInstance(&codeContext);
 		codeContext->AddRef();
-		codeContext->Init(documentContext, static_cast<uint16_t>(breakpoint->address),
+		codeContext->Init(documentContext, static_cast<uint32_t>(breakpoint->address),
 			breakpoint->module);
 
 		// Create a breakpoint resolution

File gb_debugger_msvs/code_context.cpp

View file
  • Ignore whitespace
 
 // CCodeContext methods
  
-void CCodeContext::Init(IDebugDocumentContext2 *documentContext, uint16_t address,
+void CCodeContext::Init(IDebugDocumentContext2 *documentContext, uint32_t address,
 	const optional<pair<fs::path, uint32_t> > &module)
 {
 	documentContext_ = documentContext;
 	return module_;
 }
 
-uint16_t CCodeContext::GetAddress() const
+uint32_t CCodeContext::GetAddress() const
 {
 	return address_;
 }

File gb_debugger_msvs/code_context.h

View file
  • Ignore whitespace
 	}
 
 public:
-	void Init(IDebugDocumentContext2 *documentContext, uint16_t address,
+	void Init(IDebugDocumentContext2 *documentContext, uint32_t address,
 		const boost::optional<std::pair<boost::filesystem::path, uint32_t> > &module = boost::none);
 	HRESULT GetDisassemblyStream(DISASSEMBLY_STREAM_SCOPE scope,
 		IDebugDisassemblyStream2 **disassemblyStream);
 
 	boost::optional<std::pair<boost::filesystem::path, uint32_t> > GetModule() const;
-	uint16_t GetAddress() const;
+	uint32_t GetAddress() const;
 
 protected:
 	CComPtr<CDisassemblyStream> disassembly_;
 	CComPtr<IDebugDocumentContext2> documentContext_;
 	boost::optional<std::pair<boost::filesystem::path, uint32_t> > module_;
-	uint16_t address_;
+	uint32_t address_;
 };
 
 OBJECT_ENTRY_AUTO(__uuidof(DebugContext), CCodeContext)

File gb_debugger_msvs/disassembly_stream.cpp

View file
  • Ignore whitespace
 		if (dwFields & DSF_ADDRESS)
 		{
 			wostringstream oss;
-			oss << hex << uppercase << setfill(L'0')
-			    << setw(4) << static_cast<unsigned>(instruction_->second->address);
+			oss << hex << uppercase << setfill(L'0') << setw(6) << instruction_->second->address;
 			wstring address = oss.str();
 			
 			prgDisassembly[i].dwFields |= DSF_ADDRESS;
 		if (dwFields & DSF_ADDRESSOFFSET)
 		{
 			wostringstream oss;
-			oss << hex << uppercase << setfill(L'0')
-			    << setw(4) << static_cast<unsigned>(instruction_->second->address);
+			oss << hex << uppercase << setfill(L'0') << setw(6) << instruction_->second->address;
 			wstring address = oss.str();
 			
 			prgDisassembly[i].dwFields |= DSF_ADDRESSOFFSET;
 	CComObject<CCodeContext> *context;
 	CComObject<CCodeContext>::CreateInstance(&context);
 	context->AddRef();
-	context->Init(NULL, static_cast<uint16_t>(uCodeLocationId), module_);
+	context->Init(NULL, static_cast<uint32_t>(uCodeLocationId), module_);
 
 	*ppCodeContext = context;
 	return S_OK;

File gb_debugger_msvs/stack_frame.cpp

View file
  • Ignore whitespace
 		}
 		else
 		{
-			oss << hex << setw(4) << static_cast<unsigned>(frame_->functionAddr);
+			oss << hex << setw(6) << frame_->functionAddr;
 		}
 		oss << L"()";
 

File gb_emulator/include/gb_emulator/gb_debugger.h

View file
  • Ignore whitespace
 	bool isInterrupt;
 	uint16_t stackAddrMin;
 	uint16_t stackAddrMax;
-	uint16_t functionAddr;
-	uint16_t instructionAddr;
+	uint32_t functionAddr;
+	uint32_t instructionAddr;
 	uint16_t returnAddr;
 
 	GbRegisters registers;
 
 	std::pair<boost::filesystem::path, uint32_t> getModule(bool *isRom = NULL);
 	GbRegisters getRegisters();
+	uint32_t getCodeAddr(uint16_t ptr) const;
 
 	// Disabled operations
 	GbDebugger(const GbDebugger &);

File gb_emulator/src/gb_debugger.cpp

View file
  • Ignore whitespace
 				frame->isInterrupt = false;
 				frame->stackAddrMin = address;
 				frame->stackAddrMax = address;
-				frame->functionAddr = gb_.cpu_.pc;
-				frame->instructionAddr = gb_.cpu_.pc;
+				frame->functionAddr = frame->instructionAddr = getCodeAddr(gb_.cpu_.pc);
 				frame->returnAddr = 0;
 
 				stack_.push_back(frame);
 	{
 		shared_ptr<GbStackFrame> &frame = stack_.back();
 		frame->stackAddrMin = gb_.cpu_.sp;
-		frame->instructionAddr = gb_.cpu_.pc;
+		frame->instructionAddr = getCodeAddr(gb_.cpu_.pc);
 		frame->registers = getRegisters();
 	}
 
 		{
 			shared_ptr<GbStackFrame> &frame = stack_.back();
 			frame->stackAddrMin = gb_.cpu_.sp;
-			frame->instructionAddr = gb_.cpu_.pc + 3;
+			frame->instructionAddr = getCodeAddr(gb_.cpu_.pc + 3);
 			frame->registers = getRegisters();
 		}
 
 			frame->isInterrupt = false;
 			frame->stackAddrMin = gb_.cpu_.sp - 2;
 			frame->stackAddrMax = gb_.cpu_.sp - 2;
-			frame->functionAddr = frame->instructionAddr = gb_.mem_.read16(gb_.cpu_.pc + 1);
+			frame->functionAddr = frame->instructionAddr =
+				getCodeAddr(gb_.mem_.read16(gb_.cpu_.pc + 1));
 			frame->returnAddr = gb_.cpu_.pc + 3;
 
 			stack_.push_back(frame);
 			frame->isInterrupt = false;
 			frame->stackAddrMin = gb_.cpu_.sp + 2;
 			frame->stackAddrMax = gb_.cpu_.sp + 2;
-			frame->functionAddr = returnAddr;
-			frame->instructionAddr = returnAddr;
+			frame->functionAddr = frame->instructionAddr = getCodeAddr(returnAddr);
 			frame->returnAddr = 0;
 
 			stack_.push_back(frame);
 		// Add two to the stack pointer because the return address belongs to the stack frame for
 		// the function being called
 		frame->stackAddrMin = gb_.cpu_.sp + 2;
-		frame->instructionAddr = gb_.cpu_.pc + 1;
+		frame->instructionAddr = getCodeAddr(gb_.cpu_.pc + 1);
 		frame->registers = getRegisters();
 
 		// Create a new stack frame
 		newFrame->isInterrupt = false;
 		newFrame->stackAddrMin = gb_.cpu_.sp;
 		newFrame->stackAddrMax = gb_.cpu_.sp;
-		newFrame->functionAddr = newFrame->instructionAddr = gb_.cpu_.r.r16[HL];
+		newFrame->functionAddr = newFrame->instructionAddr = getCodeAddr(gb_.cpu_.r.r16[HL]);
 		newFrame->returnAddr = returnAddr;
 
 		stack_.push_back(newFrame);
 	// Update the parameters of the current stack frame
 	shared_ptr<GbStackFrame> &frame = stack_.back();
 	frame->stackAddrMin = gb_.cpu_.sp;
-	frame->instructionAddr = gb_.cpu_.pc;
+	frame->instructionAddr = getCodeAddr(gb_.cpu_.pc);
 	frame->registers = getRegisters();
 
 	// Get the source information for the stack frames
 
 	return registers;
 }
+
+uint32_t GbDebugger::getCodeAddr(uint16_t ptr) const
+{
+	// Adjust the address based on the current ROM bank
+	uint32_t addr = ptr;
+	if (ptr >= ROM_BANKX && ptr < VIDEO_RAM)
+	{
+		// Address is in the switchable ROM bank area
+		addr = ptr - ROM_BANKX + ROM_BANK_SIZE * gb_.mem_.romBank;
+	}
+	return addr;
+}

File gb_emulator/src/gb_disassembler.cpp

View file
  • Ignore whitespace
 #include <iomanip>
 #include <iostream>
 
+#include <gb_emulator/constants.hpp>
+
 #include "gb_cpu_opcodes.hpp"
 
 using boost::shared_ptr;
 	disassemblyQueue_.push(addr);
 	for (; !disassemblyQueue_.empty(); disassemblyQueue_.pop())
 	{
-		for (uint32_t addr = disassemblyQueue_.front(); ; ++addr)
+		for (addr = disassemblyQueue_.front(); ; ++addr)
 		{
 			if (!disassembleOp(addr))
 			{
 	case CALL_Z_NN:
 	case CALL_NC_NN:
 	case CALL_C_NN:
-		disassemblyQueue_.push(operand);
+		// Can only statically disassemble code in the fixed ROM bank; everything else will be done
+		// at runtime
+		if (operand < ROM_BANKX)
+		{
+			disassemblyQueue_.push(operand);
+		}
 		break;
 					
 	case JR_N: