arch_xml.c
/*
Copyright Universite de Versailles Saint-Quentin en Yvelines 2009
AUTHORS: Sebastien Briais, Sid Touati
This file is part of GDD.
GDD is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
GDD is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with GDD. If not, see
<http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include "util.h"
#include "opcode.h"
#include "arch.h"
#include "arch_xml.h"
/** Include xml utilities functions */
#include "xmlutil.h"
typedef struct {
GDD_Arch *arch; // arch being built
GDD_Opcode *op; // current opcode
int error;
} BuildCtxt;
static void beginElement(void *user_data, const xmlChar *name, const xmlChar **attrs) {
BuildCtxt *ctxt = (BuildCtxt *)user_data;
if(ctxt->error) {
return;
}
int i;
if(xmlStrEqual(name, (xmlChar *)"arch")) {
i = findAttr("version", attrs);
int version = atoi_xml(attrs[i]);
if(version != 1) {
fprintf(stderr,"wrong arch version: %d\n",version);
ctxt->error = TRUE;
return;
}
} else if(xmlStrEqual(name, (xmlChar *)"regtype")) {
i = findAttr("type", attrs);
char *type = (char *)attrs[i];
i = findAttr("number", attrs);
int nb = atoi_xml(attrs[i]);
safe_call(GDD_arch_add_regtype(ctxt->arch, type, nb));
} else if(xmlStrEqual(name, (xmlChar *)"instruction")) {
i = findAttr("opcode", attrs);
char *mnemo = (char *)attrs[i];
if(strcmp(mnemo, "dummy") == 0) {
fprintf(stderr, "error: dummy is a reserved mnemonic\n");
exit(1);
}
i = findAttr("latency", attrs);
int latency = atoi_xml(attrs[i]);
i = findAttr("delta_r", attrs);
int delta_r = atoi_xml(attrs[i]);
GDD_Opcode *op = GDD_opcode_create(mnemo, latency, delta_r);
ctxt->op = op;
safe_call(GDD_arch_add_opcode(ctxt->arch, op));
} else if(xmlStrEqual(name, (xmlChar *)"write")) {
i = findAttr("regtype", attrs);
char *type = (char *)attrs[i];
i = findAttr("delta_w", attrs);
int delta_w = atoi_xml(attrs[i]);
GDD_Opcode *op = ctxt->op;
if(op == NULL) {
ctxt->error = TRUE;
return;
}
safe_call(GDD_opcode_extend_delta_w(op, type, delta_w));
} else {
fprintf(stderr,"ignoring %s tag\n", name);
}
}
/** Parse an architecture from an XML file stream.
@param[in] stream = file stream
@return the parsed architecture */
GDD_Arch *GDD_arch_of_xml_stream(FILE *stream) {
BuildCtxt ctxt;
ctxt.arch = GDD_arch_create();
ctxt.op = NULL;
ctxt.error = FALSE;
xmlParserCtxtPtr xmlctxt;
xmlSAXHandler sax = { 0 };
// initialise SAX callbacks
sax.startElement = beginElement;
// create SAX context
if ((xmlctxt = xmlCreateIOParserCtxt(&sax, &ctxt, sax_read, sax_close, stream, XML_CHAR_ENCODING_NONE)) == NULL) {
fprintf(stderr,"error while creating SAX context\n");
GDD_arch_delete(ctxt.arch);
return NULL;
}
/* safe_call(GDD_arch_add_opcode(ctxt.arch, GDD_opcode_create("dummy",0,0))); */
// parse stream
if(xmlParseDocument(xmlctxt) != 0) {
ctxt.error = TRUE;
}
//
xmlFreeParserCtxt(xmlctxt);
// fprint_arch(stderr, ctxt.arch);
if(ctxt.error) {
fprintf(stderr,"error while parsing arch file\n");
GDD_arch_delete(ctxt.arch);
return NULL;
}
return ctxt.arch;
}
/** Parse an architecture from a file.
@param[in] filename = filename
@return the parsed architecture */
GDD_Arch *GDD_arch_of_xml_file(const char *filename) {
FILE *f = fopen(filename, "r");
if(f == NULL) {
fprintf(stderr,"error while opening %s\n", filename);
return NULL;
}
GDD_Arch *arch = GDD_arch_of_xml_stream(f);
fclose(f);
return arch;
}