Skip to content
Newer
Older
100644 505 lines (400 sloc) 18.9 KB
099295b @kanzure load labels into the new disassembler
kanzure authored
1 import sys, os, time, datetime, json
132182e @kanzure super duper disassembler fixes
kanzure authored
2 from gbz80disasm import opt_table
4b7ca69 @kanzure advance forward when disassembling the rom
kanzure authored
3 from ctypes import c_int8
4 from copy import copy, deepcopy
099295b @kanzure load labels into the new disassembler
kanzure authored
5 from labels import get_label_from_line, get_address_from_line_comment
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
6
96596c6 @kanzure asm output for the new disassembler
kanzure authored
7 relative_jumps = [0x38, 0x30, 0x20, 0x28, 0x18, 0xc3, 0xda, 0xc2, 0x32]
132182e @kanzure super duper disassembler fixes
kanzure authored
8 relative_unconditional_jumps = [0xc3, 0x18]
9 call_commands = [0xdc, 0xd4, 0xc4, 0xcc, 0xcd]
10 end_08_scripts_with = [
11 0xe9, # jp hl
12 0xc9, # ret
13 ] # possibly also:
3359121 @kanzure graph.py - parse pokecrystal into a function graph for d3.js
kanzure authored
14 # 0xc3, # jp
132182e @kanzure super duper disassembler fixes
kanzure authored
15 # 0xc18, # jr
3359121 @kanzure graph.py - parse pokecrystal into a function graph for d3.js
kanzure authored
16 # 0xda, 0xe9, 0xd2, 0xc2, 0xca, 0x38, 0x30, 0x20, 0x28, 0x18, 0xd8,
132182e @kanzure super duper disassembler fixes
kanzure authored
17 # 0xd0, 0xc0, 0xc8, 0xc9
18
96596c6 @kanzure asm output for the new disassembler
kanzure authored
19 spacing = "\t"
20
ee7d39b @kanzure move RomStr into a shared file
kanzure authored
21 class RomStr(str):
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
22 """ Simple wrapper to prevent a giant rom from being shown on screen.
ee7d39b @kanzure move RomStr into a shared file
kanzure authored
23 """
24
099295b @kanzure load labels into the new disassembler
kanzure authored
25 def __init__(self, *args, **kwargs):
86cb61d @kanzure make pokecrystal compatible with python2.6 by default
kanzure authored
26 if "labels" in kwargs.keys() and kwargs["labels"] == True:
27 self.load_labels()
099295b @kanzure load labels into the new disassembler
kanzure authored
28 str.__init__(self)
29
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
30 def __repr__(self):
31 """ Simplifies this object so that the output doesn't overflow stdout.
32 """
33 return "RomStr(too long)"
34
35 @classmethod
36 def load(cls, crystal=True, red=False):
37 """ Loads a ROM into a RomStr.
38 """
39 if crystal and not red:
40 file_handler = open("../baserom.gbc", "r")
41 elif red and not crystal:
42 file_handler = open("../pokered-baserom.gbc", "r")
43 else:
44 raise Exception, "not sure which rom to load?"
45 bytes = file_handler.read()
46 file_handler.close()
47 return RomStr(bytes)
48
099295b @kanzure load labels into the new disassembler
kanzure authored
49 def load_labels(self, filename="labels.json"):
50 """ Loads labels from labels.json, or parses the source code file and
51 generates new labels.
52 """
b85d9b8 @kanzure use os.path.join instead of cowboying it
kanzure authored
53 filename = os.path.join(os.path.dirname(__file__), filename)
58c696c @kanzure use extras/labels.json and not ./labels.json in romstr.py
kanzure authored
54
099295b @kanzure load labels into the new disassembler
kanzure authored
55 # blank out the hash
56 self.labels = {}
57
58 # check if the labels file exists
59 file_existence = os.path.exists(filename)
60
61 generate_labels = False
62
63 # determine if the labels file needs to be regenerated
64 if file_existence:
65 modified = os.path.getmtime(filename)
66 modified = datetime.datetime.fromtimestamp(modified)
67 current = datetime.datetime.fromtimestamp(time.time())
68
69 is_old = (current - modified) > datetime.timedelta(days=3)
70
71 if is_old:
72 generate_labels = True
73 else:
74 generate_labels = True
75
76 # scan the asm source code for labels
77 if generate_labels:
b85d9b8 @kanzure use os.path.join instead of cowboying it
kanzure authored
78 asm = open(os.path.join(os.path.dirname(__file__), "../main.asm"), "r").read().split("\n")
099295b @kanzure load labels into the new disassembler
kanzure authored
79
80 for line in asm:
81 label = get_label_from_line(line)
82
83 if label:
84 address = get_address_from_line_comment(line)
85
86 self.labels[address] = label
87
88 content = json.dumps(self.labels)
89 file_handler = open(filename, "w")
90 file_handler.write(content)
91 file_handler.close()
92
93 # load the labels from the file
94 self.labels = json.loads(open(filename, "r").read())
95
ee7d39b @kanzure move RomStr into a shared file
kanzure authored
96 def length(self):
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
97 """ len(self)
98 """
ee7d39b @kanzure move RomStr into a shared file
kanzure authored
99 return len(self)
100
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
101 def len(self):
102 """ len(self)
103 """
104 return self.length()
ee7d39b @kanzure move RomStr into a shared file
kanzure authored
105
106 def interval(self, offset, length, strings=True, debug=True):
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
107 """ returns hex values for the rom starting at offset until
108 offset+length
109 """
110 returnable = []
ee7d39b @kanzure move RomStr into a shared file
kanzure authored
111 for byte in self[offset:offset+length]:
112 if strings:
113 returnable.append(hex(ord(byte)))
114 else:
115 returnable.append(ord(byte))
116 return returnable
117
118 def until(self, offset, byte, strings=True, debug=False):
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
119 """ Returns hex values from rom starting at offset until the given
120 byte.
121 """
ee7d39b @kanzure move RomStr into a shared file
kanzure authored
122 return self.interval(offset, self.find(chr(byte), offset) - offset, strings=strings)
123
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
124 def to_asm(self, address, end_address=None, size=None, max_size=0x4000, debug=None):
125 """ Disassembles ASM at some address. This will stop disassembling when
126 either the end_address or size is met. Also, there's a maximum size
127 that will be parsed, so that large patches of data aren't parsed as
128 code.
129 """
3359121 @kanzure graph.py - parse pokecrystal into a function graph for d3.js
kanzure authored
130 if type(address) == str and "0x" in address:
e2babd6 @kanzure use romstr.py as the new disassembler
kanzure authored
131 address = int(address, 16)
132
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
133 start_address = address
e2babd6 @kanzure use romstr.py as the new disassembler
kanzure authored
134
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
135 if start_address == None:
136 raise Exception, "address must be given"
137
138 if debug == None:
139 if not hasattr(self, "debug"):
140 debug = False
141 else:
142 debug = self.debug
143
144 # this is probably a terrible idea.. why am i doing this?
145 if size != None and max_size < size:
146 raise Exception, "max_size must be greater than or equal to size"
147 elif end_address != None and (end_address - start_address) > max_size:
148 raise Exception, "end_address is out of bounds"
149 elif end_address != None and size != None:
150 if (end_address - start_address) >= size:
151 size = end_address - start_address
152 else:
153 end_address = start_address + size
154 elif end_address == None and size != None:
155 end_address = start_address + size
156 elif end_address != None and size == None:
157 size = end_address - start_address
158
099295b @kanzure load labels into the new disassembler
kanzure authored
159 return DisAsm(start_address=start_address, end_address=end_address, size=size, max_size=max_size, debug=debug, rom=self)
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
160
099295b @kanzure load labels into the new disassembler
kanzure authored
161 class DisAsm:
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
162 """ z80 disassembler
163 """
164
165 def __init__(self, start_address=None, end_address=None, size=None, max_size=0x4000, debug=True, rom=None):
166 assert start_address != None, "start_address must be given"
167
168 if rom == None:
169 file_handler = open("../baserom.gbc", "r")
170 bytes = file_handler.read()
171 file_handler.close()
172 rom = RomStr(bytes)
173
174 if debug not in [None, True, False]:
175 raise Exception, "debug param is invalid"
176 if debug == None:
177 debug = False
178
179 # get end_address and size in sync with each other
180 if end_address == None and size != None:
181 end_address = start_address + size
182 elif end_address != None and size == None:
183 size = end_address - start_address
184 elif end_address != None and size != None:
185 size = max(end_address - start_address, size)
186 end_address = start_address + size
187
188 # check that the bounds make sense
189 if end_address != None:
190 if end_address <= start_address:
191 raise Exception, "end_address is out of bounds"
192 elif (end_address - start_address) > max_size:
193 raise Exception, "end_address goes beyond max_size"
194
195 # check more edge cases
196 if not start_address >= 0:
197 raise Exception, "start_address must be at least 0"
b19db1e @kanzure broken disassembler
kanzure authored
198 elif end_address != None and not end_address >= 0:
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
199 raise Exception, "end_address must be at least 0"
200
201 self.rom = rom
202 self.start_address = start_address
203 self.end_address = end_address
204 self.size = size
205 self.max_size = max_size
206 self.debug = debug
207
208 self.parse()
209
210 def parse(self):
211 """ Disassembles stuff and things.
212 """
213
214 rom = self.rom
215 start_address = self.start_address
216 end_address = self.end_address
217 max_size = self.max_size
218 debug = self.debug
219
220 bank_id = start_address / 0x4000
221
222 # [{"command": 0x20, "bytes": [0x20, 0x40, 0x50],
223 # "asm": "jp $5040", "label": "Unknown5040"}]
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
224 asm_commands = {}
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
225
226 offset = start_address
cd60a1f @kanzure backtracking and labeling for the disassembler
kanzure authored
227
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
228 last_hl_address = None
229 last_a_address = None
230 used_3d97 = False
231
232 keep_reading = True
233
b19db1e @kanzure broken disassembler
kanzure authored
234 while (end_address != 0 and offset <= end_address) or keep_reading:
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
235 # read the current opcode byte
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
236 current_byte = ord(rom[offset])
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
237 current_byte_number = len(asm_commands.keys())
cd60a1f @kanzure backtracking and labeling for the disassembler
kanzure authored
238
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
239 # setup this next/upcoming command
cd60a1f @kanzure backtracking and labeling for the disassembler
kanzure authored
240 if offset in asm_commands.keys():
241 asm_command = asm_commands[offset]
242 else:
243 asm_command = {}
244
245 asm_command["address"] = offset
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
246
cd60a1f @kanzure backtracking and labeling for the disassembler
kanzure authored
247 if not "references" in asm_command.keys():
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
248 # This counts how many times relative jumps reference this
249 # byte. This is used to determine whether or not to print out a
250 # label later.
cd60a1f @kanzure backtracking and labeling for the disassembler
kanzure authored
251 asm_command["references"] = 0
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
252
253 # some commands have two opcodes
254 next_byte = ord(rom[offset+1])
255
96596c6 @kanzure asm output for the new disassembler
kanzure authored
256 if self.debug:
257 print "offset: \t\t" + hex(offset)
258 print "current_byte: \t\t" + hex(current_byte)
259 print "next_byte: \t\t" + hex(next_byte)
b19db1e @kanzure broken disassembler
kanzure authored
260
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
261 # all two-byte opcodes also have their first byte in there somewhere
b19db1e @kanzure broken disassembler
kanzure authored
262 if (current_byte in opt_table.keys()) or ((current_byte + (next_byte << 8)) in opt_table.keys()):
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
263 # this might be a two-byte opcode
264 possible_opcode = current_byte + (next_byte << 8)
265
266 # check if this is a two-byte opcode
267 if possible_opcode in opt_table.keys():
268 op_code = possible_opcode
269 else:
270 op_code = current_byte
cd60a1f @kanzure backtracking and labeling for the disassembler
kanzure authored
271
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
272 op = opt_table[op_code]
273
274 opstr = op[0].lower()
275 optype = op[1]
276
96596c6 @kanzure asm output for the new disassembler
kanzure authored
277 if self.debug:
278 print "opstr: " + opstr
b19db1e @kanzure broken disassembler
kanzure authored
279
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
280 asm_command["type"] = "op"
281 asm_command["id"] = op_code
282 asm_command["format"] = opstr
283 asm_command["opnumberthing"] = optype
cd60a1f @kanzure backtracking and labeling for the disassembler
kanzure authored
284
96ca472 @kanzure implement a formatted-with-labels version of the opcode line
kanzure authored
285 opstr2 = None
96596c6 @kanzure asm output for the new disassembler
kanzure authored
286 base_opstr = copy(opstr)
96ca472 @kanzure implement a formatted-with-labels version of the opcode line
kanzure authored
287
4ccfe27 @kanzure more awful code for the new disassembler
kanzure authored
288 if "x" in opstr:
289 for x in range(0, opstr.count("x")):
290 insertion = ord(rom[offset + 1])
cd60a1f @kanzure backtracking and labeling for the disassembler
kanzure authored
291
292 # Certain opcodes will have a local relative jump label
293 # here instead of a raw hex value, but this is
294 # controlled through asm output.
4ccfe27 @kanzure more awful code for the new disassembler
kanzure authored
295 insertion = "$" + hex(insertion)[2:]
cd60a1f @kanzure backtracking and labeling for the disassembler
kanzure authored
296
4ccfe27 @kanzure more awful code for the new disassembler
kanzure authored
297 opstr = opstr[:opstr.find("x")].lower() + insertion + opstr[opstr.find("x")+1:].lower()
cd60a1f @kanzure backtracking and labeling for the disassembler
kanzure authored
298
96596c6 @kanzure asm output for the new disassembler
kanzure authored
299 if op_code in relative_jumps:
300 target_address = offset + 2 + c_int8(ord(rom[offset + 1])).value
301 insertion = "asm_" + hex(target_address)
36eb6c7 @kanzure use labels in the disassembler output
kanzure authored
302
303 if str(target_address) in self.rom.labels.keys():
304 insertion = self.rom.labels[str(target_address)]
305
96596c6 @kanzure asm output for the new disassembler
kanzure authored
306 opstr2 = base_opstr[:base_opstr.find("x")].lower() + insertion + base_opstr[base_opstr.find("x")+1:].lower()
307 asm_command["formatted_with_labels"] = opstr2
3359121 @kanzure graph.py - parse pokecrystal into a function graph for d3.js
kanzure authored
308 asm_command["target_address"] = target_address
96596c6 @kanzure asm output for the new disassembler
kanzure authored
309
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
310 current_byte_number += 1
cd60a1f @kanzure backtracking and labeling for the disassembler
kanzure authored
311 offset += 1
4ccfe27 @kanzure more awful code for the new disassembler
kanzure authored
312
313 if "?" in opstr:
314 for y in range(0, opstr.count("?")):
315 byte1 = ord(rom[offset + 1])
316 byte2 = ord(rom[offset + 2])
cd60a1f @kanzure backtracking and labeling for the disassembler
kanzure authored
317
4ccfe27 @kanzure more awful code for the new disassembler
kanzure authored
318 number = byte1
319 number += byte2 << 8;
cd60a1f @kanzure backtracking and labeling for the disassembler
kanzure authored
320
321 # In most cases, you can use a label here. Labels will
322 # be shown during asm output.
4ccfe27 @kanzure more awful code for the new disassembler
kanzure authored
323 insertion = "$%.4x" % (number)
cd60a1f @kanzure backtracking and labeling for the disassembler
kanzure authored
324
4ccfe27 @kanzure more awful code for the new disassembler
kanzure authored
325 opstr = opstr[:opstr.find("?")].lower() + insertion + opstr[opstr.find("?")+1:].lower()
cd60a1f @kanzure backtracking and labeling for the disassembler
kanzure authored
326
96ca472 @kanzure implement a formatted-with-labels version of the opcode line
kanzure authored
327 # This version of the formatted string has labels. In
328 # the future, the actual labels should be parsed
329 # straight out of the "main.asm" file.
330 target_address = number % 0x4000
331 insertion = "asm_" + hex(target_address)
36eb6c7 @kanzure use labels in the disassembler output
kanzure authored
332
333 if str(target_address) in self.rom.labels.keys():
334 insertion = self.rom.labels[str(target_address)]
335
96ca472 @kanzure implement a formatted-with-labels version of the opcode line
kanzure authored
336 opstr2 = base_opstr[:base_opstr.find("?")].lower() + insertion + base_opstr[base_opstr.find("?")+1:].lower()
337 asm_command["formatted_with_labels"] = opstr2
3359121 @kanzure graph.py - parse pokecrystal into a function graph for d3.js
kanzure authored
338 asm_command["target_address"] = target_address
96ca472 @kanzure implement a formatted-with-labels version of the opcode line
kanzure authored
339
4ccfe27 @kanzure more awful code for the new disassembler
kanzure authored
340 current_byte_number += 2
341 offset += 2
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
342
343 # Check for relative jumps, construct the formatted asm line.
344 # Also set the usage of labels.
4b7ca69 @kanzure advance forward when disassembling the rom
kanzure authored
345 if current_byte in [0x18, 0x20] + relative_jumps: # jr or jr nz
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
346 # generate a label for the byte we're jumping to
96596c6 @kanzure asm output for the new disassembler
kanzure authored
347 target_address = offset + 1 + c_int8(ord(rom[offset])).value
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
348
cd60a1f @kanzure backtracking and labeling for the disassembler
kanzure authored
349 if target_address in asm_commands.keys():
350 asm_commands[target_address]["references"] += 1
351 remote_label = "asm_" + hex(target_address)
352 asm_commands[target_address]["current_label"] = remote_label
353 asm_command["remote_label"] = remote_label
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
354
9a41584 @kanzure remove debug lines
kanzure authored
355 # Not sure how to set this, can't be True because an
356 # address referenced multiple times will use a label
357 # despite the label not necessarily being used in the
358 # output. The "use_remote_label" values should be
359 # calculated when rendering the asm output, based on
360 # which addresses and which op codes will be displayed
361 # (within the range).
362 asm_command["use_remote_label"] = "unknown"
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
363 else:
cd60a1f @kanzure backtracking and labeling for the disassembler
kanzure authored
364 remote_label = "asm_" + hex(target_address)
365
366 # This remote address might not be part of this
367 # function.
368 asm_commands[target_address] = {
369 "references": 1,
370 "current_label": remote_label,
96596c6 @kanzure asm output for the new disassembler
kanzure authored
371 "address": target_address,
cd60a1f @kanzure backtracking and labeling for the disassembler
kanzure authored
372 }
373 # Also, target_address can be negative (before the
374 # start_address that the user originally requested),
375 # and it shouldn't be shown on asm output because the
376 # intermediate bytes (between a negative target_address
377 # and start_address) won't be disassembled.
378
379 # Don't know yet if this remote address is part of this
380 # function or not. When the remote address is not part
381 # of this function, the label name should not be used,
382 # because that label will not be disassembled in the
383 # output, until the user asks it to.
384 asm_command["use_remote_label"] = "unknown"
385 asm_command["remote_label"] = remote_label
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
386 elif current_byte == 0x3e:
387 last_a_address = ord(rom[offset + 1])
388
389 # store the formatted string for the output later
390 asm_command["formatted"] = opstr
391
392 if current_byte == 0x21:
393 last_hl_address = byte1 + (byte2 << 8)
394
395 # this is leftover from pokered, might be meaningless
396 if current_byte == 0xcd:
397 if number == 0x3d97:
398 used_3d97 = True
cd60a1f @kanzure backtracking and labeling for the disassembler
kanzure authored
399
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
400 if current_byte == 0xc3 or current_byte in relative_unconditional_jumps:
401 if current_byte == 0xc3:
402 if number == 0x3d97:
403 used_3d97 = True
404
405 # stop reading at a jump, relative jump or return
4ccfe27 @kanzure more awful code for the new disassembler
kanzure authored
406 if current_byte in end_08_scripts_with:
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
407 is_data = False
408
132182e @kanzure super duper disassembler fixes
kanzure authored
409 if not self.has_outstanding_labels(asm_commands, offset):
4ccfe27 @kanzure more awful code for the new disassembler
kanzure authored
410 keep_reading = False
411 break
412 else:
413 keep_reading = True
414 else:
415 keep_reading = True
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
416
4ccfe27 @kanzure more awful code for the new disassembler
kanzure authored
417 else:
10a5a65 @kanzure somewhat improved disassembler
kanzure authored
418 # This shouldn't really happen, and means that this area of the
419 # ROM probably doesn't represent instructions.
420 asm_command["type"] = "data" # db
421 asm_command["value"] = current_byte
b19db1e @kanzure broken disassembler
kanzure authored
422 keep_reading = False
cd60a1f @kanzure backtracking and labeling for the disassembler
kanzure authored
423
132182e @kanzure super duper disassembler fixes
kanzure authored
424 # save this new command in the list
425 asm_commands[asm_command["address"]] = asm_command
426
4b7ca69 @kanzure advance forward when disassembling the rom
kanzure authored
427 # jump forward by a byte
428 offset += 1
429
132182e @kanzure super duper disassembler fixes
kanzure authored
430 # also save the last command if necessary
3359121 @kanzure graph.py - parse pokecrystal into a function graph for d3.js
kanzure authored
431 if len(asm_commands.keys()) > 0 and asm_commands[asm_commands.keys()[-1]] is not asm_command:
132182e @kanzure super duper disassembler fixes
kanzure authored
432 asm_commands[asm_command["address"]] = asm_command
433
434 # store the set of commands on this object
b19db1e @kanzure broken disassembler
kanzure authored
435 self.asm_commands = asm_commands
132182e @kanzure super duper disassembler fixes
kanzure authored
436
3359121 @kanzure graph.py - parse pokecrystal into a function graph for d3.js
kanzure authored
437 self.end_address = offset + 1
438 self.last_address = self.end_address
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
439
132182e @kanzure super duper disassembler fixes
kanzure authored
440 def has_outstanding_labels(self, asm_commands, offset):
441 """ Checks if there are any labels that haven't yet been created.
442 """ # is this really necessary??
443 return False
444
3359121 @kanzure graph.py - parse pokecrystal into a function graph for d3.js
kanzure authored
445 def used_addresses(self):
446 """ Returns a list of unique addresses that this function will probably
447 call.
448 """
449 addresses = set()
450
451 for (id, command) in self.asm_commands.items():
fcf43b1 @kanzure fix romstr for compiling (thanks pasky)
kanzure authored
452 if command.has_key("target_address") and command["id"] in call_commands:
3359121 @kanzure graph.py - parse pokecrystal into a function graph for d3.js
kanzure authored
453 addresses.add(command["target_address"])
454
455 return addresses
456
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
457 def __str__(self):
458 """ ASM pretty printer.
459 """
96596c6 @kanzure asm output for the new disassembler
kanzure authored
460 output = ""
461
462 for (key, line) in self.asm_commands.items():
463 # skip anything from before the beginning
464 if key < self.start_address:
465 continue
466
467 # show a label
468 if line["references"] > 0 and "current_label" in line.keys():
469 if line["address"] == self.start_address:
470 output += "thing: ; " + hex(line["address"]) + "\n"
471 else:
e471fbe @kanzure continue at relative jumps and fix formatting
kanzure authored
472 output += "." + line["current_label"] + "\@ ; " + hex(line["address"]) + "\n"
96596c6 @kanzure asm output for the new disassembler
kanzure authored
473
474 # show the actual line
475 if line.has_key("formatted_with_labels"):
476 output += spacing + line["formatted_with_labels"]
477 elif line.has_key("formatted"):
478 output += spacing + line["formatted"]
479 #output += " ; to " +
480 output += "\n"
481
482 # show the next address after this chunk
483 output += "; " + hex(self.end_address)
484
485 return output
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
486
0edf9eb @kanzure move AsmList into romstr.py too
kanzure authored
487 class AsmList(list):
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
488 """ Simple wrapper to prevent all asm lines from being shown on screen.
489 """
0edf9eb @kanzure move AsmList into romstr.py too
kanzure authored
490
491 def length(self):
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
492 """ len(self)
493 """
0edf9eb @kanzure move AsmList into romstr.py too
kanzure authored
494 return len(self)
495
496 def __repr__(self):
7dd0c86 @kanzure almost complete new disassembler version
kanzure authored
497 """ Simplifies this object so that the output doesn't overflow stdout.
498 """
0edf9eb @kanzure move AsmList into romstr.py too
kanzure authored
499 return "AsmList(too long)"
500
e2babd6 @kanzure use romstr.py as the new disassembler
kanzure authored
501 if __name__ == "__main__":
502 cryrom = RomStr(open("../pokecrystal.gbc", "r").read());
503 asm = cryrom.to_asm(sys.argv[1])
504 print asm
Something went wrong with that request. Please try again.