/* PokeMini - Pokémon-Mini Emulator Copyright (C) 2009-2012 JustBurn This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include "InstructionProc.h" #include "InstructionInfo.h" #include "PMCommon.h" // Get instruction data and size, return InstructionInfo InstructionInfo *GetInstructionInfo(InstructionProcReadCB readcb, int cpu, uint32_t addr, uint8_t *data, int *size) { InstructionInfo *II; uint8_t IR, IR2; if (!readcb) return 0; IR = readcb(cpu, addr); if (IR == 0xCE) { // Expand 1 IR2 = readcb(cpu, addr+1); II = &DebugCPUInstructions_CE[IR2]; if (data) { data[0] = IR; data[1] = IR2; if (II->size >= 3) data[2] = readcb(cpu, addr+2); if (II->size >= 4) data[3] = readcb(cpu, addr+3); } if (size) *size = II->size; return II; } else if (IR == 0xCF) { // Expand 2 IR2 = readcb(cpu, addr+1); II = &DebugCPUInstructions_CF[IR2]; if (data) { data[0] = IR; data[1] = IR2; if (II->size >= 3) data[2] = readcb(cpu, addr+2); if (II->size >= 4) data[3] = readcb(cpu, addr+3); } if (size) *size = II->size; return II; } else { // No expand II = &DebugCPUInstructions_XX[IR]; if (data) { data[0] = IR; if (II->size >= 2) data[1] = readcb(cpu, addr+1); if (II->size >= 3) data[2] = readcb(cpu, addr+2); if (II->size >= 4) data[3] = readcb(cpu, addr+3); } if (size) *size = II->size; return II; } } // %u = Unsigned 8-Bits // %U = Unsigned 16-Bits // %s = Signed 8-Bits // %S = Signed 16-Bits // %j = Relative jump (8-Bits) // %J = Relative jump (16-Bits) // %h = Relative expanded jump (8-Bits) // %i = Interrupt // Default operand number decode int DefaultOperandNumberDec(char *sout, char type, uint32_t addr, int value) { switch (type) { case 'u': // %u = Unsigned 8-Bits case 'i': // %i = Interrupt sprintf(sout, "$%02X", value); break; case 'U': // %U = Unsigned 16-Bits sprintf(sout, "$%04X", value); break; case 's': // %s = Unsigned 8-Bits if (value < 0) { sprintf(sout, "-$%02X", -value); } else { sprintf(sout, "$%02X", value); } break; case 'S': // %S = Unsigned 16-Bits if (value < 0) { sprintf(sout, "-$%04X", -value); } else { sprintf(sout, "$%04X", value); } break; case 'j': // %j = Relative jump (8-Bits) case 'J': // %J = Relative jump (16-Bits) case 'h': // %h = Relative expanded jump (8-Bits) if (value >= 0x8000) value = 0x8000 | (value & 0x7FFF); else value &= 0xFFFF; sprintf(sout, "@%04X", value); break; default: return 0; } return 1; } // Default operand number encode int DefaultOperandNumberEnc(char *sin, char type, uint32_t addr, InstructionInfo *opcode, uint8_t *data, char *err) { char ch, lastch = 0, negnum = 0; int val = 0, base = 10, absjmp = 0; while ((ch = *sin++) != 0) { switch (ch) { case '#': case '+': // Ignored break; case '@': // Absolute jump absjmp = 1; base = 16; break; case '-': // Negative negnum = !negnum; break; case '$': // Hexadecimal base = 16; break; case 'x': case 'X': if (lastch != '0') return 0; base = 16; break; case '0': case '1': case '2': case '3': // Number case '4': case '5': case '6': case '7': case '8': case '9': val = (val * base) + (ch - '0'); break; case 'a': case 'b': case 'c': case 'd': // Hex number case 'e': case 'f': if (base != 16) { sprintf(err, "Error: Invalid character: '%c'\n", ch); return 0; } val = (val * base) + (ch - 'a') + 10; break; case 'A': case 'B': case 'C': case 'D': // Hex number case 'E': case 'F': if (base != 16) { sprintf(err, "Error: Invalid character: '%c'\n", ch); return 0; } val = (val * base) + (ch - 'A') + 10; break; default: // Invalid sprintf(err, "Error: Invalid character: '%c'\n", ch); return 0; } lastch = ch; } if (negnum) val = -val; switch (type) { case 'u': // %u = Unsigned 8-Bits if (val >= 256) { sprintf(err, "Error: Value out of range %i\nMust be between 0 and 255\n", val); return 0; } data[0] = val; break; case 'U': // %U = Unsigned 16-Bits if (val >= 65536) { sprintf(err, "Error: Value out of range: %i\nMust be between 0 and 65535\n", val); return 0; } data[0] = val; data[1] = val >> 8; break; case 's': // %s = Signed 8-Bits if ((val < -128) || (val >= 256)) { sprintf(err, "Error: Value out of range: %i\nMust be between -128 and 127\n", val); return 0; } data[0] = val; break; case 'S': // %S = Signed 16-Bits if ((val < -32768) || (val >= 65536)) { sprintf(err, "Error: Value out of range: %i\nMust be between -32768 and 32767\n", val); return 0; } data[0] = val; data[1] = val >> 8; break; case 'j': // %j = Relative jump (8-Bits) if (absjmp) { val = val - addr - 1; } if ((val < -128) || (val >= 128)) { sprintf(err, "Error: Value out of range: %i\nJump out of reach\n", val); return 0; } data[0] = val; break; case 'J': // %J = Relative jump (16-Bits) if (absjmp) { val = val - addr - 2; } data[0] = val; data[1] = val >> 8; break; case 'h': // %h = Relative expanded jump (8-Bits) if (absjmp) { val = val - addr - 2; } if ((val < -128) || (val >= 128)) { sprintf(err, "Error: Value out of range: %i\nJump out of reach\n", val); return 0; } data[0] = val; break; case 'i': // %i = Interrupt if (val >= 128) { sprintf(err, "Error: Value out of range: %i\nMust be between 0 and 127\n", val); return 0; } data[0] = val << 1; break; default: return 0; } return 1; } // Default single opcode decoder TSOpcDec DefaultSOpcDec = { DefaultOperandNumberDec, // Operand number decode DefaultOperandNumberEnc, // Operand number encode DebugCPUInstructions_Opcode, // Opcode dictionary DebugCPUInstructions_Operand, // Operand dictionary "", // Opcode pre-text " ", // Opcode post-text ", " // Operand separator }; // Parse operand string (decoder) // operand - full operand string // addr - address // data - input data // pout - output string // spcdec - decoder static int ParseOperandStringDec(char *operand, uint32_t addr, uint8_t *data, char *pout, TSOpcDec *sopcdec) { char ch, cod; char tmp[256]; int val; *pout = 0; while ((ch = *operand) != 0) { if (ch == '%') { cod = operand[1]; tmp[0] = 0; switch (cod) { case 'u': // %u = Unsigned 8-Bits val = data[0]; break; case 'U': // %U = Unsigned 16-Bits val = data[1] * 256 + data[0]; break; case 's': // %s = Signed 8-Bits val = data[0]; val = (val >= 0x80) ? val - 256 : val; break; case 'S': // %S = Signed 16-Bits val = data[1] * 256 + data[0]; val = (val >= 0x8000) ? val - 65536 : val; break; case 'j': // %j = Relative jump (8-Bits) val = data[0]; val = (val >= 0x80) ? val - 256 : val; val = addr + 1 + val; break; case 'J': // %J = Relative jump (16-Bits) val = data[1] * 256 + data[0]; val = (val >= 0x8000) ? val - 65536 : val; val = addr + 2 + val; break; case 'h': // %h = Relative expanded jump (8-Bits) val = data[0]; val = (val >= 0x80) ? val - 256 : val; val = addr + 2 + val; break; case 'i': // %i = Interrupt val = data[0] >> 1; break; default: // Invalid val = 0; break; } if (!sopcdec->on_opndec(tmp, cod, addr, val)) return 0; strcat(pout, tmp); pout += strlen(tmp); operand += 2; continue; } *pout++ = ch; *pout = 0; operand++; } return 1; } // Disassemble single opcode int DisasmSingleOpcode(InstructionInfo *opcode, uint32_t addr, uint8_t *data, char *sout, TSOpcDec *sopcdec) { char tmp[256]; if ((!sout) || (!opcode)) return 0; if (!opcode->opc) { // Raw data strcpy(sout, ".DB "); if (opcode->size >= 1) { sprintf(tmp, "$%02X", data[0]); strcat(sout, tmp); } if (opcode->size >= 2) { sprintf(tmp, ",$%02X", data[1]); strcat(sout, tmp); } if (opcode->size >= 3) { sprintf(tmp, ",$%02X", data[2]); strcat(sout, tmp); } if (opcode->size >= 4) { sprintf(tmp, ",$%02X", data[3]); strcat(sout, tmp); } return 1; } else { // Instruction strcpy(sout, sopcdec->opcode_pre); strcpy(sout, sopcdec->opcode_dict[opcode->opc]); if (opcode->opclen == 1) strcat(sout, "b"); if (opcode->opclen == 2) strcat(sout, "w"); if (opcode->p1) { strcat(sout, sopcdec->opcode_post); if (!ParseOperandStringDec(sopcdec->operand_dict[opcode->p1], addr, (uint8_t *)data + opcode->p1off, tmp, sopcdec)) return 0; strcat(sout, tmp); } if (opcode->p2) { strcat(sout, sopcdec->operand_sep); if (!ParseOperandStringDec(sopcdec->operand_dict[opcode->p2], addr, (uint8_t *)data + opcode->p2off, tmp, sopcdec)) return 0; strcat(sout, tmp); } return 1; } } // Parse operand string (encoder) // operand - expected operand string // addr - address // data - output data // pin - operand input from assembly // opcode - expected opcode // spcdec - decoder static int ParseOperandStringEnc(char *operand, uint32_t addr, uint8_t *data, char *pin, InstructionInfo *opcode, TSOpcDec *sopcdec, char *err) { char ch, cod; char tok[2] = {0, 0}, tokfound; char tmp[256]; while ((ch = *operand) != 0) { if (ch == '%') { cod = operand[1]; // code tok[0] = operand[2]; // next character pin = (char *)UpToToken(tmp, pin, tok, &tokfound) - 1; if (!sopcdec->on_opnenc(tmp, cod, addr, opcode, data, err)) return 0; operand += 2; continue; } // Check for differences if (toupper(ch) != toupper(*pin)) return 0; pin++; operand++; } if ((ch == 0) && (*pin == 0)) return 1; return 0; } // Assemble single opcode InstructionInfo *AsmSingleOpcode(char *sin, uint32_t addr, uint8_t *data, TSOpcDec *sopcdec, char *err) { char tmp[256], *ctmp = tmp; char opcname[256]; char operand1[256], operand2[256]; char operand3[256], operand4[256]; InstructionInfo *opcode; int i; // Empty strings opcname[0] = 0; operand1[0] = 0; operand2[0] = 0; operand3[0] = 0; operand4[0] = 0; sprintf(err, "Error: Syntax error"); // Remove comments and trim strcpy(ctmp, sin); RemoveComments(ctmp); ctmp = TrimStr(tmp); ctmp = UpToToken(opcname, ctmp, " \t", NULL); ctmp = UpToToken(operand1, ctmp, ",", NULL); RemoveChars(operand1, operand1, " \t"); ctmp = UpToToken(operand2, ctmp, ",\n", NULL); RemoveChars(operand2, operand2, " \t"); ctmp = UpToToken(operand3, ctmp, ",\n", NULL); RemoveChars(operand3, operand3, " \t"); ctmp = UpToToken(operand4, ctmp, "\n", NULL); RemoveChars(operand4, operand4, " \t"); // Data (Byte) if (!strcasecmp(opcname, ".DB")) { i = 0; if (!ParseOperandStringEnc("%u", 0, (uint8_t *)data+0, operand1, DebugCPUInstructions_DX, sopcdec, err)) return NULL; if (strlen(operand2)) { i = 1; if (!ParseOperandStringEnc("%u", 0, (uint8_t *)data+1, operand2, DebugCPUInstructions_DX, sopcdec, err)) return NULL; } if (strlen(operand3)) { i = 2; if (!ParseOperandStringEnc("%u", 0, (uint8_t *)data+2, operand3, DebugCPUInstructions_DX, sopcdec, err)) return NULL; } if (strlen(operand4)) { i = 3; if (!ParseOperandStringEnc("%u", 0, (uint8_t *)data+3, operand4, DebugCPUInstructions_DX, sopcdec, err)) return NULL; } return &DebugCPUInstructions_DX[i]; } // Data (Word) if (!strcasecmp(opcname, ".DW")) { i = 4; if (!ParseOperandStringEnc("%U", 0, (uint8_t *)data+0, operand1, DebugCPUInstructions_DX, sopcdec, err)) return NULL; if (strlen(operand2)) { i = 5; if (!ParseOperandStringEnc("%U", 0, (uint8_t *)data+2, operand2, DebugCPUInstructions_DX, sopcdec, err)) return NULL; } if (strlen(operand3)) { i = 6; if (!ParseOperandStringEnc("%U", 0, (uint8_t *)data+4, operand3, DebugCPUInstructions_DX, sopcdec, err)) return NULL; } if (strlen(operand4)) { i = 7; if (!ParseOperandStringEnc("%U", 0, (uint8_t *)data+6, operand4, DebugCPUInstructions_DX, sopcdec, err)) return NULL; } return &DebugCPUInstructions_DX[i]; } // Find opcode from the list for (i=0; i<256; i++) { // XX Opcode opcode = (InstructionInfo *)&DebugCPUInstructions_XX[i]; strcpy(tmp, sopcdec->opcode_dict[opcode->opc]); if (opcode->opclen == 1) strcat(tmp, "b"); if (opcode->opclen == 2) strcat(tmp, "w"); if ((!strcasecmp(opcname, tmp)) || (!strcasecmp(opcname, sopcdec->opcode_dict[opcode->opc]))) { data[0] = i; if (opcode->p1 == 0) return opcode; if (ParseOperandStringEnc(sopcdec->operand_dict[opcode->p1], addr, (uint8_t *)data + opcode->p1off, operand1, opcode, sopcdec, err)) { if (opcode->p2 == 0) return opcode; if (ParseOperandStringEnc(sopcdec->operand_dict[opcode->p2], addr, (uint8_t *)data + opcode->p2off, operand2, opcode, sopcdec, err)) { return opcode; } } } // CE Opcode opcode = (InstructionInfo *)&DebugCPUInstructions_CE[i]; strcpy(tmp, sopcdec->opcode_dict[opcode->opc]); if (opcode->opclen == 1) strcat(tmp, "b"); if (opcode->opclen == 2) strcat(tmp, "w"); if ((!strcasecmp(opcname, tmp)) || (!strcasecmp(opcname, sopcdec->opcode_dict[opcode->opc]))) { data[0] = 0xCE; data[1] = i; if (opcode->p1 == 0) return opcode; if (ParseOperandStringEnc(sopcdec->operand_dict[opcode->p1], addr, (uint8_t *)data + opcode->p1off, operand1, opcode, sopcdec, err)) { if (opcode->p2 == 0) return opcode; if (ParseOperandStringEnc(sopcdec->operand_dict[opcode->p2], addr, (uint8_t *)data + opcode->p2off, operand2, opcode, sopcdec, err)) { return opcode; } } } // CF Opcode opcode = (InstructionInfo *)&DebugCPUInstructions_CF[i]; strcpy(tmp, sopcdec->opcode_dict[opcode->opc]); if (opcode->opclen == 1) strcat(tmp, "b"); if (opcode->opclen == 2) strcat(tmp, "w"); if ((!strcasecmp(opcname, tmp)) || (!strcasecmp(opcname, sopcdec->opcode_dict[opcode->opc]))) { data[0] = 0xCF; data[1] = i; if (opcode->p1 == 0) return opcode; if (ParseOperandStringEnc(sopcdec->operand_dict[opcode->p1], addr, (uint8_t *)data + opcode->p1off, operand1, opcode, sopcdec, err)) { if (opcode->p2 == 0) return opcode; if (ParseOperandStringEnc(sopcdec->operand_dict[opcode->p2], addr, (uint8_t *)data + opcode->p2off, operand2, opcode, sopcdec, err)) { return opcode; } } } } return NULL; }