Explorar o código

Working macros & OISC instr.

Fixed macros, added new OISC instructions
Min %!s(int64=5) %!d(string=hai) anos
pai
achega
a486ae7591
Modificáronse 2 ficheiros con 106 adicións e 74 borrados
  1. 27 19
      tools/asm_compiler.py
  2. 79 55
      tools/oisc8asm.py

+ 27 - 19
tools/asm_compiler.py

@@ -11,11 +11,14 @@ bin_re = re.compile(r"^[0-1_]+$", re.IGNORECASE)
 oct_re = re.compile(r"^[0-8]+$", re.IGNORECASE)
 args_re = re.compile("(?:^|,)(?=[^\"]|(\")?)\"?((?(1)[^\"]*|[^,\"]*))\"?(?=,|$)", re.IGNORECASE)
 func_re = re.compile("^([\w$#@~.?]+)\s*([|^<>+\-*/%@]{1,2})\s*([\w$#@~.?]+)$", re.IGNORECASE)
+func2_re = re.compile("^([\w$#@~.?]+)\s*\(\s*([\w$#@~.?]+)*\)$", re.IGNORECASE)
+brackets_re = re.compile(r"(\((?:\(??[^\(]*?\)))", re.IGNORECASE)
 secs_re = re.compile("^([\d]+)x([\d]+)x([\d]+)$", re.IGNORECASE)
 funcc_re = re.compile("^([\w$#@~.?]+)\(([\w,]+)\)(.*)", re.IGNORECASE)
 
 MAX_INT_BYTES = 12
 
+
 def args2operands(args):
     operands = ['"' + a[1] + '"' if a[0] == '"' else a[1] for a in args_re.findall(args or '') if a[1]]
     return operands
@@ -101,7 +104,7 @@ class Section:
         self.count = 0
         self.width = 1
         self.length = 1
-        self.size = 2**8
+        self.size = 2 ** 8
 
 
 class Compiler:
@@ -172,12 +175,12 @@ class Compiler:
         # Convert with limits
         if typ == 'uint':
             numb = int(s)
-            for i in range(1, MAX_INT_BYTES+1):
+            for i in range(1, MAX_INT_BYTES + 1):
                 if numb < 2 ** (i * 8):
                     return numb.to_bytes(i, self.order)
         elif typ == 'int':
             numb = int(s)
-            for i in range(1, MAX_INT_BYTES+1):
+            for i in range(1, MAX_INT_BYTES + 1):
                 if -2 ** (i * 7) < numb < 2 ** (i * 7):
                     return numb.to_bytes(i, self.order)
         elif typ == 'hex':
@@ -263,12 +266,12 @@ class Compiler:
         elif op == '%' or op == '%%':
             result = leftInt % rightInt
         elif op == '@':
-            return bytes([left[len(left)-rightInt-1]])
+            return bytes([left[len(left) - rightInt - 1]])
         else:
             raise CompilingError(f"Invalid function operation {op}")
         return result.to_bytes(len(left), self.order)
 
-    def __code_compiler(self, file, lnum, line_args, csect, scope):
+    def __code_compiler(self, file, lnum, line_args, csect, scope, macro):
         builtin_cmds = {'db', 'dbe'}
 
         if line_args[0].endswith(':') and label_re.match(line_args[0][:-1]) is not None:
@@ -279,7 +282,7 @@ class Compiler:
                 if scope is None:
                     raise CompilingError(f"No local scope for {label}!")
                 label = scope + label
-            else:
+            elif not macro:
                 scope = label
             if label in self.labels:
                 raise CompilingError(f"Label {label} duplicate")
@@ -322,12 +325,17 @@ class Compiler:
             argsp = args2operands(args)
             if len(argsp) != self.macros[instr_name][0]:
                 raise CompilingError(f"Invalid macro argument count!")
+            self.macros[instr_name][3] += 1  # How many time macro been used (used for macro labels)
+            mlabel = f'{instr_name}.{self.macros[instr_name][3]}'
             for slnum, sline in enumerate(self.macros[instr_name][1]):
                 slnum += 1
