qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [CONFIGURATION METHOD] A proposal
@ 2008-11-28  0:55 Salvatore Lionetti
  2008-11-28  7:37 ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 1 reply; 2+ messages in thread
From: Salvatore Lionetti @ 2008-11-28  0:55 UTC (permalink / raw)
  To: qemu-devel

Hi,

i'm working a little on ppc405 emulation and.
Instead of
- overload method with many parameter,
- putting interface definition in the same implementation module,
- duplicate lot of code between similar board,

i've elaborated a first draft, compiled and working, of configuration component: see the comment on the head of file.

Thanks for eventually feedback (information, comment, proposal)

1,528d0
< /* Configuration object
<  * ====================
<  * 
<  * Every object:
<  * - is identified by a string (es '/walnut/cpu/mal/txeobisr')
<  * - is tagged with a type (es 'INT' 'STRING' 'PTR' 'FILE' 'CALLBACK')
<  * - have a value, which can be {set,get}ted.
<  * Es "/walnut/cpu/mal/txeobisr INT 0"
<  *
<  * Collection of objects is readed from a char* variable, 
<  * so can be acquired both from configuration file and code.
<  *
<  * Every sw entity can intercept a value set over an object.
<  * Co-relation take place in the context of set operation.
<  *
<  * As special case, sharing a pointer ex toward a variable,
<  * no code change is required after registering it.
<  *
<  * Ascii representation has some constrain:
<  * - start a line with a number of space equal to level number,
<  * - every object name have to start with '/'.
<  * - multivalue have to follow strictly this format: last/{a INT 0, b INT 1, ...}
<  * 
<  * Some example:
< # Some comment
< /cpu
<  # That can be inserted
<  /emac
<   # At any level
<   /txeobisr INT 0
<  /iic/eeprom/{address INT 0x56, image FILE pid.bin}
<  /serial
<   /serial0/{base PTR 0x300, intr INT 0}
<   /serial1/{base PTR 0x400, intr INT 1, filename STRING "tcp:..."}
<  *
<  * Common interface or inheritance relation should be supported
<  * Not in this release
<  * Some example:
<  *
< eeprom{address INT, image FILE}
<  
< /cpu_meta
<  /emac
<   /txeobisr INT 0
<  /iic/eeprom
< 
< /cpu0(cpu_meta)
< /cpu1(cpu_meta)
<  *
<  * Configuration is totally dinamic so assertion about missing definition of an object (es no value during get())
<  * take place only when needed, like pure virtual function call in C++.
<  */
< 
< #include <assert.h>
< #define TEST
< #ifndef TEST
< #include "qemu-common.h"
< #include "hw.h"
< #else
< #define qemu_malloc malloc 
< #include <string.h>
< #include <stdio.h>
< #include <fcntl.h>
< #include <malloc.h>
< #include <sys/mman.h>
< /* Configuration object is a 3-ple:
<  * "/name/of/object", type, value
<  * Every function return <0 on error.
<  */
< enum hw_conf_basicT {
< 	HW_CONF_NOTYPE,
< 	HW_CONF_INT,
< 	HW_CONF_STRING,
< 	HW_CONF_PTR,
< 	HW_CONF_FUNC,
< };
< #define HW_CONF_GET(name, val) hw_conf_get(name, (void**)&val)
< #define HW_CONF_SET(name, val) hw_conf_set(name, (void*)val)
< /* 0 let change happen, 1 deny current change (a voting alg) */
< typedef int (HWConf_corelateFunc)(void *opaque, const char* name, void* newv);
< 
< /* Return number of object successfully parsed. Value is only an opaque of type void* */
< int hw_conf_parsefrom(const char* str, int sz);
< int hw_conf_get(const char* name, void** val);
< int hw_conf_set(const char* name, void* val);
< void hw_conf_corelatewith(const char* str, HWConf_corelateFunc f, void* opaque);
< #endif
< struct hw_conf_corelateT {
< 	HWConf_corelateFunc* f;
< 	void* opaque;
< };
< struct hw_conf_nodeT {
< 	/* Three related */
< 	struct hw_conf_nodeT* nextH;
< 	struct hw_conf_nodeT* nextV;
< 	struct hw_conf_nodeT* prevV;
< 
< 	char* id;
< 	/* Data contents */
< 	enum hw_conf_basicT type;
< 	void* opaque;
< 
< 	/* Communique with the world */
< 	struct hw_conf_corelateT core[10];
< };
< 
< static struct hw_conf_nodeT hw_conf_root;
< static int hw_conf_haveroot = 0;
< 
< static void hw_conf_nodeinit(struct hw_conf_nodeT* n) {
< 	int l;
< 
< 	assert(n);
< 	n->nextH = n->nextV = n->prevV = NULL;
< 	n->id = NULL;
< 	for (l=0; l<sizeof(n->core)/sizeof(n->core[0]); l++) {
< 		n->core[l].f = NULL;
< 		n->core[l].opaque = NULL;
< 	}
< }
< 
< static void hw_conf_skipword(const char** s0, int n) {
< 	const char* s = *s0;
< 	while (*s && (s-*s0)<n) {
< 		/* Until a char [^0-9xa-zA-Z_'"'"] */
< 		if (!((*s>='0' && *s<='9') || (*s>='a' && *s<='z') || (*s>='A' && *s<='Z')/*|| *s=='\'' || *s=='\"'*/)) {
< 			break;
< 		}
< 		s++;
< 	}
< 	*s0 = s;
< }
< 
< /* Return 0 => root */
< static int hw_conf_getLevel(struct hw_conf_nodeT* n) {
< 	int ret = 0;
< 	while (n->prevV != &hw_conf_root) {
< 		n = n->prevV;
< 		ret++;
< 	}
< 	return ret;
< }
< static struct hw_conf_nodeT* hw_conf_find(struct hw_conf_nodeT* n0, const char** id, int create) {
< 	char haveMultiValue;
< 	struct hw_conf_nodeT* n, *nKm1;
< 	struct hw_conf_nodeT* ret = NULL;
< 	if (n0 == NULL || id == NULL || *id==NULL)
< 		return ret;
< 
< 	(*id)++;
< 	if ((*id)[0]=='{')
< 		(*id)++;
< 	/* Root initialize */
< 	if (hw_conf_haveroot == 0) {
< 		hw_conf_nodeinit(&hw_conf_root);
< 		hw_conf_haveroot = 1;
< 	}
< 	
< 	haveMultiValue = 0;
< 	/* Down one level, then loop trow node */
< 	nKm1 = n = n0->nextV;
< 	while (n && !ret) {
< 		if (strstr(*id, n->id)) {
< 			*id+=strlen(n->id);
< 			switch (*id[0]) {
< 				case '/':
< 					ret = hw_conf_find(n, id, create);
< 					break;
< 				case '\x0':
< 					ret = n;
< 					break;
< 				default:
< 					break;
< 			}
< 		}
< 		nKm1 = n;
< 		n = n->nextH;
< 	}
< 	if (!ret && create) {
< 		struct hw_conf_nodeT* newn = (struct hw_conf_nodeT*) qemu_malloc(sizeof(struct hw_conf_nodeT));
< 		const char* eon;
< 		int len;
< 
< 		eon = *id;
< 		hw_conf_skipword(&eon, 255);
< 
< 		len = eon-*id;
< 		hw_conf_nodeinit(newn);
< 		newn->id = qemu_malloc(len+1);
< 		memcpy(newn->id, *id, len);
< 		newn->id[len] = '\x0';
< 
< 		/* 
< 		 * on new node:
< 		 * nextH: NULL (we add to the tail)
< 		 * nextV: NULL (no child when create)
< 		 * prevV: n0   (always have a node of level-1)
< 		 */
< 		newn->prevV = n0;
< 		if (n0->nextV) {
< 			/* Link to last in this level */
< 			assert(nKm1->nextH==NULL);
< 			nKm1->nextH = newn;
< 		} else {
< 			/* First item on this level */
< 			n0->nextV = newn;
< 		}
< 
< 		*id=eon;
< 		ret = *eon!='/' ? newn : hw_conf_find(newn, id, create);
< 	}
< 	if (ret) {
< 		switch (ret->type) {
< 			case HW_CONF_INT:
< 			case HW_CONF_STRING:
< 			case HW_CONF_PTR:
< 			case HW_CONF_FUNC:
< 			case HW_CONF_NOTYPE:
< 				break;
< 			default:
< 				assert("Find a node with unmanaged type!");
< 				break;
< 		}
< 	}
< 	return ret;
< }
< 
< char* hw_conf_getTypeDes(enum hw_conf_basicT t) {
< 	char* ret = NULL;
< 	switch (t) {
< 		case HW_CONF_INT:	ret = "INT"; break;
< 		case HW_CONF_STRING:	ret = "STRING"; break;
< 		case HW_CONF_PTR:	ret = "PTR"; break;
< 		case HW_CONF_FUNC:	ret = "FUNC"; break;
< 		case HW_CONF_NOTYPE:	ret = "NOTYPE"; break;
< 		default:		ret = "UNKTYPE"; break;
< 	}
< 	return ret;
< }
< 
< enum hw_conf_basicT hw_conf_parseType(const char** s, int n) {
< 	enum hw_conf_basicT ret = HW_CONF_NOTYPE;
< 	if (s==NULL || *s==NULL || n==0)
< 		return ret;
< 
< 	       if (strncmp(*s, "INT ", n>4?4:n)==0) {
< 		(*s)+=4;
< 		ret = HW_CONF_INT;
< 	} else if (strncmp(*s, "STRING ", n>7?7:n)==0) {
< 		(*s)+=7;
< 		ret = HW_CONF_STRING;
< 	} else if (strncmp(*s, "PTR ", n>4?4:n)==0) {
< 		(*s)+=4;
< 		ret = HW_CONF_PTR;
< 	} else if (strncmp(*s, "FUNC ", n>5?5:n)==0) {
< 		(*s)+=5;
< 		ret = HW_CONF_FUNC;
< 	}
< 	return ret;
< }
< int hw_conf_parseValue(const char** s0, int n, enum hw_conf_basicT t, void** o) {
< 	int ret=0;
< 	if (s0 && *s0 && n) {
< 		const char* s = *s0;
< 		switch (t) {
< 			case HW_CONF_INT:
< 			case HW_CONF_PTR:
< 				hw_conf_skipword(&s, n);
< 				if (sscanf(*s0, "0x%x", (int*)o)==1 || sscanf(*s0, "%d", (int*)o)==1)
< 					ret = 1;
< 				break;
< 			case HW_CONF_STRING:
< 			case HW_CONF_FUNC:
< 			{
< 				if (**s0=='\'' || **s0=='\"') {
< 					char* tmp;
< 					s++;
< 					while (n-(*s0-s)>0 && (*s!='\'' && *s!='\"')) {
< 						s++;
< 					}
< 					tmp = qemu_malloc(s-*s0);
< 					memcpy(tmp, *s0+1, s-*s0-1);
< 					tmp[s-*s0-1] = '\x0';
< 					*o = (void*) tmp;
< 						
< 					ret = 1;
< 				}
< 				break;
< 			}
< 		}
< 		if (ret==1) {
< 			*s0 = s;
< 		}
< 	}
< 	return ret;
< }
< 
< /* Elaborate until eof | eos */
< int hw_conf_parsefrom(const char* name, int sz) {
< 	enum {HW_CONF_READING_LEVEL, HW_CONF_READING_NAME, HW_CONF_READED_NAME, HW_CONF_READING_TYPE, HW_CONF_READING_VALUE, HW_CONF_READING_DONE} state;
< 	enum hw_conf_basicT t;
< 	void *o;
< 	char nlev, nlevKm1, comment;
< 	int nobj;
< 	const char* n = name;
< 	struct hw_conf_nodeT* node;
< 
< 	printf("len %d\n", sz);
< 	state = HW_CONF_READING_LEVEL;
< 	t = HW_CONF_NOTYPE;
< 	nlev = nlevKm1 = comment = 0;
< 	nobj = 0;
< 	if (name==NULL)
< 		return nobj;
< 	if (sz == 0)
< 		sz = strlen(name);
< 	while ((n-name)<sz && *n) {
< 		if (comment==0 || *n==0xa) {
< 		switch (*n) {
< 			case ' ':
< 				if (state == HW_CONF_READED_NAME) {
< 					state = HW_CONF_READING_TYPE;
< 				}
< 				if (state == HW_CONF_READING_LEVEL) {
< 					nlev++;
< 				}
< 				break;
< 			case ',':
< 				/* Multi value line */
< 				if (state == HW_CONF_READING_DONE) {
< 					state = HW_CONF_READING_NAME;
< 					nlev--;
< 					node = node->prevV;
< 					n++; /* Skip ',' */
< 				} else {
< 					break;
< 				}
< 			case '/':
< 				if (state <= HW_CONF_READING_NAME) {
< 					if (nlev>nlevKm1) {
< 						assert((nlev - nlevKm1) == 1);
< 					}
< 					while (nlev && nlev<=nlevKm1) {
< 						node = node->prevV;
< 						nlevKm1--;
< 					}
< 					if (nlev == 0) {
< 						node = &hw_conf_root;
< 					}
< 					node = hw_conf_find(node, &n, 1);
< 					nlev = hw_conf_getLevel(node);
< 					state=HW_CONF_READED_NAME;
< 					n--;
< 				}
< 				break;
< 			case '}':
< 				nlev--;
< 				node = node->prevV;
< 				break;
< 			case 0xa:
< 				if (comment) {
< 					nlev = 0;
< 				}
< 				comment = 0;
< 				if (state != HW_CONF_READING_LEVEL) {
< 					state = HW_CONF_READING_LEVEL;
< 					nlevKm1 = nlev;
< 					nlev = 0;
< 				}
< 				break;
< 			case '#':
< 				comment = 1;
< 				break;
< 			default:
< 				switch (state) {
< 					case HW_CONF_READING_TYPE:
< 						if ((t = hw_conf_parseType(&n, sz-(n-name)))!=HW_CONF_NOTYPE) {
< 							state = HW_CONF_READING_VALUE;
< 							n--;
< 						}
< 						break;
< 					case HW_CONF_READING_VALUE:
< 						if (hw_conf_parseValue(&n, sz-(n-name), t, &o)) {
< 							node->type = t;
< 							node->opaque = o;
< 							state = HW_CONF_READING_DONE;
< 							nobj++;
< 							n--;
< 						}
< 					default:
< 						break;
< 				}
< 				break;
< 		} /* switch */
< 		} /* if */
< 		n++;
< 
< 	}
< 	return nobj;
< }
< int hw_conf_get(const char* name, void** val) {
< 	struct hw_conf_nodeT *ret = hw_conf_find(&hw_conf_root, &name, 0);
< 	if (ret)
< 		*val = ret->opaque;
< 	return ret!=NULL;
< }
< int hw_conf_set(const char* name, void* val) {
< 	const char* orign = name;
< 	struct hw_conf_nodeT *ret = hw_conf_find(&hw_conf_root, &name, 0);
< 	if (ret) {
< 		/* Inform the world */
< 		int i, l;
< 		l = 0;
< 		for (i=0; i<sizeof(ret->core)/sizeof(ret->core[0]); i++)
< 			if (ret->core[i].f)
< 				l += ret->core[i].f(ret->core[i].opaque, orign, val);
< 
< 		if (l==0)
< 			ret->opaque = val;
< 	}
< 	return ret!=NULL;
< }
< void hw_conf_corelatewith(const char* name, HWConf_corelateFunc f, void* opaque) {
< 	struct hw_conf_nodeT *ret = hw_conf_find(&hw_conf_root, &name, 0);
< 	if (ret) {
< 		int i;
< 		for (i=0; i<sizeof(ret->core)/sizeof(ret->core[0]); i++)
< 			if (ret->core[i].f==NULL && ret->core[i].opaque==NULL) {
< 				ret->core[i].f = f;
< 				ret->core[i].opaque = opaque;
< 				break;
< 			}
< 		if (i == sizeof(ret->core)/sizeof(ret->core[0])) {
< 			assert("Not enough space for store corelation information!");
< 		}
< 	} else {
< 		assert("Corelation with non existent object");
< 	}
< }
< /* scende & stampa con nextV
<  * sale con prevV e segue nextH
<  * sale con prevV
<  * fino ad n0
<  */
< int hw_conf_printfrom(struct hw_conf_nodeT* n0) {
< 	struct hw_conf_nodeT *n;
< 	int nlev, nlevKm1, lastWasUp;
< 	int nobj = 0;
< 	if (n0==NULL || n0->nextV==NULL)
< 		return nobj;
< 	n = n0->nextV;
< 	nlev = lastWasUp = 0;
< 	while (n != n0) {
< 		if (!lastWasUp) {
< 		int i;
< 		for (i=0; i<nlev; i++)
< 			printf(" ");
< 		printf("/%s", n->id);
< 		if (n->type!=HW_CONF_NOTYPE) {
< 			printf(" %s ", hw_conf_getTypeDes(n->type));
< 			if (n->type == HW_CONF_STRING) {
< 				printf("'%s'", (char*) n->opaque);
< 			} else {
< 				printf("0x%x", n->opaque);
< 			}
< 		}
< 		printf("\n");
< 		}
< 		if (n->nextV && !lastWasUp) {
< 			nlev++;
< 			n = n->nextV;
< 		/* Are on leaf: 1) Try same level, then go up */
< 		} else {
< 			if (n->nextH) {
< 				n = n->nextH;
< 				lastWasUp = 0;
< 			} else {
< 				nlev--;
< 				n = n->prevV;
< 				lastWasUp = 1;
< 			}
< 		}
< 	}
< 	return nobj;
< }
< 
< char* open_mmap(char* fn, int* len) {
< 	int fd;
< 	char* ret = NULL;
< 	fd = open(fn, O_RDONLY);
< 	if (fd>0) {
< 		*len = lseek(fd, 0, SEEK_END);
< 		printf("File lungo %d bytes\n", *len);
< 		ret=mmap(NULL, *len, PROT_READ, MAP_SHARED, fd, 0);
< 		if (ret==MAP_FAILED)
< 			ret = NULL;
< 	}
< 	return ret;
< }
< #ifdef TEST
< int core(void *opaque, const char* name, void* newv) {
< 	printf("Co-relation(this=0x%x) %s now %x\n", opaque, name, newv);
< 	return 0;
< }
< int main(int argc, char* argv[]) {
< 	char tmp[256];
< 	char* tmp1=NULL;
< 	int len;
< 	void* serial_base;
< 	char* info = "\
< /cpu\n\
<  /serial\n\
<   /base PTR 0x500\n\
<   /intr STRING '0'\n\
<  /emac/txeobisr INT 0\n\
< /iic/eeprom\n\
<   /address INT 0x56\n\
<   /image STRING 'pid.bin'";
< 	len = 0;
< 	tmp1 = open_mmap("hw_conf.txt", &len);
< 	printf("parse = %d\n", hw_conf_parsefrom(tmp1, len));
< 	hw_conf_printfrom(&hw_conf_root);
< 	hw_conf_get("/cpu/serial/base", &serial_base);
< 	printf("get serial_base 0x%x\n", serial_base);
< 	hw_conf_corelatewith("/cpu/serial/base", core, (void*)4);
< 	serial_base++;
< 	hw_conf_set("/cpu/serial/base", serial_base);
< 	serial_base=0;
< 	hw_conf_get("/cpu/serial/base", &serial_base);
< 	printf("get serial_base 0x%x\n", serial_base);
< }
< #endif




^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [Qemu-devel] [CONFIGURATION METHOD] A proposal
  2008-11-28  0:55 [Qemu-devel] [CONFIGURATION METHOD] A proposal Salvatore Lionetti
@ 2008-11-28  7:37 ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 0 replies; 2+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2008-11-28  7:37 UTC (permalink / raw)
  To: salvatorelionetti, qemu-devel

On 00:55 Fri 28 Nov     , Salvatore Lionetti wrote:
> Hi,
> 
> i'm working a little on ppc405 emulation and.
> Instead of
> - overload method with many parameter,
> - putting interface definition in the same implementation module,
> - duplicate lot of code between similar board,
> 
> i've elaborated a first draft, compiled and working, of configuration component: see the comment on the head of file.
> 
> Thanks for eventually feedback (information, comment, proposal)
> 
It"s a good idea but IMHO it will be better to use libfdt as the kernel and
u-boot already done.

Best Regards,
J.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2008-11-28  8:12 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-11-28  0:55 [Qemu-devel] [CONFIGURATION METHOD] A proposal Salvatore Lionetti
2008-11-28  7:37 ` Jean-Christophe PLAGNIOL-VILLARD

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).