blob: 121bc42cf3170da1ee80644463862dee09346eea [file] [log] [blame]
Rich Lanebdd8e292013-12-06 17:37:39 -08001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
28"""
29Code generation
30
31These functions extract data from the IR and render templates with it.
32"""
33
34from collections import namedtuple
35from itertools import groupby
Rich Lanedef2e512013-12-15 15:54:02 -080036from StringIO import StringIO
Rich Lanebdd8e292013-12-06 17:37:39 -080037import template_utils
Rich Lanef51062b2014-02-24 23:08:26 -080038from generic_utils import chunks
Rich Lanebdd8e292013-12-06 17:37:39 -080039import loxi_globals
40import loxi_ir.ir as ir
41import util
Rich Lanece2e4642013-12-15 12:05:45 -080042import c_code_gen
Rich Lane8c4c23f2013-12-15 13:22:13 -080043import c_gen.of_g_legacy as of_g
Rich Lanecce961d2013-12-15 14:20:42 -080044import c_gen.type_maps as type_maps
Rich Lanec0e20ff2013-12-15 23:40:31 -080045import c_gen.c_type_maps as c_type_maps
Rich Lanebdd8e292013-12-06 17:37:39 -080046
Rich Lanef51062b2014-02-24 23:08:26 -080047CLASS_CHUNK_SIZE = 32
48
Rich Lane22811f52013-12-15 15:28:03 -080049PushWireTypesData = namedtuple('PushWireTypesData',
Rich Lanebdd8e292013-12-06 17:37:39 -080050 ['class_name', 'versioned_type_members'])
51PushWireTypesMember = namedtuple('PushWireTypesMember',
52 ['name', 'offset', 'length', 'value'])
53
Rich Lane22811f52013-12-15 15:28:03 -080054def push_wire_types_data(uclass):
55 if uclass.virtual or not uclass.has_type_members:
56 return None
Rich Lanebdd8e292013-12-06 17:37:39 -080057
Rich Lane22811f52013-12-15 15:28:03 -080058 # Generate a dict of version -> list of PushWireTypesMember
59 type_members_by_version = {}
60 for version, ofclass in sorted(uclass.version_classes.items()):
61 pwtms = []
62 for m in ofclass.members:
63 if isinstance(m, ir.OFTypeMember):
64 if m.name == "version" and m.value == version.wire_version:
65 # Special case for version
66 pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, "obj->version"))
67 else:
Rich Laned0c58712013-12-18 10:02:47 -080068 pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, hex(m.value)))
Rich Lane22811f52013-12-15 15:28:03 -080069 type_members_by_version[version] = pwtms
Rich Lanebdd8e292013-12-06 17:37:39 -080070
Rich Lane22811f52013-12-15 15:28:03 -080071 # Merge versions with identical type members
72 all_versions = sorted(type_members_by_version.keys())
73 versioned_type_members = []
74 for pwtms, versions in groupby(all_versions, type_members_by_version.get):
75 versioned_type_members.append((pwtms, list(versions)))
Rich Lanebdd8e292013-12-06 17:37:39 -080076
Rich Lane22811f52013-12-15 15:28:03 -080077 return PushWireTypesData(
78 class_name=uclass.name,
79 versioned_type_members=versioned_type_members)
Rich Lanece2e4642013-12-15 12:05:45 -080080
Rich Lanef51062b2014-02-24 23:08:26 -080081# Output multiple LOCI classes into each C file. This reduces the overhead of
82# parsing header files, which takes longer than compiling the actual code
83# for many classes. It also reduces the compiled code size.
Rich Lanece2e4642013-12-15 12:05:45 -080084def generate_classes(install_dir):
Rich Lanef51062b2014-02-24 23:08:26 -080085 for i, chunk in enumerate(chunks(loxi_globals.unified.classes, CLASS_CHUNK_SIZE)):
86 with template_utils.open_output(install_dir, "loci/src/class%02d.c" % i) as out:
87 for uclass in chunk:
88 util.render_template(out, "class.c",
89 push_wire_types_data=push_wire_types_data(uclass))
90 # Append legacy generated code
91 c_code_gen.gen_new_function_definitions(out, uclass.name)
92 c_code_gen.gen_accessor_definitions(out, uclass.name)
Rich Lane8c4c23f2013-12-15 13:22:13 -080093
Rich Lane573d2b22013-12-15 13:31:27 -080094# TODO remove header classes and use the corresponding class instead
95def generate_header_classes(install_dir):
96 for cls in of_g.standard_class_order:
97 if cls.find("_header") < 0:
98 continue
99 with template_utils.open_output(install_dir, "loci/src/%s.c" % cls) as out:
Rich Lane22811f52013-12-15 15:28:03 -0800100 util.render_template(out, "class.c",
101 push_wire_types_data=None)
Rich Lane573d2b22013-12-15 13:31:27 -0800102 # Append legacy generated code
103 c_code_gen.gen_new_function_definitions(out, cls)
104 c_code_gen.gen_accessor_definitions(out, cls)
105
Rich Lanedef2e512013-12-15 15:54:02 -0800106def generate_classes_header(install_dir):
107 # Collect legacy code
108 tmp = StringIO()
109 c_code_gen.gen_struct_typedefs(tmp)
110 c_code_gen.gen_new_function_declarations(tmp)
111 c_code_gen.gen_accessor_declarations(tmp)
Rich Lanedef2e512013-12-15 15:54:02 -0800112 c_code_gen.gen_generics(tmp)
113
114 with template_utils.open_output(install_dir, "loci/inc/loci/loci_classes.h") as out:
115 util.render_template(out, "loci_classes.h",
116 legacy_code=tmp.getvalue())
117
Rich Lane8c4c23f2013-12-15 13:22:13 -0800118def generate_lists(install_dir):
119 for cls in of_g.ordered_list_objects:
120 with template_utils.open_output(install_dir, "loci/src/%s.c" % cls) as out:
Rich Lane22811f52013-12-15 15:28:03 -0800121 util.render_template(out, "class.c",
122 push_wire_types_data=None)
Rich Lane8c4c23f2013-12-15 13:22:13 -0800123 # Append legacy generated code
Rich Laneb604e332013-12-15 13:23:51 -0800124 c_code_gen.gen_new_function_definitions(out, cls)
Rich Lane8c4c23f2013-12-15 13:22:13 -0800125 c_code_gen.gen_list_accessors(out, cls)
Rich Lane8a822732013-12-15 14:06:32 -0800126
127def generate_strings(install_dir):
128 object_id_strs = []
129 object_id_strs.append("of_object")
130 object_id_strs.extend(of_g.ordered_messages)
131 object_id_strs.extend(of_g.ordered_non_messages)
132 object_id_strs.extend(of_g.ordered_list_objects)
133 object_id_strs.extend(of_g.ordered_pseudo_objects)
134 object_id_strs.append("of_unknown_object")
135
136 with template_utils.open_output(install_dir, "loci/src/loci_strings.c") as out:
137 util.render_template(out, "loci_strings.c", object_id_strs=object_id_strs)
Rich Lanecce961d2013-12-15 14:20:42 -0800138
139def generate_init_map(install_dir):
140 with template_utils.open_output(install_dir, "loci/src/loci_init_map.c") as out:
141 util.render_template(out, "loci_init_map.c", classes=of_g.standard_class_order)
Rich Lanec0e20ff2013-12-15 23:40:31 -0800142
143def generate_type_maps(install_dir):
144 # Collect legacy code
145 tmp = StringIO()
146 c_type_maps.gen_type_to_obj_map_functions(tmp)
147 c_type_maps.gen_type_maps(tmp)
148 c_type_maps.gen_length_array(tmp)
149 c_type_maps.gen_extra_length_array(tmp)
150
151 with template_utils.open_output(install_dir, "loci/src/of_type_maps.c") as out:
152 util.render_template(out, "of_type_maps.c", legacy_code=tmp.getvalue())