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"
27 # define WIN32_LEAN_AND_MEAN
36 #include <libxml/parser.h>
37 #include <libxml/tree.h>
38 #include <libxml/debugXML.h>
40 #define SETTINGS_DIR "./devices/"
43 const char separatorChar
= '\\';
45 const char separatorChar
= '/';
49 * The amount of separating white space.
54 * The longest possible name of a device.
56 #define MAX_DEVICE_LENGTH 14
60 void DeviceSettings::listAll(unsigned int lineLength
/*= 80*/) {
61 unsigned int cols
= lineLength
/ (MAX_DEVICE_LENGTH
+ SPACING
);
66 std::string filter
= SETTINGS_DIR
;
67 if( filter
[filter
.length() - 1] != separatorChar
)
68 filter
+= File::separatorChar
;
72 long h
= _findfirst(filter
.c_str(), &fileinfo
);
75 const char *name
= fileinfo
.name
;
77 DIR *dir
= opendir(SETTINGS_DIR
);
82 while ( (dp
= readdir(dir
)) != 0) {
83 const char *name
= dp
->d_name
;
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
);
93 for(int ws
= nameLength
; ws
< MAX_DEVICE_LENGTH
; ++ws
)
98 if( _findnext(h
,&fileinfo
) != 0 )
108 std::cout
<< std::endl
;
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
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
);
129 throw ParseException( util::format("Unable to open %s") % filename
);
133 /*free the document */
137 * Cleanup function for the XML library.
142 operator xmlDocPtr() {
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
);
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
));
170 char *str
= reinterpret_cast<char*>(result
);
171 if( str
[0] == '$' ) { base
= 16; str
++; }// Switch base
172 ret
= strtoul( str
, 0, base
);
174 } else if( required
) {
175 throw ParseException(
176 util::format("Expected an attribute %s on node %s") % name
% node
->name
);
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
));
188 ret
= strtoul( reinterpret_cast<char*>(result
), 0, base
);
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
) {
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") )
214 else if( (reg
== 0) && compare(n
->name
, "registers") )
219 while( (reg
!= 0) && (reg
->type
!= XML_ELEMENT_NODE
) )
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
) ) {
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
);
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);
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);
272 bool HardwareSettings::getBinding(std::string
& name
, std::string
& binding
) {
277 s
= getAttribute(reg
, "name", true);
281 s
= getAttribute(reg
, "bind", true);
287 } while( (reg
!= 0) && (reg
->type
!= XML_ELEMENT_NODE
) );
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") ) {
308 pageSize
= getIntAttributeDef(node
, "page", 128, 10);
309 } else if( compare(node
->name
, "sram") )
311 else if( compare(node
->name
, "pc") )
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;
324 *size
= getIntAttribute(node
, "size", 10, true);
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
;
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
);
348 std::cout
<< "Adding register "<< n
349 << " at address "<< std::hex
<< address
<< std::dec
350 << ", initial value = "
351 << std::hex
<< (int)initial
<< std::dec
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
);
369 std::cout
<< "Adding interrupt "<< vector
370 << " at address "<< std::hex
<< address
<< std::dec
371 << ", name = " << 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);
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
);
412 void DeviceSettings::parsePackages(Device
*dev
, const char *pkgname
, xmlNode
*packages
) {
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
419 char *name
= getAttribute(node
, "name", true);
420 found
= strcasecmp(name
, pkgname
) == 0;
425 parsePackage(dev
, node
);
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
, ':');
439 std::string
filename( SETTINGS_DIR
);
441 filename
+= std::string(devicename
, package
- devicename
- 1);
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
);