format code
[openpower-isa.git] / src / openpower / simulator / program.py
1 # SPDX-License-Identifier: LGPL-3-or-later
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, orig_filename=None):
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 if orig_filename is None:
39 self.binfile.name = "bytes"
40 else:
41 self.binfile.name = orig_filename
42 self.assembly = '' # noo disassemble number fiiive
43 print("binary", self.binfile)
44 elif isinstance(instructions, str): # filename
45 # read instructions into a BytesIO to avoid "too many open files"
46 with open(instructions, "rb") as f:
47 b = f.read()
48 self.binfile = BytesIO(b)
49 self.assembly = '' # noo disassemble number fiiive
50 print("program", self.binfile)
51 else:
52 if isinstance(instructions, list):
53 instructions = '\n'.join(instructions)
54 self.assembly = instructions + '\n' # plus final newline
55 self._assemble()
56 self._instructions = list(self._get_instructions())
57
58 def __enter__(self):
59 return self
60
61 def __exit__(self, type, value, traceback):
62 self.close()
63
64 def _get_binary(self, elffile):
65 with tempfile.NamedTemporaryFile(suffix=".bin") as binfile:
66 args = [cmds['objcopy'],
67 "-O", "binary",
68 "-I", self.endian_fmt,
69 elffile.name,
70 binfile.name]
71 subprocess.check_output(args)
72 # copy over to persistent binfile (BytesIO)
73 self.binfile = BytesIO()
74 self.binfile.write(binfile.read())
75 self.binfile.seek(0)
76
77 def _link(self, ofile):
78 with tempfile.NamedTemporaryFile(suffix=".elf") as elffile:
79 args = [cmds['ld'],
80 self.ld_fmt,
81 "-o", elffile.name,
82 "-T", memmap,
83 ofile.name]
84 subprocess.check_output(args)
85 self._get_binary(elffile)
86
87 def _assemble(self):
88 with tempfile.NamedTemporaryFile(suffix=".o") as outfile:
89 args = [cmds['as'],
90 '-mpower9',
91 '-mregnames',
92 self.obj_fmt,
93 "-o",
94 outfile.name]
95 with subprocess.Popen(args, stdin=subprocess.PIPE) as p:
96 p.communicate(self.assembly.encode('utf-8'))
97 if p.wait() != 0:
98 print("Error in program:")
99 print(self.assembly)
100 sys.exit(1)
101 self._link(outfile)
102
103 def _get_instructions(self):
104 while True:
105 data = self.binfile.read(4)
106 if not data:
107 break
108 yield struct.unpack('<I', data)[0] # unsigned int
109
110 def generate_instructions(self):
111 yield from self._instructions
112
113 def reset(self):
114 self.binfile.seek(0)
115
116 def size(self):
117 curpos = self.binfile.tell()
118 self.binfile.seek(0, 2) # Seek to end of file
119 size = self.binfile.tell()
120 self.binfile.seek(curpos, 0)
121 return size
122
123 def write_bin(self, fname):
124 self.reset()
125 data = self.binfile.read()
126 with open(fname, "wb") as f:
127 f.write(data)
128
129 def close(self):
130 self.binfile.close()
131
132 if __name__ == '__main__':
133 lst = ['addi 5, 0, 4660/2',
134 'mtcrf 255, 5+3',
135 'mfocrf 2, 1',
136 'addi r2, 3, 1',
137 'attn',
138 ]
139 lst = ["addi 9, 0, 0x10", # i = 16
140 "addi 9,9,-1", # i = i - 1
141 "cmpi 2,1,9,12", # compare 9 to value 12, store in CR2
142 "bc 4,10,-8", # branch if CR2 "test was != 12"
143 'attn',
144 ]
145
146 with Program(lst, False) as p:
147 for instruction in p.generate_instructions():
148 print (hex(instruction))
149 p.write_bin("/tmp/test.bin")