-                for i in range(len(argsp)):
-                    sline = [l.replace(f'%{i+1}', argsp[i]) for l in sline]
+                mline = sline.copy()
+                for i, mline0 in enumerate(mline):
+                    for j in range(len(argsp)):
+                        mline0 = mline0.replace(f'%{j + 1}', argsp[j])
+                    mline[i] = re.sub(r'(%{2})([\w$#~.?]+)', mlabel+r'.\2', mline0)
                 try:
-                    scope = self.__code_compiler(file, lnum, sline, csect, scope)
+                    scope = self.__code_compiler(file, lnum, mline, csect, scope, True)
                 except CompilingError as e:
                     print(f"ERROR {file}:{self.macros[instr_name][2] + slnum}: {e.message}")
                     raise CompilingError(f"Previous error")
@@ -414,7 +422,7 @@ class Compiler:
                     if not line_args[2].isdigit():
                         raise CompilingError(f"%macro argument 2 must be a number")
                     macro = line_args[1].lower()
-                    self.macros[macro] = (int(line_args[2]), [], lnum)
+                    self.macros[macro] = [int(line_args[2]), [], lnum, 0]
                     continue
 
                 elif line_args[0].lower() == '%include':
@@ -426,7 +434,7 @@ class Compiler:
                 if csect is None:
                     raise CompilingError(f"No section defined!")
 
-                scope = self.__code_compiler(file, lnum, line_args, csect, scope)
+                scope = self.__code_compiler(file, lnum, line_args, csect, scope, False)
 
             except CompilingError as e:
                 failure = True
@@ -498,12 +506,12 @@ def convert_to_mem(data, width=1, uhex=False):
 
     if uhex:
         if width == 2:
-            for i in range(int(len(data)/2)):
-                x += format(data[-(i*2) - 2], f'02x').upper().encode()
-                x += format(data[-(i*2) - 1], f'02x').upper().encode()
+            for i in range(int(len(data) / 2)):
+                x += format(data[-(i * 2) - 2], f'02x').upper().encode()
+                x += format(data[-(i * 2) - 1], f'02x').upper().encode()
         else:
             for i in range(len(data)):
-                x += format(data[-i-1], f'02x').upper().encode()
+                x += format(data[-i - 1], f'02x').upper().encode()
         return x
 
     if width == 2:
@@ -514,7 +522,7 @@ def convert_to_mem(data, width=1, uhex=False):
         datax = data
 
     fa = f'0{math.ceil(math.ceil(math.log2(len(datax))) / 4)}x'
-    a = [format(d, f'0{width*2}x') for d in datax]
+    a = [format(d, f'0{width * 2}x') for d in datax]
     for i in range(int(len(a) / 8) + 1):
         y = a[i * 8:(i + 1) * 8]
         if len(y) > 0:
@@ -525,7 +533,7 @@ def convert_to_mem(data, width=1, uhex=False):
 def convert_to_mif(data, depth=32, width=1):
     x = f'''-- auto-generated memory initialisation file
 DEPTH = {math.ceil(depth)};
-WIDTH = {width*8};
+WIDTH = {width * 8};
 ADDRESS_RADIX = HEX;
 DATA_RADIX = HEX;
 CONTENT
@@ -539,8 +547,8 @@ BEGIN
             datax.append(data[-1] << 8)
     else:
         datax = data
-    a = [format(i, f'0{width*2}x') for i in datax]
-    for i in range(int(len(a*width) / 8) + 1):
+    a = [format(i, f'0{width * 2}x') for i in datax]
+    for i in range(int(len(a * width) / 8) + 1):
         y = a[i * 8:(i + 1) * 8]
         if len(y) > 0:
             x += (format(i * 8, addr_format) + ' : ' + ' '.join(y) + ';\n').encode()

+ 79 - 55
tools/oisc8asm.py

@@ -15,56 +15,80 @@ class Compiler(compiler.Compiler):
         #     width, length, size, data = sections['.text']
 
     def decompile(self, binary):
-        pass
+        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 = {
-    "NULL": 0,
-    "ALUACC0R": 1,
-    "ALU0": 1,
-    "ALUACC1R": 2,
-    "ALU1": 2,
-    "ADD": 3,
-    "ADDC": 4,
-    "SUB": 5,
-    "SUBC": 6,
-    "AND": 7,
-    "OR": 8,
-    "XOR": 9,
-    "SLL": 11,
-    "SRL": 12,
-    "EQ": 13,
-    "GT": 14,
-    "GE": 15,
-    "MULLO": 16,
-    "MULHI": 17,
-    "DIV": 18,
-    "MOD": 19,
-    "BRPT0R": 20,
-    "BR0": 20,
-    "BRPT1R": 21,
-    "BR1": 21,
-    "MEMPT0R": 22,
-    "MEM0": 22,
-    "MEMPT1R": 23,
-    "MEM1": 23,
-    "MEMPT2R": 24,
-    "MEM2": 24,
-    "MEMLWHI": 25,
-    "LWHI": 25,
-    "MEMLWLO": 26,
-    "LWLO": 26,
-    "STACKR": 27,
-    "STACK": 27,
-    "STACKPT0": 28,
-    "STACKPT1": 29,
-    "COMAR": 30,
-    "COMA": 30,
-    "COMDR": 31,
-    "COMD": 31
+    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"],
+    40: ["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"],
 }
+instrMap = {}
+for i, v in instrSrc.items():
+    for n in v:
+        instrMap[n.lower()] = i
 
 
 class InstructionDest:
@@ -81,17 +105,17 @@ class InstructionDest:
 
     @property
     def length(self):
-        return 2
+        return 1
 
     def __len__(self):
-        return 2
+        return 1
 
     def compile(self, operands, scope):
         if len(operands) != 1:
             raise CompilingError(f"Instruction has invalid amount of operands")
 
-        if operands[0].upper() in instrSrc:
-            src = instrSrc[operands[0]]
+        if operands[0].lower() in instrMap:
+            src = instrMap[operands[0].lower()]
             immediate = 0
         else:
             imm = self.compiler.decode_with_labels(operands, scope)
@@ -112,11 +136,12 @@ 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("SWHI", 9, alias=["MEMSWHI"]))
-asmc.add_instr(InstructionDest("SWLO", 10, alias=["MEMSWLO"]))
+asmc.add_instr(InstructionDest("SWHI", 9, alias=["MEMSWHI", "MEMHI"]))
+asmc.add_instr(InstructionDest("SWLO", 10, alias=["MEMSWLO", "MEMLO"]))
 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__':
     parser = argparse.ArgumentParser(description='Assembly compiler', add_help=True)
@@ -155,7 +180,7 @@ if __name__ == '__main__':
     if args.slice > 0:
         sformat = f'0{int(math.log10(args.slice)) + 1}d'
         for i in range(0, args.slice):
-            outputs.append(path.join(output_dir,f'{bname}{args.section}_{format(i, sformat)}{ext}'))
+            outputs.append(path.join(output_dir, f'{bname}{args.section}_{format(i, sformat)}{ext}'))
     else:
         outputs = [path.join(output_dir, bname + args.section + ext)]
     if not args.stdout and not args.force:
@@ -164,8 +189,7 @@ if __name__ == '__main__':
                 print(f'Output file already exists {output}!')
                 sys.exit(1)
 
-    with open(args.file, 'r') as f:
-        data = asmc.compile(args.file, f.readlines())
+    data = asmc.compile_file(args.file)
     if data is not None:
         section = args.section
         if section in data:
@@ -201,7 +225,7 @@ if __name__ == '__main__':
                     with open(output, 'wb') as of:
                         of.write(x)
 
-            print(f"Total {section} size: {len(bdata)/len(bdataf)*100:.1f}% [{len(bdata)}B/{len(bdataf)}B]")
+            print(f"Total {section} size: {len(bdata) / len(bdataf) * 100:.1f}% [{len(bdata)}B/{len(bdataf)}B]")
         else:
             print(f'No such section {section}!')
     else: