/** ** Supermodel ** A Sega Model 3 Arcade Emulator. ** Copyright 2011 Bart Trzynadlowski, Nik Henson ** ** This file is part of Supermodel. ** ** Supermodel 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. ** ** Supermodel 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 Supermodel. If not, see . **/ /* * 53C810Disasm.cpp * * NCR 53C810 SCRIPTS disassembler. * * WARNING: Not all instructions are supported. They are being added as they * are encountered in Model 3 games. Some of the complicated operand forms may * be decoded incorrectly. */ #include #include #ifdef STANDALONE #include #endif #include "Types.h" #define DISASM_VERSION "1.0" /****************************************************************************** Disassembler Function ******************************************************************************/ /* * DisassembleSCRIPTS(op, addr, mnem): * * Disassembles one SCRIPTS instruction. * * Parameters: * op Three consecutive words. * addr Current instruction address. * mnem Buffer to write instruction mnemonic to. If no instruction was * successfully decoded, will be set to '\0'. * * Returns: * Number of 32-bit words decoded (1, 2, or 3) or 0 if the instruction was * not recognized. */ int DisassembleSCRIPTS(UINT32 op[3], UINT32 addr, char *mnem) { static const char *phase[] = { "data_out", "data_in", "command", "status", "res4", "res5", "message_out", "message_in" }; int carry, bitTrue, compData, compPhase, wait, mask, data; mnem[0] = '\0'; if ((op[0]&0xC0000000) == 0) { // Block Move if ((op[0]&0x10000000)) // FROM sprintf(mnem, "move (%d) from %08X, when ", (op[0]>>27)&1, op[1]); else // count { if ((op[0]&0x20000000)) sprintf(mnem, "move (%d) %X, ptr %08X, when ", (op[0]>>27)&1, op[0]&0x00FFFFFF, op[1]); else sprintf(mnem, "move (%d) %X, %08X, when ", (op[0]>>27)&1, op[0]&0x00FFFFFF, op[1]); } strcat(mnem, phase[(op[0]>>24)&7]); return 2; } else if ((op[0]&0xE0000000) == 0xC0000000) { // Move Memory if ((op[0]&0x01000000)) sprintf(mnem, "move memory no flush %X, %08X, %08X", op[0]&0x00FFFFFF, op[1], op[2]); else sprintf(mnem, "move memory %X, %08X, %08X", op[0]&0x00FFFFFF, op[1], op[2]); return 3; } else if ((op[0]&0xF8000000) == 0x98000000) { // INT and INTFLY mnem += sprintf(mnem, "%s %08X, ", (op[0]&0x00100000)?"intfly ":"int ", op[1]); carry = op[0]&0x00200000; bitTrue = op[0]&0x00080000; compData = op[0]&0x00040000; // data (if set) compPhase = op[0]&0x00020000; // phase (if set) (or atn if neither phase nor data set) wait = op[0]&0x00010000; data = op[0]&0xFF; mask = (op[0]>>8)&0xFF; if (carry) sprintf(mnem, "%s%s carry", wait?"if":"when", bitTrue?"":" not"); else { mnem += sprintf(mnem, "%s%s ", wait?"if":"when", bitTrue?"":" not"); if (!compPhase && !compData) sprintf(mnem, "atn"); else { if (compPhase) { mnem += sprintf(mnem, phase[(op[0]>>24)&7]); if (compData) mnem += sprintf(mnem, " and "); } if (compData) mnem += sprintf(mnem, "%02X mask %02X", data, mask); } } return 2; } return 0; // no match found } /****************************************************************************** Standalone Disassembler Define STANDALONE to build a command line-driven SCRIPTS disassembler. ******************************************************************************/ #ifdef STANDALONE static void PrintUsage(void) { puts("scriptsd Version "DISASM_VERSION" by Bart Trzynadlowski: NCR 53C810 SCRIPTS Disassembler"); puts("Usage: scriptsd [options]"); puts("Options: -?,-h Show this help text"); puts(" -s Start offset (hexadecimal)"); puts(" -l Number of instructions (Default=16)"); puts(" -o Set origin (hexadecimal)"); exit(0); } /* * main(argc, argv): * * Standalone SCRIPTS disassembler. */ int main(int argc, char **argv) { char mnem[64]; FILE *fp; UINT8 *buffer; unsigned i, num, offset, fsize, start = 0, len, org, file = 0; UINT32 op[3]; bool len_specified = 0, org_specified = 0; char *c; if (argc <= 1) PrintUsage(); for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-?")) PrintUsage(); else if (!strcmp(argv[i], "-s")) { ++i; if (i >= argc) fprintf(stderr, "scriptsd: warning: no argument to %s\n", "-s"); else start = strtoul(argv[i], &c, 16); } else if (!strcmp(argv[i], "-l")) { ++i; if (i >= argc) fprintf(stderr, "scriptsd: warning: no argument to %s\n", "-l"); else { len = atoi(argv[i]); len_specified = 1; } } else if (!strcmp(argv[i], "-o")) { ++i; if (i >= argc) fprintf(stderr, "scriptsd: warning: no argument to %s\n", "-o"); else { org = strtoul(argv[i], &c, 16); org_specified = 1; } } else file = i; } if (!file) { fprintf(stderr, "scriptsd: no input file specified\n"); exit(1); } /* * Load file */ if ((fp = fopen(argv[file], "rb")) == NULL) { fprintf(stderr, "scriptsd: failed to open file: %s\n", argv[file]); exit(1); } fseek(fp, 0, SEEK_END); fsize = ftell(fp); rewind(fp); // Allocate some extra padding for operands if ((buffer = (UINT8 *) calloc(fsize+4*3, sizeof(UINT8))) == NULL) { fprintf(stderr, "scriptsd: not enough memory to load input file: %s, %lu bytes\n", argv[file], (unsigned long) fsize); fclose(fp); exit(1); } fread(buffer, sizeof(UINT8), fsize, fp); fclose(fp); if (!len_specified) len = 16; if (!org_specified) org = start; /* * Disassemble! */ offset = start; for (i = 0; (i