| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- import argparse
- import sys
- from os import path, mkdir
- import asm_compiler as compiler
- from asm_compiler import InstructionError, CompilingError
- import format_utils
- class Compiler(compiler.Compiler):
- def compile(self, file, code):
- sections = super(Compiler, self).compile(file, code)
- return sections
- # if '.text' in sections:
- # width, length, size, data = sections['.text']
- def decompile(self, binary):
- addr = 0
- res = []
- ibin = iter(binary)
- for data in ibin:
- src = int(next(ibin))
- imm = ((data & 16) >> 4) == 1
- dst = data & 15
- dst_name = None
- for instr in self.instr_db.values():
- if instr.opcode == dst:
- dst_name = instr.name.upper()
- if dst_name is None:
- dst_name = "0x" + format(dst, '02x')
- asm = f'{addr:04x}: {dst_name.ljust(6)}'
- src_name = "0x" + format(src, '02x')
- if not imm and src in instrSrc:
- src_name = instrSrc[src][-1]
- line = asm + ' ' + src_name
- tabs = ' ' * (27 - int(len(line)))
- raw = format(data, '02x') + format(src, '02x')
- res.append(f'{line}{tabs}[{raw}]')
- addr += 1
- return '\n'.join(res)
- asmc = Compiler(byte_order='big')
- instrSrc = {
- 0: ["NULL"],
- 1: ["ALUACC0R", "ALU0"],
- 2: ["ALUACC1R", "ALU1"],
- 3: ["ADD"],
- 4: ["ADDC"],
- 5: ["SUB"],
- 6: ["SUBC"],
- 7: ["AND"],
- 8: ["OR"],
- 9: ["XOR"],
- 10: ["SLL"],
- 11: ["SRL"],
- 12: ["EQ"],
- 13: ["GT"],
- 14: ["GE"],
- 15: ["NE"],
- 16: ["LT"],
- 17: ["LE"],
- 18: ["MULLO"],
- 19: ["MULHI"],
- 20: ["DIV"],
- 21: ["MOD"],
- 22: ["BRPT0R", "BR0"],
- 23: ["BRPT1R", "BR1"],
- 24: ["PC0"],
- 25: ["PC1"],
- 26: ["MEMPT0R", "MEM0"],
- 27: ["MEMPT1R", "MEM1"],
- 28: ["MEMPT2R", "MEM2"],
- 29: ["MEMLWHI", "LWHI", "MEMHI"],
- 30: ["MEMLWLO", "LWLO", "MEMLO"],
- 31: ["STACKR", "STACK"],
- 32: ["STACKPT0", "STPT0"],
- 33: ["STACKPT1", "STPT1"],
- 34: ["COMAR", "COMA"],
- 35: ["COMDR", "COMD"],
- 36: ["REG0R", "REG0"],
- 37: ["REG1R", "REG1"],
- 38: ["ADC"],
- 39: ["SBC"],
- 40: ["ROL"],
- 41: ["ROR"],
- }
- instrMap = {}
- for i, v in instrSrc.items():
- for n in v:
- instrMap[n.lower()] = i
- class InstructionDest:
- def __init__(self, name: str, opcode: int, alias=None):
- name = name.strip().lower()
- if not name or not name.isalnum():
- raise InstructionError(f"Invalid instruction name '{name}'")
- self.name = name.strip()
- self.alias = alias or []
- self.opcode = opcode
- self.imm_operands = 1
- self.reg_operands = 0
- self.compiler = None
- @property
- def length(self):
- return 1
- def __len__(self):
- return 1
- def compile(self, operands, scope):
- if len(operands) != 1:
- raise CompilingError(f"Instruction has invalid amount of operands")
- if operands[0].lower() in instrMap:
- src = instrMap[operands[0].lower()]
- immediate = 0
- else:
- imm = self.compiler.decode_with_labels(operands, scope)
- if len(imm) != 1:
- raise CompilingError(f"Instruction immediate is {len(imm)} in length. It must be 1.")
- immediate = 1
- src = imm[0]
- return (immediate << 12 | self.opcode << 8 | src).to_bytes(2, self.compiler.order)
- asmc.add_instr(InstructionDest("ALU0", 0, alias=["ALUACC0"]))
- asmc.add_instr(InstructionDest("ALU1", 1, alias=["ALUACC1"]))
- asmc.add_instr(InstructionDest("BR0", 2, alias=["BRPT0"]))
- asmc.add_instr(InstructionDest("BR1", 3, alias=["BRPT1"]))
- asmc.add_instr(InstructionDest("BRZ", 4))
- asmc.add_instr(InstructionDest("STACK", 5))
- asmc.add_instr(InstructionDest("MEM0", 6, alias=["MEMPT0"]))
- asmc.add_instr(InstructionDest("MEM1", 7, alias=["MEMPT1"]))
- asmc.add_instr(InstructionDest("MEM2", 8, alias=["MEMPT2"]))
- asmc.add_instr(InstructionDest("MEMHI", 9, alias=["MEMSWHI", "SWHI"]))
- asmc.add_instr(InstructionDest("MEMLO", 10, alias=["MEMSWLO", "SWLO"]))
- asmc.add_instr(InstructionDest("COMA", 11))
- asmc.add_instr(InstructionDest("COMD", 12))
- asmc.add_instr(InstructionDest("REG0", 13))
- asmc.add_instr(InstructionDest("REG1", 14))
- if __name__ == '__main__':
- compiler.main(asmc)
- # parser = argparse.ArgumentParser(description='Assembly compiler', add_help=True)
- # parser.add_argument('file', help='Files to compile')
- # parser.add_argument('-t', '--output_type', choices=['bin', 'mem', 'binary', 'mif', 'uhex', 'ubin'], default='mem',
- # help='Output type')
- # parser.add_argument('-S', '--slice', default=0, type=int, help='Slice output for section')
- # parser.add_argument('-o', '--output', help='Output directory')
- # parser.add_argument('-f', '--force', action='store_true', help='Force override output file')
- # parser.add_argument('-s', '--stdout', action='store_true', help='Print to stdout')
- # parser.add_argument('-D', '--decompile', action='store_true', help='Print decompiled')
- # parser.add_argument('section', help='Section')
- # args = parser.parse_args(sys.argv[1:])
- # if not path.isfile(args.file):
- # print(f'No file {args.file}!')
- # sys.exit(1)
- #
- # output_dir = args.output or path.dirname(args.file)
- # if not path.exists(output_dir):
- # mkdir(output_dir)
- #
- # if args.output_type == 'mem' or args.output_type == 'binary':
- # ext = '.mem'
- # elif args.output_type == 'bin':
- # ext = '.bin'
- # elif args.output_type == 'mif':
- # ext = '.mif'
- # elif args.output_type == 'uhex':
- # ext = '.uhex'
- # elif args.output_type == 'ubin':
- # ext = '.ubin'
- # else:
- # ext = '.out'
- # bname = path.basename(args.file).rsplit('.', 1)[0]
- #
- # outputs = []
- # if args.slice > 0:
- # for i in range(0, args.slice):
- # outputs.append(path.join(output_dir, f'{bname}{args.section}_{i}{ext}'))
- # else:
- # outputs = [path.join(output_dir, bname + args.section + ext)]
- # if not args.stdout and not args.force:
- # for output in outputs:
- # if path.isfile(output):
- # print(f'Output file already exists {output}!')
- # sys.exit(1)
- #
- # data = asmc.compile_file(args.file)
- # if data is not None:
- # section = args.section
- # if section in data:
- # width, length, size, bdata = data[section]
- # asize = len(bdata)
- #
- # if size > 0:
- # bdataf = bdata + (size - len(bdata)) * bytearray(b'\x00')
- # else:
- # bdataf = bdata
- #
- # bitwidth = width * 8
- # if section == '.text':
- # if len(bdata) % 4 != 0:
- # bdata += b'\x00\x00'
- # bitblocks = [
- # format(int.from_bytes(bdataf[i * 4:i * 4 + 2], 'big'), f'013b') +
- # format(int.from_bytes(bdataf[i * 4 + 2:i * 4 + 4], 'big'), f'013b')
- # for i in range(0, len(bdataf) // 4)
- # ]
- # bitblocks += ['0'*26] * (size//3 - len(bitblocks))
- # # calculate parity bit
- # bitblocks = [b + str(b.count('1') % 2) for b in bitblocks]
- # # divide into 3 for each memory chip
- # else:
- # bitblocks = [
- # format(int.from_bytes(bdataf[i * width:i * width + width], 'big'), f'0{bitwidth}b')
- # for i in range(len(bdataf) // width)
- # ]
- # # bitblocks = [bdataf]
- # # bitstring = ''.join(bits)
- # # bitstring += len(bitstring) % 8 * 27 * '0' # fill to the integer byte
- # # x = int(bitstring, 2).to_bytes(len(bitstring) // 8, 'big')
- #
- # for i, output in enumerate(outputs):
- # block_chunks = []
- # chunk_width = 9 if section == '.text' else 16
- # for block in bitblocks:
- # for j in range(len(outputs)):
- # block_chunks.append(block[chunk_width * j:chunk_width * (j+1)])
- #
- # y = block_chunks[i::len(outputs)]
- # if args.output_type == 'binary':
- # x = '\n'.join(y).encode()
- # elif args.output_type == 'mif':
- # x = format_utils.convert_to_mif(y, width=bitwidth)
- # else:
- # from bitstring import BitArray
- # # merge bits chunks info bytes
- # y = BitArray(bin='0b'+''.join(y)).bytes
- # if args.output_type == 'mem':
- # x = format_utils.convert_to_mem(y, width=1, uhex=True, reverse=True)
- # elif args.output_type == 'uhex':
- # x = format_utils.convert_to_mem(y, width=width, uhex=True)
- # elif args.output_type == 'ubin':
- # x = format_utils.convert_to_binary(reversed(y), width=width)
- # else:
- # x = bytes(y)
- #
- # op = 'Printing' if args.stdout else 'Saving'
- # print(f"{op} {args.output_type} {section} data '{output}' [Size: {len(y)}B Slice: {i+1}/{len(outputs)}]")
- # if args.stdout:
- # if args.decompile:
- # print(asmc.decompile(bdata))
- # else:
- # print(x.decode())
- # else:
- # with open(output, 'wb') as of:
- # of.write(x)
- # if section == '.text':
- # insUsed = int(asize)//2
- # insTotal = size//2
- # print(f"Total {section} size: {insUsed / insTotal * 100:.1f}% "
- # f"[ {insUsed} instr / {insTotal} instr ]")
- # else:
- # print(f"Total {section} size: {asize / len(bdataf) * 100:.1f}% [{int(asize)}B/{len(bdataf)}B]")
- # else:
- # print(f'No such section {section}!')
- # else:
- # print(f'Failed to compile {args.file}!')
- # sys.exit(1)
- # sys.exit(0)
|