Advertisement
NovaYoshi

NES Disassembler

Mar 9th, 2011
324
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 12.67 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. // <Alcaro> yeah you're not going to make me install yiff in alcarobot.
  6.  
  7. enum AddressingModes {
  8.   Implied,
  9.   Zeropage,
  10.   ZeropageX,
  11.   ZeropageY,
  12.   Immediate,
  13.   Absolute,
  14.   AbsoluteX,
  15.   AbsoluteY,
  16.   Relative,
  17.   Indirect,
  18.   IndirectX,
  19.   IndirectY
  20. };
  21. static struct Opcode {
  22.   unsigned char Code;
  23.   char *Name;
  24.   char Mode;
  25. } Opcodes[] = {
  26.   {0x00,  "BRK" ,Implied},
  27.   {0x01,  "ORA" ,IndirectX},
  28.   {0x02,  "KIL" ,Implied},
  29.   {0x03,  "SLO" ,IndirectX},
  30.   {0x04,  "DOP" ,Zeropage},
  31.   {0x05,  "ORA" ,Zeropage},
  32.   {0x06,  "ASL" ,Zeropage},
  33.   {0x07,  "SLO" ,Zeropage},
  34.   {0x08,  "PHP" ,Implied},
  35.   {0x09,  "ORA" ,Immediate},
  36.   {0x0A,  "ASL" ,Implied},
  37.   {0x0B,  "ANC" ,Immediate},
  38.   {0x0C,  "NOP" ,Absolute},
  39.   {0x0D,  "ORA" ,Absolute},
  40.   {0x0E,  "ASL" ,Absolute},
  41.   {0x0F,  "SLO" ,Absolute},
  42.   {0x10,  "BPL" ,Relative},
  43.   {0x11,  "ORA" ,IndirectY},
  44.   {0x12,  "KIL" ,Implied},
  45.   {0x13,  "SLO" ,IndirectY},
  46.   {0x14,  "NOP" ,ZeropageX},
  47.   {0x15,  "ORA" ,ZeropageX},
  48.   {0x16,  "ASL" ,ZeropageX},
  49.   {0x17,  "SLO" ,ZeropageX},
  50.   {0x18,  "CLC" ,Implied},
  51.   {0x19,  "ORA" ,AbsoluteY},
  52.   {0x1A,  "NOP" ,Implied},
  53.   {0x1B,  "SLO" ,AbsoluteY},
  54.   {0x1C,  "NOP" ,AbsoluteX},
  55.   {0x1D,  "ORA" ,AbsoluteX},
  56.   {0x1E,  "ASL" ,AbsoluteX},
  57.   {0x1F,  "SLO" ,AbsoluteX},
  58.   {0x20,  "JSR" ,Absolute},
  59.   {0x21,  "AND" ,IndirectX},
  60.   {0x22,  "KIL" ,Implied},
  61.   {0x23,  "RLA" ,IndirectY},
  62.   {0x24,  "BIT" ,Zeropage},
  63.   {0x25,  "AND" ,Zeropage},
  64.   {0x26,  "ROL" ,Zeropage},
  65.   {0x27,  "RLA" ,Zeropage},
  66.   {0x28,  "PLP" ,Implied},
  67.   {0x29,  "AND" ,Immediate},
  68.   {0x2A,  "ROL" ,Implied},
  69.   {0x2B,  "AND" ,Immediate},
  70.   {0x2C,  "BIT" ,Absolute},
  71.   {0x2D,  "AND" ,Absolute},
  72.   {0x2E,  "ROL" ,Absolute},
  73.   {0x2F,  "RLA" ,Absolute},
  74.   {0x30,  "BMI" ,Relative},
  75.   {0x31,  "AND" ,IndirectY},
  76.   {0x32,  "KIL" ,Implied},
  77.   {0x33,  "RLA" ,IndirectY},
  78.   {0x34,  "NOP" ,ZeropageX},
  79.   {0x35,  "AND" ,ZeropageX},
  80.   {0x36,  "ROL" ,ZeropageX},
  81.   {0x37,  "RLA" ,ZeropageX},
  82.   {0x38,  "SEC" ,Implied},
  83.   {0x39,  "AND" ,AbsoluteY},
  84.   {0x3A,  "NOP" ,Implied},
  85.   {0x3B,  "RLA" ,AbsoluteY},
  86.   {0x3C,  "NOP" ,AbsoluteX},
  87.   {0x3D,  "AND" ,AbsoluteX},
  88.   {0x3E,  "ROL" ,AbsoluteX},
  89.   {0x3F,  "RLA" ,AbsoluteX},
  90.   {0x40,  "RTI" ,Implied},
  91.   {0x41,  "EOR" ,IndirectX},
  92.   {0x42,  "KIL" ,Implied},
  93.   {0x43,  "SRE" ,IndirectX},
  94.   {0x44,  "NOP" ,Zeropage},
  95.   {0x45,  "EOR" ,Zeropage},
  96.   {0x46,  "LSR" ,Zeropage},
  97.   {0x47,  "SRE" ,Zeropage},
  98.   {0x48,  "PHA" ,Implied},
  99.   {0x49,  "EOR" ,Immediate},
  100.   {0x4A,  "LSR" ,Implied},
  101.   {0x4B,  "ALR" ,Immediate},
  102.   {0x4C,  "JMP" ,Absolute},
  103.   {0x4D,  "EOR" ,Absolute},
  104.   {0x4E,  "LSR" ,Absolute},
  105.   {0x4F,  "SRE" ,Absolute},
  106.   {0x50,  "BVC" ,Relative},
  107.   {0x51,  "EOR" ,IndirectY},
  108.   {0x52,  "KIL" ,Implied},
  109.   {0x53,  "SRE" ,IndirectY},
  110.   {0x54,  "NOP" ,ZeropageX},
  111.   {0x55,  "EOR" ,ZeropageX},
  112.   {0x56,  "LSR" ,ZeropageX},
  113.   {0x57,  "SRE" ,ZeropageX},
  114.   {0x58,  "CLI" ,Implied},
  115.   {0x59,  "EOR" ,AbsoluteY},
  116.   {0x5A,  "NOP" ,Implied},
  117.   {0x5B,  "SRE" ,AbsoluteY},
  118.   {0x5C,  "NOP" ,AbsoluteX},
  119.   {0x5D,  "EOR" ,AbsoluteX},
  120.   {0x5E,  "LSR" ,AbsoluteX},
  121.   {0x5F,  "SRE" ,AbsoluteX},
  122.   {0x60,  "RTS" ,Implied},
  123.   {0x61,  "ADC" ,IndirectX},
  124.   {0x62,  "KIL" ,Implied},
  125.   {0x63,  "RRA" ,IndirectX},
  126.   {0x64,  "NOP" ,Zeropage},
  127.   {0x65,  "ADC" ,Zeropage},
  128.   {0x66,  "ROR" ,Zeropage},
  129.   {0x67,  "RRA" ,Zeropage},
  130.   {0x68,  "PLA" ,Implied},
  131.   {0x69,  "ADC" ,Immediate},
  132.   {0x6A,  "ROR" ,Implied},
  133.   {0x6B,  "ARR" ,Immediate},
  134.   {0x6C,  "JMP" ,Indirect},
  135.   {0x6D,  "ADC" ,Absolute},
  136.   {0x6E,  "ROR" ,Absolute},
  137.   {0x6F,  "RRA" ,Absolute},
  138.   {0x70,  "BVS" ,Relative},
  139.   {0x71,  "ADC" ,IndirectY},
  140.   {0x72,  "KIL" ,Implied},
  141.   {0x73,  "RRA" ,IndirectY},
  142.   {0x74,  "NOP" ,ZeropageX},
  143.   {0x75,  "ADC" ,ZeropageX},
  144.   {0x76,  "ROR" ,ZeropageX},
  145.   {0x77,  "RRA" ,ZeropageX},
  146.   {0x78,  "SEI" ,Implied},
  147.   {0x79,  "ADC" ,AbsoluteY},
  148.   {0x7A,  "NOP" ,Implied},
  149.   {0x7B,  "RRA" ,AbsoluteY},
  150.   {0x7C,  "NOP" ,AbsoluteX},
  151.   {0x7D,  "ADC" ,AbsoluteX},
  152.   {0x7E,  "ROR" ,AbsoluteX},
  153.   {0x7F,  "RRA" ,AbsoluteX},
  154.   {0x80,  "NOP" ,Immediate},
  155.   {0x81,  "STA" ,Indirect},
  156.   {0x82,  "NOP" ,Immediate},
  157.   {0x83,  "SAX" ,IndirectX},
  158.   {0x84,  "STY" ,Zeropage},
  159.   {0x85,  "STA" ,Zeropage},
  160.   {0x86,  "STX" ,Zeropage},
  161.   {0x87,  "SAX" ,Zeropage},
  162.   {0x88,  "DEY" ,Implied},
  163.   {0x89,  "NOP" ,Immediate},
  164.   {0x8A,  "TXA" ,Implied},
  165.   {0x8B,  "XAA" ,Immediate},
  166.   {0x8C,  "STY" ,Absolute},
  167.   {0x8D,  "STA" ,Absolute},
  168.   {0x8E,  "STX" ,Absolute},
  169.   {0x8F,  "SAX" ,Absolute},
  170.   {0x90,  "BCC" ,Relative},
  171.   {0x91,  "STA" ,IndirectY},
  172.   {0x92,  "KIL" ,Implied},
  173.   {0x93,  "AHX" ,IndirectY},
  174.   {0x94,  "STY" ,ZeropageY},
  175.   {0x95,  "STA" ,ZeropageX},
  176.   {0x96,  "STX" ,ZeropageY},
  177.   {0x97,  "SAX" ,ZeropageY},
  178.   {0x98,  "TYA" ,Implied},
  179.   {0x99,  "STA" ,AbsoluteY},
  180.   {0x9A,  "TXS" ,Implied},
  181.   {0x9B,  "TAS" ,AbsoluteY},
  182.   {0x9C,  "SHY" ,AbsoluteX},
  183.   {0x9D,  "STA" ,AbsoluteX},
  184.   {0x9E,  "SHX" ,AbsoluteY},
  185.   {0x9F,  "AHX" ,AbsoluteY},
  186.   {0xA0,  "LDY" ,Immediate},
  187.   {0xA1,  "LDA" ,IndirectX},
  188.   {0xA2,  "LDX" ,Immediate},
  189.   {0xA3,  "LAX" ,IndirectX},
  190.   {0xA4,  "LDY" ,Zeropage},
  191.   {0xA5,  "LDA" ,Zeropage},
  192.   {0xA6,  "LDX" ,Zeropage},
  193.   {0xA7,  "LAX" ,Zeropage},
  194.   {0xA8,  "TAY" ,Implied},
  195.   {0xA9,  "LDA" ,Immediate},
  196.   {0xAA,  "TAX" ,Implied},
  197.   {0xAB,  "LAX" ,Immediate},
  198.   {0xAC,  "LDY" ,Absolute},
  199.   {0xAD,  "LDA" ,Absolute},
  200.   {0xAE,  "LDX" ,Absolute},
  201.   {0xAF,  "LAX" ,Absolute},
  202.   {0xB0,  "BCS" ,Relative},
  203.   {0xB1,  "LDA" ,IndirectY},
  204.   {0xB2,  "KIL" ,Implied},
  205.   {0xB3,  "LAX" ,IndirectY},
  206.   {0xB4,  "LDY" ,ZeropageX},
  207.   {0xB5,  "LDA" ,ZeropageX},
  208.   {0xB6,  "LDX" ,ZeropageY},
  209.   {0xB7,  "LAX" ,ZeropageY},
  210.   {0xB8,  "CLV" ,Implied},
  211.   {0xB9,  "LDA" ,AbsoluteY},
  212.   {0xBA,  "TSX" ,Implied},
  213.   {0xBB,  "LAS" ,AbsoluteY},
  214.   {0xBC,  "LDY" ,AbsoluteX},
  215.   {0xBD,  "LDA" ,AbsoluteX},
  216.   {0xBE,  "LDX" ,AbsoluteY},
  217.   {0xBF,  "LAX" ,AbsoluteY},
  218.   {0xC0,  "CPY" ,Immediate},
  219.   {0xC1,  "CMP" ,IndirectX},
  220.   {0xC2,  "NOP" ,Immediate},
  221.   {0xC3,  "DCP" ,IndirectX},
  222.   {0xC4,  "CPY" ,Zeropage},
  223.   {0xC5,  "CMP" ,Zeropage},
  224.   {0xC6,  "DEC" ,Zeropage},
  225.   {0xC7,  "DCP" ,Zeropage},
  226.   {0xC8,  "INY" ,Implied},
  227.   {0xC9,  "CMP" ,Immediate},
  228.   {0xCA,  "DEX" ,Implied},
  229.   {0xCB,  "AXS" ,Immediate},
  230.   {0xCC,  "CPY" ,Absolute},
  231.   {0xCD,  "CMP" ,Absolute},
  232.   {0xCE,  "DEC" ,Absolute},
  233.   {0xCF,  "DCP" ,Absolute},
  234.   {0xD0,  "BNE" ,Relative},
  235.   {0xD1,  "CMP" ,IndirectY},
  236.   {0xD2,  "KIL" ,Implied},
  237.   {0xD3,  "DCP" ,IndirectY},
  238.   {0xD4,  "NOP" ,ZeropageX},
  239.   {0xD5,  "CMP" ,ZeropageX},
  240.   {0xD6,  "DEC" ,ZeropageX},
  241.   {0xD7,  "DCP" ,ZeropageX},
  242.   {0xD8,  "CLD" ,Implied},
  243.   {0xD9,  "CMP" ,AbsoluteY},
  244.   {0xDA,  "NOP" ,Implied},
  245.   {0xDB,  "DCP" ,AbsoluteY},
  246.   {0xDC,  "NOP" ,AbsoluteX},
  247.   {0xDD,  "CMP" ,AbsoluteX},
  248.   {0xDE,  "DEC" ,AbsoluteX},
  249.   {0xDF,  "DCP" ,AbsoluteX},
  250.   {0xE0,  "CPX" ,Immediate},
  251.   {0xE1,  "SBC" ,IndirectX},
  252.   {0xE2,  "NOP" ,Immediate},
  253.   {0xE3,  "ISC" ,IndirectX},
  254.   {0xE4,  "CPX" ,Zeropage},
  255.   {0xE5,  "SBC" ,Zeropage},
  256.   {0xE6,  "INC" ,Zeropage},
  257.   {0xE7,  "ISC" ,Zeropage},
  258.   {0xE8,  "INX" ,Implied},
  259.   {0xE9,  "SBC" ,Immediate},
  260.   {0xEA,  "NOP" ,Implied},
  261.   {0xEB,  "SBC" ,Immediate},
  262.   {0xEC,  "CPX" ,Absolute},
  263.   {0xED,  "SBC" ,Absolute},
  264.   {0xEE,  "INC" ,Absolute},
  265.   {0xEF,  "ISC" ,Absolute},
  266.   {0xF0,  "BEQ" ,Relative},
  267.   {0xF1,  "SBC" ,IndirectY},
  268.   {0xF2,  "KIL" ,Implied},
  269.   {0xF3,  "ISC" ,IndirectY},
  270.   {0xF4,  "NOP" ,ZeropageX},
  271.   {0xF5,  "SBC" ,ZeropageX},
  272.   {0xF6,  "INC" ,ZeropageX},
  273.   {0xF7,  "ISC" ,ZeropageX},
  274.   {0xF8,  "SED" ,Implied},
  275.   {0xF9,  "SBC" ,AbsoluteY},
  276.   {0xFA,  "NOP" ,Implied},
  277.   {0xFB,  "ISC" ,AbsoluteY},
  278.   {0xFC,  "NOP" ,AbsoluteX},
  279.   {0xFD,  "SBC" ,AbsoluteX},
  280.   {0xFE,  "INC" ,AbsoluteX},
  281.   {0xFF,  "ISC" ,AbsoluteX},
  282. };
  283. static struct Names {
  284.   unsigned char High;
  285.   unsigned char Low;
  286.   char *Name;  
  287. } Labels[] = {
  288.   {0x20,0x00,"PPUCTRL"},
  289.   {0x20,0x01,"PPUMASK"},
  290.   {0x20,0x02,"PPUSTATUS"},
  291.   {0x20,0x03,"OAMADDR"},
  292.   {0x20,0x04,"OAMDATA"},
  293.   {0x20,0x05,"PPUSCROLL"},
  294.   {0x20,0x06,"PPUADDR"},
  295.   {0x20,0x07,"PPUDATA"},
  296.   {0x40,0x00,"SQ1_VOL"},
  297.   {0x40,0x01,"SQ1_SWEEP"},
  298.   {0x40,0x02,"SQ1_LO"},
  299.   {0x40,0x03,"SQ1_HI"},
  300.   {0x40,0x04,"SQ2_VOL"},
  301.   {0x40,0x05,"SQ2_SWEEP"},
  302.   {0x40,0x06,"SQ2_LO"},
  303.   {0x40,0x07,"SQ2_HI"},
  304.   {0x40,0x08,"TRI_LINEAR"},
  305.   {0x40,0x0a,"TRI_LO"},
  306.   {0x40,0x0b,"TRI_HI"},
  307.   {0x40,0x0c,"NOISE_VOL"},
  308.   {0x40,0x0e,"NOISE_LO"},
  309.   {0x40,0x0f,"NOISE_HI"},
  310.   {0x40,0x10,"DMC_FREQ"},
  311.   {0x40,0x11,"DMC_RAW"},
  312.   {0x40,0x12,"DMC_START"},
  313.   {0x40,0x13,"DMC_LEN"},
  314.   {0x40,0x14,"OAM_DMA"},
  315.   {0x40,0x15,"SND_CHN"},
  316.   {0x40,0x16,"JOY1"},
  317.   {0x40,0x17,"APUCTRL"},
  318.   {0x00,0x00,NULL},
  319. };
  320. //  {0x40,0x17,"JOY2"},
  321.  
  322. static int chk_strtol(char **Peek, char *End) { // returns an errorcode when out of bytes
  323.   if(*Peek>=End) return -1;
  324.   return(strtol(*Peek,Peek,16));
  325. }
  326. char *FormatAddress(char *Poke, int Low, int High, unsigned char Mode) {
  327. // todo: when only given part of an opcode ( like "8D" and nothing else after it ), don't act like
  328. //   there's a value there
  329.   char AddrBuffer[70];
  330.   char OutPoke[70];
  331.  
  332.   strcpy(Poke, "wut");
  333.   switch(Mode) {
  334.     case Implied: // wut, in that case we don't need this function
  335.       strcpy(AddrBuffer,"");
  336.       break;
  337.     case Relative: // meh
  338.       strcpy(AddrBuffer,"--");
  339.       break;
  340.     case Zeropage:
  341.     case ZeropageX:
  342.     case ZeropageY:
  343.     case Immediate:
  344.       if(Low != -1)
  345.         sprintf(AddrBuffer,"$%s%x",(Low>15?"":"0"),Low);
  346.       else
  347.         sprintf(AddrBuffer,"$??");
  348.       break;
  349.     case Absolute:
  350.     case AbsoluteX:
  351.     case AbsoluteY:
  352.       if(Low != -1 && High != -1)
  353.         sprintf(AddrBuffer,"$%s%x%s%x",(High>15 ? "" : "0"),High, (Low > 15 ? "" : "0"), Low );
  354.       else if(High == -1)
  355.         sprintf(AddrBuffer,"$%s%x??",(Low>15 ? "" : "0"),Low);
  356.       else
  357.         sprintf(AddrBuffer,"$????",(Low>15 ? "" : "0"),Low);
  358.  
  359.       int LabelMatch;
  360.       for(LabelMatch=0; Labels[LabelMatch].Name != NULL ; LabelMatch++) {
  361.         if(Labels[LabelMatch].High == High && Labels[LabelMatch].Low == Low) {
  362.           strcpy(AddrBuffer, Labels[LabelMatch].Name);
  363.           break;
  364.         }
  365.       }
  366.       break;
  367.  
  368.  
  369.     case Indirect:
  370.     case IndirectX:
  371.     case IndirectY:
  372.       sprintf(AddrBuffer,"$%s%x",(Low>15?"":"0"),Low);
  373.       break;
  374.     default:
  375. //      printf("unhandled mode %i \n", Mode);
  376.       break;
  377.   }
  378.   switch(Mode) {
  379.     case Absolute:
  380.     case Zeropage:
  381.       sprintf(Poke, "%s", AddrBuffer);
  382.       break;
  383.     case Immediate:
  384.       sprintf(Poke, "#%s", AddrBuffer);
  385.       break;
  386.     case ZeropageX:
  387.     case AbsoluteX:
  388.       sprintf(Poke, "%s,x", AddrBuffer);
  389.       break;
  390.     case ZeropageY:
  391.     case AbsoluteY:
  392.       sprintf(Poke, "%s,y", AddrBuffer);
  393.       break;
  394.     case Relative:
  395.       sprintf(Poke, "--");
  396.       break;
  397.     case Indirect:
  398.       sprintf(Poke, "(%s)", AddrBuffer);
  399.       break;
  400.     case IndirectX:
  401.       sprintf(Poke, "(%s,x)", AddrBuffer);
  402.       break;
  403.     case IndirectY:
  404.       sprintf(Poke, "(%s),y", AddrBuffer);
  405.       break;
  406.   }
  407.   return(Poke);
  408. }
  409. static int NS_NES_Disassemble(char *Input) {
  410.   char OutBuffer[512];                //
  411.   char ThisOpcode[100];               //
  412.   char AddrBuffer[100];               //
  413.   char *Peek = Input;                 // start of hex
  414.   char *End = Input + strlen(Input);  // end of hex
  415.   unsigned char Code;                 // opcode
  416.   unsigned char High;                 //
  417.   unsigned char Low;                  //
  418.   unsigned char Mode;                 //
  419.   strcpy(OutBuffer,"");
  420.   while(Peek < End) {                 // still more opcodes?
  421.     Code = strtol(Peek, &Peek, 16);
  422.     Mode = Opcodes[Code].Mode;
  423.     switch(Mode) {                    // different addressing modes will have
  424.                                       //   a different number of bytes after the op
  425.       case Zeropage:
  426.       case ZeropageX:
  427.       case ZeropageY:
  428.       case Immediate:
  429.       case IndirectX:
  430.       case IndirectY:
  431.       case Relative:
  432.         High = -1;
  433.         Low = chk_strtol(&Peek, End);
  434.         break;
  435.       case Absolute:
  436.       case AbsoluteX:
  437.       case AbsoluteY:
  438.       case Indirect:
  439.         Low = chk_strtol(&Peek, End);
  440.         High = chk_strtol(&Peek, End);
  441.         break;
  442.     }
  443.     // generate address string for the addressing mode
  444.     FormatAddress(AddrBuffer,Low,High,Mode);
  445.  
  446.     // add onto the list
  447.     sprintf(ThisOpcode, "%s %s \\ ",Opcodes[Code].Name, AddrBuffer);
  448.     strcat(OutBuffer,ThisOpcode);
  449.   }
  450.   // turn the last slash into a null
  451.   OutBuffer[strlen(OutBuffer)-3] = 0;
  452.  
  453.   printf("%s \n", OutBuffer);  // Here's your string to give to send()
  454. }
  455.  
  456. int main() {
  457.   NS_NES_Disassemble("a9 01 8d 37 13 8d 07 20");
  458. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement