rasm2armips.py (3846B)
1 #!/usr/bin/env python 2 3 # Copyright (c) 2020 queueRAM 4 # 5 # Permission is hereby granted, free of charge, to any person obtaining a copy 6 # of this software and associated documentation files (the "Software"), to deal 7 # in the Software without restriction, including without limitation the rights 8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 # copies of the Software, and to permit persons to whom the Software is 10 # furnished to do so, subject to the following conditions: 11 # 12 # The above copyright notice and this permission notice shall be included in 13 # all copies or substantial portions of the Software. 14 # 15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 # SOFTWARE. 22 23 import argparse 24 import re 25 import sys 26 27 def read_file(filepath): 28 with open(filepath) as f: 29 lines = f.readlines() 30 split_lines = [re.split(r'[ ,]+', l.strip().replace('$', '')) for l in lines] 31 return split_lines 32 33 # jumps and branches with named targets 34 jumps = ['jal', 'j'] 35 branches = ['beq', 'bgez', 'bgtz', 'blez', 'bltz', 'bne'] 36 jump_branches = jumps + branches 37 # jumps and branches with delay slots 38 has_delay_slot = jump_branches + ['jr'] 39 40 def decode_references(instructions): 41 refs = [] 42 for ins in instructions: 43 if ins[3] in jump_branches: 44 target = int(ins[-1], 0) 45 if target not in refs: 46 refs.append(target) 47 return refs 48 49 def reassemble(args, instructions, refs): 50 print('.rsp') 51 print('\n.create DATA_FILE, 0x%04X' % 0x0000) 52 print('\n.close // DATA_FILE\n') 53 print('.create CODE_FILE, 0x%08X\n' % args.base) 54 delay_slot = False 55 for ins in instructions: 56 addr = int(ins[0], 0) 57 if (addr & 0xFFFF) in refs: 58 print('%s_%08x:' % (args.name, addr)) 59 sys.stdout.write(' ' * args.indent) 60 if delay_slot: 61 sys.stdout.write(' ') 62 delay_slot = False 63 if ins[3] in jumps: 64 target = int(ins[-1], 0) | (args.base & 0xFFFF0000) 65 ins[-1] = '%s_%08x' % (args.name, target) 66 elif ins[3] in branches: 67 if ins[3][-1] =='z' and ins[5] == 'zero': 68 del ins[5] # remove 'zero' operand from branch 69 target = (int(ins[-1], 0) & 0x1FFF) + (args.base & 0xFFFF0000) 70 ins[-1] = '%s_%08x' % (args.name, target) 71 elif ins[3] == 'vsar': # fixup last operand of vsar 72 reg_map = {'ACC_H': 0, 'ACC_M': 1, 'ACC_L': 2} 73 reg = ins[4].split(r'[')[0] 74 num = reg_map[ins[-1]] 75 ins[-1] = '%s[%d]' % (reg, num) 76 if ins[3] in has_delay_slot: 77 delay_slot = True 78 if len(ins) > 4: # with args 79 print('%-5s %s' % (ins[3], ', '.join(ins[4:]))) 80 else: 81 print('%s' % ins[3]) 82 print('\n.close // CODE_FILE') 83 84 def main(): 85 parser = argparse.ArgumentParser() 86 parser.add_argument('input_file', help="input assembly file generated from `rasm2 -D -e -a rsp -B -o 0x04001000 -f`") 87 parser.add_argument('-b', type=int, help="base address of file", dest='base', default=0x04001000) 88 parser.add_argument('-i', type=int, help="amount of indentation", dest='indent', default=4) 89 parser.add_argument('-n', help="name to prefex labels with", dest='name', default='f3d') 90 args = parser.parse_args() 91 92 lines = read_file(args.input_file) 93 refs = decode_references(lines) 94 reassemble(args, lines, refs) 95 96 main()