/**************************************************************************/ /* EightBall Disassembler */ /* */ /* The Eight Bit Algorithmic Language */ /* For Apple IIe/c/gs (64K), Commodore 64, VIC-20 +32K RAM expansion */ /* (also builds for Linux as 32 bit executable (gcc -m32) only) */ /* */ /* Compiles with cc65 v2.15 for VIC-20, C64, Apple II */ /* and gcc 7.3 for Linux */ /* */ /* cc65: Define symbol VIC20 to build for Commodore VIC-20 + 32K. */ /* Define symbol C64 to build for Commodore 64. */ /* Define symbol A2E to build for Apple //e. */ /* */ /* Copyright Bobbi Webber-Manners 2018 */ /* EightBall VM disassembler */ /* */ /* Formatted with indent -kr -nut */ /**************************************************************************/ /**************************************************************************/ /* GNU PUBLIC LICENCE v3 OR LATER */ /* */ /* 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 "eightballvm.h" #include "eightballutils.h" #include #include #include #ifdef A2E #include #endif /* Order must match enum bytecode */ char *bytecodenames[] = { "END", "LDI", "LDAW", "LDAWI", "LDAB", "LDABI", "STAW", "STAWI", "STAB", "STABI", "LDRW", "LDRWI", "LDRB", "LDRBI", "STRW", "STRWI", "STRB", "STRBI", "SWP", "DUP", "DUP2", "DRP", "OVER", "PICK", "POPW", "POPB", "PSHW", "PSHB", "DISC", "SPFP", "FPSP", "ATOR", "RTOA", "INC", "DEC", "ADD", "SUB", "MUL", "DIV", "MOD", "NEG", "GT", "GTE", "LT", "LTE", "EQL", "NEQL", "AND", "OR", "NOT", "BAND", "BOR", "BXOR", "BNOT", "LSH", "RSH", "JMP", "JMPI", "BRC", "BRCI", "JSR", "JSRI", "RTS", "PRDEC", "PRHEX", "PRCH", "PRSTR", "PRMSG", "KBDCH", "KBDLN" }; /* * Call stack grows down from top of memory. * If it hits CALLSTACKLIM then VM will quit with error */ #ifdef __GNUC__ #define MEMORYSZ (64 * 1024) #else /* Has to be 64K minus a byte otherwise winds up being zero! */ #define MEMORYSZ (64 * 1024) - 1 #endif #ifdef __GNUC__ unsigned char memory[MEMORYSZ]; #else unsigned char *memory = 0; #endif #ifdef __GNUC__ #define UINT16 unsigned short #else #define UINT16 unsigned int #endif UINT16 pc = RTPCSTART; /* Program counter */ UINT16 lastpc; /* * Print a value as hex */ void _printhexbyte(unsigned char val) { printchar(hexval2char((val>>4) & 0x0f)); printchar(hexval2char(val & 0x0f)); } /* * Fetch, decode and disassemble a VM instruction, then advance the program counter. */ void disassemble_instruction() { printhex(pc); print(": "); _printhexbyte(memory[pc]); printchar(' '); switch(memory[pc++]) { case VM_LDIMM: case VM_LDAWORDIMM: case VM_LDABYTEIMM: case VM_LDRWORDIMM: case VM_LDRBYTEIMM: case VM_STAWORDIMM: case VM_STABYTEIMM: case VM_STRWORDIMM: case VM_STRBYTEIMM: case VM_JMPIMM: case VM_BRNCHIMM: case VM_JSRIMM: _printhexbyte(memory[pc++]); printchar(' '); _printhexbyte(memory[pc++]); print(" "); print(bytecodenames[memory[pc-3]]); printchar(' '); printhex(memory[pc-2] + (memory[pc-1] << 8)); print(" ("); printdec(memory[pc-2] + (memory[pc-1] << 8)); print(")"); break; case VM_PRMSG: print("...00 "); print(bytecodenames[memory[pc-1]]); print(" \""); while(memory[pc]) { printchar(memory[pc++]); } ++pc; printchar('"'); break; default: print(" "); if (memory[pc-1] <= VM_KBDLN) { print(bytecodenames[memory[pc-1]]); } else { print("**ILLEGAL**"); } } #ifdef A2E printchar('\r'); #else printchar('\n'); #endif }; /* * Disassemble the program! */ void disassemble() { while (pc < lastpc) { disassemble_instruction(); } } /* * Load bytecode into memory[]. */ void load() { FILE *fp; char ch; char *p = (char*)&memory[RTPCSTART]; pc = RTPCSTART; do { #ifndef VIC20 /* TODO: Not sure why getln() is blowing up on VIC20 */ print("\nBytecode file (CR for default)>"); getln(p, 15); #else *p = 0; #endif if (strlen(p) == 0) { strcpy(p, "bytecode"); } print("Loading '"); print(p); print("'\n"); fp = fopen(p, "r"); } while (!fp); while (!feof(fp)) { ch = fgetc(fp); memory[pc++] = ch; /* Print dot for each page */ if (pc%0xff == 0) { printchar('.'); } } fclose(fp); lastpc = pc - 1; pc = RTPCSTART; #ifdef A2E printchar(7); #endif } int main() { print("EightBall Disassembler v" VERSIONSTR "\n"); print("(c)Bobbi, 2018\n"); print("Free Software.\n"); print("Licenced under GPL.\n\n"); load(); #ifdef __GNUC__ print(" Done.\n\n"); #endif #ifdef A2E videomode(VIDEOMODE_80COL); clrscr(); #elif defined(CBM) printchar(147); /* Clear */ #endif disassemble(); #ifdef A2E cgetc(); #endif return 0; }