// ----------------------------------------------------------------------- // // // ROUTINE: CTronPlayerObj::Load // // PURPOSE: Load the object // // ----------------------------------------------------------------------- // void CTronPlayerObj::Load(ILTMessage_Read *pMsg, uint32 dwLoadFlags) { for(int i=0;i<NUM_RATINGS;i++) { LOAD_BYTE(m_iPerformanceRatings[i]); } LOAD_BYTE(m_byPSets); LOAD_BYTE(m_byOldPSets); LOAD_BYTE(m_nArmorPercentage); LOAD_WORD(m_nBuildPoints); LOAD_WORD(m_nOldBuildPoints); CPlayerObj::Load(pMsg, dwLoadFlags); }
dword TFDSize(byte *pTFD) { TRACEENTER(); word NrBlocks = 0; dword i; byte *p = pTFD; if(!pTFD) { TRACEEXIT(); return 0; } if(LOAD_WORD(p) != 8) { //Invalid header TRACEEXIT(); return 0; } if(CRC16 (0, p + 4, 6) != LOAD_WORD(p + 2)) { //Invalid header CRC TRACEEXIT(); return 0; } if(LOAD_WORD(p + 6) != 1) { //Invalid file version TRACEEXIT(); return 0; } NrBlocks = LOAD_WORD(p + 8); p += 10; for(i = 0; i < NrBlocks; i++) p += LOAD_WORD(p) + 2; TRACEEXIT(); return p - pTFD; }
dword UncompressedFirmwareSize (byte *pSrc) { word compSize = 0, uncompSize = 0; dword outSize = 0; compSize = LOAD_WORD(pSrc + 2); uncompSize = LOAD_WORD(pSrc + 0); while (uncompSize != 0xfefe) { if (uncompSize > 0x8000) return 0; pSrc += (6 + compSize); outSize += uncompSize; compSize = LOAD_WORD(pSrc + 2); uncompSize = LOAD_WORD(pSrc + 0); } return outSize; }
//Every block has the following header: // 0 - compressed size includeing header (word) // 2 - CRC-16 (word) // 4 - block type // 6 - uncompressed size (word) // 8 .. (compressed size + 5) - compressed data (byte array) dword UncompressTFD (byte *pSrc, byte *pDest, void *pPercentFinishedCallback) { word compSize = 0, uncompSize = 0, NrBlocks = 0; dword outSize = 0, i; //PercentFinishedCallback is called for every block. PercentFinished contains a number between 0 and 100 void (*PercentFinishedCallback) (dword PercentFinished) = pPercentFinishedCallback; if (LOAD_WORD(pSrc) != 8) return 0; //Invalid header? if (CRC16 (0, pSrc + 4, 6) != LOAD_WORD(pSrc + 2)) return 0; //Invalid header CRC? if (LOAD_WORD(pSrc + 6) != 1) return 0; //Invalid file version? NrBlocks = LOAD_WORD(pSrc + 8); pSrc += 10; for (i = 0; i < NrBlocks; i++) { if (PercentFinishedCallback) PercentFinishedCallback (i * 100 / NrBlocks); compSize = LOAD_WORD(pSrc) - 6; uncompSize = LOAD_WORD(pSrc + 6); if (uncompSize > 0x7ffa) return 0; pSrc += 8; if(compSize == uncompSize) { // not compressed data, copy it directly if (pDest) memcpy(pDest, pSrc, uncompSize); } else { // compressed data, uncompress it if (!UncompressBlock (pSrc, compSize, pDest, uncompSize)) return 0; } if (pDest) pDest += uncompSize; pSrc += compSize; outSize += uncompSize; } if (PercentFinishedCallback) PercentFinishedCallback (100); return outSize; }
// UncompressFirmware() is a function wrapper that decodes data blocks // encoded with AR002 algorithm until the uncompressed size field // is set to 0xfefe. This is normaly used for the Loader or the Firmware // inside of the flash memory. // The expected block structure is as follows: // 0 - uncompressed size (word) // 2 - compressed size (incl CRC-16) (word) // 4 - CRC-16 (word) // 6 .. (compressed size + 5) - compressed data (byte array) dword UncompressFirmware(byte *pSrc, byte *pDest, void *pPercentFinishedCallback) { TRACEENTER(); word compSize = 0, uncompSize = 0; dword outSize = 0, NrBlocks = 0, CurrentBlock = 0; byte *OrigpSrc; if(!pSrc || !pDest) { TRACEEXIT(); return 0; } //PercentFinishedCallback is called for every block. PercentFinished contains a number between 0 and 100 void (*PercentFinishedCallback) (dword PercentFinished) = pPercentFinishedCallback; OrigpSrc = pSrc; uncompSize = LOAD_WORD(pSrc + 0); compSize = LOAD_WORD(pSrc + 2); //Count the number of blocks while(uncompSize != 0xfefe) { NrBlocks++; if(uncompSize > 0x8000) { //Uncompressed data block size too large TRACEEXIT(); return 0; } pSrc += 4; pSrc += compSize; uncompSize = LOAD_WORD(pSrc + 0); compSize = LOAD_WORD(pSrc + 2); } pSrc = OrigpSrc; uncompSize = LOAD_WORD(pSrc + 0); compSize = LOAD_WORD(pSrc + 2); while(uncompSize != 0xfefe) { if(PercentFinishedCallback) PercentFinishedCallback(CurrentBlock * 100 / NrBlocks); CurrentBlock++; if(uncompSize > 0x8000) { //Uncompressed data block size too large TRACEEXIT(); return 0; } pSrc += 6; if(compSize == uncompSize) { // data not compressed, copy it directly if(pDest) memcpy(pDest, pSrc, uncompSize); } else { // compressed data, uncompress it if(!UncompressBlock(pSrc, compSize, pDest, uncompSize)) { //Uncompress has failed TRACEEXIT(); return 0; } } if(pDest) pDest += uncompSize; pSrc += compSize; outSize += uncompSize; uncompSize = LOAD_WORD(pSrc + 0); compSize = LOAD_WORD(pSrc + 2); } if(PercentFinishedCallback) PercentFinishedCallback(100); TRACEEXIT(); return outSize; }
/* This function disassembles the opcode at the PC and outputs it in *output */ static void disassemble(char *output, uint8_t *buffer, options_t *options, uint16_t *pc) { char opcode_repr[256], hex_dump[256]; int opcode_idx; int len = 0; int entry = 0; int found = 0; uint8_t byte_operand; uint16_t word_operand = 0; uint16_t current_addr = *pc; uint8_t opcode = buffer[current_addr]; const char *mnemonic; opcode_repr[0] = '\0'; hex_dump[0] = '\0'; // Linear search for opcode for (opcode_idx = 0; opcode_idx < NUMBER_OPCODES; opcode_idx++) { if (opcode == g_opcode_table[opcode_idx].number) { /* Found the opcode, record its table index */ found = 1; entry = opcode_idx; } } // For opcode not found, terminate early if (!found) { sprintf(opcode_repr, ".byte $%02X", opcode); if (options->hex_output) { sprintf(hex_dump, "$%04X> %02X:", current_addr, opcode); sprintf(output, "%-16s%-16s; INVALID OPCODE !!!\n", hex_dump, opcode_repr); } else { sprintf(hex_dump, "$%04X", current_addr); sprintf(output, "%-8s%-16s; INVALID OPCODE !!!\n", hex_dump, opcode_repr); } return; } // Opcode found in table: disassemble properly according to addressing mode mnemonic = g_opcode_table[entry].mnemonic; // Set hex dump to default single address format. Will be overwritten // by more complex output in case of hex dump mode enabled sprintf(hex_dump, "$%04X", current_addr); switch (g_opcode_table[entry].addressing) { case IMMED: /* Get immediate value operand */ byte_operand = buffer[*pc + 1]; *pc += 1; sprintf(opcode_repr, "%s #$%02X", mnemonic, byte_operand); if (options->hex_output) { sprintf(hex_dump, "$%04X> %02X %02X:", current_addr, opcode, byte_operand); } break; case ABSOL: /* Get absolute address operand */ word_operand = LOAD_WORD(buffer, *pc); *pc += 2; sprintf(opcode_repr, "%s $%02X%02X", mnemonic, HIGH_PART(word_operand), LOW_PART(word_operand)); if (options->hex_output) { sprintf(hex_dump, "$%04X> %02X %02X%02X:", current_addr, opcode, LOW_PART(word_operand), HIGH_PART(word_operand)); } break; case ZEROP: /* Get zero page address */ byte_operand = buffer[*pc + 1]; *pc += 1; sprintf(opcode_repr, "%s $%02X", mnemonic, byte_operand); if (options->hex_output) { sprintf(hex_dump, "$%04X> %02X %02X:", current_addr, opcode, byte_operand); } break; case IMPLI: sprintf(opcode_repr, "%s", mnemonic); if (options->hex_output) { sprintf(hex_dump, "$%04X> %02X:", current_addr, opcode); } break; case INDIA: /* Get indirection address */ word_operand = LOAD_WORD(buffer, *pc); *pc += 2; sprintf(opcode_repr, "%s ($%02X%02X)", mnemonic, HIGH_PART(word_operand), LOW_PART(word_operand)); if (options->hex_output) { sprintf(hex_dump, "$%04X> %02X %02X%02X:", current_addr, opcode, LOW_PART(word_operand), HIGH_PART(word_operand)); } break; case ABSIX: /* Get base address */ word_operand = LOAD_WORD(buffer, *pc); *pc += 2; sprintf(opcode_repr, "%s $%02X%02X,X", mnemonic, HIGH_PART(word_operand), LOW_PART(word_operand)); if (options->hex_output) { sprintf(hex_dump, "$%04X> %02X %02X%02X:", current_addr, opcode, LOW_PART(word_operand), HIGH_PART(word_operand)); } break; case ABSIY: /* Get baser address */ word_operand = LOAD_WORD(buffer, *pc); *pc += 2; sprintf(opcode_repr, "%s $%02X%02X,Y", mnemonic, HIGH_PART(word_operand), LOW_PART(word_operand)); if (options->hex_output) { sprintf(hex_dump, "$%04X> %02X %02X%02X:", current_addr, opcode, LOW_PART(word_operand), HIGH_PART(word_operand)); } break; case ZEPIX: /* Get zero-page base address */ byte_operand = buffer[*pc + 1]; *pc += 1; sprintf(opcode_repr, "%s $%02X,X", mnemonic, byte_operand); if (options->hex_output) { sprintf(hex_dump, "$%04X> %02X %02X:", current_addr, opcode, byte_operand); } break; case ZEPIY: /* Get zero-page base address */ byte_operand = buffer[*pc + 1]; *pc += 1; sprintf(opcode_repr, "%s $%02X,Y", mnemonic, byte_operand); if (options->hex_output) { sprintf(hex_dump, "$%04X> %02X %02X:", current_addr, opcode, byte_operand); } break; case INDIN: /* Get zero-page base address */ byte_operand = buffer[*pc + 1]; *pc += 1; sprintf(opcode_repr, "%s ($%02X,X)", mnemonic, byte_operand); if (options->hex_output) { sprintf(hex_dump, "$%04X> %02X %02X:", current_addr, opcode, byte_operand); } break; case ININD: /* Get zero-page base address */ byte_operand = buffer[*pc + 1]; *pc += 1; sprintf(opcode_repr, "%s ($%02X),Y", mnemonic, byte_operand); if (options->hex_output) { sprintf(hex_dump, "$%04X> %02X %02X:", current_addr, opcode, byte_operand); } break; case RELAT: /* Get relative modifier */ byte_operand = buffer[*pc + 1]; *pc += 1; // Compute displacement from first byte after full instruction. word_operand = current_addr + 2; if (byte_operand > 0x7Fu) { word_operand -= ((~byte_operand & 0x7Fu) + 1); } else { word_operand += byte_operand & 0x7Fu; } sprintf(opcode_repr, "%s $%04X", mnemonic, word_operand); if (options->hex_output) { sprintf(hex_dump, "$%04X> %02X %02X:", current_addr, opcode, byte_operand); } break; case ACCUM: sprintf(opcode_repr, "%s A", mnemonic); if (options->hex_output) { sprintf(hex_dump, "$%04X> %02X:", current_addr, opcode); } break; default: // Will not happen since each entry in opcode_table has address mode set break; } // Emit disassembly line content, prior to annotation comments len = sprintf(output, DUMP_FORMAT, hex_dump, opcode_repr); output += len; /* Add cycle count if necessary */ if (options->cycle_counting) { output = append_cycle(output, entry, *pc + 1, word_operand); } /* Add NES port info if necessary */ switch (g_opcode_table[entry].addressing) { case ABSOL: case ABSIX: case ABSIY: if (options->nes_mode) { append_nes(output, word_operand); } break; default: /* Other addressing modes: not enough info to add NES register annotation */ break; } }