From d8da78d97f340ddb9f44790ef537a72d4a75760a Mon Sep 17 00:00:00 2001 From: Aleksandr Danilov Date: Fri, 28 Feb 2025 17:49:13 +0100 Subject: [PATCH 1/2] The object structure generator prototype --- py/dml/dmlc.py | 2 + py/dml/info_backend.py | 100 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/py/dml/dmlc.py b/py/dml/dmlc.py index 2da67323e..4a1ddf05d 100644 --- a/py/dml/dmlc.py +++ b/py/dml/dmlc.py @@ -721,6 +721,8 @@ def main(argv): dev, dml_version, outputbase + '.g') logtime("g") + dml.info_backend.generate_json(dev, outputbase + '.json') + if not logging.failure: # report WREF for broken unused parameters. But just ignore it # if there's already a hard error somewhere, because if the diff --git a/py/dml/info_backend.py b/py/dml/info_backend.py index 95dff3c89..c5f41d551 100644 --- a/py/dml/info_backend.py +++ b/py/dml/info_backend.py @@ -182,3 +182,103 @@ def generate(device, filename): classname = param_str_fixup(device, 'classname', '-') with XMLWriter(filename) as outfile: dev_info(outfile, device, classname) + +import json +from dml.types import * +from . import crep +from .expr import mkLit +from .expr_util import * +from .structure import get_attr_name + +def gen_attribute(indent, node, port, prefix): + d = {} + d['name'] = get_attr_name(prefix, node) + if param_defined(node, 'desc'): + d['desc'] = param_str(node, 'desc') + if param_defined(node, 'documentation'): + d['documentation'] = param_str(node, 'documentation') + if param_defined(node, 'limitations'): + d['limitations'] = param_str(node, 'limitations') + if node.get_component('type') != None and param_defined(node, 'type'): + d['type'] = param_str(node, 'type') # not correct + if node.get_component('type_desc') != None and param_defined(node, 'type_desc'): + d['type_desc'] = param_str(node, 'type_desc') + return d + +def gen_interface(indent, node): + i = {} + i['name'] = param_str(node, 'name') + "_interface" + i['required'] = param_bool(node, 'required') + return i + +def gen_connect(indent, node, port, prefix): + d = gen_attribute(indent, node, port, prefix) + i = [] + children = sorted(node.get_components(), key=lambda o: o.name or '') + for child in children: + if child.objtype == 'interface': + i.append(gen_interface(indent, child)) + if i: + d['interface'] = i + return d + +def gen_implement(indent, node): + d = {} + d['name'] = param_str(node, 'name') + "_interface" + if param_defined(node, 'desc'): + d['desc'] = param_str(node, 'desc') + if param_defined(node, 'documentation'): + d['documentation'] = param_str(node, 'documentation') + if param_defined(node, 'limitations'): + d['limitations'] = param_str(node, 'limitations') + return d + +def gen_objects(indent, node, port=None, dimsizes=(), prefix='', loopvars=()): + + if node.objtype in {'parameter', 'method', 'session', 'saved', 'hook', + 'register', 'event'}: + return + + if node.objtype == 'attribute': + return gen_attribute(indent, node, port, prefix) + if node.objtype == 'connect': + return gen_connect(indent, node, port, prefix) + if node.objtype == 'implement': + return gen_implement(indent, node) + + # Registration order is undefined but has significance, so + # register attributes of subobjects in an order that is deterministic, + # platform-independent, and unaffected by adding or removing objects. + if node.objtype == 'group': + prefix += crep.cname(node) + '_' + for _ in node.arraylens(): + loopvars += (mkLit(None, '_i' + str(len(loopvars) + 1), + TInt(32, False)),) + dimsizes += node.arraylens() + elif node.objtype in {'device', 'bank', 'port', 'subdevice'}: + if node.objtype in {'bank', 'port', 'subdevice'} and ( + # anonymous bank + dml.globals.dml_version != (1, 2) or node.name != None): + port = node + else: + raise ICE(node, f"unknown object type {node.objtype}") + + d = {} + d['name'] = param_str(node, 'name') + children = sorted(node.get_components(), key=lambda o: o.name or '') + for child in children: + cd = gen_objects(indent + " ", child, port, dimsizes, prefix, loopvars) + if cd: + l = [] + if child.objtype in d.keys(): + l = d[child.objtype] + l.append(cd) + d[child.objtype] = l + + return d + + +def generate_json(device, filename): + json_data = gen_objects("", device) + with open(filename, mode="w", encoding="utf-8") as write_file: + json.dump(json_data, write_file, sort_keys=False, indent=2, separators=(',', ': ')) From 18e1487e8ad5e476ed653dded9539832b78fabf7 Mon Sep 17 00:00:00 2001 From: Aleksandr Danilov Date: Thu, 10 Apr 2025 08:30:09 +0200 Subject: [PATCH 2/2] Add a config file --- py/dml/info_backend.py | 168 +++++++++++++++++++++++++++++++---------- 1 file changed, 129 insertions(+), 39 deletions(-) diff --git a/py/dml/info_backend.py b/py/dml/info_backend.py index c5f41d551..62c99897b 100644 --- a/py/dml/info_backend.py +++ b/py/dml/info_backend.py @@ -189,62 +189,70 @@ def generate(device, filename): from .expr import mkLit from .expr_util import * from .structure import get_attr_name +import os +import sys -def gen_attribute(indent, node, port, prefix): + +def gen_params(config, node, type): d = {} - d['name'] = get_attr_name(prefix, node) - if param_defined(node, 'desc'): - d['desc'] = param_str(node, 'desc') - if param_defined(node, 'documentation'): - d['documentation'] = param_str(node, 'documentation') - if param_defined(node, 'limitations'): - d['limitations'] = param_str(node, 'limitations') - if node.get_component('type') != None and param_defined(node, 'type'): - d['type'] = param_str(node, 'type') # not correct - if node.get_component('type_desc') != None and param_defined(node, 'type_desc'): - d['type_desc'] = param_str(node, 'type_desc') + for a in config[type]: + p = a['param'] + if node.get_component(p) != None and param_defined(node, p): + # not sure about types, maybe param_expr() is the best options + if p == "init_val": + a = param_expr(node, p) + d[p] = str(a) + continue + type = a['type'] + if type == "str": + d[p] = param_str(node, p) + elif type == "bool": + d[p] = param_bool(node, p) + elif type == "int": + d[p] = param_int(node, p) + return d + +def gen_attribute(config, node, port, prefix): + d = gen_params(config, node, 'attribute') + d['name'] = param_str(node, 'name') + d['full_name'] = get_attr_name(prefix, node) return d -def gen_interface(indent, node): - i = {} - i['name'] = param_str(node, 'name') + "_interface" - i['required'] = param_bool(node, 'required') - return i +def gen_interface(config, node): + d = gen_params(config, node, 'interface') + d['name'] = param_str(node, 'name') + return d -def gen_connect(indent, node, port, prefix): - d = gen_attribute(indent, node, port, prefix) +def gen_connect(config, node, port, prefix): + d = gen_params(config, node, 'connect') + d['name'] = param_str(node, 'name') + d['full_name'] = get_attr_name(prefix, node) i = [] children = sorted(node.get_components(), key=lambda o: o.name or '') for child in children: if child.objtype == 'interface': - i.append(gen_interface(indent, child)) + i.append(gen_interface(config, child)) if i: d['interface'] = i return d -def gen_implement(indent, node): - d = {} - d['name'] = param_str(node, 'name') + "_interface" - if param_defined(node, 'desc'): - d['desc'] = param_str(node, 'desc') - if param_defined(node, 'documentation'): - d['documentation'] = param_str(node, 'documentation') - if param_defined(node, 'limitations'): - d['limitations'] = param_str(node, 'limitations') +def gen_implement(config, node): + d = gen_params(config, node, 'implement') + d['name'] = param_str(node, 'name') return d -def gen_objects(indent, node, port=None, dimsizes=(), prefix='', loopvars=()): +def gen_objects(config, node, port=None, dimsizes=(), prefix='', loopvars=()): - if node.objtype in {'parameter', 'method', 'session', 'saved', 'hook', - 'register', 'event'}: + if node.objtype in {'parameter', 'method', 'session', 'saved', + 'hook', 'register', 'event'}: return if node.objtype == 'attribute': - return gen_attribute(indent, node, port, prefix) + return gen_attribute(config, node, port, prefix) if node.objtype == 'connect': - return gen_connect(indent, node, port, prefix) + return gen_connect(config, node, port, prefix) if node.objtype == 'implement': - return gen_implement(indent, node) + return gen_implement(config, node) # Registration order is undefined but has significance, so # register attributes of subobjects in an order that is deterministic, @@ -267,7 +275,7 @@ def gen_objects(indent, node, port=None, dimsizes=(), prefix='', loopvars=()): d['name'] = param_str(node, 'name') children = sorted(node.get_components(), key=lambda o: o.name or '') for child in children: - cd = gen_objects(indent + " ", child, port, dimsizes, prefix, loopvars) + cd = gen_objects(config, child, port, dimsizes, prefix, loopvars) if cd: l = [] if child.objtype in d.keys(): @@ -278,7 +286,89 @@ def gen_objects(indent, node, port=None, dimsizes=(), prefix='', loopvars=()): return d -def generate_json(device, filename): - json_data = gen_objects("", device) +def load_config(filename): + script_directory = os.path.dirname(os.path.abspath(sys.argv[0])) + print(script_directory) + with open(filename) as config_file: + d = json.loads(config_file) + config_file.close() + + +def save_objects(filename, data): with open(filename, mode="w", encoding="utf-8") as write_file: - json.dump(json_data, write_file, sort_keys=False, indent=2, separators=(',', ': ')) + json.dump(data, write_file, sort_keys=False, indent=2, separators=(',', ': ')) + write_file.close() + +default_config = { + "attribute": [ + { + "param": "desc", + "type": "str" + }, + { + "param": "documentation", + "type": "str" + }, + { + "param": "limitations", + "type": "str" + }, + { + "param": "type", + "type": "str" + }, + { + "param": "internal", + "type": "bool" + }, + { + "param": "init_val", + "type": "str" + } + ], + "interface": [ + { + "param": "required", + "type": "bool" + } + ], + "implement": [ + { + "param": "desc", + "type": "str" + }, + { + "param": "documentation", + "type": "str" + }, + { + "param": "limitations", + "type": "str" + } + ], + "connect": [ + { + "param": "desc", + "type": "str" + }, + { + "param": "documentation", + "type": "str" + }, + { + "param": "limitations", + "type": "str" + }, + { + "param": "type", + "type": "str" + } + ], +} + +def generate_json(device, filename): +#TODO add an user config file option +# config = load_config(".json") + config = default_config + data = gen_objects(config, device) + save_objects(filename, data)