* CMake build infrastructure The squashed commit that builds and packages releases for the SIMH simulator suite with CMake, version 3.14 or newer. See README-CMake.md for documentation.
158 lines
6.1 KiB
Python
158 lines
6.1 KiB
Python
import pprint
|
|
|
|
import simgen.parse_makefile as SPM
|
|
import simgen.basic_simulator as SBS
|
|
import simgen.vax_simulators as VAXen
|
|
import simgen.utils as SU
|
|
|
|
## Special variables that should __not__ expand into their definitions:
|
|
_special_vars = frozenset(['DISPLAYL',
|
|
'DISPLAYVT',
|
|
'DISPLAY340',
|
|
'DISPLAYNG',
|
|
'DISPLAYIII'])
|
|
|
|
## Map simulator name to its class, for special cases
|
|
_special_simulators = {
|
|
"besm6": SBS.BESM6Simulator,
|
|
"i650": SBS.IBM650Simulator,
|
|
"ibm1130": SBS.IBM1130Simulator,
|
|
"pdp10-ka": SBS.KA10Simulator,
|
|
"vax": VAXen.VAXSimulator,
|
|
"vax730": VAXen.BasicVAXSimulator
|
|
}
|
|
|
|
ignored_display_macros = {
|
|
'DISPLAYVT': ['${DISPLAYD}/vt11.c'],
|
|
'DISPLAY340': ['${DISPLAYD}/type340.c'],
|
|
'DISPLAYNG': ['${DISPLAYD}/ng.c'],
|
|
'DISPLAYIII': ['${DISPLAYD}/iii.c']
|
|
}
|
|
|
|
def get_simulator_ctor(name):
|
|
"""Return the class object for special case simulators, otherwise
|
|
return the base 'SIMHBasicSimulator'
|
|
"""
|
|
return _special_simulators.get(name) or SBS.SIMHBasicSimulator
|
|
|
|
|
|
class SimCollection:
|
|
"""A collection of simulators.
|
|
"""
|
|
def __init__(self, dir_macro):
|
|
self.source_macros = {}
|
|
self.macro_uses = {}
|
|
self.simulators = {}
|
|
|
|
def get_simulator(self, name, dir_macro, _dir_path, test_name, buildrom):
|
|
sim = self.simulators.get(name)
|
|
if sim is None:
|
|
sim = (get_simulator_ctor(name))(name, dir_macro, test_name, buildrom)
|
|
self.simulators[name] = sim
|
|
return sim
|
|
|
|
def add_source_macro(self, macro, macro_def, sim):
|
|
if macro not in self.source_macros:
|
|
self.source_macros[macro] = macro_def
|
|
|
|
used = self.macro_uses.get(macro)
|
|
if used is None:
|
|
self.macro_uses[macro] = []
|
|
used = self.macro_uses[macro]
|
|
used.append(sim)
|
|
|
|
def get_simulator_vars(self, debug=0):
|
|
simvars = set()
|
|
ignored = set(self.source_macros.keys())
|
|
for macval in self.source_macros.values():
|
|
## This could be replaced by a functools.reduce()
|
|
for val in macval:
|
|
simvars = simvars.union(set(SPM.extract_variables(val)))
|
|
|
|
for sim in self.simulators.values():
|
|
simvars = simvars.union(sim.get_source_vars().union(sim.get_include_vars()))
|
|
|
|
simvars = simvars.difference(ignored).difference(_special_vars)
|
|
SU.emit_debug(debug, 2, 'simvars {0}'.format(simvars))
|
|
return simvars
|
|
|
|
def write_simulators(self, stream, debug=0, test_label='default'):
|
|
## Emit source macros
|
|
dontexpand = set([smac for smac, uses in self.macro_uses.items() if smac not in ignored_display_macros and len(uses) > 1])
|
|
SU.emit_debug(debug, 2, "{0}: dontexpand {1}".format(self.__class__.__name__, dontexpand))
|
|
|
|
if len(dontexpand) > 0:
|
|
smac_sorted = list(dontexpand)
|
|
smac_sorted.sort()
|
|
for smac in smac_sorted:
|
|
stream.write('\n\n')
|
|
stream.write('set({0}\n'.format(smac))
|
|
stream.write('\n'.join([' ' * 4 + f for f in self.source_macros[smac]]))
|
|
stream.write(')')
|
|
stream.write('\n\n')
|
|
|
|
## Emit the simulators
|
|
simnames = list(self.simulators.keys())
|
|
simnames.sort()
|
|
SU.emit_debug(debug, 2, "{0}: Writing {1}".format(self.__class__.__name__, simnames))
|
|
for simname in simnames:
|
|
sim = self.simulators[simname]
|
|
|
|
## Patch up the simulator source lists, expanding macros that aren't
|
|
## in the macro sources:
|
|
sim.sources = self.expand_sources(sim.sources, dontexpand, debug)
|
|
|
|
stream.write('\n')
|
|
sim.write_simulator(stream, 0, test_label)
|
|
|
|
def write_unit_tests(self, stream, debug=0, test_label='default'):
|
|
dontexpand = set([smac for smac, uses in self.macro_uses.items() if len(uses) > 1])
|
|
|
|
simnames = list(self.simulators.keys())
|
|
simnames.sort()
|
|
SU.emit_debug(debug, 2, "{0}: Writing {1}".format(self.__class__.__name__, simnames))
|
|
for simname in simnames:
|
|
sim = self.simulators[simname]
|
|
|
|
## Patch up the simulator source lists, expanding macros that aren't
|
|
## in the macro sources:
|
|
sim.sources = self.expand_sources(sim.sources, dontexpand, debug)
|
|
sim.write_unit_test(stream, 0, test_label)
|
|
|
|
def expand_sources(self, srcs, dontexpand, debug=0):
|
|
updated_srcs = []
|
|
for src in srcs:
|
|
SU.emit_debug(debug, 2, "{0}: Source {1}".format(self.__class__.__name__, src))
|
|
m = SPM._var_rx.match(src)
|
|
if m and m[1] not in dontexpand.union(_special_vars):
|
|
SU.emit_debug(debug, 2, "{0}: Expanding {1}".format(self.__class__.__name__, m[1]))
|
|
varexp = self.source_macros.get(m[1])
|
|
if varexp is not None:
|
|
updated_srcs.extend(self.source_macros[m[1]])
|
|
else:
|
|
print('!! Could not expand {0}'.format(m[1]))
|
|
else:
|
|
updated_srcs.append(src)
|
|
|
|
if updated_srcs == srcs:
|
|
return srcs
|
|
else:
|
|
return self.expand_sources(updated_srcs, dontexpand, debug)
|
|
|
|
def __len__(self):
|
|
return len(self.simulators)
|
|
|
|
if '_dispatch' in pprint.PrettyPrinter.__dict__:
|
|
def simcoll_pprinter(pprinter, simcoll, stream, indent, allowance, context, level):
|
|
cls = simcoll.__class__
|
|
stream.write(cls.__name__ + '(')
|
|
indent += len(cls.__name__) + 1
|
|
pprinter._format(simcoll.source_macros, stream, indent, allowance + 2, context, level)
|
|
stream.write(',\n' + ' ' * indent)
|
|
uses_dict = dict([(sim, len(uses)) for (sim, uses) in simcoll.macro_uses.items()])
|
|
pprinter._format(uses_dict, stream, indent, allowance + 2, context, level)
|
|
stream.write(',\n' + ' ' * indent)
|
|
pprinter._format(simcoll.simulators, stream, indent, allowance + 2, context, level)
|
|
stream.write(')')
|
|
|
|
pprint.PrettyPrinter._dispatch[SimCollection.__repr__] = simcoll_pprinter
|