xml.hpp
Go to the documentation of this file.
1 /**********************************************************************
2  * xml.hpp -- Dumps the system model as the abstract XML+C format *
3  * *
4  * Authors: Hosein Attarzadeh (shan2@kth.se) *
5  * *
6  * Purpose: Dumps the structure and behavior of a system model *
7  * *
8  * Usage: This file is included automatically *
9  * *
10  * License: BSD3 *
11  *******************************************************************/
12 
13 #ifndef XML_HPP
14 #define XML_HPP
15 
25 #include <algorithm>
26 #include "rapidxml_print.hpp"
27 
28 #include "abssemantics.hpp"
29 
30 using namespace rapidxml;
31 using namespace boost;
32 
33 namespace ForSyDe
34 {
35 using namespace sc_core;
36 
37 // Some Helper Fuctions
39 void get_moc_and_pc(const std::string& kind, std::string& moc, std::string& pc)
40 {
41  moc = kind.substr(0, kind.find(':'));
42  pc = kind.substr(kind.rfind(':')+1, kind.length());
43 }
44 
46 
49 class XMLExport
50 {
51 public:
53  XMLExport(std::string path) : path(path)
54  {
55  // Allocate global names
56  const_name = (char*)"name";
57  const_leaf_process = (char*)"leaf_process";
58  const_composite_process = (char*)"composite_process";
59  const_component_name = (char*)"component_name";
60  const_process_network = (char*)"process_network";
61  const_process_constructor = (char*)"process_constructor";
62  const_argument = (char*)"argument";
63  const_value = (char*)"value";
64  const_moc = (char*)"moc";
65  const_type = (char*)"type";
66  const_sdf = (char*)"sdf";
67  const_ut = (char*)"ut";
68  const_sy = (char*)"sy";
69  const_dde = (char*)"dde";
70  const_dt = (char*)"dt";
71  const_ct = (char*)"ct";
72  const_mi = (char*)"mi";
73  const_port = (char*)"port";
74  const_port_dir = (char*)"port_dir";
75  const_direction = (char*)"direction";
76  const_in = (char*)"in";
77  const_out = (char*)"out";
78  const_signal = (char*)"signal";
79  const_source = (char*)"source";
80  const_source_port = (char*)"source_port";
81  const_target = (char*)"target";
82  const_target_port = (char*)"target_port";
83  const_bound_process = (char*)"bound_process";
84  const_bound_port = (char*)"bound_port";
85  }
86 
89  {
90  xml_doc.clear();
91  }
92 
94 
97  void traverse(sc_module* top)
98  {
99  // Initiate the XML file for this level of hierarchy
100  xml_node<>* pn_node = init(top);
101 
102  // Get the list of module children (ports and other processes)
103  std::vector<sc_object*> children = top->get_child_objects();
104 
105  // Take care of children objects
106  for (auto it=children.begin();it!=children.end();it++)
107  {
108  // Check if it is a module, a port, or something else
109  if (is_module(*it))
110  {
111  // Is it a leaf or a composite process?
112  if (is_leaf(*it)) // Leaf process
113  {
114  // Add it to the XML document
115  add_leaf_process(static_cast<ForSyDe::process*>(*it), pn_node);
116  }
117  else
118  { // Composite process
119  add_composite_process(static_cast<sc_module*>(*it), pn_node);
120  // Recursion step
121  XMLExport dumper(path);
122  dumper.traverse(static_cast<ForSyDe::process*>(*it));
123  }
124  }
125  else if (is_port(*it))
126  {
127  // TODO: determining port direction can be done in a better way
128  char* dir = (*it)->kind()==std::string("sc_fifo_in") ? const_in : const_out;
129  const char* bound_process = dynamic_cast<ForSyDe::introspective_port*>(*it)
130  -> bound_port -> get_parent_object() -> basename();
131  const char* bound_port = dynamic_cast<ForSyDe::introspective_port*>(*it)
132  -> bound_port -> basename();
133  add_port(dynamic_cast<ForSyDe::introspective_port*>(*it), dir, pn_node, bound_process, bound_port);
134  }
135  else if (is_signal(*it))
136  {
137  add_signal(dynamic_cast<ForSyDe::introspective_channel*>(*it), pn_node);
138  }
139  }
140  // Last, print the XML structure
141  // NOTE: Extract the composite process name based on the
142  // convention: "nameX" or "nameXX", where Xs are 0-9
143  std::string name_str(top->basename());
144  name_str = name_str.substr(0, name_str.find_last_not_of("0123456789")+1).c_str();
145  printXML(path + name_str + std::string(".xml"));
146 
147  }
148 
150 
152  xml_node<>* init(const sc_module* p)
153  {
154  // The top most node
155  xml_node<> *pn_node = xml_doc.allocate_node(node_element, const_process_network);
156  xml_doc.append_node(pn_node);
157  // NOTE: Extract the composite process name based on the
158  // convention: "nameX" or "nameXX", where Xs are 0-9
159  std::string name_str(p->basename());
160  char* xml_composite_name = xml_doc.allocate_string(
161  name_str.substr(0, name_str.find_last_not_of("0123456789")+1).c_str()
162  );
163  allocate_append_attribute(pn_node, const_name, xml_composite_name);
164 
165  return pn_node;
166  }
167 
169 
173  void printXML(std::string fileName)
174  {
175  std::ofstream outFile(fileName);
176  if (!outFile.is_open())
177  SC_REPORT_ERROR(fileName.c_str(), "file could not be opened to write the introspection output. Does the path exists?");
178  outFile << "<?xml version=\"1.0\" ?>" << std::endl;
179  outFile << "<!-- Automatically generated by ForSyDe -->" << std::endl;
180  outFile << "<!DOCTYPE process_network SYSTEM \"forsyde.dtd\" >" << std::endl;
181  outFile << xml_doc;
182  }
183 
186  {
187  // Determine the process consructor and the belonging MoC
188  std::string moc, pc;
189  get_moc_and_pc(p->forsyde_kind(), moc, pc);
190  char* xml_pc = xml_doc.allocate_string(pc.c_str());
191  char* moc_name;
192  if (moc=="SDF") moc_name = const_sdf;
193  else if (moc=="UT") moc_name = const_ut;
194  else if (moc=="SY") moc_name = const_sy;
195  else if (moc=="DDE") moc_name = const_dde;
196  else if (moc=="DT") moc_name = const_dt;
197  else if (moc=="CT") moc_name = const_ct;
198  else if (moc=="MI") moc_name = const_mi;
199  else
200  {
201  SC_REPORT_ERROR("XML Backend", "MoC could not be deduced from kind.");
202  return;
203  }
204 
205  // Add the process node
206  xml_node<> *p_node = allocate_append_node(pn_node, const_leaf_process);
207  allocate_append_attribute(p_node, const_name, p->basename());
208 
209  // Add the leaf process ports
210  add_leaf_process_ports(p, p_node);
211 
212  // Add the process constructor node
213  xml_node<> *pc_node = allocate_append_node(p_node, const_process_constructor);
214  allocate_append_attribute(pc_node, const_name, xml_pc);
215  allocate_append_attribute(pc_node, const_moc, moc_name);
216 
217  // Add arguments
218  for (auto it=p->arg_vec.begin();it!=p->arg_vec.end();it++)
219  {
220  xml_node<> *arg_node = allocate_append_node(pc_node, const_argument);
221  char* arg_name = xml_doc.allocate_string(std::get<0>(*it).c_str());
222  char* arg_val = xml_doc.allocate_string(std::get<1>(*it).c_str());
223  allocate_append_attribute(arg_node, const_name, arg_name);
224  allocate_append_attribute(arg_node, const_value, arg_val);
225  }
226  }
227 
230  {
231  for (auto it=p->boundInChans.begin();it!=p->boundInChans.end();it++)
232  add_port(dynamic_cast<ForSyDe::introspective_port*>((*it).port), const_in, pn_node);
233  for (auto it=p->boundOutChans.begin();it!=p->boundOutChans.end();it++)
234  add_port(dynamic_cast<ForSyDe::introspective_port*>((*it).port), const_out, pn_node);
235  }
236 
238  void add_composite_process(const sc_module* p, xml_node<>* pn_node)
239  {
240  xml_node<> *p_node = allocate_append_node(pn_node, const_composite_process);
241  allocate_append_attribute(p_node, const_name, p->basename());
242  // NOTE: Extract the composite process name based on the
243  // convention: "nameX" or "nameXX", where Xs are 0-9
244  std::string name_str(p->basename());
245  char* xml_composite_name = xml_doc.allocate_string(
246  name_str.substr(0, name_str.find_last_not_of("0123456789")+1).c_str()
247  );
248  allocate_append_attribute(p_node, const_component_name, xml_composite_name);
249  // Add port nodes
250  std::vector<sc_object*> children = p->get_child_objects();
251  std::for_each(children.begin(), children.end(), [&](sc_object* it)
252  {
253  if (is_port(it))
254  {
255  // TODO: determining port direction can be done in a better way
256  char* dir = it->kind()==std::string("sc_fifo_in") ? const_in : const_out;
257  add_port(dynamic_cast<ForSyDe::introspective_port*>(it), dir, p_node);
258  }
259  });
260  }
261 
263  void add_port(introspective_port* port, const char* dir, xml_node<>* pn_node,
264  const char* bound_process=NULL, const char* bound_port=NULL)
265  {
266  xml_node<> *p_node = allocate_append_node(pn_node, const_port);
267  if (port != NULL)
268  {
269  allocate_append_attribute(p_node, const_name, dynamic_cast<sc_object*>(port)->basename());
270  allocate_append_attribute(p_node, const_type, port->token_type());
271  allocate_append_attribute(p_node, const_direction, dir);
272  }
273  if (bound_process != NULL && bound_port != NULL)
274  {
275  allocate_append_attribute(p_node, const_bound_process, bound_process);
276  allocate_append_attribute(p_node, const_bound_port, bound_port);
277  }
278  }
279 
282  {
283  xml_node<> *sig_node = allocate_append_node(pn_node, const_signal);
284  allocate_append_attribute(sig_node, const_name, dynamic_cast<sc_object*>(sig)->basename());
285  char* moc_name;
286  if (sig->moc()=="SDF") moc_name = const_sdf;
287  else if (sig->moc()=="UT") moc_name = const_ut;
288  else if (sig->moc()=="SY") moc_name = const_sy;
289  else if (sig->moc()=="DDE") moc_name = const_dde;
290  else if (sig->moc()=="DT") moc_name = const_dt;
291  else if (sig->moc()=="CT") moc_name = const_ct;
292  else
293  {
294  SC_REPORT_ERROR("XML Backend", "MoC could not be deduced from kind.");
295  return;
296  }
297  allocate_append_attribute(sig_node, const_moc, moc_name);
298  allocate_append_attribute(sig_node, const_type, sig->token_type());
299  allocate_append_attribute(sig_node, const_source, sig->oport->get_parent_object()->basename());
300  allocate_append_attribute(sig_node, const_source_port, sig->oport->basename());
301  allocate_append_attribute(sig_node, const_target, sig->iport->get_parent_object()->basename());
302  allocate_append_attribute(sig_node, const_target_port, sig->iport->basename());
303  }
304 
306  inline bool is_leaf(sc_object* module)
307  {
308  return dynamic_cast<ForSyDe::process*>(module) != NULL;
309  }
310 
312  inline bool is_module(const sc_object* module)
313  {
314  return module->kind() == std::string("sc_module");
315  }
316 
318  inline bool is_port(sc_object* port)
319  {
320  return dynamic_cast<introspective_port*>(port) != NULL;
321  }
322 
324  inline bool is_signal(const sc_object* sig)
325  {
326  return sig->kind() == std::string("sc_fifo");
327  }
328 
329 private:
331  std::string path;
332 
334  xml_document<> xml_doc;
335 
337  char *const_name, *const_leaf_process, *const_composite_process,
338  *const_process_network, *const_process_constructor, *const_moc,
339  *const_type, *const_port,
340  *const_sdf, *const_ut, *const_sy, *const_dde, *const_dt, *const_ct, *const_mi,
341  *const_port_dir, *const_direction, *const_in, *const_out,
342  *const_signal, *const_component_name, *const_argument, *const_value,
343  *const_source, *const_source_port, *const_target, *const_target_port,
344  *const_bound_process, *const_bound_port;
345 
346  inline xml_node<>* allocate_append_node(xml_node<>* top, const char* name)
347  {
348  xml_node<>* node = xml_doc.allocate_node(node_element, name);
349  top->append_node(node);
350  return node;
351  }
352 
353  inline void allocate_append_attribute(xml_node<>* node, const char* attr_name, const char* attr_val)
354  {
355  xml_attribute<>* attr = xml_doc.allocate_attribute(attr_name, attr_val);
356  node->append_attribute(attr);
357  }
358 
359 };
360 
361 
362 
363 }
364 
365 #endif
virtual const char * token_type() const =0
Name of the tokens of the port.
sc_object * iport
Input port to which a channel is bound.
Definition: abssemantics.hpp:62
The namespace for ForSyDe.
Definition: abssemantics.hpp:30
A helper class used to provide introspective channels.
Definition: abssemantics.hpp:48
void append_attribute(xml_attribute< Ch > *attribute)
Definition: rapidxml.hpp:1217
~XMLExport()
The destructor makes sure all XML nodes are deallocated.
Definition: xml.hpp:88
bool is_signal(const sc_object *sig)
Check if the systemC object is a ForSyDe signal.
Definition: xml.hpp:324
void add_signal(introspective_channel *sig, xml_node<> *pn_node)
Add a ForSyDe signal.
Definition: xml.hpp:281
void printXML(std::string fileName)
The print method writes the XML file to the output.
Definition: xml.hpp:173
void add_leaf_process(const ForSyDe::process *p, xml_node<> *pn_node)
Add a leaf process.
Definition: xml.hpp:185
virtual const char * token_type() const =0
Name of the tokens in the channels.
void add_composite_process(const sc_module *p, xml_node<> *pn_node)
Add a composite process.
Definition: xml.hpp:238
sc_object * oport
Output port to which a channel is bound.
Definition: abssemantics.hpp:65
void add_leaf_process_ports(const ForSyDe::process *p, xml_node<> *pn_node)
Add the ports for a leaf process.
Definition: xml.hpp:229
void get_moc_and_pc(const std::string &kind, std::string &moc, std::string &pc)
Extracts the MoC and the process constructor name from a ForSyDe kind.
Definition: xml.hpp:39
xml_node * init(const sc_module *p)
The init member initiates the XML DOM and performs initial settings.
Definition: xml.hpp:152
bool is_leaf(sc_object *module)
Check if the systemC object is a leaf process.
Definition: xml.hpp:306
virtual std::string forsyde_kind() const =0
The ForSyDe process type represented by the current module.
Definition: rapidxml.hpp:138
Abstract class used to Export a system as an XML file.
Definition: xml.hpp:49
The process constructor which defines the abstract semantics of execution.
Definition: abssemantics.hpp:212
bool is_port(sc_object *port)
Check if the systemC object is port.
Definition: xml.hpp:318
void traverse(sc_module *top)
The traverse function requires the top ForSyDe process name.
Definition: xml.hpp:97
virtual std::string moc() const =0
To which MoC does the signal belong.
void append_node(xml_node< Ch > *child)
Definition: rapidxml.hpp:1097
A helper class used to provide introspective ports.
Definition: abssemantics.hpp:109
bool is_module(const sc_object *module)
Check if the systemC object is module.
Definition: xml.hpp:312
xml_node< Ch > * allocate_node(node_type type, const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0)
Definition: rapidxml.hpp:415
An element node. Name contains element name. Value contains text of first data node.
Definition: rapidxml.hpp:146
XMLExport(std::string path)
The constructor takes the gneration path.
Definition: xml.hpp:53
This file contains rapidxml printer implementation.
Definition: rapidxml.hpp:139
Definition: rapidxml.hpp:137
Definition: rapidxml.hpp:57
void add_port(introspective_port *port, const char *dir, xml_node<> *pn_node, const char *bound_process=NULL, const char *bound_port=NULL)
Add a port.
Definition: xml.hpp:263
The common abstract semantics for all MoCs.
xml_attribute< Ch > * allocate_attribute(const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0)
Definition: rapidxml.hpp:447