Created
April 4, 2012 14:29
-
-
Save faried/2301766 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python | |
| """DCPU-16 disassembler. | |
| Run as parse.py /path/to/dcpufile. | |
| http://0x10c.com/doc/dcpu-16.txt | |
| """ | |
| import sys | |
| MASK_B = 0b1111110000000000 | |
| MASK_A = 0b0000001111110000 | |
| MASK_O = 0b0000000000001111 | |
| REGS = ['A', 'B', 'C', 'X', 'Y', 'Z', 'I', 'J'] | |
| OPCODES = ["", "SET", "ADD", "SUB", "MUL", "DIV", "MOD", "SHL", "SHR", | |
| "AND", "BOR", "XOR", "IFE", "IFN", "IFG", "IFB"] | |
| SPECIALS = ["POP", "PEEK", "PUSH", "SP", "PC", "O"] | |
| def wrs(thing): | |
| """Write something with a space after it.""" | |
| sys.stdout.write(thing + ' ') | |
| def nextword(idx, data): | |
| """Return the next word to operate on.""" | |
| return (ord(data[idx]) << 8) + ord(data[idx+1]) | |
| def parsearg(i, val, data): | |
| """An argument to an opcode can be of several types. | |
| Returns an integer to advance the index in the data array. | |
| """ | |
| newi = 0 | |
| # register | |
| if val >= 0x00 and val <= 0x07: | |
| wrs(REGS[val]) | |
| # [register] | |
| elif val >= 0x08 and val <= 0x0f: | |
| wrs('[%s]' % REGS[val - 0x08]) | |
| # [nextword + register] | |
| elif val >= 0x10 and val <= 0x17: | |
| i += 2 | |
| word = nextword(i, data) | |
| wrs('[%s + %s]' % (hex(word), REGS[val - 0x10])) | |
| newi = 2 | |
| elif val >= 0x18 and val <= 0x1d: | |
| wrs(SPECIALS[val - 0x18]) | |
| # [nextword] | |
| elif val == 0x1e: | |
| i += 2 | |
| word = nextword(i, data) | |
| wrs('[%s]' % hex(word)) | |
| newi = 2 | |
| # literal nextword | |
| elif val == 0x1f: | |
| i += 2 | |
| word = nextword(i, data) | |
| wrs(hex(word)) | |
| newi = 2 | |
| # literal between 0 and 16 | |
| elif val >= 0x20 and val <= 0x3f: | |
| val -= 0x20 | |
| wrs(hex(val)) | |
| # something else | |
| else: | |
| wrs(hex(val)) | |
| return newi | |
| def main(args): | |
| """Main branching logic.""" | |
| if len(args) != 1: | |
| sys.stderr.write('usage: %s datafile\n') | |
| sys.exit(1) | |
| data = file(args[0], 'rb').read() | |
| ldata = len(data) | |
| idx = 0 | |
| while idx < ldata: | |
| # print the PC | |
| wrs('0x%02x' % (idx / 2)) | |
| word = nextword(idx, data) | |
| opcode = word & MASK_O | |
| if opcode == 0: | |
| opcode = (word & MASK_A) >> 4 | |
| arg = (word & MASK_B) >> 10 | |
| if opcode == 0: | |
| if arg != 0: | |
| wrs('SPECIAL') | |
| else: | |
| wrs('0000') | |
| elif opcode == 1: | |
| wrs('JSR') | |
| idx += parsearg(idx, arg, data) | |
| else: | |
| wrs('RESERVED') | |
| else: | |
| wrs(OPCODES[opcode]) | |
| arg1 = (word & MASK_A) >> 4 | |
| arg2 = (word & MASK_B) >> 10 | |
| idx += parsearg(idx, arg1, data) | |
| idx += parsearg(idx, arg2, data) | |
| sys.stdout.write('\n') | |
| idx += 2 | |
| if __name__ == '__main__': | |
| main(sys.argv[1:]) | |
| # eof |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment