resolving imports changing over
[openpower-isa.git] / src / openpower / simulator / program.py
1 # License: LGPLv3+
2 # Copyright (C) 2020 Michael Nolan <mtnolan2640@gmail.com>
3 # Copyright (C) 2020 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
4
5 """POWER Program
6
7 takes powerpc assembly instructions and turns them into LE/BE binary
8 data. calls powerpc64-linux-gnu-as, ld and objcopy to do so.
9 """
10
11 import tempfile
12 import subprocess
13 import struct
14 import os
15 import sys
16 from io import BytesIO
17
18 from openpower.simulator.envcmds import cmds
19
20 filedir = os.path.dirname(os.path.realpath(__file__))
21 memmap = os.path.join(filedir, "memmap")
22
23
24 class Program:
25 def __init__(self, instructions, bigendian):
26 self.bigendian = bigendian
27 if self.bigendian:
28 self.endian_fmt = "elf64-big"
29 self.obj_fmt = "-be"
30 self.ld_fmt = "-EB"
31 else:
32 self.ld_fmt = "-EL"
33 self.endian_fmt = "elf64-little"
34 self.obj_fmt = "-le"
35
36 if isinstance(instructions, bytes): # actual bytes
37 self.binfile = BytesIO(instructions)
38 self.binfile.name = "assembly"
39 self.assembly = '' # noo disassemble number fiiive
40 elif isinstance(instructions, str): # filename
41 # read instructions into a BytesIO to avoid "too many open files"
42 with open(instructions, "rb") as f:
43 b = f.read()
44 self.binfile = BytesIO(b)
45 self.assembly = '' # noo disassemble number fiiive
46 print("program", self.binfile)
47 else:
48 if isinstance(instructions, list):
49 instructions = '\n'.join(instructions)
50 self.assembly = instructions + '\n' # plus final newline
51 self._assemble()
52 self._instructions = list(self._get_instructions())
53
54 def __enter__(self):
55 return self
56
57 def __exit__(self, type, value, traceback):
58 self.close()
59
60 def _get_binary(self, elffile):
61 self.binfile = tempfile.NamedTemporaryFile(suffix=".bin")
62 args = [cmds['objcopy'],
63 "-O", "binary",
64 "-I", self.endian_fmt,
65 elffile.name,
66 self.binfile.name]
67 subprocess.check_output(args)
68
69 def _link(self, ofile):
70 with tempfile.NamedTemporaryFile(suffix=".elf") as elffile:
71 args = [cmds['ld'],
72 self.ld_fmt,
73 "-o", elffile.name,
74 "-T", memmap,
75 ofile.name]
76 subprocess.check_output(args)
77 self._get_binary(elffile)
78
79 def _assemble(self):
80 with tempfile.NamedTemporaryFile(suffix=".o") as outfile:
81 args = [cmds['as'],
82 '-mpower9',
83 '-mregnames',
84 self.obj_fmt,
85 "-o",
86 outfile.name]
87 p = subprocess.Popen(args, stdin=subprocess.PIPE)
88 p.communicate(self.assembly.encode('utf-8'))
89 if p.wait() != 0:
90 print("Error in program:")
91 print(self.assembly)
92 sys.exit(1)
93 self._link(outfile)
94
95 def _get_instructions(self):
96 while True:
97 data = self.binfile.read(4)
98 if not data:
99 break
100 yield struct.unpack('<I', data)[0] # unsigned int
101
102 def generate_instructions(self):
103 yield from self._instructions
104
105 def reset(self):
106 self.binfile.seek(0)
107
108 def size(self):
109 curpos = self.binfile.tell()
110 self.binfile.seek(0, 2) # Seek to end of file
111 size = self.binfile.tell()
112 self.binfile.seek(curpos, 0)
113 return size
114
115 def write_bin(self, fname):
116 self.reset()
117 data = self.binfile.read()
118 with open(fname, "wb") as f:
119 f.write(data)
120
121 def close(self):
122 self.binfile.close()
123
124 if __name__ == '__main__':
125 lst = ['addi 5, 0, 4660/2',
126 'mtcrf 255, 5+3',
127 'mfocrf 2, 1',
128 'addi r2, 3, 1',
129 'attn',
130 ]
131 lst = ["addi 9, 0, 0x10", # i = 16
132 "addi 9,9,-1", # i = i - 1
133 "cmpi 2,1,9,12", # compare 9 to value 12, store in CR2
134 "bc 4,10,-8", # branch if CR2 "test was != 12"
135 'attn',
136 ]
137
138 with Program(lst, False) as p:
139 for instruction in p.generate_instructions():
140 print (hex(instruction))
141 p.write_bin("/tmp/test.bin")