Merge branch 'master' of git.libre-soc.org:soc
[soc.git] / src / soc / 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
19 filedir = os.path.dirname(os.path.realpath(__file__))
20 memmap = os.path.join(filedir, "memmap")
21
22
23 class Program:
24 def __init__(self, instructions, bigendian):
25 self.bigendian = bigendian
26 if self.bigendian:
27 self.endian_fmt = "elf64-big"
28 self.obj_fmt = "-be"
29 self.ld_fmt = "-EB"
30 else:
31 self.ld_fmt = "-EL"
32 self.endian_fmt = "elf64-little"
33 self.obj_fmt = "-le"
34
35 if isinstance(instructions, bytes): # actual bytes
36 self.binfile = BytesIO(instructions)
37 self.binfile.name = "assembly"
38 self.assembly = '' # noo disassemble number fiiive
39 elif isinstance(instructions, str): # filename
40 # read instructions into a BytesIO to avoid "too many open files"
41 with open(instructions, "rb") as f:
42 b = f.read()
43 self.binfile = BytesIO(b)
44 self.assembly = '' # noo disassemble number fiiive
45 print("program", self.binfile)
46 else:
47 if isinstance(instructions, list):
48 instructions = '\n'.join(instructions)
49 self.assembly = instructions + '\n' # plus final newline
50 self._assemble()
51 self._instructions = list(self._get_instructions())
52
53 def __enter__(self):
54 return self
55
56 def __exit__(self, type, value, traceback):
57 self.close()
58
59 def _get_binary(self, elffile):
60 self.binfile = tempfile.NamedTemporaryFile(suffix=".bin")
61 args = ["powerpc64-linux-gnu-objcopy",
62 "-O", "binary",
63 "-I", self.endian_fmt,
64 elffile.name,
65 self.binfile.name]
66 subprocess.check_output(args)
67
68 def _link(self, ofile):
69 with tempfile.NamedTemporaryFile(suffix=".elf") as elffile:
70 args = ["powerpc64-linux-gnu-ld",
71 self.ld_fmt,
72 "-o", elffile.name,
73 "-T", memmap,
74 ofile.name]
75 subprocess.check_output(args)
76 self._get_binary(elffile)
77
78 def _assemble(self):
79 with tempfile.NamedTemporaryFile(suffix=".o") as outfile:
80 args = ["powerpc64-linux-gnu-as",
81 '-mpower9',
82 self.obj_fmt,
83 "-o",
84 outfile.name]
85 p = subprocess.Popen(args, stdin=subprocess.PIPE)
86 p.communicate(self.assembly.encode('utf-8'))
87 if p.wait() != 0:
88 print("Error in program:")
89 print(self.assembly)
90 sys.exit(1)
91 self._link(outfile)
92
93 def _get_instructions(self):
94 while True:
95 data = self.binfile.read(4)
96 if not data:
97 break
98 yield struct.unpack('<I', data)[0] # unsigned int
99
100 def generate_instructions(self):
101 yield from self._instructions
102
103 def reset(self):
104 self.binfile.seek(0)
105
106 def size(self):
107 curpos = self.binfile.tell()
108 self.binfile.seek(0, 2) # Seek to end of file
109 size = self.binfile.tell()
110 self.binfile.seek(curpos, 0)
111 return size
112
113 def close(self):
114 self.binfile.close()