simh-testsetgenerator/cmake/simgen/sim_collection.py
B. Scott Michel 8b14bb69be
CMake build infrastructure II (#53)
* 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.
2023-05-17 20:18:42 -04:00

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