void Z80_Disassemble_GetDecoratedSymbolFromAddress(const char* mnemonic, u16 addr, char* buf, int buf_len, bool display_symbols, bool display_addr) { const t_debugger_symbol* symbol = NULL; if (display_symbols) { if (Z80_IsModifyingPC(mnemonic)) symbol = Debugger_Symbols_GetClosestPreviousByAddr(addr, 64); // too misleading for data address so only use for code address else symbol = Debugger_Symbols_GetLastByAddr(addr); } if (symbol != NULL) { if (display_addr) { if (symbol->cpu_addr != addr) snprintf(buf, buf_len,"%s+%Xh/%04Xh", symbol->name, addr-symbol->cpu_addr, addr); else snprintf(buf, buf_len,"%s/%04Xh", symbol->name, addr); } else { if (symbol->cpu_addr != addr) snprintf(buf, buf_len,"%s+%Xh", symbol->name, addr-symbol->cpu_addr); else snprintf(buf, buf_len,"%s", symbol->name); } } else { snprintf(buf, buf_len,"%04Xh", addr); } }
int Z80_Disassemble(char *S, word A, bool display_symbols, bool resolve_indirect_offsets) { char R[256], H[256], C, *T, *P; byte J, Offset = 0; word B; int relative_offset_base = 0; // 0 : from PC, 1 : from IX, 2 : from IY B = A; C = '\0'; J = 0; switch (RdZ80_NoHook(B)) { case 0xCB: B++;T=MnemonicsCB[RdZ80_NoHook(B++&0xFFFF)];break; case 0xED: B++;T=MnemonicsED[RdZ80_NoHook(B++&0xFFFF)];break; case 0xDD: B++;C='X'; if (RdZ80_NoHook(B&0xFFFF)!=0xCB) T=MnemonicsXX[RdZ80_NoHook(B++&0xFFFF)]; else { B++;Offset=RdZ80_NoHook(B++&0xFFFF);J=1;T=MnemonicsXCB[RdZ80_NoHook(B++&0xFFFF)]; } break; case 0xFD: B++;C='Y'; if(RdZ80_NoHook(B&0xFFFF)!=0xCB) T=MnemonicsXX[RdZ80_NoHook(B++&0xFFFF)]; else { B++;Offset=RdZ80_NoHook(B++&0xFFFF);J=1;T=MnemonicsXCB[RdZ80_NoHook(B++&0xFFFF)]; } break; default: T=Mnemonics[RdZ80_NoHook(B++&0xFFFF)]; break; } if ((P=strchr(T,'^')) != NULL) { strncpy(R,T,P-T);R[P-T]='\0'; sprintf(H,"%02Xh",RdZ80_NoHook(B++&0xFFFF)); strcat(R,H);strcat(R,P+2); } else strcpy(R,T); if ((P=strchr(R,'%')) != NULL) { *P=C; if (C == 'X') relative_offset_base = 1; else if (C == 'Y') relative_offset_base = 2; } if ((P=strchr(R,'*')) != NULL) { if (S != NULL) { strncpy(S,R,P-R);S[P-R]='\0'; sprintf(H,"%02Xh",RdZ80_NoHook(B++&0xFFFF)); strcat(S,H);strcat(S,P+2); } else { B++; } } else if ((P=strchr(R,'@')) != NULL) { if (S != NULL) { strncpy(S,R,P-R);S[P-R]='\0'; if(!J) Offset=RdZ80_NoHook(B++&0xFFFF); if (resolve_indirect_offsets && relative_offset_base == 0) { const u16 target = B + (signed char)Offset; const char sign = (Offset & 0x80) ? '-' : '+'; J = (Offset & 0x80) ? 256 - Offset : Offset; sprintf(H, "%c%02Xh (%04Xh)", sign, J, target); strcat(S,H);strcat(S,P+2); // skip the 'h' in the instruction } else { strcat(S,Offset&0x80? "-":"+"); J=Offset&0x80? 256-Offset:Offset; sprintf(H,"%02Xh",J); strcat(S,H);strcat(S,P+2); // skip the 'h' in the instruction } } else { B++; } } else if((P=strchr(R,'#')) != NULL) { if (S != NULL) { u16 addr = RdZ80_NoHook(B&0xFFFF)+256*RdZ80_NoHook((B+1)&0xFFFF); t_debugger_symbol *symbol = display_symbols ? Debugger_Symbols_GetLastByAddr(addr) : NULL; if (symbol != NULL) { strncpy(S,R,P-R);S[P-R]='\0'; snprintf(H,256,"%s (%04Xh)", symbol->name, addr); strcat(S,H);strcat(S,P+2); // skip the 'h' in the instruction } else { strncpy(S,R,P-R);S[P-R]='\0'; sprintf(H,"%04Xh", addr); strcat(S,H);strcat(S,P+2); // skip the 'h' in the instruction } } B += 2; } else { if (S != NULL) strcpy(S, R); } // MEKA-START: needed so it works properly when the instruction wrap at 0xffff if (B < A) return ((int)B+0x10000 - (int)A); // MEKA-END return (B-A); }
int Z80_Disassemble(char *S, word A, bool display_symbols, bool display_symbols_for_current_index_registers, bool resolve_indirect_offsets) { char R[256], H[256], C; byte Offset = 0; bool has_offset = false; word B; int relative_offset_base = 0; // 0 : from PC, 1 : from IX, 2 : from IY B = A; C = '\0'; const char *T_const = NULL; switch (RdZ80_NoHook(B)) { case 0xCB: B++;T_const=MnemonicsCB[RdZ80_NoHook(B++&0xFFFF)];break; case 0xED: B++;T_const=MnemonicsED[RdZ80_NoHook(B++&0xFFFF)];break; case 0xDD: B++;C='x'; if (RdZ80_NoHook(B&0xFFFF)!=0xCB) T_const=MnemonicsXX[RdZ80_NoHook(B++&0xFFFF)]; else { B++;Offset=RdZ80_NoHook(B++&0xFFFF);has_offset=true;T_const=MnemonicsXCB[RdZ80_NoHook(B++&0xFFFF)]; } break; case 0xFD: B++;C='y'; if(RdZ80_NoHook(B&0xFFFF)!=0xCB) T_const=MnemonicsXX[RdZ80_NoHook(B++&0xFFFF)]; else { B++;Offset=RdZ80_NoHook(B++&0xFFFF);has_offset=true;T_const=MnemonicsXCB[RdZ80_NoHook(B++&0xFFFF)]; } break; default: T_const=Mnemonics[RdZ80_NoHook(B++&0xFFFF)]; break; } char T[32]; strcpy(T, T_const); StrLower(T); char *P; if ((P=strchr(T,'^')) != NULL) { assert(!has_offset); // Should never get a ^ in the DD CB and FD CB paths if (S != NULL) { Offset = RdZ80_NoHook(B&0xFFFF); // convert 0xFF to -0x01 for nicer display const char offset_sign = (Offset & 0x80) ? '-' : '+'; const byte offset_abs = (Offset & 0x80) ? 256 - Offset : Offset; if (resolve_indirect_offsets) { if (display_symbols_for_current_index_registers) { // P+2: skip the 'h' in the instruction const u16 addr = ((C == 'x') ? sms.R.IX.W : sms.R.IY.W) + (signed char)Offset; Z80_Disassemble_GetDecoratedSymbolFromAddress(R, addr, H, 256, display_symbols, false); // Don't display full address because it is obvious (for IX/IY being typically stable) snprintf(R, 256, "%.*s%c%d=%s%s", (int)(P-T), T, offset_sign, offset_abs, H, P+2); } else { // P+2: skip the 'h' in the instruction snprintf(R, 256, "%.*s%c%d%s", (int)(P-T), T, offset_sign, offset_abs, P+2); } } else { snprintf(R, 256, "%.*s%c%d", (int)(P-T), T, offset_sign, offset_abs); } } else { strcpy(R,T); } B++; } else { strcpy(R,T); } if ((P=strchr(R,'%')) != NULL) { *P=C; if (C == 'x') relative_offset_base = 1; else if (C == 'y') relative_offset_base = 2; } if ((P=strchr(R,'*')) != NULL) { if (S != NULL) { strncpy(S,R,P-R);S[P-R]='\0'; sprintf(H,"%02Xh",RdZ80_NoHook(B&0xFFFF)); strcat(S,H);strcat(S,P+2); } B++; } else { if ((P=strchr(R,'@')) != NULL) { if (S != NULL) { if(!has_offset) Offset=RdZ80_NoHook(B&0xFFFF); // convert 0xFF to -0x01 for nicer display const char offset_sign = (Offset & 0x80) ? '-' : '+'; const byte offset_abs = (Offset & 0x80) ? 256 - Offset : Offset; if (resolve_indirect_offsets) { // P+2: skip the 'h' in the instruction if (relative_offset_base == 0) { const u16 addr = (B+1) + (signed char)Offset; Z80_Disassemble_GetDecoratedSymbolFromAddress(R, addr, H, 256, display_symbols, true); snprintf(S, 255, "%.*s%c%02Xh (%s)%s", (int)(P-R), R, offset_sign, offset_abs, H, P+2); } else { const u16 addr = ((relative_offset_base == 1) ? sms.R.IX.W : sms.R.IY.W) + (signed char)Offset; Z80_Disassemble_GetDecoratedSymbolFromAddress(R, addr, H, 256, display_symbols, false); // Don't display full address because it is obvious (for IX/IY being typically stable) snprintf(S, 255, "%.*s%c%d=%s%s", (int)(P-R), R, offset_sign, offset_abs, H, P+2); } } else { // P+2: skip the 'h' in the instruction snprintf(S, 256, "%.*s%c%02Xh%s", (int)(P-R), R, offset_sign, offset_abs, P+2); } } if(!has_offset) B++; } else if((P=strchr(R,'#')) != NULL) { if (S != NULL) { const u16 addr = RdZ80_NoHook(B&0xFFFF)+256*RdZ80_NoHook((B+1)&0xFFFF); Z80_Disassemble_GetDecoratedSymbolFromAddress(R, addr, H, 256, display_symbols, true); snprintf(S, 256, "%.*s%s%s", (int)(P-R), R, H, P+2); } B += 2; } else if(strncmp(R,"rst ",4)==0) { if (S != NULL) { const u16 addr = (u16)Debugger_Eval_ParseIntegerHex(R+4); const t_debugger_symbol* symbol = display_symbols ? Debugger_Symbols_GetLastByAddr(addr) : NULL; if (symbol != NULL) { sprintf(S,"rst %s/%02Xh", symbol->name, addr); } else { strcpy(S, R); } } } else { if (S != NULL) strcpy(S, R); } } // MEKA-START: needed so it works properly when the instruction wrap at 0xffff if (B < A) return ((int)B+0x10000 - (int)A); // MEKA-END return (B-A); }