oisc8asm.py 6.6 KB

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