oisc8asm.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. import argparse
  2. import sys
  3. import math
  4. from os import path, mkdir
  5. import asm_compiler as compiler
  6. from asm_compiler import InstructionError, CompilingError
  7. class Compiler(compiler.Compiler):
  8. def compile(self, file, code):
  9. sections = super(Compiler, self).compile(file, code)
  10. return sections
  11. # if '.text' in sections:
  12. # width, length, size, data = sections['.text']
  13. def decompile(self, binary):
  14. addr = 0
  15. res = []
  16. ibin = iter(binary)
  17. for data in ibin:
  18. src = int(next(ibin))
  19. imm = ((data & 16) >> 4) == 1
  20. dst = data & 15
  21. dst_name = None
  22. for instr in self.instr_db.values():
  23. if instr.opcode == dst:
  24. dst_name = instr.name.upper()
  25. if dst_name is None:
  26. dst_name = "0x" + format(dst, '02x')
  27. asm = f'{addr:04x}: {dst_name.ljust(6)}'
  28. src_name = "0x" + format(src, '02x')
  29. if not imm and src in instrSrc:
  30. src_name = instrSrc[src][-1]
  31. line = asm + ' ' + src_name
  32. tabs = ' ' * (27 - int(len(line)))
  33. raw = format(data, '02x') + format(src, '02x')
  34. res.append(f'{line}{tabs}[{raw}]')
  35. addr += 1
  36. return '\n'.join(res)
  37. asmc = Compiler(byte_order='big')
  38. instrSrc = {
  39. 0: ["NULL"],
  40. 1: ["ALUACC0R", "ALU0"],
  41. 2: ["ALUACC1R", "ALU1"],
  42. 3: ["ADD"],
  43. 4: ["ADDC"],
  44. 5: ["SUB"],
  45. 6: ["SUBC"],
  46. 7: ["AND"],
  47. 8: ["OR"],
  48. 9: ["XOR"],
  49. 10: ["SLL"],
  50. 11: ["SRL"],
  51. 12: ["EQ"],
  52. 13: ["GT"],
  53. 14: ["GE"],
  54. 15: ["NE"],
  55. 16: ["LT"],
  56. 17: ["LE"],
  57. 18: ["MULLO"],
  58. 19: ["MULHI"],
  59. 20: ["DIV"],
  60. 21: ["MOD"],
  61. 22: ["BRPT0R", "BR0"],
  62. 23: ["BRPT1R", "BR1"],
  63. 24: ["PC0"],
  64. 25: ["PC1"],
  65. 26: ["MEMPT0R", "MEM0"],
  66. 27: ["MEMPT1R", "MEM1"],
  67. 28: ["MEMPT2R", "MEM2"],
  68. 29: ["MEMLWHI", "LWHI", "MEMHI"],
  69. 30: ["MEMLWLO", "LWLO", "MEMLO"],
  70. 31: ["STACKR", "STACK"],
  71. 32: ["STACKPT0", "STPT0"],
  72. 33: ["STACKPT1", "STPT1"],
  73. 34: ["COMAR", "COMA"],
  74. 35: ["COMDR", "COMD"],
  75. 36: ["REG0R", "REG0"],
  76. 37: ["REG1R", "REG1"],
  77. 38: ["ADC"],
  78. 39: ["SBC"],
  79. 40: ["ROL"],
  80. 41: ["ROR"],
  81. }
  82. instrMap = {}
  83. for i, v in instrSrc.items():
  84. for n in v:
  85. instrMap[n.lower()] = i
  86. class InstructionDest:
  87. def __init__(self, name: str, opcode: int, alias=None):
  88. name = name.strip().lower()
  89. if not name or not name.isalnum():
  90. raise InstructionError(f"Invalid instruction name '{name}'")
  91. self.name = name.strip()
  92. self.alias = alias or []
  93. self.opcode = opcode
  94. self.imm_operands = 1
  95. self.reg_operands = 0
  96. self.compiler = None
  97. @property
  98. def length(self):
  99. return 1
  100. def __len__(self):
  101. return 1
  102. def compile(self, operands, scope):
  103. if len(operands) != 1:
  104. raise CompilingError(f"Instruction has invalid amount of operands")
  105. if operands[0].lower() in instrMap:
  106. src = instrMap[operands[0].lower()]
  107. immediate = 0
  108. else:
  109. imm = self.compiler.decode_with_labels(operands, scope)
  110. if len(imm) != 1:
  111. raise CompilingError(f"Instruction immediate is {len(imm)} in length. It must be 1.")
  112. immediate = 1
  113. src = imm[0]
  114. return (immediate << 12 | self.opcode << 8 | src).to_bytes(2, self.compiler.order)
  115. asmc.add_instr(InstructionDest("ALU0", 0, alias=["ALUACC0"]))
  116. asmc.add_instr(InstructionDest("ALU1", 1, alias=["ALUACC1"]))
  117. asmc.add_instr(InstructionDest("BR0", 2, alias=["BRPT0"]))
  118. asmc.add_instr(InstructionDest("BR1", 3, alias=["BRPT1"]))
  119. asmc.add_instr(InstructionDest("BRZ", 4))
  120. asmc.add_instr(InstructionDest("STACK", 5))
  121. asmc.add_instr(InstructionDest("MEM0", 6, alias=["MEMPT0"]))
  122. asmc.add_instr(InstructionDest("MEM1", 7, alias=["MEMPT1"]))
  123. asmc.add_instr(InstructionDest("MEM2", 8, alias=["MEMPT2"]))
  124. asmc.add_instr(InstructionDest("SWHI", 9, alias=["MEMSWHI", "MEMHI"]))
  125. asmc.add_instr(InstructionDest("SWLO", 10, alias=["MEMSWLO", "MEMLO"]))
  126. asmc.add_instr(InstructionDest("COMA", 11))
  127. asmc.add_instr(InstructionDest("COMD", 12))
  128. asmc.add_instr(InstructionDest("REG0", 13))
  129. asmc.add_instr(InstructionDest("REG1", 14))
  130. if __name__ == '__main__':
  131. parser = argparse.ArgumentParser(description='Assembly compiler', add_help=True)
  132. parser.add_argument('file', help='Files to compile')
  133. parser.add_argument('-t', '--output_type', choices=['bin', 'mem', 'binary', 'mif', 'uhex'], default='mem',
  134. help='Output type')
  135. parser.add_argument('-S', '--slice', default=-1, type=int, help='Slice output for section')
  136. parser.add_argument('-o', '--output', help='Output directory')
  137. parser.add_argument('-f', '--force', action='store_true', help='Force override output file')
  138. parser.add_argument('-s', '--stdout', action='store_true', help='Print to stdout')
  139. parser.add_argument('-D', '--decompile', action='store_true', help='Print decompiled')
  140. parser.add_argument('section', help='Section')
  141. args = parser.parse_args(sys.argv[1:])
  142. if not path.isfile(args.file):
  143. print(f'No file {args.file}!')
  144. sys.exit(1)
  145. output_dir = args.output or path.dirname(args.file)
  146. if not path.exists(output_dir):
  147. mkdir(output_dir)
  148. if args.output_type == 'mem':
  149. ext = '.mem'
  150. elif args.output_type == 'bin':
  151. ext = '.bin'
  152. elif args.output_type == 'mif':
  153. ext = '.mif'
  154. elif args.output_type == 'uhex':
  155. ext = '.uhex'
  156. else:
  157. ext = '.out'
  158. bname = path.basename(args.file).rsplit('.', 1)[0]
  159. sformat = f'01d'
  160. outputs = []
  161. if args.slice > 0:
  162. sformat = f'0{int(math.log10(args.slice)) + 1}d'
  163. for i in range(0, args.slice):
  164. outputs.append(path.join(output_dir, f'{bname}{args.section}_{format(i, sformat)}{ext}'))
  165. else:
  166. outputs = [path.join(output_dir, bname + args.section + ext)]
  167. if not args.stdout and not args.force:
  168. for output in outputs:
  169. if path.isfile(output):
  170. print(f'Output file already exists {output}!')
  171. sys.exit(1)
  172. data = asmc.compile_file(args.file)
  173. if data is not None:
  174. section = args.section
  175. if section in data:
  176. width, length, size, bdata = data[section]
  177. asize = len(bdata)
  178. if size > 0:
  179. bdataf = bdata + (size - len(bdata)) * bytearray(b'\x00')
  180. else:
  181. bdataf = bdata
  182. for i, output in enumerate(outputs):
  183. y = bdataf[i::len(outputs)]
  184. if args.output_type == 'binary':
  185. x = compiler.convert_to_binary(y)
  186. elif args.output_type == 'mem':
  187. x = compiler.convert_to_mem(y, width=width)
  188. elif args.output_type == 'mif':
  189. x = compiler.convert_to_mif(y, width=width, depth=len(y)/width)
  190. elif args.output_type == 'uhex':
  191. x = compiler.convert_to_mem(y, width=width, uhex=True)
  192. else:
  193. x = bytes(y)
  194. op = 'Printing' if args.stdout else 'Saving'
  195. print(f"{op} {args.output_type} {section} data '{output}' [Size: {len(y)}B Slice: {format(i + 1, sformat)}/{len(outputs)}]")
  196. if args.stdout:
  197. if args.decompile:
  198. print(asmc.decompile(bdata))
  199. else:
  200. print(x.decode())
  201. else:
  202. with open(output, 'wb') as of:
  203. of.write(x)
  204. print(f"Total {section} size: {len(bdata) / len(bdataf) * 100:.1f}% [{len(bdata)}B/{len(bdataf)}B]")
  205. else:
  206. print(f'No such section {section}!')
  207. else:
  208. print(f'Failed to compile {args.file}!')
  209. sys.exit(1)
  210. sys.exit(0)