Last active
March 24, 2019 21:23
-
-
Save duck2/02d001727a252de4a118ae63b680a11c to your computer and use it in GitHub Desktop.
draft for rr_graph.xml reader with SAX
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstring> | |
#include <fstream> | |
#include <iostream> | |
#include <unordered_map> | |
#include <stack> | |
#include <vector> | |
#include <libxml/parser.h> | |
#pragma pack(1) | |
typedef std::unordered_map<std::string, std::string> AttributeMap; | |
struct ChannelList { | |
int index; | |
int info; | |
}; | |
struct Channels { | |
int chan_width_max; | |
int x_min; | |
int y_min; | |
int x_max; | |
int y_max; | |
std::vector<ChannelList> x_list; | |
std::vector<ChannelList> y_list; | |
}; | |
enum SwitchType : char { | |
INVALID_SWITCH_TYPE, | |
MUX, | |
TRISTATE, | |
PASS_GATE, | |
SHORT, | |
BUFFER | |
}; | |
struct SwitchTiming { | |
float r; | |
float c_in; | |
float c_out; | |
float t_del; | |
}; | |
struct SwitchSizing { | |
float mux_trans_size; | |
float buf_size; | |
}; | |
struct Switch { | |
int id; | |
std::string name; | |
SwitchType type; | |
SwitchTiming timing; | |
SwitchSizing sizing; | |
}; | |
struct SegmentTiming { | |
float r_per_meter; | |
float c_per_meter; | |
}; | |
struct Segment { | |
int id; | |
std::string name; | |
SegmentTiming timing; | |
}; | |
enum PinType : char { | |
NONE, | |
OPEN, | |
OUTPUT, | |
INPUT | |
}; | |
struct Pin { | |
int ptc; | |
std::string name; | |
}; | |
struct PinClass { | |
PinType type; | |
std::vector<Pin> pins; | |
}; | |
struct BlockType { | |
int id; | |
std::string name; | |
int width; | |
int height; | |
std::vector<PinClass> pin_classes; | |
}; | |
struct GridLoc { | |
int x; | |
int y; | |
int block_type_id; | |
int width_offset; | |
int height_offset; | |
}; | |
enum NodeType : char { | |
INVALID_NODE_TYPE, | |
CHANX, | |
CHANY, | |
SOURCE, | |
SINK, | |
OPIN, | |
IPIN | |
}; | |
enum NodeDirection : char { | |
NO_DIR, | |
INC_DIR, | |
DEC_DIR, | |
BI_DIR | |
}; | |
enum NodeSide : char { | |
NO_SIDE, | |
LEFT, | |
RIGHT, | |
TOP, | |
BOTTOM | |
}; | |
struct NodeTiming { | |
float r; | |
float c; | |
}; | |
struct NodeLoc { | |
short x_low; | |
short y_low; | |
short x_high; | |
short y_high; | |
NodeSide side; | |
int ptc; | |
}; | |
struct NodeMetadata { | |
char *name = NULL; | |
char *value = NULL; | |
int x_offset; | |
int y_offset; | |
int z_offset; | |
void set_name(const std::string& n){ | |
name = (char *)malloc(n.length()+1); | |
strcpy(name, n.c_str()); | |
} | |
void set_value(const std::string& v){ | |
value = (char *)malloc(v.length()+1); | |
strcpy(value, v.c_str()); | |
} | |
}; | |
struct NodeSegment { | |
int segment_id = -1; | |
}; | |
struct RrNode { | |
NodeType type; | |
NodeDirection direction; | |
int id; | |
int capacity; | |
NodeSegment segment; | |
NodeTiming timing; | |
NodeLoc loc; | |
std::vector<NodeMetadata> *metadata = NULL; | |
void alloc_metadata(){ | |
metadata = new std::vector<NodeMetadata>; | |
metadata->reserve(1); | |
} | |
}; | |
struct RrEdge { | |
int src_node; | |
int sink_node; | |
int switch_id; | |
std::vector<NodeMetadata> *metadata = NULL; | |
void alloc_metadata(){ | |
metadata = new std::vector<NodeMetadata>; | |
metadata->reserve(1); | |
} | |
}; | |
struct RrGraph { | |
std::string tool_version; | |
std::string tool_comment; | |
Channels channels; | |
std::vector<Switch> switches; | |
std::vector<Segment> segments; | |
std::vector<BlockType> block_types; | |
std::vector<GridLoc> grid; | |
std::vector<RrNode> rr_nodes; | |
std::vector<RrEdge> rr_edges; | |
~RrGraph(){ | |
for(auto n : rr_nodes){ | |
if(n.metadata){ | |
for(auto m : *n.metadata){ | |
free(m.name); | |
free(m.value); | |
} | |
delete n.metadata; | |
} | |
} | |
for(auto e: rr_edges){ | |
if(e.metadata){ | |
for(auto m : *e.metadata){ | |
free(m.name); | |
free(m.value); | |
} | |
delete e.metadata; | |
} | |
} | |
} | |
}; | |
class RRSaxReader { | |
public: | |
RRSaxReader(); | |
~RRSaxReader(); | |
std::stack <const char *> parser_stack; | |
RrGraph rr_graph = {}; | |
/* <meta> tags are found in both nodes and edges, and they are deeply nested. | |
* We hold pointers to know where to push new <meta> tags and which MetaData | |
* struct to fill when a text node arrives. | |
* Note that these pointers can be invalidated when the vectors holding them do | |
* a reallocation, but text nodes we are interested in come right after their associated | |
* elements, and nothing should be push_back'ed between the tag and the text. */ | |
std::vector<NodeMetadata> *current_metadata; | |
NodeMetadata *current_meta; | |
/* <pin> tags also carry a text node */ | |
Pin *current_pin; | |
xmlSAXHandler sax_handler = {}; | |
void load_rr_file(const char *name); | |
void on_start_element(const char *name, const char **attrs); | |
void on_end_element(const char *name); | |
void on_characters(const char *text, int ch); | |
void consume_channels(AttributeMap& attrs); | |
void consume_switches(AttributeMap& attrs); | |
void consume_segments(AttributeMap& attrs); | |
void consume_block_types(AttributeMap& attrs); | |
void consume_grid(AttributeMap& attrs); | |
void consume_rr_nodes(AttributeMap& attrs); | |
void consume_rr_edges(AttributeMap& attrs); | |
void consume_channel(AttributeMap& attrs); | |
void consume_x_list(AttributeMap& attrs); | |
void consume_y_list(AttributeMap& attrs); | |
void consume_switch(AttributeMap& attrs); | |
void consume_switch_timing(AttributeMap& attrs); | |
void consume_switch_sizing(AttributeMap& attrs); | |
void consume_segment(AttributeMap& attrs); | |
void consume_segment_timing(AttributeMap& attrs); | |
void consume_block_type(AttributeMap& attrs); | |
void consume_pin_class(AttributeMap& attrs); | |
void consume_pin(AttributeMap& attrs); | |
void consume_grid_loc(AttributeMap& attrs); | |
void consume_node(AttributeMap& attrs); | |
void consume_node_loc(AttributeMap& attrs); | |
void consume_node_timing(AttributeMap& attrs); | |
void consume_node_segment(AttributeMap& attrs); | |
void consume_node_metadata(AttributeMap& attrs); | |
void consume_meta(AttributeMap& attrs); | |
void consume_edge(AttributeMap& attrs); | |
void consume_edge_metadata(AttributeMap& attrs); | |
friend struct RRSaxCallback; | |
}; | |
/* The callback functions have to be static. If we make them static in the | |
* class, they don't know which object to access. So we hide the pointer to the RRSaxReader object | |
* in the parser context, unpack it in the static function and call the object's callback. | |
* While we are at it, we can also cast xmlChars to chars because they create a bit of trouble. */ | |
struct RRSaxCallback { | |
static void on_start_element(void *ctx, const xmlChar *name, const xmlChar **attrs){ | |
auto _ctx = (_xmlParserCtxt *) ctx; | |
auto parser = (RRSaxReader *)_ctx->_private; | |
parser->on_start_element((const char *)name, (const char **)attrs); | |
} | |
static void on_end_element(void *ctx, const xmlChar *name){ | |
auto _ctx = (_xmlParserCtxt *) ctx; | |
auto parser = (RRSaxReader *)_ctx->_private; | |
parser->on_end_element((const char *)name); | |
} | |
static void on_characters(void *ctx, const xmlChar *ch, int len){ | |
auto _ctx = (_xmlParserCtxt *) ctx; | |
auto parser = (RRSaxReader *)_ctx->_private; | |
parser->on_characters((const char *)ch, len); | |
} | |
}; | |
RRSaxReader::RRSaxReader(){ | |
sax_handler.startElement = RRSaxCallback::on_start_element; | |
sax_handler.endElement = RRSaxCallback::on_end_element; | |
sax_handler.characters = RRSaxCallback::on_characters; | |
} | |
RRSaxReader::~RRSaxReader(){} | |
void RRSaxReader::load_rr_file(const char* read_rr_graph_name) { | |
/* parse the file */ | |
std::ifstream F(read_rr_graph_name); | |
char buffer[1048576]; | |
RRSaxReader parser; | |
auto ctx = xmlCreatePushParserCtxt(&sax_handler, NULL, NULL, 0, read_rr_graph_name); | |
/* Store the pointer to this in the parser context, | |
* so that the static callbacks find their way to this object. */ | |
ctx->_private = (void *) this; | |
do { | |
F.read(buffer, 1048575); | |
xmlParseChunk(ctx, buffer, F.gcount(), 0); | |
} while(F); | |
xmlParseChunk(ctx, buffer, 0, 1); | |
xmlFreeParserCtxt(ctx); | |
} | |
static std::unordered_map<std::string, std::unordered_map<std::string, void(RRSaxReader::*)(AttributeMap&)>> parse_table = { | |
{"rr_graph", { | |
{"channels", &RRSaxReader::consume_channels}, | |
{"switches", &RRSaxReader::consume_switches}, | |
{"segments", &RRSaxReader::consume_segments}, | |
{"block_types", &RRSaxReader::consume_block_types}, | |
{"grid", &RRSaxReader::consume_grid}, | |
{"rr_nodes", &RRSaxReader::consume_rr_nodes}, | |
{"rr_edges", &RRSaxReader::consume_rr_edges} | |
}}, | |
{"channels", { | |
{"channel", &RRSaxReader::consume_channel}, | |
{"x_list", &RRSaxReader::consume_x_list}, | |
{"y_list", &RRSaxReader::consume_y_list}, | |
}}, | |
{"switches", { | |
{"switch", &RRSaxReader::consume_switch}, | |
}}, | |
{"switch", { | |
{"timing", &RRSaxReader::consume_switch_timing}, | |
{"sizing", &RRSaxReader::consume_switch_sizing}, | |
}}, | |
{"segments", { | |
{"segment", &RRSaxReader::consume_segment}, | |
}}, | |
{"segment", { | |
{"timing", &RRSaxReader::consume_segment_timing}, | |
}}, | |
{"block_types", { | |
{"block_type", &RRSaxReader::consume_block_type}, | |
}}, | |
{"block_type", { | |
{"pin_class", &RRSaxReader::consume_pin_class}, | |
}}, | |
{"pin_class", { | |
{"pin", &RRSaxReader::consume_pin}, | |
}}, | |
{"grid", { | |
{"grid_loc", &RRSaxReader::consume_grid_loc}, | |
}}, | |
{"rr_nodes", { | |
{"node", &RRSaxReader::consume_node}, | |
}}, | |
{"rr_edges", { | |
{"edge", &RRSaxReader::consume_edge}, | |
}}, | |
{"node", { | |
{"loc", &RRSaxReader::consume_node_loc}, | |
{"timing", &RRSaxReader::consume_node_timing}, | |
{"segment", &RRSaxReader::consume_node_segment}, | |
{"metadata", &RRSaxReader::consume_node_metadata}, | |
}}, | |
{"edge", { | |
{"metadata", &RRSaxReader::consume_edge_metadata}, | |
}}, | |
{"metadata", { | |
{"meta", &RRSaxReader::consume_meta}, | |
}}, | |
}; | |
void RRSaxReader::on_start_element(const char *name, const char **attrs){ | |
if(parser_stack.empty()){ | |
if(strcmp(name, "rr_graph") == 0){ | |
parser_stack.push("rr_graph"); | |
} else throw std::runtime_error("no <rr_graph> tag found"); | |
return; | |
} | |
auto top = parser_stack.top(); | |
parser_stack.push(name); | |
/* Convert attributes to hashtable first. */ | |
AttributeMap map; | |
for(const char **c = attrs; c && *c; c += 2){ | |
map[*c] = *(c+1); | |
} | |
/* Look up callback function from current and previous tags. */ | |
auto fn = parse_table[top][name]; | |
if(fn != NULL){ | |
(this->*fn)(map); | |
return; | |
} | |
std::cout << "Unexpected " << name << " after " << top << std::endl; | |
return; | |
} | |
void RRSaxReader::on_end_element(const char *name){ | |
parser_stack.pop(); | |
} | |
/* A text node should only occur inside a <meta> or a <pin> tag. */ | |
void RRSaxReader::on_characters(const char *ch, int len){ | |
auto top = parser_stack.top(); | |
if(top == "meta"){ | |
//std::cout << "filling in meta " << text << " addr = " << current_meta << std::endl; | |
current_meta->set_value(ch); | |
} else if(top == "pin"){ | |
//std::cout << "filling in pin " << text << " addr=" << current_pin << std::endl; | |
current_pin->name = ch; | |
} | |
} | |
void RRSaxReader::consume_channels(AttributeMap& attrs){ | |
return; | |
} | |
void RRSaxReader::consume_switches(AttributeMap& attrs){ | |
return; | |
} | |
void RRSaxReader::consume_segments(AttributeMap& attrs){ | |
return; | |
} | |
void RRSaxReader::consume_block_types(AttributeMap& attrs){ | |
return; | |
} | |
void RRSaxReader::consume_grid(AttributeMap& attrs){ | |
return; | |
} | |
void RRSaxReader::consume_rr_nodes(AttributeMap& attrs){ | |
return; | |
} | |
void RRSaxReader::consume_rr_edges(AttributeMap& attrs){ | |
return; | |
} | |
void RRSaxReader::consume_channel(AttributeMap& attrs){ | |
rr_graph.channels.chan_width_max = std::stoi(attrs["chan_width_max"]); | |
rr_graph.channels.x_min = std::stoi(attrs["x_min"]); | |
rr_graph.channels.y_min = std::stoi(attrs["y_min"]); | |
rr_graph.channels.x_max = std::stoi(attrs["x_max"]); | |
rr_graph.channels.y_max = std::stoi(attrs["y_max"]); | |
} | |
void RRSaxReader::consume_x_list(AttributeMap& attrs){ | |
ChannelList list; | |
list.index = std::stoi(attrs["index"]); | |
list.info = std::stoi(attrs["info"]); | |
rr_graph.channels.x_list.push_back(list); | |
} | |
void RRSaxReader::consume_y_list(AttributeMap& attrs){ | |
ChannelList list; | |
list.index = std::stoi(attrs["index"]); | |
list.info = std::stoi(attrs["info"]); | |
rr_graph.channels.y_list.push_back(list); | |
} | |
void RRSaxReader::consume_switch(AttributeMap& attrs){ | |
Switch sw; | |
sw.id = std::stoi(attrs["id"]); | |
sw.name = attrs["name"]; | |
if(attrs["type"] == "mux") sw.type = MUX; | |
else if(attrs["type"] == "tristate") sw.type = TRISTATE; | |
else if(attrs["type"] == "pass_gate") sw.type = PASS_GATE; | |
else if(attrs["type"] == "short") sw.type = SHORT; | |
else if(attrs["type"] == "buffer") sw.type = BUFFER; | |
else sw.type = INVALID_SWITCH_TYPE; | |
rr_graph.switches.push_back(sw); | |
} | |
/* map's operator[] gives default value for nonexistent keys: | |
* http://www.cplusplus.com/reference/map/map/operator%5B%5D/ */ | |
void RRSaxReader::consume_switch_timing(AttributeMap& attrs){ | |
Switch& sw = rr_graph.switches.back(); | |
if(attrs["R"] != "") sw.timing.r = std::stof(attrs["R"]); | |
if(attrs["Cin"] != "") sw.timing.c_in = std::stof(attrs["Cin"]); | |
if(attrs["Cout"] != "") sw.timing.c_out = std::stof(attrs["Cout"]); | |
if(attrs["Tdel"] != "") sw.timing.t_del = std::stof(attrs["Tdel"]); | |
} | |
void RRSaxReader::consume_switch_sizing(AttributeMap& attrs){ | |
Switch& sw = rr_graph.switches.back(); | |
sw.sizing.mux_trans_size = std::stof(attrs["mux_trans_size"]); | |
sw.sizing.buf_size = std::stof(attrs["buf_size"]); | |
} | |
void RRSaxReader::consume_segment(AttributeMap& attrs){ | |
Segment seg; | |
seg.id = std::stoi(attrs["id"]); | |
seg.name = attrs["name"]; | |
rr_graph.segments.push_back(seg); | |
} | |
void RRSaxReader::consume_segment_timing(AttributeMap& attrs){ | |
Segment& seg = rr_graph.segments.back(); | |
if(attrs["R_per_meter"] != "") seg.timing.r_per_meter = std::stof(attrs["R_per_meter"]); | |
if(attrs["C_per_meter"] != "") seg.timing.c_per_meter = std::stof(attrs["C_per_meter"]); | |
} | |
void RRSaxReader::consume_block_type(AttributeMap& attrs){ | |
BlockType bt; | |
bt.id = std::stoi(attrs["id"]); | |
bt.name = attrs["name"]; | |
bt.width = std::stoi(attrs["width"]); | |
bt.height = std::stoi(attrs["height"]); | |
rr_graph.block_types.push_back(bt); | |
} | |
void RRSaxReader::consume_pin_class(AttributeMap& attrs){ | |
BlockType& bt = rr_graph.block_types.back(); | |
PinClass pc; | |
if(attrs["type"] == "open") pc.type = OPEN; | |
else if(attrs["type"] == "output") pc.type = OUTPUT; | |
else if(attrs["type"] == "input") pc.type = INPUT; | |
else pc.type = NONE; | |
bt.pin_classes.push_back(pc); | |
} | |
void RRSaxReader::consume_pin(AttributeMap& attrs){ | |
BlockType& bt = rr_graph.block_types.back(); | |
PinClass& pc = bt.pin_classes.back(); | |
Pin pin; | |
pin.ptc = std::stoi(attrs["ptc"]); | |
pc.pins.push_back(pin); | |
current_pin = &(pc.pins.back()); | |
} | |
void RRSaxReader::consume_grid_loc(AttributeMap& attrs){ | |
GridLoc gl; | |
gl.x = std::stoi(attrs["x"]); | |
gl.y = std::stoi(attrs["y"]); | |
gl.block_type_id = std::stoi(attrs["block_type_id"]); | |
gl.width_offset = std::stoi(attrs["width_offset"]); | |
gl.height_offset = std::stoi(attrs["height_offset"]); | |
rr_graph.grid.push_back(gl); | |
} | |
void RRSaxReader::consume_node(AttributeMap& attrs){ | |
RrNode node; | |
node.id = std::stoi(attrs["id"]); | |
if(attrs["type"] == "CHANX") node.type = CHANX; | |
else if(attrs["type"] == "CHANY") node.type = CHANY; | |
else if(attrs["type"] == "SOURCE") node.type = SOURCE; | |
else if(attrs["type"] == "SINK") node.type = SINK; | |
else if(attrs["type"] == "OPIN") node.type = OPIN; | |
else if(attrs["type"] == "IPIN") node.type = IPIN; | |
else node.type = INVALID_NODE_TYPE; | |
rr_graph.rr_nodes.push_back(node); | |
} | |
void RRSaxReader::consume_node_loc(AttributeMap& attrs){ | |
RrNode& node = rr_graph.rr_nodes.back(); | |
node.loc.x_low = std::stoi(attrs["xlow"]); | |
node.loc.y_low = std::stoi(attrs["ylow"]); | |
node.loc.x_high = std::stoi(attrs["xhigh"]); | |
node.loc.y_high = std::stoi(attrs["yhigh"]); | |
node.loc.ptc = std::stoi(attrs["ptc"]); | |
if(attrs["side"] == "LEFT") node.loc.side = LEFT; | |
else if(attrs["side"] == "RIGHT") node.loc.side = RIGHT; | |
else if(attrs["side"] == "TOP") node.loc.side = TOP; | |
else if(attrs["side"] == "BOTTOM") node.loc.side = BOTTOM; | |
else node.loc.side = NO_SIDE; | |
} | |
void RRSaxReader::consume_node_timing(AttributeMap& attrs){ | |
RrNode& node = rr_graph.rr_nodes.back(); | |
if(attrs["R"] != "") node.timing.r = std::stof(attrs["R"]); | |
if(attrs["C"] != "") node.timing.c = std::stof(attrs["C"]); | |
} | |
void RRSaxReader::consume_node_segment(AttributeMap& attrs){ | |
RrNode& node = rr_graph.rr_nodes.back(); | |
if(attrs["segment_id"] != "") node.segment.segment_id = std::stof(attrs["segment_id"]); | |
} | |
void RRSaxReader::consume_node_metadata(AttributeMap& attrs){ | |
RrNode& node = rr_graph.rr_nodes.back(); | |
node.alloc_metadata(); | |
current_metadata = node.metadata; | |
} | |
void RRSaxReader::consume_meta(AttributeMap& attrs){ | |
NodeMetadata md; | |
md.set_name(attrs["name"]); | |
if(attrs["x_offset"] != "") md.x_offset = std::stoi(attrs["x_offset"]); | |
if(attrs["y_offset"] != "") md.y_offset = std::stoi(attrs["y_offset"]); | |
if(attrs["z_offset"] != "") md.z_offset = std::stoi(attrs["z_offset"]); | |
(*current_metadata).push_back(md); | |
/* needed to read value */ | |
current_meta = &((*current_metadata).back()); | |
} | |
void RRSaxReader::consume_edge(AttributeMap& attrs){ | |
RrEdge edge; | |
edge.src_node = std::stoi(attrs["src_node"]); | |
edge.sink_node = std::stoi(attrs["sink_node"]); | |
edge.switch_id = std::stoi(attrs["switch_id"]); | |
rr_graph.rr_edges.push_back(edge); | |
} | |
void RRSaxReader::consume_edge_metadata(AttributeMap& attrs){ | |
RrEdge& edge = rr_graph.rr_edges.back(); | |
edge.alloc_metadata(); | |
current_metadata = edge.metadata; | |
} | |
int main(){ | |
RRSaxReader reader; | |
reader.load_rr_file("rr_graph_big.xml"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment