Fixed problem in DeviceSettings::strParam, returned wrong string
[avr-sim.git] / src / DeviceSettings.cpp
bloba11df674fd9154f0a2bd7638846bde6e454c0278
1 /*
2 * avr-sim: An atmel AVR simulator
3 * Copyright (C) 2008 Tom Haber
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "DeviceSettings.h"
20 #include "Format.h"
21 #include "Device.h"
22 #include "Util.h"
24 #ifdef _WIN32
25 # include <io.h>
26 # include <direct.h>
27 # define WIN32_LEAN_AND_MEAN
28 # include <windows.h>
29 #else
30 # include <unistd.h>
31 # include <dirent.h>
32 #endif
34 #include <iostream>
35 #include <cstring>
36 #include <libxml/parser.h>
37 #include <libxml/tree.h>
38 #include <libxml/debugXML.h>
40 #define SETTINGS_DIR "./devices/"
42 #ifdef _WIN32
43 const char separatorChar = '\\';
44 #else
45 const char separatorChar = '/';
46 #endif
49 * The amount of separating white space.
51 #define SPACING 3
54 * The longest possible name of a device.
56 #define MAX_DEVICE_LENGTH 14
58 namespace avr {
60 void DeviceSettings::listAll(unsigned int lineLength /*= 80*/) {
61 unsigned int cols = lineLength / (MAX_DEVICE_LENGTH + SPACING);
63 int count = 0;
65 #ifdef _WIN32
66 std::string filter = SETTINGS_DIR;
67 if( filter[filter.length() - 1] != separatorChar )
68 filter += File::separatorChar;
69 filter += '*';
71 _finddata_t fileinfo;
72 long h = _findfirst(filter.c_str(), &fileinfo);
73 if( h != -1 ) {
74 while( true ) {
75 const char *name = fileinfo.name;
76 #else
77 DIR *dir = opendir(SETTINGS_DIR);
78 if (dir == 0)
79 return;
81 struct dirent *dp;
82 while ( (dp = readdir(dir)) != 0) {
83 const char *name = dp->d_name;
84 #endif
86 if( (strcmp(name,".") != 0) && (strcmp(name,"..") != 0) ) {
87 int col = count++ % cols;
88 if( col == 0 ) std::cout << std::endl;
90 int nameLength = strlen(name);
91 std::cout << name;
93 for(int ws = nameLength; ws < MAX_DEVICE_LENGTH; ++ws)
94 std::cout << ' ';
97 #ifdef _WIN32
98 if( _findnext(h,&fileinfo) != 0 )
99 break;
101 _findclose(h);
103 #else
105 closedir(dir);
106 #endif
108 std::cout << std::endl;
111 class XmlHandle {
112 public:
113 XmlHandle(const char *filename) {
115 * this initialize the library and check potential ABI mismatches
116 * between the version it was compiled for and the actual shared
117 * library used.
119 LIBXML_TEST_VERSION
121 int flags = XML_PARSE_DTDATTR | /* default DTD attributes */
122 XML_PARSE_NOENT | /* substitute entities */
123 XML_PARSE_DTDVALID; /* validate with the DTD */
125 /*parse the file and get the DOM */
126 doc = xmlReadFile(filename, NULL, flags);
128 if (doc == 0)
129 throw ParseException( util::format("Unable to open %s") % filename );
132 ~XmlHandle() {
133 /*free the document */
134 xmlFreeDoc(doc);
137 * Cleanup function for the XML library.
139 xmlCleanupParser();
142 operator xmlDocPtr() {
143 return doc;
146 private:
147 xmlDocPtr doc;
150 bool hasAttribute(xmlNode *node, const char *name) {
151 return xmlGetNoNsProp(node, reinterpret_cast<const xmlChar*>(name)) != 0;
154 char *getAttribute(xmlNode *node, const char *name, bool required = false) {
155 char *result = reinterpret_cast<char*>(xmlGetNoNsProp(
156 node, reinterpret_cast<const xmlChar*>(name)));
157 if( required && (result == 0) )
158 throw ParseException(
159 util::format("Expected an attribute %s on node %s") % name % node->name );
161 return result;
164 int getIntAttribute(xmlNode *node, const char *name, int base = 10, bool required = false) {
165 xmlChar *result = xmlGetNoNsProp(node,
166 reinterpret_cast<const xmlChar*>(name));
168 int ret = 0;
169 if( result != 0 ) {
170 char *str = reinterpret_cast<char*>(result);
171 if( str[0] == '$' ) { base = 16; str++; }// Switch base
172 ret = strtoul( str, 0, base);
173 xmlFree( result );
174 } else if( required ) {
175 throw ParseException(
176 util::format("Expected an attribute %s on node %s") % name % node->name );
179 return ret;
182 int getIntAttributeDef(xmlNode *node, const char *name, int def = 0, int base = 10) {
183 xmlChar *result = xmlGetNoNsProp(node,
184 reinterpret_cast<const xmlChar*>(name));
186 int ret = 0;
187 if( result != 0 ) {
188 ret = strtoul( reinterpret_cast<char*>(result), 0, base);
189 xmlFree( result );
190 } else {
191 ret = def;
194 return ret;
197 void freeAttribute(char *attr) {
198 xmlFree( reinterpret_cast<xmlChar*>(attr) );
201 bool compare(const xmlChar *a, const char *b) {
202 return strcmp( reinterpret_cast<const char*>(a), b ) == 0;
205 HardwareSettings::HardwareSettings(XmlHandle & doc, _xmlNode *node)
206 : doc(doc), node(node) {
208 params = 0;
209 reg = 0;
210 for(xmlNode *n = node->children; n != 0; n = n->next) {
211 if( n->type == XML_ELEMENT_NODE ) {
212 if( (params == 0) && compare(n->name, "params") )
213 params = n;
214 else if( (reg == 0) && compare(n->name, "registers") )
215 reg = n->children;
219 while( (reg != 0) && (reg->type != XML_ELEMENT_NODE) )
220 reg = reg->next;
223 _xmlNode *HardwareSettings::findParam(const char *name, bool required) const {
224 for(xmlNode *n = params->children; n != 0; n = n->next) {
225 if( n->type == XML_ELEMENT_NODE ) {
226 xmlChar *result = xmlGetNoNsProp(n,
227 reinterpret_cast<const xmlChar*>("name"));
228 if( compare(result, name) ) {
229 xmlFree(result);
230 return n;
233 xmlFree(result);
237 if( required ) {
238 char *hwname = getAttribute(node, "class", true);
239 std::string className = hwname;
240 freeAttribute(hwname);
242 throw ParseException(
243 util::format("Expected parameter %s on module %s") % name % className );
246 return 0;
249 int HardwareSettings::intParam(const char *name, int base /*= 10*/) const {
250 xmlNode *node = findParam(name);
251 return getIntAttribute(node, "value", base, true);
254 int HardwareSettings::intParamDef(const char *name,
255 int def /*=0*/, int base /*= 10*/) const {
257 xmlNode *node = findParam(name, false);
258 if( node == 0 )
259 return def;
261 return getIntAttributeDef(node, "value", def, base);
264 std::string HardwareSettings::strParam(const char *name) const {
265 xmlNode *node = findParam(name);
266 char *s = getAttribute(node, "value", true);
267 std::string str = s;
268 freeAttribute(s);
269 return str;
272 bool HardwareSettings::getBinding(std::string & name, std::string & binding) {
273 if( reg == 0 )
274 return false;
276 char *s;
277 s = getAttribute(reg, "name", true);
278 name = s;
279 freeAttribute(s);
281 s = getAttribute(reg, "bind", true);
282 binding = s;
283 freeAttribute(s);
285 do {
286 reg = reg->next;
287 } while( (reg != 0) && (reg->type != XML_ELEMENT_NODE) );
288 return true;
291 void DeviceSettings::parseMemory(Device *dev, xmlNode *memory) {
292 unsigned int ioSpaceSize = 0;
293 unsigned int flashSize = 0;
294 unsigned int pageSize = 0;
295 unsigned int sramSize = 0;
296 unsigned int pcSize = 2;
297 unsigned int stackMask = 0xffff;
299 for(xmlNode *node = memory->children; node != 0; node = node->next) {
300 if( node->type == XML_ELEMENT_NODE ) {
301 if( compare(node->name, "stack") ) {
302 stackMask = getIntAttribute(node, "mask", 16, true);
305 unsigned int *size = 0;
306 if( compare(node->name, "flash") ) {
307 size = &flashSize;
308 pageSize = getIntAttributeDef(node, "page", 128, 10);
309 } else if( compare(node->name, "sram") )
310 size = &sramSize;
311 else if( compare(node->name, "pc") )
312 size = &pcSize;
313 else if( compare(node->name, "iospace") ) {
314 if( ! hasAttribute(node, "size") ) {
315 int start = getIntAttribute(node, "start", 16, true);
316 int stop = getIntAttribute(node, "stop", 16, true);
317 ioSpaceSize = stop - start + 1;
318 } else {
319 size = &ioSpaceSize;
323 if( size != 0 )
324 *size = getIntAttribute(node, "size", 10, true);
328 #ifdef DEBUG
329 std::cout << "ioSpaceSize = " << ioSpaceSize << std::endl;
330 std::cout << "flashSize = " << flashSize << std::endl;
331 std::cout << "pageSize = " << pageSize << std::endl;
332 std::cout << "sramSize = " << sramSize << std::endl;
333 std::cout << "pcSize = " << pcSize << std::endl;
334 std::cout << "stackMask = " << stackMask << std::endl;
335 #endif
337 dev->buildCore(ioSpaceSize, sramSize, flashSize, pageSize, stackMask, pcSize);
340 void DeviceSettings::parseRegisters(Device *dev, xmlNode *registers) {
341 for(xmlNode *node = registers->children; node != 0; node = node->next) {
342 if( node->type == XML_ELEMENT_NODE ) {
343 char *n = getAttribute(node, "name", true);
344 unsigned int address = getIntAttribute(node, "address", 16, true);
345 unsigned char initial = getIntAttributeDef(node, "initial", 0, 16);
346 dev->addIOReg(address, std::string(n), initial);
347 #ifdef DEBUG
348 std::cout << "Adding register "<< n
349 << " at address "<< std::hex << address << std::dec
350 << ", initial value = "
351 << std::hex << (int)initial << std::dec
352 << std::endl;
353 #endif
355 freeAttribute(n);
360 void DeviceSettings::parseInterrupts(Device *dev, xmlNode *interrupts) {
361 for(xmlNode *node = interrupts->children; node != 0; node = node->next) {
362 if( node->type == XML_ELEMENT_NODE ) {
363 unsigned int vector = getIntAttribute(node, "vector", 10, true);
364 unsigned int address = getIntAttribute(node, "address", 16, true);
365 char *name = getAttribute(node, "name", true);
367 dev->addInterrupt(vector - 1, address, name);
368 #ifdef DEBUG
369 std::cout << "Adding interrupt "<< vector
370 << " at address "<< std::hex << address << std::dec
371 << ", name = " << name
372 << std::endl;
373 #endif
375 freeAttribute(name);
380 void DeviceSettings::parseHardware(Device *dev, XmlHandle & doc, xmlNode *hardware) {
381 for(xmlNode *node = hardware->children; node != 0; node = node->next) {
382 if( node->type == XML_ELEMENT_NODE ) {
383 char *hwname = getAttribute(node, "class", true);
384 HardwareSettings hws( doc, node );
385 dev->buildHardware( hwname, hws );
386 freeAttribute(hwname);
391 void DeviceSettings::parsePackage(Device *dev, xmlNode *package) {
392 unsigned int numPins = getIntAttribute(package, "pins", 10, true);
393 for(xmlNode *node = package->children; node != 0; node = node->next) {
394 if( node->type == XML_ELEMENT_NODE ) {
395 char *n = getAttribute(node, "name", true);
396 unsigned int id = getIntAttribute(node, "id", 10, true);
397 if( id > numPins )
398 throw ParseException(
399 util::format("Pin %d (%s) goes beyond number of pins (%d)")
400 % id % n % numPins );
402 if( dev->getPin(id) != 0 )
403 throw ParseException(
404 util::format("Pin %d (%s) already exists") % id % n );
406 dev->addPin(id, n, numPins);
407 freeAttribute(n);
412 void DeviceSettings::parsePackages(Device *dev, const char *pkgname, xmlNode *packages) {
413 bool found = false;
414 for(xmlNode *node = packages->children; node != 0 && ! found; node = node->next) {
415 if( node->type == XML_ELEMENT_NODE ) {
416 if( pkgname == 0 ) { // Just go the first one
417 found = true;
418 } else {
419 char *name = getAttribute(node, "name", true);
420 found = strcasecmp(name, pkgname) == 0;
421 freeAttribute(name);
424 if( found )
425 parsePackage(dev, node);
429 if( ! found )
430 throw ParseException(
431 util::format("Requested package %s not found") % pkgname );
434 void DeviceSettings::load(Device *dev, const char *devicename) {
435 const char *package = strchr(devicename, ':');
436 if( package != 0 )
437 package++;
439 std::string filename( SETTINGS_DIR);
440 if( package != 0 )
441 filename += std::string(devicename, package - devicename - 1);
442 else
443 filename += devicename;
445 XmlHandle doc(filename.c_str() );
447 //xmlDebugDumpDocument(stdout, doc);
449 /*Get the root element node */
450 xmlNode *root = xmlDocGetRootElement(doc);
451 for(xmlNode *node = root->children; node != 0; node = node->next) {
452 if( node->type == XML_ELEMENT_NODE ) {
453 if( compare(node->name, "memory") )
454 parseMemory(dev, node);
456 if( compare(node->name, "ioregisters") )
457 parseRegisters(dev, node);
459 if( compare(node->name, "interrupts") )
460 parseInterrupts(dev, node);
462 if( compare(node->name, "hardware") )
463 parseHardware(dev, doc, node);
465 if( compare(node->name, "packages") )
466 parsePackages(dev, package, node);