From: Sebastian Date: Mon, 25 Nov 2013 16:47:40 +0000 (+0100) Subject: dol: initial dol commit X-Git-Url: http://sraa.de/git/?a=commitdiff_plain;h=8c411cf24ed0eb889191aaeafd8fa1e69081df42;p=jump.git dol: initial dol commit This is the original, unchanged DOL source code as provided by ETHZ. It is meant to be built with Ant. --- diff --git a/dol/.classpath b/dol/.classpath new file mode 100644 index 0000000..b331c6d --- /dev/null +++ b/dol/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/dol/.project b/dol/.project new file mode 100644 index 0000000..cb7f5e5 --- /dev/null +++ b/dol/.project @@ -0,0 +1,17 @@ + + + DOL_tecmp + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/dol/build.xml b/dol/build.xml new file mode 100644 index 0000000..a47b050 --- /dev/null +++ b/dol/build.xml @@ -0,0 +1,183 @@ + + + + + + Ant build file for DOL and its documentation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${api.name}]]> + Copyright © 2005-2007 Computer Engineering and Networks Laboratory (TIK), ETH Zürich. All Rights Reserved.]]> + + + + + + + + + + + + + + + + + diff --git a/dol/examples/arch/cell.xml b/dol/examples/arch/cell.xml new file mode 100644 index 0000000..c1397f3 --- /dev/null +++ b/dol/examples/arch/cell.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/arch/mparm.xml b/dol/examples/arch/mparm.xml new file mode 100644 index 0000000..af637da --- /dev/null +++ b/dol/examples/arch/mparm.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/arch/rdt1.xml b/dol/examples/arch/rdt1.xml new file mode 100644 index 0000000..aa385c7 --- /dev/null +++ b/dol/examples/arch/rdt1.xml @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/arch/rdt8.xml b/dol/examples/arch/rdt8.xml new file mode 100644 index 0000000..5f7189b --- /dev/null +++ b/dol/examples/arch/rdt8.xml @@ -0,0 +1,2059 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dol/examples/example1/example1.xml b/dol/examples/example1/example1.xml new file mode 100644 index 0000000..654aaad --- /dev/null +++ b/dol/examples/example1/example1.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/example1/map_1.xml b/dol/examples/example1/map_1.xml new file mode 100644 index 0000000..46820c3 --- /dev/null +++ b/dol/examples/example1/map_1.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + diff --git a/dol/examples/example1/map_3.xml b/dol/examples/example1/map_3.xml new file mode 100644 index 0000000..976172a --- /dev/null +++ b/dol/examples/example1/map_3.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + diff --git a/dol/examples/example1/map_mparm.xml b/dol/examples/example1/map_mparm.xml new file mode 100644 index 0000000..a68d309 --- /dev/null +++ b/dol/examples/example1/map_mparm.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/example1/src/arraygen.c b/dol/examples/example1/src/arraygen.c new file mode 100644 index 0000000..14b3fed --- /dev/null +++ b/dol/examples/example1/src/arraygen.c @@ -0,0 +1,42 @@ +#include +#include +#include + +#include "arragygen.h" + +// initialization function +void arraygen_init(DOLProcess *p) { + p->local->index = 0; + srand((unsigned) time(NULL)); + //p->local->len = LENGTH; +} + +int arraygen_fire(DOLProcess *p) { + + + /* generate a random integer array of length L */ + //int num = rand() % 1000; + + int i; + int len = LENGTH; + int * array; + array = (int *) malloc(sizeof(int)*len); + + for(i=0;i +#include "global.h" + +#define PORT_OUT1 1 +#define PORT_OUT2 2 + + +typedef struct _local_states { + int index; +} Arraygen_State; + +void arraygen_init(DOLProcess *); +int arraygen_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example1/src/consumer.c b/dol/examples/example1/src/consumer.c new file mode 100644 index 0000000..711614b --- /dev/null +++ b/dol/examples/example1/src/consumer.c @@ -0,0 +1,26 @@ +#include + +#include "consumer.h" + +void consumer_init(DOLProcess *p) { + sprintf(p->local->name, "consumer"); + p->local->index = 0; + p->local->len = LENGTH; +} + +int consumer_fire(DOLProcess *p) { + float c; + if (p->local->index < p->local->len) { + DOL_read((void*)PORT_IN, &c, sizeof(float), p); + printf("%s: %f\n", p->local->name, c); + p->local->index++; + } + + if (p->local->index >= p->local->len) { + DOL_detach(p); + return -1; + } + + return 0; +} + diff --git a/dol/examples/example1/src/consumer.h b/dol/examples/example1/src/consumer.h new file mode 100644 index 0000000..677609a --- /dev/null +++ b/dol/examples/example1/src/consumer.h @@ -0,0 +1,18 @@ +#ifndef CONSUMER_H +#define CONSUMER_H + +#include +#include "global.h" + +#define PORT_IN 1 + +typedef struct _local_states { + char name[10]; + int index; + int len; +} Consumer_State; + +void consumer_init(DOLProcess *); +int consumer_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example1/src/generator.c b/dol/examples/example1/src/generator.c new file mode 100644 index 0000000..88c801f --- /dev/null +++ b/dol/examples/example1/src/generator.c @@ -0,0 +1,27 @@ +#include +#include + +#include "generator.h" + +// initialization function +void generator_init(DOLProcess *p) { + p->local->index = 0; + p->local->len = LENGTH; +} + +int generator_fire(DOLProcess *p) { + + if (p->local->index < p->local->len) { + float x = (float)p->local->index; + DOL_write((void*)PORT_OUT, &(x), sizeof(float), p); + p->local->index++; + } + + if (p->local->index >= p->local->len) { + DOL_detach(p); + return -1; + } + + return 0; +} + diff --git a/dol/examples/example1/src/generator.h b/dol/examples/example1/src/generator.h new file mode 100644 index 0000000..b938a38 --- /dev/null +++ b/dol/examples/example1/src/generator.h @@ -0,0 +1,17 @@ +#ifndef GENERATOR_H +#define GENERATOR_H + +#include +#include "global.h" + +#define PORT_OUT 1 + +typedef struct _local_states { + int index; + int len; +} Generator_State; + +void generator_init(DOLProcess *); +int generator_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example1/src/global.h b/dol/examples/example1/src/global.h new file mode 100644 index 0000000..78aaffd --- /dev/null +++ b/dol/examples/example1/src/global.h @@ -0,0 +1,9 @@ +#ifndef GLOBAL_H +#define GLOBAL_H + +#include + +#define ARRAY_LEN 10 +#define DEBUG 1 + +#endif diff --git a/dol/examples/example1/src/printarray.c b/dol/examples/example1/src/printarray.c new file mode 100644 index 0000000..b140b96 --- /dev/null +++ b/dol/examples/example1/src/printarray.c @@ -0,0 +1,25 @@ +#include + +#include "printarray.h" + +void printarray_init(DOLProcess *p) { + p->local->index = 0; +} + +int printarray_fire(DOLProcess *p) { + + int len; + int * array; + DOL_read((void*)PORT_IN1, &len, sizeof(int), p); + DOL_read((void*)PORT_IN2, array, sizeof(int)*len, p); + + printf("sorted output\n"); + for(i=0;i +#include "global.h" + +#define PORT_IN1 1 +#define PORT_IN2 2 + +typedef struct _local_states { + int index; +} Printarray_State; + +void printarray_init(DOLProcess *); +int printarray_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example1/src/quicksort.c b/dol/examples/example1/src/quicksort.c new file mode 100644 index 0000000..5512fda --- /dev/null +++ b/dol/examples/example1/src/quicksort.c @@ -0,0 +1,120 @@ +#include +#include + +#include "quicksort.h" + +int smaller_arr(int *dst, int *src, int pivot,int len) +{ + int i; + int num=0; + for(i=0;ipivot) + { + dst[num++]=src[i]; + } + } + return num; +} + +int median_const(int len, int * array) +{ + int i,j; + int desired_rank = ceil(len/2); + + for(i=0;iarray[i]) + rank++; + } + + if(rank==desired_rank) + return array[i]; + } + return array[0]; +} + +int select_med(int size, int * array) +{ + int ret; + int * array_of_median; + int len = ceil(size/5); + int i,j; + + /* divide array into groups of five elements */ + array_of_median = malloc(sizeof(int)*len); + + for(i=0;ilocal->index = 0; +} + +int quicksort_fire(DOLProcess *p) { + + int len=LENGTH; + int * array; + int median; + int down,up; + + /* receive the 'size' / 'array' */ + DOL_read((void*)PORT_IN1, &len, sizeof(int), p); + DOL_read((void*)PORT_IN2, array, sizeof(int)*len, p); + + /* selection */ + median = select_med(len, array); + + /* divide */ + down = 0; up =0; + down=smaller_arr(arr1,array,median,len); + up=bigger_arr(arr2,array,median,len); + + // down + up == len + + /* sort */ + quick + + /* merge */ + + /* send the 'size' / 'sorted array' */ + DOL_write((void*)PORT_OUT1, &len, sizeof(int), p); + + DOL_detach(p); + return -1; +} + diff --git a/dol/examples/example1/src/quicksort.h b/dol/examples/example1/src/quicksort.h new file mode 100644 index 0000000..09227ed --- /dev/null +++ b/dol/examples/example1/src/quicksort.h @@ -0,0 +1,21 @@ +#ifndef QUICKSORT_H +#define QUICKSORT_H + +#include +#include "global.h" + +#define PORT_IN1 1 +#define PORT_IN2 2 +#define PORT_OUT1 3 +#define PORT_OUT2 4 + +typedef struct _local_states { + int index; + int * arr1; + int * arr2; +} Quicksort_State; + +void quicksort_init(DOLProcess *); +int quicksort_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example1/src/square.c b/dol/examples/example1/src/square.c new file mode 100644 index 0000000..126378b --- /dev/null +++ b/dol/examples/example1/src/square.c @@ -0,0 +1,27 @@ +#include + +#include "square.h" + +void square_init(DOLProcess *p) { + p->local->index = 0; + p->local->len = LENGTH; +} + +int square_fire(DOLProcess *p) { + float i; + + if (p->local->index < p->local->len) { + DOL_read((void*)PORT_IN, &i, sizeof(float), p); + i = i*i; + DOL_write((void*)PORT_OUT, &i, sizeof(float), p); + p->local->index++; + } + + if (p->local->index >= p->local->len) { + DOL_detach(p); + return -1; + } + + return 0; +} + diff --git a/dol/examples/example1/src/square.h b/dol/examples/example1/src/square.h new file mode 100644 index 0000000..2db7edc --- /dev/null +++ b/dol/examples/example1/src/square.h @@ -0,0 +1,18 @@ +#ifndef SQUARE_H +#define SQUARE_H + +#include +#include "global.h" + +#define PORT_IN 1 +#define PORT_OUT 2 + +typedef struct _local_states { + int index; + int len; +} Square_State; + +void square_init(DOLProcess *); +int square_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example2/example2.xml b/dol/examples/example2/example2.xml new file mode 100644 index 0000000..9a915a4 --- /dev/null +++ b/dol/examples/example2/example2.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/example2/src/consumer.c b/dol/examples/example2/src/consumer.c new file mode 100644 index 0000000..711614b --- /dev/null +++ b/dol/examples/example2/src/consumer.c @@ -0,0 +1,26 @@ +#include + +#include "consumer.h" + +void consumer_init(DOLProcess *p) { + sprintf(p->local->name, "consumer"); + p->local->index = 0; + p->local->len = LENGTH; +} + +int consumer_fire(DOLProcess *p) { + float c; + if (p->local->index < p->local->len) { + DOL_read((void*)PORT_IN, &c, sizeof(float), p); + printf("%s: %f\n", p->local->name, c); + p->local->index++; + } + + if (p->local->index >= p->local->len) { + DOL_detach(p); + return -1; + } + + return 0; +} + diff --git a/dol/examples/example2/src/consumer.h b/dol/examples/example2/src/consumer.h new file mode 100644 index 0000000..2a4a545 --- /dev/null +++ b/dol/examples/example2/src/consumer.h @@ -0,0 +1,18 @@ +#ifndef CONSUMER_H +#define CONSUMER_H + +#include +#include "global.h" + +#define PORT_IN 100 + +typedef struct _local_states { + char name[10]; + int index; + int len; +} Consumer_State; + +void consumer_init(DOLProcess *); +int consumer_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example2/src/generator.c b/dol/examples/example2/src/generator.c new file mode 100644 index 0000000..88c801f --- /dev/null +++ b/dol/examples/example2/src/generator.c @@ -0,0 +1,27 @@ +#include +#include + +#include "generator.h" + +// initialization function +void generator_init(DOLProcess *p) { + p->local->index = 0; + p->local->len = LENGTH; +} + +int generator_fire(DOLProcess *p) { + + if (p->local->index < p->local->len) { + float x = (float)p->local->index; + DOL_write((void*)PORT_OUT, &(x), sizeof(float), p); + p->local->index++; + } + + if (p->local->index >= p->local->len) { + DOL_detach(p); + return -1; + } + + return 0; +} + diff --git a/dol/examples/example2/src/generator.h b/dol/examples/example2/src/generator.h new file mode 100644 index 0000000..4f05280 --- /dev/null +++ b/dol/examples/example2/src/generator.h @@ -0,0 +1,17 @@ +#ifndef GENERATOR_H +#define GENERATOR_H + +#include +#include "global.h" + +#define PORT_OUT 10 + +typedef struct _local_states { + int index; + int len; +} Generator_State; + +void generator_init(DOLProcess *); +int generator_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example2/src/global.h b/dol/examples/example2/src/global.h new file mode 100644 index 0000000..dfcbb84 --- /dev/null +++ b/dol/examples/example2/src/global.h @@ -0,0 +1,6 @@ +#ifndef GLOBAL_H +#define GLOBAL_H + +#define LENGTH 20 + +#endif diff --git a/dol/examples/example2/src/square.c b/dol/examples/example2/src/square.c new file mode 100644 index 0000000..126378b --- /dev/null +++ b/dol/examples/example2/src/square.c @@ -0,0 +1,27 @@ +#include + +#include "square.h" + +void square_init(DOLProcess *p) { + p->local->index = 0; + p->local->len = LENGTH; +} + +int square_fire(DOLProcess *p) { + float i; + + if (p->local->index < p->local->len) { + DOL_read((void*)PORT_IN, &i, sizeof(float), p); + i = i*i; + DOL_write((void*)PORT_OUT, &i, sizeof(float), p); + p->local->index++; + } + + if (p->local->index >= p->local->len) { + DOL_detach(p); + return -1; + } + + return 0; +} + diff --git a/dol/examples/example2/src/square.h b/dol/examples/example2/src/square.h new file mode 100644 index 0000000..27b2bcc --- /dev/null +++ b/dol/examples/example2/src/square.h @@ -0,0 +1,18 @@ +#ifndef SQUARE_H +#define SQUARE_H + +#include +#include "global.h" + +#define PORT_IN 0 +#define PORT_OUT 1 + +typedef struct _local_states { + int index; + int len; +} Square_State; + +void square_init(DOLProcess *); +int square_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example3/example3.xml b/dol/examples/example3/example3.xml new file mode 100644 index 0000000..68859ae --- /dev/null +++ b/dol/examples/example3/example3.xml @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/example3/src/forward.c b/dol/examples/example3/src/forward.c new file mode 100644 index 0000000..a3b7e81 --- /dev/null +++ b/dol/examples/example3/src/forward.c @@ -0,0 +1,19 @@ +#include + +#include "forward.h" + +void forward_init(DOLProcess *p) { + sprintf(p->local->name,"Forward"); +} + +int forward_fire(DOLProcess *p) { + char c; + char c2; + + DOL_read((void*)PORT_IN1, &c, 1, p); + DOL_read((void*)PORT_IN2, &c2, 1, p); + DOL_write((void*)PORT_OUT1, &c, 1, p); + DOL_write((void*)PORT_OUT2, &c2, 1, p); + + return 0; +} diff --git a/dol/examples/example3/src/forward.h b/dol/examples/example3/src/forward.h new file mode 100644 index 0000000..62d4309 --- /dev/null +++ b/dol/examples/example3/src/forward.h @@ -0,0 +1,18 @@ +#ifndef FORWARD_H +#define FORWARD_H + +#include + +#define PORT_IN1 "west" +#define PORT_IN2 "north" +#define PORT_OUT1 "east" +#define PORT_OUT2 "south" + +typedef struct _local_states { + char name[20]; +} Forward_State; + +void forward_init(DOLProcess *); +int forward_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example3/src/horizontal_consumer.c b/dol/examples/example3/src/horizontal_consumer.c new file mode 100644 index 0000000..3849aed --- /dev/null +++ b/dol/examples/example3/src/horizontal_consumer.c @@ -0,0 +1,16 @@ +#include + +#include "horizontal_consumer.h" + +void horizontal_consumer_init(DOLProcess *p) { + sprintf(p->local->name, "h_consumer"); +} + +int horizontal_consumer_fire(DOLProcess *p) { + char c; + DOL_read((void*)PORT_IN, &c, 1, p); + printf("%s: %c\n", p->local->name, c); + + return 0; +} + diff --git a/dol/examples/example3/src/horizontal_consumer.h b/dol/examples/example3/src/horizontal_consumer.h new file mode 100644 index 0000000..f09bffb --- /dev/null +++ b/dol/examples/example3/src/horizontal_consumer.h @@ -0,0 +1,15 @@ +#ifndef CONSUMER_H +#define CONSUMER_H + +#include + +#define PORT_IN "h_in" + +typedef struct _local_states { + char name[20]; +} Horizontal_consumer_State; + +void horizontal_consumer_init(DOLProcess *); +int horizontal_consumer_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example3/src/horizontal_generator.c b/dol/examples/example3/src/horizontal_generator.c new file mode 100644 index 0000000..501ff1b --- /dev/null +++ b/dol/examples/example3/src/horizontal_generator.c @@ -0,0 +1,24 @@ +#include +#include + +#include "horizontal_generator.h" + +// initialization function +void horizontal_generator_init(DOLProcess *p) { + sprintf(p->local->str, "nopqrstuvwxyz"); + p->local->index = 0; + p->local->len = strlen(p->local->str); +} + +int horizontal_generator_fire(DOLProcess *p) { + + if (p->local->index < p->local->len) { + DOL_write((void*)PORT_OUT, (p->local->str + p->local->index), 1, p); + p->local->index++; + } + else { + DOL_detach(p); + } + return 0; +} + diff --git a/dol/examples/example3/src/horizontal_generator.h b/dol/examples/example3/src/horizontal_generator.h new file mode 100644 index 0000000..fdc8a3c --- /dev/null +++ b/dol/examples/example3/src/horizontal_generator.h @@ -0,0 +1,17 @@ +#ifndef PRODUCER_H +#define PRODUCER_H + +#include + +#define PORT_OUT "h_out" + +typedef struct _local_states { + int index; + char str[25]; + int len; +} Horizontal_generator_State; + +void horizontal_generator_init(DOLProcess *); +int horizontal_generator_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example3/src/vertical_consumer.c b/dol/examples/example3/src/vertical_consumer.c new file mode 100644 index 0000000..a4f166b --- /dev/null +++ b/dol/examples/example3/src/vertical_consumer.c @@ -0,0 +1,15 @@ +#include + +#include "vertical_consumer.h" + +void vertical_consumer_init(DOLProcess *p) { + sprintf(p->local->name, "v_consumer"); +} + +int vertical_consumer_fire(DOLProcess *p) { + char c; + DOL_read((void*)PORT_IN, &c, 1, p); + printf("%s: %c\n", p->local->name, c); + + return 0; +} diff --git a/dol/examples/example3/src/vertical_consumer.h b/dol/examples/example3/src/vertical_consumer.h new file mode 100644 index 0000000..8dd538b --- /dev/null +++ b/dol/examples/example3/src/vertical_consumer.h @@ -0,0 +1,15 @@ +#ifndef CONSUMER_H +#define CONSUMER_H + +#include + +#define PORT_IN "v_in" + +typedef struct _local_states { + char name[20]; +} Vertical_consumer_State; + +void vertical_consumer_init(DOLProcess *); +int vertical_consumer_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example3/src/vertical_generator.c b/dol/examples/example3/src/vertical_generator.c new file mode 100644 index 0000000..5dfa100 --- /dev/null +++ b/dol/examples/example3/src/vertical_generator.c @@ -0,0 +1,23 @@ +#include +#include + +#include "vertical_generator.h" + +// initialization function +void vertical_generator_init(DOLProcess *p) { + sprintf(p->local->str,"abcdefghijklm"); + p->local->index = 0; + p->local->len = strlen(p->local->str); +} + +int vertical_generator_fire(DOLProcess *p) { + + if (p->local->index < p->local->len) { + DOL_write((void*)PORT_OUT, (p->local->str + p->local->index), 1, p); + p->local->index++; + } else { + DOL_detach(p); + } + + return 0; +} diff --git a/dol/examples/example3/src/vertical_generator.h b/dol/examples/example3/src/vertical_generator.h new file mode 100644 index 0000000..f6dec58 --- /dev/null +++ b/dol/examples/example3/src/vertical_generator.h @@ -0,0 +1,17 @@ +#ifndef PRODUCER_H +#define PRODUCER_H + +#include + +#define PORT_OUT "v_out" + +typedef struct _local_states { + int index; + char str[20]; + int len; +} Vertical_generator_State; + +void vertical_generator_init(DOLProcess *); +int vertical_generator_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example4/example4.xml b/dol/examples/example4/example4.xml new file mode 100644 index 0000000..f9db3d6 --- /dev/null +++ b/dol/examples/example4/example4.xml @@ -0,0 +1,344 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/example4/src/addmult.c b/dol/examples/example4/src/addmult.c new file mode 100644 index 0000000..00ef15e --- /dev/null +++ b/dol/examples/example4/src/addmult.c @@ -0,0 +1,28 @@ +#include +#include "addmult.h" + +void addmult_init(DOLProcess *p) +{ + sprintf(p->local->id, "addmult_%d_%d_%d", + GETINDEX(0), + GETINDEX(1), + GETINDEX(2)); +} + + +int addmult_fire(DOLProcess *p) +{ + float factor1, factor2, summand; + + DOL_read((void*)PORT_FACTOR1, &factor1, sizeof(float), p); + DOL_read((void*)PORT_FACTOR2, &factor2, sizeof(float), p); + DOL_read((void*)PORT_SUMMAND, &summand, sizeof(float), p); + p->local->sum = factor1 * factor2 + summand; + DOL_write((void*)PORT_SUM, &(p->local->sum), sizeof(float), p); + + printf("%15s: %f * %f + %f = %f\n", + p->local->id, factor1, factor2, summand, p->local->sum); + + return 0; +} + diff --git a/dol/examples/example4/src/addmult.h b/dol/examples/example4/src/addmult.h new file mode 100644 index 0000000..7eb7c3a --- /dev/null +++ b/dol/examples/example4/src/addmult.h @@ -0,0 +1,20 @@ +#ifndef ADDMULT_H +#define ADDMULT_H + +#include + +#define PORT_FACTOR1 "factor1" +#define PORT_FACTOR2 "factor2" +#define PORT_SUMMAND "summand" +#define PORT_SUM "sum" + +typedef struct _local_states +{ + char id[14]; + float sum; +} Addmult_State; + +void addmult_init(DOLProcess *); +int addmult_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example4/src/constants.h b/dol/examples/example4/src/constants.h new file mode 100644 index 0000000..36d73b2 --- /dev/null +++ b/dol/examples/example4/src/constants.h @@ -0,0 +1,20 @@ +#ifndef CONSTANTS_H +#define CONSTANTS_H + +/* +#define NUMBER_OF_ROWS_COLS 1 +#define MATRIX_A_INITIAL_VALUE { 1.0 } +#define MATRIX_B_INITIAL_VALUE { 2.5 } +*/ + +#define NUMBER_OF_ROWS_COLS 2 +#define MATRIX_A_INITIAL_VALUE { {1.0, 2.0 }, { 3.0, 4.0 } } +#define MATRIX_B_INITIAL_VALUE { {0.0, -1.0 }, { -2.0, -3.0 } } + +/* +#define NUMBER_OF_ROWS_COLS 3 +#define MATRIX_A_INITIAL_VALUE { {1.0, 2.0, 3.0 }, {4.0, 5.0, -4.0 }, {-3.0, -2.0, -1.0} } +#define MATRIX_B_INITIAL_VALUE { {1.0, 0.0, 0.0 }, {0.0, 1.0, 0.0 }, { 0.0, 0.0, 1.0} } +*/ + +#endif diff --git a/dol/examples/example4/src/consumer.c b/dol/examples/example4/src/consumer.c new file mode 100644 index 0000000..ebd4e98 --- /dev/null +++ b/dol/examples/example4/src/consumer.c @@ -0,0 +1,29 @@ +#include + +#include "consumer.h" + +void output_consumer_init(DOLProcess *p) +{ + ; //nothing to be done here +} + +int output_consumer_fire(DOLProcess *p) +{ + CREATEPORTVAR(port); + + for (p->local->row = 0; p->local->row < NUMBER_OF_ROWS_COLS; p->local->row++) + { + for (p->local->col = 0; p->local->col < NUMBER_OF_ROWS_COLS; p->local->col++) + { + CREATEPORT(port, PORT_MATRIXC, 2, + p->local->row, NUMBER_OF_ROWS_COLS, + p->local->col, NUMBER_OF_ROWS_COLS); + + DOL_read((void*)port, &p->local->matrixC_value, sizeof(float), p); + printf("%15s: matrixC[%d][%d]: %f\n", + "output_consumer", p->local->row, p->local->col, p->local->matrixC_value); + } + } + return 0; +} + diff --git a/dol/examples/example4/src/consumer.h b/dol/examples/example4/src/consumer.h new file mode 100644 index 0000000..7406a75 --- /dev/null +++ b/dol/examples/example4/src/consumer.h @@ -0,0 +1,18 @@ +#ifndef CONSUMER_H +#define CONSUMER_H + +#include "constants.h" +#include + +#define PORT_MATRIXC "matrixC" + +typedef struct _local_states +{ + unsigned row, col; + float matrixC_value; +} Output_consumer_State; + +void output_consumer_init(DOLProcess *); +int output_consumer_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example4/src/generator.c b/dol/examples/example4/src/generator.c new file mode 100644 index 0000000..60f3962 --- /dev/null +++ b/dol/examples/example4/src/generator.c @@ -0,0 +1,65 @@ +#include +#include + +#include "generator.h" + + +Input_generator_State input_generator_state = + { matrixA: MATRIX_A_INITIAL_VALUE, matrixB: MATRIX_B_INITIAL_VALUE }; + +void input_generator_init(DOLProcess *p) +{ + for (p->local->row = 0; p->local->row < NUMBER_OF_ROWS_COLS; p->local->row++) + { + for (p->local->col = 0; p->local->col < NUMBER_OF_ROWS_COLS; p->local->col++) + { + p->local->matrixA[p->local->row][p->local->col] = (NUMBER_OF_ROWS_COLS * p->local->row) + p->local->col + 1; + p->local->matrixB[p->local->row][p->local->col] = -((NUMBER_OF_ROWS_COLS * p->local->row) + p->local->col); + } + } +} + + +int input_generator_fire(DOLProcess *p) +{ + CREATEPORTVAR(port); + + for (p->local->row = 0; p->local->row < NUMBER_OF_ROWS_COLS; p->local->row++) + { + for (p->local->col = 0; p->local->col < NUMBER_OF_ROWS_COLS; p->local->col++) + { + CREATEPORT(port, PORT_ZEROINPUT, 1, + p->local->row * NUMBER_OF_ROWS_COLS + p->local->col, NUMBER_OF_ROWS_COLS + * NUMBER_OF_ROWS_COLS); + printf("%15s: Write to zeroinput_%d: %f\n", "input_generator", + p->local->row * NUMBER_OF_ROWS_COLS + p->local->col, 0.0); + DOL_write((void*)port, &(p->local->zero), sizeof(float), p); + + for (p->local->i = 0; p->local->i < NUMBER_OF_ROWS_COLS; p->local->i++) + { + CREATEPORT(port, PORT_MATRIXA, 3, + p->local->row, NUMBER_OF_ROWS_COLS, + p->local->col, NUMBER_OF_ROWS_COLS, + p->local->i, NUMBER_OF_ROWS_COLS); + printf("%15s: Write to matrixA_%d_%d_%d: %f\n", + "input_generator", p->local->i, p->local->row, p->local->col, + p->local->matrixA[p->local->row][p->local->col]); + DOL_write((void*)port, &(p->local->matrixA[p->local->row][p->local->col]), + sizeof(float), p); + CREATEPORT(port, PORT_MATRIXB, 3, + p->local->row, NUMBER_OF_ROWS_COLS, + p->local->col, NUMBER_OF_ROWS_COLS, + p->local->i, NUMBER_OF_ROWS_COLS); + printf("%15s: Write to matrixB_%d_%d_%d: %f\n", + "input_generator", p->local->i, p->local->row, p->local->col, + p->local->matrixB[p->local->row][p->local->col]); + DOL_write((void*)port, &(p->local->matrixB[p->local->row][p->local->col]), + sizeof(float), p); + } + } + } + + DOL_detach(p); + return -1; +} + diff --git a/dol/examples/example4/src/generator.h b/dol/examples/example4/src/generator.h new file mode 100644 index 0000000..c4ad94e --- /dev/null +++ b/dol/examples/example4/src/generator.h @@ -0,0 +1,22 @@ +#ifndef PRODUCER_H +#define PRODUCER_H + +#include "constants.h" +#include + +#define PORT_MATRIXA "matrixA" +#define PORT_MATRIXB "matrixB" +#define PORT_ZEROINPUT "zeroinput" + +typedef struct _local_states +{ + float matrixA[NUMBER_OF_ROWS_COLS][NUMBER_OF_ROWS_COLS]; + float matrixB[NUMBER_OF_ROWS_COLS][NUMBER_OF_ROWS_COLS]; + int row, col, i; + float zero; +} Input_generator_State; + +void input_generator_init(DOLProcess *); +int input_generator_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example5/example5.xml b/dol/examples/example5/example5.xml new file mode 100644 index 0000000..659342f --- /dev/null +++ b/dol/examples/example5/example5.xml @@ -0,0 +1,305 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/example5/fft_script.m b/dol/examples/example5/fft_script.m new file mode 100644 index 0000000..4a418ea --- /dev/null +++ b/dol/examples/example5/fft_script.m @@ -0,0 +1,146 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Matlab script to compute the reference result for the FFT example. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +close all; +clear all; +clc; + +wNk = inline('exp(-j * 2 * pi * k / N)', 'N', 'k'); + +%coefficients produced by c's random number generator in producer_fire() +x = [ -9 + j * 4 + -2 + j * 0 + -3 + j * 0 + 8 + j * 3 + 6 + j * 0 + -7 + j * -9 + -5 + j * 2 + 1 + j * 2 + 8 + j * -4 + -6 + j * -4 + 9 + j * -2 + -8 + j * -4 + -3 + j * 1 + -9 + j * 7 + -9 + j * -9 + -7 + j * 7 + 4 + j * -6 + 5 + j * -5 + 4 + j * 8 + 7 + j * -6 + -3 + j * 9 + -6 + j * -2 + -8 + j * -9 + 2 + j * 7 + -5 + j * -7 + 7 + j * -9 + 0 + j * 9 + 5 + j * 1 + -8 + j * 1 + 5 + j * 6 + -2 + j * -8 + 6 + j * -8 + -5 + j * 7 + 5 + j * -9 + 8 + j * -5 + -6 + j * 9 + 2 + j * -3 + 3 + j * -6 + 5 + j * 0 + -7 + j * 6 + 3 + j * -4 + -2 + j * 4 + -4 + j * -2 + 9 + j * -8 + -3 + j * 3 + 0 + j * -6 + 6 + j * 4 + -2 + j * -4 + 9 + j * 0 + -8 + j * -9 + 0 + j * -4 + 7 + j * -4 + 8 + j * 6 + -2 + j * -1 + -8 + j * 6 + 9 + j * -3 + 1 + j * 4 + 3 + j * -3 + 2 + j * -2 + 9 + j * 6 + -8 + j * -7 + -7 + j * 2 + 8 + j * -1 + 1 + j * 0 + -1 + j * -3 + 3 + j * -9 + 1 + j * 9 + -2 + j * 8 + 8 + j * -5 + 6 + j * 4 + 8 + j * 3 + 9 + j * 9 + 3 + j * -9 + 4 + j * -5 + 4 + j * -2 + 8 + j * 2 + -3 + j * 1 + -8 + j * -9 + 4 + j * 6 + 4 + j * 7 + 2 + j * 7 + -4 + j * -6 + 6 + j * 9 + 3 + j * -5 + 6 + j * -7 + -4 + j * -6 + 3 + j * -1 + 5 + j * 8 + 6 + j * -6 + -5 + j * 0 + 2 + j * -2 + -2 + j * -5 + -4 + j * -8 + 9 + j * -5 + 3 + j * 3 + -3 + j * -9 + -5 + j * -7 + 6 + j * -6 + -9 + j * -3 + 1 + j * -9 + 3 + j * -5 + 3 + j * 9 + 8 + j * -9 + -8 + j * 3 + 1 + j * -5 + 9 + j * 4 + -6 + j * 7 + 3 + j * 5 + 9 + j * 9 + -4 + j * -6 + -1 + j * -8 + -6 + j * 3 + 4 + j * -3 + -6 + j * -7 + 2 + j * -3 + -8 + j * 0 + 1 + j * 9 + 9 + j * 0 + -3 + j * 2 + -2 + j * 7 + 8 + j * -9 + 1 + j * 6 + -4 + j * -1 + 5 + j * -1 + 8 + j * 9 + 3 + j * -9 + 8 + j * 3 + -3 + j * -2 ]; + +fft(x(1:8)) +fft(x(1:16)) +fft(x(1:64)) +fft(x) diff --git a/dol/examples/example5/src/consumer.c b/dol/examples/example5/src/consumer.c new file mode 100644 index 0000000..376ecee --- /dev/null +++ b/dol/examples/example5/src/consumer.c @@ -0,0 +1,29 @@ +#include + +#include "consumer.h" + +void consumer_init(DOLProcess *p) +{ + ; //nothing to be done here +} + +int consumer_fire(DOLProcess *p) +{ + CREATEPORTVAR(input_port); + + for (p->local->index = 0; p->local->index < NUMBER_OF_FFT_POINTS; + p->local->index++) { + CREATEPORT(input_port, PORT_OUTPUT_COEFFICIENTS, 1, + p->local->index, NUMBER_OF_FFT_POINTS); + DOL_read((void*)input_port, &(p->local->coeffs[p->local->index]), + sizeof(ComplexNumber), p); + printf("%15s: coeff[%d]: %9f + j * %9f\n", + "output_consumer", p->local->index, + p->local->coeffs[p->local->index].real, + p->local->coeffs[p->local->index].imag); + } + + DOL_detach(p); + return -1; +} + diff --git a/dol/examples/example5/src/consumer.h b/dol/examples/example5/src/consumer.h new file mode 100644 index 0000000..0daf317 --- /dev/null +++ b/dol/examples/example5/src/consumer.h @@ -0,0 +1,18 @@ +#ifndef CONSUMER_H +#define CONSUMER_H + +#include +#include "global.h" + +#define PORT_OUTPUT_COEFFICIENTS "output_coefficients" + +typedef struct _local_states +{ + int index; + ComplexNumber coeffs[NUMBER_OF_FFT_POINTS]; +} Consumer_State; + +void consumer_init(DOLProcess *); +int consumer_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example5/src/fft2.c b/dol/examples/example5/src/fft2.c new file mode 100644 index 0000000..ec56b82 --- /dev/null +++ b/dol/examples/example5/src/fft2.c @@ -0,0 +1,75 @@ +#include +#include +#include "fft2.h" + +/** + * Determines the twiddle factor of this 2-point FFT based on the + * indices of the process. + */ +void fft2_init(DOLProcess *p) +{ + const float PI = 2.0 * asin(1.0); + int layer_index = GETINDEX(0); + int process_index = GETINDEX(1); + float exponent = 2.0 * PI * + (float)(process_index % (1 << layer_index)) / + (float)(1 << (layer_index + 1)); + + sprintf(p->local->id, "FFT2_%d_%d", + GETINDEX(0), + GETINDEX(1)); + p->local->twiddle_factor.real = cos(exponent); + p->local->twiddle_factor.imag = -sin(exponent); + + printf("%15s: twiddle_factor %9f + j * %9f\n", + p->local->id, + p->local->twiddle_factor.real, + p->local->twiddle_factor.imag); +} + +/** + * Computes 2-point FFT. + */ +int fft2_fire(DOLProcess *p) +{ + DOL_read((void*)PORT_INA, &(p->local->inA), sizeof(ComplexNumber), p); + DOL_read((void*)PORT_INB, &(p->local->inB), sizeof(ComplexNumber), p); + + p->local->rotated_inB.real = p->local->inB.real + * p->local->twiddle_factor.real + - p->local->inB.imag + * p->local->twiddle_factor.imag ; + p->local->rotated_inB.imag = p->local->inB.real + * p->local->twiddle_factor.imag + + p->local->inB.imag + * p->local->twiddle_factor.real; + + p->local->outA.real = p->local->inA.real + + p->local->rotated_inB.real; + p->local->outA.imag = p->local->inA.imag + + p->local->rotated_inB.imag; + + p->local->outB.real = p->local->inA.real + - p->local->rotated_inB.real; + p->local->outB.imag = p->local->inA.imag + - p->local->rotated_inB.imag; + + DOL_write((void*)PORT_OUTA, &(p->local->outA), sizeof(ComplexNumber), p); + DOL_write((void*)PORT_OUTB, &(p->local->outB), sizeof(ComplexNumber), p); + + /* + printf("%15s: ", p->local->id); + printf("%9f + j * %9f, %9f + j * %9f => %9f + j * %9f, %9f + j * %9f\n", + p->local->inA.real, + p->local->inA.imag, + p->local->inB.real, + p->local->inB.imag, + p->local->outA.real, + p->local->outA.imag, + p->local->outB.real, + p->local->outB.imag); + */ + + DOL_detach(p); + return -1; +} diff --git a/dol/examples/example5/src/fft2.h b/dol/examples/example5/src/fft2.h new file mode 100644 index 0000000..79e567e --- /dev/null +++ b/dol/examples/example5/src/fft2.h @@ -0,0 +1,21 @@ +#ifndef FFT2_H +#define FFT2_H + +#include +#include "global.h" + +#define PORT_INA "inA" +#define PORT_INB "inB" +#define PORT_OUTA "outA" +#define PORT_OUTB "outB" + +typedef struct _local_states +{ + char id[14]; + ComplexNumber inA, inB, outA, outB, rotated_inB, twiddle_factor; +} Fft2_State; + +void fft2_init(DOLProcess *); +int fft2_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example5/src/generator.c b/dol/examples/example5/src/generator.c new file mode 100644 index 0000000..9d160cf --- /dev/null +++ b/dol/examples/example5/src/generator.c @@ -0,0 +1,47 @@ +#include + +#include "generator.h" + +/** + * Returns a random integer in the range between lower_bound and + * upper_bound, where the bounding values are included in the interval. + */ +int getRandomNumber(int lower_bound, int upper_bound) +{ + return (rand() % (upper_bound - lower_bound + 1)) + lower_bound; +} + + +void generator_init(DOLProcess *p) +{ + ; //nothing to be done here +} + + +int generator_fire(DOLProcess *p) +{ + CREATEPORTVAR(output_port); + + srand(0); //initialize random number generator + + //generate input coefficients and write them to output ports + for (p->local->index = 0; + p->local->index < NUMBER_OF_FFT_POINTS; + p->local->index++) { + p->local->coeffs[p->local->index].real = (float)getRandomNumber(-9, 9); + p->local->coeffs[p->local->index].imag = (float)getRandomNumber(-9, 9); + + CREATEPORT(output_port, PORT_INPUT_COEFFICIENTS, 1, + p->local->index, NUMBER_OF_FFT_POINTS); + printf("%15s: Write to input_coefficients_%d: %9f + j * %9f\n", + "input_generator", p->local->index, + p->local->coeffs[p->local->index].real, + p->local->coeffs[p->local->index].imag); + DOL_write((void*)output_port, &(p->local->coeffs[p->local->index]), + sizeof(ComplexNumber), p); + } + + DOL_detach(p); + return -1; +} + diff --git a/dol/examples/example5/src/generator.h b/dol/examples/example5/src/generator.h new file mode 100644 index 0000000..511ec04 --- /dev/null +++ b/dol/examples/example5/src/generator.h @@ -0,0 +1,19 @@ +#ifndef PRODUCER_H +#define PRODUCER_H + +#include +#include "global.h" +#include "stdlib.h" + +#define PORT_INPUT_COEFFICIENTS "input_coefficients" + +typedef struct _local_states +{ + int index; + ComplexNumber coeffs[NUMBER_OF_FFT_POINTS]; +} Generator_State; + +void generator_init(DOLProcess *); +int generator_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example5/src/global.h b/dol/examples/example5/src/global.h new file mode 100644 index 0000000..b1373b2 --- /dev/null +++ b/dol/examples/example5/src/global.h @@ -0,0 +1,13 @@ +#ifndef GLOBAL_H +#define GLOBAL_H + +#define NUMBER_OF_FFT_POINTS 16 + +//structure for holding complex numbers +typedef struct complex_number +{ + float real; + float imag; +} ComplexNumber; + +#endif diff --git a/dol/examples/example6/example6.xml b/dol/examples/example6/example6.xml new file mode 100644 index 0000000..f8a0d19 --- /dev/null +++ b/dol/examples/example6/example6.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/example6/src/consumer.c b/dol/examples/example6/src/consumer.c new file mode 100644 index 0000000..f79ccf9 --- /dev/null +++ b/dol/examples/example6/src/consumer.c @@ -0,0 +1,23 @@ +#include + +#include "consumer.h" + +void consumer_init(DOLProcess *p) +{ + ; //nothing to be done here +} + +int consumer_fire(DOLProcess *p) +{ + static int index; + static float sample; + + for (index = 0; index < 10; index++) + { + DOL_read((void*)PORT_IN, &sample, sizeof(float), p); + printf("%8s: Read sample[%02d]: %+6.4f\n", + "consumer", index, sample); + } + return 0; +} + diff --git a/dol/examples/example6/src/consumer.h b/dol/examples/example6/src/consumer.h new file mode 100644 index 0000000..09d158b --- /dev/null +++ b/dol/examples/example6/src/consumer.h @@ -0,0 +1,15 @@ +#ifndef CONSUMER_H +#define CONSUMER_H + +#include + +#define PORT_IN "in" + +typedef struct _local_states +{ +} Consumer_State; + +void consumer_init(DOLProcess *); +int consumer_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example6/src/filter.c b/dol/examples/example6/src/filter.c new file mode 100644 index 0000000..2715647 --- /dev/null +++ b/dol/examples/example6/src/filter.c @@ -0,0 +1,32 @@ +#include +#include +#include "filter.h" + +/** + * Write zero to feedback output. + */ +void filter_init(DOLProcess *p) +{ + p->local->zero = 0.0; + p->local->factor = 0.5; + p->local->firstiteration = 1; +} + +/** + * Filter. + */ +int filter_fire(DOLProcess *p) +{ + if (p->local->firstiteration) { + DOL_write((void*)PORT_OUTB, &(p->local->zero), sizeof(float), p); + p->local->firstiteration = 0; + } + + DOL_read((void*)PORT_INA, &(p->local->inA), sizeof(float), p); + DOL_read((void*)PORT_INB, &(p->local->inB), sizeof(float), p); + p->local->out = p->local->inA + p->local->factor * p->local->inB; + DOL_write((void*)PORT_OUTA, &(p->local->out), sizeof(float), p); + DOL_write((void*)PORT_OUTB, &(p->local->out), sizeof(float), p); + + return 0; +} diff --git a/dol/examples/example6/src/filter.h b/dol/examples/example6/src/filter.h new file mode 100644 index 0000000..a068113 --- /dev/null +++ b/dol/examples/example6/src/filter.h @@ -0,0 +1,20 @@ +#ifndef FILTER_H +#define FILTER_H + +#include + +#define PORT_INA "inA" +#define PORT_INB "inB" +#define PORT_OUTA "outA" +#define PORT_OUTB "outB" + +typedef struct _local_states +{ + int firstiteration; + float inA, inB, out, zero, factor; +} Filter_State; + +void filter_init(DOLProcess *); +int filter_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example6/src/producer.c b/dol/examples/example6/src/producer.c new file mode 100644 index 0000000..58e161a --- /dev/null +++ b/dol/examples/example6/src/producer.c @@ -0,0 +1,52 @@ +#include +#include + +#include "producer.h" + +/** + * Returns a random integer in the range between lower_bound and + * upper_bound, where the bounding values are included in the interval. + */ +int getRandomNumber(int lower_bound, int upper_bound) +{ + return (rand() % (upper_bound - lower_bound + 1)) + lower_bound; +} + + +void producer_init(DOLProcess *p) +{ + ; //nothing to be done here +} + + +int producer_fire(DOLProcess *p) +{ + static int index; + + srand(0); //initialize random number generator + + //generate input samples and display them + printf("producer: samples = { "); + + for (index = 0; index < 10; index++) { + p->local->sample[index] = (float) getRandomNumber(-9, 9); + if (index < 9) { + printf("%+3.1f, ", p->local->sample[index]); + } + else { + printf("%+3.1f }\n", p->local->sample[index]); + } + } + + //write samples to output port + for (index = 0; index < 10; index++) { + printf("%8s: Write sample[%02d]: %+6.4f\n", + "producer", index, p->local->sample[index]); + DOL_write((void*)PORT_OUT, &(p->local->sample[index]), + sizeof(float), p); + } + + DOL_detach(p); + return -1; +} + diff --git a/dol/examples/example6/src/producer.h b/dol/examples/example6/src/producer.h new file mode 100644 index 0000000..9aacfe7 --- /dev/null +++ b/dol/examples/example6/src/producer.h @@ -0,0 +1,17 @@ +#ifndef PRODUCER_H +#define PRODUCER_H + +#include +#include "stdlib.h" + +#define PORT_OUT "out" + +typedef struct _local_states +{ + float sample[10]; +} Producer_State; + +void producer_init(DOLProcess *); +int producer_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example7/example7.xml b/dol/examples/example7/example7.xml new file mode 100644 index 0000000..271c3b9 --- /dev/null +++ b/dol/examples/example7/example7.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/example7/filter_script.m b/dol/examples/example7/filter_script.m new file mode 100644 index 0000000..dab0c8a --- /dev/null +++ b/dol/examples/example7/filter_script.m @@ -0,0 +1,15 @@ +clear all; +close all; +clc; + +N = 3; +NUMBER_OF_SAMPLES = 5; +FILTER_COEFFICIENTS = [0.1 -0.1 0.4 1.0 -0.7 0.2 -0.9 -0.4 -0.8]; +x = [-9 4 -2 0 -3 0 8 3 6 0, ... + -7 -9 -5 2 1 2 8 -4 -6 -4]; + +%example 6 +y = filter(1, [1 -0.5], x(1:10)) + +%example 7 +y = filter(1, [1 -FILTER_COEFFICIENTS(1:N-1)], x (1:NUMBER_OF_SAMPLES)) diff --git a/dol/examples/example7/src/consumer.c b/dol/examples/example7/src/consumer.c new file mode 100644 index 0000000..ace9ccc --- /dev/null +++ b/dol/examples/example7/src/consumer.c @@ -0,0 +1,23 @@ +#include + +#include "consumer.h" + +void consumer_init(DOLProcess *p) +{ + printf("init consumer.\n"); +} + +int consumer_fire(DOLProcess *p) +{ + static int index; + static float sample; + + for (index = 0; index < NUMBER_OF_SAMPLES; index++) + { + DOL_read((void*)PORT_IN, &sample, sizeof(float), p); + printf("%8s: Read sample[%02d]: %+6.4f\n", + "consumer", index, sample); + } + return 0; +} + diff --git a/dol/examples/example7/src/consumer.h b/dol/examples/example7/src/consumer.h new file mode 100644 index 0000000..8908e5d --- /dev/null +++ b/dol/examples/example7/src/consumer.h @@ -0,0 +1,16 @@ +#ifndef CONSUMER_H +#define CONSUMER_H + +#include +#include "global.h" + +#define PORT_IN "in" + +typedef struct _local_states +{ +} Consumer_State; + +void consumer_init(DOLProcess *); +int consumer_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example7/src/filter.c b/dol/examples/example7/src/filter.c new file mode 100644 index 0000000..fd8c3ab --- /dev/null +++ b/dol/examples/example7/src/filter.c @@ -0,0 +1,83 @@ +#include +#include +#include "filter.h" + +/** + * Init. + */ +void filter_init(DOLProcess *p) +{ + int k; + p->local->process_index = GETINDEX(0); + + srand(0); //initialize random number generator + for (k = 0; k < p->local->process_index; k++) + rand(); + + sprintf(p->local->id, "filter_%d", + GETINDEX(0)); + p->local->first_invocation = 1; + //generate a random filter coefficient between -1 and 1 + p->local->filter_coefficient = ((float) (rand() % 21) - 10)/10.0; + p->local->zero = 0.0; + printf("init %s: filter coefficient = %+2.1f\n", + p->local->id, p->local->filter_coefficient); +} + +/** + * Filter. + */ +int filter_fire(DOLProcess *p) +{ + //behaviour of the top filter stage + if (p->local->process_index == 0) { + if (p->local->first_invocation) { + DOL_read((void*)PORT_INA, &(p->local->inA), sizeof(float), p); + p->local->out = p->local->inA; + p->local->inB = 0.0; + p->local->first_invocation = 0; + } + else { + DOL_read((void*)PORT_INA, &(p->local->inA), sizeof(float), p); + DOL_read((void*)PORT_INB, &(p->local->inB), sizeof(float), p); + p->local->out = p->local->inB + p->local->inA; + } + + DOL_write((void*)PORT_OUTA, &(p->local->out), sizeof(float), p); + DOL_write((void*)PORT_OUTB, &(p->local->out), sizeof(float), p); + + printf("%8s: inA: %6.4f, inB: %6.4f, outA = outB: %6.4f\n", + p->local->id, p->local->inA, p->local->inB, p->local->out); + } + //behaviour of the intermediate filter stages + else { + if (p->local->first_invocation) { + DOL_read((void*)PORT_INA, &(p->local->inA), sizeof(float), p); + p->local->out = p->local->filter_coefficient * p->local->inA; + p->local->inB = 0.0; + p->local->first_invocation = 0; + } + else { + DOL_read((void*)PORT_INA, &(p->local->inA), sizeof(float), p); + DOL_read((void*)PORT_INB, &(p->local->inB), sizeof(float), p); + p->local->out = p->local->inB + p->local->filter_coefficient + * p->local->inA; + } + + if (p->local->process_index < N - 1) { + DOL_write((void*)PORT_OUTA, &(p->local->inA), sizeof(float), p); + DOL_write((void*)PORT_OUTB, &(p->local->out), sizeof(float), p); + } + //behaviour of the bottom filter stage + else { + DOL_write((void*)PORT_OUTA, &(p->local->zero), sizeof(float), p); + DOL_write((void*)PORT_OUTB, &(p->local->out), sizeof(float), p); + } + + printf("%8s: inA: %6.4f, inB: %6.4f, outA: %6.4f, outB: %6.4f\n", + p->local->id, p->local->inA, p->local->inB, p->local->inA, + p->local->out); + } + + return 0; +} diff --git a/dol/examples/example7/src/filter.h b/dol/examples/example7/src/filter.h new file mode 100644 index 0000000..8d6b07b --- /dev/null +++ b/dol/examples/example7/src/filter.h @@ -0,0 +1,23 @@ +#ifndef FILTER_H +#define FILTER_H + +#include +#include "global.h" + +#define PORT_INA "inA" +#define PORT_INB "inB" +#define PORT_OUTA "outA" +#define PORT_OUTB "outB" + +typedef struct _local_states +{ + char id[10]; //will contain "filter_xx" + int first_invocation; + int process_index; + float inA, inB, out, filter_coefficient, zero; +} Filter_State; + +void filter_init(DOLProcess *); +int filter_fire(DOLProcess *); + +#endif diff --git a/dol/examples/example7/src/global.h b/dol/examples/example7/src/global.h new file mode 100644 index 0000000..b2931f2 --- /dev/null +++ b/dol/examples/example7/src/global.h @@ -0,0 +1,7 @@ +#ifndef GLOBAL_H +#define GLOBAL_H + +#define N 3 +#define NUMBER_OF_SAMPLES 5 + +#endif diff --git a/dol/examples/example7/src/producer.c b/dol/examples/example7/src/producer.c new file mode 100644 index 0000000..89f2aaa --- /dev/null +++ b/dol/examples/example7/src/producer.c @@ -0,0 +1,50 @@ +#include +#include + +#include "producer.h" + +/** + * Returns a random integer in the range between lower_bound and + * upper_bound, where the bounding values are included in the interval. + */ +int getRandomNumber(int lower_bound, int upper_bound) +{ + return (rand() % (upper_bound - lower_bound + 1)) + lower_bound; +} + + +void producer_init(DOLProcess *p) +{ + printf("init producer.\n"); +} + + +int producer_fire(DOLProcess *p) +{ + srand(0); //initialize random number generator + + //generate input samples and display them + printf("producer: samples = { "); + + for (p->local->index = 0; p->local->index < NUMBER_OF_SAMPLES; p->local->index++) { + p->local->sample[p->local->index] = (float) getRandomNumber(-9, 9); + if (p->local->index < NUMBER_OF_SAMPLES - 1) { + printf("%+3.1f, ", p->local->sample[p->local->index]); + } + else { + printf("%+3.1f }\n", p->local->sample[p->local->index]); + } + } + + //write samples to output port + for (p->local->index = 0; p->local->index < NUMBER_OF_SAMPLES; p->local->index++) { + printf("%8s: Write sample[%02d]: %+6.4f\n", + "producer", p->local->index, p->local->sample[p->local->index]); + DOL_write((void*)PORT_OUT, &(p->local->sample[p->local->index]), + sizeof(float), p); + } + + DOL_detach(p); + return -1; +} + diff --git a/dol/examples/example7/src/producer.h b/dol/examples/example7/src/producer.h new file mode 100644 index 0000000..2cffa95 --- /dev/null +++ b/dol/examples/example7/src/producer.h @@ -0,0 +1,19 @@ +#ifndef PRODUCER_H +#define PRODUCER_H + +#include +#include "global.h" +#include "stdlib.h" + +#define PORT_OUT "out" + +typedef struct _local_states +{ + int index; + float sample[NUMBER_OF_SAMPLES]; +} Producer_State; + +void producer_init(DOLProcess *); +int producer_fire(DOLProcess *); + +#endif diff --git a/dol/examples/examplecell/cell.xml b/dol/examples/examplecell/cell.xml new file mode 100644 index 0000000..c1397f3 --- /dev/null +++ b/dol/examples/examplecell/cell.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/examplecell/examplecell.xml b/dol/examples/examplecell/examplecell.xml new file mode 100644 index 0000000..5e63359 --- /dev/null +++ b/dol/examples/examplecell/examplecell.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/examplecell/mapping.xml b/dol/examples/examplecell/mapping.xml new file mode 100644 index 0000000..aafe1d8 --- /dev/null +++ b/dol/examples/examplecell/mapping.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/examplecell/src/consumer.c b/dol/examples/examplecell/src/consumer.c new file mode 100644 index 0000000..cb89dd0 --- /dev/null +++ b/dol/examples/examplecell/src/consumer.c @@ -0,0 +1,23 @@ +#include + +#include "consumer.h" + +void consumer_init(DOLProcess *p) { + sprintf(p->local->name, "consumer"); + p->local->index = 0; + p->local->len = LENGTH; +} + +int consumer_fire(DOLProcess *p) { + if (p->local->index < p->local->len) { + DOL_read((void*)PORT_IN, &p->local->c, sizeof(float), p); + printf("%s: %f\n", p->local->name, p->local->c); + p->local->index++; + } else { + DOL_detach(p); + return -1; + } + + return 0; +} + diff --git a/dol/examples/examplecell/src/consumer.h b/dol/examples/examplecell/src/consumer.h new file mode 100644 index 0000000..ca0fbba --- /dev/null +++ b/dol/examples/examplecell/src/consumer.h @@ -0,0 +1,19 @@ +#ifndef CONSUMER_H +#define CONSUMER_H + +#include +#include "global.h" + +#define PORT_IN 100 + +void consumer_init(DOLProcess *); +int consumer_fire(DOLProcess *); + +typedef struct _local_states { + char name[10]; + int index; + int len; + float c; +} Consumer_State; + +#endif diff --git a/dol/examples/examplecell/src/generator.c b/dol/examples/examplecell/src/generator.c new file mode 100644 index 0000000..237f54e --- /dev/null +++ b/dol/examples/examplecell/src/generator.c @@ -0,0 +1,23 @@ +#include + +#include "generator.h" + +void generator_init(DOLProcess *p) { + sprintf(p->local->name, "generator"); + p->local->index = 0; + p->local->len = LENGTH; +} + +int generator_fire(DOLProcess *p) { + if (p->local->index < p->local->len) { + p->local->x = (float)p->local->index; + DOL_write((void*)PORT_OUT, &p->local->x, sizeof(float), p); + p->local->index++; + } else { + DOL_detach(p); + return -1; + } + + return 0; +} + diff --git a/dol/examples/examplecell/src/generator.h b/dol/examples/examplecell/src/generator.h new file mode 100644 index 0000000..dbc225f --- /dev/null +++ b/dol/examples/examplecell/src/generator.h @@ -0,0 +1,19 @@ +#ifndef GENERATOR_H +#define GENERATOR_H + +#include +#include "global.h" + +#define PORT_OUT 10 + +void generator_init(DOLProcess *); +int generator_fire(DOLProcess *); + +typedef struct _local_states { + char name[10]; + int index; + int len; + float x; +} Generator_State; + +#endif diff --git a/dol/examples/examplecell/src/global.h b/dol/examples/examplecell/src/global.h new file mode 100644 index 0000000..92dc11c --- /dev/null +++ b/dol/examples/examplecell/src/global.h @@ -0,0 +1,6 @@ +#ifndef GLOBAL_H +#define GLOBAL_H + +#define LENGTH 6 + +#endif diff --git a/dol/examples/examplecell/src/square.c b/dol/examples/examplecell/src/square.c new file mode 100644 index 0000000..c1c6caa --- /dev/null +++ b/dol/examples/examplecell/src/square.c @@ -0,0 +1,24 @@ +#include + +#include "square.h" + +void square_init(DOLProcess *p) { + sprintf(p->local->name, "square"); + p->local->index = 0; + p->local->len = LENGTH; +} + +int square_fire(DOLProcess *p) { + if (p->local->index < p->local->len) { + DOL_read((void*)PORT_IN, &p->local->i, sizeof(float), p); + p->local->i = p->local->i + p->local->i; + DOL_write((void*)PORT_OUT, &p->local->i, sizeof(float), p); + p->local->index++; + } else { + DOL_detach(p); + return -1; + } + + return 0; +} + diff --git a/dol/examples/examplecell/src/square.h b/dol/examples/examplecell/src/square.h new file mode 100644 index 0000000..5b947a8 --- /dev/null +++ b/dol/examples/examplecell/src/square.h @@ -0,0 +1,20 @@ +#ifndef SQUARE_H +#define SQUARE_H + +#include +#include "global.h" + +#define PORT_IN 0 +#define PORT_OUT 1 + +void square_init(DOLProcess *); +int square_fire(DOLProcess *); + +typedef struct _local_states { + char name[10]; + int index; + int len; + float i; +} Square_State; + +#endif diff --git a/dol/examples/exampleproducerconsumer/exampleproducerconsumer.xml b/dol/examples/exampleproducerconsumer/exampleproducerconsumer.xml new file mode 100644 index 0000000..5ccb2f3 --- /dev/null +++ b/dol/examples/exampleproducerconsumer/exampleproducerconsumer.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/exampleproducerconsumer/src/consumer.c b/dol/examples/exampleproducerconsumer/src/consumer.c new file mode 100644 index 0000000..c39157b --- /dev/null +++ b/dol/examples/exampleproducerconsumer/src/consumer.c @@ -0,0 +1,21 @@ +#include + +#include "consumer.h" + +void consumer_init(DOLProcess *p) { + sprintf(p->local->name, "consumer"); +} + +int consumer_fire(DOLProcess *p) { + char c; + + if (DOL_rtest((void*)PORT_INB, 1, p)) { + DOL_read((void*)PORT_INA, &c, sizeof(char), p); + printf("from port B: %c\n", c); + DOL_read((void*)PORT_INA, &c, sizeof(char), p); + printf("from port A: %c\n", c); + } + + return 0; +} + diff --git a/dol/examples/exampleproducerconsumer/src/consumer.h b/dol/examples/exampleproducerconsumer/src/consumer.h new file mode 100644 index 0000000..47d5ebf --- /dev/null +++ b/dol/examples/exampleproducerconsumer/src/consumer.h @@ -0,0 +1,16 @@ +#ifndef CONSUMER_H +#define CONSUMER_H + +#include + +#define PORT_INA "A" +#define PORT_INB "B" + +typedef struct _local_states { + char name[10]; +} Consumer_State; + +void consumer_init(DOLProcess *); +int consumer_fire(DOLProcess *); + +#endif diff --git a/dol/examples/exampleproducerconsumer/src/producer.c b/dol/examples/exampleproducerconsumer/src/producer.c new file mode 100644 index 0000000..2e0130b --- /dev/null +++ b/dol/examples/exampleproducerconsumer/src/producer.c @@ -0,0 +1,37 @@ +#include +#include + +#include "producer.h" + +// initialization function +void producer_init(DOLProcess *p) { + p->local->index = 0; + p->local->len = 20; + sprintf(p->local->str, "abcdefghijklmnopqrstuvwxyz"); + +} + +int producer_fire(DOLProcess *p) { + + if (p->local->index < p->local->len) { + if (DOL_wtest((void*)PORT_OUTA, 1, p)) { + DOL_write((void*)PORT_OUTA, &(p->local->str[p->local->index]), + 1, p); + printf("p write to port A %c\n", + p->local->str[p->local->index]); + } + else { + DOL_write((void*)PORT_OUTB, &(p->local->str[p->local->index]), + 1, p); + printf("p write to port B %c\n", + p->local->str[p->local->index]); + } + p->local->index++; + return 0; + } + else { + DOL_detach(p); + return -1; + } +} + diff --git a/dol/examples/exampleproducerconsumer/src/producer.h b/dol/examples/exampleproducerconsumer/src/producer.h new file mode 100644 index 0000000..6668050 --- /dev/null +++ b/dol/examples/exampleproducerconsumer/src/producer.h @@ -0,0 +1,18 @@ +#ifndef PRODUCER_H +#define PRODUCER_H + +#include + +#define PORT_OUTA "A" +#define PORT_OUTB "B" + +typedef struct _local_states { + int index; + int len; + char str[26]; +} Producer_State; + +void producer_init(DOLProcess *); +int producer_fire(DOLProcess *); + +#endif diff --git a/dol/examples/examplesingleprocess/examplesingleprocess.xml b/dol/examples/examplesingleprocess/examplesingleprocess.xml new file mode 100644 index 0000000..07937ae --- /dev/null +++ b/dol/examples/examplesingleprocess/examplesingleprocess.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/dol/examples/examplesingleprocess/src/task.c b/dol/examples/examplesingleprocess/src/task.c new file mode 100644 index 0000000..9544c0b --- /dev/null +++ b/dol/examples/examplesingleprocess/src/task.c @@ -0,0 +1,21 @@ +#include + +#include "task.h" + +void task_init(DOLProcess *p) { + sprintf(p->local->name, "task_%d", GETINDEX(0)); + p->local->index = 0; +} + +int task_fire(DOLProcess *p) { + if (p->local->index < 10) { + printf("%s: %d\n", p->local->name, p->local->index++); + } + + if (p->local->index >= 10) { + DOL_detach(p); + } + + return 0; +} + diff --git a/dol/examples/examplesingleprocess/src/task.h b/dol/examples/examplesingleprocess/src/task.h new file mode 100644 index 0000000..c68d499 --- /dev/null +++ b/dol/examples/examplesingleprocess/src/task.h @@ -0,0 +1,15 @@ +#ifndef TASK_H +#define TASK_H + +#include + +typedef struct _local_states { + char name[10]; + int index; + int len; +} Task_State; + +void task_init(DOLProcess *); +int task_fire(DOLProcess *); + +#endif diff --git a/dol/examples/examplewindowedfifo/examplewindowedfifo.xml b/dol/examples/examplewindowedfifo/examplewindowedfifo.xml new file mode 100644 index 0000000..a09d69b --- /dev/null +++ b/dol/examples/examplewindowedfifo/examplewindowedfifo.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/examplewindowedfifo/src/consumer.c b/dol/examples/examplewindowedfifo/src/consumer.c new file mode 100644 index 0000000..cf6902a --- /dev/null +++ b/dol/examples/examplewindowedfifo/src/consumer.c @@ -0,0 +1,27 @@ +#include + +#include "consumer.h" + +void consumer_init(DOLProcess *p) { + sprintf(p->local->name, "consumer"); + p->local->index = 0; + p->local->len = LENGTH; +} + +int consumer_fire(DOLProcess *p) { + float *c; + if (p->local->index < p->local->len) { + DOL_capture((void*)PORT_IN, &c, sizeof(float), p); + printf("%s: %f\n", p->local->name, *c); + DOL_consume((void*)PORT_IN, p); + p->local->index++; + } + + if (p->local->index >= p->local->len) { + DOL_detach(p); + return -1; + } + + return 0; +} + diff --git a/dol/examples/examplewindowedfifo/src/consumer.h b/dol/examples/examplewindowedfifo/src/consumer.h new file mode 100644 index 0000000..677609a --- /dev/null +++ b/dol/examples/examplewindowedfifo/src/consumer.h @@ -0,0 +1,18 @@ +#ifndef CONSUMER_H +#define CONSUMER_H + +#include +#include "global.h" + +#define PORT_IN 1 + +typedef struct _local_states { + char name[10]; + int index; + int len; +} Consumer_State; + +void consumer_init(DOLProcess *); +int consumer_fire(DOLProcess *); + +#endif diff --git a/dol/examples/examplewindowedfifo/src/generator.c b/dol/examples/examplewindowedfifo/src/generator.c new file mode 100644 index 0000000..943294d --- /dev/null +++ b/dol/examples/examplewindowedfifo/src/generator.c @@ -0,0 +1,29 @@ +#include +#include + +#include "generator.h" + +// initialization function +void generator_init(DOLProcess *p) { + p->local->index = 0; + p->local->len = LENGTH; +} + +int generator_fire(DOLProcess *p) { + + if (p->local->index < p->local->len) { + float *x; + DOL_reserve((void*)PORT_OUT, &x, sizeof(float), p); + *x = (float)p->local->index; + DOL_release((void*)PORT_OUT, p); + p->local->index++; + } + + if (p->local->index >= p->local->len) { + DOL_detach(p); + return -1; + } + + return 0; +} + diff --git a/dol/examples/examplewindowedfifo/src/generator.h b/dol/examples/examplewindowedfifo/src/generator.h new file mode 100644 index 0000000..b938a38 --- /dev/null +++ b/dol/examples/examplewindowedfifo/src/generator.h @@ -0,0 +1,17 @@ +#ifndef GENERATOR_H +#define GENERATOR_H + +#include +#include "global.h" + +#define PORT_OUT 1 + +typedef struct _local_states { + int index; + int len; +} Generator_State; + +void generator_init(DOLProcess *); +int generator_fire(DOLProcess *); + +#endif diff --git a/dol/examples/examplewindowedfifo/src/global.h b/dol/examples/examplewindowedfifo/src/global.h new file mode 100644 index 0000000..dfcbb84 --- /dev/null +++ b/dol/examples/examplewindowedfifo/src/global.h @@ -0,0 +1,6 @@ +#ifndef GLOBAL_H +#define GLOBAL_H + +#define LENGTH 20 + +#endif diff --git a/dol/examples/examplewindowedfifo/src/square.c b/dol/examples/examplewindowedfifo/src/square.c new file mode 100644 index 0000000..7e0b5d2 --- /dev/null +++ b/dol/examples/examplewindowedfifo/src/square.c @@ -0,0 +1,29 @@ +#include + +#include "square.h" + +void square_init(DOLProcess *p) { + p->local->index = 0; + p->local->len = LENGTH; +} + +int square_fire(DOLProcess *p) { + float *i, *j; + + if (p->local->index < p->local->len) { + DOL_capture((void*)PORT_IN, &i, sizeof(float), p); + DOL_reserve((void*)PORT_OUT, &j, sizeof(float), p); + *j = *i * *i; + DOL_consume((void*)PORT_IN, p); + DOL_release((void*)PORT_OUT, p); + p->local->index++; + } + + if (p->local->index >= p->local->len) { + DOL_detach(p); + return -1; + } + + return 0; +} + diff --git a/dol/examples/examplewindowedfifo/src/square.h b/dol/examples/examplewindowedfifo/src/square.h new file mode 100644 index 0000000..e2eebd0 --- /dev/null +++ b/dol/examples/examplewindowedfifo/src/square.h @@ -0,0 +1,18 @@ +#ifndef SQUARE_H +#define SQUARE_H + +#include +#include "global.h" + +#define PORT_IN 100 +#define PORT_OUT 200 + +typedef struct _local_states { + int index; + int len; +} Square_State; + +void square_init(DOLProcess *); +int square_fire(DOLProcess *); + +#endif diff --git a/dol/examples/runexample.xml b/dol/examples/runexample.xml new file mode 100644 index 0000000..fa03bfe --- /dev/null +++ b/dol/examples/runexample.xml @@ -0,0 +1,285 @@ + + + + + + Ant build file to build and run examples. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/runprofiler.xml b/dol/examples/runprofiler.xml new file mode 100644 index 0000000..a3e4ade --- /dev/null +++ b/dol/examples/runprofiler.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/schema/architecture.xsd b/dol/examples/schema/architecture.xsd new file mode 100644 index 0000000..ddb3871 --- /dev/null +++ b/dol/examples/schema/architecture.xsd @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/schema/createschemastex b/dol/examples/schema/createschemastex new file mode 100644 index 0000000..9b7fe4a --- /dev/null +++ b/dol/examples/schema/createschemastex @@ -0,0 +1,91 @@ +#!/bin/bash + +########################################################################## +# Script to collect together processnetwork.xsd, architecture.xsd, and +# mapping.xsd into a single LaTeX document. +# +# Lines longer than 80 characters in the source files are truncated. +# +# modification history: +# 2006-08-22: created +# +########################################################################## + +########################################################################## +# create LaTeX header +########################################################################## + +echo -e %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'\n'\ +% XML Schema Definitions.'\n'\ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'\n'\ +'\n'\ +'\\'documentclass[11pt,oneside]{book}'\n'\ +'\\'usepackage{fancyhdr,ifthen,a4wide,textcomp,version,amsmath,bbm,url}'\n'\ +'\\'usepackage[latin1]{inputenc}'\n'\ +'\n'\ +%package for including listings'\n'\ +'\\'usepackage{listings}'\n'\ +'\\'lstset{basicstyle='\\'small, xleftmargin=12pt, numbersep=12pt, numbers=left,'\n'\ + numberstyle='\\'tiny, numbersep=5pt}'\n'\ +%print two-digit line numbers'\n'\ +'\\'newcommand{'\\'twodig}[1]'\n'\ + {'\\'ifcase#1 00'\\'or01'\\'or02'\\'or03'\\'or04'\\'or05'\\'or06'\\'or07'\\'or08'\\'or09'\\'else#1'\\'fi}'\n'\ +'\\'renewcommand{'\\'thelstnumber}{'\\'twodig{'\\'arabic{lstnumber}}}'\n'\ +'\n'\ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'\n'\ +%page layout and graphics path'\n'\ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'\n'\ +'\\'setlength{'\\'textwidth}{18 true cm}'\n'\ +'\\'setlength{'\\'textheight}{27.4 true cm}'\n'\ +'\\'oddsidemargin -1.0 cm'\n'\ +'\\'evensidemargin -1.0 cm'\n'\ +'\\'topmargin -2.4 cm'\n'\ +'\\'setlength{'\\'parindent}{0pt}'\n'\ +'\\'sloppy'\n'\ +'\\'flushbottom'\n'\ +'\\'pagestyle{empty}'\n'\ +'\n'\ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'\n'\ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'\n'\ +'\n'\ +'\\'begin{document} > latex_header.tex + + +########################################################################## +# create LaTeX footer +########################################################################## + +echo -e '\\'end{document} > latex_footer.tex + + +########################################################################## +# create listings header and footer +########################################################################## + +echo -e '\\'newpage'\n'\ +'\\'begin{lstlisting} > listing_header.tex + +echo -e '\\'end{lstlisting} > listing_footer.tex + + +########################################################################## +# create document +########################################################################## + +cat latex_header.tex listing_header.tex processnetwork.xsd listing_footer.tex \ + listing_header.tex architecture.xsd listing_footer.tex \ + listing_header.tex mapping.xsd listing_footer.tex latex_footer.tex > schemas.tex + + +########################################################################## +# truncate lines longer than 80 characters +########################################################################## + +sed -i 's/\(^.\{80\}\).*/\1.../g' schemas.tex + + +########################################################################## +# remove help files +########################################################################## + +rm -f latex_header.tex latex_footer.tex listing_header.tex listing_footer.tex \ No newline at end of file diff --git a/dol/examples/schema/generics.xsd b/dol/examples/schema/generics.xsd new file mode 100644 index 0000000..28b9108 --- /dev/null +++ b/dol/examples/schema/generics.xsd @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/schema/internal/architecture_internal.xsd b/dol/examples/schema/internal/architecture_internal.xsd new file mode 100644 index 0000000..e76fe32 --- /dev/null +++ b/dol/examples/schema/internal/architecture_internal.xsd @@ -0,0 +1,4 @@ + + + + diff --git a/dol/examples/schema/internal/mapping_internal.xsd b/dol/examples/schema/internal/mapping_internal.xsd new file mode 100644 index 0000000..d0cad50 --- /dev/null +++ b/dol/examples/schema/internal/mapping_internal.xsd @@ -0,0 +1,4 @@ + + + + diff --git a/dol/examples/schema/internal/processnetwork_internal.xsd b/dol/examples/schema/internal/processnetwork_internal.xsd new file mode 100644 index 0000000..0e2d87c --- /dev/null +++ b/dol/examples/schema/internal/processnetwork_internal.xsd @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/schema/mapping.xsd b/dol/examples/schema/mapping.xsd new file mode 100644 index 0000000..dbaef38 --- /dev/null +++ b/dol/examples/schema/mapping.xsd @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/examples/schema/processnetwork.xsd b/dol/examples/schema/processnetwork.xsd new file mode 100644 index 0000000..d3c2d93 --- /dev/null +++ b/dol/examples/schema/processnetwork.xsd @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/jars/jdom.jar b/dol/jars/jdom.jar new file mode 100644 index 0000000..288e64c Binary files /dev/null and b/dol/jars/jdom.jar differ diff --git a/dol/jars/xercesImpl.jar b/dol/jars/xercesImpl.jar new file mode 100644 index 0000000..33990e8 Binary files /dev/null and b/dol/jars/xercesImpl.jar differ diff --git a/dol/src/MANIFEST.MF b/dol/src/MANIFEST.MF new file mode 100644 index 0000000..19165c3 --- /dev/null +++ b/dol/src/MANIFEST.MF @@ -0,0 +1,4 @@ +Manifest-Version: 1.0 +Main-Class: dol.main.Main +Created-By: Computer Engineering Group, Computer Engineering and Networks Laboratory, ETH Zurich +Class-Path: jars/xercesImpl.jar jars/jdom.jar \ No newline at end of file diff --git a/dol/src/docs/doxygen/doxygen.cfg b/dol/src/docs/doxygen/doxygen.cfg new file mode 100644 index 0000000..7e541a1 --- /dev/null +++ b/dol/src/docs/doxygen/doxygen.cfg @@ -0,0 +1,1078 @@ +# Doxyfile 1.3.4 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = DOL + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 1.0 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ../../../build/doxygen/ + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, +# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en +# (Japanese with English messages), Korean, Norwegian, Polish, Portuguese, +# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited +# members of a class in the documentation of that class as if those members were +# ordinary class members. Constructors, destructors and assignment operators of +# the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. It is allowed to use relative paths in the argument list. + +STRIP_FROM_PATH = ../../src + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explict @brief command for a brief description. + +JAVADOC_AUTOBRIEF = YES + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# reimplements. + +INHERIT_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = YES + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../../dol + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp +# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc + +FILE_PATTERNS = *.java + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories +# that are symbolic links (a Unix filesystem feature) are excluded from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. + +INPUT_FILTER = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 1 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +#HTML_HEADER = header.html + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +#HTML_FOOTER = footer.html + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output dir. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimised for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assigments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse the +# parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. Note that this +# option is superceded by the HAVE_DOT option below. This is only a fallback. It is +# recommended to install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similiar to the OMG's Unified Modeling +# Language. + +UML_LOOK = YES + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = /usr/local/bin/dot + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 600 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 600 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes that +# lay further from the root node will be omitted. Note that setting this option to +# 1 or 2 may greatly reduce the computation time needed for large code bases. Also +# note that a graph may be further truncated if the graph's image dimensions are +# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). +# If 0 is used for the depth value (the default), the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = YES diff --git a/dol/src/docs/doxygen/footer.html b/dol/src/docs/doxygen/footer.html new file mode 100644 index 0000000..20d26b2 --- /dev/null +++ b/dol/src/docs/doxygen/footer.html @@ -0,0 +1,3 @@ +
+

Generated on $datetime for $projectname by doxygen $doxygenversion

+ diff --git a/dol/src/docs/doxygen/header.html b/dol/src/docs/doxygen/header.html new file mode 100644 index 0000000..6efcc86 --- /dev/null +++ b/dol/src/docs/doxygen/header.html @@ -0,0 +1 @@ + diff --git a/dol/src/dol.properties b/dol/src/dol.properties new file mode 100644 index 0000000..56d50ac --- /dev/null +++ b/dol/src/dol.properties @@ -0,0 +1,15 @@ +# template for dol.properties file +# use ant config to fill in the values + +# SystemC library path: +# SYSTEMC_INC and SYSTEMC_LIB are the paths to SystemC header and library, +# respectively. These two path will be used in the generated Makefile to +# build the SystemC executable binary file. They have to point to local +# SystemC directory. +# +# example: +# SYSTEMC_INC = /home/shapes/base/resources/lib/systemC/systemc-2.1.v1/include +# SYSTEMC_LIB = /home/shapes/base/resources/lib/systemC/systemc-2.1.v1/lib-linux/libsystemc.a + +SYSTEMC_INC = /home/shapes/base/resources/lib/systemC/include +SYSTEMC_LIB = /home/shapes/base/resources/lib/systemC/lib-linux/libsystemc.a diff --git a/dol/src/dol/check/SanityCheck.java b/dol/src/dol/check/SanityCheck.java new file mode 100644 index 0000000..88f82db --- /dev/null +++ b/dol/src/dol/check/SanityCheck.java @@ -0,0 +1,419 @@ +/* $Id: SanityCheck.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.check; + +import java.util.Collections; +import java.util.Comparator; +import java.util.Vector; + +import dol.datamodel.architecture.ArchiResource; +import dol.datamodel.architecture.Architecture; +import dol.datamodel.architecture.Configuration; +import dol.datamodel.architecture.Processor; +import dol.datamodel.mapping.Mapping; +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Connection; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.Resource; + +/** + * Check semantic correctness of process network. + * + * This class checks + *
  • whether it is a processnetwork
  • + *
  • a channel only has two ports
  • + *
  • each channel port has only one peer port of process
  • + *
+ */ +public class SanityCheck { + /** + * Return the singleton instance of this class; + * + * @return the instance. + */ + public final static SanityCheck getInstance() { + return _instance; + } + + /** + * Check if the process network spec is correct + * + * @param pn processnetwork to check + */ + public void checkPN(ProcessNetwork pn) { + try { + _checkNameConflict(pn); + _checkChannelPorts(pn); + _checkChannelConnection(pn); + } + catch (Exception e) { + System.out.println("err: " + e.getMessage()); + //e.printStackTrace(); + System.exit(-1); + } + + try { + _checkProcessConnection(pn); + } + catch (Exception e) { + System.out.println("warning: " + e.getMessage()); + } + } + + /** + * Check if the architecture spec is correct + * + * @param arch architecture to check + */ + public void checkArch(Architecture arch) + { + try + { + _checkNameConflict(arch); + _checkNETSIM(arch); + _checkMaster(arch); + } + catch (Exception e) + { + System.out.println("err: " + e.getMessage()); + System.exit(-1); + } + } + + /** + * Check if the mapping spec is correct + * + * @param map mapping to check + */ + public void checkMap(Mapping map) + { + try + { + _checkMultibind(map); + _checkProcessesBound(map); + } + catch (Exception e) + { + System.out.println("err: " + e.getMessage()); + System.exit(-1); + } + } + + + /** + * Check name exclusiveness, including processes, channels, and + * connections. + * + * @param pn processnetwork to check + */ + private void _checkNameConflict(ProcessNetwork pn) throws Exception { + System.out.println("APPL: Checking resource name ..."); + + Vector n = new Vector(pn.getChannelList()); + n.addAll(pn.getProcessList()); + n.addAll(pn.getConnectionList()); + + //sort resources in n by name + Collections.sort(n, + new Comparator() + { + public int compare(Resource resource1, Resource resource2) { + return resource1.getName().compareTo(resource2.getName()); + } + } ); + + //test adjacent resources in n for equal name + for (int k = 0; k < n.size() - 1; k++) + { + if (((Resource) n.elementAt(k)).getName().equals( + ((Resource) n.elementAt(k + 1)).getName())) { + throw new Exception("Name conflict: " + + ((Resource)n.elementAt(k + 1)).getName() + + " appears (at least) twice."); + } + } + } + + /** + * Check number of ports for every channel. + * + * @param pn processnetwork to check + */ + private void _checkChannelPorts(ProcessNetwork pn) throws Exception { + System.out.println("APPL: Checking channel ports ..."); + + for (Channel c : pn.getChannelList()) { + if (c.getPortList().size() < 2) { + throw new Exception("channel ports less than 2: " + + c.getName()); + } + } + } + + /** + * Check whether all processes are connected. + * + * @param pn processnetwork to check + */ + private void _checkProcessConnection(ProcessNetwork pn) + throws Exception { + System.out.println("APPL: Checking Process connection ..."); + + String result = ""; + boolean hasUnused = false; + for (Process r : pn.getProcessList()) { + boolean flag = false; + for (Connection c : pn.getConnectionList()) { + Resource origin = c.getOrigin(); + Resource target = c.getTarget(); + if (r.getName().equals(origin.getName())) { + flag = true; break; + } else if (r.getName().equals(target.getName())) { + flag = true; break; + } + } + if (flag == false) { + hasUnused = true; + result += " " + r.getName(); + } + } + + if (hasUnused == true) + throw new Exception("process(es) without connection to channels:" + result); + } + + /** + * Check whether there are unused channels in the processnetwork. + * + * @param pn processnetwork to check + */ + private void _checkChannelConnection(ProcessNetwork pn) + throws Exception { + System.out.println("APPL: Checking channel connection ..."); + + String result = ""; + boolean hasUnused = false; + for (Channel r : pn.getChannelList()) { + boolean flag = false; + for (Connection c: pn.getConnectionList()) { + Resource origin = c.getOrigin(); + Resource target = c.getTarget(); + if (r.getName().equals(origin.getName())) { + flag = true; break; + } else if (r.getName().equals(target.getName())) { + flag = true; break; + } + } + if (flag == false) { + hasUnused = true; + result += " " + r.getName(); + } + } + + if (hasUnused == true) + throw new Exception("unused channel: " + result); + } + + + /** + * Check name exclusiveness, including both processors and memories. + * + * @param arch architecture to check + */ + private void _checkNameConflict(Architecture arch) throws Exception { + System.out.println("ARCH: Checking resource name ..."); + Vector n = new Vector(arch.getProcessorList()); + n.addAll(arch.getMemoryList()); + + //sort resources in n by name + Collections.sort(n, + new Comparator() + { + public int compare(ArchiResource resource1, ArchiResource resource2) { + return resource1.getName().compareTo(resource2.getName()); + } + } ); + + //test adjacent resources in n for equal name + for (int k = 0; k < n.size() - 1; k++) + { + if (((ArchiResource) n.elementAt(k)).getName().equals( + ((ArchiResource) n.elementAt(k + 1)).getName())) { + throw new Exception("Name conflict: " + + ((ArchiResource)n.elementAt(k + 1)).getName() + + " appears (at least) twice."); + } + } + } + + /** + * every processor of type NETSIM must have a configuration tag with + * name "address" and one with name "port". these address-port pairs + * have to be unique + * @param arch + * @throws Exception + */ + private void _checkNETSIM(Architecture arch) throws Exception + { + System.out.println("ARCH: Checking network simulators ..."); + + Vector sockets = new Vector(); + + for (Processor proc : arch.getProcessorList()) { + if ( proc.getType().equals("NETSIM") ) + { + if ( proc.getCfg("address") == null + || proc.getCfg("port") == null ) + { + throw new Exception("Processor " + proc.getName() + + " is of type NETSIM but address or port is missing"); + } + if ( proc.getCfg("address").equals("") + || proc.getCfg("port").equals("") ) + { + throw new Exception("Processor " + proc.getName() + + " has empty address or port"); + } + sockets.add(proc); // add processor to socket list + } + } + + /* socket comperator */ + Comparator sockComp = new Comparator() + { + public int compare(Processor proc1, Processor proc2) + { + String ad1, ad2; + ad1 = proc1.getCfg("address").getValue(); + ad2 = proc2.getCfg("address").getValue(); + + int comp = ad1.compareToIgnoreCase(ad2); + + if (comp != 0) + { + return comp; + } + else + { + String p1, p2; + p1 = proc1.getCfg("port").getValue(); + p2 = proc2.getCfg("port").getValue(); + + return p1.compareToIgnoreCase(p2); + } + } + }; + + + /* sort sockets */ + Collections.sort(sockets, sockComp); + + /* check for uniqueness */ + Processor proc1 = null; + Processor proc2 = null; + if (!sockets.isEmpty()) + proc1 = sockets.get(0); + for (int i=1; i processes = map.getProcessList(); + + //sort processes in n by name + Collections.sort(processes, + new Comparator() + { + public int compare(Process p1, Process p2) { + return p1.getName().compareTo(p2.getName()); + } + } ); + + //test adjacent origins for equal name + String o1 = null; + String o2 = null; + if (!processes.isEmpty()) + o1 = processes.get(0).getName(); + for (int k = 1; k < processes.size(); k++) + { + o2 = processes.get(k).getName(); + if (o1.equals(o2)) + { + throw new Exception("sw resource \"" + o1 + + "\" has multiple bindings"); + } + } + } + + /** + * Checks that every process is bound to a processor. + * @param map the map to check + * @throws Exception if not all processes are bound to a processor + */ + private void _checkProcessesBound(Mapping map) throws Exception + { + System.out.println("MAP: Checking that all processes have a binding ..."); + Vector boundList = map.getProcessList(); + Vector totalList = map.getPN().getProcessList(); + + if (boundList.size() != totalList.size()) + { + throw new Exception("some processes are not bound to a processor"); + } + } + + /** + * singleton instance + */ + private final static SanityCheck _instance = new SanityCheck(); +} diff --git a/dol/src/dol/check/package.html b/dol/src/dol/check/package.html new file mode 100644 index 0000000..685bef4 --- /dev/null +++ b/dol/src/dol/check/package.html @@ -0,0 +1,20 @@ + + + + + + +Consistency checker for DOL spcific XML files. + +

Package Specification

+ + + +

Related Documentation

+ + + + + + + diff --git a/dol/src/dol/datamodel/XmlTag.java b/dol/src/dol/datamodel/XmlTag.java new file mode 100644 index 0000000..bb87156 --- /dev/null +++ b/dol/src/dol/datamodel/XmlTag.java @@ -0,0 +1,76 @@ +/* $Id: XmlTag.java 203 2010-10-11 08:59:47Z dchokshi $ */ +package dol.datamodel; + + +/** + * Class to store XML tag for xml element + */ +public class XmlTag { + + /** + * Get a single instance of the XmlTag object. + */ + private final static XmlTag _instance = new XmlTag(); + + /** + * Constructor. Private since only a single version may exist. + */ + private XmlTag() {} + + /** + * returns the singleton instance of this class. + * + * @return The instance value + */ + public final static XmlTag getInstance() { return _instance; } + + // processnetwork XML tag + public final String getPNTag() { return "processnetwork";} + public final String getVariableTag() { return "variable";} + public final String getProcessTag() { return "process";} + public final String getSWChannelTag() { return "sw_channel";} + public final String getPortTag() { return "port";} + public final String getSourceTag() { return "source";} + public final String getProfilingTag() { return "profiling";} + + // architecture XML tag + public final String getArchiTag() { return "architecture";} + public final String getProcessorTag() { return "processor";} + public final String getMemoryTag() { return "memory";} + public final String getNodeTag() { return "node";} + public final String getInPortTag() { return "inputport";} + public final String getOutPortTag() { return "outputport";} + public final String getDuplexPortTag() { return "duplexport";} + public final String getHWChannelTag() { return "hw_channel";} + public final String getReadPathTag() { return "readpath";} + public final String getWritePathTag() { return "writepath";} + public final String getTXBufTag() { return "txbuf";} + public final String getRXBufTag() { return "rxbuf";} + public final String getCHBufTag() { return "chbuf";} + + // mapping XML tag + public final String getMappingTag() { return "mapping";} + public final String getBindingTag() { return "binding";} + public final String getScheduleTag() { return "schedule";} + public final String getResourceTag() { return "resource";} + + // common tag + public final String getConfigurationTag() { return "configuration";} + + //iterator related XML tag + public final String getIteratorTag() { return "iterator";} + public final String getFunctionTag() { return "function";} + public final String getAppendTag() { return "append";} + + // connection tag + public final String getConnectionTag() { return "connection";} + public final String getOriginTag() { return "origin";} + public final String getTargetTag() { return "target";} + + // processnetwork profiling value + public final String getProfilingTotalReadData() { return "TotalReadData";} + public final String getProfilingNumOfReads() { return "NumOfReads";} + public final String getProfilingNumOfWrites() { return "NumOfWrites";} + public final String getProfilingNumOfFires() { return "NumOfFires";} +} + diff --git a/dol/src/dol/datamodel/architecture/ArchiConnection.java b/dol/src/dol/datamodel/architecture/ArchiConnection.java new file mode 100644 index 0000000..9e2d713 --- /dev/null +++ b/dol/src/dol/datamodel/architecture/ArchiConnection.java @@ -0,0 +1,80 @@ +/* $Id: ArchiConnection.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.architecture; + +import dol.visitor.ArchiVisitor; + +/** + * This class defines an architecture connection. Used in the simplified + * architecture specification. An architecture connection contains one + * origin and one target resource. + */ +public class ArchiConnection extends ArchiResource { + /** + * Constructor to create an architecture connection with a name. + * + */ + public ArchiConnection(String name) { + super(name); + } + + /** + * Accept a Visitor. + * + * @param x visitor object + */ + public void accept(ArchiVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this architectural connection. + * + * @return a new instance of the architectural connection. + */ + public Object clone() { + ArchiConnection newObj = (ArchiConnection) super.clone(); + newObj.setOrigin(_origin); + newObj.setTarget(_target); + return (newObj); + } + + /** + * Return a string representation of the architectural connection. + * + * @return string representation of the architectural connection + */ + public String toString() { + return "ArchiConnection: " + getName(); + } + + /** + * Return the origin of the architectural connection. + * + * @return origin architectural resource of the architectural connection + */ + public ArchiResource getOrigin() { return _origin; } + + /** + * Set the origin of the architectural connection. + * + * @param origin architectural resource. + */ + public void setOrigin(ArchiResource origin) { _origin = origin; } + + /** + * Return the target of the architectural connection. + * + * @return target architectural resource of the architectural connection + */ + public ArchiResource getTarget() { return _target; } + + /** + * Set the target of the architectural connection. + * + * @param target architectural resource. + */ + public void setTarget(ArchiResource target) { _target = target; } + + protected ArchiResource _origin; + protected ArchiResource _target; +} diff --git a/dol/src/dol/datamodel/architecture/ArchiResource.java b/dol/src/dol/datamodel/architecture/ArchiResource.java new file mode 100644 index 0000000..04de406 --- /dev/null +++ b/dol/src/dol/datamodel/architecture/ArchiResource.java @@ -0,0 +1,254 @@ +/* $Id: ArchiResource.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.architecture; + +import java.util.Iterator; +import java.util.StringTokenizer; +import java.util.Vector; + +import dol.visitor.ArchiVisitor; + +/** + * This class is the basic class which abstracts an architectural resource + * of a generic architecture. The architectural resource has a name and a + * list of included nodes. + */ +public class ArchiResource implements Cloneable { + /** + * Constructor to create an architectural resource with a name and + * an empty node list. + */ + public ArchiResource(String name) { + _name = name; + _basename = name; + _nodeList = new Vector(); + _cfgList = new Vector(); + } + + /** + * Accept a Visitor + * + * @param x visitor object + */ + public void accept(ArchiVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this architectural resource. + * + * @return new instance of the architectural resource. + */ + @SuppressWarnings("unchecked") + public Object clone() { + try { + ArchiResource newObj = (ArchiResource) super.clone(); + newObj.setName(_name); + newObj.setBasename(_basename); + newObj.setNodeList((Vector)_nodeList.clone() ); + newObj.setCfgList((Vector)_cfgList.clone() ); + return (newObj); + } catch (CloneNotSupportedException e) { + System.out.println("Error Clone not Supported"); + } + return null; + } + + /** + * Get the name of this architectural resource. + * + * @return name of the architectural resource + */ + public String getName() { + return _name; + } + + /** + * Set the name of this architectural resource. + * + * @param name name of the architectural resource + */ + public void setName(String name) { + _name = name; + } + + /** + * Get the basename of this architectural resource. + * + * @return basename of the architectural resource + */ + public String getBasename() { + return _basename; + } + + /** + * Set the basename of this architectural resource. + * + * @param basename name of the architectural resource + */ + public void setBasename(String basename) { + _basename = basename; + } + + /** + * Get the iterator indices of this process. + * + * @return range + */ + public Vector getIteratorIndices() { + Vector indices = new Vector(); + StringTokenizer tokenizer = + new StringTokenizer(_name.replaceAll(_basename, ""), "_"); + while (tokenizer.hasMoreTokens()) { + indices.add(Integer.valueOf(tokenizer.nextToken())); + } + return indices; + } + + /** + * Get the list of nodes of this architectural resource. + * + * @return list of nodes + */ + public Vector getNodeList() { + return _nodeList; + } + + /** + * Set the list of nodes of this architectural resource. + * + * @param nodeList nodes list + */ + public void setNodeList(Vector nodeList) { + _nodeList = nodeList; + } + + /** + * Get the hierarchical parent of this architectural resource. + * + * @return parent of this architectural resource + */ + public ArchiResource getParentResource() { + return _parentResource; + } + + /** + * Set the hierarchical parent of this architectural resource. + * + * @param parentResource new parent + */ + public void setParentResource(ArchiResource parentResource) { + _parentResource = parentResource; + } + + /** + * Return a string representation of the architectural resource. + * + * @return string representation of the architectural resource + */ + public String toString() { + return "ArchiResource: " + _name; + } + + /** + * Return a node (which has a specific name). Return null when node + * cannot be found. + * + * @param name of the node to search for + * @return node with the specified name + */ + public Node getNode(String name) { + Iterator i; + i = _nodeList.iterator(); + while (i.hasNext()) { + Node node = i.next(); + if (node.getName().equals(name)) { + return node; + } + } + return null; + } + + /** + * Return a node. Return null when node cannot be found. + * + * @return node + */ + public Node getNode() { + Iterator i; + i = _nodeList.iterator(); + while (i.hasNext()) { + Node node = i.next(); + return node; + } + return null; + } + + /** + * Has this resource nodes? + * + * @return boolean value + */ + public boolean hasNodes() { + return !_nodeList.isEmpty(); + } + + + /** + * Return the first node of the nodelist. + * + * @return the first node of the nodelist. + */ + public Node getFirstNode() { + return (Node) _nodeList.firstElement(); + } + + /** + * Get the list of configurations of this resource. + * + * @return list of configurations + */ + public Vector getCfgList() { + return _cfgList; + } + + /** + * Set the list of configurations of this resource. + * + * @param cfgList configuration list + */ + public void setCfgList(Vector cfgList) { + _cfgList = cfgList; + } + + /** + * Return a configuration which has a specific name. Return + * null when configuration cannot be found. + * + * @param name name of the configuration to search for + * @return configuration with the specified name + */ + public Configuration getCfg(String name) { + for (Configuration config : _cfgList) { + if (config.getName().equals(name)) { + return config; + } + } + return null; + } + + + /** list of the configurations of the ArchiResource */ + protected Vector _cfgList = null; + + /** name of the architectural resource */ + protected String _name = null; + + /** basename of the architectural resource, if no basename, store the name */ + protected String _basename = null; + + /** list of the nodes, paths of the architectural resource */ + protected Vector _nodeList = null; + + /** parent resource of this architectural resource */ + protected ArchiResource _parentResource = null; +} diff --git a/dol/src/dol/datamodel/architecture/Architecture.java b/dol/src/dol/datamodel/architecture/Architecture.java new file mode 100644 index 0000000..06d510d --- /dev/null +++ b/dol/src/dol/datamodel/architecture/Architecture.java @@ -0,0 +1,400 @@ +/* $Id: Architecture.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.architecture; + +import java.util.Hashtable; +import java.util.Vector; + +import dol.visitor.ArchiVisitor; + + +/** + * This class defines an architecture. + */ +public class Architecture extends ArchiResource { + /** + * Constructor to create an architecture with a name, + * empty processor list, empty memory list, empty hwChannel list and empty connection list. + */ + public Architecture(String name) { + super(name); + _processorList = new Vector(); + _memoryList = new Vector(); + _hwChannelList = new Vector(); + _varList = new Vector(); + _connectionList = new Vector(); + _readPathList = new Vector(); + _writePathList = new Vector(); + _pathList = new Vector(); + _processorPathList = new Hashtable>>(); + + } + + /** + * Accept a visitor + * + * @param x visitor object + */ + public void accept(ArchiVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this Architecture. + * + * @return new instance of the Architecure + */ + /* + @SuppressWarnings("unchecked") + public Object clone() { + Architecture newObj = (Architecture) super.clone(); + newObj.setProcessorList((Vector)_processorList.clone()); + newObj.setMemoryList((Vector)_memoryList.clone()); + newObj.setHWChannelList((Vector)_hwChannelList.clone()); + newObj.setVarList((Vector)_varList.clone()); + newObj.setConnectionList((Vector)_connectionList.clone()); + newObj.setReadPathList((Vector)_readPathList.clone()); + newObj.setWritePathList((Vector)_writePathList.clone()); + newObj.setPathList((Vector>)_pathList.clone()); + return newObj; + } + */ + + + /** + * Get the processor list of a Architecture. + * + * @return the processor list + */ + public Vector getProcessorList() { + return _processorList; + } + + /** + * Get the memory list of a Architecture. + * + * @return the memory list + */ + public Vector getMemoryList() { + return _memoryList; + } + + /** + * Get the hwChannel list of a Architecture. + * + * @return the hwChannel list + */ + public Vector getHWChannelList() { + return _hwChannelList; + } + + /** + * Get the paths list of a Architecture. + * + * @return the paths list + */ + public Vector getReadPathList() { + return _readPathList; + } + + /** + * Get the write paths list of a Architecture. + * + * @return the paths list + */ + public Vector getWritePathList( ) { + return _writePathList; + } + + /** + * Set the processor paths list of a Architecture. + * + * @param pathList The new list + */ + public void setPathList(Vector pathList) { + _pathList = pathList; + } + + /** + * Get the processor paths list of a Architecture. + * + * @return the processor paths list + */ + public Vector getPathList() { + return _pathList; + } + + /** + * Return a processor/memory/hwChannel which has a specific name. Return null if + * processor cannot be found. + * + * @param name the name of the processor/memory/hwChannel to search for. + * @return the processor/memory/hwChannel with the specific name. + */ + public Processor getProcessor(String name) { + for (Processor processor : _processorList) { + if (processor.getName().equals(name)) { + return processor; + } + } + return null; + } + + /** + * + */ + public Memory getMemory(String name) { + for (Memory memory : _memoryList) { + if (memory.getName().equals(name)) { + return memory; + } + } + return null; + } + + /** + * + */ + public HWChannel getHWChannel(String name) { + for (HWChannel hwChannel : _hwChannelList) { + if (hwChannel.getName().equals(name)) { + return hwChannel; + } + } + return null; + } + + + /** + * Return a read path which has a specific name. Return null if + * not found. + * + * @param name the name of the read path to search for. + * @return the read path with the specific name. + */ + public ReadPath getReadPath(String name) { + for (ReadPath p : _readPathList) { + if (p.getName().equals(name)) { + return p; + } + } + return null; + } + + /** + * Return a write path which has a specific name. Return null if + * not found. + * + * @param name the name of the write path to search for. + * @return the write path with the specific name. + */ + public WritePath getWritePath(String name) { + for (WritePath p : _writePathList) { + if (p.getName().equals(name)) { + return p; + } + } + return null; + } + + public Vector getVarList() { return _varList; } + + public Vector getConnectionList() { + return _connectionList; + } + + /** + * Compute all paths between processors. + */ + public void computePaths() { + for (WritePath w : _writePathList) { + String channelBuffer = w.getCHBuf().getName(); + for (ReadPath r : _readPathList) { + if (r.getCHBuf().getName().equals(channelBuffer)) { + Path path = new Path(); + path.setWritePath(w); + path.setReadPath(r); + _pathList.add(path); + } + } + } + + /* + //print all paths in this architecture + for (int j = 0; j < _pathList.size(); j++) { + Vector path = _pathList.elementAt(j).getPath(); + for (int k = 0; k < path.size(); k++) { + System.out.print(path.elementAt(k). + getName() + (k < path.size() - 1 ? " -> " : "")); + } + System.out.println(); + } + System.out.println("Found " + _pathList.size() + " paths."); + */ + + computeProcessorPath(); + } + + /** + * Compute all write path from one processor to another processor + * in this architecture. + */ + protected void computeProcessorPath() { + //iterate over all path in this architecture + for (int j = 0; j < _pathList.size(); j++) { + Processor startProcessor = _pathList.elementAt(j).getStartProcessor(); + Processor targetProcessor = _pathList.elementAt(j).getTargetProcessor(); + + //create new hashtable entry for this start processor + if (!_processorPathList.containsKey(startProcessor)) { + Hashtable> + processorPathList = new Hashtable>(); + _processorPathList.put(startProcessor, processorPathList); + } + + Hashtable> + processorPathList = _processorPathList. + get(startProcessor); + + //create new path list for this target processor + if(!processorPathList.containsKey(targetProcessor)) { + Vector processorPath = new Vector(); + processorPathList.put(targetProcessor, processorPath); + } + + Vector processorPath = + processorPathList.get(targetProcessor); + + //add this path to the list of paths + processorPath.add(_pathList.elementAt(j)); + } + + /* + //print all processor to processor path + int pathCounter = 0; + for (int j = 0; j < _processorList.size(); j++) { + for (int k = 0; k < _processorList.size(); k++) { + Vector processorPathList = + getPaths(_processorList.elementAt(j), + _processorList.elementAt(k)); + for (int l = 0; l < processorPathList.size(); l++) { + pathCounter++; + Vector path = processorPathList. + elementAt(l).getPath(); + for (int m = 0; m < path.size(); m++) { + System.out.print(path.elementAt(m).getName() + + (m < path.size() - 1 ? " -> " : "")); + } + System.out.println(); + } + } + } + System.out.println("Found " + pathCounter + " paths."); + */ + } + + /** + * Get all write paths from the given start processor to the given + * target processor. + * + * @param startProcessor processor where write path begins + * @param targetProcessor processor where write path ends + * @return vector of all write paths between startProcessor and + * targetProcessor + */ + public Vector getPaths( + Processor startProcessor, Processor targetProcessor) { + if (_processorPathList.get(startProcessor) == null) { + return null; + } + return _processorPathList.get(startProcessor).get(targetProcessor); + } + + /** + * Register the RX/TX/CH buffer to each resource. + * Can be used for dotty generation. + */ + public void registerRWPath2Resource() + { + for (ReadPath r : _readPathList) { + // register rxbuf + String memName = r.getRXBuf().getName(); + for (Memory m : _memoryList) { + if (m.getName().equals(memName)) { + m.getRXBufList().add(r.getName()); + } + } + + // register chbuf + memName = r.getCHBuf().getName(); + for (Memory m : _memoryList) { + if (m.getName().equals(memName)) { + m.getCHBufList().add(r.getName() + "_RPath"); + } + } + + // register pathes via a communication resource + for (HWChannel c : r.getHWChannelList()) { + if (c.getName().equals(r.getName())) { + // premise: a path cannot go via a bus twice. + c.getPathList().add(r.getName() + "_RPath"); + } + } + } + + for (WritePath w : _writePathList) { + // register txbuf + String memName = w.getTXBuf().getName(); + for (Memory m : _memoryList) { + if (m.getName().equals(memName)) { + m.getTXBufList().add(w.getName()); + } + } + + // register chbuf + memName = w.getCHBuf().getName(); + for (Memory m : _memoryList) { + if (m.getName().equals(memName)) { + m.getCHBufList().add(w.getName() + "_WPath"); + } + } + + // register pathes via a communication resource + for (HWChannel c : w.getHWChannelList()) { + if (c.getName().equals(w.getName())) { + // premise: a path cannot go via a bus twice. + c.getPathList().add(w.getName() + "_WPath"); + } + } + } + } + + /** List of the processors in the Architecture */ + protected Vector _processorList = null; + + /** List of the memories in the Architecture */ + protected Vector _memoryList = null; + + /** List of hwChannels in the Architecture */ + protected Vector _hwChannelList = null; + + /** List of variables in the Architecture */ + protected Vector _varList = null; + + /** List of connections in the Architecture: for simplified arch*/ + protected Vector _connectionList = null; + + /** List of read paths in the Architecture: for detail arch */ + protected Vector _readPathList = null; + + /** List of write paths in the Architecture: for detail arch */ + protected Vector _writePathList = null; + + /** List of paths in the Architecture */ + protected Vector _pathList = null; + + /** hashtable to access all processor to processor path */ + protected Hashtable>> _processorPathList = null; +} diff --git a/dol/src/dol/datamodel/architecture/Configuration.java b/dol/src/dol/datamodel/architecture/Configuration.java new file mode 100644 index 0000000..b370b95 --- /dev/null +++ b/dol/src/dol/datamodel/architecture/Configuration.java @@ -0,0 +1,113 @@ +/* $Id: Configuration.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.architecture; + + +/** + * This class represents a name-value pair of a configuration tag in XML. + */ +public class Configuration { + + /** + * Constructor to create a Configuration. + */ + public Configuration(String name) { + _name = name; + } + + /** + * Accept a Visitor. + * + * @param x visitor object + + public void accept(PNVisitor x) { + x.visitComponent(this); + } + */ + + + /** + * Clone this Configuration. + * + * @return new instance of the Configuration. + */ + public Object clone() { + try { + Configuration newObj = (Configuration) super.clone(); + newObj.setName(_name); + newObj.setValue(_value); + return (newObj); + } catch (CloneNotSupportedException e) { + System.out.println("Error Clone not Supported"); + } + return null; + } + + /** + * Get the value of the Configuration. + * + * @return the value of the configuration. + */ + public String getValue() { + return _value; + } + + /** + * Set the value of the Configuration. + * + * @param value the value of the configuration. + */ + public void setValue(String value) { + _value = value; + } + + /** + * Get the name of this configuration. + * + * @return the name + */ + public String getName() { + return _name; + } + + /** + * Set the name of this configuration. + * + * @param name name of the configuration + */ + public void setName(String name) { + _name = name; + } + + /** + * Get the hierarchical parent of this resource. + * + * @return parent of this resource + + public Resource getParentResource() { + return _parentResource; + } + */ + + /** + * Set the hierarchical parent of this resource. + * + * @param parentResource new parent + + public void setParentResource(Resource parentResource) { + _parentResource = parentResource; + } + */ + + /** + * Return a string representation of the Configuration. + * + * @return string representation of the Configuration + */ + public String toString() { + return "Configuration: " + getName(); + } + + protected String _value = null; + protected String _name = null; + protected ArchiResource _parentResource = null; +} diff --git a/dol/src/dol/datamodel/architecture/HWChannel.java b/dol/src/dol/datamodel/architecture/HWChannel.java new file mode 100644 index 0000000..f4ed94e --- /dev/null +++ b/dol/src/dol/datamodel/architecture/HWChannel.java @@ -0,0 +1,128 @@ +/* $Id: HWChannel.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.architecture; + +import java.util.Iterator; +import java.util.Vector; + +import dol.visitor.ArchiVisitor; + +/** + * This class represents an interconnect element in the architecture. + */ +public class HWChannel extends ArchiResource { + /** + * Constructor to create a HWChannel with a name and an empty + * nodeList. + */ + public HWChannel(String name) { + super(name); + _pathList = new Vector(); + } + + /** + * Accept a Visitor + * @param x A Visitor Object. + */ + public void accept(ArchiVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this HWChannel + * + * @return a new instance of the HWChannel. + */ + @SuppressWarnings("unchecked") + public Object clone() { + HWChannel newObj = (HWChannel) super.clone(); + newObj.setPathList((Vector)_pathList.clone()); + return (newObj); + } + + /** + * Get the range of this processor. + * + * @return range + */ + public String getRange() { + return _range; + } + + /** + * Set the range of this process. + * + * @param range new range value + */ + public void setRange(String range) { + _range= range; + } + + /** + * Get the type of this hw_channel. + * + * @return type + */ + public String getType() { + return _type; + } + + /** + * Set the type of this hw_channel. + * + * @param type new range value + */ + public void setType(String type) { + _type= type; + } + + /** + * Has this processor nodes? + * + * @return boolean value + */ + public boolean hasNodes() { + Iterator i = getNodeList().iterator(); + while (i.hasNext()) { + i.next(); + return true; + } + return false; + } + + /** + * Get the list of pathes via this resource. + * + * @return list of path. + */ + public Vector getPathList() { + return _pathList; + } + + /** + * Set the list of pathes via this resource. + * + * @param list path list + */ + public void setPathList(Vector list) { + _pathList = list; + } + + /** + * Return a description of the processor. + * + * @return a description of the processor. + */ + public String toString() { + return "HWChannel: " + getName() ; + } + + /** + * Range of the iterator when the instance belongs to an iterated + * series of processors. + */ + protected String _range; + protected String _type; + + // Store the name of pathes which go via this communication resource. + protected Vector _pathList; +} diff --git a/dol/src/dol/datamodel/architecture/Memory.java b/dol/src/dol/datamodel/architecture/Memory.java new file mode 100644 index 0000000..f7efe33 --- /dev/null +++ b/dol/src/dol/datamodel/architecture/Memory.java @@ -0,0 +1,170 @@ +/* $Id: Memory.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.architecture; + +import java.util.Iterator; +import java.util.Vector; + +import dol.visitor.ArchiVisitor; + +/** + * This class represents a memory element in the archietcture. + */ +public class Memory extends ArchiResource { + /** + * Constructor to create a Memory with a name and an empty + * nodeList. + */ + public Memory(String name) { + super(name); + _rxBufList = new Vector(); + _txBufList = new Vector(); + _chBufList = new Vector(); + } + + /** + * Accept a Visitor + * @param x A Visitor Object. + */ + public void accept(ArchiVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this Memory + * + * @return a new instance of the Memory. + */ + @SuppressWarnings("unchecked") + public Object clone() { + Memory newObj = (Memory) super.clone(); + newObj.setRXBufList((Vector)_rxBufList.clone()); + newObj.setTXBufList((Vector)_txBufList.clone()); + newObj.setCHBufList((Vector)_chBufList.clone()); + return (newObj); + } + + /** + * Get the range of this Memory. + * + * @return range + */ + public String getRange() { + return _range; + } + + /** + * Set the range of this Memory. + * + * @param range new range value + */ + public void setRange(String range) { + _range= range; + } + + /** + * Get the type of this Memory. + * + * @return type + */ + public String getType() { + return _type; + } + + /** + * Set the type of this Memory. + * + * @param type new range value + */ + public void setType(String type) { + _type= type; + } + + /** + * Get the list of RXBuf of this memory + * + * @return list of RX buffer. + */ + public Vector getRXBufList() { + return _rxBufList; + } + + /** + * Set the list of RXBuf of this memory. + * + * @param list RX buffer list + */ + public void setRXBufList(Vector list) { + _rxBufList = list; + } + + /** + * Get the list of TXBuf of this memory. + * + * @return list of TX buffers. + */ + public Vector getTXBufList() { + return _txBufList; + } + + /** + * Set the list of TXBuf of this memory. + * + * @param list TX buffer list + */ + public void setTXBufList(Vector list) { + _txBufList = list; + } + + /** + * Get the list of channel buffers of this memory. + * + * @return list of channel buffers. + */ + public Vector getCHBufList() { + return _chBufList; + } + + /** + * Set the list of channel Buf of this memory. + * + * @param list channel buffer list + */ + public void setCHBufList(Vector list) { + _chBufList = list; + } + + /** + * Has this memory nodes? + * + * @return boolean value + */ + public boolean hasNodes() { + Iterator i = getNodeList().iterator(); + while (i.hasNext()) { + i.next(); + return true; + } + return false; + } + + /** + * Return a description of the Memory. + * + * @return a description of the Memory. + */ + public String toString() { + return "Memory: " + getName() ; + } + + /** + * Range of the iterator when the instance belongs to an iterated + * series of Memories. + */ + protected String _range; + protected String _type; + + // store the name of rx, tx channel buffer, can be used for dotty gen. + protected Vector _rxBufList; + protected Vector _txBufList; + protected Vector _chBufList; +} diff --git a/dol/src/dol/datamodel/architecture/Node.java b/dol/src/dol/datamodel/architecture/Node.java new file mode 100644 index 0000000..89d51b8 --- /dev/null +++ b/dol/src/dol/datamodel/architecture/Node.java @@ -0,0 +1,211 @@ +/* $Id: Node.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.architecture; + +import java.util.Vector; + +import dol.visitor.ArchiVisitor; + +/** + * This class represents a node in the archietcture. + */ +public class Node implements Cloneable { + + /** + * Constructor to create a Node with a name and an empty + * portList. + */ + public Node(String name) { + _name = name; + _basename = name; + _portList = new Vector(); + } + + /** + * Accept a Visitor + * @param x A Visitor Object. + */ + public void accept(ArchiVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this Node + * + * @return a new instance of the Node. + */ + public Object clone() { + try { + Node newObj = (Node) super.clone(); + newObj.setName(_name); + newObj.setBasename(_basename); + return (newObj); + } catch (CloneNotSupportedException e) { + System.out.println("Error Clone not Supported"); + } + return null; + } + + /** + * Get the range of this node. + * + * @return range + */ + public String getRange() { + return _range; + } + + /** + * Set the range of this node. + * + * @param range new range value + */ + public void setRange(String range) { + _range= range; + } + + + /** + * Get the name of this node. + * + * @return name of the node + */ + public String getName() { + return _name; + } + + /** + * Set the name of this node. + * + * @param name name of the node + */ + public void setName(String name) { + _name = name; + } + + /** + * Get the basename of this node. + * + * @return basename of the node + */ + public String getBasename() { + return _basename; + } + + /** + * Set the basename of this node. + * + * @param basename name of the node + */ + public void setBasename(String basename) { + _basename = basename; + } + + /** + * Has this node IN/OUT/INOUT ports? + * + * @return boolean value + */ + public boolean hasInPorts() { + for (PortNode port : getPortList()) { + if (port.isInPort()) + return true; + } + return false; + } + + public boolean hasOutPorts() { + for (PortNode port : getPortList()) { + if (port.isOutPort()) + return true; + } + return false; + } + + public boolean hasInOutPorts() { + for (PortNode port : getPortList()) { + if (port.isInOutPort()) + return true; + } + return false; + } + + /** + * Return a port which has a specific name. Return null when port + * cannot be found. + * + * @param name name of the port to search for + * @return port with the specified name + */ + public PortNode getPort(String name) { + for (PortNode port : getPortList()) { + if (port.getName().equals(name)) { + return port; + } + } + return null; + } + + /** + * Return the first port on the List. + * + * @return first port element + */ + public PortNode getFirstPort() { + return (PortNode) _portList.firstElement(); + } + + /** + * Get the corresponding ArchiResource. + * + * @return the corresponding ArchiResource + */ + public ArchiResource getCorrespResource() { + return _correspResource; + } + + /** + * Set the corresponding ArchiResource. + * + * @param correspResource new ArchiResource + */ + public void setCorrespResource(ArchiResource correspResource) { + _correspResource = correspResource; + } + + /** + * Get the port list of a Node. + * + * @return the port list + */ + public Vector getPortList() { + return _portList; + } + + /** + * Set the port list of a Node. + * + * @param portList The new list + */ + public void setPortList( Vector portList ) { + _portList = portList; + } + + /** + * Return a description of the node. + * + * @return a description of the node. + */ + public String toString() { + return "Node: " + getName(); + } + + /** + * Range of the iterator when the instance belongs to an iterated + * series of nodes. + */ + protected String _range; + protected String _name = null; + protected String _basename = null; + protected ArchiResource _correspResource = null; + protected Vector _portList = null; +} diff --git a/dol/src/dol/datamodel/architecture/Path.java b/dol/src/dol/datamodel/architecture/Path.java new file mode 100644 index 0000000..c18084a --- /dev/null +++ b/dol/src/dol/datamodel/architecture/Path.java @@ -0,0 +1,118 @@ +/* $Id: Path.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.architecture; + +import java.util.Iterator; +import java.util.Vector; + +/** + * Path consisting of write path and read path. + */ +public class Path { + /** + * Default constructor. + */ + public Path() { + _path = new Vector(); + } + + /** + * Set the read path of this path. + */ + public void setReadPath(ReadPath readPath) { + _readPath = readPath; + computeArchitectureResources(); + } + + /** + * Return the read path of this path. + * + * @return read path + */ + public ReadPath getReadPath() { + return _readPath; + } + + /** + * Set the write path of this path. + */ + public void setWritePath(WritePath writePath) { + _writePath = writePath; + computeArchitectureResources(); + } + + /** + * Return the write path of this path. + * + * @return write path + */ + public WritePath getWritePath() { + return _writePath; + } + + /** + * Return all resources contained in this path. + * + * @return all resources contained in this path + */ + public Vector getPath() { + return _path; + } + + /** + * Return the processor where this path starts. + * + * @return processor where this path starts + */ + public Processor getStartProcessor() { + if (_path.size() == 0) + return null; + + return (Processor)_path.elementAt(0); + } + + /** + * Return the processor where this path ends. + * + * @return processor where this path ends + */ + public Processor getTargetProcessor() { + if (_path.size() == 0) + return null; + + return (Processor)_path.elementAt(_path.size() - 1); + } + + /** + * Compute the vector of all resources contained in this path. + */ + protected void computeArchitectureResources() { + _path.clear(); + + if (_readPath == null || _writePath == null) + return; + + _path.add(_writePath.getProcessor()); + _path.add(_writePath.getTXBuf()); + Iterator channelIterator = + _writePath.getHWChannelList().iterator(); + while (channelIterator.hasNext()) { + _path.add(channelIterator.next()); + } + _path.add(_readPath.getCHBuf()); + channelIterator = _readPath.getHWChannelList().iterator(); + while (channelIterator.hasNext()) { + _path.add(channelIterator.next()); + } + _path.add(_readPath.getRXBuf()); + _path.add(_readPath.getProcessor()); + } + + /** read path of this path*/ + protected ReadPath _readPath = null; + + /** write path of this path */ + protected WritePath _writePath = null; + + /** resources contained in this path */ + Vector _path; +} diff --git a/dol/src/dol/datamodel/architecture/PortNode.java b/dol/src/dol/datamodel/architecture/PortNode.java new file mode 100644 index 0000000..2db5cd1 --- /dev/null +++ b/dol/src/dol/datamodel/architecture/PortNode.java @@ -0,0 +1,253 @@ +/* $Id: PortNode.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.architecture; + +import dol.visitor.ArchiVisitor; + +/** + * This class represents a port of an architectural node. + */ +public class PortNode implements Cloneable { + /** + * Constructor to create a PortNode with a name. + */ + public PortNode(String name) { + _name = name; + _isInPort = false; + _isOutPort = false; + _isInOutPort = false; + } + + /** + * Constructor to create a PortNode with a name and a type. + */ + public PortNode(String name, boolean type) { + _name = name; + _isInPort = (type == INPORT); + _isOutPort = (type == OUTPORT); + _isInOutPort = (type == INOUTPORT); + } + + /** + * Accept a visitor. + * + * @param x visitor object + */ + public void accept(ArchiVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this PortNode + * + * @return new instance of the PortNode + */ + public Object clone() { + try { + PortNode newObj = (PortNode) super.clone(); + newObj.setName(_name); + newObj.setBasename(_basename); + newObj.setPeerPort(_peerPort); + newObj.setPeerResource(_peerResource); + newObj.setPeerNode(_peerNode); + newObj.setResource(_resource ); + newObj.setNode(_node); + return (newObj); + } catch (CloneNotSupportedException e) { + System.out.println("Error Clone not Supported"); + } + return null; + } + + /** + * Check whether this port is an inport. + * + * @return true if this port is an inport, otherwise false + */ + public boolean isInPort() { + return _isInPort; + } + + /** + * Check whether this port is an outport. + * + * @return true if this port is an outport, otherwise false + */ + public boolean isOutPort() { + return _isOutPort; + } + + /** + * Check whether this port is an inoutport. + * + * @return true if this port is an inoutport, otherwise false + */ + public boolean isInOutPort() { + return _isInOutPort; + } + + /** + * Get the name of this port. + * + * @return name of the port + */ + public String getName() { + return _name; + } + + /** + * Set the name of this port. + * + * @param name name of the port + */ + public void setName(String name) { + _name = name; + } + + public void setBasename(String basename) { _basename = basename; } + public String getBasename() { return _basename; } + + /** + * Get the range of this port. + * + * @return range of the port + */ + public String getRange() { + return _range; + } + + /** + * Set the range of this port. + * + * @param range range of the port + */ + public void setRange(String range) { + _range= range; + } + + /** + * Get the resource/node of this port. + * + * @return the resource/node + */ + public ArchiResource getResource() { + return _resource; + } + public Node getNode() { + return _node; + } + + /** + * Set the resource/node of this port. + * + * @param resource + */ + public void setResource(ArchiResource resource) { + _resource = resource; + } + public void setNode(Node node) { + _node = node; + } + + /** + * Set the peer resource/node/port of this port. + * + * @param peer The new node + */ + public void setPeerPort(PortNode peer) { _peerPort = peer; } + + /** + * + */ + public void setPeerResource(ArchiResource n) { _peerResource = n; } + + /** + * + */ + public void setPeerNode(Node n) { _peerNode = n; } + + /** + * Get the peer resource/node/port of this port. + * + * @return the peer resource/node/port + */ + public PortNode getPeerPort(){ return _peerPort; } + + /** + * + */ + public ArchiResource getPeerResource() { return _peerResource; } + + /** + * + */ + public Node getPeerNode() { return _peerNode; } + + /** + * Get the type of this port. + * + * @return type of this port + */ + public String getType() { + if (_isInPort) return "input"; + if (_isOutPort) return "output"; + if (_isInOutPort) return "duplex"; + return "type not set."; + } + + /** + * Return a string representation of the port. + * + * @return string representation of the port + */ + public String toString() { + return "PortNode: " + _name; + } + + /** constant for inport for usage in the constructor **/ + public static final boolean INPORT = true; + + /** constant for outport for usage in the constructor **/ + public static final boolean OUTPORT = false; + + /** constant for inoutport for usage in the constructor **/ + public static final boolean INOUTPORT = false; + + /** defines whether this port is an inport **/ + protected boolean _isInPort = false; + + /** defines whether this port is an outport **/ + protected boolean _isOutPort = false; + + /** defines whether this port is an inout **/ + protected boolean _isInOutPort = false; + + /** name of the port */ + protected String _name = null; + + /** basename of the resource, if no basename, store the name */ + protected String _basename = null; + + /** resource (process or channel) this port belongs to */ + protected ArchiResource _resource = null; + + /** node this port belongs to */ + protected Node _node = null; + + /** resource which peerPort belongs to */ + protected ArchiResource _peerResource = null; + + /** node which peerPort belongs to */ + protected Node _peerNode = null; + + /** connected peer port name */ + protected PortNode _peerPort = null; + + /** peer channel name */ + protected String _channelName = null; + + /** + * Range of the iterator when the instance belongs to an iterated + * series of ports. + */ + protected String _range = null; +} diff --git a/dol/src/dol/datamodel/architecture/Processor.java b/dol/src/dol/datamodel/architecture/Processor.java new file mode 100644 index 0000000..cffc781 --- /dev/null +++ b/dol/src/dol/datamodel/architecture/Processor.java @@ -0,0 +1,135 @@ +/* $Id: Processor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.architecture; + +import java.util.Vector; + +import dol.datamodel.pn.Process; +import dol.visitor.ArchiVisitor; + +/** + * This class represents a processor element in the architecture. + */ +public class Processor extends ArchiResource { + + /** + * Constructor to create a Processor with a name and an empty + * nodeList. + */ + public Processor(String name) { + super(name); + _processList = new Vector(); + } + + /** + * Accept a Visitor + * @param x A Visitor Object. + */ + public void accept(ArchiVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this Processor + * + * @return a new instance of the Processor. + */ + @SuppressWarnings("unchecked") + public Object clone() { + Processor newObj = (Processor) super.clone(); + newObj.setProcessList((Vector)_processList.clone()); + return (newObj); + } + + /** + * Get the range of this processor. + * + * @return range + */ + public String getRange() { + return _range; + } + + /** + * Set the range of this process. + * + * @param range new range value + */ + public void setRange(String range) { + _range= range; + } + + /** + * Get the type of this processor. + * + * @return type + */ + public String getType() { + return _type; + } + + /** + * Set the type of this processor. + * + * @param type new range value + */ + public void setType(String type) { + _type= type; + } + + + + /** + * Set the list of processes bound to this processor. + * @param processList the new process list + */ + public void setProcessList(Vector processList) + { + _processList = processList; + } + + /** + * Get the list of processes bound to this processor. + */ + public Vector getProcessList() + { + return _processList; + } + + /** + * Indicates if a process with a specific name is bound + * to this processor. + * @param name the name of the process to search for + * @return true if a process with the specifed name is bound to this + * processor + */ + public boolean hasProcess(String name) + { + for (Process iter : _processList) { + if (iter.getName().equals(name)) + return true; + } + + return false; + } + + /** + * Return a description of the processor. + * + * @return a description of the processor. + */ + public String toString() { + return "Processor: " + getName() ; + } + + /** + * Range of the iterator when the instance belongs to an iterated + * series of processors. + */ + protected String _range; + protected String _type; + + /** + * List of processes bound to this processor. + */ + protected Vector _processList; +} diff --git a/dol/src/dol/datamodel/architecture/ReadPath.java b/dol/src/dol/datamodel/architecture/ReadPath.java new file mode 100644 index 0000000..ce380c1 --- /dev/null +++ b/dol/src/dol/datamodel/architecture/ReadPath.java @@ -0,0 +1,115 @@ +/* $Id: ReadPath.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.architecture; + +import java.util.Vector; + +import dol.visitor.ArchiVisitor; + +/** + * This class defines a read path. A read path contains one processor, + * one rxbuf, one channel buf, and one or more hw channels. + */ +public class ReadPath extends ArchiResource { + /** + * Constructor to create an architecture connection with a name. + * + */ + public ReadPath(String name) { + super(name); + _hwChannelList = new Vector(); + } + + /** + * Accept a Visitor. + * + * @param x visitor object + */ + public void accept(ArchiVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this architectural connection. + * + * @return a new instance of the architectural connection. + */ + /* + @SuppressWarnings("unchecked") + public Object clone() { + ReadPath newObj = (ReadPath) super.clone(); + newObj.setProcessor(_processor); + newObj.setRXBuf(_rxBuf); + newObj.setCHBuf(_chBuf); + newObj.setHWChannelNameList((Vector)_hwChannelNameList.clone()); + return (newObj); + } + */ + + /** + * Return a string representation of the architectural connection. + * + * @return string representation of the architectural connection + */ + public String toString() { + return "ReadPath: " + getName(); + } + + /** + * Return the memory where the receive buffer is located. + * + * @return name of memory + */ + public Memory getRXBuf() { return _rxBuf; } + + /** + * Set the receive buffer location. + * + * @param rxbuf rxbuf location + */ + public void setRXBuf(Memory rxbuf) { _rxBuf = rxbuf; } + + /** + * Return the memory where the channel buffer is located. + * + * @return channel buffer location + */ + public Memory getCHBuf() { return _chBuf; } + + /** + * Set the channel buffer location + * + * @param chbuf memory where channel buffer is located. + */ + public void setCHBuf(Memory chbuf) { _chBuf = chbuf; } + + /** + * Return the list of the HW channels. + * + * @return list of HW channels + */ + public Vector getHWChannelList() { return _hwChannelList; } + + /** + * Return the processor to which this path is associated. + * + * @return processor + */ + public Processor getProcessor() { + return _processor; + } + + /** + * Set the processor to which this path is associated + * + * @param processor processor + */ + public void setProcessor(Processor processor) { + _processor = processor; + } + + + protected Processor _processor; + protected Memory _rxBuf; + protected Memory _chBuf; + protected Vector _hwChannelList; +} diff --git a/dol/src/dol/datamodel/architecture/Variable.java b/dol/src/dol/datamodel/architecture/Variable.java new file mode 100644 index 0000000..2c91a2d --- /dev/null +++ b/dol/src/dol/datamodel/architecture/Variable.java @@ -0,0 +1,109 @@ +/* $Id: Variable.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.architecture; + +import dol.visitor.ArchiVisitor; + +/** + * This class represents a global variable in the architecture XML. + */ +public class Variable implements Cloneable { + + /** + * Constructor to create a Variable. + */ + public Variable(String name) { + _name = name; + } + + /** + * Accept a Visitor. + * + * @param x visitor object + */ + public void accept(ArchiVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this Variable. + * + * @return new instance of the Variable. + */ + public Object clone() { + try { + Variable newObj = (Variable) super.clone(); + newObj.setName(_name); + return (newObj); + } catch (CloneNotSupportedException e) { + System.out.println("Error Clone not Supported"); + } + return null; + } + + /** + * Get the value of the Variable. + * + * @return the value of the variable + */ + public int getValue() { + return _value; + } + + /** + * Set the value of the Variable. + * + * @param value the value of the variable + */ + public void setValue(int value) { + _value = value; + } + + /** + * Get the name of this SourceCode. + * + * @return the name + */ + public String getName() { + return _name; + } + + /** + * Set the name of this SourceCode. + * + * @param name name of the SourceCode + */ + public void setName(String name) { + _name = name; + } + + /** + * Get the parent ArchiResource. + * + * @return parent ArchiResource + */ + public ArchiResource getParentResource() { + return _parentResource; + } + + /** + * Set the parent ArchiResource. + * + * @param parentResource new parent + */ + public void setParentResource(ArchiResource parentResource) { + _parentResource = parentResource; + } + + /** + * Return a string representation of the Variable. + * + * @return string representation of the Variable + */ + public String toString() { + return "Variable: " + getName(); + } + + protected int _value; + protected String _name = null; + protected ArchiResource _parentResource = null; +} diff --git a/dol/src/dol/datamodel/architecture/WritePath.java b/dol/src/dol/datamodel/architecture/WritePath.java new file mode 100644 index 0000000..80244a7 --- /dev/null +++ b/dol/src/dol/datamodel/architecture/WritePath.java @@ -0,0 +1,113 @@ +/* $Id: WritePath.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.architecture; + +import java.util.Vector; + +import dol.visitor.ArchiVisitor; + +/** + * This class defines a write path. A write path contains one processor, + * one txbuf, one channel buf, and one or more hw channels. + */ +public class WritePath extends ArchiResource { + /** + * Constructor to create an architecture connection with a name. + */ + public WritePath(String name) { + super(name); + _hwChannelList = new Vector(); + } + + /** + * Accept a Visitor. + * + * @param x visitor object + */ + public void accept(ArchiVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this architectural connection. + * + * @return a new instance of the architectural connection. + */ + /* + @SuppressWarnings("unchecked") + public Object clone() { + WritePath newObj = (WritePath) super.clone(); + newObj.setProcessor(_processor); + newObj.setTXBuf(_txBuf); + newObj.setCHBuf(_chBuf); + newObj.setHWChannelNameList((Vector)_hwChannelNameList.clone()); + return (newObj); + } + */ + + /** + * Return a string representation of the architectural connection. + * + * @return string representation of the architectural connection + */ + public String toString() { + return "WritePath: " + getName(); + } + + /** + * Return the memory where the transmit buffer is located. + * + * @return name of memory + */ + public Memory getTXBuf() { return _txBuf; } + + /** + * Set the transmit buffer location. + * + * @param txbuf txbuf location + */ + public void setTXBuf(Memory txbuf) { _txBuf = txbuf; } + + /** + * Return the memory where the channel buffer is located. + * + * @return channel buffer location + */ + public Memory getCHBuf() { return _chBuf; } + + /** + * Set the channel buffer location + * + * @param chbuf memory where channel buffer is located. + */ + public void setCHBuf(Memory chbuf) { _chBuf = chbuf; } + + /** + * Return the list of the HW channels. + * + * @return list of HW channels + */ + public Vector getHWChannelList() { return _hwChannelList; } + + /** + * Return the processor to which this path is associated. + * + * @return processor + */ + public Processor getProcessor() { + return _processor; + } + + /** + * Set the processor to which this path is associated. + * + * @param processor processor + */ + public void setProcessor(Processor processor) { + _processor = processor; + } + + protected Processor _processor; + protected Memory _txBuf; + protected Memory _chBuf; + protected Vector _hwChannelList; +} diff --git a/dol/src/dol/datamodel/architecture/package.html b/dol/src/dol/datamodel/architecture/package.html new file mode 100644 index 0000000..a6f1658 --- /dev/null +++ b/dol/src/dol/datamodel/architecture/package.html @@ -0,0 +1,20 @@ + + + + + + +Internal data model for the architecture representation. + +

Package Specification

+ + + +

Related Documentation

+ + + + + + + diff --git a/dol/src/dol/datamodel/mapping/Binding.java b/dol/src/dol/datamodel/mapping/Binding.java new file mode 100644 index 0000000..ac39c52 --- /dev/null +++ b/dol/src/dol/datamodel/mapping/Binding.java @@ -0,0 +1,87 @@ +package dol.datamodel.mapping; + +import dol.visitor.MapVisitor; + +/** + * This class represents a binding element in the mapping. + */ +abstract public class Binding extends MapResource { + + /** + * Constructor to create a Binding with a name. + */ + public Binding(String name) { + super(name); + } + + /** + * Accept a Visitor + * @param x A Visitor Object. + */ + public void accept(MapVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this Binding + * + * @return a new instance of the Binding. + */ + public Object clone() { + Binding newObj = (Binding) super.clone(); + return (newObj); + } + + /** + * Get the range of this binding. + * + * @return range + */ + public String getRange() { + return _range; + } + + /** + * Set the range of this binding. + * + * @param range new range value + */ + public void setRange(String range) { + _range= range; + } + + /** + * Get the type of this binding. + * + * @return type + */ + public String getType() { + return _type; + } + + /** + * Return a description of the binding. + * + * @return a description of the binding. + */ + public String toString() { + return "Binding: " + getName() ; + } + + /** + * Range of the iterator when the instance belongs to an iterated + * series of bindings. + */ + protected String _range; + protected String _type; + + /** + * Type specifier for communication bindings. + */ + public static final String COMMUNICATION = "communication"; + + /** + * Type specifier for computation bindings. + */ + public static final String COMPUTATION = "computation"; +} diff --git a/dol/src/dol/datamodel/mapping/CommunicationBinding.java b/dol/src/dol/datamodel/mapping/CommunicationBinding.java new file mode 100644 index 0000000..568c326 --- /dev/null +++ b/dol/src/dol/datamodel/mapping/CommunicationBinding.java @@ -0,0 +1,89 @@ +/* $Id: CommunicationBinding.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.mapping; + +import dol.datamodel.architecture.ReadPath; +import dol.datamodel.architecture.WritePath; +import dol.datamodel.pn.Channel; +import dol.visitor.MapVisitor; + +/** + * This class represents a communication binding element in the mapping. + */ +public class CommunicationBinding extends Binding { + + /** + * Constructor to create a CommunicationBinding with a name. + */ + public CommunicationBinding(String name) { + super(name); + _type = COMMUNICATION; + } + + /** + * Clone this Binding + * + * @return a new instance of the Binding. + */ + public Object clone() { + CommunicationBinding newObj = (CommunicationBinding) super.clone(); + newObj.setChannel(_channel); + newObj.setReadPath(_readPath); + newObj.setWritePath(_writePath); + return (newObj); + } + + /** + * Accept a Visitor + * + * @param x visitor object + */ + public void accept(MapVisitor x) { + x.visitComponent(this); + } + + /** Set the SW channel */ + public void setChannel(Channel c) { + _channel = c; + } + + /** Get the SW channel */ + public Channel getChannel() { + return _channel; + } + + /** Set the read path */ + public void setReadPath(ReadPath p) { + _readPath = p; + } + + /** Get the read path */ + public ReadPath getReadPath() { + return _readPath; + } + + /** Set the write path */ + public void setWritePath(WritePath p) { + _writePath = p; + } + + /** Get the write path */ + public WritePath getWritePath() { + return _writePath; + } + + /** + * Return a description of the binding. + * + * @return a description of the binding. + */ + public String toString() { + return "CommunicationBinding: " + getName() ; + } + + private Channel _channel = null; + + private ReadPath _readPath = null; + + private WritePath _writePath = null; + +} diff --git a/dol/src/dol/datamodel/mapping/ComputationBinding.java b/dol/src/dol/datamodel/mapping/ComputationBinding.java new file mode 100644 index 0000000..c117265 --- /dev/null +++ b/dol/src/dol/datamodel/mapping/ComputationBinding.java @@ -0,0 +1,75 @@ +/* $Id: ComputationBinding.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.mapping; + +import dol.datamodel.architecture.Processor; +import dol.datamodel.pn.Process; +import dol.visitor.MapVisitor; + +/** + * This class represents a computation binding element in the mapping. + */ +public class ComputationBinding extends Binding { + + /** + * Constructor to create a ComputationBinding with a name. + */ + public ComputationBinding(String name) { + super(name); + _type = COMPUTATION; + } + + /** + * Clone this Binding + * + * @return a new instance of the Binding. + */ + public Object clone() { + ComputationBinding newObj = (ComputationBinding) super.clone(); + newObj.setProcessor(_processor); + newObj.setProcess(_process); + return (newObj); + } + + /** + * Accept a Visitor + * + * @param x visitor object + */ + public void accept(MapVisitor x) { + x.visitComponent(this); + } + + /** Set the PN process */ + public void setProcess(Process p) { + _process = p; + } + + /** Get the PN process */ + public Process getProcess() { + return _process; + } + + /** Set the processor from the architecture */ + public void setProcessor(Processor p) { + _processor = p; + } + + /** Get the processor */ + public Processor getProcessor() { + return _processor; + } + + /** + * Return a description of the binding. + * + * @return a description of the binding. + */ + public String toString() { + return "ComputationBinding: " + getName() ; + } + + private Process _process = null; + + private Processor _processor = null; + +} diff --git a/dol/src/dol/datamodel/mapping/Configuration.java b/dol/src/dol/datamodel/mapping/Configuration.java new file mode 100644 index 0000000..fe3a3a4 --- /dev/null +++ b/dol/src/dol/datamodel/mapping/Configuration.java @@ -0,0 +1,75 @@ +/* $Id: Configuration.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.mapping; + +import dol.visitor.MapVisitor; + +/** + * This class represents a name-value pair of a configuration tag in XML. + */ +public class Configuration { + + /** + * Constructor to create a Configuration. + */ + public Configuration(String name, String value) { + _name = name; + _value = value; + } + + /** + * Accept a Visitor. + * + * @param x visitor object + */ + public void accept(MapVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this Configuration. + * + * @return new instance of the Configuration. + */ + public Object clone() { + try { + Configuration newObj = (Configuration) super.clone(); + newObj._name = _name; + newObj._value = _value; + return (newObj); + } catch (CloneNotSupportedException e) { + System.out.println("Error Clone not Supported"); + } + return null; + } + + /** + * Get the value of the Configuration. + * + * @return the value of the configuration. + */ + public String getValue() { + return _value; + } + + /** + * Get the name of this configuration. + * + * @return the name + */ + public String getName() { + return _name; + } + + /** + * Return a string representation of the Configuration. + * + * @return string representation of the Configuration + */ + public String toString() { + return "Configuration: " + _name + "/" + _value; + } + + protected String _value = null; + protected String _name = null; + +} \ No newline at end of file diff --git a/dol/src/dol/datamodel/mapping/MapResource.java b/dol/src/dol/datamodel/mapping/MapResource.java new file mode 100644 index 0000000..2aa9cf8 --- /dev/null +++ b/dol/src/dol/datamodel/mapping/MapResource.java @@ -0,0 +1,116 @@ +package dol.datamodel.mapping; + +import dol.visitor.MapVisitor; + +/** + * This class is the basic class which abstracts a mapping resource. + */ +public class MapResource implements Cloneable { + /** + * Constructor to create a mapping resource with a name. + */ + public MapResource(String name) { + _name = name; + _basename = name; + } + + /** + * Accept a Visitor + * + * @param x visitor object + */ + public void accept(MapVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this mapping resource. + * + * @return new instance of the mapping resource. + */ + public Object clone() { + try { + MapResource newObj = (MapResource) super.clone(); + newObj.setName(_name); + newObj.setBasename(_basename); + return (newObj); + } catch (CloneNotSupportedException e) { + System.out.println("Error Clone not Supported"); + } + return null; + } + + /** + * Get the name of this mapping resource. + * + * @return name of the mapping resource + */ + public String getName() { + return _name; + } + + /** + * Set the name of this mapping resource. + * + * @param name name of the mapping resource + */ + public void setName(String name) { + _name = name; + } + + /** + * Get the basename of this mapping resource. + * + * @return basename of the mapping resource + */ + public String getBasename() { + return _basename; + } + + /** + * Set the basename of this mapping resource. + * + * @param basename name of the mapping resource + */ + public void setBasename(String basename) { + _basename = basename; + } + + /** + * Get the hierarchical parent of this mapping resource. + * + * @return parent of this mapping resource + */ + public MapResource getParentResource() { + return _parentResource; + } + + /** + * Set the hierarchical parent of this mapping resource. + * + * @param parentResource new parent + */ + public void setParentResource(MapResource parentResource) { + _parentResource = parentResource; + } + + /** + * Return a string representation of the architectural resource. + * + * @return string representation of the architectural resource + */ + public String toString() { + return "MapResource: " + _name; + } + + /** name of the architectural resource */ + protected String _name = null; + + /** basename of the architectural resource, if no basename, store the name */ + protected String _basename = null; + + /** + * parent resource of this architectural resource in a hierarchical architecture network + */ + protected MapResource _parentResource = null; +} diff --git a/dol/src/dol/datamodel/mapping/Mapping.java b/dol/src/dol/datamodel/mapping/Mapping.java new file mode 100644 index 0000000..c0123a5 --- /dev/null +++ b/dol/src/dol/datamodel/mapping/Mapping.java @@ -0,0 +1,274 @@ +package dol.datamodel.mapping; + +import java.util.Iterator; +import java.util.Vector; + +import dol.datamodel.architecture.Architecture; +import dol.datamodel.architecture.Processor; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.visitor.MapVisitor; + + +/** + * This class defines a mapping. + */ +public class Mapping extends MapResource +{ + public Mapping(String name) + { + super(name); + _compBindList = new Vector(); + _commBindList = new Vector(); + _scheduleList = new Vector(); + _variableList = new Vector(); + /** + * For some code generation back end, traversing via architecture + * model rather than mapping model is more convenient, since the + * mapping model is a flattened view of the binding where one can + * not access all the binded processes from a processor. Therefore + * we annotate the binding information back to processor. + */ + _processList = new Vector(); + _processorList = new Vector(); + } + + /** + * Accept a visitor + * + * @param x visitor object + */ + public void accept(MapVisitor x) { + x.visitComponent(this); + } + + + /** + * Clone this Mapping. + * + * @return new instance of the Mapping + */ + @SuppressWarnings("unchecked") + public Object clone() { + Mapping newObj = (Mapping) super.clone(); + newObj.setCompBindList((Vector)_compBindList.clone()); + newObj.setCommBindList((Vector)_commBindList.clone()); + newObj.setScheduleList((Vector)_scheduleList.clone()); + newObj.setVarList((Vector)_variableList.clone()); + newObj.setProcessorList((Vector)_processorList.clone()); + newObj.setProcessList((Vector)_processList.clone()); + return (newObj); + } + + /** Get the process network. */ + public ProcessNetwork getPN() { return _pn; } + + /** Store a reference to the process network. */ + public void setPN(ProcessNetwork pn) { _pn = pn; } + + /** Get the architecture */ + public Architecture getArch() { return _arch; } + + /** Store a reference to the architecture. */ + public void setArch(Architecture arch) { _arch = arch; } + + /** + * Get a list of computation bindings in this Mapping. + * + * @return the binding list + */ + public Vector getCompBindList() { + return _compBindList; + } + + /** + * Get a list of processes in this Mapping. + * + * @return the process list + */ + public Vector getProcessList() { + return _processList; + } + + /** + * Return a process which has a specific name. Return null if + * process cannot be found. + * + * @param name the name of the process to search for. + * @return the process with the specific name or null if not found. + */ + public Process getProcess(String name) + { + for (Process process : _processList) { + if (process.getName().equals(name)) { + return process; + } + } + return null; + } + /** + * Set the computation binding list of this mapping. + * + * @param compBindList The new list + */ + public void setCompBindList( Vector compBindList ) { + _compBindList = compBindList; + } + + /** + * Get a list of communication bindings in this Mapping. + * + * @return the binding list + */ + public Vector getCommBindList() { + return _commBindList; + } + + /** + * Set the communication binding list of this mapping. + * + * @param commBindList The new list + */ + public void setCommBindList( Vector commBindList ) { + _commBindList = commBindList; + } + + /** + * Set the process list of this mapping. + * + * @param processList The new list + */ + public void setProcessList( Vector processList ) { + _processList = processList; + } + + /** + * Get the a list of processors in this Mapping. + * + * @return the processor list + */ + public Vector getProcessorList() { + return _processorList; + } + + /** + * Set the processor list of this mapping. + * + * @param processorList The new list + */ + public void setProcessorList( Vector processorList ) { + _processorList = processorList; + } + + /** + * Return a processor which has a specific name. Return null if + * processor cannot be found. + * + * @param name the name of the processor to search for. + * @return the processor with the specific name or null if not found. + */ + public Processor getProcessor(String name) + { + Iterator i; + i = _processorList.iterator(); + while (i.hasNext()) { + Processor processor = i.next(); + if (processor.getName().equals(name)) { + return processor; + } + } + return null; + } + + /** + * Get the a list of schedules in this Mapping. + * + * @return the schedule list + */ + public Vector getScheduleList() { + return _scheduleList; + } + + /** + * Set the schedule list of this mapping. + * + * @param scheduleList The new list + */ + public void setScheduleList( Vector scheduleList ) { + _scheduleList = scheduleList; + } + + /** + * Return the schedule for a resource that has a specific name. + * Return null if schedule cannot be found. + * + * @param name the name of the resource for which we are looking for the schedule. + * @return the schedule for the resource with the specified name. + */ + public Schedule getScheduleByResource(String name) { + for(Schedule schedule : _scheduleList) { + if (schedule.getResource().getName().equals(name)) { + return schedule; + } + } + return null; + } + + /** + * Return the communication binding for a channel that has a specific name. + * Return null if binding cannot be found. + * + * @param name the name of the channel for which we are looking for the binding. + * @return the binding for the channel with the specified name. + */ + public CommunicationBinding getCommBindingByChannel(String name) { + for(CommunicationBinding b : _commBindList) { + if (b.getChannel().getName().equals(name)) { + return b; + } + } + return null; + } + + /** + * Get the variable list of a Mapping. + * + * @return the variable list + */ + public Vector getVarList() { + return _variableList; + } + + /** + * Set the variable list of a mapping. + * + * @param variableList The new list + */ + public void setVarList( Vector variableList ) { + _variableList = variableList; + } + + /** ProcessNetwork Reference **/ + protected ProcessNetwork _pn = null; + + /** Architecture Reference **/ + protected Architecture _arch = null; + + /** List of processes in the mapping **/ + protected Vector _processList = null; + + /** List of processors actually used in the mapping **/ + protected Vector _processorList = null; + + /** List of computations bindings in the mapping **/ + protected Vector _compBindList = null; + + /** List of communication bindings in the mapping **/ + protected Vector _commBindList = null; + + /** List of schedules in the mapping **/ + protected Vector _scheduleList = null; + + /** List of variables in the mapping **/ + protected Vector _variableList = null; +} diff --git a/dol/src/dol/datamodel/mapping/Schedule.java b/dol/src/dol/datamodel/mapping/Schedule.java new file mode 100644 index 0000000..688afca --- /dev/null +++ b/dol/src/dol/datamodel/mapping/Schedule.java @@ -0,0 +1,160 @@ +/* $Id: Schedule.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.mapping; + +import java.util.Vector; + +import dol.datamodel.architecture.ArchiResource; +import dol.visitor.MapVisitor; + +/** + * This class represents a schedule element in the mapping. + */ +public class Schedule extends MapResource { + + /** + * Constructor to create a Schedule with a name. + */ + public Schedule(String name) { + super(name); + _entryList = new Vector(); + _cfgList = new Vector(); + } + + /** + * Accept a Visitor + * + * @param x visitor object + */ + public void accept(MapVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this Schedule resource. + * + * @return new instance of the Schedule resource. + */ + @SuppressWarnings("unchecked") + public Object clone() { + Schedule newObj = (Schedule) super.clone(); + newObj.setResource(_resource); + newObj.setSchedPolicy(_policy); + newObj.setCfgList((Vector)_cfgList.clone() ); + newObj.setEntryList((Vector)_entryList.clone()); + return (newObj); + } + + /** Set the resource, a HW channel or a processor from the architecture */ + public void setResource(ArchiResource r) { + _resource = r; + } + + /** Get the resource */ + public ArchiResource getResource() { + return _resource; + } + + /** Set the scheduling policy */ + public void setSchedPolicy(SchedulingPolicy p) { + _policy = p; + } + + /** Get the scheduling policy */ + public SchedulingPolicy getSchedPolicy() { + return _policy; + } + + /** + * Get the list of configurations of this schedule. + * + * @return list of configurations + */ + public Vector getCfgList() { + return _cfgList; + } + + /** + * Set the list of configurations of this schedule. + * + * @param cfgList configuration list + */ + public void setCfgList(Vector cfgList) { + _cfgList = cfgList; + } + + /** + * Set the list of scheduler table entries. + * + * @param entryList The new list + */ + public void setEntryList(Vector entryList) { + _entryList = entryList; + } + + /** Get the list of scheduler table entries */ + public Vector getEntryList() { + return _entryList; + } + + /** + * Return the scheduler table entry with its schedule configuration + * that has a specific name. + * Return null if the entry cannot be found. + * + * @param name the name of the entry for which we are looking for. + * @return the entry with its schedule configuration with the specified name. + */ + public ScheduleEntry getScheduleEntry(String name) { + for(ScheduleEntry entry : _entryList) { + if (entry.getName().equals(name)) { + return entry; + } + } + return null; + } + + /** + * Return the value for the given configuration key. Return null + * when the key cannot be found. + * + * @param name name of the configuration key to search for + * @return value of the specified configuration key + */ + public String getCfgValue(String name) { + for(Configuration c : _cfgList) { + if(c.getName().equals(name)) { + return c.getValue(); + } + } + return null; + } + + /** + * Return a string representation of the Schedule. + * + * @return string representation of the Schedule + */ + public String toString() { + return "Schedule: " + getName(); + } + + /** Resource that is scheduled */ + ArchiResource _resource = null; + + /** Scheduling policy */ + SchedulingPolicy _policy = null; + + /** List of the configurations of the Schedule */ + protected Vector _cfgList = null; + + /** List of scheduler table entries */ + Vector _entryList = null; + + /** Configuration key for the slots per cycle of a TDMA scheduler */ + final public static String cfdTdmaSlotsPerCycle = "slotsonecycle"; + + /** Configuration key for the general slot length + * in nanoseconds of a TDMA scheduler */ + final public static String cfgTdmaSlotLength = "slotlength"; + +} diff --git a/dol/src/dol/datamodel/mapping/ScheduleEntry.java b/dol/src/dol/datamodel/mapping/ScheduleEntry.java new file mode 100644 index 0000000..2ee5331 --- /dev/null +++ b/dol/src/dol/datamodel/mapping/ScheduleEntry.java @@ -0,0 +1,113 @@ +/* $Id: ScheduleEntry.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.mapping; + +import java.util.Vector; + +import dol.datamodel.pn.Schedulable; +import dol.visitor.MapVisitor; + +/** + * This class represents an origin element in the mapping which refers + * to a PN process or a SW channel with a configuration element. + */ +public class ScheduleEntry extends MapResource { + + /** + * Constructor to create a ScheduleProcess with a name. + */ + public ScheduleEntry(String name) { + super(name); + _cfgList = new Vector(); + } + + /** + * Accept a Visitor + * + * @param x visitor object + */ + public void accept(MapVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this ScheduleProcess resource. + * + * @return new instance of the ScheduleProcess resource. + */ + @SuppressWarnings("unchecked") + public Object clone() { + ScheduleEntry newObj = (ScheduleEntry) super.clone(); + newObj.setConsumer(_consumer); + newObj.setCfgList((Vector)_cfgList.clone()); + return (newObj); + } + + /** + * Get the list of configurations of this scheduled process. + * + * @return list of configurations + */ + public Vector getCfgList() { + return _cfgList; + } + + /** + * Set the list of configurations of this scheduled process. + * + * @param cfgList configuration list + */ + public void setCfgList(Vector cfgList) { + _cfgList = cfgList; + } + + /** Set the consumer */ + public void setConsumer(Schedulable c) { + _consumer = c; + } + + /** Get the consumer */ + public Schedulable getConsumer() { + return _consumer; + } + + /** + * Return the value for the given configuration key. Return null + * when the key cannot be found. + * + * @param name name of the configuration key to search for + * @return value of the specified configuration key + */ + public String getCfgValue(String name) { + for(Configuration c : _cfgList) { + if(c.getName().equals(name)) { + return c.getValue(); + } + } + return null; + } + + /** + * Return a string representation of the ScheduleProcess. + * + * @return string representation of the ScheduleProcess + */ + public String toString() { + return "ScheduleProcess: " + getName(); + } + + /** Consumer: PN process or SW channel */ + private Schedulable _consumer = null; + + /** list of the configurations of the ScheduleProcess */ + protected Vector _cfgList = null; + + /** Configuration key for the priority of a task in a fixed priority scheduler */ + final public static String cfgFpPriority = "priority"; + + /** Configuration key for the index of the TDMA slot of a process */ + final public static String cfgTdmaStartSlot = "startslot"; + + /** Configuration key for the number of TDMA slots for a process */ + final public static String cfgTdmaNumberOfSlots = "numberofslots"; + +} diff --git a/dol/src/dol/datamodel/mapping/SchedulingPolicy.java b/dol/src/dol/datamodel/mapping/SchedulingPolicy.java new file mode 100644 index 0000000..6589174 --- /dev/null +++ b/dol/src/dol/datamodel/mapping/SchedulingPolicy.java @@ -0,0 +1,43 @@ +/* $Id: SchedulingPolicy.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.mapping; + +/** + * This class defines the supported scheduling policies. + */ +public enum SchedulingPolicy { + + STATIC, FIXEDPRIORITY, FIFO, TDMA, ROUNDROBIN; + + private static final String staticVal = "static"; + private static final String fixedPriorityVal = "fixedpriority"; + private static final String fifoVal = "fifo"; + private static final String tdmaVal = "tdma"; + private static final String roundRobinVal = "roundrobin"; + + static public SchedulingPolicy fromString(String s) { + if(s.equals(staticVal)) { + return SchedulingPolicy.STATIC; + } else if(s.equals(fixedPriorityVal)) { + return SchedulingPolicy.FIXEDPRIORITY; + } else if(s.equals(fifoVal)) { + return SchedulingPolicy.FIFO; + } else if(s.equals(tdmaVal)) { + return SchedulingPolicy.TDMA; + } + return SchedulingPolicy.ROUNDROBIN; + } + + static public String toString(SchedulingPolicy t) { + if(t == SchedulingPolicy.STATIC) { + return staticVal; + } else if(t == SchedulingPolicy.FIXEDPRIORITY) { + return fixedPriorityVal; + } else if(t == SchedulingPolicy.FIFO) { + return fifoVal; + } else if(t == SchedulingPolicy.TDMA) { + return tdmaVal; + } + return roundRobinVal; + } + +} \ No newline at end of file diff --git a/dol/src/dol/datamodel/mapping/Variable.java b/dol/src/dol/datamodel/mapping/Variable.java new file mode 100644 index 0000000..a097b87 --- /dev/null +++ b/dol/src/dol/datamodel/mapping/Variable.java @@ -0,0 +1,108 @@ +package dol.datamodel.mapping; + +import dol.visitor.MapVisitor; + +/** + * This class represents a global variable in the mapping XML. + */ +public class Variable implements Cloneable { + + /** + * Constructor to create a Variable. + */ + public Variable(String name) { + _name = name; + } + + /** + * Accept a Visitor. + * + * @param x visitor object + */ + public void accept(MapVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this Variable. + * + * @return new instance of the Variable. + */ + public Object clone() { + try { + Variable newObj = (Variable) super.clone(); + newObj.setName(_name); + return (newObj); + } catch (CloneNotSupportedException e) { + System.out.println("Error Clone not Supported"); + } + return null; + } + + /** + * Get the value of the Variable. + * + * @return the value of the variable + */ + public int getValue() { + return _value; + } + + /** + * Set the value of the Variable. + * + * @param value the value of the variable + */ + public void setValue(int value) { + _value = value; + } + + /** + * Get the name of this SourceCode. + * + * @return the name + */ + public String getName() { + return _name; + } + + /** + * Set the name of this SourceCode. + * + * @param name name of the SourceCode + */ + public void setName(String name) { + _name = name; + } + + /** + * Get the parent ArchiResource. + * + * @return parent ArchiResource + */ + public MapResource getParentResource() { + return _parentResource; + } + + /** + * Set the parent ArchiResource. + * + * @param parentResource new parent + */ + public void setParentResource(MapResource parentResource) { + _parentResource = parentResource; + } + + /** + * Return a string representation of the Variable. + * + * @return string representation of the Variable + */ + public String toString() { + return "Variable: " + getName(); + } + + protected int _value; + protected String _name = null; + protected MapResource _parentResource = null; +} diff --git a/dol/src/dol/datamodel/mapping/package.html b/dol/src/dol/datamodel/mapping/package.html new file mode 100644 index 0000000..38cfb44 --- /dev/null +++ b/dol/src/dol/datamodel/mapping/package.html @@ -0,0 +1,20 @@ + + + + + + +Internal data model for the mapping representation. + +

Package Specification

+ + + +

Related Documentation

+ + + + + + + diff --git a/dol/src/dol/datamodel/package.html b/dol/src/dol/datamodel/package.html new file mode 100644 index 0000000..398bc27 --- /dev/null +++ b/dol/src/dol/datamodel/package.html @@ -0,0 +1,20 @@ + + + + + + +Internal data model. + +

Package Specification

+ + + +

Related Documentation

+ + + + + + + diff --git a/dol/src/dol/datamodel/pn/Channel.java b/dol/src/dol/datamodel/pn/Channel.java new file mode 100644 index 0000000..2aa0706 --- /dev/null +++ b/dol/src/dol/datamodel/pn/Channel.java @@ -0,0 +1,129 @@ +/* $Id: Channel.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.pn; + +import dol.visitor.PNVisitor; + +/** + * This class is the basic channel in a process network. + * The channel has a name and a list of ports connected by this channel. + * In this model, a channel has only two ports: one input port and one + * output port. + */ +public class Channel extends Resource implements Schedulable { + + /** + * Constructor to create a channel with a name and an empty + * portList. + */ + public Channel(String name) { + super(name); + } + + /** + * Accept a visitor. + * @param x visitor object + */ + public void accept(PNVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this channel. + * + * @return new instance of the channel + */ + public Object clone() { + Channel newObj = (Channel) super.clone(); + return (newObj); + } + + /** + * Get the size of this channel. + * + * @return size of the channel + */ + public int getSize() { + return _size; + } + + /** + * Set the size of this channel. + * + * @param size new size value + */ + public void setSize(int size) { + _size = size; + } + + /** + * Get the token size of this channel. + * + * @return token size of the channel + */ + public int getTokenSize() { + return _tokenSize; + } + + /** + * Set the token size of this channel. + * + * @param size new token size + */ + public void setTokenSize(int size) { + _tokenSize = size; + } + + /** + * Return a string representation of the channel. + * + * @return string representation of the channel + */ + public String toString() { + return "Channel: " + getName(); + } + + /** + * Get the process where this channel starts from. + * + * @return origin process + */ + public Process getOrigin() { + return _origin; + } + + /** + * Set the process where this channel starts from. + * + * @param origin origin process + */ + public void setOrigin(Process origin) { + _origin = origin; + } + + /** + * Get the process where this channel ends. + * + * @return target process + */ + public Process getTarget() { + return _target; + } + + /** + * Set the process where this channel ends. + * + * @param target target process + */ + public void setTarget(Process target) { + _target = target; + } + + protected Process _origin; + protected Process _target; + + /** size of the channel */ + protected int _size; + + /** token size fo the channel */ + protected int _tokenSize; +} diff --git a/dol/src/dol/datamodel/pn/Configuration.java b/dol/src/dol/datamodel/pn/Configuration.java new file mode 100644 index 0000000..153173d --- /dev/null +++ b/dol/src/dol/datamodel/pn/Configuration.java @@ -0,0 +1,112 @@ +/* $Id: Configuration.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.pn; + +import dol.visitor.PNVisitor; + +/** + * This class represents a name-value pair of a configuration tag in XML. + */ +public class Configuration { + + /** + * Constructor to create a Configuration. + */ + public Configuration(String name) { + _name = name; + } + + /** + * Accept a Visitor. + * + * @param x visitor object + */ + public void accept(PNVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this Configuration. + * + * @return new instance of the Configuration. + */ + public Object clone() { + try { + Configuration newObj = (Configuration) super.clone(); + newObj.setName(_name); + newObj.setValue(_value); + return (newObj); + } catch (CloneNotSupportedException e) { + System.out.println("Error Clone not Supported"); + } + return null; + } + + /** + * Get the value of the Configuration. + * + * @return the value of the configuration. + */ + public String getValue() { + return _value; + } + + /** + * Set the value of the Configuration. + * + * @param value the value of the configuration. + */ + public void setValue(String value) { + _value = value; + } + + /** + * Get the name of this configuration. + * + * @return the name + */ + public String getName() { + return _name; + } + + /** + * Set the name of this configuration. + * + * @param name name of the configuration + */ + public void setName(String name) { + _name = name; + } + + /** + * Get the hierarchical parent of this resource. + * + * @return parent of this resource + */ + public Resource getParentResource() { + return _parentResource; + } + + + /** + * Set the hierarchical parent of this resource. + * + * @param parentResource new parent + */ + public void setParentResource(Resource parentResource) { + _parentResource = parentResource; + } + + + /** + * Return a string representation of the Configuration. + * + * @return string representation of the Configuration + */ + public String toString() { + return "Configuration: " + getName(); + } + + protected String _value = null; + protected String _name = null; + protected Resource _parentResource = null; +} diff --git a/dol/src/dol/datamodel/pn/Connection.java b/dol/src/dol/datamodel/pn/Connection.java new file mode 100644 index 0000000..3830f96 --- /dev/null +++ b/dol/src/dol/datamodel/pn/Connection.java @@ -0,0 +1,130 @@ +/* $Id: Connection.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.pn; + +import dol.visitor.PNVisitor; + +/** + * This class defines a connection. + * A connection contains one origin and one target resource and the + * according ports. + */ +public class Connection extends Resource { + + /** + * Constructor to create a Connection with a name, + * empty process list and empty channel list. + */ + public Connection(String name) { + super(name); + } + + /** + * Accept a Visitor. + * + * @param x visitor object + */ + public void accept(PNVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this Connection. + * + * @return a new instance of the Connection. + */ + public Object clone() { + Connection newObj = (Connection) super.clone(); + newObj.setOrigin(_origin); + newObj.setOriginPort(_originPort); + newObj.setTarget(_target); + newObj.setTargetPort(_targetPort); + return (newObj); + } + + /** + * Return a string representation of the connection. + * + * @return string representation of the connection + */ + public String toString() { + return "Connection: " + getName(); + } + + + /** + * Get the origin resource of his connection. + * + * @return origin resource + */ + public Resource getOrigin() { + return _origin; + } + + /** + * Set the origin resource of this connection. + * + * @param origin origin resource + */ + public void setOrigin(Resource origin) { + _origin = origin; + } + + /** + * Get the origin port of this connection. + * + * @return origin port + */ + public Port getOriginPort() { + return _originPort; + } + + /** + * Set the origin port of this connection. + * + * @param port origin port + */ + public void setOriginPort(Port port) { + _originPort = port; + } + + /** + * Get the target resource of his connection. + * + * @return target resource + */ + public Resource getTarget() { + return _target; + } + + /** + * Set the target resource of this connection. + * + * @param target target resource + */ + public void setTarget(Resource target) { + _target = target; + } + + /** + * Get the target port of this connection. + * + * @return target port + */ + public Port getTargetPort() { + return _targetPort; + } + + /** + * Set the target port of this connection. + * + * @param port target port + */ + public void setTargetPort(Port port) { + _targetPort = port; + } + + protected Resource _origin; + protected Port _originPort; + protected Resource _target; + protected Port _targetPort; +} diff --git a/dol/src/dol/datamodel/pn/Port.java b/dol/src/dol/datamodel/pn/Port.java new file mode 100644 index 0000000..e82e46e --- /dev/null +++ b/dol/src/dol/datamodel/pn/Port.java @@ -0,0 +1,189 @@ +/* $Id: Port.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.pn; + +import dol.visitor.PNVisitor; + +/** + * This class represents a port of a process or channel. + */ +public class Port { + + /** + * Constructor to create a Port with a name. + */ + public Port(String name) { + _name = name; + _isInPort = false; + _isOutPort = false; + } + + public Port(String name, boolean type) { + _name = name; + _isInPort = (type == INPORT); + _isOutPort = (type == OUTPORT); + } + + + /** + * Accept a visitor. + * + * @param x visitor object + */ + public void accept(PNVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this Port + * + * @return new instance of the Port + */ + public Object clone() { + try { + Port newObj = (Port) super.clone(); + newObj.setName(_name); + newObj.setBasename(_basename); + newObj.setPeerPort(_peerPort); + newObj.setPeerResource(_peerResource); + newObj.setResource(_resource ); + return (newObj); + } catch (CloneNotSupportedException e) { + System.out.println("Error Clone not Supported"); + } + return null; + } + + /** + * Check whether this port is an inport. + * + * @return true if this port is an inport, otherwise false + */ + public boolean isInPort() { + return _isInPort; + } + + /** + * Check whether this port is an outport. + * + * @return true if this port is an outport, otherwise false + */ + public boolean isOutPort() { + return _isOutPort; + } + + /** + * Get the name of this port. + * + * @return name of the port + */ + public String getName() { + return _name; + } + + /** + * Set the name of this port. + * + * @param name name of the port + */ + public void setName(String name) { + _name = name; + } + + /** + * Get the range of this port. + * + * @return range of the port + */ + public String getRange() { + return _range; + } + + /** + * Set the range of this port. + * + * @param range range of the port + */ + public void setRange(String range) { + _range= range; + } + + /** + * Get the resource of this port. + * + * @return the resource + */ + public Resource getResource() { + return _resource; + } + + /** + * Set the process of this port. + * + * @param resource The new resource + */ + public void setResource(Resource resource) { + _resource = resource; + } + + public void setBasename(String basename) { _basename = basename; } + public String getBasename() { return _basename; } + + // for channel port + public void setPeerPort(Port peer) { _peerPort = peer; } + public Port getPeerPort() { return _peerPort; } + + // for process port: peer channel name + public void setPeerResource(Resource n) { _peerResource = n; } + public Resource getPeerResource() { return _peerResource; } + + public String getType() { + if (_isInPort) return "input"; + else if (_isOutPort) return "output"; + else return ""; + } + + /** + * Return a string representation of the port. + * + * @return string representation of the port + */ + public String toString() { + return "Port: " + _name; + } + + /** constant for inport for usage in the constructor **/ + public static final boolean INPORT = true; + + /** constant for outport for usage in the constructor **/ + public static final boolean OUTPORT = false; + + /** defines whether this port is an inport **/ + protected boolean _isInPort = false; + + /** defines whether this port is an outport **/ + protected boolean _isOutPort = false; + + /** name of the port */ + protected String _name = null; + + /** basename of the resource, if no basename, store the name */ + protected String _basename = null; + + /** resource (process or channel) this port belongs to */ + protected Resource _resource = null; + + /** resource which peerPort belongs to */ + protected Resource _peerResource = null; + + /** connected peer port name */ + protected Port _peerPort = null; + + /** peer channel name */ + protected String _channelName = null; + + /** + * Range of the iterator when the instance belongs to an iterated + * series of ports. + */ + protected String _range = ""; +} diff --git a/dol/src/dol/datamodel/pn/Process.java b/dol/src/dol/datamodel/pn/Process.java new file mode 100644 index 0000000..1b825b4 --- /dev/null +++ b/dol/src/dol/datamodel/pn/Process.java @@ -0,0 +1,150 @@ +/* $Id: Process.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.pn; + +import java.util.StringTokenizer; +import java.util.Vector; + +import dol.datamodel.architecture.Processor; +import dol.visitor.PNVisitor; + +/** + * This class represents a process. + */ +public class Process extends Resource implements Schedulable { + + /** + * Constructor to create a Process with a name and an empty + * portList. + */ + public Process(String name) { + super(name); + } + + /** + * Accept a Visitor + * @param x A Visitor Object. + */ + public void accept(PNVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this Process + * + * @return a new instance of the Process. + */ + public Object clone() { + Process newObj = (Process) super.clone(); + newObj.setRange(_range); + newObj.setProcessor(_processor); + return (newObj); + } + + /** + * Get the range of this process. + * + * @return range + */ + public String getRange() { + return _range; + } + + /** + * Get the iterator indices of this process. + * + * @return range + */ + public Vector getIteratorIndices() { + Vector indices = new Vector(); + StringTokenizer tokenizer = + new StringTokenizer(_name.replaceAll(_basename, ""), "_"); + while (tokenizer.hasMoreTokens()) { + indices.add(Integer.valueOf(tokenizer.nextToken())); + } + return indices; + } + + /** + * Set the range of this process. + * + * @param range new range value + */ + public void setRange(String range) { + _range= range; + } + + public boolean hasInPorts() { + for (Port port : getPortList()) { + if (port.isInPort()) + return true; + } + return false; + } + + public boolean hasOutPorts() { + for (Port port : getPortList()) { + if (port.isOutPort()) + return true; + } + return false; + } + + /** + * Get number of inport + */ + public int getNumOfInports() { + int i = 0; + for (Port port : getPortList()) + if (port.isInPort()) + i++; + return i; + } + + /** + * Get number of outport + */ + public int getNumOfOutports() { + int i = 0; + for (Port port : getPortList()) + if (port.isOutPort()) + i++; + return i; + } + + /** + * Set the processor this process runs on. + * @param processor + */ + public void setProcessor(Processor processor) + { + _processor = processor; + } + + /** + * Get the processor this process runs on. + */ + public Processor getProcessor() + { + return _processor; + } + + /** + * Return a description of the process. + * + * @return a description of the process. + */ + public String toString() { + return "Process: " + getName(); + } + + /** + * Range of the iterator when the instance belongs to an iterated + * series of processes. + */ + protected String _range = ""; + + /** + * Processor that executes this process. + */ + protected Processor _processor = null; +} diff --git a/dol/src/dol/datamodel/pn/ProcessNetwork.java b/dol/src/dol/datamodel/pn/ProcessNetwork.java new file mode 100644 index 0000000..b41facc --- /dev/null +++ b/dol/src/dol/datamodel/pn/ProcessNetwork.java @@ -0,0 +1,189 @@ +/* $Id: ProcessNetwork.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.pn; + +import java.util.Vector; + +import dol.visitor.PNVisitor; + + +/** + * This class defines a process network. + */ +public class ProcessNetwork extends Resource { + + /** + * Constructor to create a process network with a name, + * empty process list and empty channel list. + */ + public ProcessNetwork(String name) { + super(name); + _processList = new Vector(); + _channelList = new Vector(); + _varList = new Vector(); + _connectionList = new Vector(); + } + + /** + * Accept a visitor + * + * @param x visitor object + */ + public void accept(PNVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this ProcessNetwork. + * + * @return new instance of the ProcessNetwork + */ + @SuppressWarnings("unchecked") + public Object clone() { + ProcessNetwork newObj = (ProcessNetwork) super.clone(); + newObj.setProcessList((Vector)_processList.clone()); + newObj.setChannelList((Vector)_channelList.clone()); + newObj.setVarList((Vector)_varList.clone()); + newObj.setConnectionList((Vector)_connectionList.clone()); + return (newObj); + } + + /** + * Get the process list of a ProcessNetwork. + * + * @return the process list + */ + public Vector getProcessList() { + return _processList; + } + + /** + * Get the process basenames. + * + * @return process basenames + */ + public Vector getProcessBasenames() { + Vector basenames = new Vector(); + for (Process p : _processList) { + String basename = p.getBasename(); + if (!basenames.contains(basename)) { + basenames.add(basename); + } + } + return basenames; + } + + /** + * Set the process list of a ProcessNetwork. + * + * @param processList The new list + */ + public void setProcessList(Vector processList) { + _processList = processList; + } + + /** + * Get the channel list of a ProcessNetwork + * + * @return the channel list + */ + public Vector getChannelList() { + return _channelList; + } + + /** + * Set the channel list of a ProcessNetwork + * + * @param channelList The new list + */ + public void setChannelList(Vector channelList) { + _channelList = channelList; + } + + public Vector getVarList() { return _varList; } + public void setVarList(Vector list) { _varList = list; } + + public void setConnectionList(Vector list) { _connectionList = list; } + public Vector getConnectionList() { return _connectionList; } + + + /** + * Return a description of the ProcessNetwork. + * + * @return a description of the ProcessNetwork. + */ + public String toString() { + return "ProcessNetwork: " + getName(); + } + + /** + * Return a process which has a specific name. Return null if + * process cannot be found. + * + * @param name the name of the process to search for. + * @return the process with the specific name. + */ + public Process getProcess(String name) { + for (Process process : _processList) { + if (process.getName().equals(name)) { + return process; + } + } + return null; + } + + /** + * Return a channel which has a specific name. Return null if + * not found. + * + * @param name the name of the channel to search for. + * @return the channel with the specific name. + */ + public Channel getChannel(String name) { + for (Channel c : _channelList) { + if (c.getName().equals(name)) { + return c; + } + } + return null; + } + + /** + * In this version, we only deal with the flattened process network. + * Connection infomation is filled to each process and channel for fast + * iteration. + */ + public void fillPortPeerInfo() throws Exception { + for (Connection c : getConnectionList()) { + Port originPort = c.getOriginPort(); + Port targetPort = c.getTargetPort(); + originPort.setPeerResource(c.getTarget()); + originPort.setPeerPort(targetPort); + targetPort.setPeerResource(c.getOrigin()); + targetPort.setPeerPort(originPort); + } + + //for each sw channel, determine which processes it connects + for (Connection c : getConnectionList()) { + if (c.getOrigin() instanceof Process) { + Channel channel = (Channel)c.getTarget(); + channel.setOrigin((Process)c.getOrigin()); + } + else if (c.getOrigin() instanceof Channel) { + Channel channel = (Channel)c.getOrigin(); + channel.setTarget((Process)c.getTarget()); + } + } + } + + /** list of the processes in the ProcessNetwork. */ + protected Vector _processList = null; + + /** list of the channels in the ProcessNetwork. */ + protected Vector _channelList = null; + + /** list of variables in the ProcessNetwork */ + protected Vector _varList = null; + + /** list of connections in the ProcessNetwork */ + protected Vector _connectionList = null; +} diff --git a/dol/src/dol/datamodel/pn/ProfilingConfiguration.java b/dol/src/dol/datamodel/pn/ProfilingConfiguration.java new file mode 100644 index 0000000..a7c4c73 --- /dev/null +++ b/dol/src/dol/datamodel/pn/ProfilingConfiguration.java @@ -0,0 +1,34 @@ +/* $Id: ProfilingConfiguration.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.pn; + +import dol.visitor.PNVisitor; + +public class ProfilingConfiguration extends Configuration { + + /** + * Constructor to create a ProfilerConfiguration. + */ + public ProfilingConfiguration(String name) { + super(name); + } + + /** + * Accept a Visitor. + * + * @param x visitor object + */ + public void accept(PNVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this Configuration. + * + * @return new instance of the Configuration. + */ + public Object clone() { + ProfilingConfiguration newObj = (ProfilingConfiguration) super.clone(); + return newObj; + } + +} diff --git a/dol/src/dol/datamodel/pn/Resource.java b/dol/src/dol/datamodel/pn/Resource.java new file mode 100644 index 0000000..d212bbe --- /dev/null +++ b/dol/src/dol/datamodel/pn/Resource.java @@ -0,0 +1,269 @@ +/* $Id: Resource.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.pn; + +import java.util.Vector; + +import dol.visitor.PNVisitor; + +/** + * This class is the basic class which abstracts a resource of a generic + * process network. The resource has a name and a list of ports. + */ +public class Resource { + + /** + * Constructor to create a resource with a name and an empty + * portList. + */ + public Resource(String name) { + _name = name; + _basename = name; + _portList = new Vector(); + _srcList = new Vector(); + _cfgList = new Vector(); + _profilingList = new Vector(); + } + + /** + * Accept a Visitor + * + * @param x visitor object + */ + public void accept(PNVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this resource. + * + * @return new instance of the resource. + */ + @SuppressWarnings("unchecked") + public Object clone() { + try { + Resource newObj = (Resource) super.clone(); + newObj.setName(_name); + newObj.setType(_type); + newObj.setBasename(_basename); + newObj.setPortList((Vector)_portList.clone() ); + newObj.setSrcList((Vector)_srcList.clone() ); + newObj.setCfgList((Vector)_cfgList.clone() ); + newObj.setProfilingList((Vector)_profilingList.clone() ); + return (newObj); + } catch (CloneNotSupportedException e) { + System.out.println("Error Clone not Supported"); + } + return null; + } + + public String getBasename() { + return _basename; + } + + public void setBasename(String basename) { + _basename = basename; + } + + /** + * Get the name of this resource. + * + * @return name of the resource + */ + public String getName() { + return _name; + } + + /** + * Set the name of this resource. + * + * @param name name of the resource + */ + public void setName(String name) { + _name = name; + } + + /** + * Get the type of this resource. + * + * @return type of the resource + */ + public String getType() { + return _type; + } + + /** + * Set the type of this resource. + * + * @param type type of the resource + */ + public void setType(String type) { + _type = type; + } + + /** + * Get the list of source codes of this resource. + * + * @return list of source codes + */ + public Vector getSrcList() { + return _srcList; + } + + /** + * Get the list of ports of this resource. + * + * @return list of ports + */ + public Vector getPortList() { + return _portList; + } + + /** + * Set the list of ports of this resource. + * + * @param portList port list + */ + public void setPortList(Vector portList) { + _portList = portList; + } + + /** + * Get the list of configurations of this resource. + * + * @return list of configurations + */ + public Vector getCfgList() { + return _cfgList; + } + + /** + * Set the list of configurations of this resource. + * + * @param cfgList configuration list + */ + public void setCfgList(Vector cfgList) { + _cfgList = cfgList; + } + + /** + * Get the list of profiling info of this resource. + * + * @return list of profiling info + */ + public Vector getProfilingList() { + return _profilingList; + } + + /** + * Set the list of profiling info of this resource. + * + * @param cfgList profiling info list + */ + public void setProfilingList(Vector cfgList) { + _profilingList = cfgList; + } + + /** + * Return a profiling which has a specific name. Return null when it + * cannot be found. + * + * @param name name of the profiling to search for + * @return profiling with the specified name + */ + public ProfilingConfiguration getProfilingCfg(String name) { + for (ProfilingConfiguration cfg : _profilingList) { + if (cfg.getName().equals(name)) { + return cfg; + } + } + return null; + } + + /** + * Set the list of source code of this resource. + * + * @param srcList port list + */ + public void setSrcList(Vector srcList) { + _srcList = srcList; + } + + /** + * Get the hierarchical parent of this resource. + * + * @return parent of this resource + */ + public Resource getParentResource() { + return _parentResource; + } + + /** + * Set the hierarchical parent of this resource. + * + * @param parentResource new parent + */ + public void setParentResource(Resource parentResource) { + _parentResource = parentResource; + } + + /** + * Return a string representation of the resource. + * + * @return string representation of the resource + */ + public String toString() { + return "Resource: " + _name; + } + + /** + * Return a port which has a specific name. Return null when port + * cannot be found. + * + * @param name name of the port to search for + * @return port with the specified name + */ + public Port getPort(String name) { + for (Port port : _portList) { + if (port.getName().equals(name)) { + return port; + } + } + return null; + } + + /** + * Return a port which has a specific name. Return null when port + * cannot be found. + * + * @return port with the specified name + */ + public Port getFirstPort() { + return (Port) _portList.firstElement(); + } + + /** name of the resource */ + protected String _name = null; + + /** type of the resource */ + protected String _type = null; + + /** basename of the resource, if no basename, store the name */ + protected String _basename = null; + + /** list of the ports of the Resource */ + protected Vector _portList = null; + + /** list of the source codes of the Resource */ + protected Vector _srcList = null; + + /** list of the configurations of the Resource */ + protected Vector _cfgList = null; + + /** list of the profiling info of the Resource */ + protected Vector _profilingList = null; + + /** + * parent resource of this resource in a hierarchical process network + */ + protected Resource _parentResource = null; +} diff --git a/dol/src/dol/datamodel/pn/Schedulable.java b/dol/src/dol/datamodel/pn/Schedulable.java new file mode 100644 index 0000000..4e5336c --- /dev/null +++ b/dol/src/dol/datamodel/pn/Schedulable.java @@ -0,0 +1,10 @@ +/* $Id: Schedulable.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.pn; + +/** + * Marker interface for all entities that can be added + * to a scheduler table. + */ +public interface Schedulable { + +} diff --git a/dol/src/dol/datamodel/pn/SourceCode.java b/dol/src/dol/datamodel/pn/SourceCode.java new file mode 100644 index 0000000..26f09e1 --- /dev/null +++ b/dol/src/dol/datamodel/pn/SourceCode.java @@ -0,0 +1,131 @@ +/* $Id: SourceCode.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.pn; + +import dol.visitor.PNVisitor; + +/** + * This class is the basic source code of a process. + */ +public class SourceCode { + + /** + * Constructor to create a SourceCode with a name. + */ + public SourceCode(String name) { + _name = name; + } + + /** + * Accept a visitor. + * + * @param x visitor object + */ + public void accept(PNVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this SourceCode. + * + * @return new instance of the SourceCode. + */ + public Object clone() { + try { + SourceCode newObj = (SourceCode) super.clone(); + newObj.setName(_name); + newObj.setType(_type); + newObj.setLocality(_locality); + newObj.setProcess( (Process) _process.clone() ); + return (newObj); + } catch (CloneNotSupportedException e) { + System.out.println("Error Clone not Supported"); + } + return null; + } + + /** + * Get the name of this SourceCode. + * + * @return the name + */ + public String getName() { + return _name; + } + + /** + * Set the name of this SourceCode. + * + * @param name name of the SourceCode + */ + public void setName(String name) { + _name = name; + } + + /** + * Get the process of this SourceCode. + * + * @return process to which this SourceCode belongs + */ + public Process getProcess() { + return _process; + } + + /** + * Set the proces of this SourceCode. + * + * @param process process to which this SourceCode belongs + */ + public void setProcess(Process process) { + _process = process; + } + + /** + * Get the locality of this SourceCode. + * + * @return locality of the SourceCode + */ + public String getLocality() { + return _locality; + } + + /** + * Set the locality of this SourceCode. + * + * @param locality locality of the SourceCode + */ + public void setLocality(String locality) { + _locality = locality; + } + + /** + * Get the type of this SourceCode. + * + * @return type of the SourceCode + */ + public String getType() { + return _type; + } + + /** + * Set the type of this SourceCode. + * + * @param type The new type + */ + public void setType(String type) { + _type = type; + } + + /** + * Return a string representation of the SourceCode. + * + * @return string representation of the SourceCode + */ + public String toString() { + return "SourceCode: " + _name; + } + + protected String _name = null; + protected Process _process = null; + protected String _type = null; + protected String _locality = null; +} diff --git a/dol/src/dol/datamodel/pn/Variable.java b/dol/src/dol/datamodel/pn/Variable.java new file mode 100644 index 0000000..623a25c --- /dev/null +++ b/dol/src/dol/datamodel/pn/Variable.java @@ -0,0 +1,109 @@ +/* $Id: Variable.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.datamodel.pn; + +import dol.visitor.PNVisitor; + +/** + * This class represents a global variable in XML. + */ +public class Variable { + + /** + * Constructor to create a Variable. + */ + public Variable(String name) { + _name = name; + } + + /** + * Accept a Visitor. + * + * @param x visitor object + */ + public void accept(PNVisitor x) { + x.visitComponent(this); + } + + /** + * Clone this Variable. + * + * @return new instance of the Variable. + */ + public Object clone() { + try { + Variable newObj = (Variable) super.clone(); + newObj.setName(_name); + return (newObj); + } catch (CloneNotSupportedException e) { + System.out.println("Error Clone not Supported"); + } + return null; + } + + /** + * Get the value of the Variable. + * + * @return the value of the variable + */ + public int getValue() { + return _value; + } + + /** + * Set the value of the Variable. + * + * @param value the value of the variable + */ + public void setValue(int value) { + _value = value; + } + + /** + * Get the name of this SourceCode. + * + * @return the name + */ + public String getName() { + return _name; + } + + /** + * Set the name of this SourceCode. + * + * @param name name of the SourceCode + */ + public void setName(String name) { + _name = name; + } + + /** + * Get the hierarchical parent of this resource. + * + * @return parent of this resource + */ + public Resource getParentResource() { + return _parentResource; + } + + /** + * Set the hierarchical parent of this resource. + * + * @param parentResource new parent + */ + public void setParentResource(Resource parentResource) { + _parentResource = parentResource; + } + + /** + * Return a string representation of the Variable. + * + * @return string representation of the Variable + */ + public String toString() { + return "Variable: " + getName(); + } + + protected int _value; + protected String _name = null; + protected Resource _parentResource = null; +} diff --git a/dol/src/dol/datamodel/pn/package.html b/dol/src/dol/datamodel/pn/package.html new file mode 100644 index 0000000..1151360 --- /dev/null +++ b/dol/src/dol/datamodel/pn/package.html @@ -0,0 +1,20 @@ + + + + + + +Internal data model for the process network representation. + +

Package Specification

+ + + +

Related Documentation

+ + + + + + + diff --git a/dol/src/dol/helper/flattener/ArchFlattener.java b/dol/src/dol/helper/flattener/ArchFlattener.java new file mode 100644 index 0000000..c011d43 --- /dev/null +++ b/dol/src/dol/helper/flattener/ArchFlattener.java @@ -0,0 +1,281 @@ +/* $Id: ArchFlattener.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.helper.flattener; + +import java.util.List; + +import org.jdom.Element; +import org.jdom.Namespace; + +/** + * + */ +public class ArchFlattener extends FlattenerHelper { + + /** + * Constructor. + * + * @param classname class name of the generated class + */ + public ArchFlattener(String classname) { + super(classname); + } + + public String processElement(Element element) + throws RuntimeException { + + String string = ""; + + if (element.getName().equalsIgnoreCase("processor")) { + _generateElement = true; + string = generateProcessor(element); + } + else if (element.getName().equalsIgnoreCase("hw_channel")) { + _generateElement = true; + string = generateLink(element); + } + else if (element.getName().equalsIgnoreCase("memory")) { + _generateElement = true; + string = generateMemory(element); + } + else if (element.getName().equalsIgnoreCase("node")) { + _generateElement = true; + string = generateNode(element); + } + + if (element.getName().equalsIgnoreCase("connection")) { + _generateElement = false; + string = generateConnection(element); + } + + //belongs to mapping! + if (element.getName().equalsIgnoreCase("binding")) { + string = generateBinding(element); + } + return string; + } + + /** + * + */ + @SuppressWarnings("unchecked") + protected String generateProcessor(Element element) { + String attributes[] = {"name", "type", "basename"}; + String sourceCode = generateElement(element, attributes, false); + + for (Element childElement : (List)element.getChildren()) { + if (childElement.getName().equalsIgnoreCase("iterator")) { + sourceCode += generateIterator(childElement); + } + else if (childElement.getName().equalsIgnoreCase("node")) { + sourceCode += generateNode(childElement); + } + else if (childElement.getName().equalsIgnoreCase("configuration")) { + sourceCode += generateConfiguration(childElement); + } + + } + sourceCode += _indent + "System.out.println(\"
\");\n"; + return sourceCode; + } + + /** + * + */ + @SuppressWarnings("unchecked") + protected String generateMemory(Element element) { + String attributes[] = {"name", "type", "basename"}; + String sourceCode = generateElement(element, attributes, false); + + for (Element childElement : (List)element.getChildren()) { + if (childElement.getName().equalsIgnoreCase("iterator")) { + sourceCode += generateIterator(childElement); + } + else if (childElement.getName().equalsIgnoreCase("node")) { + sourceCode += generateNode(childElement); + } + else if (childElement.getName().equalsIgnoreCase("configuration")) { + sourceCode += generateConfiguration(childElement); + } + } + sourceCode += _indent + "System.out.println(\"
\");\n"; + return sourceCode; + } + + /** + * + */ + @SuppressWarnings("unchecked") + protected String generateLink(Element element) { + String attributes[] = {"name", "type", "basename"}; + String sourceCode = generateElement(element, attributes, false); + + for (Element childElement : (List)element.getChildren()) { + if (childElement.getName().equalsIgnoreCase("iterator")) { + sourceCode += generateIterator(childElement); + } + else if (childElement.getName().equalsIgnoreCase("node")) { + sourceCode += generateNode(childElement); + } + else if (childElement.getName().equalsIgnoreCase("configuration")) { + sourceCode += generateConfiguration(childElement); + } + } + sourceCode += _indent + "System.out.println(\"\");\n"; + return sourceCode; + } + + protected String generateConfiguration(Element element) { + String attributes[] = {"name", "value"}; + increaseXmlIndent(); + String sourceCode = generateElement(element, attributes, true); + decreaseXmlIndent(); + return sourceCode; + } + + /** + * + */ + @SuppressWarnings("unchecked") + protected String generateNode(Element element) { + increaseXmlIndent(); + + String sourceCode = ""; + if (_generateElement) { + String attributes[] = {"name", "basename"}; + sourceCode = generateElement(element, attributes, false); + } + else { + String attributes[] = {"name"}; + sourceCode = generateElement(element, attributes, false); + } + + for (Element childElement : (List)element.getChildren()) { + if (childElement.getName().equalsIgnoreCase("duplexport")) { + sourceCode += generatePort(childElement); + } + else if (childElement.getName().equalsIgnoreCase("inputport")) { + sourceCode += generatePort(childElement); + } + else if (childElement.getName().equalsIgnoreCase("outputport")) { + sourceCode += generatePort(childElement); + } + else if (childElement.getName().equalsIgnoreCase("port")) { + sourceCode += generatePort(childElement); + } + } + sourceCode += _indent + "System.out.println(\"" + _xmlIndent + + "
\");\n"; + + decreaseXmlIndent(); + return sourceCode; + } + + protected String generatePort(Element element) { + increaseXmlIndent(); + String sourceCode = ""; + if (_generateElement) { + String attributes[] = {"name", "basename"}; + sourceCode = generateElement(element, attributes, true); + } + else { + String attributes[] = {"name"}; + sourceCode = generateElement(element, attributes, true); + } + decreaseXmlIndent(); + return sourceCode; + } + + /** + * + */ + @SuppressWarnings("unchecked") + protected String generateConnection(Element element) { + String attributes[] = {"name"}; + String sourceCode = generateElement(element, attributes, false); + + //add origin and target elements + for (Element childElement : (List)element.getChildren()) { + if (childElement.getName().equalsIgnoreCase("origin")) { + //origin found + increaseXmlIndent(); + sourceCode += generateElement(childElement, attributes, false); + + Namespace ns= childElement.getNamespace(); + Element nodeElement = childElement.getChild("node", ns); + if (nodeElement != null) { + sourceCode += generateNode(nodeElement); + } + sourceCode += _indent + + "System.out.println(\"" + _xmlIndent + "\");\n"; + decreaseXmlIndent(); + } + else if (childElement.getName().equalsIgnoreCase("target")) { + //target found + increaseXmlIndent(); + sourceCode += generateElement(childElement, attributes, false); + + Namespace ns= childElement.getNamespace(); + Element nodeElement = childElement.getChild("node", ns); + if (nodeElement != null) { + sourceCode += generateNode(nodeElement); + } + sourceCode += _indent + + "System.out.println(\"" + _xmlIndent + "\");\n"; + decreaseXmlIndent(); + } + } + sourceCode += _indent + "System.out.println(\"\");\n"; + return sourceCode; + } + + /** + * + */ + @SuppressWarnings("unchecked") + protected String generateBinding(Element element) { + String attributes[] = {"name", "parameter", "type"}; + String sourceCode = generateElement(element, attributes, false); + + //add origin and target elements + for (Element childElement : (List)element.getChildren()) { + if (childElement.getName().equalsIgnoreCase("origin")) { + //origin found + increaseXmlIndent(); + sourceCode += generateElement(childElement, attributes, false); + + Namespace ns = childElement.getNamespace(); + Element portElement = childElement.getChild("port", ns); + if (portElement != null) { + increaseXmlIndent(); + String[] portAttributes = {"name", "basename"}; + sourceCode += generateElement(portElement, + portAttributes, true); + decreaseXmlIndent(); + } + sourceCode += _indent + + "System.out.println(\"" + _xmlIndent + "\");\n"; + decreaseXmlIndent(); + } + else if (childElement.getName().equalsIgnoreCase("target")) { + //target found + increaseXmlIndent(); + sourceCode += generateElement(childElement, attributes, false); + + Namespace ns = childElement.getNamespace(); + Element portElement = childElement.getChild("port", ns); + if (portElement != null) { + increaseXmlIndent(); + String[] portAttributes = {"name", "basename"}; + sourceCode += generateElement(portElement, + portAttributes, true); + decreaseXmlIndent(); + } + sourceCode += _indent + + "System.out.println(\"" + _xmlIndent + "\");\n"; + decreaseXmlIndent(); + } + } + sourceCode += _indent + "System.out.println(\"\");\n"; + return sourceCode; + } +} diff --git a/dol/src/dol/helper/flattener/BugCatcher.java b/dol/src/dol/helper/flattener/BugCatcher.java new file mode 100644 index 0000000..30fa28f --- /dev/null +++ b/dol/src/dol/helper/flattener/BugCatcher.java @@ -0,0 +1,26 @@ +/* $Id: BugCatcher.java 1 2010-02-24 13:03:05Z haidw $ */ + +package dol.helper.flattener; + +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXParseException; + +/** + * + */ +class BugCatcher implements ErrorHandler { + public void error(SAXParseException ex) { + System.out.println("[ERROR ]: "+ex.getMessage()); + + } + + public void fatalError(SAXParseException ex) { + System.out.println("[PIZDEC ]: "+ex.getMessage()); + + } + + public void warning(SAXParseException ex) { + System.out.println("[WARNING]: "+ex.getMessage()); + + } +} diff --git a/dol/src/dol/helper/flattener/DomDocumentParser.java b/dol/src/dol/helper/flattener/DomDocumentParser.java new file mode 100644 index 0000000..e67a896 --- /dev/null +++ b/dol/src/dol/helper/flattener/DomDocumentParser.java @@ -0,0 +1,41 @@ +/* $Id: DomDocumentParser.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.helper.flattener; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +import org.apache.xerces.parsers.DOMParser; +import org.w3c.dom.Document; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; + +/** + * + */ +public class DomDocumentParser { + + DOMParser dp = null; + public ErrorHandler bc = new BugCatcher(); + + public DomDocumentParser() { + dp = new DOMParser(); + dp.setErrorHandler(bc); + } + + public Document parseDocument(File file){ + try { + InputStream is = new FileInputStream(file); + InputSource iss = new InputSource(is); + dp.parse(iss); + return dp.getDocument(); + } catch (Exception ex) { + ex.printStackTrace(); + } + return null; + } + + public Document parseDocument(String pathToFile){ + return parseDocument(new File(pathToFile)); + } +} diff --git a/dol/src/dol/helper/flattener/FlattenerHelper.java b/dol/src/dol/helper/flattener/FlattenerHelper.java new file mode 100644 index 0000000..b11d977 --- /dev/null +++ b/dol/src/dol/helper/flattener/FlattenerHelper.java @@ -0,0 +1,314 @@ +/* $Id: FlattenerHelper.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.helper.flattener; + +import java.util.List; + +import org.jdom.Document; +import org.jdom.Element; + +import dol.datamodel.XmlTag; + +/** + * Helper class to generate the source code of a class for writing + * an XML file based on an XML file with iterators. For details, refer + * to removeIterators(). + * + * @see #removeIterators(org.jdom.Document doc) + */ +public class FlattenerHelper { + + protected String _preamble = "public class Generator {\n\n public " + + "Generator() {\n //nothing to be done here\n }\n" + + "\n public static void main(String[] args) {\n"; + + + //true, when an element is generated. places a restriction on the append + //element, namely that it must be a single variable, no function of a + //variable + protected boolean _generateElement = false; + + protected String _indent = ""; //indentation of lines in Generator class + + //code for obtaining range of iterator variables. is updated in each + //call of generateAppend + protected String _iteratorRangeCode = ""; + + //indentation of XML elements (use increaseXmlIndent() and + //decreaseXmlIndent() to change the indentation) + protected String _xmlIndent = ""; + + /** + * Default constructor. The generated class will have the name + * "Generator". + */ + public FlattenerHelper() { + } + + /** + * Constructor. + * + * @param classname class name of the generated class + */ + public FlattenerHelper(String classname) { + _preamble = _preamble.replace("Generator", classname); + } + + public String processElement(Element element) { + return ""; + } + + /** + * Generate source code for println statement that prints out an XML + * element. + * @param element the XML element itself + * @param attributes attributes to include in the XML element + * @param standalone true, when element shall be closed. false, otherwise + * @return println statement which prints out the XML element + */ + protected String generateElement(Element element, + String[] attributes, boolean standalone) + { + String sourceCode = _indent + "System.out.println(\""; + sourceCode += _xmlIndent + "<" + element.getName(); + for (int i = 0; i < attributes.length; i++) { + + if (attributes[i].equals("basename")) { + sourceCode += " " + attributes[i] + "=\\\""; + sourceCode += element.getAttributeValue("name"); + + if (!generateAppend(element).equals("")) { + sourceCode += "\\\""; + sourceCode += " range=\\\"" + _iteratorRangeCode; + } + sourceCode += "\\\""; + } else if (attributes[i].equals("name")) { + sourceCode += " " + attributes[i] + "=\\\""; + sourceCode += element.getAttributeValue("name"); + sourceCode += generateAppend(element); + sourceCode += "\\\""; + } else if (attributes[i].equals("size") + && element.getName().equals(_xt.getSWChannelTag())) { + sourceCode += " " + attributes[i] + "=\\\""; + sourceCode += "\" + "; + sourceCode += element.getAttributeValue("size"); + sourceCode += "+ \""; + sourceCode += "\\\""; + } else if (attributes[i].equals("tokensize") + && element.getName().equals(_xt.getSWChannelTag())) { + if (element.getAttributeValue("tokensize") != null) { + sourceCode += " " + attributes[i] + "=\\\""; + sourceCode += "\""; + sourceCode += " + "; + sourceCode += element.getAttributeValue("tokensize"); + sourceCode += "+ \""; + sourceCode += "\\\""; + } + } else { + sourceCode += " " + attributes[i] + "=\\\""; + sourceCode += element.getAttributeValue(attributes[i]); + sourceCode += "\\\""; + } + + } + + if (standalone) + sourceCode += "/"; + sourceCode +=">\");\n"; + + return sourceCode; + } + + /** + * + */ + @SuppressWarnings("unchecked") + public String removeIterators(Document doc) + throws RuntimeException { + String sourceCode = _preamble; + String functionString = ""; + String rootName = ""; + _indent = " "; + + Element root = doc.getRootElement(); + String xmlns = root.getNamespaceURI(); + String xsiLocation = ""; + for (org.jdom.Attribute attr : + (List)root.getAttributes()) { + //System.out.println(attr.getName() + ": "); + //System.out.println(attr.getValue()); + if (attr.getName().equals("schemaLocation")) + xsiLocation = attr.getValue(); + } + + if (!root.getChildren().isEmpty()) { + //if there are any elements in the document, create a new header + //for the xml document + rootName = root.getName(); + + sourceCode += _indent + + "java.util.Hashtable table = " + + "new java.util.Hashtable();\n"; + + sourceCode += _indent + "System.out.println(\"" + + "\");\n"; + sourceCode += _indent + "System.out.println(\"<" + + rootName + " xmlns=\\\"" + xmlns + + "\\\" xmlns:xsi=\\\"http://www.w3.org/2001/" + + "XMLSchema-instance\\\" \\n xsi:schemaLocation=\\\"" + + xsiLocation + "\\\" name=\\\"" + + root.getAttributeValue("name") + "_flattened" + + "\\\">\\n \");\n"; + } + + + for (Element elmt : (List)root.getChildren()) { + try { + if (elmt.getName().equalsIgnoreCase(_xt.getIteratorTag())) { + sourceCode += generateIterator(elmt); + } + else if (elmt.getName().equalsIgnoreCase(_xt.getVariableTag())) { + sourceCode += generateVariable(elmt); + } + else if (elmt.getName().equalsIgnoreCase(_xt.getFunctionTag())) { + functionString += generateFunction(elmt); + } + else { + sourceCode += processElement(elmt); + } + } + catch (RuntimeException e) { + String elementName = ""; + System.out.println(e.getMessage()); + if (!elmt.getName().equalsIgnoreCase(_xt.getIteratorTag()) && + !elmt.getName().equalsIgnoreCase(_xt.getVariableTag())) { + elementName = elmt.getAttributeValue("name"); + } + throw new RuntimeException( + "Error: An error occurred while parsing the <" + + elmt.getName() + "> element \"" + + elementName + "\"."); + } + } + + sourceCode += _indent + "System.out.println(\"\");\n }\n"; + _indent = " "; + sourceCode += functionString; + sourceCode += "\n}"; + + return sourceCode; + } + + + /** + * + */ + @SuppressWarnings("unchecked") + protected String generateIterator(Element element) { + String variableName = element.getAttributeValue("variable"); + /* + //extract the upper iteration boundary and construct the for loop + String forLoop = element.getAttributeValue("range"); + String boundary = forLoop.replaceAll( + "for.*;[ ]*\\w*[ ]*[<>=]* *(.*);.*", "$1"); + */ + String forLoop = "for (int " + variableName + " = 0; " + variableName + + " < " + element.getAttributeValue("range") + "; " + + variableName + "++)"; + + String sourceCode = _indent + "table.put(\"" + variableName + + "\", " + element.getAttributeValue("range") + ");\n"; + + sourceCode += _indent + forLoop + " {\n"; + _indent += " "; + + for (Element el : (List)element.getChildren()) { + try { + if (el.getName().equalsIgnoreCase(_xt.getIteratorTag())) { + sourceCode += generateIterator(el); + } + else { + sourceCode += processElement(el); + } + } + catch (RuntimeException e) { + System.out.println(e.getMessage()); + throw new RuntimeException( + "Error: An error occurred while parsing the <" + + el.getName() + "> element \"" + + el.getAttributeValue("name") + "\"."); + } + } + _indent = _indent.substring(0, _indent.length() - 2); + sourceCode += _indent + "}\n"; + sourceCode += _indent + "table.remove(\"" + variableName + "\");\n"; + + return sourceCode; + } + + /** + * + */ + @SuppressWarnings("unchecked") + protected String generateAppend(Element element) + throws RuntimeException { + String sourceCode = ""; + + _iteratorRangeCode = ""; + for (Element childElement : (List)element.getChildren()) { + if (childElement.getName().equalsIgnoreCase("append")) { + if (_generateElement && + !childElement.getAttributeValue(_xt.getFunctionTag()).replaceAll( + "\\w", "").equals("")) { + throw new RuntimeException("Error: Found \"" + + childElement.getAttributeValue("function") + + "\" in . When constructing elements with an " + + "iterator using , xxx must " + + "be a single variable. No mathematical operations " + + "are permitted."); + } + sourceCode += "\" + \"_\" + (" + + childElement.getAttributeValue(_xt.getFunctionTag()) + + ") + \""; + + if (!_iteratorRangeCode.equals("")) + _iteratorRangeCode += ";"; + + _iteratorRangeCode += "\" + table.get(\"" + + childElement.getAttributeValue(_xt.getFunctionTag()) + + "\") + \""; + } + } + return sourceCode; + } + + protected String generateVariable(Element element) { + String sourceCode = _indent + "int "; + sourceCode += element.getAttributeValue("name"); + sourceCode += " = "; + sourceCode += element.getAttributeValue("value"); + sourceCode += ";\n"; + return sourceCode; + } + + protected String generateFunction(Element element) { + return element.getText(); + } + + /** + * Increase the XML indentation. + **/ + protected void increaseXmlIndent() { + _xmlIndent += " "; + } + + /** + * Decrease the XML indentation. + */ + protected void decreaseXmlIndent() { + _xmlIndent = _xmlIndent.substring(0, _xmlIndent.length() - 2); + } + + protected XmlTag _xt = XmlTag.getInstance(); +} diff --git a/dol/src/dol/helper/flattener/MappingFlattener.java b/dol/src/dol/helper/flattener/MappingFlattener.java new file mode 100644 index 0000000..19ae0e7 --- /dev/null +++ b/dol/src/dol/helper/flattener/MappingFlattener.java @@ -0,0 +1,156 @@ +/* $Id: MappingFlattener.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.helper.flattener; + +import java.util.List; + +import org.jdom.Element; + +/** + * + */ +public class MappingFlattener extends FlattenerHelper { + + /** + * Constructor. + * + * @param classname class name of the generated class + */ + public MappingFlattener(String classname) { + super(classname); + } + + public String processElement(Element element) + throws RuntimeException { + + String string = ""; + + if (element.getName().equalsIgnoreCase("binding")) { + _generateElement = false; + string = generateBinding(element); + } + else if (element.getName().equalsIgnoreCase("path")) { + _generateElement = false; + string = generatePath(element); + } + else if (element.getName().equalsIgnoreCase("schedule")) { + _generateElement = false; + string = generateSchedule(element); + } + + return string; + } + + /** + * + */ + @SuppressWarnings("unchecked") + protected String generatePath(Element element) { + String attributes[] = {"name"}; + String sourceCode = generateElement(element, attributes, false); + + //add origin and target elements + for (Element childElement : (List)element.getChildren()) { + if (childElement.getName().equalsIgnoreCase("origin") + || childElement.getName().equalsIgnoreCase("target")) { + sourceCode += generateOriginOrTarget(childElement); + } + else if (childElement.getName().equalsIgnoreCase("resource")) { + String rAttributes[] = {"name"}; + increaseXmlIndent(); + sourceCode += generateElement(childElement,rAttributes, false); + sourceCode += _indent + + "System.out.println(\"" + _xmlIndent + "
\");\n"; + decreaseXmlIndent(); + } + else if (childElement.getName().equalsIgnoreCase("buffer")) { + String bAttributes[] = {"name"}; + increaseXmlIndent(); + sourceCode += generateElement(childElement,bAttributes, false); + sourceCode += _indent + + "System.out.println(\"" + _xmlIndent + "\");\n"; + decreaseXmlIndent(); + } + } + sourceCode += _indent + "System.out.println(\"\");\n"; + return sourceCode; + } + + /** + * + */ + @SuppressWarnings("unchecked") + protected String generateSchedule(Element element) { + String attributes[] = {"name", "type"}; + String sourceCode = generateElement(element, attributes, false); + + //add origin and target elements + + for (Element childElement : (List)element.getChildren()) { + if (childElement.getName().equalsIgnoreCase("origin")) { + sourceCode += generateOriginOrTarget(childElement); + } + else if (childElement.getName().equalsIgnoreCase("resource")) { + String rAttributes[] = {"name"}; + increaseXmlIndent(); + sourceCode += generateElement(childElement,rAttributes, false); + sourceCode += _indent + + "System.out.println(\"" + _xmlIndent + "
\");\n"; + decreaseXmlIndent(); + } + } + sourceCode += _indent + "System.out.println(\"\");\n"; + return sourceCode; + } + + /** + * + */ + @SuppressWarnings("unchecked") + protected String generateBinding(Element element) { + String attributes[] = {"name", "type"}; + String sourceCode = generateElement(element, attributes, false); + + //add origin and target elements + for (Element childElement : (List)element.getChildren()) { + if (childElement.getName().equalsIgnoreCase("origin") + || childElement.getName().equalsIgnoreCase("target")) { + sourceCode += generateOriginOrTarget(childElement); + } + } + sourceCode += _indent + "System.out.println(\"\");\n"; + return sourceCode; + } + + /** + * + */ + @SuppressWarnings("unchecked") + protected String generateOriginOrTarget(Element element) { + String attributes[] = {"name"}; + increaseXmlIndent(); + String sourceCode = generateElement(element, attributes, false); + + //add configuration elements + for (Element childElement : (List)element.getChildren()) { + if (childElement.getName().equalsIgnoreCase(_xt.getConfigurationTag())) { + sourceCode += generateConfiguration(childElement); + } + } + + sourceCode += _indent + "System.out.println(\"" + _xmlIndent + "\");\n"; + decreaseXmlIndent(); + + return sourceCode; + } + + protected String generateConfiguration(Element element) { + String attributes[] = {"name", "value"}; + increaseXmlIndent(); + String sourceCode = generateElement(element, attributes, true); + decreaseXmlIndent(); + return sourceCode; + } + + +} diff --git a/dol/src/dol/helper/flattener/PNFlattener.java b/dol/src/dol/helper/flattener/PNFlattener.java new file mode 100644 index 0000000..fc6af53 --- /dev/null +++ b/dol/src/dol/helper/flattener/PNFlattener.java @@ -0,0 +1,184 @@ +/* $Id: PNFlattener.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.helper.flattener; + +import java.util.List; + +import org.jdom.Element; +import org.jdom.Namespace; + +/** + * + */ +public class PNFlattener extends FlattenerHelper { + + /** + * Constructor. + * + * @param classname class name of the generated class + */ + public PNFlattener(String classname) { + super(classname); + } + + public String processElement(Element element) + throws RuntimeException { + + String string = ""; + + _generateElement = true; + if (element.getName().equalsIgnoreCase(_xt.getProcessTag())) { + string = generateProcess(element); + } else if (element.getName().equalsIgnoreCase(_xt.getSWChannelTag())) { + string = generateChannel(element); + } else if (element.getName().equalsIgnoreCase(_xt.getPortTag())) { + string = generatePort(element); + } else if (element.getName().equalsIgnoreCase(_xt.getConfigurationTag())) { + string = generateConfiguration(element); + } else if (element.getName().equalsIgnoreCase(_xt.getProfilingTag())) { + string = generateProfiling(element); + } + + _generateElement = false; + + if (element.getName().equalsIgnoreCase(_xt.getConnectionTag())) { + string = generateConnection(element); + } + return string; + } + + /** + * + */ + @SuppressWarnings("unchecked") + protected String generateProcess(Element element) { + String attributes[] = {"name", "basename"}; + String sourceCode = generateElement(element, attributes, false); + + for (Element childElement : (List)element.getChildren()) { + if (!(childElement.getName().equalsIgnoreCase(_xt.getPortTag()) || + childElement.getName().equalsIgnoreCase(_xt.getSourceTag()) || + childElement.getName().equalsIgnoreCase(_xt.getConfigurationTag()) || + childElement.getName().equalsIgnoreCase(_xt.getProfilingTag()))) { + if (childElement.getName().equalsIgnoreCase(_xt.getIteratorTag())) { + sourceCode += generateIterator(childElement); + } + } else { + if (childElement.getName().equalsIgnoreCase(_xt.getPortTag())) { + sourceCode += generatePort(childElement); + } else if (childElement.getName().equalsIgnoreCase(_xt.getConfigurationTag())) { + sourceCode += generateConfiguration(childElement); + } else if (childElement.getName().equalsIgnoreCase(_xt.getProfilingTag())) { + sourceCode += generateProfiling(childElement); + } + else { + //source found + increaseXmlIndent(); + String[] sourceAttributes = {"location", "type"}; + sourceCode += generateElement(childElement, + sourceAttributes, true); + decreaseXmlIndent(); + } + } + } + sourceCode += _indent + "System.out.println(\"\");\n"; + return sourceCode; + } + + /** + * + */ + @SuppressWarnings("unchecked") + protected String generateChannel(Element element) { + String attributes[] = {"name", "type", "size", + "basename", "tokensize"}; + String sourceCode = generateElement(element, attributes, false); + + for (Element childElement : (List)element.getChildren()) { + if (childElement.getName().equalsIgnoreCase(_xt.getPortTag())) { + sourceCode += generatePort(childElement); + } else if (childElement.getName().equalsIgnoreCase(_xt.getConfigurationTag())) { + sourceCode += generateConfiguration(childElement); + } else if (childElement.getName().equalsIgnoreCase(_xt.getProfilingTag())) { + sourceCode += generateProfiling(childElement); + } + } + sourceCode += _indent + "System.out.println(\"\");\n"; + return sourceCode; + } + + protected String generatePort(Element element) { + String attributes[] = {"name", "type", "basename"}; + increaseXmlIndent(); + String sourceCode = generateElement(element, attributes, true); + decreaseXmlIndent(); + return sourceCode; + } + + protected String generateConfiguration(Element element) { + String attributes[] = {"name", "value"}; + increaseXmlIndent(); + String sourceCode = generateElement(element, attributes, true); + decreaseXmlIndent(); + return sourceCode; + } + + protected String generateProfiling(Element element) { + String attributes[] = {"name", "value"}; + increaseXmlIndent(); + String sourceCode = generateElement(element, attributes, true); + decreaseXmlIndent(); + return sourceCode; + } + + /** + * + */ + @SuppressWarnings("unchecked") + protected String generateConnection(Element element) { + String attributes[] = {"name"}; + String sourceCode = generateElement(element, attributes, false); + + //add origin and target elements + for (Element childElement : (List)element.getChildren()) { + if (childElement.getName().equalsIgnoreCase("origin")) { + //origin found + increaseXmlIndent(); + sourceCode += generateElement(childElement, attributes, false); + + Namespace ns = childElement.getNamespace(); + Element portElement = childElement.getChild("port", ns); + if (portElement != null) { + increaseXmlIndent(); + String[] portAttributes = {"name"}; + sourceCode += generateElement(portElement, + portAttributes, true); + decreaseXmlIndent(); + } + decreaseXmlIndent(); + sourceCode += _indent + + "System.out.println(\" \");\n"; + } + else if (childElement.getName().equalsIgnoreCase(_xt.getTargetTag())) { + //target found + increaseXmlIndent(); + sourceCode += generateElement(childElement, attributes, false); + + Namespace ns = childElement.getNamespace(); + Element portElement = childElement.getChild(_xt.getPortTag(), ns); + if (portElement != null) { + increaseXmlIndent(); + String[] portAttributes = {"name"}; + sourceCode += generateElement(portElement, + portAttributes, true); + decreaseXmlIndent(); + } + decreaseXmlIndent(); + sourceCode += _indent + + "System.out.println(\" \");\n"; + } + } + sourceCode += _indent + "System.out.println(\"\");\n"; + return sourceCode; + } +} diff --git a/dol/src/dol/helper/flattener/SaxDocumentParser.java b/dol/src/dol/helper/flattener/SaxDocumentParser.java new file mode 100644 index 0000000..2394991 --- /dev/null +++ b/dol/src/dol/helper/flattener/SaxDocumentParser.java @@ -0,0 +1,107 @@ +/* $Id: SaxDocumentParser.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.helper.flattener; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +import org.apache.xerces.parsers.SAXParser; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * + */ +class SaxDocumentParser implements ContentHandler{ + + public ErrorHandler bc = new BugCatcher(); + public SAXParser sp = null; + protected boolean foundIterator = false; + + public SaxDocumentParser() { + try { + sp = new SAXParser(); + sp.setFeature("http://xml.org/sax/features/validation",true); + sp.setFeature("http://apache.org/xml/features/validation/schema", true); + sp.setFeature("http://apache.org/xml/features/validation/schema-full-checking", true); + sp.setErrorHandler(bc); + sp.setContentHandler(this); + sp.setProperty("http://apache.org/xml/properties/schema/external-schemaLocation", + dol.util.SchemaLocation.getInternalSchemaLocation()); + } + catch (Exception ex) { + ex.printStackTrace(); + } + } + + public boolean parseDocument(String pathToFile){ + return parseDocument(new File(pathToFile)); + } + + public boolean parseDocument(File file){ + try{ + InputStream is = new FileInputStream(file); + InputSource iss = new InputSource(is); + sp.parse(iss); + } + catch (Exception e){ + e.printStackTrace(); + } + return true;//foundIterator; + } + + /** + * Action to be done while parsing a start element of an XML + * + * @param elementName Description of the Parameter + * @param attributes Description of the Parameter + * @exception SAXException MyException If such and such occurs + */ + public void startElement(String namespaceURI, String localName, String elementName, Attributes attributes) throws SAXException { + + if (elementName.equals("iterator")) { + //System.out.println(); + //System.out.println("Iterator found in document"); + foundIterator = true; + } + else { + System.out.print("."); + } + } + + + public void startDocument() throws SAXException { + } + + public void startPrefixMapping(String prefix, String uri) throws SAXException { + } + + public void endDocument() throws SAXException { + } + + public void endElement(String namespaceURI, String localName, String elementName) throws SAXException { + } + + public void endPrefixMapping(String prefix) throws SAXException { + } + + public void characters(char buf[], int offset, int len) throws SAXException { + } + + public void skippedEntity(String string){ + } + + public void processingInstruction(String string1, String string2){ + } + + public void ignorableWhitespace(char[] characters,int int1,int int2){ + } + + public void setDocumentLocator(org.xml.sax.Locator dl){ + } + + } + diff --git a/dol/src/dol/helper/flattener/XMLFlattener.java b/dol/src/dol/helper/flattener/XMLFlattener.java new file mode 100644 index 0000000..7aade7c --- /dev/null +++ b/dol/src/dol/helper/flattener/XMLFlattener.java @@ -0,0 +1,71 @@ +/* $Id: XMLFlattener.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.helper.flattener; + +import java.io.File; +import java.io.FileWriter; + +import org.jdom.input.DOMBuilder; +import org.w3c.dom.Document; + +/** + * + */ +public class XMLFlattener { + + public static void main(String[] args) { + + if (args.length != 2) { + System.out.println("Wrong number of arguments."); + System.out.println("Correct call:"); + System.out.println("java XMLFlattener in.xml out.xml"); + System.exit(-1); + } + else { + SaxDocumentParser sdp = new SaxDocumentParser(); + boolean needsToBeFlattened = false; + needsToBeFlattened = sdp.parseDocument(args[0]); + if (needsToBeFlattened) { + // start also with DOM Parser and generate the XML-Generator + DomDocumentParser ddp = new DomDocumentParser(); + Document doc = ddp.parseDocument(args[0]); + + DOMBuilder db = new DOMBuilder(); + org.jdom.Document document = db.build(doc); + + String xmlns = document.getRootElement().getNamespaceURI(); + + String outString = ""; + + if (xmlns.endsWith("PROCESSNETWORK") || + xmlns.endsWith("processnetwork")) { + PNFlattener flattener = new PNFlattener(args[1]); + outString = flattener.removeIterators(document); + } + else if (xmlns.endsWith("ARCHITECTURE") + || xmlns.endsWith("ARCHITECTURE_OLD") + || xmlns.endsWith("architecture")) { + ArchFlattener flattener = new ArchFlattener(args[1]); + outString = flattener.removeIterators(document); + } + else if (xmlns.endsWith("MAPPING") + || xmlns.endsWith("MAPPING_OLD") + || xmlns.endsWith("mapping")) { + MappingFlattener flattener = new MappingFlattener(args[1]); + outString = flattener.removeIterators(document); + } + + + try { + FileWriter fw = new FileWriter(new File(args[1] + ".java")); + fw.write(outString); + fw.flush(); + fw.close(); + } catch (Exception ex) { + } + } + else { + System.out.println("Nothing to be done. Terminating..."); + } + } + } +} diff --git a/dol/src/dol/helper/flattener/package.html b/dol/src/dol/helper/flattener/package.html new file mode 100644 index 0000000..4f62fe4 --- /dev/null +++ b/dol/src/dol/helper/flattener/package.html @@ -0,0 +1,20 @@ + + + + + + +Flattener which unfolds all iterators inside XML files. + +

Package Specification

+ + + +

Related Documentation

+ + + + + + + diff --git a/dol/src/dol/helper/profiler/ChannelProfile.java b/dol/src/dol/helper/profiler/ChannelProfile.java new file mode 100644 index 0000000..4de3cc7 --- /dev/null +++ b/dol/src/dol/helper/profiler/ChannelProfile.java @@ -0,0 +1,221 @@ +/* $Id: ChannelProfile.java 203 2010-10-11 08:59:47Z dchokshi $ */ +package dol.helper.profiler; + +/** + * Functional simulation profile information for a channel. + */ +public class ChannelProfile { + + /** + * Constructor. + * + * @param name name of the channel this profile belongs to + * @param capacity capacity of this channel + */ + public ChannelProfile(String name, int capacity) { + _name = name; + _capacity = capacity; + } + + /** + * Adds a read access. Reduces the fifo fill level accordingly. If the + * amount is larger than the current fifo size, the read is blocking. + * + * @param amount The amount of data in bytes. + */ + public void readAccess(int amount) { + _numOfReads++; + _totalReadData += amount; + + if (amount > _maxReadChunk) + _maxReadChunk = amount; + + if (amount < _minReadChunk) + _minReadChunk = amount; + + if (_fillLevel < amount) { + _numOfBlockingReads++; + _blockedReadSize = amount; + } + else { + _fillLevel -= amount; + } + } + + /** + * Adds a write access. Enlarges the fifo size accordingly. If the + * amount plus the current size of the fifo is larger than the + * capacity, an overflow occurs (blocking write). + * + * @param amount The amount of data in bytes. + */ + public void writeAccess(int amount) { + _numOfWrites++; + if (_fillLevel + amount > _capacity) { + _numOfBlockingWrites++; + } + + _fillLevel += amount; + + if (amount > _maxWriteChunk) + _maxWriteChunk = amount; + + if (amount < _minWriteChunk) + _minWriteChunk = amount; + + if (_fillLevel > _maxFillLevel) + _maxFillLevel = _fillLevel; + + + if ((_fillLevel >= _blockedReadSize) && (_blockedReadSize != 0)) { + _fillLevel -= _blockedReadSize; + _blockedReadSize = 0; + } + } + + /** + * Returns the maximum amount of data stored in the fifo. + * + * @return Maximum fill level in bytes. + */ + public int getMaxFillLevel() { + return _maxFillLevel; + } + + /** + * Returns the size of the largest chunk of data read in a single + * read access. + * + * @return Size of the largest read chunk in bytes. + */ + public int getMaxReadChunk() { + return _maxReadChunk; + } + + /** + * Returns the size of the smallest chunk of data read in a single + * read access. + * + * @return Size of the smallest read chunk in bytes. + */ + public int getMinReadChunk() { + return _minReadChunk; + } + + /** + * Returns the size of the largest chunk of data written in a single + * write access. + * + * @return Size of the largest written chunk in bytes. + */ + public int getMaxWriteChunk() { + return _maxWriteChunk; + } + + /** + * Returns the size of the smallest chunk of data written in a single + * write access. + * + * @return Size of the smallest written chunk in bytes. + */ + public int getMinWriteChunk() { + return _minWriteChunk; + } + + /** + * Returns the number of total read accesses. + * + * @return Number of total read accesses. + */ + public int getNumOfReads() { + return _numOfReads; + } + + /** + * Returns the number of total blocking reads. + * A blocking read occurs whenever there is an attempt to read more + * data from the fifo than the fifo contains. + * + * @return Number of total blocking reads + */ + public int getNumOfBlockingReads() { + return _numOfBlockingReads; + } + + /** + * Returns the total number of write accesses. + * + * @return Number of total write accesses. + */ + public int getNumOfWrites() { + return _numOfWrites; + } + + /** + * Returns the number of total blocking writes. + * A blocking write occurs, whenever a write access tries to write + * more data into the fifo than its capacity allows. + * + * @return Number of total overflows. + */ + public int getNumOfOverflows() { + return _numOfBlockingWrites; + } + + /** + * Returns the percentage of read accesses which were blocking. + * @return Percentage of blocking reads + */ + public int getBlockingReadsPercentage() { + if (_numOfReads == 0) + return 0; + + return (_numOfBlockingReads * 100) / (_numOfReads); + } + /** + * Returns the percentage of write accesses, which led to an overflow. + * @return Percentage of overflows. + */ + public int getBlockingWritesPercentage() { + if (_numOfWrites == 0) + return 0; + + return (_numOfBlockingWrites * 100) / (_numOfWrites); + } + + /** + * Returns the total amount of read data (in bytes). + * @return Amount in bytes. + */ + public long getTotalReadData() { + return _totalReadData; + } + + /** + * Return the name of the channel this profile belongs to. + * + * @return name of the channel this profile belongs to + */ + public String getName() { + return _name; + } + + + protected String _name = ""; + protected int _capacity = 0; + + protected long _totalReadData = 0; + protected int _fillLevel = 0; + protected int _maxFillLevel = 0; + + protected int _numOfReads = 0; + protected int _numOfBlockingReads = 0; + protected int _maxReadChunk = 0; + protected int _minReadChunk = Integer.MAX_VALUE; + protected int _blockedReadSize = 0; + + protected int _numOfWrites = 0; + protected int _numOfBlockingWrites = 0; + protected int _maxWriteChunk = 0; + protected int _minWriteChunk = Integer.MAX_VALUE; +} diff --git a/dol/src/dol/helper/profiler/Constants.java b/dol/src/dol/helper/profiler/Constants.java new file mode 100644 index 0000000..673e1b5 --- /dev/null +++ b/dol/src/dol/helper/profiler/Constants.java @@ -0,0 +1,13 @@ +/* $Id: Constants.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.helper.profiler; + +/** + * Keys for accessing profile properties. + */ +public class Constants { + public final static String processFires = "Process.Fires"; + public final static String portAccesses = "Port.Accesses"; + public final static String portTokenSize = "Port.TokenSize"; + public final static String portInitialAccesses = "Port.InitialAccesses"; + public final static String portInitialTokenSize = "Port.IntialTokensize"; +} diff --git a/dol/src/dol/helper/profiler/PNProfileSummarizer.java b/dol/src/dol/helper/profiler/PNProfileSummarizer.java new file mode 100644 index 0000000..66b1d58 --- /dev/null +++ b/dol/src/dol/helper/profiler/PNProfileSummarizer.java @@ -0,0 +1,105 @@ +/* $Id: PNProfileSummarizer.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.helper.profiler; + +import java.util.HashMap; +import java.util.StringTokenizer; + +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.ProfilingConfiguration; +import dol.parser.xml.pnschema.PNXmlParser; +import dol.visitor.xml.PNXmlVisitor; + +/** + * Class to post-process profiling info in a process network XML file. + */ +public class PNProfileSummarizer { + /** + * Add up all WCED, BCED, and ACED numbers for each process in the + * given process network file. The computed numbers are back-annotated + * to a new file with the suffix _summary. + * + * @param filename filename of annotated process network XML file + */ + public static void sumDemands(String filename) { + HashMap configs = + new HashMap(); + + //load process network specification from XML + PNXmlParser parserPn = new PNXmlParser(); + ProcessNetwork pn = parserPn.doParse(filename); + + for (Process process : pn.getProcessList()) { + //System.out.println(process.getName()); + for (ProfilingConfiguration cfg : + process.getProfilingList()) { + StringTokenizer tokenizer = + new StringTokenizer(cfg.getName(), " "); + //System.out.println(cfg.getName()); + if (tokenizer.countTokens() < 2) { + continue; + } + + String demandId = tokenizer.nextToken(); + String processorName = tokenizer.nextToken(); + String key = process.getName() + " " + demandId + " " + + processorName + " sum"; + if (configs.get(key) == null) { + ProfilingConfiguration config = + new ProfilingConfiguration(demandId + " " + + processorName + " sum"); + config.setValue("0"); + configs.put(key, config); + } + ProfilingConfiguration currentCfg = configs.get(key); + /* + System.out.print(currentCfg.getName() + ": " + + currentCfg.getValue() + " / " + + cfg.getName() + ": " + + cfg.getValue()); + */ + currentCfg.setValue( + Long.toString(Long.parseLong( + currentCfg.getValue()) + + Long.parseLong(cfg.getValue()))); + /* + System.out.println(currentCfg.getName() + ": " + + currentCfg.getValue()); + */ + } + } + + for(String key : configs.keySet()) { + ProfilingConfiguration value = configs.get(key); + String process = key.substring(0, key.indexOf(" ")); + pn.getProcess(process).getProfilingList().add(value); + } + + System.out.println("Write process network XML file"); + StringBuffer buffer = new StringBuffer(); + pn.accept(new PNXmlVisitor(buffer)); + try { + java.io.BufferedWriter writer = + new java.io.BufferedWriter( + new java.io.FileWriter( + filename.replaceAll(".xml", "_summary.xml"))); + writer.write(buffer.toString()); + writer.close(); + } catch (java.io.IOException e) { + System.out.println("Caught an exception while " + + "creating XML file: " + e.getMessage()); + e.printStackTrace(System.out); + } + System.out.println(" -- Process network XML file [Finished]"); + } + + + /** + * Run summarize operations on annotated process network. + * + * @param args filename of annotated process network XML file + */ + public static void main(String args[]) throws Exception { + PNProfileSummarizer.sumDemands(args[0]); + } +} diff --git a/dol/src/dol/helper/profiler/PortProfile.java b/dol/src/dol/helper/profiler/PortProfile.java new file mode 100644 index 0000000..cd040ab --- /dev/null +++ b/dol/src/dol/helper/profiler/PortProfile.java @@ -0,0 +1,95 @@ +/* $Id: PortProfile.java 203 2010-10-11 08:59:47Z dchokshi $ */ +package dol.helper.profiler; + +/** + * Functional simulation profile information for a port. + */ +public class PortProfile { + + /** + * Constructor. + * + * @param name name of the port this profile belongs to + */ + public PortProfile(String name, ProcessProfile processProfile) { + _name = name; + _processProfile = processProfile; + _accesses = new Range(); + _tokenSize = new Range(); + _currentTokenSize = new Range(); + } + + /** + * Return the name of the channel this profile belongs to. + * + * @return name of the channel this profile belongs to + */ + public String getName() { + return _name; + } + + /** + * Add a read or write access to this port. + * + * @param tokenSize number of bytes communicated in this access + */ + public void addAccess(int tokenSize) { + _currentAccesses++; + _currentTokenSize.merge(tokenSize); + } + + /** + * Add an initial read or write access to this port (access happened + * during init() phase). + * + * @param tokenSize number of bytes communicated in this access + */ + public void addInitialAccess(int tokenSize) { + _initialAccesses++; + if (_initialTokenSize == null) { + _initialTokenSize = new Range(tokenSize); + } else { + _initialTokenSize.merge(tokenSize); + } + } + + /** + * + */ + public void update() { + _accesses.merge(_currentAccesses); + _tokenSize.merge(_currentTokenSize); + + _currentAccesses = 0; + _currentTokenSize.reset(); + } + + public int getInitialAccesses() { + return _initialAccesses; + } + + public Range getInitialTokenSize() { + if (_initialTokenSize == null) { + return new Range(0); + } else { + return _initialTokenSize; + } + } + + public Range getAccesses() { + return _accesses; + } + + public Range getTokenSize() { + return _tokenSize; + } + + String _name; + Range _accesses; + Range _tokenSize; + int _currentAccesses; + Range _currentTokenSize; + int _initialAccesses; + Range _initialTokenSize = null; + ProcessProfile _processProfile; +} diff --git a/dol/src/dol/helper/profiler/ProcessProfile.java b/dol/src/dol/helper/profiler/ProcessProfile.java new file mode 100644 index 0000000..f8e51a8 --- /dev/null +++ b/dol/src/dol/helper/profiler/ProcessProfile.java @@ -0,0 +1,97 @@ +/* $Id: ProcessProfile.java 203 2010-10-11 08:59:47Z dchokshi $ */ +package dol.helper.profiler; + +import java.util.HashMap; +import java.util.Iterator; + +/** + * Functional simulation profile information for a process. + */ +public class ProcessProfile { + + /** + * Constructor. + * + * @param name name of the process this profile belongs to + */ + public ProcessProfile(String name) { + _name = name; + _portProfiles = new HashMap(); + } + + /** + * Indicate that the process has entered fire(). + */ + public void start() { + _started = true; + _numOfFires++; + } + + /** + * Indicate that the process has leaved fire(). + */ + public void stop() { + if (!_started) { + return; + } + + _started = false; + + Iterator iterator = _portProfiles.keySet().iterator(); + + while (iterator.hasNext()) { + PortProfile profile = _portProfiles.get(iterator.next()); + profile.update(); + } + } + + /** + * Indicate a read or write access to a port. + * + * @param port the accessed port + * @param amount number of bytes communicated + */ + public void portAccess(String port, int amount) { + if (_portProfiles.get(port) == null) { + PortProfile profile = new PortProfile(port, this); + _portProfiles.put(port, profile); + } + if (_started) { + _portProfiles.get(port).addAccess(amount); + } else { + _portProfiles.get(port).addInitialAccess(amount); + } + } + + /** + * Return the number of firings. + * + * @return the number of fire() calls of a process. + **/ + public int getNumOfFires() { + return _numOfFires; + } + + /** + * Return the name of the process this profile belongs to. + * + * @return name of the process this profile belongs to + */ + public String getName() { + return _name; + } + + /** + * Return the profiles of all ports. + * + * @return profile of all ports + */ + public HashMap getPortProfiles() { + return _portProfiles; + } + + protected String _name; + boolean _started = false; + protected int _numOfFires = 0; + HashMap _portProfiles; +} diff --git a/dol/src/dol/helper/profiler/ProfileParser.java b/dol/src/dol/helper/profiler/ProfileParser.java new file mode 100644 index 0000000..5ad1304 --- /dev/null +++ b/dol/src/dol/helper/profiler/ProfileParser.java @@ -0,0 +1,273 @@ +/* $Id: ProfileParser.java 203 2010-10-11 08:59:47Z dchokshi $ */ +package dol.helper.profiler; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.StringTokenizer; +import java.util.Vector; + +/** + * Class for parsing a profile and collecting parameter statistics. + */ +public class ProfileParser { + + /** + * Constructor. + **/ + public ProfileParser(String filename) { + try { + _in = new BufferedReader(new FileReader(filename)); + } catch (IOException e) { + System.err.println(e.getLocalizedMessage()); + } + + _processProfiles = new HashMap(); + _channelProfiles = new HashMap(); + _inPortToChannelMapping = new HashMap(); + _outPortToChannelMapping = new HashMap(); + _processCommOrder = new HashMap>(); + } + + /** + * Parse the profile file and generate the profiles for processes and + * channels. After calling this function, use + * {@link #getProcessProfiles()} and {@link #getChannelProfiles()} to + * obtain the result of parsing. + * + * @see #getChannelProfiles() + * @see #getProcessProfiles() + */ + public void parseProfile() { + String nextWord; + String line = null; + + while (true) { + try { + //PERFORMANCE: do not read line-by-line but read in larger + //chunks from the file. has much more influence on the + //performance than the data structures in this class. + line = _in.readLine(); + if (line == null) { + _in.close(); + + Iterator iterator = _processProfiles.keySet().iterator(); + while (iterator.hasNext()) { + _processProfiles.get(iterator.next()).stop(); + } + return; + } + } catch (IOException e) { + System.err.println(e.getLocalizedMessage()); + return; + } + + StringTokenizer tokenizer = new StringTokenizer(line); + nextWord = tokenizer.nextToken(); + + if (nextWord.equals("c")) { + //'c' stands for a channel connection line. example: + //c filterchannel 8 o filter 0x23c738 i filter 0x23c6e8 + String channelName = tokenizer.nextToken(); + int capacity = Integer.parseInt( + tokenizer.nextToken()); + String portAType = tokenizer.nextToken(); + String processAName = tokenizer.nextToken(); + String portAName = tokenizer.nextToken(); + String portBType = tokenizer.nextToken(); + String processBName = tokenizer.nextToken(); + String portBName = tokenizer.nextToken(); + addChannelProfile(channelName, capacity, + portAType, processAName, portAName, + portBType, processBName, portBName); + } else { + //current line is an event. examples: + //examples: + //78 filter started. + //79 filter r 0x23c6c0 8 + //80 filter w 0x23c738 8 + //81 filter stopped. + + int i = Integer.parseInt(nextWord); + if (i != _lineCounter) { + System.err.println("Input file corrupt: line number " + + "expected."); + return; + } + + //get process name + String processName = tokenizer.nextToken(); + if (_processProfiles.get(processName) == null) { + ProcessProfile processProfile = new ProcessProfile( + processName); + _processProfiles.put(processName, processProfile); + } + if(_processCommOrder.get(processName) == null) { + _processCommOrder.put(processName, new Vector()); + } + + nextWord = tokenizer.nextToken(); + if(nextWord.equals("started.")) { + _processProfiles.get(processName).start(); + } + else if(nextWord.equals("stopped.")) { + _processProfiles.get(processName).stop(); + } + else if (nextWord.equals("r") || nextWord.equals("w")) { + String accessType = nextWord; + String portName = tokenizer.nextToken(); + int amount = Integer.parseInt( + tokenizer.nextToken()); + try { + _processProfiles.get(processName). + portAccess(portName, amount); + if (accessType.equals("r")) { + String channelName = + _inPortToChannelMapping.get(portName); + _channelProfiles.get(channelName). + readAccess(amount); + _processCommOrder.get(processName).add(channelName); + + } else { + String channelName = + _outPortToChannelMapping.get(portName); + _channelProfiles.get(channelName). + writeAccess(amount); + _processCommOrder.get(processName).add(channelName); + } + } catch (NullPointerException e) { + System.err.println("Input file corrupt: cannot " + + "find channel associated to port " + + portName + "(line " + + _lineCounter + ")."); + e.printStackTrace(); + return; + } + } else { + System.err.println("Input file corrupt: unknown " + + "event type (line " + _lineCounter + ")."); + return; + } + _lineCounter++; + } + } + } + + /** + * Return the profiles of all processes. + * + * @return profile of all processes + */ + public HashMap getProcessProfiles() { + return _processProfiles; + } + + /** + * Return the profiles of all channels. + * + * @return profile of all channels + */ + public HashMap getChannelProfiles() { + return _channelProfiles; + } + + /** + * Return the order in which processes write to channels. + * + * @return profile of all processes + */ + public HashMap> getProcessCommOrder() { + return _processCommOrder; + } + + /** + * Return the channel to which the port with the specified name is + * connected. + * + * @param port port name + * @return name of connected channel + */ + public String getChannel(String port) { + if (_inPortToChannelMapping.get(port) != null) { + return _inPortToChannelMapping.get(port); + } else if (_outPortToChannelMapping.get(port) != null) { + return _outPortToChannelMapping.get(port); + } + return null; + } + + /** + * Return the type of the channel with the specified name. + * + * @param port port name + * @return type of port + */ + public String getPortType(String port) { + if (_inPortToChannelMapping.get(port) != null) { + return "INPUT"; + } else if (_outPortToChannelMapping.get(port) != null) { + return "OUTPUT"; + } + return null; + } + + /** + * Add a channel profile to the HashMap of channel profiles. + * + * @param channelName name of the channel + * @param capacity capacity of the channel + * @param portAType type of first port (either "o" or "i") + * @param processAName name of process connected to first port + * @param portAName name of first port + * @param portBType type of second port (either "o" or "i") + * @param processBName name of process connected to second port + * @param portBName name of second port + */ + protected void addChannelProfile(String channelName, int capacity, + String portAType, String processAName, String portAName, + String portBType, String processBName, String portBName) { + + ChannelProfile channelProfile = + new ChannelProfile(channelName, capacity); + _channelProfiles.put(channelName, channelProfile); + + if (portAType.equals("o")) { + //first output port, then input port + _outPortToChannelMapping.put(portAName, channelName); + if (!(portBType.equals("i"))) { + System.err.println("Input file corrupt: each " + + "channel needs one input- and one " + + "output port."); + return; + } + _inPortToChannelMapping.put(portBName, channelName); + } else if (portAType.equals("i")) { + //first input port, then output port + _inPortToChannelMapping.put(portAName, channelName); + if (!(portBType.equals("o"))) { + System.err.println("Input file corrupt: each " + + "channel needs one input- and one " + + "output port."); + return; + } + _outPortToChannelMapping.put(portBName, channelName); + } else { + System.err.println("Input file corrupt: bad channel " + + "specification:"); + System.err.println(channelName + " " + capacity + " " + + portAType + " " + processAName + " " + portAName + + " " + + portBType + " " + processBName + " " + portBName); + } + } + + private BufferedReader _in = null; + protected int _lineCounter = 0; + HashMap _processProfiles; + HashMap _channelProfiles; + HashMap _inPortToChannelMapping; + HashMap _outPortToChannelMapping; + HashMap> _processCommOrder; +} diff --git a/dol/src/dol/helper/profiler/Profiler.java b/dol/src/dol/helper/profiler/Profiler.java new file mode 100644 index 0000000..e24d456 --- /dev/null +++ b/dol/src/dol/helper/profiler/Profiler.java @@ -0,0 +1,212 @@ +/* $Id: Profiler.java 203 2010-10-11 08:59:47Z dchokshi $ */ +package dol.helper.profiler; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Vector; + +import dol.datamodel.XmlTag; +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.ProfilingConfiguration; + + +/** + * DOL profiler main class. Reads in profile data and generates the + * profiling information. + */ +public class Profiler { + + /** + * Constructor + */ + public Profiler() { + } + + /** + * @param name Name of the trace file + * @param pn The process network need to be annotated + */ + public void profilePN(String name, ProcessNetwork pn) { + ProfileParser profileParser = new ProfileParser(name); + profileParser.parseProfile(); + + HashMap channelProfiles = + profileParser.getChannelProfiles(); + Iterator iterator = channelProfiles.keySet().iterator(); + + while (iterator.hasNext()) { + ChannelProfile profile = channelProfiles.get(iterator.next()); + Channel channel = pn.getChannel(profile.getName()); + ProfilingConfiguration c = channel.getProfilingCfg( + _xt.getProfilingTotalReadData()); + if (c == null) { + //no profiling present, add new one + c = new ProfilingConfiguration( + _xt.getProfilingTotalReadData()); + c.setValue(Long.toString(profile.getTotalReadData())); + channel.getProfilingList().add(c); + } else { + // profiling already present, extend existing one + Long curr = Long.decode(c.getValue()); + curr += profile.getTotalReadData(); + c.setValue(Long.toString(curr)); + } + + c = channel.getProfilingCfg(_xt.getProfilingNumOfReads()); + if (c == null) { + c = new ProfilingConfiguration( + _xt.getProfilingNumOfReads()); + c.setValue(Integer.toString(profile.getNumOfReads())); + channel.getProfilingList().add(c); + } else { + Long curr = Long.decode(c.getValue()); + curr += profile.getNumOfReads(); + c.setValue(Long.toString(curr)); + } + + c = channel.getProfilingCfg(_xt.getProfilingNumOfWrites()); + if (c == null) { + c = new ProfilingConfiguration( + _xt.getProfilingNumOfWrites()); + c.setValue(Integer.toString(profile.getNumOfWrites())); + channel.getProfilingList().add(c); + } else { + Long curr = Long.decode(c.getValue()); + curr += profile.getNumOfWrites(); + c.setValue( Long.toString(curr) ); + } + } + + HashMap processProfiles = + profileParser.getProcessProfiles(); + iterator = processProfiles.keySet().iterator(); + + while (iterator.hasNext()) { + ProcessProfile profile = processProfiles.get(iterator.next()); + Process process = pn.getProcess(profile.getName()); + ProfilingConfiguration c = process.getProfilingCfg( + _xt.getProfilingNumOfFires()); + + if (c == null) { + c = new ProfilingConfiguration( + _xt.getProfilingNumOfFires()); + c.setValue(Integer.toString(profile.getNumOfFires())); + process.getProfilingList().add(c); + } else { + int curr = Integer.valueOf(c.getValue()); + curr += profile.getNumOfFires(); + c.setValue(Integer.toString(curr)); + } + + HashMap portProfiles = + profile.getPortProfiles(); + Iterator iteratorB = portProfiles.keySet().iterator(); + + while (iteratorB.hasNext()) { + PortProfile portProfile = + portProfiles.get(iteratorB.next()); + String portName = getPNPortName(portProfile.getName(), profileParser, pn); + c = new ProfilingConfiguration(portName + ".accesses"); + c.setValue(portProfile.getAccesses().toString()); + process.getProfilingList().add(c); + c = new ProfilingConfiguration(portName + ".tokensize"); + c.setValue(portProfile.getTokenSize().toString()); + process.getProfilingList().add(c); + c = new ProfilingConfiguration(portName + ".initialAccesses"); + c.setValue(Integer.toString(portProfile.getInitialAccesses())); + process.getProfilingList().add(c); + c = new ProfilingConfiguration(portName + ".initialtokensize"); + c.setValue(portProfile.getInitialTokenSize().toString()); + process.getProfilingList().add(c); + } + } + } + + /** + * + */ + protected String getPNPortName(String profilePortName, + ProfileParser parser, ProcessNetwork pn) { + Vector ports = pn.getChannel(parser. + getChannel(profilePortName)).getPortList(); + for (int i = 0; i < ports.size(); i++) { + if (parser.getPortType(profilePortName).equals("INPUT") && + ports.elementAt(i).isOutPort()) { + return ports.elementAt(i).getPeerPort().getName(); + } else if (parser.getPortType(profilePortName).equals("OUTPUT") && + ports.elementAt(i).isInPort()) { + return ports.elementAt(i).getPeerPort().getName(); + } + } + return null; + } + + /** + * Main function + * + * @param args command line arguments. args[0] is the filename of + * the profile file. args[1] is the filename of the process network + * XML file. + */ + public static void main(String[] args) { + //check command line parameters + if (args.length != 2) { + System.out.println("Usage: Profiler "); + System.out.println(); + return; + } + + ProfileParser profileParser = new ProfileParser(args[0]); + + //parse input file + profileParser.parseProfile(); + + //print the results + System.out.println("----- Channel Analyzer Report -----"); + System.out.println(" " + + " " + + " "); + + HashMap channelProfiles = + profileParser.getChannelProfiles(); + Iterator iterator = channelProfiles.keySet().iterator(); + + while (iterator.hasNext()) { + ChannelProfile profile = channelProfiles.get(iterator.next()); + System.out.println( "<" + profile.getName() + + "> " + + profile.getMaxFillLevel() + " " + + profile.getTotalReadData() + " " + + profile.getNumOfReads() + " " + + profile.getNumOfWrites()); + } + System.out.println(); + + System.out.println("----- Processnetwork Report -----"); + System.out.println(" "); + + HashMap processProfiles = + profileParser.getProcessProfiles(); + iterator = processProfiles.keySet().iterator(); + while (iterator.hasNext()) { + ProcessProfile profile = processProfiles.get(iterator.next()); + System.out.println( "<" + profile.getName() + + "> " + profile.getNumOfFires()); + } + System.out.println(); + + /* + //another test + PNXmlParser parserPN = new PNXmlParser(); + ProcessNetwork pn = parserPN.doParse(args[1]); + Profiler p = new Profiler(); + p.profilePN(args[0], pn); + pn.accept(new PNXmlVisitor("processnetwork.xml")); + */ + } + + protected XmlTag _xt = XmlTag.getInstance(); +} diff --git a/dol/src/dol/helper/profiler/Range.java b/dol/src/dol/helper/profiler/Range.java new file mode 100644 index 0000000..7c7721f --- /dev/null +++ b/dol/src/dol/helper/profiler/Range.java @@ -0,0 +1,176 @@ +/* $Id: Range.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.helper.profiler; + +import java.util.Collections; +import java.util.Vector; + +/** + * Tuple of numbers representing an integer range. Except for an + * uninitialized range when using the default constructor, the + * range values are sorted, such that {@link #getLower()} returns + * the lower bound and {@link #getUpper()} the upper bound of the + * range. + */ +public class Range { + + protected int _lower = Integer.MAX_VALUE; + protected int _upper = Integer.MIN_VALUE; + protected int _initialLower = Integer.MAX_VALUE; + protected int _initialUpper = Integer.MIN_VALUE; + public static final String DELIMITER = "-"; + + /** + * Default constructor. When merging this range with another + * range, always the resulting range will have the values of + * the other range. + */ + public Range() { + } + + /** + * Construct a range with equal upper and lower bound. + * + * @param value upper and lower bound of range + */ + public Range(int value) { + _lower = value; + _upper = value; + _initialLower = _lower; + _initialUpper = _upper; + } + + /** + * Construct a range with the two given bounds. + * + * @param valueA upper or lower bound + * @param valueB upper or lower bound + */ + public Range(int valueA, int valueB) { + _lower = Math.min(valueA, valueB); + _upper = Math.max(valueA, valueB); + _initialLower = _lower; + _initialUpper = _upper; + } + + /** + * Construct a range with upper and lower bounds that are the minimum + * and maximum of the given vector. + * + * @param values vector whose minimum and maximum value are used as + * bounds for the range + */ + public Range(Vector values) { + if (values == null || values.size() == 0) { + return; + } + + _lower = Collections.min(values); + _upper = Collections.max(values); + } + + /** + * Return lower bound of this range. + * + * @return lower bound + */ + protected int getLower() { + return _lower; + } + + /** + * Return upper bound of this range. + * + * @return upper bound + */ + protected int getUpper() { + return _upper; + } + + /** + * Combine range with another range. The lower bound of the range is + * the minimum of the lower bounds of this range and the other range. + * The upper bound of the range is the maximum of the upper bounds of + * this range and the other range. + * + * @param range to combine with this range + */ + public void merge(Range range) { + if (range == null) + return; + + _lower = Math.min(_lower, range.getLower()); + _upper = Math.max(_upper, range.getUpper()); + } + + /** + * Combine range with a value. The lower bound of the range is + * the minimum of the lower bound of this range and the value. + * The upper bound of the range is the maximum of the upper bound of + * this range and the value. + * + * @param value integer value to combine with this range + */ + public void merge(int value) { + _lower = Math.min(_lower, value); + _upper = Math.max(_upper, value); + } + + /** + * Create a string representation of the range. + * + * @return string representation of the range + */ + public String toString() { + if (_upper == _lower) + return Integer.toString(_upper); + return _lower + DELIMITER + _upper; + } + + /** + * Create a range based on a string representation of a range. + * + * @param string representation of a range + * @return range + * @throws IllegalArgumentException + */ + public static Range valueOf(String string) throws IllegalArgumentException { + java.util.regex.Pattern pattern = + java.util.regex.Pattern.compile( + "([-]?[0-9]+)[" + DELIMITER + "]?([-]?[0-9]+)?"); + java.util.regex.Matcher m = pattern.matcher(string); + if (!m.matches()) { + throw new IllegalArgumentException("String does not " + + "represent a range."); + } + return new Range(Integer.valueOf(m.group(1)), + Integer.valueOf(m.group(2))); + } + + /** + * Reset this range to the values it had when it has been constructed. + */ + public void reset() { + _lower = _initialLower; + _upper = _initialUpper; + } + + /** + * Test cases for range class. + */ + public static void main(String args[]) throws Exception { + Range a = new Range(1); + System.out.println(a); + + Range b = new Range(1, 3); + System.out.println(b); + + Range c = new Range(4, 3); + System.out.println(c); + + b.merge(c); + System.out.println(b); + + Range d = Range.valueOf("-123" + Range.DELIMITER + "-456"); + System.out.println(d); + } +} \ No newline at end of file diff --git a/dol/src/dol/helper/profiler/VSPLogFileProfiler.java b/dol/src/dol/helper/profiler/VSPLogFileProfiler.java new file mode 100644 index 0000000..dc3b827 --- /dev/null +++ b/dol/src/dol/helper/profiler/VSPLogFileProfiler.java @@ -0,0 +1,73 @@ +/* $Id: VSPLogFileProfiler.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.helper.profiler; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.StringTokenizer; + +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.ProfilingConfiguration; + +/** + * Class for parsing a file with profiling info and annotate it to a + * process network. + */ +public class VSPLogFileProfiler { + + /** + * Parse the given file and annotate the data to the given process + * network. + * + * @param filename file with profiling info + * @param pn processnetwork to annotate + */ + public static void annotateProcessNetwork(String filename, + ProcessNetwork pn) { + try { + BufferedReader reader = new BufferedReader( + new FileReader(filename)); + String line; + while ((line = reader.readLine()) != null) { + StringTokenizer tokenizer = + new StringTokenizer(line, " "); + if (tokenizer.countTokens() == 2) { + continue; + } + else if (tokenizer.countTokens() <= 2) { + System.out.println("Warning: Each line in the log " + + "file should have the following form:" + + System.getProperty("line.separator") + + "processname config_name config_value" + + System.getProperty("line.separator") + + "Ignoring the non-conforming line:" + + System.getProperty("line.separator") + + line); + continue; + } + String processname = tokenizer.nextToken(); + Process process = pn.getProcess(processname); + if (process == null) { + System.out.println("Warning: Could not find process " + + processname + " in processnetwork " + + pn.getName() + ". Ignore configuration " + + "statement in file " + filename + "."); + continue; + } + ProfilingConfiguration config = + new ProfilingConfiguration(tokenizer.nextToken()); + String value = ""; + while (tokenizer.hasMoreTokens()) { + value += tokenizer.nextToken() + " "; + } + config.setValue(value.trim()); + config.setParentResource(process); + process.getProfilingList().add(config); + } + } + catch (IOException e) { + System.out.println(e); + } + } +} diff --git a/dol/src/dol/helper/profiler/WorkloadAnnotator.java b/dol/src/dol/helper/profiler/WorkloadAnnotator.java new file mode 100644 index 0000000..fb6b19d --- /dev/null +++ b/dol/src/dol/helper/profiler/WorkloadAnnotator.java @@ -0,0 +1,102 @@ +/* $Id: WorkloadAnnotator.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.helper.profiler; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Vector; + +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.ProfilingConfiguration; +import dol.parser.xml.pnschema.PNXmlParser; +import dol.visitor.xml.PNXmlVisitor; + +public class WorkloadAnnotator { + + /** + * + * @param args + */ + public static void main(String[] args) { + String logFile = "workload.txt"; + String pnFileIn = "processnetwork.xml"; + String pnFileOut = "processnetwork.xml"; + + try { + if (args.length > 2) { + pnFileIn = args[0]; + logFile = args[1]; + pnFileOut = args[1]; + } else if (args.length == 2) { + pnFileIn = args[0]; + logFile = args[1]; + } else if (args.length == 1) { + pnFileIn = args[0]; + } + + PNXmlParser parserPN = new PNXmlParser(); + ProcessNetwork pn = parserPN.doParse(pnFileIn); + + WorkloadAnnotator.annotateProcessNetwork(logFile, pn); + StringBuffer b = new StringBuffer(); + pn.accept(new PNXmlVisitor(b)); + FileWriter out = new FileWriter(pnFileOut); + out.write(b.toString()); + out.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * + * @param workloadFileName + * @param pn + * @throws IOException + */ + public static void annotateProcessNetwork(String workloadFileName, + ProcessNetwork pn) throws IOException { + for (Process p : pn.getProcessList()) { + Vector v = p.getProfilingList(); + if (v == null) { + p.setProfilingList(new Vector()); + } + } + + BufferedReader in = new BufferedReader(new FileReader(workloadFileName)); + String line, process, name, value; + while ((line = in.readLine()) != null) { + if (line.startsWith("wced_")) { + process = line.substring("wced_".length()).trim(); + name = "WCET"; + + } else if (line.startsWith("bced_")) { + process = line.substring("bced_".length()).trim(); + name = "BCET"; + + } else if (line.startsWith("workload_upper_")) { + process = line.substring("workload_upper_".length()). + trim(); + name = "WORKLOAD_UPPER"; + + } else if (line.startsWith("workload_lower_")) { + process = line.substring("workload_lower_".length()). + trim(); + name = "WORKLOAD_LOWER"; + + } else { + continue; + } + process = process.substring(0, process.length() - 1).trim(); + + in.readLine(); + value = in.readLine().trim(); + + ProfilingConfiguration pc = new ProfilingConfiguration(name); + pc.setValue(value); + pn.getProcess(process).getProfilingList().add(pc); + } + } +} diff --git a/dol/src/dol/helper/profiler/package.html b/dol/src/dol/helper/profiler/package.html new file mode 100644 index 0000000..77be30d --- /dev/null +++ b/dol/src/dol/helper/profiler/package.html @@ -0,0 +1,20 @@ + + + + + + +Profiler to extract parameters from a profiling file. + +

Package Specification

+ + + +

Related Documentation

+ + + + + + + diff --git a/dol/src/dol/helper/validator/XMLValidator.java b/dol/src/dol/helper/validator/XMLValidator.java new file mode 100644 index 0000000..b65b9a8 --- /dev/null +++ b/dol/src/dol/helper/validator/XMLValidator.java @@ -0,0 +1,77 @@ +/* $Id: XMLValidator.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.helper.validator; + +import java.io.IOException; + +import org.jdom.JDOMException; +import org.jdom.input.SAXBuilder; + +/** + * Class to check well-formedness and validity of XML documents. + */ +public class XMLValidator { + + /** + * Check the well-formedness and validity of an XML document. + * The file is checked against the schema which is referenced from + * within the file. When the document is an XML schema, it is checked + * against http://www.w3.org/2001/XMLSchema.xsd. + * + * @param filename filename of the file to be checked + */ + public static boolean isValid(String filename) { + SAXBuilder builder = new SAXBuilder(true); + builder.setFeature("http://xml.org/sax/features/validation", + true); + builder.setFeature("http://apache.org/xml/features/validation/" + + "schema", true); + builder.setFeature("http://apache.org/xml/features/validation/" + + "schema-full-checking", true); + builder.setProperty("http://apache.org/xml/properties/schema/" + + "external-schemaLocation", + "http://www.w3.org/2001/XMLSchema " + + "http://www.w3.org/2001/XMLSchema.xsd " + + dol.util.SchemaLocation.getExternalSchemaLocation()); + try { + builder.build(filename); + } + catch (JDOMException e) { + System.out.println("Found an error in " + filename + "."); + System.out.println(e.getMessage()); + System.out.println(""); + return false; + } + catch (IOException e) { + System.out.println("Found an error in " + filename + "."); + System.out.println(e.getMessage()); + System.out.println(""); + return false; + } + + return true; + } + + /** + * Main function. We might extend the validator to validate different + * kind of XMLs based on different schemas. + * + * @param args The command line argument. + */ + public static void main(String[] args) { + + /* Check command line parameters */ + /* maybe add options to check both external/internal schema */ + if (args.length != 1) { + System.out.println("Usage: XMLValidator "); + System.out.println(); + return; + } + + if (XMLValidator.isValid(args[0])){ + System.out.println(args[0] + " is valid."); + } else { + System.exit(1); + } + } +} diff --git a/dol/src/dol/helper/validator/package.html b/dol/src/dol/helper/validator/package.html new file mode 100644 index 0000000..b9e7084 --- /dev/null +++ b/dol/src/dol/helper/validator/package.html @@ -0,0 +1,20 @@ + + + + + + +Utilities to check well-formedness and validity of XML documents. + +

Package Specification

+ + + +

Related Documentation

+ + + + + + + diff --git a/dol/src/dol/main/Main.java b/dol/src/dol/main/Main.java new file mode 100644 index 0000000..6d0cd95 --- /dev/null +++ b/dol/src/dol/main/Main.java @@ -0,0 +1,263 @@ +/* $Id: Main.java 203 2010-10-11 08:59:47Z dchokshi $ */ +package dol.main; + +import java.io.FileOutputStream; +import java.io.OutputStream; + +import dol.check.SanityCheck; +import dol.datamodel.architecture.Architecture; +import dol.datamodel.mapping.Mapping; +import dol.datamodel.pn.ProcessNetwork; +import dol.helper.profiler.Profiler; +import dol.helper.profiler.VSPLogFileProfiler; +import dol.helper.profiler.WorkloadAnnotator; +import dol.parser.xml.archischema.ArchiXmlParser; +import dol.parser.xml.mapschema.MapXmlParser; +import dol.parser.xml.pnschema.PNXmlParser; +import dol.util.CodePrintStream; +import dol.visitor.PipeAndFilter.PipeAndFilterVisitor; +import dol.visitor.cell.CellVisitor; +import dol.visitor.dot.ArchDotVisitor; +import dol.visitor.dot.MapDotVisitor; +import dol.visitor.dot.PNDotVisitor; +import dol.visitor.hds.HdsVisitor; +import dol.visitor.hdsd.HdsdVisitor; +import dol.visitor.protothread.ProtothreadVisitor; +import dol.visitor.rtems.RtemsVisitor; +import dol.visitor.systemC.PNSystemCVisitor; +import dol.visitor.xml.PNXmlVisitor; +import dol.visitor.yapi.YapiVisitor; + +/** + * Distributed Operating Layer (DOL) + * + * This class is the main controlling part of DOL. In this class, the + * command line options are processed, the input and output files are set, + * and the complete compilation cycle is done. Also, this class is the + * final responder to exceptions occurring within the DOL. + */ +public class Main { + + /** + * The main method of this class + * + * @param args The arguments to provide to DOL. + */ + public static void main(String[] args) { + + _ui = UserInterface.getInstance(); + + try { + new Options(args); + } catch (NumberFormatException e) { + System.out.println("Error in Command line options: " + + " the numerial format for an argument is" + + " incorrect. Message: " + + e.getMessage()); + System.exit(-1); + } catch (IllegalArgumentException e) { + System.out.println("Error in Command line option: " + + e.getMessage()); + System.exit(-1); + } catch (Exception e) { + System.out.println(e.getMessage()); + System.exit(-1); + } + + try { + //loader + + //load process network specification from XML + if (_ui.getNetworkFileName() != null) { + PNXmlParser parserPN = new PNXmlParser(); + _pn = parserPN.doParse(_ui.getNetworkFileName()); + } + + //load architecture specification from XML + if (_ui.getPlatformFileName() != null) { + ArchiXmlParser parserArch = new ArchiXmlParser(); + _architecture = parserArch.doParse( + _ui.getPlatformFileName()); + + //not useful (archiPathFinderVisitor not functional) + //_architecture.setArchiConnections(); + //_architecture.accept(new dol.visitor.pathFinder. + // archiPathFinderVisitor()); + //_architecture.accept(new dol.visitor.pathFinder. + // archiPathPrinterVisitor()); + } + + //load mapping specification from XML + if ((_pn != null) && (_architecture != null) + && _ui.getMappingFileName() != null) { + MapXmlParser parserMap = new MapXmlParser(_pn, _architecture); + _mapping = parserMap.doParse(_ui.getMappingFileName()); + } + + //sanity check + if (_ui.getCheckFlag()){ + System.out.println("Consistency check:"); + //check process network + if (_pn != null) + SanityCheck.getInstance().checkPN(_pn); + + //check architecture + if (_architecture != null) + SanityCheck.getInstance().checkArch(_architecture); + + //check mapping + if (_mapping != null) + SanityCheck.getInstance().checkMap(_mapping); + + System.out.println(" -- Consistency check [Finished]"); + System.out.println(); + } + + // analyze profiling data and fill into pn + if (_ui.getProfilingFlag() && (_pn != null)) { + System.out.println(" -- ProcessNetwork profiling"); + Profiler p = new Profiler(); + p.profilePN(_ui.getTraceName(), _pn); + System.out.println(" -- Profiling [Finished]"); + System.out.println(); + } + + if (_ui.getVspLogFlag() && (_pn != null)) { + System.out.println("VSP log file back-annotation:"); + VSPLogFileProfiler.annotateProcessNetwork( + _ui.getVspLogFileName(), _pn); + System.out.println(" -- Back-annotation [Finished]"); + System.out.println(); + } + + if (_ui.getWorkloadFlag() && (_pn != null)) { + System.out.println("Workload file back-annotation:"); + WorkloadAnnotator.annotateProcessNetwork( + _ui.getWorkloadFileName(), _pn); + System.out.println(" -- Back-annotation [Finished]"); + System.out.println(); + } + + //Generator + CodePrintStream printStream; + + if (_ui.getDottyFlag()) { + OutputStream file = new FileOutputStream(_ui.getDottyFileName()); + printStream = new CodePrintStream(file); + if (_mapping != null) + { + System.out.println("Generating Mapping in Dotty format:"); + _mapping.accept(new MapDotVisitor(printStream)); + } + else if (_pn != null) + { + System.out.println("Generating ProcessNetwork in Dotty format:"); + _pn.accept(new PNDotVisitor(printStream)); + } + else if (_architecture!=null) { + System.out.println("Generating Architecture in Dotty format:"); + _architecture.registerRWPath2Resource(); + _architecture.accept(new ArchDotVisitor(printStream)); + } + System.out.println(" -- Generation [Finished]"); + System.out.println(); + } + + if (_ui.getXmlGenFlag() && (_pn != null)) { + System.out.println("Generating ProcessNetwork in XML format:"); + StringBuffer buffer = new StringBuffer(); + _pn.accept(new PNXmlVisitor(buffer)); + try { + java.io.BufferedWriter writer = + new java.io.BufferedWriter( + new java.io.FileWriter(_ui.getOutputFileName())); + writer.write(buffer.toString()); + writer.close(); + } catch (java.io.IOException e) { + System.out.println(" -- DOL caught an exception while " + + "creating XML file: " + e.getMessage()); + e.printStackTrace(System.out); + } + System.out.println(" -- Generation [Finished]"); + System.out.println(); + } + + if (_ui.getSystemCFlag() && (_pn != null)) { + System.out.println("Generating SystemC package:"); + _pn.accept(new PNSystemCVisitor(_ui.getCodeDirectoryName())); + System.out.println(" -- Generation [Finished]"); + System.out.println(); + } + + if (_ui.getPipeAndFilterFlag() && (_pn != null)) { + System.out.println("Generating PipeAndFilter package:"); + _pn.accept(new PipeAndFilterVisitor( + _ui.getPipeAndFilterCodeDirectoryName())); + System.out.println(" -- Generation [Finished]"); + System.out.println(); + } + + if (_ui.getProtothreadFlag() && (_pn != null)) { + System.out.println("Generating protothread package:"); + _pn.accept(new ProtothreadVisitor( + _ui.getProtothreadCodeDirectoryName())); + System.out.println(" -- Generation [Finished]"); + System.out.println(); + } + + if (_ui.getRtemsFlag() && (_pn != null)) { + String bsp = _ui.getRtemsBSP(); + System.out.println("Generating RTEMS-" + bsp + " package:"); + _pn.accept(new RtemsVisitor( + _ui.getRtemsCodeDirectoryName())); + System.out.println(" -- Generation [Finished]"); + System.out.println(); + } + + if (_ui.getCbeFlag() && (_pn != null)) { + System.out.println("Generating Cell-package:"); + _pn.accept(new CellVisitor( + _ui.getCbeCodeDirectoryName())); + System.out.println(" -- Generation [Finished]"); + System.out.println(); + } + + if (_ui.getYapiFlag() && (_pn != null)) { + System.out.println("Generating YAPI-package:"); + _pn.accept(new YapiVisitor( + _ui.getYapiCodeDirectoryName())); + System.out.println(" -- Generation [Finished]"); + System.out.println(); + } + + if (_ui.getHdsFlag() && (_pn != null)) { + System.out.println("Generating HdS package:"); + if ((_pn!=null) && (_architecture!=null) && (_mapping!=null)) { + System.out.println("Generating distributed HdS package:"); + // Hds with networking supportSAXException + _mapping.accept(new HdsdVisitor(_ui.getHdsCodeDirectoryName())); + + } else { + // Hds without networking support + _pn.accept(new HdsVisitor(_ui.getHdsCodeDirectoryName())); + } + System.out.println(" -- Generation [Finished]"); + System.out.println(); + } + + } + catch (NumberFormatException e) { + System.out.println(" ERROR Occured in DOL: " + e.getMessage()); + e.printStackTrace(System.out); + } + catch (Exception e) { + System.out.println(" DOL caught an exception: " + e.getMessage()); + e.printStackTrace(System.out); + } + } + + protected static ProcessNetwork _pn = null; + protected static Architecture _architecture = null; + protected static Mapping _mapping = null; + protected static UserInterface _ui = null; +} diff --git a/dol/src/dol/main/Options.java b/dol/src/dol/main/Options.java new file mode 100644 index 0000000..b284d90 --- /dev/null +++ b/dol/src/dol/main/Options.java @@ -0,0 +1,207 @@ +/* $Id: Options.java 203 2010-10-11 08:59:47Z dchokshi $ */ +package dol.main; + +/** + * This class handles the command line options. It checks if an option is + * valid, and if so, it calls the appropriate method in the UserInterface, + * that reflects the global setting of DOL. + */ +public class Options { + + /** + * Parse the command-line arguments, creating models as specified. Then + * execute each model that contains a manager. + * + * @param args + * The command-line arguments. + * @exception IllegalArgumentException + * MyException If such and such occurs + * @throws IllegalArgumentException + * if an illegal argument is found on the command line. + */ + public Options(String args[]) throws IllegalArgumentException, NumberFormatException { + _ui = UserInterface.getInstance(); + if(args != null) { + _parseArgs(args); + } + } + + /** + * Parse the command-line arguments. + * + * @param args The arguments to be parsed + * + * @throws IllegalArgumentException + * if an illegal argument is found on the command line. + */ + protected void _parseArgs(String args[]) throws IllegalArgumentException, + NumberFormatException { + if(args.length > 0) { + for(int i = 0; i < args.length; i++ ) { + String arg = args[i]; + if(_parseArg(arg) == false ) { + if(arg.startsWith("-") && i < args.length - 1 ) { + if(arg.equals("--platform") || arg.equals("-p") ) { + _ui.setPlatformFileName(args[++i]); + } else if(arg.equals("--processnetwork") || arg.equals("-P") ) { + _ui.setNetworkFileName(args[++i]); + } else if(arg.equals("--mapping") || arg.equals("-m") ) { + _ui.setMappingFileName(args[++i]); + } else if(arg.equals("--scheduler") || arg.equals("-s") ) { + _ui.setSchedulerFileName(args[++i]); + } else if(arg.equals("--systemC") || arg.equals("-C") ) { + _ui.setCodeDirectoryName(args[++i]); + _ui.setSystemCFlag(); + } else if(arg.equals("--HdS") || arg.equals("-H") ) { + _ui.setHdsCodeDirectoryName(args[++i]); + _ui.setHdsFlag(); + } else if(arg.startsWith("--rtems") || arg.startsWith("-R") ) { + String bsp = arg; + bsp = bsp.replaceAll("--rtems" , ""); + bsp = bsp.replaceAll("-R", ""); + if (bsp.equals("")) { + _ui.setRtemsBSP("pc386"); + } else if (bsp.equals("pc386") || bsp.equals("mparm")) { + _ui.setRtemsBSP(bsp); + } else { + throw new IllegalArgumentException( + "Board support package \"" + bsp + + "\" not supported by code generation."); + } + _ui.setRtemsCodeDirectoryName(args[++i]); + _ui.setRtemsFlag(); + } else if(arg.equals("--PaF") || arg.equals("-PF") ) { + _ui.setPipeAndFilterCodeDirectoryName(args[++i]); + _ui.setPipeAndFilterFlag(); + } else if(arg.equals("--protothread") || arg.equals("-PT") ) { + _ui.setProtothreadCodeDirectoryName(args[++i]); + _ui.setProtothreadFlag(); + } else if(arg.equals("--dotty") || arg.equals("-D")) { + _ui.setDottyFileName(args[++i]); + } else if(arg.equals("--profiling") || arg.equals("-T")) { + _ui.setTraceName(args[++i]); + _ui.setProfilingFlag(); + } else if (arg.equals("--vsplog") || arg.equals("-L")) { + _ui.setVspLogFileName(args[++i]); + _ui.setVspLogFlag(); + } else if (arg.equals("--workload") || arg.equals("-W")) { + _ui.setWorkloadFileName(args[++i]); + _ui.setWorkloadFlag(); + } else if(arg.equals("--xmlGen") || arg.equals("-G")) { + _ui.setOutputFileName(args[++i]); + _ui.setXmlGenFlag(); + } else if(arg.equals("--cbe") || arg.equals("-CBE")) { + _ui.setCbeCodeDirectoryName(args[++i]); + _ui.setCbeFlag(); + } else if(arg.equals("--yapi") || arg.equals("-Y")) { + _ui.setYapiCodeDirectoryName(args[++i]); + _ui.setYapiFlag(); + } else { + throw new IllegalArgumentException("Unrecognized option: " + arg); + } + } else { + throw new IllegalArgumentException("Unrecognized option: " + arg); + } + } + } + } else { + throw new IllegalArgumentException(_usage()); + } + } + + /** + * Parse a single commandline argument. + * + * @param arg commandline argument + * @return true if the argument is understood, false otherwise + * @throws IllegalArgumentExcecption thrown if an illegal argument is + * found on the command line. + */ + protected boolean _parseArg(String arg) throws IllegalArgumentException { + if(arg.equals("--help") || arg.equals("-h") ) { + //throw new IllegalArgumentException(_usage()); + System.out.println(_usage() ); + System.exit(0); + } else if(arg.equals("--version") || arg.equals("-V") ) { + System.out.println("DOL version 0.0.1\n"); + System.exit(0); + } else if(arg.equals("--verbose") || arg.equals("-v") ) { + _ui.setVerboseFlag(); + } else if(arg.equals("--check") || arg.equals("-c")) { + _ui.setCheckFlag(); + } else if(arg.equals("--debug")) { + _ui.setDebugFlag(); + } else if(arg.equals("")) { // Ignore blank argument. + } else { // Argument not recognized. + return false; + } + return true; + } + + /** + * Return a string summarizing the command-line arguments. + * + * @return A usage string. + */ + protected String _usage() { + String result = "Usage: " + _commandTemplate + "\n\n" + + "Options:\n"; + + int i; + for(i = 0; i < _commandOptions.length; i++) { + result += " " + _commandOptions[i][0] + "\tabbr[" + + _commandOptions[i][1] + " " + _commandOptions[i][2] + + "]\n"; + } + result += "\nBoolean flags:\n"; + for(i = 0; i < _commandFlags.length; i++) { + result += " " + _commandFlags[i][0] + "\tabbr[" + + _commandFlags[i][1] + "]\n"; + } + return result; + } + + /** + * The command-line options that are either present or not. Give the full + * name preceded with '--' and abbreviated version. + */ + protected String _commandFlags[][] = { + { "--check ", "-c" }, + { "--flatten ", "-F" }, + { "--help ", "-h" }, + { "--version ", "-V" }, + { "--verbose ", "-v" }, + { "--debug ", "none" }, + }; + + /** + * The command-line options that take arguments. + */ + protected String _commandOptions[][] = { + { "--platform ", "-p ", "" }, + { "--processnetwork", "-P ", "" }, + { "--mapping ", "-m ", "" }, + { "--scheduler ", "-s ", "" }, + { "--dotty ", "-D ", "" }, + { "--xmlGen ", "-G", "" }, + { "--systemC ", "-C ", "" }, + { "--HdS ", "-H ", "" }, + { "--PaF ", "-PF", "" }, + { "--rtems ", "-R", "" }, + { "--protothread ", "-PT", "" }, + { "--profiling ", "-T", "" }, + { "--vsplog ", "-L", "" }, + { "--cbe ", "-CBE", "" }, + { "--yapi ", "-Y", "" } + }; + + /** + * The form of the command line. + */ + protected String _commandTemplate = "dol [ options ]"; + + /** + * The UserInterface object. + */ + protected UserInterface _ui = null; +} diff --git a/dol/src/dol/main/UserInterface.java b/dol/src/dol/main/UserInterface.java new file mode 100644 index 0000000..f9145ea --- /dev/null +++ b/dol/src/dol/main/UserInterface.java @@ -0,0 +1,771 @@ +/* $Id: UserInterface.java 203 2010-10-11 08:59:47Z dchokshi $ */ +package dol.main; + +import java.util.ResourceBundle; + +/** + * Class to store commandline arguments and flags. + */ +public class UserInterface { + + /** + * Get a single instance of the UserInterface object. + */ + private final static UserInterface _instance = new UserInterface(); + + + // the platform file name + private String _platformFileName = null; + + // the process network file name + private String _networkFileName = null; + + // the mapping file name + private String _mappingFileName = null; + + // the scheduler file name + private String _schedulerFileName = null; + + // the dotty file name + private String _dottyFileName = "dotty.dot"; + + // the systemc directory name + private String _codeDirectoryName = "nonamePackage"; + + // the pipeandfilter directory name + private String _pipeCodeDirectoryName = "nonamePipePackage"; + + // the hds directory name + private String _hdsCodeDirectoryName = "nonameHdsPackage"; + + // the RTEMS directory name + private String _rtemsCodeDirectoryName = "nonameHdsPackage"; + + // the RTEMS board support package for which code is generated + private String _rtemsBSP = "pc386"; + + // the protothread directory name + private String _protothreadCodeDirectoryName = "nonameHdsPackage"; + + // the CBE directory name + private String _cbeCodeDirectoryName = "nonameCbePackage"; + + // the Yapi directory name + private String _yapiCodeDirectoryName = "nonameYapiPackage"; + + + // trace filename + private String _traceName = ""; + + // the xml generation flag + private boolean _xmlGen = false; + + // the trace flag + private boolean _profiling = false; + + // the verbose flag + private boolean _verbose = false; + + // the vsp log flag + private boolean _vsplog = false; + + // the name of the vsp log file + private String _vspLogFileName = ""; + + // the workload annotation flag + private boolean _workload = false; + + // the name of the workload file produces by Matlab + private String _workloadFileName = ""; + + // the SystemC flag + private boolean _systemC = false; + + // the PipeAndFilter flag + private boolean _pipeAndFilter = false; + + // the HdS flag + private boolean _hds = false; + + // the RTEMS flag + private boolean _rtems = false; + + // the CBE flag + private boolean _cbe = false; + + // the YAPI flag + private boolean _yapi = false; + + // the RTEMS flag + private boolean _protothread = false; + + // the debug flag + private boolean _debug = false; + + // the dotty flag + private boolean _dotty = false; + + // the check flag + private boolean _check = false; + + // the path finder flag + private boolean _archiPaths = true; + + // the basepath name + private String _basePath = "."; + + // the filename + private String _outputFileName = ""; + + // ResourceBundle + private ResourceBundle _rb; + private String _rbFileName = "dol"; + + + public final String getMySystemCLib() { + /* + return _rb.getString("DOL_path") + getDelimiter() + + "src" + getDelimiter() + "dol" + getDelimiter() + + "visitor" + getDelimiter() + "systemC" + getDelimiter() + + "lib"; + */ + + return this.getClass().getResource( + "/dol/visitor/systemC/lib").getFile(); + } + + public final String getVisitorDir(){ + return this.getClass().getResource("/dol/visitor/").getFile(); + } + + public final String getDOLPath() { return _rb.getString("DOL_path"); } + public final String getSystemCINC(){return _rb.getString("SYSTEMC_INC");} + public final String getSystemCLIB(){return _rb.getString("SYSTEMC_LIB");} + + /** + * returns the singleton instance of this class. + * + * @return The instance value + */ + public final static UserInterface getInstance() { + return _instance; + } + + /** + * Get the name of the platform file. + * + * @return The platformFileName value + */ + public final String getPlatformFileName() { + return _platformFileName; + } + + /** + * Set the name of the platform file. + * + * @param platformFileName + * The new platformFileName value + */ + public final void setPlatformFileName(String platformFileName) { + _platformFileName = platformFileName; + } + + /** + * Get the name of the process network file. + * + * @return The networkFileName value + */ + public final String getNetworkFileName() { + return _networkFileName; + } + + /** + * Set the name of the process network file. + * + * @param networkFileName + * The new networkFileName value + */ + public final void setNetworkFileName(String networkFileName) { + _networkFileName = networkFileName; + } + + /** + * Get the name of the mapping file. + * + * @return The mappingFileName value + */ + public final String getMappingFileName() { + return _mappingFileName; + } + + /** + * Set the name of the mapping file. + * + * @param mappingFileName + * The new mappingFileName value + */ + public final void setMappingFileName(String mappingFileName) { + _mappingFileName = mappingFileName; + } + + + /** + * Get the name of the scheduler file. + * + * @return The schedulerFileName value + */ + public final String getSchedulerFileName() { + return _schedulerFileName; + } + + /** + * Set the name of the scheduler file. + * + * @param schedulerFileName + * The new schedulerFileName value + */ + public final void setSchedulerFileName(String schedulerFileName) { + _schedulerFileName = schedulerFileName; + } + + + /** + * Get the name of the dotty file.. + * + * @return The dottyFileName value + */ + public final String getDottyFileName() { + return _dottyFileName; + } + + /** + * Set the name of the directory where the SystemC code shall be generated. + * + * @param dottyFileName The dotty file name. + */ + public final void setDottyFileName(String dottyFileName) { + _dottyFileName = dottyFileName; + setDottyFlag(); + } + + + /** + * Get the name of the SystemC directory. + * + * @return The directory name of the SystemC directory + */ + public final String getCodeDirectoryName() { + return _codeDirectoryName; + } + + /** + * Set the name of the directory where the SystemC code shall be generated. + * + * @param codeDirectoryName The code directory + */ + public final void setCodeDirectoryName(String codeDirectoryName) { + _codeDirectoryName = codeDirectoryName; + } + + /** + * Get the name of the PipeAndFilter directory. + * + * @return The directory name of the PipeAndFilter directory + */ + public final String getPipeAndFilterCodeDirectoryName() { + return _pipeCodeDirectoryName; + } + + /** + * Set the name of the directory where the Hds code shall be generated. + * + * @param codeDirectoryName The code directory + */ + public final void setPipeAndFilterCodeDirectoryName(String codeDirectoryName) { + _pipeCodeDirectoryName = codeDirectoryName; + } + + /** + * Get the name of the Hds directory. + * + * @return The directory name of the Hds directory + */ + public final String getHdsCodeDirectoryName() { + return _hdsCodeDirectoryName; + } + + /** + * Set the name of the directory where the Hds code shall be generated. + * + * @param codeDirectoryName The code directory + */ + public final void setHdsCodeDirectoryName(String codeDirectoryName) { + _hdsCodeDirectoryName = codeDirectoryName; + } + + /** + * Get the name of the protothread directory. + * + * @return The directory name of the protohread directory + */ + public final String getProtothreadCodeDirectoryName() { + return _protothreadCodeDirectoryName; + } + + /** + * Set the name of the directory where the protothread code shall be generated. + * + * @param codeDirectoryName The code directory + */ + public final void setProtothreadCodeDirectoryName(String codeDirectoryName) { + _protothreadCodeDirectoryName = codeDirectoryName; + } + + /** + * Get the name of the CBE directory. + * + * @return The directory name of the CBE directory + */ + public final String getCbeCodeDirectoryName() { + return _cbeCodeDirectoryName; + } + + /** + * Set the name of the directory where the CBE code shall be generated. + * + * @param codeDirectoryName The code directory + */ + public final void setCbeCodeDirectoryName(String codeDirectoryName) { + _cbeCodeDirectoryName = codeDirectoryName; + } + + /** + * Get the name of the YAPI directory. + * + * @return The directory name of the CBE directory + */ + public final String getYapiCodeDirectoryName() { + return _yapiCodeDirectoryName; + } + + /** + * Set the name of the directory where the YAPI code shall be generated. + * + * @param codeDirectoryName The code directory + */ + public final void setYapiCodeDirectoryName(String codeDirectoryName) { + _yapiCodeDirectoryName = codeDirectoryName; + } + + /** + * Get the name of the RTEMS directory. + * + * @return The directory name of the RTEMS directory + */ + public final String getRtemsCodeDirectoryName() { + return _rtemsCodeDirectoryName; + } + + /** + * Set the name of the directory where the RTEMS code shall be generated. + * + * @param codeDirectoryName The code directory + */ + public final void setRtemsCodeDirectoryName(String codeDirectoryName) { + _rtemsCodeDirectoryName = codeDirectoryName; + } + + /** + * Get the name of the RTEMS board support package. + * + * @return The name of the board support package + */ + public final String getRtemsBSP() { + return _rtemsBSP; + } + + /** + * Set the name of the board support package for which RTEMS code shall + * be generated. + * + * @param bsp board support package for which code is generated + * currently supported: pc386, mparm + */ + public final void setRtemsBSP(String bsp) { + _rtemsBSP = bsp; + } + + /** + * Get the status of the Verbose flag. + * + * @return verbose flag value + */ + public final boolean getVerboseFlag() { + return _verbose; + } + + /** + * Set the Verbose flag. + */ + public final void setVerboseFlag() { + _verbose = true; + } + + /** + * Get the status of the Debug flag. + * + * @return debug flag value + */ + public final boolean getDebugFlag() { + return _debug; + } + + /** + * Set the debug flag. + */ + public final void setDebugFlag() { + _debug = true; + } + + /** + * Get the status of the SystemC flag + * + * @return The systemC flag value + */ + public final boolean getSystemCFlag() { + return _systemC; + } + + /** + * Set the SystemC flag. + */ + public final void setSystemCFlag() { + _systemC = true; + } + + /** + * Get the status of the PipeAndFilter flag. + * + * @return PipeAndFilter flag value + */ + public final boolean getPipeAndFilterFlag() { + return _pipeAndFilter; + } + + /** + * Set the PipeAndFilter flag. + */ + public final void setPipeAndFilterFlag() { + _pipeAndFilter = true; + } + + /** + * Get the status of the protothread flag. + * + * @return PipeAndFilter flag value + */ + public final boolean getProtothreadFlag() { + return _protothread; + } + + /** + * Set the protothread flag. + */ + public final void setProtothreadFlag() { + _protothread = true; + } + + /** + * Get the status of the HdS flag. + * + * @return The HdS flag value + */ + public final boolean getHdsFlag() { + return _hds; + } + + /** + * Set the HdS flag. + */ + public final void setHdsFlag() { + _hds = true; + } + + /** + * Get the status of the RTEMS flag. + * + * @return The HdS flag value + */ + public final boolean getRtemsFlag() { + return _rtems; + } + + /** + * Set the RTEMS flag. + */ + public final void setRtemsFlag() { + _rtems = true; + } + + /** + * Get the status of the CBE flag. + * + * @return The CBE flag value + */ + public final boolean getCbeFlag() { + return _cbe; + } + + /** + * Set the CBE flag. + */ + public final void setCbeFlag() { + _cbe = true; + } + + /** + * Set the YAPI flag. + */ + public final void setYapiFlag() { + _yapi = true; + } + + /** + * Get the status of the YAPI flag. + * + * @return The YAPI flag value + */ + public final boolean getYapiFlag() { + return _yapi; + } + + /** + * Get the status of the dotty flag + * + * @return The dotty Flag value + */ + public final boolean getDottyFlag() { + return _dotty; + } + + /** + * Sets the dotty flag + */ + public final void setDottyFlag() { + _dotty = true; + } + + /** + * Get the status of the profiling flag + * + * @return The profiling Flag value + */ + public final boolean getProfilingFlag() { + return _profiling; + } + + /** + * Sets the profiling flag + */ + public final void setProfilingFlag() { + _profiling = true; + } + + /** + * Get the status of the vsp log flag. + * + * @return The vsp log value + */ + public final boolean getVspLogFlag() { + return _vsplog; + } + + /** + * Sets the vsp log flag. + */ + public final void setVspLogFlag() { + _vsplog = true; + } + + /** + * Get the status of the workload annotation flag. + * + * @return workload flag + */ + public final boolean getWorkloadFlag() { + return _workload; + } + + /** + * Sets the workload flag. + */ + public final void setWorkloadFlag() { + _workload = true; + } + + /** + * Get the status of the xml generation flag + * + * @return The xmlGen Flag value + */ + public final boolean getXmlGenFlag() { + return _xmlGen; + } + + /** + * Sets the xml generation flag + */ + public final void setXmlGenFlag() { + _xmlGen = true; + } + + /** + * Get the status of the check flag + * + * @return The check Flag value + */ + public final boolean getCheckFlag() { + return _check; + } + + /** + * Sets the check flag + */ + public final void setCheckFlag() { + _check = true; + } + + /** + * Get the status of the path finder flag + * + * @return The path finder Flag value + */ + public final boolean getPathsFlag() { + return _archiPaths; + } + + /** + * Sets the check flag + */ + public final void setPathsFlag() { + _archiPaths = true; + } + + /** + * Print a message to screen if the verbose flag has been selected with an + * end-of-line. + * + * @param s description that needs to printed. + */ + public void printVerbose(String s) { + if ( getVerboseFlag() ) { + System.out.print(s); + } + } + + /** + * Print a message to screen if the verbose flag has been selected. + * + * @param s description that needs to printed. + */ + public void printlnVerbose(String s) { + if( getVerboseFlag() ) { + System.out.println(s); + } + } + + + /** + * get the name of the output file name. + * + * @return The outputFileName value + */ + public final String getOutputFileName() { + return _outputFileName; + } + + /** + * set the name of the input file name. + * + * @param filename The new outputFileName value + */ + public final void setOutputFileName(String filename) { + _outputFileName = filename; + } + + /** + * get the base path name. + * + * @return The basePath value + */ + public final String getBasePath() { return _basePath; } + + /** + * sets the base path name. + * + * @param name + * The new basePath value + */ + public final void setBasePath(String name) { _basePath = name; } + + /** + * get the trace filename. + * + * @return The name value of trace file + */ + public final String getTraceName() { return _traceName; } + + /** + * sets the trace Filename. + * + * @param name trace filename + */ + public final void setTraceName(String name) { + _traceName = name; + } + + + /** + * Get the vsp log filename. + * + * @return name of the vsp log file + */ + public final String getVspLogFileName() { + return _vspLogFileName; + } + + /** + * Set the vsp log filename. + * + * @param name vsp log filename + */ + public final void setVspLogFileName(String name) { + _vspLogFileName = name; + } + + /** + * Get the workload filename. + * + * @return name workload filename + */ + public final String getWorkloadFileName() { + return _workloadFileName; + } + + /** + * Sets the workload filename. + * + * @param name workload filename + */ + public final void setWorkloadFileName(String name) { + _workloadFileName = name; + } + + /** + * Constructor. Private since only a single version may exist. + */ + private UserInterface() { + _rb = ResourceBundle.getBundle(_rbFileName); + } +} + diff --git a/dol/src/dol/main/package.html b/dol/src/dol/main/package.html new file mode 100644 index 0000000..d7cb962 --- /dev/null +++ b/dol/src/dol/main/package.html @@ -0,0 +1,20 @@ + + + + + + +DOL main program (commandline handling and dispatching of functions). + +

Package Specification

+ + + +

Related Documentation

+ + + + + + + diff --git a/dol/src/dol/parser/xml/XmlErrorHandler.java b/dol/src/dol/parser/xml/XmlErrorHandler.java new file mode 100644 index 0000000..d1105bd --- /dev/null +++ b/dol/src/dol/parser/xml/XmlErrorHandler.java @@ -0,0 +1,45 @@ +/* $Id: XmlErrorHandler.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.parser.xml; + +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * This class ... + */ + +public class XmlErrorHandler extends DefaultHandler { + + /** + * Empty constructor + */ + public XmlErrorHandler() { + super(); + } + + /** + * Treat validation errors as fatal + * + * @param e Description of the Parameter + * @exception SAXParseException MyException If such and such occurs + */ + public void error(SAXParseException e) + throws SAXParseException { + System.out.println("Error found: " + e.getMessage()); + throw e; + } + + /** + * Dump warnings too + * + * @param err Description of the Parameter + * @exception SAXParseException MyException If such and such occurs + */ + public void warning(SAXParseException err) + throws SAXParseException { + System.out.println("** Warning" + + ", line " + err.getLineNumber() + + ", uri " + err.getSystemId()); + System.out.println(" " + err.getMessage()); + } +} diff --git a/dol/src/dol/parser/xml/XmlParser.java b/dol/src/dol/parser/xml/XmlParser.java new file mode 100644 index 0000000..2032788 --- /dev/null +++ b/dol/src/dol/parser/xml/XmlParser.java @@ -0,0 +1,84 @@ +/* $Id: XmlParser.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.parser.xml; + +import java.net.MalformedURLException; +import java.net.URL; + +import org.apache.xerces.parsers.SAXParser; +import org.xml.sax.SAXException; + +import dol.main.UserInterface; + +/** + * Parser for DOL XML files. + */ +public class XmlParser extends org.xml.sax.helpers.DefaultHandler { + + /** + * Constructor. Initializes the parser. + */ + public XmlParser() { + super(); + try { + _parser = new SAXParser(); + _parser.setFeature("http://xml.org/sax/features/validation", + true); + _parser.setFeature("http://apache.org/xml/features/" + + "validation/schema", true); + _parser.setFeature("http://apache.org/xml/features/" + + "validation/schema-full-checking", true); + _parser.setErrorHandler(new XmlErrorHandler()); + _parser.setContentHandler(this); + _parser.setProperty("http://apache.org/xml/properties/schema/" + + "external-schemaLocation", + dol.util.SchemaLocation.getInternalSchemaLocation()); + _parser.setContentHandler(this); + _parser.setErrorHandler(new XmlErrorHandler()); + } catch (SAXException e) { + e.printStackTrace(); + } catch (Throwable t) { + t.printStackTrace(); + } + } + + /** + * Return a absolute URL reference for the given URL. + * + * @param url url + * @return absolute URL reference + */ + protected String _makeAbsoluteURL(String url) + throws MalformedURLException { + URL baseURL; + String fileSep = System.getProperty("file.separator"); + String base = ""; + + // Replace all separators in given URL + url = url.replace(fileSep.charAt(0), '/'); + + // Add working directory if URL is not absolute + if (url.charAt(0) != '/' && !url.matches("^[A-Za-z]:/.*")) { + base = System.getProperty("user.dir") + '/'; + base = base.replace(fileSep.charAt(0), '/'); + if (base.charAt(0) != '/') { + base = "/" + base; + } + } + + // Add front slash to Windows style URLs + if (url.matches("^[A-Za-z]:/.*")) { + url = "/" + url; + } + + baseURL = new URL("file", null, base); + System.out.println(" -- full filename: " + + new URL(baseURL, url).toString()); + return new URL(baseURL, url).toString(); + } + + /** XML parser */ + protected SAXParser _parser; + + /** user interface used for messages for users */ + protected UserInterface _ui = UserInterface.getInstance(); +} diff --git a/dol/src/dol/parser/xml/archischema/ArchiXmlParser.java b/dol/src/dol/parser/xml/archischema/ArchiXmlParser.java new file mode 100644 index 0000000..38b1c05 --- /dev/null +++ b/dol/src/dol/parser/xml/archischema/ArchiXmlParser.java @@ -0,0 +1,187 @@ +/* $Id: ArchiXmlParser.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.parser.xml.archischema; + +import java.util.Stack; + +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import dol.datamodel.XmlTag; +import dol.datamodel.architecture.Architecture; +import dol.parser.xml.XmlParser; + +/** + * Parse architecture XML file. + */ +public class ArchiXmlParser extends XmlParser { + + /** + * Constructor. + */ + public ArchiXmlParser() { + super(); + _stack = new Stack(); + _xml2Archi = new Xml2Archi(); + } + + /** + * Do the parsing of an XML file describing an architecture. + * + * @param url The input XML file + * @return the architecture + */ + public Architecture doParse(String url) { + Architecture architecture = null; + System.out.println("Read architecture from XML file"); + + try { + String uri = _makeAbsoluteURL(url); + _ui.printlnVerbose("-- processing XML file: " + uri); + _ui.printlnVerbose("-- read XML file: "); + _stack.clear(); + _parser.parse(new InputSource(uri)); + architecture = (Architecture) _stack.pop(); + _ui.printlnVerbose(" [DONE] "); + } catch (SAXParseException err) { + System.out.println("** Parsing error, line " + + err.getLineNumber() + ", uri " + err.getSystemId()); + System.out.println(" " + err.getMessage()); + } catch (SAXException e) { + e.printStackTrace(); + } catch (Throwable t) { + t.printStackTrace(); + } + + architecture.computePaths(); + + System.out.println(" -- Architecture model from XML " + + "[Finished]"); + System.out.println(); + + return architecture; + } + + /** + * Action to be done while parsing a start element of an XML. + * + * @param elementName Description of the Parameter + * @param attributes Description of the Parameter + * @exception SAXException MyException If such and such occurs + */ + public void startElement(String namespaceURI, String localName, + String elementName, Attributes attributes) + throws SAXException { + Object val = null; + + if (elementName.equals(_xt.getArchiTag())) { + val = _xml2Archi.processArchitecture(attributes); + } else if (elementName.equals(_xt.getVariableTag())) { + val = _xml2Archi.processVariable(attributes); + } else if (elementName.equals(_xt.getProcessorTag())) { + val = _xml2Archi.processProcessor(attributes); + } else if (elementName.equals(_xt.getMemoryTag())) { + val = _xml2Archi.processMemory(attributes); + } else if (elementName.equals(_xt.getHWChannelTag())) { + val = _xml2Archi.processHWChannel(attributes); + } else if (elementName.equals(_xt.getConfigurationTag())) { + val = _xml2Archi.processConfiguration(attributes); + // simplified architecture + } else if (elementName.equals(_xt.getConnectionTag())) { + val = _xml2Archi.processConnection(attributes); + } else if (elementName.equals(_xt.getOriginTag())) { + val = _xml2Archi.processOrigin(attributes); + } else if (elementName.equals(_xt.getTargetTag())) { + val = _xml2Archi.processTarget(attributes); + } else if (elementName.equals(_xt.getNodeTag())) { + val = _xml2Archi.processNode(attributes); + } else if (elementName.equals(_xt.getPortTag())) { + val = _xml2Archi.processPort(attributes); + } else if (elementName.equals(_xt.getInPortTag())) { + val = _xml2Archi.processInputPort(attributes); + } else if (elementName.equals(_xt.getOutPortTag())) { + val = _xml2Archi.processOutputPort(attributes); + } else if (elementName.equals(_xt.getDuplexPortTag())) { + val = _xml2Archi.processInOutPort(attributes); + // detailed architecture + } else if (elementName.equals(_xt.getReadPathTag())) { + val = _xml2Archi.processReadPath(attributes); + } else if (elementName.equals(_xt.getWritePathTag())) { + val = _xml2Archi.processWritePath(attributes); + } else if (elementName.equals(_xt.getTXBufTag())) { + val = _xml2Archi.processTXBuf(attributes); + } else if (elementName.equals(_xt.getRXBufTag())) { + val = _xml2Archi.processRXBuf(attributes); + } else if (elementName.equals(_xt.getCHBufTag())) { + val = _xml2Archi.processCHBuf(attributes); + } else { + System.out.println("--Warning, DOL doesn't " + + "understand tag <" + elementName + "> "); + } + + if (val != null) { + _stack.push(val); + } + } + + /** + * Action to be done while parsing an end element of an XML. + * + * @param elementName Description of the Parameter + * @exception SAXException MyException If such and such occurs + */ + public void endElement(String namespaceURI, String localName, + String elementName) throws SAXException { + if (elementName.equals(_xt.getArchiTag())) { + _xml2Archi.processArchitecture(_stack); + } else if (elementName.equals(_xt.getVariableTag())) { + _xml2Archi.processVariable(_stack); + } else if (elementName.equals(_xt.getProcessorTag())) { + _xml2Archi.processProcessor(_stack); + } else if (elementName.equals(_xt.getMemoryTag())) { + _xml2Archi.processMemory(_stack); + } else if (elementName.equals(_xt.getHWChannelTag())) { + _xml2Archi.processHWChannel(_stack); + } else if (elementName.equals(_xt.getConfigurationTag())) { + _xml2Archi.processConfiguration(_stack); + // simplified architecture + } else if (elementName.equals(_xt.getConnectionTag())) { + _xml2Archi.processConnection(_stack); + } else if (elementName.equals(_xt.getOriginTag())) { + _xml2Archi.processOrigin(_stack); + } else if (elementName.equals(_xt.getTargetTag())) { + _xml2Archi.processTarget(_stack); + } else if (elementName.equals(_xt.getNodeTag())) { + _xml2Archi.processNode(_stack); + } else if (elementName.equals(_xt.getPortTag())) { + _xml2Archi.processPort(_stack); + } else if (elementName.equals(_xt.getInPortTag())) { + _xml2Archi.processInputPort(_stack); + } else if (elementName.equals(_xt.getOutPortTag())) { + _xml2Archi.processOutputPort(_stack); + } else if (elementName.equals(_xt.getDuplexPortTag())) { + _xml2Archi.processInOutPort(_stack); + // detailed architecture + } else if (elementName.equals(_xt.getReadPathTag())) { + _xml2Archi.processReadPath(_stack); + } else if (elementName.equals(_xt.getWritePathTag())) { + _xml2Archi.processWritePath(_stack); + } else if (elementName.equals(_xt.getTXBufTag())) { + _xml2Archi.processTXBuf(_stack); + } else if (elementName.equals(_xt.getRXBufTag())) { + _xml2Archi.processRXBuf(_stack); + } else if (elementName.equals(_xt.getCHBufTag())) { + _xml2Archi.processCHBuf(_stack); + } + } + + /** stack containing the generated objects */ + protected Stack _stack; + + /** actions to be taken while parsing every XML element */ + protected Xml2Archi _xml2Archi; + + /** */ + protected XmlTag _xt = XmlTag.getInstance(); +} diff --git a/dol/src/dol/parser/xml/archischema/Xml2Archi.java b/dol/src/dol/parser/xml/archischema/Xml2Archi.java new file mode 100644 index 0000000..49d7409 --- /dev/null +++ b/dol/src/dol/parser/xml/archischema/Xml2Archi.java @@ -0,0 +1,630 @@ +/* $Id: Xml2Archi.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.parser.xml.archischema; + +import java.util.Stack; + +import org.xml.sax.Attributes; + +import dol.datamodel.architecture.ArchiConnection; +import dol.datamodel.architecture.ArchiResource; +import dol.datamodel.architecture.Architecture; +import dol.datamodel.architecture.Configuration; +import dol.datamodel.architecture.HWChannel; +import dol.datamodel.architecture.Memory; +import dol.datamodel.architecture.Node; +import dol.datamodel.architecture.PortNode; +import dol.datamodel.architecture.Processor; +import dol.datamodel.architecture.ReadPath; +import dol.datamodel.architecture.Variable; +import dol.datamodel.architecture.WritePath; + +/** + * Parse architecture XML file. + */ +public class Xml2Archi { + + /** + * Constructor. + */ + public Xml2Archi() { + } + + /** + * Process the start of the Architecture tag in the XML. + * + * @param attributes attributes of the tag + * @return an Architecture object + */ + public Architecture processArchitecture(Attributes attributes) { + Architecture arch = new Architecture(attributes.getValue("name")); + return arch; + + } + + /** + * Process the end of the Architecture tag in the XML. + * + * @param stack + */ + public void processArchitecture(Stack stack) { + } + + /** + * Process the start of a processor tag in the XML. + * + * @param attributes The attributes of the tag. + * @return a processor object. + */ + public Processor processProcessor(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String basename = (String) attributes.getValue("basename"); + String range = (String) attributes.getValue("range"); + String type = (String) attributes.getValue("type"); + Processor processor = new Processor(name); + if (basename != null) processor.setBasename(basename); + if (range != null) processor.setRange(range); + if (type != null) processor.setType(type); + return processor; + } + + /** + * Process the end of a processor tag in the XML. + * + * @param stack + */ + public void processProcessor(Stack stack) { + Processor p = (Processor) stack.pop(); + + if (stack.peek() instanceof ReadPath) { + ReadPath r = (ReadPath) stack.peek(); + Processor pro = ((Architecture)stack.elementAt(0)). + getProcessor(p.getName()); + if (pro != null) { + r.setProcessor(pro); + } + else { + undefinedReference("ReadPath", r.getName(), + "processor", p.getName()); + } + } else if (stack.peek() instanceof WritePath) { + WritePath w = (WritePath) stack.peek(); + Processor pro = ((Architecture)stack.elementAt(0)). + getProcessor(p.getName()); + if (pro != null) { + w.setProcessor(pro); + } + else { + undefinedReference("ReadPath", w.getName(), + "processor", p.getName()); + } + } else if (stack.peek() instanceof Architecture) { + Architecture a = (Architecture)stack.peek(); + p.setParentResource(a); + a.getProcessorList().add(p); + } + } + + /** + * Process the start of a memory tag in the XML. + * + * @param attributes The attributes of the tag. + * @return a memory object. + */ + public Memory processMemory(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String basename = (String) attributes.getValue("basename"); + String range = (String) attributes.getValue("range"); + String type = (String) attributes.getValue("type"); + Memory memory = new Memory(name); + if (basename != null) memory.setBasename(basename); + if (range != null) memory.setRange(range); + if (type != null) memory.setRange(type); + return memory; + } + + /** + * Process the end of a memory tag in the XML. + * + * @param stack + */ + public void processMemory(Stack stack) { + Memory m = (Memory) stack.pop(); + Architecture a = (Architecture)stack.peek(); + a.getMemoryList().add(m); + m.setParentResource(a); + } + + /** + * Process the start of a hw_channel tag in the XML. + * + * @param attributes The attributes of the tag. + * @return a hw_chnannel object. + */ + public HWChannel processHWChannel(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String basename = (String) attributes.getValue("basename"); + String range = (String) attributes.getValue("range"); + String type = (String) attributes.getValue("type"); + HWChannel hw_channel = new HWChannel(name); + if (basename != null) hw_channel.setBasename(basename); + if (range != null) hw_channel.setRange(range); + if (type != null) hw_channel.setType(type); + return hw_channel; + } + + /** + * Process the end of an hw_channel tag in the XML. + * + * @param stack + */ + public void processHWChannel(Stack stack) { + HWChannel c = (HWChannel) stack.pop(); + if (stack.peek() instanceof Architecture) { + Architecture a = (Architecture)stack.peek(); + a.getHWChannelList().add(c); + c.setParentResource(a); + } else if (stack.peek() instanceof WritePath) { + WritePath w = (WritePath)stack.peek(); + HWChannel ch = ((Architecture)stack.elementAt(0)). + getHWChannel(c.getName()); + if (ch != null) { + w.getHWChannelList().add(ch); + } + else { + undefinedReference("WritePath", w.getName(), + "hwchannel", c.getName()); + } + } else if (stack.peek() instanceof ReadPath) { + ReadPath r = (ReadPath)stack.peek(); + HWChannel ch = ((Architecture)stack.elementAt(0)). + getHWChannel(c.getName()); + if (ch != null) { + r.getHWChannelList().add(ch); + } + else { + undefinedReference("ReadPath", r.getName(), + "hwchannel", c.getName()); + } + } + } + + /** + * Process the start of a node tag in the XML. + * + * @param attributes The attributes of the tag. + * @return a node object. + */ + public Node processNode(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String basename = (String) attributes.getValue("basename"); + String range = (String) attributes.getValue("range"); + Node node = new Node(name); + if (basename != null) node.setBasename(basename); + if (range != null) node.setRange(range); + return node; + } + + /** + * Process the end of an node tag in the XML. + * + * @param stack + */ + public void processNode(Stack stack) { + Node n = (Node) stack.pop(); + ArchiResource r = (ArchiResource)stack.peek(); + r.getNodeList().add(n); + } + + /** + * Process the start of a origin tag in the XML. + * + * @param attributes attributes of the tag + * @return a ArchiResource object + */ + public ArchiResource processOrigin(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String basename = (String) attributes.getValue("basename"); + ArchiResource resource = new ArchiResource(name); + if (basename != null) resource.setBasename(basename); + + return resource; + } + + /** + * Process the end of a origin tag in the XML. + * + * @param stack + */ + public void processOrigin(Stack stack) { + ArchiResource resource = (ArchiResource) stack.pop(); + ArchiConnection connection = (ArchiConnection) stack.peek(); + connection.setOrigin(resource); + } + + /** + * Process the start of a target tag in the XML. + * + * @param attributes attributes of the tag + * @return a ArchiResource object + */ + public ArchiResource processTarget(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String basename = (String) attributes.getValue("basename"); + ArchiResource resource = new ArchiResource(name); + if (basename != null) resource.setBasename(basename); + + return resource; + } + + /** + * Process the end of a target tag in the XML. + * + * @param stack + */ + public void processTarget(Stack stack) { + ArchiResource resource = (ArchiResource) stack.pop(); + ArchiConnection connection = (ArchiConnection) stack.peek(); + connection.setTarget(resource); + } + + /** + * Process the start of a connection tag in the XML. + * + * @param attributes attributes of the tag + * @return a ArchiConnection object + */ + public ArchiConnection processConnection(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String basename = (String) attributes.getValue("basename"); + ArchiConnection connection = new ArchiConnection(name); + if (basename != null) connection.setBasename(basename); + + return connection; + } + + /** + * Process the end of a connection tag in the XML. + * + * @param stack + */ + public void processConnection(Stack stack) { + ArchiConnection connection = (ArchiConnection) stack.pop(); + Architecture architecture = (Architecture)stack.peek(); + architecture.getConnectionList().add(connection); + connection.setParentResource(architecture); + } + + /** + * Process the start of an inputport/outputport/port tag in the XML. + * + * @param attributes attributes of the tag + * @return a PortNode object + */ + public PortNode processInputPort(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String basename = (String) attributes.getValue("basename"); + String range = (String) attributes.getValue("range"); + + PortNode port = new PortNode(name, PortNode.INPORT); + + if (basename != null) + port.setBasename(basename); + else + port.setBasename(name); + + if (range != null) + port.setRange(range); + + return port; + } + + public PortNode processOutputPort(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String basename = (String) attributes.getValue("basename"); + String range = (String) attributes.getValue("range"); + + PortNode port = new PortNode(name, PortNode.OUTPORT); + + if (basename != null) + port.setBasename(basename); + else + port.setBasename(name); + + if (range != null) + port.setRange(range); + + return port; + } + + // duplexport + public PortNode processInOutPort(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String basename = (String) attributes.getValue("basename"); + String range = (String) attributes.getValue("range"); + + PortNode port = new PortNode(name, PortNode.INOUTPORT); + + if (basename != null) + port.setBasename(basename); + else + port.setBasename(name); + + if (range != null) + port.setRange(range); + + return port; + } + + public PortNode processPort(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String basename = (String) attributes.getValue("basename"); + String range = (String) attributes.getValue("range"); + + PortNode port = new PortNode(name); + + if (basename != null) + port.setBasename(basename); + else + port.setBasename(name); + + if (range != null) + port.setRange(range); + + return port; + } + + /** + * Process the end of an inputport/outputport/duplexport/port tag in the XML. + * + * @param stack + */ + public void processInputPort(Stack stack) { + PortNode port = (PortNode) stack.pop(); + Node node = (Node) stack.peek(); + port.setNode(node); + node.getPortList().add(port); + } + + public void processOutputPort(Stack stack) { + PortNode port = (PortNode) stack.pop(); + Node node = (Node) stack.peek(); + port.setNode(node); + node.getPortList().add(port); + } + + public void processInOutPort(Stack stack) { + PortNode port = (PortNode) stack.pop(); + Node node = (Node) stack.peek(); + port.setNode(node); + node.getPortList().add(port); + } + + public void processPort(Stack stack) { + PortNode port = (PortNode) stack.pop(); + Node node = (Node) stack.peek(); + port.setNode(node); + node.getPortList().add(port); + } + + /** + * Process the start of a variable tag in the XML. + * + * @param attributes attributes of the tag + * @return a Variable object + */ + public Variable processVariable(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String value = (String) attributes.getValue("value"); + Variable variable = null; + variable = new Variable(name); + variable.setValue(Integer.parseInt(value)); + + return variable; + } + + /** + * Process the end of a variable tag in the XML. + * + * @param stack + */ + public void processVariable(Stack stack) { + Variable variable = (Variable) stack.pop(); + Architecture architecture = (Architecture)stack.peek(); + variable.setParentResource(architecture); + architecture.getVarList().add(variable); + } + + /** + * Process the start of a configuration tag in the XML. + * + * @param attributes attributes of the tag + * @return a Configuration object + */ + public Configuration processConfiguration(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String value = (String) attributes.getValue("value"); + Configuration config = new Configuration(name); + config.setValue(value); + return config; + } + + /** + * Process the end of a configuration tag in the XML. + * + * @param stack + */ + public void processConfiguration(Stack stack) { + Configuration config = (Configuration) stack.pop(); + ArchiResource res = (ArchiResource)stack.peek(); + res.getCfgList().add(config); + } + + /** + * Process the start of a readPath tag in the XML. + * + * @param attributes attributes of the tag + * @return a ReadPath object + */ + public ReadPath processReadPath(Attributes attributes) { + String name = (String) attributes.getValue("name"); + ReadPath readpath = new ReadPath(name); + return readpath; + } + + /** + * Process the end of a readpath tag in the XML. + * + * @param stack + */ + public void processReadPath(Stack stack) { + ReadPath readpath = (ReadPath) stack.pop(); + Architecture res = (Architecture)stack.peek(); + res.getReadPathList().add(readpath); + } + + /** + * Process the start of a WritePath tag in the XML. + * + * @param attributes attributes of the tag + * @return a WritePath object + */ + public WritePath processWritePath(Attributes attributes) { + String name = (String) attributes.getValue("name"); + WritePath writepath = new WritePath(name); + return writepath; + } + + /** + * Process the end of a WritePath tag in the XML. + * + * @param stack + */ + public void processWritePath(Stack stack) { + WritePath writepath = (WritePath) stack.pop(); + Architecture res = (Architecture)stack.peek(); + res.getWritePathList().add(writepath); + } + + /** + * Process the start of a TXBuf tag in the XML. + * + * @param attributes attributes of the tag + * @return a TXBuf object + */ + public String processTXBuf(Attributes attributes) { + return attributes.getValue("name"); + } + + /** + * Process the end of a TXBuf tag in the XML. + * + * @param stack + */ + public void processTXBuf(Stack stack) { + String txBuf = (String) stack.pop(); + WritePath res = (WritePath)stack.peek(); + Memory mem = ((Architecture)res.getProcessor().getParentResource()).getMemory(txBuf); + if (mem != null) { + res.setTXBuf(mem); + } + else { + undefinedReference("ReadPath", res.getName(), + "transmit buffer", txBuf); + } + } + + /** + * Process the start of a RXBuf tag in the XML. + * + * @param attributes attributes of the tag + * @return a RXBuf object + */ + public String processRXBuf(Attributes attributes) { + return attributes.getValue("name"); + } + + /** + * Process the end of a RXBuf tag in the XML. + * + * @param stack + */ + public void processRXBuf(Stack stack) { + String rxBuf = (String) stack.pop(); + ReadPath res = (ReadPath)stack.peek(); + Memory mem = ((Architecture)res.getProcessor().getParentResource()).getMemory(rxBuf); + if (mem != null) { + res.setRXBuf(mem); + } + else { + undefinedReference("ReadPath", res.getName(), + "receive buffer", rxBuf); + } + } + + /** + * Process the start of a CHBuf tag in the XML. + * + * @param attributes attributes of the tag + * @return a CHBuf object + */ + public String processCHBuf(Attributes attributes) { + return attributes.getValue("name"); + } + + /** + * Process the end of a CHBuf tag in the XML. + * + * @param stack + */ + public void processCHBuf(Stack stack) { + String value= (String) stack.pop(); + if (stack.peek() instanceof ReadPath) { + ReadPath res = (ReadPath)stack.peek(); + Memory mem = ((Architecture)res.getProcessor(). + getParentResource()).getMemory(value); + if (mem != null) { + res.setCHBuf(mem); + } + else { + undefinedReference("ReadPath", res.getName(), + "channel buffer", value); + } + } + else if (stack.peek() instanceof WritePath) { + WritePath res = (WritePath)stack.peek(); + Memory mem = ((Architecture)res.getProcessor(). + getParentResource()).getMemory(value); + if (mem != null) { + res.setCHBuf(mem); + } + else { + undefinedReference("WritePath", res.getName(), + "channel buffer", value); + } + } + } + + + /** + * Write an error message and terminate program in case an + * architecture element is referenced which does not exist. + * + * @param elementType type of architecture element in which the error + * occurred + * @param elementName name of architecture element in which the error + * occurred + * @param referenceType type of referenced architecture element + * @param referenceName name of referenced architecture element + */ + protected void undefinedReference(String elementType, + String elementName, + String referenceType, + String referenceName) { + System.out.println("Error: " + elementType + " " + elementName + + " references " + referenceType + " " + referenceName + + " that has not been declared."); + System.out.println("Exit."); + System.exit(-1); + } + +} diff --git a/dol/src/dol/parser/xml/archischema/package.html b/dol/src/dol/parser/xml/archischema/package.html new file mode 100644 index 0000000..6a6b096 --- /dev/null +++ b/dol/src/dol/parser/xml/archischema/package.html @@ -0,0 +1,21 @@ + + + + + + +Architecture XML schema parser. +This package parses the architecture XML and stores the result in internal architectural data model. + +

Package Specification

+ + + +

Related Documentation

+ + + + + + + diff --git a/dol/src/dol/parser/xml/mapschema/MapXmlParser.java b/dol/src/dol/parser/xml/mapschema/MapXmlParser.java new file mode 100644 index 0000000..4849601 --- /dev/null +++ b/dol/src/dol/parser/xml/mapschema/MapXmlParser.java @@ -0,0 +1,211 @@ +/* $Id: MapXmlParser.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.parser.xml.mapschema; + +import java.util.Stack; + +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import dol.datamodel.XmlTag; +import dol.datamodel.architecture.Architecture; +import dol.datamodel.mapping.Mapping; +import dol.datamodel.pn.ProcessNetwork; +import dol.parser.xml.XmlParser; + + +/** + * Parse mapping XML file. + */ +public class MapXmlParser extends XmlParser { + + /** + * Constructor. + * @param pn the process network the mapping is referring to + * @param arch the architecture the mapping is referring to + */ + public MapXmlParser(ProcessNetwork pn, Architecture arch) { + super(); + _stack = new Stack(); + _xml2Map = new Xml2Map(pn, arch); + } + + /** + * Do the parsing of an XML file describing a mapping. + * + * @param url The input XML file + * @return the mapping + */ + public Mapping doParse(String url) { + Mapping map = null; + System.out.println("Read mapping from XML file"); + + try { + String uri = _makeAbsoluteURL(url); + _ui.printlnVerbose("-- processing XML file: " + uri); + _ui.printlnVerbose("-- read XML file: "); + _stack.clear(); + _parser.parse(new InputSource(uri)); + map = (Mapping) _stack.pop(); + _ui.printlnVerbose(" [DONE] "); + } catch (SAXParseException err) { + System.out.println("** Parsing error, line " + + err.getLineNumber() + ", uri " + err.getSystemId()); + System.out.println(" " + err.getMessage()); + } catch (SAXException e) { + //e.printStackTrace(); + e.getMessage(); + System.exit(-1); + } catch (Throwable t) { + t.printStackTrace(); + } + + System.out.println(" -- Mapping from XML " + + "[Finished]"); + System.out.println(); + + return map; + } + + /** + * Action to be done while parsing a start element of an XML. + * + * @param elementName Description of the Parameter + * @param attributes Description of the Parameter + * @exception SAXException MyException If such and such occurs + */ + public void startElement(String namespaceURI, String localName, + String elementName, Attributes attributes) + throws SAXException { + Object val = null; + + if (elementName.equals(_xt.getMappingTag())) { + val = _xml2Map.processMapping(attributes); + } else if (elementName.equals(_xt.getVariableTag())) { + val = _xml2Map.processVariable(attributes); + } else if (elementName.equals(_xt.getBindingTag())) { + val = _xml2Map.processBinding(attributes); + } else if (elementName.equals(_xt.getOriginTag())) { + val = _xml2Map.processOrigin(attributes); + } else if (elementName.equals(_xt.getProcessTag())) { + val = _xml2Map.processProcess(attributes); + } else if (elementName.equals(_xt.getProcessorTag())) { + val = _xml2Map.processProcessor(attributes); + } else if (elementName.equals(_xt.getSWChannelTag())) { + val = _xml2Map.processChannel(attributes); + } else if (elementName.equals(_xt.getReadPathTag())) { + val = _xml2Map.processReadPath(attributes); + } else if (elementName.equals(_xt.getWritePathTag())) { + val = _xml2Map.processWritePath(attributes); + } else if (elementName.equals(_xt.getScheduleTag())) { + val = _xml2Map.processSchedule(attributes); + } else if (elementName.equals(_xt.getResourceTag())) { + val = _xml2Map.processResource(attributes); + } else if (elementName.equals(_xt.getConfigurationTag())) { + val = _xml2Map.processConfiguration(attributes); + } else { + System.out.println(" -- Warning, DOL doesn't " + + "understand tag <" + elementName + "> "); + } + + if (val != null) { + _stack.push(val); + } + + consistencyCheck(elementName, attributes, val); + } + + + /** + * Action to be done while parsing an end element of an XML. + * + * @param elementName Description of the Parameter + * @exception SAXException MyException If such and such occurs + */ + public void endElement(String namespaceURI, String localName, + String elementName) throws SAXException { + if (elementName.equals(_xt.getMappingTag())) { + _xml2Map.processMapping(_stack); + } else if (elementName.equals(_xt.getVariableTag())) { + _xml2Map.processVariable(_stack); + } else if (elementName.equals(_xt.getBindingTag())) { + _xml2Map.processBinding(_stack); + } else if (elementName.equals(_xt.getOriginTag())) { + _xml2Map.processOrigin(_stack); + /* + } else if (elementName.equals(_xt.getTargetTag())) { + _xml2Map.processTarget(_stack); + */ + } else if (elementName.equals(_xt.getProcessTag())) { + _xml2Map.processProcess(_stack); + } else if (elementName.equals(_xt.getProcessorTag())) { + _xml2Map.processProcessor(_stack); + } else if (elementName.equals(_xt.getSWChannelTag())) { + _xml2Map.processChannel(_stack); + } else if (elementName.equals(_xt.getReadPathTag())) { + _xml2Map.processReadPath(_stack); + } else if (elementName.equals(_xt.getWritePathTag())) { + _xml2Map.processWritePath(_stack); + } else if (elementName.equals(_xt.getScheduleTag())) { + _xml2Map.processSchedule(_stack); + } else if (elementName.equals(_xt.getResourceTag())) { + _xml2Map.processResource(_stack); + } else if (elementName.equals(_xt.getConfigurationTag())) { + _xml2Map.processConfiguration(_stack); + } + } + + /** + * + */ + protected void consistencyCheck(String elementName, + Attributes attributes, Object val) { + boolean isConsistent = true; + + if (elementName.equals(_xt.getProcessorTag()) + && val == null) { + System.out.println(" -- Error: Could not find processor \"" + + attributes.getValue("name") + "\" in " + + "architecture."); + isConsistent = false; + } else if (elementName.equals(_xt.getProcessTag()) + && val == null) { + System.out.println(" -- Error: Could not find process \"" + + attributes.getValue("name") + "\" in " + + "process network."); + isConsistent = false; + } else if (elementName.equals(_xt.getSWChannelTag()) + && val == null) { + System.out.println(" -- Error: Could not find channel \"" + + attributes.getValue("name") + "\" in " + + "process network."); + isConsistent = false; + } else if (elementName.equals(_xt.getReadPathTag()) + && val == null) { + System.out.println(" -- Error: Could not find read path \"" + + attributes.getValue("name") + "\" in " + + "architecture."); + isConsistent = false; + } else if (elementName.equals(_xt.getWritePathTag()) + && val == null) { + System.out.println(" -- Error: Could not find write path \"" + + attributes.getValue("name") + "\" in " + + "architecture."); + isConsistent = false; + } + + if (!isConsistent) { + System.exit(-1); + } + } + + /** stack containing the generated objects */ + protected Stack _stack; + + /** actions to be taken while parsing every XML element */ + protected Xml2Map _xml2Map; + + /** */ + protected XmlTag _xt = XmlTag.getInstance(); +} diff --git a/dol/src/dol/parser/xml/mapschema/Xml2Map.java b/dol/src/dol/parser/xml/mapschema/Xml2Map.java new file mode 100644 index 0000000..4d15666 --- /dev/null +++ b/dol/src/dol/parser/xml/mapschema/Xml2Map.java @@ -0,0 +1,381 @@ +package dol.parser.xml.mapschema; + +import java.util.Stack; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +import dol.datamodel.architecture.ArchiResource; +import dol.datamodel.architecture.Architecture; +import dol.datamodel.architecture.Processor; +import dol.datamodel.architecture.ReadPath; +import dol.datamodel.architecture.WritePath; +import dol.datamodel.mapping.Binding; +import dol.datamodel.mapping.CommunicationBinding; +import dol.datamodel.mapping.ComputationBinding; +import dol.datamodel.mapping.Configuration; +import dol.datamodel.mapping.Mapping; +import dol.datamodel.mapping.Schedule; +import dol.datamodel.mapping.ScheduleEntry; +import dol.datamodel.mapping.SchedulingPolicy; +import dol.datamodel.mapping.Variable; +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; + + +/** + * + */ +public class Xml2Map { + + /** + * Constructor. + * @param pn the process network the mapping is refering to + * @param arch the architecture the mapping is refering to + */ + public Xml2Map(ProcessNetwork pn, Architecture arch) { + _pn = pn; + _arch = arch; + } + + /** + * Process the start of the mapping tag in the XML. + * + * @param attributes attributes of the tag + * @return a Mapping object + */ + public Mapping processMapping(Attributes attributes) { + String name = (String) attributes.getValue("name"); + Mapping map = new Mapping(name); + map.setArch(_arch); + map.setPN(_pn); + return map; + } + + /** + * Process the end of the mapping tag in the XML. + * + * @param stack + */ + public void processMapping(Stack stack) { + } + + /** + * Process the start of a binding tag in the XML. + * + * @param attributes The attributes of the tag. + * @return a Binding object. + */ + public Binding processBinding(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String basename = (String) attributes.getValue("basename"); + String type = (String) attributes.getValue( + "http://www.w3.org/2001/XMLSchema-instance", "type"); + Binding b = null; + // Create ComputationBinding or CommunicationBinding object + if(type.equals(Binding.COMPUTATION)) { + b = new ComputationBinding(name); + } else if(type.equals(Binding.COMMUNICATION)) { + b = new CommunicationBinding(name); + } + + if (basename != null) b.setBasename(basename); + + return b; + } + + /** + * Process the end of a binding tag in the XML. + * + * @param stack + */ + public void processBinding(Stack stack) throws SAXException + { + Binding bind = (Binding)stack.pop(); + Mapping map = (Mapping)stack.peek(); + bind.setParentResource(map); + + if(bind instanceof ComputationBinding) { + ComputationBinding cb = (ComputationBinding)bind; + Process process = cb.getProcess(); + Processor processor = cb.getProcessor(); + process.setProcessor(processor); + processor.getProcessList().add(process); + + map.getCompBindList().add(cb); + map.getProcessList().add(process); + if (!map.getProcessorList().contains(processor)) { + map.getProcessorList().add(processor); + } + + } else { + map.getCommBindList().add((CommunicationBinding)bind); + } + } + + /** + * Process the start of a origin tag in the XML. + * + * @param attributes attributes of the tag + * @return a ScheduleEntry object + */ + public ScheduleEntry processOrigin(Attributes attributes) { + String name = (String) attributes.getValue("name"); + ScheduleEntry schedEntry = new ScheduleEntry(name); + + // A scheduled resource is either a PN process + // or a SW channel. + Process process = _pn.getProcess(name); + if(process != null) { + schedEntry.setConsumer(process); + } else { + Channel channel = _pn.getChannel(name); + schedEntry.setConsumer(channel); + } + return schedEntry; + } + + /** + * Process the end of a origin tag in the XML. + * + * @param stack + */ + public void processOrigin(Stack stack) { + ScheduleEntry schedProcess = (ScheduleEntry) stack.pop(); + Schedule sched = (Schedule) stack.peek(); + sched.getEntryList().add(schedProcess); + schedProcess.setParentResource(sched); + } + + /** + * Process the start of a variable tag in the XML. + * + * @param attributes attributes of the tag + * @return a Variable object + */ + public Variable processVariable(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String value = (String) attributes.getValue("value"); + Variable variable = new Variable(name); + variable.setValue(Integer.parseInt(value)); + return variable; + } + + /** + * Process the end of a variable tag in the XML. + * + * @param stack + */ + public void processVariable(Stack stack) { + Variable variable = (Variable) stack.pop(); + Mapping map = (Mapping) stack.peek(); + variable.setParentResource(map); + map.getVarList().add(variable); + } + + /** + * Process the start of a process tag in the XML. + * + * @param attributes attributes of the tag + * @return a Process object + */ + public Process processProcess(Attributes attributes) { + String name = (String) attributes.getValue("name"); + Process process = _pn.getProcess(name); + return process; + } + + /** + * Process the end of a process tag in the XML. + * + * @param stack + */ + public void processProcess(Stack stack) { + Process p = (Process) stack.pop(); + ComputationBinding b = (ComputationBinding) stack.peek(); + b.setProcess(p); + } + + /** + * Process the start of a processor tag in the XML. + * + * @param attributes attributes of the tag + * @return a Processor object + */ + public Processor processProcessor(Attributes attributes) { + String name = (String) attributes.getValue("name"); + Processor processor = _arch.getProcessor(name); + return processor; + } + + /** + * Process the end of a processor tag in the XML. + * + * @param stack + */ + public void processProcessor(Stack stack) { + Processor p = (Processor) stack.pop(); + ComputationBinding b = (ComputationBinding) stack.peek(); + b.setProcessor(p); + } + + /** + * Process the start of a channel tag in the XML. + * + * @param attributes attributes of the tag + * @return a Channel object + */ + public Channel processChannel(Attributes attributes) { + String name = (String) attributes.getValue("name"); + Channel channel = _pn.getChannel(name); + return channel; + } + + /** + * Process the end of a channel tag in the XML. + * + * @param stack + */ + public void processChannel(Stack stack) { + Channel chan = (Channel) stack.pop(); + CommunicationBinding b = (CommunicationBinding) stack.peek(); + b.setChannel(chan); + } + + /** + * Process the start of a read path tag in the XML. + * + * @param attributes attributes of the tag + * @return a ReadPath object + */ + public ReadPath processReadPath(Attributes attributes) { + String name = (String) attributes.getValue("name"); + ReadPath path = _arch.getReadPath(name); + return path; + } + + /** + * Process the end of a read path tag in the XML. + * + * @param stack + */ + public void processReadPath(Stack stack) { + ReadPath path = (ReadPath) stack.pop(); + CommunicationBinding b = (CommunicationBinding) stack.peek(); + b.setReadPath(path); + } + + /** + * Process the start of a write path tag in the XML. + * + * @param attributes attributes of the tag + * @return a WritePath object + */ + public WritePath processWritePath(Attributes attributes) { + String name = (String) attributes.getValue("name"); + WritePath path = _arch.getWritePath(name); + return path; + } + + /** + * Process the end of a write path tag in the XML. + * + * @param stack + */ + public void processWritePath(Stack stack) { + WritePath path = (WritePath) stack.pop(); + CommunicationBinding b = (CommunicationBinding) stack.peek(); + b.setWritePath(path); + } + + /** + * Process the start of a schedule tag in the XML. + * + * @param attributes attributes of the tag + * @return a Schedule object + */ + public Schedule processSchedule(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String type = (String) attributes.getValue("type"); + String basename = (String) attributes.getValue("basename"); + + Schedule schedule = new Schedule(name); + schedule.setSchedPolicy(SchedulingPolicy.fromString(type)); + + if (basename != null) schedule.setBasename(basename); + + return schedule; + } + + /** + * Process the end of a schedule tag in the XML. + * + * @param stack + */ + public void processSchedule(Stack stack) { + Schedule sched = (Schedule) stack.pop(); + Mapping map = (Mapping) stack.peek(); + map.getScheduleList().add(sched); + sched.setParentResource(map); + } + + /** + * Process the start of a resource tag in the XML. + * + * @param attributes attributes of the tag + * @return a ArchiResource object + */ + public ArchiResource processResource(Attributes attributes) { + String name = (String) attributes.getValue("name"); + // We are either looking for a HW channel or for a processor. + ArchiResource resource = null; + if((resource = _arch.getHWChannel(name)) == null) { + resource = _arch.getProcessor(name); + } + return resource; + } + + /** + * Process the end of a resource tag in the XML. + * + * @param stack + */ + public void processResource(Stack stack) { + ArchiResource resource = (ArchiResource) stack.pop(); + Schedule schedule = (Schedule) stack.peek(); + schedule.setResource(resource); + } + + /** + * Process the start of a configuration tag in the XML. + * + * @param attributes attributes of the tag + * @return a Configuration object + */ + public Configuration processConfiguration(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String value = (String) attributes.getValue("value"); + Configuration config = new Configuration(name, value); + return config; + } + + /** + * Process the end of a configuration tag in the XML. + * + * @param stack + */ + public void processConfiguration(Stack stack) { + Configuration config = (Configuration) stack.pop(); + if(stack.peek() instanceof ScheduleEntry) { + ScheduleEntry schedProc = (ScheduleEntry) stack.peek(); + schedProc.getCfgList().add(config); + } else if(stack.peek() instanceof Schedule) { + Schedule sched = (Schedule) stack.peek(); + sched.getCfgList().add(config); + } + } + + protected ProcessNetwork _pn = null; + protected Architecture _arch = null; +} diff --git a/dol/src/dol/parser/xml/mapschema/package.html b/dol/src/dol/parser/xml/mapschema/package.html new file mode 100644 index 0000000..5fa0ab3 --- /dev/null +++ b/dol/src/dol/parser/xml/mapschema/package.html @@ -0,0 +1,21 @@ + + + + + + +Mapping XML schema parser. +This package parses the mapping XML and stores the result in internal architectural data model. + +

Package Specification

+ + + +

Related Documentation

+ + + + + + + diff --git a/dol/src/dol/parser/xml/package.html b/dol/src/dol/parser/xml/package.html new file mode 100644 index 0000000..50319b9 --- /dev/null +++ b/dol/src/dol/parser/xml/package.html @@ -0,0 +1,20 @@ + + + + + + +Parser for DOL specific XML files. + +

Package Specification

+ + + +

Related Documentation

+ + + + + + + diff --git a/dol/src/dol/parser/xml/pnschema/PNXmlParser.java b/dol/src/dol/parser/xml/pnschema/PNXmlParser.java new file mode 100644 index 0000000..70a4f8a --- /dev/null +++ b/dol/src/dol/parser/xml/pnschema/PNXmlParser.java @@ -0,0 +1,158 @@ +/* $Id: PNXmlParser.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.parser.xml.pnschema; + +import java.util.Stack; + +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import dol.datamodel.XmlTag; +import dol.datamodel.pn.ProcessNetwork; +import dol.parser.xml.XmlParser; + +/** + * Parse processnetwork XML file. + */ +public class PNXmlParser extends XmlParser { + + /** + * Constructor. + */ + public PNXmlParser() { + super(); + _stack = new Stack(); + _xml2PN = new Xml2PN(); + } + + /** + * Do the parsing of an XML file describing a processnetwork. + * + * @param url input XML file + * @return the processnetwork + */ + public ProcessNetwork doParse(String url) { + ProcessNetwork pn = null; + System.out.println("Read process network from XML file"); + + try { + String uri = _makeAbsoluteURL(url); + _ui.printlnVerbose("-- processing XML file: " + uri); + _ui.printlnVerbose("-- read XML file: "); + _stack.clear(); + _parser.parse(new InputSource(uri)); + pn = (ProcessNetwork) _stack.pop(); + _ui.printlnVerbose(" [DONE] "); + } catch (SAXParseException err) { + System.out.println("** Parsing error, line " + + err.getLineNumber() + ", uri " + err.getSystemId()); + System.out.println(" " + err.getMessage()); + } catch (SAXException e) { + e.printStackTrace(); + } catch (Throwable t) { + t.printStackTrace(); + } + + try { + pn.fillPortPeerInfo(); + } catch (Exception e) { + System.out.println("Exception\n " + e.getMessage()); + e.printStackTrace(System.out); + } + + System.out.println(" -- Process network model from XML " + + "[Finished]"); + System.out.println(); + + return pn; + } + + /** + * Action to be done while parsing a start element of an XML. + * + * @param namespaceURI + * @param localName + * @param elementName name of element + * @param attributes attributes of element + * @exception SAXException thrown when a parsing error occurs + */ + public void startElement(String namespaceURI, String localName, + String elementName, Attributes attributes) + throws SAXException { + Object val = null; + + if (elementName.equals(_xt.getPNTag())) { + val = _xml2PN.processPN(attributes); + } else if (elementName.equals(_xt.getVariableTag())) { + val = _xml2PN.processVariable(attributes); + } else if (elementName.equals(_xt.getProcessTag())) { + val = _xml2PN.processProcess(attributes); + } else if (elementName.equals(_xt.getSWChannelTag())) { + val = _xml2PN.processChannel(attributes); + } else if (elementName.equals(_xt.getConnectionTag())) { + val = _xml2PN.processConnection(attributes); + } else if (elementName.equals(_xt.getOriginTag())) { + val = _xml2PN.processOrigin(attributes); + } else if (elementName.equals(_xt.getTargetTag())) { + val = _xml2PN.processTarget(attributes); + } else if (elementName.equals(_xt.getPortTag())) { + val = _xml2PN.processPort(attributes); + } else if (elementName.equals(_xt.getSourceTag())) { + val = _xml2PN.processSource(attributes); + } else if (elementName.equals(_xt.getProfilingTag())) { + val = _xml2PN.processProfiling(attributes); + } else if (elementName.equals(_xt.getConfigurationTag())) { + val = _xml2PN.processConfiguration(attributes); + } else { + System.out.println("--Warning, DOL doesn't " + + "understand tag <" + elementName + "> "); + } + + if (val != null) { + _stack.push(val); + } + } + + /** + * Action to be done while parsing an end element of an XML. + * + * @param elementName Description of the Parameter + * @exception SAXException MyException If such and such occurs + */ + public void endElement(String namespaceURI, String localName, + String elementName) throws SAXException { + if (elementName.equals(_xt.getPNTag())) { + _xml2PN.processPN(_stack); + } else if (elementName.equals(_xt.getVariableTag())) { + _xml2PN.processVariable(_stack); + } else if (elementName.equals(_xt.getProcessTag())) { + _xml2PN.processProcess(_stack); + } else if (elementName.equals(_xt.getSWChannelTag())) { + _xml2PN.processChannel(_stack); + } else if (elementName.equals(_xt.getConnectionTag())) { + _xml2PN.processConnection(_stack); + } else if (elementName.equals(_xt.getOriginTag())) { + _xml2PN.processOrigin(_stack); + } else if (elementName.equals(_xt.getTargetTag())) { + _xml2PN.processTarget(_stack); + } else if (elementName.equals(_xt.getSourceTag())) { + _xml2PN.processSource(_stack); + } else if (elementName.equals(_xt.getProfilingTag())) { + _xml2PN.processProfiling(_stack); + } else if (elementName.equals(_xt.getConfigurationTag())) { + _xml2PN.processConfiguration(_stack); + } else if (elementName.equals(_xt.getPortTag())) { + _xml2PN.processPort(_stack); + } + } + + /** stack containing the generated objects */ + protected Stack _stack; + + /** actions to be taken while parsing every XML element */ + protected Xml2PN _xml2PN; + + /** */ + protected XmlTag _xt = XmlTag.getInstance(); +} diff --git a/dol/src/dol/parser/xml/pnschema/Xml2PN.java b/dol/src/dol/parser/xml/pnschema/Xml2PN.java new file mode 100644 index 0000000..5586c16 --- /dev/null +++ b/dol/src/dol/parser/xml/pnschema/Xml2PN.java @@ -0,0 +1,457 @@ +/* $Id: Xml2PN.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.parser.xml.pnschema; + +import java.util.Stack; + +import org.xml.sax.Attributes; + +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Configuration; +import dol.datamodel.pn.Connection; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.ProfilingConfiguration; +import dol.datamodel.pn.Resource; +import dol.datamodel.pn.SourceCode; +import dol.datamodel.pn.Variable; + +/** + * + */ +public class Xml2PN { + + /** + * Constructor. + */ + public Xml2PN() { + } + + /** + * Process the start of the process network tag in the XML. + * + * @param attributes attributes of the tag + * @return a ProcessNetwork object + */ + public ProcessNetwork processPN(Attributes attributes) { + String name = (String) attributes.getValue("name"); + ProcessNetwork p = new ProcessNetwork(name); + return p; + } + + /** + * Process the end of the processnetwork tag in the XML. + * + * @param stack + */ + public void processPN(Stack stack) { + } + + /** + * Process the start of a process tag in the XML. + * + * @param attributes The attributes of the tag. + * @return a process object. + */ + public Process processProcess(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String basename = (String) attributes.getValue("basename"); + String range = (String) attributes.getValue("range"); + Process process = new Process(name); + if (basename != null) process.setBasename(basename); + if (range != null) process.setRange(range); + return process; + } + + /** + * Process the end of a process tag in the XML. + * + * @param stack + */ + public void processProcess(Stack stack) { + Process p = (Process) stack.pop(); + ProcessNetwork r = (ProcessNetwork)stack.peek(); + r.getProcessList().add(p); + } + + /** + * Process the start of a origin tag in the XML. + * + * @param attributes attributes of the tag + * @return a Resource object + */ + public Resource processOrigin(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String basename = (String) attributes.getValue("basename"); + Resource resource = new Resource(name); + if (basename != null) resource.setBasename(basename); + return resource; + } + + /** + * Process the end of a origin tag in the XML. + * + * @param stack + */ + public void processOrigin(Stack stack) { + Port port = (Port)stack.pop(); + Resource resource = (Resource)stack.pop(); + Connection connection = (Connection)stack.peek(); + + if(port != null) { + if (!port.isOutPort()) { + System.out.println("Error: Connection " + + connection.getName() + + " must be defined in the direction of the " + + " data flow!"); + System.out.println("Exit."); + System.exit(-1); + } + connection.setOriginPort(port); + } else { + undefinedReference("Connection", connection.getName(), + "element", resource.getName()); + } + + Process process = ((ProcessNetwork)stack.elementAt(0)). + getProcess(resource.getName()); + Channel channel = ((ProcessNetwork)stack.elementAt(0)). + getChannel(resource.getName()); + + if (process != null) { + connection.setOrigin(process); + } + else if (channel != null) { + connection.setOrigin(channel); + } + else { + undefinedReference("Connection", connection.getName(), + "element", resource.getName()); + } + } + + /** + * Process the start of a target tag in the XML. + * + * @param attributes attributes of the tag + * @return a Resource object + */ + public Resource processTarget(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String basename = (String) attributes.getValue("basename"); + Resource resource = new Resource(name); + if (basename != null) resource.setBasename(basename); + return resource; + } + + /** + * Process the end of a target tag in the XML. + * + * @param stack + */ + public void processTarget(Stack stack) { + Port port = (Port)stack.pop(); + Resource resource = (Resource)stack.pop(); + Connection connection = (Connection)stack.peek(); + + if(port != null) { + if (!port.isInPort()) { + System.out.println("Error: Connection " + + connection.getName() + + " must be defined in the direction of the " + + " data flow!"); + System.out.println("Exit."); + System.exit(-1); + } + connection.setTargetPort(port); + } else { + undefinedReference("Connection", connection.getName(), + "element", resource.getName()); + } + + Process process = ((ProcessNetwork)stack.elementAt(0)). + getProcess(resource.getName()); + Channel channel = ((ProcessNetwork)stack.elementAt(0)). + getChannel(resource.getName()); + + if (process != null) { + connection.setTarget(process); + } + else if (channel != null) { + connection.setTarget(channel); + } + else { + undefinedReference("Connection", connection.getName(), + "element", resource.getName()); + } + } + + /** + * Process the start of a connection tag in the XML. + * + * @param attributes attributes of the tag + * @return a Connection object + */ + public Connection processConnection(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String basename = (String) attributes.getValue("basename"); + Connection connection = new Connection(name); + if (basename != null) connection.setBasename(basename); + return connection; + } + + /** + * Process the end of a connection tag in the XML. + * + * @param stack + */ + public void processConnection(Stack stack) { + Connection connection = (Connection) stack.pop(); + ProcessNetwork pn = (ProcessNetwork)stack.peek(); + pn.getConnectionList().add(connection); + } + + /** + * Process the start of a port tag in the XML. + * + * @param attributes attributes of the tag + * @return a Port object + */ + public Port processPort(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String type = (String) attributes.getValue("type"); + String basename = (String) attributes.getValue("basename"); + String range = (String) attributes.getValue("range"); + + Port port = null; + + if (type != null) { + if( type.equals("input") ) { + port = new Port(name, Port.INPORT); + } else if( type.equals("output") ) { + port = new Port(name, Port.OUTPORT); + } + } else { + port = new Port(name); + } + + if (basename != null) + port.setBasename(basename); + else + port.setBasename(name); + + if (range != null) port.setRange(range); + + return port; + } + + /** + * Process the end of a port tag in the XML. + * + * @param stack + */ + public void processPort(Stack stack) { + Port port = (Port)stack.pop(); + Resource resource = (Resource)stack.peek(); + + //check if this is a port or just a port reference + if (!(stack.elementAt(stack.size() - 2) instanceof Connection)) { + port.setResource(resource); + resource.getPortList().add(port); + } + //port reference + else { + Process process = ((ProcessNetwork)stack.elementAt(0)). + getProcess(resource.getName()); + Channel channel = ((ProcessNetwork)stack.elementAt(0)). + getChannel(resource.getName()); + + Resource refResource = null; + + if (process != null) { + refResource = process; + } + else if (channel != null) { + refResource = channel; + } + else { + undefinedReference("Connection", + ((Connection)stack.peek()).getName(), + "element", resource.getName()); + } + + Port refPort = refResource.getPort(port.getName()); + + if (refPort == null) { + undefinedReference("Connection", + ((Connection)stack.peek()).getName(), + "port", port.getName()); + } + + // Put real port back on the stack. Will be popped in + // processOrigin and processTarget respectively + stack.push(refPort); + + } + } + + /** + * Process the start of a channel tag in the XML. + * + * @param attributes attributes of the tag + * @return a Channel object + */ + public Channel processChannel(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String size = (String) attributes.getValue("size"); + String type = (String) attributes.getValue("type"); + String tSize = (String) attributes.getValue("tokensize"); + Channel channel = new Channel(name); + channel.setSize(new Integer(size)); + channel.setTokenSize(new Integer(tSize)); + channel.setType(type); + return channel; + } + + /** + * Process the end of a channel tag in the XML. + * + * @param stack + */ + public void processChannel(Stack stack) { + Channel channel = (Channel) stack.pop(); + ProcessNetwork r = (ProcessNetwork)stack.peek(); + r.getChannelList().add(channel); + } + + /** + * Process the end of a configuration tag in the XML. + * + * @param stack + */ + public void processConfiguration(Stack stack) { + Configuration configuration = (Configuration) stack.pop(); + Resource r = (Resource) stack.peek(); + configuration.setParentResource(r); + r.getCfgList().add(configuration); + } + + /** + * Process the start of a configuration tag in the XML. + * + * @param attributes attributes of the tag + * @return a Configuration object + */ + public Configuration processConfiguration(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String value = (String) attributes.getValue("value"); + Configuration code = new Configuration(name); + code.setName(name); + code.setValue(value); + return code; + } + + /** + * Process the end of a profiling tag in the XML. + * + * @param stack + */ + public void processProfiling(Stack stack) { + ProfilingConfiguration configuration = ( ProfilingConfiguration) stack.pop(); + Resource r = (Resource) stack.peek(); + configuration.setParentResource(r); + r.getProfilingList().add(configuration); + } + + /** + * Process the start of a profiling tag in the XML. + * + * @param attributes attributes of the tag + * @return a profiling object + */ + public Configuration processProfiling(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String value = (String) attributes.getValue("value"); + ProfilingConfiguration code = new ProfilingConfiguration(name); + code.setName(name); + code.setValue(value); + return code; + } + + /** + * Process the start of a channel source tag in the XML. + * + * @param attributes attributes of the tag + * @return a SourceCode object + */ + public SourceCode processSource(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String type = (String) attributes.getValue("type"); + String l = (String) attributes.getValue("location"); + SourceCode code = new SourceCode(name); + code.setType(type); + code.setLocality(l); + return code; + } + + /** + * Process the end of a source tag in the XML. + * + * @param stack + */ + public void processSource(Stack stack) { + SourceCode source = (SourceCode) stack.pop(); + Process process = (Process) stack.peek(); + source.setProcess(process); + process.getSrcList().add(source); + } + + /** + * Process the start of a variable tag in the XML. + * + * @param attributes attributes of the tag + * @return a Variable object + */ + public Variable processVariable(Attributes attributes) { + String name = (String) attributes.getValue("name"); + String value = (String) attributes.getValue("value"); + Variable variable = null; + variable = new Variable(name); + variable.setValue(Integer.parseInt(value)); + return variable; + } + + /** + * Process the end of a variable tag in the XML. + * + * @param stack + */ + public void processVariable(Stack stack) { + Variable variable = (Variable) stack.pop(); + ProcessNetwork pn = (ProcessNetwork)stack.peek(); + variable.setParentResource(pn); + pn.getVarList().add(variable); + } + + /** + * Write an error message and terminate program in case an + * processnetwork element is referenced which does not exist. + * + * @param elementType type of processnetwork element in which the error + * occurred + * @param elementName name of processnetwork element in which the error + * occurred + * @param referenceType type of referenced processnetwork element + * @param referenceName name of referenced processnetwork element + */ + protected void undefinedReference(String elementType, + String elementName, + String referenceType, + String referenceName) { + System.out.println("Error: " + elementType + " " + elementName + + " references " + referenceType + " " + referenceName + + " that has not been declared."); + System.out.println("Exit."); + System.exit(-1); + } +} diff --git a/dol/src/dol/parser/xml/pnschema/package.html b/dol/src/dol/parser/xml/pnschema/package.html new file mode 100644 index 0000000..97ca537 --- /dev/null +++ b/dol/src/dol/parser/xml/pnschema/package.html @@ -0,0 +1,21 @@ + + + + + + +Process network XML schema parser. +This package parses the process network XML and stores the result in internal data model for the process network. + +

Package Specification

+ + + +

Related Documentation

+ + + + + + + diff --git a/dol/src/dol/util/ApplicationGenerator.java b/dol/src/dol/util/ApplicationGenerator.java new file mode 100644 index 0000000..a193614 --- /dev/null +++ b/dol/src/dol/util/ApplicationGenerator.java @@ -0,0 +1,914 @@ +/* $Id: ApplicationGenerator.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.util; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.util.Random; +import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import dol.datamodel.architecture.Processor; +import dol.datamodel.architecture.ReadPath; +import dol.datamodel.architecture.WritePath; +import dol.datamodel.mapping.CommunicationBinding; +import dol.datamodel.mapping.ComputationBinding; +import dol.datamodel.mapping.Mapping; +import dol.datamodel.mapping.Schedule; +import dol.datamodel.mapping.ScheduleEntry; +import dol.datamodel.mapping.SchedulingPolicy; +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Connection; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.ProfilingConfiguration; +import dol.datamodel.pn.SourceCode; +import dol.visitor.xml.MapXmlVisitor; +import dol.visitor.xml.PNXmlVisitor; + +/** + * + */ +public class ApplicationGenerator { + /* + protected String _processes[] = + {"producer", "consumer"}; + + protected int _computation[] = + {1000, 1000}; + + protected int _communication[][] = + {{0, 4}, {-4, 0}}; + + protected String _binding[] = + {"tile_0.arm", "tile_0.arm"}; + + protected int _iterations = 1000; + */ + + /* + protected String _processes[] = + {"producer", "forwarder", "consumer"}; + + protected int _computation[] = + {1000, 1000, 1000}; + + protected int _communication[][] = + {{ 0, 4, 0}, + {-4, 0, 4}, + { 0, -4, 0}}; + + protected String _binding[] = + {"tile_0.arm", "tile_0.arm", "tile_0.arm"}; + + protected int _iterations = 10; + */ + + /* + protected String _processes[] = + {"stageA", "stageB", "stageC", "stageD", + "stageE", "stageF", "stageG", "stageH", + "stageI", "stageJ", "stageK", "stageL", + "stageM", "stageN", "stageO", "stageP"}; + + protected int _computation[] = + {1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16}; + + protected int _communication[][] = + {{ 0, 1024, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {-1024, 0, 1024, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, -1024, 0, 1024, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, -1024, 0, 1024, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, -1024, 0, 1024, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, -1024, 0, 1024, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, -1024, 0, 1024, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, -1024, 0, 1024, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, -1024, 0, 1024, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, -1024, 0, 1024, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, -1024, 0, 1024, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1024, 0, 1024, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1024, 0, 1024, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1024, 0, 1024, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1024, 0, 1024}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1024, 0}}; + + + //protected String _binding[] = + // {"tile_0.arm", "tile_0.arm", "tile_1.arm", "tile_1.arm", + // "tile_2.arm", "tile_2.arm", "tile_3.arm", "tile_3.arm", + // "tile_4.arm", "tile_4.arm", "tile_5.arm", "tile_5.arm", + // "tile_6.arm", "tile_6.arm", "tile_7.arm", "tile_7.arm"}; + + //protected String _binding[] = + // {"tile_0.arm", "tile_1.arm", "tile_2.arm", "tile_3.arm", + // "tile_4.arm", "tile_5.arm", "tile_6.arm", "tile_7.arm", + // "tile_0.arm", "tile_1.arm", "tile_2.arm", "tile_3.arm", + // "tile_4.arm", "tile_5.arm", "tile_6.arm", "tile_7.arm"}; + + protected String _binding[] = + {"tile_0.arm", "tile_1.arm", "tile_2.arm", "tile_3.arm", + "tile_4.arm", "tile_5.arm", "tile_6.arm", "tile_7.arm", + "tile_7.arm", "tile_6.arm", "tile_5.arm", "tile_4.arm", + "tile_3.arm", "tile_2.arm", "tile_1.arm", "tile_0.arm"}; + + protected int _iterations = 10; + */ + + protected String _processes[] = + {"splitAA", "splitBA", "splitBB", + "pipeAA", "pipeBA", "pipeCA", "pipeDA", + "pipeEA", "pipeFA", "pipeAB", "pipeBB", + "pipeCB", "pipeDB", "pipeEB", "pipeFB", + "mergeBA", "mergeBB", "mergeAA"}; + + protected int _armComputation[] = + {1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; + protected int _magicComputation[] = + {1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; + + + protected int _communication[][] = + {{ 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { -4, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { -4, 0, 0, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, -4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, -4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0}, + { 0, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0}, + { 0, 0, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0}, + { 0, 0, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0}, + { 0, 0, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0}, + { 0, 0, 0, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0}, + { 0, 0, 0, 0, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0}, + { 0, 0, 0, 0, 0, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0}, + { 0, 0, 0, 0, 0, 0, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0}, + { 0, 0, 0, 0, 0, 0, 0, -4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, -4, 0, 0, 0, 0, 0, 0, 0, 4, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, -4, -4, 0, 0, 0, 0, 0, 4}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, -4, -4, 0, 0, 4}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, -4, 0}}; + + + //working + protected String _binding[] = + {"tile_0.arm", "tile_1.arm", "tile_4.arm", + "tile_1.arm", "tile_2.arm", "tile_3.arm", "tile_4.arm", + "tile_5.arm", "tile_6.arm", "tile_1.arm", "tile_2.arm", + "tile_3.arm", "tile_4.arm", "tile_5.arm", "tile_6.arm", + "tile_3.arm", "tile_7.arm", "tile_0.arm"}; + + /* + protected String _binding[] = + {"tile_0.arm", "tile_1.arm", "tile_3.arm", + "tile_1.arm", "tile_1.arm", "tile_2.arm", "tile_2.arm", + "tile_3.arm", "tile_3.arm", "tile_4.arm", "tile_4.arm", + "tile_5.arm", "tile_5.arm", "tile_6.arm", "tile_6.arm", + "tile_7.arm", "tile_7.arm", "tile_0.arm"}; + + protected String _binding[] = + {"tile_0.arm", "tile_1.arm", "tile_7.arm", + "tile_1.arm", "tile_1.arm", "tile_2.arm", "tile_2.arm", + "tile_3.arm", "tile_3.arm", "tile_4.arm", "tile_4.arm", + "tile_5.arm", "tile_5.arm", "tile_6.arm", "tile_6.arm", + "tile_7.arm", "tile_3.arm", "tile_0.arm"}; + */ + + //not working + /* + protected String _binding[] = + {"tile_0.arm", "tile_1.arm", "tile_2.arm", "tile_3.arm", + "tile_4.arm", "tile_5.arm", "tile_6.arm", "tile_7.arm", + "tile_7.arm", "tile_6.arm", "tile_5.arm", "tile_4.arm", + "tile_3.arm", "tile_2.arm", "tile_1.arm", "tile_0.arm", + "tile_0.arm", "tile_0.arm"}; + */ + + protected int _iterations = 10; + + public String getStringEncoding(int i, int total) { + if (total > 26 * 26) { + System.out.println("\"total\" needs to be less than " + + 26 * 26 + "."); + return ""; + } else if (total <= 26) { + return Character.toString((char)('A' + (i % 26))); + } + return Character.toString((char)('A' + (i / 26))) + + Character.toString((char)('A' + (i % 26))); + } + + /** + * + * @param stages + * @param communication + */ + public void generateIndependentTasks(int numberOfTasks) { + _processes = new String[numberOfTasks]; + _armComputation = new int[numberOfTasks]; + _magicComputation = new int[numberOfTasks]; + _communication = new int[numberOfTasks][numberOfTasks]; + _binding = new String[numberOfTasks]; + _iterations = 1000; + + for (int i = 0; i < numberOfTasks; i++) { + _processes[i] = ((i < numberOfTasks / 2) ? "armProcess" + : "magicProcess") + + getStringEncoding(i, numberOfTasks); + System.out.println(_processes[i]); + _armComputation[i] = + (i < numberOfTasks / 2) ? 100000000 : 200000000; + _magicComputation[i] = + (i < numberOfTasks / 2) ? 200000000 : 100000000; + _binding[i] = (i < numberOfTasks / 2) ? "tile_0.arm" + : "tile_0.magic"; + } + + //no communication + for (int i = 0; i < numberOfTasks; i++) { + for (int j = 0; j < numberOfTasks; j++) { + _communication[i][j] = 0; + } + } + } + + /** + * + * @param pipelines + * @param stages + * @param communication + */ + public void generateIndpendentPipelines(int pipelines, int stages, int communication) { + Random random = new Random(); + _processes = new String[stages * pipelines]; + _armComputation = new int[stages * pipelines]; + _magicComputation = new int[stages * pipelines]; + _communication = new int[stages * pipelines][stages * pipelines]; + _binding = new String[stages * pipelines]; + _iterations = 1000; + + for (int i = 0; i < pipelines; i++) { + for (int j = 0; j < stages; j++) { + _processes[i * stages + j] = + ((i < pipelines / 2) ? "arm" : "magic") + + "stage" + + getStringEncoding(i, pipelines) + "x" + + getStringEncoding(j, stages); + System.out.println(_processes[i * stages + j]); + _armComputation[i * stages + j] = + 0 * random.nextInt(10000000) + + ((i < pipelines / 2) ? 100000000 : 200000000); + _magicComputation[i * stages + j] = + 0 * random.nextInt(10000000) + + ((i < pipelines / 2) ? 200000000 : 100000000); + _binding[i * stages + j] = "tile_0.arm"; + } + } + + for (int i = 0; i < pipelines; i++) { + for (int j = 0; j < stages; j++) { + for (int k = 0; k < pipelines; k++) { + for (int l = 0; l < stages; l++) { + _communication[i * stages + j][k * stages + l] = 0; + if (i == k && l == j + 1) { + _communication[i * stages + j][k * stages + l] = communication; + } else if (i == k && j == l + 1) { + _communication[i * stages + j][k * stages + l] = -communication; + } + } + } + } + } + } + + + /** + * + * @param pipelines + * @param stages + * @param communication + */ + public void generateIndpendentPipelines2(int pipelines, int stages, int communication) { + Random random = new Random(); + _processes = new String[stages * pipelines]; + _armComputation = new int[stages * pipelines]; + _magicComputation = new int[stages * pipelines]; + _communication = new int[stages * pipelines][stages * pipelines]; + _binding = new String[stages * pipelines]; + _iterations = 1000; + + for (int i = 0; i < pipelines; i++) { + for (int j = 0; j < stages; j++) { + _processes[i * stages + j] = + ((j < stages / 2) ? "arm" : "magic") + + "stage" + + getStringEncoding(i, pipelines) + "x" + + getStringEncoding(j, stages); + System.out.println(_processes[i * stages + j]); + _armComputation[i * stages + j] = + 0 * random.nextInt(10000000) + + ((j < stages / 2) ? 100000000 : 200000000); + _magicComputation[i * stages + j] = + 0 * random.nextInt(10000000) + + ((j < stages / 2) ? 200000000 : 100000000); + _binding[i * stages + j] = "tile_0.arm"; + } + } + + for (int i = 0; i < pipelines; i++) { + for (int j = 0; j < stages; j++) { + for (int k = 0; k < pipelines; k++) { + for (int l = 0; l < stages; l++) { + _communication[i * stages + j][k * stages + l] = 0; + if (i == k && l == j + 1) { + _communication[i * stages + j][k * stages + l] = communication; + } else if (i == k && j == l + 1) { + _communication[i * stages + j][k * stages + l] = -communication; + } + } + } + } + } + } + + + /** + * + * @param stages + * @param communication + */ + public void generatePipeline(int stages, int communication) { + _processes = new String[stages]; + _armComputation = new int[stages]; + _magicComputation = new int[stages]; + _communication = new int[stages][stages]; + _binding = new String[stages]; + //_iterations = 1000; + _iterations = 1000; + + for (int i = 0; i < stages; i++) { + _processes[i] = ((i % 8 < 4) ? "arm" : "magic") + + "stage" + getStringEncoding(i, stages); + System.out.println(_processes[i]); + _armComputation[i] = + (i % 8 < 4) ? 100 : 200; + _magicComputation[i] = + (i % 8 < 4) ? 200 : 100; + _binding[i] = "tile_0.arm"; + } + + for (int i = 0; i < stages; i++) { + for (int j = 0; j < stages; j++) { + _communication[i][j] = 0; + if (j == i + 1) { + _communication[i][j] = communication; + } else if (i == j + 1) { + _communication[i][j] = -communication; + } + } + } + } + + + /** + * + * @param pn + */ + public void generateProcessNetwork(ProcessNetwork pn) { + System.out.print("Generate process network. "); + int numberOfProcesses = 0; + int numberOfChannels = 0; + + for (int j = 0; j < _processes.length; j++) { + String processName = _processes[j]; + Process p = new Process(processName); + SourceCode srcCode = new SourceCode(processName); + srcCode.setLocality(processName + ".c"); + srcCode.setType("c"); + p.getSrcList().add(srcCode); + pn.getProcessList().add(p); + numberOfProcesses++; + for (int i = 0; i < 8; i++) { + ProfilingConfiguration c = new ProfilingConfiguration( + "BCED tile_" + i + ".arm"); + c.setValue(Integer.toString(_armComputation[j])); + p.getProfilingList().add(c); + c = new ProfilingConfiguration( + "BCED tile_" + i + ".magic"); + c.setValue(Integer.toString(_magicComputation[j])); + p.getProfilingList().add(c); + } + } + + //check whether communication matrix is symmetric + if (_communication[0].length != numberOfProcesses) { + System.out.println(); + System.out.println("Error: Size of communication matrix (" + + _communication[0].length + " columns) must match " + + "number of processes (" + numberOfProcesses + ")."); + System.exit(-1); + } + for (int row = 0; row < numberOfProcesses; row++) { + for (int col = 0; col < numberOfProcesses; col++) { + if (row == col && _communication[row][col] != 0) { + System.out.println(); + System.out.println("Error: No self-channels allowed. " + + "Problem for process " + row + " (" + + _processes[row] + ")."); + System.exit(-1); + } + if (_communication[row][col] != + -_communication[col][row]) { + System.out.println(); + System.out.println("Error: Communication matrix " + + "needs to be symmetric. Mismatch for row " + + row + " column " + col + "."); + System.exit(-1); + } + } + } + + for (int row = 0; row < numberOfProcesses; row++) { + for (int col = row; col < numberOfProcesses; col++) { + if (_communication[row][col] == 0) { + continue; + } + int src = row; + int dst = col; + + if (_communication[row][col] < 0) { + src = col; + dst = row; + } + + Channel c = new Channel("channel" + _processes[src] + + _processes[dst]); + c.setSize(Math.abs(2 * _communication[src][dst])); + c.setType("fifo"); + ProfilingConfiguration p = new ProfilingConfiguration( + "TotalReadData"); + p.setValue(Integer.toString(_communication[row][col])); + c.getProfilingList().add(p); + pn.getChannelList().add(c); + numberOfChannels++; + + Port channelPort0 = new Port("0", Port.INPORT); + Port channelPort1 = new Port("1", Port.OUTPORT); + c.getPortList().add(channelPort0); + c.getPortList().add(channelPort1); + + Connection c1 = new Connection( + "c1" + _processes[src] + _processes[dst]); + Connection c2 = new Connection( + "c2" + _processes[src] + _processes[dst]); + pn.getConnectionList().add(c1); + pn.getConnectionList().add(c2); + + Port p0 = new Port(Integer.toString(pn.getProcess( + _processes[src]).getPortList().size()), + Port.OUTPORT); + Port p1 = new Port(Integer.toString(pn.getProcess( + _processes[dst]).getPortList().size()), + Port.INPORT); + pn.getProcess(_processes[src]).getPortList().add(p0); + pn.getProcess(_processes[dst]).getPortList().add(p1); + + c1.setOriginPort(p0); + c1.setTargetPort(channelPort0); + c1.setOrigin(pn.getProcess(_processes[src])); + c1.setTarget(c); + p0.setPeerResource(c); + p0.setPeerPort(channelPort0); + channelPort0.setPeerResource(pn.getProcess( + _processes[src])); + channelPort0.setPeerPort(p0); + + c2.setOriginPort(channelPort1); + c2.setTargetPort(p1); + c2.setOrigin(c); + c2.setTarget(pn.getProcess(_processes[dst])); + channelPort1.setPeerResource(pn.getProcess( + _processes[dst])); + channelPort1.setPeerPort(p1); + p1.setPeerResource(c); + p1.setPeerPort(channelPort1); + + c.setOrigin(pn.getProcess(_processes[src])); + c.setTarget(pn.getProcess(_processes[dst])); + } + } + + System.out.println("Finished."); + } + + /** + * + * @param pn + */ + public void generateProcessNetworkXml(ProcessNetwork pn, + String filename) { + System.out.print("Generate process network XML. "); + StringBuffer buffer = new StringBuffer(); + pn.accept(new PNXmlVisitor(buffer)); + try { + java.io.BufferedWriter writer = + new java.io.BufferedWriter( + new java.io.FileWriter(filename)); + writer.write(buffer.toString()); + writer.close(); + } catch (java.io.IOException e) { + System.out.println(); + System.out.println("Error: Could not write XML file."); + System.exit(-1); + } + System.out.println("Finished."); + } + + /** + * + * @param pn + * @param path + */ + public void generateCode(ProcessNetwork pn, String path) { + System.out.print("Generate source code of processes. "); + + String newline = System.getProperty("line.separator"); + int maxProcessNameLength = 0; + for (String processName : _processes) { + maxProcessNameLength = Math.max(maxProcessNameLength, + processName.length()); + } + + String global = ""; + global += "#ifndef GLOBAL_H" + newline; + global += "#define GLOBAL_H" + newline; + global += newline; + + global += "#define ITERATIONS " + _iterations + newline; + global += newline; + + for (int i = 0; i < _processes.length; i++) { + global += "#define LOOPS_ARM_" + _processes[i].toUpperCase() + + " " + _armComputation[i] + newline; + global += "#define LOOPS_MAGIC_" + _processes[i].toUpperCase() + + " " + _magicComputation[i] + newline; + } + + for (int row = 0; row < _communication[0].length; row++) { + for (int col = row; col < _communication[0].length; col++) { + if (_communication[row][col] == 0) { + continue; + } + int src = row; + int dst = col; + + if (_communication[row][col] < 0) { + src = col; + dst = row; + } + + global += "#define TOKEN_SIZE_" + + _processes[src].toUpperCase() + "_" + + _processes[dst].toUpperCase() + " " + + _communication[src][dst] + newline; + } + } + global += newline; + global += "#endif" + newline; + + try { + BufferedWriter out = new BufferedWriter( + new FileWriter(path + "global.h")); + out.write(global); + out.close(); + } catch (Exception e) { + System.out.println(); + System.out.println("Error: While writing global.h file."); + System.exit(-1); + } + + + for (Process p : pn.getProcessList()) { + String state = p.getName().substring(0, 1).toUpperCase() + + p.getName().substring(1) + "_State"; + + String h = ""; + h += "#ifndef " + p.getName().toUpperCase() + "_H" + newline; + h += "#define " + p.getName().toUpperCase() + "_H" + newline; + h += newline; + h += "#include " + newline; + h += newline; + for (Port port : p.getPortList()) { + h += "#define PORT_" + p.getName().toUpperCase() + "_" + + (port.isInPort() ? "IN_" : "OUT_" ) + + port.getName() + " " + port.getName() + newline; + } + h += newline; + h += "typedef struct {" + newline; + h += " int iterations;" + newline; + h += "} " + state + ";" + newline; + h += newline; + h += "void " + p.getName() + "_init(DOLProcess *p);" + + newline; + h += "int " + p.getName() + "_fire(DOLProcess *p);" + newline; + h += newline; + h += "#endif" + newline; + + String c = ""; + String printPrefix = String.format(" printf(\"[%-" + + maxProcessNameLength + "s] ", p.getName()); + c += "#include " + newline; + c += newline; + c += "#include \"" + p.getName() + ".h\"" + newline; + c += "#include \"global.h\"" + newline; + c += newline; + c += "void " + p.getName() + "_init(DOLProcess *p) {" + + newline; + c += " " + state + " *state = (" + state + "*)p->local;" + + newline; + c += " state->iterations = 0;" + newline; + c += "}" + newline; + c += newline; + c += "int " + p.getName() + "_fire(DOLProcess *p) {" + + newline; + + int processIndex = getProcessIndex(p.getName()); + int maxBuffer = 0; + for (int i = 0; i < _communication[processIndex].length; i++) { + maxBuffer = Math.max(maxBuffer, + Math.abs(_communication[processIndex][i])); + } + c += " int buffer[" + ((maxBuffer + (4 - 1)) / 4) + "];" + newline; + c += " int i;" + newline; + c += " " + state + " *state = (" + state + "*)p->local;"; + c += newline + newline; + + for (Port port : p.getPortList()) { + if (port.isInPort()) { + int originIndex = getProcessIndex( + ((Channel)port.getPeerResource()).getOrigin() + .getName()); + String tokenSize = "TOKEN_SIZE_" + + _processes[originIndex].toUpperCase() + "_" + + _processes[processIndex].toUpperCase(); + c += printPrefix + "read %d bytes from " + + _processes[originIndex] + ".\\n\", " + tokenSize + + ");" + newline; + c += " DOL_read((void*)" + + "PORT_" + p.getName().toUpperCase() + "_IN_" + + port.getName() + ", buffer, " + tokenSize + + ", p);" + newline; + } + } + c += newline; + //c += " printf(\"[%-20s ] iteration %d/n\", \"" + // + p.getName() + "\", state->iterations);" + newline; + c += printPrefix + "iteration %d.\\n\" , " + + "state->iterations);" + newline; + c += newline; + c += "#ifdef __arm__" + newline; + c += " for (i = 0; i < LOOPS_ARM_" + p.getName().toUpperCase() + + "; i++) { ; }" + newline; + c += "#else" + newline; + c += " for (i = 0; i < LOOPS_MAGIC_" + p.getName().toUpperCase() + + "; i++) { ; }" + newline; + c += "#endif" + newline; + for (Port port : p.getPortList()) { + if (port.isOutPort()) { + int targetIndex = getProcessIndex( + ((Channel)port.getPeerResource()).getTarget() + .getName()); + String tokenSize = "TOKEN_SIZE_" + + _processes[processIndex].toUpperCase() + "_" + + _processes[targetIndex].toUpperCase(); + c += printPrefix + "write %d bytes to " + + _processes[targetIndex] + ".\\n\", " + tokenSize + + ");" + newline; + c += " DOL_write((void*)" + + "PORT_" + p.getName().toUpperCase() + "_OUT_" + + port.getName() + ", buffer, "+ tokenSize + + ", p);" + newline; + } + } + c += newline; + c += " state->iterations++;" + newline; + c += " if (state->iterations >= ITERATIONS) {" + + newline; + c += " DOL_detach(p);" + newline; + c += " return -1;" + newline; + c += " }" + newline; + c += newline; + c += " return 0;" + newline; + c += "}" + newline; + + try { + BufferedWriter out = new BufferedWriter( + new FileWriter(path + p.getName() + ".h")); + out.write(h); + out.close(); + out = new BufferedWriter( + new FileWriter(path + p.getName() + ".c")); + out.write(c); + out.close(); + } catch (Exception e) { + System.out.println(); + System.out.println("Error: While writing source files."); + System.exit(-1); + } + } + System.out.println("Finished."); + } + + + /** + * + * @param map + * @param pn + */ + public void generateMapping(ProcessNetwork pn, Mapping map) { + System.out.print("Generate mapping. "); + map.setPN(pn); + + //binding of processes + Vector processors = new Vector(); + for (int i = 0; i < _binding.length; i++) { + String processName = _processes[i]; + String processorName = _binding[i]; + Processor processor = null; + + boolean processorExists = false; + for (Processor proc : processors) { + if (proc.getName().equals(processorName)) { + processor = proc; + processorExists = true; + break; + } + } + + if (!processorExists) { + processor = new Processor(processorName); + processors.add(processor); + } + + ComputationBinding compBinding = new ComputationBinding( + processName + "binding"); + compBinding.setProcess(pn.getProcess(processName)); + compBinding.setProcessor(processor); + processor.getProcessList().add(pn.getProcess(processName)); + map.getCompBindList().add(compBinding); + } + + //schedules + for (Processor p : processors) { + Schedule s = new Schedule(p.getName() + "schedule"); + s.setSchedPolicy(SchedulingPolicy.FIFO); + s.setResource(p); + for (Process process : p.getProcessList()) { + ScheduleEntry entry = new ScheduleEntry( + process.getName()); + entry.setConsumer(process); + s.getEntryList().add(entry); + } + map.getScheduleList().add(s); + } + + //binding of channels + for (Channel c : pn.getChannelList()) { + String originProcess = c.getOrigin().getName(); + String targetProcess = c.getTarget().getName(); + + String originBinding = _binding[getProcessIndex( + originProcess)]; + String targetBinding = _binding[getProcessIndex( + targetProcess)]; + + Pattern pattern0 = Pattern.compile( + "tile_(\\d)\\.(arm)|tile_(\\d)\\.(magic)"); + Matcher matcher0 = pattern0.matcher(originBinding); + Pattern pattern1 = Pattern.compile( + "tile_(\\d)\\.(arm)|tile_(\\d)\\.(magic)"); + Matcher matcher1 = pattern1.matcher(targetBinding); + + if (!matcher0.matches() || !matcher1.matches()) { + System.out.println("binding needs to comply to the" + + " following regular expression: " + + "tile_(\\d)\\.(arm)|tile_(\\d)\\.(magic)"); + System.exit(-1); + } + + int srcIndex = Integer.valueOf(matcher0.group(1)); + int dstIndex = Integer.valueOf(matcher1.group(1)); + String srcProcessor = matcher0.group(2); + String dstProcessor = matcher1.group(2); + + String writePath = ""; + String readPath = ""; + + if (srcIndex == dstIndex) { + if (srcProcessor.equals("arm")) { + writePath = "tile_" + srcIndex + ".rdmtodxm"; + } else { + writePath = "tile_" + srcIndex + ".ddmtodxm"; + } + } else { + if (srcProcessor.equals("arm")) { + writePath = "tile_" + srcIndex + ".rdmtodnp_" + + dstIndex; + } else { + writePath = "tile_" + srcIndex + ".ddmtodnp_" + + dstIndex; + } + } + + if (dstProcessor.equals("arm")) { + readPath = "tile_" + dstIndex + ".rdmfromdxm"; + } else { + readPath = "tile_" + dstIndex + ".ddmfromdxm"; + } + + CommunicationBinding commBinding = new CommunicationBinding( + c.getName() + "binding"); + commBinding.setChannel(c); + commBinding.setWritePath(new WritePath(writePath)); + commBinding.setReadPath(new ReadPath(readPath)); + map.getCommBindList().add(commBinding); + } + System.out.println("Finished."); + } + + /** + * + * @param processName + * @return + */ + protected int getProcessIndex(String processName) { + for (int i = 0; i < _processes.length; i++) { + if (_processes[i].equals(processName)) { + return i; + } + } + System.out.println("Error: Could not find process " + + processName + "."); + System.exit(-1); + return 0; + } + + /** + * + * @param map + */ + public void generateMappingXml(Mapping map, String filename) { + System.out.print("Generate mapping XML. "); + StringBuffer buffer = new StringBuffer(); + map.accept(new MapXmlVisitor(buffer)); + try { + java.io.BufferedWriter writer = + new java.io.BufferedWriter( + new java.io.FileWriter(filename)); + writer.write(buffer.toString()); + writer.close(); + } catch (java.io.IOException e) { + System.out.println("Could not write XML file."); + System.exit(-1); + } + System.out.println("Finished."); + } + + /** + * + * @param args + */ + public static void main(String args[]) { + /* + Pattern pattern = Pattern.compile("tile_(\\d)\\."); + Matcher matcher = pattern.matcher("tile_3."); + matcher.matches(); + System.out.println(matcher.group(1)); + */ + + String appName = "exampleAuto"; + String path = System.getProperty("user.dir") + "/" + appName + "/"; + File dir = new File(path); + dir.mkdirs(); + dir = new File(path + "src/"); + dir.mkdirs(); + + System.out.println("Generate application \"" + appName + "\"" + + " in directory \"" + path + "\"."); + ApplicationGenerator appGen = new ApplicationGenerator(); + //appGen.generateIndpendentPipelines2(16, 4, 10000000); + appGen.generatePipeline(64, 10); + //appGen.generateIndependentTasks(64); + ProcessNetwork pn = new ProcessNetwork(appName); + appGen.generateProcessNetwork(pn); + appGen.generateProcessNetworkXml(pn, path + appName + ".xml"); + appGen.generateCode(pn, path + "src/"); + Mapping map = new Mapping("mapping"); + appGen.generateMapping(pn, map); + appGen.generateMappingXml(map, path + "mapping.xml"); + System.out.println("Done."); + } +} \ No newline at end of file diff --git a/dol/src/dol/util/CheckXMLs.java b/dol/src/dol/util/CheckXMLs.java new file mode 100644 index 0000000..71ff63f --- /dev/null +++ b/dol/src/dol/util/CheckXMLs.java @@ -0,0 +1,45 @@ +/* $Id: CheckXMLs.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.util; + +import dol.datamodel.architecture.Architecture; +import dol.datamodel.mapping.Mapping; +import dol.datamodel.pn.ProcessNetwork; +import dol.parser.xml.archischema.ArchiXmlParser; +import dol.parser.xml.mapschema.MapXmlParser; +import dol.parser.xml.pnschema.PNXmlParser; + + +public class CheckXMLs { + public static void main(String args[]) { + + /* + String pnFile = "D:\\shapes\\pa\\tools\\exampleTest.xml"; + String archFile = "D:\\shapes\\pa\\tools\\rdt8.xml"; + String mapFile = "D:\\shapes\\pa\\tools\\mapping_2tiles.xml"; + */ + String pnFile = "processnetwork.xml"; + String archFile = "rdt8.xml"; + String mapFile = "mapping.xml"; + + if (args.length == 3) { + pnFile = args[0]; + archFile = args[1]; + mapFile = args[2]; + } + + System.out.println("Process network: " + pnFile); + System.out.println("Architecture: " + archFile); + System.out.println("Mapping: " + mapFile); + PNXmlParser parserPn = new PNXmlParser(); + ProcessNetwork pn = parserPn.doParse(pnFile); + + ArchiXmlParser parserArch = new ArchiXmlParser(); + Architecture arch = parserArch.doParse(archFile); + + MapXmlParser parserMap = new MapXmlParser(pn, arch); + Mapping mapping = parserMap.doParse(mapFile); + + mapping.getArch(); + System.out.println("XML files seem to be consistent."); + } +} \ No newline at end of file diff --git a/dol/src/dol/util/CodePrintStream.java b/dol/src/dol/util/CodePrintStream.java new file mode 100644 index 0000000..2a3a80b --- /dev/null +++ b/dol/src/dol/util/CodePrintStream.java @@ -0,0 +1,115 @@ +/* $Id: CodePrintStream.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.util; + +import java.io.OutputStream; +import java.io.PrintStream; + +/** + * Class to print code that is correctly indented. + */ +public class CodePrintStream extends PrintStream { + + /** + * + */ + public CodePrintStream(OutputStream out) { + super(out); + } + + /** + * + */ + public CodePrintStream(OutputStream out, boolean autoFlush) { + super(out, autoFlush); + } + + /** + * + */ + public void print(String x) { + super.print(x); + } + + /** + * + */ + public void println(String x) { + super.println(x); + } + + /** + * + */ + public void printPrefix(String x) { + super.print(_prefix + x); + } + + /** + * + */ + public void printPrefix() { + super.print(_prefix); + } + + /** + * + */ + public void printPrefixln(String x) { + super.println(_prefix + x); + } + + /** + * + */ + public void printPrefixln() { + super.println(); + } + + /** + * Print an opening curly brace and increase the indentation. + */ + public void printLeftBracket() { + printPrefix(); + println("{"); + prefixInc(); + } + + /** + * Decrease the indentation and print a closing curly brace. + */ + public void printRightBracket() { + prefixDec(); + printPrefixln("}"); + } + + /** + * Decrement the indentation. + */ + public void prefixDec() { + if( _prefix.length() >= _offset.length() ) { + _prefix = _prefix.substring(_offset.length()); + } + } + + /** + * Increment the indentation. + */ + public void prefixInc() { + _prefix += _offset; + } + + /** + * + */ + public static void main(String[] args) { + CodePrintStream ps = new CodePrintStream(System.out); + ps.println("aa"); + ps.print("bb"); + } + + private static String _offset = " "; + private String _prefix = ""; +} + + + diff --git a/dol/src/dol/util/CodePrintString.java b/dol/src/dol/util/CodePrintString.java new file mode 100644 index 0000000..b7ab780 --- /dev/null +++ b/dol/src/dol/util/CodePrintString.java @@ -0,0 +1,129 @@ +/* $Id: CodePrintString.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.util; + +/** + * Class to print code that is correctly indented. + */ +public class CodePrintString { + + /** + * Default constructor. + * + * @param stringBuffer string buffer where the result is stored + */ + public CodePrintString(StringBuffer stringBuffer) { + _code = stringBuffer; + } + + /** + * Print a line without indentation. + */ + public void print(String string) { + _code.append(string); + } + + /** + * Add a line break to the current line. Results in an empty + * line if the current line is empty. + */ + public void println() { + _code.append(System.getProperty("line.separator")); + } + + /** + * Print a line without indentation and add a line break. + * @param string string to print + */ + public void println(String string) { + _code.append(string + System.getProperty("line.separator")); + } + + /** + * Print spaces according to current level of indentation. + */ + public void printPrefix() { + _code.append(_prefix); + } + + /** + * Print a line at the current level of indentation. + * @param string string to print + */ + public void printPrefix(String string) { + _code.append(_prefix + string); + } + + /** + * Print a line at the current level of indentation and a line break. + * @param string string to print + */ + public void printPrefixln(String string) { + _code.append(_prefix + string + + System.getProperty("line.separator")); + } + + /** + * Print the opening tag for the given XML tag name and increase + * the indentation. + * @param tagName name of the XML tag + */ + public void printOpeningTag(String tagName) { + printPrefix(); + print("<" + tagName); + prefixInc(); + } + + /** + * Decrease the indentation and print the closing tag for the given + * XML tag name. + * @param tagName name of the XML tag + */ + public void printClosingTag(String tagName) { + prefixDec(); + printPrefixln(""); + } + + /** + * Decrement the indentation. + */ + public void prefixDec() { + if( _prefix.length() >= _offset.length() ) { + _prefix = _prefix.substring(_offset.length()); + } + } + + /** + * Increment the indentation. + */ + public void prefixInc() { + _prefix += _offset; + } + + /** + * Get the formatted output string. + * @return output string + */ + public String toString() { + return _code.toString(); + } + + /** + * Test the CodePrintString implementation. + */ + public static void main(String[] args) { + StringBuffer buffer = new StringBuffer(); + CodePrintString ps = new CodePrintString(buffer); + ps.printOpeningTag("tag"); + ps.println(">"); + ps.printPrefixln(""); + ps.printClosingTag("tag"); + System.out.println(ps.toString()); + } + + protected static String _offset = " "; + protected String _prefix = ""; + protected StringBuffer _code = null; +} + + + diff --git a/dol/src/dol/util/Copier.java b/dol/src/dol/util/Copier.java new file mode 100644 index 0000000..cb230d7 --- /dev/null +++ b/dol/src/dol/util/Copier.java @@ -0,0 +1,155 @@ +/* $Id: Copier.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.util; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.channels.FileChannel; +import java.util.jar.JarFile; + +/** + * Class to recursively copy a directory. + */ +public class Copier { + + String _destination; //target directory + + /** + * Copy a file. + * + * @param from source file + * @param to destination file + */ + public void copyFile(File from, File to) + throws IOException { + + FileChannel srcChannel = new FileInputStream(from).getChannel(); + FileChannel dstChannel = new FileOutputStream(to).getChannel(); + try { + dstChannel.transferFrom(srcChannel, 0, srcChannel.size()); + srcChannel.close(); + dstChannel.close(); + } + finally { + if (srcChannel != null) + srcChannel.close(); + + if (dstChannel != null) + dstChannel.close(); + } + } + + /** + * Method which defines what is done for each file found in the + * directory tree: It is copied to the corresponding target directory. + * + * @param filename file to process + * @param directory the subdirectory currently processed + */ + protected void processFile(String filename, String directory) + throws IOException { + File from = new File(filename); + File to = new File(_destination + directory + from.getName()); + copyFile(from, to); + //System.out.println("Copied " + from.getPath() + " to " + // + to.getPath()); + } + + /** + * Iterate through the given directory tree. For each file found in + * the file, the method + * {@link #processFile(java.lang.String, java.lang.String)} is called. + * + * @param path the path of the directory to be browsed + * @param currentDir the subdirectory currently explored + */ + protected void browseDirectoryTree(String path, String currentDir) + throws IOException { + File file = new File(path); + + if (!file.exists()) return; + if (!file.isDirectory()) return; + + //loop through files in directory + String[] files = file.list(); + + for (int k = 0; k < files.length; k++) { + File newfile = new File(file.getPath(), files[k]); + if (newfile.isFile()) + processFile(path + System.getProperty("file.separator") + + files[k], currentDir); + else if (newfile.isDirectory()) { + File newDirectory = new File(_destination + currentDir + + files[k]); + newDirectory.mkdirs(); + //System.out.println("Created directory " + // + newDirectory.getPath()); + browseDirectoryTree(file.getPath() + + System.getProperty("file.separator") + + files[k], currentDir + files[k] + + System.getProperty("file.separator")); + } + } + } + + /** + * Recursively copy a directory. + * + * @param source source directory + * @param destination target directory + */ + public void copy(File source, File destination) + throws IOException { + try { + //treat jar archives differently + if (source.toString().contains("dol.jar!")) { + String jarName = source.toString(); + jarName = jarName.substring(jarName.indexOf("file:") + 5, jarName.lastIndexOf("!")); + String sourceName = source.toString(); + sourceName = sourceName.substring( + sourceName.lastIndexOf("!") + 2); + sourceName = sourceName.replaceAll("\\\\", "/"); + + JarFile jar = new JarFile(jarName); + JarCopier copier = new JarCopier(); + copier.copy(jar, sourceName, destination.toString()); + return; + } + + _destination = destination.getPath(); + + if (!source.isDirectory()) + throw (new IOException("Source is not a directory.")); + + File destinationDir = new File(_destination); + destinationDir.mkdirs(); + + browseDirectoryTree(source.getPath(), + System.getProperty("file.separator")); + } + catch (IOException e) { + System.out.println("An error has occured while copying \"" + + source.getPath() + "\" to \"" + + destination.getPath() + "\":"); + System.out.println(e.getMessage()); + throw e; + } + } + + /** + * Test the implementation. + * + * @param args args[0] specifies the source directory, + * args[1] specifies the destination directory + */ + public static void main(String args[]) + throws Exception { + Copier copier = new Copier(); + if (args.length == 2) + copier.copy(new File(args[0]), new File(args[1])); + else + System.out.println("usage: java Copier " + + "sourceDirectory targetDirectory"); + } +} diff --git a/dol/src/dol/util/JarCopier.java b/dol/src/dol/util/JarCopier.java new file mode 100644 index 0000000..aeff404 --- /dev/null +++ b/dol/src/dol/util/JarCopier.java @@ -0,0 +1,114 @@ +/* $Id: JarCopier.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.util; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.Vector; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +/** + * Class to copy files from a jar archive. + */ +public class JarCopier { + + /** + * Copy a file from the specified jar file to the specified + * destination file. The file path must be specified using forward + * slashes, for instance, META-INF/MANIFEST.MF. + * + * @param jar jar archive + * @param from file to extract from jar archive + * @param to file to copy the file to + */ + public void copyFile(JarFile jar, String from, String to) { + try { + InputStream in = jar.getInputStream(jar.getEntry(from)); + OutputStream out = new FileOutputStream(new File(to)); + int c; + while ((c = in.read()) != -1) { + out.write(c); + } + in.close(); + out.close(); + } + catch (IOException e) { + System.out.println("An error has occured while copying \"" + + from + "\" to \"" + to + "\":"); + System.out.println(e.getMessage()); + } + } + + /** + * Get all files located in the given path of the given jar archive. + * The path must be specified with forward slashes. + * + * @param jar jar archive + * @param path path to search for files + * @return vector of all files in the specified path + */ + public Vector getFilesInDirectory(JarFile jar, String path) { + Vector filelist = new Vector(); + Enumeration entries = jar.entries(); + + while (entries.hasMoreElements()) { + String entry = entries.nextElement().toString(); + if (entry.startsWith(path)) { + filelist.add(entry); + } + } + return filelist; + } + + /** + * Recursively copy a directory from the specified jar archive. + * + * @param jar jar archive + * @param srcDir source directory + * @param destDir target directory + */ + public void copy(JarFile jar, String srcDir, String destDir) + throws IOException { + File directory = new File(destDir); + if (!directory.exists()) { + directory.mkdirs(); + } + for (String file : getFilesInDirectory(jar, srcDir)) { + String dir = file.substring(0, file.lastIndexOf("/")); + directory = new File(destDir + + System.getProperty("file.separator") + + dir.substring(srcDir.length())); + if (!directory.exists()) { + directory.mkdirs(); + } + if (!file.endsWith("/")) { + copyFile(jar, file, destDir + + System.getProperty("file.separator") + + file.substring(srcDir.length() + 1)); + } + } + } + + /** + * Copy the specified directory from the jar archive to the specified + * destination. + * + * @param args args[0] specifies the jar file to read from, + * args[1] specifies the source directory, + * args[2] specifies the destination directory + */ + public static void main(String args[]) + throws Exception { + JarCopier copier = new JarCopier(); + JarFile jar = new JarFile(args[0]); + if (args.length == 3) + copier.copy(jar, args[1], args[2]); + else + System.out.println("usage: java JarCopier " + + "jarFile sourceDirectory targetDirectory"); + } +} \ No newline at end of file diff --git a/dol/src/dol/util/SchemaLocation.java b/dol/src/dol/util/SchemaLocation.java new file mode 100644 index 0000000..de46cef --- /dev/null +++ b/dol/src/dol/util/SchemaLocation.java @@ -0,0 +1,137 @@ +/* $Id: SchemaLocation.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.util; + +/** + * Class to get the location of schemas. + */ +public class SchemaLocation { + + protected static final String PN_NAMESPACE = + "http://www.tik.ee.ethz.ch/~shapes/schema/PROCESSNETWORK"; + protected static final String PN_LOCATION = + "http://www.tik.ee.ethz.ch/~shapes/schema/processnetwork.xsd"; + protected static final String ARCH_NAMESPACE = + "http://www.tik.ee.ethz.ch/~shapes/schema/ARCHITECTURE"; + protected static final String ARCH_LOCATION = + "http://www.tik.ee.ethz.ch/~shapes/schema/architecture.xsd"; + protected static final String ARCH_NAMESPACE_OLD = + "http://www.tik.ee.ethz.ch/~shapes/schema/ARCHITECTURE_OLD"; + protected static final String MAP_NAMESPACE = + "http://www.tik.ee.ethz.ch/~shapes/schema/MAPPING"; + protected static final String MAP_LOCATION = + "http://www.tik.ee.ethz.ch/~shapes/schema/mapping.xsd"; + protected static final String MAP_NAMESPACE_OLD = + "http://www.tik.ee.ethz.ch/~shapes/schema/MAPPING_OLD"; + + /** singleton instance */ + protected final static SchemaLocation _schemaLocation = + new SchemaLocation(); + + /** + * Default constructor. + */ + public SchemaLocation() { + } + + /** + * Return the process network namespace. + * + * @return process network namespace + */ + public static String getProcessNetworkNamespace() { + return PN_NAMESPACE; + } + + /** + * Return the process network schema location. + * + * @return process network schema location + */ + public static String getProcessNetworkSchemaLocation() { + return PN_LOCATION; + } + + /** + * Return the architecture namespace. + * + * @return architecture namespace + */ + public static String getArchitectureNamespace() { + return ARCH_NAMESPACE; + } + + /** + * Return the architecture schema location. + * + * @return architecture schema location + */ + public static String getArchitectureSchemaLocation() { + return ARCH_LOCATION; + } + + /** + * Return the mapping namespace. + * + * @return mapping namespace + */ + public static String getMappingNamespace() { + return MAP_NAMESPACE; + } + + /** + * Return the mapping schema location. + * + * @return mapping schema location + */ + public static String getMappingSchemaLocation() { + return MAP_LOCATION; + } + + /** + * Return a string with the references to the external schema files. + * + * @return references to external schemas + */ + public static String getExternalSchemaLocation() { + String loc = PN_NAMESPACE + " "; + loc += _schemaLocation.getClass().getResource( + "/schema/processnetwork.xsd"); + loc += " " + ARCH_NAMESPACE + " "; + loc += _schemaLocation.getClass().getResource( + "/schema/architecture.xsd"); + loc += " " + ARCH_NAMESPACE_OLD + " "; + loc += _schemaLocation.getClass().getResource( + "/schema/architecture_old.xsd"); + loc += " " + MAP_NAMESPACE + " "; + loc += _schemaLocation.getClass().getResource( + "/schema/mapping.xsd"); + return loc; + } + + /** + * Return a string with the references to the internal schema files. + * + * @return references to internal schemas + */ + public static String getInternalSchemaLocation() { + String loc = PN_NAMESPACE + " "; + loc += _schemaLocation.getClass().getResource( + "/schema/internal/processnetwork_internal.xsd"); + loc += " " + ARCH_NAMESPACE + " "; + loc += _schemaLocation.getClass().getResource( + "/schema/internal/architecture_internal.xsd"); + loc += " " + ARCH_NAMESPACE_OLD + " "; + loc += _schemaLocation.getClass().getResource( + "/schema/internal/architecture_old_internal.xsd"); + loc += " " + MAP_NAMESPACE + " "; + loc += _schemaLocation.getClass().getResource( + "/schema/internal/mapping_internal.xsd"); + loc += " " + MAP_NAMESPACE_OLD + " "; + loc += _schemaLocation.getClass().getResource( + "/schema/internal/mapping_old_internal.xsd"); + return loc; + } +} + + + diff --git a/dol/src/dol/util/Sed.java b/dol/src/dol/util/Sed.java new file mode 100644 index 0000000..ae610f6 --- /dev/null +++ b/dol/src/dol/util/Sed.java @@ -0,0 +1,133 @@ +/* $Id: Sed.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.util; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; + +/** + * Class to find and replace strings in a files of a directory. + * The intention is to get a behavior similar to UNIX's sed (stream + * editor). + */ +public class Sed { + + /** + * In the given file, search for occurences of the given search + * pattern and replace it by the given replacement. + * searchPattern, replacementPattern will be used in a call of + * String.replaceAll(searchPattern, replacementPattern). + * + * @param filename file to search + * @param searchPattern regular expression to search for + * @param replacementPattern replacement + */ + protected void readReplace(String filename, String searchPattern, + String replacementPattern) throws IOException { + String line; + StringBuffer buffer = new StringBuffer(); + FileInputStream fileInputStream = new FileInputStream(filename); + BufferedReader reader = new BufferedReader( + new InputStreamReader(fileInputStream)); + while((line = reader.readLine()) != null) { + String newline = line.replaceAll(searchPattern, replacementPattern); + /* + if (!newline.equals(line)) { + System.out.println("Found pattern in " + filename + + ". New line: " + newline); + } + */ + buffer.append(newline + "\n"); + } + reader.close(); + BufferedWriter out = new BufferedWriter(new FileWriter(filename)); + out.write(buffer.toString()); + out.close(); + } + + /** + * Iterate through the given directory tree. For each file found in + * the file, the method + * {@link #processFile(java.lang.String)} is called. + * + * @param path the path of the directory to be browsed + * @param currentDir the subdirectory currently explored + */ + protected void browseDirectoryTree(String path) + throws IOException { + File file = new File(path); + + if (!file.exists()) return; + if (!file.isDirectory()) return; + + //loop through files in directory + String[] files = file.list(); + + for (int k = 0; k < files.length; k++) { + File newfile = new File(file.getPath(), files[k]); + if (newfile.isFile()) + readReplace(path + System.getProperty("file.separator") + + files[k], _searchPattern, _replacementPattern); + else if (newfile.isDirectory()) { + browseDirectoryTree(file.getPath() + + System.getProperty("file.separator") + + files[k]); + } + } + } + + /** + * In the given file or in the files located in the given directory, + * search for occurences of the given search pattern and replace it + * by the given replacement. searchPattern, replacementPattern will + * be used in a call of + * String.replaceAll(searchPattern, replacementPattern). + * + * @param path file or path to search + * @param searchPattern regular expression to search for + * @param replacementPattern replacement + */ + public void sed(String path, String searchPattern, + String replacementPattern) throws IOException { + File file = new File(path); + _searchPattern = searchPattern; + _replacementPattern = replacementPattern; + if (!file.exists()) return; + if (file.isFile()) { + readReplace(path, searchPattern, replacementPattern); + } + else if (file.isDirectory()) { + browseDirectoryTree(path); + } + } + + /** + * Test the implementation. + * + * @param args args[0] file or directory to search + * args[1] regular expression to search for + * args[2] replacement + */ + public static void main(String args[]) { + if (args.length == 3) { + try { + new Sed().sed(args[0], args[1], args[2]); + } + catch (IOException e) { + System.out.println("Sed: An error occured:"); + System.out.println(e.getMessage()); + } + } + else { + System.out.println("usage: java Sed directory|file " + + "searchPattern replacementPattern"); + } + } + + String _searchPattern = ""; + String _replacementPattern = ""; +} diff --git a/dol/src/dol/util/package.html b/dol/src/dol/util/package.html new file mode 100644 index 0000000..bb9fea5 --- /dev/null +++ b/dol/src/dol/util/package.html @@ -0,0 +1,20 @@ + + + + + + +Collection of tools for file operations. + +

Package Specification

+ + + +

Related Documentation

+ + + + + + + diff --git a/dol/src/dol/visitor/ArchiVisitor.java b/dol/src/dol/visitor/ArchiVisitor.java new file mode 100644 index 0000000..b72c2d2 --- /dev/null +++ b/dol/src/dol/visitor/ArchiVisitor.java @@ -0,0 +1,47 @@ +/* $Id: ArchiVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor; + +import dol.datamodel.architecture.ArchiConnection; +import dol.datamodel.architecture.ArchiResource; +import dol.datamodel.architecture.Architecture; +import dol.datamodel.architecture.Configuration; +import dol.datamodel.architecture.HWChannel; +import dol.datamodel.architecture.Memory; +import dol.datamodel.architecture.Node; +import dol.datamodel.architecture.PortNode; +import dol.datamodel.architecture.Processor; +import dol.datamodel.architecture.ReadPath; +import dol.datamodel.architecture.Variable; +import dol.datamodel.architecture.WritePath; +import dol.main.UserInterface; +import dol.util.CodePrintStream; + +/** + * This class is an abstract class for a visitor that is used to + * generate an Archietcture description. + */ +public abstract class ArchiVisitor implements Visitor { + + public ArchiVisitor() { + _ui = UserInterface.getInstance(); + } + + public void visitComponent(Architecture x) { } + public void visitComponent(ArchiResource x) { } + public void visitComponent(Processor x) { } + public void visitComponent(Memory x) { } + public void visitComponent(HWChannel x) { } + public void visitComponent(Configuration x) {} + public void visitComponent(Variable x) { } + public void visitComponent(Node x) { } + public void visitComponent(PortNode x) { } + public void visitComponent(ArchiConnection x) {} + public void visitComponent(ReadPath x) {} + public void visitComponent(WritePath x) {} + + /** + * Stream where the print output is sent to. + */ + protected CodePrintStream _printStream = null; + protected UserInterface _ui = null; +} diff --git a/dol/src/dol/visitor/MapVisitor.java b/dol/src/dol/visitor/MapVisitor.java new file mode 100644 index 0000000..b12e585 --- /dev/null +++ b/dol/src/dol/visitor/MapVisitor.java @@ -0,0 +1,41 @@ +/* $Id: MapVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor; + +import dol.datamodel.mapping.Binding; +import dol.datamodel.mapping.CommunicationBinding; +import dol.datamodel.mapping.ComputationBinding; +import dol.datamodel.mapping.Configuration; +import dol.datamodel.mapping.MapResource; +import dol.datamodel.mapping.Mapping; +import dol.datamodel.mapping.Schedule; +import dol.datamodel.mapping.ScheduleEntry; +import dol.datamodel.mapping.Variable; +import dol.main.UserInterface; +import dol.util.CodePrintStream; + +/** + * This class is an abstract class for a visitor that is used to + * generate a mapping description. + */ +public abstract class MapVisitor implements Visitor { + + public MapVisitor() { + _ui = UserInterface.getInstance(); + } + + public void visitComponent(Mapping x) { } + public void visitComponent(MapResource x) { } + public void visitComponent(Binding x) {} + public void visitComponent(ComputationBinding x) {} + public void visitComponent(CommunicationBinding x) {} + public void visitComponent(Schedule x) {} + public void visitComponent(ScheduleEntry x) {} + public void visitComponent(Variable x) {} + public void visitComponent(Configuration x) {} + + /** + * Stream where the print output is sent to. + */ + protected CodePrintStream _printStream = null; + protected UserInterface _ui = null; +} diff --git a/dol/src/dol/visitor/PNVisitor.java b/dol/src/dol/visitor/PNVisitor.java new file mode 100644 index 0000000..ec36dd3 --- /dev/null +++ b/dol/src/dol/visitor/PNVisitor.java @@ -0,0 +1,44 @@ +/* $Id: PNVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor; + +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Configuration; +import dol.datamodel.pn.Connection; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.ProfilingConfiguration; +import dol.datamodel.pn.Resource; +import dol.datamodel.pn.SourceCode; +import dol.datamodel.pn.Variable; +import dol.main.UserInterface; +import dol.util.CodePrintStream; + +/** + * This class is an abstract class for a visitor that is used to + * generate a Process Network description. + */ +public abstract class PNVisitor implements Visitor { + + public PNVisitor() { + _ui = UserInterface.getInstance(); + } + + public void visitComponent(ProcessNetwork x) { } + public void visitComponent(Resource x) { } + public void visitComponent(Process x) { } + public void visitComponent(Variable x) { } + public void visitComponent(Channel x) { } + public void visitComponent(Connection x) { } + public void visitComponent(Configuration x) { } + public void visitComponent(ProfilingConfiguration x) { } + public void visitComponent(Port x) { } + public void visitComponent(SourceCode x) { } + + /** + * Stream where the print output is sent to. + */ + protected CodePrintStream _printStream = null; + protected UserInterface _ui = null; + protected String _delimiter = "/"; +} diff --git a/dol/src/dol/visitor/PipeAndFilter/PipeAndFilterMakefileVisitor.java b/dol/src/dol/visitor/PipeAndFilter/PipeAndFilterMakefileVisitor.java new file mode 100644 index 0000000..feb3257 --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/PipeAndFilterMakefileVisitor.java @@ -0,0 +1,63 @@ +/* $Id: PipeAndFilterMakefileVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.PipeAndFilter; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; + +import dol.datamodel.pn.ProcessNetwork; +import dol.visitor.PNVisitor; + +/** + * + */ +public class PipeAndFilterMakefileVisitor extends PNVisitor { + + /** + * + */ + public PipeAndFilterMakefileVisitor(String dir) { + _dir = dir; + } + + /** + * + */ + public void visitComponent(ProcessNetwork x) { + try { + String filename = _dir + _delimiter + "Makefile"; + OutputStream file = new FileOutputStream(filename); + PrintStream ps = new PrintStream(file); + + ps.println("CXX = g++"); + ps.println("CXXFLAGS = -g -Wall"); + ps.println("COMPILE = ${CXX} ${CXXFLAGS} -c"); + ps.println("LINK = ${CXX} -lpthread"); + ps.println("LIB_INC = -Ilib -Iwrappers -Iprocesses"); + ps.println(); + ps.println("src := $(wildcard lib/*.cpp) " + + "$(wildcard wrappers/*.cpp) $(wildcard *.cpp)"); + ps.println("obj = $(src:.cpp=.o)"); + ps.println(); + ps.println("app : ${obj} ${src}"); + ps.println("\t${LINK} -o " + _name + " $(obj)"); + ps.println(); + ps.println("%.o :"); + ps.println("\t${COMPILE} -o $(*D)/$(*F).o $(*D)/$(*F).cpp $(LIB_INC)"); + ps.println(); + ps.println("clean :"); + ps.println("\trm ${obj}"); + } + catch (IOException e) { + System.out.println(" PipeAndFilter Makefile Visitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + protected String _dir = null; + protected String _name = "sc_application"; + +} + diff --git a/dol/src/dol/visitor/PipeAndFilter/PipeAndFilterModuleVisitor.java b/dol/src/dol/visitor/PipeAndFilter/PipeAndFilterModuleVisitor.java new file mode 100644 index 0000000..04d9f57 --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/PipeAndFilterModuleVisitor.java @@ -0,0 +1,311 @@ +/* $Id: PipeAndFilterModuleVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.PipeAndFilter; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.Resource; +import dol.util.CodePrintStream; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate + * the main program. + */ +public class PipeAndFilterModuleVisitor extends PNVisitor { + + /** + * Constructor. + */ + public PipeAndFilterModuleVisitor(String dir) { + _dir = dir; + } + + public void visitComponent(ProcessNetwork x) { + try { + String filename = _dir + _delimiter + "sc_application.cpp"; + OutputStream file = new FileOutputStream(filename); + _code = new CodePrintStream(file); + + _code.println("#include "); + _code.println(); + + _code.printPrefixln("#include \"lib/Fifo.h\""); + _code.printPrefixln("#include \"lib/Scheduler.h\""); + _code.printPrefixln("#include \"lib/WindowedFifo.h\""); + _code.println(); + _code.printPrefixln("#include \"wrappers/wrappers.h\""); + _code.println(); + _code.printPrefixln("#include \"processnetwork.h\""); + _code.println(); + _code.printPrefixln("int main(void)"); + _code.printLeftBracket(); + + _code.printPrefixln("std::map *processes"); + _code.printPrefixln(" = new std::map();"); + _code.println(); + + _code.printPrefixln("Scheduler *scheduler = " + + "new Scheduler();"); + _code.println(); + + //instantiate channels + for (Channel c : x.getChannelList()) { + if (c.getType().equals("fifo")) { + printProcessNetwork("Fifo *" + c.getName() + + " = new Fifo(\"" + c.getName() + + "\", " + c.getSize() * c.getTokenSize() + + ");"); + } else if (c.getType().equals("wfifo")) { + printProcessNetwork("WindowedFifo *" + c.getName() + + " = new WindowedFifo(\"" + c.getName() + + "\", " + c.getSize() * c.getTokenSize() + + ");"); + } + } + printProcessNetwork(""); + + // instantiate processes and connect to channels + for (Process p : x.getProcessList()) { + printProcessNetwork(p.getBasename() + "_wrapper *" + + p.getName() + " = new " + + p.getBasename() + "_wrapper(\"" + + p.getName() + "\");"); + printProcessNetwork("processes->insert(std::pair" + + "(\"" + + p.getName() + "\", " + p.getName() + "));"); + printProcessNetwork(""); + } + + //build the network + for (Channel ch : x.getChannelList()) { + ch.accept(this); + } + + printProcessNetwork("}"); + + String headerfilename = _dir + _delimiter + + "processnetwork.h"; + OutputStream headerfile = new FileOutputStream( + headerfilename); + CodePrintStream processnetworkHeader = new + CodePrintStream(headerfile); + processnetworkHeader.printPrefixln( + "#ifndef PROCESSNETWORK_H"); + processnetworkHeader.printPrefixln( + "#define PROCESSNETWORK_H"); + processnetworkHeader.println(); + + for (int counter = 1; counter <= _processNetworkCounter; + counter++) { + _code.printPrefixln("processnetwork_part" + + String.format("%03d", counter) + "::create(" + + "processes);"); + processnetworkHeader.println("#include " + + "\"processnetwork_part" + + String.format("%03d", counter) + ".h\""); + } + _code.println(); + + processnetworkHeader.println(); + processnetworkHeader.printPrefixln("#endif"); + + + //register processes + _code.printPrefixln("std::map::iterator process_iterator;"); + _code.printPrefixln("for (process_iterator = " + + "processes->begin();"); + _code.printPrefixln(" process_iterator != " + + "processes->end();"); + _code.printPrefixln(" process_iterator++) {"); + _code.printPrefixln(" scheduler->registerProcess(" + + "static_cast"); + _code.printPrefixln(" ((*process_iterator).second));"); + _code.printPrefixln("}"); + _code.println(); + + //run scheduler + _code.printPrefixln("scheduler->run();"); + _code.println(); + + //clean up + _code.println(); + _code.printPrefixln("for (process_iterator = " + + "processes->begin();"); + _code.printPrefixln(" process_iterator != " + + "processes->end();"); + _code.printPrefixln(" process_iterator++) {"); + _code.printPrefixln(" delete static_cast" + + "((*process_iterator).second);"); + _code.printPrefixln("}"); + _code.println(); + //_code.printPrefixln("std::cout << \"End.\" << std::endl;"); + _code.printPrefixln("return 0;"); + _code.printRightBracket(); + } + catch (Exception e) { + System.out.println("PipeAndFilterModuleVisitor: " + + "exception occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * + */ + protected void createProcessNetworkHeader(int part) + throws IOException { + String partString = String.format("%03d", part); + String filename = _dir + _delimiter + "processnetwork_part" + + partString + ".h"; + OutputStream file = new FileOutputStream(filename); + CodePrintStream header = new CodePrintStream(file); + + header.println("#ifndef PROCESSNETWORK_PART" + + partString + "_H"); + header.println("#define PROCESSNETWORK_PART" + + partString + "_H"); + header.println(); + header.println("#include "); + header.println("#include "); + header.println(); + header.println("#include \"lib/ProcessWrapper.h\""); + header.println("#include \"lib/Fifo.h\""); + header.println("#include \"lib/WindowedFifo.h\""); + header.println(); + header.println("#include \"wrappers/wrappers.h\""); + header.println(); + header.println("class processnetwork_part" + partString + " {"); + header.println(" public:"); + header.println(" processnetwork_part" + + partString + "();"); + header.println(" virtual ~processnetwork_part" + + partString + "();"); + header.println(" static void create("); + header.println(" std::map *processes);"); + header.println("};"); + header.println(); + header.println("#endif"); + } + + + /** + * + */ + protected void printProcessNetwork(String nextLine) + throws IOException { + if (!_fileOpen || + (_numberOfLines >= MAX_NUMBER_OF_LINES && + !nextLine.contains("->insert") && + !nextLine.equals("") && + !nextLine.contains("Port(") && + !nextLine.contains(""))) { + + if (_fileOpen) { + _pn.printRightBracket(); + } + + _processNetworkCounter++; + _numberOfLines = 0; + createProcessNetworkHeader(_processNetworkCounter); + String partString = String.format("%03d", + _processNetworkCounter); + String processNetworkFilename = _dir + _delimiter + + "processnetwork_part" + partString + ".cpp"; + + _file = new FileOutputStream(processNetworkFilename); + _pn = new CodePrintStream(_file); + _fileOpen = true; + + _pn.printPrefixln("#include \"processnetwork_part" + + partString + ".h\""); + _pn.println(); + + _pn.printPrefixln("processnetwork_part" + partString + + "::processnetwork_part" + partString + "() {"); + _pn.printPrefixln(" //nothing to do"); + _pn.printPrefixln("}"); + _pn.println(); + _pn.printPrefixln("processnetwork_part" + partString + + "::~processnetwork_part" + partString + "() {"); + _pn.printPrefixln(" //nothing to do"); + _pn.printPrefixln("}"); + _pn.println(); + _pn.printPrefixln("void processnetwork_part" + partString + + "::create("); + _pn.printPrefixln(" std::map *processes)"); + _pn.printLeftBracket(); + } + + _pn.printPrefixln(nextLine); + _numberOfLines++; + } + + /** + * + * @param x channel that needs to be rendered + */ + public void visitComponent(Channel x) { + try { + for (Port p : x.getPortList()) { + Port peerPort = (Port)(p.getPeerPort()); + Resource peerResource = p.getPeerResource(); + String codeLine = ""; + if (peerPort.getRange() != null) { + if (p.isOutPort()) { + codeLine = peerResource.getName() + + "->INPORT_" + + peerPort.getBasename() + + peerPort.getName().replaceAll( + "_([0-9]+)", "[$1]").replaceFirst( + peerPort.getBasename(), ""); + } + else if (p.isInPort()) { + codeLine = peerResource.getName() + + "->OUTPORT_" + + peerPort.getBasename() + + peerPort.getName().replaceAll( + "_([0-9]+)", "[$1]").replaceFirst( + peerPort.getBasename(), ""); + } + } + else { + if (p.isOutPort()) { + codeLine = peerResource.getName() + + "->INPORT_" + peerPort.getName(); + } + else if (p.isInPort()) { + codeLine = peerResource.getName() + + "->OUTPORT_" + peerPort.getName(); + } + } + printProcessNetwork(codeLine + " = " + x.getName() + ";"); + } + } + catch (Exception e) { + System.out.println("PipeAndFilterModuleVisitor: " + + "exception occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + protected CodePrintStream _code = null; + protected String _dir = null; + protected boolean _fileOpen = false; + protected int _processNetworkCounter = 0; + protected int _numberOfLines = 0; + protected static final int MAX_NUMBER_OF_LINES = 1000; + protected OutputStream _file; + protected CodePrintStream _pn; +} + diff --git a/dol/src/dol/visitor/PipeAndFilter/PipeAndFilterProcessVisitor.java b/dol/src/dol/visitor/PipeAndFilter/PipeAndFilterProcessVisitor.java new file mode 100644 index 0000000..a1ec83b --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/PipeAndFilterProcessVisitor.java @@ -0,0 +1,60 @@ +/* $Id: PipeAndFilterProcessVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.PipeAndFilter; + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.util.Vector; + +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.util.CodePrintStream; +import dol.visitor.PNVisitor; +import dol.visitor.hds.HdsProcessVisitor; + +/** + * + */ +public class PipeAndFilterProcessVisitor extends PNVisitor { + + /** + * Constructor. + */ + public PipeAndFilterProcessVisitor(String dir) { + _dir = dir; + } + + /** + * + */ + public void visitComponent(ProcessNetwork x) { + HdsProcessVisitor visitor = new HdsProcessVisitor(_dir); + x.accept(visitor); + + try { + String filename = _dir + _delimiter + "wrappers.h"; + OutputStream file = new FileOutputStream(filename); + _wrapperHeader = new CodePrintStream(file); + _wrapperHeader.printPrefixln("#ifndef WRAPPERS_H"); + _wrapperHeader.printPrefixln("#define WRAPPERS_H"); + _wrapperHeader.println(); + Vector pList = new Vector(); + for (Process p : x.getProcessList()) { + String basename = p.getBasename(); + if (!pList.contains(basename)) { + pList.add(basename); + _wrapperHeader.printPrefixln("#include \"" + + p.getBasename() + "_wrapper.h\""); + } + } + _wrapperHeader.println(); + _wrapperHeader.printPrefixln("#endif"); + } catch (Exception e) { + System.out.println("Process Visitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + protected String _dir = null; + CodePrintStream _wrapperHeader; +} diff --git a/dol/src/dol/visitor/PipeAndFilter/PipeAndFilterVisitor.java b/dol/src/dol/visitor/PipeAndFilter/PipeAndFilterVisitor.java new file mode 100644 index 0000000..c545a77 --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/PipeAndFilterVisitor.java @@ -0,0 +1,96 @@ +/* $Id: PipeAndFilterVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.PipeAndFilter; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; + +import dol.datamodel.pn.ProcessNetwork; +import dol.util.Copier; +import dol.visitor.PNVisitor; + +/** + * + */ +public class PipeAndFilterVisitor extends PNVisitor { + + /** + * Constructor. + */ + public PipeAndFilterVisitor(String packageName) { + _packageName = packageName; + } + + /** + * + */ + public void visitComponent(ProcessNetwork x) { + try { + _generateDirHierarchy(); + + x.accept(new PipeAndFilterMakefileVisitor(_srcDir)); + x.accept(new PipeAndFilterModuleVisitor(_srcDir)); + x.accept(new PipeAndFilterProcessVisitor(_wrapperDir)); + + } catch (Exception e) { + System.out.println(" SystemC PN Visitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + + } + + /** + * + */ + private void _generateDirHierarchy() + throws IOException, FileNotFoundException { + + File dir = new File(_packageName); + dir.mkdirs(); + + _srcDir = _packageName + _delimiter + _srcDirName; + dir = new File(_srcDir); + dir.mkdirs(); + + _libDir = _srcDir + _delimiter + _libDirName; + dir = new File(_libDir); + dir.mkdirs(); + + _processDir = _srcDir + _delimiter + _processDirName; + dir = new File(_processDir); + dir.mkdirs(); + + _wrapperDir = _srcDir + _delimiter + _wrapperDirName; + dir = new File(_wrapperDir); + dir.mkdirs(); + + // copy library + String libraryPath = _ui.getMySystemCLib(); + libraryPath = libraryPath.replaceAll("systemC", + "PipeAndFilter"); + File source = new File(libraryPath); + File destination = new File(_libDir); + new Copier().copy(source, destination); + + //copy process src code + source = new File(_srcDirName); + destination = new File(_processDir); + new Copier().copy(source, destination); + } + + protected String _packageName = null; + + protected String _srcDir = ""; + protected static String _srcDirName = "src"; + + protected String _libDir = ""; + protected static String _libDirName = "lib"; + + protected String _processDir = ""; + protected static String _processDirName = "processes"; + + protected String _wrapperDir = ""; + protected static String _wrapperDirName = "wrappers"; +} + diff --git a/dol/src/dol/visitor/PipeAndFilter/lib/Condition.cpp b/dol/src/dol/visitor/PipeAndFilter/lib/Condition.cpp new file mode 100644 index 0000000..4525b37 --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/lib/Condition.cpp @@ -0,0 +1,31 @@ +#include "Condition.h" + +Condition::Condition(Mutex *mutex) { + //std::cout << "Create Condition." << std::endl; + _mutex = mutex; + _condition = new pthread_cond_t; + pthread_cond_init(_condition, NULL); +} + + +Condition::~Condition() { + //std::cout << "Delete Condition." << std::endl; + pthread_cond_destroy(_condition); + delete _condition; + //std::cout << "Deleted Condition." << std::endl; +} + + +void Condition::notify() { + pthread_cond_signal(_condition); +} + + +void Condition::notifyAll() { + pthread_cond_broadcast(_condition); +} + + +void Condition::wait() { + pthread_cond_wait(_condition, _mutex->getPThreadMutex()); +} diff --git a/dol/src/dol/visitor/PipeAndFilter/lib/Condition.h b/dol/src/dol/visitor/PipeAndFilter/lib/Condition.h new file mode 100644 index 0000000..c669892 --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/lib/Condition.h @@ -0,0 +1,21 @@ +#ifndef _CONDITION_H_ +#define _CONDITION_H_ + +#include +#include +#include "Mutex.h" + +class Condition { + public: + Condition(Mutex *mutex); + virtual ~Condition(); + virtual void notify(); + virtual void notifyAll(); + virtual void wait(); + + protected: + Mutex *_mutex; + pthread_cond_t *_condition; +}; + +#endif diff --git a/dol/src/dol/visitor/PipeAndFilter/lib/Event.cpp b/dol/src/dol/visitor/PipeAndFilter/lib/Event.cpp new file mode 100644 index 0000000..52490b2 --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/lib/Event.cpp @@ -0,0 +1,73 @@ +#include "Event.h" + +Event::Event() { + _name = "Event"; + //std::cout << "Create " << _name << "." << std::endl; + _mutex = new Mutex(); + _condition = new Condition(_mutex); + _waitMutex = new Mutex(); + _waitCondition = new Condition(_waitMutex); + _pendingWait = false; +} + + +Event::Event(std::string name) { + _name = "Event " + name; + //std::cout << "Create " << _name << "." << std::endl; + _mutex = new Mutex(); + _condition = new Condition(_mutex); + _waitMutex = new Mutex(); + _waitCondition = new Condition(_waitMutex); + _pendingWait = false; +} + + +Event::~Event() { + //std::cout << "Delete " << _name << "." << std::endl; + delete _condition; + delete _waitCondition; + delete _mutex; + delete _waitMutex; + //std::cout << "Deleted " << _name << "." << std::endl; +} + + +void Event::notify() { + _mutex->lock(); + _condition->notify(); + _mutex->unlock(); +} + + +void Event::notifyAll() { + _mutex->lock(); + _condition->notifyAll(); + _mutex->unlock(); +} + + +void Event::wait() { + _mutex->lock(); + _pendingWait = true; + _waitMutex->lock(); + _waitCondition->notify(); + _waitMutex->unlock(); + _condition->wait(); + _pendingWait = false; + _mutex->unlock(); +} + + +void Event::notifyAfterWait() { + _mutex->lock(); + + if (!_pendingWait) { + _waitMutex->lock(); + _mutex->unlock(); + _waitCondition->wait(); + _mutex->lock(); + _waitMutex->unlock(); + } + _condition->notify(); + _mutex->unlock(); +} diff --git a/dol/src/dol/visitor/PipeAndFilter/lib/Event.h b/dol/src/dol/visitor/PipeAndFilter/lib/Event.h new file mode 100644 index 0000000..51d14e8 --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/lib/Event.h @@ -0,0 +1,30 @@ +#ifndef _EVENT_H_ +#define _EVENT_H_ + +#include +#include +#include +#include "Mutex.h" +#include "Condition.h" + +class Event { + public: + Event(); + Event(std::string name); + Event(Mutex *mutex); + virtual ~Event(); + virtual void notify(); + virtual void notifyAll(); + virtual void wait(); + virtual void notifyAfterWait(); + + protected: + Mutex *_mutex; + Condition *_condition; + Mutex *_waitMutex; + Condition *_waitCondition; + bool _pendingWait; + std::string _name; +}; + +#endif diff --git a/dol/src/dol/visitor/PipeAndFilter/lib/Fifo.cpp b/dol/src/dol/visitor/PipeAndFilter/lib/Fifo.cpp new file mode 100644 index 0000000..a88fd98 --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/lib/Fifo.cpp @@ -0,0 +1,229 @@ +#include "Fifo.h" + +/** + * + */ +Fifo::Fifo(char* name, unsigned size = 18) { + //std::cout << "Create Fifo." << std::endl; + //except at the beginning, _head and _tail must never overlap, + //otherwise one does not know whether the buffer is full or + //empty. to have nevertheless a buffer with the given capacity, + //a buffer with one more element is allocated. + _size = size + 1; + _buffer = new char[_size]; + _head = 0; + _tail = 0; + _name = new char[strlen(name) + 1]; + strcpy(_name, name); + _mutex = new Mutex(); + _readCondition = new Condition(_mutex); + _writeCondition = new Condition(_mutex); +} + +/** + * + */ +Fifo::~Fifo() { + //std::cout << "Delete Fifo." << std::endl; + if (_buffer) { + delete _buffer; + } + if (_name) { + delete _name; + } + if (_readCondition) { + delete _readCondition; + } + if (_writeCondition) { + delete _writeCondition; + } + if (_mutex) { + delete _mutex; + } + + _buffer = 0; + _head = 0; + _tail = 0; + _name = 0; + _readCondition = 0; + _writeCondition = 0; + _mutex = 0; + //std::cout << "Deleted Fifo." << std::endl; +} + +/** + * + */ +unsigned Fifo::read(void *destination, unsigned len) { + char* buffer = (char*)destination; + unsigned read = 0; + //std::cout << "Try to read " << len << " bytes from Fifo " << _name << "." << std::endl; + + while (read < len) { + _mutex->lock(); + while (used() == 0) { + _writeCondition->wait(); + } + _mutex->unlock(); + + if ((len - read) < used()) { + while (read < len) { + _mutex->lock(); + unsigned tocopy = (len - read + _tail >= _size) ? _size - _tail : len - read; + memcpy(buffer, _buffer + _tail, tocopy); + _tail = (_tail + tocopy) % _size; + read += tocopy; + buffer += tocopy; + _mutex->unlock(); + } + _readCondition->notify(); + } else { + _mutex->lock(); + *buffer++ = *(_buffer + _tail % _size); + _tail = (_tail + 1) % _size; + read++; + _mutex->unlock(); + _readCondition->notify(); + } + } + + //std::cout << "Read " << read << " bytes from Fifo " << _name << "." << std::endl; + return read; +} + +/** + * + */ +unsigned Fifo::write(const void *source, unsigned len) { + char* buffer = (char*)source; + unsigned write = 0; + //std::cout << "Try to write " << len << " bytes to Fifo " << _name << std::endl; + + while (write < len) { + _mutex->lock(); + while (unused() == 0) { + _readCondition->wait(); + } + _mutex->unlock(); + + if ((len - write) < unused()) { + while (write < len) { + unsigned tocopy = (len - write + _head >= _size) ? _size - _head : len - write; + _mutex->lock(); + memcpy(_buffer + _head, buffer, tocopy); + _head = (_head + tocopy) % _size; + write += tocopy; + buffer += tocopy; + _mutex->unlock(); + } + _writeCondition->notify(); + } else { + _mutex->lock(); + *(_buffer + (unsigned)(_head) % _size) = *buffer++; + _head = (_head + 1) % _size; + write++; + _mutex->unlock(); + _writeCondition->notify(); + } + } + //std::cout << "Wrote " << write << " bytes to Fifo " << _name << "." << std::endl; + return write; +} + +/** + * + */ +unsigned Fifo::size() const { + return (_size - 1); +} + +/** + * + */ +unsigned Fifo::unused() const { + return (_size - 1) - used(); +} + +/** + * + */ +unsigned Fifo::used() const { + if (_head >= _tail) { + return _head - _tail; + } + return _head + _size - _tail; +} + +/** + * + */ +char* Fifo::getName() const { + return _name; +} + +/** + * Test the implementation + */ +/* +#include +void* producer(void *fifo) +{ + const char *str = + "Visit www.systemc.org and see what SystemC can do for you today!\n"; + + while (*str) { + //printf("%c", *str); + ((Fifo*)fifo)->write((void*)str++, 4); + } + printf("\nproducer returns.\n"); + return 0; +} + +void* consumer(void *fifo) +{ + char c; + while (c != '\n') { + ((Fifo*)fifo)->read(&c, 4); + std::cout << c << std::flush; + + if (((Fifo*)fifo)->used() == 1) + std::cout << "<1>" << std::flush; + if (((Fifo*)fifo)->used() == 9) + std::cout << "<9>" << std::flush; + } + printf("\nconsumer returns.\n"); + return 0; +} + + +int main() { + Fifo *fifo = new Fifo("fifo", 3); + pthread_t *producer_thread = new pthread_t; + pthread_t *consumer_thread = new pthread_t; + + pthread_attr_t attributes; + pthread_attr_init(&attributes); + pthread_attr_setstacksize(&attributes, 131072); + + if (pthread_create(consumer_thread, &attributes, consumer, fifo)) { + std::cout << "Error: Could not start consumer." << std::endl; + std::cout << "Exit." << std::endl; + exit(1); + } + pthread_attr_destroy(&attributes); + + pthread_attr_init(&attributes); + pthread_attr_setstacksize(&attributes, 131072); + if (pthread_create(producer_thread, &attributes, producer, fifo)) { + std::cout << "Error: Could not start producer." << std::endl; + std::cout << "Exit." << std::endl; + exit(1); + } + pthread_attr_destroy(&attributes); + + + pthread_join(*consumer_thread, 0); + delete fifo; + return 0; +} +*/ diff --git a/dol/src/dol/visitor/PipeAndFilter/lib/Fifo.h b/dol/src/dol/visitor/PipeAndFilter/lib/Fifo.h new file mode 100644 index 0000000..e1adb03 --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/lib/Fifo.h @@ -0,0 +1,31 @@ +#ifndef _FIFO_H_ +#define _FIFO_H_ + +#include +#include +#include "Mutex.h" +#include "Condition.h" + +class Fifo { + public: + Fifo(char* name, unsigned size); + virtual ~Fifo(); + + virtual unsigned read(void *destination, unsigned len); + virtual unsigned write(const void *source, unsigned len); + virtual unsigned used() const; + virtual unsigned unused() const; + virtual unsigned size() const; + virtual char* getName() const; + + protected: + char *_buffer; + unsigned _head; + unsigned _tail; + unsigned _size; + char *_name; + Mutex *_mutex; + Condition *_readCondition, *_writeCondition; +}; + +#endif diff --git a/dol/src/dol/visitor/PipeAndFilter/lib/Mutex.cpp b/dol/src/dol/visitor/PipeAndFilter/lib/Mutex.cpp new file mode 100644 index 0000000..b943ff3 --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/lib/Mutex.cpp @@ -0,0 +1,48 @@ +#include "Mutex.h" + +Mutex::Mutex() { + //std::cout << "Create Mutex." << std::endl; + _mutex = new pthread_mutex_t; + pthread_mutex_init(_mutex, NULL); //_mutexAttribute); + + _localMutex = new pthread_mutex_t; + pthread_mutex_init(_localMutex, NULL); + + _lockCondition = new pthread_cond_t; + pthread_cond_init(_lockCondition, NULL); +} + + +Mutex::~Mutex() { + //std::cout << "Delete Mutex." << std::endl; + pthread_mutex_destroy(_mutex); + delete _mutex; + + pthread_mutex_destroy(_localMutex); + delete _localMutex; + + pthread_cond_destroy(_lockCondition); + delete _lockCondition; + //std::cout << "Deleted Mutex." << std::endl; +} + + +int Mutex::trylock() { + int success = pthread_mutex_trylock(_mutex); + return success; +} + + +void Mutex::lock() { + pthread_mutex_lock(_mutex); +} + + +void Mutex::unlock() { + pthread_mutex_unlock(_mutex); +} + + +pthread_mutex_t *Mutex::getPThreadMutex() const { + return _mutex; +} diff --git a/dol/src/dol/visitor/PipeAndFilter/lib/Mutex.h b/dol/src/dol/visitor/PipeAndFilter/lib/Mutex.h new file mode 100644 index 0000000..a88268c --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/lib/Mutex.h @@ -0,0 +1,22 @@ +#ifndef _MUTEX_H_ +#define _MUTEX_H_ + +#include +#include + +class Mutex { + public: + Mutex(); + virtual ~Mutex(); + virtual void lock(); + virtual void unlock(); + virtual int trylock(); + virtual pthread_mutex_t *getPThreadMutex() const; + + protected: + pthread_mutex_t *_mutex; + pthread_mutex_t *_localMutex; + pthread_cond_t *_lockCondition; +}; + +#endif diff --git a/dol/src/dol/visitor/PipeAndFilter/lib/ProcessWrapper.cpp b/dol/src/dol/visitor/PipeAndFilter/lib/ProcessWrapper.cpp new file mode 100644 index 0000000..fbba359 --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/lib/ProcessWrapper.cpp @@ -0,0 +1,128 @@ +#include "ProcessWrapper.h" +#include "dolSupport.h" + +/** + * + */ +ProcessWrapper::ProcessWrapper(char* name) { + _name = new char[strlen(name) + 1]; + strcpy(_name, name); + + _isDetached = false; + for (int i = 0; i < 4; i++) { + _iteratorIndex[i] = getIndex(_name, "_", i); + } +} + +/** + * + */ +ProcessWrapper::~ProcessWrapper() { + if (_name) { + delete _name; + } +} + +/** + * + */ +void ProcessWrapper::initialize() { + _process.init(&_process); +} + +/** + * + */ +int ProcessWrapper::fire() +{ + return _process.fire(&_process); +} + + +/** + * + */ +void ProcessWrapper::detach() { + _isDetached = true; +} + + +/** + * Gets an index of a string, where the index must be separated by + * a character specified in tokens. + * Returns -1, when an error occurs. + * + * Example: + * getIndex("name_1_2", "_", 0) will return 1. + * getIndex("name_1_2", "_", 1) will return 2. + * + * @param string string to parse + * @param tokens delimiter of indices + * @param indexNumber position of index (starting at 0) + */ +int ProcessWrapper::getIndex(const char* string, char* tokens, + int indexNumber) const { + char* string_copy; + char* token_pointer; + int index = 0; + + string_copy = (char*) malloc(sizeof(char) * (strlen(string) + 1)); + if (!string_copy) { + fprintf(stderr, "getIndex(): could not allocate memory.\n"); + return -1; + } + + strcpy(string_copy, string); + + token_pointer = strtok(string_copy, tokens); + do { + token_pointer = strtok(NULL, tokens); + index++; + } while (index <= indexNumber && token_pointer != 0); + + if (token_pointer) { + index = atoi(token_pointer); + free(string_copy); + return index; + } + + return -1; +} + + +/** + * Get the index of this process. + * @param indexNumber position of index (starting at 0) + */ +int ProcessWrapper::getIndex(unsigned indexNumber) const { + if (indexNumber < 4) { + return _iteratorIndex[indexNumber]; + } + return -1; +} + + +/** + * Get the name of this process. + */ +char* ProcessWrapper::getName() const { + return _name; +} + + +/** + * + */ +#ifdef INCLUDE_PROFILER +void ProcessWrapper::addToProfile(const char *event, void *port, + int length) { + if (profiler_output_file != NULL) { + fprintf(profiler_output_file, "%u %s %s %p %d\n", + profiler_event_counter++, _name, event, port, + length); + + } else { + printf("profiler_output_file does not exist"); + } +} +#endif diff --git a/dol/src/dol/visitor/PipeAndFilter/lib/ProcessWrapper.h b/dol/src/dol/visitor/PipeAndFilter/lib/ProcessWrapper.h new file mode 100644 index 0000000..da7335f --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/lib/ProcessWrapper.h @@ -0,0 +1,55 @@ +#ifndef _PROCESSWRAPPER_H_ +#define _PROCESSWRAPPER_H_ + +#include +#include +#include "dol.h" +#include "Fifo.h" +#include "WindowedFifo.h" + +#ifdef INCLUDE_PROFILER +extern FILE *profiler_output_file; +extern unsigned int profiler_event_counter; +#endif + +class ProcessWrapper +{ + public: + ProcessWrapper(char* name); + virtual ~ProcessWrapper(); + virtual void initialize(); + virtual int fire(); + virtual bool isDetached() { return _isDetached; } + virtual void detach(); + virtual int getIndex(unsigned indexNumber) const; + virtual char* getName() const; + +#ifdef INCLUDE_PROFILER + virtual void addToProfile(const char *event, void *port, + int length); +#endif + +#ifdef INCLUDE_TRACE + int start_line; + int end_line; + char channel_name[NAME_LENGTH]; +#endif + +#ifdef INCLUDE_PERFORMANCE + int start_line; + int end_line; + CURRENT_TIME start_time; + CURRENT_TIME end_time; +#endif + + protected: + char* _name; + DOLProcess _process; + bool _isDetached; + int _iteratorIndex[4]; + virtual int getIndex(const char* string, char* tokens, + int indexNumber) const; +}; + +#endif + diff --git a/dol/src/dol/visitor/PipeAndFilter/lib/Scheduler.cpp b/dol/src/dol/visitor/PipeAndFilter/lib/Scheduler.cpp new file mode 100644 index 0000000..260729a --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/lib/Scheduler.cpp @@ -0,0 +1,185 @@ +#include "Scheduler.h" + +typedef struct { + Scheduler *scheduler; + ProcessWrapper *process; +} ProcessArgs; + + +void* runProcessWrapperWrapper(void* arg) { + ProcessArgs *args = (ProcessArgs*)arg; + (args->scheduler)->runProcessWrapper(args->process); + delete args; + return 0; +} + + +void *scheduleWrapper(void *arg) { + ((Scheduler*)arg)->schedule(); + return 0; +} + + +Scheduler::Scheduler() { + //std::cout << "Create Scheduler." << std::endl; + _listsMutex = new Mutex(); + _listsCondition = new Condition(_listsMutex); + _mapsMutex = new Mutex(); + _mapsCondition = new Condition(_mapsMutex); + _processMap = new std::map(); + _notificationEventMap = new std::map(); + _scheduleList = new std::list(); + _detachList = new std::list(); + _stopScheduler = false; + _allStarted = false; +} + + +Scheduler::~Scheduler() { + delete _listsCondition; + delete _listsMutex; + delete _mapsCondition; + delete _mapsMutex; + delete _processMap; + delete _notificationEventMap; + delete _scheduleList; + delete _detachList; +} + + +void Scheduler::registerProcess(ProcessWrapper *process) { + pthread_t *newThread = new pthread_t; + _processMap->insert(std::pair + (process, newThread)); + Event *newNotificationEvent = + new Event("notificationEvent for " + std::string(process->getName())); + _notificationEventMap->insert(std::pair + (process, newNotificationEvent)); + process->initialize(); +} + + +void Scheduler::run() { + _mapsMutex->lock(); + + pthread_t scheduleThread; + if (pthread_create(&scheduleThread, NULL, scheduleWrapper, this)) { + std::cout << "Error: Could not start scheduler thread." + << std::endl; + std::cout << "Exit." << std::endl; + exit(1); + } + std::map::iterator iterator; + for (iterator = _processMap->begin(); + iterator != _processMap->end(); + iterator++) { + + pthread_t *thread = (*iterator).second; + + pthread_attr_t attributes; + pthread_attr_init(&attributes); + pthread_attr_setstacksize(&attributes, 131072); + + ProcessArgs *args = new ProcessArgs; + args->scheduler = this; + args->process = (*iterator).first; + //std::cout << "Starting process " + // << ((ProcessWrapper*)args->process)->getName() + // << "." << std::endl; + if (pthread_create(thread, &attributes, runProcessWrapperWrapper, args)) { + std::cout << "Error: Could not start thread for process " + << ((ProcessWrapper*)(args->process))->getName() + << "." << std::endl; + std::cout << "Exit." << std::endl; + exit(1); + } + pthread_attr_destroy(&attributes); + + //std::cout << "Started process " + // << ((ProcessWrapper*)(args->process))->getName() + // << "." << std::endl; + } + _mapsMutex->unlock(); + + //std::cout << "Started all registered processes." << std::endl; + _allStarted = true; + _listsCondition->notify(); + //std::cout << "Wait until scheduler has stopped." << std::endl; + + //wait until all processes have been detached + pthread_join(scheduleThread, 0); + + //std::cout << "Scheduler has stopped." << std::endl; +} + + +void Scheduler::runProcessWrapper(ProcessWrapper *process) { + Event *_notificationEvent = (*_notificationEventMap)[process]; + + while (!process->isDetached()) { + _listsMutex->lock(); + _scheduleList->push_back(process); + _listsCondition->notify(); + _listsMutex->unlock(); + _notificationEvent->wait(); + process->fire(); + } + + _listsMutex->lock(); + _detachList->push_back(process); + _listsMutex->unlock(); + _listsCondition->notify(); +} + + +void Scheduler::detachProcess(ProcessWrapper *process) { + _mapsMutex->lock(); + pthread_t *threadToKill = (*_processMap)[process]; + pthread_join(*threadToKill, 0); + delete threadToKill; + _processMap->erase(process); + + Event *notificationEventToKill = (*_notificationEventMap)[process]; + delete notificationEventToKill; + _notificationEventMap->erase(process); + + if (_processMap->empty()) { + //std::cout << "No processes left in process map. Terminate." + // << std::endl; + _stopScheduler = true; + } + _mapsMutex->unlock(); +} + + +void Scheduler::schedule() { + _listsMutex->lock(); + + while(!_stopScheduler) { + _listsCondition->wait(); + + if (_allStarted) { + std::list::iterator listIterator; + for (listIterator = _detachList->begin(); + listIterator != _detachList->end(); + listIterator++) { + ProcessWrapper *process = (*listIterator); + detachProcess(process); + //std::cout << "Scheduler detached process " + // << process->getName() << "." << std::endl; + } + _detachList->clear(); + + for (listIterator = _scheduleList->begin(); + listIterator != _scheduleList->end(); + listIterator++) { + ProcessWrapper *process = (*listIterator); + ((Event*)(*_notificationEventMap)[process])->notifyAfterWait(); + } + _scheduleList->clear(); + } + } + + _listsMutex->unlock(); + //std::cout << "Stopped scheduler." << std::endl; +} diff --git a/dol/src/dol/visitor/PipeAndFilter/lib/Scheduler.h b/dol/src/dol/visitor/PipeAndFilter/lib/Scheduler.h new file mode 100644 index 0000000..791f6f0 --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/lib/Scheduler.h @@ -0,0 +1,35 @@ +#ifndef _SCHEDULER_H_ +#define _SCHEDULER_H_ + +#include +#include +#include +#include "Event.h" +#include "ProcessWrapper.h" + +class Scheduler +{ + public: + Scheduler(); + virtual ~Scheduler(); + + void registerProcess(ProcessWrapper *process); + void run(); + void runProcessWrapper(ProcessWrapper *process); + void detachProcess(ProcessWrapper *process); + void schedule(); + + protected: + Mutex *_listsMutex; + Condition *_listsCondition; + Mutex *_mapsMutex; + Condition *_mapsCondition; + std::map *_processMap; + std::map *_notificationEventMap; + std::list *_scheduleList; + std::list *_detachList; + bool _stopScheduler; + bool _allStarted; +}; + +#endif diff --git a/dol/src/dol/visitor/PipeAndFilter/lib/WindowedFifo.cpp b/dol/src/dol/visitor/PipeAndFilter/lib/WindowedFifo.cpp new file mode 100644 index 0000000..ddeb970 --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/lib/WindowedFifo.cpp @@ -0,0 +1,304 @@ +#include "WindowedFifo.h" +#include + +/** + * + */ +WindowedFifo::WindowedFifo(char* name, unsigned size = 20) { + //std::cout << "Create WindowedFifo." << std::endl; + _size = size; + _buffer = new char[_size]; + _head = 0; + _tail = 0; + _headRoom = 0; + _tailRoom = 0; + _use = 0; + //indicates whether Fifo is empty or full if _head == _tail + //_isFull = false; + _isHeadReserved = false; + _isTailReserved = false; + _name = new char[strlen(name) + 1]; + strcpy(_name, name); + _mutex = new Mutex(); + _readCondition = new Condition(_mutex); + _writeCondition = new Condition(_mutex); +} + +/** + * + */ +WindowedFifo::~WindowedFifo() { + //std::cout << "Delete WindowedFifo." << std::endl; + if (_buffer) { + delete _buffer; + } + if (_name) { + delete _name; + } + if (_readCondition) { + delete _readCondition; + } + if (_writeCondition) { + delete _writeCondition; + } + if (_mutex) { + delete _mutex; + } + _buffer = 0; + _head = 0; + _tail = 0; + _name = 0; + _use = 0; + _readCondition = 0; + _writeCondition = 0; + _mutex = 0; + //std::cout << "Deleted WindowedFifo." << std::endl; +} + +/** + * + */ +unsigned WindowedFifo::reserve(void** dest, unsigned len) { + char** destination = (char**)dest; + //std::cout << "Attempt to reserve " << len << " bytes." << std::endl; + + //can only reserve once piece at a time + if (_isHeadReserved) { + *destination = 0; + return 0; + } + + _mutex->lock(); + while (unused() == 0) { + _readCondition->wait(); + } + + //reserve at most as much memory as still available in the buffer + unsigned write = (len <= _size - _use ? len : _size - _use); + + if ( write > 0 ) { + //if wrap-around in buffer: return only buffer for the + //contiguous buffer space + if (_head + write > _size) { + write = _size - _head; + } + + _headRoom = (_head + write) == _size? 0 : _head + write; + *destination = &(_buffer[_head]); + _isHeadReserved = true; + + //the following comparison is unsafe in a multi-threaded + //environment and potentially leads to race-conditions + /*if (_headRoom == _tail) { + _isFull = true; + } else { + _isFull = false; + }*/ + } + _writeReserve = write; + _mutex->unlock(); + + //std::cout << "Reserved " << write << " bytes." << std::endl; + return write; +} + +/** + * + */ +void WindowedFifo::release() { + if (_isHeadReserved) { + //std::cout << "Released " << _headRoom - _head << " bytes." << std::endl; + _head = _headRoom; + _use += _writeReserve; + _isHeadReserved = false; + _writeCondition->notify(); + } +} + +/** + * + */ +unsigned WindowedFifo::capture(void **dest, unsigned len) { + char** destination = (char**)dest; + //std::cout << "Attempt to capture " << len << " bytes." << std::endl; + + if (_isTailReserved) { + //std::cout << "Only one attempt to capture allowed." << std::endl; + *destination = 0; + return 0; + } + + _mutex->lock(); + while (used() == 0) { + _writeCondition->wait(); + } + + //capture at most as much data as available in the buffer + unsigned read = (len <= _use ? len : _use); + + if (read > 0) { + //if wrap-around in buffer: return only buffer for the + //contiguous buffer space + if (_tail + read> _size) { + read = _size - _tail; + } + + _tailRoom = (_tail + read) == _size ? 0 : _tailRoom = _tail + read; + *destination = &(_buffer[_tail]); + _isTailReserved = true; + } + _readReserve = read; + _mutex->unlock(); + //std::cout << "Captured " << read << " bytes." << std::endl; + + return read; +} + +/** + * + */ +void WindowedFifo::consume() { + _mutex->lock(); + if (_isTailReserved) { + //std::cout << "Consumed " << _tailRoom - _tail << " bytes." << std::endl; + _tail = _tailRoom; + //_isFull = false; + _use -= _readReserve; + _isTailReserved = false; + _readCondition->notify(); + } + _mutex->unlock(); +} + +/** + * + */ +unsigned WindowedFifo::size() const { + return _size; +} + +/** + * + */ +unsigned WindowedFifo::unused() const { + return _size - _use; +} + +/** + * + */ +unsigned WindowedFifo::used() const { + return _use; + /*if (_headRoom > _tail) { + return _headRoom - _tail; + } else if (_headRoom == _tail) { + if (_isFull == true) { + return _size; + } else { + return 0; + } + } + return _headRoom + _size - _tail;*/ +} + +/** + * + */ +char* WindowedFifo::getName() const { + return _name; +} + +/** + * Test the implementation + */ +/* +#include +#include +#define LENGTH 10 + +void* producer(void *fifo) +{ + WindowedFifo* wfifo = (WindowedFifo*)fifo; + for (int j = 0; j < LENGTH; j++) { + //std::cout << "write " << i << " to Fifo. "; + int *buf1; + int write = wfifo->reserve((void**)&buf1, sizeof(int)); + + if (write == sizeof(int)) { + *buf1 = j; + wfifo->release(); + //std::cout << "used: " << std::setw(2) << wfifo->used() + // << ", unused: " << std::setw(2) << wfifo->unused() + // << ", size: " << std::setw(2) << wfifo->size() + // << std::endl; + } else { + std::cout << "Not successful: " << write << std::endl; + } + } + printf("producer returns.\n"); + return 0; +} + +void* consumer(void *fifo) +{ + WindowedFifo* wfifo = (WindowedFifo*)fifo; + for (int j = 0; j < LENGTH; j++) { + int* buf3; + int read = wfifo->capture((void**)&buf3, sizeof(int)); + if (read == sizeof(int)) { + std::cout << "read " << (unsigned)*buf3 << " from WindowedFifo "; + std::cout << "used: " << std::setw(2) << wfifo->used() + << ", unused: " << std::setw(2) << wfifo->unused() + << ", size: " << std::setw(2) << wfifo->size() + << std::endl; + wfifo->consume(); + } else { + std::cout << "Read nothing from WindowedFifo." << std::endl; + } + } + printf("consumer returns.\n"); + return 0; +} + +int main() { + WindowedFifo *wfifo = new WindowedFifo("fifo", 12); + + int* buf1; + int* buf2; + wfifo->reserve((void**)&buf1, 8); + *buf1 = 10; + *(buf1 + 1) = 20; + wfifo->release(); + wfifo->capture((void**)&buf2, 8); + std::cout << "read " << *buf2 << " " << *(buf2 + 1) << std::endl; + wfifo->consume(); + + pthread_t *producer_thread = new pthread_t; + pthread_t *consumer_thread = new pthread_t; + + pthread_attr_t attributes; + pthread_attr_init(&attributes); + pthread_attr_setstacksize(&attributes, 131072); + + if (pthread_create(consumer_thread, &attributes, consumer, wfifo)) { + std::cout << "Error: Could not start consumer." << std::endl; + std::cout << "Exit." << std::endl; + exit(1); + } + pthread_attr_destroy(&attributes); + + pthread_attr_init(&attributes); + pthread_attr_setstacksize(&attributes, 131072); + if (pthread_create(producer_thread, &attributes, producer, wfifo)) { + std::cout << "Error: Could not start producer." << std::endl; + std::cout << "Exit." << std::endl; + exit(1); + } + pthread_attr_destroy(&attributes); + + + pthread_join(*consumer_thread, 0); + delete wfifo; + return 0; +} +*/ diff --git a/dol/src/dol/visitor/PipeAndFilter/lib/WindowedFifo.h b/dol/src/dol/visitor/PipeAndFilter/lib/WindowedFifo.h new file mode 100644 index 0000000..edab527 --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/lib/WindowedFifo.h @@ -0,0 +1,41 @@ +#ifndef _WINDOWEDFIFO_H_ +#define _WINDOWEDFIFO_H_ + +#include "Mutex.h" +#include "Condition.h" + +class WindowedFifo { + public: + WindowedFifo(char* name, unsigned size); + virtual ~WindowedFifo(); + + virtual unsigned reserve(void** destination, unsigned len); + virtual void release(); + + virtual unsigned capture(void** destination, unsigned len); + virtual void consume(); + + virtual unsigned used() const; + virtual unsigned unused() const; + virtual unsigned size() const; + virtual char* getName() const; + + protected: + char *_buffer; + unsigned _head; + unsigned _tail; + unsigned _headRoom; + unsigned _tailRoom; + unsigned _size; + unsigned _use; + unsigned _writeReserve; + unsigned _readReserve; + //bool _isFull; + bool _isHeadReserved; + bool _isTailReserved; + char *_name; + Mutex *_mutex; + Condition *_readCondition, *_writeCondition; +}; + +#endif diff --git a/dol/src/dol/visitor/PipeAndFilter/lib/dol.h b/dol/src/dol/visitor/PipeAndFilter/lib/dol.h new file mode 100644 index 0000000..8fbefe4 --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/lib/dol.h @@ -0,0 +1,39 @@ +#ifndef DOL_H +#define DOL_H + +/************************************************************************ + * do not add code to this header + ************************************************************************/ + +/** + * Define the DOL process handler scheme. + * - Local variables are defined in structure LocalState. Local + * variables may vary from different processes. + * - The ProcessInit function pointer points to a function which + * initializes a process. + * - The ProcessFire function pointer points to a function which + * performs the actual computation. The communication between + * processes is inside the ProcessFire function. + * - The WPTR is a placeholder for callback. One can just + * leave it blank. + */ + +//structure for local memory of process +typedef struct _local_states *LocalState; + +//additional behavioral functions could be declared here +typedef void (*ProcessInit)(struct _process*); +typedef int (*ProcessFire)(struct _process*); +typedef void *WPTR; + +//process handler +struct _process; + +typedef struct _process { + LocalState local; + ProcessInit init; + ProcessFire fire; + WPTR wptr; //placeholder for wrapper instance +} DOLProcess; + +#endif diff --git a/dol/src/dol/visitor/PipeAndFilter/lib/dolSupport.cpp b/dol/src/dol/visitor/PipeAndFilter/lib/dolSupport.cpp new file mode 100644 index 0000000..1359379 --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/lib/dolSupport.cpp @@ -0,0 +1,133 @@ +#include "dolSupport.h" +#include "ProcessWrapper.h" + +/** + * + */ +unsigned write(void *port, void *buf, unsigned len, DOLProcess *process) +{ + Fifo *fifo = static_cast(port); + char *str = static_cast(buf); + fifo->write((void*)str, len); + return len; +} + + +/** + * + */ +unsigned read(void *port, void *buf, unsigned len, DOLProcess *process) { + Fifo *fifo = static_cast(port); + char *str = static_cast(buf); + fifo->read((void*)str, len); + return len; +} + + +/** + * + */ +int wtest(void *port, unsigned len, DOLProcess *process) { + Fifo *fifo = static_cast(port); + return (fifo->unused() >= len) ? 1 : 0; +} + + +/** + * + */ +int rtest(void *port, unsigned len, DOLProcess *process) { + Fifo *fifo = static_cast(port); + return (fifo->used() >= len) ? 1 : 0; +} + + +/** + * + */ +unsigned reserve(void* fifo, void** destination, unsigned len, DOLProcess* p) { + return ((WindowedFifo*)fifo)->reserve(destination, len); +} + +/** + * + */ +void release(void* fifo, DOLProcess* p) { + ((WindowedFifo*)fifo)->release(); +} + +/** + * + */ +unsigned capture(void* fifo, void** destination, unsigned len, DOLProcess* p) { + return ((WindowedFifo*)fifo)->capture(destination, len); +} + +/** + * + */ +void consume(void* fifo, DOLProcess* p) { + ((WindowedFifo*)fifo)->consume(); +} + + +/** + * + */ +void DOL_detach(DOLProcess* p) { + static_cast(p->wptr)->detach(); +} + + +/** + * + */ +void createPort(void** port, + void* base, + int number_of_indices, + int index0, int range0) { + *port = (void**)((void**)base)[index0]; +} + + +/** + * + */ +void createPort(void** port, + void* base, + int number_of_indices, + int index0, int range0, + int index1, int range1) { + *port = (void**)((void**)base)[index0 * range1 + index1]; +} + + +/** + * + */ +void createPort(void** port, + void* base, + int number_of_indices, + int index0, int range0, + int index1, int range1, + int index2, int range2) { + *port = (void**)((void**)base)[index0 * range1 * range2 + + index1 * range2 + index2]; +} + + +/** + * + */ +void createPort(void** port, + void* base, + int number_of_indices, + int index0, int range0, + int index1, int range1, + int index2, int range2, + int index3, int range3) { + *port = (void**)((void**)base)[index0 * range1 * range2 * range3 + + index1 * range2 * range3 + + index2 * range3 + + index3]; +} diff --git a/dol/src/dol/visitor/PipeAndFilter/lib/dolSupport.h b/dol/src/dol/visitor/PipeAndFilter/lib/dolSupport.h new file mode 100644 index 0000000..3430033 --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/lib/dolSupport.h @@ -0,0 +1,151 @@ +#ifndef DOLSUPPORT_H +#define DOLSUPPORT_H + +#include "dol.h" +#include "Fifo.h" +#ifdef INCLUDE_PERFORMANCE +#include "Performance_Extraction.h" +#elif INCLUDE_TRACE +#include "functional_trace.h" +#endif + +#ifdef INCLUDE_PERFORMANCE +#define DOL_write(port, buf, len, process) {\ + (static_cast(p->wptr))->end_line = __LINE__;\ + get_current_time(&((static_cast(p->wptr))->\ + end_time));\ + performance_extraction.add_computation_performance(\ + (static_cast(p->wptr))->basename(),\ + (static_cast(p->wptr))->start_line,\ + (static_cast(p->wptr))->end_line,\ + &((static_cast(p->wptr))->start_time),\ + &((static_cast(p->wptr))->end_time));\ + write(port, buf, len, process);\ + (static_cast(p->wptr))->start_line = __LINE__;\ + get_current_time(&((static_cast(p->wptr))->\ + start_time)); } +#define DOL_read(port, buf, len, process) {\ + (static_cast(p->wptr))->end_line = __LINE__;\ + get_current_time(&((static_cast(p->wptr))->\ + end_time));\ + performance_extraction.add_computation_performance(\ + (static_cast(p->wptr))->basename(),\ + (static_cast(p->wptr))->start_line,\ + (static_cast(p->wptr))->end_line,\ + &((static_cast(p->wptr))->start_time),\ + &((static_cast(p->wptr))->end_time));\ + read(port, buf, len, process);\ + (static_cast(p->wptr))->start_line = __LINE__;\ + get_current_time(&((static_cast(p->wptr))->\ + start_time)); } +#elif INCLUDE_TRACE +#define DOL_write(port, buf, len, process) {\ + (static_cast(p->wptr))->end_line = __LINE__;\ + dol_functional_trace.create_computation_event(\ + (static_cast(p->wptr))->basename(),\ + (static_cast(p->wptr))->start_line,\ + (static_cast(p->wptr))->end_line);\ + write(port, buf, len, process);\ + dol_functional_trace.create_write_event(\ + (static_cast(p->wptr))->basename(), len,\ + (static_cast(p->wptr))->channel_name);\ + (static_cast(p->wptr))->start_line = __LINE__; } +#define DOL_read(port, buf, len, process) {\ + (static_cast(p->wptr))->end_line = __LINE__;\ + dol_functional_trace.create_computation_event(\ + (static_cast(p->wptr))->basename(),\ + (static_cast(p->wptr))->start_line,\ + (static_cast(p->wptr))->end_line);\ + read(port, buf, len, process);\ + dol_functional_trace.create_read_event(\ + (static_cast(p->wptr))->basename(), len,\ + (static_cast(p->wptr))->channel_name);\ + (static_cast(p->wptr))->start_line = __LINE__; } +#else + #define DOL_write(port, buf, len, process) \ + write(port, buf, len, process) + #define DOL_read(port, buf, len, process) \ + read(port, buf, len, process) +#endif + +#define DOL_reserve(port, buf, size, process) \ + reserve(port, (void**)buf, size, process); + +#define DOL_release(port, process) \ + release(port, process); + +#define DOL_capture(port, buf, size, process) \ + capture(port, (void**)buf, size, process); + +#define DOL_consume(port, process) \ + consume(port, process); + +#define DOL_wtest(port, len, process) wtest(port, len, process) + +#define DOL_rtest(port, len, process) rtest(port, len, process) + +void DOL_detach(DOLProcess* p); + +//fifo access functions +unsigned write(void* fifo, void* buf, unsigned len, DOLProcess* p); +unsigned read(void* fifo, void* buf, unsigned len, DOLProcess* p); +int wtest(void *port, unsigned len, DOLProcess *process); +int rtest(void *port, unsigned len, DOLProcess *process); + +//windowed fifo access functions +unsigned reserve(void* fifo, void** destination, unsigned len, DOLProcess* p); +void release(void* fifo, DOLProcess* p); +unsigned capture(void* fifo, void** destination, unsigned len, DOLProcess* p); +void consume(void* fifo, DOLProcess* p); + + +void createPort(void **port, + void *base, + int number_of_indices, + int index0, int range0); + +void createPort(void **port, + void *base, + int number_of_indices, + int index0, int range0, + int index1, int range1); + +void createPort(void **port, + void *base, + int number_of_indices, + int index0, int range0, + int index1, int range1, + int index2, int range2); + +void createPort(void **port, + void *base, + int number_of_indices, + int index0, int range0, + int index1, int range1, + int index2, int range2, + int index3, int range3); + +#define GETINDEX(dimension) \ + static_cast(p->wptr)->getIndex(dimension) + +/** + * macro to create a variable to store a port name + * + * @param name name of the variable + */ +#define CREATEPORTVAR(name) Fifo *name + +/** + * Create the port name of an iterated port based on its basename and the + * given indices. + * + * @param port buffer where the result is stored (created using + * CREATEPORTVAR) + * @param base basename of the port + * @param number_of_indices number of dimensions of the port + * @param index_range_pairs index and range values for each dimension + */ +#define CREATEPORT(port, base, number_of_indices, index_range_pairs...) \ + createPort((void**)(&port), base, number_of_indices, index_range_pairs) + +#endif diff --git a/dol/src/dol/visitor/PipeAndFilter/package.html b/dol/src/dol/visitor/PipeAndFilter/package.html new file mode 100644 index 0000000..91e4bd2 --- /dev/null +++ b/dol/src/dol/visitor/PipeAndFilter/package.html @@ -0,0 +1,20 @@ + + + + + + +Code generator for functional simulation using threads for execution (no SystemC required). + +

Package Specification

+ + + +

Related Documentation

+ + + + + + + diff --git a/dol/src/dol/visitor/Visitor.java b/dol/src/dol/visitor/Visitor.java new file mode 100644 index 0000000..3af1dd8 --- /dev/null +++ b/dol/src/dol/visitor/Visitor.java @@ -0,0 +1,9 @@ +/* $Id: Visitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor; + +/** + * This class is a marker Class, to indicate that derived classes are all + * visitor. + */ +public interface Visitor { +} diff --git a/dol/src/dol/visitor/cbe/CbeBuildFileVisitor.java b/dol/src/dol/visitor/cbe/CbeBuildFileVisitor.java new file mode 100644 index 0000000..4500d91 --- /dev/null +++ b/dol/src/dol/visitor/cbe/CbeBuildFileVisitor.java @@ -0,0 +1,109 @@ +/* $Id: CbeBuildFileVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.cbe; + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.Vector; + +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate the build + * file for the application on the CBE (i.e. a bash file for the CBE) + * + * @author lschor, 2008-10-30 + * + * Revision: + * 2008-10-30: Updated the file for the CBE + * 2008-11-08: Add double buffering + */ +public class CbeBuildFileVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir path of the Makefile + */ + public CbeBuildFileVisitor(String dir) { + _dir = dir; + } + + /** + * Create a Makefile for the given process network. + * + * @param pn process network + */ + public void visitComponent(ProcessNetwork pn) { + try { + String filename = _dir + _delimiter + "pncbe.sh"; + OutputStream file = new FileOutputStream(filename); + PrintStream ps = new PrintStream(file); + + // General information / notes and commands + ps.println("#!/bin/bash"); + ps.println("clear"); + ps.println(); + ps.println("# Bash file to run a DOL application on the CBE"); + ps.println("# Start the CBE-Simulator and enter the " + + "following commands: "); + ps.println("# callthru source /pncbe.sh > pncbe.sh"); + ps.println("# for example: callthru source /opt/cell/sdk/src/" + + "tutorial/pn_test/pncbe.sh > pncbe.sh"); + ps.println("# chmod +x pncbe.sh"); + ps.println(); + ps.println("# To run the DOL application, use the following " + + "command: "); + ps.println("# ./pncbe.sh"); + ps.println(); + ps.println("# Folder in which the application is stored"); + ps.println("FOLDER=/opt/cell/sdk/src/tutorial/pn_test"); + ps.println(); + + // Go through each process and copy its data to the Cell + String subdirectory = ""; + String applicationName = ""; + Vector pList = new Vector(); + + for (Process process : pn.getProcessList()) { + String basename = process.getBasename(); + if (!pList.contains(basename) + && process.getNumOfInports() > 0 + && process.getNumOfOutports() > 0) { + subdirectory = "spu_" + basename; + applicationName = subdirectory + "/spu_" + + basename + "_wrapper"; + + ps.println("# " + basename); + ps.println("if [ ! -d " + subdirectory + " ]; then"); + ps.println("\tmkdir " + subdirectory); + ps.println("fi;"); + ps.println("callthru source $FOLDER/" + + applicationName + " > " + applicationName); + ps.println("chmod +x " + applicationName); + ps.println(); + pList.add(basename); + } + } + + // Load also the main application to the CBE + ps.println("# Main program"); + ps.println("callthru source $FOLDER/ppu_main > ppu_main"); + ps.println("chmod +x ppu_main"); + ps.println(); + + // Run the main program + ps.println("# run the main program"); + ps.println("./ppu_main"); + } catch (Exception e) { + System.out.println("CbeMakefileVisitor: exception occured: " + + e.getMessage()); + e.printStackTrace(); + } + } + + protected String _dir = null; +} diff --git a/dol/src/dol/visitor/cbe/CbeConstantVisitor.java b/dol/src/dol/visitor/cbe/CbeConstantVisitor.java new file mode 100644 index 0000000..594673b --- /dev/null +++ b/dol/src/dol/visitor/cbe/CbeConstantVisitor.java @@ -0,0 +1,102 @@ +/* $Id: CbeConstantVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.cbe; + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.util.HashMap; + +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.main.UserInterface; +import dol.util.CodePrintStream; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a constant file + * + * @author lschor, 2008-11-08 + * + * Revision: + * 2008-11-08: Created + */ +public class CbeConstantVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir path of this file + */ + public CbeConstantVisitor(String dir, HashMap portMap) { + _dir = dir; + _portMap = portMap; + } + + /** + * Visit process network. + * + * @param x process network that needs to be rendered + */ + public void visitComponent(ProcessNetwork x) { + try { + _ui = UserInterface.getInstance(); + String filename = _dir + _delimiter + "lib" + _delimiter + + "constant.h"; + OutputStream file = new FileOutputStream(filename); + _mainPS = new CodePrintStream(file); + + int numSpes = 0; + + for (Process p : x.getProcessList()) + { + if (p.getNumOfInports() > 0 && p.getNumOfOutports() > 0) + numSpes++; + } + + //create header section + _mainPS.println("// ========================"); + _mainPS.println("// constant.c file"); + _mainPS.println("// ========================"); + + //includes + _mainPS.println("#include "); + + //define the number of FIFO queues and the number of processes + _mainPS.println("#ifndef _CONSTANT_H_"); + _mainPS.println("#define _CONSTANT_H_"); + _mainPS.println(""); + _mainPS.println("#define NUM_PROCS " + + x.getProcessList().size()); + _mainPS.println("#define NUM_SPES " + numSpes); + _mainPS.println("#define NUM_FIFO " + + x.getChannelList().size()); + _mainPS.println(""); + _mainPS.println("#endif // _CONSTANT_H_ "); + _mainPS.println(""); + } + catch (Exception e) { + System.out.println("CbeModuleVisitor: exception occured: " + + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * + * @param x process that needs to be processed + */ + public void visitComponent(Process x) { + } + + /** + * + * @param x channel that needs to be processed + */ + public void visitComponent(Channel x) { + } + + protected CodePrintStream _mainPS = null; + protected String _dir = null; + protected HashMap _portMap; +} diff --git a/dol/src/dol/visitor/cbe/CbeMakefileVisitor.java b/dol/src/dol/visitor/cbe/CbeMakefileVisitor.java new file mode 100644 index 0000000..45a4f2a --- /dev/null +++ b/dol/src/dol/visitor/cbe/CbeMakefileVisitor.java @@ -0,0 +1,151 @@ +/* $Id: CbeMakefileVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.cbe; + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.Vector; + +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate a CBE + * package Makefile. + */ +public class CbeMakefileVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir path of the Makefile + */ + public CbeMakefileVisitor(String dir) { + _dir = dir; + } + + /** + * Create a Makefile for the given process network. + * + * @param pn process network + */ + public void visitComponent(ProcessNetwork pn) { + try { + String filename = _dir + _delimiter + "Makefile"; + OutputStream file = new FileOutputStream(filename); + PrintStream ps = new PrintStream(file); + + ps.println("##############################################"); + ps.println("# Main Makefile for DOL application on the CBE"); + ps.println("##############################################"); + ps.println(); + ps.println("# Subdirectories"); + + String subdirectories = ""; + Vector pList = new Vector(); + for (Process process : pn.getProcessList()) { + String basename = process.getBasename(); + if (!pList.contains(basename)) { + if (process.getNumOfInports() > 0 + && process.getNumOfOutports() > 0) { + subdirectories += "spu_" + basename + " "; + } + pList.add(basename); + } + } + pList.clear(); + + String linkList = ""; + String srcList = ""; + for (Process process : pn.getProcessList()) { + String basename = process.getBasename(); + if (!pList.contains(basename)) { + if (!(process.getNumOfInports() > 0 + && process.getNumOfOutports() > 0)) { + linkList += "ppu_" + basename + "/ppu_" + basename + + ".o "; + srcList += "$(wildcard ppu_" + basename + + "/*.c) "; + + } + pList.add(basename); + } + } + pList.clear(); + + ps.println("DIRS\t := " + subdirectories); + ps.println(""); + + ps.println("# General definitions:"); + ps.println("CC = ppu-g++"); + ps.println("CCFLAGS = -ftree-vectorize -O3 -maltivec " + + "-funroll-loops -mabi=altivec -mcpu=cell"); + ps.println("COMPILE = $(CC) $(CCFLAGS) -c"); + ps.println("LINK = $(CC) -lspe2 -lpthread"); + ps.println("CBE_INCLUDE = /opt/cell/sdk/src/include/ppu"); + ps.println("LIB_INC = -I lib -I . -I $(CBE_INCLUDE)"); + ps.println("RM = rm"); + ps.println("ECHO = echo"); + ps.println("EXE = ppu_main"); + ps.println(""); + ps.println("src := $(wildcard lib/*.c) $(wildcard *.c)"); + ps.println("srcAll := $(wildcard lib/*.c) " + + "$(wildcard lib/*.c) " + srcList); + ps.println("obj = $(src:.c=.o)"); + ps.println(""); + ps.println("$(EXE): $(obj) $(srcAll)"); + ps.println("\tfor d in $(DIRS); do (cd $$d; $(MAKE) ); done"); + + for (Process process : pn.getProcessList()) { + String basename = process.getBasename(); + if (!pList.contains(basename)) { + if (!(process.getNumOfInports() > 0 + && process.getNumOfOutports() > 0)) { + ps.println("\tcd ppu_" + basename + + "; $(COMPILE) -o ppu_" + basename + + ".o ppu_" + basename + + "_wrapper.c -I .. -I ../lib;"); + } + pList.add(basename); + } + } + pList.clear(); + + ps.println("\t$(LINK) -o $(EXE) " + linkList + " $(obj)"); + ps.println(""); + ps.println("%.o :"); + ps.println("\t$(COMPILE) -o $(*D)/$(*F).o $(*D)/$(*F).c " + + "$(LIB_INC)"); + ps.println(""); + ps.println("clean:"); + ps.println("\tfor d in $(DIRS); do (cd $$d; $(MAKE) clean );" + + " done"); + ps.println("\trm $(obj) "); + + for (Process process : pn.getProcessList()) { + String basename = process.getBasename(); + if (!pList.contains(basename)) { + if (!(process.getNumOfInports() > 0 + && process.getNumOfOutports() > 0)) + { + ps.println("\trm ppu_" + basename + "/ppu_" + + basename + ".o"); + } + pList.add(basename); + } + } + pList.clear(); + + ps.println("\trm ppu_main"); + ps.println(""); + + } catch (Exception e) { + System.out.println("CbeMakefileVisitor: exception occured: " + + e.getMessage()); + e.printStackTrace(); + } + } + + protected String _dir = null; +} diff --git a/dol/src/dol/visitor/cbe/CbeModuleVisitor.java b/dol/src/dol/visitor/cbe/CbeModuleVisitor.java new file mode 100644 index 0000000..7987bfc --- /dev/null +++ b/dol/src/dol/visitor/cbe/CbeModuleVisitor.java @@ -0,0 +1,417 @@ +/* $Id: CbeModuleVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.cbe; + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Vector; + +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.main.UserInterface; +import dol.util.CodePrintStream; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate + * the main program. + * + * @author lschor, 2008-10-30 + * + * Revision: + * 2008-10-30: Updated the file for the CBE + * 2008-11-08: Add double buffering + * 2008-11-16: Add new fifo implementation and defines for measurement + * 2008-11-21: Sink/Source do not run on the SPE, but on the PPE (as Linux + * thread) + */ +public class CbeModuleVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir path of this file + */ + public CbeModuleVisitor(String dir, HashMap portMap) { + _dir = dir; + _portMap = portMap; + } + + /** + * Visit process network. + * + * @param x process network that needs to be rendered + */ + public void visitComponent(ProcessNetwork x) { + try { + _ui = UserInterface.getInstance(); + String filename = _dir + _delimiter + "ppu_main.c"; + OutputStream file = new FileOutputStream(filename); + _mainPS = new CodePrintStream(file); + + //create header section + _mainPS.println("// ========================"); + _mainPS.println("// ppu_main.c file"); + _mainPS.println("// ========================"); + _mainPS.println(""); + + // Includes + _mainPS.println("#include \"ppu_main.h\""); + _mainPS.println(""); + + _mainPS.println(""); + _mainPS.println("// include main function for a workloop"); + _mainPS.println("#include \"ppu_main_workloop.h\""); + _mainPS.println(""); + + // Function to create and run one SPE thread + _mainPS.println("// create and run one SPE thread"); + _mainPS.println("void *spu_pthread(void *arg) {"); + _mainPS.println("\t spu_data_t *datp = (spu_data_t *)arg;"); + _mainPS.println("\t uint32_t entry = SPE_DEFAULT_ENTRY;"); + _mainPS.println("\t printf(\")PPE: spe thread starts\\n\");"); + _mainPS.println("\t if (spe_context_run(datp->spe_ctx, " + + "&entry, 0, datp->argp, NULL, NULL) < 0) {"); + _mainPS.println("\t\t perror (\"Failed running context\"); " + + "exit (1);"); + _mainPS.println("\t}"); + _mainPS.println("\t printf(\")PPE: spe thread stops\\n\");"); + _mainPS.println("\t pthread_exit(NULL);"); + _mainPS.println("}"); + _mainPS.println(""); + + // Declaration of the Header function for the PPE-Wrappers + Vector processList = new Vector(); + for (Process p : x.getProcessList()) { + String basename = p.getBasename(); + if (!processList.contains(basename)) { + processList.add(basename); + if (!(p.getNumOfInports() > 0 + && p.getNumOfOutports() > 0)) + _mainPS.println("void *" + basename + + "_wrapper( void *ptr );"); + } + } + _mainPS.println(); + + // Create the port_id and the port_queue_id arrays to send + // over the DMA + for (Process process : x.getProcessList()) { + String processName = process.getName(); + _mainPS.println("volatile uint32_t "+ processName + + "_port_id[" + + roundDMA(process.getPortList().size()) + + "] __attribute__ ((aligned(16))); "); + _mainPS.println("volatile uint32_t " + processName + + "_port_queue_id[" + + roundDMA(process.getPortList().size()) + + "] __attribute__ ((aligned(16)));"); + _mainPS.println("volatile char " + processName + + "_name[256] __attribute__ ((aligned(16)));"); + } + _mainPS.println(); + + // Create the main function + _mainPS.println("int main()"); + _mainPS.println("{"); + + // For Measure + _mainPS.println("#ifdef MEASURE_APPLICATION"); + _mainPS.println("\tstruct timeval t_ppe_start, t_ppe_end;"); + _mainPS.println("\tgettimeofday(&t_ppe_start,NULL);"); + _mainPS.println("#endif"); + _mainPS.println(); + + _mainPS.println("#ifdef MEASURE_SET_UP_SPE_THREAD"); + _mainPS.println("\tstruct timeval t_ppe_setup_start, " + + "t_ppe_setup_end;"); + _mainPS.println("\tgettimeofday(&t_ppe_setup_start,NULL);"); + _mainPS.println("#endif"); + _mainPS.println(); + + // List with all process to be open + _mainPS.println("\tchar spe_names[NUM_SPES][60] = {"); + int count = 0; + for (Process process : x.getProcessList()) { + if (process.getNumOfInports() > 0 + && process.getNumOfOutports() > 0) { + count++; + String processName = process.getBasename(); + _mainPS.println("\t\t\"spu_" + processName + "/spu_" + + processName + "_wrapper\"" + + (count == x.getProcessList().size() + ? "" : ", ") ); + } + } + _mainPS.println("\t};"); + _mainPS.println(); + _mainPS.println("\t// Initialize the fifo, we use"); + _mainPS.println("\tint j; "); + _mainPS.println("\tfor (j = 0; j < NUM_FIFO; j++)"); + _mainPS.println("\t{"); + _mainPS.println("\t\tlocBuf[j] = " + + "(char*)malloc(MAXELEMENT * sizeof(char));"); + _mainPS.println("\t\tlocBufCount[j] = 0;"); + _mainPS.println("\t\tlocBufStart[j] = 0;"); + _mainPS.println("\t\tpthread_mutex_init(&(mutex[j]), NULL);"); + _mainPS.println("\t}"); + + //connect ports to channels + HashMap channel_map = + new HashMap(); + + int j = 0; + for (Channel c : x.getChannelList()) { + channel_map.put(c, j++); + } + + // Init the SPE control structure + _mainPS.println("\t//Initiate SPEs control structure"); + _mainPS.println("\tint num = 0; "); + _mainPS.println("\tfor( num=0; num 0 + && process.getNumOfOutports() > 0) { + _mainPS.println("\tctx[" + j + "]" + + ".port_id = (uint64_t)" + + processName + "_port_id;"); + _mainPS.println("\tctx[" + j + "]" + + ".port_queue_id = (uint64_t)" + + processName + "_port_queue_id;"); + _mainPS.println("\tctx[" + j + "]" + + ".number_of_ports = " + i + ";"); + _mainPS.println("\tctx[" + j + "]" + + ".is_detached = 0;"); + _mainPS.println("\tstrcpy((char *)" + processName + + "_name, " + "\"" + + processName + "\");"); + _mainPS.println("\tctx[" + j + "]" + + ".processName = (uint64_t) " + processName + + "_name;"); + _mainPS.println("\tctx[" + j + "]" + + ".processNameLen = ((strlen((char *)" + + processName + "_name) + 15) & ~15);"); + _mainPS.println(); + j++; + } + // Process is Sink or source + else { + _mainPS.println("\tProcessWrapper *" + + process.getName() + + "_Process_Wrapper = (ProcessWrapper*)" + + "malloc(sizeof(ProcessWrapper)); "); + _mainPS.println("\t" + process.getName() + + "_Process_Wrapper->port_id = " + processName + + "_port_id;"); + _mainPS.println("\t" + process.getName() + + "_Process_Wrapper->port_queue_id = " + + processName + "_port_queue_id;"); + _mainPS.println("\t" + process.getName() + + "_Process_Wrapper->number_of_ports = " + + i + ";"); + _mainPS.println("\t" + process.getName() + + "_Process_Wrapper->is_detached = 0;"); + _mainPS.println("\t" + process.getName() + + "_Process_Wrapper->name = (char*)malloc(" + + "strlen(\"" + processName + "\"));"); + _mainPS.println("\tstrcpy(" + process.getName() + + "_Process_Wrapper->name, \"" + processName + + "\");"); + _mainPS.println("\t" + process.getName() + + "_Process_Wrapper->locBuf = locBuf;"); + _mainPS.println("\t" + process.getName() + + "_Process_Wrapper->MAXELEMENT = " + + "MAXELEMENT;"); + _mainPS.println("\t" + process.getName() + + "_Process_Wrapper->locBufCount = " + + "locBufCount;"); + _mainPS.println("\t" + process.getName() + + "_Process_Wrapper->locBufStart = " + + "locBufStart;"); + _mainPS.println("\t" + process.getName() + + "_Process_Wrapper->processFinished = " + + "&processFinished;"); + _mainPS.println("\t" + process.getName() + + "_Process_Wrapper->mutex = mutex;"); + _mainPS.println("\t" + process.getName() + + "_Process_Wrapper->mutexProcessNr = " + + "&mutexProcessNr;"); + _mainPS.println(); + } + } + + _mainPS.println("\t// Loop on all SPEs and for each perform " + + "three steps:"); + _mainPS.println("\t// - create SPE context"); + _mainPS.println("\t// - open images of SPE programs into main " + + "storage"); + _mainPS.println("\t// variable store the " + + "executable name"); + _mainPS.println("\t// - Load SPEs objects into SPE context " + + "local store"); + _mainPS.println("\tfor( num=0; num 0 + && process.getNumOfOutports() > 0)) { + _mainPS.println("\tpthread_t thread_" + + process.getName() + ";"); + _mainPS.println("\tpthread_create( &thread_" + + process.getName() + ", NULL, " + + process.getBasename() + "_wrapper, " + + process.getName() + "_Process_Wrapper);"); + } + } + _mainPS.println("\t"); + + _mainPS.println("\t// create SPE pthreads"); + _mainPS.println("\tfor( num=0; num 16) { + return number + 16 - (number % 16); + } else if (number > 8) { + return 16; + } else if (number > 4) { + return 8; + } else if (number > 2) { + return 4; + } else if (number > 1) { + return 2; + } else { + return 1; + } + } + + protected CodePrintStream _mainPS = null; + protected String _dir = null; + protected HashMap _portMap; +} diff --git a/dol/src/dol/visitor/cbe/CbeProcessVisitor.java b/dol/src/dol/visitor/cbe/CbeProcessVisitor.java new file mode 100644 index 0000000..17044e0 --- /dev/null +++ b/dol/src/dol/visitor/cbe/CbeProcessVisitor.java @@ -0,0 +1,340 @@ +/* $Id: CbeProcessVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.cbe; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.HashMap; +import java.util.Vector; + +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.SourceCode; +import dol.util.CodePrintStream; +import dol.util.Copier; +import dol.util.Sed; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate the main + * makefile for the application. + * + * @author lschor, 2008-10-30 + * + * Revision: + * 2008-10-30: Updated the file for the CBE + * 2008-11-08: Add double buffering + */ +public class CbeProcessVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir target directory + */ + public CbeProcessVisitor(String dir, HashMap portMap) { + _dir = dir; + _portMap = portMap; + } + + /** + * + * @param x process network that needs to be processed + */ + public void visitComponent(ProcessNetwork x) { + try { + Vector pList = new Vector(); + + for (Process p : x.getProcessList()) { + String basename = p.getBasename(); + if (!pList.contains(basename)) { + pList.add(basename); + p.accept(this); + } + } + } catch (Exception e) { + System.out.println("CbeProcessVisitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * Visit process. + * + * @param p process that needs to be processed + */ + public void visitComponent(Process p) + { + // Differ if the process is a source/sink or a normal process + // - Source/Sink: Mapped to the PPE + // - Normal process: Mapped to the SPE + + if (p.getNumOfInports() > 0 && p.getNumOfOutports() > 0) + { + createSPEWrapper(p); + } + else + { + createPPEWrapper(p); + } + } + + /** + * Creates a Wrapper for an SPE process + * + * @param p process that needs to be processed + */ + protected void createSPEWrapper(Process p) + { + try { + + // Create of each process an own folder + // add to this folder the source, the wrapper and a makefile + String processDir = _dir + _delimiter + "spu_" + + p.getBasename(); + File dir = new File(processDir); + dir.mkdirs(); + + // Create the filename for the new wrapper + String filename = processDir + _delimiter + "spu_" + + p.getBasename() + "_wrapper.c"; + File process_file = new File(filename); + File pattern_file = new File(_dir + _delimiter + _tempDirName + + _delimiter + "spu_process_wrapper_template.c"); + new Copier().copyFile(pattern_file, process_file); + + String includes = ""; + for (SourceCode code : p.getSrcList()) { + includes += "#include \"" + code.getLocality() + "\"" + + System.getProperty("line.separator"); + } + + Sed sed = new Sed(); + // Replace the include of the main c-file + sed.sed(filename, "//#include \"@PROCESSNAME@.c\"", includes); + // Replace the process-name in the whole file + sed.sed(filename, "@PROCESSNAME@", p.getBasename()); + + // Go through all source files + for (SourceCode sourceCode : p.getSrcList()) { + // Copy the files to the new folder + String oldFilename = _dir + + _delimiter + + sourceCode.getLocality().replaceAll( + "(.*)\\.[cC][pP]*[pP]*", "$1\\.h"); + filename = processDir + + _delimiter + + sourceCode.getLocality().replaceAll( + "(.*)\\.[cC][pP]*[pP]*", "$1\\.h"); + + if (new File(filename).exists()) { + new File(filename).delete(); + } + + new File(oldFilename).renameTo(new File(filename)); + + // Copy also the c-files + if ((oldFilename.substring(oldFilename.length() - 2)) + .equals(".h")) { + String newFileNameC = filename.substring(0, filename + .length() - 2) + ".c"; + if (new File(newFileNameC).exists()) { + new File(newFileNameC).delete(); + } + new File(oldFilename.substring( + 0, oldFilename.length() - 2) + + ".c").renameTo(new File(newFileNameC)); + } + + // Update the files for the DOL project + sed.sed(filename, "", "\"dol.h\""); + + // Create the port list + for (Port port : p.getPortList()) { + Integer portId = _portMap.get(port); + if (!port.getBasename().equals(port.getName())) { + for (Port port2 : p.getPortList()) { + if (port2.getBasename().equals( + port.getBasename())) { + if (_portMap.get(port2) < + _portMap.get(port)) { + portId = _portMap.get(port2); + } + } + } + } + + // Update the port list with the base names + sed.sed(filename, "(#define[ ]+PORT_\\w*[ ]+)\"?" + + port.getBasename() + "\"?", "$1 " + portId); + } + + // Create the makefile for the process + createMakefile(p); + } + } catch (Exception e) { + System.out.println("CbeProcessVisitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * Creates a Wrapper for an SPE process + * + * @param p process that needs to be processed + */ + protected void createPPEWrapper(Process p) + { + try { + // Create of each process an own folder + // add to this folder the source, the wrapper and a makefile + String processDir = _dir + _delimiter + "ppu_" + + p.getBasename(); + File dir = new File(processDir); + dir.mkdirs(); + + // Create the filename for the new wrapper + String filename = processDir + _delimiter + "ppu_" + + p.getBasename() + "_wrapper.c"; + File process_file = new File(filename); + File pattern_file = new File(_dir + _delimiter + _tempDirName + + _delimiter + "ppu_process_wrapper_template.c"); + new Copier().copyFile(pattern_file, process_file); + + String includes = ""; + for (SourceCode code : p.getSrcList()) { + includes += "#include \"" + code.getLocality() + "\"" + + System.getProperty("line.separator"); + } + + Sed sed = new Sed(); + // Replace the include of the main c-file + sed.sed(filename, "//#include \"@PROCESSNAME@.c\"", includes); + // Replace the process-name in the whole file + sed.sed(filename, "@PROCESSNAME@", p.getBasename()); + + // Go through all source files + for (SourceCode sourceCode : p.getSrcList()) { + // Copy the files to the new folder + String oldFilename = _dir + + _delimiter + + sourceCode.getLocality().replaceAll( + "(.*)\\.[cC][pP]*[pP]*", "$1\\.h"); + filename = processDir + + _delimiter + + sourceCode.getLocality().replaceAll( + "(.*)\\.[cC][pP]*[pP]*", "$1\\.h"); + + if (new File(filename).exists()) { + new File(filename).delete(); + } + + new File(oldFilename).renameTo(new File(filename)); + + // Copy also the c-files + if ((oldFilename.substring(oldFilename.length() - 2)) + .equals(".h")) { + String newFileNameC = filename.substring(0, filename + .length() - 2) + + ".c"; + if (new File(newFileNameC).exists()) { + new File(newFileNameC).delete(); + } + new File(oldFilename.substring( + 0, oldFilename.length() - 2) + + ".c").renameTo(new File(newFileNameC)); + } + + // Update the files for the DOL project + sed.sed(filename, "", "\"dol.h\""); + + // Create the port list + for (Port port : p.getPortList()) { + Integer portId = _portMap.get(port); + if (!port.getBasename().equals(port.getName())) { + for (Port port2 : p.getPortList()) { + if (port2.getBasename().equals( + port.getBasename())) { + if (_portMap.get(port2) < + _portMap.get(port)) { + portId = _portMap.get(port2); + } + } + } + } + + // Update the port list with the base names + sed.sed(filename, "(#define[ ]+PORT_\\w*[ ]+)\"?" + + port.getBasename() + "\"?", "$1 " + portId); + } + + } + } catch (Exception e) { + System.out.println("CbeProcessVisitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * Create the makefile for a special process -> Each subprocess + * gets its own makefile + * + * @param p process for which the makefile should be created + */ + protected void createMakefile(Process p) { + try { + // Directory of the process + String processDir = _dir + _delimiter + "spu_" + + p.getBasename(); + + // Create the filename for the new wrapper + String filename = processDir + _delimiter + "Makefile"; + // File makefile = new File(filename); + + OutputStream file; + + file = new FileOutputStream(filename); + + PrintStream _makefilePS = new CodePrintStream(file); + + _makefilePS.println("# Makefile for process " + p.getName()); + _makefilePS.println(""); + + String dependency = "all: spu_" + p.getBasename() + + "_wrapper.c ../lib/ProcessWrapper.h " + + "../lib/ProcessFifo.h"; + + for (SourceCode code: p.getSrcList()) + { + dependency += " " + code.getLocality(); + } + + _makefilePS.println(dependency); + _makefilePS.println("\t spu-g++ -I .. -I ../lib -g -o spu_" + + p.getBasename() + "_wrapper spu_" + p.getBasename() + + "_wrapper.c -ftree-vectorize -lm -mtune=cell -O3 " + + "-fmodulo-sched -funroll-loops -ffast-math"); + _makefilePS.println("clean: "); + _makefilePS.println("\t rm spu_" + p.getBasename() + + "_wrapper"); + _makefilePS.println(); + + } catch (FileNotFoundException e) { + System.out.println("CbeProcessVisitor - Makefile: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + protected String _dir = null; + protected HashMap _portMap; + + protected static String _libDirName = "lib"; + protected static String _tempDirName = "template"; +} diff --git a/dol/src/dol/visitor/cbe/CbeVisitor.java b/dol/src/dol/visitor/cbe/CbeVisitor.java new file mode 100644 index 0000000..d70b347 --- /dev/null +++ b/dol/src/dol/visitor/cbe/CbeVisitor.java @@ -0,0 +1,183 @@ +/* $Id: CbeVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.cbe; + +import java.io.File; +import java.util.HashMap; +import java.util.Vector; + +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.util.Copier; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate + * a CBE package. + */ +public class CbeVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param packageName name of the Cbe directory + */ + public CbeVisitor(String packageName) { + _packageName = packageName; + } + + /** + * Visit process network. + * + * @param pn process network that needs to be rendered. + */ + public void visitComponent(ProcessNetwork pn) { + try { + File dir = new File(_packageName); + dir.mkdirs(); + + // Create the library + File lib = new File(_packageName + _delimiter + "lib"); + lib.mkdirs(); + + //copy library files + File source = new File(_ui.getMySystemCLib(). + replaceAll("systemC", "cbe").replace("%20", " ")); + new Copier().copy(source, lib); + + // Create the template + File template = new File(_packageName + _delimiter + + "template"); + template.mkdirs(); + + //copy the templates + source = new File(_ui.getMySystemCLib(). + replaceAll("systemC", "cbe"). + replace("lib", "template").replace("%20", " ")); + new Copier().copy(source, template); + + // Some library files must be copied to the main directory + (new File(lib.getPath() + _delimiter + "ppu_main.h")). + renameTo(new File (dir.getPath() + _delimiter + + "ppu_main.h")); + + //copy process source code + source = new File(_srcDirName.replace("%20", " ")); + new Copier().copy(source, dir); + + createPortMap(pn); + pn.accept(new CbeMakefileVisitor(_packageName)); + pn.accept(new CbeBuildFileVisitor(_packageName)); + pn.accept(new CbeProcessVisitor(_packageName, _portMap)); + pn.accept(new CbeModuleVisitor(_packageName, _portMap)); + pn.accept(new CbeConstantVisitor(_packageName, _portMap)); + } + catch (Exception e) { + System.out.println("CbeVisitor: exception occured: " + + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * Create a hashmap which maps each port of the given process network + * to an integer. For each process, ports are numbered with integers + * starting from 0. + * + * @param pn process network for which the map should be generated + */ + protected void createPortMap(ProcessNetwork pn) { + _portMap = new HashMap(); + + for (Process process : pn.getProcessList()) { + int portCount = 0; + Vector portList = process.getPortList(); + Vector portNameList = new Vector(); + portNameList.clear(); + HashMap portMap = + new HashMap(); + portMap.clear(); + + for (int i = 0; i < portList.size(); i++) { + //treat single ports differently than iterated ports + String portName = portList.elementAt(i).getName(); + String baseName = portList.elementAt(i).getBasename(); + + if (portName.equals(baseName)) { + portNameList.add(portName); + portMap.put(portName, portCount++); + } else { + String range_indices = + portList.elementAt(i).getRange(); + Vector range_indices_values = + getIndex(range_indices, ";"); + + String port_indices = portName; + port_indices.replaceAll(baseName, ""); + Vector port_indices_values = + getIndex(port_indices, "_"); + + if (!portNameList.contains(baseName)) { + portNameList.add(baseName); + portMap.put(baseName, portCount); + + int size = 1; + for (int j = 0; + j < range_indices_values.size(); j++) { + size *= range_indices_values.elementAt(j); + } + portCount += size; + } + + int portId = portMap.get(baseName); + for (int j = 0; j < port_indices_values.size(); j++) { + int weight = 1; + for (int k = j + 1; + k < range_indices_values.size(); k++) { + weight *= range_indices_values.elementAt(k); + } + portId += port_indices_values.elementAt(j) + * weight; + } + portMap.put(portName, portId); + } + } + + for (int i = 0; i < portList.size(); i++) { + _portMap.put(portList.elementAt(i), + portMap.get(portList.elementAt(i).getName())); + } + } + } + + /** + * Gets vector of indices of a string, where the index must be + * separated by the specified separator. + * examples: + * getIndex("name_1_2", "_", 0) will return 1. + * getIndex("name_1_2", "_", 1) will return 2. + * + * @param range string to parse + * @param separator delimiter of indices + * @return vector of indices + */ + protected Vector getIndex(String range, String separator) { + Vector indices = new Vector(); + String[] subranges = range.split(separator); + for (int i = 0; i < subranges.length; i++) { + try { + int value = Integer.valueOf(subranges[i]); + indices.add(value); + } catch (Exception e) { + continue; + } + } + return indices; + } + + protected HashMap _portMap; + protected String _packageName = null; + + protected String _srcDir = ""; + protected static String _srcDirName = "src"; +} diff --git a/dol/src/dol/visitor/cbe/lib/ProcessFifo.h b/dol/src/dol/visitor/cbe/lib/ProcessFifo.h new file mode 100644 index 0000000..8054cd2 --- /dev/null +++ b/dol/src/dol/visitor/cbe/lib/ProcessFifo.h @@ -0,0 +1,219 @@ +/**************************************************************** + * FIFO Functions + * Creator: lschor, 2008-10-30 + * Description: Defines Main functions for a FIFO in the Local Store of a SPE + * + * Revision: + * - 2008-11-08: Created + * - 2008-11-15: Added Performance Estimation methods + */ + +#ifndef _PROCESS_FIFO_H_ +#define _PROCESS_FIFO_H_ + +// Maximum data allowed in the FIFO +static const int MAXELEMENT = 1024; + +// Varialbes to store a fifo-read process +uint32_t tag_id_read = 99; +uint32_t lenRead = 0; +uint32_t queueRead = 0; +char * resultRead; + +char *locBuf[NUM_FIFO]; +int locBufCount[NUM_FIFO]; +int locBufStart[NUM_FIFO]; + +// How many is free in a fifo +uint32_t freespaceQueue(int queue) +{ + return MAXELEMENT - locBufCount[queue]; +} + + +// Init all fifos +void initQueues() +{ + int j; + for (j = 0; j < NUM_FIFO; j++) + { + locBuf[j] = NULL; + locBufCount[j] = 0; + locBufStart[j] = 0; + } +} + +// Init a special queue +void initLocBuf(int queue) +{ + locBuf[queue] = NULL; + locBufCount[queue] = 0; + locBufStart[queue] = 0; +} + +// Gives the memory of the buffers free +void deinitLocBuf() +{ + int j; + for (j = 0; j < NUM_FIFO; j++) + { + if (locBuf[j] != NULL) + { + free(locBuf[j]); + } + } +} + +void updateLocBuf(int queue) +{ + // If the buffer is used the first time, allocate him + if (locBuf[queue]== NULL) + { + locBuf[queue] = (char *)malloc(MAXELEMENT * sizeof(char)); + } +#ifdef MEASURE_DOL_READ_START_DMA + double t_dol_read_start_dma = spu_read_decrementer(); +#endif + + // Double-Buffering --> Try to close the old read-process + if (tag_id_read != 99) + { + waittag(tag_id_read); + // Write the data you read into the queue; + int i; + + #ifdef MEASURE_DOL_READ_DOUBLEBUF + double t_dol_read_doublebuf = spu_read_decrementer(); + #endif + + // Has to write all elements at the beginning or write all elements at the end of the buffer + if (locBufStart[queueRead] + locBufCount[queueRead] > MAXELEMENT || locBufStart[queueRead] + locBufCount[queueRead] + lenRead < MAXELEMENT) + { + memcpy(&(locBuf[queueRead][(locBufStart[queueRead] + locBufCount[queueRead]) % MAXELEMENT]), resultRead, lenRead); + } + + // Otherwise something at the end and something at the beginning + else + { + // At the end of the buffer + memcpy(&(locBuf[queueRead][(locBufStart[queueRead] + locBufCount[queueRead])]), resultRead, MAXELEMENT - locBufStart[queueRead] - locBufCount[queueRead]); + + // At the beginning + memcpy(locBuf[queueRead], &(resultRead[MAXELEMENT - locBufStart[queueRead] - locBufCount[queueRead]]), lenRead - (MAXELEMENT - locBufStart[queueRead] - locBufCount[queueRead])); + } + + locBufCount[queueRead]+=lenRead; + + #ifdef MEASURE_DOL_READ_DOUBLEBUF + t_dol_read_doublebuf -= spu_read_decrementer(); + printf("DOL_READ_DOUBLEBUF_DMA;%f\n",t_dol_read_doublebuf * 1 / MEASURE_CPU); + #endif + + mfc_tag_release(tag_id_read); // release tag ID before exiting + _free_align(resultRead); + + // Send a okey about the data to the PPE + spu_write_out_mbox((uint32_t)(SPE_READ_SUC << 28)); // stalls mailbox is full. + tag_id_read = 99; + } + + uint32_t message = (SPE_READ_DEMAND << 28) | (queue << 16) | (freespaceQueue(queue)); + +#ifdef MEASURE_DOL_READ_HANDSHAKE + double t_dol_read_handshake = spu_read_decrementer(); +#endif + + spu_write_out_mbox((uint32_t)(message)); + + message = spu_read_in_mbox(); + uint32_t request = message >> 28; + lenRead = (0xffff & message); + + if (request != (uint32_t) 1) + { + return; + } + + if((tag_id_read=mfc_tag_reserve())==MFC_TAG_INVALID){ + printf("SPE: ERROR - can't reserve a tag ID\n"); return; + } + + // Wait for the response of the PPE --> The address where to read + uint32_t ea_mfc_h, ea_mfc_l; + uint64_t ea_mfc; + + ea_mfc_h = spu_read_in_mbox(); + ea_mfc_l = spu_read_in_mbox(); + ea_mfc = mfc_hl2ea(ea_mfc_h, ea_mfc_l); + +#ifdef MEASURE_DOL_READ_HANDSHAKE + t_dol_read_handshake -= spu_read_decrementer(); + printf("DOL_READ_HANDSHAKE;%f\n",t_dol_read_handshake * 1 / MEASURE_CPU); +#endif + +#ifdef MEASURE_DOL_READ_START_DMA + t_dol_read_start_dma -= spu_read_decrementer(); + printf("DOL_READ_START_DMA;%f\n",t_dol_read_start_dma * 1 / MEASURE_CPU); +#endif + + resultRead = (char *)_malloc_align(lenRead, 4); + +#ifdef MEASURE_DOL_READ_DMA + double t_dol_read_dma = spu_read_decrementer(); +#endif + + // Read the data from the address we got from the PPE + mfc_get(&(resultRead[0]), ea_mfc, lenRead, tag_id_read, 0, 0); +#ifdef MEASURE_DOL_READ_DMA + t_dol_read_dma -= spu_read_decrementer(); + printf("DOL_READ_DMA;%f\n",t_dol_read_dma * 1 / MEASURE_CPU); +#endif + + queueRead = queue; +} + +// Read from the local buffer +void readLocBuf(int queue, void *destination, int len) +{ +#ifdef MEASURE_DOL_READ_LOCBUF + double t_dol_read_locbuf = spu_read_decrementer(); +#endif + int count = 0; + int newLen = 0; + char* buffer = (char*) destination; + int i; + + while (count < len) + { + newLen = (len - count) > MAXELEMENT? MAXELEMENT : len - count; + + while (locBufCount[queue] < newLen) + { + updateLocBuf(queue); + } + + // Can directly read all elements from the end of the buffer + if (locBufStart[queue] + newLen < MAXELEMENT) + { + memcpy(buffer, &(locBuf[queue][locBufStart[queue]]), newLen); + } + + // Has to write from the end and from the beginning of the buffer + else + { + memcpy(&(buffer[count]), &(locBuf[queue][locBufStart[queue]]), MAXELEMENT - locBufStart[queue]); + memcpy(&(buffer[count + MAXELEMENT - locBufStart[queue]]), locBuf[queue], newLen - MAXELEMENT + locBufStart[queue]); + } + + locBufCount[queue] -= newLen; + locBufStart[queue] = (locBufStart[queue] + newLen) % MAXELEMENT; + count += newLen; + } +#ifdef MEASURE_DOL_READ_LOCBUF + t_dol_read_locbuf -= spu_read_decrementer(); + printf("DOL_READ_LOCBUF;%f\n",t_dol_read_locbuf * 1 / MEASURE_CPU); +#endif +} + + +#endif // _PROCESS_FIFO_H_ diff --git a/dol/src/dol/visitor/cbe/lib/ProcessWrapper.h b/dol/src/dol/visitor/cbe/lib/ProcessWrapper.h new file mode 100644 index 0000000..c06075d --- /dev/null +++ b/dol/src/dol/visitor/cbe/lib/ProcessWrapper.h @@ -0,0 +1,248 @@ +/**************************************************************** + * Process Wrapper Functions + * Creator: lschor, 2008-10-30 + * Description: General process wrapper file, includes DOL_read and DOL_write as main functions + * + * Revision: + * - 2008-10-30: Created + * - 2008-11-08: Update to Double Buffering + * - 2008-11-15: Added Performance Estimation methods + */ + +#ifndef __PROCESS_WRAPPER_H__ +#define __PROCESS_WRAPPER_H__ + +#include +#include +#include +#include +#include // Used for va_list +#include +#include "lib/malloc_align.h" // Malloc for DMA +#include "lib/free_align.h" // Free for DMA +#include "dol.h" +#include "common.h" +#include "estimation.h" + +//Cell Macros +#define waittag(tag_id) mfc_write_tag_mask(1<wptr))->index[dimension] + +#define CREATEPORTVAR(name) \ + int name + +#define CREATEPORT(port, base, number_of_indices, index_range_pairs...) \ + createPort(&port, base, number_of_indices, index_range_pairs) + +// Include the FIFO Functions +#include "lib/ProcessFifo.h" + +// Include some help functions +#include "lib/ProcessWrapperHelp.h" + +// Struct for a process +typedef struct _process_wrapper { + char* name; + uint32_t* index; + uint32_t is_detached; + uint32_t* port_id; + uint32_t* port_queue_id; + uint32_t number_of_ports; +} ProcessWrapper; + +// Tag address for the write process +uint32_t tag_id_write = 99; + +// Pointer to the current data buffer +char * resultWrite; + +/** + * Finish a DOL_write process + */ +void finish_DOL_write() +{ + if (tag_id_write != 99) + { + #ifdef MEASURE_DOL_WRITE_FINISH + double t_dol_write_finish = spu_read_decrementer(); + #endif + + // Wait until the write process is finished + waittag(tag_id_write); + mfc_tag_release(tag_id_write); // release tag ID before exiting + _free_align(resultWrite); + // Send a okey about the data to the PPE + spu_write_out_mbox((uint32_t)(SPE_WRITE_SUC << 28)); // stalls mailbox is full. + tag_id_write = 99; + //queueWrite = -1; + + #ifdef MEASURE_DOL_WRITE_FINISH + t_dol_write_finish -= spu_read_decrementer(); + printf("DOL_WRITE_FINISH;%f\n",t_dol_write_finish * 1 / MEASURE_CPU); + #endif + + } +} + +/** + * Read from the FIFO + */ +void DOL_read(void *port, void *buf, int len, DOLProcess *process) +{ +#ifdef MEASURE_DOL_READ + double t_dol_read = spu_read_decrementer(); +#endif + + ProcessWrapper* process_wrapper = (ProcessWrapper*)process->wptr; + int i; + + for (i = 0; i < process_wrapper->number_of_ports; i++) + { + if (process_wrapper->port_id[i] == (int)port) + { + int queue = process_wrapper->port_queue_id[i]; + + finish_DOL_write(); + + // Try to get new data into the local Buffer + updateLocBuf(queue); + + // Read from the Buffer + readLocBuf(queue, buf, len); + + break; + } + } +#ifdef MEASURE_DOL_READ + t_dol_read -= spu_read_decrementer(); + printf("DOL_READ;%f\n",t_dol_read * 1 / MEASURE_CPU); +#endif + +} + + +/** + * Write data into the FIFO + */ +void DOL_write(void *port, void *buf, int len, DOLProcess *process) +{ +#ifdef MEASURE_DOL_WRITE + double t_dol_write = spu_read_decrementer(); +#endif + + ProcessWrapper* process_wrapper = (ProcessWrapper*)process->wptr; + int i; + + for (i = 0; i < process_wrapper->number_of_ports; i++) + { + if (process_wrapper->port_id[i] == (int)port) + { + // This is our queue + int queue = process_wrapper->port_queue_id[i]; + + #ifdef MEASURE_DOL_WRITE_START_DMA + double t_dol_write_start_dma = spu_read_decrementer(); + #endif + + // There has been a writing process. Is it already finished? + finish_DOL_write(); + + // Create the new write process + + // reserve DMA tag ID + if((tag_id_write=mfc_tag_reserve())==MFC_TAG_INVALID){ + printf("SPE: ERROR - can't reserve a tag ID\n"); return; + } + + // Create the message we like to send, format: + // 4 bit: code (total 16 possibilities) + // 12 bit: queue (total 4096 possibilities) + // 16 bit: len (total maximal size of 512 KB which could be send) + uint32_t message = (SPE_WRITE_DEMAND << 28) | (queue << 16) | (len); + + #ifdef MEASURE_DOL_WRITE_HANDSHAKE + double t_dol_write_handshake = spu_read_decrementer(); + #endif + // Demand the PPE for an address + spu_write_out_mbox(message); + + // Copy the data into the right data-alignment + resultWrite = (char *)_malloc_align(roundDMA(len), 4); + memcpy(resultWrite, buf, len); + + // Is there enough free space to write into the queues? + uint32_t messageIn = spu_read_in_mbox(); + uint32_t request = messageIn >> 28; + + while (request != (uint32_t) 1) + { + spu_write_out_mbox(message); + messageIn = spu_read_in_mbox(); + request = messageIn >> 28; + } + + // Wait for the response of the PPE, i.e. the address for the FIFO element + uint32_t ea_mfc_h, ea_mfc_l; + uint64_t ea_mfc; + ea_mfc_h = spu_read_in_mbox(); + ea_mfc_l = spu_read_in_mbox(); + ea_mfc = mfc_hl2ea(ea_mfc_h, ea_mfc_l); + + #ifdef MEASURE_DOL_WRITE_HANDSHAKE + t_dol_write_handshake -= spu_read_decrementer(); + printf("DOL_WRITE_HANDSHAKE;%f\n",t_dol_write_handshake * 1 / MEASURE_CPU); + #endif + + + #ifdef MEASURE_DOL_WRITE_START_DMA + t_dol_write_start_dma -= spu_read_decrementer(); + printf("DOL_WRITE_START_DMA;%f\n",t_dol_write_start_dma * 1 / MEASURE_CPU); + #endif + + #ifdef MEASURE_DOL_WRITE_DMA + double t_dol_write_dma = spu_read_decrementer(); + #endif + + // Write the data to the address we got from the PPE + mfc_put((void *)&(resultWrite[0]), ea_mfc, roundDMA(len), tag_id_write, 0, 0); + + #ifdef MEASURE_DOL_WRITE_DMA + t_dol_write_dma -= spu_read_decrementer(); + printf("DOL_WRITE_DMA;%f\n",t_dol_write_dma * 1 / MEASURE_CPU); + #endif + + + break; + } + } +#ifdef MEASURE_DOL_WRITE + t_dol_write -= spu_read_decrementer(); + printf("DOL_WRITE;%f\n",t_dol_write * 1 / MEASURE_CPU); +#endif +} + +/** + * Detach the DOL Process + */ +void DOL_detach(DOLProcess *process) { + //printf("[%s] DOL_detach.\n", (char*)(((ProcessWrapper*)process->wptr)->name)); + + // Check if all write processes are finished + if (tag_id_write != 99) + { + waittag(tag_id_write); + mfc_tag_release(tag_id_write); // release tag ID before exiting + _free_align(resultWrite); + spu_write_out_mbox((uint32_t)(2 << 28)); // stalls mailbox is full. + } + + uint32_t message = (SPE_DETACH << 28); + spu_write_out_mbox(message); + deinitLocBuf(); + ((ProcessWrapper*)process->wptr)->is_detached = 1; +} + +#endif diff --git a/dol/src/dol/visitor/cbe/lib/ProcessWrapperHelp.h b/dol/src/dol/visitor/cbe/lib/ProcessWrapperHelp.h new file mode 100644 index 0000000..7d2a117 --- /dev/null +++ b/dol/src/dol/visitor/cbe/lib/ProcessWrapperHelp.h @@ -0,0 +1,100 @@ +/**************************************************************** + * Process Wrapper Help functions + * Creator: lschor, 2008-11-21 + * Description: General process wrapper fucntions + * + * Revision: + * - 2008-11-21: Created + */ + +#ifndef __PROCESS_WRAPPER_HELP_H__ +#define __PROCESS_WRAPPER_HELP_H__ + +#include // Used for va_list + +/** + * Gets an index of a string, where the index must be separated by + * a character specified in tokens. + * Returns -1, when an error occurs. + * + * Example: + * getIndex("name_1_2", "_", 0) will return 1. + * getIndex("name_1_2", "_", 1) will return 2. + * + * @param string string to parse + * @param tokens delimiter of indices + * @param indexNumber position of index (starting at 0) + */ +int getIndex(const char* string, char* tokens, int indexNumber) { + char* string_copy; + char* token_pointer; + int index = 0; + + string_copy = (char*) malloc(sizeof(char) * (strlen(string) + 1)); + if (!string_copy) { + fprintf(stderr, "getIndex(): could not allocate memory.\n"); + return -1; + } + + strcpy(string_copy, string); + + token_pointer = strtok(string_copy, tokens); + do { + token_pointer = strtok(NULL, tokens); + index++; + } while (index <= indexNumber && token_pointer != 0); + + if (token_pointer) { + index = atoi(token_pointer); + free(string_copy); + return index; + } + + free(string_copy); + return -1; +} + +/** + * Create the port name of an iterated port based on its basename and the + * given indices. + * + * @param port buffer where the result is stored (created using + * CREATEPORTVAR) + * @param base basename of the port + * @param number_of_indices number of dimensions of the port + * @param index_range_pairs index and range values for each dimension + */ +int *createPort(int *port, int base, int number_of_indices, + int index_range_pairs, ...) { + int index[4]; + int range[4]; + int i; + int value; + + va_list marker; + va_start(marker, index_range_pairs); + + value = index_range_pairs; + for (i = 0; i < number_of_indices; i++) { + index[i] = value; + value = va_arg(marker, int); + range[i] = value; + if (i < number_of_indices - 1) { + value = va_arg(marker, int); + } + } + + *port = base; + for (i = 0; i < number_of_indices; i++) { + int j; + int weight = 1; + for (j = 1; j < number_of_indices - i; j ++) { + weight *= range[j]; + } + *port += index[i] * weight; + } + + return port; +} + +#endif diff --git a/dol/src/dol/visitor/cbe/lib/ProcessWrapperPPE.c b/dol/src/dol/visitor/cbe/lib/ProcessWrapperPPE.c new file mode 100644 index 0000000..f94c7ea --- /dev/null +++ b/dol/src/dol/visitor/cbe/lib/ProcessWrapperPPE.c @@ -0,0 +1,150 @@ +/**************************************************************** + * Process Wrapper Functions + * Creator: lschor, 2008-10-30 + * Description: General process wrapper file, includes DOL_read and DOL_write as main functions + * + * Revision: + * - 2008-10-30: Created + * - 2008-11-08: Update to Double Buffering + * - 2008-11-15: Added Performance Estimation methods + */ + +#ifndef __PROCESS_WRAPPER_PPE_H__ +#define __PROCESS_WRAPPER_PPE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common_ppu.h" +#include "dol.h" +#include "ProcessWrapperHelp.h" + + +/** + * Read from the FIFO + */ +void DOL_read(void *port, void *buf, int len, DOLProcess *process) +{ + ProcessWrapper* process_wrapper = (ProcessWrapper*)process->wptr; + int i; + + for (i = 0; i < process_wrapper->number_of_ports; i++) + { + if (process_wrapper->port_id[i] == (uint64_t)port) + { + int queue = process_wrapper->port_queue_id[i]; + int i = 0; + struct timespec t; + t.tv_sec = 0; + t.tv_nsec = 5; + + + while (process_wrapper->locBufCount[queue] < len) + { + nanosleep(&t, NULL); + }; + + char *buffer = (char *)buf; + + pthread_mutex_lock( &(process_wrapper->mutex[queue]) ); + + // Can directly read all elements from the end of the buffer + if (process_wrapper->locBufStart[queue] + len < process_wrapper->MAXELEMENT) + { + memcpy(buffer, &(process_wrapper->locBuf[queue][process_wrapper->locBufStart[queue]]), len); + } + + // Has to write from the end and from the beginning of the buffer + else + { + memcpy(&(buffer[0]), &(process_wrapper->locBuf[queue][process_wrapper->locBufStart[queue]]), process_wrapper->MAXELEMENT - process_wrapper->locBufStart[queue]); + memcpy(&(buffer[process_wrapper->MAXELEMENT - process_wrapper->locBufStart[queue]]), process_wrapper->locBuf[queue], len - process_wrapper->MAXELEMENT + process_wrapper->locBufStart[queue]); + } + + process_wrapper->locBufCount[queue] -= len; + process_wrapper->locBufStart[queue] = (process_wrapper->locBufStart[queue] + len) % process_wrapper->MAXELEMENT; + + pthread_mutex_unlock( & (process_wrapper->mutex[queue]) ); + + + break; + } + } +} + + +/** + * Write data into the FIFO + */ +void DOL_write(void *port, void *buf, int len, DOLProcess *process) +{ + ProcessWrapper* process_wrapper = (ProcessWrapper*)process->wptr; + int i; + + for (i = 0; i < process_wrapper->number_of_ports; i++) + { + if (process_wrapper->port_id[i] == (uint64_t)port) + { + // This is our queue + int queue = process_wrapper->port_queue_id[i]; + + struct timespec t; + t.tv_sec = 0; + t.tv_nsec = 5; + + // Wait if there is not enough space in the fifo + while (process_wrapper->MAXELEMENT - process_wrapper->locBufCount[queue] < len) + { + nanosleep(&t, NULL); + }; + + char *buffer = (char *)buf; + + pthread_mutex_lock( &(process_wrapper->mutex[queue]) ); + + // Has to write all elements at the beginning or write all elements at the end of the buffer + if (process_wrapper->locBufStart[queue] + process_wrapper->locBufCount[queue] > process_wrapper->MAXELEMENT || process_wrapper->locBufStart[queue] + process_wrapper->locBufCount[queue] + len < process_wrapper->MAXELEMENT) + { + memcpy(&(process_wrapper->locBuf[queue][(process_wrapper->locBufStart[queue] + process_wrapper->locBufCount[queue]) % process_wrapper->MAXELEMENT]), buffer, len); + } + + // Otherwise something at the end and something at the beginning + else + { + // At the end of the buffer + memcpy(&(process_wrapper->locBuf[queue][(process_wrapper->locBufStart[queue] + process_wrapper->locBufCount[queue])]), buffer, process_wrapper->MAXELEMENT - process_wrapper->locBufStart[queue] - process_wrapper->locBufCount[queue]); + + // At the beginning + memcpy(process_wrapper->locBuf[queue], &(buffer[process_wrapper->MAXELEMENT - process_wrapper->locBufStart[queue] - process_wrapper->locBufCount[queue]]), len - (process_wrapper->MAXELEMENT - process_wrapper->locBufStart[queue] - process_wrapper->locBufCount[queue])); + } + + process_wrapper->locBufCount[queue]+=len; + + pthread_mutex_unlock( & (process_wrapper->mutex[queue]) ); + + break; + } + } +} + +/** + * Detach the DOL Process + */ +void DOL_detach(DOLProcess *process) { + ProcessWrapper* process_wrapper = (ProcessWrapper*)process->wptr; + printf("[%s] DOL_detach.\n", (char*)(((ProcessWrapper*)process->wptr)->name)); + + pthread_mutex_lock( (process_wrapper->mutexProcessNr) ); + (* process_wrapper->processFinished)++; + pthread_mutex_unlock( (process_wrapper->mutexProcessNr) ); + + ((ProcessWrapper*)process->wptr)->is_detached = 1; +} + +#endif diff --git a/dol/src/dol/visitor/cbe/lib/common.h b/dol/src/dol/visitor/cbe/lib/common.h new file mode 100644 index 0000000..9370673 --- /dev/null +++ b/dol/src/dol/visitor/cbe/lib/common.h @@ -0,0 +1,59 @@ +/**************************************************************** + * COMMON.H + * Creator: lschor, 2008-10-30 + * Description: Specifies some structs and Constants for the CBE-DOL-Implementation + * + * Revision: + * - 2008-10-30: Created + */ + +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#include "dol.h" +#include "lib/constant.h" + +#define SPE_WRITE_DEMAND 0 +#define SPE_READ_DEMAND 1 +#define SPE_WRITE_SUC 2 +#define SPE_READ_SUC 3 +#define SPE_DETACH 4 + +// the context that PPE forward to SPE +typedef struct{ + uint64_t port_id; + uint64_t port_queue_id; + + uint64_t processName; // Address for the name of the process + uint64_t processNameLen; // Len of the process Name + + uint32_t number_of_ports; + uint32_t is_detached; + uint32_t padd[2]; // dummy - for alignment --> It always has to be a multiple of 128 bit! +} parm_context; // aligned to 16B + +typedef struct{ + uint32_t d; + uint32_t padd[31]; //padd to cache line +} status_s; + + +// Round a number ot the right DMA number --> Is used for DMA transfers +uint32_t roundDMA(uint32_t number) +{ + if (number > 16) + return number + 16 - (number % 16); + else if (number > 8) + return 16; + else if (number > 4) + return 8; + else if (number > 2) + return 4; + else if (number > 1) + return 2; + else + return 1; +} + +#endif // _COMMON_H_ + diff --git a/dol/src/dol/visitor/cbe/lib/common_ppu.h b/dol/src/dol/visitor/cbe/lib/common_ppu.h new file mode 100644 index 0000000..7ee1ed0 --- /dev/null +++ b/dol/src/dol/visitor/cbe/lib/common_ppu.h @@ -0,0 +1,41 @@ +/**************************************************************** + * Common structs for the PPU + * Creator: lschor, 2008-11-21 + * Description: Common structs for the PPU + * + * Revision: + * - 2008-11-21: Created + */ + +#ifndef __COMMON_PPU_H__ +#define __COMMON_PPU_H__ + +//DOL macros +#define GETINDEX(dimension) \ + ((ProcessWrapper*)(p->wptr))->index[dimension] + +#define CREATEPORTVAR(name) \ + int name + +#define CREATEPORT(port, base, number_of_indices, index_range_pairs...) \ + createPort(&port, base, number_of_indices, index_range_pairs) + + +// Struct for a process +typedef struct _process_wrapper { + char* name; + uint32_t* index; + uint32_t is_detached; + volatile uint32_t* port_id; + volatile uint32_t* port_queue_id; + uint32_t number_of_ports; + char ** locBuf; + int * locBufCount; + int * locBufStart; + int MAXELEMENT; + int * processFinished; + pthread_mutex_t * mutex; + pthread_mutex_t * mutexProcessNr; +} ProcessWrapper; + +#endif diff --git a/dol/src/dol/visitor/cbe/lib/dol.h b/dol/src/dol/visitor/cbe/lib/dol.h new file mode 100644 index 0000000..2838938 --- /dev/null +++ b/dol/src/dol/visitor/cbe/lib/dol.h @@ -0,0 +1,28 @@ +#ifndef __DOL_H__ +#define __DOL_H__ + +//structure for local memory of process +typedef struct _local_states *LocalState; + +//structure for process +struct _process; + +// +typedef void (*ProcessInit)(struct _process*); +typedef int (*ProcessFire)(struct _process*); +typedef void *WPTR; + +typedef struct _process { + LocalState local; + ProcessInit init; + ProcessFire fire; + WPTR wptr; +} DOLProcess; + +void DOL_read(void *port, void *buf, int len, DOLProcess *process); +void DOL_write(void *port, void *buf, int len, DOLProcess *process); +void DOL_detach(DOLProcess *process); +int getIndex(const char* string, char* tokens, int indexNumber); +int *createPort(int *port, int base, int number_of_indices, int index_range_pairs, ...); + +#endif diff --git a/dol/src/dol/visitor/cbe/lib/estimation.h b/dol/src/dol/visitor/cbe/lib/estimation.h new file mode 100644 index 0000000..667f60b --- /dev/null +++ b/dol/src/dol/visitor/cbe/lib/estimation.h @@ -0,0 +1,50 @@ +/**************************************************************** + * Estimation Defintions + * Creator: lschor, 2008-11-15 + * Description: File with includes for time measurements + * Principle: if 1 then this point will be measured, if 0 then this point will not be measured + * + * Revision: + * - 2008-11-15: Created + */ + +// +#ifndef __ESTIMATION_H__ +#define __ESTIMATION_H__ + +// What to measure? +//#define MEASURE 0 // Measure activeted + +#ifdef MEASURE + //#define MEASURE_DOL_READ 0 // Measure DOL READ + //#define MEASURE_DOL_READ_FINISH 0 // Measure FINISH DOL Read + //#define MEASURE_DOL_READ_START_DMA 0 // Measure Time from start until the DMA process has started + //#define MEASURE_DOL_READ_HANDSHAKE 0 // Measure Time of the whole handshake + //#define MEASURE_DOL_READ_DMA 0 // Measure Time of DMA Setup + //#define MEASURE_DOL_READ_LOCBUF 0 // Measure Time for LocBuf read + //#define MEASURE_DOL_READ_DOUBLEBUF 0 // Measure Time for writing into the buffer + + //#define MEASURE_DOL_WRITE 0 // Measure DOL WRITE + //#define MEASURE_DOL_WRITE_FINISH 0 // Measure FINISH DOL Write + //#define MEASURE_DOL_WRITE_START_DMA 0 // Measure Time from start until the DMA process has started + //#define MEASURE_DOL_WRITE_HANDSHAKE 0 // Measure Time of the whole handshake + //#define MEASURE_DOL_WRITE_DMA 0 // Measure Time of DMA Setup + + //#define MEASURE_DOL_FIRE 0 // Measure DOL FIRE + //#define MEASURE_DOL_INIT 0 // Measure DOL INIT + //#define MEASURE_SPE 0 // Measure whole SPE process + + //#define MEASURE_APPLICATION 0 // Measure whole execution time + //#define MEASURE_SET_UP_SPE_THREAD 0 // Measure time to set up the SPE-threads + //#define MEASURE_SPE_WRITE_DEMAND 0 // Measure time of write demand + //#define MEASURE_SPE_READ_DEMAND 0 // Measure time of read demand + //#define MEASURE_SPE_WRITE_SUC 0 // Measure time of write successful + //#define MEASURE_SPE_READ_SUC 0 // Measure time of read successful + +#endif + +// Some constants +#define MEASURE_START 0xFFFFFFFF // Start decrementer at this value +#define MEASURE_CPU 79800000.0 // Timebase PS3 (in Hz) + +#endif diff --git a/dol/src/dol/visitor/cbe/lib/free_align.h b/dol/src/dol/visitor/cbe/lib/free_align.h new file mode 100644 index 0000000..5924871 --- /dev/null +++ b/dol/src/dol/visitor/cbe/lib/free_align.h @@ -0,0 +1,65 @@ +/* -------------------------------------------------------------- */ +/* (C)Copyright 2001,2006, */ +/* International Business Machines Corporation, */ +/* Sony Computer Entertainment, Incorporated, */ +/* Toshiba Corporation, */ +/* */ +/* All Rights Reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or */ +/* without modification, are permitted provided that the */ +/* following conditions are met: */ +/* */ +/* - Redistributions of source code must retain the above copyright*/ +/* notice, this list of conditions and the following disclaimer. */ +/* */ +/* - Redistributions in binary form must reproduce the above */ +/* copyright notice, this list of conditions and the following */ +/* disclaimer in the documentation and/or other materials */ +/* provided with the distribution. */ +/* */ +/* - Neither the name of IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products */ +/* derived from this software without specific prior written */ +/* permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND */ +/* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, */ +/* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ +/* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ +/* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR */ +/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT */ +/* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */ +/* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) */ +/* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN */ +/* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR */ +/* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */ +/* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* -------------------------------------------------------------- */ +/* PROLOG END TAG zYx */ +#ifndef _FREE_ALIGN_H_ +#define _FREE_ALIGN_H_ 1 + +#include + +/* Function + * + * void free_align(void *ptr) + * + * Description + * The free_align routine frees a memory buffer allocate by the + * malloc_align routine. See malloc_align for complete details. + */ + +static __inline void _free_align(void *ptr) +{ + void * real; + + if (ptr) { + real = *((void **)(ptr)-1); + free(real); + } +} + +#endif /* _FREE_ALIGN_H_ */ diff --git a/dol/src/dol/visitor/cbe/lib/malloc_align.h b/dol/src/dol/visitor/cbe/lib/malloc_align.h new file mode 100644 index 0000000..0a19068 --- /dev/null +++ b/dol/src/dol/visitor/cbe/lib/malloc_align.h @@ -0,0 +1,105 @@ +/* -------------------------------------------------------------- */ +/* (C)Copyright 2001,2007, */ +/* International Business Machines Corporation, */ +/* Sony Computer Entertainment, Incorporated, */ +/* Toshiba Corporation, */ +/* */ +/* All Rights Reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or */ +/* without modification, are permitted provided that the */ +/* following conditions are met: */ +/* */ +/* - Redistributions of source code must retain the above copyright*/ +/* notice, this list of conditions and the following disclaimer. */ +/* */ +/* - Redistributions in binary form must reproduce the above */ +/* copyright notice, this list of conditions and the following */ +/* disclaimer in the documentation and/or other materials */ +/* provided with the distribution. */ +/* */ +/* - Neither the name of IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products */ +/* derived from this software without specific prior written */ +/* permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND */ +/* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, */ +/* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ +/* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ +/* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR */ +/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT */ +/* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */ +/* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) */ +/* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN */ +/* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR */ +/* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */ +/* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* -------------------------------------------------------------- */ +/* PROLOG END TAG zYx */ + +#ifndef _MALLOC_ALIGN_H_ +#define _MALLOC_ALIGN_H_ 1 + +#include + +/* Function + * + * void * malloc_align(size_t size, unsigned int log2_align) + * + * Description + * The malloc_align routine allocates a memory buffer of + * bytes aligned to the power of 2 alignment specified by . + * For example, malloc_align(4096, 7) will allocate a memory heap + * buffer of 4096 bytes aligned on a 128 byte boundary. + * + * The aligned malloc routine allocates an enlarged buffer + * from the standard memory heap. Space for the real allocated memory + * pointer is reserved on the front of the memory buffer. + * + * ----------------- <--- start of allocated memory + * | pad 0 to | + * |(1< +#include +#include +#include +#include +#include +#include +#include +#include + +// Local includes +#include "lib/malloc_align.h" +#include "lib/free_align.h" +#include "common.h" +#include "lib/estimation.h" +#include "common_ppu.h" +#include "cbe_mfc.h" + +// Handler for the SPE +extern spe_program_handle_t spu; + +// Program context for the SPEs +volatile parm_context ctx[NUM_SPES] __attribute__ ((aligned(16))); + +// The SPE-program-handler +spe_program_handle_t *program[NUM_SPES]; + +// data structure for running SPE thread +typedef struct spu_data { + spe_context_ptr_t spe_ctx; + pthread_t pthread; + void *argp; +} spu_data_t; + +// Data for the SPEs +spu_data_t data[NUM_SPES]; + +// Struct which stores a fifo entry temporary +struct fifoEntry { + uint64_t ea; + int length; + int queue; +}; + +// Two temporary store elements +struct fifoEntry tmpFifoEntryRead[NUM_SPES]; +struct fifoEntry tmpFifoEntryWrite[NUM_SPES]; + +// Initialize the fifo, we use +const int MAXELEMENT = 262144; +char *locBuf[NUM_FIFO]; +int locBufCount[NUM_FIFO]; +int locBufStart[NUM_FIFO]; + +// Mutex-variables for the read/write process of the Queues +pthread_mutex_t mutex [NUM_FIFO]; +pthread_mutex_t mutexProcessNr = PTHREAD_MUTEX_INITIALIZER; + +// Number of process that have been finished +int processFinished = 0; + + +#endif diff --git a/dol/src/dol/visitor/cbe/lib/ppu_main_workloop.h b/dol/src/dol/visitor/cbe/lib/ppu_main_workloop.h new file mode 100644 index 0000000..874bf32 --- /dev/null +++ b/dol/src/dol/visitor/cbe/lib/ppu_main_workloop.h @@ -0,0 +1,235 @@ +/**************************************************************** + * Main Loop function + * Creator: lschor, 2008-11-21 + * Description: Includes the main loop function for the ppu_main function + * + * Revision: + * - 2008-11-21: Created + */ + +void workloop() +{ + // Buffer to an address for sending to to the PPE + volatile char *dataToWriteP __attribute__ ((aligned(128))); + + // Number of corrent working process + int processNr; + + // General variables that have been used in the main workloop + uint32_t message; + uint32_t request; + uint32_t len; + uint32_t queue; + + struct timespec t; + t.tv_sec = 0; + t.tv_nsec = 5; + + while (1) + { + // Goes through all nodes and check if they like to send some data + // - Which node has some information + // - Run through all nodes and if one has some work, do that + for (processNr = 0; processNr < NUM_SPES; processNr++) + { + if (!spe_out_mbox_status(data[processNr].spe_ctx)) continue; + + // Get the data + spe_out_mbox_read(data[processNr].spe_ctx, &message, 1); + + request = message >> 28; + len = (0xffff & message); + queue = (message >> 16) & 0xfff; + + // What type of request are the data? + if (request == SPE_WRITE_DEMAND) // Want an address to write + { + + // If there is not enough space in the queue + if (MAXELEMENT - locBufCount[queue] < len) + { + int message = (0 << 28) | (queue << 16) | locBufCount[queue]; + spe_in_mbox_write(data[processNr].spe_ctx, (uint32_t*)&message, 1, SPE_MBOX_ANY_NONBLOCKING); + } + + // There is enough space in the queue + else + { + #ifdef MEASURE_SPE_WRITE_DEMAND + struct timeval t_ppe_write_demand_start, t_ppe_write_demand_end; + gettimeofday(&t_ppe_write_demand_start,NULL); + #endif + int message = (1 << 28) | (queue << 16) | len; + spe_in_mbox_write(data[processNr].spe_ctx, (uint32_t*)&message, 1, SPE_MBOX_ANY_NONBLOCKING); + + // Create the memory for the element + dataToWriteP = (char *)malloc(roundDMA(len)); + + // Create the address to send + uint64_t ea; + ea = (uint64_t)dataToWriteP; + + // Enter the information into the temporary Buffer + tmpFifoEntryWrite[processNr].ea = ea; + tmpFifoEntryWrite[processNr].length=len; + tmpFifoEntryWrite[processNr].queue = queue; + + // Send the address + spe_in_mbox_write(data[processNr].spe_ctx, (uint32_t*)&ea, 2,SPE_MBOX_ANY_NONBLOCKING); + #ifdef MEASURE_SPE_WRITE_DEMAND + gettimeofday(&t_ppe_write_demand_end, NULL); + printf("PPE_WRITE_DEMAND;%f\n",(t_ppe_write_demand_end.tv_sec - t_ppe_write_demand_start.tv_sec) + 0.000001 * (t_ppe_write_demand_end.tv_usec - t_ppe_write_demand_start.tv_usec)); + #endif + } + } + + /***************************************************************************************************************/ + else if (request == SPE_READ_DEMAND) // Want an address to read + { + // If no element is in the fifo queue + if (locBufCount[queue] <= 0) + { + int message = (0 << 28) | (queue << 16) | locBufCount[queue]; + spe_in_mbox_write(data[processNr].spe_ctx, (uint32_t*)&message, 1, SPE_MBOX_ANY_NONBLOCKING); + } + + // Has some elements in the fifo queue + else + { + #ifdef MEASURE_SPE_READ_DEMAND + struct timeval t_ppe_read_demand_start, t_ppe_read_demand_end; + gettimeofday(&t_ppe_read_demand_start,NULL); + #endif + + pthread_mutex_lock( &(mutex[queue]) ); + + len = len > locBufCount[queue] ? locBufCount[queue] : len; + + // Can only send special sizes over the DMA + // 1, 2, 4, 8, 16, ..., 16*x + + if (len >= 16) + len = len - (len % 16); + else if (len >= 8) + len = 8; + else if (len >= 4) + len = 4; + else if (len >= 2) + len = 2; + else + len = 1; + + int message = (1 << 28) | (queue << 16) | len; + spe_in_mbox_write(data[processNr].spe_ctx, (uint32_t*)&message, 1, SPE_MBOX_ANY_NONBLOCKING); + + char *buf = (char *)_malloc_align(sizeof(char) * len, 4); + + // Can directly read all elements from the end of the buffer + if (locBufStart[queue] + len < MAXELEMENT) + { + memcpy(buf, &(locBuf[queue][locBufStart[queue]]), len); + } + + // Has to write from the end and from the beginning of the buffer + else + { + memcpy(&(buf[0]), &(locBuf[queue][locBufStart[queue]]), MAXELEMENT - locBufStart[queue]); + memcpy(&(buf[MAXELEMENT - locBufStart[queue]]), locBuf[queue], len - MAXELEMENT + locBufStart[queue]); + } + + locBufCount[queue] -= len; + locBufStart[queue] = (locBufStart[queue] + len) % MAXELEMENT; + + pthread_mutex_unlock( & (mutex[queue]) ); + + // Create the address to send + uint64_t ea; + ea = (uint64_t)buf; + + // Enter the information into the temporary Buffer + tmpFifoEntryRead[processNr].ea = ea; + tmpFifoEntryRead[processNr].length = len; + tmpFifoEntryRead[processNr].queue = queue; + + spe_in_mbox_write(data[processNr].spe_ctx, (uint32_t*)&(tmpFifoEntryRead[processNr].ea), 2,SPE_MBOX_ANY_NONBLOCKING); + #ifdef MEASURE_SPE_READ_DEMAND + gettimeofday(&t_ppe_read_demand_end, NULL); + printf("PPE;%f\n",(t_ppe_read_demand_end.tv_sec - t_ppe_read_demand_start.tv_sec) + 0.000001 * (t_ppe_read_demand_end.tv_usec - t_ppe_read_demand_start.tv_usec)); + #endif + } + } + + /***************************************************************************************************************/ + else if (request == SPE_WRITE_SUC) // Has finished writing + { + #ifdef MEASURE_SPE_WRITE_SUC + struct timeval t_ppe_write_suc_start, t_ppe_write_suc_end; + gettimeofday(&t_ppe_write_suc_start,NULL); + #endif + // Enter the data into the FIFO + int queueW = tmpFifoEntryWrite[processNr].queue; + int lenW = tmpFifoEntryWrite[processNr].length; + char *bufferW = (char *)(tmpFifoEntryWrite[processNr].ea); + + pthread_mutex_lock( &(mutex[queueW]) ); + + // Has to write all elements at the beginning or write all elements at the end of the buffer + if (locBufStart[queueW] + locBufCount[queueW] > MAXELEMENT || locBufStart[queueW] + locBufCount[queueW] + lenW < MAXELEMENT) + { + memcpy(&(locBuf[queueW][(locBufStart[queueW] + locBufCount[queueW]) % MAXELEMENT]), bufferW, lenW); + } + + // Otherwise something at the end and something at the beginning + else + { + // At the end of the buffer + memcpy(&(locBuf[queueW][(locBufStart[queueW] + locBufCount[queueW])]), bufferW, MAXELEMENT - locBufStart[queueW] - locBufCount[queueW]); + + // At the beginning + memcpy(locBuf[queueW], &(bufferW[MAXELEMENT - locBufStart[queueW] - locBufCount[queueW]]), lenW - (MAXELEMENT - locBufStart[queueW] - locBufCount[queueW])); + } + + locBufCount[queueW]+=lenW; + + pthread_mutex_unlock( & (mutex[queueW]) ); + + // Set the temporary entry to null + #ifdef MEASURE_SPE_WRITE_SUC + gettimeofday(&t_ppe_write_suc_end, NULL); + printf("PPE;%f\n",(t_ppe_write_suc_end.tv_sec - t_ppe_write_suc_start.tv_sec) + 0.000001 * (t_ppe_write_suc_end.tv_usec - t_ppe_write_suc_start.tv_usec)); + #endif + } + + /***************************************************************************************************************/ + else if (request == SPE_READ_SUC) // Has finished reading + { + #ifdef MEASURE_SPE_READ_SUC + struct timeval t_ppe_read_suc_start, t_ppe_read_suc_end; + gettimeofday(&t_ppe_read_suc_start,NULL); + #endif + #ifdef MEASURE_SPE_READ_SUC + gettimeofday(&t_ppe_read_suc_end, NULL); + printf("PPE;%f\n",(t_ppe_read_suc_end.tv_sec - t_ppe_read_suc_start.tv_sec) + 0.000001 * (t_ppe_read_suc_end.tv_usec - t_ppe_read_suc_start.tv_usec)); + #endif + } + + /***************************************************************************************************************/ + else if (request == SPE_DETACH) // A process has finished + { + pthread_mutex_lock( &(mutexProcessNr) ); + processFinished++; + pthread_mutex_unlock( &(mutexProcessNr) ); + } + + /***************************************************************************************************************/ + else // Did nothing + { + nanosleep(&t, NULL); + } + } + + // Check if we can stop the execution + if (processFinished >= NUM_PROCS) break; + } +} + diff --git a/dol/src/dol/visitor/cbe/template/ppu_process_wrapper_template.c b/dol/src/dol/visitor/cbe/template/ppu_process_wrapper_template.c new file mode 100644 index 0000000..a47b3db --- /dev/null +++ b/dol/src/dol/visitor/cbe/template/ppu_process_wrapper_template.c @@ -0,0 +1,68 @@ +/**************************************************************** + * Process Wrapper file for a PPE process + * Creator: lschor, 2008-11-21 + * Description: Wrapper for a specific PPE process + * + * Revision: + * - 2008-11-21: Created + */ + +// Include the standard thread functions +#include +#include +#include +#include +#include +#include +#include + +#include "common_ppu.h" + +// Include of the process --> Because all is mapped to one file, each source file is only allow to appear once +//#include "@PROCESSNAME@.c" + +/* + * The wrapper process + */ +void *@PROCESSNAME@_wrapper( void *ptr ) +{ + // Create the wrapper process + ProcessWrapper *wrapper = (ProcessWrapper *)ptr; + + //initialize the index array + int i; + wrapper->index = (uint32_t *)malloc(4 * sizeof(int)); + for (i = 0; i < 4; i++) + { + wrapper->index[i] = getIndex(wrapper->name, "_", i); + } + + // DOL process + DOLProcess* process; + struct _local_states *state; + + process = (DOLProcess *)malloc(sizeof(DOLProcess)); + state = (struct _local_states *)malloc(sizeof(struct _local_states)); + + memcpy(process, &@PROCESSNAME@, sizeof(DOLProcess)); + memcpy(state, @PROCESSNAME@.local, sizeof(struct _local_states)); + process->local = state; + process->wptr = wrapper; + + // Init the process + process->init(process); + + // Run the process + while (!wrapper->is_detached) + { + process->fire(process); + } + + // Delete all malloc memory + free(state); + free(process); + free(wrapper->name); + free(wrapper); +} + + diff --git a/dol/src/dol/visitor/cbe/template/spu_process_wrapper_template.c b/dol/src/dol/visitor/cbe/template/spu_process_wrapper_template.c new file mode 100644 index 0000000..703518e --- /dev/null +++ b/dol/src/dol/visitor/cbe/template/spu_process_wrapper_template.c @@ -0,0 +1,150 @@ +/**************************************************************** + * Process Wrapper file + * Creator: lschor, 2008-10-30 + * Description: Wrapper for a specific SPE process + * + * Revision: + * - 2008-10-30: Created + * - 2008-11-08: Update to Double Buffering + * - 2008-11-15: Added Performance Estimation methods + */ + +// General includes +#include +extern "C" { + #include +} +#include +#include +#include + +// Include to allocate/free using for DMA transfers +#include "lib/malloc_align.h" +#include "lib/free_align.h" + +// Local includes +#include "common.h" +#include "lib/ProcessWrapper.h" +#include "lib/estimation.h" + +// Context file +static parm_context ctx __attribute__ ((aligned (128))); + +// Include of the process +//#include "@PROCESSNAME@.c" + +// Main application +int main(int speid , uint64_t argp) +{ +#ifdef MEASURE + // Start the decrementer for time measurement + spu_write_decrementer(MEASURE_START); +#endif + +#ifdef MEASURE_SPE + double t_dol_spe = spu_read_decrementer(); +#endif + + // reserve DMA tag ID + uint32_t tag_id; + if((tag_id=mfc_tag_reserve())==MFC_TAG_INVALID){ + printf("SPE: ERROR - can't reserve a tag ID\n"); return 1; + } + + + // Get the context information for the whole system + mfc_get((void*) &ctx, argp, sizeof(ctx), tag_id, 0, 0); + mfc_write_tag_mask(1<number_of_ports = ctx.number_of_ports; + wrapper->port_id = port_id; + wrapper->port_queue_id = port_queue_id; + wrapper->is_detached = 0; + wrapper->name = (char *)_malloc_align((uint32_t)ctx.processNameLen, 4); + mfc_get((void *)wrapper->name, ctx.processName, ctx.processNameLen, tag_id, 0, 0); + waittag(tag_id); + + + //initialize the index array + int i; + wrapper->index = (uint32_t *)malloc(4 * sizeof(int)); + for (i = 0; i < 4; i++) + { + wrapper->index[i] = getIndex(wrapper->name, "_", i); + } + + // Init the queues for local buffering in the LS + // Only the queues we really need + initQueues(); + + // DOL process + DOLProcess* process; + struct _local_states *state; + + process = (DOLProcess *)malloc(sizeof(DOLProcess)); + state = (struct _local_states *)malloc(sizeof(struct _local_states)); + + memcpy(process, &@PROCESSNAME@, sizeof(DOLProcess)); + memcpy(state, @PROCESSNAME@.local, sizeof(struct _local_states)); + process->local = state; + process->wptr = wrapper; + + // Init the process +#ifdef MEASURE_DOL_INIT + double t_dol_init = spu_read_decrementer(); +#endif + process->init(process); +#ifdef MEASURE_DOL_INIT + t_dol_init -= spu_read_decrementer(); + printf("DOL_INIT;%f\n",t_dol_init * 1 / MEASURE_CPU); +#endif + + // Run the process + while (!wrapper->is_detached) + { + #ifdef MEASURE_DOL_FIRE + double t_dol_fire = spu_read_decrementer(); + #endif + + process->fire(process); + + #ifdef MEASURE_DOL_FIRE + t_dol_fire -= spu_read_decrementer(); + printf("DOL_FIRE;%f\n",t_dol_fire * 1 / MEASURE_CPU); + #endif + } + + // Delete all malloc memory + free(state); + free(process); + _free_align(wrapper->name); + free(wrapper); + + // release tag ID before exiting + mfc_tag_release(tag_id); + + + // Inform the main process that we have finished! + spu_write_out_mbox((uint32_t)(4)); + +#ifdef MEASURE_SPE + t_dol_spe -= spu_read_decrementer(); + printf("DOL_SPE_@PROCESSNAME@;%f\n",t_dol_spe * 1 / MEASURE_CPU); +#endif + + return 0; +} + + diff --git a/dol/src/dol/visitor/cell/CellBuildFileVisitor.java b/dol/src/dol/visitor/cell/CellBuildFileVisitor.java new file mode 100644 index 0000000..31daef5 --- /dev/null +++ b/dol/src/dol/visitor/cell/CellBuildFileVisitor.java @@ -0,0 +1,110 @@ +package dol.visitor.cell; + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.Vector; + +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate the build file + * for the Application on the CBE (i.e. a bash file for the cell + * + * @author lschor, 2008-10-30 + * + * Revision: + * 2008-10-30: Updated the file for the CBE + * 2008-11-08: Add double buffering + */ +public class CellBuildFileVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir + * path of the Makefile + */ + public CellBuildFileVisitor(String dir) { + _dir = dir; + } + + /** + * Create a Makefile for the given process network. + * + * @param pn + * process network + */ + public void visitComponent(ProcessNetwork pn) { + try { + String filename = _dir + _delimiter + "pncbe.sh"; + OutputStream file = new FileOutputStream(filename); + PrintStream ps = new PrintStream(file); + + // General information / notes and commands + ps.println("#!/bin/bash"); + ps.println("clear"); + ps.println(); + ps + .println("# Bash file to run the DOL application on the Cell processor"); + ps + .println("# Start the Cell-Simulator and enter the following commands: "); + ps + .println("# callthru source /pncbe.sh > pncbe.sh"); + ps + .println("# for example: callthru source /opt/cell/sdk/src/tutorial/pn_test/pncbe.sh > pncbe.sh"); + ps.println("# chmod +x pncbe.sh"); + ps.println(); + ps + .println("# To run the DOL application, use the following command: "); + ps.println("# ./pncbe.sh"); + ps.println(); + ps.println("# Folder in which the application is stored"); + ps.println("FOLDER=/opt/cell/sdk/src/tutorial/pn_test"); + ps.println(); + + // Go through each process and copy its data to the Cell + String subdirectory = ""; + String applicationName = ""; + Vector pList = new Vector(); + + for (Process process : pn.getProcessList()) { + String basename = process.getBasename(); + if (!pList.contains(basename) && process.getNumOfInports() > 0 && process.getNumOfOutports() > 0) { + subdirectory = "spu_" + basename; + applicationName = subdirectory + "/spu_" + + basename + "_wrapper"; + + ps.println("# " + basename); + ps.println("if [ ! -d " + subdirectory + " ]; then"); + ps.println(" mkdir " + subdirectory); + ps.println("fi;"); + ps.println("callthru source $FOLDER/" + applicationName + + " > " + applicationName); + ps.println("chmod +x " + applicationName); + ps.println(); + pList.add(basename); + } + } + + // Load also the main application to the CBE + ps.println("# Main program"); + ps.println("callthru source $FOLDER/ppu_main > ppu_main"); + ps.println("chmod +x ppu_main"); + ps.println(); + + // Run the main program + ps.println("# run the main program"); + ps.println("./ppu_main"); + } catch (Exception e) { + System.out.println("CbeMakefileVisitor: exception occured: " + + e.getMessage()); + e.printStackTrace(); + } + } + + protected String _dir = null; + +} diff --git a/dol/src/dol/visitor/cell/CellConstantVisitor.java b/dol/src/dol/visitor/cell/CellConstantVisitor.java new file mode 100644 index 0000000..ce7e2a1 --- /dev/null +++ b/dol/src/dol/visitor/cell/CellConstantVisitor.java @@ -0,0 +1,128 @@ +package dol.visitor.cell; + +import java.io.FileOutputStream; +import java.io.OutputStream; + +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.visitor.PNVisitor; +import dol.main.UserInterface; +import dol.util.CodePrintStream; + +/** + * This class is a class for a constant file + * + * @author lschor, 2008-11-08 + * + * Revision: + * 2008-11-08: Created + */ +public class CellConstantVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir path of this file + */ + public CellConstantVisitor(String dir, CellMapping mapping) { + _dir = dir; + _mapping = mapping; + } + + /** + * Visit process network. + * + * @param x process network that needs to be rendered + */ + public void visitComponent(ProcessNetwork x) { + try { + _ui = UserInterface.getInstance(); + String filename = _dir + _delimiter + "lib" + _delimiter + "constant.h"; + OutputStream file = new FileOutputStream(filename); + _mainPS = new CodePrintStream(file); + + int numSpes = 0; + + for (Process p : x.getProcessList()) { + if (p.getNumOfInports() > 0 && p.getNumOfOutports() > 0) + numSpes++; + } + + //create header section + _mainPS.println("// ========================"); + _mainPS.println("// constant.h file"); + _mainPS.println("// ========================"); + + // Includes + _mainPS.println("#include "); + + // Define the number of FIFO queues and the number of processes + _mainPS.println("#ifndef _CONSTANT_H_"); + _mainPS.println("#define _CONSTANT_H_"); + _mainPS.println(""); + _mainPS.println("#define NUM_PROCS " + x.getProcessList().size() + + " // total number of processes"); + _mainPS.println("#define NUM_PROCS_SPU " + _mapping.getNrSPUProcess() + + " // number of processes to map on the SPU"); + _mainPS.println("#define NUM_PROCS_PPU " + _mapping.getNrPPUProcess() + + " // number of processes to map to the PPU"); + _mainPS.println("#define NUM_SPES " + _mapping.getNrSPE() + + " // number of SPE's to be used (PS3 = 6)"); + _mainPS.println("#define NUM_FIFO " + x.getChannelList().size() + + " // number of FIFOs we use"); + _mainPS.println("#define FIFO_SIZE_FACTOR 10 " + + " // factor to increase the IN-Channels of the PPE"); + _mainPS.println("#define ALIGNMENT_FACTOR 7 " + + " // alignment factor for the DMA transfers (at least 4, " + + "7 for optimal performance)"); + _mainPS.println("#define ALIGNMENT_FACTOR_POWER2 128"); + _mainPS.println("#define BLOCKED_MAX_NR 5 " + + " // number of times a process should wait until " + + "resending a request"); + _mainPS.println("#define STORE_REQUESTS " + + " // defines if one would like to store requests which" + + "cannot be worked out currently (see also FastCommunication.cpp)"); + _mainPS.println(""); + _mainPS.print("static unsigned long int FIFO_SIZE[NUM_FIFO] = {"); + for (int indx = 0; indx < x.getChannelList().size(); indx++) { + int size = x.getChannelList().elementAt(indx).getSize(); + if (x.getChannelList().elementAt(indx).getTokenSize() != 0) { + size *= x.getChannelList().elementAt(indx).getTokenSize(); + } + if(indx == x.getChannelList().size() - 1) { + _mainPS.print(size); + } else { + _mainPS.print(size + ", "); + } + } + + _mainPS.println("}; // Size of the FIFOs"); + _mainPS.println(""); + _mainPS.println("#endif // _CONSTANT_H_ "); + } + catch (Exception e) { + System.out.println("CellModuleVisitor: exception occured: " + + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * + * @param x process that needs to be processed + */ + public void visitComponent(Process x) { + } + + /** + * + * @param x channel that needs to be processed + */ + public void visitComponent(Channel x) { + } + + protected CellMapping _mapping; + protected CodePrintStream _mainPS = null; + protected String _dir = null; +} diff --git a/dol/src/dol/visitor/cell/CellMakefileVisitor.java b/dol/src/dol/visitor/cell/CellMakefileVisitor.java new file mode 100644 index 0000000..8c7e22e --- /dev/null +++ b/dol/src/dol/visitor/cell/CellMakefileVisitor.java @@ -0,0 +1,130 @@ +package dol.visitor.cell; + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.Vector; + +import dol.datamodel.pn.Configuration; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate a CBE package + * Makefile. + */ +public class CellMakefileVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir + * path of the Makefile + */ + public CellMakefileVisitor(String dir, CellMapping mapping) { + _dir = dir; + _mapping = mapping; + } + + /** + * Create a Makefile for the given process network. + * + * @param pn + * process network + */ + public void visitComponent(ProcessNetwork pn) { + try { + String filename = _dir + _delimiter + "Makefile"; + OutputStream file = new FileOutputStream(filename); + PrintStream ps = new PrintStream(file); + + ps.println("####################"); + ps.println("# Main Makefile for the DOL application on the CBE"); + ps.println("####################"); + ps.println(); + ps.println("# Subdirectories"); + + + // Subdirectories of baseprocesses on the SPU + String subdirectories = ""; + Vector pList = new Vector(); + for (Process process : _mapping.getAllSpuBaseProcess()) { + String basename = process.getBasename(); + subdirectories += "spu_" + basename + " "; + } + + // Directory for the SPU OS'es (only if there are really processes on the SPE! + if (_mapping.getNrSPUProcess() > 0) + subdirectories += "spu"; + + String srcdirectories = ""; + + // Subdirectory of baseprocesses on the PPU + for (Process process : _mapping.getAllPPUBaseProcess()) { + String basename = process.getBasename(); + srcdirectories += " $(wildcard ppu_" + basename + "/*.cpp)"; + } + + // Directory for the PPU OS'es + srcdirectories += " $(wildcard ppu/*.cpp)"; + + String linkList = ""; + String srcList = ""; + for (Process process : _mapping.getAllPPUBaseProcess()) { + String basename = process.getBasename(); + linkList += "ppu_" + basename + "/ppu_" + basename + ".o "; + srcList += "$(wildcard ppu_" + basename + "/*.cpp) "; + } + pList.clear(); + + ps.println("DIRS := " + subdirectories); + ps.println(""); + + ps.println("# General definitions:"); + ps.println("CC = ppu-g++"); + ps.println("CCFLAGS = -ftree-vectorize -O3 -maltivec -funroll-loops -mabi=altivec -mcpu=cell"); + ps.println("COMPILE = $(CC) $(CCFLAGS) -c"); + ps.print("LINK = $(CC) -lspe2 -lpthread "); + for (Configuration conf : pn.getCfgList()) { + if (conf.getName().equals("DYNAMIC_LINK")) + ps.print(conf.getValue() + " "); + } + ps.println(""); + + ps.println("CBE_INCLUDE = /opt/cell/sdk/usr/include"); + ps.println("LIB_INC = -I lib -I lib/ppu -I lib/pt -I . -I $(CBE_INCLUDE)"); + ps.println("RM = rm"); + ps.println("ECHO = echo"); + ps.println("EXE = sc_application"); + ps.println(""); + ps.println("src := $(wildcard lib/ppu/*.cpp) $(wildcard *.cpp)" + srcdirectories); + ps.println("srcAll := $(wildcard lib/ppu/*.cpp) $(wildcard *.cpp) " + srcList); + ps.println("srcspu := $(wildcard lib/spu/*.cpp) "); + ps.println("obj = $(src:.cpp=.o)"); + ps.println("objspu = $(srcspu:.cpp=.o)"); + ps.println(""); + ps.println("$(EXE): $(obj) $(srcAll)"); + ps.println("\tfor d in $(DIRS); do (cd $$d; $(MAKE) ); done"); + ps.println("\t$(LINK) -o $(EXE) $(obj)"); + ps.println(""); + ps.println("%.o :"); + ps.println("\t$(COMPILE) -o $(*D)/$(*F).o $(*D)/$(*F).cpp $(LIB_INC)"); + ps.println(""); + ps.println("clean:"); + ps.println("\tfor d in $(DIRS); do (cd $$d; $(MAKE) clean ); done"); + ps.println("\trm $(objspu)"); + ps.println("\trm $(obj) "); + ps.println("\trm $(EXE)"); + ps.println(""); + + } catch (Exception e) { + System.out.println("CbeMakefileVisitor: exception occured: " + + e.getMessage()); + e.printStackTrace(); + } + } + + protected String _dir = null; + protected CellMapping _mapping; +} diff --git a/dol/src/dol/visitor/cell/CellMapping.java b/dol/src/dol/visitor/cell/CellMapping.java new file mode 100644 index 0000000..d5421c5 --- /dev/null +++ b/dol/src/dol/visitor/cell/CellMapping.java @@ -0,0 +1,324 @@ +package dol.visitor.cell; + +import java.util.ArrayList; +import java.util.Vector; + +import dol.datamodel.architecture.Architecture; +import dol.datamodel.mapping.ComputationBinding; +import dol.datamodel.mapping.Mapping; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.main.UserInterface; +import dol.parser.xml.archischema.ArchiXmlParser; +import dol.parser.xml.mapschema.MapXmlParser; + +public class CellMapping { + + /** + * Constructor + * @param pn + */ + CellMapping(ProcessNetwork pn, String mapping, boolean ppu, int nrSPU) { + _pn = pn; + + _maxSPU = nrSPU; + + // Select the mapping + + // Structural mapping + if (mapping.compareTo("structural") == 0) { + System.out.println("Cell: use structural mapping"); + structuralMapping(pn, ppu); + } + + // Random mapping + else if (mapping.compareTo("random") == 0) { + System.out.println("Cell: use random mapping"); + randomMapping(pn, ppu); + } + + // Predefined + else if (mapping.compareTo("predefined") == 0) { + System.out.println("Cell: Use predefined mapping."); + System.out.println(" All other parameters are ignored."); + predefinedMapping(pn); + + _maxSPU = _SPUList.size(); + ppu = this._PPU.size() == 0 ? false : true; + } + + // All to PPU + else if (mapping.compareTo("ppu") == 0) { + System.out.println("Cell: Map all processes to the PPU"); + allPPUMapping(pn); + } + + // Default mapping + else { + System.out.println("WARNING: Cell: use default mapping"); + structuralMapping(pn, ppu); + } + + System.out.println("Cell: Nr of SPE is " + _maxSPU); + + if (ppu) { + System.out.println("Cell: Mapped some processes to the PPE"); + } + } + + /** + * Returns a list which process is mapped to which spu + * + * @return the process list + */ + public ArrayList> getSPUList() { + return _SPUList; + } + + /** + * Returns list of all processes which are mapped to an spu + */ + public Vector getAllSpuProcess() { + Vector processList = new Vector(); + + for (Vector spu : _SPUList) { + for (Process p : spu) { + processList.add(p); + } + } + return processList; + } + + /** + * Returns a list of all base processes which occur on the spu's + */ + public Vector getAllSpuBaseProcess() { + Vector pList = new Vector(); + Vector pListName = new Vector(); + for (Process process : getAllSpuProcess()) { + String basename = process.getBasename(); + if (!pListName.contains(basename)) { + pList.add(process); + pListName.add(basename); + } + } + return pList; + } + + /** + * Returns a list of all processes which are mapped to the ppu + */ + public Vector getPPU() { + return _PPU; + } + + /** + * Returns a list of all base processes which occur on the ppu + */ + public Vector getAllPPUBaseProcess() { + Vector pList = new Vector(); + Vector pListName = new Vector(); + for (Process process : _PPU) { + String basename = process.getBasename(); + if (!pListName.contains(basename)) { + pList.add(process); + pListName.add(basename); + } + } + return pList; + } + + /** + * Return the number of processes which are mapped to the ppu + */ + public int getNrPPUProcess() { + return _PPU.size(); + } + + /** + * Returns the number of processes which are mapped to the SPU + */ + public int getNrSPUProcess() { + return getAllSpuProcess().size(); + } + + /** + * Returns the number of SPU which are used + */ + public int getNrSPE() { + return _SPUList.size(); + } + + /** + * Performs a random mapping of the processes + * + * @param x + * the process network + * @param ppu_choose + * true if the sinks and sources should be mapped to the PPU + */ + protected void randomMapping(ProcessNetwork x, boolean ppu_choose) { + ArrayList> spu = new ArrayList>(); + Vector ppu = new Vector(); + + int addSPU = 0; + for (Process p : x.getProcessList()) { + // A process to map to the PPU + if ((p.getNumOfInports() == 0 || p.getNumOfOutports() == 0) + && ppu_choose) { + ppu.add(p); + } + + // A process to map to the SPU + else { + // As long as there is a free SPU, add the process to this SPU + if (addSPU < _maxSPU) { + Vector pList = new Vector(); + pList.add(p); + spu.add(pList); + } + + // Have to add the process to an already used SPU + else { + spu.get(addSPU % _maxSPU).add(p); + } + + addSPU++; + } + } + + _SPUList = spu; + _PPU = ppu; + } + + /** + * Performs a structural mapping of the processes. That means that the + * function tries to keep the structural order of the process network. The + * order is given depending on the occurrence of the process in the + * structure file. + * + * @param x + * the process network + * @param ppu_choose + * true if the sinks and sources should be mapped to the PPU + */ + protected void structuralMapping(ProcessNetwork x, boolean ppu_choose) { + ArrayList> spu = new ArrayList>(); + Vector ppu = new Vector(); + + Vector spu_temp = new Vector(); + + // Each process is allocated to the PPE or the SPE (as general) + for (Process p : x.getProcessList()) { + // A process to map to the PPU + if ((p.getNumOfInports() == 0 || p.getNumOfOutports() == 0) + && ppu_choose) { + ppu.add(p); + } + + // A process to map to the SPU + else { + spu_temp.add(p); + } + } + + System.out.println("Total processes: " + spu_temp.size()); + + // Do the structural mapping for all the SPE processes + int nrSPUProcess = spu_temp.size(); + for (int i = 0; i < _maxSPU; i++) { + + if (spu_temp.size() <= 0) + break; + + Vector pList = new Vector(); + for (int j = 0; j < Math.ceil(((double) (nrSPUProcess - i)) + / _maxSPU); j++) { + pList.add(spu_temp.remove(0)); + } + + spu.add(pList); + } + + System.out.println("End Total processes: " + spu_temp.size()); + + _SPUList = spu; + _PPU = ppu; + } + + /** + * Maps the processes depending on the architectural and mapping files + * + * @param x + */ + protected void predefinedMapping(ProcessNetwork x) { + // The SPUs + ArrayList> spu = new ArrayList>(); + + // The PPU + Vector ppu = new Vector(); + + ArchiXmlParser archParser = new ArchiXmlParser(); + //System.out.println(_ui.getPlatformFileName()); + Architecture arch = archParser.doParse(_ui.getPlatformFileName()); + MapXmlParser mappingParser = new MapXmlParser(x, arch); + Mapping mapping = mappingParser.doParse(_ui.getMappingFileName()); + + // Go through all process and check where to add + for (Process p : x.getProcessList()) { + for (ComputationBinding b : mapping.getCompBindList()) { + if (b.getProcess().getName().equals(p.getName())) { + // Mapping to PPU + if (b.getProcessor().getName().equals("ppu")) { + System.out.println("Mapped process " + p.getName() + + " to the PPU"); + ppu.add(p); + } + // Maps to one of the SPU, they are written in the format + // spu_0, spu_1, ... + else { + int index = Integer.valueOf(b.getProcessor() + .getName().replaceAll(".*_", "")); + + while (spu.size() <= index) { + Vector spu_temp = new Vector(); + spu.add(spu_temp); + } + + spu.get(index).add(p); + System.out.println("Mapped process " + p.getName() + + " to the SPU_" + index); + } + } + } + } + + _SPUList = spu; + _PPU = ppu; + } + + + /** + * Performs a mapping of all processes to the PPU. + * + * @param x the process network + */ + protected void allPPUMapping(ProcessNetwork x) { + ArrayList> spu = new ArrayList>(); + Vector ppu = new Vector(); + + // Each process is allocated to the PPE or the SPE (as general) + for (Process p : x.getProcessList()) { + ppu.add(p); + } + + _SPUList = spu; + _PPU = ppu; + } + + protected ArrayList> _SPUList = null; + protected Vector _PPU = null; + protected ProcessNetwork _pn; + protected int _maxSPU = 6; + protected UserInterface _ui = UserInterface.getInstance(); +} diff --git a/dol/src/dol/visitor/cell/CellModuleVisitor.java b/dol/src/dol/visitor/cell/CellModuleVisitor.java new file mode 100644 index 0000000..10c700b --- /dev/null +++ b/dol/src/dol/visitor/cell/CellModuleVisitor.java @@ -0,0 +1,386 @@ +package dol.visitor.cell; + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Vector; + +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.visitor.PNVisitor; +import dol.main.UserInterface; +import dol.util.CodePrintStream; + +/** + * This class is a class for a visitor that is used to generate the main + * program. + * + * @author lschor, 2008-10-30 + * + * Remarks: Based on a original file from khuang for rtems + * + * Revision: 2008-10-30: Updated the file for the CBE 2008-11-08: Add + * double buffering 2008-11-16: Add new fifo implementation and defines + * for measurement 2008-11-21: Sink/Source do not run on the SPE, but on + * the PPE (as Linux thread) 2009-03-17: Added Protothread Support + * 2009-04-07: Several modifications, so that one only writes if there + * is enough memory, do not allocate all queues on PPU + */ +public class CellModuleVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir + * path of this file + */ + public CellModuleVisitor(String dir, HashMap portMap, + CellMapping mapping) { + _dir = dir; + _portMap = portMap; + _mapping = mapping; + } + + /** + * Visit process network. + * + * @param x + * process network that needs to be rendered + */ + public void visitComponent(ProcessNetwork x) { + try { + // Create in a first step the different SPU OS Layers + ArrayList> spuList = _mapping.getSPUList(); + Vector ppu = _mapping.getPPU(); + + // Create the main file for the PPU + _ui = UserInterface.getInstance(); + String filename = _dir + _delimiter + "ppu_main.cpp"; + OutputStream file = new FileOutputStream(filename); + _mainPS = new CodePrintStream(file); + + // create header section + _mainPS.println("// ========================"); + _mainPS.println("// ppu_main.cpp file"); + _mainPS.println("// ========================"); + _mainPS.println(""); + + // Includes + _mainPS.println("#include \"ppu_main.h\""); + _mainPS.println(""); + + // Function to create and run one SPE thread + _mainPS.println("// create and run one SPE thread"); + _mainPS.println("void *spu_pthread(void *arg) {"); + _mainPS.println(" spu_data_t *datp = (spu_data_t *)arg;"); + _mainPS.println(" uint32_t entry = SPE_DEFAULT_ENTRY;"); + _mainPS.println(" printf(\")PPE: spe thread start run\\n\" );"); + _mainPS.println(" if(spe_context_run(datp->spe_ctx,&entry,0,datp->argp,NULL,NULL)<0){"); + _mainPS.println(" perror (\"Failed running context\"); exit (1);"); + _mainPS.println(" }"); + _mainPS.println(" printf(\")PPE: spe thread finish run\\n\");"); + _mainPS.println(" pthread_exit(NULL);"); + _mainPS.println("}"); + _mainPS.println(""); + + // Declaration of the Header function for the PPE-Wrappers + /* + * for (Process p : ppu) { _mainPS.println("void *"+ p.getBasename() + * + "_wrapper( void *ptr );"); } + */ + _mainPS.println("void *ppu( void *ptr );"); + _mainPS.println(); + + // Create the port_id and the port_queue_id arrays to send over the + // DMA + for (Process process : _mapping.getAllSpuProcess()) { + String processName = process.getName(); + _mainPS.println("volatile char " + processName + + "_name[256] __attribute__ ((aligned(16)));"); + } + _mainPS.println(); + + // Go through all SPEs + for (Vector spu : spuList) { + _mainPS.println("volatile uint64_t spu_" + + spuList.indexOf(spu) + "[" + spu.size() + + "] __attribute__ ((aligned(16)));"); + } + _mainPS.println(); + _mainPS.println("// The input queue of a process is always on the SPU of the receiver, negative means that the queue is on the PPE"); + _mainPS.println("volatile int32_t queueOnSPU [NUM_FIFO] __attribute__ ((aligned(16)));"); + _mainPS.println(); + _mainPS.println(" // The queue comes from this SPU"); + _mainPS.println("volatile int32_t queueFromSPU [NUM_FIFO] __attribute__ ((aligned(16)));"); + _mainPS.println(); + _mainPS.println(" volatile uint64_t ea_ls_base[NUM_SPES] __attribute__ ((aligned(16)));"); + _mainPS.println("volatile uint64_t context_addr[NUM_SPES] __attribute__ ((aligned(16)));"); + _mainPS.println("volatile spe_spu_control_area_t* mfc_ctl[NUM_SPES] __attribute__ ((aligned(16)));"); + _mainPS.println("volatile uint64_t fifoTails[NUM_FIFO] __attribute__ ((aligned(16)));"); + _mainPS.println(); + + // Create the main function + _mainPS.println("int main()"); + _mainPS.println("{"); + + // List with all SPU to be open + _mainPS.println(" char spe_names[NUM_SPES][60] = {"); + for (Vector spu : spuList) { + _mainPS.println(" \"spu/spu_os_" + spuList.indexOf(spu) + + "\","); + } + _mainPS.println(" };"); + + _mainPS.println(); + + for (Channel c : x.getChannelList()) { + // Search for the origin spe + int origin = -1; + + for (Vector spu : spuList) { + + if (spu.contains(c.getOrigin())) { + origin = spuList.indexOf(spu); + break; + } + } + + // Origin on the PPU + if (origin == -1) { + origin = (-1) * (ppu.indexOf(c.getOrigin()) + 1); + } + + _mainPS.println(" queueFromSPU[" + + x.getChannelList().indexOf(c) + "] = " + origin + + ";"); + } + + _mainPS.println(); + + for (Channel c : x.getChannelList()) { + // Search for the origin spe + int origin = -1; + + for (Vector spu : spuList) { + if (spu.contains(c.getTarget())) { + origin = spuList.indexOf(spu); + break; + } + } + + // Origin on the PPU + if (origin == -1) { + origin = (-1) * (ppu.indexOf(c.getTarget()) + 1); + } + + _mainPS.println(" queueOnSPU[" + + x.getChannelList().indexOf(c) + "] = " + origin + + ";"); + } + + _mainPS.println(); + + // connect ports to channels + HashMap channel_map = new HashMap(); + + int j = 0; + for (Channel c : x.getChannelList()) { + channel_map.put(c, j++); + } + + // Add to each process the ports and the queues + _mainPS + .println(" //Add to each process the ports and the queues"); + j = 0; + + // SPU Process + for (Process process : _mapping.getAllSpuProcess()) { + String processName = process.getName(); + _mainPS.println(" ctx_proc[" + j + "]" + + ".is_detached = 0;"); + _mainPS.println(" strcpy((char *)" + processName + + "_name, " + "\"" + processName + "\");"); + _mainPS.println(" ctx_proc[" + j + "]" + + ".processName = (uint64_t) " + processName + + "_name;"); + _mainPS.println(" ctx_proc[" + j + "]" + + ".processNameLen = ((strlen((char *)" + + processName + "_name) + 15) & ~15);"); + _mainPS.println(); + j++; + } + + _mainPS.println(" // Mapping tasks -> What to map to which SPE?"); + _mainPS.println(" // Example: Square 0-2 to SPE 0 AND Square 3-5 to SPE 1"); + j = 0; + for (Process process : _mapping.getAllSpuProcess()) { + for (Vector spu : spuList) { + if (spu.contains(process)) { + _mainPS.println(" spu_" + spuList.indexOf(spu) + + "[" + spu.indexOf(process) + + "] = (uint64_t) &(ctx_proc[" + j + + "]);"); + j++; + break; + } + } + } + + for (Vector spu : spuList) { + _mainPS.println(" ctx_spu[" + spuList.indexOf(spu) + + "].procContents = (uint64_t) spu_" + + spuList.indexOf(spu) + ";"); + _mainPS.println(" ctx_spu[" + spuList.indexOf(spu) + + "].procContentsLen = " + spu.size() + ";"); + } + + _mainPS.println(); + + // Init the SPE control structure + _mainPS.println(" //Initiate SPEs control structure"); + _mainPS.println(" int num = 0; "); + _mainPS.println(" for( num=0; num variable store the executable name"); + _mainPS.println(" // - Load SPEs objects into SPE context local store"); + _mainPS.println(" for( num=0; numprocContentsAll = (uint64_t *) context_addr;"); + _mainPS.println(" ppu_Process_Wrapper->queueFromSPU = (int32_t *)queueFromSPU;"); + _mainPS.println(" ppu_Process_Wrapper->queueOnSPU = (int32_t *)queueOnSPU;"); + _mainPS.println(" ppu_Process_Wrapper->ea_ls_base = (uint64_t *)ea_ls_base;"); + _mainPS.println(" ppu_Process_Wrapper->fifoTails = (uint64_t *) fifoTails;"); + _mainPS.println(" "); + + _mainPS.println(" // create SPE pthreads"); + _mainPS.println(" for( num=0; num 16) + return number + 16 - (number % 16); + else if (number > 8) + return 16; + else if (number > 4) + return 8; + else if (number > 2) + return 4; + else if (number > 1) + return 2; + else + return 1; + } + + protected CodePrintStream _mainPS = null; + protected String _dir = null; + protected HashMap _portMap; + protected CellMapping _mapping; + +} diff --git a/dol/src/dol/visitor/cell/CellPPEVisitor.java b/dol/src/dol/visitor/cell/CellPPEVisitor.java new file mode 100644 index 0000000..e283fa6 --- /dev/null +++ b/dol/src/dol/visitor/cell/CellPPEVisitor.java @@ -0,0 +1,421 @@ +package dol.visitor.cell; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.StringTokenizer; +import java.util.Vector; + +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.util.CodePrintStream; +import dol.visitor.PNVisitor; + +public class CellPPEVisitor extends PNVisitor { + /** + * Constructor. + * + * @param dir + * path of this file + */ + public CellPPEVisitor(String dir, CellMapping mapping) { + _dir = dir; + _mapping = mapping; + } + + /** + * Visit process network. + * + * @param x + * process network that needs to be rendered + */ + public void visitComponent(ProcessNetwork x) { + try { + // Create a directory for the OS Layer: + _ppuDir = _dir + _delimiter + "ppu"; + File dir = new File(_ppuDir); + dir.mkdirs(); + + // Copy the header file to this directory + // Some library files must be copied to the main directory + (new File(_dir + _delimiter + "lib" + _delimiter + "ppu_os.h")) + .renameTo(new File(dir.getPath() + _delimiter + + "spu_os.h")); + + createOSLayer(x, _mapping.getPPU()); + + createMakefilePPU(); + } catch (Exception e) { + System.out.println("CellPPEVisitor: exception occured: " + + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * Creates the OS layer for one SPU + * + * @param spu + * List of all processes a SPU gets + * @param index + * index of the SPU in the SPU list + */ + protected void createOSLayer(ProcessNetwork x, Vector ppu) { + try { + // Create the filename for the new layer + String filename = _ppuDir + _delimiter + "ppu_os.cpp"; + + // PrintStream for writing to the file + OutputStream file = new FileOutputStream(filename); + CodePrintStream _code = new CodePrintStream(file); + + _code = new CodePrintStream(file); + + _code.printPrefixln("#include \"pt.h\""); + _code.printPrefixln("#include \"Fifo.h\""); + _code.printPrefixln("#include \"WindowedFifo.h\""); + _code.printPrefixln("#include \"FastCommunication.h\""); + _code.printPrefixln("#include \"common_ppu.h\""); + _code.printPrefixln("#include \"common.h\""); + for (Process p : ppu) { + _code.printPrefixln("#include \".." + _delimiter + "ppu_" + + p.getBasename() + _delimiter + p.getBasename() + + "Wrapper.h\""); + } + + _code.println(); + _code.printPrefixln("void *ppu( void *ptr )"); + _code.printLeftBracket(); + + // instantiate channels + Vector channelList = new Vector(); + int indx = 0; + for (Channel c : x.getChannelList()) { + if (ppu.contains(c.getOrigin()) + || ppu.contains(c.getTarget())) { + channelList.add(c); + + if (c.getType().equals("fifo")) { + // This is a IN-Channel --> Add an additional Factor to increase the speed + if (ppu.contains(c.getTarget()) && !ppu.contains(c.getOrigin())) { + _code.printPrefixln("Fifo " + c.getName() + + "(FIFO_SIZE[" + indx +"] * FIFO_SIZE_FACTOR);"); + // OUT-Channel --> Do not add any factor as we like to stall sometimes + } else { + _code.printPrefixln("Fifo " + c.getName() + + "(FIFO_SIZE[" + indx + "]);"); + } + } else if (c.getType().equals("wfifo")) { + _code.printPrefixln("WindowedFifo " + c.getName() + + "(FIFO_SIZE[" + indx + "]);"); + } + } + indx++; + } + _code.println(); + + // instantiate processes + for (Process p : ppu) { + _code.printPrefix("int " + p.getName() + "Indices[] = { "); + Vector iteratorIndex = p.getIteratorIndices(); + if (iteratorIndex.size() < 4) { + while (iteratorIndex.size() < 4) { + iteratorIndex.add(-1); + } + } else if (iteratorIndex.size() > 4) { + new RuntimeException("Error: Currently not more than " + + "4 iterator dimensions are supported." + + "Consider revising " + p.getBasename() + "."); + } + for (int i = 0; i < 4; i++) { + if (i < 3) { + _code.print(iteratorIndex.elementAt(i) + ", "); + } else { + _code.println(iteratorIndex.elementAt(i) + " };"); + } + } + _code.println(); + _code.printPrefixln(p.getBasename() + "Wrapper *" + p.getName() + ";"); + _code.printPrefixln("try { " + + p.getName() + " = new " + p.getBasename() + + "Wrapper(\"" + p.getName() + "\", " + + p.getName() + "Indices); }"); + _code.println(" catch(std::bad_alloc &e) {"); + _code.println(" fprintf(stderr, \"[" + p.getBasename() +"Wrapper] Memory allocation failure\\n\");"); + _code.println(" exit(1);"); + _code.println(" }"); + } + _code.println(); + + // connect the network + for (Process p : ppu) { + for (Port port : p.getPortList()) { + if (port.getName().equals(port.getBasename())) { + _code.printPrefixln(p.getName() + "->_port" + + port.getName() + "Fifo = &" + + port.getPeerResource().getName() + ";"); + } else { + _code.printPrefix(p.getName() + "->_port" + + port.getBasename() + "Fifo"); + StringTokenizer tokenizer = new StringTokenizer( + port.getName().replaceFirst( + port.getBasename(), ""), "_"); + while (tokenizer.hasMoreTokens()) { + _code.print("[" + tokenizer.nextToken() + "]"); + } + _code.println(" = &" + + port.getPeerResource().getName() + ";"); + } + } + } + _code.println(); + + /**************************************************************************/ + // This is the synchronisation code + _code.println(" for (int i = 0; i < NUM_FIFO; i++)"); + _code.println(" ((ProcessData *)ptr)->fifoTails[i] = 0;"); + _code.println(" "); + + int outQueues = 0; + + // Check all out queues on the SPU + for (Channel c : x.getChannelList()) { + + // Check all SPUs + for (Vector spu : _mapping.getSPUList()) { + if (spu.contains(c.getOrigin()) && !spu.contains(c.getTarget())) { + outQueues++; + } + } + + // Check the PPU + if (ppu.contains(c.getOrigin()) && !ppu.contains(c.getTarget())) { + outQueues++; + } + } + + // On how much queues we have to wait + _code.println(" uint32_t nrOutQueues = NUM_FIFO;"); + _code.println(" uint32_t countOutQueues = 0;"); + _code.println(" uint32_t processNr = 0;"); + _code.println(" uint32_t message;"); + _code.println(""); + + // Add all out queues of the PPE + + for (Channel c : channelList) { + if (ppu.contains(c.getOrigin()) && !ppu.contains(c.getTarget())) { + _code.println(" ((ProcessData *)ptr)->fifoTails[" + x.getChannelList().indexOf(c) + "] = (uint64_t) " + c.getName() + ".getQueuePointer();"); + _code.println(" countOutQueues++;"); + } + } + + // Check to get all messages back + _code.println(" "); + _code.println(" // Get the offset of the queues"); + _code.println(" while (countOutQueues < nrOutQueues) {"); + _code.println(" for (processNr = 0; processNr < NUM_SPES; processNr++) {"); + _code.println(" if (!spe_out_mbox_status((spe_context*)((ProcessData *)ptr)->procContentsAll[processNr])) continue;"); + _code.println(" "); + _code.println(" spe_out_mbox_read((spe_context*)((ProcessData *)ptr)->procContentsAll[processNr], &message, 1);"); + _code.println(" "); + _code.println(" uint32_t queue = ((message >> 24) & 0xFF);"); + _code.println(" uint32_t offset = ((message >> 0) & 0xFFFFFF);"); + _code.println(" "); + _code.println(" if (((ProcessData *)ptr)->queueOnSPU[queue] < 0)"); + _code.println(" ((ProcessData *)ptr)->fifoTails[queue] = offset; // Only the offset if the PPE needs to access the data"); + _code.println(" else"); + _code.println(" ((ProcessData *)ptr)->fifoTails[queue] = offset + ((ProcessData *)ptr)->ea_ls_base[processNr];"); + _code.println(" countOutQueues++;"); + _code.println(" }"); + _code.println(" }"); + _code.println(" "); + + // Send a message that each SPE knows that he can access the list + _code.println(" // Send the Okay to all SPEs for that they can start reading the tail pointers of the fifos"); + _code.println(" message = MSG_OK;"); + _code.println(" for (processNr = 0; processNr < NUM_SPES; processNr++) {"); + _code.println(" spe_in_mbox_write((spe_context*)((ProcessData *)ptr)->procContentsAll[processNr], (uint32_t*)&message, 1, SPE_MBOX_ANY_NONBLOCKING);"); + _code.println(" }"); + + /**************************************************************************/ + + // initialize processes + for (Process p : ppu) { + _code.printPrefixln(p.getName() + "->init();"); + } + _code.println(); + + // Count the effected channels + int countChannels = 0; + for (Channel c : channelList) { + if (ppu.contains(c.getOrigin()) + && ppu.contains(c.getTarget())) { + continue; + } else if (ppu.contains(c.getOrigin())) + countChannels++; + else if (ppu.contains(c.getTarget())) + countChannels++; + else + System.out.println("ERROR! Channel Mapping is wrong."); + } + + + _code.println(" FastCommunication * com;"); + _code + .println(" try { com = new FastCommunication(" + + countChannels + + ", ((ProcessData *)ptr)->procContentsAll, ((ProcessData *)ptr)->ea_ls_base, ((ProcessData *)ptr)->queueFromSPU, ((ProcessData *)ptr)->queueOnSPU, ((ProcessData *)ptr)->fifoTails); }"); + _code.println(" catch(std::bad_alloc &e) {"); + _code.println(" fprintf(stderr, \"[FastCommunication] Memory allocation failure\\n\");"); + _code.println(" exit(1);"); + _code.println(" }"); + + String channelTyp = ""; + int i = 0; + for (Channel c : channelList) { + if (ppu.contains(c.getOrigin()) + && ppu.contains(c.getTarget())) { + // Local channels have no influence on external + // communication (should be Windowed Fifos...) + channelTyp = "local"; + continue; + } else if (ppu.contains(c.getOrigin())) { + channelTyp = "out"; + } else if (ppu.contains(c.getTarget())) { + channelTyp = "in"; + } else { + System.out.println("ERROR! Channel Mapping is wrong."); + } + + if (c.getType().equals("fifo")) { + _code.println(" com->addFifo(" + (i) + ", &" + + c.getName() + ", com->" + channelTyp + ", " + + x.getChannelList().indexOf(c) + ");"); + } else if (c.getType().equals("wfifo")) { + _code.println(" com->addWFifo(" + (i) + ", &" + + c.getName() + ", com->" + channelTyp + ", " + + x.getChannelList().indexOf(c) + ");"); + } + i++; + } + + _code.printPrefixln("bool allBlocked = false;"); + _code.printPrefixln("while(!allBlocked)"); + _code.printLeftBracket(); + _code.printPrefixln("allBlocked = true;"); + for (Process p : ppu) { + _code.printPrefixln("if (!" + p.getName() + + "->isDetached()) {"); + _code.printPrefixln(" " + p.getName() + "->fire();"); + _code.printPrefixln(" allBlocked = false;"); + _code.printPrefixln("}"); + _code.printPrefixln(""); + + + + // Communication only if this process needs some communication + for (Channel c : channelList) { + // The channel may goes away + if (!ppu.contains(c.getOrigin()) || !ppu.contains(c.getTarget())) { + if (c.getOrigin().equals(p) || c.getTarget().equals(p)) { + _code.printPrefixln("com->update();"); + _code.printPrefixln(""); + break; + } + } + } + + } + _code.printRightBracket(); + _code.println(); + + _code.println(); + _code.println(" // Are there any open communication requests?"); + _code.println(" while (!com->empty())"); + _code.println(" {"); + _code.println(" com->update();"); + _code.println(" }"); + _code.println(" "); + _code.println(" // Send all SPUs the complete message"); + _code.println(" message = MSG_OK;"); + _code.println(" for (processNr = 0; processNr < NUM_SPES; processNr++) {"); + _code.println(" spe_in_mbox_write((spe_context*)((ProcessData *)ptr)->procContentsAll[processNr], (uint32_t*)&message, 1, SPE_MBOX_ANY_NONBLOCKING);"); + _code.println(" }"); + _code.println(""); + for (Process p : ppu) { + _code.printPrefixln("delete " + p.getName() + ";"); + } + _code.printPrefixln("delete com;"); + _code.println(); + _code.printPrefixln("pthread_exit(NULL);"); + _code.printRightBracket(); + } catch (Exception e) { + System.out.println("ProtothreadModuleVisitor: " + + "exception occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * + */ + protected void createMakefilePPU() { + try { + // Directory of the process + String ppuDir = _dir + _delimiter + "ppu"; + + // Create the filename for the new wrapper + String filename = ppuDir + _delimiter + "Makefile"; + + OutputStream file = new FileOutputStream(filename); + + PrintStream _makefilePS = new CodePrintStream(file); + + _makefilePS.println("# Makefile for PPU OS"); + _makefilePS.println(""); + _makefilePS.println("src := $(wildcard ../lib/ppu/*.cpp)"); + _makefilePS.println("obj = $(src:.cpp=.o)"); + _makefilePS.println(""); + + // The Makefile must include all o-Files of the processes needed + String dependency = ""; + + // Go through all possible processes + for (Process p : _mapping.getAllPPUBaseProcess()) { + dependency += " .." + _delimiter + "ppu_" + + p.getBasename() + _delimiter + p.getBasename() + + "Wrapper.o"; + } + + _makefilePS.println("all: ${obj}"); + _makefilePS + .println("\tppu-g++ -c -I .. -I ../lib -I ../lib/pt -I ../lib/ppu -o ppu_os.o ppu_os.cpp -ftree-vectorize -lm -mtune=cell -O3 -fmodulo-sched -funroll-loops -ffast-math"); + + _makefilePS.println(); + _makefilePS.println("clean: "); + _makefilePS.println("\trm ppu_os"); + + _makefilePS.println(); + _makefilePS.println("%.o : "); + _makefilePS + .println("\tppu-g++ -c -o $(*D)/$(*F).o $(*D)/$(*F).cpp -I .. -I ../lib -I ../lib/pt -I ../lib/ppu -ftree-vectorize -lm -mtune=cell -O3 -fmodulo-sched -funroll-loops -ffast-math"); + _makefilePS.println(); + + } catch (FileNotFoundException e) { + System.out.println("CbeProcessVisitor - Makefile: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + protected String _ppuDir = null; + protected CodePrintStream _mainPS = null; + protected String _dir = null; + protected CellMapping _mapping = null; + +} diff --git a/dol/src/dol/visitor/cell/CellProcessVisitor.java b/dol/src/dol/visitor/cell/CellProcessVisitor.java new file mode 100644 index 0000000..a0c70e4 --- /dev/null +++ b/dol/src/dol/visitor/cell/CellProcessVisitor.java @@ -0,0 +1,652 @@ +package dol.visitor.cell; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.HashMap; +import java.util.StringTokenizer; +import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.SourceCode; +import dol.visitor.PNVisitor; +import dol.util.CodePrintStream; +import dol.util.Copier; +import dol.util.Sed; + +/** + * This class is a class for a visitor that is used to generate the main + * makefile for the application. + * + * @author lschor, 2008-10-30 + * + * Remarks: Based on a original file from wolferl for rtems + * + * Revision: 2008-10-30: Updated the file for the CBE 2008-11-08: Add + * double buffering 2009-03-17: Add protothreads + */ +public class CellProcessVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir + * target directory + */ + public CellProcessVisitor(String dir, HashMap portMap, + CellMapping mapping) { + _dir = dir; + _portMap = portMap; + _mapping = mapping; + } + + /** + * + * @param x + * process network that needs to be processed + */ + public void visitComponent(ProcessNetwork x) { + try { + // Create the Process staff for all processes on the SPU + for (Process p : _mapping.getAllSpuBaseProcess()) { + createSPEWrapper(p); + createMakefileProcess(p); + _adaptSources("spu_" + p.getBasename(), p); + } + + // Create the Process staff for all processes on the SPU + for (Process p : _mapping.getAllPPUBaseProcess()) { + createPPEWrapper(p); + } + } catch (Exception e) { + System.out.println("CellProcessVisitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * Creates a Wrapper for an SPE process + * + * @param p + * process that needs to be processed + */ + protected void createSPEWrapper(Process p) { + try { + + // Create of each process an own folder + // Insert into this folder the source, the wrapper and a makefile + String processDir = _dir + _delimiter + "spu_" + + p.getBasename(); + File dir = new File(processDir); + dir.mkdirs(); + + /***************** class File ******************************/ + + // Create the filename for the new wrapper + String filename = processDir + _delimiter + p.getBasename() + + "Wrapper.cpp"; + File process_file = new File(filename); + File pattern_file = new File(_dir + _delimiter + _tempDirName + + _delimiter + "spu_process_wrapper_template.cpp"); + new Copier().copyFile(pattern_file, process_file); + + String includes = ""; + for (SourceCode code : p.getSrcList()) { + includes += "#include \"" + code.getLocality() + "\"" + + System.getProperty("line.separator"); + } + + Sed sed = new Sed(); + // Replace the include of the main c-file + sed.sed(filename, "//#include \"@PROCESSNAME@.c\"", includes); + // Replace the process-name in the whole file + sed.sed(filename, "@PROCESSNAME@", p.getBasename()); + sed.sed(filename, "@PROCESSNAME_UPPER@", p.getBasename() + .substring(0, 1).toUpperCase() + + p.getBasename().substring(1)); + + /***************** header File ******************************/ + // Create the filename for the new wrapper + filename = processDir + _delimiter + p.getBasename() + + "Wrapper.h"; + process_file = new File(filename); + pattern_file = new File(_dir + _delimiter + _tempDirName + + _delimiter + "spu_process_wrapper_template.h"); + new Copier().copyFile(pattern_file, process_file); + + includes = ""; + for (SourceCode code : p.getSrcList()) { + includes += "#include \"" + code.getLocality() + "\"" + + System.getProperty("line.separator"); + } + + sed = new Sed(); + // Replace the include of the main c-file + sed.sed(filename, "//#include \"@PROCESSNAME@.c\"", includes); + // Replace the process-name in the whole file + sed.sed(filename, "@PROCESSNAME@", p.getBasename()); + + // Create the correct Port and Fifo List + String fifolist = ""; + Vector basenames = new Vector(); + for (Port port : p.getPortList()) { + if (!basenames.contains(port.getBasename())) { + basenames.add(port.getBasename()); + } else { + continue; + } + + Channel c = (Channel) port.getPeerResource(); + if (port.getName().equals(port.getBasename())) { + if (c.getType().equals("fifo")) { + fifolist += "Fifo* _port" + port.getName() + + "Fifo;"; + } else if (c.getType().equals("wfifo")) { + fifolist += "WindowedFifo* _port" + port.getName() + + "Fifo;"; + } + } else { + if (c.getType().equals("fifo")) { + fifolist += "Fifo* _port" + port.getBasename() + + "Fifo"; + } else if (c.getType().equals("wfifo")) { + fifolist += "WindowedFifo* _port" + + port.getBasename() + "Fifo"; + } + StringTokenizer tokenizer = new StringTokenizer(port + .getRange(), ";"); + while (tokenizer.hasMoreTokens()) { + fifolist += "[" + tokenizer.nextToken() + "]"; + } + fifolist += ";"; + } + } + + // Set the correct Fifo's + sed.sed(filename, "@FIFO@", fifolist); + + /***************** source File ******************************/ + + // Go through all source files + for (SourceCode sourceCode : p.getSrcList()) { + // Copy the files to the new folder + String oldFilename = _dir + + _delimiter + + sourceCode.getLocality().replaceAll( + "(.*)\\.[cC][pP]*[pP]*", "$1\\.h"); + filename = processDir + + _delimiter + + sourceCode.getLocality().replaceAll( + "(.*)\\.[cC][pP]*[pP]*", "$1\\.h"); + + if (new File(filename).exists()) { + new File(filename).delete(); + } + + new File(oldFilename).renameTo(new File(filename)); + + // Copy also the c-files + if ((oldFilename.substring(oldFilename.length() - 2)) + .equals(".h")) { + String newFileNameC = filename.substring(0, filename + .length() - 2) + + ".c"; + if (new File(newFileNameC).exists()) { + new File(newFileNameC).delete(); + } + // new Copier().copyFile(new File(oldFilename.substring(0, + // oldFilename.length() - 2) + ".c"), new + // File(filename.substring(0, filename.length() - 2) + + // ".c")); + new File(oldFilename.substring(0, + oldFilename.length() - 2) + + ".c").renameTo(new File(newFileNameC)); + } + + // Update the files for the DOL project + sed.sed(filename, "", "\"dol.h\""); + + } + } catch (Exception e) { + System.out.println("CbeProcessVisitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * Creates a Wrapper for a PPE process + * + * @param p + * process that needs to be processed + */ + protected void createPPEWrapper(Process p) { + try { + // Create of each process an own folder + // Insert into this folder the source, the wrapper and a makefile + String processDir = _dir + _delimiter + "ppu_" + + p.getBasename(); + File dir = new File(processDir); + dir.mkdirs(); + + // Go through all source files + for (SourceCode sourceCode : p.getSrcList()) { + // Copy the files to the new folder + String oldFilename = _dir + + _delimiter + + sourceCode.getLocality().replaceAll( + "(.*)\\.[cC][pP]*[pP]*", "$1\\.h"); + String filename = processDir + + _delimiter + + sourceCode.getLocality().replaceAll( + "(.*)\\.[cC][pP]*[pP]*", "$1\\.h"); + + if (new File(filename).exists()) { + new File(filename).delete(); + } + + new File(oldFilename).renameTo(new File(filename)); + + // Copy also the c-files + if ((oldFilename.substring(oldFilename.length() - 2)) + .equals(".h")) { + String newFileNameC = filename.substring(0, filename + .length() - 2) + + ".c"; + if (new File(newFileNameC).exists()) { + new File(newFileNameC).delete(); + } + new File(oldFilename.substring(0, + oldFilename.length() - 2) + + ".c").renameTo(new File(newFileNameC)); + } + } + + _createPPECppFile(dir, p); + _createPPEHeaderFile(dir, p); + _adaptSources("ppu_" + p.getBasename(), p); + createMakeFilePPUProcess("ppu_" + p.getBasename(), p); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * + */ + private void _createPPECppFile(File dir, Process p) throws IOException { + String classname = p.getBasename() + "Wrapper"; + String filename = dir + _delimiter + classname + ".cpp"; + OutputStream file = new FileOutputStream(filename); + CodePrintStream ps = new CodePrintStream(file); + + ps.printPrefixln("#include \"" + classname + ".h\""); + ps.printPrefixln("#include \"dolSupport.h\""); + ps.printPrefixln("#include "); + ps.println(); + for (SourceCode sr : p.getSrcList()) { + ps.printPrefixln("#include \"" + sr.getLocality() + "\""); + } + ps.println(); + ps.printPrefixln(classname + "::" + classname + + "(char* name, int iteratorIndex[4]) :"); + ps.printPrefixln(" ProcessWrapper(name, iteratorIndex)"); + ps.printLeftBracket(); + ps.printPrefixln("_state = (LocalState)new " + + p.getBasename().substring(0, 1).toUpperCase() + + p.getBasename().substring(1) + "_State;"); + ps.printPrefixln("_process.init = " + p.getBasename() + "_init;"); + ps.printPrefixln("_process.fire = " + p.getBasename() + "_fire;"); + ps.printPrefixln("_process.local = _state;"); + ps.printPrefixln("_process.wptr = (void*)&_wrapper_data;"); + ps.printPrefixln("_wrapper_data.wrapper = this;"); + ps.printRightBracket(); + ps.println(); + ps.printPrefixln(classname + "::~" + classname + "()"); + ps.printLeftBracket(); + ps.printPrefixln("if (_state)"); + ps.printPrefixln(" delete (" + + p.getBasename().substring(0, 1).toUpperCase() + + p.getBasename().substring(1) + "_State*)_state;"); + // ps.printPrefixln(" delete _state;"); + ps.printRightBracket(); + } + + /** + * + */ + private void _createPPEHeaderFile(File dir, Process p) + throws IOException { + String classname = p.getBasename() + "Wrapper"; + String filename = dir + _delimiter + classname + ".h"; + OutputStream file = new FileOutputStream(filename); + CodePrintStream ps = new CodePrintStream(file); + + ps.printPrefixln("#ifndef " + classname.toUpperCase() + "_H"); + ps.printPrefixln("#define " + classname.toUpperCase() + "_H"); + ps.println(); + ps.printPrefixln("#include \"ProcessWrapper.h\""); + ps.printPrefixln("#include \"Fifo.h\""); + ps.printPrefixln("#include \"WindowedFifo.h\""); + ps.println(); + ps.printPrefixln("class " + classname + ";"); + ps.println(); + ps.printPrefixln("typedef struct _" + p.getBasename() + "_data {"); + ps.printPrefixln(" int lc;"); + ps.printPrefixln(" " + classname + " *wrapper;"); + ps.printPrefixln("} " + p.getBasename() + "_data;"); + ps.println(); + ps + .printPrefixln("class " + classname + + " : public ProcessWrapper"); + ps.printLeftBracket(); + ps.printPrefixln("public:"); + ps.printPrefixln(" " + classname + "(char* name, " + + "int iteratorIndex[4]);"); + ps.printPrefixln(" virtual ~" + classname + "();"); + ps.println(); + + Vector basenames = new Vector(); + for (Port port : p.getPortList()) { + if (!basenames.contains(port.getBasename())) { + basenames.add(port.getBasename()); + } else { + continue; + } + + Channel c = (Channel) port.getPeerResource(); + if (port.getName().equals(port.getBasename())) { + if (c.getType().equals("fifo")) { + ps.printPrefixln(" Fifo* _port" + port.getName() + + "Fifo;"); + } else if (c.getType().equals("wfifo")) { + ps.printPrefixln(" WindowedFifo* _port" + + port.getName() + "Fifo;"); + } + } else { + if (c.getType().equals("fifo")) { + ps.printPrefix(" Fifo* _port" + port.getBasename() + + "Fifo"); + } else if (c.getType().equals("wfifo")) { + ps.printPrefix(" WindowedFifo* _port" + + port.getBasename() + "Fifo"); + } + StringTokenizer tokenizer = new StringTokenizer(port + .getRange(), ";"); + while (tokenizer.hasMoreTokens()) { + ps.print("[" + tokenizer.nextToken() + "]"); + } + ps.println(";"); + } + } + ps.println(""); + ps.printPrefixln("protected:"); + ps.printPrefixln(" struct _local_states *_state;"); + ps + .printPrefixln(" " + p.getBasename() + + "_data _wrapper_data;"); + ps.printRightBracket(); + + ps.printPrefixln(";"); + ps.println(); + ps.printPrefixln("#endif"); + } + + /** + * Create the makefile for a special process --> Each subprocess gets its + * own makefile + * + * @param p + * process for which the makefile should be created + */ + protected void createMakefileProcess(Process p) { + try { + // Directory of the process + String processDir = _dir + _delimiter + "spu_" + + p.getBasename(); + + // Create the filename for the new wrapper + String filename = processDir + _delimiter + "Makefile"; + // File makefile = new File(filename); + + OutputStream file; + + file = new FileOutputStream(filename); + + PrintStream _makefilePS = new CodePrintStream(file); + + _makefilePS.println("# Makefile for process " + + p.getBasename()); + _makefilePS.println(""); + + String dependency = "all: " + p.getBasename() + "Wrapper.cpp"; + + for (SourceCode code : p.getSrcList()) { + dependency += " " + code.getLocality(); + } + + _makefilePS.println(dependency); + _makefilePS + .println("\tspu-g++ -c -I .. -I ../lib -o " + + p.getBasename() + + "Wrapper.o " + + p.getBasename() + + "Wrapper.cpp -ftree-vectorize -mtune=cell -O3 -fmodulo-sched -funroll-loops -ffast-math -fno-rtti -ffunction-sections -fdata-sections" ); + _makefilePS.println("clean: "); + _makefilePS.println("\trm " + p.getBasename() + "Wrapper.o"); + _makefilePS.println(); + + } catch (FileNotFoundException e) { + System.out.println("CbeProcessVisitor - Makefile: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + private void createMakeFilePPUProcess(String subdir, Process p) { + try { + // Directory of the process + String processDir = _dir + _delimiter + subdir; + + // Create the filename for the new wrapper + String filename = processDir + _delimiter + "Makefile"; + // File makefile = new File(filename); + + OutputStream file; + + file = new FileOutputStream(filename); + + PrintStream _makefilePS = new CodePrintStream(file); + + _makefilePS.println("# Makefile for process " + + p.getBasename()); + _makefilePS.println(""); + + String dependency = "all: " + p.getBasename() + "Wrapper.cpp"; + + for (SourceCode code : p.getSrcList()) { + dependency += " " + code.getLocality(); + } + _makefilePS.println("# General definitions:"); + _makefilePS.println("CC = ppu-g++"); + _makefilePS + .println("CCFLAGS = -ftree-vectorize -O3 -maltivec -funroll-loops -mabi=altivec -mcpu=cell"); + _makefilePS.println("COMPILE = $(CC) $(CCFLAGS) -c"); + + _makefilePS.println(dependency); + _makefilePS + .println("\t$(COMPILE) -o " + + p.getBasename() + + "Wrapper.o " + + p.getBasename() + + "Wrapper.cpp -I .. -I ../lib -I ../lib/ppu -I ../lib/pt;"); + _makefilePS.println("clean: "); + _makefilePS.println("\trm " + p.getBasename() + "Wrapper.o"); + _makefilePS.println(); + + } catch (FileNotFoundException e) { + System.out + .println("CbeProcessVisitor - Makefile PPU: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * Make modifications to source files of a process. Port names need to be + * strings for the SystemC code generation. Therefore, in the header files + * integer port names are put into quotation marks. + * + * @param p + * process whose sources should be adapted + * @throws IOException + * @author haidw + */ + protected void _adaptSources(String subdir, Process p) + throws IOException { + Sed sed = new Sed(); + // modify header file + for (Port port : p.getPortList()) { + String processHeaderFile; + + for (SourceCode sr : p.getSrcList()) { + processHeaderFile = _dir + + _delimiter + + subdir + + _delimiter + + sr.getLocality().replaceAll( + "(.*)\\.[cC][pP]*[pP]*", "$1\\.h"); + + sed.sed(processHeaderFile, "(#define[ ]*PORT_\\w*[ ]*)\"?" + + port.getBasename() + "\"?", "$1 " + + "static_cast<" + p.getBasename() + + "Wrapper *>((static_cast<" + p.getBasename() + + "_data *>(p->wptr))->wrapper)->_port" + + port.getBasename() + "Fifo"); + } + } + + // modify source file + for (SourceCode sr : p.getSrcList()) { + String processSourceFile = _dir + _delimiter + subdir + + _delimiter + sr.getLocality(); + + String line; + StringBuffer buffer = new StringBuffer(); + FileInputStream fileInputStream = new FileInputStream( + processSourceFile); + BufferedReader reader = new BufferedReader( + new InputStreamReader(fileInputStream)); + while ((line = reader.readLine()) != null) { + buffer.append(line + "\n"); + } + reader.close(); + + String file = buffer.toString(); + // insert PT_BEGIN() at beginning of fire() function + file = file.replaceAll("(int[ ]*" + p.getBasename() + + "_fire[ ]*\\([ ]*DOLProcess[ ]*\\*p[ ]*\\)" + + "[\\s\\S&&[^\\{]]*)\\{", "$1" + + System.getProperty("line.separator") + "{" + + System.getProperty("line.separator") + + " PT_BEGIN((pt*)(p->wptr));"); + + // replace last return statement in fire function by PT_END() + // find beginning of fire function + Matcher matcher = Pattern.compile( + "(int[ ]*" + p.getBasename() + + "_fire[ ]*\\([ ]*DOLProcess[ ]*\\*p[ ]*\\)" + + "[\\s\\S&&[^\\{]]*)\\{").matcher(file); + matcher.find(); + int i = 0; + try { + i = matcher.start(); + } catch (Exception e) { + System.out.println("Error: could not find " + + p.getBasename() + "_fire() function in " + + processSourceFile + "."); + e.printStackTrace(); + } + int openBraces = 0; // counter for open curly braces + // position of last return statement + int lastReturnStartPosition = 0; + int lastReturnEndPosition = 0; + while (i < file.length()) { + // ignore single-line comments + if (i < (file.length() - 1) + && file.substring(i, i + 2).equals("//")) { + while (!file.substring(i, i + 1).equals("\n")) { + i++; + } + } + // ignore multi-line comments + else if (i < (file.length() - 1) + && file.substring(i, i + 2).equals("/*")) { + while (!file.substring(i, i + 2).equals("*/")) { + i++; + } + } + // ignore strings + else if (file.substring(i, i + 1).equals("\"")) { + matcher = Pattern.compile("[\\s\\S&&[^\\\\]]\\\"") + .matcher(file); + matcher.find(i + 1); + i = matcher.start() + 1; + } else if (i < (file.length() - 5) + && file.substring(i, i + 6).equals("return")) { + lastReturnStartPosition = i; + while (!file.substring(i, i + 1).equals(";")) { + i++; + } + lastReturnEndPosition = i; + } else if (file.substring(i, i + 1).equals("{")) { + openBraces++; + } else if (file.substring(i, i + 1).equals("}")) { + openBraces--; + if (openBraces == 0) { + break; + } + } + i++; + } + + file = file.substring(0, lastReturnStartPosition) + + "/* " + + file.substring(lastReturnStartPosition, + lastReturnEndPosition + 1) + + " (commented out by DOL) */" + + System.getProperty("line.separator") + + " PT_END((pt*)(p->wptr));" + + System.getProperty("line.separator") + + file.substring(lastReturnEndPosition + 2, file + .length()); + + BufferedWriter out = new BufferedWriter(new FileWriter( + processSourceFile)); + out.write(file); + out.close(); + } + } + + protected CellMapping _mapping; + protected String _dir = null; + protected HashMap _portMap; + + protected static String _libDirName = "lib"; + protected static String _tempDirName = "template"; + +} diff --git a/dol/src/dol/visitor/cell/CellSPEVisitor.java b/dol/src/dol/visitor/cell/CellSPEVisitor.java new file mode 100644 index 0000000..a8061ec --- /dev/null +++ b/dol/src/dol/visitor/cell/CellSPEVisitor.java @@ -0,0 +1,416 @@ +package dol.visitor.cell; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.StringTokenizer; +import java.util.Vector; + +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.visitor.PNVisitor; +import dol.util.CodePrintStream; + +/** + * This class is a class for a visitor that is used to generate the the OS for + * the SPEs. + * + * @author lschor, 2009-03-24 * Revision: 2009-03-24: Created + */ +public class CellSPEVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir + * path of this file + */ + public CellSPEVisitor(String dir, CellMapping mapping) { + _dir = dir; + _mapping = mapping; + } + + /** + * Visit process network. + * + * @param x + * process network that needs to be rendered + */ + public void visitComponent(ProcessNetwork x) { + try { + // Create a directory where all SPU's are stored: + _spuDir = _dir + _delimiter + "spu"; + File dir = new File(_spuDir); + dir.mkdirs(); + + // Copy the header file to this directory + // Some library files must be copied to the main directory + (new File(_dir + _delimiter + "lib" + _delimiter + "spu_os.h")) + .renameTo(new File(dir.getPath() + _delimiter + + "spu_os.h")); + + ArrayList> spuList = _mapping.getSPUList(); + + int i = 0; + for (Vector spu : spuList) { + createOSLayer(x, spu, i++); + } + + createMakefileSPU(); + + } catch (Exception e) { + System.out.println("CellSPEVisitor: exception occured: " + + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * Create the makefile for a SPU (so for the layer). Each SPU gets its own + * Makefile + * + * @param spu + * SPU for which the Makefile should be used + */ + protected void createMakefileSPU() { + try { + // Directory of the process + String spuDir = _dir + _delimiter + "spu"; + + // Create the filename for the new wrapper + String filename = spuDir + _delimiter + "Makefile"; + + OutputStream file = new FileOutputStream(filename); + + PrintStream _makefilePS = new CodePrintStream(file); + + _makefilePS.println("# Makefile for SPU OS"); + _makefilePS.println(""); + _makefilePS.println("src := $(wildcard ../lib/spu/*.cpp)"); + _makefilePS.println("obj = $(src:.cpp=.o)"); + _makefilePS.println(""); + + // The Makefile must include all o-Files of the processes needed + String dependency = ""; + + // Go through all possible processes + for (Process p : _mapping.getAllSpuBaseProcess()) { + dependency += " .." + _delimiter + "spu_" + + p.getBasename() + _delimiter + p.getBasename() + + "Wrapper.o"; + } + + _makefilePS.println("all: ${obj}" + dependency); + for (int i = 0; i < _mapping.getNrSPE(); i++) { + _makefilePS.println("\tspu-g++ -Wall -I .. -I ../lib -o " + + "spu_os_" + i + " spu_os_" + i + ".cpp " + + "../lib/spu/Fifo.o ../lib/spu/WindowedFifo.o " + + "../lib/spu/dolSupport.o " + + "../lib/spu/proc_wrapper.o ../lib/spu/common.o " + + "../lib/spu/FastCommunication.o" + dependency + + " -ftree-vectorize -lm -mtune=cell -O3" + + " -fmodulo-sched -funroll-loops " + + " -ffast-math -fno-rtti -ffunction-sections" + + " -fdata-sections -Wl,--gc-sections"); + } + _makefilePS.println(); + _makefilePS.println("clean: "); + for (int i = 0; i < _mapping.getNrSPE(); i++) { + _makefilePS.println("\trm spu_os_" + i); + } + _makefilePS.println(); + _makefilePS.println("%.o : "); + _makefilePS.println("\tspu-g++ -c -o $(*D)/$(*F).o " + + "$(*D)/$(*F).cpp -I .. -I" + + " ../lib -ftree-vectorize -mtune=cell -O3" + + " -fmodulo-sched -funroll-loops -ffast-math" + + " -fno-rtti -ffunction-sections -fdata-sections"); + _makefilePS.println(); + } catch (FileNotFoundException e) { + System.out.println("CbeProcessVisitor - Makefile: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * Creates the OS layer for one SPU + * + * @param spu + * List of all processes a SPU gets + * @param index + * index of the SPU in the SPU list + */ + protected void createOSLayer(ProcessNetwork x, Vector spu, + int index) { + try { + // Create the filename for the new layer + String filename = _spuDir + _delimiter + "spu_os_" + index + + ".cpp"; + + // PrintStream for writing to the file + OutputStream file = new FileOutputStream(filename); + CodePrintStream _code = new CodePrintStream(file); + + _code.println("/****************************************************************"); + _code.println(" * SPU OS file"); + _code.println(" * Description: OS for one SPU"); + _code.println(" */"); + _code.println(); + _code.println("#include \"spu_os.h\""); + + // Must include all possible wrappers + Vector pList = new Vector(); + // Go through all possible processes + for (Process p : spu) { + String basename = p.getBasename(); + if (!pList.contains(basename)) { + pList.add(basename); + _code.println("#include \".." + _delimiter + "spu_" + + p.getBasename() + _delimiter + + p.getBasename() + "Wrapper.h\""); + } + } + + _code.println(""); + _code.println("// Main application"); + _code.println("int main(int speid , uint64_t argp)"); + _code.println("{"); + _code.println(" // reserve DMA tag ID"); + _code.println(" uint32_t tag_id;"); + _code.println(" if((tag_id=mfc_tag_reserve())==MFC_TAG_INVALID){"); + _code.println(" printf(\"SPE: ERROR - can't reserve a tag ID\"); return 1;"); + _code.println(" }"); + _code.println(" "); + _code.println(" // Get the context information for the whole system"); + _code.println(" mfc_get((void*) &ctx_spu, argp, sizeof(ctx_spu), tag_id, 0, 0);"); + _code.println(" mfc_write_tag_mask(1< channelList = new Vector(); + int indx = 0; + // instantiate channels + for (Channel c : x.getChannelList()) { + if (spu.contains(c.getOrigin()) + || spu.contains(c.getTarget())) { + channelList.add(c); + if (c.getType().equals("fifo")) { + _code.printPrefixln(" Fifo " + c.getName() + "(" + + "FIFO_SIZE[" + indx + "]);"); + } else if (c.getType().equals("wfifo")) { + _code.printPrefixln(" WindowedFifo " + + c.getName() + "(" + "FIFO_SIZE[" + indx + + "]);"); + } + } + indx++; + } + + _code.println(); + + // Go through all processes + for (Process p : spu) { + // Create the process wrapper + _code.println(" " + p.getBasename() + "Wrapper *" + p.getName() +";"); + _code.println(" try { " + + p.getName() + " = new " + p.getBasename() + + "Wrapper (context_addr[" + spu.indexOf(p) + + "]); }"); + _code.println(" catch(std::bad_alloc &e) {"); + _code.println(" fprintf(stderr, \"[" + p.getBasename() +"Wrapper] Memory allocation failure\\n\");"); + _code.println(" exit(1);"); + _code.println(" }"); + + // Create the port-mapping + for (Port port : p.getPortList()) { + if (port.getName().equals(port.getBasename())) { + _code.printPrefixln(" " + p.getName() + "->_port" + + port.getName() + "Fifo = &" + + port.getPeerResource().getName() + ";"); + } else { + _code.printPrefix(" " + p.getName() + "->_port" + + port.getBasename() + "Fifo"); + StringTokenizer tokenizer = new StringTokenizer( + port.getName().replaceFirst( + port.getBasename(), ""), "_"); + while (tokenizer.hasMoreTokens()) { + _code.print("[" + tokenizer.nextToken() + "]"); + } + _code.println(" = &" + + port.getPeerResource().getName() + ";"); + } + } + _code.println(); + } + + // Count the effected channels + int countChannels = 0; + for (Channel c : channelList) { + if (spu.contains(c.getOrigin()) + && spu.contains(c.getTarget())) { + continue; + } else if (spu.contains(c.getOrigin())) + countChannels++; + else if (spu.contains(c.getTarget())) + countChannels++; + else + System.out.println("ERROR! Channel Mapping is wrong."); + } + + _code.println(" // inited all queues, now one has to know:"); + _code.println(" // sends out the start addresses to the SPU (of all out channels)"); + + // Check all out queues on the SPU + _code.println(" uint32_t queuemessage;"); + for (Channel c : channelList) { + if (spu.contains(c.getOrigin()) && !spu.contains(c.getTarget())) { + _code.println(" queuemessage = CREATEQUEUEMESSAGE(" + x.getChannelList().indexOf(c) + ", (uint32_t)" + c.getName() + ".getQueuePointer());"); + _code.println(" spu_write_out_mbox(queuemessage);"); + } + } + + _code.println(" "); + _code.println(" // Wait until we get the okey to read the tail pointers"); + _code.println(" uint32_t messageIn = spu_read_in_mbox();"); + _code.println(""); + _code.println(" mfc_get((void*)tailAddresses, ctx_spu.fifoTails, sizeof(uint64_t) * roundDMA(NUM_FIFO), tag_id,0,0);"); + _code.println(" mfc_write_tag_mask(1<addFifo(" + (i) + ", &" + + c.getName() + ", com->" + channelTyp + ", " + + x.getChannelList().indexOf(c) + ");"); + } + else if (c.getType().equals("wfifo")) { + _code.println(" com->addWFifo(" + (i) + ", &" + + c.getName() + ", com->" + channelTyp + ", " + + x.getChannelList().indexOf(c) + ");"); + } + i++; + } + + // The scheduler (yes, this could be optimized...) + _code.println(""); + _code.println(" printf(\"SPU " + index + ": start to execute\\n\"); "); + _code.println(""); + _code.println(" bool allBlocked = false;"); + _code.println(" while (!allBlocked)"); + _code.println(" {"); + _code.println(" allBlocked = true;"); + for (Process p : spu) { + _code.println(" if (!" + p.getName() + + "->isDetached())"); + _code.println(" {"); + _code.println(" " + p.getName() + "->fire();"); + _code.println(" allBlocked = false;"); + _code.println(" }"); + + // communication only if this process needs some communication + for (Channel c : channelList) { + // the channel may go away + if (!spu.contains(c.getOrigin()) || !spu.contains(c.getTarget())) { + if (c.getOrigin().equals(p) || c.getTarget().equals(p)) { + _code.println(" com->update();"); + break; + } + } + } + _code.println(); + } + _code.println(" }"); + _code.println(); + + // End --> wait until all communications are finished + _code + .println(" // Are there any open communication requests?"); + _code.println(" while (!com->empty())"); + _code.println(" {"); + _code.println(" com->update();"); + _code.println(" }"); + + for (Process p : spu) { + _code.println(" delete " + p.getName() + ";"); + } + + _code.println(" delete com;"); + _code.println(" "); + _code.println(" // release tag ID before exiting"); + _code.println(" mfc_tag_release(tag_id);"); + _code.println(" "); + _code.println(" uint32_t message = CREATEFASTMESSAGE(SPE_COMPLETE, 0, 0);"); + _code.println(" spu_write_out_mbox(message);"); + _code.println(" "); + _code.println(" messageIn = spu_read_in_mbox();"); + _code.println("}"); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + + protected String _spuDir = null; + protected CodePrintStream _mainPS = null; + protected String _dir = null; + protected CellMapping _mapping = null; +} diff --git a/dol/src/dol/visitor/cell/CellVisitor.java b/dol/src/dol/visitor/cell/CellVisitor.java new file mode 100644 index 0000000..43c609d --- /dev/null +++ b/dol/src/dol/visitor/cell/CellVisitor.java @@ -0,0 +1,179 @@ +package dol.visitor.cell; + +import java.io.File; +import java.util.HashMap; +import java.util.Vector; + +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.main.UserInterface; +import dol.visitor.PNVisitor; +import dol.util.Copier; + +/** + * This class is a class for a visitor that is used to generate + * a CELL package. + */ +public class CellVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param packageName name of the Cell directory + */ + public CellVisitor(String packageName) { + _packageName = packageName; + _ui = UserInterface.getInstance(); + } + + /** + * Visit process network. + * + * @param pn process network that needs to be rendered. + */ + public void visitComponent(ProcessNetwork pn) { + try { + File dir = new File(_packageName); + dir.mkdirs(); + + // Create the library + File lib = new File(_packageName + _delimiter + "lib"); + lib.mkdirs(); + + //copy library files + File source = new File(_ui.getMySystemCLib(). + replaceAll("systemC", "cell").replace("%20", " ")); + new Copier().copy(source, lib); + + // Create the template + File template = new File(_packageName + _delimiter + "template"); + template.mkdirs(); + + //copy the templates + source = new File(_ui.getMySystemCLib().replaceAll("systemC", "cell").replace("lib", "template").replace("%20", " ")); + new Copier().copy(source, template); + + // Some library files must be copied to the main directory + (new File(lib.getPath() + _delimiter + "ppu_main.h")).renameTo(new File (dir.getPath() + _delimiter + "ppu_main.h")); + + //copy process source code + source = new File(_srcDirName.replace("%20", " ")); + new Copier().copy(source, dir); + + createPortMap(pn); + + // Create the mapping for this process network on the cell + CellMapping mapping = new CellMapping(pn, "predefined", true, MAX_SPUS); + + pn.accept(new CellMakefileVisitor(_packageName, mapping)); + pn.accept(new CellProcessVisitor(_packageName, _portMap, mapping)); + pn.accept(new CellModuleVisitor(_packageName, _portMap, mapping)); + pn.accept(new CellConstantVisitor(_packageName, mapping)); + pn.accept(new CellSPEVisitor(_packageName, mapping)); + pn.accept(new CellPPEVisitor(_packageName, mapping)); + } + catch (Exception e) { + System.out.println("CellVisitor: exception occured: " + + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * Create a hashmap which maps each port of the given process network + * to an integer. For each process, ports are numbered with integers + * starting from 0. + * + * @param pn process network for which the map should be generated + */ + protected void createPortMap(ProcessNetwork pn) { + _portMap = new HashMap(); + + for (Process process : pn.getProcessList()) { + int portCount = 0; + Vector portList = process.getPortList(); + Vector portNameList = new Vector(); + portNameList.clear(); + HashMap portMap = + new HashMap(); + portMap.clear(); + + for (int i = 0; i < portList.size(); i++) { + //treat single ports differently than iterated ports + String portName = portList.elementAt(i).getName(); + String baseName = portList.elementAt(i).getBasename(); + + if (portName.equals(baseName)) { + portNameList.add(portName); + portMap.put(portName, portCount++); + } else { + String range_indices = portList.elementAt(i).getRange(); + Vector range_indices_values = getIndex(range_indices, ";"); + + String port_indices = portName; + port_indices.replaceAll(baseName, ""); + Vector port_indices_values = getIndex(port_indices, "_"); + + if (!portNameList.contains(baseName)) { + portNameList.add(baseName); + portMap.put(baseName, portCount); + + int size = 1; + for (int j = 0; j < range_indices_values.size(); j++) { + size *= range_indices_values.elementAt(j); + } + portCount += size; + } + + int portId = portMap.get(baseName); + for (int j = 0; j < port_indices_values.size(); j++) { + int weight = 1; + for (int k = j + 1; k < range_indices_values.size(); k++) { + weight *= range_indices_values.elementAt(k); + } + portId += port_indices_values.elementAt(j) * weight; + } + portMap.put(portName, portId); + } + } + + for (int i = 0; i < portList.size(); i++) { + _portMap.put(portList.elementAt(i), + portMap.get(portList.elementAt(i).getName())); + } + } + } + + /** + * Gets vector of indices of a string, where the index must be + * separated by the specified separator. + * examples: + * getIndex("name_1_2", "_", 0) will return 1. + * getIndex("name_1_2", "_", 1) will return 2. + * + * @param range string to parse + * @param separator delimiter of indices + * @return vector of indices + */ + protected Vector getIndex(String range, String separator) { + Vector indices = new Vector(); + String[] subranges = range.split(separator); + for (int i = 0; i < subranges.length; i++) { + try { + int value = Integer.valueOf(subranges[i]); + indices.add(value); + } catch (Exception e) { + continue; + } + } + return indices; + } + + public final static int MAX_SPUS = 6; + protected HashMap _portMap; + protected String _packageName = null; + + protected String _srcDir = ""; + protected static String _srcDirName = "src"; +} diff --git a/dol/src/dol/visitor/cell/lib/common.h b/dol/src/dol/visitor/cell/lib/common.h new file mode 100644 index 0000000..b890fb9 --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/common.h @@ -0,0 +1,91 @@ +/**************************************************************** + * COMMON.H + * Creator: lschor, 2008-10-30 + * Description: Specifies some structs and Constants for the CBE-DOL-Implementation + * + * Revision: + * - 2008-10-30: Created + */ + +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#include +#include +#include + +#include "dol.h" +#include "constant.h" + +#define SPE_READ_DEMAND 0 +#define SPE_READ_COMPLETE 1 +#define SPE_COMPLETE 2 + +// Context for one process --> 384 bit +typedef struct{ + uint64_t port_id; + uint64_t port_queue_id; + + uint64_t processName; // Address for the name of the process + uint64_t processNameLen; // Len of the process Name + + uint32_t number_of_ports; + uint32_t is_detached; + uint32_t padd[2]; // dummy - for alignment --> It always has to be a multiple of 128 bit! +} process_context; + +// Context for one SPU --> This is send to him! +typedef struct{ + uint64_t procContents; + uint64_t procContentsLen; + + uint64_t procContentsAll; + uint64_t queueFromSPU; + uint64_t queueOnSPU; + + uint64_t fifoTails; + + uint64_t ea_base; // Base address of the context + uint32_t padd[2]; // dummy - for alignment --> It always has to be a multiple of 128 bit! +} spu_context; + + +// Create a message to send the queue offset +// 8 bit: queue number +// 24 bit: offset of the LS +#define CREATEQUEUEMESSAGE(_queue, _offset) \ + ((_queue << 24) | (_offset)) + +#define QUEUEMSGQUEUE(_message) \ + ((_message >> 24) & 0xFF) + +#define QUEUEMSGOFFSET(_message) \ + ((_message >> 0) & 0xFFFFFF) + + +// Create the message we like to send, format: +// 4 bit: code (total 16 possibilities) +// 9 bit: queue (total 512 possibilities) +// 19 bit: len +#define CREATEFASTMESSAGE(_code, _queue, _len) \ + ((_code << 28) | (_queue << 19) | (_len)) + +// Get the code from a message +#define GETFASTCODE(_message) \ + ((_message >> 28) & 0xF) + +// Get the queue from a message +#define GETFASTQUEUE(_message) \ + ((_message >> 19) & 0x1FF) + +// Get the len from a message +#define GETFASTLEN(_message) \ + ((_message >> 0) & 0x7FFFF) + +#define MSG_OK 19 + +// Round a number ot the right DMA number --> Is used for DMA transfers +uint32_t roundDMA(uint32_t number); + +#endif // _COMMON_H_ + diff --git a/dol/src/dol/visitor/cell/lib/dol.h b/dol/src/dol/visitor/cell/lib/dol.h new file mode 100644 index 0000000..297f8c5 --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/dol.h @@ -0,0 +1,34 @@ +#ifndef __DOL_H__ +#define __DOL_H__ + +// structure for local memory of process +typedef struct _local_states *LocalState; + +// structure for process +struct _process; + +// standard functions +typedef void (*ProcessInit)(struct _process*); +typedef int (*ProcessFire)(struct _process*); +typedef void *WPTR; + +typedef struct _process { + LocalState local; + ProcessInit init; + ProcessFire fire; + WPTR wptr; +} DOLProcess; + +void DOL_read(void *port, void *buf, int len, DOLProcess *process); +void DOL_write(void *port, void *buf, int len, DOLProcess *process); + +unsigned DOL_reserve(void* port, void** destination, unsigned len, DOLProcess* process); +void DOL_release(void* port, DOLProcess* process); +unsigned DOL_capture(void* port, void** destination, unsigned len, DOLProcess* process); +void DOL_consume(void* port, DOLProcess* process); + +void DOL_detach(DOLProcess *process); +int getIndex(const char* string, char* tokens, int indexNumber); +int *createPort(int *port, int base, int number_of_indices, int index_range_pairs, ...); + +#endif diff --git a/dol/src/dol/visitor/cell/lib/estimation.h b/dol/src/dol/visitor/cell/lib/estimation.h new file mode 100644 index 0000000..eb1570a --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/estimation.h @@ -0,0 +1,50 @@ +/**************************************************************** + * Estimation Defintions + * Creator: lschor, 2008-11-15 + * Description: File with includes for time measurements + * Principle: if 1 then this point will be measured, if 0 then this point will not be measured + * + * Revision: + * - 2008-11-15: Created + */ + +// +#ifndef __ESTIMATION_H__ +#define __ESTIMATION_H__ + +// What to measure? +//#define MEASURE 0 // Measure activeted + +#ifdef MEASURE + //#define MEASURE_DOL_READ 0 // Measure DOL READ + //#define MEASURE_DOL_READ_FINISH 0 // Measure FINISH DOL Read + //#define MEASURE_DOL_READ_START_DMA 0 // Measure Time from start until the DMA process has started + //#define MEASURE_DOL_READ_HANDSHAKE 0 // Measure Time of the whole handshake + //#define MEASURE_DOL_READ_DMA 0 // Measure Time of DMA Setup + //#define MEASURE_DOL_READ_LOCBUF 0 // Measure Time for LocBuf read + //#define MEASURE_DOL_READ_DOUBLEBUF 0 // Measure Time for writing into the buffer + + //#define MEASURE_DOL_WRITE 0 // Measure DOL WRITE + //#define MEASURE_DOL_WRITE_FINISH 0 // Measure FINISH DOL Write + //#define MEASURE_DOL_WRITE_START_DMA 0 // Measure Time from start until the DMA process has started + //#define MEASURE_DOL_WRITE_HANDSHAKE 0 // Measure Time of the whole handshake + //#define MEASURE_DOL_WRITE_DMA 0 // Measure Time of DMA Setup + + //#define MEASURE_DOL_FIRE 0 // Measure DOL FIRE + //#define MEASURE_DOL_INIT 0 // Measure DOL INIT + //#define MEASURE_SPE 0 // Measure whole SPE process + + //#define MEASURE_APPLICATION 0 // Measure whole execution time + //#define MEASURE_SET_UP_SPE_THREAD 0 // Measure time to set up the SPE-threads + //#define MEASURE_SPE_WRITE_DEMAND 0 // Measure time of write demand + //#define MEASURE_SPE_READ_DEMAND 0 // Measure time of read demand + //#define MEASURE_SPE_WRITE_SUC 0 // Measure time of write successful + //#define MEASURE_SPE_READ_SUC 0 // Measure time of read successful + +#endif + +// Some constants +#define MEASURE_START 0xFFFFFFFF // Start decrementer at this value +#define MEASURE_CPU 79800000.0 // Timebase PS3 (in Hz) + +#endif diff --git a/dol/src/dol/visitor/cell/lib/free_align.h b/dol/src/dol/visitor/cell/lib/free_align.h new file mode 100644 index 0000000..5924871 --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/free_align.h @@ -0,0 +1,65 @@ +/* -------------------------------------------------------------- */ +/* (C)Copyright 2001,2006, */ +/* International Business Machines Corporation, */ +/* Sony Computer Entertainment, Incorporated, */ +/* Toshiba Corporation, */ +/* */ +/* All Rights Reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or */ +/* without modification, are permitted provided that the */ +/* following conditions are met: */ +/* */ +/* - Redistributions of source code must retain the above copyright*/ +/* notice, this list of conditions and the following disclaimer. */ +/* */ +/* - Redistributions in binary form must reproduce the above */ +/* copyright notice, this list of conditions and the following */ +/* disclaimer in the documentation and/or other materials */ +/* provided with the distribution. */ +/* */ +/* - Neither the name of IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products */ +/* derived from this software without specific prior written */ +/* permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND */ +/* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, */ +/* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ +/* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ +/* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR */ +/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT */ +/* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */ +/* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) */ +/* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN */ +/* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR */ +/* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */ +/* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* -------------------------------------------------------------- */ +/* PROLOG END TAG zYx */ +#ifndef _FREE_ALIGN_H_ +#define _FREE_ALIGN_H_ 1 + +#include + +/* Function + * + * void free_align(void *ptr) + * + * Description + * The free_align routine frees a memory buffer allocate by the + * malloc_align routine. See malloc_align for complete details. + */ + +static __inline void _free_align(void *ptr) +{ + void * real; + + if (ptr) { + real = *((void **)(ptr)-1); + free(real); + } +} + +#endif /* _FREE_ALIGN_H_ */ diff --git a/dol/src/dol/visitor/cell/lib/malloc_align.h b/dol/src/dol/visitor/cell/lib/malloc_align.h new file mode 100644 index 0000000..0a19068 --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/malloc_align.h @@ -0,0 +1,105 @@ +/* -------------------------------------------------------------- */ +/* (C)Copyright 2001,2007, */ +/* International Business Machines Corporation, */ +/* Sony Computer Entertainment, Incorporated, */ +/* Toshiba Corporation, */ +/* */ +/* All Rights Reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or */ +/* without modification, are permitted provided that the */ +/* following conditions are met: */ +/* */ +/* - Redistributions of source code must retain the above copyright*/ +/* notice, this list of conditions and the following disclaimer. */ +/* */ +/* - Redistributions in binary form must reproduce the above */ +/* copyright notice, this list of conditions and the following */ +/* disclaimer in the documentation and/or other materials */ +/* provided with the distribution. */ +/* */ +/* - Neither the name of IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products */ +/* derived from this software without specific prior written */ +/* permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND */ +/* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, */ +/* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ +/* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ +/* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR */ +/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT */ +/* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */ +/* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) */ +/* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN */ +/* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR */ +/* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */ +/* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* -------------------------------------------------------------- */ +/* PROLOG END TAG zYx */ + +#ifndef _MALLOC_ALIGN_H_ +#define _MALLOC_ALIGN_H_ 1 + +#include + +/* Function + * + * void * malloc_align(size_t size, unsigned int log2_align) + * + * Description + * The malloc_align routine allocates a memory buffer of + * bytes aligned to the power of 2 alignment specified by . + * For example, malloc_align(4096, 7) will allocate a memory heap + * buffer of 4096 bytes aligned on a 128 byte boundary. + * + * The aligned malloc routine allocates an enlarged buffer + * from the standard memory heap. Space for the real allocated memory + * pointer is reserved on the front of the memory buffer. + * + * ----------------- <--- start of allocated memory + * | pad 0 to | + * |(1< (2) + { + // Find out for which fifo the request is + fifoCollection *fifocol = NULL; + int i; + for (i = 0; i < _nrOfQueues; i++) { + if (_fifos[i].queue == queue) { + fifocol = &_fifos[i]; + break; + } + } + + // The queue was not found + if (fifocol == NULL) { + printf("PPU COM> ERROR, this queue does not exists!\n"); + return false; + } + + // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // Windowed FIFO + if (_fifos[i].iswfifo) { + WindowedFifo* wfifo = NULL; + wfifo = _fifos[i].wfifo; + + uint32_t inTail = wfifo->_inTail; + + // This is the len we like to read + len = len > (wfifo->unused()) ? wfifo->unused() : len; + + // We can read something + if (len > 0) { + // Write all information we used to the request-memory + comRequest* request = newRequest(); + + // Has no memory to store a new request + if (request == NULL) { + // not possible to start a request for this SPE --> Send len = 0 + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_COMPLETE, queue, 0); + sendMessage(message, queueFromSPE[queue]); + return false; + } + + uint64_t baseAddress = _fifoTails[queue] + inTail; + while (baseAddress % ALIGNMENT_FACTOR_POWER2 != 0) + baseAddress--; + + // Offset + uint32_t offset = _fifoTails[queue] + inTail + - baseAddress; + + // Store all data in the request buffer + request->data = (char *) _malloc_align(roundDMA(len + + offset), ALIGNMENT_FACTOR); + request->len = len; + request->wfifo = wfifo; + request->iswfifo = true; + request->status = read_started; + request->queue = queue; + request->offset = offset; + + int ret; + do { + ret = spe_mfcio_put( + (spe_context*) _context_all[processNr], + baseAddress, (void *) &(request->data[0]), + roundDMA(len + offset), request->tag_id, + 0, 0); + } while (ret != 0); + } else { +#ifndef STORE_REQUESTS // Send len = 0 back to the sender, this one should try it in a later phase + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_COMPLETE, queue, 0); + sendMessage(message, queueFromSPE[queue]); +#else // I store the request and may try in a later time to start the transfer + comRequest* request = newRequest(); + + // Has no memory to store a new request + if (request == NULL) + { + // not possible to start a request for this SPE --> Send len = 0 + uint32_t message = CREATEFASTMESSAGE(SPE_READ_COMPLETE, queue, 0); + sendMessage(message, queueFromSPE[queue]); + return false; + } + + request->len = len; + request->wfifo = wfifo; + request->iswfifo = true; + request->status = read_pending; + request->queue = queue; +#endif + } + + } + + // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // Classic FIFO + else { + Fifo* fifo = NULL; + fifo = _fifos[i].fifo; + + uint32_t inTail = fifo->_inTail; + + // This is the len we like to read + len = len > (fifo->unused()) ? fifo->unused() : len; + + // We can read something + if (len > 0) { + // Write all information we used to the request-memory + comRequest* request = newRequest(); + + // Has no memory to store a new request + if (request == NULL) { + // not possible to start a request for this SPE --> Send len = 0 + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_COMPLETE, queue, 0); + sendMessage(message, queueFromSPE[queue]); + return false; + } + + uint64_t baseAddress = _fifoTails[queue] + inTail; + while (baseAddress % ALIGNMENT_FACTOR_POWER2 != 0) + baseAddress--; + + // Offset + uint32_t offset = _fifoTails[queue] + inTail + - baseAddress; + + // Store all data in the request buffer + request->data = (char *) _malloc_align(roundDMA(len + + offset), ALIGNMENT_FACTOR); + request->len = len; + request->fifo = fifo; + request->iswfifo = false; + request->status = read_started; + request->queue = queue; + request->offset = offset; + + int ret; + do { + ret = spe_mfcio_put( + (spe_context*) _context_all[processNr], + baseAddress, (void *) &(request->data[0]), + roundDMA(len + offset), request->tag_id, + 0, 0); + } while (ret != 0); + } + + // Len == 0 + else { +#ifndef STORE_REQUESTS // Send len = 0 back to the sender, this one should try it in a later phase + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_COMPLETE, queue, 0); + sendMessage(message, queueFromSPE[queue]); +#else // I store the request and may try in a later time to start the transfer + comRequest* request = newRequest(); + + // Has no memory to store a new request + if (request == NULL) { + // not possible to start a request for this SPE --> Send len = 0 + uint32_t message = CREATEFASTMESSAGE(SPE_READ_COMPLETE, queue, 0); + sendMessage(message, queueFromSPE[queue]); + return false; + } + + request->len = len; + request->fifo = fifo; + request->iswfifo = false; + request->status = read_pending; + request->queue = queue; +#endif + } + } + } + + /***************************************************************************************************************/ + else if (code == SPE_READ_COMPLETE) // Can finish a write request (4) --> (5) + { + // Get the stored request + comRequest* request = getRequest(read_request_sent, queue); + + if (request == NULL) { + printf("PPU Communicate> Couldn't find the request\n"); + return 0; + } + + // Inform my FIFO that the request is completed + if (request->iswfifo) + request->wfifo->dmaRead(len); + else + request->fifo->dmaRead(len); + + // Request free + deleteRequest(request); + } + + /***************************************************************************************************************/ + else if (code == SPE_COMPLETE) // One SPE has finished + { + _nrSpeComplete++; + } + } + + /***************************************************************************************************************/ + // Check if some active write processes have finished (4) + uint8_t req = _currentRequest; + + for (int i = 0; i < _nrOfRequest; i++) { + if (_request[req].valid) { + if (_request[req].status == read_started) { + if (!(testMessage(queueFromSPE[_request[req].queue]) > 0)) + continue; + + uint32_t tag_id = _request[req].tag_id; + uint32_t ret; + uint32_t + test = + spe_mfcio_tag_status_read( + (spe_context*) _context_all[queueFromSPE[_request[req].queue]], + 0, SPE_TAG_IMMEDIATE, &ret); + + if (((ret & (1 << tag_id)) == 0)) { + // Have to write the data into the fifo + if (_request[req].iswfifo) { // WFIFO + + _request[req].wfifo->dmaWrite( + (char *) _request[req].data + + _request[req].offset, + _request[req].len); + _free_align(_request[req].data); + + // Increase the inTail value (used to know where the last request was started) + + _request[req].wfifo->_inTail + = (_request[req].wfifo->_inTail + + _request[req].len) % (FIFO_SIZE[_request[req].queue]); + } else { // FIFO + _request[req].fifo->write( + (char *) _request[req].data + + _request[req].offset, + _request[req].len); + _free_align(_request[req].data); + + _request[req].fifo->_inTail + = (_request[req].fifo->_inTail + + _request[req].len) % (FIFO_SIZE[_request[req].queue]); + + } + + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_COMPLETE, _request[req].queue, + _request[req].len); + sendMessage(message, queueFromSPE[_request[req].queue]); + + deleteRequest(&_request[req]); + _currentRequest = (req + 1) % _nrOfRequest; + + break; + } + } else if (_request[req].status == read_pending) { // Has an open request for sending + + // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // Windowed FIFO + if (_request[req].iswfifo) { + + if (_request[req].wfifo->unused() > 0) { + comRequest *request = &_request[req]; + + // This is the len we like to read + uint32_t len = request->len > (request->wfifo->unused()) ? request->wfifo->unused() + : request->len; + + uint32_t inTail = request->wfifo->_inTail; + uint64_t baseAddress = _fifoTails[request->queue] + + inTail; + + while (baseAddress % ALIGNMENT_FACTOR_POWER2 != 0) + baseAddress--; + + // Offset --> How much we had to align + uint32_t offset = _fifoTails[request->queue] + + inTail - baseAddress; + + request->data = (char *) _malloc_align(roundDMA( + len + offset), ALIGNMENT_FACTOR); + request->len = len; + request->status = read_started; + request->offset = offset; + + // Set up the request in the MFC + int ret; + do { + ret = spe_mfcio_put( + (spe_context*) _context_all[queueFromSPE[_request[req].queue]], + baseAddress, + (void *) &(request->data[0]), + roundDMA(len + offset), + request->tag_id, 0, 0); + } while (ret != 0); + } + } + + // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // Classic FIFO + else { + + if (_request[req].fifo->unused() > 0) { + comRequest *request = &_request[req]; + + // This is the len we like to read + uint32_t len = request->len > (request->fifo->unused()) ? request->fifo->unused() : request->len; + + uint32_t inTail = request->fifo->_inTail; + uint64_t baseAddress = _fifoTails[request->queue] + + inTail; + + while (baseAddress % 16 != 0) + baseAddress--; + + // Offset + uint32_t offset = _fifoTails[request->queue] + + inTail - baseAddress; + + // Store all data in the request buffer + request->data = (char *) _malloc_align(roundDMA( + len + offset), ALIGNMENT_FACTOR); + request->len = len; + request->status = read_started; + request->offset = offset; + + // Start the DMA transfer + int ret; + do { + ret + = spe_mfcio_put( + (spe_context*) _context_all[queueFromSPE[_request[req].queue]], + baseAddress, + (void *) &(request->data[0]), + roundDMA(len + offset), + request->tag_id, 0, 0); + } while (ret != 0); + } + } + } + } + req = (req + 1) % _nrOfRequest; + } + + /***************************************************************************************************************/ + // Have some out - queue some data to send + for (int i = 0; i < _nrOfQueues; i++) { + if (_fifos[i].type == this->out) { + if (_fifos[i].iswfifo) { // WFIFO + // Start only a write process if there is really enough place in the outbound mailbox + if (_fifos[i].wfifo->dmaAllowed() + && _fifos[i].wfifo->used() > 0) { + uint32_t queue = _fifos[i].queue; + + // Can we send a message to this processor or is it blocked? + if (testMessage(queueOnSPE[queue]) <= 0) { + continue; + } + + // Write all information we used to the request-memory + comRequest* request = newRequest(); + + // Has no memory to store a new request + if (request == NULL) { + } else { + uint32_t len = _fifos[i].wfifo->dmaStart(); + // Create a write-demand message + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_DEMAND, queue, len); + + request->len = len; + request->queue = queue; + request->status = read_request_sent; + request->wfifo = _fifos[i].wfifo; + request->iswfifo = true; + + sendMessage(message, queueOnSPE[queue]); + } + break; + } + } else { // FIFO + // Start only a write process if there is really enough place in the outbound mailbox + if (_fifos[i].fifo->dmaAllowed() && _fifos[i].fifo->used() + > 0) { + uint32_t queue = _fifos[i].queue; + + if (testMessage(queueOnSPE[queue]) <= 0) + continue; + + // Write all information we used to the request-memory + comRequest* request = newRequest(); + + // Has no memory to store a new request + if (request == NULL) { + } else { + uint32_t len = _fifos[i].fifo->dmaStart(); + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_DEMAND, queue, len); + request->len = len; + request->queue = queue; + request->status = read_request_sent; + request->fifo = _fifos[i].fifo; + request->iswfifo = false; + + sendMessage(message, queueOnSPE[queue]); + } + break; + } + } + } + } + return true; +} + +/* + * Create a new request to store in the cache + * + */ +comRequest* FastCommunication::newRequest() { + for (int i = 0; i < _nrOfRequest; i++) { + if (!_request[i].valid) { + _request[i].tag_id = i + 3; + _request[i].valid = true; + return &(_request[i]); + } + } + + return NULL; +} + +/* + * Delete the request + * + */ +void FastCommunication::deleteRequest(comRequest* request) { + request->valid = false; + request->tag_id = 0; +} + +/* + * Returns the request one like to get + */ +comRequest* FastCommunication::getRequest(uint8_t status, uint32_t queue) { + uint8_t req = _currentRequest; + + for (int i = 0; i < _nrOfRequest; i++) { + if (_request[req].valid && _request[req].status == status + && _request[req].queue == queue) { + _currentRequest = (req + 1) % _nrOfRequest; + return &(_request[req]); + } + req = (req + 1) % _nrOfRequest; + } + + return NULL; +} + +/** + * True if no communication is necessary, false if there is active communication + */ +bool FastCommunication::empty() { ///////////////////////////////////////////////////////////////// + // check if one fifo would like to send something to another SPE + for (int i = 0; i < _nrOfQueues; i++) { + if (_fifos[i].type == this->out) { + if (_fifos[i].iswfifo) { // WFIFO + if (_fifos[i].wfifo->used() > 0) + { + return false; + } + } else { + if (_fifos[i].fifo->used() > 0) + { + return false; + } + } + } + } + + // are open sendings? + for (int i = 0; i < _nrOfRequest; i++) { + if (_request[i].valid) { + return false; + } + } + + if (_nrSpeComplete < NUM_SPES) { + return false; + } + + return true; +} + +/** + * Send a message to a SPE + */ +void FastCommunication::sendMessage(uint32_t message, int32_t process) { + spe_in_mbox_write((spe_context*) _context_all[process], + (uint32_t*) &message, 1, SPE_MBOX_ANY_NONBLOCKING); +} + +/** + * Test if we can send a message to an SPE without stalling + */ +int FastCommunication::testMessage(int32_t process) { + return spe_in_mbox_status((spe_context*) _context_all[process]); +} + diff --git a/dol/src/dol/visitor/cell/lib/ppu/FastCommunication.h b/dol/src/dol/visitor/cell/lib/ppu/FastCommunication.h new file mode 100644 index 0000000..8ba7731 --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/ppu/FastCommunication.h @@ -0,0 +1,118 @@ +/* + * Communication.h + * + * Created on: Mar 3, 2009 + * Author: lschor + */ + +#ifndef FASTCOMMUNICATION_H_ +#define FASTCOMMUNICATION_H_ + +// System includes +#include "cbe_mfc.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Local includes +#include "lib/ppu/common_ppu.h" +#include "Fifo.h" +#include "WindowedFifo.h" +#include "../common.h" + + +// Include to allocate/free using for DMA transfers +#include "../lib/malloc_align.h" +#include "../lib/free_align.h" + +//Cell Macros +#define waittag(tag_id) mfc_write_tag_mask(1< _size) { + return _size - _tail; + } else { + return _pos; + } +} + +/* + * Is allowed to start a dma request + */ +bool Fifo::dmaAllowed() { + if (_blocked > 0) { + _blocked--; + return false; + } else { + return !_activeDMA; + } +} diff --git a/dol/src/dol/visitor/cell/lib/ppu/Fifo.h b/dol/src/dol/visitor/cell/lib/ppu/Fifo.h new file mode 100644 index 0000000..8a06087 --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/ppu/Fifo.h @@ -0,0 +1,45 @@ +#ifndef _FIFO_H_ +#define _FIFO_H_ + +#include +#include + +#include "../constant.h" + +#include "../lib/malloc_align.h" +#include "../lib/free_align.h" + +/** + * FIFO Class: For remarks see SPE + */ +class Fifo { + public: + Fifo(unsigned size); + virtual ~Fifo(); + + virtual unsigned read(void *destination, unsigned len); + virtual unsigned write(const void *source, unsigned len); + + virtual unsigned used() const; + virtual unsigned unused() const; + virtual unsigned size() const; + + virtual char *getQueuePointer(); + virtual void dmaRead(unsigned len); + virtual unsigned dmaStart(); + virtual bool dmaAllowed(); + + unsigned _inTail; + + protected: + char *_buffer; + + unsigned _tail; + unsigned _pos; + unsigned _size; + + unsigned _blocked; + bool _activeDMA; +}; + +#endif diff --git a/dol/src/dol/visitor/cell/lib/ppu/ProcessWrapper.cpp b/dol/src/dol/visitor/cell/lib/ppu/ProcessWrapper.cpp new file mode 100644 index 0000000..fcd5f0e --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/ppu/ProcessWrapper.cpp @@ -0,0 +1,66 @@ +#include "ProcessWrapper.h" + +/** + * + */ +ProcessWrapper::ProcessWrapper(char* name, int iteratorIndex[4]) { + //copy name, deliberately avoid using strlen and strcpy for code size + //minimization + int nameLength = 0; + while (name[nameLength] != 0) { + nameLength++; + } + _name = new char[nameLength + 1]; + for (int i = 0; i < nameLength; i++) { + _name[i] = name[i]; + } + + _isDetached = false; + for (int i = 0; i < 4; i++) { + _iteratorIndex[i] = iteratorIndex[i]; + } + + readPos = 0; + writePos = 0; +} + +/** + * + */ +ProcessWrapper::~ProcessWrapper() { + if (_name) { + delete _name; + } +} + +/** + * + */ +void ProcessWrapper::init() { + _process.init(&_process); +} + +/** + * + */ +int ProcessWrapper::fire() { + return _process.fire(&_process); +} + +/** + * + */ +void ProcessWrapper::detach() { + _isDetached = true; +} + +/** + * Get the index of this process. + * @param indexNumber position of index (starting at 0) + */ +int ProcessWrapper::getIndex(unsigned indexNumber) const { + if (indexNumber < 4) { + return _iteratorIndex[indexNumber]; + } + return -1; +} diff --git a/dol/src/dol/visitor/cell/lib/ppu/ProcessWrapper.h b/dol/src/dol/visitor/cell/lib/ppu/ProcessWrapper.h new file mode 100644 index 0000000..0754af4 --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/ppu/ProcessWrapper.h @@ -0,0 +1,32 @@ +#ifndef _PROCESSWRAPPER_H_ +#define _PROCESSWRAPPER_H_ + +#include + +/** + * Process Wrapper Class + */ +class ProcessWrapper +{ + public: + ProcessWrapper(char* name, int iteratorIndex[4]); + virtual ~ProcessWrapper(); + + virtual void init(); + virtual int fire(); + virtual bool isDetached() { return _isDetached; } + virtual void detach(); + virtual int getIndex(unsigned indexNumber) const; + + // Positions for read and write operations which are blocked by Protothread + unsigned int readPos; + unsigned int writePos; + + protected: + char* _name;; + DOLProcess _process; + bool _isDetached; + int _iteratorIndex[4]; +}; + +#endif diff --git a/dol/src/dol/visitor/cell/lib/ppu/WindowedFifo.cpp b/dol/src/dol/visitor/cell/lib/ppu/WindowedFifo.cpp new file mode 100644 index 0000000..16e09ba --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/ppu/WindowedFifo.cpp @@ -0,0 +1,223 @@ +#include "WindowedFifo.h" + +/** + * + */ +WindowedFifo::WindowedFifo(unsigned size = 20) { + //std::cout << "Create WindowedFifo." << std::endl; + _size = size; + _buffer = (char *) _malloc_align(_size, ALIGNMENT_FACTOR); + if(!_buffer) { + fprintf(stderr,"[WFIFO] Memory allocation failure\n"); + exit(-1); + } + + _head = 0; + _tail = 0; + + _headRoom = 0; + _tailRoom = 0; + _use = 0; + _blocked = 0; + + _isHeadReserved = false; + _isTailReserved = false; + _activeDMA = false; +} + +/** + * + */ +WindowedFifo::~WindowedFifo() { + if (_buffer) { + _free_align(_buffer); + } + _buffer = 0; + _head = 0; + _tail = 0; + _use = 0; +} + +/** + * + */ +unsigned WindowedFifo::reserve(void** dest, unsigned len) { + char** destination = (char**) dest; + //std::cout << "Attempt to reserve " << len << " bytes." << std::endl; + + //can only reserve one piece at a time + if (_isHeadReserved) { + *destination = 0; + return 0; + } + + //reserve at most as much memory as still available in the buffer + unsigned write = (len <= _size - _use ? len : _size - _use); + + if (write > 0) { + //if wrap-around in buffer: return only buffer for the + //contiguous buffer space + if (_head + write > _size) { + write = _size - _head; + } + + _headRoom = (_head + write) == _size ? 0 : _head + write; + *destination = &(_buffer[_head]); + _isHeadReserved = true; + } + + //std::cout << "Reserved " << write << " bytes." << std::endl; + _writeReserve = write; + return write; +} + +/** + * + */ +void WindowedFifo::release() { + if (_isHeadReserved) { + //std::cout << "Released " << _headRoom - _head << " bytes." << std::endl; + _head = _headRoom; + _use += _writeReserve; + _isHeadReserved = false; + } +} + +/** + * + */ +unsigned WindowedFifo::capture(void **dest, unsigned len) { + char** destination = (char**) dest; + //std::cout << "Attempt to capture " << len << " bytes." << std::endl; + + if (_isTailReserved) { + //std::cout << "Only one attempt to capture allowed." << std::endl; + *destination = 0; + return 0; + } + + //capture at most as much data as available in the buffer + unsigned read = (len <= _use ? len : _use); + + if (read > 0) { + //if wrap-around in buffer: return only buffer for the + //conntiguous buffer space + if (_tail + read > _size) { + read = _size - _tail; + } + + _tailRoom = (_tail + read) == _size ? 0 : _tailRoom = _tail + read; + *destination = &(_buffer[_tail]); + _isTailReserved = true; + } + + //std::cout << "Captured " << read << " bytes." << std::endl; + _readReserve = read; + return read; +} + +/** + * + */ +void WindowedFifo::consume() { + if (_isTailReserved) { + //std::cout << "Consumed " << _tailRoom - _tail << " bytes." << std::endl; + _tail = _tailRoom; + _use -= _readReserve; + _isTailReserved = false; + } +} + +/** + * + */ +unsigned WindowedFifo::size() const { + return _size; +} + +/** + * + */ +unsigned WindowedFifo::unused() const { + return _size - _use; +} + +/** + * + */ +unsigned WindowedFifo::used() const { + return _use; +} + +/* + * Get the pointer to the start of the queue + */ +char *WindowedFifo::getQueuePointer() { + return _buffer; +} + +/* + * Has completed a dma read process, i.e. has read out of the queue + */ +void WindowedFifo::dmaRead(unsigned len) { + _activeDMA = false; + + if (len == 0) { + _blocked = BLOCKED_MAX_NR; + } else { + _tail = ((unsigned) (_tail + len) % _size); + _use -= len; + } +} + +/* + * Start a DMA request, returns the current space one have + */ +unsigned WindowedFifo::dmaStart() { + _activeDMA = true; + + // If we go over the end, we only take as much as is on one side! + //return used(); + + if (_tail + _use > _size) { + return _size - _tail; + } else { + return _use; + } +} + +/* + * Is allowed to start a dma request + */ +bool WindowedFifo::dmaAllowed() { +#ifndef STORE_REQUESTS + if (_blocked > 0) { + _blocked--; + return false; + } else { + return !_activeDMA; + } +#else + return !_activeDMA; +#endif +} + +/** + * Is needed for DMA transfers + */ +unsigned WindowedFifo::dmaWrite(const void *source, unsigned len) { + + char* buffer = (char*) source; + + if (_head + len < _size) { + memcpy(_buffer + _head, buffer, len); + } else { + // We should never be here! + memcpy(_buffer + _head, buffer, _size - _head); + memcpy(_buffer, buffer + _size - _head, len - _size + _head); + } + _use += len; + _head = (_head + len) >= _size ? _head + len - _size : _head + len; + + return len; +} diff --git a/dol/src/dol/visitor/cell/lib/ppu/WindowedFifo.h b/dol/src/dol/visitor/cell/lib/ppu/WindowedFifo.h new file mode 100644 index 0000000..2e94c46 --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/ppu/WindowedFifo.h @@ -0,0 +1,61 @@ +#ifndef _WINDOWEDFIFO_H_ +#define _WINDOWEDFIFO_H_ + +#include +#include + +#include "../constant.h" + +#include "../lib/malloc_align.h" +#include "../lib/free_align.h" + +class WindowedFifo { + public: + WindowedFifo(unsigned size); + virtual ~WindowedFifo(); + + // Write + virtual unsigned reserve(void** destination, unsigned len); + virtual void release(); + + // Read + virtual unsigned capture(void** destination, unsigned len); + virtual void consume(); + + // General FIFO functions + virtual unsigned used() const; + virtual unsigned unused() const; + virtual unsigned size() const; + + // DMA functions + virtual char *getQueuePointer(); + virtual void dmaRead(unsigned len); + virtual unsigned dmaStart(); + virtual bool dmaAllowed(); + virtual unsigned dmaWrite(const void *source, unsigned len); + + // Global variables + unsigned _inTail; + protected: + char *_buffer; + + unsigned _head; + unsigned _tail; + unsigned _headRoom; + unsigned _tailRoom; + + unsigned _size; + unsigned _use; + + unsigned _writeReserve; + unsigned _readReserve; + + bool _isHeadReserved; + bool _isTailReserved; + + unsigned _blocked; // Blocked number the request has to wait + bool _activeDMA; // Is there an active DMA on this buffer + +}; + +#endif diff --git a/dol/src/dol/visitor/cell/lib/ppu/common.cpp b/dol/src/dol/visitor/cell/lib/ppu/common.cpp new file mode 100644 index 0000000..bdaf7c8 --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/ppu/common.cpp @@ -0,0 +1,28 @@ +/* + * common.cpp + * + * Created on: Feb 27, 2009 + * Author: lschor + */ + +#include "../common.h" + +/** + * Aligend a number to to the data bus + */ +uint32_t roundDMA(uint32_t number) +{ + if (number > 16) + if (number % 16 == 0) return number; + else return number + 16 - (number % 16); + else if (number > 8) + return 16; + else if (number > 4) + return 8; + else if (number > 2) + return 4; + else if (number > 1) + return 2; + else + return 1; +} diff --git a/dol/src/dol/visitor/cell/lib/ppu/common_ppu.h b/dol/src/dol/visitor/cell/lib/ppu/common_ppu.h new file mode 100644 index 0000000..09a8d78 --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/ppu/common_ppu.h @@ -0,0 +1,32 @@ +/**************************************************************** + * Common structs for the PPU + * Creator: lschor, 2008-11-21 + * Description: Common structs for the PPU + * + * Revision: + * - 2008-11-21: Created + */ + +#ifndef __COMMON_PPU_H__ +#define __COMMON_PPU_H__ + +#include + +// data structure for running SPE thread +typedef struct spu_data { + spe_context_ptr_t spe_ctx; + pthread_t pthread; + void *argp; +} spu_data_t; + +// Struct for a process +typedef struct _process_data { + uint64_t *procContentsAll; + int32_t *queueFromSPU; + int32_t *queueOnSPU; + uint64_t *ea_ls_base; + uint64_t *fifoTails; +} ProcessData; + + +#endif diff --git a/dol/src/dol/visitor/cell/lib/ppu/dolSupport.cpp b/dol/src/dol/visitor/cell/lib/ppu/dolSupport.cpp new file mode 100644 index 0000000..3c6d36d --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/ppu/dolSupport.cpp @@ -0,0 +1,98 @@ +#include "dolSupport.h" + +/** + * + */ +unsigned read(void* fifo, void* buf, unsigned len, DOLProcess* p) { + unsigned int + pos = + static_cast ((static_cast (p->wptr))->wrapper)->readPos; + pos += ((Fifo*) fifo)->read((char *) buf + pos, len - pos); + + if (pos == len) + static_cast ((static_cast (p->wptr))->wrapper)->readPos + = 0; + else + static_cast ((static_cast (p->wptr))->wrapper)->readPos + = pos; + return pos; +} + +/** + * + */ +unsigned write(void* fifo, void* buf, unsigned len, DOLProcess* p) { + unsigned int + pos = + static_cast ((static_cast (p->wptr))->wrapper)->writePos; + pos += ((Fifo*) fifo)->write((char *) buf + pos, len - pos); + + if (pos == len) + static_cast ((static_cast (p->wptr))->wrapper)->writePos + = 0; + else + static_cast ((static_cast (p->wptr))->wrapper)->writePos + = pos; + return pos; +} + +/** + * + */ +unsigned reserve(void* fifo, void** destination, unsigned len, + DOLProcess* p) { + return ((WindowedFifo*) fifo)->reserve(destination, len); +} + +/** + * + */ +void release(void* fifo, DOLProcess* p) { + ((WindowedFifo*) fifo)->release(); +} + +/** + * + */ +unsigned capture(void* fifo, void** destination, unsigned len, + DOLProcess* p) { + return ((WindowedFifo*) fifo)->capture(destination, len); +} + +/** + * + */ +void consume(void* fifo, DOLProcess* p) { + ((WindowedFifo*) fifo)->consume(); +} + +/** + * + */ +void DOL_detach(DOLProcess* p) { + static_cast ((static_cast (p->wptr))->wrapper)->detach(); +} + +void createPort(void** port, void* base, int number_of_indices, + int index0, int range0) { + *port = (void**) ((void**) base)[index0]; +} + +void createPort(void** port, void* base, int number_of_indices, + int index0, int range0, int index1, int range1) { + *port = (void**) ((void**) base)[index0 * range1 + index1]; +} + +void createPort(void** port, void* base, int number_of_indices, + int index0, int range0, int index1, int range1, int index2, + int range2) { + *port = (void**) ((void**) base)[index0 * range1 * range2 + index1 + * range2 + index2]; +} + +void createPort(void** port, void* base, int number_of_indices, + int index0, int range0, int index1, int range1, int index2, + int range2, int index3, int range3) { + *port = (void**) ((void**) base)[index0 * range1 * range2 * range3 + + index1 * range2 * range3 + index2 * range3 + index3]; +} diff --git a/dol/src/dol/visitor/cell/lib/ppu/dolSupport.h b/dol/src/dol/visitor/cell/lib/ppu/dolSupport.h new file mode 100644 index 0000000..14a1c55 --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/ppu/dolSupport.h @@ -0,0 +1,78 @@ +#ifndef DOLSUPPORT_H +#define DOLSUPPORT_H + +#include "dol.h" +#include "pt.h" + +#include "ProcessWrapper.h" + +#include "Fifo.h" +#include "WindowedFifo.h" + +typedef struct _process_data { + int lc; + ProcessWrapper *wrapper; +} process_data; + + +#define DOL_read(port, buf, size, process) \ + PT_WAIT_UNTIL((pt*)(p->wptr), read(port, buf, size, process) == size); + +#define DOL_write(port, buf, size, process) \ + PT_WAIT_UNTIL((pt*)(p->wptr), write(port, buf, size, process) == size); + +#define DOL_reserve(port, buf, size, process) \ + PT_WAIT_UNTIL((pt*)(p->wptr), reserve(port, (void**)buf, size, process) == size); + +#define DOL_release(port, process) \ + release(port, process); + +#define DOL_capture(port, buf, size, process) \ + PT_WAIT_UNTIL((pt*)(p->wptr), capture(port, (void**)buf, size, process) == size); + +#define DOL_consume(port, process) \ + consume(port, process); + +void DOL_detach(DOLProcess* p); + +//macros to deal with iterated ports +/** + * macro to create a variable to store a port name + * + * @param name name of the variable + */ +#define CREATEPORTVAR(name) static Fifo *name + +/** + * Create the port name of an iterated port based on its basename and the + * given indices. + * + * @param port buffer where the result is stored (created using + * CREATEPORTVAR) + * @param base basename of the port + * @param number_of_indices number of dimensions of the port + * @param index_range_pairs index and range values for each dimension + */ + +#define CREATEPORT(port, base, number_of_indices, index_range_pairs...) \ + createPort((void**)(&port), base, number_of_indices, index_range_pairs) + +#define GETINDEX(dimension) \ + static_cast((static_cast(p->wptr))->wrapper)->getIndex(dimension) + +void createPort(void** port, void* base, int number_of_indices, int index0, int range0); +void createPort(void** port, void* base, int number_of_indices, int index0, int range0, int index1, int range1); +void createPort(void** port, void* base, int number_of_indices, int index0, int range0, int index1, int range1, int index2, int range2); +void createPort(void** port, void* base, int number_of_indices, int index0, int range0, int index1, int range1, int index2, int range2, int index3, int range3); + +//fifo access functions +unsigned write(void* fifo, void* buf, unsigned len, DOLProcess* p); +unsigned read(void* fifo, void* buf, unsigned len, DOLProcess* p); + +//windowed fifo access functions +unsigned reserve(void* fifo, void** destination, unsigned len, DOLProcess* p); +void release(void* fifo, DOLProcess* p); +unsigned capture(void* fifo, void** destination, unsigned len, DOLProcess* p); +void consume(void* fifo, DOLProcess* p); + +#endif diff --git a/dol/src/dol/visitor/cell/lib/ppu_main.h b/dol/src/dol/visitor/cell/lib/ppu_main.h new file mode 100644 index 0000000..3b80e8a --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/ppu_main.h @@ -0,0 +1,43 @@ +/**************************************************************** + * Header for the main function + * Creator: lschor, 2008-11-21 + * Description: Header file for the main function of the PPU + * + * Revision: + * - 2008-11-21: Created + */ + +#ifndef __PPU_MAIN_H__ +#define __PPU_MAIN_H__ + +// System includes +#include +#include +#include +#include +#include +#include +#include +#include + +// Local includes +#include "lib/malloc_align.h" +#include "lib/free_align.h" +#include "lib/common.h" +#include "lib/estimation.h" +#include "lib/ppu/common_ppu.h" +#include "cbe_mfc.h" + +// Program context for the Processes +volatile process_context ctx_proc[NUM_PROCS_SPU] __attribute__ ((aligned(16))); + +// Program context for the SPEs +volatile spu_context ctx_spu[NUM_SPES] __attribute__ ((aligned(16))); + +// The SPE-program-handler +spe_program_handle_t *program[NUM_SPES]; + +// Data for the SPEs +spu_data_t data[NUM_SPES]; + +#endif diff --git a/dol/src/dol/visitor/cell/lib/pt/lc-addrlabels.h b/dol/src/dol/visitor/cell/lib/pt/lc-addrlabels.h new file mode 100644 index 0000000..b75f4e7 --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/pt/lc-addrlabels.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2004-2005, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * Author: Adam Dunkels + * + * $Id: lc-addrlabels.h 1 2010-02-24 13:03:05Z haidw $ + */ + +/** + * \addtogroup lc + * @{ + */ + +/** + * \file + * Implementation of local continuations based on the "Labels as + * values" feature of gcc + * \author + * Adam Dunkels + * + * This implementation of local continuations is based on a special + * feature of the GCC C compiler called "labels as values". This + * feature allows assigning pointers with the address of the code + * corresponding to a particular C label. + * + * For more information, see the GCC documentation: + * http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html + * + */ + +#ifndef __LC_ADDRLABELS_H__ +#define __LC_ADDRLABELS_H__ + +/** \hideinitializer */ +typedef void * lc_t; + +#define LC_INIT(s) s = NULL + +#define LC_RESUME(s) \ + do { \ + if(s != NULL) { \ + goto *s; \ + } \ + } while(0) + +#define LC_CONCAT2(s1, s2) s1##s2 +#define LC_CONCAT(s1, s2) LC_CONCAT2(s1, s2) + +#define LC_SET(s) \ + do { \ + LC_CONCAT(LC_LABEL, __LINE__): \ + (s) = &&LC_CONCAT(LC_LABEL, __LINE__); \ + } while(0) + +#define LC_END(s) + +#endif /* __LC_ADDRLABELS_H__ */ +/** @} */ diff --git a/dol/src/dol/visitor/cell/lib/pt/lc-switch.h b/dol/src/dol/visitor/cell/lib/pt/lc-switch.h new file mode 100644 index 0000000..e47085c --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/pt/lc-switch.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2004-2005, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * Author: Adam Dunkels + * + * $Id: lc-switch.h 1 2010-02-24 13:03:05Z haidw $ + */ + +/** + * \addtogroup lc + * @{ + */ + +/** + * \file + * Implementation of local continuations based on switch() statment + * \author Adam Dunkels + * + * This implementation of local continuations uses the C switch() + * statement to resume execution of a function somewhere inside the + * function's body. The implementation is based on the fact that + * switch() statements are able to jump directly into the bodies of + * control structures such as if() or while() statmenets. + * + * This implementation borrows heavily from Simon Tatham's coroutines + * implementation in C: + * http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html + */ + +#ifndef __LC_SWITCH_H__ +#define __LC_SWITCH_H__ + +/* WARNING! lc implementation using switch() does not work if an + LC_SET() is done within another switch() statement! */ + +/** \hideinitializer */ +typedef unsigned short lc_t; + +#define LC_INIT(s) s = 0; + +#define LC_RESUME(s) switch(s) { case 0: + +#define LC_SET(s) s = __LINE__; case __LINE__: + +#define LC_END(s) } + +#endif /* __LC_SWITCH_H__ */ + +/** @} */ diff --git a/dol/src/dol/visitor/cell/lib/pt/lc.h b/dol/src/dol/visitor/cell/lib/pt/lc.h new file mode 100644 index 0000000..9ef2f0f --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/pt/lc.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2004-2005, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the protothreads library. + * + * Author: Adam Dunkels + * + * $Id: lc.h 1 2010-02-24 13:03:05Z haidw $ + */ + +/** + * \addtogroup pt + * @{ + */ + +/** + * \defgroup lc Local continuations + * @{ + * + * Local continuations form the basis for implementing protothreads. A + * local continuation can be set in a specific function to + * capture the state of the function. After a local continuation has + * been set can be resumed in order to restore the state of the + * function at the point where the local continuation was set. + * + * + */ + +/** + * \file lc.h + * Local continuations + * \author + * Adam Dunkels + * + */ + +#ifdef DOXYGEN +/** + * Initialize a local continuation. + * + * This operation initializes the local continuation, thereby + * unsetting any previously set continuation state. + * + * \hideinitializer + */ +#define LC_INIT(lc) + +/** + * Set a local continuation. + * + * The set operation saves the state of the function at the point + * where the operation is executed. As far as the set operation is + * concerned, the state of the function does not include the + * call-stack or local (automatic) variables, but only the program + * counter and such CPU registers that needs to be saved. + * + * \hideinitializer + */ +#define LC_SET(lc) + +/** + * Resume a local continuation. + * + * The resume operation resumes a previously set local continuation, thus + * restoring the state in which the function was when the local + * continuation was set. If the local continuation has not been + * previously set, the resume operation does nothing. + * + * \hideinitializer + */ +#define LC_RESUME(lc) + +/** + * Mark the end of local continuation usage. + * + * The end operation signifies that local continuations should not be + * used any more in the function. This operation is not needed for + * most implementations of local continuation, but is required by a + * few implementations. + * + * \hideinitializer + */ +#define LC_END(lc) + +/** + * \var typedef lc_t; + * + * The local continuation type. + * + * \hideinitializer + */ +#endif /* DOXYGEN */ + +#ifndef __LC_H__ +#define __LC_H__ + + +#ifdef LC_INCLUDE +#include LC_INCLUDE +#else +#include "lc-switch.h" +#endif /* LC_INCLUDE */ + +#endif /* __LC_H__ */ + +/** @} */ +/** @} */ diff --git a/dol/src/dol/visitor/cell/lib/pt/pt-sem.h b/dol/src/dol/visitor/cell/lib/pt/pt-sem.h new file mode 100644 index 0000000..a6e1428 --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/pt/pt-sem.h @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the protothreads library. + * + * Author: Adam Dunkels + * + * $Id: pt-sem.h 1 2010-02-24 13:03:05Z haidw $ + */ + +/** + * \addtogroup pt + * @{ + */ + +/** + * \defgroup ptsem Protothread semaphores + * @{ + * + * This module implements counting semaphores on top of + * protothreads. Semaphores are a synchronization primitive that + * provide two operations: "wait" and "signal". The "wait" operation + * checks the semaphore counter and blocks the thread if the counter + * is zero. The "signal" operation increases the semaphore counter but + * does not block. If another thread has blocked waiting for the + * semaphore that is signalled, the blocked thread will become + * runnable again. + * + * Semaphores can be used to implement other, more structured, + * synchronization primitives such as monitors and message + * queues/bounded buffers (see below). + * + * The following example shows how the producer-consumer problem, also + * known as the bounded buffer problem, can be solved using + * protothreads and semaphores. Notes on the program follow after the + * example. + * + \code +#include "pt-sem.h" + +#define NUM_ITEMS 32 +#define BUFSIZE 8 + +static struct pt_sem mutex, full, empty; + +PT_THREAD(producer(struct pt *pt)) +{ + static int produced; + + PT_BEGIN(pt); + + for(produced = 0; produced < NUM_ITEMS; ++produced) { + + PT_SEM_WAIT(pt, &full); + + PT_SEM_WAIT(pt, &mutex); + add_to_buffer(produce_item()); + PT_SEM_SIGNAL(pt, &mutex); + + PT_SEM_SIGNAL(pt, &empty); + } + + PT_END(pt); +} + +PT_THREAD(consumer(struct pt *pt)) +{ + static int consumed; + + PT_BEGIN(pt); + + for(consumed = 0; consumed < NUM_ITEMS; ++consumed) { + + PT_SEM_WAIT(pt, &empty); + + PT_SEM_WAIT(pt, &mutex); + consume_item(get_from_buffer()); + PT_SEM_SIGNAL(pt, &mutex); + + PT_SEM_SIGNAL(pt, &full); + } + + PT_END(pt); +} + +PT_THREAD(driver_thread(struct pt *pt)) +{ + static struct pt pt_producer, pt_consumer; + + PT_BEGIN(pt); + + PT_SEM_INIT(&empty, 0); + PT_SEM_INIT(&full, BUFSIZE); + PT_SEM_INIT(&mutex, 1); + + PT_INIT(&pt_producer); + PT_INIT(&pt_consumer); + + PT_WAIT_THREAD(pt, producer(&pt_producer) & + consumer(&pt_consumer)); + + PT_END(pt); +} + \endcode + * + * The program uses three protothreads: one protothread that + * implements the consumer, one thread that implements the producer, + * and one protothread that drives the two other protothreads. The + * program uses three semaphores: "full", "empty" and "mutex". The + * "mutex" semaphore is used to provide mutual exclusion for the + * buffer, the "empty" semaphore is used to block the consumer is the + * buffer is empty, and the "full" semaphore is used to block the + * producer is the buffer is full. + * + * The "driver_thread" holds two protothread state variables, + * "pt_producer" and "pt_consumer". It is important to note that both + * these variables are declared as static. If the static + * keyword is not used, both variables are stored on the stack. Since + * protothreads do not store the stack, these variables may be + * overwritten during a protothread wait operation. Similarly, both + * the "consumer" and "producer" protothreads declare their local + * variables as static, to avoid them being stored on the stack. + * + * + */ + +/** + * \file + * Couting semaphores implemented on protothreads + * \author + * Adam Dunkels + * + */ + +#ifndef __PT_SEM_H__ +#define __PT_SEM_H__ + +#include "pt.h" + +struct pt_sem { + unsigned int count; +}; + +/** + * Initialize a semaphore + * + * This macro initializes a semaphore with a value for the + * counter. Internally, the semaphores use an "unsigned int" to + * represent the counter, and therefore the "count" argument should be + * within range of an unsigned int. + * + * \param s (struct pt_sem *) A pointer to the pt_sem struct + * representing the semaphore + * + * \param c (unsigned int) The initial count of the semaphore. + * \hideinitializer + */ +#define PT_SEM_INIT(s, c) (s)->count = c + +/** + * Wait for a semaphore + * + * This macro carries out the "wait" operation on the semaphore. The + * wait operation causes the protothread to block while the counter is + * zero. When the counter reaches a value larger than zero, the + * protothread will continue. + * + * \param pt (struct pt *) A pointer to the protothread (struct pt) in + * which the operation is executed. + * + * \param s (struct pt_sem *) A pointer to the pt_sem struct + * representing the semaphore + * + * \hideinitializer + */ +#define PT_SEM_WAIT(pt, s) \ + do { \ + PT_WAIT_UNTIL(pt, (s)->count > 0); \ + --(s)->count; \ + } while(0) + +/** + * Signal a semaphore + * + * This macro carries out the "signal" operation on the semaphore. The + * signal operation increments the counter inside the semaphore, which + * eventually will cause waiting protothreads to continue executing. + * + * \param pt (struct pt *) A pointer to the protothread (struct pt) in + * which the operation is executed. + * + * \param s (struct pt_sem *) A pointer to the pt_sem struct + * representing the semaphore + * + * \hideinitializer + */ +#define PT_SEM_SIGNAL(pt, s) ++(s)->count + +#endif /* __PT_SEM_H__ */ + +/** @} */ +/** @} */ + diff --git a/dol/src/dol/visitor/cell/lib/pt/pt.h b/dol/src/dol/visitor/cell/lib/pt/pt.h new file mode 100644 index 0000000..a834a13 --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/pt/pt.h @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2004-2005, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * Author: Adam Dunkels + * + * $Id: pt.h 1 2010-02-24 13:03:05Z haidw $ + */ + +/** + * \addtogroup pt + * @{ + */ + +/** + * \file + * Protothreads implementation. + * \author + * Adam Dunkels + * + */ + +#ifndef __PT_H__ +#define __PT_H__ + +#include "lc.h" + +typedef struct _pt { + lc_t lc; +} pt; + +#define PT_WAITING 0 +#define PT_YIELDED 1 +#define PT_EXITED 2 +#define PT_ENDED 3 + +/** + * \name Initialization + * @{ + */ + +/** + * Initialize a protothread. + * + * Initializes a protothread. Initialization must be done prior to + * starting to execute the protothread. + * + * \param pt A pointer to the protothread control structure. + * + * \sa PT_SPAWN() + * + * \hideinitializer + */ +#define PT_INIT(pt) LC_INIT((pt)->lc) + +/** @} */ + +/** + * \name Declaration and definition + * @{ + */ + +/** + * Declaration of a protothread. + * + * This macro is used to declare a protothread. All protothreads must + * be declared with this macro. + * + * \param name_args The name and arguments of the C function + * implementing the protothread. + * + * \hideinitializer + */ +#define PT_THREAD(name_args) char name_args + +/** + * Declare the start of a protothread inside the C function + * implementing the protothread. + * + * This macro is used to declare the starting point of a + * protothread. It should be placed at the start of the function in + * which the protothread runs. All C statements above the PT_BEGIN() + * invokation will be executed each time the protothread is scheduled. + * + * \param pt A pointer to the protothread control structure. + * + * \hideinitializer + */ +#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; LC_RESUME((pt)->lc) + +/** + * Declare the end of a protothread. + * + * This macro is used for declaring that a protothread ends. It must + * always be used together with a matching PT_BEGIN() macro. + * + * \param pt A pointer to the protothread control structure. + * + * \hideinitializer + */ +#define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \ + PT_INIT(pt); return PT_ENDED; } + +/** @} */ + +/** + * \name Blocked wait + * @{ + */ + +/** + * Block and wait until condition is true. + * + * This macro blocks the protothread until the specified condition is + * true. + * + * \param pt A pointer to the protothread control structure. + * \param condition The condition. + * + * \hideinitializer + */ +#define PT_WAIT_UNTIL(pt, condition) \ + do {/*printf("Test1: %d, %s\n",__LINE__,__FILE__);*/ \ + LC_SET((pt)->lc); /*printf("Test2: %d\n",(pt)->lc);*/ \ + if(!(condition)) { \ + return PT_WAITING; \ + } \ + } while(0) + +/** + * Block and wait while condition is true. + * + * This function blocks and waits while condition is true. See + * PT_WAIT_UNTIL(). + * + * \param pt A pointer to the protothread control structure. + * \param cond The condition. + * + * \hideinitializer + */ +#define PT_WAIT_WHILE(pt, cond) PT_WAIT_UNTIL((pt), !(cond)) + +/** @} */ + +/** + * \name Hierarchical protothreads + * @{ + */ + +/** + * Block and wait until a child protothread completes. + * + * This macro schedules a child protothread. The current protothread + * will block until the child protothread completes. + * + * \note The child protothread must be manually initialized with the + * PT_INIT() function before this function is used. + * + * \param pt A pointer to the protothread control structure. + * \param thread The child protothread with arguments + * + * \sa PT_SPAWN() + * + * \hideinitializer + */ +#define PT_WAIT_THREAD(pt, thread) PT_WAIT_WHILE((pt), PT_SCHEDULE(thread)) + +/** + * Spawn a child protothread and wait until it exits. + * + * This macro spawns a child protothread and waits until it exits. The + * macro can only be used within a protothread. + * + * \param pt A pointer to the protothread control structure. + * \param child A pointer to the child protothread's control structure. + * \param thread The child protothread with arguments + * + * \hideinitializer + */ +#define PT_SPAWN(pt, child, thread) \ + do { \ + PT_INIT((child)); \ + PT_WAIT_THREAD((pt), (thread)); \ + } while(0) + +/** @} */ + +/** + * \name Exiting and restarting + * @{ + */ + +/** + * Restart the protothread. + * + * This macro will block and cause the running protothread to restart + * its execution at the place of the PT_BEGIN() call. + * + * \param pt A pointer to the protothread control structure. + * + * \hideinitializer + */ +#define PT_RESTART(pt) \ + do { \ + PT_INIT(pt); \ + return PT_WAITING; \ + } while(0) + +/** + * Exit the protothread. + * + * This macro causes the protothread to exit. If the protothread was + * spawned by another protothread, the parent protothread will become + * unblocked and can continue to run. + * + * \param pt A pointer to the protothread control structure. + * + * \hideinitializer + */ +#define PT_EXIT(pt) \ + do { \ + PT_INIT(pt); \ + return PT_EXITED; \ + } while(0) + +/** @} */ + +/** + * \name Calling a protothread + * @{ + */ + +/** + * Schedule a protothread. + * + * This function shedules a protothread. The return value of the + * function is non-zero if the protothread is running or zero if the + * protothread has exited. + * + * \param f The call to the C function implementing the protothread to + * be scheduled + * + * \hideinitializer + */ +#define PT_SCHEDULE(f) ((f) < PT_EXITED) + +/** @} */ + +/** + * \name Yielding from a protothread + * @{ + */ + +/** + * Yield from the current protothread. + * + * This function will yield the protothread, thereby allowing other + * processing to take place in the system. + * + * \param pt A pointer to the protothread control structure. + * + * \hideinitializer + */ +#define PT_YIELD(pt) \ + do { \ + PT_YIELD_FLAG = 0; \ + LC_SET((pt)->lc); \ + if(PT_YIELD_FLAG == 0) { \ + return PT_YIELDED; \ + } \ + } while(0) + +/** + * \brief Yield from the protothread until a condition occurs. + * \param pt A pointer to the protothread control structure. + * \param cond The condition. + * + * This function will yield the protothread, until the + * specified condition evaluates to true. + * + * + * \hideinitializer + */ +#define PT_YIELD_UNTIL(pt, cond) \ + do { \ + PT_YIELD_FLAG = 0; \ + LC_SET((pt)->lc); \ + if((PT_YIELD_FLAG == 0) || !(cond)) { \ + return PT_YIELDED; \ + } \ + } while(0) + +/** @} */ + +#endif /* __PT_H__ */ + +/** @} */ diff --git a/dol/src/dol/visitor/cell/lib/spu/FastCommunication.cpp b/dol/src/dol/visitor/cell/lib/spu/FastCommunication.cpp new file mode 100644 index 0000000..2f2c3de --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/spu/FastCommunication.cpp @@ -0,0 +1,707 @@ +/* + * FastCommunication.cpp + * + * Created on: Mar 3, 2009 + * Author: lschor + * + * Provides the communication between various processors. + * + * + * + * Description: + * + * Sender: The processor now has some data that need to be forwarded + * to another processor. + * Receiver: The processor that needs to get the data. + * + * Sender ---- * + * -----> Have some data * + * (Len, queue) * + * -----------> Receiver * + * * + * Check its len * + * * + * Sets up a DMA * + * transfer to * + * read from the * + * <-------------- queue to a * + * MFC performs the local buffer * + * transfer (Alignment) * + * <--------- * + * * + * * + * (Pools if the * + * transfer is * + * completed) * + * * + * * + * Copy the data * + * from its temp. * + * buffer to the * + * queue und * + * Have completed <------------ informs the * + * <---------- (queue, len) sender * + * Can increase the * + * pointers in the FIFO + * + * + * Has two ways to handling request, which are not possible + * to work out currently: + * 1) Send back "len = 0" + * --> Needs to send more messages, but may bigger lens + * 2) Store them until you have enough space to read + * --> Smaller lens and less messages + */ + +#include "FastCommunication.h" + +/* + * Constructor + */ +FastCommunication::FastCommunication(int nrOfQueues, uint64_t ea_base, + uint64_t *ea_base_all, int32_t * queueFromSPEIn, + int32_t * queueOnSPEIn, uint64_t *fifoTails) { + + // Set the base address + _ea_base = ea_base; + + _ea_base_all = ea_base_all; + queueFromSPE = queueFromSPEIn; + queueOnSPE = queueOnSPEIn; + _fifoTails = fifoTails; + + _nrOfQueues = nrOfQueues; + try { _fifos = new fifoCollection[nrOfQueues]; } + catch(std::bad_alloc &e) { + fprintf(stderr, "[FastCommunication] Memory allocation failure\n"); + exit(1); + } + _nrOfRequest = 0; + + for (int i = 0; i < MAXNOREQ; i++) { + _request[i].valid = false; + } +} + +/* + * Deconstructor + */ +FastCommunication::~FastCommunication() { + delete _fifos; +} + +/* + * Register an additional FIFO in the Communication + */ +bool FastCommunication::addFifo(int fifoNr, Fifo* fifo, int type, + int queue) { + _fifos[fifoNr].fifo = fifo; + _fifos[fifoNr].queue = queue; + _fifos[fifoNr].type = type; + _fifos[fifoNr].iswfifo = false; + + // Per FIFO queue, we need two requests, but we store at max MAXNOREQ of them + if (_nrOfRequest < MAXNOREQ) { + _nrOfRequest += 2; + } + + return true; +} + +/* + * Register an additional WindowedFIFO in the Communication + */ +bool FastCommunication::addWFifo(int fifoNr, WindowedFifo* wfifo, + int type, int queue) { + _fifos[fifoNr].wfifo = wfifo; + _fifos[fifoNr].queue = queue; + _fifos[fifoNr].type = type; + _fifos[fifoNr].iswfifo = true; + + // Per FIFO queue, we need two requests, but we store at max MAXNOREQ of them + if (_nrOfRequest < MAXNOREQ) { + _nrOfRequest += 2; + } + + return true; +} + +/* + * Communication: Main update procedure to update + */ +bool FastCommunication::update() { + // Check if you have received a new message + while (spu_stat_in_mbox() > 0) { + uint32_t messageIn = spu_read_in_mbox(); + + uint32_t code = GETFASTCODE(messageIn); + uint32_t queue = GETFASTQUEUE(messageIn); + uint32_t len = GETFASTLEN(messageIn); + + /***************************************************************************************************************/ + if (code == SPE_READ_DEMAND) // One should start a read process + { + // Find out for which fifo the request is + fifoCollection *fifocol = NULL; + int i = 0; + for (i = 0; i < _nrOfQueues; i++) { + if (_fifos[i].queue == queue) { + fifocol = &_fifos[i]; + break; + } + } + + // The queue was not found + if (fifocol == NULL) { + printf("SPU COM> ERROR, this queue does not exists!\n"); + return false; + } + + // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // Windowed FIFO + if (_fifos[i].iswfifo) { + + WindowedFifo* wfifo = NULL; + wfifo = _fifos[i].wfifo; + + // Find the current tail of the queue from where to read + uint32_t inTail = wfifo->_inTail; + + // This is the len we like to read + len = len > (wfifo->unused()) ? wfifo->unused() : len; + + // We can read something + if (len > 0) { + // Write all information we used to the request-memory + comRequest* request = newRequest(); + + // Has no memory to store a new request + if (request == NULL) { + // not possible to start a request for this SPE --> Send len = 0 + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_COMPLETE, queue, 0); + sendMessage(message, queueFromSPE[queue]); + return false; + } + + // reserve DMA tag ID + uint32_t tag_id; + if ((tag_id = mfc_tag_reserve()) == MFC_TAG_INVALID) { + printf("SPE: ERROR - can't reserve a tag ID\n"); + return false; + } + + // Generate the base address of the input FIFO + uint64_t baseAddress = _fifoTails[queue] + inTail; + + // Align the address to the correct factor (in general 128 or 32) + while (baseAddress % ALIGNMENT_FACTOR_POWER2 != 0) + baseAddress--; + + // Offset --> How much we had to align + uint32_t offset = _fifoTails[queue] + inTail + - baseAddress; + + request->data = (char *) _malloc_align(roundDMA(len + + offset), ALIGNMENT_FACTOR); + + // Store all data in the request buffer + request->len = len; + + request->wfifo = wfifo; + request->iswfifo = true; + + request->status = read_started; + request->queue = queue; + request->offset = offset; + request->tag_id = tag_id; + + // Set up the request in the MFC + mfc_get((void *) &(request->data[0]), baseAddress, + roundDMA(len + offset), tag_id, 0, 0); + } + + else { +#ifndef STORE_REQUESTS // Send len = 0 back to the sender, this one should try it in a later phase + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_COMPLETE, queue, 0); + sendMessage(message, queueFromSPE[queue]); +#else // I store the request and may try in a later time to start the transfer + comRequest* request = newRequest(); + + // Has no memory to store a new request + if (request == NULL) + { + // not possible to start a request for this SPE --> Send len = 0 + uint32_t message = CREATEFASTMESSAGE(SPE_READ_COMPLETE, queue, 0); + sendMessage(message, queueFromSPE[queue]); + return false; + } + + request->len = len; + request->wfifo = wfifo; + request->iswfifo = true; + request->status = read_pending; + request->queue = queue; +#endif + } + } + + // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // Classic FIFO + else { + Fifo* fifo = NULL; + fifo = _fifos[i].fifo; + + uint32_t inTail = fifo->_inTail; + + // This is the len we like to read + len = len > (fifo->unused()) ? fifo->unused() : len; + + // We can read something + if (len > 0) { + // Write all information we used to the request-memory + comRequest* request = newRequest(); + + // Has no memory to store a new request + if (request == NULL) { + // not possible to start a request for this SPE --> Send len = 0 + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_COMPLETE, queue, 0); + sendMessage(message, queueFromSPE[queue]); + return false; + } + + uint32_t tag_id; + + // reserve DMA tag ID + if ((tag_id = mfc_tag_reserve()) == MFC_TAG_INVALID) { + printf("SPE: ERROR - can't reserve a tag ID\n"); + return false; + } + + uint64_t baseAddress = _fifoTails[queue] + inTail; + + while (baseAddress % ALIGNMENT_FACTOR_POWER2 != 0) + baseAddress--; + + // Offset + uint32_t offset = _fifoTails[queue] + inTail + - baseAddress; + + // Store all data in the request buffer + request->data = (char *) _malloc_align(roundDMA(len + + offset), ALIGNMENT_FACTOR); + request->len = len; + request->fifo = fifo; + request->iswfifo = false; + request->status = read_started; + request->queue = queue; + request->offset = offset; + request->tag_id = tag_id; + + // Tell the fifo that one has reserved some data + + mfc_get((void *) &(request->data[0]), baseAddress, + roundDMA(len + offset), tag_id, 0, 0); + } + + // len == 0 + else { +#ifndef STORE_REQUESTS // Send len = 0 back to the sender, this one should try it in a later phase + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_COMPLETE, queue, 0); + sendMessage(message, queueFromSPE[queue]); +#else // I store the request and may try in a later time to start the transfer + comRequest* request = newRequest(); + + // Has no memory to store a new request + if (request == NULL) + { + // not possible to start a request for this SPE --> Send len = 0 + uint32_t message = CREATEFASTMESSAGE(SPE_READ_COMPLETE, queue, 0); + sendMessage(message, queueFromSPE[queue]); + return false; + } + + request->len = len; + request->fifo = fifo; + request->iswfifo = false; + request->status = read_pending; + request->queue = queue; +#endif + } + } + } + + /***************************************************************************************************************/ + else if (code == SPE_READ_COMPLETE) // A read has finished + { + // Get the stored request + comRequest* request = getRequest(read_request_sent, queue); + if (request == NULL) { + printf( + ">>>>>>>>>>>>>>>>> Communicate SPU> Couldn't find the request\n"); + return 0; + } + + // Inform my FIFO that the request is completed + if (request->iswfifo) + request->wfifo->dmaRead(len); + else + request->fifo->dmaRead(len); + + // Request free + deleteRequest(request); + } + } + + /***************************************************************************************************************/ + // Check if some active write processes have finished + uint8_t req = _currentRequest; + + for (int i = 0; i < _nrOfRequest; i++) // Check all possible requests + { + if (_request[req].valid) // Only to check if the request is valid + { + if (_request[req].status == read_started) { // We have setup the request, now check if it is complete + + // If I cannot send a message to the corresponding processor --> Do not have to check it + if (!(testMessage(queueOnSPE[_request[req].queue]) > 0)) + continue; + + // Check if the specific Tag-ID has completed + uint32_t tag_id = _request[req].tag_id; + mfc_write_tag_mask(1 << tag_id); + mfc_write_tag_update(MFC_TAG_UPDATE_IMMEDIATE); + uint32_t ret = mfc_read_tag_status(); + + if (!((ret & (1 << tag_id)) == 0)) { + + // This update is finished + mfc_tag_release(tag_id); + + // Have to write the data into the fifo + if (_request[req].iswfifo) { // WFIFO + + _request[req].wfifo->dmaWrite( + (char *) _request[req].data + + _request[req].offset, + _request[req].len); + _free_align(_request[req].data); + + // Increase the inTail value (used to know where the last request was started) + _request[req].wfifo->_inTail + = (_request[req].wfifo->_inTail + + _request[req].len) % (FIFO_SIZE[_request[req].queue]); + } else { // FIFO + _request[req].fifo->write( + (char *) _request[req].data + + _request[req].offset, + _request[req].len); + _free_align(_request[req].data); + + _request[req].fifo->_inTail + = (_request[req].fifo->_inTail + + _request[req].len) % (FIFO_SIZE[_request[req].queue]); + + } + + // Inform the sender about the event + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_COMPLETE, _request[req].queue, + _request[req].len); + sendMessage(message, queueFromSPE[_request[req].queue]); + + // Delete the request + deleteRequest(&_request[req]); + _currentRequest = (req + 1) % _nrOfRequest; + + break; // continue is also working + } + } else if (_request[req].status == read_pending) { // Has an open request for sending + + // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // Windowed FIFO + if (_request[req].iswfifo) { + + if (_request[req].wfifo->unused() > 0) { + comRequest *request = &_request[req]; + + // This is the len we like to read + uint32_t len = request->len > (request->wfifo->unused()) ? request->wfifo->unused() + : request->len; + + // reserve DMA tag ID + uint32_t tag_id; + if ((tag_id = mfc_tag_reserve()) + == MFC_TAG_INVALID) { + printf("SPE: ERROR - can't reserve a tag ID\n"); + return false; + } + + uint32_t inTail = request->wfifo->_inTail; + uint64_t baseAddress = _fifoTails[request->queue] + + inTail; + + while (baseAddress % ALIGNMENT_FACTOR_POWER2 != 0) + baseAddress--; + + // Offset --> How much we had to align + uint32_t offset = _fifoTails[request->queue] + + inTail - baseAddress; + + request->data = (char *) _malloc_align(roundDMA( + len + offset), ALIGNMENT_FACTOR); + request->len = len; + request->status = read_started; + request->offset = offset; + request->tag_id = tag_id; + + // Set up the request in the MFC + mfc_get((void *) &(request->data[0]), baseAddress, + roundDMA(len + offset), tag_id, 0, 0); + } + } + + // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // Classic FIFO + else { + + if (_request[req].fifo->unused() > 0) { + comRequest *request = &_request[req]; + + // This is the len we like to read + uint32_t len = request->len > (request->fifo->unused()) ? request->fifo->unused() + : request->len; + + uint32_t tag_id; + // reserve DMA tag ID + if ((tag_id = mfc_tag_reserve()) + == MFC_TAG_INVALID) { + printf("SPE: ERROR - can't reserve a tag ID\n"); + return false; + } + + uint32_t inTail = request->fifo->_inTail; + uint64_t baseAddress = _fifoTails[request->queue] + inTail; + + while (baseAddress % ALIGNMENT_FACTOR_POWER2 != 0) + baseAddress--; + + // Offset + uint32_t offset = _fifoTails[request->queue] + + inTail - baseAddress; + + // Store all data in the request buffer + request->data = (char *) _malloc_align(roundDMA( + len + offset), ALIGNMENT_FACTOR); + request->len = len; + request->status = read_started; + request->offset = offset; + request->tag_id = tag_id; + + // Start the DMA transfer + mfc_get((void *) &(request->data[0]), baseAddress, + roundDMA(len + offset), tag_id, 0, 0); + } + } + } + } + // Go to the next Request + req = (req + 1) % _nrOfRequest; + } + + /***************************************************************************************************************/ + // Start a new request to the receiver of a FIFO + for (int i = 0; i < _nrOfQueues; i++) { + if (_fifos[i].type == this->out) // Only out-FIFO have to be quecked + { + if (_fifos[i].iswfifo) { // WFIFO + + // Start only a write process if there is really enough place in the outbound mailbox + if (_fifos[i].wfifo->dmaAllowed() && _fifos[i].wfifo->used() > 0) { + uint32_t queue = _fifos[i].queue; + + // Can we send a message to this processor or is it blocked? + if (testMessage(queueOnSPE[queue]) <= 0) { + continue; + } + + // Write all information we used to the request-memory + comRequest* request = newRequest(); + + // Has no memory to store a new request + if (request == NULL) { + } else { + uint32_t len = _fifos[i].wfifo->dmaStart(); + // Create a write-demand message + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_DEMAND, queue, len); + + request->len = len; + request->queue = queue; + request->status = read_request_sent; + request->wfifo = _fifos[i].wfifo; + request->iswfifo = true; + + sendMessage(message, queueOnSPE[queue]); + } + break; + } + } else { // FIFO + + // Start only a write process if there is really enough place in the outbound mailbox + if (_fifos[i].fifo->dmaAllowed() && _fifos[i].fifo->used() > 0) { + uint32_t queue = _fifos[i].queue; + + // Check if we can send a message to the processor + if (testMessage(queueOnSPE[queue]) <= 0) { + continue; + } + + // Write all information we used to the request-memory + comRequest* request = newRequest(); + + // Has no memory to store a new request + if (request == NULL) { + } else { + uint32_t len = _fifos[i].fifo->dmaStart(); + // Create a write-demand message + uint32_t message = CREATEFASTMESSAGE( + SPE_READ_DEMAND, queue, len); + + request->len = len; + request->queue = queue; + request->status = read_request_sent; + request->fifo = _fifos[i].fifo; + request->iswfifo = false; + + sendMessage(message, queueOnSPE[queue]); + } + break; + } + } + } + } + return true; +} + +/* + * Create a new request to store in the cache + * + */ +comRequest* FastCommunication::newRequest() { + for (int i = 0; i < _nrOfRequest; i++) { + if (!_request[i].valid) { + _request[i].valid = true; + return &(_request[i]); + } + } + + return NULL; +} + +/* + * Delete the request + * + */ +void FastCommunication::deleteRequest(comRequest* request) { + request->valid = false; +} + +/* + * Returns the request one like to get + */ +comRequest* FastCommunication::getRequest(uint8_t status, uint32_t queue) { + uint8_t req = _currentRequest; + + for (int i = 0; i < _nrOfRequest; i++) { + if (_request[req].valid && _request[req].status == status + && _request[req].queue == queue) { + _currentRequest = (req + 1) % _nrOfRequest; + return &(_request[req]); + } + req = (req + 1) % _nrOfRequest; + } + + return NULL; +} + +/** + * True if no communication is necessary, false if there is active communication + */ +bool FastCommunication::empty() { + // check if one fifo would like to send something to another SPE + for (int i = 0; i < _nrOfQueues; i++) { + if (_fifos[i].type == this->out) { + if (_fifos[i].iswfifo) { + if (_fifos[i].wfifo->used() > 0) + { + return false; + } + } else { + if (_fifos[i].fifo->used() > 0) + { + return false; + } + } + } + } + + // are open sendings? + for (int i = 0; i < _nrOfRequest; i++) { + if (_request[i].valid) { + return false; + } + } + + return true; +} + +void FastCommunication::sendMessage(uint32_t message, int32_t process) { + // Simple forward the message to the PPE + if (process <= -1) { + spu_write_out_mbox(message); + } + + // Forward message to the corresponding SPE + else { + uint32_t tag_id; + + // reserve DMA tag ID + if ((tag_id = mfc_tag_reserve()) == MFC_TAG_INVALID) { + printf("SPE: ERROR - can't reserve a tag ID\n"); + return; + } + + //printf("SPE > OUT Message to process = %d, addr = %llx\n", process, _ea_base_all[process]); + write_in_mbox(message, _ea_base_all[process], tag_id); + mfc_tag_release(tag_id); + } +} + +int FastCommunication::testMessage(int32_t process) { + //int32_t process = queueOnSPE[queue]; + + // Simple forward the message to the PPE + if (process <= -1) { + return spu_stat_out_mbox(); + } + + // Forward message to the corresponding SPE + else { + uint32_t tag_id; + + // reserve DMA tag ID + if ((tag_id = mfc_tag_reserve()) == MFC_TAG_INVALID) { + printf("SPE: ERROR - can't reserve a tag ID\n"); + return 0; + } + + // IMPORTANT: THIS IS NOT RACE CONDITION FREE!!!! + int test = status_in_mbox(_ea_base_all[process], tag_id); + mfc_tag_release(tag_id); + return test; + } +} diff --git a/dol/src/dol/visitor/cell/lib/spu/FastCommunication.h b/dol/src/dol/visitor/cell/lib/spu/FastCommunication.h new file mode 100644 index 0000000..a787556 --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/spu/FastCommunication.h @@ -0,0 +1,119 @@ +/* + * FastCommunication.h + * + * Created on: Mar 3, 2009 + * Author: lschor + */ + +#ifndef FASTCOMMUNICATION_H_ +#define FASTCOMMUNICATION_H_ + +// CBE includes +#include +#include + +// C++ includes +#include +#include +#include +#include +#include +#include + +// Local includes +#include "Fifo.h" +#include "WindowedFifo.h" +#include "../common.h" + +// For external Mailbox Communication +#include "../spu_mfcio_ext.h" + +// Include to allocate/free using for DMA transfers +#include "../lib/malloc_align.h" +#include "../lib/free_align.h" + +//Cell Macros +#define waittag(tag_id) mfc_write_tag_mask(1< _size) { + return _size - _tail; + } else { + return _pos; + } +} + +/* + * Is allowed to start a dma request + */ +bool Fifo::dmaAllowed() { + if (_blocked > 0) { + _blocked--; + return false; + } else { + return !_activeDMA; + } +} + +/** + * Test the implementation + */ +/* + int main() { + std::cout.width(5); + Fifo *myFifo = new Fifo(); + for (int j = 0; j < 3; j++) { + for (int i = 0; i < 6; i++) { + std::cout << "write " << i << " to Fifo. "; + int write = myFifo->write(&i, sizeof(int)); + printf(" %d ", write); + if (write == sizeof(int)) { + std::cout << "used: " << std::setw(2) << myFifo->used() + << ", unused: " << std::setw(2) << myFifo->unused() + << ", size: " << std::setw(2) << myFifo->size() + << std::endl; + } else { + std::cout << std::endl; + } + } + for (int i = 0; i < 6; i++) { + int value; + int read = myFifo->read(&value, sizeof(int)); + printf(" %d ", read); + if (read == sizeof(int)) { + std::cout << "read " << value << " from Fifo "; + std::cout << "used: " << std::setw(2) << myFifo->used() + << ", unused: " << std::setw(2) << myFifo->unused() + << ", size: " << std::setw(2) << myFifo->size() + << std::endl; + } + } + } + delete myFifo; + return 0; + } + */ diff --git a/dol/src/dol/visitor/cell/lib/spu/Fifo.h b/dol/src/dol/visitor/cell/lib/spu/Fifo.h new file mode 100644 index 0000000..798e7dd --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/spu/Fifo.h @@ -0,0 +1,47 @@ +#ifndef _FIFO_H_ +#define _FIFO_H_ + +#include +#include + +#include "../constant.h" + +#include "../lib/malloc_align.h" +#include "../lib/free_align.h" + +class Fifo { + public: + Fifo(unsigned size); + virtual ~Fifo(); + + // Read / Write + virtual unsigned read(void *destination, unsigned len); + virtual unsigned write(const void *source, unsigned len); + + // Buffer functions + virtual unsigned used() const; + virtual unsigned unused() const; + virtual unsigned size() const; + + // DMA functions + virtual char *getQueuePointer(); + virtual void dmaRead(unsigned len); + virtual unsigned dmaStart(); + virtual bool dmaAllowed(); + + // Global Variables + unsigned _inTail; + + protected: + char *_buffer; // Buffer pointer + + unsigned _tail; // Pointer to the tail + + unsigned _pos; // Amount used + unsigned _size; // Size of the buffer + + unsigned _blocked; // Number of blocking necessary + bool _activeDMA; // Active DMA? +}; + +#endif diff --git a/dol/src/dol/visitor/cell/lib/spu/WindowedFifo.cpp b/dol/src/dol/visitor/cell/lib/spu/WindowedFifo.cpp new file mode 100644 index 0000000..9b03f6a --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/spu/WindowedFifo.cpp @@ -0,0 +1,277 @@ +#include "WindowedFifo.h" + +/** + * + */ +WindowedFifo::WindowedFifo(unsigned size = 20) { + //std::cout << "Create WindowedFifo." << std::endl; + + _size = size; + _buffer = (char *) _malloc_align(_size, ALIGNMENT_FACTOR); + if(!_buffer) { + fprintf(stderr,"[WFIFO] Memory allocation failure\n"); + exit(-1); + } + _head = 0; + _tail = 0; + _headRoom = 0; + _tailRoom = 0; + _use = 0; + + _isHeadReserved = false; + _isTailReserved = false; + + // For DMA transfers + _blocked = 0; + _activeDMA = false; +} + +/** + * + */ +WindowedFifo::~WindowedFifo() { + //std::cout << "Delete WindowedFifo." << std::endl; + if (_buffer) { + _free_align(_buffer); + } + _buffer = 0; + _head = 0; + _tail = 0; + _use = 0; + //std::cout << "Deleted WindowedFifo." << std::endl; +} + +/** + * + */ +unsigned WindowedFifo::reserve(char** destination, unsigned len) { + + //std::cout << "Attempt to reserve " << len << " bytes." << std::endl; + + //can only reserve once piece at a time + if (_isHeadReserved) { + *destination = 0; + return 0; + } + + //reserve at most as much memory as still available in the buffer + unsigned write = (len <= _size - _use ? len : 0); + + if (write > 0) { + //if wrap-around in buffer: return only buffer for the + //contiguous buffer space + if (_head + write > _size) { + write = _size - _head; + } + + _headRoom = (_head + write) == _size ? 0 : _head + write; + *destination = &(_buffer[_head]); + _isHeadReserved = true; + } + + //std::cout << "Reserved " << write << " bytes." << std::endl; + _writeReserve = write; + return write; +} + +/** + * + */ +void WindowedFifo::release() { + if (_isHeadReserved) { + //std::cout << "Released " << _headRoom - _head << " bytes." << std::endl; + _head = _headRoom; + _use += _writeReserve; + _isHeadReserved = false; + } +} + +/** + * + */ +unsigned WindowedFifo::capture(char **destination, unsigned len) { + + //std::cout << "Attempt to capture " << len << " bytes." << std::endl; + + if (_isTailReserved) { + //std::cout << "Only one attempt to capture allowed." << std::endl; + *destination = 0; + return 0; + } + + //capture at most as much data as available in the buffer + unsigned read = (len <= _use ? len : 0); + + if (read > 0) { + //if wrap-around in buffer: return only buffer for the + //conntiguous buffer space + if (_tail + read > _size) { + read = _size - _tail; + } + + _tailRoom = (_tail + read) == _size ? 0 : _tailRoom = _tail + read; + *destination = &(_buffer[_tail]); + _isTailReserved = true; + } + + _readReserve = read; + //std::cout << "Captured " << read << " bytes." << std::endl; + + return read; +} + +/** + * + */ +void WindowedFifo::consume() { + if (_isTailReserved) { + //std::cout << "Consumed " << _tailRoom - _tail << " bytes." << std::endl; + _tail = _tailRoom; + _use -= _readReserve; + _isTailReserved = false; + } +} + +/** + * + */ +unsigned WindowedFifo::size() const { + return _size; +} + +/** + * + */ +unsigned WindowedFifo::unused() const { + return _size - _use; +} + +/** + * + */ +unsigned WindowedFifo::used() const { + return _use; +} + +/* + * Get the pointer to the start of the queue + */ +char *WindowedFifo::getQueuePointer() { + return _buffer; +} + +/* + * Has completed a dma read process, i.e. has read out of the queue + */ +void WindowedFifo::dmaRead(unsigned len) { + if (len == 0) { + _blocked = BLOCKED_MAX_NR; + } else { + _tail = ((unsigned) (_tail + len) % _size); + _use -= len; + } + + _activeDMA = false; +} + +/* + * Start a DMA request, returns the current space one have + */ +unsigned WindowedFifo::dmaStart() { + _activeDMA = true; + + if (_tail + _use > _size) { + return _size - _tail; + } else { + return _use; + } +} + +/* + * Is allowed to start a dma request + */ +bool WindowedFifo::dmaAllowed() { +#ifndef STORE_REQUESTS + if (_blocked > 0) { + _blocked--; + return false; + } else { + return !_activeDMA; + } +#else + return !_activeDMA; +#endif +} + +/** + * Is needed for DMA transfers + */ +unsigned WindowedFifo::dmaWrite(const void *source, unsigned len) { + + char* buffer = (char*) source; + + if (_head + len < _size) { + memcpy(_buffer + _head, buffer, len); + } else { + // We should never be here! + memcpy(_buffer + _head, buffer, _size - _head); + memcpy(_buffer, buffer + _size - _head, len - _size + _head); + } + _use += len; + _head = (_head + len) >= _size ? _head + len - _size : _head + len; + + return len; +} + +/** + * Test the implementation + */ +/* + int main() { + WindowedFifo *myFifo = new WindowedFifo(16); + + int* buf1; + int* buf2; + int x = myFifo->reserve((char**)&buf1, 8); + *buf1 = 10; + *(buf1 + 1) = 20; + myFifo->release(); + int y = myFifo->capture((char**)&buf2, 8); + std::cout << "read " << *buf2 << " " << *(buf2 + 1) << std::endl; + myFifo->consume(); + + for (int j = 0; j < 3; j++) { + for (int i = 0; i < 6; i++) { + std::cout << "write " << i << " to Fifo. "; + int write = myFifo->reserve((char**)&buf1, sizeof(int)); + if (write == sizeof(int)) { + *buf1 = i; + myFifo->release(); + std::cout << "used: " << std::setw(2) << myFifo->used() + << ", unused: " << std::setw(2) << myFifo->unused() + << ", size: " << std::setw(2) << myFifo->size() + << std::endl; + } else { + std::cout << std::endl; + } + } + for (int i = 0; i < 16; i++) { + char* buf3; + int read = myFifo->capture((char**)&buf3, sizeof(char)); + if (read == sizeof(char)) { + std::cout << "read " << (unsigned)*buf3 << " from Fifo "; + std::cout << "used: " << std::setw(2) << myFifo->used() + << ", unused: " << std::setw(2) << myFifo->unused() + << ", size: " << std::setw(2) << myFifo->size() + << std::endl; + myFifo->consume(); + } else { + std::cout << "read nothing from Fifo." << std::endl; + } + + } + } + delete myFifo; + return 0; + } + */ diff --git a/dol/src/dol/visitor/cell/lib/spu/WindowedFifo.h b/dol/src/dol/visitor/cell/lib/spu/WindowedFifo.h new file mode 100644 index 0000000..5ef97d9 --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/spu/WindowedFifo.h @@ -0,0 +1,60 @@ +#ifndef _WINDOWEDFIFO_H_ +#define _WINDOWEDFIFO_H_ + +#include +#include + +#include "../constant.h" + +#include "../lib/malloc_align.h" +#include "../lib/free_align.h" + +class WindowedFifo { + public: + WindowedFifo(unsigned size); + virtual ~WindowedFifo(); + + // Write + virtual unsigned reserve(char** destination, unsigned len); + virtual void release(); + + // Read + virtual unsigned capture(char** destination, unsigned len); + virtual void consume(); + + // General functions + virtual unsigned used() const; + virtual unsigned unused() const; + virtual unsigned size() const; + + // DMA functions + virtual char *getQueuePointer(); + virtual void dmaRead(unsigned len); + virtual unsigned dmaStart(); + virtual bool dmaAllowed(); + virtual unsigned dmaWrite(const void *source, unsigned len); + + // Global variables + unsigned _inTail; + + protected: + char *_buffer; // Pointer to the buffer + + unsigned _head; // Current position of the head + unsigned _tail; // Current position of the tail + unsigned _headRoom; // HeadRoom pointer + unsigned _tailRoom; // Tailroom pointer + + unsigned _size; // Total space of the buffer + unsigned _use; // How many data are used in the buffer + unsigned _writeReserve; // Number of tokens one is writing + unsigned _readReserve; // Number of tokens one is reading + + bool _isHeadReserved; // Head reserved? + bool _isTailReserved; // Tail reserved? + + unsigned _blocked; // Blocked number the request has to wait + bool _activeDMA; // Is there an active DMA on this buffer +}; + +#endif diff --git a/dol/src/dol/visitor/cell/lib/spu/common.cpp b/dol/src/dol/visitor/cell/lib/spu/common.cpp new file mode 100644 index 0000000..df56fc8 --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/spu/common.cpp @@ -0,0 +1,29 @@ +/* + * common.cpp + * + * Created on: Feb 27, 2009 + * Author: lschor + */ + +#include "../common.h" + +/** + Round a number to the alignment of the Cell + */ +uint32_t roundDMA(uint32_t number) { + if (number > 16) + if (number % 16 == 0) + return number; + else + return number + 16 - (number % 16); + else if (number > 8) + return 16; + else if (number > 4) + return 8; + else if (number > 2) + return 4; + else if (number > 1) + return 2; + else + return 1; +} diff --git a/dol/src/dol/visitor/cell/lib/spu/dolSupport.cpp b/dol/src/dol/visitor/cell/lib/spu/dolSupport.cpp new file mode 100644 index 0000000..4bf2b6e --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/spu/dolSupport.cpp @@ -0,0 +1,98 @@ +#include "dolSupport.h" + +/** + * + */ +unsigned read(void* fifo, void* buf, unsigned len, DOLProcess* p) { + unsigned int + pos = + static_cast ((static_cast (p->wptr))->wrapper)->readPos; + pos += ((Fifo*) fifo)->read((char *) buf + pos, len - pos); + + if (pos == len) + static_cast ((static_cast (p->wptr))->wrapper)->readPos + = 0; + else + static_cast ((static_cast (p->wptr))->wrapper)->readPos + = pos; + return pos; +} + +/** + * + */ +unsigned write(void* fifo, void* buf, unsigned len, DOLProcess* p) { + unsigned int + pos = + static_cast ((static_cast (p->wptr))->wrapper)->writePos; + pos += ((Fifo*) fifo)->write((char *) buf + pos, len - pos); + + if (pos == len) + static_cast ((static_cast (p->wptr))->wrapper)->writePos + = 0; + else + static_cast ((static_cast (p->wptr))->wrapper)->writePos + = pos; + return pos; +} + +/** + * + */ +void DOL_detach(DOLProcess* p) { + static_cast ((static_cast (p->wptr))->wrapper)->detach(); +} + +/** + * + */ +unsigned reserve(void* fifo, void** destination, unsigned len, + DOLProcess* p) { + return ((WindowedFifo*) fifo)->reserve((char **) destination, len); +} + +/** + * + */ +void release(void* fifo, DOLProcess* p) { + ((WindowedFifo*) fifo)->release(); +} + +/** + * + */ +unsigned capture(void* fifo, void** destination, unsigned len, + DOLProcess* p) { + return ((WindowedFifo*) fifo)->capture((char **) destination, len); +} + +/** + * + */ +void consume(void* fifo, DOLProcess* p) { + ((WindowedFifo*) fifo)->consume(); +} + +void createPort(void** port, void* base, int number_of_indices, + int index0, int range0) { + *port = (void**) ((void**) base)[index0]; +} + +void createPort(void** port, void* base, int number_of_indices, + int index0, int range0, int index1, int range1) { + *port = (void**) ((void**) base)[index0 * range1 + index1]; +} + +void createPort(void** port, void* base, int number_of_indices, + int index0, int range0, int index1, int range1, int index2, + int range2) { + *port = (void**) ((void**) base)[index0 * range1 * range2 + index1 + * range2 + index2]; +} + +void createPort(void** port, void* base, int number_of_indices, + int index0, int range0, int index1, int range1, int index2, + int range2, int index3, int range3) { + *port = (void**) ((void**) base)[index0 * range1 * range2 * range3 + + index1 * range2 * range3 + index2 * range3 + index3]; +} diff --git a/dol/src/dol/visitor/cell/lib/spu/dolSupport.h b/dol/src/dol/visitor/cell/lib/spu/dolSupport.h new file mode 100644 index 0000000..63f1f74 --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/spu/dolSupport.h @@ -0,0 +1,88 @@ +#ifndef DOLSUPPORT_H +#define DOLSUPPORT_H + +#include + +#include "dol.h" +#include "../pt/pt.h" +#include "proc_wrapper.h" + +#include "Fifo.h" +#include "WindowedFifo.h" + + +typedef struct _process_data { + int lc; + proc_wrapper *wrapper; +} process_data; + + +#define DOL_read(port, buf, size, process) \ + PT_WAIT_UNTIL((pt*)(p->wptr), read(port, buf, size, process) == size); + +#define DOL_write(port, buf, size, process) \ + PT_WAIT_UNTIL((pt*)(p->wptr), write(port, buf, size, process) == size); + +#define DOL_reserve(port, buf, size, process) \ + PT_WAIT_UNTIL((pt*)(p->wptr), reserve(port, (void**)buf, size, process) == size); + + //should stall only if the return size is 0!!! (but how, one has to give a return value...) + +#define DOL_release(port, process) \ + release(port, process); + +#define DOL_capture(port, buf, size, process) \ + PT_WAIT_UNTIL((pt*)(p->wptr), capture(port, (void**)buf, size, process) == size); + + //should stall only if the return size is 0!!! (but how, one has to give a return value...) + +#define DOL_consume(port, process) \ + consume(port, process); + + +void DOL_detach(DOLProcess* p); + +unsigned write(void* fifo, void* buf, unsigned len, DOLProcess* p); + +unsigned read(void* fifo, void* buf, unsigned len, DOLProcess* p); + +unsigned reserve(void* fifo, void** destination, unsigned len, DOLProcess* p); + +void release(void* fifo, DOLProcess* p); + +unsigned capture(void* fifo, void** destination, unsigned len, DOLProcess* p); + +void consume(void* fifo, DOLProcess* p); + + +//macros to deal with iterated ports +/** + * macro to create a variable to store a port name + * + * @param name name of the variable + */ +#define CREATEPORTVAR(name) static Fifo *name + +/** + * Create the port name of an iterated port based on its basename and the + * given indices. + * + * @param port buffer where the result is stored (created using + * CREATEPORTVAR) + * @param base basename of the port + * @param number_of_indices number of dimensions of the port + * @param index_range_pairs index and range values for each dimension + */ + +#define CREATEPORT(port, base, number_of_indices, index_range_pairs...) \ + createPort((void**)(&port), base, number_of_indices, index_range_pairs) + +#define GETINDEX(dimension) \ + static_cast((static_cast(p->wptr))->wrapper)->getIndex(dimension) + +void createPort(void** port, void* base, int number_of_indices, int index0, int range0); +void createPort(void** port, void* base, int number_of_indices, int index0, int range0, int index1, int range1); +void createPort(void** port, void* base, int number_of_indices, int index0, int range0, int index1, int range1, int index2, int range2); +void createPort(void** port, void* base, int number_of_indices, int index0, int range0, int index1, int range1, int index2, int range2, int index3, int range3); + +#endif diff --git a/dol/src/dol/visitor/cell/lib/spu/proc_wrapper.cpp b/dol/src/dol/visitor/cell/lib/spu/proc_wrapper.cpp new file mode 100644 index 0000000..41e2705 --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/spu/proc_wrapper.cpp @@ -0,0 +1,92 @@ +/** + * proc_wrapper.cpp + * + * Created on: Feb 24, 2009 + * Author: lschor + */ + +#include "proc_wrapper.h" + +proc_wrapper::proc_wrapper() { + _isDetached = false; + readPos = 0; + writePos = 0; +} + +proc_wrapper::~proc_wrapper() { +} + +/** + * + */ +void proc_wrapper::init() { + _process.init(&_process); +} + +/** + * + */ +int proc_wrapper::fire() { + return _process.fire(&_process); +} + +/** + * + */ +void proc_wrapper::detach() { + _isDetached = true; +} + +/** + * Gets an index of a string, where the index must be separated by + * a character specified in tokens. + * Returns -1, when an error occurs. + * + * Example: + * getIndex("name_1_2", "_", 0) will return 1. + * getIndex("name_1_2", "_", 1) will return 2. + * + * @param string string to parse + * @param tokens delimiter of indices + * @param indexNumber position of index (starting at 0) + */ +int proc_wrapper::getIndex(const char* string, char* tokens, + int indexNumber) { + char* string_copy; + char* token_pointer; + int index = 0; + + string_copy = (char*) malloc(sizeof(char) * (strlen(string) + 1)); + if (!string_copy) { + fprintf(stderr, "getIndex(): could not allocate memory.\n"); + return -1; + } + + strcpy(string_copy, string); + + token_pointer = strtok(string_copy, tokens); + do { + token_pointer = strtok(NULL, tokens); + index++; + } while (index <= indexNumber && token_pointer != 0); + + if (token_pointer) { + index = atoi(token_pointer); + free(string_copy); + return index; + } + + free(string_copy); + return -1; +} + +/** + * Get the index of this process. + * @param indexNumber position of index (starting at 0) + */ +int proc_wrapper::getIndex(unsigned indexNumber) const { + if (indexNumber < 4) { + return _iteratorIndex[indexNumber]; + } + return -1; +} diff --git a/dol/src/dol/visitor/cell/lib/spu/proc_wrapper.h b/dol/src/dol/visitor/cell/lib/spu/proc_wrapper.h new file mode 100644 index 0000000..656fcdb --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/spu/proc_wrapper.h @@ -0,0 +1,55 @@ +/* + * proc_wrapper.h + * + * Created on: Feb 24, 2009 + * Author: lschor + */ + +#ifndef PROC_WRAPPER_H_ +#define PROC_WRAPPER_H_ + +#include +#include + +#include +#include +#include + +//CBE Macros +#define waittag(tag_id) mfc_write_tag_mask(1< current position you are while blocking + unsigned int readPos; + unsigned int writePos; + +protected: + char* name; + DOLProcess _process; + bool _isDetached; + int _iteratorIndex[4]; + + uint32_t* port_id; + uint32_t* port_queue_id; + uint32_t number_of_ports; + virtual int getIndex(const char* string, char* tokens, + int indexNumber); +}; + +#endif /* PROC_WRAPPER_H_ */ diff --git a/dol/src/dol/visitor/cell/lib/spu_mfcio_ext.h b/dol/src/dol/visitor/cell/lib/spu_mfcio_ext.h new file mode 100644 index 0000000..d85f1e8 --- /dev/null +++ b/dol/src/dol/visitor/cell/lib/spu_mfcio_ext.h @@ -0,0 +1,173 @@ +// -------------------------------------------------------------- +// (C)Copyright 2007, +// International Business Machines Corporation, +// All Rights Reserved. +// -------------------------------------------------------------- + +#ifndef _spu_mfcio_ext_h_ +#define _spu_mfcio_ext_h_ + +#include +#include +#include + +#include +#include + +static uint32_t msg[4]__attribute__ ((aligned (16))); + +// ========================================================================== +// Definitions +// ========================================================================== +#define SPU_IN_MBOX_OFFSET 0x0C // offset of mailbox status register from control area base +#define SPU_IN_MBOX_OFFSET_SLOT 0x3 // 16B alignment of mailbox status register = (SPU_MBOX_STAT_OFFSET&0xF)>>2 +#define SPU_MBOX_STAT_OFFSET 0x14 // offset of mailbox status register from control area base +#define SPU_MBOX_STAT_OFFSET_SLOT 0x1 // 16B alignment of mailbox status register = (SPU_MBOX_STAT_OFFSET&0xF)>>2 + +#define SPU_SIG_NOTIFY_OFFSET 0x0C // offset of signal notify 1 or 2 registera from signal notify 1 or 2 areas base +#define SPU_SIG_NOTIFY_OFFSET_SLOT 0x3 // 16B alignment of signal notify 1 or 2 register = (SPU_SIG_NOTIFY_OFFSET&0xF)>>2 + +// ========================================================================== +// Functions definitions +// ========================================================================== + +inline int status_mbox(uint64_t ea_mfc, uint32_t tag_id); +inline int status_in_mbox(uint64_t ea_mfc, uint32_t tag_id); +inline int status_out_mbox(uint64_t ea_mfc, uint32_t tag_id); +inline int status_outintr_mbox(uint64_t ea_mfc, uint32_t tag_id); + +int write_in_mbox(uint32_t data, uint64_t ea_mfc, uint32_t tag_id); +int write_signal1(uint32_t data, uint64_t ea_mfc, uint32_t tag_id); +int write_signal2(uint32_t data, uint64_t ea_mfc, uint32_t tag_id); + +// returns the value of mailbox status register of remote SPE +inline int status_mbox(uint64_t ea_mfc, uint32_t tag_id) +{ + uint32_t status[4], idx; + uint64_t ea_stat_mbox = ea_mfc + SPU_MBOX_STAT_OFFSET; + + //printf(">16, (status[idx]&0x0000ff00)>>8, (status[idx]&0x000000ff) ); + //printf(">8; + + //printf(">16; + + //printf(" +#include + +#include +#include +#include +#include + +// Include to allocate/free using for DMA transfers +#include "../lib/malloc_align.h" +#include "../lib/free_align.h" + +// Local includes +#include "../lib/spu/Fifo.h" +#include "../lib/common.h" +//#include "../lib/spu/Communication.h" +#include "../lib/spu/FastCommunication.h" + +// Protothread includes +#include "../lib/pt/pt.h" + +// Context file +static spu_context ctx_spu __attribute__ ((aligned (128))); + +#endif /* SPU_OS_H_ */ diff --git a/dol/src/dol/visitor/cell/template/spu_process_wrapper_template.cpp b/dol/src/dol/visitor/cell/template/spu_process_wrapper_template.cpp new file mode 100644 index 0000000..ebb1f4c --- /dev/null +++ b/dol/src/dol/visitor/cell/template/spu_process_wrapper_template.cpp @@ -0,0 +1,66 @@ +/* + * Square_wrapper.cpp + * + * Created on: Feb 27, 2009 + * Author: lschor + */ + + +#include "@PROCESSNAME@Wrapper.h" +#include "../lib/spu/dolSupport.h" + +#include "@PROCESSNAME@.c" + +@PROCESSNAME@Wrapper::@PROCESSNAME@Wrapper(uint64_t argp) { + // reserve DMA tag ID + uint32_t tag_id; + if((tag_id=mfc_tag_reserve())==MFC_TAG_INVALID){ + printf("SPE: ERROR - can't reserve a tag ID\n"); return; + } + + // Get the context information for the whole system + mfc_get((void*) &ctx_proc, argp, sizeof(ctx_proc), tag_id, 0, 0); + mfc_write_tag_mask(1<name = (char *)_malloc_align((uint32_t)ctx_proc.processNameLen, 4); + if(!this->name) { + fprintf(stderr,"[SPUProcessWrapper] Memory allocation failure\n"); + exit(-1); + } + mfc_get((void *)this->name, ctx_proc.processName, ctx_proc.processNameLen, tag_id, 0, 0); + waittag(tag_id); + + + //initialize the index array + for (int i = 0; i < 4; i++) { + this->_iteratorIndex[i] = getIndex(this->name, "_", i); + } + + try { _state = (LocalState) new @PROCESSNAME_UPPER@_State; } + catch(std::bad_alloc &e) { + fprintf(stderr, "[SPUProcessWrapper] Memory allocation failure\n"); + exit(-1); + } + _process.local = _state; + _process.init = @PROCESSNAME@_init; + _process.fire = @PROCESSNAME@_fire; + _process.wptr = (void*)&_wrapper_data; + + _wrapper_data.wrapper = this; + + // Init the process + _process.init(&_process); + + // release tag ID before exiting + mfc_tag_release(tag_id); +} + +@PROCESSNAME@Wrapper::~@PROCESSNAME@Wrapper() { + // Free the state + if (_state) + delete (@PROCESSNAME_UPPER@_State*) _state; + + // Free the name of the wrapper + _free_align(this->name); +} diff --git a/dol/src/dol/visitor/cell/template/spu_process_wrapper_template.h b/dol/src/dol/visitor/cell/template/spu_process_wrapper_template.h new file mode 100644 index 0000000..a0f9800 --- /dev/null +++ b/dol/src/dol/visitor/cell/template/spu_process_wrapper_template.h @@ -0,0 +1,56 @@ +/**************************************************************** + * Process Wrapper file + * Creator: lschor, 2009-02-24 + * Description: Wrapper for a specific SPE process + * + * Revision: + * - 2009-02-24: Created + */ + +#ifndef @PROCESSNAME@_WRAPPER_H_ +#define @PROCESSNAME@_WRAPPER_H_ + +// General includes +#include +#include +#include +#include +#include +#include + +// Include to allocate/free using for DMA transfers +#include "../lib/malloc_align.h" +#include "../lib/free_align.h" +#include "../lib/spu/Fifo.h" +#include "../lib/spu/WindowedFifo.h" + +// Local includes +#include "../lib/common.h" +//#include "../lib/estimation.h" + +#include "../lib/spu/proc_wrapper.h" + +class @PROCESSNAME@Wrapper; + +typedef struct _@PROCESSNAME@_data { + int lc; + @PROCESSNAME@Wrapper *wrapper; +} @PROCESSNAME@_data; + +class @PROCESSNAME@Wrapper : public proc_wrapper { + +// Context file +public: + @PROCESSNAME@Wrapper(uint64_t argp); + virtual ~@PROCESSNAME@Wrapper(); + + @FIFO@ + +protected: + LocalState _state; + process_context ctx_proc __attribute__ ((aligned (128))); + @PROCESSNAME@_data _wrapper_data; + +}; + +#endif /* @PROCESSNAME@_WRAPPER_H_ */ diff --git a/dol/src/dol/visitor/dot/ArchDotVisitor.java b/dol/src/dol/visitor/dot/ArchDotVisitor.java new file mode 100644 index 0000000..5f71ee8 --- /dev/null +++ b/dol/src/dol/visitor/dot/ArchDotVisitor.java @@ -0,0 +1,250 @@ +/* $Id: ArchDotVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.dot; + +import java.util.Iterator; + +import dol.datamodel.architecture.ArchiConnection; +import dol.datamodel.architecture.Architecture; +import dol.datamodel.architecture.HWChannel; +import dol.datamodel.architecture.Memory; +import dol.datamodel.architecture.Processor; +import dol.datamodel.architecture.ReadPath; +import dol.datamodel.architecture.WritePath; +import dol.datamodel.pn.Process; +import dol.util.CodePrintStream; +import dol.visitor.ArchiVisitor; + +/** + * Helps to generate DOTTY information for architecture resources. + */ +public class ArchDotVisitor extends ArchiVisitor +{ + /** + * Constructor. + * + * @param printStream print stream to which the contents is written + */ + public ArchDotVisitor(CodePrintStream printStream) { + _printStream = printStream; + _pnVisitor = new PNDotVisitor(printStream); + } + + /** + * Print a .dot file in the correct format for DOTTY. + * + * @param arch architecture that needs to be rendered + */ + public void visitComponent(Architecture arch) { + _printStream.printPrefixln("digraph architecture {"); + _printStream.println(); + _printStream.prefixInc(); + _printStream.printPrefixln("ratio = auto;"); + _printStream.printPrefixln("rankdir = LR;"); + _printStream.printPrefixln("ranksep = 2;"); + _printStream.printPrefixln("nodesep = 0.2;"); + _printStream.printPrefixln("center = true;"); + _printStream.printPrefixln(""); + _printStream.printPrefixln("node [ fontsize=12, height=0.4, " + + "width=0.4, style=filled, color=\"0.65 0.20 1.00\" ]"); + _printStream.println(); + + //visit all processors + Processor processor; + Iterator processorIter = arch.getProcessorList().iterator(); + while( processorIter.hasNext() ) { + processor = processorIter.next(); + processor.accept(this); + } + + //visit all hw_channels + HWChannel chan; + Iterator chanIter = arch.getHWChannelList().iterator(); + while(chanIter.hasNext()) { + chan = chanIter.next(); + chan.accept(this); + } + + //visit all memories + Memory mem; + Iterator memIter = arch.getMemoryList().iterator(); + while(memIter.hasNext()) { + mem = memIter.next(); + mem.accept(this); + } + + //visit all connections + ArchiConnection cn; + Iterator cnIter = arch.getConnectionList().iterator(); + while(cnIter.hasNext()) { + cn = cnIter.next(); + cn.accept(this); + } + + ReadPath rPath; + Iterator rpIter = arch.getReadPathList().iterator(); + while(rpIter.hasNext()) { + rPath = rpIter.next(); + rPath.accept(this); + } + + WritePath wPath; + Iterator wpIter = arch.getWritePathList().iterator(); + while(wpIter.hasNext()) { + wPath = wpIter.next(); + wPath.accept(this); + } + + _printStream.prefixDec(); + _printStream.println(); + _printStream.printPrefixln("}"); + } + + public void visitComponent(HWChannel chan) + { + _printStream.printPrefixln("subgraph cluster_" + + chan.getName().replaceAll("\\.", "") + " {"); + _printStream.prefixInc(); + _printStream.printPrefixln("label = \"" + chan.getName() + "\""); + + if (!chan.getPathList().isEmpty()) { + Iterator pIter = chan.getPathList().iterator(); + String path; + while (pIter.hasNext()) { + path = (String) pIter.next(); + _printStream.printPrefixln("\"" + path + "_" + chan.getName() + + "\" [label=\" " + + "\" shape=circle style=solid]"); + } + } + + _printStream.prefixDec(); + _printStream.printPrefixln("}"); + _printStream.println(); + } + + public void visitComponent(Memory mem) + { + _printStream.printPrefixln("subgraph cluster_" + + mem.getName().replaceAll("\\.", "") + " {"); + _printStream.prefixInc(); + _printStream.printPrefixln("label = \"" + mem.getName() + "\""); + + if (!mem.getRXBufList().isEmpty()) { + Iterator rIter = mem.getRXBufList().iterator(); + String rxBuf; + while (rIter.hasNext()) { + rxBuf = (String) rIter.next(); + _printStream.printPrefixln("\"" + rxBuf.replaceAll("\\.", "") + + "_RX\" [label=\"RX" + + "\" shape=circle style=dotted]"); + } + } + + if (!mem.getTXBufList().isEmpty()) { + Iterator rIter = mem.getTXBufList().iterator(); + String txBuf; + while (rIter.hasNext()) { + txBuf = (String) rIter.next(); + _printStream.printPrefixln("\"" + txBuf.replaceAll("\\.", "") + + "_TX\" [label=\"TX" + + "\" shape=circle style=dashed]"); + } + } + + if (!mem.getCHBufList().isEmpty()) { + Iterator rIter = mem.getCHBufList().iterator(); + String chBuf; + while (rIter.hasNext()) { + chBuf = (String) rIter.next(); + _printStream.printPrefixln("\"" + chBuf.replaceAll("\\.", "") + + "_CH\" [label=\"CH" + + "\" shape=circle style=bold]"); + } + } + + _printStream.prefixDec(); + _printStream.printPrefixln("}"); + _printStream.println(); + } + + + public void visitComponent(ArchiConnection cn) + { + _printStream.printPrefix(); + _printStream.print("\"" + + cn.getOrigin().getName().replaceAll("\\.", "") + "\" -> \"" + + cn.getTarget().getName().replaceAll("\\.", "") + + "\" [ color=" + _color + " ];"); + _printStream.println(); + } + + public void visitComponent(ReadPath rp) + { + String rName = rp.getName().replaceAll("\\.", ""); + + _printStream.printPrefix(); + _printStream.print(rName + "_RPath_CH->" ); + + Iterator cIter = rp.getHWChannelList().iterator(); + while (cIter.hasNext()) { + HWChannel channel = cIter.next(); + _printStream.print(rName + "_RPath_" + + channel.getName().replaceAll("\\.", "") + + "->"); + } + _printStream.println(rName + "_RX"); + } + + public void visitComponent(WritePath rp) + { + String rName = rp.getName().replaceAll("\\.", ""); + + _printStream.printPrefix(); + _printStream.print(rName + "_TX->" ); + + Iterator cIter = rp.getHWChannelList().iterator(); + while (cIter.hasNext()) { + HWChannel channel = cIter.next(); + _printStream.print(rName + "_WPath_" + + channel.getName().replaceAll("\\.", "") + + "->"); + } + _printStream.println(rName + "_WPath_CH"); + } + + /** + * Clusters all processes of this processor. + */ + public void visitComponent(Processor processor) + { + /* + _printStream.printPrefix(); + _printStream.print("\"" + processor.getName() + "\" [ label=\"" + + processor.getName() + "\", color=" + _color + + ", shape=box];"); + _printStream.println(); + */ + + _printStream.printPrefixln("subgraph cluster_" + + processor.getName().replaceAll("\\.", "") + " {"); + _printStream.prefixInc(); + _printStream.printPrefixln("label = \"" + processor.getName() + "\""); + + // labeleling clusters with dot2.8 & graphviz2.8 seems buggy + //_printStream.printPrefixln("label = \"" + processor.getName()+"\";"); + if (!processor.getProcessList().isEmpty()) { + Iterator pIter = processor.getProcessList().iterator(); + while (pIter.hasNext()) { + pIter.next().accept(_pnVisitor); + } + } + _printStream.prefixDec(); + _printStream.printPrefixln("}"); + _printStream.println(); + } + + /** DOT Visitor to visit process network resources */ + protected PNDotVisitor _pnVisitor = null; + + protected String _color = "dimgray"; +} diff --git a/dol/src/dol/visitor/dot/MapDotVisitor.java b/dol/src/dol/visitor/dot/MapDotVisitor.java new file mode 100644 index 0000000..581c615 --- /dev/null +++ b/dol/src/dol/visitor/dot/MapDotVisitor.java @@ -0,0 +1,80 @@ +/* $Id: MapDotVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.dot; + +import java.util.Iterator; + +import dol.datamodel.architecture.Processor; +import dol.datamodel.mapping.Mapping; +import dol.datamodel.pn.Channel; +import dol.util.CodePrintStream; +import dol.visitor.MapVisitor; + +/** + * This class is a class for a visitor that is used to generate + * ".dot" output in order to visualize a mapping using the DOTTY tool. + */ +public class MapDotVisitor extends MapVisitor { + + /** + * Constructor. + * + * @param printStream print stream to which the contents is written + */ + public MapDotVisitor(CodePrintStream printStream) { + _printStream = printStream; + _pnVisitor = new PNDotVisitor(printStream); + _archiVisitor = new ArchDotVisitor(printStream); + } + + /** + * Print a .dot file in the correct format for DOTTY. + * + * @param map process network that needs to be rendered + */ + public void visitComponent(Mapping map) { + _printStream.printPrefixln("digraph mapping {"); + _printStream.println(); + _printStream.prefixInc(); + _printStream.printPrefixln("ratio = auto;"); + _printStream.printPrefixln("rankdir = LR;"); + _printStream.printPrefixln("ranksep = 0.3;"); + _printStream.printPrefixln("nodesep = 0.2;"); + _printStream.printPrefixln("center = true;"); + _printStream.printPrefixln(""); + _printStream.printPrefixln("node [ fontsize=12, height=0.4, " + + "width=0.4, style=filled, color=\"0.65 0.20 1.00\" ];"); + _printStream.printPrefixln("edge [ fontsize=10, arrowhead=normal, " + + "arrowsize=0.8, style=\"setlinewidth(2)\" ];"); + _printStream.println(); + + //visit all processors + Processor processor; + Iterator processorIter = map.getProcessorList().iterator(); + while( processorIter.hasNext() ) + { + processor = processorIter.next(); + processor.accept(_archiVisitor); + } + + //visit all channels (from PN) + _pnVisitor.setMapping(map); + Channel chan; + Iterator chanIter = map.getPN().getChannelList().iterator(); + while (chanIter.hasNext() ) + { + chan = chanIter.next(); + chan.accept(_pnVisitor); + } + + _printStream.prefixDec(); + _printStream.println(); + _printStream.printPrefixln("}"); + } + + + /** DOT Visitor to visit process network resources */ + protected PNDotVisitor _pnVisitor = null; + + /** DOT Visitor to visit architecture resources */ + protected ArchDotVisitor _archiVisitor = null; +} diff --git a/dol/src/dol/visitor/dot/PNDotVisitor.java b/dol/src/dol/visitor/dot/PNDotVisitor.java new file mode 100644 index 0000000..3a0205a --- /dev/null +++ b/dol/src/dol/visitor/dot/PNDotVisitor.java @@ -0,0 +1,163 @@ +/* $Id: PNDotVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.dot; + +import java.util.Iterator; + +import dol.datamodel.mapping.ComputationBinding; +import dol.datamodel.mapping.Mapping; +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.util.CodePrintStream; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate + * ".dot" output in order to visualize a PN using the DOTTY tool. + */ +public class PNDotVisitor extends PNVisitor { + + Mapping _mapping = null; + + /** + * Constructor. + * + * @param printStream print stream to which the contents is written + */ + public PNDotVisitor(CodePrintStream printStream) { + _printStream = printStream; + } + + /** + * Print a .dot file in the correct format for DOTTY. + * + * @param x process network that needs to be rendered + */ + public void visitComponent(ProcessNetwork x) { + _printStream.printPrefixln("digraph pn {"); + _printStream.println(); + _printStream.prefixInc(); + _printStream.printPrefixln("ratio = auto;"); + _printStream.printPrefixln("rankdir = LR;"); + _printStream.printPrefixln("ranksep = 0.3;"); + _printStream.printPrefixln("nodesep = 0.2;"); + _printStream.printPrefixln("center = true;"); + _printStream.printPrefixln(""); + _printStream.printPrefixln("node [ fontsize=12, height=0.4, " + + "width=0.4, style=filled, color=\"0.65 0.20 1.00\" ];"); + _printStream.printPrefixln("edge [ fontsize=10, arrowhead=normal, " + + "arrowsize=0.8, style=\"setlinewidth(2)\" ];"); + _printStream.println(); + + //visit all processes + Iterator pIter; + Process p; + pIter = x.getProcessList().iterator(); + while (pIter.hasNext()) + { + p = pIter.next(); + p.accept(this); + } + _printStream.println(); + + //visit all channels + Iterator cIter; + Channel c; + cIter = x.getChannelList().iterator(); + while( cIter.hasNext() ) { + c = cIter.next(); + c.accept(this); + } + + _printStream.prefixDec(); + _printStream.println(); + _printStream.printPrefixln("}"); + } + + /** + * Print a line for the process in the correct format for DOTTY. + * + * @param x process that needs to be rendered + */ + public void visitComponent(Process x) { + //other colors: beige, lightgoldenrod, orange, tan, khaki3, + //aliceblue, lightskyblue, lightseagreen, mintcream, + //burlywood3, lightblue1, linen, papayawhip, azure1,2,3 + String color = "lightskyblue"; + + _printStream.printPrefix(); + _printStream.print("\"" + x.getName() + "\" [ label=\"" + + x.getName() + "\", color=" + + color); + if (!x.hasInPorts() || !x.hasOutPorts()) + _printStream.print(", shape=diamond"); + else + _printStream.print(", shape=ellipse"); + _printStream.print(" ];"); + _printStream.println(); + } + + /** + * Print a line for the channel in the correct format for DOTTY. + * + * @param x channel that needs to be rendered + */ + public void visitComponent(Channel x) { + String color = "lightblue3"; + + //change the color of the channel to indicate whether connection + //is on-tile or off-tile + if (_mapping != null) { + String process1 = _mapping.getPN().getProcess(x.getOrigin(). + getName()).getName(); + String process2 = _mapping.getPN().getProcess(x.getTarget(). + getName()).getName(); + String processor1 = ""; + String processor2 = ""; + + for (ComputationBinding binding : + _mapping.getCompBindList()) { + if (binding.getProcess().getName(). + equals(process1)) { + processor1 = binding.getProcessor().getName(); + } else if (binding.getProcess().getName(). + equals(process2)) { + processor2 = binding.getProcessor().getName(); + } + } + if (processor1.equals(processor2)) { + } else if (processor1.length() >= 6 && processor2.length() >=6 + && processor1.substring(0, 6).equals( + processor2.substring(0, 6))) { + color = "orange"; + } else { + color = "red"; + } + } + + + Iterator i; + Port port, portNext; + i = x.getPortList().iterator(); + + port = (Port) i.next(); + + portNext = (Port) i.next(); + _printStream.printPrefix(); + + _printStream.print("\"" + port.getPeerResource().getName() + + "\" -> " + "\"" + portNext.getPeerResource().getName() + + "\" [" ); + _printStream.print(" label=\"" + x.getName() + "\"" + + ", color=" + color + " ];"); + _printStream.println(); + } + + /** + * + */ + public void setMapping(Mapping mapping) { + _mapping = mapping; + } +} diff --git a/dol/src/dol/visitor/dot/package.html b/dol/src/dol/visitor/dot/package.html new file mode 100644 index 0000000..f219d05 --- /dev/null +++ b/dol/src/dol/visitor/dot/package.html @@ -0,0 +1,21 @@ + + + + + + +Dotty graphical representation generation. +This package will generate a dotty representation for a given example. + +

Package Specification

+ + + +

Related Documentation

+ + + + + + + diff --git a/dol/src/dol/visitor/hds/HdsMakefileVisitor.java b/dol/src/dol/visitor/hds/HdsMakefileVisitor.java new file mode 100644 index 0000000..9256b2a --- /dev/null +++ b/dol/src/dol/visitor/hds/HdsMakefileVisitor.java @@ -0,0 +1,93 @@ +/* $Id: HdsMakefileVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.hds; + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; + +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.Configuration; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate + * a HdS package Makefile. + */ +public class HdsMakefileVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir path of the Makefile + */ + public HdsMakefileVisitor(String dir) { + _dir = dir; + } + + /** + * Create a Makefile for the given process network. + * + * @param x process network that needs to be rendered. + */ + public void visitComponent(ProcessNetwork x) { + try { + String filename = _dir + _delimiter + "Makefile"; + OutputStream file = new FileOutputStream(filename); + PrintStream ps = new PrintStream(file); + + ps.println("CXX = g++"); + ps.println("CC = g++"); + ps.println(); + ps.println("PREPROC_MACROS = -D__DOL_ETHZ_GEN__ " + + " -DINCLUDE_PROFILER #-DINCLUDE_PERFORMANCE" + + " #-DINCLUDE_TRACE"); + ps.println(); + ps.println("SYSTEMC_INC = -I" + _ui.getSystemCINC()); + ps.println("SYSTEMC_LIB = " + _ui.getSystemCLIB()); + ps.println("MY_LIB_INC = -Ilib -Isc_wrappers -Iprocesses"); + ps.println("VPATH = lib:sc_wrappers:processes"); + ps.println(); + ps.println("CXXFLAGS = -g -O0 -Wall $(PREPROC_MACROS) " + + "$(SYSTEMC_INC) $(MY_LIB_INC)"); + ps.println("CFLAGS = $(CXXFLAGS)"); + ps.println(); + + ps.print("PROCESS_OBJS = dolSupport.o ProcessWrapper.o " + + "Fifo.o WindowedFifo.o "); + + for (String basename : x.getProcessBasenames()) { + ps.print(basename + "_wrapper.o "); + } + + for (Configuration conf : x.getCfgList()) { + if (conf.getName().equals("EXTERNAL_SRC")) { + ps.print(conf.getValue() + " "); + } + } + + ps.println("#xmlParser.o Performance_Extraction.o " + + "functional_trace.o"); + ps.println(); + ps.println("all:" + _name); + ps.println(); + ps.println(_name + ": " + _name + ".o $(PROCESS_OBJS)"); + ps.print("\t$(CXX) $(CXXFLAGS) -o $@ $^ $(SYSTEMC_LIB) "); + for (Configuration conf : x.getCfgList()) { + if (conf.getName().equals("DYNAMIC_LINK")) + ps.print(conf.getValue() + " "); + } + ps.println("# -lpthread -lX11 -lrt"); + ps.println("clean:"); + ps.println("\t-rm -f *.o core core.* *.core *.tga " + + "static_characterization.xml " + _name); + + } catch (Exception e) { + System.out.println("HdsMakefileVisitor: exception occured: " + + e.getMessage()); + e.printStackTrace(); + } + } + + protected String _dir = null; + protected String _name = "sc_application"; +} diff --git a/dol/src/dol/visitor/hds/HdsModuleVisitor.java b/dol/src/dol/visitor/hds/HdsModuleVisitor.java new file mode 100644 index 0000000..f00bbe3 --- /dev/null +++ b/dol/src/dol/visitor/hds/HdsModuleVisitor.java @@ -0,0 +1,347 @@ +/* $Id: HdsModuleVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.hds; + +import java.io.FileOutputStream; +import java.io.OutputStream; + +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.Resource; +import dol.util.CodePrintStream; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate + * the main program. + */ +public class HdsModuleVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir path of this file + */ + public HdsModuleVisitor(String dir) { + _dir = dir; + } + + /** + * + * @param x process network that needs to be rendered + */ + public void visitComponent(ProcessNetwork x) { + try { + String filename = _dir + _delimiter + "sc_application.cpp"; + OutputStream file = new FileOutputStream(filename); + _mainPS = new CodePrintStream(file); + + _mainPS.printPrefixln("#include "); + _mainPS.printPrefixln("#include "); + + /* begin of profiling: standard i/o file handling routines */ + _mainPS.printPrefixln("#ifdef INCLUDE_PROFILER"); + _mainPS.printPrefixln("#include "); + _mainPS.printPrefixln("#endif"); + /* end of profiling */ + + _mainPS.printPrefixln("#include \"dol_sched_if.h\""); + _mainPS.println(); + + for (String basename : x.getProcessBasenames()) { + _mainPS.printPrefixln("#include \"" + basename + + "_wrapper.h\""); + } + _mainPS.println(); + _mainPS.printPrefixln("using namespace std;"); + + /* begin of profiling: global variables */ + _mainPS.println(); + _mainPS.printPrefixln("#ifdef INCLUDE_PROFILER"); + _mainPS.printPrefixln("#define PROFILER_OUTPUT_FILENAME \"profile.txt\""); + _mainPS.printPrefixln("FILE *profiler_output_file;"); + _mainPS.printPrefixln("unsigned int profiler_event_counter;"); + _mainPS.printPrefixln("#endif"); + /* end of profiling */ + + _mainPS.println(); + _mainPS.printPrefixln("class sc_application : public sc_module "); + _mainPS.printLeftBracket(); + + _mainPS.printPrefixln("public:"); + _mainPS.printPrefixln("SC_HAS_PROCESS(sc_application);"); + + //declare processes + _mainPS.println(); + for (Process p : x.getProcessList()) { + _mainPS.printPrefixln(p.getBasename() + "_wrapper " + + p.getName() + "_ins"+ ";"); + _mainPS.printPrefixln("sc_event " + p.getName() + + "_event;"); + } + _mainPS.println(); + + //define the scheduler + _mainPS.printPrefixln("sc_event sched_event;"); + _mainPS.printPrefixln("list eventList;"); + _mainPS.printPrefixln("list::iterator iter;"); + _mainPS.println(); + + //declare channels + _mainPS.println(); + for (Channel p : x.getChannelList()) { + if (p.getType().equals("fifo")) { + _mainPS.printPrefixln("Fifo " + p.getName() + "_ins;"); + } else if (p.getType().equals("wfifo")) { + _mainPS.printPrefixln("WindowedFifo " + p.getName() + "_ins;"); + } + } + _mainPS.println(); + + //model constructor + _mainPS.printPrefixln("sc_application(sc_module_name name)"); + + //parameter of constructor + _mainPS.printPrefix(": sc_module(name)"); + for (Process p : x.getProcessList()) { + _mainPS.println(","); + _mainPS.printPrefix(p.getName() + "_ins(\"" + + p.getName() +"\")"); + } + + if (x.getChannelList().size() > 0) { + for (Channel c : x.getChannelList()) { + _mainPS.println(","); + _mainPS.printPrefix(c.getName() + "_ins(" + + "\"" + c.getName() + "\", " + + c.getSize() * c.getTokenSize() + + ")"); + } + } + _mainPS.println(""); + _mainPS.printLeftBracket(); + + //construtor content + //build the network + for (Channel ch : x.getChannelList()) { + ch.accept(this); + } + _mainPS.println(""); + + _mainPS.println(""); + + _mainPS.printPrefixln("SC_THREAD(thread_init);"); + //init thread + _mainPS.printPrefixln("SC_THREAD(thread_sched);"); + + //declare concurrent non-terminating threads + for (Process p : x.getProcessList()) { + _mainPS.printPrefixln("SC_THREAD(thread_" + + p.getName() + ");"); + } + _mainPS.printRightBracket(); + _mainPS.println(); + + //define scheduler thread + _mainPS.printPrefixln("void thread_init()"); + _mainPS.printLeftBracket(); + //init + for (Process p : x.getProcessList()) { + _mainPS.printPrefixln(p.getName() + "_ins.initialize();"); + } + _mainPS.printRightBracket(); + _mainPS.println(); + + + //different scheduling algorithm can be put here + _mainPS.printPrefixln("void thread_sched()"); + _mainPS.printLeftBracket(); + _mainPS.printPrefixln("while (1)"); + _mainPS.printLeftBracket(); + _mainPS.printPrefixln("for (iter=eventList.begin(); iter != " + + "eventList.end(); ++iter)"); + _mainPS.printLeftBracket(); + _mainPS.printPrefixln("sc_event* e = (*iter);"); + _mainPS.printPrefixln("e->notify();"); + _mainPS.printRightBracket(); + _mainPS.printPrefixln("eventList.clear();"); + _mainPS.printPrefixln("wait(sched_event);"); + _mainPS.printRightBracket(); + _mainPS.printRightBracket(); + _mainPS.println(); + + //define threads + for (Process p : x.getProcessList()) { + p.accept(this); + } + + /* begin of profiling: initialization function. */ + /* - opens file */ + /* - writes a list of all channels with the connected ports to the file. */ + _mainPS.printPrefixln("#ifdef INCLUDE_PROFILER"); + _mainPS.printPrefixln("void initialize_profiler()"); + _mainPS.printLeftBracket(); + _mainPS.printPrefixln("if ((profiler_output_file = fopen(PROFILER_OUTPUT_FILENAME,\"w\"))==NULL)"); + _mainPS.printLeftBracket(); + _mainPS.printPrefixln("printf(\"Unable to open profiler output file. No profiling output is written.\\n\");"); + _mainPS.printPrefixln("return;"); + _mainPS.printRightBracket(); + //_mainPS.printPrefixln("printf(\"Profiling data is written to %s.\\n\", PROFILER_OUTPUT_FILENAME);"); + _mainPS.println(); + + for (Channel ch : x.getChannelList()) { + String outputString = "fprintf(profiler_output_file, \"c " + ch.getName() + " " + ch.getSize(); + String outputStringAppendix = ""; + for (Port p : ch.getPortList()) { + Port peerPort = (Port)(p.getPeerPort()); + Resource peerResource = p.getPeerResource(); + + if (p.isOutPort()) { + // channel.out == process.in + outputString += " i " + peerResource.getName() + " %pI"; + outputStringAppendix += ",(" + peerResource.getName() + + "_ins.INPORT_" + + peerPort.getBasename() + + peerPort.getName().replaceAll( + "_([0-9]+)", "[$1]").replaceFirst( + peerPort.getBasename(), "") + ")"; + } else { + outputString += " o " + peerResource.getName() + " %pO"; + outputStringAppendix += ",(" + peerResource.getName() + + "_ins.OUTPORT_" + + peerPort.getBasename() + + peerPort.getName().replaceAll( + "_([0-9]+)", "[$1]").replaceFirst( + peerPort.getBasename(), "") + ")"; + } + } + outputString += "\\n\"" + outputStringAppendix + ");"; + _mainPS.printPrefixln(outputString); + } + _mainPS.printRightBracket(); + _mainPS.printPrefixln("#endif"); + _mainPS.println(); + /* end of profiling */ + + _mainPS.printRightBracket(); // end of class + _mainPS.println(";"); + + //create and run the simulator + _mainPS.printPrefixln("int sc_main (int argc, char *argv[])"); + _mainPS.printLeftBracket(); + _mainPS.printPrefixln("sc_report_handler::set_actions(\"" + + "/IEEE_Std_1666/deprecated\", SC_DO_NOTHING);"); + _mainPS.printPrefixln("sc_report::register_id(" + + "5000, " + + "\"parameter problem\" );"); + + //create an instance of the application model + //remove potential whitespaces before using the process + //network name as a systemc identifier + _mainPS.printPrefixln("sc_application my_app_mdl(\"" + + x.getName().replaceAll(" ", "") + "\");"); + + /* begin of profiling: initialize the profiler */ + _mainPS.printPrefixln("#ifdef INCLUDE_PROFILER"); + _mainPS.printPrefixln("my_app_mdl.initialize_profiler();"); + _mainPS.printPrefixln("#endif"); + /* end of profiling */ + + _mainPS.printPrefixln("sc_start(-1,SC_NS);"); + /* begin of profiling: close the output file */ + _mainPS.printPrefixln("#ifdef INCLUDE_PROFILER"); + _mainPS.printPrefixln("if (profiler_output_file != NULL) fclose(profiler_output_file);"); + _mainPS.printPrefixln("#endif"); + /* end of profiling */ + + _mainPS.printPrefixln("return 0;"); + + _mainPS.printRightBracket(); + + } + catch (Exception e) { + System.out.println("HdsModuleVisitor: exception occured: " + + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * Print a line for the process in the correct format for DOTTY. + * + * @param x process that needs to be rendered + */ + public void visitComponent(Process x) { + _mainPS.printPrefixln("void thread_" + x.getName() + "()"); + _mainPS.printLeftBracket(); + _mainPS.printPrefixln("while (!" + x.getName() + + "_ins.isDetached())"); + _mainPS.printLeftBracket(); + + /* begin of profiling: start event */ + _mainPS.printPrefixln("#ifdef INCLUDE_PROFILER"); + _mainPS.printPrefixln("if (profiler_output_file != NULL) fprintf(profiler_output_file, \"%u "+ x.getName() + " started.\\n\", profiler_event_counter++);"); + _mainPS.printPrefixln("#endif"); + /* end of profiling */ + + _mainPS.printPrefixln(x.getName() + "_ins.fire();"); + + /* begin of profiling: stop event */ + _mainPS.printPrefixln("#ifdef INCLUDE_PROFILER"); + _mainPS.printPrefixln("if (profiler_output_file != NULL) fprintf(profiler_output_file, \"%u "+ x.getName() + " stopped.\\n\", profiler_event_counter++);"); + _mainPS.printPrefixln("#endif"); + /* end of profiling */ + + _mainPS.printPrefixln("eventList.push_back(&" + x.getName() + + "_event);"); + _mainPS.printPrefixln("sched_event.notify();"); + _mainPS.printPrefixln("wait(" + x.getName() + "_event);"); + + _mainPS.printRightBracket(); + _mainPS.printRightBracket(); + } + + /** + * + * @param x channel that needs to be rendered + */ + public void visitComponent(Channel x) { + for (Port p : x.getPortList()) { + Port peerPort = (Port)(p.getPeerPort()); + Resource peerResource = p.getPeerResource(); + if (peerPort.getRange() != null) { + if (p.isOutPort()) { + _mainPS.printPrefix(peerResource.getName() + + "_ins.INPORT_" + + peerPort.getBasename() + + peerPort.getName().replaceAll( + "_([0-9]+)", "[$1]").replaceFirst( + peerPort.getBasename(), "")); + } + else if (p.isInPort()) { + _mainPS.printPrefix(peerResource.getName() + + "_ins.OUTPORT_" + + peerPort.getBasename() + + peerPort.getName().replaceAll( + "_([0-9]+)", "[$1]").replaceFirst( + peerPort.getBasename(), "")); + } + } + else { + if (p.isOutPort()) { + _mainPS.printPrefix(peerResource.getName() + + "_ins.INPORT_" + peerPort.getName()); + } + else if (p.isInPort()) { + _mainPS.printPrefix(peerResource.getName() + + "_ins.OUTPORT_" + peerPort.getName()); + } + } + _mainPS.println(" = &" + x.getName() + "_ins;"); + } + } + + protected CodePrintStream _mainPS = null; + protected String _dir = null; +} diff --git a/dol/src/dol/visitor/hds/HdsProcessVisitor.java b/dol/src/dol/visitor/hds/HdsProcessVisitor.java new file mode 100644 index 0000000..3912408 --- /dev/null +++ b/dol/src/dol/visitor/hds/HdsProcessVisitor.java @@ -0,0 +1,232 @@ +/* $Id: HdsProcessVisitor.java 1 2010-02-24 13:03:05Z haidw $$ */ +package dol.visitor.hds; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Vector; + +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.SourceCode; +import dol.util.CodePrintStream; +import dol.util.Sed; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate + * a wrapper class for a process: process_wrapper.[h/cpp]. + */ +public class HdsProcessVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir target directory + */ + public HdsProcessVisitor(String dir) { + _dir = dir; + } + + /** + * + * @param x process network that needs to be rendered + */ + public void visitComponent(ProcessNetwork x) { + try { + Vector pList = new Vector(); + + for (Process p : x.getProcessList()) { + String basename = p.getBasename(); + if (!pList.contains(basename)) { + pList.add(basename); + p.accept(this); + } + } + } + catch (Exception e) { + System.out.println("Process Visitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * + * @param p process that needs to be rendered + */ + public void visitComponent(Process p) { + try { + _createCppFile(p); + _createHeaderFile(p); + _adaptSources(p); + } + catch (Exception e) { + System.out.println("Process Visitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * + */ + protected void _adaptSources(Process p) throws IOException { + Sed sed = new Sed(); + for (Port port : p.getPortList()) { + String processHeaderFile; + + for (SourceCode sr : p.getSrcList()) { + processHeaderFile = _dir + _delimiter + ".." + + _delimiter + "processes" + _delimiter + + sr.getLocality(). + replaceAll("(.*)\\.[cC][pP]*[pP]*", "$1\\.h"); + + if (port.isOutPort()) { + sed.sed(processHeaderFile, + "(#define[ ]+PORT_\\w*[ ]+)\"?" + + port.getBasename() + "\"?", + "$1 " + "((static_cast<" + p.getBasename() + + "_wrapper *>(p->wptr))->OUTPORT_" + + port.getBasename() + ")"); + + } + else if (port.isInPort()) { + sed.sed(processHeaderFile, + "(#define[ ]+PORT_\\w*[ ]+)\"?" + + port.getBasename() + "\"?", + "$1 " + "((static_cast<" + p.getBasename() + + "_wrapper *>(p->wptr))->INPORT_" + + port.getBasename() + ")"); + } + } + } + } + + /** + * + */ + protected void _createCppFile(Process p) throws IOException { + String filename = _dir + _delimiter + p.getBasename() + + "_wrapper.cpp"; + OutputStream file = new FileOutputStream(filename); + CodePrintStream ps = new CodePrintStream(file); + + String newline = System.getProperty("line.separator"); + String code = "#include \"" + p.getBasename() + "_wrapper.h\"" + + newline; + for (SourceCode sr : p.getSrcList()) { + code += "#include \"" + sr.getLocality() + "\"" + newline; + } + /* + for (SourceCode sr : p.getSrcList()) { + code += "#include \"" + sr.getLocality().substring(0, + sr.getLocality().lastIndexOf(".") + 1) + "h\"" + + newline; + } + */ + + code += newline; + + code += p.getBasename() + "_wrapper::" + + p.getBasename() + "_wrapper(char* name)" + + newline; + code += " : ProcessWrapper(name) {" + newline; + code += " _state = (LocalState)new " + + p.getBasename().substring(0, 1).toUpperCase() + + p.getBasename().substring(1) + "_State;" + + newline; + code += " _process.local = _state;" + newline; + code += " _process.init = " + p.getBasename() + "_init;" + + newline; + code += " _process.fire = " + p.getBasename() + "_fire;" + + newline; + code += " _process.wptr = this;" + newline; + code += "}" + newline + newline; + + code += p.getBasename() + "_wrapper::~" + p.getBasename() + + "_wrapper() {" + newline; + code += " if (_state)" + newline; + code += " delete (" + + p.getBasename().substring(0, 1).toUpperCase() + + p.getBasename().substring(1) + "_State*)_state;" + + newline; + code += "}" + newline; + ps.printPrefixln(code); + } + + protected void _createHeaderFile(Process p) + throws IOException { + String filename = _dir + _delimiter + p.getBasename() + + "_wrapper.h"; + OutputStream file = new FileOutputStream(filename); + CodePrintStream ps = new CodePrintStream(file); + + String newline = System.getProperty("line.separator"); + String code = "#ifndef " + p.getBasename() + "_WRAPPER_H" + + newline; + code += "#define " + p.getBasename() + "_WRAPPER_H" + newline + + newline; + code += "#include \"ProcessWrapper.h\"" + newline; + code += "#include \"dolSupport.h\"" + newline; + code += newline; + + code += "class " + p.getBasename() + "_wrapper : " + + "public ProcessWrapper {" + newline; + code += " public:" + newline; + code += " " + p.getBasename() + + "_wrapper(char* name);" + newline; + code += " virtual ~" + p.getBasename() + "_wrapper();" + + newline; + + Vector portList = new Vector(); + for (Port port : p.getPortList()) { + String basename = port.getBasename(); + + if (!portList.contains(basename)) { + portList.add(basename); + + if (((Channel)port.getPeerResource()).getType(). + equals("wfifo")) { + code += " WindowedFifo *"; + } else { + code += " Fifo *"; + } + if (!port.getRange().equals("")) { + if (port.isOutPort()) { + code += "OUTPORT_" + + port.getBasename() + "[" + + port.getRange().replaceAll( + ";", "\\]\\[") + "];" + newline; + } + else if (port.isInPort()) { + code += "INPORT_" + + port.getBasename() + "[" + + port.getRange().replaceAll( + ";", "\\]\\[") + "];" + newline; + } + } + else { + if (port.isOutPort()) { + code += "OUTPORT_" + + port.getName() + ";" + newline; + } + else if (port.isInPort()) { + code += "INPORT_" + + port.getName() + ";" + newline; + } + } + } + } + + code += " protected:" + newline; + code += " LocalState _state;" + newline; + code += "};" + newline + newline; + code += "#endif"; + ps.printPrefixln(code); + } + + protected String _dir = null; +} diff --git a/dol/src/dol/visitor/hds/HdsVisitor.java b/dol/src/dol/visitor/hds/HdsVisitor.java new file mode 100644 index 0000000..bb8d47a --- /dev/null +++ b/dol/src/dol/visitor/hds/HdsVisitor.java @@ -0,0 +1,100 @@ +/* $Id: HdsVisitor.java 1 2010-02-24 13:03:05Z haidw $$ */ +package dol.visitor.hds; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; + +import dol.datamodel.pn.ProcessNetwork; +import dol.util.CodePrintStream; +import dol.util.Copier; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate + * a HdS package. + */ +public class HdsVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param packageName name of the HdS directory + */ + public HdsVisitor(String packageName) { + _packageName = packageName; + } + + /** + * + * @param x process network that needs to be rendered. + */ + public void visitComponent(ProcessNetwork x) { + try { + _generateDirHierarchy(); + + x.accept(new HdsMakefileVisitor(_srcDir)); + x.accept(new HdsModuleVisitor(_srcDir)); + x.accept(new HdsProcessVisitor(_wrapperDir)); + } + catch (Exception e) { + System.out.println("HdSVisitor: exception occured: " + + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * + */ + protected void _generateDirHierarchy() + throws IOException, FileNotFoundException { + File dir = new File(_packageName); + dir.mkdirs(); + + _srcDir = _packageName + _delimiter + _srcDirName; + dir = new File(_srcDir); + dir.mkdirs(); + + _libDir = _srcDir + _delimiter + _libDirName; + dir = new File(_libDir); + dir.mkdirs(); + + _processDir = _srcDir + _delimiter + _processDirName; + dir = new File(_processDir); + dir.mkdirs(); + + _wrapperDir = _srcDir + _delimiter + _wrapperDirName; + dir = new File(_wrapperDir); + dir.mkdirs(); + + //copy library files + File source = new File(_ui.getMySystemCLib(). + replaceAll("systemC", "hds")); + File destination = new File(_libDir); + new Copier().copy(source, destination); + + //copy process source code + source = new File(_srcDirName); + destination = new File(_processDir); + new Copier().copy(source, destination); + } + + protected String _packageName = null; + + protected String _srcDir = ""; + protected static String _srcDirName = "src"; + + protected String _libDir = ""; + protected static String _libDirName = "lib"; + + protected String _processDir = ""; + protected static String _processDirName = "processes"; + + protected String _wrapperDir = ""; + protected static String _wrapperDirName = "sc_wrappers"; + + protected String _threadPostfix = "_thread"; + + protected CodePrintStream _mainPS = null; +} diff --git a/dol/src/dol/visitor/hds/lib/Fifo.cpp b/dol/src/dol/visitor/hds/lib/Fifo.cpp new file mode 100644 index 0000000..4c66c4c --- /dev/null +++ b/dol/src/dol/visitor/hds/lib/Fifo.cpp @@ -0,0 +1,254 @@ +#include "Fifo.h" + +/** + * + */ +Fifo::Fifo(char* name, unsigned size = 18) { + //std::cout << "Create Fifo." << std::endl; + //except at the beginning, _head and _tail must never overlap, + //otherwise one does not know whether the buffer is full or + //empty. to have nevertheless a buffer with the given capacity, + //a buffer with one more element is allocated. + _size = size; + _buffer = new char[_size]; + //_head = 0; + _use = 0; + _tail = 0; + _name = new char[strlen(name) + 1]; + strcpy(_name, name); +} + +/** + * + */ +Fifo::~Fifo() { + //std::cout << "Delete Fifo." << std::endl; + if (_buffer) { + delete _buffer; + } + if (_name) { + delete _name; + } + _buffer = 0; + //_head = 0; + _use = 0; + _tail = 0; + _name = 0; + //std::cout << "Deleted Fifo." << std::endl; +} + +/** + * + */ +unsigned Fifo::read(void *destination, unsigned len) { + char* buffer = (char*)destination; + unsigned read = 0; + //std::cout << "Try to read " << len << " bytes from Fifo " << _name << "." << std::endl; + + + while (read < len) { + while( _use < len) + wait(_writeEvent); + unsigned tocopy = (len - read <= _use ? len - read : _use); + + if ((unsigned)_tail + tocopy < _size) { + memcpy(buffer, _buffer + (unsigned)_tail, tocopy); + } + else { + memcpy(buffer, _buffer + (unsigned)_tail, _size - (unsigned)_tail); + memcpy(buffer + _size - (unsigned)_tail, _buffer, tocopy - _size + (unsigned)_tail); + } + + read += tocopy; + buffer += tocopy; + _tail = (_tail + tocopy) % _size; + _use -= read; + _readEvent.notify(); + } + + /*while (read < len) { + if (used() == 0) { + wait(_writeEvent); + } else if ((len - read) < used()) { + while (read < len) { + unsigned tocopy = (len - read + _tail >= _size) ? _size - _tail : len - read; + memcpy(buffer, _buffer + _tail, tocopy); + _tail = (_tail + tocopy) % _size; + read += tocopy; + buffer += tocopy; + } + _readEvent.notify(); + } else { + *buffer++ = *(_buffer + _tail % _size); + _tail = (_tail + 1) % _size; + read++; + _readEvent.notify(); + } + }*/ + + //std::cout << "Read " << read << " bytes from Fifo " << _name << "." << std::endl; + return read; +} + +/** + * + */ +unsigned Fifo::write(const void *source, unsigned len) { + char* buffer = (char*)source; + unsigned write = 0; + unsigned head = (_tail + _use) % _size; + //std::cout << "Try to write " << len << " bytes to Fifo " << _name << std::endl; + + while (write < len) { + while (unused() < len) + wait(_readEvent); + unsigned tocopy = (len - write <= unused() ? len - write : unused()); + + if (head + tocopy < _size) { + memcpy(_buffer + head, buffer, tocopy); + } + else { + memcpy(_buffer + head, buffer, _size - head); + memcpy(_buffer, buffer + _size - head, tocopy - _size + head); + } + + write += tocopy; + buffer += tocopy; + head = (head + tocopy) % _size; + _use += write; + _writeEvent.notify(); + } + + /* while (write < len) { + if (unused() == 0) { + wait(_readEvent); + } else if ((len - write) < unused()) { + while (write < len) { + unsigned tocopy = (len - write + _head >= _size) ? _size - _head : len - write; + memcpy(_buffer + _head, buffer, tocopy); + _head = (_head + tocopy) % _size; + write += tocopy; + buffer += tocopy; + } + _writeEvent.notify(); + } else { + *(_buffer + (unsigned)(_head) % _size) = *buffer++; + _head = (_head + 1) % _size; + write++; + _writeEvent.notify(); + } + }*/ + + //std::cout << "Wrote " << write << " bytes to Fifo " << _name << "." << std::endl; + return write; +} + +/** + * + */ +unsigned Fifo::size() const { + return (_size); +} + +/** + * + */ +unsigned Fifo::unused() const { + return (_size) - _use; +} + +/** + * + */ +unsigned Fifo::used() const { + return _use; +} + +/** + * + */ +char* Fifo::getName() const { + return _name; +} + +/** + * Test the implementation + */ +/* +class producer : public sc_module +{ + public: + Fifo *fifo; + + SC_HAS_PROCESS(producer); + + producer(sc_module_name name) : sc_module(name) + { + SC_THREAD(main); + } + + void main() + { + const char *str = + "Visit www.systemc.org and see what SystemC can do for you today!\n"; + + while (*str) { + fifo->write((void*)str++, 4); + } + } +}; + +class consumer : public sc_module +{ + public: + Fifo *fifo; + + SC_HAS_PROCESS(consumer); + + consumer(sc_module_name name) : sc_module(name) + { + SC_THREAD(main); + } + + void main() + { + char c; + cout << endl << endl; + + while (true) { + fifo->read(&c, 4); + cout << c << flush; + + if (fifo->used() == 1) + cout << "<1>" << flush; + if (fifo->used() == 9) + cout << "<9>" << flush; + } + } +}; + +class top : public sc_module +{ + public: + Fifo *fifo_inst; + producer *prod_inst; + consumer *cons_inst; + + top(sc_module_name name) : sc_module(name) + { + fifo_inst = new Fifo("myfifo", 10); + + prod_inst = new producer("producer"); + prod_inst->fifo = fifo_inst; + + cons_inst = new consumer("consumer"); + cons_inst->fifo = fifo_inst; + } +}; + +int sc_main (int argc , char *argv[]) { + top top1("top"); + sc_start(); + return 0; +} +*/ diff --git a/dol/src/dol/visitor/hds/lib/Fifo.h b/dol/src/dol/visitor/hds/lib/Fifo.h new file mode 100644 index 0000000..e694612 --- /dev/null +++ b/dol/src/dol/visitor/hds/lib/Fifo.h @@ -0,0 +1,29 @@ +#ifndef _FIFO_H_ +#define _FIFO_H_ + +#include "systemc.h" + +class Fifo { + public: + Fifo(char* name, unsigned size); + virtual ~Fifo(); + + virtual unsigned read(void *destination, unsigned len); + virtual unsigned write(const void *source, unsigned len); + virtual unsigned used() const; + virtual unsigned unused() const; + virtual unsigned size() const; + virtual char* getName() const; + + protected: + char *_buffer; + //unsigned _head; + unsigned _tail; + unsigned _size; + unsigned _use; + char *_name; + sc_event _readEvent; + sc_event _writeEvent; +}; + +#endif diff --git a/dol/src/dol/visitor/hds/lib/Performance_Extraction.cpp b/dol/src/dol/visitor/hds/lib/Performance_Extraction.cpp new file mode 100644 index 0000000..9322648 --- /dev/null +++ b/dol/src/dol/visitor/hds/lib/Performance_Extraction.cpp @@ -0,0 +1,447 @@ +#include "Performance_Extraction.h" +#include +#include + + +Performance_Extraction performance_extraction("static_characterization.xml"); + +/** + * + */ +int get_current_time(CURRENT_TIME *current_time_ptr) +{ + return clock_gettime(CLOCK_REALTIME, &(current_time_ptr->ts)); +} + + +/** + * + */ +double sub_time(CURRENT_TIME *start_time_ptr, CURRENT_TIME *end_time_ptr) +{ + CURRENT_TIME diff_time; + double time_ns; + + diff_time.ts.tv_sec = end_time_ptr->ts.tv_sec - start_time_ptr->ts.tv_sec; + diff_time.ts.tv_nsec = end_time_ptr->ts.tv_nsec - start_time_ptr->ts.tv_nsec; + time_ns = diff_time.ts.tv_sec * 1E+9 + diff_time.ts.tv_nsec; + + return time_ns; +} + + +/** + * + */ +Process_Performance::Process_Performance(const char *name) +{ + strcpy(_process_name, name); + _head = NULL; + _tail = NULL; +} + + +/** + * + */ +Process_Performance::~Process_Performance() +{ + COMP_ENTRY *temp; + DBGPRINT; + while (_head != NULL) { + temp = _head; + _head = _head->next; + delete temp; + } +} + + +/** + * + */ +const char *Process_Performance::get_name() +{ + return _process_name; +} + + +/** + * + */ +COMP_ENTRY *Process_Performance::get_head_entry() +{ + return _head; +} + + +/** + * + */ +COMP_ENTRY *Process_Performance::get_entry(int start_line, int end_line) +{ + COMP_ENTRY *temp = NULL; + temp = _head; + while (temp != NULL) { + if ((temp->start_line == start_line) && (temp->end_line == end_line)) { + break; + } + temp = temp->next; + } + + return temp; +} + + +/** + * + */ +COMP_ENTRY *Process_Performance::add_entry(int start_line, int end_line) +{ + COMP_ENTRY *temp = NULL; + temp = get_entry(start_line, end_line); + if (temp == NULL) { + temp = new COMP_ENTRY; + + if (_head == NULL) { + _head = temp; + _tail = temp; + temp->next = NULL; + } else { + _tail->next = temp; + _tail = temp; + temp->next = NULL; + } + temp->start_line = start_line; + temp->end_line = end_line; + temp->total_computation_time = 0; + temp->called_times = 0; + } + + return temp; +} + + +/** + * + */ +int Process_Performance::set_entry(int start_line, int end_line, + CURRENT_TIME *start_time_ptr, + CURRENT_TIME *end_time_ptr) +{ + int ret = 0; + COMP_ENTRY *temp; + double computation_time; + computation_time = sub_time(start_time_ptr, end_time_ptr); + temp = get_entry(start_line, end_line); + if (temp == NULL) { + temp = add_entry(start_line, end_line); + } + + temp->total_computation_time += computation_time; + temp->called_times++; + + return ret; +} + + +/** + * + */ +Performance_Extraction::Performance_Extraction(const char *chr_file_name) +{ + strcpy(_chr_file_name, chr_file_name); +} + + +/** + * + */ +Performance_Extraction::~Performance_Extraction() +{ + Process_Performance *process_performance_ptr; + +#ifdef INCLUDE_PERFORMANCE + //strcpy(_processor_type, "DSP"); + //add_to_xml_file(_chr_file_name); + //strcpy(_processor_type, "RISC"); + //add_to_xml_file(_chr_file_name); + + write_to_xml_file(_chr_file_name); +#endif + + for (_iter_process_performance = _list_process_performance.begin(); + _iter_process_performance != _list_process_performance.end(); + _iter_process_performance++) + { + process_performance_ptr = *_iter_process_performance; + delete process_performance_ptr; + } + _list_process_performance.clear(); + +} + + +/** + * + */ +int Performance_Extraction::add_computation_performance( + const char *process_name, int start_line, int end_line, + CURRENT_TIME *start_time_ptr, CURRENT_TIME *end_time_ptr) +{ + int ret = 0; + Process_Performance *process_performance_ptr; + + process_performance_ptr = get_process_performance(process_name); + if (process_performance_ptr == NULL) { + process_performance_ptr = new Process_Performance(process_name); + _list_process_performance.push_back(process_performance_ptr); + } + + process_performance_ptr->set_entry(start_line, end_line, + start_time_ptr, end_time_ptr); + + return ret; +} + + +/** + * + */ +Process_Performance *Performance_Extraction::get_process_performance( + const char *process_name) +{ + Process_Performance *process_performance_ptr = NULL; + + for (_iter_process_performance = _list_process_performance.begin(); + _iter_process_performance != _list_process_performance.end(); + _iter_process_performance++) { + process_performance_ptr = *_iter_process_performance; + if (strcmp(process_performance_ptr->get_name(), process_name) == 0) { + break; + } + } + + if (_iter_process_performance == _list_process_performance.end()) { + process_performance_ptr = NULL; + } + + return process_performance_ptr; +} + + +/** + * write performance data into XML file. (identical to add_to_xml_file() + * if file does not exist). + */ +int Performance_Extraction::write_to_xml_file(const char *chr_file_name) +{ + char start_line_str[NAME_LENGTH]; + char end_line_str[NAME_LENGTH]; + char computation_time_str[NAME_LENGTH]; + double computation_time; + Process_Performance *process_performance_ptr; + COMP_ENTRY *comp_entry; + + //create xml + string text = "\n\n"; + for (_iter_process_performance = _list_process_performance.begin(); + _iter_process_performance != _list_process_performance.end(); + _iter_process_performance++) { + process_performance_ptr = *_iter_process_performance; + + text += " get_name(); + text += "\">\n"; + + for (comp_entry = process_performance_ptr->get_head_entry(); + comp_entry != NULL; + comp_entry = comp_entry->next) { + sprintf(start_line_str, "%d", comp_entry->start_line); + sprintf(end_line_str, "%d", comp_entry->end_line); + + //hack to eliminate the overhead of system call clock_gettime. + //computation_time is nano sec. To get cycles, need to mutiply + //by the frequency of cpu. result is in cycles. + computation_time = (comp_entry->total_computation_time + / comp_entry->called_times - SYS_OVERHEAD) + * HOST_FREQUENCY; + if (computation_time < 0) { + computation_time = 0; + } + sprintf(computation_time_str, "%.0f", computation_time); + + text += " \n"; + text += " \n"; + text += " \n"; + text += " \n"; + } + text += " \n"; + } + text += " \n"; + text += " \n"; + text += " \n"; + text += " \n"; + text += " \n"; + text += " \n"; + text += " \n"; + text += " \n"; + text += "\n"; + + //write xml to file + std::ofstream out(chr_file_name, ios::out); + if (!out) { + printf("Cannot open file %s. Return.\n", chr_file_name); + return -1; + } + out.write(text.c_str(), text.size()); + out.close(); + return 0; +} + + +/** + * add performance data to existing XML file (or create new one if file + * does not exist). + */ +int Performance_Extraction::add_to_xml_file(const char *chr_file_name) +{ + int ret = 0; + XMLNode file_node; + XMLNode root_node; + XMLNode process_node; + XMLNode comp_node; + int computation_index = 0; + XMLNode processor_node; + XMLNode read_node; + XMLNode write_node; + + Process_Performance *process_performance_ptr; + COMP_ENTRY *comp_entry; + + char start_line_str[NAME_LENGTH]; + char end_line_str[NAME_LENGTH]; + char computation_time_str[NAME_LENGTH]; + double computation_time; + + file_node = XMLNode::parseFile(chr_file_name); + if (file_node.isEmpty()) { + file_node = XMLNode::createXMLTopNode("xml", TRUE); + file_node.addAttribute("version", "1.0"); + root_node = file_node.addChild("characterization"); + } + + root_node = file_node.getChildNode(); + if (root_node.isEmpty()) { + ret = -1; + printf("Open characterization file error\n"); + return ret; + } + + for (_iter_process_performance = _list_process_performance.begin(); + _iter_process_performance != _list_process_performance.end(); + _iter_process_performance++) { + process_performance_ptr = *_iter_process_performance; + + printf("%s\n", process_performance_ptr->get_name()); + + process_node = root_node.getChildNodeWithAttribute( + "process", "name", process_performance_ptr->get_name()); + if (process_node.isEmpty()) + { + process_node = root_node.addChild("process"); + process_node.addAttribute( + "name",process_performance_ptr->get_name()); + } + + for (comp_entry = process_performance_ptr->get_head_entry(); + comp_entry != NULL; + comp_entry = comp_entry->next) { + sprintf(start_line_str, "%d", comp_entry->start_line); + sprintf(end_line_str, "%d", comp_entry->end_line); + + printf("%d %d\n", comp_entry->start_line, comp_entry->end_line); + + /* Hack to eliminate the overhead of system call clock_gettime. + computation_time is nano sec. To get cycles, need to mutiply + by the frequency of cpu. + result is cycles */ + computation_time = (comp_entry->total_computation_time + / comp_entry->called_times - SYS_OVERHEAD) + * HOST_FREQUENCY; + + if (computation_time < 0) { + computation_time = 0; + } + + sprintf(computation_time_str, "%.0f", computation_time); + computation_index = 0; + comp_node = process_node.getChildNode("computation", + computation_index++); + while (!comp_node.isEmpty()) { + if (strcmp(comp_node.getAttribute("start"),start_line_str)==0 + && strcmp(comp_node.getAttribute("end"),end_line_str)==0) { + break; + } + + comp_node = process_node.getChildNode("computation", + computation_index++); + } + + if (comp_node.isEmpty()) { + comp_node = process_node.addChild("computation"); + comp_node.addAttribute("start", start_line_str); + comp_node.addAttribute("end", end_line_str); + } + + processor_node = comp_node.getChildNodeWithAttribute("processor", "type", _processor_type); + if (processor_node.isEmpty()) { + processor_node = comp_node.addChild("processor"); + processor_node.addAttribute("type", _processor_type); + processor_node.addAttribute("time", computation_time_str); + } + } + } + + read_node = root_node.getChildNodeWithAttribute("communication", + "name", "read"); + if (read_node.isEmpty()) { + read_node = root_node.addChild("communication"); + read_node.addAttribute("name", "read"); + } + + processor_node = read_node.getChildNodeWithAttribute("processor", + "type", + _processor_type); + if (processor_node.isEmpty()) { + processor_node = read_node.addChild("processor"); + processor_node.addAttribute("type", _processor_type); + processor_node.addAttribute("time", "2"); + } + + write_node = root_node.getChildNodeWithAttribute("communication", + "name", "write"); + if (write_node.isEmpty()) { + write_node = root_node.addChild("communication"); + write_node.addAttribute("name", "write"); + } + + processor_node = write_node.getChildNodeWithAttribute("processor", + "type", + _processor_type); + if (processor_node.isEmpty()) { + processor_node = write_node.addChild("processor"); + processor_node.addAttribute("type", _processor_type); + processor_node.addAttribute("time", "2"); + } + + file_node.writeToFile(chr_file_name); + return 0; +} diff --git a/dol/src/dol/visitor/hds/lib/Performance_Extraction.h b/dol/src/dol/visitor/hds/lib/Performance_Extraction.h new file mode 100644 index 0000000..f122696 --- /dev/null +++ b/dol/src/dol/visitor/hds/lib/Performance_Extraction.h @@ -0,0 +1,67 @@ +#ifndef _PERFORMANCE_EXTRACTION_H +#define _PERFORMANCE_EXTRACTION_H + +#include +#include +#include "trace.h" + +#define SYS_OVERHEAD 1400 //what should be exact vale +#define HOST_FREQUENCY 3 //Ghz + +typedef struct COMP_ENTRY { + int start_line; + int end_line; + double total_computation_time; + int called_times; + COMP_ENTRY *next; +} COMP_ENTRY; + +typedef struct CURRENT_TIME { + struct timespec ts; +}CURRENT_TIME; + +extern int get_current_time(CURRENT_TIME *current_time_ptr); +extern double sub_time(CURRENT_TIME *start_time_ptr, CURRENT_TIME *end_time_ptr); + +class Process_Performance +{ +private: + char _process_name[NAME_LENGTH]; + COMP_ENTRY *_head; + COMP_ENTRY *_tail; + +public: + Process_Performance(const char *process_name); + ~Process_Performance(); + + const char *get_name(); + COMP_ENTRY * add_entry(int start_line, int end_line); + int set_entry(int start_line, int end_line, CURRENT_TIME *start_time_ptr, + CURRENT_TIME *end_time_ptr); + COMP_ENTRY *get_entry(int start_line, int end_line); + COMP_ENTRY *get_head_entry(); +}; + +class Performance_Extraction +{ +private: + char _processor_type[NAME_LENGTH]; + char _chr_file_name[NAME_LENGTH]; + list _list_process_performance; + list::iterator _iter_process_performance; + +public: + Performance_Extraction(const char *chr_file_name); + ~Performance_Extraction(); + + int add_computation_performance(const char *process_name, int start_line, + int end_line, CURRENT_TIME *start_time_ptr, + CURRENT_TIME *end_time_ptr); + Process_Performance *get_process_performance(const char *process_name); + int write_to_xml_file(const char *chr_file_name); + int add_to_xml_file(const char *chr_file_name); +}; + +extern Performance_Extraction performance_extraction; + +#endif diff --git a/dol/src/dol/visitor/hds/lib/ProcessWrapper.cpp b/dol/src/dol/visitor/hds/lib/ProcessWrapper.cpp new file mode 100644 index 0000000..89f413a --- /dev/null +++ b/dol/src/dol/visitor/hds/lib/ProcessWrapper.cpp @@ -0,0 +1,157 @@ +#include "ProcessWrapper.h" +#include "dolSupport.h" + +/** + * + */ +ProcessWrapper::ProcessWrapper( + sc_module_name name = sc_gen_unique_name("process")) + : sc_module(name) { + + _name = new char[strlen(name) + 1]; + strcpy(_name, name); + + _isDetached = false; + for (int i = 0; i < 4; i++) { + _iteratorIndex[i] = getIndex(_name, "_", i); + } +} + +/** + * + */ +ProcessWrapper::~ProcessWrapper() { + if (_name) { + delete _name; + } +} + +/** + * + */ +void ProcessWrapper::initialize() { + _process.init(&_process); +} + +/** + * + */ +int ProcessWrapper::fire() +{ + int returnValue; + + #ifdef INCLUDE_TRACE + start_line = -1; + #endif + + #ifdef INCLUDE_PERFORMANCE + start_line = -1; + get_current_time(&start_time); + #endif + + returnValue = _process.fire(&_process); + + #ifdef INCLUDE_TRACE + end_line = -1; + dol_functional_trace.create_computation_event(basename(), + start_line, end_line); + #endif + + #ifdef INCLUDE_PERFORMANCE + get_current_time(&end_time); + end_line = -1; + performance_extraction.add_computation_performance(basename(), + start_line, end_line, &start_time, &end_time); + #endif + + return returnValue; +} + + +/** + * + */ +void ProcessWrapper::detach() { + _isDetached = true; +} + + +/** + * Gets an index of a string, where the index must be separated by + * a character specified in tokens. + * Returns -1, when an error occurs. + * + * Example: + * getIndex("name_1_2", "_", 0) will return 1. + * getIndex("name_1_2", "_", 1) will return 2. + * + * @param string string to parse + * @param tokens delimiter of indices + * @param indexNumber position of index (starting at 0) + */ +int ProcessWrapper::getIndex(const char* string, char* tokens, + int indexNumber) const { + char* string_copy; + char* token_pointer; + int index = 0; + + string_copy = (char*) malloc(sizeof(char) * (strlen(string) + 1)); + if (!string_copy) { + fprintf(stderr, "getIndex(): could not allocate memory.\n"); + return -1; + } + + strcpy(string_copy, string); + + token_pointer = strtok(string_copy, tokens); + do { + token_pointer = strtok(NULL, tokens); + index++; + } while (index <= indexNumber && token_pointer != 0); + + if (token_pointer) { + index = atoi(token_pointer); + free(string_copy); + return index; + } + + return -1; +} + + +/** + * Get the index of this process. + * @param indexNumber position of index (starting at 0) + */ +int ProcessWrapper::getIndex(unsigned indexNumber) const { + if (indexNumber < 4) { + return _iteratorIndex[indexNumber]; + } + return -1; +} + + +/** + * Get the name of this process. + */ +char* ProcessWrapper::getName() const { + return _name; +} + + +/** + * + */ +#ifdef INCLUDE_PROFILER +void ProcessWrapper::addToProfile(const char *event, void *port, + int length) { + if (profiler_output_file != NULL) { + fprintf(profiler_output_file, "%u %s %s %p%s %d\n", + profiler_event_counter++, _name, event, port, (event[0] == 'r') ? "I" : "O", + length); + + } else { + printf("profiler_output_file does not exist"); + } +} +#endif diff --git a/dol/src/dol/visitor/hds/lib/ProcessWrapper.h b/dol/src/dol/visitor/hds/lib/ProcessWrapper.h new file mode 100644 index 0000000..76ab3b3 --- /dev/null +++ b/dol/src/dol/visitor/hds/lib/ProcessWrapper.h @@ -0,0 +1,58 @@ +#ifndef _PROCESSWRAPPER_H_ +#define _PROCESSWRAPPER_H_ + +#include "systemc.h" +#include "dol.h" +#include "dol_sched_if.h" +#include "Fifo.h" +#include "WindowedFifo.h" +#include "functional_trace.h" +#include "Performance_Extraction.h" + + +#ifdef INCLUDE_PROFILER +extern FILE *profiler_output_file; +extern unsigned int profiler_event_counter; +#endif + +class ProcessWrapper : virtual public dol_sched_if, public sc_module +{ + public: + ProcessWrapper(sc_module_name name); + virtual ~ProcessWrapper(); + virtual void initialize(); + virtual int fire(); + virtual bool isDetached() { return _isDetached; } + virtual void detach(); + virtual int getIndex(unsigned indexNumber) const; + virtual char* getName() const; + +#ifdef INCLUDE_PROFILER + virtual void addToProfile(const char *event, void *port, + int length); +#endif + +#ifdef INCLUDE_TRACE + int start_line; + int end_line; + char channel_name[NAME_LENGTH]; +#endif + +#ifdef INCLUDE_PERFORMANCE + int start_line; + int end_line; + CURRENT_TIME start_time; + CURRENT_TIME end_time; +#endif + + protected: + char* _name; + DOLProcess _process; + bool _isDetached; + int _iteratorIndex[4]; + virtual int getIndex(const char* string, char* tokens, + int indexNumber) const; +}; + +#endif + diff --git a/dol/src/dol/visitor/hds/lib/WindowedFifo.cpp b/dol/src/dol/visitor/hds/lib/WindowedFifo.cpp new file mode 100644 index 0000000..50e960a --- /dev/null +++ b/dol/src/dol/visitor/hds/lib/WindowedFifo.cpp @@ -0,0 +1,288 @@ +#include "WindowedFifo.h" + +/** + * + */ +WindowedFifo::WindowedFifo(char* name, unsigned size = 20) { + //std::cout << "Create WindowedFifo." << std::endl; + _size = size; + _buffer = new char[_size]; + _head = 0; + _tail = 0; + _headRoom = 0; + _tailRoom = 0; + _use = 0; + //indicates whether Fifo is empty or full if _head == _tail + //_isFull = false; + _isHeadReserved = false; + _isTailReserved = false; + _name = new char[strlen(name) + 1]; + strcpy(_name, name); +} + +/** + * + */ +WindowedFifo::~WindowedFifo() { + //std::cout << "Delete WindowedFifo." << std::endl; + if (_buffer) { + delete _buffer; + } + if (_name) { + delete _name; + } + _buffer = 0; + _head = 0; + _tail = 0; + _name = 0; + _use = 0; + //std::cout << "Deleted WindowedFifo." << std::endl; +} + +/** + * + */ +unsigned WindowedFifo::reserve(void** dest, unsigned len) { + char** destination = (char**)dest; + //std::cout << "Attempt to reserve " << len << " bytes." << std::endl; + + //can only reserve once piece at a time + if (_isHeadReserved) { + *destination = 0; + return 0; + } + + while (unused() == 0) { + wait(_readEvent); + } + + //reserve at most as much memory as still available in the buffer + unsigned write = (len <= _size - _use ? len : _size - _use); + + if (write > 0) { + //if wrap-around in buffer: return only buffer for the + //contiguous buffer space + if (_head + write > _size) { + write = _size - _head; + } + + _headRoom = (_head + write) == _size? 0 : _head + write; + *destination = &(_buffer[_head]); + _isHeadReserved = true; + + //the following comparison is unsafe in a multi-threaded + //environment and potentially leads to race-conditions + /*if (_headRoom == _tail) { + _isFull = true; + } else { + _isFull = false; + }*/ + } + + //std::cout << "Reserved " << write << " bytes." << std::endl; + _writeReserve = write; + return write; +} + +/** + * + */ +void WindowedFifo::release() { + if (_isHeadReserved) { + //std::cout << "Released " << _headRoom - _head << " bytes." << std::endl; + _head = _headRoom; + _use += _writeReserve; + _isHeadReserved = false; + _writeEvent.notify(); + } +} + +/** + * + */ +unsigned WindowedFifo::capture(void **dest, unsigned len) { + char** destination = (char**)dest; + //std::cout << "Attempt to capture " << len << " bytes." << std::endl; + + if (_isTailReserved) { + //std::cout << "Only one attempt to capture allowed." << std::endl; + *destination = 0; + return 0; + } + + while (used() == 0) { + wait(_writeEvent); + } + + //capture at most as much data as available in the buffer + unsigned read = (len <= _use ? len : _use); + + if ( read > 0 ) { + //if wrap-around in buffer: return only buffer for the + //contiguous buffer space + if (_tail + read> _size) { + read = _size - _tail; + } + + _tailRoom = (_tail + read) == _size ? 0 : _tailRoom = _tail + read; + *destination = &(_buffer[_tail]); + _isTailReserved = true; + } + + //std::cout << "Captured " << read << " bytes." << std::endl; + + _readReserve = read; + return read; +} + +/** + * + */ +void WindowedFifo::consume() { + if (_isTailReserved) { + //std::cout << "Consumed " << _tailRoom - _tail << " bytes." << std::endl; + _tail = _tailRoom; + _use -= _readReserve; + _isTailReserved = false; + //_isFull = false; + _readEvent.notify(); + } +} + +/** + * + */ +unsigned WindowedFifo::size() const { + return _size; +} + +/** + * + */ +unsigned WindowedFifo::unused() const { + return _size - _use; +} + +/** + * + */ +unsigned WindowedFifo::used() const { + return _use; + /*if (_headRoom > _tail) { + return _headRoom - _tail; + } else if (_headRoom == _tail) { + if (_isFull == true) { + return _size; + } else { + return 0; + } + } + return _headRoom + _size - _tail;*/ +} + +/** + * + */ +char* WindowedFifo::getName() const { + return _name; +} + +/** + * Test the implementation + */ +/* +#include +#include +#define LENGTH 10 + +class producer : public sc_module +{ + public: + WindowedFifo *wfifo; + + SC_HAS_PROCESS(producer); + + producer(sc_module_name name) : sc_module(name) + { + SC_THREAD(main); + } + + void main() + { + for (int j = 0; j < LENGTH; j++) { + //std::cout << "write " << i << " to Fifo. "; + int *buf1; + int write = wfifo->reserve((void**)&buf1, sizeof(int)); + + if (write == sizeof(int)) { + *buf1 = j; + wfifo->release(); + //std::cout << "used: " << std::setw(2) << wfifo->used() + // << ", unused: " << std::setw(2) << wfifo->unused() + // << ", size: " << std::setw(2) << wfifo->size() + // << std::endl; + } else { + std::cout << "Not successful: " << write << std::endl; + } + } + printf("producer returns.\n"); + } +}; + +class consumer : public sc_module +{ + public: + WindowedFifo *wfifo; + + SC_HAS_PROCESS(consumer); + + consumer(sc_module_name name) : sc_module(name) + { + SC_THREAD(main); + } + + void main() + { + for (int j = 0; j < LENGTH; j++) { + int* buf3; + int read = wfifo->capture((void**)&buf3, sizeof(int)); + if (read == sizeof(int)) { + std::cout << "read " << (unsigned)*buf3 << " from WindowedFifo "; + std::cout << "used: " << std::setw(2) << wfifo->used() + << ", unused: " << std::setw(2) << wfifo->unused() + << ", size: " << std::setw(2) << wfifo->size() + << std::endl; + wfifo->consume(); + } else { + std::cout << "Read nothing from WindowedFifo." << std::endl; + } + } + printf("consumer returns.\n"); + } +}; + +class top : public sc_module +{ + public: + WindowedFifo *wfifo_inst; + producer *prod_inst; + consumer *cons_inst; + + top(sc_module_name name) : sc_module(name) + { + wfifo_inst = new WindowedFifo("myfifo", 4); + + prod_inst = new producer("producer"); + prod_inst->wfifo = wfifo_inst; + + cons_inst = new consumer("consumer"); + cons_inst->wfifo = wfifo_inst; + } +}; + +int sc_main (int argc , char *argv[]) { + top top1("top"); + sc_start(); + return 0; +} +*/ diff --git a/dol/src/dol/visitor/hds/lib/WindowedFifo.h b/dol/src/dol/visitor/hds/lib/WindowedFifo.h new file mode 100644 index 0000000..a223c95 --- /dev/null +++ b/dol/src/dol/visitor/hds/lib/WindowedFifo.h @@ -0,0 +1,40 @@ +#ifndef _WINDOWEDFIFO_H_ +#define _WINDOWEDFIFO_H_ + +#include "systemc.h" + +class WindowedFifo { + public: + WindowedFifo(char* name, unsigned size); + virtual ~WindowedFifo(); + + virtual unsigned reserve(void** destination, unsigned len); + virtual void release(); + + virtual unsigned capture(void** destination, unsigned len); + virtual void consume(); + + virtual unsigned used() const; + virtual unsigned unused() const; + virtual unsigned size() const; + virtual char* getName() const; + + protected: + char *_buffer; + unsigned _head; + unsigned _tail; + unsigned _headRoom; + unsigned _tailRoom; + unsigned _size; + unsigned _use; + unsigned _writeReserve; + unsigned _readReserve; + //bool _isFull; + bool _isHeadReserved; + bool _isTailReserved; + char *_name; + sc_event _readEvent; + sc_event _writeEvent; +}; + +#endif diff --git a/dol/src/dol/visitor/hds/lib/dol.h b/dol/src/dol/visitor/hds/lib/dol.h new file mode 100644 index 0000000..8fbefe4 --- /dev/null +++ b/dol/src/dol/visitor/hds/lib/dol.h @@ -0,0 +1,39 @@ +#ifndef DOL_H +#define DOL_H + +/************************************************************************ + * do not add code to this header + ************************************************************************/ + +/** + * Define the DOL process handler scheme. + * - Local variables are defined in structure LocalState. Local + * variables may vary from different processes. + * - The ProcessInit function pointer points to a function which + * initializes a process. + * - The ProcessFire function pointer points to a function which + * performs the actual computation. The communication between + * processes is inside the ProcessFire function. + * - The WPTR is a placeholder for callback. One can just + * leave it blank. + */ + +//structure for local memory of process +typedef struct _local_states *LocalState; + +//additional behavioral functions could be declared here +typedef void (*ProcessInit)(struct _process*); +typedef int (*ProcessFire)(struct _process*); +typedef void *WPTR; + +//process handler +struct _process; + +typedef struct _process { + LocalState local; + ProcessInit init; + ProcessFire fire; + WPTR wptr; //placeholder for wrapper instance +} DOLProcess; + +#endif diff --git a/dol/src/dol/visitor/hds/lib/dolSupport.cpp b/dol/src/dol/visitor/hds/lib/dolSupport.cpp new file mode 100644 index 0000000..1db732a --- /dev/null +++ b/dol/src/dol/visitor/hds/lib/dolSupport.cpp @@ -0,0 +1,149 @@ +#include "dolSupport.h" +#include "ProcessWrapper.h" + +/** + * + */ +unsigned write(void *port, void *buf, unsigned len, DOLProcess *process) +{ + Fifo *fifo = static_cast(port); + char *str = static_cast(buf); + #ifdef INCLUDE_PROFILER + (static_cast(process->wptr))->addToProfile( + "w", port, len); + #endif + fifo->write((void*)str, len); + #ifdef INCLUDE_TRACE + strcpy((static_cast(process->wptr))->channel_name, + fifo->getName()); + #endif + return len; +} + + +/** + * + */ +unsigned read(void *port, void *buf, unsigned len, DOLProcess *process) { + Fifo *fifo = static_cast(port); + char *str = static_cast(buf); + #ifdef INCLUDE_PROFILER + (static_cast(process->wptr))->addToProfile( + "r", port, len); + #endif + fifo->read((void*)str, len); + #ifdef INCLUDE_TRACE + strcpy((static_cast(process->wptr))->channel_name, + fifo->getName()); + #endif + return len; +} + + +/** + * + */ +int wtest(void *port, unsigned len, DOLProcess *process) { + Fifo *fifo = static_cast(port); + return (fifo->unused() >= len) ? 1 : 0; +} + + +/** + * + */ +int rtest(void *port, unsigned len, DOLProcess *process) { + Fifo *fifo = static_cast(port); + return (fifo->used() >= len) ? 1 : 0; +} + + +/** + * + */ +unsigned reserve(void* fifo, void** destination, unsigned len, DOLProcess* p) { + return ((WindowedFifo*)fifo)->reserve(destination, len); +} + +/** + * + */ +void release(void* fifo, DOLProcess* p) { + ((WindowedFifo*)fifo)->release(); +} + +/** + * + */ +unsigned capture(void* fifo, void** destination, unsigned len, DOLProcess* p) { + return ((WindowedFifo*)fifo)->capture(destination, len); +} + +/** + * + */ +void consume(void* fifo, DOLProcess* p) { + ((WindowedFifo*)fifo)->consume(); +} + + +/** + * + */ +void DOL_detach(DOLProcess* p) { + static_cast(p->wptr)->detach(); +} + + +/** + * + */ +void createPort(void** port, + void* base, + int number_of_indices, + int index0, int range0) { + *port = (void**)((void**)base)[index0]; +} + + +/** + * + */ +void createPort(void** port, + void* base, + int number_of_indices, + int index0, int range0, + int index1, int range1) { + *port = (void**)((void**)base)[index0 * range1 + index1]; +} + + +/** + * + */ +void createPort(void** port, + void* base, + int number_of_indices, + int index0, int range0, + int index1, int range1, + int index2, int range2) { + *port = (void**)((void**)base)[index0 * range1 * range2 + + index1 * range2 + index2]; +} + + +/** + * + */ +void createPort(void** port, + void* base, + int number_of_indices, + int index0, int range0, + int index1, int range1, + int index2, int range2, + int index3, int range3) { + *port = (void**)((void**)base)[index0 * range1 * range2 * range3 + + index1 * range2 * range3 + + index2 * range3 + + index3]; +} diff --git a/dol/src/dol/visitor/hds/lib/dolSupport.h b/dol/src/dol/visitor/hds/lib/dolSupport.h new file mode 100644 index 0000000..5f0505c --- /dev/null +++ b/dol/src/dol/visitor/hds/lib/dolSupport.h @@ -0,0 +1,148 @@ +#ifndef DOLSUPPORT_H +#define DOLSUPPORT_H + +#include "dol.h" +#include "Fifo.h" +#include "functional_trace.h" +#include "Performance_Extraction.h" + +#ifdef INCLUDE_PERFORMANCE +#define DOL_write(port, buf, len, process) {\ + (static_cast(p->wptr))->end_line = __LINE__;\ + get_current_time(&((static_cast(p->wptr))->\ + end_time));\ + performance_extraction.add_computation_performance(\ + (static_cast(p->wptr))->basename(),\ + (static_cast(p->wptr))->start_line,\ + (static_cast(p->wptr))->end_line,\ + &((static_cast(p->wptr))->start_time),\ + &((static_cast(p->wptr))->end_time));\ + write(port, buf, len, process);\ + (static_cast(p->wptr))->start_line = __LINE__;\ + get_current_time(&((static_cast(p->wptr))->\ + start_time)); } +#define DOL_read(port, buf, len, process) {\ + (static_cast(p->wptr))->end_line = __LINE__;\ + get_current_time(&((static_cast(p->wptr))->\ + end_time));\ + performance_extraction.add_computation_performance(\ + (static_cast(p->wptr))->basename(),\ + (static_cast(p->wptr))->start_line,\ + (static_cast(p->wptr))->end_line,\ + &((static_cast(p->wptr))->start_time),\ + &((static_cast(p->wptr))->end_time));\ + read(port, buf, len, process);\ + (static_cast(p->wptr))->start_line = __LINE__;\ + get_current_time(&((static_cast(p->wptr))->\ + start_time)); } +#elif INCLUDE_TRACE +#define DOL_write(port, buf, len, process) {\ + (static_cast(p->wptr))->end_line = __LINE__;\ + dol_functional_trace.create_computation_event(\ + (static_cast(p->wptr))->basename(),\ + (static_cast(p->wptr))->start_line,\ + (static_cast(p->wptr))->end_line);\ + write(port, buf, len, process);\ + dol_functional_trace.create_write_event(\ + (static_cast(p->wptr))->basename(), len,\ + (static_cast(p->wptr))->channel_name);\ + (static_cast(p->wptr))->start_line = __LINE__; } +#define DOL_read(port, buf, len, process) {\ + (static_cast(p->wptr))->end_line = __LINE__;\ + dol_functional_trace.create_computation_event(\ + (static_cast(p->wptr))->basename(),\ + (static_cast(p->wptr))->start_line,\ + (static_cast(p->wptr))->end_line);\ + read(port, buf, len, process);\ + dol_functional_trace.create_read_event(\ + (static_cast(p->wptr))->basename(), len,\ + (static_cast(p->wptr))->channel_name);\ + (static_cast(p->wptr))->start_line = __LINE__; } +#else + #define DOL_write(port, buf, len, process) \ + write(port, buf, len, process) + #define DOL_read(port, buf, len, process) \ + read(port, buf, len, process) +#endif + +#define DOL_reserve(port, buf, size, process) \ + reserve(port, (void**)buf, size, process); + +#define DOL_release(port, process) \ + release(port, process); + +#define DOL_capture(port, buf, size, process) \ + capture(port, (void**)buf, size, process); + +#define DOL_consume(port, process) \ + consume(port, process); + +#define DOL_wtest(port, len, process) wtest(port, len, process) + +#define DOL_rtest(port, len, process) rtest(port, len, process) + +void DOL_detach(DOLProcess* p); + +//fifo access functions +unsigned write(void* fifo, void* buf, unsigned len, DOLProcess* p); +unsigned read(void* fifo, void* buf, unsigned len, DOLProcess* p); +int wtest(void *port, unsigned len, DOLProcess *process); +int rtest(void *port, unsigned len, DOLProcess *process); + +//windowed fifo access functions +unsigned reserve(void* fifo, void** destination, unsigned len, DOLProcess* p); +void release(void* fifo, DOLProcess* p); +unsigned capture(void* fifo, void** destination, unsigned len, DOLProcess* p); +void consume(void* fifo, DOLProcess* p); + + +void createPort(void **port, + void *base, + int number_of_indices, + int index0, int range0); + +void createPort(void **port, + void *base, + int number_of_indices, + int index0, int range0, + int index1, int range1); + +void createPort(void **port, + void *base, + int number_of_indices, + int index0, int range0, + int index1, int range1, + int index2, int range2); + +void createPort(void **port, + void *base, + int number_of_indices, + int index0, int range0, + int index1, int range1, + int index2, int range2, + int index3, int range3); + +#define GETINDEX(dimension) \ + static_cast(p->wptr)->getIndex(dimension) + +/** + * macro to create a variable to store a port name + * + * @param name name of the variable + */ +#define CREATEPORTVAR(name) Fifo *name + +/** + * Create the port name of an iterated port based on its basename and the + * given indices. + * + * @param port buffer where the result is stored (created using + * CREATEPORTVAR) + * @param base basename of the port + * @param number_of_indices number of dimensions of the port + * @param index_range_pairs index and range values for each dimension + */ +#define CREATEPORT(port, base, number_of_indices, index_range_pairs...) \ + createPort((void**)(&port), base, number_of_indices, index_range_pairs) + +#endif diff --git a/dol/src/dol/visitor/hds/lib/dol_sched_if.h b/dol/src/dol/visitor/hds/lib/dol_sched_if.h new file mode 100644 index 0000000..d861b1e --- /dev/null +++ b/dol/src/dol/visitor/hds/lib/dol_sched_if.h @@ -0,0 +1,43 @@ +/************************************************************************** + dol_sched_if.h + + Scheduler interface for a DOL process + + (c) 2006 by Alexander Maxiaguine + + Computer Engineering and Networks Laboratory, TIK + Swiss Federal Institute of Technology, ETHZ Zurich + Switzerland + +**************************************************************************/ + +/************************************************************************** + Change Log: + + 14.03.06 -- creation + +**************************************************************************/ + +#ifndef DOL_SCHED_IF_H +#define DOL_SCHED_IF_H + +class dol_sched_if +{ + +public: + virtual void initialize() = 0; + virtual int fire() = 0; + + +protected: + dol_sched_if() {} + + +private: + + // disabled + dol_sched_if( const dol_sched_if& ); + dol_sched_if& operator = ( const dol_sched_if& ); +}; + +#endif diff --git a/dol/src/dol/visitor/hds/lib/functional_trace.cpp b/dol/src/dol/visitor/hds/lib/functional_trace.cpp new file mode 100644 index 0000000..efca06c --- /dev/null +++ b/dol/src/dol/visitor/hds/lib/functional_trace.cpp @@ -0,0 +1,295 @@ +#include "functional_trace.h" + +functional_trace dol_functional_trace; + +functional_trace::functional_trace() +{ + //DBGPRINT; + strcpy(trace_file_name, "trace1.txt"); + event_num = 0; + file_index = 1; +} + +functional_trace::~functional_trace() +{ + //DBGPRINT; + char temp[NAME_LENGTH]; +#ifdef INCLUDE_TRACE + strcpy(trace_file_name, "trace"); + sprintf(temp, "%d", file_index); + strcat(trace_file_name, temp); + strcat(trace_file_name, ".txt"); + write_to_file(trace_file_name); + free_traces(); + //printf("The traces in the memory have been freed\n"); +#endif + //DBGPRINT; +} + +void functional_trace::add_event_node(TRACE_EVENT &trace_event) +{ + Process_Trace *process_trace_ptr; + char temp[NAME_LENGTH]; + + process_trace_ptr = get_process_trace(trace_event.process_name); + if (process_trace_ptr == NULL) + { + process_trace_ptr = new Process_Trace(trace_event.process_name); + _list_process_trace.push_back(process_trace_ptr); + } + + process_trace_ptr->add_entry(&trace_event); + + event_num++; + if (event_num > 8000000) + { + strcpy(trace_file_name, "trace"); + sprintf(temp, "%d", file_index); + strcat(trace_file_name, temp); + strcat(trace_file_name, ".txt"); + write_to_file(trace_file_name); + free_traces(); + file_index++; + event_num = 0; + } + +} + +/* +void functional_trace::add_event_node(TRACE_EVENT &trace_event) +{ + XMLNode process_node; + char temp[NAME_LENGTH]; + process_node = xml_main_node.getChildNode(trace_event.process_name); + + if(process_node.isEmpty()) + { + process_node = xml_main_node.addChild(trace_event.process_name); + } + + XMLNode event_node = process_node.addChild("event"); + + event_node.addAttribute("type", trace_event_type_string[trace_event.event_type]); + + if(trace_event.event_type == COMPUTATION_EVENT) + { + + sprintf(temp, "%d", trace_event.computation_start_line); + event_node.addAttribute("start", temp); + sprintf(temp, "%d", trace_event.computation_end_line); + event_node.addAttribute("end", temp); + } + else if((trace_event.event_type == READ_EVENT) || (trace_event.event_type == WRITE_EVENT)) + { + sprintf(temp, "%d", trace_event.data_num); + event_node.addAttribute("data_num", temp); + event_node.addAttribute("channel_name", trace_event.channel_name); + } +} +*/ + +void functional_trace::create_computation_event(const char *process_name, int start_line, int end_line) +{ + TRACE_EVENT trace_event; + + trace_event.event_type = COMPUTATION_EVENT; + strcpy(trace_event.process_name, process_name); + trace_event.computation_start_line = start_line; + trace_event.computation_end_line = end_line; + strcpy(trace_event.channel_name, ""); + trace_event.data_num = 0; + + add_event_node(trace_event); +} + +void functional_trace::create_read_event(const char *process_name, int data_num, const char *channel_name) +{ + //DBGPRINT; + TRACE_EVENT trace_event; + trace_event.event_type = READ_EVENT; + strcpy(trace_event.process_name, process_name); + trace_event.data_num = data_num; + strcpy(trace_event.channel_name, channel_name); + + trace_event.computation_start_line = 0; + trace_event.computation_end_line = 0; + + add_event_node(trace_event); +} + +void functional_trace::create_write_event(const char *process_name, int data_num, const char *channel_name) +{ + //DBGPRINT; + TRACE_EVENT trace_event; + trace_event.event_type = WRITE_EVENT; + strcpy(trace_event.process_name, process_name); + trace_event.data_num = data_num; + strcpy(trace_event.channel_name, channel_name); + + trace_event.computation_start_line = 0; + trace_event.computation_end_line = 0; + + add_event_node(trace_event); +} + + +Process_Trace *functional_trace::get_process_trace(const char *process_name) +{ + Process_Trace *process_trace_ptr; + + for (_iter_process_trace = _list_process_trace.begin(); + _iter_process_trace != _list_process_trace.end(); + _iter_process_trace++) + { + process_trace_ptr = *_iter_process_trace; + + if (strcmp(process_trace_ptr->get_name(), process_name) == 0) + { + break; + } + } + + if (_iter_process_trace == _list_process_trace.end()) + { + process_trace_ptr = NULL; + } + + return process_trace_ptr; +} + +void functional_trace::free_traces() +{ + Process_Trace *process_trace_ptr; + + for (_iter_process_trace = _list_process_trace.begin(); + _iter_process_trace != _list_process_trace.end(); + _iter_process_trace++) + { + process_trace_ptr = *_iter_process_trace; + delete process_trace_ptr; + } + _list_process_trace.clear(); +} + +int functional_trace::write_to_file(const char *trace_file_name) { + int ret = -1; + Process_Trace *process_trace_ptr; + FILE *trace_file_handle; + EVENT_ENTRY *event_entry_ptr; + + if ((trace_file_handle = fopen(trace_file_name, "w")) == NULL) { + ret = -1; + printf("Can not create file: %s\n", trace_file_name); + goto end1; + } + + for (_iter_process_trace = _list_process_trace.begin(); + _iter_process_trace != _list_process_trace.end(); + _iter_process_trace++) { + process_trace_ptr = *_iter_process_trace; + fprintf(trace_file_handle, "$ %s\n", process_trace_ptr->get_name()); + + event_entry_ptr = process_trace_ptr->get_head_entry(); + while (event_entry_ptr != NULL) { + if (event_entry_ptr->event_type == COMPUTATION_EVENT) { + if (event_entry_ptr->end_line!=(event_entry_ptr->start_line+1)) + fprintf(trace_file_handle, "c %d %d\n", + event_entry_ptr->start_line, + event_entry_ptr->end_line); + } + else if (event_entry_ptr->event_type == WRITE_EVENT) { + fprintf(trace_file_handle, "w %d %s\n", + event_entry_ptr->data_num, + event_entry_ptr->channel_name); + } + else if (event_entry_ptr->event_type == READ_EVENT) { + fprintf(trace_file_handle, "r %d %s\n", + event_entry_ptr->data_num, + event_entry_ptr->channel_name); + } + + event_entry_ptr = event_entry_ptr->next; + } + } + + fflush(trace_file_handle); + fseek(trace_file_handle, 0, SEEK_SET); + fclose(trace_file_handle); + +end1: + return ret; +} + +Process_Trace::Process_Trace(const char *process_name) +{ + strcpy(_process_name, process_name); + _head = NULL; + _tail = NULL; +} + +Process_Trace::~Process_Trace() +{ + EVENT_ENTRY *temp; + + while (_head != NULL) + { + temp = _head; + _head = _head->next; + if (temp->channel_name != NULL) + delete [] temp->channel_name; + delete temp; + } +} + +const char *Process_Trace::get_name() +{ + return _process_name; +} + +EVENT_ENTRY *Process_Trace::get_head_entry() +{ + return _head; +} + +int Process_Trace::add_entry(TRACE_EVENT *trace_event_ptr) +{ + int ret = 0; + EVENT_ENTRY *temp; + int channel_name_length; + + temp = new EVENT_ENTRY; + memset(temp, 0, sizeof(EVENT_ENTRY)); + + temp->event_type = trace_event_ptr->event_type; + temp->start_line = trace_event_ptr->computation_start_line; + temp->end_line = trace_event_ptr->computation_end_line; + temp->data_num = trace_event_ptr->data_num; + + channel_name_length = strlen(trace_event_ptr->channel_name); + if (channel_name_length != 0) + { + temp->channel_name = new char[channel_name_length + 1]; + strcpy(temp->channel_name, trace_event_ptr->channel_name); + } + else + { + temp->channel_name = NULL; + } + + if (_head == NULL) + { + _head = temp; + _tail = temp; + temp->next = NULL; + } + else + { + _tail->next = temp; + _tail = temp; + temp->next = NULL; + } + + return ret; +} + + diff --git a/dol/src/dol/visitor/hds/lib/functional_trace.h b/dol/src/dol/visitor/hds/lib/functional_trace.h new file mode 100644 index 0000000..f3f0a8b --- /dev/null +++ b/dol/src/dol/visitor/hds/lib/functional_trace.h @@ -0,0 +1,57 @@ +#ifndef _FUNCTIONAL_H +#define _FUNCTIONAL_H + +#include "trace.h" + +typedef struct EVENT_ENTRY +{ + char event_type; + int start_line; + int end_line; + int data_num; + char *channel_name; + + EVENT_ENTRY *next; +}EVENT_ENTRY; + +class Process_Trace +{ +private: + char _process_name[NAME_LENGTH]; + EVENT_ENTRY *_head; + EVENT_ENTRY *_tail; + +public: + Process_Trace(const char *process_name); + ~Process_Trace(); + + const char *get_name(); + int add_entry(TRACE_EVENT *trace_event_ptr); + EVENT_ENTRY *get_head_entry(); +}; + +class functional_trace +{ +public: + char trace_file_name[NAME_LENGTH]; + unsigned long event_num; + int file_index; + + list _list_process_trace; + list::iterator _iter_process_trace; + + functional_trace(); + ~functional_trace(); + + void add_event_node(TRACE_EVENT &trace_event); + void create_computation_event(const char *process_name, int start_line, int end_line); + void create_read_event(const char *process_name, int data_num, const char *channel_name); + void create_write_event(const char *process_name, int data_num, const char *channel_name); + int write_to_file(const char *trace_file_name); + Process_Trace *get_process_trace(const char *process_name); + void free_traces(); +}; + +extern functional_trace dol_functional_trace; + +#endif diff --git a/dol/src/dol/visitor/hds/lib/trace.h b/dol/src/dol/visitor/hds/lib/trace.h new file mode 100644 index 0000000..3d92e67 --- /dev/null +++ b/dol/src/dol/visitor/hds/lib/trace.h @@ -0,0 +1,38 @@ +#ifndef _TRACE_H +#define _TRACE_H + +#include +#include +#include "xmlParser.h" +#include + +using namespace std; + +#define NAME_LENGTH 256 +#ifdef DBG +#define DBGPRINT printf("file: %s--line: %d\n", __FILE__, __LINE__) +#else +#define DBGPRINT +#endif + +typedef enum TRACE_EVENT_TYPE +{ + COMPUTATION_EVENT, + READ_EVENT, + WRITE_EVENT, + UNKOWN +}TRACE_EVENT_TYPE; + +#define MAX_EVENT_TYPE 3 + +typedef struct TRACE_EVENT +{ + char process_name[NAME_LENGTH]; + char event_type; + int computation_start_line; + int computation_end_line; + int data_num; + char channel_name[NAME_LENGTH]; +}TRACE_EVENT; + +#endif diff --git a/dol/src/dol/visitor/hds/lib/xmlParser.cpp b/dol/src/dol/visitor/hds/lib/xmlParser.cpp new file mode 100644 index 0000000..9868566 --- /dev/null +++ b/dol/src/dol/visitor/hds/lib/xmlParser.cpp @@ -0,0 +1,2594 @@ +/** + **************************************************************************** + *

XML.c - implementation file for basic XML parser written in ANSI C++ + * for portability. It works by using recursion and a node tree for breaking + * down the elements of an XML document.

+ * + * @version V2.23 + * @author Frank Vanden Berghen + * + * NOTE: + * + * If you add "#define STRICT_PARSING", on the first line of this file + * the parser will see the following XML-stream: + * some textother text + * as an error. Otherwise, this tring will be equivalent to: + * some textother text + * + * NOTE: + * + * If you add "#define APPROXIMATE_PARSING" on the first line of this file + * the parser will see the following XML-stream: + * + * + * + * as equivalent to the following XML-stream: + * + * + * + * This can be useful for badly-formed XML-streams but prevent the use + * of the following XML-stream (problem is: tags at contiguous levels + * have the same names): + * + * + * + * + * + * + * NOTE: + * + * If you add "#define _XMLPARSER_NO_MESSAGEBOX_" on the first line of this file + * the "openFileHelper" function will always display error messages inside the + * console instead of inside a message-box-window. Message-box-windows are + * available on windows 9x/NT/2000/XP/Vista only. + * + * BSD license: + * Copyright (c) 2002, Frank Vanden Berghen + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Frank Vanden Berghen nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************** + */ +#ifndef _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE +#endif +#include "xmlParser.h" +#ifdef _XMLWINDOWS +//#ifdef _DEBUG +//#define _CRTDBG_MAP_ALLOC +//#include +//#endif +#define WIN32_LEAN_AND_MEAN +#include // to have IsTextUnicode, MultiByteToWideChar, WideCharToMultiByte to handle unicode files + // to have "MessageBoxA" to display error messages for openFilHelper +#endif + +#include +#include +#include +#include +#include + +XMLCSTR XMLNode::getVersion() { return _T("v2.23"); } +void free_XMLDLL(void *t){free(t);} + +static char strictUTF8Parsing=1, guessUnicodeChars=1, dropWhiteSpace=1; + +inline int mmin( const int t1, const int t2 ) { return t1 < t2 ? t1 : t2; } + +// You can modify the initialization of the variable "XMLClearTags" below +// to change the clearTags that are currently recognized by the library. +// The number on the second columns is the length of the string inside the +// first column. The "") }, + { _T("") }, + { _T("
")    ,5,  _T("
") }, + { _T("")}, + { _T("") }, + { NULL ,0, NULL } +}; +ALLXMLClearTag* XMLNode::getClearTagTable() { return XMLClearTags; } + +// You can modify the initialization of the variable "XMLEntities" below +// to change the character entities that are currently recognized by the library. +// The number on the second columns is the length of the string inside the +// first column. Additionally, the syntaxes " " and " " are recognized. +typedef struct { XMLCSTR s; int l; XMLCHAR c;} XMLCharacterEntity; +static XMLCharacterEntity XMLEntities[] = +{ + { _T("&" ), 5, _T('&' )}, + { _T("<" ), 4, _T('<' )}, + { _T(">" ), 4, _T('>' )}, + { _T("""), 6, _T('\"')}, + { _T("'"), 6, _T('\'')}, + { NULL , 0, '\0' } +}; + +// When rendering the XMLNode to a string (using the "createXMLString" function), +// you can ask for a beautiful formatting. This formatting is using the +// following indentation character: +#define INDENTCHAR _T('\t') + +// The following function parses the XML errors into a user friendly string. +// You can edit this to change the output language of the library to something else. +XMLCSTR XMLNode::getError(XMLError xerror) +{ + switch (xerror) + { + case eXMLErrorNone: return _T("No error"); + case eXMLErrorMissingEndTag: return _T("Warning: Unmatched end tag"); + case eXMLErrorEmpty: return _T("Error: No XML data"); + case eXMLErrorFirstNotStartTag: return _T("Error: First token not start tag"); + case eXMLErrorMissingTagName: return _T("Error: Missing start tag name"); + case eXMLErrorMissingEndTagName: return _T("Error: Missing end tag name"); + case eXMLErrorNoMatchingQuote: return _T("Error: Unmatched quote"); + case eXMLErrorUnmatchedEndTag: return _T("Error: Unmatched end tag"); + case eXMLErrorUnmatchedEndClearTag: return _T("Error: Unmatched clear tag end"); + case eXMLErrorUnexpectedToken: return _T("Error: Unexpected token found"); + case eXMLErrorInvalidTag: return _T("Error: Invalid tag found"); + case eXMLErrorNoElements: return _T("Error: No elements found"); + case eXMLErrorFileNotFound: return _T("Error: File not found"); + case eXMLErrorFirstTagNotFound: return _T("Error: First Tag not found"); + case eXMLErrorUnknownCharacterEntity:return _T("Error: Unknown character entity"); + case eXMLErrorCharConversionError: return _T("Error: unable to convert between UNICODE and MultiByte chars"); + case eXMLErrorCannotOpenWriteFile: return _T("Error: unable to open file for writing"); + case eXMLErrorCannotWriteFile: return _T("Error: cannot write into file"); + + case eXMLErrorBase64DataSizeIsNotMultipleOf4: return _T("Warning: Base64-string length is not a multiple of 4"); + case eXMLErrorBase64DecodeTruncatedData: return _T("Warning: Base64-string is truncated"); + case eXMLErrorBase64DecodeIllegalCharacter: return _T("Error: Base64-string contains an illegal character"); + case eXMLErrorBase64DecodeBufferTooSmall: return _T("Error: Base64 decode output buffer is too small"); + }; + return _T("Unknown"); +} + +// Here is an abstraction layer to access some common string manipulation functions. +// The abstraction layer is currently working for gcc, Microsoft Visual Studio 6.0, +// Microsoft Visual Studio .NET, CC (sun compiler) and Borland C++. +// If you plan to "port" the library to a new system/compiler, all you have to do is +// to edit the following lines. +#ifdef XML_NO_WIDE_CHAR +char myIsTextUnicode(const void *b, int len) { return FALSE; } +#else + #if defined (UNDER_CE) || !defined(WIN32) + char myIsTextUnicode(const void *b, int len) // inspired by the Wine API: RtlIsTextUnicode + { +#ifdef sun + // for SPARC processors: wchar_t* buffers must always be alligned, otherwise it's a char* buffer. + if ((((unsigned long)b)%sizeof(wchar_t))!=0) return FALSE; +#endif + const wchar_t *s=(const wchar_t*)b; + + // buffer too small: + if (len<(int)sizeof(wchar_t)) return FALSE; + + // odd length test + if (len&1) return FALSE; + + /* only checks the first 256 characters */ + len=mmin(256,len/sizeof(wchar_t)); + + // Check for the special byte order: + if (*s == 0xFFFE) return FALSE; // IS_TEXT_UNICODE_REVERSE_SIGNATURE; + if (*s == 0xFEFF) return TRUE; // IS_TEXT_UNICODE_SIGNATURE + + // checks for ASCII characters in the UNICODE stream + int i,stats=0; + for (i=0; ilen/2) return TRUE; + + // Check for UNICODE NULL chars + for (i=0; i + int _tcsnicmp(XMLCSTR c1, XMLCSTR c2, int l) { return wsncasecmp(c1,c2,l);} + int _tcsicmp(XMLCSTR c1, XMLCSTR c2) { return wscasecmp(c1,c2); } + #else + // for gcc + int _tcsnicmp(XMLCSTR c1, XMLCSTR c2, int l) { return wcsncasecmp(c1,c2,l);} + int _tcsicmp(XMLCSTR c1, XMLCSTR c2) { return wcscasecmp(c1,c2); } + #endif + XMLSTR _tcsstr(XMLCSTR c1, XMLCSTR c2) { return (XMLSTR)wcsstr(c1,c2); } + XMLSTR _tcscpy(XMLSTR c1, XMLCSTR c2) { return (XMLSTR)wcscpy(c1,c2); } + FILE *_tfopen(XMLCSTR filename,XMLCSTR mode) + { + char *filenameAscii=myWideCharToMultiByte(filename,0); + FILE *f; + if (mode[0]==_T('r')) f=fopen(filenameAscii,"rb"); + else f=fopen(filenameAscii,"wb"); + free(filenameAscii); + return f; + } + #else + FILE *_tfopen(XMLCSTR filename,XMLCSTR mode) { return fopen(filename,mode); } + int _tcslen(XMLCSTR c) { return strlen(c); } + int _tcsnicmp(XMLCSTR c1, XMLCSTR c2, int l) { return strncasecmp(c1,c2,l);} + int _tcsicmp(XMLCSTR c1, XMLCSTR c2) { return strcasecmp(c1,c2); } + XMLSTR _tcsstr(XMLCSTR c1, XMLCSTR c2) { return (XMLSTR)strstr(c1,c2); } + XMLSTR _tcscpy(XMLSTR c1, XMLCSTR c2) { return (XMLSTR)strcpy(c1,c2); } + #endif + int _strnicmp(const char *c1,const char *c2, int l) { return strncasecmp(c1,c2,l);} +#endif + +///////////////////////////////////////////////////////////////////////// +// Here start the core implementation of the XMLParser library // +///////////////////////////////////////////////////////////////////////// + +// You should normally not change anything below this point. +// For your own information, I suggest that you read the openFileHelper below: +XMLNode XMLNode::openFileHelper(XMLCSTR filename, XMLCSTR tag) +{ + // guess the value of the global parameter "strictUTF8Parsing" + // (the guess is based on the first 200 bytes of the file). + FILE *f=_tfopen(filename,_T("rb")); + if (f) + { + char bb[205]; + int l=(int)fread(bb,1,200,f); + setGlobalOptions(guessUnicodeChars,guessUTF8ParsingParameterValue(bb,l),dropWhiteSpace); + fclose(f); + } + + // parse the file + XMLResults pResults; + XMLNode xnode=XMLNode::parseFile(filename,tag,&pResults); + + // display error message (if any) + if (pResults.error != eXMLErrorNone) + { + // create message + char message[2000],*s1=(char*)"",*s3=(char*)""; XMLCSTR s2=_T(""); + if (pResults.error==eXMLErrorFirstTagNotFound) { s1=(char*)"First Tag should be '"; s2=tag; s3=(char*)"'.\n"; } + sprintf(message, +#ifdef _XMLUNICODE + "XML Parsing error inside file '%S'.\n%S\nAt line %i, column %i.\n%s%S%s" +#else + "XML Parsing error inside file '%s'.\n%s\nAt line %i, column %i.\n%s%s%s" +#endif + ,filename,XMLNode::getError(pResults.error),pResults.nLine,pResults.nColumn,s1,s2,s3); + + // display message +#if defined(WIN32) && !defined(UNDER_CE) && !defined(_XMLPARSER_NO_MESSAGEBOX_) + MessageBoxA(NULL,message,"XML Parsing error",MB_OK|MB_ICONERROR|MB_TOPMOST); +#else + printf("%s",message); +#endif + exit(255); + } + return xnode; +} + +#ifndef _XMLUNICODE +// If "strictUTF8Parsing=0" then we assume that all characters have the same length of 1 byte. +// If "strictUTF8Parsing=1" then the characters have different lengths (from 1 byte to 4 bytes). +// This table is used as lookup-table to know the length of a character (in byte) based on the +// content of the first byte of the character. +// (note: if you modify this, you must always have XML_utf8ByteTable[0]=0 ). +static const char XML_utf8ByteTable[256] = +{ + // 0 1 2 3 4 5 6 7 8 9 a b c d e f + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x00 + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x10 + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x20 + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x30 + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x40 + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x50 + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x60 + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x70End of ASCII range + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x80 0x80 to 0xc1 invalid + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x90 + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0xa0 + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0xb0 + 1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xc0 0xc2 to 0xdf 2 byte + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xd0 + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,// 0xe0 0xe0 to 0xef 3 byte + 4,4,4,4,4,1,1,1,1,1,1,1,1,1,1,1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid +}; +static const char XML_asciiByteTable[256] = +{ + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 +}; +static const char *XML_ByteTable=(const char *)XML_utf8ByteTable; // the default is "strictUTF8Parsing=1" +#endif + +XMLError XMLNode::writeToFile(XMLCSTR filename, const char *encoding, char nFormat) const +{ + int i; + XMLSTR t=createXMLString(nFormat,&i); + FILE *f=_tfopen(filename,_T("wb")); + if (!f) return eXMLErrorCannotOpenWriteFile; +#ifdef _XMLUNICODE + unsigned char h[2]={ 0xFF, 0xFE }; + if (!fwrite(h,2,1,f)) return eXMLErrorCannotWriteFile; + if (!isDeclaration()) + { + if (!fwrite(_T("\n"),sizeof(wchar_t)*40,1,f)) + return eXMLErrorCannotWriteFile; + } +#else + if (!isDeclaration()) + { + if ((!encoding)||(XML_ByteTable==XML_utf8ByteTable)) + { + // header so that windows recognize the file as UTF-8: +// unsigned char h[3]={0xEF,0xBB,0xBF}; +// if (!fwrite(h,3,1,f)) return eXMLErrorCannotWriteFile; + if (!fwrite("\n",39,1,f)) return eXMLErrorCannotWriteFile; + } + else + if (fprintf(f,"\n",encoding)<0) return eXMLErrorCannotWriteFile; + } else + { + if (XML_ByteTable==XML_utf8ByteTable) // test if strictUTF8Parsing==1" + { +// unsigned char h[3]={0xEF,0xBB,0xBF}; if (!fwrite(h,3,1,f)) return eXMLErrorCannotWriteFile; + } + } +#endif + if (!fwrite(t,sizeof(XMLCHAR)*i,1,f)) return eXMLErrorCannotWriteFile; + if (fclose(f)!=0) return eXMLErrorCannotWriteFile; + free(t); + return eXMLErrorNone; +} + +// Duplicate a given string. +XMLSTR stringDup(XMLCSTR lpszData, int cbData) +{ + if (lpszData==NULL) return NULL; + + XMLSTR lpszNew; + if (cbData==0) cbData=(int)_tcslen(lpszData); + lpszNew = (XMLSTR)malloc((cbData+1) * sizeof(XMLCHAR)); + if (lpszNew) + { + memcpy(lpszNew, lpszData, (cbData) * sizeof(XMLCHAR)); + lpszNew[cbData] = (XMLCHAR)NULL; + } + return lpszNew; +} + +XMLNode XMLNode::emptyXMLNode; +XMLClear XMLNode::emptyXMLClear={ NULL, NULL, NULL}; +XMLAttribute XMLNode::emptyXMLAttribute={ NULL, NULL}; + +// Enumeration used to decipher what type a token is +typedef enum XMLTokenTypeTag +{ + eTokenText = 0, + eTokenQuotedText, + eTokenTagStart, /* "<" */ + eTokenTagEnd, /* "" */ + eTokenEquals, /* "=" */ + eTokenDeclaration, /* "" */ + eTokenClear, + eTokenError +} XMLTokenType; + +// Main structure used for parsing XML +typedef struct XML +{ + XMLCSTR lpXML; + XMLCSTR lpszText; + int nIndex,nIndexMissigEndTag; + enum XMLError error; + XMLCSTR lpEndTag; + int cbEndTag; + XMLCSTR lpNewElement; + int cbNewElement; + int nFirst; +} XML; + +typedef struct +{ + ALLXMLClearTag *pClr; + XMLCSTR pStr; +} NextToken; + +// Enumeration used when parsing attributes +typedef enum Attrib +{ + eAttribName = 0, + eAttribEquals, + eAttribValue +} Attrib; + +// Enumeration used when parsing elements to dictate whether we are currently +// inside a tag +typedef enum Status +{ + eInsideTag = 0, + eOutsideTag +} Status; + +// private (used while rendering): +XMLSTR toXMLString(XMLSTR dest,XMLCSTR source) +{ + XMLSTR dd=dest; + XMLCHAR ch; + XMLCharacterEntity *entity; + while ((ch=*source)) + { + entity=XMLEntities; + do + { + if (ch==entity->c) {_tcscpy(dest,entity->s); dest+=entity->l; source++; goto out_of_loop1; } + entity++; + } while(entity->s); +#ifdef _XMLUNICODE + *(dest++)=*(source++); +#else + switch(XML_ByteTable[(unsigned char)ch]) + { + case 4: *(dest++)=*(source++); + case 3: *(dest++)=*(source++); + case 2: *(dest++)=*(source++); + case 1: *(dest++)=*(source++); + } +#endif +out_of_loop1: + ; + } + *dest=0; + return dd; +} + +// private (used while rendering): +int lengthXMLString(XMLCSTR source) +{ + int r=0; + XMLCharacterEntity *entity; + XMLCHAR ch; + while ((ch=*source)) + { + entity=XMLEntities; + do + { + if (ch==entity->c) { r+=entity->l; source++; goto out_of_loop1; } + entity++; + } while(entity->s); +#ifdef _XMLUNICODE + r++; source++; +#else + ch=XML_ByteTable[(unsigned char)ch]; r+=ch; source+=ch; +#endif +out_of_loop1: + ; + } + return r; +} + +XMLSTR toXMLString(XMLCSTR source) +{ + XMLSTR dest=(XMLSTR)malloc((lengthXMLString(source)+1)*sizeof(XMLCHAR)); + return toXMLString(dest,source); +} + +XMLSTR toXMLStringFast(XMLSTR *dest,int *destSz, XMLCSTR source) +{ + int l=lengthXMLString(source)+1; + if (l>*destSz) { *destSz=l; *dest=(XMLSTR)realloc(*dest,l*sizeof(XMLCHAR)); } + return toXMLString(*dest,source); +} + +// private: +XMLSTR fromXMLString(XMLCSTR s, int lo, XML *pXML) +{ + // This function is the opposite of the function "toXMLString". It decodes the escape + // sequences &, ", ', <, > and replace them by the characters + // &,",',<,>. This function is used internally by the XML Parser. All the calls to + // the XML library will always gives you back "decoded" strings. + // + // in: string (s) and length (lo) of string + // out: new allocated string converted from xml + if (!s) return NULL; + + int ll=0,j; + XMLSTR d; + XMLCSTR ss=s; + XMLCharacterEntity *entity; + while ((lo>0)&&(*s)) + { + if (*s==_T('&')) + { + if ((lo>2)&&(s[1]==_T('#'))) + { + s+=2; lo-=2; + if ((*s==_T('X'))||(*s==_T('x'))) { s++; lo--; } + while ((*s)&&(*s!=_T(';'))&&((lo--)>0)) s++; + if (*s!=_T(';')) + { + pXML->error=eXMLErrorUnknownCharacterEntity; + return NULL; + } + s++; lo--; + } else + { + entity=XMLEntities; + do + { + if ((lo>=entity->l)&&(_tcsnicmp(s,entity->s,entity->l)==0)) { s+=entity->l; lo-=entity->l; break; } + entity++; + } while(entity->s); + if (!entity->s) + { + pXML->error=eXMLErrorUnknownCharacterEntity; + return NULL; + } + } + } else + { +#ifdef _XMLUNICODE + s++; lo--; +#else + j=XML_ByteTable[(unsigned char)*s]; s+=j; lo-=j; ll+=j-1; +#endif + } + ll++; + } + + d=(XMLSTR)malloc((ll+1)*sizeof(XMLCHAR)); + s=d; + while (ll-->0) + { + if (*ss==_T('&')) + { + if (ss[1]==_T('#')) + { + ss+=2; j=0; + if ((*ss==_T('X'))||(*ss==_T('x'))) + { + ss++; + while (*ss!=_T(';')) + { + if ((*ss>=_T('0'))&&(*ss<=_T('9'))) j=(j<<4)+*ss-_T('0'); + else if ((*ss>=_T('A'))&&(*ss<=_T('F'))) j=(j<<4)+*ss-_T('A')+10; + else if ((*ss>=_T('a'))&&(*ss<=_T('f'))) j=(j<<4)+*ss-_T('a')+10; + else { free((void*)s); pXML->error=eXMLErrorUnknownCharacterEntity;return NULL;} + ss++; + } + } else + { + while (*ss!=_T(';')) + { + if ((*ss>=_T('0'))&&(*ss<=_T('9'))) j=(j*10)+*ss-_T('0'); + else { free((void*)s); pXML->error=eXMLErrorUnknownCharacterEntity;return NULL;} + ss++; + } + } + (*d++)=(XMLCHAR)j; ss++; + } else + { + entity=XMLEntities; + do + { + if (_tcsnicmp(ss,entity->s,entity->l)==0) { *(d++)=entity->c; ss+=entity->l; break; } + entity++; + } while(entity->s); + } + } else + { +#ifdef _XMLUNICODE + *(d++)=*(ss++); +#else + switch(XML_ByteTable[(unsigned char)*ss]) + { + case 4: *(d++)=*(ss++); ll--; + case 3: *(d++)=*(ss++); ll--; + case 2: *(d++)=*(ss++); ll--; + case 1: *(d++)=*(ss++); + } +#endif + } + } + *d=0; + return (XMLSTR)s; +} + +#define XML_isSPACECHAR(ch) ((ch==_T('\n'))||(ch==_T(' '))||(ch== _T('\t'))||(ch==_T('\r'))) + +// private: +char myTagCompare(XMLCSTR cclose, XMLCSTR copen) +// !!!! WARNING strange convention&: +// return 0 if equals +// return 1 if different +{ + if (!cclose) return 1; + int l=(int)_tcslen(cclose); + if (_tcsnicmp(cclose, copen, l)!=0) return 1; + const XMLCHAR c=copen[l]; + if (XML_isSPACECHAR(c)|| + (c==_T('/' ))|| + (c==_T('<' ))|| + (c==_T('>' ))|| + (c==_T('=' ))) return 0; + return 1; +} + +// Obtain the next character from the string. +static inline XMLCHAR getNextChar(XML *pXML) +{ + XMLCHAR ch = pXML->lpXML[pXML->nIndex]; +#ifdef _XMLUNICODE + if (ch!=0) pXML->nIndex++; +#else + pXML->nIndex+=XML_ByteTable[(unsigned char)ch]; +#endif + return ch; +} + +// Find the next token in a string. +// pcbToken contains the number of characters that have been read. +static NextToken GetNextToken(XML *pXML, int *pcbToken, enum XMLTokenTypeTag *pType) +{ + NextToken result; + XMLCHAR ch; + XMLCHAR chTemp; + int indexStart,nFoundMatch,nIsText=FALSE; + result.pClr=NULL; // prevent warning + + // Find next non-white space character + do { indexStart=pXML->nIndex; ch=getNextChar(pXML); } while XML_isSPACECHAR(ch); + + if (ch) + { + // Cache the current string pointer + result.pStr = &pXML->lpXML[indexStart]; + + // First check whether the token is in the clear tag list (meaning it + // does not need formatting). + ALLXMLClearTag *ctag=XMLClearTags; + do + { + if (_tcsnicmp(ctag->lpszOpen, result.pStr, ctag->openTagLen)==0) + { + result.pClr=ctag; + pXML->nIndex+=ctag->openTagLen-1; + *pType=eTokenClear; + return result; + } + ctag++; + } while(ctag->lpszOpen); + + // If we didn't find a clear tag then check for standard tokens + switch(ch) + { + // Check for quotes + case _T('\''): + case _T('\"'): + // Type of token + *pType = eTokenQuotedText; + chTemp = ch; + + // Set the size + nFoundMatch = FALSE; + + // Search through the string to find a matching quote + while((ch = getNextChar(pXML))) + { + if (ch==chTemp) { nFoundMatch = TRUE; break; } + if (ch==_T('<')) break; + } + + // If we failed to find a matching quote + if (nFoundMatch == FALSE) + { + pXML->nIndex=indexStart+1; + nIsText=TRUE; + break; + } + +// 4.02.2002 +// if (FindNonWhiteSpace(pXML)) pXML->nIndex--; + + break; + + // Equals (used with attribute values) + case _T('='): + *pType = eTokenEquals; + break; + + // Close tag + case _T('>'): + *pType = eTokenCloseTag; + break; + + // Check for tag start and tag end + case _T('<'): + + // Peek at the next character to see if we have an end tag 'lpXML[pXML->nIndex]; + + // If we have a tag end... + if (chTemp == _T('/')) + { + // Set the type and ensure we point at the next character + getNextChar(pXML); + *pType = eTokenTagEnd; + } + + // If we have an XML declaration tag + else if (chTemp == _T('?')) + { + + // Set the type and ensure we point at the next character + getNextChar(pXML); + *pType = eTokenDeclaration; + } + + // Otherwise we must have a start tag + else + { + *pType = eTokenTagStart; + } + break; + + // Check to see if we have a short hand type end tag ('/>'). + case _T('/'): + + // Peek at the next character to see if we have a short end tag '/>' + chTemp = pXML->lpXML[pXML->nIndex]; + + // If we have a short hand end tag... + if (chTemp == _T('>')) + { + // Set the type and ensure we point at the next character + getNextChar(pXML); + *pType = eTokenShortHandClose; + break; + } + + // If we haven't found a short hand closing tag then drop into the + // text process + + // Other characters + default: + nIsText = TRUE; + } + + // If this is a TEXT node + if (nIsText) + { + // Indicate we are dealing with text + *pType = eTokenText; + while((ch = getNextChar(pXML))) + { + if XML_isSPACECHAR(ch) + { + indexStart++; break; + + } else if (ch==_T('/')) + { + // If we find a slash then this maybe text or a short hand end tag + // Peek at the next character to see it we have short hand end tag + ch=pXML->lpXML[pXML->nIndex]; + // If we found a short hand end tag then we need to exit the loop + if (ch==_T('>')) { pXML->nIndex--; break; } + + } else if ((ch==_T('<'))||(ch==_T('>'))||(ch==_T('='))) + { + pXML->nIndex--; break; + } + } + } + *pcbToken = pXML->nIndex-indexStart; + } else + { + // If we failed to obtain a valid character + *pcbToken = 0; + *pType = eTokenError; + result.pStr=NULL; + } + + return result; +} + +XMLCSTR XMLNode::updateName_WOSD(XMLCSTR lpszName) +{ + if (d->lpszName&&(lpszName!=d->lpszName)) free((void*)d->lpszName); + d->lpszName=lpszName; + return lpszName; +} + +// private: +XMLNode::XMLNode(struct XMLNodeDataTag *p){ d=p; (p->ref_count)++; } +XMLNode::XMLNode(XMLNodeData *pParent, XMLCSTR lpszName, char isDeclaration) +{ + d=(XMLNodeData*)malloc(sizeof(XMLNodeData)); + d->ref_count=1; + + d->lpszName=NULL; + d->nChild= 0; + d->nText = 0; + d->nClear = 0; + d->nAttribute = 0; + + d->isDeclaration = isDeclaration; + + d->pParent = pParent; + d->pChild= NULL; + d->pText= NULL; + d->pClear= NULL; + d->pAttribute= NULL; + d->pOrder= NULL; + + updateName_WOSD(lpszName); +} + +XMLNode XMLNode::createXMLTopNode_WOSD(XMLCSTR lpszName, char isDeclaration) { return XMLNode(NULL,lpszName,isDeclaration); } +XMLNode XMLNode::createXMLTopNode(XMLCSTR lpszName, char isDeclaration) { return XMLNode(NULL,stringDup(lpszName),isDeclaration); } + +#define MEMORYINCREASE 50 + +static inline void *myRealloc(void *p, int newsize, int memInc, int sizeofElem) +{ + if (p==NULL) { if (memInc) return malloc(memInc*sizeofElem); return malloc(sizeofElem); } + if ((memInc==0)||((newsize%memInc)==0)) p=realloc(p,(newsize+memInc)*sizeofElem); +// if (!p) +// { +// printf("XMLParser Error: Not enough memory! Aborting...\n"); exit(220); +// } + return p; +} + +// private: +int XMLNode::findPosition(XMLNodeData *d, int index, XMLElementType xtype) +{ + if (index<0) return -1; + int i=0,j=(int)((index<<2)+xtype),*o=d->pOrder; while (o[i]!=j) i++; return i; +} + +// private: +// update "order" information when deleting a content of a XMLNode +int XMLNode::removeOrderElement(XMLNodeData *d, XMLElementType t, int index) +{ + int n=d->nChild+d->nText+d->nClear, *o=d->pOrder,i=findPosition(d,index,t); + memmove(o+i, o+i+1, (n-i)*sizeof(int)); + for (;ipOrder=(int)realloc(d->pOrder,n*sizeof(int)); + // but we skip reallocation because it's too time consuming. + // Anyway, at the end, it will be free'd completely at once. + return i; +} + +void *XMLNode::addToOrder(int memoryIncrease,int *_pos, int nc, void *p, int size, XMLElementType xtype) +{ + // in: *_pos is the position inside d->pOrder ("-1" means "EndOf") + // out: *_pos is the index inside p + p=myRealloc(p,(nc+1),memoryIncrease,size); + int n=d->nChild+d->nText+d->nClear; + d->pOrder=(int*)myRealloc(d->pOrder,n+1,memoryIncrease*3,sizeof(int)); + int pos=*_pos,*o=d->pOrder; + + if ((pos<0)||(pos>=n)) { *_pos=nc; o[n]=(int)((nc<<2)+xtype); return p; } + + int i=pos; + memmove(o+i+1, o+i, (n-i)*sizeof(int)); + + while ((pos>2; + memmove(((char*)p)+(pos+1)*size,((char*)p)+pos*size,(nc-pos)*size); + + return p; +} + +// Add a child node to the given element. +XMLNode XMLNode::addChild_priv(int memoryIncrease, XMLCSTR lpszName, char isDeclaration, int pos) +{ + if (!lpszName) return emptyXMLNode; + d->pChild=(XMLNode*)addToOrder(memoryIncrease,&pos,d->nChild,d->pChild,sizeof(XMLNode),eNodeChild); + d->pChild[pos].d=NULL; + d->pChild[pos]=XMLNode(d,lpszName,isDeclaration); + d->nChild++; + return d->pChild[pos]; +} + +// Add an attribute to an element. +XMLAttribute *XMLNode::addAttribute_priv(int memoryIncrease,XMLCSTR lpszName, XMLCSTR lpszValuev) +{ + if (!lpszName) return &emptyXMLAttribute; + int nc=d->nAttribute; + d->pAttribute=(XMLAttribute*)myRealloc(d->pAttribute,(nc+1),memoryIncrease,sizeof(XMLAttribute)); + XMLAttribute *pAttr=d->pAttribute+nc; + pAttr->lpszName = lpszName; + pAttr->lpszValue = lpszValuev; + d->nAttribute++; + return pAttr; +} + +// Add text to the element. +XMLCSTR XMLNode::addText_priv(int memoryIncrease, XMLCSTR lpszValue, int pos) +{ + if (!lpszValue) return NULL; + d->pText=(XMLCSTR*)addToOrder(memoryIncrease,&pos,d->nText,d->pText,sizeof(XMLSTR),eNodeText); + d->pText[pos]=lpszValue; + d->nText++; + return lpszValue; +} + +// Add clear (unformatted) text to the element. +XMLClear *XMLNode::addClear_priv(int memoryIncrease, XMLCSTR lpszValue, XMLCSTR lpszOpen, XMLCSTR lpszClose, int pos) +{ + if (!lpszValue) return &emptyXMLClear; + d->pClear=(XMLClear *)addToOrder(memoryIncrease,&pos,d->nClear,d->pClear,sizeof(XMLClear),eNodeClear); + XMLClear *pNewClear=d->pClear+pos; + pNewClear->lpszValue = lpszValue; + if (!lpszOpen) lpszOpen=getClearTagTable()->lpszOpen; + if (!lpszClose) lpszOpen=getClearTagTable()->lpszClose; + pNewClear->lpszOpenTag = lpszOpen; + pNewClear->lpszCloseTag = lpszClose; + d->nClear++; + return pNewClear; +} + +// private: +// Parse a clear (unformatted) type node. +char XMLNode::parseClearTag(void *px, ALLXMLClearTag *pClear) +{ + XML *pXML=(XML *)px; + int cbTemp=0; + XMLCSTR lpszTemp=NULL; + XMLCSTR lpXML=&pXML->lpXML[pXML->nIndex]; + static XMLCSTR docTypeEnd=_T("]>"); + + // Find the closing tag + // Seems the lpszOpen==XMLClearTags[1].lpszOpen) + { + XMLCSTR pCh=lpXML; + while (*pCh) + { + if (*pCh==_T('<')) { pClear->lpszClose=docTypeEnd; lpszTemp=_tcsstr(lpXML,docTypeEnd); break; } + else if (*pCh==_T('>')) { lpszTemp=pCh; break; } +#ifdef _XMLUNICODE + pCh++; +#else + pCh+=XML_ByteTable[(unsigned char)(*pCh)]; +#endif + } + } else lpszTemp=_tcsstr(lpXML, pClear->lpszClose); + + if (lpszTemp) + { + // Cache the size and increment the index + cbTemp = (int)(lpszTemp - lpXML); + + pXML->nIndex += cbTemp+(int)_tcslen(pClear->lpszClose); + + // Add the clear node to the current element + addClear_priv(MEMORYINCREASE,stringDup(lpXML,cbTemp), pClear->lpszOpen, pClear->lpszClose,-1); + return 0; + } + + // If we failed to find the end tag + pXML->error = eXMLErrorUnmatchedEndClearTag; + return 1; +} + +void XMLNode::exactMemory(XMLNodeData *d) +{ + if (d->pOrder) d->pOrder=(int*)realloc(d->pOrder,(d->nChild+d->nText+d->nClear)*sizeof(int)); + if (d->pChild) d->pChild=(XMLNode*)realloc(d->pChild,d->nChild*sizeof(XMLNode)); + if (d->pAttribute) d->pAttribute=(XMLAttribute*)realloc(d->pAttribute,d->nAttribute*sizeof(XMLAttribute)); + if (d->pText) d->pText=(XMLCSTR*)realloc(d->pText,d->nText*sizeof(XMLSTR)); + if (d->pClear) d->pClear=(XMLClear *)realloc(d->pClear,d->nClear*sizeof(XMLClear)); +} + +char XMLNode::maybeAddTxT(void *pa, XMLCSTR tokenPStr) +{ + XML *pXML=(XML *)pa; + XMLCSTR lpszText=pXML->lpszText; + if (!lpszText) return 0; + if (dropWhiteSpace) while (XML_isSPACECHAR(*lpszText)&&(lpszText!=tokenPStr)) lpszText++; + int cbText = (int)(tokenPStr - lpszText); + if (!cbText) { pXML->lpszText=NULL; return 0; } + if (dropWhiteSpace) { cbText--; while ((cbText)&&XML_isSPACECHAR(lpszText[cbText])) cbText--; cbText++; } + if (!cbText) { pXML->lpszText=NULL; return 0; } + lpszText=fromXMLString(lpszText,cbText,pXML); + if (!lpszText) return 1; + addText_priv(MEMORYINCREASE,lpszText,-1); + pXML->lpszText=NULL; + return 0; +} +// private: +// Recursively parse an XML element. +int XMLNode::ParseXMLElement(void *pa) +{ + XML *pXML=(XML *)pa; + int cbToken; + enum XMLTokenTypeTag type; + NextToken token; + XMLCSTR lpszTemp=NULL; + int cbTemp=0; + char nDeclaration; + XMLNode pNew; + enum Status status; // inside or outside a tag + enum Attrib attrib = eAttribName; + + assert(pXML); + + // If this is the first call to the function + if (pXML->nFirst) + { + // Assume we are outside of a tag definition + pXML->nFirst = FALSE; + status = eOutsideTag; + } else + { + // If this is not the first call then we should only be called when inside a tag. + status = eInsideTag; + } + + // Iterate through the tokens in the document + for(;;) + { + // Obtain the next token + token = GetNextToken(pXML, &cbToken, &type); + + if (type != eTokenError) + { + // Check the current status + switch(status) + { + + // If we are outside of a tag definition + case eOutsideTag: + + // Check what type of token we obtained + switch(type) + { + // If we have found text or quoted text + case eTokenText: + case eTokenCloseTag: /* '>' */ + case eTokenShortHandClose: /* '/>' */ + case eTokenQuotedText: + case eTokenEquals: + break; + + // If we found a start tag '<' and declarations 'error = eXMLErrorMissingTagName; + return FALSE; + } + + // If we found a new element which is the same as this + // element then we need to pass this back to the caller.. + +#ifdef APPROXIMATE_PARSING + if (d->lpszName && + myTagCompare(d->lpszName, token.pStr) == 0) + { + // Indicate to the caller that it needs to create a + // new element. + pXML->lpNewElement = token.pStr; + pXML->cbNewElement = cbToken; + return TRUE; + } else +#endif + { + // If the name of the new element differs from the name of + // the current element we need to add the new element to + // the current one and recurse + pNew = addChild_priv(MEMORYINCREASE,stringDup(token.pStr,cbToken), nDeclaration,-1); + + while (!pNew.isEmpty()) + { + // Callself to process the new node. If we return + // FALSE this means we dont have any more + // processing to do... + + if (!pNew.ParseXMLElement(pXML)) return FALSE; + else + { + // If the call to recurse this function + // evented in a end tag specified in XML then + // we need to unwind the calls to this + // function until we find the appropriate node + // (the element name and end tag name must + // match) + if (pXML->cbEndTag) + { + // If we are back at the root node then we + // have an unmatched end tag + if (!d->lpszName) + { + pXML->error=eXMLErrorUnmatchedEndTag; + return FALSE; + } + + // If the end tag matches the name of this + // element then we only need to unwind + // once more... + + if (myTagCompare(d->lpszName, pXML->lpEndTag)==0) + { + pXML->cbEndTag = 0; + } + + return TRUE; + } else + if (pXML->cbNewElement) + { + // If the call indicated a new element is to + // be created on THIS element. + + // If the name of this element matches the + // name of the element we need to create + // then we need to return to the caller + // and let it process the element. + + if (myTagCompare(d->lpszName, pXML->lpNewElement)==0) + { + return TRUE; + } + + // Add the new element and recurse + pNew = addChild_priv(MEMORYINCREASE,stringDup(pXML->lpNewElement,pXML->cbNewElement),0,-1); + pXML->cbNewElement = 0; + } + else + { + // If we didn't have a new element to create + pNew = emptyXMLNode; + + } + } + } + } + break; + + // If we found an end tag + case eTokenTagEnd: + + // If we have node text then add this to the element + if (maybeAddTxT(pXML,token.pStr)) return FALSE; + + // Find the name of the end tag + token = GetNextToken(pXML, &cbTemp, &type); + + // The end tag should be text + if (type != eTokenText) + { + pXML->error = eXMLErrorMissingEndTagName; + return FALSE; + } + lpszTemp = token.pStr; + + // After the end tag we should find a closing tag + token = GetNextToken(pXML, &cbToken, &type); + if (type != eTokenCloseTag) + { + pXML->error = eXMLErrorMissingEndTagName; + return FALSE; + } + pXML->lpszText=pXML->lpXML+pXML->nIndex; + + // We need to return to the previous caller. If the name + // of the tag cannot be found we need to keep returning to + // caller until we find a match + if (myTagCompare(d->lpszName, lpszTemp) != 0) +#ifdef STRICT_PARSING + { + pXML->error=eXMLErrorUnmatchedEndTag; + pXML->nIndexMissigEndTag=pXML->nIndex; + return FALSE; + } +#else + { + pXML->error=eXMLErrorMissingEndTag; + pXML->nIndexMissigEndTag=pXML->nIndex; + pXML->lpEndTag = lpszTemp; + pXML->cbEndTag = cbTemp; + } +#endif + + // Return to the caller + exactMemory(d); + return TRUE; + + // If we found a clear (unformatted) token + case eTokenClear: + // If we have node text then add this to the element + if (maybeAddTxT(pXML,token.pStr)) return FALSE; + if (parseClearTag(pXML, token.pClr)) return FALSE; + pXML->lpszText=pXML->lpXML+pXML->nIndex; + break; + + default: + break; + } + break; + + // If we are inside a tag definition we need to search for attributes + case eInsideTag: + + // Check what part of the attribute (name, equals, value) we + // are looking for. + switch(attrib) + { + // If we are looking for a new attribute + case eAttribName: + + // Check what the current token type is + switch(type) + { + // If the current type is text... + // Eg. 'attribute' + case eTokenText: + // Cache the token then indicate that we are next to + // look for the equals + lpszTemp = token.pStr; + cbTemp = cbToken; + attrib = eAttribEquals; + break; + + // If we found a closing tag... + // Eg. '>' + case eTokenCloseTag: + // We are now outside the tag + status = eOutsideTag; + pXML->lpszText=pXML->lpXML+pXML->nIndex; + break; + + // If we found a short hand '/>' closing tag then we can + // return to the caller + case eTokenShortHandClose: + exactMemory(d); + pXML->lpszText=pXML->lpXML+pXML->nIndex; + return TRUE; + + // Errors... + case eTokenQuotedText: /* '"SomeText"' */ + case eTokenTagStart: /* '<' */ + case eTokenTagEnd: /* 'error = eXMLErrorUnexpectedToken; + return FALSE; + default: break; + } + break; + + // If we are looking for an equals + case eAttribEquals: + // Check what the current token type is + switch(type) + { + // If the current type is text... + // Eg. 'Attribute AnotherAttribute' + case eTokenText: + // Add the unvalued attribute to the list + addAttribute_priv(MEMORYINCREASE,stringDup(lpszTemp,cbTemp), NULL); + // Cache the token then indicate. We are next to + // look for the equals attribute + lpszTemp = token.pStr; + cbTemp = cbToken; + break; + + // If we found a closing tag 'Attribute >' or a short hand + // closing tag 'Attribute />' + case eTokenShortHandClose: + case eTokenCloseTag: + // If we are a declaration element 'lpszText=pXML->lpXML+pXML->nIndex; + + if (d->isDeclaration && + (lpszTemp[cbTemp-1]) == _T('?')) + { + cbTemp--; + } + + if (cbTemp) + { + // Add the unvalued attribute to the list + addAttribute_priv(MEMORYINCREASE,stringDup(lpszTemp,cbTemp), NULL); + } + + // If this is the end of the tag then return to the caller + if (type == eTokenShortHandClose) + { + exactMemory(d); + return TRUE; + } + + // We are now outside the tag + status = eOutsideTag; + break; + + // If we found the equals token... + // Eg. 'Attribute =' + case eTokenEquals: + // Indicate that we next need to search for the value + // for the attribute + attrib = eAttribValue; + break; + + // Errors... + case eTokenQuotedText: /* 'Attribute "InvalidAttr"'*/ + case eTokenTagStart: /* 'Attribute <' */ + case eTokenTagEnd: /* 'Attribute error = eXMLErrorUnexpectedToken; + return FALSE; + default: break; + } + break; + + // If we are looking for an attribute value + case eAttribValue: + // Check what the current token type is + switch(type) + { + // If the current type is text or quoted text... + // Eg. 'Attribute = "Value"' or 'Attribute = Value' or + // 'Attribute = 'Value''. + case eTokenText: + case eTokenQuotedText: + // If we are a declaration element 'isDeclaration && + (token.pStr[cbToken-1]) == _T('?')) + { + cbToken--; + } + + if (cbTemp) + { + // Add the valued attribute to the list + if (type==eTokenQuotedText) { token.pStr++; cbToken-=2; } + XMLCSTR attrVal=token.pStr; + if (attrVal) + { + attrVal=fromXMLString(attrVal,cbToken,pXML); + if (!attrVal) return FALSE; + } + addAttribute_priv(MEMORYINCREASE,stringDup(lpszTemp,cbTemp),attrVal); + } + + // Indicate we are searching for a new attribute + attrib = eAttribName; + break; + + // Errors... + case eTokenTagStart: /* 'Attr = <' */ + case eTokenTagEnd: /* 'Attr = ' */ + case eTokenShortHandClose: /* "Attr = />" */ + case eTokenEquals: /* 'Attr = =' */ + case eTokenDeclaration: /* 'Attr = error = eXMLErrorUnexpectedToken; + return FALSE; + break; + default: break; + } + } + } + } + // If we failed to obtain the next token + else + { + if ((!d->isDeclaration)&&(d->pParent)) + { +#ifdef STRICT_PARSING + pXML->error=eXMLErrorUnmatchedEndTag; +#else + pXML->error=eXMLErrorMissingEndTag; +#endif + pXML->nIndexMissigEndTag=pXML->nIndex; + } + return FALSE; + } + } +} + +// Count the number of lines and columns in an XML string. +static void CountLinesAndColumns(XMLCSTR lpXML, int nUpto, XMLResults *pResults) +{ + XMLCHAR ch; + assert(lpXML); + assert(pResults); + + struct XML xml={ lpXML,lpXML, 0, 0, eXMLErrorNone, NULL, 0, NULL, 0, TRUE }; + + pResults->nLine = 1; + pResults->nColumn = 1; + while (xml.nIndexnColumn++; + else + { + pResults->nLine++; + pResults->nColumn=1; + } + } +} + +// Parse XML and return the root element. +XMLNode XMLNode::parseString(XMLCSTR lpszXML, XMLCSTR tag, XMLResults *pResults) +{ + if (!lpszXML) + { + if (pResults) + { + pResults->error=eXMLErrorNoElements; + pResults->nLine=0; + pResults->nColumn=0; + } + return emptyXMLNode; + } + + XMLNode xnode(NULL,NULL,FALSE); + struct XML xml={ lpszXML, lpszXML, 0, 0, eXMLErrorNone, NULL, 0, NULL, 0, TRUE }; + + // Create header element + xnode.ParseXMLElement(&xml); + enum XMLError error = xml.error; + if ((xnode.nChildNode()==1)&&(xnode.nElement()==1)) xnode=xnode.getChildNode(); // skip the empty node + + // If no error occurred + if ((error==eXMLErrorNone)||(error==eXMLErrorMissingEndTag)) + { + XMLCSTR name=xnode.getName(); + if (tag&&_tcslen(tag)&&((!name)||(_tcsicmp(xnode.getName(),tag)))) + { + XMLNode nodeTmp; + int i=0; + while (i=xnode.nChildNode()) + { + if (pResults) + { + pResults->error=eXMLErrorFirstTagNotFound; + pResults->nLine=0; + pResults->nColumn=0; + } + return emptyXMLNode; + } + xnode=nodeTmp; + } + } else + { + // Cleanup: this will destroy all the nodes + xnode = emptyXMLNode; + } + + + // If we have been given somewhere to place results + if (pResults) + { + pResults->error = error; + + // If we have an error + if (error!=eXMLErrorNone) + { + if (error==eXMLErrorMissingEndTag) xml.nIndex=xml.nIndexMissigEndTag; + // Find which line and column it starts on. + CountLinesAndColumns(xml.lpXML, xml.nIndex, pResults); + } + } + return xnode; +} + +XMLNode XMLNode::parseFile(XMLCSTR filename, XMLCSTR tag, XMLResults *pResults) +{ + if (pResults) { pResults->nLine=0; pResults->nColumn=0; } + FILE *f=_tfopen(filename,_T("rb")); + if (f==NULL) { if (pResults) pResults->error=eXMLErrorFileNotFound; return emptyXMLNode; } + fseek(f,0,SEEK_END); + int l=ftell(f),headerSz=0; + if (!l) { if (pResults) pResults->error=eXMLErrorEmpty; return emptyXMLNode; } + fseek(f,0,SEEK_SET); + unsigned char *buf=(unsigned char*)malloc(l+1); + fread(buf,l,1,f); + fclose(f); + buf[l]=0; +#ifdef _XMLUNICODE + if (guessUnicodeChars) + { + if (!myIsTextUnicode(buf,l)) + { + if ((buf[0]==0xef)&&(buf[1]==0xbb)&&(buf[2]==0xbf)) headerSz=3; + XMLSTR b2=myMultiByteToWideChar((const char*)(buf+headerSz),l-headerSz); + free(buf); buf=(unsigned char*)b2; headerSz=0; + } else + { + if ((buf[0]==0xef)&&(buf[1]==0xff)) headerSz=2; + if ((buf[0]==0xff)&&(buf[1]==0xfe)) headerSz=2; + } + } +#else + if (guessUnicodeChars) + { + if (myIsTextUnicode(buf,l)) + { + l/=sizeof(wchar_t); + if ((buf[0]==0xef)&&(buf[1]==0xff)) headerSz=2; + if ((buf[0]==0xff)&&(buf[1]==0xfe)) headerSz=2; + char *b2=myWideCharToMultiByte((const wchar_t*)(buf+headerSz),l-headerSz); + free(buf); buf=(unsigned char*)b2; headerSz=0; + } else + { + if ((buf[0]==0xef)&&(buf[1]==0xbb)&&(buf[2]==0xbf)) headerSz=3; + } + } +#endif + + if (!buf) { if (pResults) pResults->error=eXMLErrorCharConversionError; return emptyXMLNode; } + XMLNode x=parseString((XMLSTR)(buf+headerSz),tag,pResults); + free(buf); + return x; +} + +static inline void charmemset(XMLSTR dest,XMLCHAR c,int l) { while (l--) *(dest++)=c; } +// private: +// Creates an user friendly XML string from a given element with +// appropriate white space and carriage returns. +// +// This recurses through all subnodes then adds contents of the nodes to the +// string. +int XMLNode::CreateXMLStringR(XMLNodeData *pEntry, XMLSTR lpszMarker, int nFormat) +{ + int nResult = 0; + int cb; + int cbElement; + int nChildFormat=-1; + int nElementI=pEntry->nChild+pEntry->nText+pEntry->nClear; + int i,j; + + assert(pEntry); + +#define LENSTR(lpsz) (lpsz ? _tcslen(lpsz) : 0) + + // If the element has no name then assume this is the head node. + cbElement = (int)LENSTR(pEntry->lpszName); + + if (cbElement) + { + // "isDeclaration) lpszMarker[nResult++]=_T('?'); + _tcscpy(&lpszMarker[nResult], pEntry->lpszName); + nResult+=cbElement; + lpszMarker[nResult++]=_T(' '); + + } else + { + nResult+=cbElement+2+cb; + if (pEntry->isDeclaration) nResult++; + } + + // Enumerate attributes and add them to the string + XMLAttribute *pAttr=pEntry->pAttribute; + for (i=0; inAttribute; i++) + { + // "Attrib + cb = (int)LENSTR(pAttr->lpszName); + if (cb) + { + if (lpszMarker) _tcscpy(&lpszMarker[nResult], pAttr->lpszName); + nResult += cb; + // "Attrib=Value " + if (pAttr->lpszValue) + { + cb=(int)lengthXMLString(pAttr->lpszValue); + if (lpszMarker) + { + lpszMarker[nResult]=_T('='); + lpszMarker[nResult+1]=_T('"'); + if (cb) toXMLString(&lpszMarker[nResult+2],pAttr->lpszValue); + lpszMarker[nResult+cb+2]=_T('"'); + } + nResult+=cb+3; + } + if (lpszMarker) lpszMarker[nResult] = _T(' '); + nResult++; + } + pAttr++; + } + + if (pEntry->isDeclaration) + { + if (lpszMarker) + { + lpszMarker[nResult-1]=_T('?'); + lpszMarker[nResult]=_T('>'); + } + nResult++; + if (nFormat!=-1) + { + if (lpszMarker) lpszMarker[nResult]=_T('\n'); + nResult++; + } + } else + // If there are child nodes we need to terminate the start tag + if (nElementI) + { + if (lpszMarker) lpszMarker[nResult-1]=_T('>'); + if (nFormat!=-1) + { + if (lpszMarker) lpszMarker[nResult]=_T('\n'); + nResult++; + } + } else nResult--; + } + + // Calculate the child format for when we recurse. This is used to + // determine the number of spaces used for prefixes. + if (nFormat!=-1) + { + if (cbElement&&(!pEntry->isDeclaration)) nChildFormat=nFormat+1; + else nChildFormat=nFormat; + } + + // Enumerate through remaining children + for (i=0; ipOrder[i]; + switch((XMLElementType)(j&3)) + { + // Text nodes + case eNodeText: + { + // "Text" + XMLCSTR pChild=pEntry->pText[j>>2]; + cb = (int)lengthXMLString(pChild); + if (cb) + { + if (nFormat!=-1) + { + if (lpszMarker) + { + charmemset(&lpszMarker[nResult],INDENTCHAR,sizeof(XMLCHAR)*(nFormat + 1)); + toXMLString(&lpszMarker[nResult+nFormat+1],pChild); + lpszMarker[nResult+nFormat+1+cb]=_T('\n'); + } + nResult+=cb+nFormat+2; + } else + { + if (lpszMarker) toXMLString(&lpszMarker[nResult], pChild); + nResult += cb; + } + } + break; + } + + // Clear type nodes + case eNodeClear: + { + XMLClear *pChild=pEntry->pClear+(j>>2); + // "OpenTag" + cb = (int)LENSTR(pChild->lpszOpenTag); + if (cb) + { + if (nFormat!=-1) + { + if (lpszMarker) + { + charmemset(&lpszMarker[nResult], INDENTCHAR, sizeof(XMLCHAR)*(nFormat + 1)); + _tcscpy(&lpszMarker[nResult+nFormat+1], pChild->lpszOpenTag); + } + nResult+=cb+nFormat+1; + } + else + { + if (lpszMarker)_tcscpy(&lpszMarker[nResult], pChild->lpszOpenTag); + nResult += cb; + } + } + + // "OpenTag Value" + cb = (int)LENSTR(pChild->lpszValue); + if (cb) + { + if (lpszMarker) _tcscpy(&lpszMarker[nResult], pChild->lpszValue); + nResult += cb; + } + + // "OpenTag Value CloseTag" + cb = (int)LENSTR(pChild->lpszCloseTag); + if (cb) + { + if (lpszMarker) _tcscpy(&lpszMarker[nResult], pChild->lpszCloseTag); + nResult += cb; + } + + if (nFormat!=-1) + { + if (lpszMarker) lpszMarker[nResult] = _T('\n'); + nResult++; + } + break; + } + + // Element nodes + case eNodeChild: + { + // Recursively add child nodes + nResult += CreateXMLStringR(pEntry->pChild[j>>2].d, lpszMarker ? lpszMarker + nResult : 0, nChildFormat); + break; + } + default: break; + } + } + + if ((cbElement)&&(!pEntry->isDeclaration)) + { + // If we have child entries we need to use long XML notation for + // closing the element - "blah blah blah" + if (nElementI) + { + // "\0" + if (lpszMarker) + { + if (nFormat != -1) + { + if (nFormat) + { + charmemset(&lpszMarker[nResult], INDENTCHAR,sizeof(XMLCHAR)*nFormat); + nResult+=nFormat; + } + } + + _tcscpy(&lpszMarker[nResult], _T("lpszName); + nResult += cbElement; + + if (nFormat == -1) + { + _tcscpy(&lpszMarker[nResult], _T(">")); + nResult++; + } else + { + _tcscpy(&lpszMarker[nResult], _T(">\n")); + nResult+=2; + } + } else + { + if (nFormat != -1) nResult+=cbElement+4+nFormat; + else nResult+=cbElement+3; + } + } else + { + // If there are no children we can use shorthand XML notation - + // "" + // "/>\0" + if (lpszMarker) + { + if (nFormat == -1) + { + _tcscpy(&lpszMarker[nResult], _T("/>")); + nResult += 2; + } + else + { + _tcscpy(&lpszMarker[nResult], _T("/>\n")); + nResult += 3; + } + } + else + { + nResult += nFormat == -1 ? 2 : 3; + } + } + } + + return nResult; +} + +#undef LENSTR + +// Create an XML string +// @param int nFormat - 0 if no formatting is required +// otherwise nonzero for formatted text +// with carriage returns and indentation. +// @param int *pnSize - [out] pointer to the size of the +// returned string not including the +// NULL terminator. +// @return XMLSTR - Allocated XML string, you must free +// this with free(). +XMLSTR XMLNode::createXMLString(int nFormat, int *pnSize) const +{ + if (!d) { if (pnSize) *pnSize=0; return NULL; } + + XMLSTR lpszResult = NULL; + int cbStr; + + // Recursively Calculate the size of the XML string + if (!dropWhiteSpace) nFormat=0; + nFormat = nFormat ? 0 : -1; + cbStr = CreateXMLStringR(d, 0, nFormat); + assert(cbStr); + // Alllocate memory for the XML string + the NULL terminator and + // create the recursively XML string. + lpszResult=(XMLSTR)malloc((cbStr+1)*sizeof(XMLCHAR)); + CreateXMLStringR(d, lpszResult, nFormat); + if (pnSize) *pnSize = cbStr; + return lpszResult; +} + +XMLNode::~XMLNode() { deleteNodeContent(); } + +int XMLNode::detachFromParent(XMLNodeData *d) +{ + XMLNode *pa=d->pParent->pChild; + int i=0; + while (((void*)(pa[i].d))!=((void*)d)) i++; + d->pParent->nChild--; + if (d->pParent->nChild) memmove(pa+i,pa+i+1,(d->pParent->nChild-i)*sizeof(XMLNode)); + else { free(pa); d->pParent->pChild=NULL; } + return removeOrderElement(d->pParent,eNodeChild,i); +} + +void XMLNode::deleteNodeContent(char force) +{ + if (!d) return; + (d->ref_count) --; + if ((d->ref_count==0)||force) + { + int i; + if (d->pParent) detachFromParent(d); + for(i=0; inChild; i++) { d->pChild[i].d->pParent=NULL; d->pChild[i].deleteNodeContent(force); } + free(d->pChild); + for(i=0; inText; i++) free((void*)d->pText[i]); + free(d->pText); + for(i=0; inClear; i++) free((void*)d->pClear[i].lpszValue); + free(d->pClear); + for(i=0; inAttribute; i++) + { + free((void*)d->pAttribute[i].lpszName); + if (d->pAttribute[i].lpszValue) free((void*)d->pAttribute[i].lpszValue); + } + free(d->pAttribute); + free(d->pOrder); + free((void*)d->lpszName); + free(d); + d=NULL; + } +} + +XMLNode XMLNode::addChild(XMLNode childNode, int pos) +{ + XMLNodeData *dc=childNode.d; + if ((!dc)||(!d)) return childNode; + if (dc->pParent) { if ((detachFromParent(dc)<=pos)&&(dc->pParent==d)) pos--; } else dc->ref_count++; + dc->pParent=d; +// int nc=d->nChild; +// d->pChild=(XMLNode*)myRealloc(d->pChild,(nc+1),memoryIncrease,sizeof(XMLNode)); + d->pChild=(XMLNode*)addToOrder(0,&pos,d->nChild,d->pChild,sizeof(XMLNode),eNodeChild); + d->pChild[pos].d=dc; + d->nChild++; + return childNode; +} + +void XMLNode::deleteAttribute(int i) +{ + if ((!d)||(i<0)||(i>=d->nAttribute)) return; + d->nAttribute--; + XMLAttribute *p=d->pAttribute+i; + free((void*)p->lpszName); + if (p->lpszValue) free((void*)p->lpszValue); + if (d->nAttribute) memmove(p,p+1,(d->nAttribute-i)*sizeof(XMLAttribute)); else { free(p); d->pAttribute=NULL; } +} + +void XMLNode::deleteAttribute(XMLAttribute *a){ if (a) deleteAttribute(a->lpszName); } +void XMLNode::deleteAttribute(XMLCSTR lpszName) +{ + int j=0; + getAttribute(lpszName,&j); + if (j) deleteAttribute(j-1); +} + +XMLAttribute *XMLNode::updateAttribute_WOSD(XMLCSTR lpszNewValue, XMLCSTR lpszNewName,int i) +{ + if (!d) return NULL; + if (i>=d->nAttribute) + { + if (lpszNewName) return addAttribute_WOSD(lpszNewName,lpszNewValue); + return NULL; + } + XMLAttribute *p=d->pAttribute+i; + if (p->lpszValue&&p->lpszValue!=lpszNewValue) free((void*)p->lpszValue); + p->lpszValue=lpszNewValue; + if (lpszNewName&&p->lpszName!=lpszNewName) { free((void*)p->lpszName); p->lpszName=lpszNewName; }; + return p; +} + +XMLAttribute *XMLNode::updateAttribute_WOSD(XMLAttribute *newAttribute, XMLAttribute *oldAttribute) +{ + if (oldAttribute) return updateAttribute_WOSD(newAttribute->lpszValue,newAttribute->lpszName,oldAttribute->lpszName); + return addAttribute_WOSD(newAttribute->lpszName,newAttribute->lpszValue); +} + +XMLAttribute *XMLNode::updateAttribute_WOSD(XMLCSTR lpszNewValue, XMLCSTR lpszNewName,XMLCSTR lpszOldName) +{ + int j=0; + getAttribute(lpszOldName,&j); + if (j) return updateAttribute_WOSD(lpszNewValue,lpszNewName,j-1); + else + { + if (lpszNewName) return addAttribute_WOSD(lpszNewName,lpszNewValue); + else return addAttribute_WOSD(stringDup(lpszOldName),lpszNewValue); + } +} + +int XMLNode::indexText(XMLCSTR lpszValue) const +{ + if (!d) return -1; + int i,l=d->nText; + if (!lpszValue) { if (l) return 0; return -1; } + XMLCSTR *p=d->pText; + for (i=0; i=d->nText)) return; + d->nText--; + XMLCSTR *p=d->pText+i; + free((void*)*p); + if (d->nText) memmove(p,p+1,(d->nText-i)*sizeof(XMLCSTR)); else { free(p); d->pText=NULL; } + removeOrderElement(d,eNodeText,i); +} + +void XMLNode::deleteText(XMLCSTR lpszValue) { deleteText(indexText(lpszValue)); } + +XMLCSTR XMLNode::updateText_WOSD(XMLCSTR lpszNewValue, int i) +{ + if (!d) return NULL; + if (i>=d->nText) return addText_WOSD(lpszNewValue); + XMLCSTR *p=d->pText+i; + if (*p!=lpszNewValue) { free((void*)*p); *p=lpszNewValue; } + return lpszNewValue; +} + +XMLCSTR XMLNode::updateText_WOSD(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue) +{ + if (!d) return NULL; + int i=indexText(lpszOldValue); + if (i>=0) return updateText_WOSD(lpszNewValue,i); + return addText_WOSD(lpszNewValue); +} + +void XMLNode::deleteClear(int i) +{ + if ((!d)||(i<0)||(i>=d->nClear)) return; + d->nClear--; + XMLClear *p=d->pClear+i; + free((void*)p->lpszValue); + if (d->nClear) memmove(p,p+1,(d->nText-i)*sizeof(XMLClear)); else { free(p); d->pClear=NULL; } + removeOrderElement(d,eNodeClear,i); +} + +int XMLNode::indexClear(XMLCSTR lpszValue) const +{ + if (!d) return -1; + int i,l=d->nClear; + if (!lpszValue) { if (l) return 0; return -1; } + XMLClear *p=d->pClear; + for (i=0; ilpszValue); } + +XMLClear *XMLNode::updateClear_WOSD(XMLCSTR lpszNewContent, int i) +{ + if (!d) return NULL; + if (i>=d->nClear) + { + return addClear_WOSD(XMLClearTags[0].lpszOpen,lpszNewContent,XMLClearTags[0].lpszClose); + } + XMLClear *p=d->pClear+i; + if (lpszNewContent!=p->lpszValue) { free((void*)p->lpszValue); p->lpszValue=lpszNewContent; } + return p; +} + +XMLClear *XMLNode::updateClear_WOSD(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue) +{ + if (!d) return NULL; + int i=indexClear(lpszOldValue); + if (i>=0) return updateClear_WOSD(lpszNewValue,i); + return addClear_WOSD(lpszNewValue,XMLClearTags[0].lpszOpen,XMLClearTags[0].lpszClose); +} + +XMLClear *XMLNode::updateClear_WOSD(XMLClear *newP,XMLClear *oldP) +{ + if (oldP) return updateClear_WOSD(newP->lpszValue,oldP->lpszValue); + return NULL; +} + +XMLNode& XMLNode::operator=( const XMLNode& A ) +{ + // shallow copy + if (this != &A) + { + deleteNodeContent(); + d=A.d; + if (d) (d->ref_count) ++ ; + } + return *this; +} + +XMLNode::XMLNode(const XMLNode &A) +{ + // shallow copy + d=A.d; + if (d) (d->ref_count)++ ; +} + +int XMLNode::nChildNode(XMLCSTR name) const +{ + if (!d) return 0; + int i,j=0,n=d->nChild; + XMLNode *pc=d->pChild; + for (i=0; id->lpszName, name)==0) j++; + pc++; + } + return j; +} + +XMLNode XMLNode::getChildNode(XMLCSTR name, int *j) const +{ + if (!d) return emptyXMLNode; + int i=0,n=d->nChild; + if (j) i=*j; + XMLNode *pc=d->pChild+i; + for (; id->lpszName, name)==0) + { + if (j) *j=i+1; + return *pc; + } + pc++; + } + return emptyXMLNode; +} + +XMLNode XMLNode::getChildNode(XMLCSTR name, int j) const +{ + if (!d) return emptyXMLNode; + int i=0; + while (j-->0) getChildNode(name,&i); + return getChildNode(name,&i); +} + +int XMLNode::positionOfText (int i) const { if (i>=d->nText ) i=d->nText-1; return findPosition(d,i,eNodeText ); } +int XMLNode::positionOfClear (int i) const { if (i>=d->nClear) i=d->nClear-1; return findPosition(d,i,eNodeClear); } +int XMLNode::positionOfChildNode(int i) const { if (i>=d->nChild) i=d->nChild-1; return findPosition(d,i,eNodeChild); } +int XMLNode::positionOfText (XMLCSTR lpszValue) const { return positionOfText (indexText (lpszValue)); } +int XMLNode::positionOfClear(XMLCSTR lpszValue) const { return positionOfClear(indexClear(lpszValue)); } +int XMLNode::positionOfClear(XMLClear *a) const { if (a) return positionOfClear(a->lpszValue); return positionOfClear(); } +int XMLNode::positionOfChildNode(XMLNode x) const +{ + if ((!d)||(!x.d)) return -1; + XMLNodeData *dd=x.d; + XMLNode *pc=d->pChild; + int i=d->nChild; + while (i--) if (pc[i].d==dd) return findPosition(d,i,eNodeChild); + return -1; +} +int XMLNode::positionOfChildNode(XMLCSTR name, int count) const +{ + if (!name) return positionOfChildNode(count); + int j=0; + do { getChildNode(name,&j); if (j<0) return -1; } while (count--); + return findPosition(d,j-1,eNodeChild); +} + +XMLNode XMLNode::getChildNodeWithAttribute(XMLCSTR name,XMLCSTR attributeName,XMLCSTR attributeValue, int *k) const +{ + int i=0,j; + if (k) i=*k; + XMLNode x; + XMLCSTR t; + do + { + x=getChildNode(name,&i); + if (!x.isEmpty()) + { + if (attributeValue) + { + j=0; + do + { + t=x.getAttribute(attributeName,&j); + if (t&&(_tcsicmp(attributeValue,t)==0)) { if (k) *k=i+1; return x; } + } while (t); + } else + { + if (x.isAttributeSet(attributeName)) { if (k) *k=i+1; return x; } + } + } + } while (!x.isEmpty()); + return emptyXMLNode; +} + +// Find an attribute on an node. +XMLCSTR XMLNode::getAttribute(XMLCSTR lpszAttrib, int *j) const +{ + if (!d) return NULL; + int i=0,n=d->nAttribute; + if (j) i=*j; + XMLAttribute *pAttr=d->pAttribute+i; + for (; ilpszName, lpszAttrib)==0) + { + if (j) *j=i+1; + return pAttr->lpszValue; + } + pAttr++; + } + return NULL; +} + +char XMLNode::isAttributeSet(XMLCSTR lpszAttrib) const +{ + if (!d) return FALSE; + int i,n=d->nAttribute; + XMLAttribute *pAttr=d->pAttribute; + for (i=0; ilpszName, lpszAttrib)==0) + { + return TRUE; + } + pAttr++; + } + return FALSE; +} + +XMLCSTR XMLNode::getAttribute(XMLCSTR name, int j) const +{ + if (!d) return NULL; + int i=0; + while (j-->0) getAttribute(name,&i); + return getAttribute(name,&i); +} + +XMLNodeContents XMLNode::enumContents(int i) const +{ + XMLNodeContents c; + if (!d) { c.type=eNodeNULL; return c; } + if (inAttribute) + { + c.type=eNodeAttribute; + c.attrib=d->pAttribute[i]; + return c; + } + i-=d->nAttribute; + c.type=(XMLElementType)(d->pOrder[i]&3); + i=(d->pOrder[i])>>2; + switch (c.type) + { + case eNodeChild: c.child = d->pChild[i]; break; + case eNodeText: c.text = d->pText[i]; break; + case eNodeClear: c.clear = d->pClear[i]; break; + default: break; + } + return c; +} + +XMLCSTR XMLNode::getName() const { if (!d) return NULL; return d->lpszName; } +int XMLNode::nText() const { if (!d) return 0; return d->nText; } +int XMLNode::nChildNode() const { if (!d) return 0; return d->nChild; } +int XMLNode::nAttribute() const { if (!d) return 0; return d->nAttribute; } +int XMLNode::nClear() const { if (!d) return 0; return d->nClear; } +int XMLNode::nElement() const { if (!d) return 0; return d->nAttribute+d->nChild+d->nText+d->nClear; } +XMLClear XMLNode::getClear (int i) const { if ((!d)||(i>=d->nClear )) return emptyXMLClear; return d->pClear[i]; } +XMLAttribute XMLNode::getAttribute (int i) const { if ((!d)||(i>=d->nAttribute)) return emptyXMLAttribute; return d->pAttribute[i]; } +XMLCSTR XMLNode::getAttributeName (int i) const { if ((!d)||(i>=d->nAttribute)) return NULL; return d->pAttribute[i].lpszName; } +XMLCSTR XMLNode::getAttributeValue(int i) const { if ((!d)||(i>=d->nAttribute)) return NULL; return d->pAttribute[i].lpszValue; } +XMLCSTR XMLNode::getText (int i) const { if ((!d)||(i>=d->nText )) return NULL; return d->pText[i]; } +XMLNode XMLNode::getChildNode (int i) const { if ((!d)||(i>=d->nChild )) return emptyXMLNode; return d->pChild[i]; } +XMLNode XMLNode::getParentNode ( ) const { if ((!d)||(!d->pParent )) return emptyXMLNode; return XMLNode(d->pParent); } +char XMLNode::isDeclaration ( ) const { if (!d) return 0; return d->isDeclaration; } +char XMLNode::isEmpty ( ) const { return (d==NULL); } + +XMLNode XMLNode::addChild(XMLCSTR lpszName, char isDeclaration, int pos) + { return addChild_priv(0,stringDup(lpszName),isDeclaration,pos); } +XMLNode XMLNode::addChild_WOSD(XMLCSTR lpszName, char isDeclaration, int pos) + { return addChild_priv(0,lpszName,isDeclaration,pos); } +XMLAttribute *XMLNode::addAttribute(XMLCSTR lpszName, XMLCSTR lpszValue) + { return addAttribute_priv(0,stringDup(lpszName),stringDup(lpszValue)); } +XMLAttribute *XMLNode::addAttribute_WOSD(XMLCSTR lpszName, XMLCSTR lpszValuev) + { return addAttribute_priv(0,lpszName,lpszValuev); } +XMLCSTR XMLNode::addText(XMLCSTR lpszValue, int pos) + { return addText_priv(0,stringDup(lpszValue),pos); } +XMLCSTR XMLNode::addText_WOSD(XMLCSTR lpszValue, int pos) + { return addText_priv(0,lpszValue,pos); } +XMLClear *XMLNode::addClear(XMLCSTR lpszValue, XMLCSTR lpszOpen, XMLCSTR lpszClose, int pos) + { return addClear_priv(0,stringDup(lpszValue),lpszOpen,lpszClose,pos); } +XMLClear *XMLNode::addClear_WOSD(XMLCSTR lpszValue, XMLCSTR lpszOpen, XMLCSTR lpszClose, int pos) + { return addClear_priv(0,lpszValue,lpszOpen,lpszClose,pos); } +XMLCSTR XMLNode::updateName(XMLCSTR lpszName) + { return updateName_WOSD(stringDup(lpszName)); } +XMLAttribute *XMLNode::updateAttribute(XMLAttribute *newAttribute, XMLAttribute *oldAttribute) + { return updateAttribute_WOSD(stringDup(newAttribute->lpszValue),stringDup(newAttribute->lpszName),oldAttribute->lpszName); } +XMLAttribute *XMLNode::updateAttribute(XMLCSTR lpszNewValue, XMLCSTR lpszNewName,int i) + { return updateAttribute_WOSD(stringDup(lpszNewValue),stringDup(lpszNewName),i); } +XMLAttribute *XMLNode::updateAttribute(XMLCSTR lpszNewValue, XMLCSTR lpszNewName,XMLCSTR lpszOldName) + { return updateAttribute_WOSD(stringDup(lpszNewValue),stringDup(lpszNewName),lpszOldName); } +XMLCSTR XMLNode::updateText(XMLCSTR lpszNewValue, int i) + { return updateText_WOSD(stringDup(lpszNewValue),i); } +XMLCSTR XMLNode::updateText(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue) + { return updateText_WOSD(stringDup(lpszNewValue),lpszOldValue); } +XMLClear *XMLNode::updateClear(XMLCSTR lpszNewContent, int i) + { return updateClear_WOSD(stringDup(lpszNewContent),i); } +XMLClear *XMLNode::updateClear(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue) + { return updateClear_WOSD(stringDup(lpszNewValue),lpszOldValue); } +XMLClear *XMLNode::updateClear(XMLClear *newP,XMLClear *oldP) + { return updateClear_WOSD(stringDup(newP->lpszValue),oldP->lpszValue); } + +void XMLNode::setGlobalOptions(char _guessUnicodeChars, char _strictUTF8Parsing, char _dropWhiteSpace) +{ + guessUnicodeChars=_guessUnicodeChars; dropWhiteSpace=_dropWhiteSpace; strictUTF8Parsing=_strictUTF8Parsing; +#ifndef _XMLUNICODE + if (_strictUTF8Parsing) XML_ByteTable=XML_utf8ByteTable; else XML_ByteTable=XML_asciiByteTable; +#endif +} + +char XMLNode::guessUTF8ParsingParameterValue(void *buf,int l, char useXMLEncodingAttribute) +{ +#ifdef _XMLUNICODE + return 0; +#else + if (l<25) return 0; + if (myIsTextUnicode(buf,l)) return 0; + unsigned char *b=(unsigned char*)buf; + if ((b[0]==0xef)&&(b[1]==0xbb)&&(b[2]==0xbf)) return 1; + + // Match utf-8 model ? + int i=0; + while (i>2 ]; + *(curr++)=base64EncodeTable[(inbuf[0]<<4)&0x3F]; + *(curr++)=base64Fillchar; + *(curr++)=base64Fillchar; + } else if (eLen==2) + { + j=(inbuf[0]<<8)|inbuf[1]; + *(curr++)=base64EncodeTable[ j>>10 ]; + *(curr++)=base64EncodeTable[(j>> 4)&0x3f]; + *(curr++)=base64EncodeTable[(j<< 2)&0x3f]; + *(curr++)=base64Fillchar; + } + *(curr++)=0; + return (XMLSTR)buf; +} + +unsigned int XMLParserBase64Tool::decodeSize(XMLCSTR data,XMLError *xe) +{ + if (xe) *xe=eXMLErrorNone; + int size=0; + unsigned char c; + //skip any extra characters (e.g. newlines or spaces) + while (*data) + { +#ifdef _XMLUNICODE + if (*data>255) { if (xe) *xe=eXMLErrorBase64DecodeIllegalCharacter; return 0; } +#endif + c=base64DecodeTable[(unsigned char)(*data)]; + if (c<97) size++; + else if (c==98) { if (xe) *xe=eXMLErrorBase64DecodeIllegalCharacter; return 0; } + data++; + } + if (xe&&(size%4!=0)) *xe=eXMLErrorBase64DataSizeIsNotMultipleOf4; + if (size==0) return 0; + do { data--; size--; } while(*data==base64Fillchar); size++; + return (unsigned int)((size*3)/4); +} + +unsigned char XMLParserBase64Tool::decode(XMLCSTR data, unsigned char *buf, int len, XMLError *xe) +{ + if (xe) *xe=eXMLErrorNone; + int i=0,p=0; + unsigned char d,c; + for(;;) + { + +#ifdef _XMLUNICODE +#define BASE64DECODE_READ_NEXT_CHAR(c) \ + do { \ + if (data[i]>255){ c=98; break; } \ + c=base64DecodeTable[(unsigned char)data[i++]]; \ + }while (c==97); \ + if(c==98){ if(xe)*xe=eXMLErrorBase64DecodeIllegalCharacter; return 0; } +#else +#define BASE64DECODE_READ_NEXT_CHAR(c) \ + do { c=base64DecodeTable[(unsigned char)data[i++]]; }while (c==97); \ + if(c==98){ if(xe)*xe=eXMLErrorBase64DecodeIllegalCharacter; return 0; } +#endif + + BASE64DECODE_READ_NEXT_CHAR(c) + if (c==99) { return 2; } + if (c==96) + { + if (p==(int)len) return 2; + if (xe) *xe=eXMLErrorBase64DecodeTruncatedData; + return 1; + } + + BASE64DECODE_READ_NEXT_CHAR(d) + if ((d==99)||(d==96)) { if (xe) *xe=eXMLErrorBase64DecodeTruncatedData; return 1; } + if (p==(int)len) { if (xe) *xe=eXMLErrorBase64DecodeBufferTooSmall; return 0; } + buf[p++]=(c<<2)|((d>>4)&0x3); + + BASE64DECODE_READ_NEXT_CHAR(c) + if (c==99) { if (xe) *xe=eXMLErrorBase64DecodeTruncatedData; return 1; } + if (p==(int)len) + { + if (c==96) return 2; + if (xe) *xe=eXMLErrorBase64DecodeBufferTooSmall; + return 0; + } + if (c==96) { if (xe) *xe=eXMLErrorBase64DecodeTruncatedData; return 1; } + buf[p++]=((d<<4)&0xf0)|((c>>2)&0xf); + + BASE64DECODE_READ_NEXT_CHAR(d) + if (d==99 ) { if (xe) *xe=eXMLErrorBase64DecodeTruncatedData; return 1; } + if (p==(int)len) + { + if (d==96) return 2; + if (xe) *xe=eXMLErrorBase64DecodeBufferTooSmall; + return 0; + } + if (d==96) { if (xe) *xe=eXMLErrorBase64DecodeTruncatedData; return 1; } + buf[p++]=((c<<6)&0xc0)|d; + } +} +#undef BASE64DECODE_READ_NEXT_CHAR + +void XMLParserBase64Tool::alloc(int newsize) +{ + if ((!buf)&&(newsize)) { buf=malloc(newsize); buflen=newsize; return; } + if (newsize>buflen) { buf=realloc(buf,newsize); buflen=newsize; } +} + +unsigned char *XMLParserBase64Tool::decode(XMLCSTR data, int *outlen, XMLError *xe) +{ + if (xe) *xe=eXMLErrorNone; + unsigned int len=decodeSize(data,xe); + if (outlen) *outlen=len; + if (!len) return NULL; + alloc(len+1); + if(!decode(data,(unsigned char*)buf,len,xe)){ return NULL; } + return (unsigned char*)buf; +} + diff --git a/dol/src/dol/visitor/hds/lib/xmlParser.h b/dol/src/dol/visitor/hds/lib/xmlParser.h new file mode 100644 index 0000000..7da09a5 --- /dev/null +++ b/dol/src/dol/visitor/hds/lib/xmlParser.h @@ -0,0 +1,529 @@ +/** + **************************************************************************** + *

XML.c - implementation file for basic XML parser written in ANSI C++ + * for portability. It works by using recursion and a node tree for breaking + * down the elements of an XML document.

+ * + * @version V2.23 + * @author Frank Vanden Berghen + * + * BSD license: + * Copyright (c) 2002, Frank Vanden Berghen + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Frank Vanden Berghen nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************** + */ +#ifndef __INCLUDE_XML_NODE__ +#define __INCLUDE_XML_NODE__ + +#include + +#ifdef _UNICODE +// If you comment the next "define" line then the library will never "switch to" _UNICODE (wchar_t*) mode (16/32 bits per characters). +// This is useful when you get error messages like: +// 'XMLNode::openFileHelper' : cannot convert parameter 2 from 'const char [5]' to 'const wchar_t *' +// The _XMLUNICODE preprocessor variable force the XMLParser library into either utf16/32-mode (the proprocessor variable +// must be defined) or utf8-mode(the pre-processor variable must be undefined). +#define _XMLUNICODE +#endif + +#if defined(WIN32) || defined(UNDER_CE) +// comment the next line if you are under windows and the compiler is not Microsoft Visual Studio (6.0 or .NET) +#define _XMLWINDOWS +#endif + +#ifdef DLLENTRY +#undef DLLENTRY +#endif +#ifdef _USE_XMLPARSER_DLL +#ifdef _DLL_EXPORTS_ +#define DLLENTRY __declspec(dllexport) +#else +#define DLLENTRY __declspec(dllimport) +#endif +#else +#define DLLENTRY +#endif + +// uncomment the next line if you want no support for wchar_t* (no need for the or libraries anymore to compile) +//#define XML_NO_WIDE_CHAR + +#ifdef XML_NO_WIDE_CHAR +#undef _XMLWINDOWS +#undef _XMLUNICODE +#endif + +#ifdef _XMLWINDOWS +#include +#else +#define DLLENTRY +#ifndef XML_NO_WIDE_CHAR +#include // to have 'wcsrtombs' for ANSI version + // to have 'mbsrtowcs' for UNICODE version +#endif +#endif + +// Some common types for char set portable code +#ifdef _XMLUNICODE + #ifndef _T + #define _T(c) L ## c + #endif + #define XMLCSTR const wchar_t * + #define XMLSTR wchar_t * + #define XMLCHAR wchar_t +#else + #ifndef _T + #define _T(c) c + #endif + #define XMLCSTR const char * + #define XMLSTR char * + #define XMLCHAR char +#endif +#ifndef FALSE + #define FALSE 0 +#endif /* FALSE */ +#ifndef TRUE + #define TRUE 1 +#endif /* TRUE */ + + +// Enumeration for XML parse errors. +typedef enum XMLError +{ + eXMLErrorNone = 0, + eXMLErrorMissingEndTag, + eXMLErrorEmpty, + eXMLErrorFirstNotStartTag, + eXMLErrorMissingTagName, + eXMLErrorMissingEndTagName, + eXMLErrorNoMatchingQuote, + eXMLErrorUnmatchedEndTag, + eXMLErrorUnmatchedEndClearTag, + eXMLErrorUnexpectedToken, + eXMLErrorInvalidTag, + eXMLErrorNoElements, + eXMLErrorFileNotFound, + eXMLErrorFirstTagNotFound, + eXMLErrorUnknownCharacterEntity, + eXMLErrorCharConversionError, + eXMLErrorCannotOpenWriteFile, + eXMLErrorCannotWriteFile, + + eXMLErrorBase64DataSizeIsNotMultipleOf4, + eXMLErrorBase64DecodeIllegalCharacter, + eXMLErrorBase64DecodeTruncatedData, + eXMLErrorBase64DecodeBufferTooSmall +} XMLError; + +// Enumeration used to manage type of data. Use in conjunction with structure XMLNodeContents +typedef enum XMLElementType +{ + eNodeChild=0, + eNodeAttribute=1, + eNodeText=2, + eNodeClear=3, + eNodeNULL=4 +} XMLElementType; + +// Structure used to obtain error details if the parse fails. +typedef struct XMLResults +{ + enum XMLError error; + int nLine,nColumn; +} XMLResults; + +// Structure for XML clear (unformatted) node (usually comments) +typedef struct { + XMLCSTR lpszValue; XMLCSTR lpszOpenTag; XMLCSTR lpszCloseTag; +} XMLClear; + +// Structure for XML attribute. +typedef struct { + XMLCSTR lpszName; XMLCSTR lpszValue; +} XMLAttribute; + +// Structure for XML clear tags. +typedef struct { + XMLCSTR lpszOpen; int openTagLen; XMLCSTR lpszClose; +} ALLXMLClearTag; + +struct XMLNodeContents; + +typedef struct DLLENTRY XMLNode +{ + private: + + struct XMLNodeDataTag; + + // protected constructors: use one of these four methods to get your first instance of XMLNode: + // - parseString + // - parseFile + // - openFileHelper + // - createXMLTopNode + XMLNode(struct XMLNodeDataTag *pParent, XMLCSTR lpszName, char isDeclaration); + XMLNode(struct XMLNodeDataTag *p); + + public: + + // You can create your first instance of XMLNode with these 4 functions: + // (see complete explanation of parameters below) + + static XMLNode createXMLTopNode(XMLCSTR lpszName, char isDeclaration=FALSE); + static XMLNode parseString (XMLCSTR lpXMLString, XMLCSTR tag=NULL, XMLResults *pResults=NULL); + static XMLNode parseFile (XMLCSTR filename, XMLCSTR tag=NULL, XMLResults *pResults=NULL); + static XMLNode openFileHelper(XMLCSTR filename, XMLCSTR tag=NULL ); + + // The tag parameter should be the name of the first tag inside the XML file. + // If the tag parameter is omitted, the 3 functions return a node that represents + // the head of the xml document including the declaration term (). + + // The "openFileHelper" reports to the screen all the warnings & errors that occurred during + // parsing of the XML file. Since each application has its own way to report and deal with errors, + // you should rather use the "parseFile" function to parse XML files and program yourself thereafter + // an "error reporting" tailored for your needs (instead of using the very crude "error reporting" + // mechanism included inside the "openFileHelper" function). + + // If the XML document is corrupted: + // * The "openFileHelper" method will: + // - display an error message on the console (or inside a messageBox for windows). + // - stop execution (exit). + // I suggest that you write your own "openFileHelper" method tailored to your needs. + // * The 2 other methods will initialize the "pResults" variable with some information that + // can be used to trace the error. + // * If you still want to parse the file, you can use the APPROXIMATE_PARSING option as + // explained inside the note at the beginning of the "xmlParser.cpp" file. + // You can have a user-friendly explanation of the parsing error with this function: + static XMLCSTR getError(XMLError error); + static XMLCSTR getVersion(); + static ALLXMLClearTag* getClearTagTable(); + + XMLCSTR getName() const; // name of the node + XMLCSTR getText(int i=0) const; // return ith text field + int nText() const; // nbr of text field + XMLNode getParentNode() const; // return the parent node + XMLNode getChildNode(int i=0) const; // return ith child node + XMLNode getChildNode(XMLCSTR name, int i) const; // return ith child node with specific name + // (return an empty node if failing) + XMLNode getChildNode(XMLCSTR name, int *i=NULL) const; // return next child node with specific name + // (return an empty node if failing) + XMLNode getChildNodeWithAttribute(XMLCSTR tagName, // return child node with specific name/attribute + XMLCSTR attributeName, // (return an empty node if failing) + XMLCSTR attributeValue=NULL, // + int *i=NULL) const; // + int nChildNode(XMLCSTR name) const; // return the number of child node with specific name + int nChildNode() const; // nbr of child node + XMLAttribute getAttribute(int i=0) const; // return ith attribute + XMLCSTR getAttributeName(int i=0) const; // return ith attribute name + XMLCSTR getAttributeValue(int i=0) const; // return ith attribute value + char isAttributeSet(XMLCSTR name) const; // test if an attribute with a specific name is given + XMLCSTR getAttribute(XMLCSTR name, int i) const; // return ith attribute content with specific name + // (return a NULL if failing) + XMLCSTR getAttribute(XMLCSTR name, int *i=NULL) const; // return next attribute content with specific name + // (return a NULL if failing) + int nAttribute() const; // nbr of attribute + XMLClear getClear(int i=0) const; // return ith clear field (comments) + int nClear() const; // nbr of clear field + XMLSTR createXMLString(int nFormat=1, int *pnSize=NULL) const; // create XML string starting from current XMLNode + // if nFormat==0, no formatting is required + // otherwise this returns an user friendly XML string from a + // given element with appropriate white spaces and carriage returns. + // if pnSize is given it returns the size in character of the string. + XMLError writeToFile(XMLCSTR filename, const char *encoding=NULL, char nFormat=1) const; + // save the content of an xmlNode inside a file. + // the nFormat parameter has the same meaning as in the + // createXMLString function. If "strictUTF8Parsing=1", the + // the encoding parameter is ignored and always set to + // "utf-8". If "_XMLUNICODE=1", the encoding parameter is + // ignored and always set to "utf-16". + XMLNodeContents enumContents(int i) const; // enumerate all the different contents (attribute,child,text, + // clear) of the current XMLNode. The order is reflecting + // the order of the original file/string. + // NOTE: 0 <= i < nElement(); + int nElement() const; // nbr of different contents for current node + char isEmpty() const; // is this node Empty? + char isDeclaration() const; // is this node a declaration + +// to allow shallow/fast copy: + ~XMLNode(); + XMLNode(const XMLNode &A); + XMLNode& operator=( const XMLNode& A ); + + XMLNode(): d(NULL){}; + static XMLNode emptyXMLNode; + static XMLClear emptyXMLClear; + static XMLAttribute emptyXMLAttribute; + + // The following functions allows you to create from scratch (or update) a XMLNode structure + // Start by creating your top node with the "createXMLTopNode" function and then add new nodes with the "addChild" function. + // The parameter 'pos' gives the position where the childNode, the text or the XMLClearTag will be inserted. + // The default value (pos=-1) inserts at the end. The value (pos=0) insert at the beginning (Insertion at the beginning is slower than at the end). + // REMARK: 0 <= pos < nChild()+nText()+nClear() + XMLNode addChild(XMLCSTR lpszName, char isDeclaration=FALSE, int pos=-1); + XMLAttribute *addAttribute(XMLCSTR lpszName, XMLCSTR lpszValuev); + XMLCSTR addText(XMLCSTR lpszValue, int pos=-1); + XMLClear *addClear(XMLCSTR lpszValue, XMLCSTR lpszOpen=NULL, XMLCSTR lpszClose=NULL, int pos=-1); + // default values: lpszOpen=XMLNode::getClearTagTable()->lpszOpen; + // lpszClose=XMLNode::getClearTagTable()->lpszClose; + XMLNode addChild(XMLNode nodeToAdd, int pos=-1); // If the "nodeToAdd" has some parents, it will be detached + // from it's parents before being attached to the current XMLNode + // Some update functions: + XMLCSTR updateName(XMLCSTR lpszName); // change node's name + XMLAttribute *updateAttribute(XMLAttribute *newAttribute, XMLAttribute *oldAttribute); // if the attribute to update is missing, a new one will be added + XMLAttribute *updateAttribute(XMLCSTR lpszNewValue, XMLCSTR lpszNewName=NULL,int i=0); // if the attribute to update is missing, a new one will be added + XMLAttribute *updateAttribute(XMLCSTR lpszNewValue, XMLCSTR lpszNewName,XMLCSTR lpszOldName); // set lpszNewName=NULL if you don't want to change the name of the attribute + // if the attribute to update is missing, a new one will be added + XMLCSTR updateText(XMLCSTR lpszNewValue, int i=0); // if the text to update is missing, a new one will be added + XMLCSTR updateText(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue); // if the text to update is missing, a new one will be added + XMLClear *updateClear(XMLCSTR lpszNewContent, int i=0); // if the clearTag to update is missing, a new one will be added + XMLClear *updateClear(XMLClear *newP,XMLClear *oldP); // if the clearTag to update is missing, a new one will be added + XMLClear *updateClear(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue); // if the clearTag to update is missing, a new one will be added + + // Some deletion functions: + void deleteNodeContent(char force=0); // delete the content of this XMLNode and the subtree. + // if force=0, while (references to this node still exist), no memory free occurs + // if force=1, always delete the content of this XMLNode and the subtree and free associated memory + void deleteAttribute(XMLCSTR lpszName); + void deleteAttribute(int i=0); + void deleteAttribute(XMLAttribute *anAttribute); + void deleteText(int i=0); + void deleteText(XMLCSTR lpszValue); + void deleteClear(int i=0); + void deleteClear(XMLClear *p); + void deleteClear(XMLCSTR lpszValue); + + // The strings given as parameters for the following add and update methods (all these methods have + // a name with the postfix "_WOSD" that means "WithOut String Duplication" ) will be free'd by the + // XMLNode class. For example, it means that this is incorrect: + // xNode.addText_WOSD("foo"); + // xNode.updateAttribute_WOSD("#newcolor" ,NULL,"color"); + // In opposition, this is correct: + // xNode.addText("foo"); + // xNode.addText_WOSD(stringDup("foo")); + // xNode.updateAttribute("#newcolor" ,NULL,"color"); + // xNode.updateAttribute_WOSD(stringDup("#newcolor"),NULL,"color"); + // Typically, you will never do: + // char *b=(char*)malloc(...); + // xNode.addText(b); + // free(b); + // ... but rather: + // char *b=(char*)malloc(...); + // xNode.addText_WOSD(b); + // ('free(b)' is performed by the XMLNode class) + + static XMLNode createXMLTopNode_WOSD(XMLCSTR lpszName, char isDeclaration=FALSE); + XMLNode addChild_WOSD(XMLCSTR lpszName, char isDeclaration=FALSE, int pos=-1); + XMLAttribute *addAttribute_WOSD(XMLCSTR lpszName, XMLCSTR lpszValue); + XMLCSTR addText_WOSD(XMLCSTR lpszValue, int pos=-1); + XMLClear *addClear_WOSD(XMLCSTR lpszValue, XMLCSTR lpszOpen=NULL, XMLCSTR lpszClose=NULL, int pos=-1); + + XMLCSTR updateName_WOSD(XMLCSTR lpszName); + XMLAttribute *updateAttribute_WOSD(XMLAttribute *newAttribute, XMLAttribute *oldAttribute); + XMLAttribute *updateAttribute_WOSD(XMLCSTR lpszNewValue, XMLCSTR lpszNewName=NULL,int i=0); + XMLAttribute *updateAttribute_WOSD(XMLCSTR lpszNewValue, XMLCSTR lpszNewName,XMLCSTR lpszOldName); + XMLCSTR updateText_WOSD(XMLCSTR lpszNewValue, int i=0); + XMLCSTR updateText_WOSD(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue); + XMLClear *updateClear_WOSD(XMLCSTR lpszNewContent, int i=0); + XMLClear *updateClear_WOSD(XMLClear *newP,XMLClear *oldP); + XMLClear *updateClear_WOSD(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue); + + // These are some useful functions when you want to insert a childNode, a text or a XMLClearTag in the + // middle (at a specified position) of a XMLNode tree already constructed. The value returned by these + // methods is to be used as last parameter (parameter 'pos') of addChild, addText or addClear. + int positionOfText(int i=0) const; + int positionOfText(XMLCSTR lpszValue) const; + int positionOfClear(int i=0) const; + int positionOfClear(XMLCSTR lpszValue) const; + int positionOfClear(XMLClear *a) const; + int positionOfChildNode(int i=0) const; + int positionOfChildNode(XMLNode x) const; + int positionOfChildNode(XMLCSTR name, int i=0) const; // return the position of the ith childNode with the specified name + // if (name==NULL) return the position of the ith childNode + + // The setGlobalOptions function allows you to change two global parameters that affect string&file + // parsing. First of all, you most-probably will never have to change these 2 global parameters. + // About the "guessUnicodeChars" parameter: + // If "guessUnicodeChars=1" and if this library is compiled in UNICODE mode, then the + // "parseFile" and "openFileHelper" functions will test if the file contains ASCII + // characters. If this is the case, then the file will be loaded and converted in memory to + // UNICODE before being parsed. If "guessUnicodeChars=0", no conversion will + // be performed. + // + // If "guessUnicodeChars=1" and if this library is compiled in ASCII/UTF8 mode, then the + // "parseFile" and "openFileHelper" functions will test if the file contains UNICODE + // characters. If this is the case, then the file will be loaded and converted in memory to + // ASCII/UTF8 before being parsed. If "guessUnicodeChars=0", no conversion will + // be performed + // + // Sometime, it's useful to set "guessUnicodeChars=0" to disable any conversion + // because the test to detect the file-type (ASCII/UTF8 or UNICODE) may fail (rarely). + // + // About the "strictUTF8Parsing" parameter: + // If "strictUTF8Parsing=0" then we assume that all characters have the same length of 1 byte. + // If "strictUTF8Parsing=1" then the characters have different lengths (from 1 byte to 4 bytes) + // depending on the content of the first byte of the character. + // About the "dropWhiteSpace" parameter: + // + + static void setGlobalOptions(char guessUnicodeChars=1, char strictUTF8Parsing=1, char dropWhiteSpace=1); + + // The next function try to guess if the character encoding is UTF-8. You most-probably will never + // have to use this function. It then returns the appropriate value of the global parameter + // "strictUTF8Parsing" described above. The guess is based on the content of a buffer of length + // "bufLen" bytes that contains the first bytes (minimum 25 bytes; 200 bytes is a good value) of the + // file to be parsed. The "openFileHelper" function is using this function to automatically compute + // the value of the "strictUTF8Parsing" global parameter. There are several heuristics used to do the + // guess. One of the heuristic is based on the "encoding" attribute. The original XML specifications + // forbids to use this attribute to do the guess but you can still use it if you set + // "useXMLEncodingAttribute" to 1 (this is the default behavior and the behavior of most parsers). + + static char guessUTF8ParsingParameterValue(void *buffer, int bufLen, char useXMLEncodingAttribute=1); + + private: + +// these are functions and structures used internally by the XMLNode class (don't bother about them): + + typedef struct XMLNodeDataTag // to allow shallow copy and "intelligent/smart" pointers (automatic delete): + { + XMLCSTR lpszName; // Element name (=NULL if root) + int nChild, // Number of child nodes + nText, // Number of text fields + nClear, // Number of Clear fields (comments) + nAttribute; // Number of attributes + char isDeclaration; // Whether node is an XML declaration - '' + struct XMLNodeDataTag *pParent; // Pointer to parent element (=NULL if root) + XMLNode *pChild; // Array of child nodes + XMLCSTR *pText; // Array of text fields + XMLClear *pClear; // Array of clear fields + XMLAttribute *pAttribute; // Array of attributes + int *pOrder; // order of the child_nodes,text_fields,clear_fields + int ref_count; // for garbage collection (smart pointers) + } XMLNodeData; + XMLNodeData *d; + + char parseClearTag(void *px, ALLXMLClearTag *pa); + char maybeAddTxT(void *pa, XMLCSTR tokenPStr); + int ParseXMLElement(void *pXML); + void *addToOrder(int memInc, int *_pos, int nc, void *p, int size, XMLElementType xtype); + int indexText(XMLCSTR lpszValue) const; + int indexClear(XMLCSTR lpszValue) const; + XMLNode addChild_priv(int,XMLCSTR,char,int); + XMLAttribute *addAttribute_priv(int,XMLCSTR,XMLCSTR); + XMLCSTR addText_priv(int,XMLCSTR,int); + XMLClear *addClear_priv(int,XMLCSTR,XMLCSTR,XMLCSTR,int); + static inline int findPosition(XMLNodeData *d, int index, XMLElementType xtype); + static int CreateXMLStringR(XMLNodeData *pEntry, XMLSTR lpszMarker, int nFormat); + static int removeOrderElement(XMLNodeData *d, XMLElementType t, int index); + static void exactMemory(XMLNodeData *d); + static int detachFromParent(XMLNodeData *d); +} XMLNode; + +// This structure is given by the function "enumContents". +typedef struct XMLNodeContents +{ + // This dictates what's the content of the XMLNodeContent + enum XMLElementType type; + // should be an union to access the appropriate data. + // compiler does not allow union of object with constructor... too bad. + XMLNode child; + XMLAttribute attrib; + XMLCSTR text; + XMLClear clear; + +} XMLNodeContents; + +DLLENTRY void free_XMLDLL(void *t); // {free(t);} + +// Duplicate (copy in a new allocated buffer) the source string. This is +// a very handy function when used with all the "XMLNode::*_WOSD" functions. +// (If (cbData!=0) then cbData is the number of chars to duplicate) +DLLENTRY XMLSTR stringDup(XMLCSTR source, int cbData=0); + +// The 3 following functions are processing strings so that all the characters +// &,",',<,> are replaced by their XML equivalent: &, ", ', <, >. +// These 3 functions are useful when creating from scratch an XML file using the +// "printf", "fprintf", "cout",... functions. If you are creating from scratch an +// XML file using the provided XMLNode class you cannot use these functions (the +// XMLNode class does the processing job for you during rendering). The second +// function ("toXMLStringFast") allows you to re-use the same output buffer +// for all the conversions so that only a few memory allocations are performed. +// If the output buffer is too small to contain thee resulting string, it will +// be enlarged. +DLLENTRY XMLSTR toXMLString(XMLCSTR source); +DLLENTRY XMLSTR toXMLStringFast(XMLSTR *destBuffer,int *destSz, XMLCSTR source); + +// you should not use this one (there is a possibility of "destination-buffer-overflow"): +DLLENTRY XMLSTR toXMLString(XMLSTR dest,XMLCSTR source); + +// Below is a class that allows you to include any binary data (images, sounds,...) +// into an XML document using "Base64 encoding". This class is completely +// separated from the rest of the xmlParser library and can be removed without any problem. +// To include some binary data into an XML file, you must convert the binary data into +// standard text (using "encode"). To retrieve the original binary data from the +// b64-encoded text included inside the XML file use "decode". Alternatively, these +// functions can also be used to "encrypt/decrypt" some critical data contained inside +// the XML. + +class DLLENTRY XMLParserBase64Tool +{ +public: + XMLParserBase64Tool(): buf(NULL),buflen(0){} + ~XMLParserBase64Tool(); + + void freeBuffer(); + + // returns the length of the base64 string that encodes a data buffer of size inBufLen bytes. + // If "formatted" parameter is true, some space will be reserved for a carriage-return every 72 chars. + static int encodeLength(int inBufLen, char formatted=0); + + // The "base64Encode" function returns a string containing the base64 encoding of "inByteLen" bytes + // from "inByteBuf". If "formatted" parameter is true, then there will be a carriage-return every 72 chars. + // The string will be free'd when the XMLParserBase64Tool object is deleted. + // All returned strings are sharing the same memory space. + XMLSTR encode(unsigned char *inByteBuf, unsigned int inByteLen, char formatted=0); + + // returns the number of bytes which will be decoded from "inString". + static unsigned int decodeSize(XMLCSTR inString, XMLError *xe=NULL); + + // returns a pointer to a buffer containing the binary data decoded from "inString" + // If "inString" is malformed NULL will be returned + // The output buffer will be free'd when the XMLParserBase64Tool object is deleted. + // All output buffer are sharing the same memory space. + unsigned char* decode(XMLCSTR inString, int *outByteLen=NULL, XMLError *xe=NULL); + + // The next function is deprecated. + // decodes data from "inString" to "outByteBuf". You need to provide the size (in byte) of "outByteBuf" + // in "inMaxByteOutBuflen". If "outByteBuf" is not large enough or if data is malformed, then "FALSE" + // will be returned; otherwise "TRUE". + static unsigned char decode(XMLCSTR inString, unsigned char *outByteBuf, int inMaxByteOutBuflen, XMLError *xe=NULL); + +private: + void *buf; + int buflen; + void alloc(int newsize); +}; + +#undef DLLENTRY + +#endif diff --git a/dol/src/dol/visitor/hdsd/HdsdMakefileVisitor.java b/dol/src/dol/visitor/hdsd/HdsdMakefileVisitor.java new file mode 100644 index 0000000..8458b32 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/HdsdMakefileVisitor.java @@ -0,0 +1,134 @@ +package dol.visitor.hdsd; + + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import dol.datamodel.architecture.Processor; +import dol.datamodel.mapping.Mapping; +import dol.datamodel.pn.Process; +import dol.visitor.MapVisitor; + +/** + * Visitor that is used to generate + * a HdS package Makefile for a distributed simulation. + */ +public class HdsdMakefileVisitor extends MapVisitor { + + /** + * Constructor. + * + * @param dir path of the Makefile + */ + public HdsdMakefileVisitor(String dir) { + _dir = dir; + } + + /** + * Create a Makefile for the given mapping. + * + * @param x mapping that needs to be rendered. + */ + public void visitComponent(Mapping x) { + try { + String filename = _dir + "/" + "Makefile"; + OutputStream file = new FileOutputStream(filename); + PrintStream ps = new PrintStream(file); + + ps.println("CXX = g++"); + ps.println("CC = g++"); + ps.println(); + ps.println("PREPROC_MACROS = -D __DOL_ETHZ_GEN__ -DINCLUDE_PROFILER"); + ps.println(); + ps.println("SYSTEMC_INC = -I" + _ui.getSystemCINC()); + ps.println("SYSTEMC_LIB = " + _ui.getSystemCLIB()); + ps.println("MY_LIB_INC = -Ilib -Iscd -Isc_wrappers -Iprocesses"); + ps.println("VPATH = lib:scd:scd/fsm:sc_wrappers:processes"); + ps.println(); + ps.println("# append '-rdynamic' for name resolution in exception stack traces"); + ps.println("# append '-g' for debugging"); + ps.println("CXXFLAGS = -O0 $(PREPROC_MACROS) $(SYSTEMC_INC) $(MY_LIB_INC)"); + ps.println("CFLAGS = $(CXXFLAGS)"); + ps.println(); + + // scd library objects + ps.println("# scd library objects"); + ps.println("SCD_OBJS = scd_logging.o scd_exception.o scd_socket.o scd_sock_poller.o \\"); + ps.println("\tscd_init_listener.o scd_in_connector.o scd_out_connector.o \\"); + ps.println("\tscd_command.o scd_command_reader.o scd_command_writer.o \\"); + ps.println("\tscd_simulator.o scd_chan_man.o scd_chan_wrapper.o \\"); + ps.println("\tscd_cont_man_master.o scd_cont_man_slave.o scd_cont_slave_wrapper.o \\"); + ps.println("\tscd_rem_fifo_in.o scd_rem_fifo_out.o scd_cont_fsm.o \\"); + ps.println("\tscd_sts_base.o scd_sts_init.o scd_sts_busy.o scd_sts_idle.o \\"); + ps.println("\tscd_sts_done.o scd_sts_time_ack.o scd_sts_time.o scd_sts_term_ack.o \\"); + ps.println("\tscd_sts_terminated.o scd_sts_fail.o scd_sts_failed.o \\"); + ps.println("\tscd_stm_base.o scd_stm_init.o scd_stm_busy.o scd_stm_idle.o \\"); + ps.println("\tscd_stm_done.o scd_stm_time_req.o scd_stm_time.o scd_stm_term_req.o \\"); + ps.println("\tscd_stm_terminate.o scd_stm_terminated.o \\"); + ps.println("\tscd_stm_fail.o scd_stm_failed.o \\"); + ps.println("\tscd_stsw_base.o scd_stsw_init.o scd_stsw_busy.o \\"); + ps.println("\tscd_stsw_idle.o scd_stsw_done.o scd_stsw_time_req.o \\"); + ps.println("\tscd_stsw_time_ack.o scd_stsw_term_req.o scd_stsw_term_ack.o \\"); + ps.println("\tscd_stsw_terminate.o scd_stsw_terminated.o \\"); + ps.println("\tscd_stsw_fail.o scd_stsw_failed.o"); + ps.println(); + + // process objects + ps.println("# process objects"); + ps.print("PROCESS_OBJS = dol.o "); + Iterator i = x.getProcessList().iterator(); + Set pSet = new HashSet(); + while (i.hasNext()) { + String basename = i.next().getBasename(); + if (pSet.add(basename)) + ps.print(basename + "_wrapper.o "); + } + ps.println(); + ps.println(); + + // target all + Iterator iter = x.getProcessorList().iterator(); + String processorList = new String(); + while (iter.hasNext()) + { + Processor p = iter.next(); + if (x.getProcessList().isEmpty()) + continue; + processorList += " scd_" + p.getName(); + } + ps.println("all:" + processorList); + ps.println(); + + // processor targets + iter = x.getProcessorList().iterator(); + while (iter.hasNext()) + { + Processor p = iter.next(); + if (x.getProcessList().isEmpty()) + continue; + ps.println("scd_" + p.getName() + ": scd_" + + p.getName() + ".o $(PROCESS_OBJS)" + + " $(SCD_OBJS)"); + ps.println("\t$(CXX) $(CXXFLAGS) -o $@ $^ $(SYSTEMC_LIB)"); + ps.println(); + } + + // clean target + ps.println("clean:"); + ps.println("\t-rm -f *.o core core.* *.core" + processorList); + + } catch (Exception e) { + System.out.println("HdsdMakefileVisitor: exception occured: " + + e.getMessage()); + e.printStackTrace(); + } + + } + + protected String _dir = null; +} + diff --git a/dol/src/dol/visitor/hdsd/HdsdModuleArchVisitor.java b/dol/src/dol/visitor/hdsd/HdsdModuleArchVisitor.java new file mode 100644 index 0000000..4b89646 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/HdsdModuleArchVisitor.java @@ -0,0 +1,491 @@ +package dol.visitor.hdsd; + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.Vector; + +import dol.datamodel.architecture.Configuration; +import dol.datamodel.architecture.Processor; +import dol.datamodel.mapping.Mapping; +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.Resource; +import dol.main.UserInterface; +import dol.util.CodePrintStream; +import dol.visitor.ArchiVisitor; + +/** + * Visitor that generates the main program for one distributed simulator. + */ +public class HdsdModuleArchVisitor extends ArchiVisitor { + + /** + * Constructor. + * @param map mapping of this code generation + * @param dir path of this file + */ + public HdsdModuleArchVisitor(Mapping map, String dir) { + _map = map; + _dir = dir; + _channels = new LinkedHashSet(); + _remInChannels = new LinkedHashSet(); + _remOutChannels = new LinkedHashSet(); + _locChannels = new LinkedHashSet(); + } + + /** + * + * @param x Processor that needs to be rendered + */ + public void visitComponent(Processor x) { + + // get channels for this processor + _getChannels(x); + + try { + String filename = _dir + "/" + "scd_" + + x.getName() + ".cpp"; + OutputStream file = new FileOutputStream(filename); + _mainPS = new CodePrintStream(file); + + _mainPS.printPrefixln("#include "); + _mainPS.printPrefixln("#include "); + + /* begin of profiling: standard i/o file handling routines */ + _mainPS.printPrefixln("#ifdef INCLUDE_PROFILER"); + _mainPS.printPrefixln("#include "); + _mainPS.printPrefixln("#endif"); + /* end of profiling */ + + _mainPS.printPrefixln("#include \"dol_sched_if.h\""); + _mainPS.printPrefixln("#include \"simple_fifo.h\""); + _mainPS.printPrefixln("#include \"scd_logging.h\""); + _mainPS.printPrefixln("#include \"scd_simulator.h\""); + _mainPS.printPrefixln("#include \"scd_rem_fifo_in.h\""); + _mainPS.printPrefixln("#include \"scd_rem_fifo_out.h\""); + _mainPS.println(); + + // include process files + Iterator pIt = x.getProcessList().iterator(); + Vector pList = new Vector(); + while (pIt.hasNext()) { + Process p = pIt.next(); + String basename = p.getBasename(); + if (!pList.contains(basename)) { + _mainPS.printPrefixln("#include \"" + p.getBasename() + + "_wrapper.h\""); + pList.add(basename); + } + } + _mainPS.println(); + + // namespaces + _mainPS.printPrefixln("using namespace std;"); + _mainPS.printPrefixln("using sc_core::sc_module;"); + _mainPS.printPrefixln("using sc_core::sc_event;"); + _mainPS.printPrefixln("using sc_core::sc_prim_channel;"); + + + /* begin of profiling: global variables */ + _mainPS.println(); + _mainPS.printPrefixln("#ifdef INCLUDE_PROFILER"); + _mainPS.printPrefixln("#define PROFILER_OUTPUT_FILENAME " + + "\"profile_" + x.getName() + ".txt\""); + _mainPS.printPrefixln("FILE *profiler_output_file;"); + _mainPS.printPrefixln("unsigned int profiler_event_counter;"); + _mainPS.printPrefixln("#endif"); + /* end of profiling */ + + _mainPS.println(); + _mainPS.printPrefixln("class sc_application : public sc_module "); + _mainPS.printLeftBracket(); + + _mainPS.printPrefixln("public:"); + _mainPS.printPrefixln("SC_HAS_PROCESS(sc_application);"); + + //declare processes + _mainPS.println(); + pIt = x.getProcessList().iterator(); + while (pIt.hasNext()) { + Process p = pIt.next(); + _mainPS.printPrefixln(p.getBasename() + "_wrapper " + + p.getName() + "_ins"+ ";"); + _mainPS.printPrefixln("sc_event " + p.getName() + + "_event;"); + } + _mainPS.println(); + + //define the scheduler + _mainPS.printPrefixln("sc_event sched_event;"); + _mainPS.printPrefixln("list eventList;"); + _mainPS.printPrefixln("list::iterator iter;"); + _mainPS.println(); + + //declare channels + _mainPS.println(); + Iterator cIt; + cIt = _locChannels.iterator(); + while (cIt.hasNext()) + _mainPS.printPrefixln("fifo " + cIt.next() + "_ins;"); + cIt = _remInChannels.iterator(); + while (cIt.hasNext()) + _mainPS.printPrefixln("scd_rem_fifo_in " + cIt.next() + "_ins;"); + cIt = _remOutChannels.iterator(); + while (cIt.hasNext()) + _mainPS.printPrefixln("scd_rem_fifo_out " + cIt.next() + "_ins;"); + _mainPS.println(); + + // model constructor + _mainPS.printPrefixln("sc_application(sc_module_name name)"); + + // parameter of constructor (processes) + _mainPS.printPrefixln(": sc_module(name),"); + pIt = x.getProcessList().iterator(); + while (pIt.hasNext()) { + Process p = pIt.next(); + _mainPS.printPrefixln(p.getName() + "_ins(\"" + + p.getName() +"\"),"); + } + + // parameter of constructor (channels) + cIt = _channels.iterator(); + while (cIt.hasNext()) { + Channel c = _map.getPN().getChannel( cIt.next() ); + _mainPS.printPrefix(c.getName() + "_ins(\"" + + c.getName() +"\", " + + c.getSize()*c.getTokenSize() + + ")"); + if (cIt.hasNext()) + _mainPS.println(","); + else + _mainPS.println(); + } + _mainPS.printLeftBracket(); + + //construtor content + //build the network + cIt = _channels.iterator(); + while (cIt.hasNext()) + { + Channel c = _map.getPN().getChannel(cIt.next()); + c.accept( new HdsdModulePNVisitor(x, _mainPS) ); + } + _mainPS.println(); + + _mainPS.println(); + + _mainPS.printPrefixln("SC_THREAD(thread_init);"); + // init thread + _mainPS.printPrefixln("SC_THREAD(thread_sched);"); + + // declare concurrent non-terminating threads + pIt = x.getProcessList().iterator(); + while (pIt.hasNext()) { + _mainPS.printPrefixln("SC_THREAD(thread_" + + pIt.next().getName() + ");"); + } + _mainPS.printRightBracket(); + _mainPS.println(); + + //define scheduler thread + _mainPS.printPrefixln("void thread_init()"); + _mainPS.printLeftBracket(); + //init + pIt = x.getProcessList().iterator(); + while (pIt.hasNext()) { + Process p = pIt.next(); + _mainPS.printPrefixln(p.getName() + "_ins.initialize();"); + } + _mainPS.printRightBracket(); + _mainPS.println(); + + + //different scheduling algorithm can be put here + _mainPS.printPrefixln("void thread_sched()"); + _mainPS.printLeftBracket(); + _mainPS.printPrefixln("while (1)"); + _mainPS.printLeftBracket(); + _mainPS.printPrefixln("for (iter=eventList.begin(); iter != " + + "eventList.end(); ++iter)"); + _mainPS.printLeftBracket(); + _mainPS.printPrefixln("sc_event* e = (*iter);"); + _mainPS.printPrefixln("e->notify();"); + _mainPS.printRightBracket(); + _mainPS.printPrefixln("eventList.clear();"); + _mainPS.printPrefixln("wait(sched_event);"); + _mainPS.printRightBracket(); + _mainPS.printRightBracket(); + _mainPS.println(); + + //define threads + pIt = x.getProcessList().iterator(); + while (pIt.hasNext()) + pIt.next().accept( new HdsdModulePNVisitor(x, _mainPS) ); + + /* begin of profiling: initialization function. */ + /* - opens file */ + /* - writes a list of all channels with the connected ports to the file. */ + _mainPS.printPrefixln("#ifdef INCLUDE_PROFILER"); + _mainPS.printPrefixln("void initialize_profiler()"); + _mainPS.printLeftBracket(); + _mainPS.printPrefixln("if ((profiler_output_file = fopen(PROFILER_OUTPUT_FILENAME,\"w\"))==NULL)"); + _mainPS.printLeftBracket(); + _mainPS.printPrefixln("printf(\"Unable to open profiler output file. No profiling output is written.\\n\");"); + _mainPS.printPrefixln("return;"); + _mainPS.printRightBracket(); + //_mainPS.printPrefixln("printf(\"Profiling data is written to %s.\\n\", PROFILER_OUTPUT_FILENAME);"); + _mainPS.println(); + + cIt = _channels.iterator(); + while (cIt.hasNext()) { + String cName = cIt.next(); + Channel ch = _map.getPN().getChannel(cName); + Iterator poIt = ch.getPortList().iterator(); + String outputString = "fprintf(profiler_output_file, \"c " + ch.getName() + " " + ch.getSize(); + String outputStringAppendix = ""; + while (poIt.hasNext()) { + Port p = poIt.next(); + Port peerPort = p.getPeerPort(); + Resource peerResource = p.getPeerResource(); + + if (p.isOutPort()) { + // channel.out == process.in + String portAddr = null; + if ( x.hasProcess(peerResource.getName()) ) + portAddr = "&(" + peerResource.getName() + + "_ins.INPORT_" + peerPort.getBasename() + + peerPort.getName().replace( + peerPort.getBasename(), "").replaceAll( + "_([0-9]+)", "[$1]") + ")"; + else + portAddr = "0x00000000"; + outputString += " i " + peerResource.getName() + " %p";// + p.getPeerPort().getName(); + outputStringAppendix += "," + portAddr; + } else { + String portAddr = null; + if ( x.hasProcess(peerResource.getName()) ) + portAddr = "&(" + peerResource.getName() + + "_ins.OUTPORT_" + peerPort.getBasename() + + peerPort.getName().replace( + peerPort.getBasename(), "").replaceAll( + "_([0-9]+)", "[$1]") + ")"; + else + portAddr = "0x00000000"; + outputString += " o " + peerResource.getName() + " %p";// + p.getPeerPort().getName(); + outputStringAppendix += "," + portAddr; + } + } + outputString += "\\n\"" + outputStringAppendix + ");"; + _mainPS.printPrefixln(outputString); + } + _mainPS.printRightBracket(); + _mainPS.printPrefixln("#endif"); + _mainPS.println(); + /* end of profiling */ + + _mainPS.printRightBracket(); // end of class + _mainPS.println(";"); + + //create and run the simulator + _mainPS.printPrefixln("int sc_main (int argc, char *argv[])"); + _mainPS.printLeftBracket(); + + //create an instance of the application model + //remove potential whitespaces before using the process + //network name as a systemc identifier + _mainPS.printPrefixln("sc_application my_app_mdl(\"" + + x.getName().replaceAll(" ", "") + "\");"); + + /* begin of profiling: initialize the profiler */ + _mainPS.printPrefixln("#ifdef INCLUDE_PROFILER"); + _mainPS.printPrefixln("my_app_mdl.initialize_profiler();"); + _mainPS.printPrefixln("#endif"); + _mainPS.printPrefixln(); + /* end of profiling */ + + /* begin distributed simulation */ + if (UserInterface.getInstance().getDebugFlag()) + _mainPS.printPrefixln("scd_set_loglevel(SCD_DEBUG);"); + else + _mainPS.printPrefixln("scd_set_loglevel(SCD_INFO);"); + // simulator && master/slaves + Configuration opt = x.getCfg("master"); + if (opt != null && opt.getValue().equals("true")) // master + { + // simulator constructor + _mainPS.printPrefixln("scd_simulator sim(\"" + + x.getName() + "\", \"" + + x.getCfg("address").getValue() + "\", " + + x.getCfg("port").getValue() + ", SCD_MASTER);"); + // register slaves + Iterator iter = _map.getProcessorList().iterator(); + while (iter.hasNext()) + { + Processor p = iter.next(); + opt = p.getCfg("master"); + if ( !(opt != null && opt.getValue().equals("true")) ) + { + _mainPS.printPrefixln("sim.get_cont_man()." + + "register_slave(\"" + p.getName() + + "\");"); + } + } + } // end master + else // slave + { + // simulator constructor + _mainPS.printPrefixln("scd_simulator sim(\"" + + x.getName() + "\", \"" + + x.getCfg("address").getValue() + "\", " + + x.getCfg("port").getValue() + ", SCD_SLAVE);"); + // find and set master + Iterator iter = _map.getProcessorList().iterator(); + while (iter.hasNext()) + { + Processor p = iter.next(); + opt = p.getCfg("master"); + if (opt != null && opt.getValue().equals("true")) + { + _mainPS.printPrefixln("sim.get_cont_man().set_master(\"" + + p.getCfg("address").getValue() + "\", " + + p.getCfg("port").getValue() + ");"); + break; + } + } + } // end slave + + // register channels + // remote out channels + cIt = _remOutChannels.iterator(); + while (cIt.hasNext()) + { + String cName = cIt.next(); + Channel c = _map.getPN().getChannel(cName); + Iterator poIt = c.getPortList().iterator(); + Processor p = null; + while (poIt.hasNext()) + { + Port po = poIt.next(); + if (po.isOutPort()) + { + Process pr = _map.getProcess( + po.getPeerResource().getName() ); + p = pr.getProcessor(); + } + } + _mainPS.printPrefixln("sim.get_chan_man()." + + "register_channel(\"" + cName + "\","); + _mainPS.printPrefixln(" my_app_mdl." + cName + + "_ins, \"" + p.getCfg("address").getValue() + "\", " + + p.getCfg("port").getValue() + ");"); + } + // remote in channels + cIt = _remInChannels.iterator(); + while (cIt.hasNext()) + { + String cName = cIt.next(); + _mainPS.printPrefixln("sim.get_chan_man().register_channel(" + + "\"" + cName + "\","); + _mainPS.printPrefixln(" my_app_mdl." + cName + "_ins);"); + } + + // init & start + _mainPS.printPrefixln("bool ret = sim.init();"); + _mainPS.printPrefixln("if (ret)"); + _mainPS.prefixInc(); + _mainPS.printPrefixln("ret = sim.start();"); + _mainPS.prefixDec(); + _mainPS.printPrefixln(); + /* end distributed simulation */ + + /* begin of profiling: close the output file */ + _mainPS.printPrefixln("#ifdef INCLUDE_PROFILER"); + _mainPS.printPrefixln("if (profiler_output_file != NULL) fclose(profiler_output_file);"); + _mainPS.printPrefixln("#endif"); + /* end of profiling */ + + _mainPS.printPrefixln("if (ret)"); + _mainPS.prefixInc(); + _mainPS.printPrefixln("return 0;"); + _mainPS.prefixDec(); + _mainPS.printPrefixln("else"); + _mainPS.prefixInc(); + _mainPS.printPrefixln("return 1;"); + _mainPS.prefixDec(); + + _mainPS.printRightBracket(); + + } + catch (Exception e) { + System.out.println("HdsdModuleVisitor: exception occured: " + + e.getMessage()); + e.printStackTrace(); + } + } + + + /** + * Retrieves all channels that have an endpoint on the specified + * processor and fills them into the channel sets. + * @param x the processor to get the channels for + */ + private void _getChannels(Processor x) + { + Iterator iter = _map.getPN().getChannelList().iterator(); + + while (iter.hasNext()) + { + Channel c = iter.next(); + + boolean isIn = false; + boolean isOut = false; + + /* check if the in/out endpoint of this channel is on this + * processor + */ + Iterator poIt = c.getPortList().iterator(); + while (poIt.hasNext()) + { + Port p = poIt.next(); + if (x.hasProcess(p.getPeerResource().getName())) + { + if (p.isInPort()) // inPort of channel = outport + isOut = true; + if (p.isOutPort()) // outPort of channel = inport + isIn = true; + } + } + + // add name to channel lists + if (isIn && isOut) + { + _channels.add(c.getName()); + _locChannels.add(c.getName()); + } + else if (isIn && !isOut) + { + _channels.add(c.getName()); + _remInChannels.add(c.getName()); + } + else if (!isIn && isOut) + { + _channels.add(c.getName()); + _remOutChannels.add(c.getName()); + } + } + } // _getChannels() + + + protected CodePrintStream _mainPS = null; + protected String _dir = null; + protected Mapping _map = null; + + protected Set _channels = null; + protected Set _remInChannels = null; + protected Set _remOutChannels = null; + protected Set _locChannels = null; +} diff --git a/dol/src/dol/visitor/hdsd/HdsdModulePNVisitor.java b/dol/src/dol/visitor/hdsd/HdsdModulePNVisitor.java new file mode 100644 index 0000000..466dba3 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/HdsdModulePNVisitor.java @@ -0,0 +1,113 @@ +package dol.visitor.hdsd; + +import dol.datamodel.architecture.Processor; +import dol.datamodel.mapping.Mapping; +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.Resource; +import dol.util.CodePrintStream; +import dol.visitor.PNVisitor; + +/** + * Visitor that generates the main program thread of a process + * and the process network in the constructor. + */ +public class HdsdModulePNVisitor extends PNVisitor { + + /** + * Constructor. + */ + public HdsdModulePNVisitor(Processor processor, CodePrintStream stream) { + _processor = processor; + _mainPS = stream; + } + + /** + * Generates the thread for this process. + * + * @param x process that needs to be rendered + */ + public void visitComponent(Process x) { + _mainPS.printPrefixln("void thread_" + x.getName() + "()"); + _mainPS.printLeftBracket(); + _mainPS.printPrefixln("while (!" + x.getName() + + "_ins.isDetached())"); + _mainPS.printLeftBracket(); + + /* begin of profiling: start event */ + _mainPS.printPrefixln("#ifdef INCLUDE_PROFILER"); + _mainPS.printPrefixln("if (profiler_output_file != NULL) fprintf(profiler_output_file, \"%u "+ x.getName() + " started.\\n\", profiler_event_counter++);"); + _mainPS.printPrefixln("#endif"); + /* end of profiling */ + + _mainPS.printPrefixln(x.getName() + "_ins.fire();"); + + /* begin of profiling: stop event */ + _mainPS.printPrefixln("#ifdef INCLUDE_PROFILER"); + _mainPS.printPrefixln("if (profiler_output_file != NULL) fprintf(profiler_output_file, \"%u "+ x.getName() + " stopped.\\n\", profiler_event_counter++);"); + _mainPS.printPrefixln("#endif"); + /* end of profiling */ + + _mainPS.printPrefixln("eventList.push_back(&" + x.getName() + + "_event);"); + _mainPS.printPrefixln("sched_event.notify(SC_ZERO_TIME);"); + _mainPS.printPrefixln("wait(" + x.getName() + "_event);"); + + _mainPS.printRightBracket(); + _mainPS.printRightBracket(); + } + + /** + * Generates the process network. This is the channel content + * in the model constructor. + * @param x channel that needs to be rendered + */ + public void visitComponent(Channel x) { + for (Port p : x.getPortList()) { + Port peerPort = (Port)(p.getPeerPort()); + Resource peerResource = p.getPeerResource(); + + if (!_processor.hasProcess(peerResource.getName())) + continue; + + if (peerPort.getRange() != null) { + if (p.isOutPort()) { + _mainPS.printPrefixln(peerResource.getName() + + "_ins.INPORT_" + + peerPort.getBasename() + + peerPort.getName().replace( + peerPort.getBasename(), "").replaceAll( + "_([0-9]+)", "[$1]") + "(" + x.getName() + + "_ins);"); + } + else if (p.isInPort()) { + _mainPS.printPrefixln(peerResource.getName() + + "_ins.OUTPORT_" + + peerPort.getBasename() + + peerPort.getName().replace( + peerPort.getBasename(), "").replaceAll( + "_([0-9]+)", "[$1]") + "(" + x.getName() + + "_ins);"); + } + } + else { + if (p.isOutPort()) { + _mainPS.printPrefixln(peerResource.getName() + + "_ins.INPORT_" + peerPort.getName() + + "(" + x.getName() + "_ins);"); + } + else if (p.isInPort()) { + _mainPS.printPrefixln(peerResource.getName() + + "_ins.OUTPORT_" + peerPort.getName() + + "(" + x.getName() + "_ins);"); + } + } + } + } + + protected CodePrintStream _mainPS = null; + protected String _dir = null; + protected Mapping _map = null; + protected Processor _processor = null; +} diff --git a/dol/src/dol/visitor/hdsd/HdsdModuleVisitor.java b/dol/src/dol/visitor/hdsd/HdsdModuleVisitor.java new file mode 100644 index 0000000..e7b316f --- /dev/null +++ b/dol/src/dol/visitor/hdsd/HdsdModuleVisitor.java @@ -0,0 +1,38 @@ +package dol.visitor.hdsd; + +import java.util.Iterator; + +import dol.datamodel.architecture.Processor; +import dol.datamodel.mapping.Mapping; +import dol.visitor.MapVisitor; + +/** + * Visitor that generates the main programs of distributed simulators. + */ +public class HdsdModuleVisitor extends MapVisitor { + + /** + * Constructor. + * + * @param dir path of this file + */ + public HdsdModuleVisitor(String dir) { + _dir = dir; + } + + /** + * + * @param x mapping that needs to be rendered + */ + public void visitComponent(Mapping x) { + Iterator iter; + iter = x.getProcessorList().iterator(); + while (iter.hasNext()) + { + Processor p = iter.next(); + p.accept(new HdsdModuleArchVisitor(x, _dir)); + } + } + + protected String _dir = null; +} diff --git a/dol/src/dol/visitor/hdsd/HdsdProcessVisitor.java b/dol/src/dol/visitor/hdsd/HdsdProcessVisitor.java new file mode 100644 index 0000000..2ba1044 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/HdsdProcessVisitor.java @@ -0,0 +1,364 @@ +package dol.visitor.hdsd; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Vector; + +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.SourceCode; +import dol.util.CodePrintStream; +import dol.util.Sed; +import dol.visitor.PNVisitor; + +/** + * Visitor that is used to generate + * a wrapper class for a process: process_wrapper.[h/cpp]. + */ +public class HdsdProcessVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir target directory + */ + public HdsdProcessVisitor(String dir) { + _dir = dir; + } + + /** + * + * @param x process network that needs to be rendered + */ + public void visitComponent(ProcessNetwork x) { + try { + Vector pList = new Vector(); + + for (Process p : x.getProcessList()) { + String basename = p.getBasename(); + if (!pList.contains(basename)) { + pList.add(basename); + p.accept(this); + } + } + } + catch (Exception e) { + System.out.println("Process Visitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * + * @param p process that needs to be rendered + */ + public void visitComponent(Process p) { + try { + _createCppFile(p); + _createHeaderFile(p); + _adaptSources(p); + } + catch (Exception e) { + System.out.println("Process Visitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * + */ + protected void _adaptSources(Process p) throws IOException { + Sed sed = new Sed(); + for (Port port : p.getPortList()) { + String processHeaderFile; + + for (SourceCode sr : p.getSrcList()) { + processHeaderFile = _dir + _delimiter + ".." + + _delimiter + "processes" + _delimiter + + sr.getLocality(). + replaceAll("(.*)\\.[cC][pP]*[pP]*", "$1\\.h"); + + if (port.isOutPort()) { + sed.sed(processHeaderFile, + "(#define[ ]*PORT_\\w*[ ]*)\"?" + + port.getBasename() + "\"?", + "$1 " + "&((static_cast<" + p.getBasename() + + "_wrapper *>(p->wptr))->OUTPORT_" + + port.getBasename() + ")"); + + } + else if (port.isInPort()) { + sed.sed(processHeaderFile, + "(#define[ ]*PORT_\\w*[ ]*)\"?" + + port.getBasename() + "\"?", + "$1 " + "&((static_cast<" + p.getBasename() + + "_wrapper *>(p->wptr))->INPORT_" + + port.getBasename() + ")"); + } + } + } + } + + /** + * + */ + protected void _createCppFile(Process p) throws IOException { + String filename = _dir + _delimiter + p.getBasename() + + "_wrapper.cpp"; + OutputStream file = new FileOutputStream(filename); + CodePrintStream ps = new CodePrintStream(file); + + ps.printPrefixln("#include \"" + p.getBasename() + + "_wrapper.h\""); + ps.printPrefixln(); + + //define the write/read + if (p.hasOutPorts()) { + ps.printPrefixln("static inline int DOL_write(void *port, " + + "void *buf, int len, DOLProcess *process)"); + ps.printLeftBracket(); + ps.printPrefixln("sc_port *write_port = static_cast" + + " *>(port);"); + ps.printPrefixln("char *str = static_cast(buf);"); + + /* begin of profiling: write event */ + ps.printPrefixln("#ifdef INCLUDE_PROFILER"); + ps.printPrefixln("(static_cast<" + p.getBasename() + + "_wrapper *>(process->wptr))" + "->addToProfile(\"w\", port, len);"); + ps.printPrefixln("#endif"); + /* end of profiling */ + + ps.printPrefixln("while (len-- > 0) "); + ps.printPrefixln(" (*write_port)->write(*str++);"); + ps.printRightBracket(); + ps.printPrefixln(); + ps.printPrefixln("static inline int DOL_wtest(void *port, " + + "int len, DOLProcess *process)"); + ps.printLeftBracket(); + ps.printPrefixln("sc_port *write_port = static_cast" + + " *>(port);"); + ps.printPrefixln("return (*write_port)->wtest(len);"); + ps.printRightBracket(); + ps.printPrefixln(); + } + if (p.hasInPorts()) { + ps.printPrefixln("static inline int DOL_read(void *port, " + + "void *buf, int len, DOLProcess *process)"); + ps.printLeftBracket(); + ps.printPrefixln("sc_port *read_port = static_cast" + + " *>(port);"); + ps.printPrefixln("char *str = static_cast(buf);"); + + /* begin of profiling: read event */ + ps.printPrefixln("#ifdef INCLUDE_PROFILER"); + ps.printPrefixln("(static_cast<" + p.getBasename() + + "_wrapper *>(process->wptr))" + "->addToProfile(\"r\", port, len);"); + ps.printPrefixln("#endif"); + /* end of profiling */ + + ps.printPrefixln("while (len-- > 0) "); + ps.printPrefixln(" (*read_port)->read(*str++);"); + ps.printRightBracket(); + ps.printPrefixln(); + ps.printPrefixln("static inline int DOL_rtest(void *port, " + + "int len, DOLProcess *process)"); + ps.printLeftBracket(); + ps.printPrefixln("sc_port *read_port = static_cast" + + " *>(port);"); + ps.printPrefixln("return (*read_port)->rtest(len);"); + ps.printRightBracket(); + } + ps.printPrefixln(); + ps.printPrefixln("static inline int DOL_detach(DOLProcess *p)"); + ps.printLeftBracket(); + ps.printPrefixln("(static_cast<" + p.getBasename() + + "_wrapper *>(p->wptr))" + "->setDetached();"); + ps.printRightBracket(); + ps.printPrefixln(); + + ps.printPrefixln("#define GETINDEX(dimension) \\"); + ps.printPrefixln("(static_cast<" + p.getBasename() + + "_wrapper *>(p->wptr))->_processIndex[dimension]"); + ps.printPrefixln(); + //include c file + for (SourceCode sr : p.getSrcList()) { + ps.printPrefixln("#include \"" + sr.getLocality() + "\""); + } + ps.printPrefixln(); + + /* begin of profiling: function that adds an entry to the profile */ + ps.printPrefixln("#ifdef INCLUDE_PROFILER"); + ps.printPrefixln("void " + p.getBasename() + "_wrapper::addToProfile(const char *evnt, void *port, int length)"); + ps.printLeftBracket(); + ps.printPrefixln("if (profiler_output_file != NULL) fprintf(profiler_output_file, \"%u %s %s %p %d\\n\", profiler_event_counter++, _uniqueName, evnt, port, length);"); + ps.printRightBracket(); + ps.printPrefixln("#endif"); + /* end of profiling */ + + ps.printPrefixln("void " + p.getBasename() + + "_wrapper::setDetached() { _detached = 1; }"); + ps.printPrefixln("int " + p.getBasename() + + "_wrapper::isDetached() { return _detached; }"); + ps.printPrefixln(); + + //constructor + ps.printPrefixln(p.getBasename() + "_wrapper::" + p.getBasename() + + "_wrapper(sc_module_name name=sc_gen_unique_name(\"" + + p.getBasename() + "\" )) : sc_module(name), _process(" + + p.getBasename() + ")" + ", _detached(0)"); + ps.printLeftBracket(); + ps.printPrefixln("struct _local_states *_state = " + + "new struct _local_states;"); + ps.printPrefixln("memcpy(_state, " + p.getBasename() + + ".local, sizeof(struct _local_states));"); + ps.printPrefixln("_process.local = _state;"); + //ps.printPrefixln("sprintf(_process.local->id, name);"); + ps.printPrefixln("_process.wptr = this;"); + ps.printPrefixln(); + ps.printPrefixln("char buffer[255];"); + ps.printPrefixln("sprintf(buffer, name);"); + + /* begin of profiling: save unique name for writing it to + the profile later */ + ps.printPrefixln("#ifdef INCLUDE_PROFILER"); + ps.printPrefixln("sprintf(_uniqueName, name);"); + ps.printPrefixln("#endif"); + /* end of profiling */ + + ps.printPrefixln("for (int i = 0; i < 4; i++)"); + ps.printPrefixln(" _processIndex[i] = " + + "getIndex(buffer, \"_\", i);"); + + ps.printPrefixln(); + ps.printRightBracket(); + + ps.printPrefixln(); + ps.printPrefixln("void " + p.getBasename() + + "_wrapper::initialize()"); + ps.printLeftBracket(); + ps.printPrefixln("_process.init(&_process);"); + ps.printRightBracket(); + ps.printPrefixln(); + ps.printPrefixln("int " + p.getBasename() + "_wrapper::fire()"); + ps.printLeftBracket(); + ps.printPrefixln(); + ps.printPrefixln("return _process.fire(&_process);"); + ps.printRightBracket(); + } + + protected void _createHeaderFile(Process p) + throws IOException { + String filename = _dir + _delimiter + p.getBasename() + + "_wrapper.h"; + OutputStream file = new FileOutputStream(filename); + CodePrintStream ps = new CodePrintStream(file); + + ps.printPrefixln("#ifndef " + p.getBasename() + "_WRAPPER_H"); + ps.printPrefixln("#define " + p.getBasename() + "_WRAPPER_H"); + ps.printPrefixln(); + ps.printPrefixln("#include \"systemc.h\""); + ps.printPrefixln(); + ps.printPrefixln("#include \"dol_sched_if.h\""); + ps.printPrefixln("#include \"simple_fifo.h\""); + ps.printPrefixln(); + ps.printPrefixln("#include "); + ps.printPrefixln(); + + /* begin of profiling: externally defined global variables */ + ps.println(); + ps.printPrefixln("#ifdef INCLUDE_PROFILER"); + ps.printPrefixln("extern FILE *profiler_output_file;"); + ps.printPrefixln("extern unsigned int profiler_event_counter;"); + ps.printPrefixln("#endif"); + ps.printPrefixln(); + /* end of profiling */ + + ps.printPrefixln("class " + p.getBasename() + + "_wrapper : virtual public dol_sched_if, " + + "public sc_module"); + ps.printLeftBracket(); + ps.printPrefixln("public:"); + + + Vector portList = new Vector(); + for (Port port : p.getPortList()) { + String basename = port.getBasename(); + + if (!portList.contains(basename)) { + portList.add(basename); + + if (!port.getRange().equals("")) { + if (port.isOutPort()) { + ps.printPrefixln("sc_port OUTPORT_" + + port.getBasename() + "[" + + port.getRange().replaceAll( + ";", "\\]\\[") + "];"); + } + else if (port.isInPort()) { + ps.printPrefixln("sc_port INPORT_" + + port.getBasename() + "[" + + port.getRange().replaceAll( + ";", "\\]\\[") + "];"); + } + } + else { + if (port.isOutPort()) { + ps.printPrefixln("sc_port OUTPORT_" + + port.getName() + ";"); + } + else if (port.isInPort()) { + ps.printPrefixln("sc_port INPORT_" + + port.getName() + ";"); + } + } + } + } + ps.printPrefixln("int _processIndex[4];"); + + /* begin of profiling: name variable declaration */ + ps.printPrefixln("#ifdef INCLUDE_PROFILER"); + ps.printPrefixln("char _uniqueName[255];"); + ps.printPrefixln("#endif"); + /* end of profiling */ + + ps.printPrefixln(); + ps.printPrefixln("" + p.getBasename() + + "_wrapper(sc_module_name name);"); + ps.printPrefixln(); + ps.printPrefixln("~" + p.getBasename() + "_wrapper() {}"); + ps.printPrefixln(); + + /* begin of profiling: addtoprofile member function */ + ps.printPrefixln("#ifdef INCLUDE_PROFILER"); + ps.printPrefixln("void addToProfile(const char *, void *, int);"); + ps.printPrefixln("#endif"); + ps.printPrefixln(); + /* end of profiling */ + + ps.printPrefixln("// DOL scheduler interface"); + ps.printPrefixln("void initialize();"); + ps.printPrefixln("int fire();"); + ps.printPrefixln("void setDetached();"); + ps.printPrefixln("int isDetached();"); + ps.printPrefixln(); + ps.printPrefixln(); + ps.printPrefixln("protected:"); + ps.printPrefixln(); + ps.printPrefixln("private:"); + ps.printPrefixln("" + p.getBasename() + "_wrapper( const " + + p.getBasename() + "_wrapper& );"); + ps.printPrefixln("" + p.getBasename() + "_wrapper& operator = " + + "( const " + p.getBasename() + "_wrapper& );"); + ps.printPrefixln("DOLProcess _process;"); + ps.printPrefixln("int _detached;"); + ps.printRightBracket(); + ps.printPrefixln(";"); + ps.printPrefixln("#endif"); + } + + protected String _dir = null; +} diff --git a/dol/src/dol/visitor/hdsd/HdsdScriptVisitor.java b/dol/src/dol/visitor/hdsd/HdsdScriptVisitor.java new file mode 100644 index 0000000..322cb77 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/HdsdScriptVisitor.java @@ -0,0 +1,376 @@ +package dol.visitor.hdsd; + + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.util.Iterator; +import java.util.List; + +import dol.datamodel.architecture.Configuration; +import dol.datamodel.architecture.Processor; +import dol.datamodel.mapping.Mapping; +import dol.main.UserInterface; +import dol.util.CodePrintStream; +import dol.visitor.MapVisitor; + +/** + * Visitor that is used to generate a shell script to + * distribute, run, monitor, profile and clean up a distributed + * simulation. + */ +public class HdsdScriptVisitor extends MapVisitor { + + /** + * Constructor. + * + * @param dir path of the shell script + */ + public HdsdScriptVisitor(String dir) { + _dir = dir; + } + + /** + * Create the shell script for the given mapping. + * + * @param x mapping that needs to be rendered. + */ + public void visitComponent(Mapping x) { + try { + String filename = _dir + "/" + "scd.sh"; + OutputStream file = new FileOutputStream(filename); + CodePrintStream ps = new CodePrintStream(file); + + List pList = x.getProcessorList(); + int numProcessors = pList.size(); + + // arrays to hold strings for generation + String[] hNames = new String[numProcessors]; + String[] hAddrs = new String[numProcessors]; + String[] hDirs = new String[numProcessors]; + String[] hUsers = new String[numProcessors]; + + // get processor information and fill to string arrays + int numSlaves = 0; + Iterator iter = pList.iterator(); + while (iter.hasNext()) + { + Processor p = iter.next(); + int pIdx = numSlaves; + boolean master = false; + Configuration c = p.getCfg("master"); + if (c != null && c.getValue().equals("true")) + master = true; + + // if it is the master, it will be the last processor + if (master) + pIdx = numProcessors-1; + + // fill information to string arrays + hNames[pIdx] = p.getName(); + hAddrs[pIdx] = p.getCfg("address").getValue(); + c = p.getCfg("basedir"); + if (c != null) + { + String dir = c.getValue(); + // remove tailing '/' + if ( dir.endsWith("/") ) + dir = dir.replaceAll("/" + "$", ""); + if (dir.equals("")) + hDirs[pIdx] = hNames[pIdx]; + else + hDirs[pIdx] = dir + "/" + hNames[pIdx]; + } + else + hDirs[pIdx] = hNames[pIdx]; + c = p.getCfg("username"); + if (c != null) + hUsers[pIdx] = c.getValue() + "@"; + else + hUsers[pIdx] = ""; + + if (!master) + numSlaves++; + } // end get and fill information + + /* generate script */ + // head + ps.println("#!/bin/bash"); + ps.println(); + ps.println("SCRIPTNAME=\"`echo $0 | sed 's/.*\\///'`\""); + ps.println(); + + // host configuration + ps.println("### host configuration"); + ps.print("NAME=( "); + for (int i=0; i scd_profilerout.txt 2>&1"); + ps.printPrefixln("if [ $? -ne 0 ]; then"); + ps.prefixInc(); + ps.printPrefixln("echo"); + ps.printPrefixln("echo \"Profiling ${NAME[$1]} failed!\""); + ps.printPrefixln("echo \"Check scd_tmp_profilerout.txt for more information.\""); + ps.printPrefixln("echo"); + ps.printPrefixln("rm scd_tmp_profiled.xml"); + ps.printPrefixln("exit 1"); + ps.prefixDec(); + ps.printPrefixln("fi"); + ps.printPrefixln("rm scd_profilerout.txt"); + ps.printPrefixln("mv scd_tmp_profiled_annotated.xml scd_tmp_profiled.xml"); + ps.printPrefixln("rm profile_${NAME[$1]}.txt"); + ps.prefixDec(); + ps.println("}"); + ps.println(); + + // main programm start + ps.println("### main program"); + ps.println(); + ps.println("# require at least one argument"); + ps.println("if [ ! $# -ge 1 ]; then"); + ps.prefixInc(); + ps.printPrefixln("echo"); + ps.printPrefixln("echo \"Error: At least one argument is required!\""); + ps.printPrefixln("usage"); + ps.printPrefixln("exit 1"); + ps.prefixDec(); + ps.println("fi"); + ps.println(); + ps.println("# switch on operation"); + ps.println("case \"$1\" in"); + + // distribute binaries to simulators + ps.println("\"distribute\")"); + ps.prefixInc(); + ps.printPrefixln("echo \"Distributing binaries to simulators...\""); + ps.printPrefixln("# prepare directories"); + for (int i=0; i stdout_${NAME[" + i + "]}.txt 2>&1 &"); + ps.printPrefixln("ssh ${USER[" + (numProcessors-1) + + "]}${ADDR[" + (numProcessors-1) + + "]} \"cd ${DIR[" + (numProcessors-1) + + "]}; ./scd_${NAME[" + (numProcessors-1) + + "]}\" 2>&1 | tee stdout_${NAME[" + + (numProcessors-1) + "]}.txt"); + ps.prefixDec(); + ps.println(";;"); + + // check if simulators are running + ps.println("\"check\")"); + ps.prefixInc(); + ps.printPrefixln("echo \"Checking which simulators are active...\""); + for (int i=0; i /dev/null && echo ${NAME[" + i + "]} is active || echo ${NAME[" + i + "]} is not active\""); + ps.prefixDec(); + ps.println(";;"); + + // kill all simulators + ps.println("\"kill\")"); + ps.prefixInc(); + ps.printPrefixln("echo \"Killing all simulators...\""); + for (int i=0; i /dev/null"); + ps.printPrefixln("if [ $? -ne 0 ]; then"); + ps.prefixInc(); + ps.printPrefixln("echo"); + ps.printPrefixln("echo \"Error: Illegal file extension: required .xml!\""); + ps.printPrefixln("echo"); + ps.printPrefixln("exit 1"); + ps.prefixDec(); + ps.printPrefixln("fi"); + ps.println(); + ps.printPrefixln("PFILE=`echo $2 | sed 's/.*\\///' | sed 's/\\.xml$/_annotated.xml/'`"); + ps.printPrefixln("echo \"Profiling into ${PFILE}...\""); + ps.println(); + ps.printPrefixln("# check that the DOL is found and the classpath set correctly"); + ps.printPrefixln("java dol.main.Main > /dev/null 2>&1"); + ps.printPrefixln("if [ $? -eq 1 ]; then"); + ps.prefixInc(); + ps.printPrefixln("echo"); + ps.printPrefixln("echo \"DOL framework not found!\""); + ps.printPrefixln("echo"); + ps.printPrefixln("exit 1"); + ps.prefixDec(); + ps.printPrefixln("fi"); + ps.printPrefixln("cp \"$2\" scd_tmp_profiled.xml"); + ps.println(); + for (int i=0; i +#include +#include + +#ifdef __DOL_ETHZ_GEN__ +#include +using sc_core::sc_port; +#endif + +/************************************************************************ + * do not add code to this header + ************************************************************************/ + +/** + * Define the DOL process handler scheme. + * - Local variables are defined in structure LocalState. Local + * variables may vary from different processes. + * - The ProcessInit function pointer points to a function which + * initializes a process. + * - The ProcessFire function pointer points to a function which + * performs the actual computation. The communication between + * processes is inside the ProcessFire function. + * - The WPTR is a placeholder for callback. One can just + * leave it blank. + */ + +//structure for local memory of process +typedef struct _local_states *LocalState; + +//additional behavioral functions could be declared here +typedef void (*ProcessInit)(struct _process*); +typedef int (*ProcessFire)(struct _process*); +typedef void *WPTR; + +//process handler +struct _process; + +typedef struct _process { + LocalState local; + ProcessInit init; + ProcessFire fire; + WPTR wptr; //placeholder for wrapper instance +} DOLProcess; + + +//macros to deal with iterated ports +/** + ****************************************************** + * The HdS code is needed to replace the current ETHZ * + * implementation. * + ****************************************************** + * + * Macro to create a variable to store a port name. + * + * @param name name of the variable + */ +#ifdef __DOL_ETHZ_GEN__ +#define CREATEPORTVAR(name) sc_port *name +#else +#define CREATEPORTVAR(name) // Hds Code +#endif + +/** + * Create the port name of an iterated port based on its basename and the + * given indices. + * + * @param port buffer where the result is stored (created using + * CREATEPORTVAR) + * @param base basename of the port + * @param number_of_indices number of dimensions of the port + * @param index_range_pairs index and range values for each dimension + */ +#define CREATEPORT(port, base, number_of_indices, index_range_pairs...) \ + createPort(&port, base, number_of_indices, index_range_pairs) + +int getIndex(const char* string, char* tokens, int indexNumber); + +/* + ****************************************************** + * The HdS code is needed to replace the current ETHZ * + * implementation. * + ****************************************************** + */ +#ifdef __DOL_ETHZ_GEN__ +template +sc_port *createPort(sc_port **port, + void *base, + int number_of_indices, + int index0, int range0) { + *port = &((static_cast *>(base))[index0]); + return &((static_cast *>(base))[index0]); +} + +template +sc_port *createPort(sc_port **port, + void *base, + int number_of_indices, + int index0, int range0, + int index1, int range1) { + *port = &((static_cast *>(base))[ + index0 * range1 + index1]); + return &((static_cast *>(base))[ + index0 * range1 + index1]); +} + +template +sc_port *createPort(sc_port **port, + void *base, + int number_of_indices, + int index0, int range0, + int index1, int range1, + int index2, int range2) { + *port = &((static_cast *>(base))[ + index0 * range1 * range2 + index1 * range0 + index2]); + return &((static_cast *>(base))[ + index0 * range1 * range2 + index1 * range0 + index2]); +} + +template +sc_port *createPort(sc_port **port, + void *base, + int number_of_indices, + int index0, int range0, + int index1, int range1, + int index2, int range2, + int index3, int range3) { + *port = &((static_cast *>(base))[ + index0 * range1 * range2 * range3 + + index1 * range2 * range3 + index2 * range3 + index3]); + return &((static_cast *>(base))[ + index0 * range1 * range2 * range3 + + index1 * range2 * range3 + index2 * range3 + index3]); +} +#else +#define createPort() //HdS code +#endif + +#endif diff --git a/dol/src/dol/visitor/hdsd/lib/dol_sched_if.h b/dol/src/dol/visitor/hdsd/lib/dol_sched_if.h new file mode 100644 index 0000000..d861b1e --- /dev/null +++ b/dol/src/dol/visitor/hdsd/lib/dol_sched_if.h @@ -0,0 +1,43 @@ +/************************************************************************** + dol_sched_if.h + + Scheduler interface for a DOL process + + (c) 2006 by Alexander Maxiaguine + + Computer Engineering and Networks Laboratory, TIK + Swiss Federal Institute of Technology, ETHZ Zurich + Switzerland + +**************************************************************************/ + +/************************************************************************** + Change Log: + + 14.03.06 -- creation + +**************************************************************************/ + +#ifndef DOL_SCHED_IF_H +#define DOL_SCHED_IF_H + +class dol_sched_if +{ + +public: + virtual void initialize() = 0; + virtual int fire() = 0; + + +protected: + dol_sched_if() {} + + +private: + + // disabled + dol_sched_if( const dol_sched_if& ); + dol_sched_if& operator = ( const dol_sched_if& ); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/lib/simple_fifo.h b/dol/src/dol/visitor/hdsd/lib/simple_fifo.h new file mode 100644 index 0000000..b070b8b --- /dev/null +++ b/dol/src/dol/visitor/hdsd/lib/simple_fifo.h @@ -0,0 +1,186 @@ +/***************************************************************************** + + The following code is derived, directly or indirectly, from the SystemC + source code Copyright (c) 1996-2004 by all Contributors. + All Rights reserved. + + The contents of this file are subject to the restrictions and limitations + set forth in the SystemC Open Source License Version 2.4 (the "License"); + You may not use this file except in compliance with such restrictions and + limitations. You may obtain instructions on how to receive a copy of the + License at http://www.systemc.org/. Software distributed by Contributors + under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the License for the specific + language governing rights and limitations under the License. + + *****************************************************************************/ + +/***************************************************************************** + + simple_fifo.cpp -- Simple SystemC 2.0 producer/consumer example. + + From "An Introduction to System Level Modeling in + SystemC 2.0". By Stuart Swan, Cadence Design Systems. + Available at www.systemc.org + + Original Author: Stuart Swan, Cadence Design Systems, 2001-06-18 + + *****************************************************************************/ + +/***************************************************************************** + + MODIFICATION LOG - modifiers, enter your name, affiliation, date and + changes you are making here. + + Name, Affiliation, Date: + Description of Modification: + + *****************************************************************************/ + +#ifndef _SIMPLE_FIFO_H_ +#define _SIMPLE_FIFO_H_ + +#include +using sc_core::sc_interface; +using sc_core::sc_channel; +using sc_core::sc_event; +using sc_core::sc_module_name; + +class write_if : virtual public sc_interface +{ + public: + virtual void write(char) = 0; + virtual void reset() = 0; + virtual int wtest(int) = 0; +}; + +class read_if : virtual public sc_interface +{ + public: + virtual void read(char &) = 0; + virtual int num_available() = 0; + virtual int rtest(int) = 0; +}; + +class fifo : public sc_channel, public write_if, public read_if +{ + public: + fifo(sc_module_name name, int size) + : sc_channel(name), num_elements(0), first(0), max(size) { + data = new char[size]; + } + + void write(char c) { + if (num_elements == max) + wait(read_event); + + data[(first + num_elements) % max] = c; + ++ num_elements; + write_event.notify(); + } + + void read(char &c){ + if (num_elements == 0) + wait(write_event); + + c = data[first]; + -- num_elements; + first = (first + 1) % max; + read_event.notify(); + } + + int rtest(int size) { return (size <= num_elements) ? 1 : 0; } + int wtest(int size) { return (size <= max - num_elements) ? 1 : 0; } + + + void reset() { num_elements = first = 0; } + + int num_available() { return num_elements;} + + private: + int max; + char *data; + int num_elements, first; + sc_event write_event, read_event; +}; + + +#endif + +/* +class producer : public sc_module +{ + public: + sc_port out; + + SC_HAS_PROCESS(producer); + + producer(sc_module_name name) : sc_module(name) + { + SC_THREAD(main); + } + + void main() + { + const char *str = + "Visit www.systemc.org and see what SystemC can do for you today!\n"; + + while (*str) + out->write(*str++); + } +}; + +class consumer : public sc_module +{ + public: + sc_port in; + + SC_HAS_PROCESS(consumer); + + consumer(sc_module_name name) : sc_module(name) + { + SC_THREAD(main); + } + + void main() + { + char c; + cout << endl << endl; + + while (true) { + in->read(c); + cout << c << flush; + + if (in->num_available() == 1) + cout << "<1>" << flush; + if (in->num_available() == 9) + cout << "<9>" << flush; + } + } +}; + +class top : public sc_module +{ + public: + fifo *fifo_inst; + producer *prod_inst; + consumer *cons_inst; + + top(sc_module_name name) : sc_module(name) + { + fifo_inst = new fifo("Fifo1"); + + prod_inst = new producer("Producer1"); + prod_inst->out(*fifo_inst); + + cons_inst = new consumer("Consumer1"); + cons_inst->in(*fifo_inst); + } +}; + +int sc_main (int argc , char *argv[]) { + top top1("Top1"); + sc_start(-1); + return 0; +} +*/ diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_cont_fsm.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_cont_fsm.cpp new file mode 100644 index 0000000..68fc296 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_cont_fsm.cpp @@ -0,0 +1,30 @@ +#include "fsm/scd_cont_fsm.h" + +#include "scd_logging.h" +#include "scd_cont_state.h" + + +void scd_cont_fsm::set_state(scd_cont_state& state) +{ + _state = &state; + scd_debug(_name + ": [" + _state->get_name() +"]"); +} + + +void scd_cont_fsm::save_state() +{ + _hist_state = _state; +} + + +void scd_cont_fsm::save_state(scd_cont_state& state) +{ + _hist_state = &state; +} + + +void scd_cont_fsm::load_state() +{ + _state = _hist_state; + scd_debug(_name + ": [" + _state->get_name() +"]"); +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_cont_fsm.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_cont_fsm.h new file mode 100644 index 0000000..f5d2eb4 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_cont_fsm.h @@ -0,0 +1,54 @@ +#ifndef SCD_CONT_FSM_H +#define SCD_CONT_FSM_H + +#include + +/* forward declaration */ +class scd_cont_state; + + +/** + * FSM base class. Holds the current and the history state and allows + * state transitions. Transitions are logged in debug loglevel. + */ +class scd_cont_fsm +{ + +public: + /** + * Constructor. + * \param name the name of the state machine + */ + scd_cont_fsm(const std::string& name): _name(name) {} + + virtual ~scd_cont_fsm() {} + + /** + * Sets a new state. This is a state transition. + */ + void set_state(scd_cont_state& state); + + /** + * Saves the current state as the history state. This is not a state + * transition. + */ + void save_state(); + + /** + * Saves a specified state as the history state. This is not a state + * transition. + */ + void save_state(scd_cont_state& state); + + /** + * Restores the saved history state. This is a state transition. + */ + void load_state(); + +protected: + scd_cont_state* _state; + scd_cont_state* _hist_state; + std::string _name; +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_cont_fsm_if.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_cont_fsm_if.h new file mode 100644 index 0000000..b8897a5 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_cont_fsm_if.h @@ -0,0 +1,80 @@ +#ifndef SCD_CONT_FSM_IF_H +#define SCD_CONT_FSM_IF_H + +#include "systemc" + + +/** + * Public interface for control manager state machines (master, slave, slave + * wrapper). + */ +class scd_cont_fsm_if +{ +public: + virtual ~scd_cont_fsm_if() {} + + /** + * Signalize the FSM that the simulation is idle and the next event + * is in a specific amount of time (relative). + * \param time time of next event relative to current time + */ + virtual void set_idle(const sc_core::sc_time& time) = 0; + + /** + * Signalizes the FSM that the simulation can be run. + */ + virtual void set_busy() = 0; + + /** + * Signalizes the FSM that the simulation on this simulator has finished. + * No more events exist right now. + */ + virtual void set_done() = 0; + + /** + * Signalizes the FSM that an error has occured and the simulation + * has to be brought down. + */ + virtual void set_fail() = 0; + + /** + * Drives the control FSM. Shall be called repeatedly (i.e. from the + * main loop). + */ + virtual void process() = 0; + + /** + * Indicates if the FSM is initiated and still working. + * \return true if the state is not init, terminated or failed + */ + virtual bool active() const = 0; + + /** + * Indicates if another step should be simulated (i.e. the FSM is in + * the busy state). + * \return true if the FSM is in busy state + */ + virtual bool busy() const = 0; + + /** + * Indicates if the FSM is in the failed state. + * \return false if an error occured and the FSM stopped working + */ + virtual bool failed() const = 0; + + /** + * Indicates if simulation time has to be advanced (i.e. the FSM + * is in the time state). If this is the case, the time step + * shall be obtained by calling get_time_step(). + * \return true if the time has to be advanced + */ + virtual bool advance_time() const = 0; + + /** + * Returns the time step by which the simulation time has to be advanced. + * Shall only be called in time state. + */ + virtual const sc_core::sc_time& get_time_step() = 0; +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_cont_state.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_cont_state.h new file mode 100644 index 0000000..82e09d3 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_cont_state.h @@ -0,0 +1,38 @@ +#ifndef SCD_CONT_STATE_H +#define SCD_CONT_STATE_H + +#include + +#include "scd_simulator.h" +#include "fsm/scd_cont_fsm_if.h" + + +/* forward declaration */ +class scd_simulator; + + +/** + * Base class of all FSM states. + */ +class scd_cont_state : public scd_cont_fsm_if +{ +public: + /** + * Constructor. + * \param sim the simulation environment + */ + scd_cont_state(scd_simulator& sim): _sim(sim) {} + + virtual ~scd_cont_state() {} + + /** + * Returns the name of the state. + */ + const std::string& get_name() const { return _name; } + +protected: + scd_simulator& _sim; + std::string _name; +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_cont_wrapper_if.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_cont_wrapper_if.h new file mode 100644 index 0000000..12d6f50 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_cont_wrapper_if.h @@ -0,0 +1,80 @@ +#ifndef SCD_CONT_WRAPPER_IF_H +#define SCD_CONT_WRAPPER_IF_H + +#include "systemc" + + +/** + * Extends the public interface of the slave wrapper FSM. + */ +class scd_cont_wrapper_if +{ +public: + /** + * Sends a time_req command to the slave. + */ + virtual void send_time_req() = 0; + + /** + * Sends a time_nack command to the slave. + */ + virtual void send_time_nack() = 0; + + /** + * Sends a time command to the slave. + */ + virtual void send_time(const sc_core::sc_time& time) = 0; + + /** + * Sends a term_req command to the slave. + */ + virtual void send_term_req() = 0; + + /** + * Sends a term_nack command to the slave. + */ + virtual void send_term_nack() = 0; + + /** + * Sends a term command to the slave. + */ + virtual void send_term() = 0; + + /** + * Inidcates if the slave is in term_req state. + * \return true if the slave seems to be in time_req state + */ + virtual bool time_req() const = 0; + + /** + * Inidcates if the slave is in time_ack state. + * \return true if the slave seems to be in time_ack state + */ + virtual bool time_ack() const = 0; + + /** + * Inidcates if the slave is in term_req state. + * \return true if the slave seems to be in term_req state + */ + virtual bool term_req() const = 0; + + /** + * Inidcates if the slave is in term_ack state. + * \return true if the slave seems to be in term_ack state + */ + virtual bool term_ack() const = 0; + + /** + * Inidcates if the slave is in idle state. + * \return true if the slave seems to be in idle state + */ + virtual bool idle() const = 0; + + /** + * Indicates if the slave is in done state. + * \return true if the slave seems to be in done state + */ + virtual bool done() const = 0; +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_base.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_base.cpp new file mode 100644 index 0000000..a0175a3 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_base.cpp @@ -0,0 +1,103 @@ +#include "fsm/scd_stm_base.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_man_master.h" +#include "scd_command.h" +#include "scd_cont_man.h" + + +scd_stm_base::scd_stm_base(scd_simulator& sim, scd_cont_man_master& fsm): + scd_cont_state(sim), _fsm(fsm), _slaves(fsm._slaves), + _time_step(fsm._time_step), + _st_init(fsm._st_init), _st_busy(fsm._st_busy), _st_idle(fsm._st_idle), + _st_done(fsm._st_done), _st_time_req(fsm._st_time_req), + _st_time(fsm._st_time), _st_term_req(fsm._st_term_req), + _st_terminate(fsm._st_terminate), _st_terminated(fsm._st_terminated), + _st_fail(fsm._st_fail), _st_failed(fsm._st_failed) +{ +} + + +void scd_stm_base::set_fail() +{ + std::list::iterator it; + + for (it = _slaves.begin(); it != _slaves.end(); it++) + { + (*it)->set_fail(); + } + + _fsm.set_state(_st_fail); +} // set_fail() + + +void scd_stm_base::process() +{ + // check for failed slaves and react + if (!_check_slaves()) + return; +} + + +bool scd_stm_base::active() const { return true; } + + +bool scd_stm_base::busy() const { return false; } + + +bool scd_stm_base::failed() const { return false; } + + +bool scd_stm_base::advance_time() const { return false; } + + +const sc_core::sc_time& scd_stm_base::get_time_step() +{ + scd_error("illegal call to get_time_step()"); + throw scd_exception("illegal call"); +} + + +bool scd_stm_base::_check_slaves() +{ + + std::list::iterator iter; + + for (iter = _slaves.begin(); iter != _slaves.end(); iter++) + { + if ( (*iter)->failed() ) + { + scd_error("slave \"" + (*iter)->get_name() + "\" failed"); + set_fail(); + return false; + } + } + + return true; + +} // _check_slaves() + + +bool scd_stm_base::_some_slaves_active() +{ + std::list::iterator iter; + + for (iter = _slaves.begin(); iter != _slaves.end(); iter++) + { + if ( (*iter)->active() ) + return true; + } + + return false; + +} // _some_slaves_active() + + +void scd_stm_base::_close_slaves() +{ + std::list::iterator iter; + + for (iter = _slaves.begin(); iter != _slaves.end(); iter++) + (*iter)->close(); +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_base.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_base.h new file mode 100644 index 0000000..6b8463f --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_base.h @@ -0,0 +1,64 @@ +#ifndef SCD_STM_BASE_H +#define SCD_STM_BASE_H + +#include + +#include "scd_simulator.h" +#include "scd_cont_slave_wrapper.h" +#include "fsm/scd_cont_state.h" + + +/* forward declaration */ +class scd_cont_man_master; + + +/** + * Base class for all control master states. + */ +class scd_stm_base : public scd_cont_state +{ +public: + /** + * Constructor. + * \param sim the simulation environment + * \param fsm the FSM of this state + */ + scd_stm_base(scd_simulator& sim, scd_cont_man_master& fsm); + + virtual ~scd_stm_base() {} + + /* scd_cont_fsm_if */ + void set_busy() {} + void set_idle(const sc_core::sc_time& time) {} + void set_done() {} + void set_fail(); + void process(); + bool active() const; + bool busy() const; + bool failed() const; + bool advance_time() const; + const sc_core::sc_time& get_time_step(); + +protected: + scd_cont_man_master& _fsm; + std::list& _slaves; + sc_core::sc_time& _time_step; + scd_cont_state& _st_init; + scd_cont_state& _st_busy; + scd_cont_state& _st_idle; + scd_cont_state& _st_done; + scd_cont_state& _st_time_req; + scd_cont_state& _st_time; + scd_cont_state& _st_term_req; + scd_cont_state& _st_terminate; + scd_cont_state& _st_terminated; + scd_cont_state& _st_fail; + scd_cont_state& _st_failed; + + /* member functions */ + bool _check_slaves(); + bool _some_slaves_active(); + void _close_slaves(); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_busy.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_busy.cpp new file mode 100644 index 0000000..fcb322c --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_busy.cpp @@ -0,0 +1,34 @@ +#include "fsm/scd_stm_busy.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_man_master.h" + + +void scd_stm_busy::set_idle(const sc_core::sc_time& time) +{ + /* prevents the situation where no events exist, but a huge + * ammount of data is being transferred that will generate events later + */ + if (_sim.get_poller().wait(SCD_CONT_DELAY)) + return; + + _time_step = time; + _fsm.set_state(_st_idle); +} + + +void scd_stm_busy::set_done() +{ + /* prevents the situation where no events exist, but a huge + * ammount of data is being transferred that will generate events later + */ + if (_sim.get_poller().wait(SCD_CONT_DELAY)) + return; + + _time_step = sc_core::SC_ZERO_TIME; + _fsm.set_state(_st_done); +} + + +bool scd_stm_busy::busy() const { return true; } diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_busy.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_busy.h new file mode 100644 index 0000000..ae9eb1d --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_busy.h @@ -0,0 +1,22 @@ +#ifndef SCD_STM_BUSY_H +#define SCD_STM_BUSY_H + +#include "fsm/scd_stm_base.h" + + +class scd_stm_busy : public scd_stm_base +{ +public: + scd_stm_busy(scd_simulator& sim, scd_cont_man_master& fsm): + scd_stm_base(sim, fsm) { _name = "busy"; } + virtual ~scd_stm_busy() {} + + + /* scd_cont_fsm_if */ + void set_idle(const sc_core::sc_time& time); + void set_done(); + bool busy() const; + +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_done.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_done.cpp new file mode 100644 index 0000000..9d54d60 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_done.cpp @@ -0,0 +1,64 @@ +#include "fsm/scd_stm_done.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_man_master.h" + + +void scd_stm_done::set_busy() +{ + _fsm.set_state(_st_busy); +} + + +void scd_stm_done::set_idle(const sc_core::sc_time& time) +{ + _time_step = time; + _fsm.set_state(_st_idle); +} + + +void scd_stm_done::process() +{ + if (!_check_slaves()) + return; + + std::list::iterator iter; + bool terminate = true; + + for (iter = _slaves.begin(); iter != _slaves.end(); iter++) + { + if (!(*iter)->idle() && !(*iter)->done()) + { + // this slave is not ready yet + return; + } + + if (!(*iter)->done()) + terminate = false; + } + + /* all slaves seem idle or done. wait a short moment, to prevent + * race conditions (channel data in transit but both endpoints done). + * if no socket activity occured we can move on, else we cancel. + */ + if (_sim.get_poller().wait(SCD_CONT_DELAY)) + return; + + if (terminate) + { + // all slaves seem to be done + for (iter = _slaves.begin(); iter != _slaves.end(); iter++) + (*iter)->send_term_req(); + _fsm.save_state(); + _fsm.set_state(_st_term_req); + } + else + { + // some slaves are not done yet + for (iter = _slaves.begin(); iter != _slaves.end(); iter++) + (*iter)->send_time_req(); + _fsm.save_state(); + _fsm.set_state(_st_time_req); + } +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_done.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_done.h new file mode 100644 index 0000000..de20874 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_done.h @@ -0,0 +1,21 @@ +#ifndef SCD_STM_DONE_H +#define SCD_STM_DONE_H + +#include "fsm/scd_stm_base.h" + + +class scd_stm_done : public scd_stm_base +{ +public: + scd_stm_done(scd_simulator& sim, scd_cont_man_master& fsm): + scd_stm_base(sim, fsm) { _name = "done"; } + virtual ~scd_stm_done() {} + + + /* scd_cont_fsm_if */ + void set_busy(); + void set_idle(const sc_core::sc_time& time); + void process(); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_fail.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_fail.cpp new file mode 100644 index 0000000..53b13d3 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_fail.cpp @@ -0,0 +1,17 @@ +#include "fsm/scd_stm_fail.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_man_master.h" + + +void scd_stm_fail::process() +{ + if (!_some_slaves_active()) + { + // all slaves have terminated + _sim.get_chan_man().close(); + _close_slaves(); + _fsm.set_state(_st_failed); + } +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_fail.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_fail.h new file mode 100644 index 0000000..38b9e87 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_fail.h @@ -0,0 +1,25 @@ +#ifndef SCD_STM_FAIL_H +#define SCD_STM_FAIL_H + +#include "fsm/scd_stm_base.h" + + +/* forward declaration */ +class scd_cont_man_master; + + +class scd_stm_fail : public scd_stm_base +{ +public: + scd_stm_fail(scd_simulator& sim, scd_cont_man_master& fsm): + scd_stm_base(sim, fsm) { _name = "fail"; } + + virtual ~scd_stm_fail() {} + + + /* scd_cont_fsm_if */ + void set_fail() {} + void process(); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_failed.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_failed.cpp new file mode 100644 index 0000000..fd0cd9b --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_failed.cpp @@ -0,0 +1,10 @@ +#include "fsm/scd_stm_failed.h" + +#include "scd_logging.h" +#include "scd_exception.h" + + +bool scd_stm_failed::active() const { return false; } + + +bool scd_stm_failed::failed() const { return true; } diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_failed.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_failed.h new file mode 100644 index 0000000..148a56b --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_failed.h @@ -0,0 +1,25 @@ +#ifndef SCD_STM_FAILED_H +#define SCD_STM_FAILED_H + +#include "fsm/scd_stm_base.h" + + +/* forward declaration */ +class scd_cont_man_master; + + +class scd_stm_failed : public scd_stm_base +{ +public: + scd_stm_failed(scd_simulator& sim, scd_cont_man_master& fsm): + scd_stm_base(sim, fsm) { _name = "failed"; } + virtual ~scd_stm_failed() {} + + /* scd_cont_fsm_if */ + void set_fail() {} + void process() {} + bool active() const; + bool failed() const; +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_idle.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_idle.cpp new file mode 100644 index 0000000..1138ab7 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_idle.cpp @@ -0,0 +1,50 @@ +#include "fsm/scd_stm_idle.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_man_master.h" + + +void scd_stm_idle::set_busy() +{ + _fsm.set_state(_st_busy); +} + + +void scd_stm_idle::set_done() +{ + _time_step = sc_core::SC_ZERO_TIME; + _fsm.set_state(_st_done); +} + + +void scd_stm_idle::process() +{ + if (!_check_slaves()) + return; + + std::list::iterator iter; + + for (iter = _slaves.begin(); iter != _slaves.end(); iter++) + { + if (!(*iter)->idle() && !(*iter)->done()) + { + // this slave is not ready yet + return; + } + } + + /* all slaves seem idle or done. wait a short moment, to prevent + * race conditions (channel data in transit but both endpoints done). + * if no socket activity occured we can move on, else we cancel. + */ + if (_sim.get_poller().wait(SCD_CONT_DELAY)) + return; + + // all slaves seem to be ready to advance time + for (iter = _slaves.begin(); iter != _slaves.end(); iter++) + (*iter)->send_time_req(); + + _fsm.save_state(); + _fsm.set_state(_st_time_req); +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_idle.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_idle.h new file mode 100644 index 0000000..b19e4f0 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_idle.h @@ -0,0 +1,20 @@ +#ifndef SCD_STM_IDLE_H +#define SCD_STM_IDLE_H + +#include "fsm/scd_stm_base.h" + + +class scd_stm_idle : public scd_stm_base +{ +public: + scd_stm_idle(scd_simulator& sim, scd_cont_man_master& fsm): + scd_stm_base(sim, fsm) { _name = "idle"; } + virtual ~scd_stm_idle() {} + + /* scd_cont_fsm_if */ + void set_busy(); + void set_done(); + void process(); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_init.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_init.cpp new file mode 100644 index 0000000..3027ad8 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_init.cpp @@ -0,0 +1,58 @@ +#include "fsm/scd_stm_init.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_man_master.h" + + +void scd_stm_init::set_idle(const sc_core::sc_time& time) +{ + scd_error("init: illegal call to set_idle()"); + throw scd_exception("illegal call"); +} + + +void scd_stm_init::set_busy() +{ + scd_error("init: illegal call to set_busy()"); + throw scd_exception("illegal call"); +} + + +void scd_stm_init::set_done() +{ + scd_error("init: illegal call to set_done()"); + throw scd_exception("illegal call"); +} + + +void scd_stm_init::process() +{ + // check for failed slaves and react + if (!_check_slaves()) + return; + + std::list::iterator iter; + + for (iter = _slaves.begin(); iter != _slaves.end(); iter++) + { + // if this is still in init state we terminate + if ( !(*iter)->active() ) + return; + } + + // all slaves are active + scd_info("all slaves connected"); + _fsm.set_state(_st_busy); + +} // process() + + +bool scd_stm_init::active() const { return false; } + + +bool scd_stm_init::advance_time() const +{ + scd_error("illegal call to advance_time()"); + throw scd_exception("illegal call"); +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_init.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_init.h new file mode 100644 index 0000000..b146a46 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_init.h @@ -0,0 +1,27 @@ +#ifndef SCD_STM_INIT_H +#define SCD_STM_INIT_H + +#include "fsm/scd_stm_base.h" + + +/* forward declaration */ +class scd_cont_man_master; + + +class scd_stm_init : public scd_stm_base +{ +public: + scd_stm_init(scd_simulator& sim, scd_cont_man_master& fsm): + scd_stm_base(sim, fsm) { _name = "init"; } + virtual ~scd_stm_init() {} + + /* scd_cont_fsm_if */ + void set_idle(const sc_core::sc_time& time); + void set_busy(); + void set_done(); + void process(); + bool active() const; + bool advance_time() const; +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_term_req.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_term_req.cpp new file mode 100644 index 0000000..1d65952 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_term_req.cpp @@ -0,0 +1,59 @@ +#include "fsm/scd_stm_term_req.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_man_master.h" + + +void scd_stm_term_req::set_busy() +{ + _send_term_nack(); + _fsm.load_state(); +} + + +void scd_stm_term_req::set_idle(const sc_core::sc_time& time) +{ + _send_term_nack(); + _fsm.load_state(); +} + + +void scd_stm_term_req::process() +{ + if (!_check_slaves()) + return; + + std::list::iterator iter; + + for (iter = _slaves.begin(); iter != _slaves.end(); iter++) + { + if ( !(*iter)->term_req() && !(*iter)->term_ack() ) + { + // received term_nack from this slave + _send_term_nack(); + _fsm.load_state(); + return; + } + else if ( !(*iter)->term_ack() ) + { + // this slave did not respond yet + return; + } + } + + // all slaves acknkowledged + for (iter = _slaves.begin(); iter != _slaves.end(); iter++) + (*iter)->send_term(); + + _fsm.set_state(_st_terminate); +} + + +void scd_stm_term_req::_send_term_nack() +{ + std::list::iterator iter; + + for (iter = _slaves.begin(); iter != _slaves.end(); iter++) + (*iter)->send_term_nack(); +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_term_req.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_term_req.h new file mode 100644 index 0000000..b93e082 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_term_req.h @@ -0,0 +1,23 @@ +#ifndef SCD_STM_TERM_REQ_H +#define SCD_STM_TERM_REQ_H + +#include "fsm/scd_stm_base.h" + + +class scd_stm_term_req : public scd_stm_base +{ +public: + scd_stm_term_req(scd_simulator& sim, scd_cont_man_master& fsm): + scd_stm_base(sim, fsm) { _name = "term_req"; } + virtual ~scd_stm_term_req() {} + + /* scd_cont_fsm_if */ + void set_busy(); + void set_idle(const sc_core::sc_time& time); + void process(); + +private: + void _send_term_nack(); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_terminate.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_terminate.cpp new file mode 100644 index 0000000..3035321 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_terminate.cpp @@ -0,0 +1,40 @@ +#include "fsm/scd_stm_terminate.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_man_master.h" + + +void scd_stm_terminate::set_busy() +{ + scd_error("received further events while terminating"); + set_fail(); +} + + +void scd_stm_terminate::set_idle(const sc_core::sc_time& time) +{ + scd_error("received future events while terminating"); + set_fail(); +} + + +void scd_stm_terminate::process() +{ + // check for failed slaves and react + if (!_check_slaves()) + return; + + if (_some_slaves_active()) + { + // not all slaves have terminated yet + return; + } + else + { + // all slaves terminated + _sim.get_chan_man().close(); + _close_slaves(); + _fsm.set_state(_st_terminated); + } +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_terminate.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_terminate.h new file mode 100644 index 0000000..f568d8c --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_terminate.h @@ -0,0 +1,21 @@ +#ifndef SCD_STM_TERMINATE_H +#define SCD_STM_TERMINATE_H + +#include "fsm/scd_stm_base.h" + + +class scd_stm_terminate : public scd_stm_base +{ +public: + scd_stm_terminate(scd_simulator& sim, scd_cont_man_master& fsm): + scd_stm_base(sim, fsm) { _name = "terminate"; } + virtual ~scd_stm_terminate() {} + + /* scd_cont_fsm_if */ + void set_busy(); + void set_idle(const sc_core::sc_time& time); + void process(); + +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_terminated.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_terminated.cpp new file mode 100644 index 0000000..5d7e165 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_terminated.cpp @@ -0,0 +1,8 @@ +#include "fsm/scd_stm_terminated.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_man_master.h" + + +bool scd_stm_terminated::active() const { return false; } diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_terminated.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_terminated.h new file mode 100644 index 0000000..2551b78 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_terminated.h @@ -0,0 +1,21 @@ +#ifndef SCD_STM_TERMINATED_H +#define SCD_STM_TERMINATED_H + +#include "fsm/scd_stm_base.h" + + +class scd_stm_terminated : public scd_stm_base +{ +public: + scd_stm_terminated(scd_simulator& sim, scd_cont_man_master& fsm): + scd_stm_base(sim, fsm) { _name = "terminated"; } + virtual ~scd_stm_terminated() {} + + /* scd_cont_fsm_if */ + void set_fail() {} + void process() {} + bool active() const; + +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_time.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_time.cpp new file mode 100644 index 0000000..89df203 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_time.cpp @@ -0,0 +1,15 @@ +#include "fsm/scd_stm_time.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_man_master.h" + + +bool scd_stm_time::advance_time() const { return true; } + + +const sc_core::sc_time& scd_stm_time::get_time_step() +{ + _fsm.set_state(_st_busy); + return _time_step; +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_time.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_time.h new file mode 100644 index 0000000..52e0a59 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_time.h @@ -0,0 +1,19 @@ +#ifndef SCD_STM_TIME_H +#define SCD_STM_TIME_H + +#include "fsm/scd_stm_base.h" + + +class scd_stm_time : public scd_stm_base +{ +public: + scd_stm_time(scd_simulator& sim, scd_cont_man_master& fsm): + scd_stm_base(sim, fsm) { _name = "time"; } + virtual ~scd_stm_time() {} + + /* scd_cont_fsm_if */ + bool advance_time() const; + const sc_core::sc_time& get_time_step(); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_time_req.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_time_req.cpp new file mode 100644 index 0000000..fb96b26 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_time_req.cpp @@ -0,0 +1,64 @@ +#include "fsm/scd_stm_time_req.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_man_master.h" + + +void scd_stm_time_req::set_busy() +{ + _send_time_nack(); + _fsm.load_state(); +} + + +void scd_stm_time_req::process() +{ + if (!_check_slaves()) + return; + + std::list::iterator iter; + sc_core::sc_time min_step = _time_step; + + for (iter = _slaves.begin(); iter != _slaves.end(); iter++) + { + if ( !(*iter)->time_req() && !(*iter)->time_ack() ) + { + // received time_nack from this slave + _send_time_nack(); + _fsm.load_state(); + return; + } + else if ( !(*iter)->time_ack() ) + { + // this slave did not respond yet + return; + } + else + { + // received time_ack => search the smallest step + sc_core::sc_time time_slave = (*iter)->get_time_step(); + if (min_step == sc_core::SC_ZERO_TIME) + min_step = time_slave; + else if (min_step > time_slave && + time_slave != sc_core::SC_ZERO_TIME) + min_step = time_slave; + } + } + + // all slaves acknkowledged + _time_step = min_step; + for (iter = _slaves.begin(); iter != _slaves.end(); iter++) + (*iter)->send_time(min_step); + + _fsm.set_state(_st_time); +} + + +void scd_stm_time_req::_send_time_nack() +{ + std::list::iterator iter; + + for (iter = _slaves.begin(); iter != _slaves.end(); iter++) + (*iter)->send_time_nack(); +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_time_req.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_time_req.h new file mode 100644 index 0000000..275bd95 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stm_time_req.h @@ -0,0 +1,22 @@ +#ifndef SCD_STM_TIME_REQ_H +#define SCD_STM_TIME_REQ_H + +#include "fsm/scd_stm_base.h" + + +class scd_stm_time_req : public scd_stm_base +{ +public: + scd_stm_time_req(scd_simulator& sim, scd_cont_man_master& fsm): + scd_stm_base(sim, fsm) { _name = "time_req"; } + virtual ~scd_stm_time_req() {} + + /* scd_cont_fsm_if */ + void set_busy(); + void process(); + +private: + void _send_time_nack(); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_base.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_base.cpp new file mode 100644 index 0000000..b4d0af0 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_base.cpp @@ -0,0 +1,81 @@ +#include "fsm/scd_sts_base.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_man_slave.h" +#include "scd_command.h" +#include "scd_cont_man.h" + + + +scd_sts_base::scd_sts_base(scd_simulator& sim, scd_cont_man_slave& fsm): + scd_cont_state(sim), _fsm(fsm), + _st_init(fsm._st_init), _st_busy(fsm._st_busy), _st_idle(fsm._st_idle), + _st_done(fsm._st_done), _st_time_ack(fsm._st_time_ack), + _st_time(fsm._st_time), _st_term_ack(fsm._st_term_ack), + _st_terminated(fsm._st_terminated), _st_fail(fsm._st_fail), + _st_failed(fsm._st_failed), + _writer(fsm._writer), _reader(fsm._reader), _connector(fsm._connector) +{ +} + + +void scd_sts_base::set_failed() +{ + _sim.get_poller().remove_handler(_fsm); + _sim.get_chan_man().close(); + _fsm.set_state(_st_failed); +} + + +void scd_sts_base::recv_time_req() +{ + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_TIME_NACK); + _fsm.send_command(cmd); +} + + +void scd_sts_base::recv_time(const sc_core::sc_time& time) +{ + scd_warn("received time message in wrong state"); +} + + +void scd_sts_base::recv_term_req() +{ + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_TERM_NACK); + _fsm.send_command(cmd); +} + + +void scd_sts_base::recv_term() +{ + scd_warn("received terminate message in wrong state"); +} + + +void scd_sts_base::set_fail() +{ + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_FAILED); + _fsm.send_command(cmd); + _fsm.set_state(_st_fail); +} + + +bool scd_sts_base::active() const { return true; } + + +bool scd_sts_base::busy() const { return false; } + + +bool scd_sts_base::failed() const { return false; } + + +bool scd_sts_base::advance_time() const { return false; } + + +const sc_core::sc_time& scd_sts_base::get_time_step() +{ + scd_warn("illegal call to get_time_step()"); + throw scd_exception("illegal call"); +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_base.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_base.h new file mode 100644 index 0000000..05c1e8d --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_base.h @@ -0,0 +1,101 @@ +#ifndef SCD_STS_BASE_H +#define SCD_STS_BASE_H + +#include "scd_simulator.h" +#include "scd_out_connector.h" +#include "scd_command_writer.h" +#include "scd_command_reader.h" +#include "fsm/scd_cont_state.h" + + +/* forward declaration */ +class scd_cont_man_slave; + + +/** + * Base class for all control slave states. + */ +class scd_sts_base : public scd_cont_state +{ +public: + /** + * Constructor. + * \param sim the simulation environment + * \param fsm the FSM of this state + */ + scd_sts_base(scd_simulator& sim, scd_cont_man_slave& fsm); + + virtual ~scd_sts_base() {} + + /** + * Signalizes the state, that a failed message has been received + * from the master. + */ + virtual void set_failed(); + + /** + * Signalizes the state, that a time_req message has been received + * from the master. + */ + virtual void recv_time_req(); + + /** + * Signalizes the state, that a time_nack message has been received + * from the master. + */ + virtual void recv_time_nack() {} + + /** + * Signalizes the state, that a time message has been received + * from the master. + */ + virtual void recv_time(const sc_core::sc_time& time); + + /** + * Signalizes the state, that a term_req message has been received + * from the master. + */ + virtual void recv_term_req(); + + /** + * Signalizes the state, that a term_nack message has been received + * from the master. + */ + virtual void recv_term_nack() {} + + /** + * Signalizes the state, that a term message has been received + * from the master. + */ + virtual void recv_term(); + + /* scd_cont_fsm_if */ + void set_busy() {} + void set_idle(const sc_core::sc_time& time) {} + void set_done() {} + void set_fail(); + void process() {} + bool active() const; + bool busy() const; + bool failed() const; + bool advance_time() const; + const sc_core::sc_time& get_time_step(); + +protected: + scd_cont_man_slave& _fsm; + scd_command_writer& _writer; + scd_command_reader& _reader; + scd_out_connector& _connector; + scd_cont_state& _st_init; + scd_cont_state& _st_busy; + scd_cont_state& _st_idle; + scd_cont_state& _st_done; + scd_cont_state& _st_time_ack; + scd_cont_state& _st_time; + scd_cont_state& _st_term_ack; + scd_cont_state& _st_terminated; + scd_cont_state& _st_fail; + scd_cont_state& _st_failed; +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_busy.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_busy.cpp new file mode 100644 index 0000000..a9bb214 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_busy.cpp @@ -0,0 +1,36 @@ +#include "fsm/scd_sts_busy.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_man_slave.h" + + +void scd_sts_busy::set_idle(const sc_core::sc_time& time) +{ + /* prevents the situation where no events exist, but a huge + * ammount of data is being transferred that will generate events later + */ + if (_sim.get_poller().wait(SCD_CONT_DELAY)) + return; + + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_IDLE, time); + _fsm.send_command(cmd); + _fsm.set_state(_st_idle); +} + + +void scd_sts_busy::set_done() +{ + /* prevents the situation where no events exist, but a huge + * ammount of data is being transferred that will generate events later + */ + if (_sim.get_poller().wait(SCD_CONT_DELAY)) + return; + + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_DONE); + _fsm.send_command(cmd); + _fsm.set_state(_st_done); +} + + +bool scd_sts_busy::busy() const { return true; } diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_busy.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_busy.h new file mode 100644 index 0000000..b2130ad --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_busy.h @@ -0,0 +1,21 @@ +#ifndef SCD_STS_BUSY_H +#define SCD_STS_BUSY_H + +#include "fsm/scd_sts_base.h" + + +class scd_sts_busy : public scd_sts_base +{ +public: + scd_sts_busy(scd_simulator& sim, scd_cont_man_slave& fsm): + scd_sts_base(sim, fsm) { _name = "busy"; } + virtual ~scd_sts_busy() {} + + /* scd_cont_fsm_if */ + void set_idle(const sc_core::sc_time& time); + void set_done(); + bool busy() const; + +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_done.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_done.cpp new file mode 100644 index 0000000..ddd8203 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_done.cpp @@ -0,0 +1,58 @@ +#include "fsm/scd_sts_done.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_man_slave.h" +#include "scd_cont_man.h" + + +void scd_sts_done::recv_time_req() +{ + if (_sim.get_poller().wait(SCD_CONT_DELAY)) + { + // had activity on sockets => we might be receiving data + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_TIME_NACK); + _fsm.send_command(cmd); + } + else + { + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_TIME_ACK); + _fsm.send_command(cmd); + _fsm.save_state(); + _fsm.set_state(_st_time_ack); + } +} + + +void scd_sts_done::recv_term_req() +{ + if (_sim.get_poller().wait(SCD_CONT_DELAY)) + { + // had activity on sockets => we might be receiving data + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_TERM_NACK); + _fsm.send_command(cmd); + } + else + { + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_TERM_ACK); + _fsm.send_command(cmd); + _fsm.save_state(); + _fsm.set_state(_st_term_ack); + } +} + + +void scd_sts_done::set_idle(const sc_core::sc_time& time) +{ + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_IDLE, time); + _fsm.send_command(cmd); + _fsm.set_state(_st_idle); +} + + +void scd_sts_done::set_busy() +{ + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_BUSY); + _fsm.send_command(cmd); + _fsm.set_state(_st_busy); +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_done.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_done.h new file mode 100644 index 0000000..14e762f --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_done.h @@ -0,0 +1,27 @@ +#ifndef SCD_STS_DONE_H +#define SCD_STS_DONE_H + +#include "fsm/scd_sts_base.h" + + +/* forward declaration */ +class scd_cont_man_slave; + + +class scd_sts_done : public scd_sts_base +{ +public: + scd_sts_done(scd_simulator& sim, scd_cont_man_slave& fsm): + scd_sts_base(sim, fsm) { _name = "done"; } + virtual ~scd_sts_done() {} + + void recv_time_req(); + void recv_term_req(); + + /* scd_cont_fsm_if */ + void set_idle(const sc_core::sc_time& time); + void set_busy(); + +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_fail.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_fail.cpp new file mode 100644 index 0000000..b026fa2 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_fail.cpp @@ -0,0 +1,17 @@ +#include "fsm/scd_sts_fail.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_man_slave.h" + + +void scd_sts_fail::process() +{ + if (!_fsm.is_sending()) + { + _sim.get_poller().remove_handler(_fsm); + _sim.get_chan_man().close(); + _fsm.close(); + _fsm.set_state(_st_failed); + } +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_fail.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_fail.h new file mode 100644 index 0000000..dc2fb1d --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_fail.h @@ -0,0 +1,28 @@ +#ifndef SCD_STS_FAIL_H +#define SCD_STS_FAIL_H + +#include "fsm/scd_sts_base.h" + + +/* forward declaration */ +class scd_cont_man_slave; + + +class scd_sts_fail : public scd_sts_base +{ +public: + scd_sts_fail(scd_simulator& sim, scd_cont_man_slave& fsm): + scd_sts_base(sim, fsm) { _name = "fail"; } + virtual ~scd_sts_fail() {} + + void recv_time_req() {} + void recv_time(const sc_core::sc_time& time) {} + void recv_term_req() {} + void recv_term() {} + + /* scd_cont_fsm_if */ + void set_fail() {} + void process(); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_failed.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_failed.cpp new file mode 100644 index 0000000..5e6966d --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_failed.cpp @@ -0,0 +1,11 @@ +#include "fsm/scd_sts_failed.h" + +#include "scd_logging.h" +#include "scd_exception.h" + + + +bool scd_sts_failed::active() const { return false; } + + +bool scd_sts_failed::failed() const { return true; } diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_failed.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_failed.h new file mode 100644 index 0000000..c699dbb --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_failed.h @@ -0,0 +1,31 @@ +#ifndef SCD_STS_FAILED_H +#define SCD_STS_FAILED_H + +#include "fsm/scd_sts_base.h" + + +/* forward declaration */ +class scd_cont_man_slave; + + +class scd_sts_failed : public scd_sts_base +{ +public: + scd_sts_failed(scd_simulator& sim, scd_cont_man_slave& fsm): + scd_sts_base(sim, fsm) { _name = "failed"; } + virtual ~scd_sts_failed() {} + + void set_failed() {} + + void recv_time_req() {} + void recv_time(const sc_core::sc_time& time) {} + void recv_term_req() {} + void recv_term() {} + + /* scd_cont_fsm_if */ + void set_fail() {} + bool active() const; + bool failed() const; +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_idle.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_idle.cpp new file mode 100644 index 0000000..cbb0f94 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_idle.cpp @@ -0,0 +1,37 @@ +#include "fsm/scd_sts_idle.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_man_slave.h" + + +void scd_sts_idle::recv_time_req() +{ + if (_sim.get_poller().wait(SCD_CONT_DELAY)) + { + // had activity on sockets => we might be receiving data + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_TIME_NACK); + _fsm.send_command(cmd); + } + else + { + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_TIME_ACK); + _fsm.send_command(cmd); + _fsm.save_state(); + _fsm.set_state(_st_time_ack); + } +} + + +void scd_sts_idle::set_busy() +{ + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_BUSY); + _fsm.send_command(cmd); + _fsm.set_state(_st_busy); +} + + +void scd_sts_idle::set_done() +{ + scd_warn("slave: transition attempt from idle to done"); +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_idle.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_idle.h new file mode 100644 index 0000000..df68cd1 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_idle.h @@ -0,0 +1,25 @@ +#ifndef SCD_STS_IDLE_H +#define SCD_STS_IDLE_H + +#include "fsm/scd_sts_base.h" + + +/* forward declaration */ +class scd_cont_man_slave; + + +class scd_sts_idle : public scd_sts_base +{ +public: + scd_sts_idle(scd_simulator& sim, scd_cont_man_slave& fsm): + scd_sts_base(sim, fsm) { _name = "idle"; } + virtual ~scd_sts_idle() {} + + void recv_time_req(); + + /* scd_cont_fsm_if */ + void set_busy(); + void set_done(); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_init.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_init.cpp new file mode 100644 index 0000000..d4d05e9 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_init.cpp @@ -0,0 +1,70 @@ +#include "fsm/scd_sts_init.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_man_slave.h" + + +void scd_sts_init::set_failed() +{ + _fsm.set_state(_st_failed); +} + + +void scd_sts_init::set_idle(const sc_core::sc_time& time) +{ + scd_error("init: illegal call to set_idle()"); + throw scd_exception("illegal call"); +} + + +void scd_sts_init::set_busy() +{ + scd_error("init: illegal call to set_busy()"); + throw scd_exception("illegal call"); +} + + +void scd_sts_init::set_done() +{ + scd_error("init: illegal call to set_done()"); + throw scd_exception("illegal call"); +} + + +void scd_sts_init::set_fail() +{ + _fsm.set_state(_st_failed); +} + + +void scd_sts_init::process() +{ + _connector.process(); + + if (!_connector.is_connecting() && !_connector.has_connection()) + { + // unable to connect to master + scd_error("connecting to master failed"); + _fsm.set_state(_st_failed); + } + else if (!_connector.is_connecting() && _connector.has_connection()) + { + // successfully connected to master + scd_info("connected to master"); + _fsm.set_socket(); + _sim.get_poller().register_handler(_fsm, SOCK_EV_READ | SOCK_EV_CLOSE); + _fsm.set_state(_st_busy); + } + +} // process() + + +bool scd_sts_init::active() const { return false; } + + +bool scd_sts_init::advance_time() const +{ + scd_error("illegal call to advance_time()"); + throw scd_exception("illegal call"); +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_init.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_init.h new file mode 100644 index 0000000..3fff4ea --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_init.h @@ -0,0 +1,30 @@ +#ifndef SCD_STS_INIT_H +#define SCD_STS_INIT_H + +#include "fsm/scd_sts_base.h" + + +/* forward declaration */ +class scd_cont_man_slave; + + +class scd_sts_init : public scd_sts_base +{ +public: + scd_sts_init(scd_simulator& sim, scd_cont_man_slave& fsm): + scd_sts_base(sim, fsm) { _name = "init"; } + virtual ~scd_sts_init() {} + + void set_failed(); + + /* scd_cont_fsm_if */ + void set_idle(const sc_core::sc_time& time); + void set_busy(); + void set_done(); + void set_fail(); + void process(); + bool active() const; + bool advance_time() const; +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_term_ack.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_term_ack.cpp new file mode 100644 index 0000000..e3433ff --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_term_ack.cpp @@ -0,0 +1,36 @@ +#include "fsm/scd_sts_term_ack.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_man_slave.h" + + +void scd_sts_term_ack::recv_time_req() +{ + scd_warn("received time request in illegal state"); +} + + +void scd_sts_term_ack::recv_term_req() +{ + scd_warn("received terminate request in illegal state"); +} + + +void scd_sts_term_ack::recv_term_nack() +{ + _fsm.load_state(); +} + + +void scd_sts_term_ack::recv_term() +{ + _sim.get_poller().remove_handler(_fsm); + _fsm.set_state(_st_terminated); +} + + +void scd_sts_term_ack::set_busy() +{ + scd_warn("received channel data while synchronizing to terminate"); +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_term_ack.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_term_ack.h new file mode 100644 index 0000000..2a32250 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_term_ack.h @@ -0,0 +1,28 @@ +#ifndef SCD_STS_TERM_ACK_H +#define SCD_STS_TERM_ACK_H + +#include "fsm/scd_sts_base.h" + + +/* forward declaration */ +class scd_cont_man_slave; + + +class scd_sts_term_ack : public scd_sts_base +{ +public: + scd_sts_term_ack(scd_simulator& sim, scd_cont_man_slave& fsm): + scd_sts_base(sim, fsm) { _name = "term_ack"; } + virtual ~scd_sts_term_ack() {} + + void recv_time_req(); + void recv_term_req(); + void recv_term_nack(); + void recv_term(); + + void set_fail() {} + void set_busy(); + +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_terminated.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_terminated.cpp new file mode 100644 index 0000000..7bd4233 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_terminated.cpp @@ -0,0 +1,19 @@ +#include "fsm/scd_sts_terminated.h" + +#include "scd_logging.h" +#include "scd_exception.h" + + +void scd_sts_terminated::set_busy() +{ + scd_error("received further events while synchronizing (terminate)"); +} + + +void scd_sts_terminated::set_idle(const sc_core::sc_time& time) +{ + scd_error("received future events while synchronizing (terminate)"); +} + + +bool scd_sts_terminated::active() const { return false; } diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_terminated.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_terminated.h new file mode 100644 index 0000000..d05996a --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_terminated.h @@ -0,0 +1,30 @@ +#ifndef SCD_STS_TERMINATED_H +#define SCD_STS_TERMINATED_H + +#include "fsm/scd_sts_base.h" + + +/* forward declaration */ +class scd_cont_man_slave; + + +class scd_sts_terminated : public scd_sts_base +{ +public: + scd_sts_terminated(scd_simulator& sim, scd_cont_man_slave& fsm): + scd_sts_base(sim, fsm) { _name = "terminated"; } + virtual ~scd_sts_terminated() {} + + void set_failed() {} + void recv_time_req() {} + void recv_term_req() {} + + /* scd_cont_fsm_if */ + void set_busy(); + void set_idle(const sc_core::sc_time& time); + void set_fail() {} + bool active() const; + +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_time.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_time.cpp new file mode 100644 index 0000000..09e69e5 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_time.cpp @@ -0,0 +1,21 @@ +#include "fsm/scd_sts_time.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_man_slave.h" + + +void scd_sts_time::set_time_step(const sc_core::sc_time& time) +{ + _time_step = time; +} + + +bool scd_sts_time::advance_time() const { return true; } + + +const sc_core::sc_time& scd_sts_time::get_time_step() +{ + _fsm.set_state(_st_busy); + return _time_step; +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_time.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_time.h new file mode 100644 index 0000000..8467342 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_time.h @@ -0,0 +1,28 @@ +#ifndef SCD_STS_TIME_H +#define SCD_STS_TIME_H + +#include "fsm/scd_sts_base.h" + + +/* forward declaration */ +class scd_cont_man_slave; + + +class scd_sts_time : public scd_sts_base +{ +public: + scd_sts_time(scd_simulator& sim, scd_cont_man_slave& fsm): + scd_sts_base(sim, fsm) { _name = "time"; } + virtual ~scd_sts_time() {} + + void set_time_step(const sc_core::sc_time& time); + + /* scd_cont_fsm_if */ + bool advance_time() const; + const sc_core::sc_time& get_time_step(); + +private: + sc_core::sc_time _time_step; +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_time_ack.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_time_ack.cpp new file mode 100644 index 0000000..53c6827 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_time_ack.cpp @@ -0,0 +1,36 @@ +#include "fsm/scd_sts_time_ack.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_man_slave.h" + + +void scd_sts_time_ack::recv_time_req() +{ + scd_warn("received time request in wrong state"); +} + + +void scd_sts_time_ack::recv_time_nack() +{ + _fsm.load_state(); +} + + +void scd_sts_time_ack::recv_time(const sc_core::sc_time& time) +{ + static_cast(_st_time).set_time_step(time); + _fsm.set_state(_st_time); +} + + +void scd_sts_time_ack::recv_term_req() +{ + scd_warn("received terminate request in wrong state"); +} + + +void scd_sts_time_ack::set_busy() +{ + scd_warn("received channel data while synchronizing to terminate"); +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_time_ack.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_time_ack.h new file mode 100644 index 0000000..ef2c39a --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_sts_time_ack.h @@ -0,0 +1,28 @@ +#ifndef SCD_STS_TIME_ACK_H +#define SCD_STS_TIME_ACK_H + +#include "fsm/scd_sts_base.h" + + +/* forward declaration */ +class scd_cont_man_slave; + + +class scd_sts_time_ack : public scd_sts_base +{ +public: + scd_sts_time_ack(scd_simulator& sim, scd_cont_man_slave& fsm): + scd_sts_base(sim, fsm) { _name = "time_ack"; } + virtual ~scd_sts_time_ack() {} + + /* scd_sts_base */ + void recv_time_req(); + void recv_time_nack(); + void recv_time(const sc_core::sc_time& time); + void recv_term_req(); + + void set_busy(); + +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_base.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_base.cpp new file mode 100644 index 0000000..a4f0c46 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_base.cpp @@ -0,0 +1,125 @@ +#include "fsm/scd_stsw_base.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_slave_wrapper.h" +#include "scd_command.h" + + +scd_stsw_base::scd_stsw_base(scd_simulator& sim, scd_cont_slave_wrapper& fsm): + scd_cont_state(sim), _fsm(fsm), _time_step(fsm._time_step), + _st_init(fsm._st_init), _st_busy(fsm._st_busy), _st_idle(fsm._st_idle), + _st_done(fsm._st_done), _st_time_req(fsm._st_time_req), + _st_time_ack(fsm._st_time_ack), _st_term_req(fsm._st_term_req), + _st_term_ack(fsm._st_term_ack), _st_terminate(fsm._st_terminate), + _st_terminated(fsm._st_terminated), _st_fail(fsm._st_fail), + _st_failed(fsm._st_failed) +{ +} + + +void scd_stsw_base::set_connected() +{ + scd_warn("illegal call to set_connected()"); + throw scd_exception("illegal call"); +} + + +void scd_stsw_base::set_failed() +{ + _sim.get_poller().remove_handler(_fsm); + _fsm.set_state(_st_failed); +} + + +void scd_stsw_base::send_time_req() +{ + scd_warn("illegal call to send_time_req()"); + throw scd_exception("illegal call"); +} + + +void scd_stsw_base::send_time(const sc_core::sc_time& time) +{ + scd_warn("illegal call to send_time()"); + throw scd_exception("illegal call"); +} + +void scd_stsw_base::send_term_req() +{ + scd_warn("illegal call to send_term_req()"); + throw scd_exception("illegal call"); +} + + +void scd_stsw_base::send_term() +{ + scd_warn("illegal call to send_term()"); + throw scd_exception("illegal call"); +} + + +bool scd_stsw_base::time_req() const { return false; } + + +bool scd_stsw_base::time_ack() const { return false; } + + +bool scd_stsw_base::term_req() const { return false; } + + +bool scd_stsw_base::term_ack() const { return false; } + + +bool scd_stsw_base::idle() const { return false; } + + +bool scd_stsw_base::done() const { return false; } + + +void scd_stsw_base::set_busy() +{ + scd_error("illegal call to set_busy()"); + throw scd_exception("illegal call"); +} + + +void scd_stsw_base::set_idle(const sc_core::sc_time& time) +{ + scd_error("illegal call to set_idle()"); + throw scd_exception("illegal call"); +} + + +void scd_stsw_base::set_done() +{ + scd_error("illegal call to set_done()"); + throw scd_exception("illegal call"); +} + + +void scd_stsw_base::set_fail() +{ + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_FAILED); + _fsm.send_command(cmd); + _fsm.set_state(_st_fail); +} + + +bool scd_stsw_base::active() const { return true; } + + +bool scd_stsw_base::busy() const { return false; } + + +bool scd_stsw_base::failed() const { return false; } + + +bool scd_stsw_base::advance_time() const { return false; } + + +const sc_core::sc_time& scd_stsw_base::get_time_step() +{ + scd_error("illegal call to get_time_step()"); + throw scd_exception("illegal call"); +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_base.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_base.h new file mode 100644 index 0000000..8ac5750 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_base.h @@ -0,0 +1,106 @@ +#ifndef SCD_STSW_BASE_H +#define SCD_STSW_BASE_H + +#include "scd_simulator.h" +#include "fsm/scd_cont_state.h" +#include "fsm/scd_cont_wrapper_if.h" + + +/* forward declaration */ +class scd_cont_slave_wrapper; + + +/** + * Base class for all control slave wrapper states. + */ +class scd_stsw_base : public scd_cont_state, public scd_cont_wrapper_if +{ +public: + /** + * Constructor. + * \param sim the simulation environment + * \param fsm the FSM of this state + */ + scd_stsw_base(scd_simulator& sim, scd_cont_slave_wrapper& fsm); + + virtual ~scd_stsw_base() {} + + /** + * Signalizes the state that the slave has been connected to the wrapper. + */ + virtual void set_connected(); + + /** + * Signalizes the state that a failed command has been received + * from the slave. + */ + virtual void set_failed(); + + /** + * Signalizes the state that a time_nack command has been received + * from the slave. + */ + virtual void recv_time_nack() {} + + /** + * Signalizes the state that a time_ack command has been received + * from the slave. + */ + virtual void recv_time_ack() {} + + /** + * Signalizes the state that a term_nack command has been received + * from the slave. + */ + virtual void recv_term_nack() {} + + /** + * Signalizes the state that a term_ack command has been received + * from the slave. + */ + virtual void recv_term_ack() {} + + /* scd_cont_wrapper_if */ + void send_time_req(); + void send_time_nack() {} + void send_time(const sc_core::sc_time& time); + void send_term_req(); + void send_term_nack() {}; + void send_term(); + bool time_req() const; + bool time_ack() const; + bool term_req() const; + bool term_ack() const; + bool idle() const; + bool done() const; + + /* scd_cont_fsm_if */ + void set_busy(); + void set_idle(const sc_core::sc_time& time); + void set_done(); + void set_fail(); + void process() {}; + bool active() const; + bool busy() const; + bool failed() const; + bool advance_time() const; + const sc_core::sc_time& get_time_step(); + +protected: + scd_cont_slave_wrapper& _fsm; + sc_core::sc_time& _time_step; + scd_cont_state& _st_init; + scd_cont_state& _st_busy; + scd_cont_state& _st_idle; + scd_cont_state& _st_done; + scd_cont_state& _st_time_req; + scd_cont_state& _st_time_ack; + scd_cont_state& _st_term_req; + scd_cont_state& _st_term_ack; + scd_cont_state& _st_terminate; + scd_cont_state& _st_terminated; + scd_cont_state& _st_fail; + scd_cont_state& _st_failed; +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_busy.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_busy.cpp new file mode 100644 index 0000000..f96ba77 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_busy.cpp @@ -0,0 +1,22 @@ +#include "fsm/scd_stsw_busy.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_slave_wrapper.h" + + +void scd_stsw_busy::set_idle(const sc_core::sc_time& time) +{ + _time_step = time; + _fsm.set_state(_st_idle); +} + + +void scd_stsw_busy::set_done() +{ + _time_step = sc_core::SC_ZERO_TIME; + _fsm.set_state(_st_done); +} + + +bool scd_stsw_busy::busy() const { return true; } diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_busy.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_busy.h new file mode 100644 index 0000000..1194bdf --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_busy.h @@ -0,0 +1,21 @@ +#ifndef SCD_STSW_BUSY_H +#define SCD_STSW_BUSY_H + +#include "fsm/scd_stsw_base.h" + + +class scd_stsw_busy : public scd_stsw_base +{ +public: + scd_stsw_busy(scd_simulator& sim, scd_cont_slave_wrapper& fsm): + scd_stsw_base(sim, fsm) { _name = "busy"; } + virtual ~scd_stsw_busy() {} + + /* scd_cont_fsm_if */ + void set_idle(const sc_core::sc_time& time); + void set_done(); + bool busy() const; + +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_done.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_done.cpp new file mode 100644 index 0000000..329b81b --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_done.cpp @@ -0,0 +1,39 @@ +#include "fsm/scd_stsw_done.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_slave_wrapper.h" + + +void scd_stsw_done::send_time_req() +{ + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_TIME_REQ); + _fsm.send_command(cmd); + _fsm.save_state(); + _fsm.set_state(_st_time_req); +} + + +void scd_stsw_done::send_term_req() +{ + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_TERM_REQ); + _fsm.send_command(cmd); + _fsm.save_state(); + _fsm.set_state(_st_term_req); +} + + +bool scd_stsw_done::done() const { return true; } + + +void scd_stsw_done::set_busy() +{ + _fsm.set_state(_st_busy); +} + + +void scd_stsw_done::set_idle(const sc_core::sc_time& time) +{ + _time_step = time; + _fsm.set_state(_st_idle); +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_done.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_done.h new file mode 100644 index 0000000..148d973 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_done.h @@ -0,0 +1,28 @@ +#ifndef SCD_STSW_DONE_H +#define SCD_STSW_DONE_H + +#include "fsm/scd_stsw_base.h" + + +/* forward declaration */ +class scd_cont_slave_wrapper; + + +class scd_stsw_done : public scd_stsw_base +{ +public: + scd_stsw_done(scd_simulator& sim, scd_cont_slave_wrapper& fsm): + scd_stsw_base(sim, fsm) { _name = "done"; } + virtual ~scd_stsw_done() {} + + /* scd_cont_wrapper_if */ + void send_time_req(); + void send_term_req(); + bool done() const; + + /* scd_cont_fsm_if */ + void set_busy(); + void set_idle(const sc_core::sc_time& time); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_fail.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_fail.cpp new file mode 100644 index 0000000..51348d3 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_fail.cpp @@ -0,0 +1,18 @@ +#include "fsm/scd_stsw_fail.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_slave_wrapper.h" + + +void scd_stsw_fail::set_fail() {} + + +void scd_stsw_fail::process() +{ + if (!_fsm.is_sending()) + { + _sim.get_poller().remove_handler(_fsm); + _fsm.set_state(_st_failed); + } +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_fail.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_fail.h new file mode 100644 index 0000000..cb8fe22 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_fail.h @@ -0,0 +1,23 @@ +#ifndef SCD_STSW_FAIL_H +#define SCD_STSW_FAIL_H + +#include "fsm/scd_stsw_base.h" + + +/* forward declaration */ +class scd_cont_slave_wrapper; + + +class scd_stsw_fail : public scd_stsw_base +{ +public: + scd_stsw_fail(scd_simulator& sim, scd_cont_slave_wrapper& fsm): + scd_stsw_base(sim, fsm) { _name = "fail"; } + virtual ~scd_stsw_fail() {} + + /* scd_cont_fsm_if */ + void set_fail(); + void process(); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_failed.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_failed.cpp new file mode 100644 index 0000000..ab2db2e --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_failed.cpp @@ -0,0 +1,16 @@ +#include "fsm/scd_stsw_failed.h" + +#include "scd_logging.h" +#include "scd_exception.h" + + +void scd_stsw_failed::set_failed() {} + + +void scd_stsw_failed::set_fail() {} + + +bool scd_stsw_failed::active() const { return false; } + + +bool scd_stsw_failed::failed() const { return true; } diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_failed.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_failed.h new file mode 100644 index 0000000..cf13d9d --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_failed.h @@ -0,0 +1,26 @@ +#ifndef SCD_STSW_FAILED_H +#define SCD_STSW_FAILED_H + +#include "fsm/scd_stsw_base.h" + + +/* forward declaration */ +class scd_cont_slave_wrapper; + + +class scd_stsw_failed : public scd_stsw_base +{ +public: + scd_stsw_failed(scd_simulator& sim, scd_cont_slave_wrapper& fsm): + scd_stsw_base(sim, fsm) { _name = "failed"; } + virtual ~scd_stsw_failed() {} + + void set_failed(); + + /* scd_cont_fsm_if */ + void set_fail(); + bool active() const; + bool failed() const; +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_idle.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_idle.cpp new file mode 100644 index 0000000..6883648 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_idle.cpp @@ -0,0 +1,29 @@ +#include "fsm/scd_stsw_idle.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_slave_wrapper.h" + + +void scd_stsw_idle::send_time_req() +{ + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_TIME_REQ); + _fsm.send_command(cmd); + _fsm.save_state(); + _fsm.set_state(_st_time_req); +} + + +bool scd_stsw_idle::idle() const { return true; } + + +void scd_stsw_idle::set_busy() +{ + _fsm.set_state(_st_busy); +} + + +void scd_stsw_idle::set_done() +{ + scd_warn("slave " + _fsm.get_name() + " transition attempt from idle to done"); +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_idle.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_idle.h new file mode 100644 index 0000000..4af1c6d --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_idle.h @@ -0,0 +1,28 @@ +#ifndef SCD_STSW_IDLE_H +#define SCD_STSW_IDLE_H + +#include "fsm/scd_stsw_base.h" + + +/* forward declaration */ +class scd_cont_slave_wrapper; + + +class scd_stsw_idle : public scd_stsw_base +{ +public: + scd_stsw_idle(scd_simulator& sim, scd_cont_slave_wrapper& fsm): + scd_stsw_base(sim, fsm) { _name = "idle"; } + virtual ~scd_stsw_idle() {} + + /* scd_cont_wrapper_if */ + void send_time_req(); + bool idle() const; + + /* scd_cont_fsm_if */ + void set_busy(); + void set_done(); + +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_init.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_init.cpp new file mode 100644 index 0000000..d4f27bd --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_init.cpp @@ -0,0 +1,58 @@ +#include "fsm/scd_stsw_init.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_slave_wrapper.h" + + +void scd_stsw_init::set_connected() +{ + _sim.get_poller().register_handler(_fsm, SOCK_EV_READ | SOCK_EV_CLOSE); + _fsm.set_state(_st_busy); +} + + +void scd_stsw_init::set_failed() +{ + _fsm.set_state(_st_failed); +} + + +void scd_stsw_init::set_idle(const sc_core::sc_time& time) +{ + scd_error("init: illegal call to set_idle()"); + throw scd_exception("illegal call"); +} + + +void scd_stsw_init::set_busy() +{ + scd_error("init: illegal call to set_idle()"); + throw scd_exception("illegal call"); +} + + +void scd_stsw_init::set_done() +{ + scd_error("init: illegal call to set_done()"); + throw scd_exception("illegal call"); +} + + +void scd_stsw_init::set_fail() +{ + _fsm.set_state(_st_failed); +} + + +void scd_stsw_init::process() {} + + +bool scd_stsw_init::active() const { return false; } + + +bool scd_stsw_init::advance_time() const +{ + scd_error("illegal call to advance_time()"); + throw scd_exception("illegal call"); +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_init.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_init.h new file mode 100644 index 0000000..aa4d8a3 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_init.h @@ -0,0 +1,31 @@ +#ifndef SCD_STSW_INIT_H +#define SCD_STSW_INIT_H + +#include "fsm/scd_stsw_base.h" + + +/* forward declaration */ +class scd_cont_slave_wrapper; + + +class scd_stsw_init : public scd_stsw_base +{ +public: + scd_stsw_init(scd_simulator& sim, scd_cont_slave_wrapper& fsm): + scd_stsw_base(sim, fsm) { _name = "init"; } + virtual ~scd_stsw_init() {} + + void set_connected(); + void set_failed(); + + /* scd_cont_fsm_if */ + void set_idle(const sc_core::sc_time& time); + void set_busy(); + void set_done(); + void set_fail(); + void process(); + bool active() const; + bool advance_time() const; +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_term_ack.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_term_ack.cpp new file mode 100644 index 0000000..5fc0a51 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_term_ack.cpp @@ -0,0 +1,36 @@ +#include "fsm/scd_stsw_term_ack.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_slave_wrapper.h" + + +void scd_stsw_term_ack::recv_term_nack() +{ + scd_warn("received term_nack message in wrong state"); +} + + +void scd_stsw_term_ack::recv_term_ack() +{ + scd_warn("received term_nack message in wrong state"); +} + + +void scd_stsw_term_ack::send_term_nack() +{ + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_TERM_NACK); + _fsm.send_command(cmd); + _fsm.load_state(); +} + + +void scd_stsw_term_ack::send_term() +{ + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_TERM); + _fsm.send_command(cmd); + _fsm.set_state(_st_terminate); +} + + +bool scd_stsw_term_ack::term_ack() const { return true; } diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_term_ack.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_term_ack.h new file mode 100644 index 0000000..19ae78d --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_term_ack.h @@ -0,0 +1,28 @@ +#ifndef SCD_STSW_TERM_ACK_H +#define SCD_STSW_TERM_ACK_H + +#include "fsm/scd_stsw_base.h" + + +/* forward declaration */ +class scd_cont_slave_wrapper; + + +class scd_stsw_term_ack : public scd_stsw_base +{ +public: + scd_stsw_term_ack(scd_simulator& sim, scd_cont_slave_wrapper& fsm): + scd_stsw_base(sim, fsm) { _name = "term_ack"; } + virtual ~scd_stsw_term_ack() {} + + /* scd_stsw_base */ + void recv_term_nack(); + void recv_term_ack(); + + /* scd_cont_wrapper_if */ + void send_term_nack(); + void send_term(); + bool term_ack() const; +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_term_req.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_term_req.cpp new file mode 100644 index 0000000..3bd39dc --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_term_req.cpp @@ -0,0 +1,48 @@ +#include "fsm/scd_stsw_term_req.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_slave_wrapper.h" + + +void scd_stsw_term_req::recv_term_nack() +{ + _fsm.load_state(); +} + + +void scd_stsw_term_req::recv_term_ack() +{ + _fsm.set_state(_st_term_ack); +} + + +void scd_stsw_term_req::send_term_nack() +{ + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_TERM_NACK); + _fsm.send_command(cmd); + _fsm.load_state(); +} + + +bool scd_stsw_term_req::term_req() const { return true; } + + +void scd_stsw_term_req::set_busy() +{ + _time_step = sc_core::SC_ZERO_TIME; + _fsm.save_state(_st_busy); +} + + +void scd_stsw_term_req::set_idle(const sc_core::sc_time& time) +{ + _time_step = time; + _fsm.save_state(_st_idle); +} + + +void scd_stsw_term_req::set_done() +{ + _fsm.save_state(_st_done); +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_term_req.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_term_req.h new file mode 100644 index 0000000..1c39d7f --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_term_req.h @@ -0,0 +1,32 @@ +#ifndef SCD_STSW_TERM_REQ_H +#define SCD_STSW_TERM_REQ_H + +#include "fsm/scd_stsw_base.h" + + +/* forward declaration */ +class scd_cont_slave_wrapper; + + +class scd_stsw_term_req : public scd_stsw_base +{ +public: + scd_stsw_term_req(scd_simulator& sim, scd_cont_slave_wrapper& fsm): + scd_stsw_base(sim, fsm) { _name = "term_req"; } + virtual ~scd_stsw_term_req() {} + + /* sdc_stsw_base */ + void recv_term_nack(); + void recv_term_ack(); + + /* scd_cont_wrapper_if */ + void send_term_nack(); + bool term_req() const; + + /* scd_cont_fsm_if */ + void set_busy(); + void set_idle(const sc_core::sc_time& time); + void set_done(); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_terminate.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_terminate.cpp new file mode 100644 index 0000000..98fa64f --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_terminate.cpp @@ -0,0 +1,18 @@ +#include "fsm/scd_stsw_terminate.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_slave_wrapper.h" + + +void scd_stsw_terminate::set_fail() {} + + +void scd_stsw_terminate::process() +{ + if (!_fsm.is_sending()) + { + _sim.get_poller().remove_handler(_fsm); + _fsm.set_state(_st_terminated); + } +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_terminate.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_terminate.h new file mode 100644 index 0000000..3671316 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_terminate.h @@ -0,0 +1,23 @@ +#ifndef SCD_STSW_TERMINATE_H +#define SCD_STSW_TERMINATE_H + +#include "fsm/scd_stsw_base.h" + + +/* forward declaration */ +class scd_cont_slave_wrapper; + + +class scd_stsw_terminate : public scd_stsw_base +{ +public: + scd_stsw_terminate(scd_simulator& sim, scd_cont_slave_wrapper& fsm): + scd_stsw_base(sim, fsm) { _name = "terminate"; } + virtual ~scd_stsw_terminate() {} + + /* scd_cont_fsm_if */ + void set_fail(); + void process(); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_terminated.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_terminated.cpp new file mode 100644 index 0000000..8a9a045 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_terminated.cpp @@ -0,0 +1,13 @@ +#include "fsm/scd_stsw_terminated.h" + +#include "scd_logging.h" +#include "scd_exception.h" + + +void scd_stsw_terminated::set_failed() {} + + +void scd_stsw_terminated::set_fail() {} + + +bool scd_stsw_terminated::active() const { return false; } diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_terminated.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_terminated.h new file mode 100644 index 0000000..b0d22b1 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_terminated.h @@ -0,0 +1,25 @@ +#ifndef SCD_STSW_TERMINATED_H +#define SCD_STSW_TERMINATED_H + +#include "fsm/scd_stsw_base.h" + + +/* forward declaration */ +class scd_cont_slave_wrapper; + + +class scd_stsw_terminated : public scd_stsw_base +{ +public: + scd_stsw_terminated(scd_simulator& sim, scd_cont_slave_wrapper& fsm): + scd_stsw_base(sim, fsm) { _name = "terminated"; } + virtual ~scd_stsw_terminated() {} + + void set_failed(); + + /* scd_cont_fsm_if */ + void set_fail(); + bool active() const; +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_time_ack.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_time_ack.cpp new file mode 100644 index 0000000..53d0a4c --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_time_ack.cpp @@ -0,0 +1,42 @@ +#include "fsm/scd_stsw_time_ack.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_slave_wrapper.h" + + +void scd_stsw_time_ack::recv_time_nack() +{ + scd_warn("received time_nack message in wrong state"); +} + + +void scd_stsw_time_ack::recv_time_ack() +{ + scd_warn("received time_nack message in wrong state"); +} + + +void scd_stsw_time_ack::send_time_nack() +{ + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_TIME_NACK); + _fsm.send_command(cmd); + _fsm.load_state(); +} + + +void scd_stsw_time_ack::send_time(const sc_core::sc_time& time) +{ + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_TIME, time); + _fsm.send_command(cmd); + _fsm.set_state(_st_busy); +} + + +bool scd_stsw_time_ack::time_ack() const { return true; } + + +const sc_core::sc_time& scd_stsw_time_ack::get_time_step() +{ + return _time_step; +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_time_ack.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_time_ack.h new file mode 100644 index 0000000..a71ca7e --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_time_ack.h @@ -0,0 +1,29 @@ +#ifndef SCD_STSW_TIME_ACK_H +#define SCD_STSW_TIME_ACK_H + +#include "fsm/scd_stsw_base.h" + + +/* forward declaration */ +class scd_cont_slave_wrapper; + + +class scd_stsw_time_ack : public scd_stsw_base +{ +public: + scd_stsw_time_ack(scd_simulator& sim, scd_cont_slave_wrapper& fsm): + scd_stsw_base(sim, fsm) { _name = "time_ack"; } + virtual ~scd_stsw_time_ack() {} + + /* scd_stsw_base */ + void recv_time_nack(); + void recv_time_ack(); + + /* scd_cont_wrapper_if */ + void send_time_nack(); + void send_time(const sc_core::sc_time& time); + bool time_ack() const; + const sc_core::sc_time& get_time_step(); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_time_req.cpp b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_time_req.cpp new file mode 100644 index 0000000..0336c06 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_time_req.cpp @@ -0,0 +1,48 @@ +#include "fsm/scd_stsw_time_req.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_cont_slave_wrapper.h" + + +void scd_stsw_time_req::recv_time_nack() +{ + _fsm.load_state(); +} + + +void scd_stsw_time_req::recv_time_ack() +{ + _fsm.set_state(_st_time_ack); +} + + +void scd_stsw_time_req::send_time_nack() +{ + scd_command* cmd = new scd_command(SCD_CM_CONTROL, SCD_CM_TIME_NACK); + _fsm.send_command(cmd); + _fsm.load_state(); +} + + +bool scd_stsw_time_req::time_req() const { return true; } + + +void scd_stsw_time_req::set_busy() +{ + _fsm.save_state(_st_busy); +} + + +void scd_stsw_time_req::set_idle(const sc_core::sc_time& time) +{ + _time_step = time; + _fsm.save_state(_st_idle); +} + + +void scd_stsw_time_req::set_done() +{ + _time_step = sc_core::SC_ZERO_TIME; + _fsm.save_state(_st_done); +} diff --git a/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_time_req.h b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_time_req.h new file mode 100644 index 0000000..2f45f84 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/fsm/scd_stsw_time_req.h @@ -0,0 +1,33 @@ +#ifndef SCD_STSW_TIME_REQ_H +#define SCD_STSW_TIME_REQ_H + +#include "fsm/scd_stsw_base.h" + + +/* forward declaration */ +class scd_cont_slave_wrapper; + + +class scd_stsw_time_req : public scd_stsw_base +{ +public: + scd_stsw_time_req(scd_simulator& sim, scd_cont_slave_wrapper& fsm): + scd_stsw_base(sim, fsm) { _name = "time_req"; } + virtual ~scd_stsw_time_req() {} + + /* sdc_stsw_base */ + void recv_time_nack(); + void recv_time_ack(); + + /* scd_cont_wrapper_if */ + void send_time_nack(); + bool time_req() const; + + /* scd_cont_fsm_if */ + void set_busy(); + void set_idle(const sc_core::sc_time& time); + void set_done(); + +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/scd_chan_man.cpp b/dol/src/dol/visitor/hdsd/scd/scd_chan_man.cpp new file mode 100644 index 0000000..d98e8ea --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_chan_man.cpp @@ -0,0 +1,216 @@ +#include "scd_chan_man.h" + +#include "scd_logging.h" + + +scd_chan_man::scd_chan_man(scd_simulator &sim): + _sim(sim), _is_ready(false) {} + + +scd_chan_man::~scd_chan_man() +{ + std::list::iterator coit; + std::list::iterator chit; + + for (coit = _connectors.begin(); coit != _connectors.end(); coit++) + delete *coit; + + for (chit = _channels.begin(); chit != _channels.end(); chit++) + delete *chit; +} + + +void scd_chan_man::register_channel(const std::string &name, sc_prim_channel& mchan) +{ + if ( _get_channel(name) != NULL ) + { + scd_warn("channel \"" + name + "\" already registered, ignoring..."); + } + else + { + scd_chan_wrapper* wrap = new scd_chan_wrapper(_sim, name, mchan); + _channels.push_back(wrap); + } + +} // register_channel() - master + + +void scd_chan_man::register_channel(const std::string &name, + sc_prim_channel& schan, const std::string &host, const uint16_t port) +{ + if ( _get_channel(name) != NULL ) + { + scd_warn("channel \"" + name + "\" already registered, ignoring..."); + } + else + { + // register channel + scd_chan_wrapper* wrap = new scd_chan_wrapper(_sim, name, schan); + _channels.push_back(wrap); + + // create connector + scd_out_connector* conn = new scd_out_connector(_sim, SCD_CM_CHANNEL, + name); + conn->connect_to(host, port); + _connectors.push_back(conn); + } + +} // register_channel() - slave + + +void scd_chan_man::init_process() +{ + if (_is_ready) + return; + + std::list::iterator coit; + + // check all connectors + for (coit = _connectors.begin(); coit != _connectors.end();) + { + scd_out_connector& conn = **coit; + + // retry to connect if necessary + conn.process(); + + if (!conn.is_connecting() && !conn.has_connection()) + { + // an error occured + scd_error("failed to connect channel \"" + + conn.get_name() + "\""); + + delete *coit; + coit = _connectors.erase(coit); + + _sim.get_cont_man().set_fail(); + return; + } + else if (!conn.is_connecting() && conn.has_connection()) + { + // channel is connected + scd_chan_wrapper& chan = *_get_channel(conn.get_name()); + + if (chan.is_initialized()) + { + scd_error("channel \"" + + conn.get_name() + "\" already connected"); + + delete *coit; + coit = _connectors.erase(coit); + + _sim.get_cont_man().set_fail(); + return; + } + else + { + scd_info("connected channel \"" + conn.get_name() + "\""); + chan.connect(conn.get_connection()); + + delete *coit; + coit = _connectors.erase(coit); + } + } // end channel connected + else + { + // still trying to connect + coit++; + } + // end this connector + } // end check all connectors + + // check if everything is initiated + _check_ready(); + +} // init_process() + + +void scd_chan_man::connect_channel(const scd_command &c, scd_socket* sock) +{ + std::string name = c.get_string(); + + scd_chan_wrapper* chan = _get_channel(name); + + if (chan == NULL) + { + scd_warn("unknown channel \"" + name + "\" supplied by peer"); + delete sock; + } + else if (chan->is_initialized()) + { + scd_warn("channel \"" + name + "\" supplied by peer already connected"); + } + else + { + scd_info("connected channel \"" + name + "\""); + chan->connect(sock); + } + +} // connect() + + +bool scd_chan_man::ready() const { return _is_ready; } + + +void scd_chan_man::process() +{ + std::list::iterator chit; + + for (chit = _channels.begin(); chit != _channels.end(); chit++) + (*chit)->process(); + +} // process() + + +void scd_chan_man::close() +{ + std::list::iterator coit; + std::list::iterator chit; + + for (coit = _connectors.begin(); coit != _connectors.end(); coit++) + (*coit)->close(); + + for (chit = _channels.begin(); chit != _channels.end(); chit++) + (*chit)->close(); + +} // close() + + +bool scd_chan_man::_check_ready() +{ + if (_is_ready) + return true; + + if (_connectors.empty()) + { + std::list::iterator chit; + + // check all channels + for (chit = _channels.begin(); chit != _channels.end(); chit++) + { + if ( !(*chit)->is_initialized() ) + return false; + } + + // all channels initiated + _is_ready = true; + return true; + } + else + return false; + +} // _check_ready() + + +scd_chan_wrapper* scd_chan_man::_get_channel(const std::string& name) +{ + std::list::iterator chit; + + for (chit = _channels.begin(); chit != _channels.end(); chit++) + { + if ( (*chit)->get_name() == name ) + return *chit; + } + + return NULL; + +} // _get_channel() diff --git a/dol/src/dol/visitor/hdsd/scd/scd_chan_man.h b/dol/src/dol/visitor/hdsd/scd/scd_chan_man.h new file mode 100644 index 0000000..0b026cc --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_chan_man.h @@ -0,0 +1,117 @@ +#ifndef SCD_CHAN_MAN_H +#define SCD_CHAN_MAN_H + +#include +#include + +#include +using sc_core::sc_prim_channel; + +#include "scd_simulator.h" +#include "scd_command.h" +#include "scd_chan_wrapper.h" +#include "scd_out_connector.h" + + +/* forward declaration */ +class scd_out_connector; +class scd_chan_wrapper; + + +/** + * The channel manager holds all remote channels. The channels have + * to be registered before the simulator is initiated. The channel + * manager will then initiate connections to other simulators + * and will handle channels from incomming connections. + * During simulation data is sent from the channel output buffers + * to remote hosts and data is received and stored in the input buffers. + * The channel implementation will then generate events to resume + * simulation processes. + */ +class scd_chan_man +{ +public: + /** + * Constructor. + * \param sim the simulator + */ + scd_chan_man(scd_simulator &sim); + + virtual ~scd_chan_man(); + + /** + * Registers a remote channel with master endpoint on this host. + * Another host will initiate the connection and the channel will + * be connected by an in-connector calling connect_channel(). + * \param name the name of the remote channel + * \param mchan the SystemC channel implementing the + * remote-in and/or the remote-out interface. + */ + void register_channel(const std::string &name, sc_prim_channel& mchan); + + /** + * Registers a remote channel with slave endpoint on this host. + * This host will initiate the connection to the host with the + * master endpoint. To drive this process init_process() has to + * be called periodically. + * \param name the name of the remote channel + * \param mchan the SystemC channel implementing the + * remote-in and/or the remote-out interface. + * \param host the FQDN or IP address of the remote simulator + * with the master endpoint of the channel + * \param port TCP port of the remote simulator + */ + void register_channel(const std::string &name, sc_prim_channel& schan, + const std::string &host, const uint16_t port); + /** + * Drives the initialization process. Restarts outgoing connection + * attempts to connect channels to other simulators if previous + * attempts have timed out. ready() indicates the end of the + * initialization. + */ + void init_process(); + + /** + * Connects a channel from an incomming connection. Is intended to be + * called from an in-connector. + * \param c the register command received by the in-connector (contains + * the channel name) + * \param sock the socket of the incoming connection that is used + * as the data channel + */ + void connect_channel(const scd_command &c, scd_socket* sock); + + /** + * Indicates if all clients have been connected. + * \return true if the channel manager completed initialization + */ + bool ready() const; + + /** + * Checks if channels have data in the output buffers and activates + * the transmission if necessary. Receiption is resumed if the input + * buffer can accept data again. Call this function after each + * simulation step (which might fill data into the buffers that has + * to be sent). + */ + void process(); + + /** + * Closes all channels. + */ + void close(); + +private: + /* member variables */ + scd_simulator& _sim; + std::list _channels; + std::list _connectors; + + bool _is_ready; + + /* member functions */ + bool _check_ready(); + scd_chan_wrapper* _get_channel(const std::string& name); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/scd_chan_wrapper.cpp b/dol/src/dol/visitor/hdsd/scd/scd_chan_wrapper.cpp new file mode 100644 index 0000000..2629240 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_chan_wrapper.cpp @@ -0,0 +1,201 @@ +#include "scd_chan_wrapper.h" + +#include +#include + +#include "scd_logging.h" + + +scd_chan_wrapper::scd_chan_wrapper(scd_simulator& sim, const std::string& name, + sc_prim_channel& chan): + _sim(sim), _name(name), _is_initialized(false), + _is_writing(false), _is_reading(false) +{ + try + { + _chan_in = &dynamic_cast(chan); + } catch (std::bad_cast e) + { + _chan_in = NULL; + } + + try + { + _chan_out = &dynamic_cast(chan); + } catch (std::bad_cast e) + { + _chan_out = NULL; + } + + if (_chan_in == NULL && _chan_out == NULL) + scd_warn("channel \"" + _name + "\" is not a remote channel"); +} + + +scd_chan_wrapper::~scd_chan_wrapper() +{ + if ( _is_initialized ) + { + _sim.get_poller().remove_handler(*this); + _socket->close(); + delete _socket; + } +} + + +bool scd_chan_wrapper::is_initialized() const { return _is_initialized; } + + +const std::string& scd_chan_wrapper::get_name() const { return _name; } + + +void scd_chan_wrapper::connect(scd_socket* sock) +{ + assert(!_is_initialized); + + _socket = sock; + _is_initialized = true; + + sock_ev flags = SOCK_EV_CLOSE; + if (_chan_in != NULL) + { + flags |= SOCK_EV_READ; + _is_reading = true; + } + _sim.get_poller().register_handler(*this, flags); + +} // connect() + + +void scd_chan_wrapper::process() +{ + // check if channel has data to send + if (_chan_out != NULL && _is_initialized ) + { + if (!_is_writing && _socket->is_valid() && _chan_out->available() > 0 ) + { + // register write event + sock_ev events; + _sim.get_poller().get_ev(*this, events); + events |= SOCK_EV_WRITE; + _sim.get_poller().set_ev( *this, events ); + _is_writing = true; + } + } + + // check if channel has data to read + if (_chan_in != NULL && _is_initialized ) + { + if (!_is_reading && _socket->is_valid() && _chan_in->free() > 0 ) + { + // register read event + sock_ev events; + _sim.get_poller().get_ev(*this, events); + events |= SOCK_EV_READ; + _sim.get_poller().set_ev( *this, events ); + _is_reading = true; + } + } + +} // process() + + +void scd_chan_wrapper::close() +{ + if (_is_initialized) + _socket->close(); + +} // close() + + +void scd_chan_wrapper::handle_sock_ev(sock_ev events) +{ + if (events & SOCK_EV_CLOSE) + { + scd_debug("channel \"" + _name + "\" closed connection"); + _sim.get_poller().set_ev(*this, 0); + _sim.get_cont_man().set_fail(); + close(); + return; + } // end close event + + if (events & SOCK_EV_READ) + { + _read_event(); + } + + if (events & SOCK_EV_WRITE) + { + _write_event(); + } + +} // handle_sock_ev() + + +const scd_socket& scd_chan_wrapper::get_sock() { return *_socket; } + + +void scd_chan_wrapper::_read_event() +{ + size_t free = _chan_in->free(); + + /* receive portions as long as they can be received */ + size_t recv = 0xFF; //dummy + while ( free != 0 && recv != 0) + { + free = ( free < SCD_CHAN_BUFLEN ) ? free : SCD_CHAN_BUFLEN ; + recv = _socket->recv(_buf, free); + if (recv != 0) + _chan_in->receive(_buf, recv); + free = _chan_in->free(); + } + + if (free == 0) + { + sock_ev events; + _sim.get_poller().get_ev(*this, events); + events &= ~SOCK_EV_READ; + _sim.get_poller().set_ev(*this, events ); + _is_reading = false; + return; + } + + if (!_socket->is_valid()) + { + scd_debug("channel \"" + _name + "\" closed connection"); + _sim.get_poller().set_ev(*this, 0); + _sim.get_cont_man().set_fail(); + return; + } + +} // end _read_event() + + +void scd_chan_wrapper::_write_event() +{ + /* send portions as long as they can be sent */ + size_t sent = 0xFF; //dummy + while ( sent ) + { + sent = _socket->send( _chan_out->send(), _chan_out->available() ); + if (sent != 0) + _chan_out->remove(sent); + } + + if (_chan_out->available() == 0) + { + sock_ev events; + _sim.get_poller().get_ev(*this, events); + events &= ~SOCK_EV_WRITE; + _sim.get_poller().set_ev(*this, events ); + _is_writing = false; + return; + } + + if (!_socket->is_valid()) + { + scd_debug("channel \"" + _name + "\" closed connection"); + _sim.get_poller().set_ev(*this, 0); + _sim.get_cont_man().set_fail(); + } +} diff --git a/dol/src/dol/visitor/hdsd/scd/scd_chan_wrapper.h b/dol/src/dol/visitor/hdsd/scd/scd_chan_wrapper.h new file mode 100644 index 0000000..44115b0 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_chan_wrapper.h @@ -0,0 +1,95 @@ +#ifndef SCD_CHAN_WRAPPER_H +#define SCD_CHAN_WRAPPER_H + +#include + +#include +using sc_core::sc_prim_channel; + +#include "scd_sock_poller.h" +#include "scd_socket.h" +#include "scd_simulator.h" +#include "scd_rem_chan_if.h" + + +/** + * Size of the input buffer. Limits the ammount of data that + * can be read from the socket in one system call. + */ +static const size_t SCD_CHAN_BUFLEN = 512; + +/* forward declaration */ +class scd_simulator; + + +/** + * Wrapper for a remote channel. Writes data from the output buffer + * of the channel to the socket. Receives data from the socket and + * writes it to the input buffer of the channel. + */ +class scd_chan_wrapper : public scd_sock_ev_handler_if +{ +public: + /** + * Constructor. + * \param sim the simulation environment + * \param name the name of the channel + * \param chan the SystemC channel implementing + * remote channel interface(s) + */ + scd_chan_wrapper(scd_simulator& sim, const std::string& name, + sc_prim_channel& chan); + + virtual ~scd_chan_wrapper(); + + /** + * Indicates if a socket has been set for this channel. + * \return true if a socket has been set + */ + bool is_initialized() const; + + /** + * Returns the name of the channel. + */ + const std::string& get_name() const; + + /** + * Sets the socket of the channel. + */ + void connect(scd_socket* sock); + + /** + * Checks if data has to be send or can be received again and activates + * transmission if necessary. Call this function after every simulation + * step. + */ + void process(); + + /** + * Closes the connection to the peer. + */ + void close(); + + + /* scd_sock_ev_handler_if */ + void handle_sock_ev(sock_ev events); + const scd_socket &get_sock(); + +private: + scd_simulator& _sim; + std::string _name; + bool _is_initialized; + + scd_socket* _socket; + scd_rem_chan_in_if* _chan_in; + scd_rem_chan_out_if* _chan_out; + char _buf[SCD_CHAN_BUFLEN]; + bool _is_writing; + bool _is_reading; + + /* member functions */ + void _write_event(); + void _read_event(); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/scd_command.cpp b/dol/src/dol/visitor/hdsd/scd/scd_command.cpp new file mode 100644 index 0000000..008171d --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_command.cpp @@ -0,0 +1,105 @@ +#include "scd_command.h" + +#include "cstring" +#include "arpa/inet.h" + + +scd_command::scd_command(): _type(0), _subtype(0), _msglen(0) +{ + _msg = NULL; +} + + +scd_command::scd_command(uint16_t type, uint16_t subtype): + _type(type), _subtype(subtype), _msglen(0) +{ + _msg = NULL; +} + + +scd_command::scd_command(uint16_t type, uint16_t subtype, + const std::string& msg): + _type(type), _subtype(subtype) +{ + if (msg.length() > 0) + { + _msglen = msg.length()+1; + _msg = new char[_msglen]; + strncpy(_msg, msg.c_str(), _msglen); + _msg[_msglen-1] = 0; + } + else + { + _msglen = 0; + _msg = NULL; + } +} + + +scd_command::scd_command(uint16_t type, uint16_t subtype, + const sc_core::sc_time& time) : _type(type), _subtype(subtype) +{ + uint64_t value; + uint32_t hi, lo; + + _msglen = 8; + _msg = new char[_msglen]; + + // obtain high and low words + value = time.value(); + lo = value & 0xFFFFFFFF; + value >>= 32; + hi = value & 0xFFFFFFFF; + + // do network conversion + hi = htonl(hi); + lo = htonl(lo); + + // store to buffer + memcpy(_msg, &hi, 4); + memcpy(_msg + 4, &lo, 4); +} + + + +scd_command::~scd_command() +{ + if (_msg != NULL) + delete _msg; +} + + +uint16_t scd_command::get_type() const { return _type; } + + +uint16_t scd_command::get_subtype() const { return _subtype; } + + +std::string scd_command::get_string() const +{ + if (_msglen <= 1) + return std::string(); + else + return std::string(_msg, _msglen-1); +} + + +sc_core::sc_time scd_command::get_time() const +{ + if (_msglen != 8) + return sc_core::SC_ZERO_TIME; + + uint64_t value; + uint32_t hi, lo; + + // get value from buffer + memcpy(&hi, _msg, 4); + memcpy(&lo, _msg+4, 4); + + // do network conversion + value = ntohl(hi); + value <<= 32; + value |= ntohl(lo); + + return sc_core::sc_time(value, false); +} diff --git a/dol/src/dol/visitor/hdsd/scd/scd_command.h b/dol/src/dol/visitor/hdsd/scd/scd_command.h new file mode 100644 index 0000000..cbb3bed --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_command.h @@ -0,0 +1,108 @@ +#ifndef SCD_COMMAND_H +#define SCD_COMMAND_H + +#include +#include +#include + +#include "systemc" + + +const size_t SCD_CM_MAXLEN = 512; +const size_t SCD_CM_HEADER = 3*2; + +/* command types */ +const uint16_t SCD_CM_REGISTER = 1; +const uint16_t SCD_CM_CONFIG = 2; +const uint16_t SCD_CM_CONTROL = 3; + +/* command subtypes */ +// register +const uint16_t SCD_CM_NETSIM = 1; +const uint16_t SCD_CM_CHANNEL = 2; +// control +const uint16_t SCD_CM_BUSY = 1; +const uint16_t SCD_CM_IDLE = 2; +const uint16_t SCD_CM_DONE = 3; +const uint16_t SCD_CM_FAILED = 4; +const uint16_t SCD_CM_TIME_REQ = 5; +const uint16_t SCD_CM_TIME_ACK = 6; +const uint16_t SCD_CM_TIME_NACK = 7; +const uint16_t SCD_CM_TIME = 8; +const uint16_t SCD_CM_TERM_REQ = 9; +const uint16_t SCD_CM_TERM_ACK = 10; +const uint16_t SCD_CM_TERM_NACK = 11; +const uint16_t SCD_CM_TERM = 12; + +/* forward declarations */ +class scd_command_reader; +class scd_command_writer; + + +/** + * Command class. Commands are control messages that are sent between + * the different simulators. A command has a type, a subtype and a potential + * message part. + */ +class scd_command +{ +friend class scd_command_reader; +friend class scd_command_writer; + +public: + /** + * Default constructor. Creates an empty command. + */ + scd_command(); + + /* + * Constructor. Creates a command with no message part. + * \param type the type of this command + * \param subtype the subtype of this command + */ + scd_command(uint16_t type, uint16_t subtype); + + /** + * Constructor. Creates a new command with a string as message + * part. + */ + scd_command(uint16_t type, uint16_t subtype, const std::string& msg); + + /** + * Constructor. Creates a new command with a SystemC time value as + * message part. + */ + scd_command(uint16_t type, uint16_t subtype, const sc_core::sc_time& time); + + virtual ~scd_command(); + + /** + * Returns the type of the command. + */ + uint16_t get_type() const; + + /** + * Returns the subtype of the command. + */ + uint16_t get_subtype() const; + + /** + * Returns the message part interpreted as a string. + */ + std::string get_string() const; + + /** + * Returns the message part interpreted as a SystemC time. + * If the message part does not have the correct size SC_ZERO_TIME + * is returned instead. + */ + sc_core::sc_time get_time() const; + +private: + uint16_t _type; + uint16_t _subtype; + uint16_t _msglen; + char* _msg; +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/scd_command_reader.cpp b/dol/src/dol/visitor/hdsd/scd/scd_command_reader.cpp new file mode 100644 index 0000000..7c9d904 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_command_reader.cpp @@ -0,0 +1,119 @@ +#include "scd_command_reader.h" + +#include + +#include "scd_logging.h" + + +scd_command_reader::scd_command_reader(): + _command(NULL), _is_reading(false), _success(false) {} + + +scd_command_reader::~scd_command_reader() +{ + if (_is_reading || _success) + { + delete _command; + } +} + + +void scd_command_reader::set_socket(scd_socket& sock) { _socket = &sock; } + + +void scd_command_reader::read() +{ + if (!_is_reading) + { + if (_success) + return; + + _is_reading = true; + _header_read = false; + _remaining = SCD_CM_HEADER; + _off = 0; + _command = new scd_command; + } + + // receive header + if (!_header_read) + { + // read header + size_t read = _socket->recv(_header_buf + _off, _remaining); + _remaining -= read; + _off += read; + + if (_remaining == 0) + { + // read values from buffer + uint16_t* intbuf = reinterpret_cast(_header_buf); + _command->_type = ntohs( intbuf[0] ); + _command->_subtype = ntohs( intbuf[1] ); + _command->_msglen = ntohs( intbuf[2] ); + + _header_read = true; + + // allocate buffer for further receiption + if (_command->_msglen > 0) + { + if (_command->_msglen > SCD_CM_MAXLEN) + { + // illegal command + _command->_msglen = 0; + delete _command; + _is_reading = false; + } + else + { + _command->_msg = new char[_command->_msglen]; + _remaining = _command->_msglen; + _off = 0; + } + } + else + { + // command without payload + _command->_msglen = 0; // to prevent negative values + _remaining = 0; + _is_reading = false; + _success = true; + } + } + } + + // receive msg + if (_header_read && _is_reading) + { + size_t read = _socket->recv(_command->_msg + _off, _remaining); + _remaining -= read; + _off += read; + + if (_remaining == 0) + { + _is_reading = false; + _success = true; + } + } + +} // read() + + +bool scd_command_reader::is_reading() { return _is_reading; } + + +bool scd_command_reader::has_command() { return _success; } + + +scd_command* scd_command_reader::get_command() +{ + if (!_success) + { + return NULL; + } + else + { + _success = false; + return _command; + } + +} // get_command() diff --git a/dol/src/dol/visitor/hdsd/scd/scd_command_reader.h b/dol/src/dol/visitor/hdsd/scd/scd_command_reader.h new file mode 100644 index 0000000..db06830 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_command_reader.h @@ -0,0 +1,64 @@ +#ifndef SCD_COMMAND_READER_H +#define SCD_COMMAND_READER_H + +#include "scd_command.h" +#include "scd_socket.h" + +/** + * Reads commands from a socket. The receiption does not have to complete + * withing one call. As long as it is ongoing the socket shall not be read + * by the application. + */ +class scd_command_reader +{ +public: + scd_command_reader(); + + virtual ~scd_command_reader(); + + /** + * Sets the socket to read from. Do not try to read before setting the + * socket. + */ + void set_socket(scd_socket &sock); + + /** + * Initiates reading a command if it is not reading yet or continues + * to read a previously unfinished command. + */ + void read(); + + /** + * Indicates if a command is being read. This is the case between calling + * read() and the completion of the command (or failure if an illegal + * command was received). + * \return true if a command is currently being received + */ + bool is_reading(); + + /** + * Indicates if a command has been received successfully and is ready + * to be picked up. + * \return true if a command can be collected + */ + bool has_command(); + + /** + * Returns a successfully received command. The application has to free + * it by itself. The reader does not keep a reference. + * \return the command or NULL if has_command() is false + */ + scd_command* get_command(); + +private: + scd_socket* _socket; + scd_command* _command; + bool _is_reading; + bool _header_read; + bool _success; + size_t _remaining; + size_t _off; + char _header_buf[SCD_CM_HEADER]; +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/scd_command_writer.cpp b/dol/src/dol/visitor/hdsd/scd/scd_command_writer.cpp new file mode 100644 index 0000000..64193ff --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_command_writer.cpp @@ -0,0 +1,93 @@ +#include "scd_command_writer.h" + +#include + +#include "scd_logging.h" + + +scd_command_writer::scd_command_writer(): + _is_writing(false), _remaining(0) {} + + +scd_command_writer::~scd_command_writer() +{ + std::list::iterator iter; + for ( iter = _commands.begin(); iter != _commands.end(); iter++) + delete *iter; +} + + +void scd_command_writer::set_socket(scd_socket& sock) { _socket = &sock; } + + +bool scd_command_writer::is_writing() const { return _is_writing; } + + +bool scd_command_writer::queue_command(scd_command* cmd) +{ + if (cmd->_msglen <= SCD_CM_MAXLEN) + { + _commands.push_back(cmd); + _is_writing = true; + return true; + } + else + { + scd_warn("command too long"); + delete cmd; + return false; + } +} + +void scd_command_writer::write() +{ + bool finishedmsg; + do + { + finishedmsg = _send_cmd(); + } + while (finishedmsg); + +} // write() + + +inline bool scd_command_writer::_send_cmd() +{ + if (!_is_writing) + return false; + + if (_remaining == 0) + { + /* fetch next command */ + scd_command* cmd = _commands.front(); + _commands.pop_front(); + + // store header to buffer + uint16_t* intbuf = reinterpret_cast(_buf); + intbuf[0] = htons(cmd->_type); + intbuf[1] = htons(cmd->_subtype); + intbuf[2] = htons(cmd->_msglen); + + // store message to buffer + memcpy(_buf + SCD_CM_HEADER, cmd->_msg, cmd->_msglen); + + _remaining = SCD_CM_HEADER + cmd->_msglen; + _off = 0; + delete cmd; + } + + size_t sent = _socket->send(_buf + _off, _remaining); + + _off += sent; + _remaining -= sent; + + if (_remaining == 0) + { + if (_commands.empty()) + _is_writing = false; + return true; + } + else + return false; + +} // _send_cmd() diff --git a/dol/src/dol/visitor/hdsd/scd/scd_command_writer.h b/dol/src/dol/visitor/hdsd/scd/scd_command_writer.h new file mode 100644 index 0000000..a8bb427 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_command_writer.h @@ -0,0 +1,61 @@ +#ifndef SCD_COMMAND_WRITER_H +#define SCD_COMMAND_WRITER_H + +#include + +#include "scd_command.h" +#include "scd_socket.h" + + +/** + * Queues multiple commands and writes then to a socket continuously. + */ +class scd_command_writer +{ +public: + scd_command_writer(); + + virtual ~scd_command_writer(); + + /** + * Sets the socket to write to. Do not try to write before + * setting the socket. + */ + void set_socket(scd_socket& sock); + + /** + * Indicates if the writer is currently sending a command. + * \return true if the writer is busy sending commands + */ + bool is_writing() const; + + /** + * Queues a command to be sent. Commands will be sent out in FIFO + * manner. Sending is not initiated by this call. + * \param message to send + * \return false if the message is longet than SCD_CM_MAXLEN. In this + * case the message is destroyed. + */ + bool queue_command(scd_command* cmd); + + /** + * Write commands or part of commands to the socket. As many queued + * commands as possible are sent but none has to be finished. + * \exception scd_exception if unexpected errors occured + */ + void write(); + +private: + scd_socket* _socket; + bool _is_writing; + + std::list_commands; + char _buf[SCD_CM_HEADER + SCD_CM_MAXLEN]; + size_t _remaining; + size_t _off; + + inline bool _send_cmd(); + +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/scd_cont_man.h b/dol/src/dol/visitor/hdsd/scd/scd_cont_man.h new file mode 100644 index 0000000..5499984 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_cont_man.h @@ -0,0 +1,38 @@ +#ifndef SCD_CONT_MAN_H +#define SCD_CONT_MAN_H + +#include + +#include "fsm/scd_cont_fsm_if.h" + + +const bool SCD_MASTER = true; +const bool SCD_SLAVE = false; + +const int SCD_CONT_DELAY = 20; + +/** + * Control manager. Shall be set up before the simulation is initialized. + */ +class scd_cont_man : public scd_cont_fsm_if +{ +public: + virtual ~scd_cont_man() {}; + + /** + * Sets the master simulator for a slave. + * \param host the FQDN or IP of the master simulator + * \param port the TCP port of the master simulator + * \exception scd_exception if the simulator is not a slave + */ + virtual void set_master(const std::string& host, uint16_t port) = 0; + + /** + * Registers a slave simulator for the master. + * \param name the name of the slave + * \exception scd_exception if the simulator is not the master + */ + virtual void register_slave(const std::string& name) = 0; +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/scd_cont_man_master.cpp b/dol/src/dol/visitor/hdsd/scd/scd_cont_man_master.cpp new file mode 100644 index 0000000..932644c --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_cont_man_master.cpp @@ -0,0 +1,93 @@ +#include "scd_cont_man_master.h" + +#include "scd_logging.h" +#include "scd_exception.h" + + +scd_cont_man_master::scd_cont_man_master(scd_simulator& sim): + _sim(sim), scd_cont_fsm("master"), + _st_init(sim, *this), _st_busy(sim, *this), _st_idle(sim, *this), + _st_done(sim, *this), _st_time_req(sim, *this), _st_time(sim, *this), + _st_term_req(sim, *this), _st_terminate(sim, *this), + _st_terminated(sim, *this), _st_fail(sim, *this), _st_failed(sim, *this) +{ + // set initial state + set_state(_st_init); +} + + +scd_cont_man_master::~scd_cont_man_master() +{ + std::list::iterator it; + + for (it = _slaves.begin(); it != _slaves.end(); it++) + delete *it; +} + + +void scd_cont_man_master::connect_slave(const scd_command &c, scd_socket* sock) +{ + std::string name = c.get_string(); + + scd_cont_slave_wrapper* slave = _get_slave(name); + + if (slave == NULL) + { + scd_warn("unknown slave \"" + name + "\""); + delete sock; + } + else + slave->connect(sock); + +} // connect() + + +void scd_cont_man_master::set_master(const std::string& host, uint16_t port) +{ + scd_error("simulator is master, can not have another master"); + throw scd_exception("simulator is master"); +} // set_master() + + +void scd_cont_man_master::register_slave(const std::string& name) +{ + if ( _get_slave(name) != NULL ) + { + scd_warn("slave \"" + name + "\" already registered, ignoring..."); + } + else + { + scd_cont_slave_wrapper* wrap; + wrap = new scd_cont_slave_wrapper(_sim, name); + _slaves.push_back(wrap); + } + +} // register_slave + + +void scd_cont_man_master::process() +{ + std::list::iterator it; + + // process all slaves + for (it = _slaves.begin(); it != _slaves.end(); it++) + (*it)->process(); + + // process the local state + _state->process(); +} + + +scd_cont_slave_wrapper* scd_cont_man_master::_get_slave(const std::string& name) +{ + std::list::iterator it; + + for (it = _slaves.begin(); it != _slaves.end(); it++) + { + if ( (*it)->get_name() == name ) + return *it; + } + + return NULL; + +} // _get_slave() diff --git a/dol/src/dol/visitor/hdsd/scd/scd_cont_man_master.h b/dol/src/dol/visitor/hdsd/scd/scd_cont_man_master.h new file mode 100644 index 0000000..f240321 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_cont_man_master.h @@ -0,0 +1,86 @@ +#ifndef SCD_CONT_MAN_MASTER_H +#define SCD_CONT_MAN_MASTER_H + +#include + +#include "scd_simulator.h" +#include "scd_cont_man.h" +#include "scd_cont_slave_wrapper.h" +#include "fsm/scd_cont_fsm.h" + +#include "fsm/scd_stm_init.h" +#include "fsm/scd_stm_busy.h" +#include "fsm/scd_stm_idle.h" +#include "fsm/scd_stm_done.h" +#include "fsm/scd_stm_time_req.h" +#include "fsm/scd_stm_time.h" +#include "fsm/scd_stm_term_req.h" +#include "fsm/scd_stm_terminate.h" +#include "fsm/scd_stm_terminated.h" +#include "fsm/scd_stm_fail.h" +#include "fsm/scd_stm_failed.h" + +/** + * Control manager for the master. Waits for all slaves to connect. + * Synchronizes the global simulation state. + */ +class scd_cont_man_master : public scd_cont_man, public scd_cont_fsm +{ + friend class scd_stm_base; + +public: + /** + * Constructor. + * \param sim the simulation environment + */ + scd_cont_man_master(scd_simulator& sim); + + virtual ~scd_cont_man_master(); + + /** + * Connects a slave. Is called from an in-connector. + * \param c the register command that has been received by the in-connector + * (contains the slave name). + * \param sock the incomming connection + */ + void connect_slave(const scd_command& c, scd_socket* sock); + + /* scd_cont_man */ + void set_master(const std::string& host, uint16_t port); + void register_slave(const std::string& name); + + /* scd_cont_fsm_if */ + void set_idle(const sc_core::sc_time& t) { return _state->set_idle(t); } + void set_busy() { return _state->set_busy(); } + void set_done() { return _state->set_done(); } + void set_fail() { return _state->set_fail(); } + void process(); + bool active() const { return _state->active(); } + bool busy() const { return _state->busy(); } + bool failed() const { return _state->failed(); } + bool advance_time() const { return _state->advance_time(); } + const sc_core::sc_time& get_time_step() { return _state->get_time_step(); } + +private: + scd_simulator& _sim; + std::list _slaves; + sc_core::sc_time _time_step; + + /* states */ + scd_stm_init _st_init; + scd_stm_busy _st_busy; + scd_stm_idle _st_idle; + scd_stm_done _st_done; + scd_stm_time_req _st_time_req; + scd_stm_time _st_time; + scd_stm_term_req _st_term_req; + scd_stm_terminate _st_terminate; + scd_stm_terminated _st_terminated; + scd_stm_fail _st_fail; + scd_stm_failed _st_failed; + + /* member functions */ + scd_cont_slave_wrapper* _get_slave(const std::string& name); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/scd_cont_man_slave.cpp b/dol/src/dol/visitor/hdsd/scd/scd_cont_man_slave.cpp new file mode 100644 index 0000000..7368ef9 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_cont_man_slave.cpp @@ -0,0 +1,181 @@ +#include "scd_cont_man_slave.h" + +#include "scd_logging.h" +#include "scd_exception.h" + + +scd_cont_man_slave::scd_cont_man_slave(scd_simulator& sim): + scd_cont_fsm("slave"), _sim(sim), + _connector(sim, SCD_CM_NETSIM, sim.get_name()), _has_master(false), + _st_init(sim, *this), _st_busy(sim, *this), _st_fail(sim, *this), + _st_failed(sim, *this), _st_idle(sim, *this), _st_done(sim, *this), + _st_time_ack(sim, *this), _st_time(sim, *this), _st_term_ack(sim, *this), + _st_terminated(sim, *this) +{ + // set initial state + set_state(_st_init); +} + + +scd_cont_man_slave::~scd_cont_man_slave() +{ + if (_socket != NULL) + delete _socket; +} + + +void scd_cont_man_slave::set_socket() +{ + _socket = _connector.get_connection(); + _writer.set_socket(*_socket); + _reader.set_socket(*_socket); +} // set_socket() + + +void scd_cont_man_slave::send_command(scd_command* cmd) +{ + // register write event if not registered + if (!_writer.is_writing() && _socket->is_valid()) + _sim.get_poller().set_ev(*this, SOCK_EV_WRITE | SOCK_EV_READ + | SOCK_EV_CLOSE); + + // queue command to be written + _writer.queue_command(cmd); +} + + +bool scd_cont_man_slave::is_sending() +{ + return _writer.is_writing() && _socket->is_valid(); +} + + +void scd_cont_man_slave::close() +{ + if (_socket != NULL) + _socket->close(); +} + + +void scd_cont_man_slave::set_master(const std::string& host, uint16_t port) +{ + if (!_has_master) + _connector.connect_to(host, port); + else + { + scd_error("master already set"); + throw scd_exception("master already set"); + } +} // set_master() + + +void scd_cont_man_slave::register_slave(const std::string& name) +{ + scd_error("simulator is slave, can not have other slaves"); + throw scd_exception("simulator is slave"); + +} // register_slave + + +void scd_cont_man_slave::handle_sock_ev(sock_ev events) +{ + scd_sts_base& state = *static_cast(_state); + + if (events & SOCK_EV_CLOSE) + { + scd_error("connection to master lost"); + _socket->close(); + state.set_failed(); + return; + } + + if (events & SOCK_EV_READ) + { + _reader.read(); + + if (!_socket->is_valid()) + { + // connection closed + scd_error("connection to master lost"); + state.set_failed(); + return; + } + + if (!_reader.is_reading() && !_reader.has_command()) + { + // received an illegal command + scd_error("received illegal command"); + state.set_fail(); + return; + } + + if (_reader.has_command()) + { + scd_command* cmd = _reader.get_command(); + _process_cmd(*cmd); + delete cmd; + } + + } // end read event + + if (events & SOCK_EV_WRITE) + { + _writer.write(); + if (!_writer.is_writing()) + { + // done sending commands + _sim.get_poller().set_ev(*this, SOCK_EV_READ | SOCK_EV_CLOSE); + } + } // end write event + + if (!_socket->is_valid()) + { + scd_error("connection to master lost"); + state.set_failed(); + } + +} // handle_sock_ev() + + +const scd_socket& scd_cont_man_slave::get_sock() { return *_socket; } + + +void scd_cont_man_slave::_process_cmd(scd_command& cmd) +{ + if (cmd.get_type() != SCD_CM_CONTROL) + { + scd_warn("received non-control command"); + return; + } + + scd_sts_base* state = static_cast(_state); + + switch (cmd.get_subtype()) + { + case SCD_CM_FAILED: + scd_error("master failed"); + state->set_failed(); + break; + case SCD_CM_TIME_REQ: + state->recv_time_req(); + break; + case SCD_CM_TIME_NACK: + state->recv_time_nack(); + break; + case SCD_CM_TIME: + state->recv_time(cmd.get_time()); + break; + case SCD_CM_TERM_REQ: + state->recv_term_req(); + break; + case SCD_CM_TERM_NACK: + state->recv_term_nack(); + break; + case SCD_CM_TERM: + state->recv_term(); + break; + default: + scd_warn("received unknown command"); + break; + } +} // _process_cmd() diff --git a/dol/src/dol/visitor/hdsd/scd/scd_cont_man_slave.h b/dol/src/dol/visitor/hdsd/scd/scd_cont_man_slave.h new file mode 100644 index 0000000..4156f7c --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_cont_man_slave.h @@ -0,0 +1,111 @@ +#ifndef SCD_CONT_MAN_SLAVE_H +#define SCD_CONT_MAN_SLAVE_H + +#include "scd_simulator.h" +#include "scd_socket.h" +#include "scd_out_connector.h" +#include "scd_command_writer.h" +#include "scd_command_reader.h" +#include "scd_cont_man.h" +#include "scd_sock_poller.h" + +#include "fsm/scd_cont_fsm.h" +#include "fsm/scd_sts_init.h" +#include "fsm/scd_sts_busy.h" +#include "fsm/scd_sts_idle.h" +#include "fsm/scd_sts_done.h" +#include "fsm/scd_sts_time_ack.h" +#include "fsm/scd_sts_time.h" +#include "fsm/scd_sts_term_ack.h" +#include "fsm/scd_sts_terminated.h" +#include "fsm/scd_sts_fail.h" +#include "fsm/scd_sts_failed.h" + +/** + * Control manager for a slave. Connects to the master controller and + * synchronizes the local and global simulation state. + */ +class scd_cont_man_slave : public scd_cont_man, public scd_cont_fsm, + public scd_sock_ev_handler_if +{ + friend class scd_sts_base; + +public: + /** + * Constructor. + * \param sim the simulation environment + */ + scd_cont_man_slave(scd_simulator& sim); + + virtual ~scd_cont_man_slave(); + + /** + * Sets the socket where to read from and write to after the connection + * has been established to the master. + */ + void set_socket(); + + /** + * Sends a command to the master. + * \param cmd the command to send + */ + void send_command(scd_command* cmd); + + /** + * Indicates if a command is being sent to the master (and did not finish + * yet). + * \return true if a command is currently being sent + */ + bool is_sending(); + + /** + * Closes the connection to the master controller. + */ + void close(); + + /* scd_cont_man */ + void set_master(const std::string& host, uint16_t port); + void register_slave(const std::string& name); + + /* scd_cont_fsm_if */ + void set_idle(const sc_core::sc_time& t) { return _state->set_idle(t); } + void set_busy() { return _state->set_busy(); } + void set_done() { return _state->set_done(); } + void set_fail() { return _state->set_fail(); } + void process() { return _state->process(); } + bool active() const { return _state->active(); } + bool busy() const { return _state->busy(); } + bool failed() const { return _state->failed(); } + bool advance_time() const { return _state->advance_time(); } + const sc_core::sc_time& get_time_step() { return _state->get_time_step(); } + + /* scd_sock_ev_handler_if */ + void handle_sock_ev(sock_ev events); + const scd_socket& get_sock(); + +private: + scd_simulator& _sim; + + scd_socket* _socket; + scd_out_connector _connector; + scd_command_writer _writer; + scd_command_reader _reader; + bool _has_master; + + /* states */ + scd_sts_init _st_init; + scd_sts_busy _st_busy; + scd_sts_idle _st_idle; + scd_sts_done _st_done; + scd_sts_time_ack _st_time_ack; + scd_sts_time _st_time; + scd_sts_term_ack _st_term_ack; + scd_sts_terminated _st_terminated; + scd_sts_fail _st_fail; + scd_sts_failed _st_failed; + + /* member functions */ + void _process_cmd(scd_command& cmd); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/scd_cont_slave_wrapper.cpp b/dol/src/dol/visitor/hdsd/scd/scd_cont_slave_wrapper.cpp new file mode 100644 index 0000000..0bc710a --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_cont_slave_wrapper.cpp @@ -0,0 +1,182 @@ +#include "scd_cont_slave_wrapper.h" + +#include "scd_logging.h" +#include "scd_exception.h" + + +scd_cont_slave_wrapper::scd_cont_slave_wrapper(scd_simulator& sim, + const std::string& name): + _sim(sim), scd_cont_fsm(name), _name(name), _is_connected(false), + _st_init(sim, *this), _st_busy(sim, *this), _st_idle(sim, *this), + _st_done(sim, *this), _st_time_req(sim, *this), _st_time_ack(sim, *this), + _st_term_req(sim, *this), _st_term_ack(sim, *this), + _st_terminate(sim, *this), _st_terminated(sim, *this), _st_fail(sim, *this), + _st_failed(sim, *this) +{ + // set initial state + set_state(_st_init); +} + + +scd_cont_slave_wrapper::~scd_cont_slave_wrapper() +{ + if (_socket != NULL) + delete _socket; +} + + +const std::string& scd_cont_slave_wrapper::get_name() const { return _name; } + + +void scd_cont_slave_wrapper::connect(scd_socket* sock) +{ + if (!_is_connected) + { + _socket = sock; + _writer.set_socket(*_socket); + _reader.set_socket(*_socket); + _is_connected = true; + scd_info("slave \"" + _name + "\" connected"); + static_cast(_state)->set_connected(); + } + else + { + scd_warn("slave " + _name + " has already been connected"); + delete sock; + } +} // connect() + + +void scd_cont_slave_wrapper::send_command(scd_command* cmd) +{ + // register write event if not registered + if (!_writer.is_writing() && _is_connected && _socket->is_valid()) + _sim.get_poller().set_ev(*this, SOCK_EV_WRITE | SOCK_EV_READ + | SOCK_EV_CLOSE); + + // queue command to be written + _writer.queue_command(cmd); +} + + +bool scd_cont_slave_wrapper::is_sending() const +{ + return _writer.is_writing() && _is_connected && _socket->is_valid(); +} + + +void scd_cont_slave_wrapper::close() +{ + if (_is_connected) + _socket->close(); +} + + +void scd_cont_slave_wrapper::handle_sock_ev(sock_ev events) +{ + scd_stsw_base& state = *static_cast(_state); + + if (events & SOCK_EV_CLOSE) + { + _socket->close(); + scd_error("connection to slave \"" + _name + "\" lost"); + state.set_failed(); + return; + } + + if (events & SOCK_EV_READ) + { + _reader.read(); + + if (!_socket->is_valid()) + { + // connection closed + scd_error("connection to slave \"" + _name + "\" lost"); + state.set_failed(); + return; + } + + if (!_reader.is_reading() && !_reader.has_command()) + { + // received an illegal command + scd_error("received illegal command"); + state.set_fail(); + return; + } + + if (_reader.has_command()) + { + scd_command* cmd = _reader.get_command(); + _process_cmd(*cmd); + delete cmd; + } + + } // end read event + + if (events & SOCK_EV_WRITE) + { + _writer.write(); + + if (!_writer.is_writing()) + { + // done sending commands + _sim.get_poller().set_ev(*this, SOCK_EV_READ | SOCK_EV_CLOSE); + } + + if (!_socket->is_valid()) + { + scd_error("connection to slave \"" + _name + "\" lost"); + state.set_failed(); + return; + } + } // end write event + + +} // handle_sock_ev() + + +const scd_socket& scd_cont_slave_wrapper::get_sock() { return *_socket; } + + +void scd_cont_slave_wrapper::_process_cmd(const scd_command& cmd) +{ + if (cmd.get_type() != SCD_CM_CONTROL) + { + scd_warn("received non-control command"); + return; + } + + scd_stsw_base* state = static_cast(_state); + + switch(cmd.get_subtype()) + { + case SCD_CM_BUSY: + state->set_busy(); + break; + case SCD_CM_IDLE: + state->set_idle(cmd.get_time()); + break; + case SCD_CM_DONE: + state->set_done(); + break; + case SCD_CM_TIME_NACK: + state->recv_time_nack(); + break; + case SCD_CM_TIME_ACK: + state->recv_time_ack(); + break; + case SCD_CM_TERM_NACK: + state->recv_term_nack(); + break; + case SCD_CM_TERM_ACK: + state->recv_term_ack(); + break; + case SCD_CM_FAILED: + scd_error("slave \"" + _name + "\" failed"); + state->set_failed(); + break; + default: + scd_warn("received unknown command"); + break; + } +} // _process_cmd() diff --git a/dol/src/dol/visitor/hdsd/scd/scd_cont_slave_wrapper.h b/dol/src/dol/visitor/hdsd/scd/scd_cont_slave_wrapper.h new file mode 100644 index 0000000..882f9ac --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_cont_slave_wrapper.h @@ -0,0 +1,142 @@ +#ifndef SCD_CONT_SLAVE_WRAPPER_H +#define SCD_CONT_SLAVE_WRAPPER_H + +#include "scd_simulator.h" +#include "scd_socket.h" +#include "scd_command_writer.h" +#include "scd_command_reader.h" +#include "scd_cont_man.h" +#include "scd_sock_poller.h" +#include "fsm/scd_cont_fsm.h" +#include "fsm/scd_cont_wrapper_if.h" + +#include "fsm/scd_stsw_init.h" +#include "fsm/scd_stsw_busy.h" +#include "fsm/scd_stsw_idle.h" +#include "fsm/scd_stsw_done.h" +#include "fsm/scd_stsw_time_req.h" +#include "fsm/scd_stsw_time_ack.h" +#include "fsm/scd_stsw_term_req.h" +#include "fsm/scd_stsw_term_ack.h" +#include "fsm/scd_stsw_terminate.h" +#include "fsm/scd_stsw_terminated.h" +#include "fsm/scd_stsw_fail.h" +#include "fsm/scd_stsw_failed.h" + +/** + * Control manager wrapper for a slave. Reflects the masters view of the + * slaves state. + */ +class scd_cont_slave_wrapper : public scd_cont_fsm_if, public scd_cont_fsm, + public scd_cont_wrapper_if, public scd_sock_ev_handler_if +{ + friend class scd_stsw_base; + +public: + /** + * Constructor. + * \param sim the simulation environment + * \param name the name of the slave + */ + scd_cont_slave_wrapper(scd_simulator& sim, const std::string& name); + + virtual ~scd_cont_slave_wrapper(); + + /** + * Returns the name of the slave. + */ + const std::string& get_name() const; + + /** + * Sets the socket of the slave. + * \param sock the connection to the slave + */ + void connect(scd_socket* sock); + + /** + * Sends a command to the slave. + */ + void send_command(scd_command* cmd); + + /** + * Indicates if a command is being sent to the slave. + * \return true if a command is still being sent + */ + bool is_sending() const; + + /** + * Closes the connection to the slave. + */ + void close(); + + /* scd_cont_slave_wrapper_if */ + void send_time_req() + { return static_cast(_state)->send_time_req(); } + void send_time_nack() + { return static_cast(_state)->send_time_nack(); } + void send_time(const sc_core::sc_time& time) + { return static_cast(_state)->send_time(time); } + void send_term_req() + { return static_cast(_state)->send_term_req(); } + void send_term_nack() + { return static_cast(_state)->send_term_nack(); } + void send_term() + { return static_cast(_state)->send_term(); } + bool time_req() const + { return static_cast(_state)->time_req(); } + bool time_ack() const + { return static_cast(_state)->time_ack(); } + bool term_req() const + { return static_cast(_state)->term_req(); } + bool term_ack() const + { return static_cast(_state)->term_ack(); } + bool idle() const + { return static_cast(_state)->idle(); } + bool done() const + { return static_cast(_state)->done(); } + + /* scd_cont_fsm_if */ + void set_busy() { return _state->set_busy(); } + void set_idle(const sc_core::sc_time& t) { return _state->set_idle(t); } + void set_done() { return _state->set_done(); } + void set_fail() { return _state->set_fail(); } + void process() { return _state->process(); } + bool active() const { return _state->active(); } + bool busy() const { return _state->busy(); } + bool failed() const { return _state->failed(); } + bool advance_time() const { return _state->advance_time(); } + const sc_core::sc_time& get_time_step() { return _state->get_time_step(); } + + /* scd_sock_ev_handler_if */ + void handle_sock_ev(sock_ev events); + const scd_socket& get_sock(); + +private: + scd_simulator& _sim; + std::string _name; + bool _is_connected; + + scd_socket* _socket; + scd_command_writer _writer; + scd_command_reader _reader; + sc_core::sc_time _time_step; + + /* states */ + scd_stsw_init _st_init; + scd_stsw_busy _st_busy; + scd_stsw_idle _st_idle; + scd_stsw_done _st_done; + scd_stsw_time_req _st_time_req; + scd_stsw_time_ack _st_time_ack; + scd_stsw_term_req _st_term_req; + scd_stsw_term_ack _st_term_ack; + scd_stsw_terminate _st_terminate; + scd_stsw_terminated _st_terminated; + scd_stsw_fail _st_fail; + scd_stsw_failed _st_failed; + + /* member functions */ + void _process_cmd(const scd_command& cmd); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/scd_exception.cpp b/dol/src/dol/visitor/hdsd/scd/scd_exception.cpp new file mode 100644 index 0000000..f5eb4f8 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_exception.cpp @@ -0,0 +1,35 @@ +#include "scd_exception.h" + + +scd_exception::scd_exception(const std::string& msg): _msg(msg) +{ + _get_backtrace(); +} + + +scd_exception::scd_exception(const std::string& msg, int errn) +{ + _msg = msg + ": " + std::string(strerror(errn)); + _get_backtrace(); +} + + +const char* scd_exception::what() throw() { return _msg.c_str(); } + + +const char* scd_exception::stacktrace() { return _backtrace.c_str(); } + + +void scd_exception::_get_backtrace() +{ + void* traces[SCD_EX_TRACES]; + int num_traces = backtrace(traces, SCD_EX_TRACES); + char ** symbols = backtrace_symbols(traces, num_traces); + for (int i = 0; i < num_traces; i++) + { + _backtrace += std::string(symbols[i]); + _backtrace += "\r\n"; + } + + free(symbols); +} // _obtain_backtrace() diff --git a/dol/src/dol/visitor/hdsd/scd/scd_exception.h b/dol/src/dol/visitor/hdsd/scd/scd_exception.h new file mode 100644 index 0000000..aa12e28 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_exception.h @@ -0,0 +1,57 @@ +#ifndef SCD_EXCEPTION_H +#define SCD_EXCEPTION_H + +#include +#include +#include + + +/** + * Maximum level of stacktrace. + */ +const int SCD_EX_TRACES = 15; + + +/** + * General exeption. Can give a stack trace and generates error messages + * from error numbers. + */ +class scd_exception : public std::exception +{ +public: + /** + * Constructor to create an exception with a string as cause. + * \param the cause + */ + scd_exception(const std::string& msg); + + /** + * Constroctor to create an exception with a string and an error + * message generated from an error number (errno) as cause. + * \param the cause prefix + * \param the error number to generate the error message for + */ + scd_exception(const std::string& msg, int errn); + + virtual ~scd_exception() throw() {} + + /** + * Returns a C-String showing the cause of the exception. + */ + virtual const char* what() throw(); + + /** + * Returns a C-String showing the stack trace. For name resolution + * -rdynamic has to be used while compiling. + */ + const char* stacktrace(); + +private: + std::string _msg; + std::string _backtrace; + + void _get_backtrace(); + +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/scd_in_connector.cpp b/dol/src/dol/visitor/hdsd/scd/scd_in_connector.cpp new file mode 100644 index 0000000..e289d25 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_in_connector.cpp @@ -0,0 +1,130 @@ +#include "scd_in_connector.h" + +#include "scd_logging.h" +#include "scd_cont_man_master.h" + + +scd_in_connector::scd_in_connector(scd_simulator &sim, scd_socket* sock): + _sim(sim), _socket(sock), _is_connecting(true) +{ + // register this event handler + _sim.get_poller().register_handler(*this, SOCK_EV_READ | SOCK_EV_CLOSE); + + // set the socket for the reader + _reader.set_socket(*sock); +} + + +scd_in_connector::~scd_in_connector() +{ + if (_is_connecting) + { + _cleanup(); + } +} + + +bool scd_in_connector::is_connecting() { return _is_connecting; } + + +void scd_in_connector::handle_sock_ev(sock_ev events) +{ + if (events & SOCK_EV_CLOSE) + { + scd_debug("in_connector: received close event"); + _cleanup(); + } + else if (events & SOCK_EV_READ) + { + _reader.read(); + + if (!_socket->is_valid()) + { + // connection closed + _cleanup(); + scd_debug("in_connector: connection closed"); + return; + } + + if (!_reader.is_reading() && !_reader.has_command()) + { + // received an illegal command + scd_debug("in_connector: received illegal command"); + _cleanup(); + return; + } + + if (_reader.has_command()) + { + scd_command* cmd = _reader.get_command(); + + if (cmd->get_type() == SCD_CM_REGISTER && + cmd->get_subtype() == SCD_CM_NETSIM) + { + // register host + scd_debug("in_connector: received cmd \"register host\""); + + try + { + // check if we are the master + scd_cont_man_master& master = + dynamic_cast(_sim.get_cont_man()); + + _sim.get_poller().remove_handler(*this); + + master.connect_slave(*cmd, _socket); + + delete cmd; + _is_connecting = false; + return; + } + catch ( std::bad_cast e) + { + scd_warn("slave tried to register"); + delete cmd; + _cleanup(); + return; + } + } // end register host + else if (cmd->get_type() == SCD_CM_REGISTER && + cmd->get_subtype() == SCD_CM_CHANNEL) + { + // register channel + scd_debug("in_connector: received cmd \"register channel\""); + + _sim.get_poller().remove_handler(*this); + + _sim.get_chan_man().connect_channel(*cmd, _socket); + + delete cmd; + _is_connecting = false; + return; + } // end register channel + else + { + // received wrong command + scd_debug("in_connector: received unknown command"); + delete cmd; + _cleanup(); + return; + } + } // end receive command + } // end read event + +} // handle_sock_ev() + + +const scd_socket& scd_in_connector::get_sock() +{ + return *_socket; +} + + +void scd_in_connector::_cleanup() +{ + if (_is_connecting) + _sim.get_poller().remove_handler(*this); + _socket->close(); + delete _socket; + _is_connecting = false; +} diff --git a/dol/src/dol/visitor/hdsd/scd/scd_in_connector.h b/dol/src/dol/visitor/hdsd/scd/scd_in_connector.h new file mode 100644 index 0000000..46e3c10 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_in_connector.h @@ -0,0 +1,46 @@ +#ifndef SCD_IN_CONNECTOR_H +#define SCD_IN_CONNECTOR_H + +#include "scd_socket.h" +#include "scd_sock_poller.h" +#include "scd_simulator.h" +#include "scd_command_reader.h" + +/** + * Reads a command from a socket handled over by scd_init_listener + * and dispatches the connection to either the control or channel manager. + * This is used during the initialization phase. + */ +class scd_in_connector : public scd_sock_ev_handler_if +{ +public: + /** + * Constructor. + * \param sim the simulator + * \param sock the socket of the connection to read the command from + */ + scd_in_connector(scd_simulator &sim, scd_socket* sock); + + ~scd_in_connector(); + + /** + * Indicates if this in_connector is still reading the incomming command. + * It can be deconstructed when this indicates false. + * \return true if this in_connector is still working + */ + bool is_connecting(); + + /* scd_sock_ev_handler_if */ + void handle_sock_ev(sock_ev events); + const scd_socket& get_sock(); + +private: + scd_socket* _socket; + scd_simulator &_sim; + bool _is_connecting; + scd_command_reader _reader; + + void _cleanup(); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/scd_init_listener.cpp b/dol/src/dol/visitor/hdsd/scd/scd_init_listener.cpp new file mode 100644 index 0000000..700df8b --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_init_listener.cpp @@ -0,0 +1,126 @@ +#include "scd_init_listener.h" + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_in_connector.h" + + +scd_init_listener::scd_init_listener(scd_simulator &sim, uint16_t port): + _sim(sim), _host(""), _port(port), _handler(false) {} + + +scd_init_listener::scd_init_listener(scd_simulator &sim, + const std::string &host, uint16_t port): + _sim(sim), _host(host), _port(port), _handler(false) {} + + +scd_init_listener::~scd_init_listener() +{ + cleanup(true); + close(); +} + + +void scd_init_listener::listen() +{ + if (!_socket.is_valid()) + { + // create listening socket + if (!_socket.create()) + throw scd_exception("creating listening socket failed"); + if (!_socket.bind(_host, _port)) + throw scd_exception("binding listening socket failed"); + if (!_socket.listen()) + throw scd_exception("listening to socket failed"); + + // register socket + if (!_handler) + { + _sim.get_poller().register_handler(*this, + SOCK_EV_READ | SOCK_EV_CLOSE); + _handler = true; + } + + scd_debug("socket listening"); + } + else + scd_warn("socket is already listening"); + +} // listen() + + +void scd_init_listener::close() +{ + if (_handler) + { + _sim.get_poller().remove_handler(*this); + _handler = false; + } + + if (_socket.is_valid()) + { + _socket.close(); + scd_debug("listener socket closed"); + } + +} // close() + + +void scd_init_listener::cleanup(bool hard) +{ + std::list::iterator iter; + + for( iter=_connectors.begin(); iter!=_connectors.end();) + { + if ( hard || !(*iter)->is_connecting() ) + { + delete *iter; + iter = _connectors.erase(iter); + } + else + iter++; + } +} // cleanup() + + +void scd_init_listener::handle_sock_ev(sock_ev events) +{ + if (events & SOCK_EV_READ) + { + scd_debug("incomming connection"); + + scd_socket* newconn = new scd_socket(); + + if (_socket.accept(*newconn)) + { + /* create a new connector that handles the connection + * and store it in the list of connectors */ + scd_in_connector* connector; + connector = new scd_in_connector(_sim, newconn); + _connectors.push_back(connector); + } + else + { + // connection could not be accepted + scd_debug("accepting connection failed"); + delete newconn; + } + } + + if (events & SOCK_EV_CLOSE) + { + throw scd_exception("init_listener: experienced an error"); + } + + if (!_socket.is_valid()) + { + throw scd_exception("init_listener: unexpectedly closed"); + } + +} // sock_ev_handler() + + +const scd_socket& scd_init_listener::get_sock() +{ + return _socket; +} diff --git a/dol/src/dol/visitor/hdsd/scd/scd_init_listener.h b/dol/src/dol/visitor/hdsd/scd/scd_init_listener.h new file mode 100644 index 0000000..5ae7b5a --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_init_listener.h @@ -0,0 +1,73 @@ +#ifndef SCD_INIT_LISTENER_H +#define SCD_INIT_LISTENER_H + +#include + +#include "scd_sock_poller.h" +#include "scd_socket.h" +#include "scd_simulator.h" +#include "scd_in_connector.h" + +/** + * Accepts incomming connection during initialization and instanciates + * a connector that handles the new connection. + */ +class scd_init_listener : public scd_sock_ev_handler_if +{ +public: + /** + * Constructor. Binds the listener to the specified TCP port on all + * available network interfaces. + * \param sim the simulator + * \param port TCP port to bind to + */ + scd_init_listener(scd_simulator &sim, uint16_t port); + + /** + * Constructor. Binds the listener to the specified TCP port + * only on the specified network interface. + * \param sim the simulator + * \param host IP or domain name of the interface to bind to + * \param port TCP port to bind to + */ + scd_init_listener(scd_simulator &sim, + const std::string &host, uint16_t port); + + /** + * Deconstructor. + */ + virtual ~scd_init_listener(); + + /** + * Creates the listening socket. + * \exception scd_exception if unexpected errors occure + */ + void listen(); + + /** + * Closes the listening socket. + */ + void close(); + + /** + * Removes connectors that finished their job. If the optional argument + * hard is true all connectors are destroyed independend if they + * have finished or not. + * \param hard if true all connectors will be destroyed + */ + void cleanup(bool hard = false); + + /* scd_sock_ev_handler_if */ + void handle_sock_ev(sock_ev events); + const scd_socket& get_sock(); + +private: + scd_simulator &_sim; + std::string _host; + uint16_t _port; + scd_socket _socket; + std::list_connectors; + bool _handler; +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/scd_logging.cpp b/dol/src/dol/visitor/hdsd/scd/scd_logging.cpp new file mode 100644 index 0000000..5b3fc4c --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_logging.cpp @@ -0,0 +1,40 @@ +#include +#include + +#include "scd_logging.h" + +static scd_loglevel _curr_level = SCD_INFO; + +void scd_log(const scd_loglevel &level, const string &str) +{ + std::ostream &out = std::clog; + + if (_curr_level > level) + return; + + switch(level) + { + case SCD_DEBUG: + out << "debug: "; + break; + case SCD_INFO: + out << "info: "; + break; + case SCD_WARN: + out << "warn: "; + break; + case SCD_ERROR: + out << "error: "; + break; + default: + out << "unknown: "; + break; + } + + out << str << std::endl; +} + +void scd_set_loglevel(const scd_loglevel &level) +{ + _curr_level = level; +} diff --git a/dol/src/dol/visitor/hdsd/scd/scd_logging.h b/dol/src/dol/visitor/hdsd/scd/scd_logging.h new file mode 100644 index 0000000..9112dc8 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_logging.h @@ -0,0 +1,56 @@ +#ifndef SCD_LOGGING_H +#define SCD_LOGGING_H + +#include +using std::string; + +/* Loglevels. Default is SCD_INFO */ +typedef int scd_loglevel; +const scd_loglevel SCD_DEBUG = 0; +const scd_loglevel SCD_INFO = 1; +const scd_loglevel SCD_WARN = 2; +const scd_loglevel SCD_ERROR = 3; + +/** + * Log message if the current loglevel is low enough. + */ +void scd_log(const scd_loglevel &level, const string &str); + +/** + * Log message with loglevel SCD_DEBUG. + */ +inline void scd_debug(const string &str) +{ + scd_log(SCD_DEBUG, str); +} + +/** + * Log message with loglevel SCD_INFO. + */ +inline void scd_info(const string &str) +{ + scd_log(SCD_INFO, str); +} + +/** + * Log message with loglevel SCD_WARN. + */ +inline void scd_warn(const string &str) +{ + scd_log(SCD_WARN, str); +} + +/** + * Log message with loglevel SCD_ERROR. + */ +inline void scd_error(const string &str) +{ + scd_log(SCD_ERROR, str); +} + +/** + * Set the current loglevel. Events with lower priorities are not logged. + */ +void scd_set_loglevel(const scd_loglevel &level); + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/scd_out_connector.cpp b/dol/src/dol/visitor/hdsd/scd/scd_out_connector.cpp new file mode 100644 index 0000000..999a423 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_out_connector.cpp @@ -0,0 +1,185 @@ +#include "scd_out_connector.h" + +#include + +#include "scd_logging.h" +#include "scd_exception.h" +#include "scd_command.h" + + +scd_out_connector::scd_out_connector(scd_simulator& sim, uint16_t type, + const std::string& name): + _sim(sim), _name(name), + _is_connecting(true), _is_connected(false), _has_connection(false) +{ + // create socket + _socket = new scd_socket; + _socket->create(); + + // prepare register command (do not send yet) + scd_command* cmd = new scd_command(SCD_CM_REGISTER, type, name); + _writer = new scd_command_writer(); + _writer->set_socket(*_socket); + _writer->queue_command(cmd); +} + + +scd_out_connector::~scd_out_connector() +{ + close(); + delete _writer; +} + + +void scd_out_connector::connect_to(const std::string& host, uint16_t port) +{ + _host = host; + _port = port; + + // register the handler to check if a connection attempt succeeded + _sim.get_poller().register_handler(*this, SOCK_EV_WRITE); + + // start connection attempt + _conn_attempt(); + +} // connect_to() + + +bool scd_out_connector::is_connecting() { return _is_connecting; } + + +bool scd_out_connector::has_connection() { return _has_connection; } + + +scd_socket* scd_out_connector::get_connection() +{ + if (_has_connection) + { + _has_connection = false; + return _socket; + } + else + return NULL; +} + + +void scd_out_connector::process() +{ + if (_is_connecting && !_is_connected) + { + struct timeval now; + gettimeofday(&now, NULL); + + // check if an attempt had timed out (i.e. because of "drop" FW policy) + if ( _socket->is_connecting() && + (now.tv_sec - _last_con.tv_sec >= SCD_CON_TIMEOUT) ) + { + // close and reopen the socket + scd_debug("connecting to " + _host + " timed out"); + _sim.get_poller().remove_handler(*this); + _socket->close(); + _socket->create(); + _sim.get_poller().register_handler(*this, 0); + } + + // check if it is time to try again + if ( !_socket->is_connecting() && + (now.tv_sec - _last_con.tv_sec >= SCD_CON_RETRY) ) + { + scd_debug("reconnecting to " + _host); + _conn_attempt(); + _sim.get_poller().set_ev(*this, SOCK_EV_WRITE); + } + } // still trying to tcp-connect + +} // process() + + +void scd_out_connector::close() +{ + if (_is_connecting) + { + _sim.get_poller().remove_handler(*this); + } + + if (_is_connecting || _has_connection) + { + _socket->close(); + delete _socket; + + _is_connecting = false; + _has_connection = false; + } + + _is_connected = false; + +} // close() + + +const std::string& scd_out_connector::get_name() const { return _name; } + + +void scd_out_connector::handle_sock_ev(sock_ev events) +{ + if (events & SOCK_EV_CLOSE) + { + // the close event is only polled if _is_connected is true + scd_error("outgoing connection closed"); + close(); + return; + } // end close event + else if (events & SOCK_EV_WRITE) + { + if (!_is_connected) + { + if (_socket->connected_event()) + { + // connection established + scd_debug("ougoing connection established to " + _host); + _is_connected = true; + _sim.get_poller().set_ev(*this, SOCK_EV_WRITE | SOCK_EV_CLOSE); + } + else + { + // connection attempt failed + _sim.get_poller().set_ev(*this, 0); + return; + } + } + + assert( _is_connected || !_socket->is_connecting()); + + _writer->write(); + if (!_writer->is_writing()) + { + // done sending the command + _is_connecting = false; + _has_connection = true; + _sim.get_poller().remove_handler(*this); + } + + if (!_socket->is_valid()) + { + close(); + } + } // end write event + +} // handle_sock_ev() + + +const scd_socket& scd_out_connector::get_sock() { return *_socket; } + + +void scd_out_connector::_conn_attempt() +{ + if (_socket->connect(_host, _port)) + { + gettimeofday(&_last_con, NULL); + } + else + { + scd_error("unable to connect to " + _host); + close(); + } + +} // _conn_attempt() diff --git a/dol/src/dol/visitor/hdsd/scd/scd_out_connector.h b/dol/src/dol/visitor/hdsd/scd/scd_out_connector.h new file mode 100644 index 0000000..f8a9a9c --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_out_connector.h @@ -0,0 +1,110 @@ +#ifndef SCD_OUT_CONNECTOR_H +#define SCD_OUT_CONNECTOR_H + +#include +#include +#include + +#include "scd_socket.h" +#include "scd_sock_poller.h" +#include "scd_simulator.h" +#include "scd_command_writer.h" + + +const time_t SCD_CON_TIMEOUT = 2; +const time_t SCD_CON_RETRY = 1; + + +/* forward declaration */ +class scd_simulator; + + +/** + * Initiates an outgoing connection and sends the register command + * to the other side. If an attempt to connect failes it is + * retried after some time. To drive this, process() has to be called + * repeatedly. + */ +class scd_out_connector : public scd_sock_ev_handler_if +{ +public: + /** + * Constructor. + * \param sim the simulator + * \param type what should be connected (SCD_CM_NETSIM or SCD_CM_CHANNEL) + * \param name the name of the ressource to connect (i.e. channel name + * or slave name) + */ + scd_out_connector(scd_simulator& sim, uint16_t type, + const std::string& name); + + virtual ~scd_out_connector(); + + /** + * Sets the host to connect to and starts the first connection attempt. + * + * \param host the IP or hostname to connect to + * \param port the port to connect to + */ + void connect_to(const std::string& host, uint16_t port); + + /** + * Indicates if this out_connector is still trying to connect or + * sending the command. + * * \return true if this out_connector is still working + */ + bool is_connecting(); + + /** + * Indicates if the command has been sent successfully and the registered + * connection can be collected. + * \return true if a connection is registered + */ + bool has_connection(); + + /** + * Returns the established and registered connection. + */ + scd_socket* get_connection(); + + + /** + * Checks if a time outs have occured. A connection attempt that is running + * for more than SCD_CON_TIMEOUT seconds is terminated and failed + * connection attempts are retried after SCD_CON_RETRY seconds. + */ + void process(); + + /** + * Stops to try to connect or terminates an already established + * connection. + */ + void close(); + + /** + * Returns the name of the ressource to connect. + */ + const std::string& get_name() const; + + /* scd_sock_ev_handler_if */ + void handle_sock_ev(sock_ev events); + const scd_socket& get_sock(); + +private: + scd_simulator &_sim; + std::string _name; + std::string _host; + uint16_t _port; + + bool _is_connecting; + bool _has_connection; + scd_socket* _socket; + scd_command_writer* _writer; + + bool _is_connected; + struct timeval _last_con; + + void _conn_attempt(); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/scd_rem_chan_if.h b/dol/src/dol/visitor/hdsd/scd/scd_rem_chan_if.h new file mode 100644 index 0000000..e478cc6 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_rem_chan_if.h @@ -0,0 +1,67 @@ +#ifndef SCD_REM_CHAN_IF_H +#define SCD_REM_CHAN_IF_H + +#include + + +/** + * Interface for SystemC channels with remote input. + */ +class scd_rem_chan_in_if +{ +public: + + /** + * Indicates how many bytes can be received by this channel. + */ + virtual size_t free() const = 0; + + /** + * Receive bytes, convert to internal data structures and generate + * notifications if necessary. + * + * \param buf pointer to buffer to read data from + * \param len number of bytes to receive (not larger than free()) + */ + virtual void receive(const void* buf, size_t len) = 0; + + /** + * Virtual deconstructor + */ + virtual ~scd_rem_chan_in_if() {} +}; + + +/** + * Interface for SystemC channels with remote output. + */ +class scd_rem_chan_out_if +{ +public: + + /** + * Inidcates how many bytes are available to be sent from this channel. + */ + virtual size_t available() const = 0; + + /** + * Get the available data to be sent. Does not guarantee that it is + * actually sent. At most available() bytes are sent. + */ + virtual const void* send() const = 0; + + /** + * Remove bytes from channel that have been successully sent. + * + * \param len number of bytes that have been sent (not larger than + * available()) + */ + virtual void remove(size_t len) = 0; + + /** + * Virtual deconstructor + */ + virtual ~scd_rem_chan_out_if() {} +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/scd_rem_fifo_in.cpp b/dol/src/dol/visitor/hdsd/scd/scd_rem_fifo_in.cpp new file mode 100644 index 0000000..62346fc --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_rem_fifo_in.cpp @@ -0,0 +1,62 @@ +#include "scd_rem_fifo_in.h" + +#include + +#include "scd_logging.h" + + +scd_rem_fifo_in::scd_rem_fifo_in(sc_module_name name, int size): + sc_prim_channel(name), _num_elements(0), _first(0), _size(size) +{ + assert(size > 0); + _data = new char[size]; +} + + +scd_rem_fifo_in::~scd_rem_fifo_in() +{ + delete _data; +} + + +void scd_rem_fifo_in::read(char &c) +{ + while (_num_elements == 0) + wait(_write_event); + + c = _data[_first]; + _num_elements--; + _first = (_first + 1) % _size; +} + + +int scd_rem_fifo_in::rtest(int size) +{ + return (size <= _num_elements) ? 1 : 0; +} + + +void scd_rem_fifo_in::reset() { _num_elements = _first = 0; } + + +int scd_rem_fifo_in::num_available() { return _num_elements ;} + + +size_t scd_rem_fifo_in::free() const { return _size - _num_elements; } + + +void scd_rem_fifo_in::receive(const void* buf, size_t len) +{ + if (len == 0) + return; + + assert(_num_elements + len <= _size); + + for (int i=0; i + +#include "scd_logging.h" + + +scd_rem_fifo_out::scd_rem_fifo_out(sc_module_name name, int size): + sc_prim_channel(name), _num_elements(0), _first(0), _size(size) +{ + assert(size > 0); + _data = new char[size]; +} + + +scd_rem_fifo_out::~scd_rem_fifo_out() +{ + delete _data; +} + + +void scd_rem_fifo_out::write(char c) +{ + while (_num_elements == _size) + wait(_read_event); + + _data[ (_first + _num_elements) % _size ] = c; + _num_elements++; +} + + +int scd_rem_fifo_out::wtest(int size) +{ + return (size <= _size - _num_elements) ? 1 : 0; +} + + +void scd_rem_fifo_out::reset() { _num_elements = _first = 0; } + + +size_t scd_rem_fifo_out::available() const +{ + size_t avail; + + if (_num_elements <= _size - _first) + avail = _num_elements; + else + avail = _size - _first; + + return avail; +} + + +const void* scd_rem_fifo_out::send() const { return _data + _first; } + + +void scd_rem_fifo_out::remove(size_t len) +{ + if (len == 0) + return; + + assert(_num_elements >= len); + + _first = (_first + len) % _size; + + _num_elements -= len; + + _read_event.notify(); +} diff --git a/dol/src/dol/visitor/hdsd/scd/scd_rem_fifo_out.h b/dol/src/dol/visitor/hdsd/scd/scd_rem_fifo_out.h new file mode 100644 index 0000000..2025a1e --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_rem_fifo_out.h @@ -0,0 +1,83 @@ +/***************************************************************************** + + The following code is derived, directly or inror: pointdirectly, from the SystemC + source code Copyright (c) 1996-2007 by all Contributors. + All Rights reserved. + + The contents of this file are subject to the restrictions and limitations + set forth in the SystemC Open Source License Version 2.4 (the "License"); + You may not use this file except in compliance with such restrictions and + limitations. You may obtain instructions on how to receive a copy of the + License at http://www.systemc.org/. Software distributed by Contributors + under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the License for the specific + language governing rights and limitations under the License. + + *****************************************************************************/ + +/***************************************************************************** + + simple_fifo.cpp -- Simple SystemC 2.0 producer/consumer example. + + From "An Introduction to System Level Modeling in + SystemC 2.0". By Stuart Swan, Cadence Design Systems. + Available at www.systemc.org + + Original Author: Stuart Swan, Cadence Design Systems, 2001-06-18 + + *****************************************************************************/ + +/***************************************************************************** + + MODIFICATION LOG - modifiers, enter your name, affiliation, date and + changes you are making here. + + Name, Affiliation, Date: Fabian Hugelshofer, ETH Zurich, 13.11.2007 + Description of Modification: Used code as base for remote fifo channels. + + *****************************************************************************/ + +#ifndef SCD_REM_FIFO_OUT_H_ +#define SCD_REM_FIFO_OUT_H_ + +#include "systemc" + +#include "simple_fifo.h" // for write_if +#include "scd_rem_chan_if.h" + + +/** + * FIFO channel with remote output. Data written to this FIFO endpoint + * is transmitted to another host. + */ +class scd_rem_fifo_out : public sc_core::sc_prim_channel, public write_if, + public scd_rem_chan_out_if +{ +public: + /** + * Constructor. + * \param name the name of the channel (is passed to parent constructor) + * \param size size of the output buffer in bytes + */ + scd_rem_fifo_out(sc_module_name name, int size); + + virtual ~scd_rem_fifo_out(); + + /* write_if */ + void write(char c); + int wtest(int size); + void reset(); + + /* scd_rem_chan_out_if */ + size_t available() const; + const void* send() const; + void remove(size_t len); + +private: + int _size; + char* _data; + int _num_elements, _first; + sc_event _read_event; +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/scd_simulator.cpp b/dol/src/dol/visitor/hdsd/scd/scd_simulator.cpp new file mode 100644 index 0000000..86c2196 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_simulator.cpp @@ -0,0 +1,218 @@ +#include "scd_simulator.h" + +#include +#include + +#include "systemc" + +#include "scd_cont_man_master.h" +#include "scd_cont_man_slave.h" +#include "scd_init_listener.h" +#include "scd_logging.h" + + +scd_simulator::scd_simulator(const std::string& name, + const std::string &loc_host, uint16_t loc_port, bool master): + _name(name), _loc_host(loc_host), _loc_port(loc_port) +{ + _poller = new scd_sock_poller; + + if (master == SCD_MASTER) + _cont_man = new scd_cont_man_master(*this); + else + _cont_man = new scd_cont_man_slave(*this); + + _chan_man = new scd_chan_man(*this); +} + + +scd_simulator::scd_simulator(const std::string& name, uint16_t loc_port, + bool master): + _name(name), _loc_host(""), _loc_port(loc_port) +{ + _poller = new scd_sock_poller; + + if (master == SCD_MASTER) + _cont_man = new scd_cont_man_master(*this); + else + _cont_man = new scd_cont_man_slave(*this); + + _chan_man = new scd_chan_man(*this); +} + + +scd_simulator::~scd_simulator() +{ + delete _chan_man; + delete _cont_man; + delete _poller; +} + + +const std::string& scd_simulator::get_name() const { return _name; } + + +scd_sock_poller& scd_simulator::get_poller() { return *_poller; } + + +scd_chan_man& scd_simulator::get_chan_man() { return *_chan_man; } + + +scd_cont_man& scd_simulator::get_cont_man() { return *_cont_man; } + + +bool scd_simulator::init() +{ + scd_info("initialization start"); + + /* open port for incomming connections */ + scd_init_listener listener(*this, _loc_host, _loc_port); + listener.listen(); + + /* + * init until the initialization failed or chan_man and cont_man are + * successfully initiated + */ + while ( !_cont_man->failed() && + ( !_chan_man->ready() || !_cont_man->active() ) ) + { + // poll the sockets and execute callback handlers + _poller->process(); + + // connect channels + _chan_man->init_process(); + + // process state transitions + _cont_man->process(); + + /* as we might be waiting for a peer coming up we can not use + * a blocking poll as errors would always exist and the poller would + * wake up immediately + * => sleep some milliseconds + */ + usleep(50); + } + + listener.close(); + + if (_cont_man->failed()) + { + scd_error("initialization failed"); + return false; + } + else + { + scd_info("initialization done"); + return true; + } + +} // init() + + +bool scd_simulator::start() +{ + scd_info("simulation start"); + + /* first delta cycle to initialize the SystemC scheduler + * else the _pending*() functions would fail */ + sc_core::sc_start(sc_core::SC_ZERO_TIME); + + while (_cont_man->active()) + { + /* signalize the simulation state to the controller */ + if (_pending()) + { + if (_pending_now()) + { + // events in this time step + _cont_man->set_busy(); + } + else + { + // signalize time step until next event + sc_core::sc_time step; + step = _next_time() - sc_core::sc_time_stamp(); + _cont_man->set_idle(step); + } + } + else + _cont_man->set_done(); + + // check for state changes + _cont_man->process(); + + /* run simulation if something to do and in right state */ + if (_cont_man->busy()) + { + // simulate one delta cycle + sc_core::sc_start(sc_core::SC_ZERO_TIME); + + // check if we have to wait for new socket events + _chan_man->process(); + + // poll the sockets to induce transmissions + _poller->process(); + } + else + { + if (_cont_man->advance_time()) + { + sc_core::sc_time step = _cont_man->get_time_step(); + // advance simulation time, nothing should actually be simulated + sc_start(step); + scd_info("time advanced by " + step.to_string() + " to " + + sc_core::sc_time_stamp().to_string() ); + } + else if ( _cont_man->active() ) + { + // wait for activity on sockets + _poller->wait_process(); + } + } + + } // while simulation is running + + /* simulation terminated */ + + if (_cont_man->failed()) + { + scd_error("simulation failed"); + return false; + } + else + { + scd_info("simulation done"); + return true; + } + +} // start() + + +/** + * Returns true if events exist at current simulation time. + */ +bool scd_simulator::_pending_now() +{ + return sc_core::sc_pending_activity_at_current_time(); +} + + +/** + * Returns true if events exist at current or later simulation time. + */ +bool scd_simulator::_pending() +{ + sc_core::sc_time next = _next_time(); + return ( (next != sc_core::SC_ZERO_TIME) || _pending_now() ); +} + + +/** + * Returns the time of the next earliest timed event + * or SC_ZERO_TIME if no such event exists. + */ +const sc_core::sc_time scd_simulator::_next_time() +{ + return sc_core::sc_get_curr_simcontext()->next_time(); +} + diff --git a/dol/src/dol/visitor/hdsd/scd/scd_simulator.h b/dol/src/dol/visitor/hdsd/scd/scd_simulator.h new file mode 100644 index 0000000..48b4b3f --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_simulator.h @@ -0,0 +1,118 @@ +#ifndef SCD_SIMULATOR_H +#define SCD_SIMULATOR_H + +#include +#include + +#include "scd_sock_poller.h" +#include "scd_chan_man.h" +#include "scd_cont_man.h" + + +/* forward declaration */ +class scd_chan_man; +class scd_cont_man_if; + + +/** + * Simulator to run a distributed SystemC simulation. First the + * channel with remote endpoints, the slave controllers and the + * master controller have to be registered with the channel manager + * and the control manager. Second the simulation has to be + * initialized and third the simulation can be started. + */ +class scd_simulator +{ +public: + + /** + * Constructor. Binds the simulator to the specified TCP port + * only on the specified network interface. + * \param name the name of this simulator + * \param loc_host IP or domain name of the interface to bind to + * \param loc_port TCP port to bind to + * \bool master SCD_MASTER if this simulator is the master, else + * SCD_SLAVE + */ + scd_simulator(const std::string& name, const std::string &loc_host, + uint16_t loc_port, bool master); + + /** + * Constructor. Binds the simulator to the specified TCP port on all + * available network interfaces. + * \param name the name of this simulator + * \param loc_port TCP port to bind to + * \bool master SCD_MASTER if this simulator is the master, else + * SCD_SLAVE + */ + scd_simulator(const std::string& name, uint16_t loc_port, bool master); + + virtual ~scd_simulator(); + + + /** + * Returns the name of this simulator. + */ + const std::string& get_name() const; + + /** + * Returns the socket poller of this simulation. + */ + scd_sock_poller& get_poller(); + + /** + * Returns the channel manager of this simulation. + */ + scd_chan_man& get_chan_man(); + + /** + * Returns the control manager of this simulation. + */ + scd_cont_man& get_cont_man(); + + /** + * Initializes the distributed simulation. Connects all remote channels + * and the control infrastructure. The channels, the slaves and the master + * have to be registered before initializating. A simulation can only + * be initialized once. + */ + bool init(); + + /** + * Runs the simulation until an error occures or no more events + * exist globally. A simulation can only be started once. + */ + bool start(); + + +private: + scd_sock_poller* _poller; + scd_chan_man* _chan_man; + scd_cont_man* _cont_man; + + std::string _name; + std::string _loc_host; + uint16_t _loc_port; + + /* member functions */ + + /** + * Indicates if events exist for the current simulation time. + * \return true if events exist for the current time + */ + bool _pending_now(); + + /** + * Indicates if events exist in the event queues. + * \return true if events exist + */ + bool _pending(); + + /** + * Returns the absolute time of the next event in the queues. + * \retunrs the absoulte time of the next event or 0 if no such event exists + */ + const sc_core::sc_time _next_time(); +}; + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/scd_sock_poller.cpp b/dol/src/dol/visitor/hdsd/scd/scd_sock_poller.cpp new file mode 100644 index 0000000..1cff374 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_sock_poller.cpp @@ -0,0 +1,201 @@ +#include "scd_sock_poller.h" + +#include +#include +#include +#include + +#include "scd_exception.h" +#include "scd_logging.h" + + +bool scd_sock_poller::register_handler(scd_sock_ev_handler_if& handler, + sock_ev events) +{ + // can not register the same handler twice + if (_handler_exists(handler)) + { + scd_warn("socket handler already registered while registering"); + return false; + } + + // register handler + _handlers.push_back(&handler); + + // register socket and events + struct pollfd fd; + fd.fd = handler.get_sock()._socket; + fd.events = events; + _events.push_back(fd); + return true; + +} // register_handler() + + +bool scd_sock_poller::remove_handler(const scd_sock_ev_handler_if &handler) +{ + int idx = _get_index(handler); + + // check if handler was found + if (idx == -1) + { + scd_warn("socket handler not registered while removing poll handler"); + return false; + } + + // remove events and handler from vectors + _events.erase(_events.begin() + idx); + _handlers.erase(_handlers.begin() + idx); + + return true; + +} // remove_handler() + + +bool scd_sock_poller::set_ev(const scd_sock_ev_handler_if &handler, + sock_ev events) +{ + int idx = _get_index(handler); + + if (idx == -1) + { + scd_warn("socket handler not registered while setting poll events"); + return false; + } + + _events[idx].events = events; + + return true; +} // set_ev() + + +bool scd_sock_poller::get_ev(const scd_sock_ev_handler_if &handler, + sock_ev &events) const +{ + int idx = _get_index(handler); + + if (idx == -1) + { + scd_warn("socket handler not registered while getting poll events"); + return false; + } + + events = _events[idx].events; + + return true; + +} // get_ev() + + +bool scd_sock_poller::wait(int ms) +{ + int ret = _poll(ms); + if (ret > 0) + return true; + else + return false; +} + + +bool scd_sock_poller::process() +{ + int ret = _poll(0); + + if (ret != 0) // events occured + { + _callback(); + return true; + } + else + return false; + +} // process() + + +void scd_sock_poller::wait_process() +{ + _poll(-1); + _callback(); + +} // wait_process() + + +bool scd_sock_poller::_handler_exists(const scd_sock_ev_handler_if &handler) + const +{ + std::vector::const_iterator iter; + + iter = std::find(_handlers.begin(), _handlers.end(), &handler); + + if (iter == _handlers.end()) + return false; + else + return true; + +} // _handler_exists() + + +int scd_sock_poller::_get_index(const scd_sock_ev_handler_if &handler) const +{ + std::vector::const_iterator iter; + + iter = std::find(_handlers.begin(), _handlers.end(), &handler); + + if (iter == _handlers.end()) + { + // handler not found + return -1; + } + else + { + // return index (random access iterator) + return iter - _handlers.begin(); + } + +} // _get_index() + + +int scd_sock_poller::_poll(int ms) +{ + int ret; + + if (ms < 0 && _events.size() == 0) + { + scd_debug("immediately returning form infinite poll: no events to watch"); + return 0; + } + + do + { + ret = poll(&_events[0], _events.size(), ms); + if (ret == -1 && errno != EINTR) + { + std::string error("poll(): "); + error += std::string(strerror(errno)); + throw scd_exception(error); + } + } + while (ret == -1 && errno == EINTR); + + return ret; + +} // _poll() + + +void scd_sock_poller::_callback() +{ + /* called handlers might remove themselves. as the order + * should not break we operate on copies here */ + std::vector events_cpy = _events; + std::vector handlers_cpy = _handlers; + + // for all handlers + for (int i=0; i callback handler + handlers_cpy[i]->handle_sock_ev(events_cpy[i].revents); + } + } // for all events +} // _callback() diff --git a/dol/src/dol/visitor/hdsd/scd/scd_sock_poller.h b/dol/src/dol/visitor/hdsd/scd/scd_sock_poller.h new file mode 100644 index 0000000..b19cece --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_sock_poller.h @@ -0,0 +1,144 @@ +#ifndef SCD_SOCK_POLLER_H +#define SCD_SOCK_POLLER_H + +#include +#include "poll.h" + +#include "scd_socket.h" + + +typedef short sock_ev; +const sock_ev SOCK_EV_READ = POLLIN; +const sock_ev SOCK_EV_WRITE = POLLOUT; +const sock_ev SOCK_EV_CLOSE = POLLERR | POLLHUP | POLLNVAL; + + +/** + * Interface for classes able to handle socket events. + */ +class scd_sock_ev_handler_if +{ +public: + /** + * Executes the handler for socket events that have been registered + * and have ocured. Callback carried out by scd_sock_poller. + *\param events the events that occured + */ + virtual void handle_sock_ev(sock_ev events) = 0; + + /** + * Returns the socket that should be watched. The socket must + * be the same as long the handler is registered. + */ + virtual const scd_socket &get_sock() = 0; + + virtual ~scd_sock_ev_handler_if() {}; +}; + + +/** + * Dispatcher that watches sockets and executes call backs if watched + * event occure. Socket events (sock_ev) are an OR combination of flags + * supported by ::poll. See "man 2 poll". The watched events for a specific + * event handler stay watched until the events are overwritten or the handler + * is removed. + */ +class scd_sock_poller +{ +public: + /** + * Register a socket event handler (a class handling socket events). + * Optionally the events to watch can be specified. + * \param handler the object that wants to watch a socket + * \param events (optional) the events to watch + * \return true if the handler could be registered succesfully + */ + bool register_handler(scd_sock_ev_handler_if &handler, sock_ev events = 0); + + /** + * Remove a socket event handler. The socket is not watched anymore. + * \param the object that has previously been registered + * \return false if no such handler was registered + */ + bool remove_handler(const scd_sock_ev_handler_if &handler); + + /** + * Set events to watch. The events expire only when overwritten + * by calling this function again or by removing the handler. + * \param handler the handler that has been registered before + * \param events the events the handler is interested in + * \return false if the handler has not been registered before + */ + bool set_ev(const scd_sock_ev_handler_if &handler, sock_ev events); + + /** + * Gets the events that are currently watched for the handler. + * \param the handler to get the watched events for + * \param events the variable where the watched events are written to + * \return false if the handler has not been registered before + */ + bool get_ev(const scd_sock_ev_handler_if &handler, sock_ev &events) const; + + /** + * Wait (blocking) for registered events or a timeout to occure. + * No callbacks are executed. + * \param milis timeout in milliseconds to wait for events, if omitted + * or -1 it is waited until events occure + * \return true if events occured, false otherwise + * \exception scd_exception if unexpected errors occured + */ + bool wait(int ms = -1); + + /** + * Check if events occured and callback the affected handlers. + * \return true if some events occured + * \exception scd_exception if unexcpected errors occured + */ + bool process(); + + /** + * Wait (blocking) for registered events to occure and callback the + * affected handlers. + * \exception scd_exception if unexcpected errors occured + */ + void wait_process(); + +private: + /* member variables */ + std::vector _handlers; + std::vector _events; + + /* member functions */ + + /** + * Checks if a handler is already registered. + * \param handler the handler to check for existence + * \return true if the handler has been registered before + */ + bool _handler_exists(const scd_sock_ev_handler_if& handler) const; + + /** + * Returns the index of an event handler in the vector. This is the same + * index as the corresponding pollfd. + * \param handler the handler to get the index of + * \return the index of the handler or -1 if it could not be found + */ + int _get_index(const scd_sock_ev_handler_if& handler) const; + + /** + * Polls during a specified amount of time. + * \param ms miliseconds to block (-1 for infinite) + * \exception scd_exception if an unexpected error occured + * \return number of sockets for witch events occured + */ + int _poll(int ms); + + /** + * Calls handlers back for which events occured. + */ + void _callback(); +}; + +//scd_sock_poller* scd_get_sock_poller(); + +#endif diff --git a/dol/src/dol/visitor/hdsd/scd/scd_socket.cpp b/dol/src/dol/visitor/hdsd/scd/scd_socket.cpp new file mode 100644 index 0000000..a5ca5de --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_socket.cpp @@ -0,0 +1,439 @@ +#include "scd_socket.h" + +#include +#include // for TCP_NODELAY +#include +#include +#include + +#include "scd_logging.h" +#include "scd_exception.h" + +scd_socket::scd_socket() +{ + _socket = -1; + _is_connecting = false; + _is_connected = false; +} + +scd_socket::~scd_socket() {} + +bool scd_socket::is_valid() const +{ + return (_socket != -1); +} + +bool scd_socket::create() +{ + // check if socket already created before + if ( is_valid() ) + { + return false; + } + + // create TCP socket + _socket = socket(PF_INET, SOCK_STREAM, 0); + + assert(is_valid()); + + _set_blocking(false); + + _is_connecting = false; + _is_connected = false; + + return true; + +} // create() + +void scd_socket::close() +{ + if ( is_valid() ) + { + ::close(_socket); + } + + _socket = -1; + _is_connecting = false; + _is_connected = false; +} + +bool scd_socket::bind(const std::string &loc_name, const uint16_t loc_port) +{ + int ret; + + if ( ! is_valid() ) + { + return false; + } + + // prepare the local address + sockaddr_in loc_addr; + if ( !_get_sockaddr(loc_addr, loc_name, loc_port) ) + { + return false; + } + + // set socket reusable (to recreate listener without timeout) + int on = 1; + ret = setsockopt( _socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ); + if (ret == -1) + { + throw scd_exception("setsockopt()", errno); + } + + ret = ::bind( _socket, reinterpret_cast(&loc_addr), + sizeof( loc_addr ) ); + + if ( ret == -1 ) + { + switch(errno) + { + case EACCES: + scd_error("must be root to bind to desired port"); + break; + case EADDRINUSE: + scd_error("unable to bind as the address is already in use"); + break; + default: + throw scd_exception("bind()", errno); + } + return false; + } + + return true; + +} // bind() + + +bool scd_socket::bind(const uint16_t loc_port) +{ + return bind("", loc_port); +} // bind() + + +bool scd_socket::listen() +{ + int ret; + + if ( !is_valid() ) + { + return false; + } + + ret = ::listen(_socket, SCD_MAXCONN); + + if (ret == -1) + { + throw scd_exception("listen()", errno); + } + + return true; +} // listen() + +bool scd_socket::accept(scd_socket &new_sock) +{ + int ret; + + if ( !is_valid() ) + { + return false; + } + + ret = ::accept(_socket, NULL, NULL); + + if (ret < 0) + { + switch (errno) + { + case EAGAIN: + case ECONNABORTED: + case EINTR: + case EPROTO: + return false; + break; + default: + throw scd_exception("accept()", errno); + break; + } + } + else + { + new_sock._is_connected = true; + new_sock._socket = ret; + new_sock._set_blocking(false); + #ifdef TCP_NODELAY + new_sock._set_nodelay(); + #endif + } + + return true; + +} // accept() + + +bool scd_socket::connect(const std::string &rem_name, const uint16_t rem_port) +{ + int ret; + + if ( !is_valid() || _is_connecting || _is_connected ) + return false; + + sockaddr_in rem_addr; + if ( !_get_sockaddr(rem_addr, rem_name, rem_port) ) + return false; + + ret = ::connect(_socket, reinterpret_cast(&rem_addr), + sizeof(rem_addr)); + + if (ret == -1) + { + switch(errno) + { + case EINPROGRESS: + _is_connecting = true; + break; + case ECONNABORTED: + case ECONNREFUSED: + case EINTR: + case ENETUNREACH: + case ETIMEDOUT: + break; + case EALREADY: // should be prevented by _is_connecting + default: + throw scd_exception("connect()", errno); + break; + } + } + else // ret == 0 + { + _is_connected = true; + _is_connecting = false; + } + + return true; + +} // connect() + +bool scd_socket::is_connecting() +{ + if ( !is_valid() || !_is_connecting || _is_connected ) + return false; + + return true; + +} // is_connecting() + + +bool scd_socket::is_connected() +{ + if ( !is_valid() || _is_connecting || !_is_connected) + return false; + + return true; + +} // is_connecting() + + +bool scd_socket::connected_event() +{ + if (_is_connected) + return true; + + if ( !is_valid() ) + { + scd_warn("write event occured on an invalid socket"); + return false; + } + else if ( !_is_connecting ) + { + scd_warn("checking connected event while not connecting"); + return false; + } + + // get possible errors from connection attempt + int err, ret; + socklen_t err_size = sizeof(err); + ret = getsockopt(_socket, SOL_SOCKET, SO_ERROR, &err, &err_size); + + if (ret == -1) + { + throw scd_exception("getsockopt()", errno); + } + + // handle errors + switch(err) + { + case 0: + // connection established + _is_connecting = false; + _is_connected = true; + #ifdef TCP_NODELAY + _set_nodelay(); + #endif + return true; + break; + case ECONNABORTED: + case ECONNREFUSED: + case EINTR: + case ENETUNREACH: + case ETIMEDOUT: + // connection attempt failed + _is_connecting = false; + return false; + break; + case EINPROGRESS: + // should not be possible as we received a completion event + throw scd_exception("checking connected event while still connecting"); + break; + case EALREADY: // should be prevented by _is_connecting + default: + throw scd_exception("connect()", errno); + break; + } + + // not reached +} //connected_event() + + +size_t scd_socket::send(const void* buf, size_t len) +{ + ssize_t ret; + + if ( !is_valid() || len == 0 || !_is_connected ) + return 0; + + ret = ::send(_socket, buf, len, MSG_NOSIGNAL); + + if (ret < 0) + { + switch(errno) + { + case ECONNRESET: + case EPIPE: + case ETIMEDOUT: + close(); + break; + case EWOULDBLOCK: + break; + default: + throw scd_exception("send()", errno); + break; + } + return 0; + } + else + return ret; + +} // send() + +size_t scd_socket::recv(void* buf, size_t len) +{ + ssize_t ret; + + if ( !is_valid() || len == 0 || !_is_connected) + return 0; + + ret = ::recv(_socket, buf, len, MSG_NOSIGNAL); + + if (ret < 0) + { + switch(errno) + { + case ETIMEDOUT: + close(); + break; + case EAGAIN: + case EINTR: + break; + case ENOTCONN: + default: + throw scd_exception("recv()", errno); + break; + } + return 0; + } + else if (ret == 0) + { + close(); + return 0; + } + else + return ret; + +} // recv() + +bool scd_socket::_get_sockaddr(sockaddr_in &addr, const std::string &name, + const uint16_t port) const +{ + // flush addr + memset( &addr, 0, sizeof(addr) ); + + /* set content */ + addr.sin_family = AF_INET; + addr.sin_port = htons( port ); + if ( name.empty() ) + { + // bind to all local addresses + addr.sin_addr.s_addr = INADDR_ANY; + } + else + { + // bint to specified address only + struct hostent* he; + + // resolve name + he = gethostbyname2(&name[0], AF_INET); + if (he == NULL) + return false; + + // copy address (network order) + addr.sin_addr.s_addr = + reinterpret_cast(he->h_addr_list[0])->s_addr; + } + + return true; + +} // _get_sockaddr() + + +bool scd_socket::_set_blocking(const bool mode) +{ + if ( !is_valid() ) + { + return false; + } + + int opts = fcntl( _socket, F_GETFL ); + + if ( opts < 0 ) + { + throw scd_exception("fcntl()", errno); + } + + if ( !mode ) + opts = ( opts | O_NONBLOCK ); + else + opts = ( opts & ~O_NONBLOCK ); + + fcntl( _socket, F_SETFL,opts ); + + return true; + +} //_set_blocking() + + +bool scd_socket::_set_nodelay() +{ + if ( !is_valid()) + return false; + + // disable Nagle algorithm + int on = 1; + int ret = setsockopt( _socket, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on) ); + if (ret == -1) + { + throw scd_exception("setsockopt()", errno); + } + + return true; +} diff --git a/dol/src/dol/visitor/hdsd/scd/scd_socket.h b/dol/src/dol/visitor/hdsd/scd/scd_socket.h new file mode 100644 index 0000000..30c2e79 --- /dev/null +++ b/dol/src/dol/visitor/hdsd/scd/scd_socket.h @@ -0,0 +1,168 @@ +#ifndef SCD_SOCKET_H +#define SCD_SOCKET_H + +#include +#include +#include + +const int SCD_MAXCONN = 100; + +// forward declaration for friends +class scd_sock_poller; + +/** + * Berkeley TCP socket API wrapper class. The socket is put into non blocking + * mode. + */ +class scd_socket +{ + friend class scd_sock_poller; + +public: + scd_socket(); + virtual ~scd_socket(); + + /** + * Returns true if this socket has been successfully created and + * has not been closed since then. Use this function to check if an + * error occured. + */ + bool is_valid() const; + + /** + * Creates the socket. + * \return false if the socket is already valid + * \exception scd_exception if unexpected errors occured + */ + bool create(); + + /** + * Closes the socket and marks it as invalid. + */ + void close(); + + /** + * Binds the socket to a local address and port. + * \param loc_name the local IP or hostname or empty string + * \param loc_port the local port or 0 + * \return false if the socket is not valid or an invalid address + * was specified + * \exception scd_exception if ::bind() failed for unexpected reason + */ + bool bind(const std::string &loc_name, const uint16_t loc_port); + + /** + * Binds the socket to a port. + * \param loc_port the local port + * \exception scd_exception if ::bind() failed for unexpected reason + * \return false if the sockat is not valid + */ + bool bind(const uint16_t loc_port); + + /** + * Marks a previously bound socket as listening. + * \return false if the socket is not valid + * \exception scd_exception if ::listen() failed + */ + bool listen(); + + /** + * Accept a new connection from a listening socket. + * \param new_sock the object to hold the new connection + * \return true if a new connection was accepted + * \exception scd_exception if unexpected errors occured + */ + bool accept(scd_socket &new_sock); + + /** + * Initiates a connection attempt to a remote host. Use is_connecting() + * to check whether this attempt is still in progress or is_connected() + * to check whether the socket is connected. If the connection attempt + * is in progress, the socket has to be polled for a write event. + * If this event occures its handler shall call connected_event() + * to check if the connection was established successully. + * It is not possible to try to connect again if the write event + * is not polled and processed by calling connected_event() after + * is_connecting() has indicated that the attempt is still in progress. + * \param rem_name the hostname of the remote host (IP or host name) + * \param rem_port the port to connect to + * \return true if the connection attempt was started successfully, + * false if the hostname could not be resolved or a connection attempt + * was not possible + * \exception scd_exception if unexpected errors occured + */ + bool connect(const std::string &rem_name, const uint16_t rem_port); + + /** + * Indicates if a previous connection attempt is still in progress. + * \return true if a conneciton attempt is still in progress + */ + bool is_connecting(); + + /** + * Indicates if this socket is connected to a peer either while it has + * been accepted from an incoming connection or the outgoing connection + * is established. + * \return true if the socket is valid and connected + */ + bool is_connected(); + + /** + * Check if a connection attempt has succeeded on a write event. Shall + * only be called from the write event handler. Especially after a + * connection attempt was in progress. Can also be called if the + * connection has already been established. + * \return true if the socket is valid and the connection is established + * \exception scd_exception if unexpected errors occured + */ + bool connected_event(); + + /** + * Tries to send at most len data from the buffer. + * Might close the socket on errors. + * \return the number of successfully sent bytes + * \exception scd_exception if unexpected errors occured + */ + size_t send(const void* buf, size_t len); + + /** + * Tries to receive at most len data to the buffer. + * Might close the socket on errors. + * \return the number of successfully received bytes + * \exception scd_exception if unexpected errors occured + */ + size_t recv(void* buf, size_t len); + + +private: + /* member variables */ + + int _socket; + bool _is_connecting; + bool _is_connected; + + /* member functions */ + + /** + * Initializes a sockaddr_in struct. Can resolve hostnames. + */ + bool _get_sockaddr(sockaddr_in &addr, const std::string &name, + const uint16_t port) const; + + /** + * Sets the socket in blocking or non blocking mode. + * \param mode true to set blocking mode + * \return false if the socket is not valid + * \exception scd_exception if unexpected errors occured + */ + bool _set_blocking(const bool mode); + + /** + * Disables the Nagle algorithm which buffers outgoing data up to 200ms + * before sending it. Disabling causes more network traffic but + * decreases the delay. + */ + bool _set_nodelay(); +}; + +#endif diff --git a/dol/src/dol/visitor/package.html b/dol/src/dol/visitor/package.html new file mode 100644 index 0000000..94a87f3 --- /dev/null +++ b/dol/src/dol/visitor/package.html @@ -0,0 +1,20 @@ + + + + + + +Code generator. + +

Package Specification

+ + + +

Related Documentation

+ + + + + + + diff --git a/dol/src/dol/visitor/protothread/ProtothreadMakefileVisitor.java b/dol/src/dol/visitor/protothread/ProtothreadMakefileVisitor.java new file mode 100644 index 0000000..184a928 --- /dev/null +++ b/dol/src/dol/visitor/protothread/ProtothreadMakefileVisitor.java @@ -0,0 +1,63 @@ +/* $Id: ProtothreadMakefileVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.protothread; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; + +import dol.datamodel.pn.ProcessNetwork; +import dol.visitor.PNVisitor; + +/** + * + */ +public class ProtothreadMakefileVisitor extends PNVisitor { + + /** + * + */ + public ProtothreadMakefileVisitor(String dir) { + _dir = dir; + } + + /** + * + */ + public void visitComponent(ProcessNetwork x) { + try { + String filename = _dir + _delimiter + "Makefile"; + OutputStream file = new FileOutputStream(filename); + PrintStream ps = new PrintStream(file); + + ps.println("CXX = g++"); + ps.println("CXXFLAGS = -g -Wall"); + ps.println("COMPILE = ${CXX} ${CXXFLAGS} -c"); + ps.println("LINK = ${CXX}"); + ps.println("LIB_INC = -Ilib -Iwrappers"); + ps.println(); + ps.println("src := $(wildcard lib/*.cpp) " + + "$(wildcard wrappers/*.cpp) $(wildcard *.cpp)"); + ps.println("obj = $(src:.cpp=.o)"); + ps.println(); + ps.println("app : ${obj} ${src}"); + ps.println("\t${LINK} -o " + _name + " $(obj)"); + ps.println(); + ps.println("%.o :"); + ps.println("\t${COMPILE} -o $(*D)/$(*F).o $(*D)/$(*F).cpp " + + "$(LIB_INC)"); + ps.println(); + ps.println("clean :"); + ps.println("\trm ${obj}"); + } + catch (IOException e) { + System.out.println(" Protothread Makefile Visitor: " + + "exception occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + protected String _dir = null; + protected String _name = "sc_application"; +} + diff --git a/dol/src/dol/visitor/protothread/ProtothreadModuleVisitor.java b/dol/src/dol/visitor/protothread/ProtothreadModuleVisitor.java new file mode 100644 index 0000000..897d496 --- /dev/null +++ b/dol/src/dol/visitor/protothread/ProtothreadModuleVisitor.java @@ -0,0 +1,170 @@ +/* $Id: ProtothreadModuleVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.protothread; + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.util.StringTokenizer; +import java.util.Vector; + +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.util.CodePrintStream; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate + * the main program. + */ +public class ProtothreadModuleVisitor extends PNVisitor { + + /** + * Constructor. + */ + public ProtothreadModuleVisitor(String dir) { + _dir = dir; + } + + public void visitComponent(ProcessNetwork x) { + try { + String filename = _dir + _delimiter + "sc_application.cpp"; + OutputStream file = new FileOutputStream(filename); + _code = new CodePrintStream(file); + + _code.printPrefixln("#include \"pt.h\""); + _code.printPrefixln("#include \"Fifo.h\""); + _code.printPrefixln("#include \"WindowedFifo.h\""); + for (String basename : x.getProcessBasenames()) { + _code.printPrefixln("#include \"" + basename + + "Wrapper.h\""); + } + + _code.println(); + _code.printPrefixln("int main(void)"); + _code.printLeftBracket(); + + //instantiate channels + for (Channel c : x.getChannelList()) { + if (c.getType().equals("fifo")) { + _code.printPrefixln("Fifo " + c.getName() + "(" + + c.getSize() * c.getTokenSize() + ");"); + } else if (c.getType().equals("wfifo")) { + _code.printPrefixln("WindowedFifo " + c.getName() + "(" + + c.getSize() * c.getTokenSize() + ");"); + } + } + _code.println(); + + //instantiate processes + for (Process p : x.getProcessList()) { + _code.printPrefix("int " + p.getName() + + "Indices[] = { "); + Vector iteratorIndex = + p.getIteratorIndices(); + if (iteratorIndex.size() < 4) { + while (iteratorIndex.size() < 4) { + iteratorIndex.add(-1); + } + } else if (iteratorIndex.size() > 4) { + new RuntimeException("Error: Currently not more than " + + "4 iterator dimensions are supported." + + "Consider revising " + p.getBasename() + + "."); + } + for (int i = 0; i < 4; i++) { + if (i < 3) { + _code.print(iteratorIndex.elementAt(i) + ", "); + } else { + _code.println(iteratorIndex.elementAt(i) + " };"); + } + } + _code.printPrefixln(p.getBasename() + "Wrapper *" + + p.getName() + " = new " + + p.getBasename() + "Wrapper(\"" + + p.getName() + "\", " + + p.getName() + "Indices);"); + } + _code.println(); + + //connect the network + for (Process p : x.getProcessList()) { + for (Port port : p.getPortList()) { + if (port.getName().equals(port.getBasename())) { + _code.printPrefixln(p.getName() + + "->_port" + port.getName() + "Fifo = &" + + port.getPeerResource().getName() + ";"); + } else { + _code.printPrefix(p.getName() + + "->_port" + port.getBasename() + + "Fifo"); + StringTokenizer tokenizer = + new StringTokenizer(port.getName(). + replaceFirst(port.getBasename(), ""), "_"); + while (tokenizer.hasMoreTokens()) { + _code.print("[" + tokenizer.nextToken() + + "]"); + } + _code.println(" = &" + + port.getPeerResource().getName() + ";"); + } + } + } + _code.println(); + + //initialize processes + for (Process p : x.getProcessList()) { + _code.printPrefixln(p.getName() + "->init();"); + } + _code.println(); + + /* + _code.printPrefix("while("); + int counter = 0; + for (Process p : x.getProcessList()) { + if (counter > 0) { + _code.printPrefix(" "); + } + _code.print("!" + p.getName() + "->isDetached()"); + if (counter++ < x.getProcessList().size() - 1) { + _code.println(" ||"); + } else { + _code.println(")"); + } + } + */ + _code.printPrefixln("bool allBlocked = false;"); + _code.printPrefixln("while(!allBlocked)"); + _code.printLeftBracket(); + _code.printPrefixln("allBlocked = true;"); + for (Process p : x.getProcessList()) { + _code.printPrefixln("if (!" + p.getName() + + "->isDetached()) {"); + //_code.printPrefixln(" " + p.getName() + "->fire();"); + _code.printPrefixln(" if (" + p.getName() + + "->fire() == PT_ENDED) {"); + _code.printPrefixln(" allBlocked = false;"); + _code.printPrefixln(" }"); + _code.printPrefixln("}"); + } + _code.printRightBracket(); + _code.println(); + + for (Process p : x.getProcessList()) { + _code.printPrefixln("delete " + p.getName() + ";"); + } + _code.println(); + _code.printPrefixln("return 0;"); + _code.printRightBracket(); + } + catch (Exception e) { + System.out.println("ProtothreadModuleVisitor: " + + "exception occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + protected CodePrintStream _code = null; + protected String _dir = null; +} + diff --git a/dol/src/dol/visitor/protothread/ProtothreadProcessVisitor.java b/dol/src/dol/visitor/protothread/ProtothreadProcessVisitor.java new file mode 100644 index 0000000..e67ac18 --- /dev/null +++ b/dol/src/dol/visitor/protothread/ProtothreadProcessVisitor.java @@ -0,0 +1,343 @@ +/* $Id: ProtothreadProcessVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.protothread; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.util.StringTokenizer; +import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.SourceCode; +import dol.util.CodePrintStream; +import dol.util.Sed; +import dol.visitor.PNVisitor; + +/** + * + */ +public class ProtothreadProcessVisitor extends PNVisitor { + + /** + * Constructor. + */ + public ProtothreadProcessVisitor(String dir) { + _dir = dir; + } + + /** + * + */ + public void visitComponent(ProcessNetwork x) { + try { + Vector processList = new Vector(); + for (Process p : x.getProcessList()) { + String basename = p.getBasename(); + if (!processList.contains(basename)) { + processList.add(basename); + p.accept(this); + } + } + } catch (Exception e) { + System.out.println("Process Visitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * + */ + public void visitComponent(Process p) { + try { + _createCppFile(p); + _createHeaderFile(p); + _adaptSources(p); + } + catch (Exception e) { + System.out.println("Process Visitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * + */ + private void _createCppFile(Process p) + throws IOException { + String classname = p.getBasename() + "Wrapper"; + String filename = _dir + _delimiter + classname + ".cpp"; + OutputStream file = new FileOutputStream(filename); + CodePrintStream ps = new CodePrintStream(file); + + ps.printPrefixln("#include \"" + classname + ".h\""); + ps.printPrefixln("#include \"dolSupport.h\""); + ps.printPrefixln("#include "); + ps.println(); + for (SourceCode sr : p.getSrcList()) { + ps.printPrefixln("#include \"" + "../processes/" + + sr.getLocality() + "\""); + } + ps.println(); + ps.printPrefixln(classname + "::" + classname + + "(char* name, int iteratorIndex[4]) :"); + ps.printPrefixln(" ProcessWrapper(name, iteratorIndex)"); + ps.printLeftBracket(); + //ps.printPrefixln("_state = new struct _local_states;"); + //ps.printPrefixln("memcpy(_state, " + p.getBasename() + ".local, " + // + "sizeof(struct _local_states));"); + //ps.printPrefixln("memcpy(&_process, &" + p.getBasename() + // + ", sizeof(DOLProcess));"); + ps.printPrefixln("_state = (LocalState)new " + + p.getBasename().substring(0, 1).toUpperCase() + + p.getBasename().substring(1) + "_State;"); + ps.printPrefixln("_process.init = " + p.getBasename() + "_init;"); + ps.printPrefixln("_process.fire = " + p.getBasename() + "_fire;"); + ps.printPrefixln("_process.local = _state;"); + ps.printPrefixln("_process.wptr = (void*)&_wrapper_data;"); + ps.printPrefixln("_wrapper_data.wrapper = this;"); + ps.printRightBracket(); + ps.println(); + ps.printPrefixln(classname + "::~" + classname + "()"); + ps.printLeftBracket(); + ps.printPrefixln("if (_state)"); + ps.printPrefixln(" delete (" + + p.getBasename().substring(0, 1).toUpperCase() + + p.getBasename().substring(1) + "_State*)_state;"); + //ps.printPrefixln(" delete _state;"); + ps.printRightBracket(); + } + + /** + * + */ + private void _createHeaderFile(Process p) + throws IOException { + String classname = p.getBasename() + "Wrapper"; + String filename = _dir + _delimiter + classname + ".h"; + OutputStream file = new FileOutputStream(filename); + CodePrintStream ps = new CodePrintStream(file); + + ps.printPrefixln("#ifndef " + classname.toUpperCase() + + "_H"); + ps.printPrefixln("#define " + classname.toUpperCase() + + "_H"); + ps.println(); + ps.printPrefixln("#include \"ProcessWrapper.h\""); + ps.printPrefixln("#include \"Fifo.h\""); + ps.printPrefixln("#include \"WindowedFifo.h\""); + ps.println(); + ps.printPrefixln("class " + classname + ";"); + ps.println(); + ps.printPrefixln("typedef struct _" + p.getBasename() + + "_data {"); + ps.printPrefixln(" int lc;"); + ps.printPrefixln(" " + classname + " *wrapper;"); + ps.printPrefixln("} " + p.getBasename() + "_data;"); + ps.println(); + ps.printPrefixln("class " + classname + + " : public ProcessWrapper"); + ps.printLeftBracket(); + ps.printPrefixln("public:"); + ps.printPrefixln(" " + classname + "(char* name, " + + "int iteratorIndex[4]);"); + ps.printPrefixln(" virtual ~" + classname + "();"); + ps.println(); + + Vector basenames = new Vector(); + for (Port port : p.getPortList()) { + if (!basenames.contains(port.getBasename())) { + basenames.add(port.getBasename()); + } else { + continue; + } + + Channel c = (Channel)port.getPeerResource(); + if (port.getName().equals(port.getBasename())) { + if (c.getType().equals("fifo")) { + ps.printPrefixln(" Fifo* _port" + port.getName() + + "Fifo;"); + } else if (c.getType().equals("wfifo")) { + ps.printPrefixln(" WindowedFifo* _port" + + port.getName() + "Fifo;"); + } + } else { + if (c.getType().equals("fifo")) { + ps.printPrefix(" Fifo* _port" + + port.getBasename() + + "Fifo"); + } else if (c.getType().equals("wfifo")) { + ps.printPrefix(" WindowedFifo* _port" + + port.getBasename() + + "Fifo"); + } + StringTokenizer tokenizer = + new StringTokenizer(port.getRange(), ";"); + while (tokenizer.hasMoreTokens()) { + ps.print("[" + tokenizer.nextToken() + + "]"); + } + ps.println(";"); + } + } + ps.println(""); + ps.printPrefixln("protected:"); + ps.printPrefixln(" struct _local_states *_state;"); + ps.printPrefixln(" " + p.getBasename() + + "_data _wrapper_data;"); + ps.printRightBracket(); + + ps.printPrefixln(";"); + ps.println(); + ps.printPrefixln("#endif"); + } + + /** + * Make modifications to source files of a process. + * Port names need to be strings for the SystemC code generation. + * Therefore, in the header files integer port names are put into + * quotation marks. + * + * @param p process whose sources should be adapted + * @throws IOException + */ + protected void _adaptSources(Process p) throws IOException { + Sed sed = new Sed(); + //modify header file + for (Port port : p.getPortList()) { + String processHeaderFile; + + for (SourceCode sr : p.getSrcList()) { + processHeaderFile = _dir + _delimiter + ".." + + _delimiter + "processes" + _delimiter + + sr.getLocality(). + replaceAll("(.*)\\.[cC][pP]*[pP]*", "$1\\.h"); + + sed.sed(processHeaderFile, + "(#define[ ]+PORT_\\w*[ ]+)\"?" + + port.getBasename() + "\"?", + "$1 " + "static_cast<" + p.getBasename() + + "Wrapper *>((static_cast<" + p.getBasename() + + "_data *>(p->wptr))->wrapper)->_port" + + port.getBasename() + "Fifo"); + } + } + + //modify source file + for (SourceCode sr : p.getSrcList()) { + String processSourceFile = _dir + _delimiter + ".." + + _delimiter + "processes" + _delimiter + + sr.getLocality(); + + String line; + StringBuffer buffer = new StringBuffer(); + FileInputStream fileInputStream = new FileInputStream( + processSourceFile); + BufferedReader reader = new BufferedReader( + new InputStreamReader(fileInputStream)); + while((line = reader.readLine()) != null) { + buffer.append(line + "\n"); + } + reader.close(); + + String file = buffer.toString(); + //insert PT_BEGIN() at beginning of fire() function + file = file.replaceAll( + "(int[ ]*" + p.getBasename() + + "_fire[ ]*\\([ ]*DOLProcess[ ]*\\*p[ ]*\\)" + + "[\\s\\S&&[^\\{]]*)\\{", + "$1" + System.getProperty("line.separator") + "{" + + System.getProperty("line.separator") + + " PT_BEGIN((pt*)(p->wptr));"); + + //replace last return statement in fire function by PT_END() + //find beginning of fire function + Matcher matcher = Pattern.compile( + "(int[ ]*" + p.getBasename() + + "_fire[ ]*\\([ ]*DOLProcess[ ]*\\*p[ ]*\\)" + + "[\\s\\S&&[^\\{]]*)\\{").matcher(file); + matcher.find(); + int i = 0; + try { + i = matcher.start(); + } catch (Exception e) { + System.out.println("Error: could not find " + + p.getBasename() + "_fire() function in " + + processSourceFile + "."); + e.printStackTrace(); + } + int openBraces = 0; //counter for open curly braces + //position of last return statement + int lastReturnStartPosition = 0; + int lastReturnEndPosition = 0; + while (i < file.length()) { + //ignore single-line comments + if (i < (file.length() - 1) && + file.substring(i, i + 2).equals("//")) { + while (!file.substring(i, i + 1).equals("\n")) { + i++; + } + } + //ignore multi-line comments + else if (i < (file.length() - 1) && + file.substring(i, i + 2).equals("/*")) { + while (!file.substring(i, i + 2).equals("*/")) { + i++; + } + } + //ignore strings + else if (file.substring(i, i + 1).equals("\"")) { + matcher = Pattern.compile("[\\s\\S&&[^\\\\]]\\\""). + matcher(file); + matcher.find(i + 1); + i = matcher.start() + 1; + } + else if (i < (file.length() - 5) && + file.substring(i, i + 6).equals("return")) { + lastReturnStartPosition = i; + while (!file.substring(i, i + 1).equals(";")) { + i++; + } + lastReturnEndPosition = i; + } else if (file.substring(i, i + 1).equals("{")) { + openBraces++; + } else if (file.substring(i, i + 1).equals("}")) { + openBraces--; + if (openBraces == 0) { + break; + } + } + i++; + } + + file = file.substring(0, lastReturnStartPosition) + "/* " + + file.substring(lastReturnStartPosition, + lastReturnEndPosition + 1) + + " (commented out by DOL) */" + + System.getProperty("line.separator") + + " PT_END((pt*)(p->wptr));" + + System.getProperty("line.separator") + + file.substring(lastReturnEndPosition + 2, + file.length()); + + BufferedWriter out = new BufferedWriter(new + FileWriter(processSourceFile)); + out.write(file); + out.close(); + } + } + + protected String _dir = null; + CodePrintStream _wrapperHeader; +} diff --git a/dol/src/dol/visitor/protothread/ProtothreadVisitor.java b/dol/src/dol/visitor/protothread/ProtothreadVisitor.java new file mode 100644 index 0000000..88937a7 --- /dev/null +++ b/dol/src/dol/visitor/protothread/ProtothreadVisitor.java @@ -0,0 +1,96 @@ +/* $Id: ProtothreadVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.protothread; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; + +import dol.datamodel.pn.ProcessNetwork; +import dol.util.Copier; +import dol.visitor.PNVisitor; + +/** + * + */ +public class ProtothreadVisitor extends PNVisitor { + + /** + * Constructor. + */ + public ProtothreadVisitor(String packageName) { + _packageName = packageName; + } + + /** + * + */ + public void visitComponent(ProcessNetwork x) { + try { + _generateDirHierarchy(); + + x.accept(new ProtothreadMakefileVisitor(_srcDir)); + x.accept(new ProtothreadModuleVisitor(_srcDir)); + x.accept(new ProtothreadProcessVisitor(_wrapperDir)); + + } catch (Exception e) { + System.out.println(" SystemC PN Visitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + + } + + /** + * + */ + private void _generateDirHierarchy() + throws IOException, FileNotFoundException { + + File dir = new File(_packageName); + dir.mkdirs(); + + _srcDir = _packageName + _delimiter + _srcDirName; + dir = new File(_srcDir); + dir.mkdirs(); + + _libDir = _srcDir + _delimiter + _libDirName; + dir = new File(_libDir); + dir.mkdirs(); + + _processDir = _srcDir + _delimiter + _processDirName; + dir = new File(_processDir); + dir.mkdirs(); + + _wrapperDir = _srcDir + _delimiter + _wrapperDirName; + dir = new File(_wrapperDir); + dir.mkdirs(); + + // copy library + String libraryPath = _ui.getMySystemCLib(); + libraryPath = libraryPath.replaceAll("systemC", + "protothread"); + File source = new File(libraryPath); + File destination = new File(_libDir); + new Copier().copy(source, destination); + + //copy process src code + source = new File(_srcDirName); + destination = new File(_processDir); + new Copier().copy(source, destination); + } + + protected String _packageName = null; + + protected String _srcDir = ""; + protected static String _srcDirName = "src"; + + protected String _libDir = ""; + protected static String _libDirName = "lib"; + + protected String _processDir = ""; + protected static String _processDirName = "processes"; + + protected String _wrapperDir = ""; + protected static String _wrapperDirName = "wrappers"; +} + diff --git a/dol/src/dol/visitor/protothread/lib/Fifo.cpp b/dol/src/dol/visitor/protothread/lib/Fifo.cpp new file mode 100644 index 0000000..767b784 --- /dev/null +++ b/dol/src/dol/visitor/protothread/lib/Fifo.cpp @@ -0,0 +1,130 @@ +#include "Fifo.h" + +/** + * + */ +Fifo::Fifo(unsigned size = 18) { + //std::cout << "Create Fifo." << std::endl; + _size = size; + _buffer = new char[_size]; + _use = 0; + _tail = 0; +} + +/** + * + */ +Fifo::~Fifo() { + //std::cout << "Delete Fifo." << std::endl; + if (_buffer) { + delete _buffer; + } + _buffer = 0; + _use = 0; + _tail = 0; + //std::cout << "Deleted Fifo." << std::endl; +} + +/** + * + */ +unsigned Fifo::read(void *destination, unsigned len) { + char* buffer = (char*)destination; + unsigned read = (len <= _use ? len : 0); + //std::cout << "Try to read " << len << " bytes from Fifo." << std::endl; + + if (_tail + read <= _size) { + memcpy(buffer, _buffer + _tail, read); + } + else { + memcpy(buffer, _buffer + _tail, _size - _tail); + memcpy(buffer + _size - _tail, _buffer, read - _size + _tail); + } + + _tail = (_tail + read) % _size; + _use -= read; + //std::cout << "Read " << read << " bytes from Fifo." << std::endl; + return read; +} + +/** + * + */ +unsigned Fifo::write(const void *source, unsigned len) { + char* buffer = (char*)source; + unsigned write = (len <= unused() ? len : 0); + unsigned head = (_tail + _use) % _size; + //std::cout << "Try to write " << len << " bytes to Fifo." << std::endl; + + if (head + write <= _size) { + memcpy(_buffer + head, buffer, write); + } + else { + memcpy(_buffer + head, buffer, _size - head); + memcpy(_buffer, buffer + _size - head, write - _size + head); + } + + _use += write; + //std::cout << "Wrote " << write << " bytes to Fifo." << std::endl; + return write; +} + +/** + * + */ +unsigned Fifo::size() const { + return (_size); +} + +/** + * + */ +unsigned Fifo::unused() const { + return (_size) - _use; +} + +/** + * + */ +unsigned Fifo::used() const { + return _use; +} + +/** + * Test the implementation + */ +/* +int main() { + std::cout.width(5); + Fifo *myFifo = new Fifo(); + for (int j = 0; j < 3; j++) { + for (int i = 0; i < 6; i++) { + std::cout << "write " << i << " to Fifo. "; + int write = myFifo->write(&i, sizeof(int)); + printf(" %d ", write); + if (write == sizeof(int)) { + std::cout << "used: " << std::setw(2) << myFifo->used() + << ", unused: " << std::setw(2) << myFifo->unused() + << ", size: " << std::setw(2) << myFifo->size() + << std::endl; + } else { + std::cout << std::endl; + } + } + for (int i = 0; i < 6; i++) { + int value; + int read = myFifo->read(&value, sizeof(int)); + printf(" %d ", read); + if (read == sizeof(int)) { + std::cout << "read " << value << " from Fifo "; + std::cout << "used: " << std::setw(2) << myFifo->used() + << ", unused: " << std::setw(2) << myFifo->unused() + << ", size: " << std::setw(2) << myFifo->size() + << std::endl; + } + } + } + delete myFifo; + return 0; +} +*/ diff --git a/dol/src/dol/visitor/protothread/lib/Fifo.h b/dol/src/dol/visitor/protothread/lib/Fifo.h new file mode 100644 index 0000000..a1929dd --- /dev/null +++ b/dol/src/dol/visitor/protothread/lib/Fifo.h @@ -0,0 +1,25 @@ +#ifndef _FIFO_H_ +#define _FIFO_H_ + +#include +#include + +class Fifo { + public: + Fifo(unsigned size); + virtual ~Fifo(); + + virtual unsigned read(void *destination, unsigned len); + virtual unsigned write(const void *source, unsigned len); + virtual unsigned used() const; + virtual unsigned unused() const; + virtual unsigned size() const; + + protected: + char *_buffer; + unsigned _use; + unsigned _tail; + unsigned _size; +}; + +#endif diff --git a/dol/src/dol/visitor/protothread/lib/ProcessWrapper.cpp b/dol/src/dol/visitor/protothread/lib/ProcessWrapper.cpp new file mode 100644 index 0000000..261f65c --- /dev/null +++ b/dol/src/dol/visitor/protothread/lib/ProcessWrapper.cpp @@ -0,0 +1,68 @@ +#include "ProcessWrapper.h" + +/** + * + */ +ProcessWrapper::ProcessWrapper(char* name, int iteratorIndex[4]) { + //copy name, deliberately avoid using strlen and strcpy for code size + //minimization + int nameLength = 0; + while (name[nameLength] != 0) { + nameLength++; + } + _name = new char[nameLength + 1]; + for (int i = 0; i < nameLength; i++) { + _name[i] = name[i]; + } + + /* + _name = new char[strlen(name) + 1]; + strcpy(_name, name); + */ + + _isDetached = false; + for (int i = 0; i < 4; i++) { + _iteratorIndex[i] = iteratorIndex[i]; + } +} + +/** + * + */ +ProcessWrapper::~ProcessWrapper() { + if (_name) { + delete _name; + } +} + +/** + * + */ +void ProcessWrapper::init() { + _process.init(&_process); +} + +/** + * + */ +int ProcessWrapper::fire() { + return _process.fire(&_process); +} + +/** + * + */ +void ProcessWrapper::detach() { + _isDetached = true; +} + +/** + * Get the index of this process. + * @param indexNumber position of index (starting at 0) + */ +int ProcessWrapper::getIndex(unsigned indexNumber) const { + if (indexNumber < 4) { + return _iteratorIndex[indexNumber]; + } + return -1; +} diff --git a/dol/src/dol/visitor/protothread/lib/ProcessWrapper.h b/dol/src/dol/visitor/protothread/lib/ProcessWrapper.h new file mode 100644 index 0000000..24ef2b2 --- /dev/null +++ b/dol/src/dol/visitor/protothread/lib/ProcessWrapper.h @@ -0,0 +1,25 @@ +#ifndef _PROCESSWRAPPER_H_ +#define _PROCESSWRAPPER_H_ + +#include + +class ProcessWrapper +{ + public: + ProcessWrapper(char* name, int iteratorIndex[4]); + virtual ~ProcessWrapper(); + + virtual void init(); + virtual int fire(); + virtual bool isDetached() { return _isDetached; } + virtual void detach(); + virtual int getIndex(unsigned indexNumber) const; + + protected: + char* _name;; + DOLProcess _process; + bool _isDetached; + int _iteratorIndex[4]; +}; + +#endif diff --git a/dol/src/dol/visitor/protothread/lib/WindowedFifo.cpp b/dol/src/dol/visitor/protothread/lib/WindowedFifo.cpp new file mode 100644 index 0000000..743fc0b --- /dev/null +++ b/dol/src/dol/visitor/protothread/lib/WindowedFifo.cpp @@ -0,0 +1,203 @@ +#include "WindowedFifo.h" + +/** + * + */ +WindowedFifo::WindowedFifo(unsigned size = 20) { + //std::cout << "Create WindowedFifo." << std::endl; + _size = size; + _buffer = new char[_size]; + _head = 0; + _tail = 0; + _headRoom = 0; + _tailRoom = 0; + _use = 0; + //indicates whether Fifo is empty or full if _head == _tail + //_isFull = false; + _isHeadReserved = false; + _isTailReserved = false; +} + +/** + * + */ +WindowedFifo::~WindowedFifo() { + //std::cout << "Delete WindowedFifo." << std::endl; + if (_buffer) { + delete _buffer; + } + _buffer = 0; + _head = 0; + _tail = 0; + _use = 0; + //std::cout << "Deleted WindowedFifo." << std::endl; +} + +/** + * + */ +unsigned WindowedFifo::reserve(void** dest, unsigned len) { + char** destination = (char**)dest; + //std::cout << "Attempt to reserve " << len << " bytes." << std::endl; + + //can only reserve once piece at a time + if (_isHeadReserved) { + *destination = 0; + return 0; + } + + //reserve at most as much memory as still available in the buffer + unsigned write = (len <= _size - _use ? len : _size - _use); + + if (write > 0) { + //if wrap-around in buffer: return only buffer for the + //contiguous buffer space + if (_head + write > _size) { + write = _size - _head; + } + + _headRoom = (_head + write) == _size? 0 : _head + write; + *destination = &(_buffer[_head]); + _isHeadReserved = true; + } + + //std::cout << "Reserved " << write << " bytes." << std::endl; + _writeReserve = write; + return write; +} + +/** + * + */ +void WindowedFifo::release() { + if (_isHeadReserved) { + //std::cout << "Released " << _headRoom - _head << " bytes." << std::endl; + _head = _headRoom; + _use += _writeReserve; + _isHeadReserved = false; + } +} + +/** + * + */ +unsigned WindowedFifo::capture(void **dest, unsigned len) { + char** destination = (char**)dest; + //std::cout << "Attempt to capture " << len << " bytes." << std::endl; + + if (_isTailReserved) { + //std::cout << "Only one attempt to capture allowed." << std::endl; + *destination = 0; + return 0; + } + + //capture at most as much data as available in the buffer + unsigned read = (len <= _use ? len : _use); + + if (read > 0) { + //if wrap-around in buffer: return only buffer for the + //conntiguous buffer space + if (_tail + read> _size) { + read = _size - _tail; + } + + _tailRoom = (_tail + read) == _size ? 0 : _tailRoom = _tail + read; + *destination = &(_buffer[_tail]); + _isTailReserved = true; + } + + //std::cout << "Captured " << read << " bytes." << std::endl; + + _readReserve = read; + return read; +} + +/** + * + */ +void WindowedFifo::consume() { + if (_isTailReserved) { + //std::cout << "Consumed " << _tailRoom - _tail << " bytes." << std::endl; + _tail = _tailRoom; + _use -= _readReserve; + _isTailReserved = false; + } +} + +/** + * + */ +unsigned WindowedFifo::size() const { + return _size; +} + +/** + * + */ +unsigned WindowedFifo::unused() const { + return _size - _use; +} + +/** + * + */ +unsigned WindowedFifo::used() const { + return _use; +} + +/** + * Test the implementation + */ +/* +#include +#include +using namespace std; + +int main() { + WindowedFifo *myFifo = new WindowedFifo(16); + + int* buf1; + int* buf2; + int x = myFifo->reserve((void**)&buf1, 8); + *buf1 = 10; + *(buf1 + 1) = 20; + myFifo->release(); + int y = myFifo->capture((void**)&buf2, 8); + std::cout << "read " << *buf2 << " " << *(buf2 + 1) << std::endl; + myFifo->consume(); + + for (int j = 0; j < 3; j++) { + for (int i = 0; i < 6; i++) { + std::cout << "write " << i << " to Fifo. "; + int write = myFifo->reserve((void**)&buf1, sizeof(int)); + if (write == sizeof(int)) { + *buf1 = i; + myFifo->release(); + std::cout << "used: " << std::setw(2) << myFifo->used() + << ", unused: " << std::setw(2) << myFifo->unused() + << ", size: " << std::setw(2) << myFifo->size() + << std::endl; + } else { + std::cout << std::endl; + } + } + for (int i = 0; i < 16; i++) { + char* buf3; + int read = myFifo->capture((void**)&buf3, sizeof(char)); + if (read == sizeof(char)) { + std::cout << "read " << (unsigned)*buf3 << " from Fifo "; + std::cout << "used: " << std::setw(2) << myFifo->used() + << ", unused: " << std::setw(2) << myFifo->unused() + << ", size: " << std::setw(2) << myFifo->size() + << std::endl; + myFifo->consume(); + } else { + std::cout << "read nothing from Fifo." << std::endl; + } + + } + } + delete myFifo; + return 0; +} +*/ diff --git a/dol/src/dol/visitor/protothread/lib/WindowedFifo.h b/dol/src/dol/visitor/protothread/lib/WindowedFifo.h new file mode 100644 index 0000000..2803558 --- /dev/null +++ b/dol/src/dol/visitor/protothread/lib/WindowedFifo.h @@ -0,0 +1,32 @@ +#ifndef _WINDOWEDFIFO_H_ +#define _WINDOWEDFIFO_H_ + +class WindowedFifo { + public: + WindowedFifo(unsigned size); + virtual ~WindowedFifo(); + + virtual unsigned reserve(void** destination, unsigned len); + virtual void release(); + + virtual unsigned capture(void** destination, unsigned len); + virtual void consume(); + + virtual unsigned used() const; + virtual unsigned unused() const; + virtual unsigned size() const; + protected: + char *_buffer; + unsigned _head; + unsigned _tail; + unsigned _headRoom; + unsigned _tailRoom; + unsigned _size; + unsigned _use; + unsigned _writeReserve; + unsigned _readReserve; + bool _isHeadReserved; + bool _isTailReserved; +}; + +#endif diff --git a/dol/src/dol/visitor/protothread/lib/dol.h b/dol/src/dol/visitor/protothread/lib/dol.h new file mode 100644 index 0000000..8fbefe4 --- /dev/null +++ b/dol/src/dol/visitor/protothread/lib/dol.h @@ -0,0 +1,39 @@ +#ifndef DOL_H +#define DOL_H + +/************************************************************************ + * do not add code to this header + ************************************************************************/ + +/** + * Define the DOL process handler scheme. + * - Local variables are defined in structure LocalState. Local + * variables may vary from different processes. + * - The ProcessInit function pointer points to a function which + * initializes a process. + * - The ProcessFire function pointer points to a function which + * performs the actual computation. The communication between + * processes is inside the ProcessFire function. + * - The WPTR is a placeholder for callback. One can just + * leave it blank. + */ + +//structure for local memory of process +typedef struct _local_states *LocalState; + +//additional behavioral functions could be declared here +typedef void (*ProcessInit)(struct _process*); +typedef int (*ProcessFire)(struct _process*); +typedef void *WPTR; + +//process handler +struct _process; + +typedef struct _process { + LocalState local; + ProcessInit init; + ProcessFire fire; + WPTR wptr; //placeholder for wrapper instance +} DOLProcess; + +#endif diff --git a/dol/src/dol/visitor/protothread/lib/dolSupport.cpp b/dol/src/dol/visitor/protothread/lib/dolSupport.cpp new file mode 100644 index 0000000..0c73f6d --- /dev/null +++ b/dol/src/dol/visitor/protothread/lib/dolSupport.cpp @@ -0,0 +1,89 @@ +#include "dolSupport.h" + +/** + * + */ +unsigned read(void* fifo, void* buf, unsigned len, DOLProcess* p) { + return ((Fifo*)fifo)->read(buf, len); +} + +/** + * + */ +unsigned write(void* fifo, void* buf, unsigned len, DOLProcess* p) { + return ((Fifo*)fifo)->write(buf, len); +} + +/** + * + */ +unsigned reserve(void* fifo, void** destination, unsigned len, DOLProcess* p) { + return ((WindowedFifo*)fifo)->reserve(destination, len); +} + +/** + * + */ +void release(void* fifo, DOLProcess* p) { + ((WindowedFifo*)fifo)->release(); +} + +/** + * + */ +unsigned capture(void* fifo, void** destination, unsigned len, DOLProcess* p) { + return ((WindowedFifo*)fifo)->capture(destination, len); +} + +/** + * + */ +void consume(void* fifo, DOLProcess* p) { + ((WindowedFifo*)fifo)->consume(); +} + +/** + * + */ +void DOL_detach(DOLProcess* p) { + static_cast((static_cast(p->wptr))->wrapper)->detach(); +} + + +void createPort(void** port, + void* base, + int number_of_indices, + int index0, int range0) { + *port = (void**)((void**)base)[index0]; +} + +void createPort(void** port, + void* base, + int number_of_indices, + int index0, int range0, + int index1, int range1) { + *port = (void**)((void**)base)[index0 * range1 + index1]; +} + +void createPort(void** port, + void* base, + int number_of_indices, + int index0, int range0, + int index1, int range1, + int index2, int range2) { + *port = (void**)((void**)base)[index0 * range1 * range2 + + index1 * range2 + index2]; +} + +void createPort(void** port, + void* base, + int number_of_indices, + int index0, int range0, + int index1, int range1, + int index2, int range2, + int index3, int range3) { + *port = (void**)((void**)base)[index0 * range1 * range2 * range3 + + index1 * range2 * range3 + + index2 * range3 + + index3]; +} diff --git a/dol/src/dol/visitor/protothread/lib/dolSupport.h b/dol/src/dol/visitor/protothread/lib/dolSupport.h new file mode 100644 index 0000000..f07a804 --- /dev/null +++ b/dol/src/dol/visitor/protothread/lib/dolSupport.h @@ -0,0 +1,76 @@ +#ifndef DOLSUPPORT_H +#define DOLSUPPORT_H + +#include "dol.h" +#include "ProcessWrapper.h" +#include "Fifo.h" +#include "WindowedFifo.h" +#include "pt.h" + +typedef struct _process_data { + int lc; + ProcessWrapper *wrapper; +} process_data; + + +#define DOL_read(port, buf, size, process) \ + PT_WAIT_UNTIL((pt*)(p->wptr), read(port, buf, size, process) == size); + +#define DOL_write(port, buf, size, process) \ + PT_WAIT_UNTIL((pt*)(p->wptr), write(port, buf, size, process) == size); + +#define DOL_reserve(port, buf, size, process) \ + PT_WAIT_UNTIL((pt*)(p->wptr), reserve(port, (void**)buf, size, process) == size); + +#define DOL_release(port, process) \ + release(port, process); + +#define DOL_capture(port, buf, size, process) \ + PT_WAIT_UNTIL((pt*)(p->wptr), capture(port, (void**)buf, size, process) == size); + +#define DOL_consume(port, process) \ + consume(port, process); + +void DOL_detach(DOLProcess* p); + +//macros to deal with iterated ports +/** + * macro to create a variable to store a port name + * + * @param name name of the variable + */ +#define CREATEPORTVAR(name) static Fifo *name + +/** + * Create the port name of an iterated port based on its basename and the + * given indices. + * + * @param port buffer where the result is stored (created using + * CREATEPORTVAR) + * @param base basename of the port + * @param number_of_indices number of dimensions of the port + * @param index_range_pairs index and range values for each dimension + */ + +#define CREATEPORT(port, base, number_of_indices, index_range_pairs...) \ + createPort((void**)(&port), base, number_of_indices, index_range_pairs) + +#define GETINDEX(dimension) \ + static_cast((static_cast(p->wptr))->wrapper)->getIndex(dimension) + +void createPort(void** port, void* base, int number_of_indices, int index0, int range0); +void createPort(void** port, void* base, int number_of_indices, int index0, int range0, int index1, int range1); +void createPort(void** port, void* base, int number_of_indices, int index0, int range0, int index1, int range1, int index2, int range2); +void createPort(void** port, void* base, int number_of_indices, int index0, int range0, int index1, int range1, int index2, int range2, int index3, int range3); + +//fifo access functions +unsigned write(void* fifo, void* buf, unsigned len, DOLProcess* p); +unsigned read(void* fifo, void* buf, unsigned len, DOLProcess* p); + +//windowed fifo access functions +unsigned reserve(void* fifo, void** destination, unsigned len, DOLProcess* p); +void release(void* fifo, DOLProcess* p); +unsigned capture(void* fifo, void** destination, unsigned len, DOLProcess* p); +void consume(void* fifo, DOLProcess* p); + +#endif diff --git a/dol/src/dol/visitor/protothread/lib/lc-addrlabels.h b/dol/src/dol/visitor/protothread/lib/lc-addrlabels.h new file mode 100644 index 0000000..b75f4e7 --- /dev/null +++ b/dol/src/dol/visitor/protothread/lib/lc-addrlabels.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2004-2005, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * Author: Adam Dunkels + * + * $Id: lc-addrlabels.h 1 2010-02-24 13:03:05Z haidw $ + */ + +/** + * \addtogroup lc + * @{ + */ + +/** + * \file + * Implementation of local continuations based on the "Labels as + * values" feature of gcc + * \author + * Adam Dunkels + * + * This implementation of local continuations is based on a special + * feature of the GCC C compiler called "labels as values". This + * feature allows assigning pointers with the address of the code + * corresponding to a particular C label. + * + * For more information, see the GCC documentation: + * http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html + * + */ + +#ifndef __LC_ADDRLABELS_H__ +#define __LC_ADDRLABELS_H__ + +/** \hideinitializer */ +typedef void * lc_t; + +#define LC_INIT(s) s = NULL + +#define LC_RESUME(s) \ + do { \ + if(s != NULL) { \ + goto *s; \ + } \ + } while(0) + +#define LC_CONCAT2(s1, s2) s1##s2 +#define LC_CONCAT(s1, s2) LC_CONCAT2(s1, s2) + +#define LC_SET(s) \ + do { \ + LC_CONCAT(LC_LABEL, __LINE__): \ + (s) = &&LC_CONCAT(LC_LABEL, __LINE__); \ + } while(0) + +#define LC_END(s) + +#endif /* __LC_ADDRLABELS_H__ */ +/** @} */ diff --git a/dol/src/dol/visitor/protothread/lib/lc-switch.h b/dol/src/dol/visitor/protothread/lib/lc-switch.h new file mode 100644 index 0000000..e47085c --- /dev/null +++ b/dol/src/dol/visitor/protothread/lib/lc-switch.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2004-2005, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * Author: Adam Dunkels + * + * $Id: lc-switch.h 1 2010-02-24 13:03:05Z haidw $ + */ + +/** + * \addtogroup lc + * @{ + */ + +/** + * \file + * Implementation of local continuations based on switch() statment + * \author Adam Dunkels + * + * This implementation of local continuations uses the C switch() + * statement to resume execution of a function somewhere inside the + * function's body. The implementation is based on the fact that + * switch() statements are able to jump directly into the bodies of + * control structures such as if() or while() statmenets. + * + * This implementation borrows heavily from Simon Tatham's coroutines + * implementation in C: + * http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html + */ + +#ifndef __LC_SWITCH_H__ +#define __LC_SWITCH_H__ + +/* WARNING! lc implementation using switch() does not work if an + LC_SET() is done within another switch() statement! */ + +/** \hideinitializer */ +typedef unsigned short lc_t; + +#define LC_INIT(s) s = 0; + +#define LC_RESUME(s) switch(s) { case 0: + +#define LC_SET(s) s = __LINE__; case __LINE__: + +#define LC_END(s) } + +#endif /* __LC_SWITCH_H__ */ + +/** @} */ diff --git a/dol/src/dol/visitor/protothread/lib/lc.h b/dol/src/dol/visitor/protothread/lib/lc.h new file mode 100644 index 0000000..9ef2f0f --- /dev/null +++ b/dol/src/dol/visitor/protothread/lib/lc.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2004-2005, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the protothreads library. + * + * Author: Adam Dunkels + * + * $Id: lc.h 1 2010-02-24 13:03:05Z haidw $ + */ + +/** + * \addtogroup pt + * @{ + */ + +/** + * \defgroup lc Local continuations + * @{ + * + * Local continuations form the basis for implementing protothreads. A + * local continuation can be set in a specific function to + * capture the state of the function. After a local continuation has + * been set can be resumed in order to restore the state of the + * function at the point where the local continuation was set. + * + * + */ + +/** + * \file lc.h + * Local continuations + * \author + * Adam Dunkels + * + */ + +#ifdef DOXYGEN +/** + * Initialize a local continuation. + * + * This operation initializes the local continuation, thereby + * unsetting any previously set continuation state. + * + * \hideinitializer + */ +#define LC_INIT(lc) + +/** + * Set a local continuation. + * + * The set operation saves the state of the function at the point + * where the operation is executed. As far as the set operation is + * concerned, the state of the function does not include the + * call-stack or local (automatic) variables, but only the program + * counter and such CPU registers that needs to be saved. + * + * \hideinitializer + */ +#define LC_SET(lc) + +/** + * Resume a local continuation. + * + * The resume operation resumes a previously set local continuation, thus + * restoring the state in which the function was when the local + * continuation was set. If the local continuation has not been + * previously set, the resume operation does nothing. + * + * \hideinitializer + */ +#define LC_RESUME(lc) + +/** + * Mark the end of local continuation usage. + * + * The end operation signifies that local continuations should not be + * used any more in the function. This operation is not needed for + * most implementations of local continuation, but is required by a + * few implementations. + * + * \hideinitializer + */ +#define LC_END(lc) + +/** + * \var typedef lc_t; + * + * The local continuation type. + * + * \hideinitializer + */ +#endif /* DOXYGEN */ + +#ifndef __LC_H__ +#define __LC_H__ + + +#ifdef LC_INCLUDE +#include LC_INCLUDE +#else +#include "lc-switch.h" +#endif /* LC_INCLUDE */ + +#endif /* __LC_H__ */ + +/** @} */ +/** @} */ diff --git a/dol/src/dol/visitor/protothread/lib/pt-sem.h b/dol/src/dol/visitor/protothread/lib/pt-sem.h new file mode 100644 index 0000000..a6e1428 --- /dev/null +++ b/dol/src/dol/visitor/protothread/lib/pt-sem.h @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the protothreads library. + * + * Author: Adam Dunkels + * + * $Id: pt-sem.h 1 2010-02-24 13:03:05Z haidw $ + */ + +/** + * \addtogroup pt + * @{ + */ + +/** + * \defgroup ptsem Protothread semaphores + * @{ + * + * This module implements counting semaphores on top of + * protothreads. Semaphores are a synchronization primitive that + * provide two operations: "wait" and "signal". The "wait" operation + * checks the semaphore counter and blocks the thread if the counter + * is zero. The "signal" operation increases the semaphore counter but + * does not block. If another thread has blocked waiting for the + * semaphore that is signalled, the blocked thread will become + * runnable again. + * + * Semaphores can be used to implement other, more structured, + * synchronization primitives such as monitors and message + * queues/bounded buffers (see below). + * + * The following example shows how the producer-consumer problem, also + * known as the bounded buffer problem, can be solved using + * protothreads and semaphores. Notes on the program follow after the + * example. + * + \code +#include "pt-sem.h" + +#define NUM_ITEMS 32 +#define BUFSIZE 8 + +static struct pt_sem mutex, full, empty; + +PT_THREAD(producer(struct pt *pt)) +{ + static int produced; + + PT_BEGIN(pt); + + for(produced = 0; produced < NUM_ITEMS; ++produced) { + + PT_SEM_WAIT(pt, &full); + + PT_SEM_WAIT(pt, &mutex); + add_to_buffer(produce_item()); + PT_SEM_SIGNAL(pt, &mutex); + + PT_SEM_SIGNAL(pt, &empty); + } + + PT_END(pt); +} + +PT_THREAD(consumer(struct pt *pt)) +{ + static int consumed; + + PT_BEGIN(pt); + + for(consumed = 0; consumed < NUM_ITEMS; ++consumed) { + + PT_SEM_WAIT(pt, &empty); + + PT_SEM_WAIT(pt, &mutex); + consume_item(get_from_buffer()); + PT_SEM_SIGNAL(pt, &mutex); + + PT_SEM_SIGNAL(pt, &full); + } + + PT_END(pt); +} + +PT_THREAD(driver_thread(struct pt *pt)) +{ + static struct pt pt_producer, pt_consumer; + + PT_BEGIN(pt); + + PT_SEM_INIT(&empty, 0); + PT_SEM_INIT(&full, BUFSIZE); + PT_SEM_INIT(&mutex, 1); + + PT_INIT(&pt_producer); + PT_INIT(&pt_consumer); + + PT_WAIT_THREAD(pt, producer(&pt_producer) & + consumer(&pt_consumer)); + + PT_END(pt); +} + \endcode + * + * The program uses three protothreads: one protothread that + * implements the consumer, one thread that implements the producer, + * and one protothread that drives the two other protothreads. The + * program uses three semaphores: "full", "empty" and "mutex". The + * "mutex" semaphore is used to provide mutual exclusion for the + * buffer, the "empty" semaphore is used to block the consumer is the + * buffer is empty, and the "full" semaphore is used to block the + * producer is the buffer is full. + * + * The "driver_thread" holds two protothread state variables, + * "pt_producer" and "pt_consumer". It is important to note that both + * these variables are declared as static. If the static + * keyword is not used, both variables are stored on the stack. Since + * protothreads do not store the stack, these variables may be + * overwritten during a protothread wait operation. Similarly, both + * the "consumer" and "producer" protothreads declare their local + * variables as static, to avoid them being stored on the stack. + * + * + */ + +/** + * \file + * Couting semaphores implemented on protothreads + * \author + * Adam Dunkels + * + */ + +#ifndef __PT_SEM_H__ +#define __PT_SEM_H__ + +#include "pt.h" + +struct pt_sem { + unsigned int count; +}; + +/** + * Initialize a semaphore + * + * This macro initializes a semaphore with a value for the + * counter. Internally, the semaphores use an "unsigned int" to + * represent the counter, and therefore the "count" argument should be + * within range of an unsigned int. + * + * \param s (struct pt_sem *) A pointer to the pt_sem struct + * representing the semaphore + * + * \param c (unsigned int) The initial count of the semaphore. + * \hideinitializer + */ +#define PT_SEM_INIT(s, c) (s)->count = c + +/** + * Wait for a semaphore + * + * This macro carries out the "wait" operation on the semaphore. The + * wait operation causes the protothread to block while the counter is + * zero. When the counter reaches a value larger than zero, the + * protothread will continue. + * + * \param pt (struct pt *) A pointer to the protothread (struct pt) in + * which the operation is executed. + * + * \param s (struct pt_sem *) A pointer to the pt_sem struct + * representing the semaphore + * + * \hideinitializer + */ +#define PT_SEM_WAIT(pt, s) \ + do { \ + PT_WAIT_UNTIL(pt, (s)->count > 0); \ + --(s)->count; \ + } while(0) + +/** + * Signal a semaphore + * + * This macro carries out the "signal" operation on the semaphore. The + * signal operation increments the counter inside the semaphore, which + * eventually will cause waiting protothreads to continue executing. + * + * \param pt (struct pt *) A pointer to the protothread (struct pt) in + * which the operation is executed. + * + * \param s (struct pt_sem *) A pointer to the pt_sem struct + * representing the semaphore + * + * \hideinitializer + */ +#define PT_SEM_SIGNAL(pt, s) ++(s)->count + +#endif /* __PT_SEM_H__ */ + +/** @} */ +/** @} */ + diff --git a/dol/src/dol/visitor/protothread/lib/pt.h b/dol/src/dol/visitor/protothread/lib/pt.h new file mode 100644 index 0000000..a7d3829 --- /dev/null +++ b/dol/src/dol/visitor/protothread/lib/pt.h @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2004-2005, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * Author: Adam Dunkels + * + * $Id: pt.h 1 2010-02-24 13:03:05Z haidw $ + */ + +/** + * \addtogroup pt + * @{ + */ + +/** + * \file + * Protothreads implementation. + * \author + * Adam Dunkels + * + */ + +#ifndef __PT_H__ +#define __PT_H__ + +#include "lc.h" + +typedef struct _pt { + lc_t lc; +} pt; + +#define PT_WAITING 0 +#define PT_YIELDED 1 +#define PT_EXITED 2 +#define PT_ENDED 3 + +/** + * \name Initialization + * @{ + */ + +/** + * Initialize a protothread. + * + * Initializes a protothread. Initialization must be done prior to + * starting to execute the protothread. + * + * \param pt A pointer to the protothread control structure. + * + * \sa PT_SPAWN() + * + * \hideinitializer + */ +#define PT_INIT(pt) LC_INIT((pt)->lc) + +/** @} */ + +/** + * \name Declaration and definition + * @{ + */ + +/** + * Declaration of a protothread. + * + * This macro is used to declare a protothread. All protothreads must + * be declared with this macro. + * + * \param name_args The name and arguments of the C function + * implementing the protothread. + * + * \hideinitializer + */ +#define PT_THREAD(name_args) char name_args + +/** + * Declare the start of a protothread inside the C function + * implementing the protothread. + * + * This macro is used to declare the starting point of a + * protothread. It should be placed at the start of the function in + * which the protothread runs. All C statements above the PT_BEGIN() + * invokation will be executed each time the protothread is scheduled. + * + * \param pt A pointer to the protothread control structure. + * + * \hideinitializer + */ +#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; LC_RESUME((pt)->lc) + +/** + * Declare the end of a protothread. + * + * This macro is used for declaring that a protothread ends. It must + * always be used together with a matching PT_BEGIN() macro. + * + * \param pt A pointer to the protothread control structure. + * + * \hideinitializer + */ +#define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \ + PT_INIT(pt); return PT_ENDED; } + +/** @} */ + +/** + * \name Blocked wait + * @{ + */ + +/** + * Block and wait until condition is true. + * + * This macro blocks the protothread until the specified condition is + * true. + * + * \param pt A pointer to the protothread control structure. + * \param condition The condition. + * + * \hideinitializer + */ +#define PT_WAIT_UNTIL(pt, condition) \ + do { \ + LC_SET((pt)->lc); \ + if(!(condition)) { \ + return PT_WAITING; \ + } \ + } while(0) + +/** + * Block and wait while condition is true. + * + * This function blocks and waits while condition is true. See + * PT_WAIT_UNTIL(). + * + * \param pt A pointer to the protothread control structure. + * \param cond The condition. + * + * \hideinitializer + */ +#define PT_WAIT_WHILE(pt, cond) PT_WAIT_UNTIL((pt), !(cond)) + +/** @} */ + +/** + * \name Hierarchical protothreads + * @{ + */ + +/** + * Block and wait until a child protothread completes. + * + * This macro schedules a child protothread. The current protothread + * will block until the child protothread completes. + * + * \note The child protothread must be manually initialized with the + * PT_INIT() function before this function is used. + * + * \param pt A pointer to the protothread control structure. + * \param thread The child protothread with arguments + * + * \sa PT_SPAWN() + * + * \hideinitializer + */ +#define PT_WAIT_THREAD(pt, thread) PT_WAIT_WHILE((pt), PT_SCHEDULE(thread)) + +/** + * Spawn a child protothread and wait until it exits. + * + * This macro spawns a child protothread and waits until it exits. The + * macro can only be used within a protothread. + * + * \param pt A pointer to the protothread control structure. + * \param child A pointer to the child protothread's control structure. + * \param thread The child protothread with arguments + * + * \hideinitializer + */ +#define PT_SPAWN(pt, child, thread) \ + do { \ + PT_INIT((child)); \ + PT_WAIT_THREAD((pt), (thread)); \ + } while(0) + +/** @} */ + +/** + * \name Exiting and restarting + * @{ + */ + +/** + * Restart the protothread. + * + * This macro will block and cause the running protothread to restart + * its execution at the place of the PT_BEGIN() call. + * + * \param pt A pointer to the protothread control structure. + * + * \hideinitializer + */ +#define PT_RESTART(pt) \ + do { \ + PT_INIT(pt); \ + return PT_WAITING; \ + } while(0) + +/** + * Exit the protothread. + * + * This macro causes the protothread to exit. If the protothread was + * spawned by another protothread, the parent protothread will become + * unblocked and can continue to run. + * + * \param pt A pointer to the protothread control structure. + * + * \hideinitializer + */ +#define PT_EXIT(pt) \ + do { \ + PT_INIT(pt); \ + return PT_EXITED; \ + } while(0) + +/** @} */ + +/** + * \name Calling a protothread + * @{ + */ + +/** + * Schedule a protothread. + * + * This function shedules a protothread. The return value of the + * function is non-zero if the protothread is running or zero if the + * protothread has exited. + * + * \param f The call to the C function implementing the protothread to + * be scheduled + * + * \hideinitializer + */ +#define PT_SCHEDULE(f) ((f) < PT_EXITED) + +/** @} */ + +/** + * \name Yielding from a protothread + * @{ + */ + +/** + * Yield from the current protothread. + * + * This function will yield the protothread, thereby allowing other + * processing to take place in the system. + * + * \param pt A pointer to the protothread control structure. + * + * \hideinitializer + */ +#define PT_YIELD(pt) \ + do { \ + PT_YIELD_FLAG = 0; \ + LC_SET((pt)->lc); \ + if(PT_YIELD_FLAG == 0) { \ + return PT_YIELDED; \ + } \ + } while(0) + +/** + * \brief Yield from the protothread until a condition occurs. + * \param pt A pointer to the protothread control structure. + * \param cond The condition. + * + * This function will yield the protothread, until the + * specified condition evaluates to true. + * + * + * \hideinitializer + */ +#define PT_YIELD_UNTIL(pt, cond) \ + do { \ + PT_YIELD_FLAG = 0; \ + LC_SET((pt)->lc); \ + if((PT_YIELD_FLAG == 0) || !(cond)) { \ + return PT_YIELDED; \ + } \ + } while(0) + +/** @} */ + +#endif /* __PT_H__ */ + +/** @} */ diff --git a/dol/src/dol/visitor/rtems/RtemsMakefileVisitor.java b/dol/src/dol/visitor/rtems/RtemsMakefileVisitor.java new file mode 100644 index 0000000..04c617e --- /dev/null +++ b/dol/src/dol/visitor/rtems/RtemsMakefileVisitor.java @@ -0,0 +1,296 @@ +/* $Id: RtemsMakefileVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.rtems; + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.Vector; + +import dol.datamodel.architecture.Architecture; +import dol.datamodel.mapping.Mapping; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.Configuration; +import dol.main.UserInterface; +import dol.parser.xml.archischema.ArchiXmlParser; +import dol.parser.xml.mapschema.MapXmlParser; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate + * a RTEMS package Makefile. + */ +public class RtemsMakefileVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir path of the Makefile + */ + public RtemsMakefileVisitor(String dir) { + _dir = dir; + } + + /** + * Create a Makefile for the given process network. + * + * @param pn process network + */ + public void visitComponent(ProcessNetwork pn) { + try { + String filename = _dir + _delimiter + "Makefile"; + OutputStream file = new FileOutputStream(filename); + PrintStream ps = new PrintStream(file); + + _ui = UserInterface.getInstance(); + if (_ui.getRtemsBSP().equals("pc386")) { + ps.println(getPc386Makefile(pn)); + } else if (_ui.getRtemsBSP().equals("mparm")) { + ps.println(getMparmMakefile(pn)); + } + } catch (Exception e) { + System.out.println("RtemsMakefileVisitor: exception occured: " + + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * Create a makefile for the pc386 board support package. + * + * @param pn process network + * @return makefile for pc386 board support package + */ + protected String getMparmMakefile(ProcessNetwork pn) { + String makefile = ""; + String newline = System.getProperty("line.separator"); + makefile += "ifndef SWARMDIR" + newline; + makefile += " $(error Fatal error: Undefined SWARMDIR " + + "environment variable!)" + newline; + makefile += "endif" + newline; + makefile += "" + newline; + makefile += "ifndef RTEMS_MAKEFILE_PATH" + newline; + makefile += " $(error Fatal error: Undefined " + + "RTEMS_MAKEFILE_PATH environment variable!)" + newline; + makefile += "endif" + newline; + makefile += "" + newline; + makefile += "ifdef EXENAME" + newline; + makefile += " EXEC=$(EXENAME).exe" + newline; + makefile += "else" + newline; + makefile += " EXEC=app.exe" + newline; + makefile += "endif" + newline; + makefile += "" + newline; + makefile += "PGM=${ARCH}/$(EXEC)" + newline; + makefile += "" + newline; + makefile += "# optional managers required" + newline; + makefile += "MANAGERS=io mp msg signal event region partition"; + makefile += newline + newline; + + if (_ui.getRtemsBSP().equals("mparm")) { + makefile += "# scratchpad queue lib" + newline; + makefile += "QUEUELIB=que_lib/lib" + newline; + makefile += "SS_SEMAPHORE_LIB_PATH = " + + "${QUEUELIB}/ss_semaphore_lib" + newline; + makefile +="SCRATCH_QUEUE_LIB_PATH = " + + "${QUEUELIB}/scratch_queue_lib" + newline; + makefile += "SCRATCH_SEMAPHORE_LIB_PATH = " + + "${QUEUELIB}/scratch_semaphore_lib" + newline; + makefile += "EXT_INT_LIB_PATH = ${QUEUELIB}/ext_int_lib" + newline; + } + + makefile += "" + newline; + makefile += "#H_files" + newline; + makefile += "H_FILES=buffer_test_io.h" + newline; + + if (_ui.getRtemsBSP().equals("mparm")) { + makefile += "H_FILES += system.h tmacros.h" + newline; + makefile += newline; + makefile += "COMMON_FLAGS += -DMPARM" + newline; + makefile += "COMMON_FLAGS += -I$(QUEUELIB)" + newline; + makefile += "COMMON_FLAGS += -I$(SS_SEMAPHORE_LIB_PATH)" + + newline; + makefile += "COMMON_FLAGS += -I$(SCRATCH_QUEUE_LIB_PATH)" + + newline; + makefile += "COMMON_FLAGS += -I$(SCRATCH_SEMAPHORE_LIB_PATH)"; + makefile += newline; + makefile += newline; + makefile += "# communication options" + newline; + makefile += "COMMON_FLAGS += -DMPARM_SCRATCHPAD_QUEUE" + + newline; + makefile+="COMMON_FLAGS += -DQUEUE_BUFF_IN_PRODUCER " + + "-Dshaper_PROCESSOR" + newline; + makefile+="#COMMON_FLAGS += -DQUEUE_BUFF_IN_PRODUCER_DMA " + + "-Dshaper_PROCESSOR" + newline; + makefile+="#COMMON_FLAGS += -DQUEUE_BUFF_IN_CONSUMER " + + "-Dshaper_PROCESSOR" + newline; + makefile+="#COMMON_FLAGS += -DQUEUE_BUFF_IN_CONSUMER_DMA " + + "-Dshaper_PROCESSOR" + newline; + makefile+="#COMMON_FLAGS += -DQUEUE_BUFF_IN_SHARDMEM " + + "-Dshaper_PROCESSOR" + newline; + + int shaperProcessorID; + if (_ui.getMappingFileName() == null) { + shaperProcessorID = pn.getProcessList().size(); + } else { + ArchiXmlParser archParser = new ArchiXmlParser(); + Architecture arch = archParser. + doParse(_ui.getPlatformFileName()); + MapXmlParser mappingParser = new MapXmlParser(pn, arch); + Mapping mapping = mappingParser. + doParse(_ui.getMappingFileName()); + shaperProcessorID = mapping.getProcessorList().size(); + } + makefile +="#COMMON_FLAGS += -DQUEUE_BUFF_SHAPER " + + "-Dshaper_PROCESSOR=" + shaperProcessorID + newline; + + makefile += newline; + makefile += "LIBFILECXX = " + + "$(SS_SEMAPHORE_LIB_PATH)/ss_semaphore.cpp " + + "$(SCRATCH_QUEUE_LIB_PATH)/scratch_queue.cpp" + + newline; + makefile += "VPATH = SCRATCH_QUEUE_LIB_PATH" + newline; + } + + makefile += "" + newline; + makefile += "# C source names" + newline; + if (_ui.getRtemsBSP().equals("pc386")) { + makefile += "CSRCS = main.c rtems_process_wrapper.c "; + for (String basename : pn.getProcessBasenames()) { + makefile += basename + "_wrapper.c "; + } + } + makefile += newline; + makefile += "COBJS_ = $(CSRCS:.c=.o)" + newline; + makefile += "COBJS = $(COBJS_:%=%)" + newline; + makefile += "" + newline; + makefile += "# C++ source names" + newline; + makefile += "CXXSRCS = appsupport.c" + newline; + + if (_ui.getRtemsBSP().equals("mparm")) { + makefile += "CXXSRCS += main.c traffic_shaping.c " + + "rtems_process_wrapper.c "; + Vector pList = new Vector(); + for (Process p : pn.getProcessList()) { + String basename = p.getBasename(); + if (!pList.contains(basename)) { + makefile += p.getBasename() + "_wrapper.c "; + pList.add(basename); + } + } + makefile += newline; + makefile += "CXXSRCS += $(LIBFILECXX)" + newline; + } + + makefile += newline; + makefile += newline; + makefile += "CXXOBJS_ = $(CXXSRCS:.cpp=.o)" + newline; + makefile += "CXXOBJS = $(CXXOBJS_:%=%)" + newline; + makefile += "" + newline; + makefile += "# AS source names" + newline; + makefile += "ASSRCS =" + newline; + makefile += "ASOBJS_ = $(ASSRCS:.s=.o)" + newline; + makefile += "ASOBJS = $(ASOBJS_:%=%)" + newline; + makefile += "" + newline; + makefile += "# Libraries" + newline; + makefile += "LIBS = -lrtemsall -lc" + newline; + makefile += "" + newline; + makefile += "include $(RTEMS_MAKEFILE_PATH)/Makefile.inc" + + newline; + makefile += "include $(RTEMS_CUSTOM)" + newline; + makefile += "include $(PROJECT_ROOT)/make/leaf.cfg" + newline; + makefile += "" + newline; + makefile += "#CXXFLAGS += -DAUTOSTARTMEASURING" + newline; + makefile += "#CXXFLAGS += -DVERBOSE" + newline; + makefile += "CXXFLAGS += -I$(SWARMDIR)/core" + newline; + makefile += "CFLAGS += -I$(SWARMDIR)/core" + newline; + + if (_ui.getRtemsBSP().equals("mparm")) { + makefile += "CXXFLAGS += $(COMMON_FLAGS) -I${PWD}" + newline; + makefile += "CFLAGS += $(COMMON_FLAGS) -I${PWD}" + newline; + + makefile += newline; + makefile += "#### for calibration" + newline; + makefile += "CXXFLAGS += -Ilib" + newline; + makefile += "CXXFLAGS += -D_GLIBCPP_HAVE_WCHAR_H " + + "-D_GLIBCPP_HAVE_MBSTATE_T" + newline; + makefile += "CXXFLAGS += -DWORKLOAD_EXTRACT" + newline; + makefile += "CXXFLAGS += -DPRINTF_TO_DEBUG" + newline; + } + makefile += "" + newline; + makefile += "SRCS=$(H_FILES)" + newline; + makefile += "OBJS= $(COBJS) $(CXXOBJS) $(ASOBJS)" + newline; + makefile += "" + newline; + makefile += "all: ${ARCH} $(SRCS) $(PGM) " + newline; + makefile += "" + newline; + makefile += "$(PGM): $(OBJS) " + newline; + makefile += "\t$(make-exe)" + newline; + makefile += "clean:" + newline; + makefile += "\t-rm -f ${SS_SEMAPHORE_LIB_PATH}/*.o " + + "${SCRATCH_QUEUE_LIB_PATH}/*.o" + newline; + + return makefile; + } + + /** + * Create a makefile for the pc386 board support package. + * + * @param pn process network + * @return makefile for pc386 board support package + */ + protected String getPc386Makefile(ProcessNetwork pn) { + String makefile = ""; + String newline = System.getProperty("line.separator"); + makefile += "EXEC=main.exe" + newline; + makefile += "PGM=${ARCH}/$(EXEC)" + newline; + makefile += newline; + makefile += "# optional managers required" + newline; + makefile += "MANAGERS=all" + newline; + makefile += newline; + makefile += "# C source names" + newline; + makefile += "CSRCS = main.c rtems_process_wrapper.c "; + for (String basename : pn.getProcessBasenames()) { + makefile += basename + "_wrapper.c "; + } + for (Configuration conf : pn.getCfgList()) { + if (conf.getName().equals("EXTERNAL_SRC")) { + makefile += conf.getValue(); + } + } + makefile += newline; + makefile += "COBJS_ = $(CSRCS:.c=.o)" + newline; + makefile += "COBJS = $(COBJS_:%=${ARCH}/%)" + newline; + makefile += newline; + makefile += "# C++ source names" + newline; + makefile += "CXXSRCS =" + newline; + makefile += "CXXOBJS_ = $(CXXSRCS:.cc=.o)" + newline; + makefile += "CXXOBJS = $(CXXOBJS_:%=${ARCH}/%)" + newline; + makefile += newline; + makefile += "# AS source names" + newline; + makefile += "ASSRCS =" + newline; + makefile += "ASOBJS_ = $(ASSRCS:.s=.o)" + newline; + makefile += "ASOBJS = $(ASOBJS_:%=${ARCH}/%)" + newline; + makefile += newline; + makefile += "# Libraries" + newline; + makefile += "LIBS = -lrtemsall -lc "; + for (Configuration conf : pn.getCfgList()) { + if (conf.getName().equals("DYNAMIC_LINK")) + makefile += conf.getValue() + newline; + } + makefile += newline; + makefile += "include $(RTEMS_MAKEFILE_PATH)/Makefile.inc" + + newline; + makefile += newline; + makefile += "include $(RTEMS_CUSTOM)" + newline; + makefile += "include $(PROJECT_ROOT)/make/leaf.cfg" + newline; + makefile += newline; + makefile += "OBJS= $(COBJS) $(CXXOBJS) $(ASOBJS)" + newline; + makefile += newline; + makefile += "all: ${ARCH} $(PGM)" + newline; + makefile += newline; + makefile += "$(PGM): $(OBJS)" + newline; + makefile += "\t$(make-exe)" + newline; + return makefile; + } + + protected String _dir = null; +} diff --git a/dol/src/dol/visitor/rtems/RtemsModuleVisitor.java b/dol/src/dol/visitor/rtems/RtemsModuleVisitor.java new file mode 100644 index 0000000..d62eda3 --- /dev/null +++ b/dol/src/dol/visitor/rtems/RtemsModuleVisitor.java @@ -0,0 +1,864 @@ +/* $Id: RtemsModuleVisitor.java 114 2010-07-05 07:47:02Z haidw $ */ +package dol.visitor.rtems; + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Vector; + +import dol.datamodel.architecture.Architecture; +import dol.datamodel.mapping.ComputationBinding; +import dol.datamodel.mapping.Mapping; +import dol.datamodel.mapping.Schedule; +import dol.datamodel.mapping.ScheduleEntry; +import dol.datamodel.mapping.SchedulingPolicy; +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.main.UserInterface; +import dol.parser.xml.archischema.ArchiXmlParser; +import dol.parser.xml.mapschema.MapXmlParser; +import dol.util.CodePrintStream; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate + * the main program. + */ +public class RtemsModuleVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir path of this file + */ + public RtemsModuleVisitor(String dir, HashMap portMap) { + _dir = dir; + _portMap = portMap; + } + + /** + * Visit process network. + * + * @param x process network that needs to be rendered + */ + public void visitComponent(ProcessNetwork x) { + try { + _ui = UserInterface.getInstance(); + String filename = _dir + _delimiter + "main.c"; + OutputStream file = new FileOutputStream(filename); + _mainPS = new CodePrintStream(file); + + Vector pList = x.getProcessList(); + Vector processList = new Vector(); + for (Process p : x.getProcessList()) { + String basename = p.getBasename(); + if (!processList.contains(basename)) { + processList.add(basename); + } + } + + Architecture arch = null; + Mapping mapping = null; + + //create header section + if (_ui.getRtemsBSP().equals("pc386")) { + _mainPS.println("#include "); + _mainPS.println("#include "); + _mainPS.println("#include "); + _mainPS.println("#include "); + _mainPS.println(); + _mainPS.println("rtems_task Init(rtems_task_argument argument);"); + _mainPS.println(); + _mainPS.println("#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER"); + _mainPS.println("#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER"); + _mainPS.println("#define CONFIGURE_RTEMS_INIT_TASKS_TABLE"); + _mainPS.println("#define CONFIGURE_MAXIMUM_TASKS " + + (x.getProcessList().size() + 2)); + _mainPS.println("#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES " + + x.getChannelList().size()); + _mainPS.println("#define CONFIGURE_INIT"); + _mainPS.println("#include "); + _mainPS.println(); + } else if (_ui.getRtemsBSP().equals("mparm")) { + _mainPS.println("#define TEST_INIT"); + _mainPS.println("#include "); + _mainPS.println("#include "); + _mainPS.println("#include "); + _mainPS.println(); + _mainPS.println("#define RTEMS_TRACE_MAIN_APP"); + _mainPS.println("#include \"system.h\""); + _mainPS.println("#include \"appsupport.h\""); + _mainPS.println("#include \"scratch_queue.h\""); + _mainPS.println(); + } + + _mainPS.println("#include \"dol.h\""); + _mainPS.println("#include \"rtems_process_wrapper.h\""); + _mainPS.println(); + + if (_ui.getRtemsBSP().equals("pc386")) { + _mainPS.println("rtems_task CleanupTask(rtems_task_argument arg);"); + _mainPS.println("rtems_id queue_id[" + + x.getChannelList().size() + "];"); + _mainPS.println(); + } else if (_ui.getRtemsBSP().equals("mparm")) { + //if no mapping is provided, map each process to a new + //processor + //shaper + _mainPS.println("#ifdef QUEUE_BUFF_SHAPER"); + _mainPS.println("#include \"traffic_shaping.h\""); + //_mainPS.println("#define shaper_PROCESSOR " + // + (pList.size()+1)); + _mainPS.println("#endif // shaper"); + _mainPS.println(); + + if (_ui.getMappingFileName() == null) { + + int i = 0; + for (Process p : pList) { + _mainPS.println("#define " + p.getName() + + "_PROCESSOR " + ++i); //count from 1 + } + _mainPS.println(); + + _mainPS.print("unsigned int number_of_processes[" + + pList.size() + "] = { "); + for (i = 0; i < pList.size(); i++) { + _mainPS.print("1, "); + } + _mainPS.println("};"); + _mainPS.println(); + + } else { //map processes according to mapping file + ArchiXmlParser archParser = new ArchiXmlParser(); + arch = archParser.doParse(_ui.getPlatformFileName()); + MapXmlParser mappingParser = new MapXmlParser(x, arch); + mapping = mappingParser.doParse(_ui.getMappingFileName()); + int numOfUsedProcessors = mapping.getProcessorList().size(); + int numOfProcessors = arch.getProcessorList().size(); + int processesPerProcessor[] = new int[numOfProcessors]; + + // need to check processors used start from 0 and + //continuous + for (Process p : pList) { + for (ComputationBinding b : mapping.getCompBindList()){ + int processorIndex = Integer.valueOf( + b.getProcessor().getName(). + replaceAll(".*_", "")); + if (b.getProcess().getName(). + equals(p.getName())) { + processesPerProcessor[processorIndex]++; + //processor indices start at 1 in MPARM + _mainPS.println("#define " + p.getName() + + "_PROCESSOR " + + (processorIndex + 1)); + } + } + } + + + for (int i=0; i < numOfUsedProcessors; i++) { + if (processesPerProcessor[i] < 1) + throw new Exception("No process is mapped to " + + "PROCESSOR[" + i + "]. For the MPARM " + + "platform, processors should be used " + + "starting from 0 until N (in the " + + "generated code, from 1 to N + 1), and " + + "every processor between 0 and N " + + "should have at least one process " + + "mapped on it!"); + } + + _mainPS.println(); + /* + _mainPS.println("#ifdef QUEUE_BUFF_SHAPER"); + _mainPS.println("#define shaper_PROCESSOR " + + (numOfUsedProcessors+1)); + _mainPS.println("#endif // shaper"); + _mainPS.println(); + */ + _mainPS.print("unsigned int number_of_processes[]" + + " = { "); + for (int i = 0; i < numOfUsedProcessors; i++) { + _mainPS.print(processesPerProcessor[i] + ", "); + } + _mainPS.println("};"); + _mainPS.println(); + } + + _mainPS.println("unsigned int active_processes;"); + _mainPS.println("inline void processor_init() " + + "{active_processes" + + " = number_of_processes[get_id() - 1];}"); + _mainPS.println(); + + for (Process p : pList) { + _mainPS.println("void " + "rtems_" + p.getName() + + "_init(rtems_task_argument arg);"); + } + _mainPS.println(); + } + + for (String pName : x.getProcessBasenames()) { + _mainPS.println("extern rtems_task " + pName + + "_task(rtems_task_argument argument);"); + } + _mainPS.println(); + + //declare processes and channels + for (Process process : x.getProcessList()) { + _mainPS.println("RtemsProcessWrapper *" + process.getName() + + "_wrapper;"); + } + _mainPS.println(); + + _mainPS.println("#ifdef PRINTF_TO_DEBUG"); + _mainPS.println("#undef printf"); + _mainPS.println("#define printf(...) \\"); + _mainPS.println(" do { \\"); + _mainPS.println(" char _buffer[128]; \\"); + _mainPS.println(" sprintf(_buffer, __VA_ARGS__); \\"); + _mainPS.println(" SHOW_DEBUG((int)_buffer); \\"); + _mainPS.println(" } while (0)"); + _mainPS.println("#endif"); + _mainPS.println(); + _mainPS.println("#ifdef WORKLOAD_EXTRACT"); + _mainPS.println("void callback(int code, int* arg, int size) " + + "{"); + _mainPS.println(" long unsigned int time = get_cycle1();"); + _mainPS.println(" Thread_Control *x = " + + "(Thread_Control*)arg;"); + _mainPS.println(" SHOW_DEBUG(\"log callback\");"); + _mainPS.println(" SHOW_DEBUG_INT((int)time);"); + _mainPS.println(" SHOW_DEBUG_INT(x->Object.id);"); + _mainPS.println("}"); + _mainPS.println("#endif"); + _mainPS.println(); + _mainPS.println("rtems_id timer_sem_id;"); + _mainPS.println(); + //RTEMS init task + _mainPS.println("/**"); + _mainPS.println(" *"); + _mainPS.println(" */"); + _mainPS.println("rtems_task Init(rtems_task_argument arg) {"); + + if (_ui.getRtemsBSP().equals("mparm")) { + // //////////////////// mparm ///////////////////////// + int processCount = 0; + + _mainPS.println(" rtems_id task_id;"); + _mainPS.println(" rtems_status_code status;"); + _mainPS.println(); + _mainPS.println(" status = rtems_semaphore_create(rtems_build_name('c','s','e','m'), 1, RTEMS_BINARY_SEMAPHORE |RTEMS_NO_PRIORITY_CEILING |RTEMS_LOCAL |RTEMS_PRIORITY, 0,&timer_sem_id);"); + _mainPS.println(" if (status != RTEMS_SUCCESSFUL) {"); + _mainPS.println(" printf(\"[init ] Could not create semaphore (status %d).\", status);"); + _mainPS.println(" rtems_shutdown_executive(0);"); + _mainPS.println(" }"); + + + _mainPS.println(); + + _mainPS.println(" scratch_queue_autoinit_system();"); + _mainPS.println(); + + _mainPS.println("#ifdef WORKLOAD_EXTRACT"); + _mainPS.println(" rtems_monitor_register_callback" + + "(callback);"); + for (Channel c : x.getChannelList()) { + _mainPS.println(" SHOW_DEBUG(\"log " + + "create_channel\");"); + _mainPS.println(" SHOW_DEBUG(\"log " + c.getName() + + "\");"); + _mainPS.println(" SHOW_DEBUG_INT((int)" + + (c.getSize() * c.getTokenSize()) + ");"); + } + _mainPS.println("#endif"); + + //shaper process + _mainPS.println("#ifdef QUEUE_BUFF_SHAPER"); + _mainPS.println(" if ((get_id()-1) == shaper_PROCESSOR) " + + "{"); + _mainPS.println(" rtems_name name = rtems_build_name" + +"('s', 's', '0', ' ');"); + _mainPS.println(); + + // create pre task + _mainPS.println(" //one more init to prevent the" + + "blocking instatiation of scrach queue"); + _mainPS.println(" status = rtems_task_create("); + _mainPS.println(" name,"); + _mainPS.println(" 1,"); + _mainPS.println(" RTEMS_MINIMUM_STACK_SIZE,"); + _mainPS.println(" RTEMS_DEFAULT_MODES,"); + _mainPS.println(" RTEMS_LOCAL,"); + _mainPS.println(" &task_id, -1);"); + _mainPS.println(" if (status != RTEMS_SUCCESSFUL) {"); + _mainPS.println(" printf(\"[init ] " + + "Could not create init shaper" + + "(status %d).\\n\", status);"); + _mainPS.println(" rtems_shutdown_executive(0);"); + _mainPS.println(" }"); + _mainPS.println(); + + // start pre init + _mainPS.println(" status = rtems_task_start(task_id, " + + "shaping_init, arg);"); + _mainPS.println(" if (status != RTEMS_SUCCESSFUL) {"); + _mainPS.println(" printf(\"[init ] " + + "Could not start init shaping" + + " (status %d).\\n\", status);"); + _mainPS.println(" rtems_shutdown_executive(0);"); + _mainPS.println(" }"); + _mainPS.println(" }"); + _mainPS.println("#endif // QUEUE_BUFF_SHAPER"); + _mainPS.println(); + + for (Process process : x.getProcessList()) { + _mainPS.println(" if (get_id() == " + + process.getName() + "_PROCESSOR) {"); + _mainPS.println(" processor_init();"); + _mainPS.println(" rtems_name name = " + + "rtems_build_name" + + "('p', 'i', 0x" + ++processCount + + ", ' ');"); + _mainPS.println(); + + // create pre task + _mainPS.println(" //one more init to prevent the" + + "blocking instatiation of scrach queue"); + _mainPS.println(" status = rtems_task_create("); + _mainPS.println(" name,"); + _mainPS.println(" 1,"); + _mainPS.println(" RTEMS_MINIMUM_STACK_SIZE" + + ","); + _mainPS.println(" RTEMS_DEFAULT_MODES,"); + _mainPS.println(" RTEMS_LOCAL,"); + _mainPS.println(" &task_id, -1);"); + _mainPS.println(" if (status != RTEMS_SUCCESSFUL) " + + "{"); + _mainPS.println(" printf(\"[init ] " + + "Could not create init task[" + + process.getName() + "] " + +"(status %d).\\n\", status);"); + _mainPS.println(" rtems_shutdown_executive(0);"); + _mainPS.println(" }"); + _mainPS.println(); + + // start pre init + _mainPS.println(" status = rtems_task_start(task_id, " + + "rtems_" + process.getName() + + "_init, arg);"); + _mainPS.println(" if (status != RTEMS_SUCCESSFUL) {"); + _mainPS.println(" printf(\"[init ] " + + "Could not start init task [ " + + process.getName() + + "] (status %d).\\n\", status);"); + _mainPS.println(" rtems_shutdown_executive(0);"); + _mainPS.println(" }"); + /* + _mainPS.println(" rtems_" + process.getName() + + "_init(arg);"); + _mainPS.println(" rtems_task_delete(RTEMS_SELF);"); + */ + _mainPS.println(" }"); + _mainPS.println(); + } + + // shaper process + _mainPS.println("#ifdef QUEUE_BUFF_SHAPER"); + _mainPS.println(" if ((get_id()-1) == shaper_PROCESSOR) " + + "{"); + _mainPS.println(" rtems_name name = rtems_build_name" + +"('s', 's', '0', ' ');"); + _mainPS.println(); + + // create pre task + _mainPS.println(" //one more init to prevent the" + + "blocking instatiation of scrach queue"); + _mainPS.println(" status = rtems_task_create("); + _mainPS.println(" name,"); + _mainPS.println(" 128,"); + _mainPS.println(" RTEMS_MINIMUM_STACK_SIZE,"); + _mainPS.println(" RTEMS_DEFAULT_MODES,"); + _mainPS.println(" RTEMS_LOCAL,"); + _mainPS.println(" &task_id, -1);"); + _mainPS.println(" if (status != RTEMS_SUCCESSFUL) {"); + _mainPS.println(" printf(\"[init ] " + + "Could not create init shaper" + +"(status %d).\\n\", status);"); + _mainPS.println(" rtems_shutdown_executive(0);"); + _mainPS.println(" }"); + _mainPS.println(); + + // start pre init + _mainPS.println(" status = rtems_task_start(task_id, " + + "shaping_init, arg);"); + _mainPS.println(" if (status != RTEMS_SUCCESSFUL) {"); + _mainPS.println(" printf(\"[init ] " + + "Could not start init shaping" + + " (status %d).\\n\", status);"); + _mainPS.println(" rtems_shutdown_executive(0);"); + _mainPS.println(" }"); + _mainPS.println(" }"); + _mainPS.println("#endif // QUEUE_BUFF_SHAPER"); + _mainPS.println(); + + _mainPS.println("if (number_of_processes[get_id() - 1]" + + " == 0) {"); + _mainPS.println(" printf(\"No process on processor " + + "%d.\", get_id());"); + _mainPS.println(" rtems_shutdown_executive(0);"); + _mainPS.println("}"); + _mainPS.println(); + + _mainPS.println(" rtems_task_delete(RTEMS_SELF);"); + _mainPS.println("}"); + _mainPS.println(); + // end of init + + processCount = 0; + for (Process process : x.getProcessList()) { + String processName = process.getName(); + _mainPS.println("void rtems_" + process.getName() + + "_init(rtems_task_argument arg) {"); + _mainPS.println(" rtems_id task_id;"); + _mainPS.println(" rtems_status_code status;"); + + + _mainPS.println(" " + process.getName() + + "_wrapper = " + + "(RtemsProcessWrapper *)malloc" + + "(sizeof(RtemsProcessWrapper));"); + + int numOfOutports = process.getNumOfOutports(); + int numOfInports = process.getNumOfInports(); + if (numOfOutports > 0) { + _mainPS.println(" int* " + + process.getName() + + "_out_port_id = (int *)malloc(" + + numOfOutports + + " * sizeof(int));"); + _mainPS.println(" SCRATCH_QUEUE_PRODUCER **" + + process.getName() + + "_out_queue_id = " + + "(SCRATCH_QUEUE_PRODUCER **)" + + "malloc(" + + numOfOutports + + "*sizeof(SCRATCH_QUEUE_PRODUCER));"); + } + + if (numOfInports > 0) { + _mainPS.println(" int *" + + process.getName() + + "_in_port_id = (int *)malloc(" + + numOfInports + + " * sizeof(int));"); + _mainPS.println(" SCRATCH_QUEUE_CONSUMER **" + + process.getName() + + "_in_queue_id = " + + "(SCRATCH_QUEUE_CONSUMER **)" + + "malloc(" + + numOfOutports + + "*sizeof(SCRATCH_QUEUE_CONSUMER));"); + } + _mainPS.println(); + + // create task + _mainPS.println(" status = rtems_task_create("); + _mainPS.println(" " + ++processCount + ","); + _mainPS.println(" 1,"); + _mainPS.println(" RTEMS_MINIMUM_STACK_SIZE,"); + _mainPS.println(" RTEMS_DEFAULT_MODES,"); + _mainPS.println(" RTEMS_LOCAL,"); + _mainPS.println(" &task_id, -1);"); + _mainPS.println(" if (status != RTEMS_SUCCESSFUL) {"); + _mainPS.println(" printf(\"[init ] " + + "Could not create task[" + + processName + "] " + +"(status %d).\\n\", status);"); + _mainPS.println(" rtems_shutdown_executive(0);"); + _mainPS.println(" }"); + + _mainPS.println("#ifdef WORKLOAD_EXTRACT"); + _mainPS.println(" SHOW_DEBUG(\"log create_task\");"); + _mainPS.println(" SHOW_DEBUG_INT(task_id);"); + _mainPS.println(" SHOW_DEBUG(\"log " + processName + "\");"); + for (Port port : process.getPortList()) { + Channel c = (Channel) port.getPeerResource(); + if (port.isInPort()) { + _mainPS.println(" SHOW_DEBUG(\"log in_port\");"); + _mainPS.println(" SHOW_DEBUG_INT((int)" + _portMap.get(port) + ");"); + _mainPS.println(" SHOW_DEBUG(\"log " + c.getName() + "\");"); + } + if (port.isOutPort()) { + _mainPS.println(" SHOW_DEBUG(\"log out_port\");"); + _mainPS.println(" SHOW_DEBUG_INT((int)" + _portMap.get(port) + ");"); + _mainPS.println(" SHOW_DEBUG(\"log " + c.getName() + "\");"); + } + } + _mainPS.println("#endif"); + _mainPS.println(); + + // connect ports to channels + HashMap channel_map = + new HashMap(); + int channelCount = 1; + for (Channel c : x.getChannelList()) { + channel_map.put(c, channelCount++); + } + _mainPS.println(); + + // fill the wrapper, instantiate queues + int i = 0, j = 0; + for (Port port : process.getPortList()) { + Channel c = (Channel)(port.getPeerResource()); + if (port.isInPort()) { + _mainPS.println(" " + processName + "_in_port_id[" + + i + "] = " + + _portMap.get(port) + ";"); + _mainPS.println(" " + processName + + "_in_queue_id[" + + i + "] = "); + _mainPS.println("#if defined (QUEUE_BUFF_IN_PRODUCER) || (QUEUE_BUFF_IN_PRODUCER_DMA)"); + _mainPS.println(" scratch_queue_autoinit_consumer(" + + channel_map.get(c) + + ", true);"); + _mainPS.println("#elif defined (QUEUE_BUFF_IN_CONSUMER) || (QUEUE_BUFF_IN_CONSUMER_DMA)"); + _mainPS.println(" scratch_queue_autoinit_consumer(" + + c.getOrigin().getName() + + "_PROCESSOR, " + + channel_map.get(c) + ", " + + c.getSize() + ", " + + c.getTokenSize() + + ");"); + _mainPS.println("#elif defined (QUEUE_BUFF_IN_SHARDMEM)"); + _mainPS.println(" scratch_queue_autoinit_consumer(" + + channel_map.get(c) + + ", true);"); + _mainPS.println("#elif defined (QUEUE_BUFF_SHAPER)"); + _mainPS.println(" scratch_queue_autoinit_consumer(" + + channel_map.get(c) + + ");"); + _mainPS.println("#endif"); + + + i++; + } else if (port.isOutPort()) { + _mainPS.println(" " + processName+"_out_port_id[" + + j + "] = " + + _portMap.get(port) + ";"); + _mainPS.println(" " + processName + + "_out_queue_id[" + + j + "] = "); + + _mainPS.println("#if defined (QUEUE_BUFF_IN_PRODUCER) || (QUEUE_BUFF_IN_PRODUCER_DMA)"); + _mainPS.println(" scratch_queue_autoinit_producer(" + + c.getTarget().getName() + + "_PROCESSOR," + + channel_map.get(c) + ", " + + c.getSize() + ", " + + c.getTokenSize() + + ", 0);"); + _mainPS.println("#elif defined (QUEUE_BUFF_IN_CONSUMER) || (QUEUE_BUFF_IN_CONSUMER_DMA)"); + _mainPS.println(" scratch_queue_autoinit_producer(" + + channel_map.get(c) + + ", true);"); + _mainPS.println("#elif defined (QUEUE_BUFF_IN_SHARDMEM)"); + _mainPS.println(" scratch_queue_autoinit_producer(" + + c.getTarget().getName() + + "_PROCESSOR," + + channel_map.get(c) + ", " + + c.getSize() + ", " + + c.getTokenSize() + + ", 1);"); + _mainPS.println("#elif defined (QUEUE_BUFF_SHAPER)"); + _mainPS.println(" scratch_queue_autoinit_producer(" + + c.getTarget().getName() + + "_PROCESSOR," + + channel_map.get(c) + ", " + + c.getSize() + ", " + + c.getTokenSize() + + ");"); + _mainPS.println("#endif"); + + j++; + } + } + + if (numOfInports > 0) { + _mainPS.println(" " + processName + + "_wrapper->in_port_id = " + + processName + + "_in_port_id;"); + _mainPS.println(" " + processName + + "_wrapper->in_queue_id = " + + processName + + "_in_queue_id;"); + _mainPS.println(" " + processName + + "_wrapper->number_of_in_ports = " + + numOfInports + ";"); + } + + if (numOfOutports > 0) { + _mainPS.println(" " + processName + + "_wrapper->out_port_id = " + + processName + + "_out_port_id;"); + _mainPS.println(" " + processName + + "_wrapper->out_queue_id = " + + processName + + "_out_queue_id;"); + _mainPS.println(" " + processName + + "_wrapper->number_of_out_ports = " + + numOfOutports + ";"); + } + + _mainPS.println(" " + processName + + "_wrapper->is_detached = 0;"); + + int priority = 127; + if (mapping != null) { + Schedule s = mapping.getScheduleByResource( + process.getProcessor().getName()); + if (s != null && s.getSchedPolicy() == + SchedulingPolicy.FIXEDPRIORITY) { + ScheduleEntry e = s.getScheduleEntry( + process.getName()); + if (e != null) { + String value = e.getCfgValue("priority"); + if (value != null) { + priority = Integer.parseInt(value); + } + } + } + } + _mainPS.println(" " + processName + + "_wrapper->priority = " + priority + ";"); + + _mainPS.println(" " + processName + + "_wrapper->name = (char *)malloc((" + + processName.length() + + " + 1) * sizeof(char));"); + _mainPS.println(" strcpy(" + processName + + "_wrapper->name, " + "\"" + + processName + "\");"); + _mainPS.println(); + + _mainPS.println(" status = rtems_task_start(" + + "task_id, " + process.getBasename() + + "_task, " + "(rtems_task_argument)" + + process.getName() + "_wrapper);"); + _mainPS.println(" if (status != RTEMS_SUCCESSFUL) " + + "{"); + _mainPS.println(" printf(\"[init ] " + + "Could not start " + process.getName() + + " (status %d).\\n\", status);"); + _mainPS.println(" rtems_shutdown_executive(0);"); + _mainPS.println(" }"); + _mainPS.println(" rtems_task_delete(RTEMS_SELF);"); + _mainPS.println("}"); + _mainPS.println(); + _mainPS.println(); + } + } else if (_ui.getRtemsBSP().equals("pc386")) { + // //////////////////// pc386 //////////////////////// + _mainPS.println(" int j;"); + _mainPS.println(" rtems_id task_id[" + + + (x.getProcessList().size() + 1) + "];"); + _mainPS.println(" rtems_status_code status;"); + _mainPS.println(); + + //initialize process-specific information + for (Process process : x.getProcessList()) { + int numberOfPorts = x.getProcess(process.getName()) + .getPortList().size(); + _mainPS.println(" " + process.getName() + + "_wrapper = " + + "malloc(sizeof(RtemsProcessWrapper));"); + _mainPS.println(" int *" + + process.getName() + "_port_id = malloc(" + + numberOfPorts + " * sizeof(int));"); + _mainPS.println(" int *" + + process.getName() + + "_port_queue_id = malloc(" + + numberOfPorts + " * sizeof(int));"); + _mainPS.println(); + } + + //create a task for each process + _mainPS.println(" for (j = 0; j < " + + (x.getProcessList().size()+1) + "; j++) {"); + _mainPS.println(" status = rtems_task_create("); + _mainPS.println(" j + 1,"); + _mainPS.println(" 128,"); + _mainPS.println(" RTEMS_MINIMUM_STACK_SIZE,"); + _mainPS.println(" RTEMS_DEFAULT_MODES,"); + _mainPS.println(" RTEMS_DEFAULT_ATTRIBUTES,"); + _mainPS.println(" &(task_id[j]));"); + _mainPS.println(" if (status != RTEMS_SUCCESSFUL) {"); + _mainPS.println(" printf(\"[init ] " + + "Could not create task[%d] (status %d).\\n\", " + + "(int)j, status);"); + _mainPS.println(" rtems_shutdown_executive(0);"); + _mainPS.println(" }"); + _mainPS.println(" }"); + _mainPS.println(); + + //create a message queue for each channel + int j = 0; + for (Channel channel : x.getChannelList()) { + _mainPS.println(" status = " + + "rtems_message_queue_create("); + _mainPS.println(" " + (j + 1) + ","); + _mainPS.println(" " + channel.getSize() + + ","); + _mainPS.println(" 1,"); + _mainPS.println(" RTEMS_DEFAULT_ATTR" + + "IBUTES,"); + _mainPS.println(" &queue_id[" + j + "]);"); + _mainPS.println(" if (status != RTEMS_SUCCESSFUL) " + + "{"); + _mainPS.println(" printf(\"[init ] " + + "Could not create queue[" + j + + "] (status %d).\\n\", status);"); + _mainPS.println(" rtems_shutdown_executive(0);"); + _mainPS.println(" }"); + _mainPS.println(); + j++; + } + + //connect ports to channels + HashMap channel_map = + new HashMap(); + j = 0; + for (Channel c : x.getChannelList()) { + channel_map.put(c, j++); + } + + for (Process process : x.getProcessList()) { + String processName = process.getName(); + int i = 0; + for (Port port : process.getPortList()) { + Channel c = (Channel)(port.getPeerResource()); + + _mainPS.println(" " + processName + "_port_id[" + + i + "] = " + + _portMap.get(port) + ";"); + _mainPS.println(" " + processName + + "_port_queue_id[" + i + "] = queue_id[" + + channel_map.get(c) + "];"); + i++; + } + _mainPS.println(" " + processName + + "_wrapper->port_id = " + processName + + "_port_id;"); + _mainPS.println(" " + processName + + "_wrapper->port_queue_id = " + + processName + + "_port_queue_id;"); + _mainPS.println(" " + processName + + "_wrapper->number_of_ports = " + + i + ";"); + _mainPS.println(" " + processName + + "_wrapper->is_detached = 0;"); + _mainPS.println(" " + processName + + "_wrapper->name = malloc((" + + processName.length() + + " + 1) * sizeof(char));"); + _mainPS.println(" strcpy(" + processName + + "_wrapper->name, " + "\"" + + processName + "\");"); + _mainPS.println(); + } + + //start cleanup task + _mainPS.println(" printf(\"[init ] " + + "Start cleanup.\\n\");"); + _mainPS.println(" status = rtems_task_start(task_id[0], " + + "CleanupTask, 0);"); + _mainPS.println(" if (status != RTEMS_SUCCESSFUL) {"); + _mainPS.println(" printf(\"[init ] Could not start " + + "cleanup (status %d).\\n\", status);"); + _mainPS.println(" rtems_shutdown_executive(0);"); + _mainPS.println(" }"); + _mainPS.println(); + + //start processes + j = 1; + for (Process process : x.getProcessList()) { + _mainPS.println(" printf(\"[init ] Start " + + process.getName() + ".\\n\");"); + _mainPS.println(" status = rtems_task_start(task_id[" + + j + "], " + process.getBasename() + + "_task, " + + "(rtems_task_argument)" + + process.getName() + + "_wrapper);"); + _mainPS.println(" if (status != RTEMS_SUCCESSFUL) " + + "{"); + _mainPS.println(" printf(\"[init ] " + + "Could not start " + process.getName() + + " (status %d).\\n\", status);"); + _mainPS.println(" rtems_shutdown_executive(0);"); + _mainPS.println(" }"); + _mainPS.println(); + j++; + } + + _mainPS.println(" printf(\"[init ] Done.\\n\");"); + _mainPS.println(" rtems_task_delete(RTEMS_SELF);"); + _mainPS.println("}"); + _mainPS.println(); + + _mainPS.println("rtems_task CleanupTask(rtems_task_argument " + + "argument) {"); + _mainPS.println(" printf(\"[cleanup ] Started.\\n\");"); + _mainPS.println(" do {"); + _mainPS.println(" rtems_task_wake_after(0);"); + _mainPS.println(" } while ("); + j = 0; + for (Process process : x.getProcessList()) { + _mainPS.print(" !(" + + process.getName() + + "_wrapper->is_detached)"); + j++; + if (j < x.getProcessList().size()) { + _mainPS.println(" || "); + } else { + _mainPS.println(");"); + } + } + _mainPS.println(); + _mainPS.println(" printf(\"[cleanup ] Shutdown.\\n\");"); + _mainPS.println(" rtems_shutdown_executive(0);"); + _mainPS.println("}"); + _mainPS.println(); + } + } + catch (Exception e) { + System.out.println("RtemsModuleVisitor: exception occured: " + + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * + * @param x process that needs to be processed + */ + public void visitComponent(Process x) { + } + + /** + * + * @param x channel that needs to be processed + */ + public void visitComponent(Channel x) { + } + + protected CodePrintStream _mainPS = null; + protected String _dir = null; + protected HashMap _portMap; +} diff --git a/dol/src/dol/visitor/rtems/RtemsProcessVisitor.java b/dol/src/dol/visitor/rtems/RtemsProcessVisitor.java new file mode 100644 index 0000000..27b02a1 --- /dev/null +++ b/dol/src/dol/visitor/rtems/RtemsProcessVisitor.java @@ -0,0 +1,168 @@ +/* $Id: RtemsProcessVisitor.java 213 2010-10-20 09:40:59Z khuang $ */ +package dol.visitor.rtems; + +import java.io.File; +import java.util.HashMap; +import java.util.Vector; + +import dol.datamodel.pn.Configuration; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.SourceCode; +import dol.util.Copier; +import dol.util.Sed; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate + * a wrapper class for a process. + */ +public class RtemsProcessVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir target directory + */ + public RtemsProcessVisitor(String dir, + HashMap portMap, + HashMap sinkMap) { + _dir = dir; + _portMap = portMap; + _sinkMap = sinkMap; + } + + /** + * + * @param x process network that needs to be processed + */ + public void visitComponent(ProcessNetwork x) { + try { + Vector pList = new Vector(); + + for (Process p : x.getProcessList()) { + String basename = p.getBasename(); + if (!pList.contains(basename)) { + pList.add(basename); + p.accept(this); + } + } + } + catch (Exception e) { + System.out.println("RtemsProcessVisitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * Visit process. + * + * @param p process that needs to be processed + */ + public void visitComponent(Process p) { + try { + String filename = _dir + _delimiter + p.getBasename() + + "_wrapper.c"; + File process_file = new File(filename); + File pattern_file = new File(_dir + _delimiter + + "process_wrapper_template.c"); + new Copier().copyFile(pattern_file, process_file); + + String includes = ""; + for (SourceCode code : p.getSrcList()) { + includes += "#include \"" + code.getLocality() + "\"" + + System.getProperty("line.separator"); + } + + Sed sed = new Sed(); + sed.sed(filename, "//#include \"@PROCESSNAME@.c\"", includes); + sed.sed(filename, "@PROCESSNAME@", p.getBasename()); + sed.sed(filename, "@Processname@", + p.getBasename().substring(0, 1).toUpperCase() + + p.getBasename().substring(1)); + + String triggerPeriod = null; + String burstSize = null; + String burstPosition = null; + for (Configuration c : p.getCfgList()) { + if (c.getName().equals("triggerPeriod")) { + triggerPeriod = c.getValue(); + } else if (c.getName().equals("burstSize")) { + burstSize = c.getValue(); + } else if (c.getName().equals("burstPosition")) { + burstPosition = c.getValue(); + } + } + if (triggerPeriod != null) { + if (burstSize == null) { + burstSize = "0"; + } + if (burstPosition == null) { + burstPosition = "0"; + } + + String periodicTrigger = + "//limits the number of process activations\n" + + " while ((((int)get_cycle() - " + + "1511576) / " + triggerPeriod + ") " + + "< number_of_activations - (((int)get_cycle()" + // + " - 1511576) > " + burstPosition + " ? " + + " ) > " + burstPosition + " ? " + + burstSize + " : 0)) {\n" + + " rtems_task_set_priority(" + + "RTEMS_SELF, 127, &old_priority);\n" + + " rtems_task_wake_after(" + + "RTEMS_YIELD_PROCESSOR);\n" + + " }\n" + + " rtems_task_set_priority(RTEMS_SELF, " + + "wrapper->priority, &old_priority);\n"; + + sed.sed(filename, + "//placeholder for periodic trigger", + periodicTrigger); + } + + if (!p.hasOutPorts()) { + sed.sed(filename, "@ENDING_SHAPER@", + "ss_sem_signal(get_sem_terminate(" + + _sinkMap.get(p) + "));"); + } else { + sed.sed(filename, "@ENDING_SHAPER@", ""); + } + + for(SourceCode sourceCode : p.getSrcList()) { + filename = _dir + _delimiter + + sourceCode.getLocality().replaceAll( + "(.*)\\.[cC][pP]*[pP]*", "$1\\.h"); + sed.sed(filename, "", "\"dol.h\""); + + for (Port port : p.getPortList()) { + Integer portId = _portMap.get(port); + if (!port.getBasename().equals(port.getName())) { + for (Port port2 : p.getPortList()) { + if (port2.getBasename().equals(port.getBasename())) { + if (_portMap.get(port2) < _portMap.get(port)) { + portId = _portMap.get(port2); + } + } + } + } + sed.sed(filename, "(#define[ ]+PORT_\\w*[ ]+)\"?" + + port.getBasename() + "\"?", + "$1 " + portId); + } + } + } + catch (Exception e) { + System.out.println("RtemsProcessVisitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + protected String _dir = null; + protected HashMap _portMap; + protected HashMap _sinkMap; +} diff --git a/dol/src/dol/visitor/rtems/RtemsPropertiesVisitor.java b/dol/src/dol/visitor/rtems/RtemsPropertiesVisitor.java new file mode 100644 index 0000000..71d9afd --- /dev/null +++ b/dol/src/dol/visitor/rtems/RtemsPropertiesVisitor.java @@ -0,0 +1,93 @@ +/* $Id: RtemsPropertiesVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.rtems; + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; + +import dol.datamodel.architecture.Architecture; +import dol.datamodel.architecture.Processor; +import dol.datamodel.mapping.Mapping; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.parser.xml.archischema.ArchiXmlParser; +import dol.parser.xml.mapschema.MapXmlParser; +import dol.visitor.PNVisitor; + +public class RtemsPropertiesVisitor extends PNVisitor { + + protected String _dir = null; + + public RtemsPropertiesVisitor(String dir) { + _dir = dir; + } + + public void visitComponent(ProcessNetwork x) { + try { + String filename = _dir + _delimiter + "properties"; + OutputStream file = new FileOutputStream(filename); + PrintStream ps = new PrintStream(file); + + ps.println(getProperties(x)); + } catch (Exception e) { + System.out.println("RtemsPropertiesVisitor: " + + "exception occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + public String getProperties(ProcessNetwork x) { + String file = ""; + String newline = System.getProperty("line.separator"); + file += "" + newline; + + int maxProcessorIndex; + String processorList = null; + String processList = null; + + if (_ui.getMappingFileName() == null) { + maxProcessorIndex = x.getProcessList().size() - 1; + } else { + ArchiXmlParser architectureParser = + new ArchiXmlParser(); + Architecture architecture = architectureParser.doParse( + _ui.getPlatformFileName()); + + MapXmlParser mappingParser = + new MapXmlParser(x, architecture); + Mapping mapping = mappingParser.doParse( + _ui.getMappingFileName()); + + maxProcessorIndex = 0; + for (Processor p : mapping.getProcessorList()) { + if (p.getProcessList().size() > 0) { + maxProcessorIndex = + Math.max(p.getIteratorIndices().elementAt(0), + maxProcessorIndex); + } + } + //maxProcessorIndex = mapping.getProcessorList().size() - 1; + } + + processorList = "1"; + for (int i = 1; i <= maxProcessorIndex; i++) { + processorList += "," + (i + 1); + } + + for (Process p : x.getProcessList()) { + if (processList == null) { + processList = p.getName(); + } else { + processList += "," + p.getName(); + } + } + + + file += "processors=" + (maxProcessorIndex + 1) + newline; + file += "processorList=" + processorList + newline; + file += "processList=" + processList + newline; + + return file; + } +} diff --git a/dol/src/dol/visitor/rtems/RtemsShaperVisitor.java b/dol/src/dol/visitor/rtems/RtemsShaperVisitor.java new file mode 100644 index 0000000..cd50166 --- /dev/null +++ b/dol/src/dol/visitor/rtems/RtemsShaperVisitor.java @@ -0,0 +1,50 @@ +/* $Id: RtemsShaperVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.rtems; + +import java.util.HashMap; + +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.util.Sed; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate + * a wrapper class for the traffic shaper. + */ +public class RtemsShaperVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir target directory + */ + public RtemsShaperVisitor(String dir, HashMap sinkMap) { + _dir = dir; + _sinkMap = sinkMap; + } + + /** + * + * @param x process network that needs to be processed + */ + public void visitComponent(ProcessNetwork x) { + try { + String filename = _dir + _delimiter + "traffic_shaping.h"; + + Sed sed = new Sed(); + String tmp = "NUMBER_OF_QUEUES " + x.getChannelList().size(); + sed.sed(filename, "@NUMBER_OF_QUEUES@", tmp); + tmp = "NUMBER_OF_SINKS " + _sinkMap.size(); + sed.sed(filename, "@NUMBER_OF_SINKS@", tmp); + } + catch (Exception e) { + System.out.println("RtemsProcessVisitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + protected String _dir = null; + protected HashMap _sinkMap; +} diff --git a/dol/src/dol/visitor/rtems/RtemsVisitor.java b/dol/src/dol/visitor/rtems/RtemsVisitor.java new file mode 100644 index 0000000..82b20ef --- /dev/null +++ b/dol/src/dol/visitor/rtems/RtemsVisitor.java @@ -0,0 +1,179 @@ +/* $Id: RtemsVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.rtems; + +import java.io.File; +import java.util.HashMap; +import java.util.Vector; + +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.util.Copier; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate + * a RTEMS package. + */ +public class RtemsVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param packageName name of the Rtems directory + */ + public RtemsVisitor(String packageName) { + _packageName = packageName; + } + + /** + * Visit process network. + * + * @param pn process network that needs to be rendered. + */ + public void visitComponent(ProcessNetwork pn) { + try { + File dir = new File(_packageName); + dir.mkdirs(); + + //copy library files + File source = new File(_ui.getMySystemCLib(). + replaceAll("systemC", "rtems")); + new Copier().copy(source, dir); + + //copy process source code + source = new File(_srcDirName); + new Copier().copy(source, dir); + + createPortMap(pn); + createSinkMap(pn); + pn.accept(new RtemsMakefileVisitor(_packageName)); + pn.accept(new RtemsProcessVisitor(_packageName,_portMap,_sinkMap)); + pn.accept(new RtemsModuleVisitor(_packageName, _portMap)); + pn.accept(new RtemsShaperVisitor(_packageName, _sinkMap)); + pn.accept(new RtemsPropertiesVisitor(_packageName)); + } + catch (Exception e) { + System.out.println("RtemsVisitor: exception occured: " + + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * Create a hashmap which maps each port of the given process network + * to an integer. For each process, ports are numbered with integers + * starting from 0. + * + * @param pn process network for which the map should be generated + */ + protected void createPortMap(ProcessNetwork pn) { + _portMap = new HashMap(); + + for (Process process : pn.getProcessList()) { + int portCount = 0; + Vector portList = process.getPortList(); + Vector portNameList = new Vector(); + portNameList.clear(); + HashMap portMap = + new HashMap(); + portMap.clear(); + + for (int i = 0; i < portList.size(); i++) { + //treat single ports differently than iterated ports + String portName = portList.elementAt(i).getName(); + String baseName = portList.elementAt(i).getBasename(); + + if (portName.equals(baseName)) { + portNameList.add(portName); + portMap.put(portName, portCount++); + } else { + String range_indices = portList.elementAt(i).getRange(); + Vector range_indices_values = getIndex(range_indices, ";"); + + String port_indices = portName; + port_indices.replaceAll(baseName, ""); + Vector port_indices_values = getIndex(port_indices, "_"); + + if (!portNameList.contains(baseName)) { + portNameList.add(baseName); + portMap.put(baseName, portCount); + + int size = 1; + for (int j = 0; j < range_indices_values.size(); j++) { + size *= range_indices_values.elementAt(j); + } + portCount += size; + } + + int portId = portMap.get(baseName); + for (int j = 0; j < port_indices_values.size(); j++) { + int weight = 1; + for (int k = j + 1; k < range_indices_values.size(); k++) { + weight *= range_indices_values.elementAt(k); + } + portId += port_indices_values.elementAt(j) * weight; + } + portMap.put(portName, portId); + } + } + + for (int i = 0; i < portList.size(); i++) { + _portMap.put(portList.elementAt(i), + portMap.get(portList.elementAt(i).getName())); + } + } + } + + + /** + * Create a hashmap which maps each sink of the given process network + * to an integer. For each process, sinks are numbered with integers + * starting from 1. + * + * @param pn process network for which the map should be generated + */ + protected void createSinkMap(ProcessNetwork pn) { + _sinkMap = new HashMap(); + int i = 1; + + for (Process process : pn.getProcessList()) { + if (!process.hasOutPorts()) { + _sinkMap.put(process, i); + i++; + } + } + } + + /** + * Gets vector of indices of a string, where the index must be + * separated by the specified separator. + * examples: + * getIndex("name_1_2", "_", 0) will return 1. + * getIndex("name_1_2", "_", 1) will return 2. + * + * @param range string to parse + * @param separator delimiter of indices + * @return vector of indices + */ + protected Vector getIndex(String range, String separator) { + Vector indices = new Vector(); + String[] subranges = range.split(separator); + for (int i = 0; i < subranges.length; i++) { + try { + int value = Integer.valueOf(subranges[i]); + indices.add(value); + } catch (Exception e) { + continue; + } + } + return indices; + } + + protected HashMap _portMap; + protected HashMap _sinkMap; + protected String _packageName = null; + + protected String _srcDir = ""; + protected static String _srcDirName = "src"; +} diff --git a/dol/src/dol/visitor/rtems/lib/README b/dol/src/dol/visitor/rtems/lib/README new file mode 100644 index 0000000..e5d0dc0 --- /dev/null +++ b/dol/src/dol/visitor/rtems/lib/README @@ -0,0 +1,80 @@ +How-to for running code in MPARM environment: + +One-to-one mapping: +- Generate the code: ant -f runexample -Dnumber=? mparm +- Copy the generated dir 'systemc' to /MPARM/apps +- Copy the library 'queue_lib' into dir 'systemc' +- Compile the code: make +- Link the binary: ln -sf o-optimize/app.exe TargetMem_.mem + ? depends on how many processors +- Run: $SWARMDIR/bin/mpsim.x -c --intc=i -C -S -D + ? is number of processors + + +Multi-to-one mapping: +- Modify main.c + - number_of_processes: each field is number of processes per processor + - xxx_PROCESSOR: set to a same number if mapping to common processor + - processor_init(): leave one for each processor (not necessary) +- system.c + - macro CONFIGURE_MAXIMUM_TASKS should be two times larger than the + maximum number of processes mapped to one processor. +- MAXQUEUE + - where should we put this macro ? +- If using the dol mapping specification, the processor 1 should be reserved + in the case of enabling macro QUEUE_BUFF_SHAPER ! + +MPARM queue_lib spec: +- Always use interrupt +- Always use memcpy +- DMA always enables, the switch is in the Makefile +- Token size is always 32 bits +- Default Queue size is 4, can be redefined + + +Segment wide Calibration: +- Modify Makefile: + - enable macro PERFORMANCE_EXTRACT (default disable) + - uncomment line: + CXXSRCS += lib/xmlParser.cpp lib/Performance_Extraction.cpp +- main.c: Map all processes into one processor +- Run: $SWARMDIR/bin/mpsim.x -c 1 --intc=i -C -S -D + + +Communication exploration: +- Modify Makefile: + - enable one of below macro exclusively: + - QUEUE_BUFF_IN_PRODUCER (default) + - QUEUE_BUFF_IN_PRODUCER_DMA + - QUEUE_BUFF_IN_CONSUMER + - QUEUE_BUFF_IN_CONSUMER_DMA + - QUEUE_BUFF_SHAPER + +Running mpeg2 decoder on MPARM: +- copy dol.h from other case studies +- add macro _DOL_ETHZ_GEN_ to Makefile +- change queue size to 4096 in system.h +- call mpsim.x with option --s-size=19 (scratchpad size=1Mbyts) + +Running mjpeg-2000 decoder on MPARM: +- jpeg.h + - disable macro VIEWER + - disable macros VERBOSE and INFO +- scratch_queue.h + - macro MAXQUEUE > 24, if mapping all to one processor +- system.h + - macro CONFIGURE_MAXIMUM_TASKS > 9 + + +Tricks: +- CONFIGURE_MAXIMUM_TASKS in system.h +- MAXQUEUE in scratch_queue.h +- Token size should be multiple of 4 bytes +- W/R operations should be the same size, otherwise token size should be + gcd(Write_token, Read_token). + +BUGS & TODO: +- free() in wrapper not correct +- Iterated port not tested yet +- Shaper not finished! +- Timeslice works? (Yes) diff --git a/dol/src/dol/visitor/rtems/lib/appsupport.c b/dol/src/dol/visitor/rtems/lib/appsupport.c new file mode 100644 index 0000000..7ced4a5 --- /dev/null +++ b/dol/src/dol/visitor/rtems/lib/appsupport.c @@ -0,0 +1,136 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright 2003 DEIS - Universita' di Bologna +// +// name appsupport.c +// author DEIS - Universita' di Bologna +// Davide Bertozzi - dbertozzi@deis.unibo.it +// Mirko Loghi - mloghi@deis.unibo.it +// Federico Angiolini - fangiolini@deis.unibo.it +// Francesco Poletti - fpoletti@deis.unibo.it +// portions by Massimo Scardamaglia - mascard@vizzavi.it +// info Provides support for testbench compilation +// +/////////////////////////////////////////////////////////////////////////////// +#include + +#include "appsupport.h" + +volatile char *time_low_ptr = (char *)(SIMSUPPORT_BASE + GET_TIME_ADDRESS_LO); +volatile char *time_high_ptr = (char *)(SIMSUPPORT_BASE + GET_TIME_ADDRESS_HI); +volatile char *time_stop_ptr = (char *)(SIMSUPPORT_BASE + STOP_TIME_ADDRESS); +volatile char *time_rel_ptr = (char *)(SIMSUPPORT_BASE + RELEASE_TIME_ADDRESS); + +volatile char *cycle_low_ptr = (char *)(SIMSUPPORT_BASE + GET_CYCLE_ADDRESS_LO); +volatile char *cycle_high_ptr = (char *)(SIMSUPPORT_BASE + GET_CYCLE_ADDRESS_HI); +volatile char *cycle_stop_ptr = (char *)(SIMSUPPORT_BASE + STOP_CYCLE_ADDRESS); +volatile char *cycle_rel_ptr = (char *)(SIMSUPPORT_BASE + RELEASE_CYCLE_ADDRESS); + + +/////////////////////////////////////////////////////////////////////////////// +// pr - Allows printing debug info even without support from an OS. See +// user_swi.cpp for printable messages, or to create your own + +void pr(int proc, int msg_num, int num_arg) +{ +#ifndef __OPTIMIZE__ + __asm ("ldr r1, %0" : : "g" (proc) : "r1" ); + __asm ("ldr r2, %0" : : "g" (msg_num) : "r2" ); + __asm ("ldr r3, %0" : : "g" (num_arg) : "r3" ); + __asm ("swi " SWI_PRINTstr); +#else + __asm ("mov r1, %0" : : "g" (proc) : "r1" ); + __asm ("mov r2, %0" : : "g" (msg_num) : "r2" ); + __asm ("mov r3, %0" : : "g" (num_arg) : "r3" ); + __asm ("swi " SWI_PRINTstr); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// +// get_proc_id - Allows getting the processor's ID (from 1 onwards) +unsigned int get_proc_id() +{ + char *ptr = (char *)(SIMSUPPORT_BASE + GET_CPU_ID_ADDRESS); + return (*(unsigned long int *)ptr); +} + +/////////////////////////////////////////////////////////////////////////////// +// get_proc_num - Allows getting the number of processors in the platform +unsigned int get_proc_num() +{ + char *ptr = (char *)(SIMSUPPORT_BASE + GET_CPU_CNT_ADDRESS); + return (*(unsigned long int *)ptr); +} + +// --------------------------- +// Frequency scaling functions +// --------------------------- +volatile unsigned int *freqdevice = (unsigned int *)FREQ_BASE; + +/////////////////////////////////////////////////////////////////////////////// +// scale_this_core_frequency - Scales the frequency of the core on which +// the application is running +void scale_this_core_frequency(unsigned short int divider) +{ + freqdevice[get_proc_id() - 1] = divider; +} +/////////////////////////////////////////////////////////////////////////////// +// scale_device_frequency - Scales the frequency of any device in the system +void scale_device_frequency(unsigned short int divider, int ID) +{ + freqdevice[ID] = divider; +} +/////////////////////////////////////////////////////////////////////////////// +// get_this_core_frequency - Gets the frequency divider of the core on which +// the application is running +unsigned short int get_this_core_frequency() +{ + return (freqdevice[get_proc_id() - 1]); +} +/////////////////////////////////////////////////////////////////////////////// +// get_device_frequency - Gets the frequency divider of any device in the system +unsigned short int get_device_frequency(int ID) +{ + return (freqdevice[ID]); +} + +/////////////////////////////////////////////////////////////////////////////// +// get_time - Allows getting the current simulation time +unsigned long long int get_time() +{ + unsigned long long int time; + + *time_stop_ptr = 1; + time = (((unsigned long long int)(*(unsigned long int *)time_high_ptr)) << 32) + *(unsigned long int *)time_low_ptr; + *time_rel_ptr = 1; + + return (time); +} + +/////////////////////////////////////////////////////////////////////////////// +// get_cycle - Allows getting the current simulation cycle +unsigned long long int get_cycle1() +{ + unsigned long long int cycle; + + *cycle_stop_ptr = 1; + cycle = (((unsigned long long int)(*(unsigned long int *)cycle_high_ptr)) << 32) + *(unsigned long int *)cycle_low_ptr; + *cycle_rel_ptr = 1; + + return (cycle); +} + +extern rtems_id timer_sem_id; +unsigned long long int get_cycle() +{ + unsigned long long int cycle; + rtems_status_code rtems_status; + + rtems_status = rtems_semaphore_obtain(timer_sem_id, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + *cycle_stop_ptr = 1; + cycle = (((unsigned long long int)(*(unsigned long int *)cycle_high_ptr)) + << 32) + *(unsigned long int *)cycle_low_ptr; + *cycle_rel_ptr = 1; + rtems_status = rtems_semaphore_release(timer_sem_id); + + return (cycle); +} diff --git a/dol/src/dol/visitor/rtems/lib/appsupport.h b/dol/src/dol/visitor/rtems/lib/appsupport.h new file mode 100644 index 0000000..6e50558 --- /dev/null +++ b/dol/src/dol/visitor/rtems/lib/appsupport.h @@ -0,0 +1,79 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright 2003 DEIS - Universita' di Bologna +// +// name appsupport.h +// author DEIS - Universita' di Bologna +// Davide Bertozzi - dbertozzi@deis.unibo.it +// Mirko Loghi - mloghi@deis.unibo.it +// Federico Angiolini - fangiolini@deis.unibo.it +// Francesco Poletti - fpoletti@deis.unibo.it +// portions by Massimo Scardamaglia - mascard@vizzavi.it +// info Provides support for testbench compilation +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef __APPSUPPORT_H__ +#define __APPSUPPORT_H__ + +#include "swi_calls.h" +#include "config.h" +#include "sim_support_flags.h" + +#define start_metric() __asm ("swi " SWI_METRIC_STARTstr) +#define stop_metric() __asm ("swi " SWI_METRIC_STOPstr) +#define dump_metric() __asm ("swi " SWI_METRIC_DUMPstr) +#define clear_metric() __asm ("swi " SWI_METRIC_CLEARstr) +#define stop_simulation() __asm ("swi " SWI_EXITstr) +void pr(int proc, int msg_num, int num_arg); +unsigned int get_proc_id(); + +#undef get_id +#define get_id() get_proc_id() + +unsigned int get_proc_num(); + +// --------------------------- +// Frequency scaling functions +// --------------------------- +void scale_this_core_frequency(unsigned short int divider); +void scale_device_frequency(unsigned short int divider, int ID); +unsigned short int get_this_core_frequency(); +unsigned short int get_device_frequency(int ID); + +#define RTEMS_TRACE_MAIN_APP + +#ifdef RTEMS_TRACE_MAIN_APP +//It print out the processor id, the parameter "a" and the actual clock cycles +//Eg. Processor 0 - 0x3e740 start_cycle:353089 +#define SHOW_TIME_START(a) pr(0x11111, 0x10020, (int)a) +//Eg. Processor 0 - 0x3e740 stop_cycle:353143 +#define SHOW_TIME_STOP(a) pr(0x11111, 0x10030, (int)a) +//It print out the string a +#define SHOW_DEBUG(a) pr(0x11111, 0x10000, (int)a) +#define SHOW_DEBUG_NON(a) pr(0x11111, 0x10001, (int)a) +#define SHOW_DEBUG_NOP(a) pr(0x11111, 0x10002, (int)a) +#define SHOW_DEBUG_NON_NOP(a) pr(0x11111, 0x10003, (int)a) +//It print out the integer a +#define SHOW_DEBUG_INT(a) pr(0x11111, 0x10010, (int)a) +#define SHOW_DEBUG_INT_NON(a) pr(0x11111, 0x10011, (int)a) +#define SHOW_DEBUG_INT_NOP(a) pr(0x11111, 0x10012, (int)a) +#define SHOW_DEBUG_INT_NON_NOP(a) pr(0x11111, 0x10013, (int)a) +#else +//empty definitions +#define SHOW_TIME_START(a) +#define SHOW_TIME_STOP(a) +#define SHOW_DEBUG(a) +#define SHOW_DEBUG_NON(a) +#define SHOW_DEBUG_INT_NOP(a) +#define SHOW_DEBUG_INT_NON_NOP(a) +#define SHOW_DEBUG_INT(a) +#define SHOW_DEBUG_INT_NON(a) +#define SHOW_DEBUG_INT_NOP(a) +#define SHOW_DEBUG_INT_NON_NOP(a) +#endif + +unsigned long long int get_time(); +unsigned long long int get_cycle(); +unsigned long long int get_cycle1(); + +#endif // __APPSUPPORT_H__ diff --git a/dol/src/dol/visitor/rtems/lib/buffer_test_io.h b/dol/src/dol/visitor/rtems/lib/buffer_test_io.h new file mode 100644 index 0000000..605a608 --- /dev/null +++ b/dol/src/dol/visitor/rtems/lib/buffer_test_io.h @@ -0,0 +1,117 @@ +/* + * Support for running the test output through a buffer + * + * buffer_test_io.h,v 1.1 2002/08/02 00:51:52 joel Exp + */ + +#ifndef __BUFFER_TEST_IO_h +#define __BUFFER_TEST_IO_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* + * Uncomment this to get buffered test output. When commented out, + * test output behaves as it always has and is printed ASAP. + */ + +/* #define TESTS_BUFFER_OUTPUT */ + +#if !defined(TESTS_BUFFER_OUTPUT) + +#define rtems_test_exit(_s) \ + do { \ + exit(_s); \ + } while (0) + +#define FLUSH_OUTPUT() \ + do { \ + fflush(stdout); \ + } while (0) + +#else /* buffer test output */ + +#define _TEST_OUTPUT_BUFFER_SIZE 2048 +extern char _test_output_buffer[_TEST_OUTPUT_BUFFER_SIZE]; +void _test_output_append(char *); +void _test_output_flush(void); + +#define rtems_test_exit(_s) \ + do { \ + _test_output_flush(); \ + exit(_s); \ + } while (0) + +#undef printf +#define printf(...) \ + do { \ + char _buffer[128]; \ + sprintf( _buffer, __VA_ARGS__); \ + _test_output_append( _buffer ); \ + } while (0) + +#undef puts +#define puts(_string) \ + do { \ + char _buffer[128]; \ + sprintf( _buffer, "%s\n", _string ); \ + _test_output_append( _buffer ); \ + } while (0) + +#undef putchar +#define putchar(_c) \ + do { \ + char _buffer[2]; \ + _buffer[0] = _c; \ + _buffer[1] = '\0'; \ + _test_output_append( _buffer ); \ + } while (0) + +/* we write to stderr when there is a pause() */ +#define FLUSH_OUTPUT() _test_output_flush() + +#if defined(TEST_INIT) || defined(CONFIGURE_INIT) + +char _test_output_buffer[_TEST_OUTPUT_BUFFER_SIZE]; +int _test_output_buffer_index = 0; + +void _test_output_append(char *_buffer) +{ + char *p; + + for ( p=_buffer ; *p ; p++ ) { + _test_output_buffer[_test_output_buffer_index++] = *p; + _test_output_buffer[_test_output_buffer_index] = '\0'; +#if 0 + if ( *p == '\n' ) { + fprintf( stderr, "BUFFER -- %s", _test_output_buffer ); + _test_output_buffer_index = 0; + _test_output_buffer[0] = '\0'; + } +#endif + if ( _test_output_buffer_index >= (_TEST_OUTPUT_BUFFER_SIZE - 80) ) + _test_output_flush(); + } +} + +#include +#include + +void _test_output_flush(void) +{ + fprintf( stderr, "%s", _test_output_buffer ); + _test_output_buffer_index = 0; + tcdrain( 2 ); +} + +#endif /* TEST_INIT */ +#endif /* TESTS_BUFFER_OUTPUT */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/dol/src/dol/visitor/rtems/lib/dol.h b/dol/src/dol/visitor/rtems/lib/dol.h new file mode 100644 index 0000000..f07b246 --- /dev/null +++ b/dol/src/dol/visitor/rtems/lib/dol.h @@ -0,0 +1,26 @@ +#ifndef __DOL_H__ +#define __DOL_H__ + +//structure for local memory of process +typedef struct _local_states *LocalState; + +//structure for process +struct _process; + +// +typedef void (*ProcessInit)(struct _process*); +typedef int (*ProcessFire)(struct _process*); +typedef void *WPTR; + +typedef struct _process { + LocalState local; + ProcessInit init; + ProcessFire fire; + WPTR wptr; +} DOLProcess; + +void DOL_read(void *port, void *buf, int len, DOLProcess *process); +void DOL_write(void *port, void *buf, int len, DOLProcess *process); +void DOL_detach(DOLProcess *process); + +#endif diff --git a/dol/src/dol/visitor/rtems/lib/process_wrapper_template.c b/dol/src/dol/visitor/rtems/lib/process_wrapper_template.c new file mode 100644 index 0000000..15c262b --- /dev/null +++ b/dol/src/dol/visitor/rtems/lib/process_wrapper_template.c @@ -0,0 +1,116 @@ +#include +#include +#include + +#include "rtems_process_wrapper.h" + +#ifdef WORKLOAD_EXTRACT +#define DOL_read(port, buf, len, process) \ +{ ((RtemsProcessWrapper*)process->wptr)->end_line = __LINE__; \ + DOL_read(port, buf, len, process); \ + ((RtemsProcessWrapper*)process->wptr)->start_line = __LINE__; } + +#define DOL_write(port, buf, len, process) \ +{ ((RtemsProcessWrapper*)process->wptr)->end_line = __LINE__; \ + DOL_write(port, buf, len, process); \ + ((RtemsProcessWrapper*)process->wptr)->start_line = __LINE__; } +#endif + +#ifdef PRINTF_TO_DEBUG +#undef printf +#define printf(...) \ + do { \ + char _buffer[128]; \ + sprintf(_buffer, __VA_ARGS__); \ + SHOW_DEBUG((int)_buffer); \ + } while (0) +#endif + +//#include "@PROCESSNAME@.c" + +//DOL-specific implementation +rtems_task @PROCESSNAME@_task(rtems_task_argument argument) { + RtemsProcessWrapper* wrapper = (RtemsProcessWrapper*)argument; + DOLProcess* process; + LocalState state; + int number_of_activations = 0; + int i; + rtems_task_priority old_priority; + + process = (DOLProcess *)malloc(sizeof(DOLProcess)); + state = (LocalState)malloc(sizeof(@Processname@_State)); + process->init = @PROCESSNAME@_init; + process->fire = @PROCESSNAME@_fire; + process->local = state; + process->wptr = wrapper; + + //initialize the index array + wrapper->index = (int *)malloc(4 * sizeof(int)); + for (i = 0; i < 4; i++) { + wrapper->index[i] = getIndex(wrapper->name, "_", i); + } + + printf("Start process %s.\n", wrapper->name); + process->init(process); + + //yield process such that other processes can be initialized +#ifdef MPARM + do { + rtems_task_wake_after(RTEMS_YIELD_PROCESSOR); + } while((int)get_cycle() < 1511576); +#endif + rtems_task_set_priority(RTEMS_SELF, wrapper->priority, &old_priority); + + while (!wrapper->is_detached) { + + //placeholder for periodic trigger + +#ifdef WORKLOAD_EXTRACT + wrapper->start_line = 0; + SHOW_DEBUG("log start_fire"); + SHOW_DEBUG_INT((int)get_cycle()); +#endif + + process->fire(process); + +#ifdef WORKLOAD_EXTRACT + SHOW_DEBUG("log end_fire"); + SHOW_DEBUG_INT((int)get_cycle()); + wrapper->end_line = 0; +#endif + number_of_activations++; + } + +#ifdef MPARM_SCRATCHPAD_QUEUE + #ifdef QUEUE_BUFF_SHAPER + @ENDING_SHAPER@ + #endif +#else // pc386 + //below is not necessary if no dynamic switching + //printf("Detached @PROCESSNAME@. Cleanup... "); + if (wrapper->index) { + free(wrapper->index); + } else { + printf("Could not free memory for index of @PROCESSNAME@.\n"); + } + + if (wrapper->port_id) { + free(wrapper->port_id); + } else { + printf("Could not free memory for port_id of @PROCESSNAME@.\n"); + } + + if (wrapper->port_queue_id) { + } else { + printf("Could not free memory for port_queue_id of @PROCESSNAME@.\n"); + } +#endif // MPARM_SCRATCHPAD_QUEUE + //printf("Done.\n"); + + printf("Detach process %s.\n", wrapper->name); +#ifdef MPARM + Cleanup(); +#endif + + rtems_task_delete(RTEMS_SELF); +} diff --git a/dol/src/dol/visitor/rtems/lib/rtems_process_wrapper.c b/dol/src/dol/visitor/rtems/lib/rtems_process_wrapper.c new file mode 100644 index 0000000..387818e --- /dev/null +++ b/dol/src/dol/visitor/rtems/lib/rtems_process_wrapper.c @@ -0,0 +1,253 @@ +#include +#include "rtems_process_wrapper.h" + +/** + * + */ +void DOL_read(void *port, void *buf, int len, DOLProcess *process) { + RtemsProcessWrapper* process_wrapper = (RtemsProcessWrapper*)process->wptr; + int i; + +#ifdef WORKLOAD_EXTRACT + SHOW_DEBUG("log start_read"); + SHOW_DEBUG_INT((int)get_cycle()); + SHOW_DEBUG_INT((int)port); + SHOW_DEBUG_INT((int)(process_wrapper->start_line)); + SHOW_DEBUG_INT((int)(process_wrapper->end_line)); + SHOW_DEBUG_INT((int)len); +#endif + +#ifdef MPARM_SCRATCHPAD_QUEUE + for (i = 0; i < process_wrapper->number_of_in_ports; i++) { + // len not taken into account yet !!!!!!! + if (process_wrapper->in_port_id[i] == (int)port) { + SCRATCH_QUEUE_CONSUMER* queue_id = + (SCRATCH_QUEUE_CONSUMER*)process_wrapper->in_queue_id[i]; + +#if defined (QUEUE_BUFF_IN_PRODUCER) + scratch_queue_read(queue_id, (char *)buf, len); +#elif defined (QUEUE_BUFF_IN_PRODUCER_DMA) + scratch_queue_read_dma(queue_id, (char *)buf, len); +#elif defined (QUEUE_BUFF_IN_CONSUMER) + scratch_queue_read(queue_id, (char *)buf, len); +#elif defined (QUEUE_BUFF_IN_CONSUMER_DMA) + scratch_queue_read(queue_id, (char *)buf, len); +#elif defined (QUEUE_BUFF_IN_SHARDMEM) + scratch_queue_read(queue_id, (char *)buf, len); +#elif defined (QUEUE_BUFF_SHAPER) + scratch_queue_read_2(queue_id, (char *)buf, len); +#endif + break; + } + } +#else // pc386 + for (i = 0; i < process_wrapper->number_of_ports; i++) { + if (process_wrapper->port_id[i] == (int)port) { + int queue_id = process_wrapper->port_queue_id[i]; + int j; + + //receive message byte-per-byte + for (j = 0; j < len; j++) { + size_t size = 1; + rtems_message_queue_receive( + queue_id, + buf + j, + &size, + RTEMS_DEFAULT_ATTRIBUTES, + RTEMS_NO_TIMEOUT); + } + break; + } + } +#endif // end MPARM_SCRATCHPAD_QUEUE + + //SHOW_DEBUG("read from app"); + //SHOW_DEBUG_INT(*(int *)buf); + +#ifdef WORKLOAD_EXTRACT + SHOW_DEBUG("log end_read"); + SHOW_DEBUG_INT((int)get_cycle()); + SHOW_DEBUG_INT((int)port); +#endif +} + +/** + * + */ +void DOL_write(void *port, void *buf, int len, DOLProcess *process) { + RtemsProcessWrapper* process_wrapper = (RtemsProcessWrapper*)process->wptr; + int i; + +#ifdef WORKLOAD_EXTRACT + SHOW_DEBUG("log start_write"); + SHOW_DEBUG_INT((int)get_cycle()); + SHOW_DEBUG_INT((int)port); + SHOW_DEBUG_INT((int)(process_wrapper->start_line)); + SHOW_DEBUG_INT((int)(process_wrapper->end_line)); + SHOW_DEBUG_INT((int)len); +#endif + +#if defined MPARM_SCRATCHPAD_QUEUE + for (i = 0; i < process_wrapper->number_of_out_ports; i++) { + if (process_wrapper->out_port_id[i] == (int)port) { + SCRATCH_QUEUE_PRODUCER* queue_id = + (SCRATCH_QUEUE_PRODUCER*)process_wrapper->out_queue_id[i]; + + +#if defined (QUEUE_BUFF_IN_PRODUCER) || (QUEUE_BUFF_IN_CONSUMER) + scratch_queue_write(queue_id, (char *)buf, len); +#elif defined (QUEUE_BUFF_IN_PRODUCER_DMA) || (QUEUE_BUFF_IN_CONSUMER_DMA) + scratch_queue_write_dma(queue_id, (char *)buf, len); +#elif defined (QUEUE_BUFF_IN_SHARDMEM) + scratch_queue_write(queue_id, (char *)buf, len); +#elif defined(QUEUE_BUFF_SHAPER) + scratch_queue_write_2(queue_id, (char *)buf, len); // (2) shaper +#endif + + break; + } + } +#else // pc386 + for (i = 0; i < process_wrapper->number_of_ports; i++) { + if (process_wrapper->port_id[i] == (int)port) { + int queue_id = process_wrapper->port_queue_id[i]; + rtems_status_code status; + int j; + + //send message byte-per-byte + for (j = 0; j < len; j++) { + do { + status = rtems_message_queue_send(queue_id, buf + j, 1); + if (status != RTEMS_SUCCESSFUL) { + rtems_task_wake_after(0); + } + } while (status != RTEMS_SUCCESSFUL); + } + + break; + } + } +#endif // end MPARM_SCRATCHPAD_QUEUE + +#ifdef WORKLOAD_EXTRACT + SHOW_DEBUG("log end_write"); + SHOW_DEBUG_INT((int)get_cycle()); + SHOW_DEBUG_INT((int)port); +#endif +} + +/** + * + */ +void DOL_detach(DOLProcess *process) { + //printf("[%s] DOL_detach.\n", (char*)(process->local)); + ((RtemsProcessWrapper*)process->wptr)->is_detached = 1; +} + +/** + * Gets an index of a string, where the index must be separated by + * a character specified in tokens. + * Returns -1, when an error occurs. + * + * Example: + * getIndex("name_1_2", "_", 0) will return 1. + * getIndex("name_1_2", "_", 1) will return 2. + * + * @param string string to parse + * @param tokens delimiter of indices + * @param indexNumber position of index (starting at 0) + */ +int getIndex(const char* string, char* tokens, int indexNumber) { + char* string_copy; + char* token_pointer; + int index = 0; + + string_copy = (char*) malloc(sizeof(char) * (strlen(string) + 1)); + if (!string_copy) { + fprintf(stderr, "getIndex(): could not allocate memory.\n"); + return -1; + } + + strcpy(string_copy, string); + + token_pointer = strtok(string_copy, tokens); + do { + token_pointer = strtok(NULL, tokens); + index++; + } while (index <= indexNumber && token_pointer != 0); + + if (token_pointer) { + index = atoi(token_pointer); + free(string_copy); + return index; + } + + free(string_copy); + return -1; +} + +/** + * Create the port name of an iterated port based on its basename and the + * given indices. + * + * @param port buffer where the result is stored (created using + * CREATEPORTVAR) + * @param base basename of the port + * @param number_of_indices number of dimensions of the port + * @param index_range_pairs index and range values for each dimension + */ +int *createPort(int *port, int base, int number_of_indices, + int index_range_pairs, ...) { + int index[4]; + int range[4]; + int i; + int value; + + va_list marker; + va_start(marker, index_range_pairs); + + value = index_range_pairs; + for (i = 0; i < number_of_indices; i++) { + index[i] = value; + value = va_arg(marker, int); + range[i] = value; + if (i < number_of_indices - 1) { + value = va_arg(marker, int); + } + } + + *port = base; + for (i = 0; i < number_of_indices; i++) { + int j; + int weight = 1; + for (j = 1; j < number_of_indices - i; j ++) { + weight *= range[j]; + } + *port += index[i] * weight; + } + + /* + switch (number_of_indices) { + case 1: + *port = base + index[0]; + break; + case 2: + *port = base + index[0] * range[1] + + index[1]; + break; + case 3: + *port = base + index[0] * range[1] * range[2] + + index[1] * range[0] + + index[2]; + break; + case 4: + *port = base + index[0] * range[1] * range[2] * range[3] + + index[1] * range[2] * range[3] + + index[2] * range[3] + + index[3]; + break; + } + */ + + return port; +} diff --git a/dol/src/dol/visitor/rtems/lib/rtems_process_wrapper.h b/dol/src/dol/visitor/rtems/lib/rtems_process_wrapper.h new file mode 100644 index 0000000..c72022b --- /dev/null +++ b/dol/src/dol/visitor/rtems/lib/rtems_process_wrapper.h @@ -0,0 +1,106 @@ +#ifndef __RTEMS_PROCESS_WRAPPER_H__ +#define __RTEMS_PROCESS_WRAPPER_H__ + +#include +#include +#include +#include +#include +#include "dol.h" + +#ifdef MPARM_SCRATCHPAD_QUEUE +#include "scratch_queue.h" +#endif + +#ifdef MPARM +#define printf(format ...) { char stringBuffer[80]; sprintf(stringBuffer, format); SHOW_DEBUG(stringBuffer); } +#endif + +typedef struct _process_wrapper { + DOLProcess *dol_process; + char* name; + int* index; + int is_detached; + int priority; +#ifdef WORKLOAD_EXTRACT + int start_line; + int end_line; +#endif +#ifdef MPARM_SCRATCHPAD_QUEUE + int* in_port_id; + int* out_port_id; + SCRATCH_QUEUE_PRODUCER** out_queue_id; + SCRATCH_QUEUE_CONSUMER** in_queue_id; + int number_of_in_ports; + int number_of_out_ports; +#else // for pc396 + int* port_id; + int* port_queue_id; + int number_of_ports; +#endif +} RtemsProcessWrapper; + +// define queue memory in consumer scratchpad +//#define QUEUE_IN_CONSUMER + +/** + * Gets an index of a string, where the index must be separated by + * a character specified in tokens. + * Returns -1, when an error occurs. + * + * Example: + * getIndex("name_1_2", "_", 0) will return 1. + * getIndex("name_1_2", "_", 1) will return 2. + * + * @param string string to parse + * @param tokens delimiter of indices + * @param indexNumber position of index (starting at 0) + */ +int getIndex(const char* string, char* tokens, int indexNumber); + +/** + * Create the port name of an iterated port based on its basename and the + * given indices. + * + * @param port buffer where the result is stored (created using + * CREATEPORTVAR) + * @param base basename of the port + * @param number_of_indices number of dimensions of the port + * @param index_range_pairs index and range values for each dimension + */ +int *createPort(int *port, int base, int number_of_indices, int index_range_pairs, ...); + +//DOL macros +#define GETINDEX(dimension) \ + ((RtemsProcessWrapper*)(p->wptr))->index[dimension] + +#define CREATEPORTVAR(name) \ + int name + +#define CREATEPORT(port, base, number_of_indices, index_range_pairs...) \ + createPort(&port, base, number_of_indices, index_range_pairs) + +#ifdef PERFORMANCE_EXTRACT +#include "Performance_Extraction.h" +#endif + +#ifdef MPARM +extern unsigned int active_processes; +inline void Cleanup() { + register rtems_interrupt_level level; + rtems_interrupt_disable(level); + active_processes--; + + if(active_processes==0) { +#ifdef PERFORMANCE_EXTRACT + performance_extraction.write_to_xml_file("calibration"); +#endif + printf("All processes detached."); + rtems_interrupt_enable(level); + exit(0); + } + rtems_interrupt_enable(level); +} +#endif + +#endif diff --git a/dol/src/dol/visitor/rtems/lib/system.h b/dol/src/dol/visitor/rtems/lib/system.h new file mode 100644 index 0000000..147d79f --- /dev/null +++ b/dol/src/dol/visitor/rtems/lib/system.h @@ -0,0 +1,64 @@ +/* system.h + * + * This include file contains information that is included in every + * function in the test set. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * + * system.h,v 1.12 2000/06/12 15:00:11 joel Exp + */ + +#include "tmacros.h" +#include "appsupport.h" + +// Functions +rtems_task Init(rtems_task_argument argument); +rtems_task Test_task(rtems_task_argument argument); + +// Configuration information +#define CONFIGURE_TEST_NEEDS_CONSOLE_DRIVER + +#define MAXIMUM_REGIONS 2 + +#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES 4 + +// Tells confdefs.h to build the init task configuration +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE +// ?????? +#define CONFIGURE_TICKS_PER_TIMESLICE 100 // ??? + +#define CONFIGURE_MAXIMUM_TASKS 32 + +// Tells confdefs.h to build the default configuration table +#ifdef TEST_INIT +#define CONFIGURE_INIT +#endif + +#define CONFIGURE_MP_APPLICATION +//These are just to allow the OS to be able to compile. +//Then this value is overwritten during the boot of the OS, +//using the call to coprocessor functions +#define CONFIGURE_MP_MAXIMUM_NODES 1 +#define NODE_NUMBER 1 + + +///////////////////////////////// +#define SCRATCHPAD_QUEUE // enable scratchpad queue + +#define DEFAULT_BUFFER_SIZE 100 //scratchpad queue size +#define TOKEN_BYTES 4096 + +#define CONFIGURE_MAXIMUM_SEMAPHORES 2 + +//#define MAXQUEUE 10 +//#define SCRATCH_SIZE_PLATFORM (1024*512) + + + +#include + diff --git a/dol/src/dol/visitor/rtems/lib/tmacros.h b/dol/src/dol/visitor/rtems/lib/tmacros.h new file mode 100644 index 0000000..76308ad --- /dev/null +++ b/dol/src/dol/visitor/rtems/lib/tmacros.h @@ -0,0 +1,247 @@ +/* tmacros.h + * + * This include file contains macros which are useful in the RTEMS + * test suites. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * + * tmacros.h,v 1.25 2002/08/02 00:51:52 joel Exp + */ + +#ifndef __TMACROS_h +#define __TMACROS_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include /* includes */ + +#include +#include +#include +#include +#include + +#define FOREVER 1 /* infinite loop */ + +#ifdef TEST_INIT +#define TEST_EXTERN +#else +#define TEST_EXTERN extern +#endif + +#include "buffer_test_io.h" + +/* + * Check that that the dispatch disable level is proper for the + * mode/state of the test. Normally it should be 0 when in task space. + */ + +#define check_dispatch_disable_level( _expect ) \ + do { \ + extern volatile rtems_unsigned32 _Thread_Dispatch_disable_level; \ + if ( (_expect) != -1 && _Thread_Dispatch_disable_level != (_expect) ) { \ + printf( "\n_Thread_Dispatch_disable_level is (%d) not %d\n", \ + _Thread_Dispatch_disable_level, (_expect) ); \ + FLUSH_OUTPUT(); \ + rtems_test_exit( 1 ); \ + } \ + } while ( 0 ) + +/* + * These macros properly report errors within the Classic API + */ + +#define directive_failed( _dirstat, _failmsg ) \ + fatal_directive_status( _dirstat, RTEMS_SUCCESSFUL, _failmsg ) + +#define directive_failed_with_level( _dirstat, _failmsg, _level ) \ + fatal_directive_status_with_level( \ + _dirstat, RTEMS_SUCCESSFUL, _failmsg, _level ) + +#define fatal_directive_status( _stat, _desired, _msg ) \ + fatal_directive_status_with_level( _stat, _desired, _msg, 0 ) + +#define fatal_directive_check_status_only( _stat, _desired, _msg ) \ + do { \ + if ( (_stat) != (_desired) ) { \ + printf( "\n%s FAILED -- expected (%s) got (%s)\n", \ + (_msg), rtems_status_text(_desired), rtems_status_text(_stat) ); \ + FLUSH_OUTPUT(); \ + rtems_test_exit( _stat ); \ + } \ + } while ( 0 ) + +#define fatal_directive_status_with_level( _stat, _desired, _msg, _level ) \ + do { \ + check_dispatch_disable_level( _level ); \ + fatal_directive_check_status_only( _stat, _desired, _msg ); \ + } while ( 0 ) + +/* + * These macros properly report errors from the POSIX API + */ + +#define posix_service_failed( _dirstat, _failmsg ) \ + fatal_posix_service_status( _dirstat, RTEMS_SUCCESSFUL, _failmsg ) + +#define posix_service_failed_with_level( _dirstat, _failmsg, _level ) \ + fatal_posix_service_status_with_level( \ + _dirstat, RTEMS_SUCCESSFUL, _failmsg, _level ) + +#define fatal_posix_service_status( _stat, _desired, _msg ) \ + fatal_posix_service_status_with_level( _stat, _desired, _msg, 0 ) + +#define fatal_posix_service_status_with_level( _stat, _desired, _msg, _level ) \ + do { \ + check_dispatch_disable_level( _level ); \ + if ( (_stat) != (_desired) ) { \ + printf( "\n%s FAILED -- expected (%d - %s) got (%d - %s)\n", \ + (_msg), _desired, strerror(_desired), _stat, strerror(_stat) ); \ + printf( "\n FAILED -- errno (%d - %s)\n", \ + errno, strerror(errno) ); \ + FLUSH_OUTPUT(); \ + rtems_test_exit( _stat ); \ + } \ + } while ( 0 ) + +/* + * Generic integer version of the error reporting + */ + +#define int_service_failed( _dirstat, _failmsg ) \ + fatal_int_service_status( _dirstat, RTEMS_SUCCESSFUL, _failmsg ) + +#define int_service_failed_with_level( _dirstat, _failmsg, _level ) \ + fatal_int_service_status_with_level( \ + _dirstat, RTEMS_SUCCESSFUL, _failmsg, _level ) + +#define fatal_int_service_status( _stat, _desired, _msg ) \ + fatal_int_service_status_with_level( _stat, _desired, _msg, 0 ) + +#define fatal_int_service_status_with_level( _stat, _desired, _msg, _level ) \ + do { \ + check_dispatch_disable_level( _level ); \ + if ( (_stat) != (_desired) ) { \ + printf( "\n%s FAILED -- expected (%d) got (%d)\n", \ + (_msg), (_desired), (_stat) ); \ + FLUSH_OUTPUT(); \ + rtems_test_exit( _stat ); \ + } \ + } while ( 0 ) + +/* + * Print the time: modificata per swarm da Poletti Francesco per risolvere il + * problema di stampa degli interi + */ + +#define print_time(_s1, _tb, _s2) \ + do { \ + myprint( "%s%02d:%02d:%02d %02d/%02d/%0d%s", \ + _s1, (_tb)->hour, (_tb)->minute, (_tb)->second, \ + (_tb)->month, (_tb)->day, (_tb)->year, _s2 ); \ + fflush(stdout); \ + } while ( 0 ) + + +#define sprint_time(_str, _s1, _tb, _s2) \ + do { \ + sprintf( (str), "%s%02d:%02d:%02d %02d/%02d/%04d%s", \ + _s1, (_tb)->hour, (_tb)->minute, (_tb)->second, \ + (_tb)->month, (_tb)->day, (_tb)->year, _s2 ); \ + } while ( 0 ) + +#define put_dot( _c ) \ + do { \ + putchar( _c ); \ + FLUSH_OUTPUT(); \ + } while ( 0 ) + +#define new_line puts( "" ) + +#define puts_nocr printf + +#ifdef RTEMS_TEST_NO_PAUSE +#define rtems_test_pause() \ + do { \ + printf( "\n" ); \ + FLUSH_OUTPUT(); \ + } while ( 0 ) + +#define rtems_test_pause_and_screen_number( _screen ) \ + do { \ + printf( "\n", (_screen) ); \ + FLUSH_OUTPUT(); \ + } while ( 0 ) +#else +#define rtems_test_pause() \ + do { \ + char buffer[ 80 ]; \ + printf( "" ); \ + FLUSH_OUTPUT(); \ + gets( buffer ); \ + puts( "" ); \ + } while ( 0 ) + +#define rtems_test_pause_and_screen_number( _screen ) \ + do { \ + char buffer[ 80 ]; \ + printf( "", (_screen) ); \ + FLUSH_OUTPUT(); \ + gets( buffer ); \ + puts( "" ); \ + } while ( 0 ) +#endif + +#define put_name( _name, _crlf ) \ + do { char buf[6];int i=1;\ + rtems_unsigned32 c0, c1, c2, c3; \ + \ + c0 = ((_name) >> 24) & 0xff; \ + c1 = ((_name) >> 16) & 0xff; \ + c2 = ((_name) >> 8) & 0xff; \ + c3 = (_name) & 0xff; \ + buf[0]=c0; \ + if ( c1 ) {buf[i]=(char)c1; i++;} ; \ + if ( c2 ) {buf[i]=(char)c2; i++;}; \ + if ( c3 ) {buf[i]=(char)c3; i++;}; \ + if ( (_crlf) ) {buf[i]='\n'; i++;}\ + buf[i]=0;\ + printf(buf);\ + } while (0) + +#ifndef build_time +#define build_time( TB, MON, DAY, YR, HR, MIN, SEC, TK ) \ + { (TB)->year = YR; \ + (TB)->month = MON; \ + (TB)->day = DAY; \ + (TB)->hour = HR; \ + (TB)->minute = MIN; \ + (TB)->second = SEC; \ + (TB)->ticks = TK; } +#endif + +#define task_number( tid ) \ + ( rtems_get_index( tid ) - \ + rtems_configuration_get_rtems_api_configuration()->number_of_initialization_tasks ) + +static inline rtems_unsigned32 get_ticks_per_second( void ) +{ + rtems_interval ticks_per_second; + (void) rtems_clock_get( RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second ); + return ticks_per_second; +} + +#define TICKS_PER_SECOND get_ticks_per_second() + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/dol/src/dol/visitor/rtems/lib/traffic_shaping.c b/dol/src/dol/visitor/rtems/lib/traffic_shaping.c new file mode 100644 index 0000000..d47d2f5 --- /dev/null +++ b/dol/src/dol/visitor/rtems/lib/traffic_shaping.c @@ -0,0 +1,189 @@ +#include +#include + +#include "appsupport.h" +#include "rtems_process_wrapper.h" +#include "traffic_shaping.h" + +unsigned int sink_processes; +void sink_end_process(rtems_task_argument argument); +void queue_status_process(rtems_task_argument argument); +void shaping_process(rtems_task_argument argument); +rtems_task shaping_init(rtems_task_argument argument) { + rtems_id task_id; + rtems_status_code status; + QUEUE_WRAPPER *queue_wrap, *sink_wrap; + rtems_name name; + int i; + + // instatiate daemons for data transfer notices + queue_wrap = (QUEUE_WRAPPER *)malloc(NUMBER_OF_QUEUES * + sizeof(QUEUE_WRAPPER)); + for (i=0; i < NUMBER_OF_QUEUES; i++) { + queue_wrap[i].q = scratch_queue_autoinit_shaper(i+1, 0, 0, 0); + queue_wrap[i].hasData = 0; + } + + for (i=0; i< NUMBER_OF_QUEUES; i++) { + name = rtems_build_name('q', 's', i+1, 'c'); + status = rtems_task_create(name, + 127, + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_MODES, + RTEMS_LOCAL, + &task_id, -1); + if (status != RTEMS_SUCCESSFUL) { + printf("[init ] Create queue process failed (status %d).\n", + status); + rtems_shutdown_executive(0); + } + status = rtems_task_start(task_id, queue_status_process, + (rtems_task_argument)&queue_wrap[i]); + if (status != RTEMS_SUCCESSFUL) { + printf("[init ] Start queue process failed (status %d).\n", + status); + rtems_shutdown_executive(0); + } + } + + // instatiate daemons to wait for sinks finishing + sink_processes = NUMBER_OF_SINKS; + sink_wrap = (QUEUE_WRAPPER *)malloc(NUMBER_OF_SINKS * + sizeof(QUEUE_WRAPPER)); + for (i=0; iq; + +/* printf("queue:%x, traffice_shaping: " + "\n\t sem_shaper_used:%x, " + "\n\t sem_shaper_left:%x, " + "\n\t semaphore_left:%x, " + "\n\t semaphore_used:%x", + wrap->q, + queue->sem_shaper_used, + queue->sem_shaper_left, + queue->semaphore_left, + queue->semaphore_used + ); */ + + while (1) { + // always USEINTERRUPT + ss_sem_wait(queue->sem_shaper_used); + ss_sem_wait(queue->sem_shaper_left); + + wrap->hasData ++; + } +} + +void sink_end_process(rtems_task_argument argument) +{ + QUEUE_WRAPPER *queue_wrap = (QUEUE_WRAPPER *) argument; + + // wait for terminating signal from sink + ss_sem_wait(queue_wrap->sem_terminate); + + sink_processes--; + if (sink_processes == 0) { + SHOW_DEBUG("END!!!"); + exit(0); + } +} + +static int cur_queue; // current queue +QUEUE_WRAPPER * get_next_queue(QUEUE_WRAPPER * queue_wrap); +int canSend(QUEUE_WRAPPER * queue); +void shaping_process(rtems_task_argument argument) +{ + QUEUE_WRAPPER *queue_wrap = (QUEUE_WRAPPER *) argument; + cur_queue = 0; + + while (1) { + QUEUE_WRAPPER *q_w; + q_w = get_next_queue(queue_wrap); + + if (canSend(q_w)) { + if (q_w->hasData) { + scratch_queue_shaperRW(q_w->q); + q_w->hasData--; + } + } + } + +} + +#define PULL_MODE +// queue scheduling +QUEUE_WRAPPER * get_next_queue(QUEUE_WRAPPER * queue_wrap) +{ + // round robin +#ifdef PULL_MODE + cur_queue = (cur_queue == 0) ? NUMBER_OF_QUEUES : cur_queue; + cur_queue --; +#else // PUSH MODE + cur_queue++; + cur_queue = (cur_queue == NUMBER_OF_QUEUES) ? 0 : cur_queue; +#endif + return &queue_wrap[cur_queue]; +} + + +// shaping +int canSend(QUEUE_WRAPPER * queue) +{ + return 1; +} + + + diff --git a/dol/src/dol/visitor/rtems/lib/traffic_shaping.h b/dol/src/dol/visitor/rtems/lib/traffic_shaping.h new file mode 100644 index 0000000..2ff49b8 --- /dev/null +++ b/dol/src/dol/visitor/rtems/lib/traffic_shaping.h @@ -0,0 +1,17 @@ +#ifndef TRAFFIC_SHAPING_H +#define TRAFFIC_SHAPING_H + +#include "scratch_queue.h" + +typedef struct _queue_wrapper { + SCRATCH_QUEUE_SHAPER *q; + int hasData; + QUEUE_SEMAPHORE sem_terminate; +} QUEUE_WRAPPER; + +#define @NUMBER_OF_QUEUES@ // generated +#define @NUMBER_OF_SINKS@ // generated + +rtems_task shaping_init(rtems_task_argument argument); + +#endif diff --git a/dol/src/dol/visitor/systemC/MakefileVisitor.java b/dol/src/dol/visitor/systemC/MakefileVisitor.java new file mode 100644 index 0000000..c53f585 --- /dev/null +++ b/dol/src/dol/visitor/systemC/MakefileVisitor.java @@ -0,0 +1,72 @@ +/* $Id: MakefileVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.systemC; + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; + +import dol.datamodel.pn.ProcessNetwork; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate + * a SystemC package Makefile. + */ +public class MakefileVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir path of the Makefile + */ + public MakefileVisitor(String dir) { + _dir = dir; + } + + /** + * Create a Makefile for the given process network. + * + * @param x process network that needs to be rendered. + */ + public void visitComponent(ProcessNetwork x) { + try { + String filename = _dir + _delimiter + "Makefile"; + OutputStream file = new FileOutputStream(filename); + PrintStream ps = new PrintStream(file); + + ps.println("CXX = g++"); + ps.println("CC = g++"); + ps.println(); + ps.println("SYSTEMC_INC = -I" + _ui.getSystemCINC()); + ps.println("SYSTEMC_LIB = " + _ui.getSystemCLIB()); + ps.println("MY_LIB_INC = -Ilib -Isc_wrappers -Iprocesses"); + ps.println("VPATH = lib:sc_wrappers:processes"); + ps.println(); + ps.println("CXXFLAGS = -g -O0 -D__DOL_ETHZ_GEN__ $(SYSTEMC_INC) $(MY_LIB_INC)"); + ps.println("CFLAGS = $(CXXFLAGS)"); + ps.println(); + + ps.print("PROCESS_OBJS = dol.o "); + for (String basename : x.getProcessBasenames()) { + ps.print(basename + "_wrapper.o "); + } + ps.println(); + ps.println(); + ps.println("all:" + _name); + ps.println(); + ps.println(_name + ": " + _name + ".o $(PROCESS_OBJS)"); + ps.println("\t$(CXX) $(CXXFLAGS) -o $@ $^ $(SYSTEMC_LIB)"); + ps.println("clean:"); + ps.println("\t-rm -f *.o core core.* *.core " + _name); + + } catch (Exception e) { + System.out.println(" SystemC Makefile Visitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + + } + + protected String _dir = null; + protected String _name = "sc_application"; +} diff --git a/dol/src/dol/visitor/systemC/PNSystemCVisitor.java b/dol/src/dol/visitor/systemC/PNSystemCVisitor.java new file mode 100644 index 0000000..e043782 --- /dev/null +++ b/dol/src/dol/visitor/systemC/PNSystemCVisitor.java @@ -0,0 +1,101 @@ +/* $Id: PNSystemCVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.systemC; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; + +import dol.datamodel.pn.ProcessNetwork; +import dol.util.CodePrintStream; +import dol.util.Copier; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate + * a SystemC package. + */ +public class PNSystemCVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param packageName Name of the SystemC directory + */ + public PNSystemCVisitor(String packageName) { + _packageName = packageName; + } + + /** + * + * @param x process network that needs to be rendered. + */ + public void visitComponent(ProcessNetwork x) { + try { + //_packageName = x.getName() + "SystemCPackage"; + _generateDirHierarchy(); + + x.accept(new MakefileVisitor(_srcDir)); + x.accept(new SCModuleVisitor(_srcDir)); + x.accept(new ProcessVisitor(_wrapperDir)); + + } + catch (Exception e) { + System.out.println(" SystemC PN Visitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * + */ + protected void _generateDirHierarchy() + throws IOException, FileNotFoundException { + File dir = new File(_packageName); + dir.mkdirs(); + + _srcDir = _packageName + _delimiter + _srcDirName; + dir = new File(_srcDir); + dir.mkdirs(); + + _libDir = _srcDir + _delimiter + _libDirName; + dir = new File(_libDir); + dir.mkdirs(); + + _processDir = _srcDir + _delimiter + _processDirName; + dir = new File(_processDir); + dir.mkdirs(); + + _wrapperDir = _srcDir + _delimiter + _wrapperDirName; + dir = new File(_wrapperDir); + dir.mkdirs(); + + //copy library files + File source = new File(_ui.getMySystemCLib()); + File destination = new File(_libDir); + new Copier().copy(source, destination); + + //copy process source code + source = new File(_srcDirName); + destination = new File(_processDir); + new Copier().copy(source, destination); + } + + protected String _packageName = null; + + protected String _srcDir = ""; + protected static String _srcDirName = "src"; + + protected String _libDir = ""; + protected static String _libDirName = "lib"; + + protected String _processDir = ""; + protected static String _processDirName = "processes"; + + protected String _wrapperDir = ""; + protected static String _wrapperDirName = "sc_wrappers"; + + protected String _threadPostfix = "_thread"; + + protected CodePrintStream _mainPS = null; +} diff --git a/dol/src/dol/visitor/systemC/ProcessVisitor.java b/dol/src/dol/visitor/systemC/ProcessVisitor.java new file mode 100644 index 0000000..f87545b --- /dev/null +++ b/dol/src/dol/visitor/systemC/ProcessVisitor.java @@ -0,0 +1,351 @@ +/* $Id: ProcessVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.systemC; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Vector; + +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.SourceCode; +import dol.util.CodePrintStream; +import dol.util.Sed; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate + * a SystemC wrapper for a process: process_wrapper.[h/cpp]. + */ +public class ProcessVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir target directory + */ + public ProcessVisitor(String dir) { + _dir = dir; + } + + /** + * + * @param x process network that needs to be rendered + */ + public void visitComponent(ProcessNetwork x) { + try { + Vector pList = new Vector(); + + for (Process p : x.getProcessList()) { + String basename = p.getBasename(); + if (!pList.contains(basename)) { + pList.add(basename); + p.accept(this); + } + } + } + catch (Exception e) { + System.out.println("Process Visitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * + * @param p process that needs to be rendered + */ + public void visitComponent(Process p) { + try { + _createCppFile(p); + _createHeaderFile(p); + _adaptSources(p); + } + catch (Exception e) { + System.out.println("Process Visitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * + */ + protected void _createCppFile(Process p) throws IOException { + String filename = _dir + _delimiter + p.getBasename() + + "_wrapper.cpp"; + OutputStream file = new FileOutputStream(filename); + CodePrintStream ps = new CodePrintStream(file); + + ps.printPrefixln("#include \"" + p.getBasename() + + "_wrapper.h\""); + ps.printPrefixln(); + + if (p.hasOutPorts()) { + //DOL_write() + ps.printPrefixln("static inline int DOL_write(void *port, " + + "void *buf, int len, DOLProcess *process)"); + ps.printLeftBracket(); + ps.printPrefixln("char *str = (char *)buf;"); + ps.printPrefixln("while (len-- > 0) "); + ps.printLeftBracket(); + + int j = 0; + for (Port ip : p.getPortList()) { + if (ip.isOutPort()) { + String s = (j++ == 0) ? "if " : " else if "; + ps.printPrefixln(s + "(strstr(\" OUTPORT_" + + ip.getName() + "\", (const char*)port)) "); + ps.printLeftBracket(); + ps.printPrefixln("(static_cast<" + p.getBasename() + + "_wrapper *>(process->wptr))->OUTPORT_" + + ip.getName() + "->write(*(str++));"); + ps.printRightBracket(); + } + } + ps.printRightBracket(); + ps.printRightBracket(); + + //DOL_wtest() + ps.printPrefixln("static inline int DOL_wtest(void *port, " + + "int len, DOLProcess *process)"); + ps.printLeftBracket(); + j = 0; + for (Port ip : p.getPortList()) { + if (ip.isOutPort()) { + String s = (j++ == 0) ? "if " : "else if "; + ps.printPrefixln(s + "(strstr(\" OUTPORT_" + + ip.getName() + "\", (const char*)port)) "); + ps.printLeftBracket(); + ps.printPrefixln("return (static_cast<" + p.getBasename() + + "_wrapper *>(process->wptr))->OUTPORT_" + + ip.getName() + "->wtest(len);"); + ps.printRightBracket(); + } + } + ps.printRightBracket(); + } + + ps.printPrefixln(); + if (p.hasInPorts()) { + //DOL_read() + ps.printPrefixln("static inline int DOL_read(void *port, " + + "void *buf, int len, DOLProcess *process)"); + ps.printLeftBracket(); + ps.printPrefixln("char *str = (char *)buf;"); + ps.printPrefixln("while (len-- > 0)"); + ps.printLeftBracket(); + + int j = 0; + for (Port ip : p.getPortList()) { + if (ip.isInPort()) { + String s = (j++ == 0) ? "if " : "else if "; + ps.printPrefixln(s + "(strstr(\" INPORT_" + + ip.getName() + "\", (const char*)port))"); + ps.printLeftBracket(); + ps.printPrefixln("(static_cast<" + p.getBasename() + + "_wrapper *>(process->wptr))->INPORT_" + + ip.getName() + "->read(*(str++));"); + ps.printRightBracket(); + } + } + ps.printRightBracket(); + ps.printRightBracket(); + + //DOL_rtest() + ps.printPrefixln("static inline int DOL_rtest(void *port, " + + "int len, DOLProcess *process)"); + ps.printLeftBracket(); + j = 0; + for (Port ip : p.getPortList()) { + if (ip.isInPort()) { + String s = (j++ == 0) ? "if " : " else if "; + ps.printPrefixln(s + "(strstr(\" INPORT_" + + ip.getName() + "\", (const char*)port))"); + ps.printLeftBracket(); + ps.printPrefixln("return (static_cast<" + p.getBasename() + + "_wrapper *>(process->wptr))->INPORT_" + + ip.getName() + "->rtest(len);"); + ps.printRightBracket(); + } + } + ps.printRightBracket(); + + } + + ps.printPrefixln(); + ps.printPrefixln("static inline int DOL_detach(DOLProcess *p)"); + ps.printLeftBracket(); + ps.printPrefixln("(static_cast<" + p.getBasename() + + "_wrapper *>(p->wptr))" + "->setDetached();"); + ps.printRightBracket(); + ps.printPrefixln(); + + ps.printPrefixln("#define GETINDEX(dimension) \\"); + ps.printPrefixln("(static_cast<" + p.getBasename() + + "_wrapper *>(p->wptr))->_processIndex[dimension]"); + ps.printPrefixln(); + + //include c file + for (SourceCode sr : p.getSrcList()) { + ps.printPrefixln("#include \"" + sr.getLocality() + "\""); + } + ps.printPrefixln(); + + + ps.printPrefixln("void " + p.getBasename() + + "_wrapper::setDetached() { _detached = 1; }"); + ps.printPrefixln("int " + p.getBasename() + + "_wrapper::isDetached() { return _detached; }"); + ps.printPrefixln(); + + //constructor + ps.printPrefixln(p.getBasename() + "_wrapper::" + p.getBasename() + + "_wrapper(sc_module_name name=sc_gen_unique_name(\"" + + p.getBasename() + "\" )) : sc_module(name), " + // + "_process(" + p.getBasename() + "), " + + "_detached(0)"); + ps.printLeftBracket(); + ps.printPrefixln("_state = (LocalState)new " + + p.getBasename().substring(0, 1).toUpperCase() + + p.getBasename().substring(1) + "_State;"); + //ps.printPrefixln("struct _local_states *_state = " + // + "new struct _local_states;"); + //ps.printPrefixln("memcpy(_state, " + p.getBasename() + // + ".local, sizeof(struct _local_states));"); + ps.printPrefixln("_process.local = _state;"); + //ps.printPrefixln("sprintf(_process.local->id, name);"); + ps.printPrefixln("_process.init = " + p.getBasename() + "_init;"); + ps.printPrefixln("_process.fire = " + p.getBasename() + "_fire;"); + ps.printPrefixln("_process.wptr = this;"); + ps.printPrefixln(); + ps.printPrefixln("char buffer[255];"); + ps.printPrefixln("sprintf(buffer, name);"); + ps.printPrefixln("for (int i = 0; i < 4; i++)"); + ps.printPrefixln(" _processIndex[i] = " + + "getIndex(buffer, \"_\", i);"); + + ps.printPrefixln(); + ps.printRightBracket(); + + ps.printPrefixln(); + ps.printPrefixln("void " + p.getBasename() + + "_wrapper::initialize()"); + ps.printLeftBracket(); + ps.printPrefixln("_process.init(&_process);"); + ps.printRightBracket(); + ps.printPrefixln(); + ps.printPrefixln("int " + p.getBasename() + "_wrapper::fire()"); + ps.printLeftBracket(); + ps.printPrefixln("return _process.fire(&_process);"); + ps.printRightBracket(); + ps.printPrefixln(); + ps.printPrefixln(p.getBasename() + "_wrapper::~" + p.getBasename() + + "_wrapper()"); + ps.printLeftBracket(); + ps.printPrefixln("if (_state)"); + ps.printLeftBracket(); + ps.printPrefixln("delete (" + + p.getBasename().substring(0, 1).toUpperCase() + + p.getBasename().substring(1) + "_State*)_state;"); + ps.printRightBracket(); + ps.printRightBracket(); + } + + protected void _createHeaderFile(Process p) + throws IOException { + String filename = _dir + _delimiter + p.getBasename() + + "_wrapper.h"; + OutputStream file = new FileOutputStream(filename); + CodePrintStream ps = new CodePrintStream(file); + + ps.printPrefixln("#ifndef " + p.getBasename() + "_WRAPPER_H"); + ps.printPrefixln("#define " + p.getBasename() + "_WRAPPER_H"); + ps.printPrefixln(); + ps.printPrefixln("#include \"systemc.h\""); + ps.printPrefixln(); + ps.printPrefixln("#include \"dol_sched_if.h\""); + ps.printPrefixln("#include \"dol_fifo_if.h\""); + ps.printPrefixln("#include \"simple_fifo.h\""); + ps.printPrefixln(); + ps.printPrefixln("#include "); + ps.printPrefixln(); + ps.printPrefixln("class " + p.getBasename() + + "_wrapper : virtual public dol_sched_if, " + + "public sc_module"); + ps.printLeftBracket(); + ps.printPrefixln("public:"); + + for (Port pr : p.getPortList()) { + if (pr.isOutPort()) { + ps.printPrefixln("sc_port OUTPORT_" + + pr.getName() + ";"); + } + else if (pr.isInPort()) { + ps.printPrefixln("sc_port INPORT_" + + pr.getName() + ";"); + } + } + ps.printPrefixln("int _processIndex[4];"); + + ps.printPrefixln(); + ps.printPrefixln("" + p.getBasename() + + "_wrapper(sc_module_name name);"); + ps.printPrefixln(); + ps.printPrefixln("virtual ~" + p.getBasename() + "_wrapper();"); + ps.printPrefixln(); + ps.printPrefixln("// DOL scheduler interface"); + ps.printPrefixln("void initialize();"); + ps.printPrefixln("int fire();"); + ps.printPrefixln("void setDetached();"); + ps.printPrefixln("int isDetached();"); + ps.printPrefixln(); + ps.printPrefixln(); + ps.printPrefixln("protected:"); + ps.printPrefixln("LocalState _state;"); + + ps.printPrefixln(); + ps.printPrefixln("private:"); + ps.printPrefixln("" + p.getBasename() + "_wrapper( const " + + p.getBasename() + "_wrapper& );"); + ps.printPrefixln("" + p.getBasename() + "_wrapper& operator = " + + "( const " + p.getBasename() + "_wrapper& );"); + ps.printPrefixln("DOLProcess _process;"); + ps.printPrefixln("int _detached;"); + ps.printRightBracket(); + ps.printPrefixln(";"); + ps.printPrefixln("#endif"); + } + + /** + * Make modifications to source files of a process. + * Port names need to be strings for the SystemC code generation. + * Therefore, in the header files integer port names are put into + * quotation marks. + * + * @param p process whose sources should be adapted + * @throws IOException + */ + protected void _adaptSources(Process p) throws IOException { + Sed sed = new Sed(); + for (Port port : p.getPortList()) { + String processHeaderFile; + + for (SourceCode sr : p.getSrcList()) { + processHeaderFile = _dir + _delimiter + ".." + + _delimiter + "processes" + _delimiter + + sr.getLocality(). + replaceAll("(.*)\\.[cC][pP]*[pP]*", "$1\\.h"); + + sed.sed(processHeaderFile, + "(#define[ ]*PORT_\\w*[ ]*)\"?" + + port.getBasename() + "\"?[ ]*$", + "$1 " + "\"" + port.getBasename() + "\""); + } + } + } + + + protected String _dir = null; +} diff --git a/dol/src/dol/visitor/systemC/SCModuleVisitor.java b/dol/src/dol/visitor/systemC/SCModuleVisitor.java new file mode 100644 index 0000000..006a08c --- /dev/null +++ b/dol/src/dol/visitor/systemC/SCModuleVisitor.java @@ -0,0 +1,232 @@ +/* $Id: SCModuleVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.systemC; + +import java.io.FileOutputStream; +import java.io.OutputStream; + +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.util.CodePrintStream; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate + * the top sc module: sc_applicaion.cpp. + */ +public class SCModuleVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param dir path of this file + */ + public SCModuleVisitor(String dir) { + _dir = dir; + } + + /** + * + * @param x process network that needs to be rendered + */ + public void visitComponent(ProcessNetwork x) { + try { + String filename = _dir + _delimiter + "sc_application.cpp"; + OutputStream file = new FileOutputStream(filename); + _mainPS = new CodePrintStream(file); + + _mainPS.printPrefixln("#include "); + _mainPS.printPrefixln("#include "); + _mainPS.printPrefixln("#include \"dol_fifo.h\""); + _mainPS.printPrefixln("#include \"dol_sched_if.h\""); + _mainPS.println(); + + for (String basename : x.getProcessBasenames()) { + _mainPS.printPrefixln("#include \"" + basename + + "_wrapper.h\""); + } + _mainPS.println(); + _mainPS.printPrefixln("using namespace std;"); + + _mainPS.println(); + _mainPS.printPrefixln("class sc_application : public sc_module "); + _mainPS.printLeftBracket(); + + _mainPS.printPrefixln("public:"); + _mainPS.printPrefixln("SC_HAS_PROCESS(sc_application);"); + + //declare processes + _mainPS.println(); + for (Process p : x.getProcessList()) { + _mainPS.printPrefixln(p.getBasename() + "_wrapper " + + p.getName() + "_ins"+ ";"); + _mainPS.printPrefixln("sc_event " + p.getName() + + "_event;"); + } + _mainPS.println(); + + //define the scheduler + _mainPS.printPrefixln("sc_event sched_event;"); + _mainPS.printPrefixln("list eventList;"); + _mainPS.printPrefixln("list::iterator iter;"); + _mainPS.println(); + + //declare channels + _mainPS.println(); + for (Channel p : x.getChannelList()) { + _mainPS.printPrefixln("fifo " + p.getName() + "_ins;"); + } + _mainPS.println(); + + //model constructor + _mainPS.printPrefixln("sc_application(sc_module_name name)"); + + //parameter of constructor + _mainPS.printPrefix(": sc_module(name)"); + for (Process p : x.getProcessList()) { + _mainPS.println(","); + _mainPS.printPrefix(p.getName() + "_ins(\"" + + p.getName() +"\")"); + } + + if (x.getChannelList().size() > 0) { + for (Channel c : x.getChannelList()) { + _mainPS.println(","); + _mainPS.printPrefix(c.getName() + "_ins(" + + "\"" + c.getName() + "\", " + + c.getSize() * c.getTokenSize() + + ")"); + } + } + _mainPS.println(""); + _mainPS.printLeftBracket(); + + //construtor content + //build the network + for (Channel p : x.getChannelList()) { + p.accept(this); + } + _mainPS.println(""); + + _mainPS.println(""); + + _mainPS.printPrefixln("SC_THREAD(thread_init);"); + //init thread + _mainPS.printPrefixln("SC_THREAD(thread_sched);"); + + //declare concurrent non-terminating threads + for (Process p : x.getProcessList()) { + _mainPS.printPrefixln("SC_THREAD(thread_" + + p.getName() + ");"); + } + _mainPS.printRightBracket(); + _mainPS.println(); + + //define scheduler thread + _mainPS.printPrefixln("void thread_init()"); + _mainPS.printLeftBracket(); + //init + for (Process p : x.getProcessList()) { + _mainPS.printPrefixln(p.getName() + "_ins.initialize();"); + } + _mainPS.printRightBracket(); + _mainPS.println(); + + + //different scheduling algorithm can be put here + _mainPS.printPrefixln("void thread_sched()"); + _mainPS.printLeftBracket(); + _mainPS.printPrefixln("while (1)"); + _mainPS.printLeftBracket(); + _mainPS.printPrefixln("for (iter=eventList.begin(); iter != " + + "eventList.end(); ++iter)"); + _mainPS.printLeftBracket(); + _mainPS.printPrefixln("sc_event* e = (*iter);"); + _mainPS.printPrefixln("notify(*e);"); + _mainPS.printRightBracket(); + _mainPS.printPrefixln("eventList.clear();"); + _mainPS.printPrefixln("wait(sched_event);"); + _mainPS.printRightBracket(); + _mainPS.printRightBracket(); + _mainPS.println(); + + //define threads + for (Process p : x.getProcessList()) { + p.accept(this); + } + + _mainPS.printRightBracket(); // end of class + _mainPS.println(";"); + + //create and run the simulator + _mainPS.printPrefixln("int sc_main (int argc, char *argv[])"); + _mainPS.printLeftBracket(); + _mainPS.printPrefixln("sc_report_handler::set_actions(\"" + + "/IEEE_Std_1666/deprecated\", SC_DO_NOTHING);"); + _mainPS.printPrefixln("sc_report::register_id(" + + "RP_ID_PARAMETER_PROBLEM, " + + "\"parameter problem\" );"); + + //create an instance of the application model + //remove potential whitespaces before using the process + //network name as a systemc identifier + _mainPS.printPrefixln("sc_application my_app_mdl(\"" + + x.getName().replaceAll(" ", "") + "\");"); + _mainPS.printPrefixln("sc_start(-1,SC_NS);"); + _mainPS.printPrefixln("return 0;"); + + _mainPS.printRightBracket(); + + } + catch (Exception e) { + System.out.println(" SystemC module visitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * Print a line for the process in the correct format for DOTTY. + * + * @param x process that needs to be rendered + */ + public void visitComponent(Process x) { + _mainPS.printPrefixln("void thread_" + x.getName() + "()"); + _mainPS.printLeftBracket(); + _mainPS.printPrefixln("while (!" + x.getName() + + "_ins.isDetached())"); + _mainPS.printLeftBracket(); + _mainPS.printPrefixln(x.getName() + "_ins.fire();"); + _mainPS.printPrefixln("eventList.push_back(&" + x.getName() + + "_event);"); + _mainPS.printPrefixln("sched_event.notify();"); + _mainPS.printPrefixln("wait(" + x.getName() + "_event);"); + + _mainPS.printRightBracket(); + _mainPS.printRightBracket(); + } + + /** + * + * @param x channel that needs to be rendered + */ + public void visitComponent(Channel x) { + for (Port p : x.getPortList()) { + if (p.isOutPort()) { + //we get port name from channel + //channel.out == process.in + _mainPS.printPrefixln(p.getPeerResource().getName() + + "_ins.INPORT_" + p.getPeerPort().getName() + + "(" + x.getName() + "_ins);"); + } else if (p.isInPort()) { + _mainPS.printPrefixln(p.getPeerResource().getName() + + "_ins.OUTPORT_" + p.getPeerPort().getName() + + "(" + x.getName() + "_ins);"); + } + } + } + + protected CodePrintStream _mainPS = null; + protected String _dir = null; +} diff --git a/dol/src/dol/visitor/systemC/lib/dol.c b/dol/src/dol/visitor/systemC/lib/dol.c new file mode 100644 index 0000000..d852cf5 --- /dev/null +++ b/dol/src/dol/visitor/systemC/lib/dol.c @@ -0,0 +1,81 @@ +#include "dol.h" + +/** + * Create the port name of an iterated port based on its basename and the + * given indices. + * Example: createPort(xxx, "port", 2, 1, N1, 3, N2) will result in xxx + * having the value "port_1_3". The range definitions N1, N2 will be ignored + * in this implementation + * + * @param port buffer where the result is stored + * @param base basename of the port + * @param number_of_indices number of dimensions of the port + * @param index_range_pairs index and range values for each dimension + */ +char* createPort(char* port, char* base, + int number_of_indices, int indices, ...) { + char next_index_string[10]; + strcpy(port, base); + + if (number_of_indices > 4) { + printf("Error: iterated ports must not have more than "); + printf("4 dimensions.\n"); + exit(-1); + } + + va_list argumentlist; + va_start(argumentlist, indices); + + if (number_of_indices > 0) { + sprintf(next_index_string, "_%d", indices); + strcat(port, next_index_string); + + for (int k = 1; k < number_of_indices; k++) { + va_arg(argumentlist, int); //skip the range value + sprintf(next_index_string, "_%d", va_arg(argumentlist, int)); + strcat(port, next_index_string); + } + } + return port; +} + +/** + * Gets an index of a string, where the index must be separated by + * a character specified in tokens. + * Returns -1, when an error occurs. + * + * Example: + * getIndex("name_1_2", "_", 0) will return 1. + * getIndex("name_1_2", "_", 1) will return 2. + * + * @param string string to parse + * @param tokens delimiter of indices + * @param indexNumber position of index (starting at 0) + */ +int getIndex(const char* string, char* tokens, int indexNumber) { + char* string_copy; + char* token_pointer; + int index = 0; + + string_copy = (char*) malloc(sizeof(char) * (strlen(string) + 1)); + if (!string_copy) { + fprintf(stderr, "getIndex(): could not allocate memory.\n"); + return -1; + } + + strcpy(string_copy, string); + + token_pointer = strtok(string_copy, tokens); + do { + token_pointer = strtok(NULL, tokens); + index++; + } while (index <= indexNumber && token_pointer != 0); + + if (token_pointer) { + index = atoi(token_pointer); + free(string_copy); + return index; + } + + return -1; +} diff --git a/dol/src/dol/visitor/systemC/lib/dol.h b/dol/src/dol/visitor/systemC/lib/dol.h new file mode 100644 index 0000000..282bc4d --- /dev/null +++ b/dol/src/dol/visitor/systemC/lib/dol.h @@ -0,0 +1,77 @@ +#ifndef DOL_H +#define DOL_H + +#include +#include +#include +#include + +/************************************************************************ + * do not add code to this header + ************************************************************************/ + +/** + * - Local variables for each process can be defined in the structure + * LocalState. For each process, a new instance of LocalState is + * instantiated. + * - The ProcessInit function pointer points to the function which is + * called to initialize a process. + * - The ProcessFire function pointer points to the function which is + * called repeatedly by the scheduler. + * - The wptr is a placeholder for callback. A pointer to the wrapper + * class instance of the process can be assigned. This is done in the + * code generated by the code generation, so one can just leave it + * blank. + */ + +//structure for local memory of process +typedef struct _local_states *LocalState; + +//additional behavioral functions could be declared here +typedef void (*ProcessInit)(struct _process*); +typedef int (*ProcessFire)(struct _process*); +typedef void *WPTR; + +//process handler +struct _process; + +typedef struct _process { + LocalState local; + ProcessInit init; + ProcessFire fire; + WPTR wptr; //placeholder for wrapper instance +} DOLProcess; + + +//macros to deal with iterated ports + +/** + * macro to create a variable to store a port name + * + * @param name name of the variable + */ +#define MAX_PORT_NAME_LENGTH 255 +#define CREATEPORTVAR(name) char name[MAX_PORT_NAME_LENGTH] + + +/** + * Create the port name of an iterated port based on its basename and the + * given indices. + * + * @param port buffer where the result is stored (created using + * CREATEPORTVAR) + * @param base basename of the port + * @param number_of_indices number of dimensions of the port + * @param index_range_pairs index and range values for each dimension + */ +#define CREATEPORT(port, base, number_of_indices, indices...) \ + createPort(port, base, number_of_indices, indices) + +char* createPort(char* port, + char* base, + int number_of_indices, + int indices, ...); + +int getIndex(const char* string, char* tokens, int indexNumber); + +#endif diff --git a/dol/src/dol/visitor/systemC/lib/dol_fifo.h b/dol/src/dol/visitor/systemC/lib/dol_fifo.h new file mode 100644 index 0000000..5646682 --- /dev/null +++ b/dol/src/dol/visitor/systemC/lib/dol_fifo.h @@ -0,0 +1,432 @@ +/************************************************************************** + dol_fifo.h + + DOL FIFO channel: + relative bloking (RB) and relative non-bloking (RN) + task transaction level (TTL) fifo channel + + (c) 2006 by Alexander Maxiaguine + + Computer Engineering and Networks Laboratory, TIK + Swiss Federal Institute of Technology, ETHZ Zurich + Switzerland + +**************************************************************************/ + +/************************************************************************** + Change Log: + + 14.03.06 -- creation + +**************************************************************************/ + +#ifndef DOL_FIFO_H +#define DOL_FIFO_H + +#include +#include "systemc.h" + +#include "dol_rp_ids.h" +#include "dol_fifo_if.h" + + +template +class dol_fifo +: public dol_fifo_write_if, + public dol_fifo_read_if, + public sc_prim_channel +{ +public: + + // constructors + explicit dol_fifo( int size ) : sc_prim_channel( sc_gen_unique_name( "dol_fifo" ) ) + { init( size ); } + + explicit dol_fifo( const char* name, int size) : sc_prim_channel( name) + { init( size ); } + + // destructor + virtual ~dol_fifo() + { delete [] m_buf; } + + virtual void register_port( sc_port_base&, const char* ); + + // ********* WRITE interface methods ************** + // bloking (re)acquire free room in the channel + virtual void reAcquireRoom(int count); + + // non-bloking (re)acquire free room in the channel + virtual bool tryReAcquireRoom(int count); + + // store data into the acquired free room + virtual void store(int offset, T* data, int count); + + // release the stored data to the channel (commit write) + virtual void releaseData(int count); + + // ********* READ interface methods ************** + // bloking (re)acquire data in the channel + virtual void reAcquireData(int count); + + // non-bloking (re)acquire data in the channel + virtual bool tryReAcquireData(int count); + + // load the acquired data into a vector + virtual void load(int offset, T* vector, int count); + + // free up the room in the channel (commit read) + virtual void releaseRoom(int count); + + + // *************************************** + // helper methods (for debug, etc.) + + bool in_deadlock() { + return reader_is_blocked && writer_is_blocked; + } + + void trace( sc_trace_file* tf ) const; + virtual void print( ::std::ostream& = ::std::cout ) const; + virtual void dump( ::std::ostream& = ::std::cout ) const; + + + virtual const char* kind() const + { return "dol_fifo"; } + + +protected: + + virtual void update(); + void init( int ); + + +protected: + + int m_size; // buffer size + T* m_buf; // the buffer + + // channel state variables + int m_rwin_head; // index of read window head (oldest full token) + int m_wwin_head; // index of write window head (oldest empty token) + + int m_readable; // number of readable tokens (number of full tokens) + int m_acquired_room; // size of acquired room (write window) + int m_acquired_data; // size of acquired data (read window) + + int m_released_data; // size of data (filled tokens) released during this delta cycle + int m_released_room; // size of room (emptied tokens) released during this delta cycle + + + // SC specific properties + sc_event m_data_released_event; + sc_event m_room_released_event; + + sc_port_base* m_reader; // used for static design rule checking + sc_port_base* m_writer; // used for static design rule checking + + // used to detect deadlocks + bool reader_is_blocked; + bool writer_is_blocked; + +private: + + // disabled + dol_fifo( const dol_fifo& ); + dol_fifo& operator = ( const dol_fifo& ); +}; + + + + +// ************ Implementation ************************************ + +// *** WRITE interface methods **** + +// blocking (re)acquire free room of size COUNT in the channel +template +inline void dol_fifo::reAcquireRoom( int count ) +{ + while( m_size - m_readable < count ) { + if( m_size < count) { + SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Requested room is larger than total available buffer space \n --> This is a deadlock\n\n"); + } + + writer_is_blocked = true; + sc_core::wait( m_room_released_event ); + writer_is_blocked = false; + } + m_acquired_room = count; +} + +// non-bloking (re)acquire free room in the channel +template +inline bool dol_fifo::tryReAcquireRoom( int count ) +{ + if( m_size - m_readable < count ) { + if( m_size < count) { + SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Requested room is larger than the total available buffer space \n\n"); + } + return false; + } + m_acquired_room = count; + return true; +} + +// write COUNT data into the acquired free room starting from the position indicated by OFFSET +template +inline void dol_fifo::store( int offset, T* data, int count ) +{ + // sanity checks + if( m_acquired_room <= 0) { + SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Attempt to write without acquiring the room\n --> I ignore this action\n\n"); + return; + } + if( offset > m_acquired_room - 1 ) { + SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Attempt to write beyond the acquired room: offset value may be too large\n --> I ignore this action\n\n"); + return; + } + if( count > m_acquired_room - offset ) { + SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Attempt to write beyound the acquired room: data size may be too large\n --> I'm decreasing the data size\n\n"); + count = m_acquired_room - offset; + } + + int wi = ( m_wwin_head + offset ) % m_size; + for(int i=0; i +inline void dol_fifo::releaseData( int count ) +{ + // sanity check + if( count > m_acquired_room ) { + SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Attempt to release more room than was acquired\n --> I'm decreasing the size of released room\n\n"); + count = m_acquired_room; + } + + m_readable += count; + m_released_data += count; + + m_acquired_room -= count; + m_wwin_head = ( m_wwin_head + count ) % m_size; + + request_update(); +} + + +// *** READ interface methods **** + +// bloking (re)acquire COUNT data in the channel +template +inline void dol_fifo::reAcquireData( int count ) +{ + while( m_readable < count ) { + if( m_size < count) { + SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Acquired data size is larger than total available buffer space\n --> This is a deadlock\n\n"); + } + + reader_is_blocked = true; + sc_core::wait( m_data_released_event ); + reader_is_blocked = false; + } + + m_acquired_data = count; +} + +// non-bloking (re)acquire COUNT data in the channel +template +inline +bool +dol_fifo::tryReAcquireData( int count ) { + if( m_readable < count ) { + + if( m_size < count) { + SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Acquired data size is larger than total available buffer space \n\n"); + } + return false; + } + + m_acquired_data = count; + return true; +} + +// load COUNT acquired data into a vector +// from the read window starting at the position indicated by OFFSET +template +inline void dol_fifo::load( int offset, T* vector, int count ) +{ + // sanity checks + if( m_acquired_data <= 0) { + + SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Attempt to load without acquiring the data\n --> I ignore this action\n\n"); + return; + } + + if( offset > m_acquired_data - 1 ) { + + SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Attempt to read beyond the acquired data: offset value may be too large\n --> I ignore this action\n\n"); + return; + } + + if( count > m_acquired_data - offset ) { + + SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Attempt to read beyound the acquired data: data size may be too large\n --> I'm decreasing the data size\n\n"); + count = m_acquired_data - offset; + } + + + int ri = ( m_rwin_head + offset ) % m_size; + + for(int i=0; i +inline void dol_fifo::releaseRoom( int count ) +{ + // sanity check + if( count > m_acquired_data ) { + SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Attempt to free up more room than was acquired\n --> I'm decreasing the size of released room\n\n"); + count = m_acquired_data; + } + + m_readable -= count; + m_released_room += count; + + m_acquired_data -= count; + m_rwin_head = ( m_rwin_head + count ) % m_size; + + request_update(); +} + + + + +// *** Other methods *** + + +template +inline void dol_fifo::update() +{ + if( m_released_room > 0 ) { + m_room_released_event.notify_delayed(); + } + + if( m_released_data > 0 ) { + m_data_released_event.notify_delayed(); + } + + m_released_room = 0; + m_released_data = 0; +} + + +template +inline void dol_fifo::init( int size ) +{ + if( size <= 0 ) { + SC_REPORT_ERROR( SC_ID_INVALID_FIFO_SIZE_, 0 ); + } + + m_size = size; + m_buf = new T[m_size]; + + m_readable = 0; + + m_acquired_room = 0; + m_acquired_data = 0; + + m_rwin_head = 0; + m_wwin_head = 0; + + m_released_data = 0; + m_released_room = 0; + + m_reader = 0; + m_writer = 0; + + reader_is_blocked = false; + writer_is_blocked = false; +} + + +template +inline void dol_fifo::register_port( sc_port_base& port_, + const char* if_typename_ ) +{ + std::string nm( if_typename_ ); + if( nm == typeid( dol_fifo_read_if ).name() ) { + // only one reader can be connected + if( m_reader != 0 ) { + SC_REPORT_ERROR( SC_ID_MORE_THAN_ONE_FIFO_READER_, 0 ); + } + m_reader = &port_; + } else { // nm == typeid( dol_fifo_write_if ).name() + // only one writer can be connected + if( m_writer != 0 ) { + SC_REPORT_ERROR( SC_ID_MORE_THAN_ONE_FIFO_WRITER_, 0 ); + } + m_writer = &port_; + } +} + + + +template +inline void dol_fifo::trace( sc_trace_file* tf ) const +{ +#ifdef DEBUG_SYSTEMC + char buf[32]; + std::string nm = name(); + for( int i = 0; i < m_size; ++ i ) { + sprintf( buf, "_%d", i ); + sc_trace( tf, m_buf[i], nm + buf ); + } +#endif +} + + +template +inline void dol_fifo::print( ::std::ostream& os ) const +{ + if( m_readable ) { + for(int j=0, i = m_rwin_head; j +inline void dol_fifo::dump( ::std::ostream& os ) const +{ + os << "name = " << name() << ::std::endl; + if( m_readable ) { + for(int j=0, i = m_rwin_head; j +class dol_fifo_write_if : virtual public sc_interface +{ +public: + + // bloking (re)acquire free room in the channel + virtual void reAcquireRoom(int count) = 0; + + // non-bloking (re)acquire free room in the channel + virtual bool tryReAcquireRoom(int count) = 0; + + // store data into the acquired free room + virtual void store(int offset, T* data, int count) = 0; + + // release the stored data to the channel (commit write) + virtual void releaseData(int count) = 0; + + +protected: + + // constructor + dol_fifo_write_if() {} + + +private: + + // disabled + dol_fifo_write_if( const dol_fifo_write_if& ); + dol_fifo_write_if& operator = ( const dol_fifo_write_if& ); +}; + +template +class dol_fifo_read_if : virtual public sc_interface +{ +public: + + // bloking (re)acquire data in the channel + virtual void reAcquireData(int count) = 0; + + // non-bloking (re)acquire data in the channel + virtual bool tryReAcquireData(int count) = 0; + + // load the acquired data into a vector + virtual void load(int offset, T* vector, int count) = 0; + + // free up the room in the channel (commit read) + virtual void releaseRoom(int count) = 0; + + +protected: + + // constructor + dol_fifo_read_if() {} + + +private: + + // disabled + dol_fifo_read_if( const dol_fifo_read_if& ); + dol_fifo_read_if& operator = ( const dol_fifo_read_if& ); +}; + + +#endif diff --git a/dol/src/dol/visitor/systemC/lib/dol_rp_ids.h b/dol/src/dol/visitor/systemC/lib/dol_rp_ids.h new file mode 100644 index 0000000..1bd44c5 --- /dev/null +++ b/dol/src/dol/visitor/systemC/lib/dol_rp_ids.h @@ -0,0 +1,28 @@ +/************************************************************************** + dol_rp_ids.h + + Report IDs + + (c) 2006 by Alexander Maxiaguine + + Computer Engineering and Networks Laboratory, TIK + Swiss Federal Institute of Technology, ETHZ Zurich + Switzerland + +**************************************************************************/ + +/************************************************************************** + Change Log: + + 14.03.06 -- creation + +**************************************************************************/ + +#ifndef DOL_RP_IDS_H +#define DOL_RP_IDS_H + +//----------------- REPORT IDs -------------------------- +const int RP_ID_PARAMETER_PROBLEM = 5000; + + +#endif diff --git a/dol/src/dol/visitor/systemC/lib/dol_sched_if.h b/dol/src/dol/visitor/systemC/lib/dol_sched_if.h new file mode 100644 index 0000000..1856731 --- /dev/null +++ b/dol/src/dol/visitor/systemC/lib/dol_sched_if.h @@ -0,0 +1,46 @@ +/************************************************************************** + dol_sched_if.h + + Scheduler interface for a DOL process + + (c) 2006 by Alexander Maxiaguine + + Computer Engineering and Networks Laboratory, TIK + Swiss Federal Institute of Technology, ETHZ Zurich + Switzerland + +**************************************************************************/ + +/************************************************************************** + Change Log: + + 14.03.06 -- creation + +**************************************************************************/ + +#ifndef DOL_SCHED_IF_H +#define DOL_SCHED_IF_H + +#include "systemc.h" + + +class dol_sched_if +{ + +public: + virtual void initialize() = 0; + virtual int fire() = 0; + + +protected: + dol_sched_if() {} + + +private: + + // disabled + dol_sched_if( const dol_sched_if& ); + dol_sched_if& operator = ( const dol_sched_if& ); +}; + +#endif diff --git a/dol/src/dol/visitor/systemC/lib/simple_fifo.h b/dol/src/dol/visitor/systemC/lib/simple_fifo.h new file mode 100644 index 0000000..d11aecf --- /dev/null +++ b/dol/src/dol/visitor/systemC/lib/simple_fifo.h @@ -0,0 +1,182 @@ +/***************************************************************************** + + The following code is derived, directly or indirectly, from the SystemC + source code Copyright (c) 1996-2004 by all Contributors. + All Rights reserved. + + The contents of this file are subject to the restrictions and limitations + set forth in the SystemC Open Source License Version 2.4 (the "License"); + You may not use this file except in compliance with such restrictions and + limitations. You may obtain instructions on how to receive a copy of the + License at http://www.systemc.org/. Software distributed by Contributors + under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF + ANY KIND, either express or implied. See the License for the specific + language governing rights and limitations under the License. + + *****************************************************************************/ + +/***************************************************************************** + + simple_fifo.cpp -- Simple SystemC 2.0 producer/consumer example. + + From "An Introduction to System Level Modeling in + SystemC 2.0". By Stuart Swan, Cadence Design Systems. + Available at www.systemc.org + + Original Author: Stuart Swan, Cadence Design Systems, 2001-06-18 + + *****************************************************************************/ + +/***************************************************************************** + + MODIFICATION LOG - modifiers, enter your name, affiliation, date and + changes you are making here. + + Name, Affiliation, Date: + Description of Modification: + + *****************************************************************************/ + +#ifndef _SIMPLE_FIFO_H_ +#define _SIMPLE_FIFO_H_ + +#include + +class write_if : virtual public sc_interface +{ + public: + virtual void write(char) = 0; + virtual void reset() = 0; + virtual int wtest(int) = 0; +}; + +class read_if : virtual public sc_interface +{ + public: + virtual void read(char &) = 0; + virtual int num_available() = 0; + virtual int rtest(int) = 0; +}; + +class fifo : public sc_channel, public write_if, public read_if +{ + public: + fifo(sc_module_name name, int size) + : sc_channel(name), num_elements(0), first(0), max(size) { + data = new char[size]; + } + + void write(char c) { + if (num_elements == max) + wait(read_event); + + data[(first + num_elements) % max] = c; + ++ num_elements; + write_event.notify(); + } + + void read(char &c){ + if (num_elements == 0) + wait(write_event); + + c = data[first]; + -- num_elements; + first = (first + 1) % max; + read_event.notify(); + } + + int rtest(int size) { return (size <= num_elements) ? 1 : 0; } + int wtest(int size) { return (size <= max - num_elements) ? 1 : 0; } + + + void reset() { num_elements = first = 0; } + + int num_available() { return num_elements;} + + private: + int max; + char *data; + int num_elements, first; + sc_event write_event, read_event; +}; + + +#endif + +/* +class producer : public sc_module +{ + public: + sc_port out; + + SC_HAS_PROCESS(producer); + + producer(sc_module_name name) : sc_module(name) + { + SC_THREAD(main); + } + + void main() + { + const char *str = + "Visit www.systemc.org and see what SystemC can do for you today!\n"; + + while (*str) + out->write(*str++); + } +}; + +class consumer : public sc_module +{ + public: + sc_port in; + + SC_HAS_PROCESS(consumer); + + consumer(sc_module_name name) : sc_module(name) + { + SC_THREAD(main); + } + + void main() + { + char c; + cout << endl << endl; + + while (true) { + in->read(c); + cout << c << flush; + + if (in->num_available() == 1) + cout << "<1>" << flush; + if (in->num_available() == 9) + cout << "<9>" << flush; + } + } +}; + +class top : public sc_module +{ + public: + fifo *fifo_inst; + producer *prod_inst; + consumer *cons_inst; + + top(sc_module_name name) : sc_module(name) + { + fifo_inst = new fifo("Fifo1"); + + prod_inst = new producer("Producer1"); + prod_inst->out(*fifo_inst); + + cons_inst = new consumer("Consumer1"); + cons_inst->in(*fifo_inst); + } +}; + +int sc_main (int argc , char *argv[]) { + top top1("Top1"); + sc_start(-1); + return 0; +} +*/ diff --git a/dol/src/dol/visitor/systemC/package.html b/dol/src/dol/visitor/systemC/package.html new file mode 100644 index 0000000..10fe852 --- /dev/null +++ b/dol/src/dol/visitor/systemC/package.html @@ -0,0 +1,20 @@ + + + + + + +Code generator for SystemC functional simulation. + +

Package Specification

+ + + +

Related Documentation

+ + + + + + + diff --git a/dol/src/dol/visitor/xml/MapXmlVisitor.java b/dol/src/dol/visitor/xml/MapXmlVisitor.java new file mode 100644 index 0000000..564715a --- /dev/null +++ b/dol/src/dol/visitor/xml/MapXmlVisitor.java @@ -0,0 +1,193 @@ +/* $Id: MapXmlVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.xml; + +import dol.datamodel.XmlTag; +import dol.datamodel.mapping.CommunicationBinding; +import dol.datamodel.mapping.ComputationBinding; +import dol.datamodel.mapping.Configuration; +import dol.datamodel.mapping.Mapping; +import dol.datamodel.mapping.Schedule; +import dol.datamodel.mapping.ScheduleEntry; +import dol.datamodel.mapping.SchedulingPolicy; +import dol.datamodel.mapping.Variable; +import dol.util.CodePrintString; +import dol.visitor.MapVisitor; + +public class MapXmlVisitor extends MapVisitor { + + /** + * Constructor. + * + * @param stringBuffer buffer where the result is stored + */ + public MapXmlVisitor(StringBuffer stringBuffer) { + _ps = new CodePrintString(stringBuffer); + } + + /** + * + * @param x mapping that needs to be rendered. + */ + public void visitComponent(Mapping x) { + String xmlns = dol.util.SchemaLocation. + getMappingNamespace(); + String xsiLocation = dol.util.SchemaLocation. + getMappingSchemaLocation(); + + _ps.println(""); + _ps.printOpeningTag(_xt.getMappingTag()); + _ps.println(" xmlns=\"" + xmlns + + "\" xmlns:xsi=\"http://www.w3.org/2001/" + + "XMLSchema-instance\"" + + System.getProperty("line.separator") + + " xsi:schemaLocation=\"" + + xmlns + " " + xsiLocation + "\" name=\"" + + x.getName() + "\">"); + + // Visit variables + for(Variable v : x.getVarList()) { + v.accept(this); + } + + // Visit computation bindings + for(ComputationBinding b : x.getCompBindList()) { + b.accept(this); + } + + // Visit communication bindings + for(CommunicationBinding b : x.getCommBindList()) { + b.accept(this); + } + + // Visit schedules + for(Schedule s : x.getScheduleList()) { + s.accept(this); + } + + _ps.printClosingTag(_xt.getMappingTag()); + } + + /** + * + */ + public void visitComponent(ComputationBinding x) { + _ps.printOpeningTag(_xt.getBindingTag()); + _ps.println(" name=\"" + x.getName() + + "\" xsi:type=\"computation\">"); + + // Process + _ps.printPrefix(); + String s = "<" + _xt.getProcessTag() + + " name=\"" + x.getProcess().getName() + "\"/>"; + _ps.println(s); + + // Processor + _ps.printPrefix(); + s = "<" + _xt.getProcessorTag() + + " name=\"" + x.getProcessor().getName() + "\"/>"; + _ps.println(s); + _ps.printClosingTag(_xt.getBindingTag()); + } + + /** + * + */ + public void visitComponent(CommunicationBinding x) { + _ps.printOpeningTag(_xt.getBindingTag()); + _ps.println(" name=\"" + x.getName() + + "\" xsi:type=\"communication\">"); + + // SW channel + _ps.printPrefix(); + String s = "<" + _xt.getSWChannelTag() + + " name=\"" + x.getChannel().getName() + "\"/>"; + _ps.println(s); + + // Write path + _ps.printPrefix(); + s = "<" + _xt.getWritePathTag() + + " name=\"" + x.getWritePath().getName() + "\"/>"; + _ps.println(s); + + // Read path + _ps.printPrefix(); + s = "<" + _xt.getReadPathTag() + + " name=\"" + x.getReadPath().getName() + "\"/>"; + _ps.println(s); + + _ps.printClosingTag(_xt.getBindingTag()); + } + + /** + * + */ + public void visitComponent(Schedule x) { + _ps.printOpeningTag(_xt.getScheduleTag()); + _ps.println(" name=\"" + x.getName() + + "\" type=\"" + + SchedulingPolicy.toString(x.getSchedPolicy()) + "\">"); + + // Resource + _ps.printPrefix(); + String s = "<" + _xt.getResourceTag() + + " name=\"" + x.getResource().getName() + "\"/>"; + _ps.println(s); + + // Scheduler table entries + for (ScheduleEntry p : x.getEntryList()) { + p.accept(this); + } + + // Configuration of schedule + for (Configuration c : x.getCfgList()) { + c.accept(this); + } + + _ps.printClosingTag(_xt.getScheduleTag()); + } + + /** + * + */ + public void visitComponent(ScheduleEntry x) { + if (x.getCfgList().size() == 0) { + _ps.printPrefixln("<" + _xt.getOriginTag() + " name=\"" + + x.getName() + "\"/>"); + } else { + _ps.printOpeningTag(_xt.getOriginTag()); + _ps.println(" name=\"" + x.getName() + "\">"); + + // Configuration of the scheduler entry + for (Configuration c : x.getCfgList()) { + c.accept(this); + } + + _ps.printClosingTag(_xt.getOriginTag()); + } + } + + /** + * + */ + public void visitComponent(Variable x) { + _ps.printPrefix(); + String s = "<" + _xt.getVariableTag() + + " name=\"" + x.getName() + "\"" + + " value=\"" + Integer.toString(x.getValue()) + "\"/>"; + _ps.println(s); + } + + /** + * + */ + public void visitComponent(Configuration x) { + _ps.printPrefix(); + String s = "<" + _xt.getConfigurationTag() + + " name=\"" + x.getName() + "\"" + + " value=\"" + x.getValue() + "\"/>"; + _ps.println(s); + } + + protected CodePrintString _ps = null; + protected XmlTag _xt = XmlTag.getInstance(); +} diff --git a/dol/src/dol/visitor/xml/PNXmlVisitor.java b/dol/src/dol/visitor/xml/PNXmlVisitor.java new file mode 100644 index 0000000..19666e0 --- /dev/null +++ b/dol/src/dol/visitor/xml/PNXmlVisitor.java @@ -0,0 +1,217 @@ +/* $Id: PNXmlVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.xml; + +import dol.datamodel.XmlTag; +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Configuration; +import dol.datamodel.pn.Connection; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.ProfilingConfiguration; +import dol.datamodel.pn.SourceCode; +import dol.util.CodePrintString; +import dol.visitor.PNVisitor; + +/** + * This is a class for a visitor that is used to generate + * a schema compatible XML for process network. + */ +public class PNXmlVisitor extends PNVisitor { + + /** + * Constructor. + * + * @param stringBuffer buffer where the result is stored + */ + public PNXmlVisitor(StringBuffer stringBuffer) { + _ps = new CodePrintString(stringBuffer); + } + + /** + * + * @param x process network that needs to be rendered. + */ + public void visitComponent(ProcessNetwork x) { + String xmlns = dol.util.SchemaLocation. + getProcessNetworkNamespace(); + String xsiLocation = dol.util.SchemaLocation. + getProcessNetworkSchemaLocation(); + + + _ps.println(""); + _ps.printOpeningTag(_xt.getPNTag()); + _ps.println(" xmlns=\"" + xmlns + + "\" xmlns:xsi=\"http://www.w3.org/2001/" + + "XMLSchema-instance\"" + + System.getProperty("line.separator") + + " xsi:schemaLocation=\"" + + xmlns + " " + xsiLocation + "\" name=\"" + + x.getName() + "_annotated" + "\">"); + + //visit all processes + for (Process p : x.getProcessList()) { + p.accept(this); + } + _ps.println(); + + //visit all channels + for (Channel c : x.getChannelList()) { + c.accept(this); + } + _ps.println(); + + //visit all connections + for (Connection n : x.getConnectionList()) { + n.accept(this); + } + + _ps.printClosingTag(_xt.getPNTag()); + } + + /** + * Print a line for the process in the correct format for XML. + * + * @param x process that needs to be rendered + */ + public void visitComponent(Process x) { + _ps.printOpeningTag(_xt.getProcessTag()); + _ps.println(" name=\"" + x.getName() + + "\" basename=\"" + x.getBasename() + + "\" range=\"" + x.getRange() + + "\">"); + + for (Port p : x.getPortList()) { + p.accept(this); + } + + for (SourceCode s : x.getSrcList()) { + s.accept(this); + } + + for (Configuration c : x.getCfgList()) { + c.accept(this); + } + + for (ProfilingConfiguration c : x.getProfilingList()) { + c.accept(this); + } + + _ps.printClosingTag(_xt.getProcessTag()); + } + + /** + * Print a line for the channel in the correct format for XML. + * + * @param x channel that needs to be rendered + */ + public void visitComponent(Channel x) { + _ps.printOpeningTag(_xt.getSWChannelTag()); + _ps.println(" name=\"" + x.getName() + + "\" basename=\"" + x.getBasename() + + "\" type=\"" + x.getType() + + "\" size=\"" + x.getSize() + + "\">"); + + for (Port p : x.getPortList()) { + p.accept(this); + } + + for (Configuration c : x.getCfgList()) { + c.accept(this); + } + + for (ProfilingConfiguration c : x.getProfilingList()) { + c.accept(this); + } + + _ps.printClosingTag(_xt.getSWChannelTag()); + } + + /** + * Print a line for the connection in the correct format for XML. + * + * @param x channel that needs to be rendered + */ + public void visitComponent(Connection x) { + _ps.printOpeningTag(_xt.getConnectionTag()); + _ps.println(" name=\"" + x.getName() + "\">"); + + //origin + _ps.printOpeningTag("origin"); + _ps.println(" name=\"" + x.getOrigin().getName() + "\">"); + _ps.println(" "); + _ps.printClosingTag("origin"); + + //target + _ps.printOpeningTag("target"); + _ps.println(" name=\"" + x.getTarget().getName() + "\">"); + _ps.println(" "); + _ps.printClosingTag("target"); + _ps.printClosingTag("connection"); + } + + /** + * Print a line for the port in the correct format for XML. + * + * @param x port that needs to be rendered + */ + public void visitComponent(Port x) { + _ps.printPrefix(); + String s = "<" + _xt.getPortTag() + + " name=\"" + x.getName() + + "\" basename=\"" + x.getBasename() + + "\" range=\"" + x.getRange() + + "\""; + if (!x.getType().equals("")) + s += " type=\"" + x.getType() + "\""; + s += " />"; + + _ps.println(s); + } + + /** + * Print a line for the source code in the correct format for XML. + * + * @param x source that needs to be rendered + */ + public void visitComponent(SourceCode x) { + _ps.printPrefix(); + _ps.println("<" + _xt.getSourceTag() + + " type=\"" + x.getType() + + "\" location=\"" + x.getLocality() + + "\" />"); + } + + /** + * Print a line for the configuration in the correct format for XML. + * + * @param x configuration that needs to be rendered + */ + public void visitComponent(Configuration x) { + _ps.printPrefix(); + _ps.println("<" + _xt.getConfigurationTag() + + " name=\"" + x.getName() + + "\" value=\"" + x.getValue() + + "\" />"); + } + + /** + * Print a line for the profiling configuration in the correct format for XML. + * + * @param x configuration that needs to be rendered + */ + public void visitComponent(ProfilingConfiguration x) { + _ps.printPrefix(); + _ps.println("<" + _xt.getProfilingTag() + + " name=\"" + x.getName() + + "\" value=\"" + x.getValue() + + "\" />"); + } + + protected CodePrintString _ps = null; + + protected XmlTag _xt = XmlTag.getInstance(); +} diff --git a/dol/src/dol/visitor/xml/package.html b/dol/src/dol/visitor/xml/package.html new file mode 100644 index 0000000..a476417 --- /dev/null +++ b/dol/src/dol/visitor/xml/package.html @@ -0,0 +1,22 @@ + + + + + + +Schema compatible XML generator for process network. + +Maybe for architecture and mapping in the future. + +

Package Specification

+ + + +

Related Documentation

+ + + + + + + diff --git a/dol/src/dol/visitor/yapi/YapiMakefileVisitor.java b/dol/src/dol/visitor/yapi/YapiMakefileVisitor.java new file mode 100644 index 0000000..5103ec9 --- /dev/null +++ b/dol/src/dol/visitor/yapi/YapiMakefileVisitor.java @@ -0,0 +1,76 @@ +/* $Id: YapiMakefileVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.yapi; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.Vector; + +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.visitor.PNVisitor; + +/** + * + */ +public class YapiMakefileVisitor extends PNVisitor { + + /** + * + */ + public YapiMakefileVisitor(String dir) { + _dir = dir; + } + + /** + * + */ + public void visitComponent(ProcessNetwork pn) { + try { + String filename = _dir + _delimiter + "Makefile"; + OutputStream file = new FileOutputStream(filename); + PrintStream ps = new PrintStream(file); + ps.println("YAPI = /lib/yapi"); + ps.println("INCLUDES = -I$(YAPI)/include -Iwrappers -Ilib -Iprocesses -I."); + ps.println("LIBS = $(YAPI)/lib/libyapi.a"); + ps.println("CXX = g++"); + ps.println("CXXFLAGS = -g -Wall -O $(INCLUDES)"); + ps.println("OBJS = application.o \\"); + Vector processList = new Vector(); + for (Process p : pn.getProcessList()) { + String basename = p.getBasename(); + if (!processList.contains(basename)) { + processList.add(basename); + ps.println(" wrappers/" + p.getBasename() + + "_wrapper.o \\"); + } + } + ps.println(" lib/dolSupport.o \\"); + ps.println(" lib/ProcessWrapper.o \\"); + ps.println(" lib/main.o"); + ps.println(); + ps.println("EXE = ./sc_application"); + ps.println(); + ps.println("all : $(EXE)"); + ps.println(); + ps.println("test : $(EXE)"); + ps.println("\t@$(EXE)"); + ps.println(); + ps.println("$(EXE) : $(OBJS)"); + ps.println("\t$(CXX) $(LDFLAGS) $(OBJS) $(LIBS) -o $(EXE)"); + ps.println(); + ps.println("clean : ;"); + ps.println("\trm -rf $(OBJS) $(EXE)"); + } + catch (IOException e) { + System.out.println(" Yapi Makefile Visitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + protected String _dir = null; + protected String _name = "sc_application"; +} + diff --git a/dol/src/dol/visitor/yapi/YapiModuleVisitor.java b/dol/src/dol/visitor/yapi/YapiModuleVisitor.java new file mode 100644 index 0000000..bf2f699 --- /dev/null +++ b/dol/src/dol/visitor/yapi/YapiModuleVisitor.java @@ -0,0 +1,126 @@ +/* $Id: YapiModuleVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.yapi; + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.util.Vector; + +import dol.datamodel.pn.Channel; +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.util.CodePrintStream; +import dol.visitor.PNVisitor; + +/** + * This class is a class for a visitor that is used to generate + * the main program. + */ +public class YapiModuleVisitor extends PNVisitor { + + /** + * Constructor. + */ + public YapiModuleVisitor(String dir) { + _dir = dir; + } + + /** + * + */ + public void visitComponent(ProcessNetwork pn) { + try { + //create header file + String filename = _dir + _delimiter + "application.h"; + OutputStream file = new FileOutputStream(filename); + _code = new CodePrintStream(file); + + _code.println("#include \"yapi.h\""); + _code.println(); + + Vector processList = new Vector(); + for (Process p : pn.getProcessList()) { + String basename = p.getBasename(); + if (!processList.contains(basename)) { + processList.add(basename); + _code.println("#include \"" + + p.getBasename() + "_wrapper.h\""); + } + } + _code.println(); + _code.println("class Application : public ProcessNetwork"); + _code.println("{"); + _code.println("public:"); + _code.println(" Application(const Id& n);"); + _code.println(" const char* type() const;"); + _code.println(); + _code.println("private:"); + + for (Channel c : pn.getChannelList()) { + if (c.getType().equals("fifo")) { + _code.println(" Fifo " + c.getName() + + ";"); + } else if (c.getType().equals("wfifo")) { + System.out.println("Warning: YAPI visitor does not " + + "support windowed FIFOs."); + } + } + _code.println(); + + for (Process p : pn.getProcessList()) { + _code.println(" " + p.getBasename() + "_wrapper " + + p.getName() + ";"); + } + _code.println("};"); + file.close(); + + + //create cpp file + filename = _dir + _delimiter + "application.cpp"; + file = new FileOutputStream(filename); + _code = new CodePrintStream(file); + + _code.println("#include \"application.h\""); + _code.println(); + _code.println("Application::Application(const Id& n) :"); + _code.print(" ProcessNetwork(n)"); + for (Channel c : pn.getChannelList()) { + if (c.getType().equals("fifo")) { + _code.print(",\n " + c.getName() + "(id(\"" + + c.getName() + "\"))"); + } else if (c.getType().equals("wfifo")) { + System.out.println("Warning: YAPI visitor does not " + + "support windowed FIFOs."); + } + } + for (Process p : pn.getProcessList()) { + _code.print(",\n " + p.getName() + "(\"" + + p.getName() + "\", id(\"" + p.getName() + + "\")"); + + for (Port port : p.getPortList()) { + _code.print(", " + port.getPeerResource().getName()); + } + _code.print(")"); + } + _code.println(); + _code.println("{ }"); + _code.println(); + _code.println("const char* Application::type() const"); + _code.println("{"); + _code.println(" return \"Application\";"); + _code.println("}"); + } + catch (Exception e) { + System.out.println("YapiModuleVisitor: " + + "exception occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + protected CodePrintStream _code = null; + protected String _dir = null; + protected OutputStream _file; + protected CodePrintStream _pn; +} + diff --git a/dol/src/dol/visitor/yapi/YapiProcessVisitor.java b/dol/src/dol/visitor/yapi/YapiProcessVisitor.java new file mode 100644 index 0000000..660f540 --- /dev/null +++ b/dol/src/dol/visitor/yapi/YapiProcessVisitor.java @@ -0,0 +1,309 @@ +/* $Id: YapiProcessVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.yapi; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Vector; + +import dol.datamodel.pn.Port; +import dol.datamodel.pn.Process; +import dol.datamodel.pn.ProcessNetwork; +import dol.datamodel.pn.SourceCode; +import dol.util.CodePrintStream; +import dol.util.Sed; +import dol.visitor.PNVisitor; + +/** + * + */ +public class YapiProcessVisitor extends PNVisitor { + + /** + * Constructor. + */ + public YapiProcessVisitor(String dir) { + _dir = dir; + } + + /** + * + * @param x process network that needs to be rendered + */ + public void visitComponent(ProcessNetwork x) { + try { + Vector pList = new Vector(); + + for (Process p : x.getProcessList()) { + String basename = p.getBasename(); + if (!pList.contains(basename)) { + pList.add(basename); + p.accept(this); + } + } + } + catch (Exception e) { + System.out.println("Process Visitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * + * @param p process that needs to be rendered + */ + public void visitComponent(Process p) { + try { + _createCppFile(p); + _createHeaderFile(p); + _adaptSources(p); + } + catch (Exception e) { + System.out.println("Process Visitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * + */ + protected void _adaptSources(Process p) throws IOException { + Sed sed = new Sed(); + for (Port port : p.getPortList()) { + String processHeaderFile; + + for (SourceCode sr : p.getSrcList()) { + processHeaderFile = _dir + _delimiter + ".." + + _delimiter + "processes" + _delimiter + + sr.getLocality(). + replaceAll("(.*)\\.[cC][pP]*[pP]*", "$1\\.h"); + + if (port.isOutPort()) { + sed.sed(processHeaderFile, + "(#define[ ]*PORT_\\w*[ ]*)\"?" + + port.getBasename() + "\"?", + "$1 " + "(const_cast((const void*)" + +"(((static_cast<" + p.getBasename() + + "_wrapper *>(p->wptr))->OUTPORT_" + + port.getBasename() + "))))"); + } + else if (port.isInPort()) { + sed.sed(processHeaderFile, + "(#define[ ]*PORT_\\w*[ ]*)\"?" + + port.getBasename() + "\"?", + "$1 " + "(const_cast((const void*)" + +"(((static_cast<" + p.getBasename() + + "_wrapper *>(p->wptr))->INPORT_" + + port.getBasename() + "))))"); + } + } + } + } + + /** + * + */ + protected void _createCppFile(Process p) throws IOException { + String filename = _dir + _delimiter + p.getBasename() + + "_wrapper.cpp"; + OutputStream file = new FileOutputStream(filename); + CodePrintStream ps = new CodePrintStream(file); + + String newline = System.getProperty("line.separator"); + String code = "#include \"" + p.getBasename() + "_wrapper.h\"" + + newline; + code += "#include \"dolSupport.h\"" + newline; + for (SourceCode sr : p.getSrcList()) { + code += "#include \"" + sr.getLocality() + "\"" + newline; + } + + code += newline; + + code += p.getBasename() + "_wrapper::" + p.getBasename() + + "_wrapper(const char* name, const Id& n"; + for (Port port : p.getPortList()) { + if (port.isInPort()) { + code += ", In& inport_" + port.getName(); + } else { + code += ", Out& outport_" + port.getName(); + } + } + code += ")" + newline; + + code += " : ProcessWrapper(name, n)" + newline; + code += " {" + newline; + code += " _state = (LocalState)new " + + p.getBasename().substring(0, 1).toUpperCase() + + p.getBasename().substring(1) + "_State;" + + newline; + code += " _process.local = _state;" + newline; + code += " _process.init = " + p.getBasename() + "_init;" + + newline; + code += " _process.fire = " + p.getBasename() + "_fire;" + + newline; + code += " _process.wptr = this;" + newline; + for (Port port : p.getPortList()) { + if (!port.getRange().equals("")) { + String portName = + port.getName().replaceAll("_([0-9])", "][$1"); + portName += "]"; + portName = portName.replaceFirst("]", ""); + if (port.isOutPort()) { + code += " OUTPORT_" + portName + + " = new OutPort(id(\"" + port.getName() + + "\"), outport_" + port.getName() + ");" + + newline; + } + else if (port.isInPort()) { + code += " INPORT_" + portName + + " = new InPort(id(\"" + port.getName() + + "\"), inport_" + port.getName() + ");" + + newline; + } + } else { + if (port.isInPort()) { + code += " INPORT_" + port.getName() + + " = new InPort(id(\"" + port.getName() + + "\"), inport_" + port.getName() + ");" + + newline; + } else { + code += " OUTPORT_" + port.getName() + + " = new OutPort(id(\"" + port.getName() + + "\"), outport_" + port.getName() + ");" + + newline; + } + } + } + code += "}" + newline + newline; + + code += p.getBasename() + "_wrapper::~" + p.getBasename() + + "_wrapper() {" + newline; + code += " if (_state)" + newline; + code += " delete (" + + p.getBasename().substring(0, 1).toUpperCase() + + p.getBasename().substring(1) + "_State*)_state;" + + newline; + for (Port port : p.getPortList()) { + if (!port.getRange().equals("")) { + String portName = + port.getName().replaceAll("_([0-9])", "][$1"); + portName += "]"; + portName = portName.replaceFirst("]", ""); + if (port.isOutPort()) { + code += " if (OUTPORT_" + portName + ")" + newline; + code += " delete OUTPORT_" + portName + ";" + + newline; + } + else if (port.isInPort()) { + code += " if (INPORT_" + portName + ")" + newline; + code += " delete INPORT_" + portName + ";" + + newline; + } + } else { + if (port.isInPort()) { + code += " if(INPORT_" + port.getName() + ")" + + newline; + code += " delete INPORT_" + port.getName() + ";" + + newline; + } else { + code += " if(OUTPORT_" + port.getName() + ")" + + newline; + code += " delete OUTPORT_" + port.getName() + ";" + + newline; + } + } + } + code += "}" + newline + newline; + + code += "const char* " + + p.getBasename() + "_wrapper::type() const {" + newline; + code += " return \"" + p.getName() + "\";" + newline; + code += "}" + newline + newline; + + code += "void " + p.getBasename() + "_wrapper::main() {" + newline; + code += " _process.init(&_process);" + newline; + code += " while(!isDetached()) {" + newline; + code += " _process.fire(&_process);" + newline; + code += " }" + newline; + code += "}" + newline; + ps.printPrefixln(code); + } + + protected void _createHeaderFile(Process p) + throws IOException { + String filename = _dir + _delimiter + p.getBasename() + + "_wrapper.h"; + OutputStream file = new FileOutputStream(filename); + CodePrintStream ps = new CodePrintStream(file); + + String newline = System.getProperty("line.separator"); + String code = "#ifndef " + p.getBasename() + "_WRAPPER_H" + + newline; + code += "#define " + p.getBasename() + "_WRAPPER_H" + newline + + newline; + code += "#include \"ProcessWrapper.h\"" + newline; + code += newline; + + code += "class " + p.getBasename() + "_wrapper : " + + "public ProcessWrapper {" + newline; + code += " public:" + newline; + code += " " + p.getBasename() + + "_wrapper(const char* name, const Id& n"; + for (Port port : p.getPortList()) { + if (port.isInPort()) { + code += ", In& inport_" + port.getName(); + } else { + code += ", Out& outport_" + port.getName(); + } + } + code += ");" + newline; + code += " virtual ~" + p.getBasename() + "_wrapper();" + + newline; + code += " const char* type() const;" + newline; + code += " void main();" + newline + newline; + + Vector portList = new Vector(); + for (Port port : p.getPortList()) { + String basename = port.getBasename(); + + if (!portList.contains(basename)) { + portList.add(basename); + + if (!port.getRange().equals("")) { + if (port.isOutPort()) { + code += " OutPort *OUTPORT_" + + port.getBasename() + "[" + + port.getRange().replaceAll( + ";", "\\]\\[") + "];" + newline; + } + else if (port.isInPort()) { + code += " InPort *INPORT_" + + port.getBasename() + "[" + + port.getRange().replaceAll( + ";", "\\]\\[") + "];" + newline; + } + } + else { + if (port.isOutPort()) { + code += " OutPort *OUTPORT_" + + port.getName() + ";" + newline; + } + else if (port.isInPort()) { + code += " InPort *INPORT_" + + port.getName() + ";" + newline; + } + } + } + } + code += newline; + code += " protected:" + newline; + code += " LocalState _state;" + newline; + code += "};" + newline + newline; + code += "#endif"; + ps.printPrefixln(code); + } + + protected String _dir = null; +} diff --git a/dol/src/dol/visitor/yapi/YapiVisitor.java b/dol/src/dol/visitor/yapi/YapiVisitor.java new file mode 100644 index 0000000..3815727 --- /dev/null +++ b/dol/src/dol/visitor/yapi/YapiVisitor.java @@ -0,0 +1,95 @@ +/* $Id: YapiVisitor.java 1 2010-02-24 13:03:05Z haidw $ */ +package dol.visitor.yapi; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; + +import dol.datamodel.pn.ProcessNetwork; +import dol.util.Copier; +import dol.visitor.PNVisitor; + +/** + * + */ +public class YapiVisitor extends PNVisitor { + + /** + * Constructor. + */ + public YapiVisitor(String packageName) { + _packageName = packageName; + } + + /** + * + */ + public void visitComponent(ProcessNetwork pn) { + try { + _generateDirHierarchy(); + + pn.accept(new YapiMakefileVisitor(_srcDir)); + pn.accept(new YapiModuleVisitor(_srcDir)); + pn.accept(new YapiProcessVisitor(_wrapperDir)); + + } catch (Exception e) { + System.out.println(" SystemC PN Visitor: exception " + + "occured: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * + */ + private void _generateDirHierarchy() + throws IOException, FileNotFoundException { + + File dir = new File(_packageName); + dir.mkdirs(); + + _srcDir = _packageName + _delimiter + _srcDirName; + dir = new File(_srcDir); + dir.mkdirs(); + + _libDir = _srcDir + _delimiter + _libDirName; + dir = new File(_libDir); + dir.mkdirs(); + + _processDir = _srcDir + _delimiter + _processDirName; + dir = new File(_processDir); + dir.mkdirs(); + + _wrapperDir = _srcDir + _delimiter + _wrapperDirName; + dir = new File(_wrapperDir); + dir.mkdirs(); + + // copy library + String libraryPath = _ui.getMySystemCLib(); + libraryPath = libraryPath.replaceAll("systemC", + "yapi"); + File source = new File(libraryPath); + File destination = new File(_libDir); + new Copier().copy(source, destination); + + //copy process src code + source = new File(_srcDirName); + destination = new File(_processDir); + new Copier().copy(source, destination); + } + + protected String _packageName = null; + + protected String _srcDir = ""; + protected static String _srcDirName = "src"; + + protected String _libDir = ""; + protected static String _libDirName = "lib"; + + protected String _processDir = ""; + protected static String _processDirName = "processes"; + + protected String _wrapperDir = ""; + protected static String _wrapperDirName = "wrappers"; +} + diff --git a/dol/src/dol/visitor/yapi/lib/ProcessWrapper.cpp b/dol/src/dol/visitor/yapi/lib/ProcessWrapper.cpp new file mode 100644 index 0000000..de28efe --- /dev/null +++ b/dol/src/dol/visitor/yapi/lib/ProcessWrapper.cpp @@ -0,0 +1,107 @@ +#include "ProcessWrapper.h" +#include "dolSupport.h" + +/** + * + */ +ProcessWrapper::ProcessWrapper(const char* name, const Id& n) : Process(n) { + _name = new char[strlen(name) + 1]; + strcpy(_name, name); + + _isDetached = false; + for (int i = 0; i < 4; i++) { + _iteratorIndex[i] = getIndex(_name, "_", i); + } +} + +/** + * + */ +ProcessWrapper::~ProcessWrapper() { +} + +/** + * + */ +void ProcessWrapper::initialize() { + _process.init(&_process); +} + +/** + * + */ +int ProcessWrapper::fire() +{ + return _process.fire(&_process); +} + + +/** + * + */ +void ProcessWrapper::detach() { + _isDetached = true; +} + + +/** + * Gets an index of a string, where the index must be separated by + * a character specified in tokens. + * Returns -1, when an error occurs. + * + * Example: + * getIndex("name_1_2", "_", 0) will return 1. + * getIndex("name_1_2", "_", 1) will return 2. + * + * @param string string to parse + * @param tokens delimiter of indices + * @param indexNumber position of index (starting at 0) + */ +int ProcessWrapper::getIndex(const char* string, char* tokens, + int indexNumber) const { + char* string_copy; + char* token_pointer; + int index = 0; + + string_copy = (char*) malloc(sizeof(char) * (strlen(string) + 1)); + if (!string_copy) { + fprintf(stderr, "getIndex(): could not allocate memory.\n"); + return -1; + } + + strcpy(string_copy, string); + + token_pointer = strtok(string_copy, tokens); + do { + token_pointer = strtok(NULL, tokens); + index++; + } while (index <= indexNumber && token_pointer != 0); + + if (token_pointer) { + index = atoi(token_pointer); + free(string_copy); + return index; + } + + return -1; +} + + +/** + * Get the name of this process. + */ +char* ProcessWrapper::getName() const { + return _name; +} + + +/** + * Get the index of this process. + * @param indexNumber position of index (starting at 0) + */ +int ProcessWrapper::getIndex(unsigned indexNumber) const { + if (indexNumber < 4) { + return _iteratorIndex[indexNumber]; + } + return -1; +} diff --git a/dol/src/dol/visitor/yapi/lib/ProcessWrapper.h b/dol/src/dol/visitor/yapi/lib/ProcessWrapper.h new file mode 100644 index 0000000..bdecd34 --- /dev/null +++ b/dol/src/dol/visitor/yapi/lib/ProcessWrapper.h @@ -0,0 +1,29 @@ +#ifndef _PROCESSWRAPPER_H_ +#define _PROCESSWRAPPER_H_ + +#include "dol.h" +#include "yapi.h" + +class ProcessWrapper : public Process +{ + public: + ProcessWrapper(const char* name, const Id& n); + virtual ~ProcessWrapper(); + virtual void initialize(); + virtual int fire(); + virtual bool isDetached() const { return _isDetached; } + virtual void detach(); + virtual int getIndex(unsigned indexNumber) const; + virtual char* getName() const; + + protected: + char* _name; + DOLProcess _process; + bool _isDetached; + int _iteratorIndex[4]; + virtual int getIndex(const char* string, char* tokens, + int indexNumber) const; +}; + +#endif + diff --git a/dol/src/dol/visitor/yapi/lib/dol.h b/dol/src/dol/visitor/yapi/lib/dol.h new file mode 100644 index 0000000..8fbefe4 --- /dev/null +++ b/dol/src/dol/visitor/yapi/lib/dol.h @@ -0,0 +1,39 @@ +#ifndef DOL_H +#define DOL_H + +/************************************************************************ + * do not add code to this header + ************************************************************************/ + +/** + * Define the DOL process handler scheme. + * - Local variables are defined in structure LocalState. Local + * variables may vary from different processes. + * - The ProcessInit function pointer points to a function which + * initializes a process. + * - The ProcessFire function pointer points to a function which + * performs the actual computation. The communication between + * processes is inside the ProcessFire function. + * - The WPTR is a placeholder for callback. One can just + * leave it blank. + */ + +//structure for local memory of process +typedef struct _local_states *LocalState; + +//additional behavioral functions could be declared here +typedef void (*ProcessInit)(struct _process*); +typedef int (*ProcessFire)(struct _process*); +typedef void *WPTR; + +//process handler +struct _process; + +typedef struct _process { + LocalState local; + ProcessInit init; + ProcessFire fire; + WPTR wptr; //placeholder for wrapper instance +} DOLProcess; + +#endif diff --git a/dol/src/dol/visitor/yapi/lib/dolSupport.cpp b/dol/src/dol/visitor/yapi/lib/dolSupport.cpp new file mode 100644 index 0000000..164e1a6 --- /dev/null +++ b/dol/src/dol/visitor/yapi/lib/dolSupport.cpp @@ -0,0 +1,81 @@ +#include "dolSupport.h" +#include "ProcessWrapper.h" + +/** + * + */ +unsigned dolwrite(OutPort *out, const void *buf, unsigned len, const DOLProcess *process) +{ + write(*out, (char*)buf, len); + return len; +} + + +/** + * + */ +unsigned dolread(InPort *in, const void *buf, unsigned len, const DOLProcess *process) { + read(*in, (char*)buf, len); + return len; +} + +/** + * + */ +void DOL_detach(DOLProcess* p) { + static_cast(p->wptr)->detach(); +} + + +/** + * + */ +void createPort(void** port, + void* base, + int number_of_indices, + int index0, int range0) { + *port = (void**)((void**)base)[index0]; +} + + +/** + * + */ +void createPort(void** port, + void* base, + int number_of_indices, + int index0, int range0, + int index1, int range1) { + *port = (void**)((void**)base)[index0 * range1 + index1]; +} + + +/** + * + */ +void createPort(void** port, + void* base, + int number_of_indices, + int index0, int range0, + int index1, int range1, + int index2, int range2) { + *port = (void**)((void**)base)[index0 * range1 * range2 + + index1 * range2 + index2]; +} + + +/** + * + */ +void createPort(void** port, + void* base, + int number_of_indices, + int index0, int range0, + int index1, int range1, + int index2, int range2, + int index3, int range3) { + *port = (void**)((void**)base)[index0 * range1 * range2 * range3 + + index1 * range2 * range3 + + index2 * range3 + + index3]; +} diff --git a/dol/src/dol/visitor/yapi/lib/dolSupport.h b/dol/src/dol/visitor/yapi/lib/dolSupport.h new file mode 100644 index 0000000..897516f --- /dev/null +++ b/dol/src/dol/visitor/yapi/lib/dolSupport.h @@ -0,0 +1,67 @@ +#ifndef DOLSUPPORT_H +#define DOLSUPPORT_H + +#include "dol.h" +#include "yapi.h" + +#define DOL_write(port, buf, len, process) \ + dolwrite(static_cast *>(port), buf, len, process) +#define DOL_read(port, buf, len, process) \ + dolread(static_cast *>(port), buf, len, process) + +void DOL_detach(DOLProcess* p); + +//fifo access functions +unsigned dolwrite(OutPort *out, const void *buf, unsigned len, const DOLProcess *process); +unsigned dolread(InPort *in, const void *buf, unsigned len, const DOLProcess *process); + +void createPort(void **port, + void *base, + int number_of_indices, + int index0, int range0); + +void createPort(void **port, + void *base, + int number_of_indices, + int index0, int range0, + int index1, int range1); + +void createPort(void **port, + void *base, + int number_of_indices, + int index0, int range0, + int index1, int range1, + int index2, int range2); + +void createPort(void **port, + void *base, + int number_of_indices, + int index0, int range0, + int index1, int range1, + int index2, int range2, + int index3, int range3); + +#define GETINDEX(dimension) \ + static_cast(p->wptr)->getIndex(dimension) + +/** + * macro to create a variable to store a port name + * + * @param name name of the variable + */ +#define CREATEPORTVAR(name) void *name + +/** + * Create the port name of an iterated port based on its basename and the + * given indices. + * + * @param port buffer where the result is stored (created using + * CREATEPORTVAR) + * @param base basename of the port + * @param number_of_indices number of dimensions of the port + * @param index_range_pairs index and range values for each dimension + */ +#define CREATEPORT(port, base, number_of_indices, index_range_pairs...) \ + createPort((void**)(&port), base, number_of_indices, index_range_pairs) + +#endif diff --git a/dol/src/dol/visitor/yapi/lib/main.cpp b/dol/src/dol/visitor/yapi/lib/main.cpp new file mode 100644 index 0000000..2879eb3 --- /dev/null +++ b/dol/src/dol/visitor/yapi/lib/main.cpp @@ -0,0 +1,41 @@ +#include "yapi.h" +#include "application.h" +#include + +using namespace std; + +int main() +{ + // create yapi run-time environment + RTE rte; + + // redirect standard output + ofstream f("./app.out"); + rte.setOutStream(f); + + // redirect standard error + ofstream g("./app.err"); + rte.setErrorStream(g); + + // create toplevel process network + Application app(id("app")); + + // start the process network and + // wait for processes to finish + rte.start(app); + + // print workload + ofstream h("./appworkload.txt"); + printWorkload(app, h); + + // generate dotty file + ofstream i("./app.dot"); + printDotty(app, i); + + f.close(); + g.close(); + h.close(); + i.close(); + + return 0; +} diff --git a/dol/src/dol/visitor/yapi/package.html b/dol/src/dol/visitor/yapi/package.html new file mode 100644 index 0000000..813bcf2 --- /dev/null +++ b/dol/src/dol/visitor/yapi/package.html @@ -0,0 +1,20 @@ + + + + + + +Code generator for YAPI functional simulation. + +

Package Specification

+ + + +

Related Documentation

+ + + + + + + diff --git a/dol/src/dol_template.properties b/dol/src/dol_template.properties new file mode 100644 index 0000000..85d8e36 --- /dev/null +++ b/dol/src/dol_template.properties @@ -0,0 +1,23 @@ +# template for dol.properties file +# use ant config to fill in the values + +# DOL path: +# path to local directory of DOL +# +# example: +# DOL_PATH = /home/shapes/dol + +DOL_path = @dol_path@ + +# SystemC library path: +# SYSTEMC_INC and SYSTEMC_LIB are the paths to SystemC header and library, +# respectively. These two path will be used in the generated +# Makefile to build the SystemC executable binary file. +# They have to point to local SystemC directory. +# +# example: +# SYSTEMC_INC = /home/shapes/base/resources/lib/systemC/systemc-2.1.v1/include +# SYSTEMC_LIB = /home/shapes/base/resources/lib/systemC/systemc-2.1.v1/lib-linux/libsystemc.a + +SYSTEMC_INC = @systemc_inc@ +SYSTEMC_LIB = @systemc_lib@ diff --git a/dol/test/dolziptest.xml b/dol/test/dolziptest.xml new file mode 100644 index 0000000..2c6d3e7 --- /dev/null +++ b/dol/test/dolziptest.xml @@ -0,0 +1,78 @@ + + + + + + Ant build file for automated testing of DOL. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/test/reference/example1_Linux.txt b/dol/test/reference/example1_Linux.txt new file mode 100644 index 0000000..28e844f --- /dev/null +++ b/dol/test/reference/example1_Linux.txt @@ -0,0 +1,20 @@ +consumer: 0.000000 +consumer: 1.000000 +consumer: 4.000000 +consumer: 9.000000 +consumer: 16.000000 +consumer: 25.000000 +consumer: 36.000000 +consumer: 49.000000 +consumer: 64.000000 +consumer: 81.000000 +consumer: 100.000000 +consumer: 121.000000 +consumer: 144.000000 +consumer: 169.000000 +consumer: 196.000000 +consumer: 225.000000 +consumer: 256.000000 +consumer: 289.000000 +consumer: 324.000000 +consumer: 361.000000 diff --git a/dol/test/reference/example1_Windows XP.txt b/dol/test/reference/example1_Windows XP.txt new file mode 100644 index 0000000..28e844f --- /dev/null +++ b/dol/test/reference/example1_Windows XP.txt @@ -0,0 +1,20 @@ +consumer: 0.000000 +consumer: 1.000000 +consumer: 4.000000 +consumer: 9.000000 +consumer: 16.000000 +consumer: 25.000000 +consumer: 36.000000 +consumer: 49.000000 +consumer: 64.000000 +consumer: 81.000000 +consumer: 100.000000 +consumer: 121.000000 +consumer: 144.000000 +consumer: 169.000000 +consumer: 196.000000 +consumer: 225.000000 +consumer: 256.000000 +consumer: 289.000000 +consumer: 324.000000 +consumer: 361.000000 diff --git a/dol/test/reference/example2_Linux.txt b/dol/test/reference/example2_Linux.txt new file mode 100644 index 0000000..6db8b1c --- /dev/null +++ b/dol/test/reference/example2_Linux.txt @@ -0,0 +1,20 @@ +consumer: 0.000000 +consumer: 1.000000 +consumer: 256.000000 +consumer: 6561.000000 +consumer: 65536.000000 +consumer: 390625.000000 +consumer: 1679616.000000 +consumer: 5764801.000000 +consumer: 16777216.000000 +consumer: 43046720.000000 +consumer: 100000000.000000 +consumer: 214358880.000000 +consumer: 429981696.000000 +consumer: 815730752.000000 +consumer: 1475789056.000000 +consumer: 2562890752.000000 +consumer: 4294967296.000000 +consumer: 6975757312.000000 +consumer: 11019960320.000000 +consumer: 16983563264.000000 diff --git a/dol/test/reference/example2_Windows XP.txt b/dol/test/reference/example2_Windows XP.txt new file mode 100644 index 0000000..6db8b1c --- /dev/null +++ b/dol/test/reference/example2_Windows XP.txt @@ -0,0 +1,20 @@ +consumer: 0.000000 +consumer: 1.000000 +consumer: 256.000000 +consumer: 6561.000000 +consumer: 65536.000000 +consumer: 390625.000000 +consumer: 1679616.000000 +consumer: 5764801.000000 +consumer: 16777216.000000 +consumer: 43046720.000000 +consumer: 100000000.000000 +consumer: 214358880.000000 +consumer: 429981696.000000 +consumer: 815730752.000000 +consumer: 1475789056.000000 +consumer: 2562890752.000000 +consumer: 4294967296.000000 +consumer: 6975757312.000000 +consumer: 11019960320.000000 +consumer: 16983563264.000000 diff --git a/dol/test/reference/example3_Linux.txt b/dol/test/reference/example3_Linux.txt new file mode 100644 index 0000000..975ef62 --- /dev/null +++ b/dol/test/reference/example3_Linux.txt @@ -0,0 +1,78 @@ +v_consumer: a +v_consumer: a +h_consumer: n +h_consumer: n +h_consumer: n +v_consumer: a +v_consumer: b +v_consumer: b +h_consumer: o +h_consumer: o +h_consumer: o +v_consumer: b +v_consumer: c +v_consumer: c +h_consumer: p +h_consumer: p +h_consumer: p +v_consumer: c +v_consumer: d +v_consumer: d +h_consumer: q +h_consumer: q +h_consumer: q +v_consumer: d +v_consumer: e +v_consumer: e +h_consumer: r +h_consumer: r +h_consumer: r +v_consumer: e +v_consumer: f +v_consumer: f +h_consumer: s +h_consumer: s +h_consumer: s +v_consumer: f +v_consumer: g +v_consumer: g +h_consumer: t +h_consumer: t +h_consumer: t +v_consumer: g +v_consumer: h +v_consumer: h +h_consumer: u +h_consumer: u +h_consumer: u +v_consumer: h +v_consumer: i +v_consumer: i +h_consumer: v +h_consumer: v +h_consumer: v +v_consumer: i +v_consumer: j +v_consumer: j +h_consumer: w +h_consumer: w +h_consumer: w +v_consumer: j +v_consumer: k +v_consumer: k +h_consumer: x +h_consumer: x +h_consumer: x +v_consumer: k +v_consumer: l +v_consumer: l +h_consumer: y +h_consumer: y +h_consumer: y +v_consumer: l +v_consumer: m +v_consumer: m +h_consumer: z +h_consumer: z +h_consumer: z +v_consumer: m diff --git a/dol/test/reference/example3_Windows XP.txt b/dol/test/reference/example3_Windows XP.txt new file mode 100644 index 0000000..975ef62 --- /dev/null +++ b/dol/test/reference/example3_Windows XP.txt @@ -0,0 +1,78 @@ +v_consumer: a +v_consumer: a +h_consumer: n +h_consumer: n +h_consumer: n +v_consumer: a +v_consumer: b +v_consumer: b +h_consumer: o +h_consumer: o +h_consumer: o +v_consumer: b +v_consumer: c +v_consumer: c +h_consumer: p +h_consumer: p +h_consumer: p +v_consumer: c +v_consumer: d +v_consumer: d +h_consumer: q +h_consumer: q +h_consumer: q +v_consumer: d +v_consumer: e +v_consumer: e +h_consumer: r +h_consumer: r +h_consumer: r +v_consumer: e +v_consumer: f +v_consumer: f +h_consumer: s +h_consumer: s +h_consumer: s +v_consumer: f +v_consumer: g +v_consumer: g +h_consumer: t +h_consumer: t +h_consumer: t +v_consumer: g +v_consumer: h +v_consumer: h +h_consumer: u +h_consumer: u +h_consumer: u +v_consumer: h +v_consumer: i +v_consumer: i +h_consumer: v +h_consumer: v +h_consumer: v +v_consumer: i +v_consumer: j +v_consumer: j +h_consumer: w +h_consumer: w +h_consumer: w +v_consumer: j +v_consumer: k +v_consumer: k +h_consumer: x +h_consumer: x +h_consumer: x +v_consumer: k +v_consumer: l +v_consumer: l +h_consumer: y +h_consumer: y +h_consumer: y +v_consumer: l +v_consumer: m +v_consumer: m +h_consumer: z +h_consumer: z +h_consumer: z +v_consumer: m diff --git a/dol/test/reference/example4_Linux.txt b/dol/test/reference/example4_Linux.txt new file mode 100644 index 0000000..3a7079b --- /dev/null +++ b/dol/test/reference/example4_Linux.txt @@ -0,0 +1,32 @@ +input_generator: Write to zeroinput_0: 0.000000 +input_generator: Write to matrixA_0_0_0: 1.000000 +input_generator: Write to matrixB_0_0_0: 0.000000 +input_generator: Write to matrixA_1_0_0: 1.000000 +input_generator: Write to matrixB_1_0_0: 0.000000 +input_generator: Write to zeroinput_1: 0.000000 +input_generator: Write to matrixA_0_0_1: 2.000000 +input_generator: Write to matrixB_0_0_1: -1.000000 +input_generator: Write to matrixA_1_0_1: 2.000000 +input_generator: Write to matrixB_1_0_1: -1.000000 +input_generator: Write to zeroinput_2: 0.000000 +input_generator: Write to matrixA_0_1_0: 3.000000 +input_generator: Write to matrixB_0_1_0: -2.000000 +input_generator: Write to matrixA_1_1_0: 3.000000 +input_generator: Write to matrixB_1_1_0: -2.000000 +input_generator: Write to zeroinput_3: 0.000000 +input_generator: Write to matrixA_0_1_1: 4.000000 +input_generator: Write to matrixB_0_1_1: -3.000000 +input_generator: Write to matrixA_1_1_1: 4.000000 +input_generator: Write to matrixB_1_1_1: -3.000000 + addmult_0_0_0: 1.000000 * 0.000000 + 0.000000 = 0.000000 + addmult_0_0_1: 2.000000 * -2.000000 + 0.000000 = -4.000000 + addmult_0_1_0: 3.000000 * 0.000000 + 0.000000 = 0.000000 + addmult_0_1_1: 4.000000 * -2.000000 + 0.000000 = -8.000000 + addmult_1_0_0: 1.000000 * -1.000000 + 0.000000 = -1.000000 + addmult_1_0_1: 2.000000 * -3.000000 + -1.000000 = -7.000000 + addmult_1_1_0: 3.000000 * -1.000000 + 0.000000 = -3.000000 + addmult_1_1_1: 4.000000 * -3.000000 + -3.000000 = -15.000000 +output_consumer: matrixC[0][0]: -4.000000 +output_consumer: matrixC[0][1]: -7.000000 +output_consumer: matrixC[1][0]: -8.000000 +output_consumer: matrixC[1][1]: -15.000000 diff --git a/dol/test/reference/example4_Windows XP.txt b/dol/test/reference/example4_Windows XP.txt new file mode 100644 index 0000000..3a7079b --- /dev/null +++ b/dol/test/reference/example4_Windows XP.txt @@ -0,0 +1,32 @@ +input_generator: Write to zeroinput_0: 0.000000 +input_generator: Write to matrixA_0_0_0: 1.000000 +input_generator: Write to matrixB_0_0_0: 0.000000 +input_generator: Write to matrixA_1_0_0: 1.000000 +input_generator: Write to matrixB_1_0_0: 0.000000 +input_generator: Write to zeroinput_1: 0.000000 +input_generator: Write to matrixA_0_0_1: 2.000000 +input_generator: Write to matrixB_0_0_1: -1.000000 +input_generator: Write to matrixA_1_0_1: 2.000000 +input_generator: Write to matrixB_1_0_1: -1.000000 +input_generator: Write to zeroinput_2: 0.000000 +input_generator: Write to matrixA_0_1_0: 3.000000 +input_generator: Write to matrixB_0_1_0: -2.000000 +input_generator: Write to matrixA_1_1_0: 3.000000 +input_generator: Write to matrixB_1_1_0: -2.000000 +input_generator: Write to zeroinput_3: 0.000000 +input_generator: Write to matrixA_0_1_1: 4.000000 +input_generator: Write to matrixB_0_1_1: -3.000000 +input_generator: Write to matrixA_1_1_1: 4.000000 +input_generator: Write to matrixB_1_1_1: -3.000000 + addmult_0_0_0: 1.000000 * 0.000000 + 0.000000 = 0.000000 + addmult_0_0_1: 2.000000 * -2.000000 + 0.000000 = -4.000000 + addmult_0_1_0: 3.000000 * 0.000000 + 0.000000 = 0.000000 + addmult_0_1_1: 4.000000 * -2.000000 + 0.000000 = -8.000000 + addmult_1_0_0: 1.000000 * -1.000000 + 0.000000 = -1.000000 + addmult_1_0_1: 2.000000 * -3.000000 + -1.000000 = -7.000000 + addmult_1_1_0: 3.000000 * -1.000000 + 0.000000 = -3.000000 + addmult_1_1_1: 4.000000 * -3.000000 + -3.000000 = -15.000000 +output_consumer: matrixC[0][0]: -4.000000 +output_consumer: matrixC[0][1]: -7.000000 +output_consumer: matrixC[1][0]: -8.000000 +output_consumer: matrixC[1][1]: -15.000000 diff --git a/dol/test/reference/example5_Linux.txt b/dol/test/reference/example5_Linux.txt new file mode 100644 index 0000000..3e36a91 --- /dev/null +++ b/dol/test/reference/example5_Linux.txt @@ -0,0 +1,64 @@ + FFT2_0_0: twiddle_factor 1.000000 + j * -0.000000 + FFT2_0_1: twiddle_factor 1.000000 + j * -0.000000 + FFT2_0_2: twiddle_factor 1.000000 + j * -0.000000 + FFT2_0_3: twiddle_factor 1.000000 + j * -0.000000 + FFT2_0_4: twiddle_factor 1.000000 + j * -0.000000 + FFT2_0_5: twiddle_factor 1.000000 + j * -0.000000 + FFT2_0_6: twiddle_factor 1.000000 + j * -0.000000 + FFT2_0_7: twiddle_factor 1.000000 + j * -0.000000 + FFT2_1_0: twiddle_factor 1.000000 + j * -0.000000 + FFT2_1_1: twiddle_factor -0.000000 + j * -1.000000 + FFT2_1_2: twiddle_factor 1.000000 + j * -0.000000 + FFT2_1_3: twiddle_factor -0.000000 + j * -1.000000 + FFT2_1_4: twiddle_factor 1.000000 + j * -0.000000 + FFT2_1_5: twiddle_factor -0.000000 + j * -1.000000 + FFT2_1_6: twiddle_factor 1.000000 + j * -0.000000 + FFT2_1_7: twiddle_factor -0.000000 + j * -1.000000 + FFT2_2_0: twiddle_factor 1.000000 + j * -0.000000 + FFT2_2_1: twiddle_factor 0.707107 + j * -0.707107 + FFT2_2_2: twiddle_factor -0.000000 + j * -1.000000 + FFT2_2_3: twiddle_factor -0.707107 + j * -0.707107 + FFT2_2_4: twiddle_factor 1.000000 + j * -0.000000 + FFT2_2_5: twiddle_factor 0.707107 + j * -0.707107 + FFT2_2_6: twiddle_factor -0.000000 + j * -1.000000 + FFT2_2_7: twiddle_factor -0.707107 + j * -0.707107 + FFT2_3_0: twiddle_factor 1.000000 + j * -0.000000 + FFT2_3_1: twiddle_factor 0.923880 + j * -0.382683 + FFT2_3_2: twiddle_factor 0.707107 + j * -0.707107 + FFT2_3_3: twiddle_factor 0.382683 + j * -0.923880 + FFT2_3_4: twiddle_factor -0.000000 + j * -1.000000 + FFT2_3_5: twiddle_factor -0.382684 + j * -0.923880 + FFT2_3_6: twiddle_factor -0.707107 + j * -0.707107 + FFT2_3_7: twiddle_factor -0.923880 + j * -0.382683 +input_generator: Write to input_coefficients_0: -7.000000 + j * 6.000000 +input_generator: Write to input_coefficients_1: -6.000000 + j * -6.000000 +input_generator: Write to input_coefficients_2: 1.000000 + j * -1.000000 +input_generator: Write to input_coefficients_3: 1.000000 + j * 2.000000 +input_generator: Write to input_coefficients_4: -7.000000 + j * -2.000000 +input_generator: Write to input_coefficients_5: -8.000000 + j * 0.000000 +input_generator: Write to input_coefficients_6: -8.000000 + j * 1.000000 +input_generator: Write to input_coefficients_7: -8.000000 + j * 1.000000 +input_generator: Write to input_coefficients_8: -2.000000 + j * 8.000000 +input_generator: Write to input_coefficients_9: -4.000000 + j * 0.000000 +input_generator: Write to input_coefficients_10: 1.000000 + j * 6.000000 +input_generator: Write to input_coefficients_11: -1.000000 + j * 3.000000 +input_generator: Write to input_coefficients_12: -2.000000 + j * 3.000000 +input_generator: Write to input_coefficients_13: -3.000000 + j * -2.000000 +input_generator: Write to input_coefficients_14: -4.000000 + j * -8.000000 +input_generator: Write to input_coefficients_15: -3.000000 + j * -5.000000 +output_consumer: coeff[0]: -60.000000 + j * 6.000000 +output_consumer: coeff[1]: 0.616942 + j * -12.269464 +output_consumer: coeff[2]: 8.464464 + j * -18.677670 +output_consumer: coeff[3]: -7.116004 + j * 10.640678 +output_consumer: coeff[4]: -17.000000 + j * 27.000000 +output_consumer: coeff[5]: -9.306217 + j * 18.624950 +output_consumer: coeff[6]: -1.393398 + j * 27.707106 +output_consumer: coeff[7]: -3.112326 + j * -3.457108 +output_consumer: coeff[8]: 4.000000 + j * 20.000000 +output_consumer: coeff[9]: -12.131660 + j * 1.298900 +output_consumer: coeff[10]: 15.535534 + j * 16.677666 +output_consumer: coeff[11]: 4.287576 + j * 3.643592 +output_consumer: coeff[12]: 1.000000 + j * 7.000000 +output_consumer: coeff[13]: -19.179064 + j * 4.345614 +output_consumer: coeff[14]: -22.606600 + j * 26.292894 +output_consumer: coeff[15]: 5.940753 + j * -38.827164 diff --git a/dol/test/reference/example5_Windows XP.txt b/dol/test/reference/example5_Windows XP.txt new file mode 100644 index 0000000..dfe7b6f --- /dev/null +++ b/dol/test/reference/example5_Windows XP.txt @@ -0,0 +1,64 @@ + FFT2_0_0: twiddle_factor 1.000000 + j * -0.000000 + FFT2_0_1: twiddle_factor 1.000000 + j * -0.000000 + FFT2_0_2: twiddle_factor 1.000000 + j * -0.000000 + FFT2_0_3: twiddle_factor 1.000000 + j * -0.000000 + FFT2_0_4: twiddle_factor 1.000000 + j * -0.000000 + FFT2_0_5: twiddle_factor 1.000000 + j * -0.000000 + FFT2_0_6: twiddle_factor 1.000000 + j * -0.000000 + FFT2_0_7: twiddle_factor 1.000000 + j * -0.000000 + FFT2_1_0: twiddle_factor 1.000000 + j * -0.000000 + FFT2_1_1: twiddle_factor -0.000000 + j * -1.000000 + FFT2_1_2: twiddle_factor 1.000000 + j * -0.000000 + FFT2_1_3: twiddle_factor -0.000000 + j * -1.000000 + FFT2_1_4: twiddle_factor 1.000000 + j * -0.000000 + FFT2_1_5: twiddle_factor -0.000000 + j * -1.000000 + FFT2_1_6: twiddle_factor 1.000000 + j * -0.000000 + FFT2_1_7: twiddle_factor -0.000000 + j * -1.000000 + FFT2_2_0: twiddle_factor 1.000000 + j * -0.000000 + FFT2_2_1: twiddle_factor 0.707107 + j * -0.707107 + FFT2_2_2: twiddle_factor -0.000000 + j * -1.000000 + FFT2_2_3: twiddle_factor -0.707107 + j * -0.707107 + FFT2_2_4: twiddle_factor 1.000000 + j * -0.000000 + FFT2_2_5: twiddle_factor 0.707107 + j * -0.707107 + FFT2_2_6: twiddle_factor -0.000000 + j * -1.000000 + FFT2_2_7: twiddle_factor -0.707107 + j * -0.707107 + FFT2_3_0: twiddle_factor 1.000000 + j * -0.000000 + FFT2_3_1: twiddle_factor 0.923880 + j * -0.382683 + FFT2_3_2: twiddle_factor 0.707107 + j * -0.707107 + FFT2_3_3: twiddle_factor 0.382683 + j * -0.923880 + FFT2_3_4: twiddle_factor -0.000000 + j * -1.000000 + FFT2_3_5: twiddle_factor -0.382683 + j * -0.923880 + FFT2_3_6: twiddle_factor -0.707107 + j * -0.707107 + FFT2_3_7: twiddle_factor -0.923880 + j * -0.382683 +input_generator: Write to input_coefficients_0: -9.000000 + j * 4.000000 +input_generator: Write to input_coefficients_1: -2.000000 + j * 0.000000 +input_generator: Write to input_coefficients_2: -3.000000 + j * 0.000000 +input_generator: Write to input_coefficients_3: 8.000000 + j * 3.000000 +input_generator: Write to input_coefficients_4: 6.000000 + j * 0.000000 +input_generator: Write to input_coefficients_5: -7.000000 + j * -9.000000 +input_generator: Write to input_coefficients_6: -5.000000 + j * 2.000000 +input_generator: Write to input_coefficients_7: 1.000000 + j * 2.000000 +input_generator: Write to input_coefficients_8: 8.000000 + j * -4.000000 +input_generator: Write to input_coefficients_9: -6.000000 + j * -4.000000 +input_generator: Write to input_coefficients_10: 9.000000 + j * -2.000000 +input_generator: Write to input_coefficients_11: -8.000000 + j * -4.000000 +input_generator: Write to input_coefficients_12: -3.000000 + j * 1.000000 +input_generator: Write to input_coefficients_13: -9.000000 + j * 7.000000 +input_generator: Write to input_coefficients_14: -9.000000 + j * -9.000000 +input_generator: Write to input_coefficients_15: -7.000000 + j * 7.000000 +output_consumer: coeff[0]: -36.000000 + j * -6.000000 +output_consumer: coeff[1]: -27.156870 + j * -5.812504 +output_consumer: coeff[2]: -6.071069 + j * -25.242640 +output_consumer: coeff[3]: -7.438680 + j * 7.017483 +output_consumer: coeff[4]: -3.999999 + j * 28.000000 +output_consumer: coeff[5]: 1.106642 + j * 13.313931 +output_consumer: coeff[6]: -18.899494 + j * 3.443651 +output_consumer: coeff[7]: -46.865753 + j * -33.359482 +output_consumer: coeff[8]: 24.000000 + j * -10.000000 +output_consumer: coeff[9]: -13.085772 + j * 2.398290 +output_consumer: coeff[10]: 8.071067 + j * -16.757360 +output_consumer: coeff[11]: 16.450871 + j * 51.024147 +output_consumer: coeff[12]: 24.000000 + j * -8.000000 +output_consumer: coeff[13]: -32.863998 + j * -13.899717 +output_consumer: coeff[14]: 0.899496 + j * 34.556351 +output_consumer: coeff[15]: -26.146439 + j * 43.317848 diff --git a/dol/test/reference/example6_Linux.txt b/dol/test/reference/example6_Linux.txt new file mode 100644 index 0000000..aef2f51 --- /dev/null +++ b/dol/test/reference/example6_Linux.txt @@ -0,0 +1,21 @@ +producer: samples = { -7.0, +6.0, -6.0, -6.0, +1.0, -1.0, +1.0, +2.0, -7.0, -2.0 } +producer: Write sample[00]: -7.0000 +producer: Write sample[01]: +6.0000 +producer: Write sample[02]: -6.0000 +consumer: Read sample[00]: -7.0000 +producer: Write sample[03]: -6.0000 +consumer: Read sample[01]: +2.5000 +producer: Write sample[04]: +1.0000 +consumer: Read sample[02]: -4.7500 +producer: Write sample[05]: -1.0000 +consumer: Read sample[03]: -8.3750 +producer: Write sample[06]: +1.0000 +consumer: Read sample[04]: -3.1875 +producer: Write sample[07]: +2.0000 +consumer: Read sample[05]: -2.5938 +producer: Write sample[08]: -7.0000 +consumer: Read sample[06]: -0.2969 +producer: Write sample[09]: -2.0000 +consumer: Read sample[07]: +1.8516 +consumer: Read sample[08]: -6.0742 +consumer: Read sample[09]: -5.0371 diff --git a/dol/test/reference/example6_Windows XP.txt b/dol/test/reference/example6_Windows XP.txt new file mode 100644 index 0000000..d266e3c --- /dev/null +++ b/dol/test/reference/example6_Windows XP.txt @@ -0,0 +1,21 @@ +producer: samples = { -9.0, +4.0, -2.0, +0.0, -3.0, +0.0, +8.0, +3.0, +6.0, +0.0 } +producer: Write sample[00]: -9.0000 +producer: Write sample[01]: +4.0000 +producer: Write sample[02]: -2.0000 +consumer: Read sample[00]: -9.0000 +producer: Write sample[03]: +0.0000 +consumer: Read sample[01]: -0.5000 +producer: Write sample[04]: -3.0000 +consumer: Read sample[02]: -2.2500 +producer: Write sample[05]: +0.0000 +consumer: Read sample[03]: -1.1250 +producer: Write sample[06]: +8.0000 +consumer: Read sample[04]: -3.5625 +producer: Write sample[07]: +3.0000 +consumer: Read sample[05]: -1.7812 +producer: Write sample[08]: +6.0000 +consumer: Read sample[06]: +7.1094 +producer: Write sample[09]: +0.0000 +consumer: Read sample[07]: +6.5547 +consumer: Read sample[08]: +9.2773 +consumer: Read sample[09]: +4.6387 diff --git a/dol/test/reference/example7_Linux.txt b/dol/test/reference/example7_Linux.txt new file mode 100644 index 0000000..3639ade --- /dev/null +++ b/dol/test/reference/example7_Linux.txt @@ -0,0 +1,31 @@ +init producer. +init consumer. +init filter_0: filter coefficient = -0.9 +init filter_1: filter coefficient = -0.6 +init filter_2: filter coefficient = -0.1 +producer: samples = { -7.0, +6.0, -6.0, -6.0, +1.0 } +producer: Write sample[00]: -7.0000 +producer: Write sample[01]: +6.0000 +filter_0: inA: -7.0000, inB: 0.0000, outA = outB: -7.0000 +filter_1: inA: -7.0000, inB: 0.0000, outA: -7.0000, outB: 4.2000 +filter_2: inA: -7.0000, inB: 0.0000, outA: -7.0000, outB: 0.7000 +producer: Write sample[02]: -6.0000 +consumer: Read sample[00]: -7.0000 +filter_0: inA: 6.0000, inB: 4.2000, outA = outB: 10.2000 +filter_1: inA: 10.2000, inB: 0.7000, outA: 10.2000, outB: -5.4200 +filter_2: inA: 10.2000, inB: 0.0000, outA: 10.2000, outB: -1.0200 +producer: Write sample[03]: -6.0000 +consumer: Read sample[01]: +10.2000 +filter_0: inA: -6.0000, inB: -5.4200, outA = outB: -11.4200 +filter_1: inA: -11.4200, inB: -1.0200, outA: -11.4200, outB: 5.8320 +filter_2: inA: -11.4200, inB: 0.0000, outA: -11.4200, outB: 1.1420 +producer: Write sample[04]: +1.0000 +consumer: Read sample[02]: -11.4200 +filter_0: inA: -6.0000, inB: 5.8320, outA = outB: -0.1680 +filter_1: inA: -0.1680, inB: 1.1420, outA: -0.1680, outB: 1.2428 +filter_2: inA: -0.1680, inB: 0.0000, outA: -0.1680, outB: 0.0168 +consumer: Read sample[03]: -0.1680 +filter_0: inA: 1.0000, inB: 1.2428, outA = outB: 2.2428 +filter_1: inA: 2.2428, inB: 0.0168, outA: 2.2428, outB: -1.3289 +filter_2: inA: 2.2428, inB: 0.0000, outA: 2.2428, outB: -0.2243 +consumer: Read sample[04]: +2.2428 diff --git a/dol/test/reference/example7_Windows XP.txt b/dol/test/reference/example7_Windows XP.txt new file mode 100644 index 0000000..9305352 --- /dev/null +++ b/dol/test/reference/example7_Windows XP.txt @@ -0,0 +1,31 @@ +init producer. +init consumer. +init filter_0: filter coefficient = -1.0 +init filter_1: filter coefficient = +0.1 +init filter_2: filter coefficient = -0.1 +producer: samples = { -9.0, +4.0, -2.0, +0.0, -3.0 } +producer: Write sample[00]: -9.0000 +producer: Write sample[01]: +4.0000 +filter_0: inA: -9.0000, inB: 0.0000, outA = outB: -9.0000 +filter_1: inA: -9.0000, inB: 0.0000, outA: -9.0000, outB: -0.9000 +filter_2: inA: -9.0000, inB: 0.0000, outA: -9.0000, outB: 0.9000 +producer: Write sample[02]: -2.0000 +consumer: Read sample[00]: -9.0000 +filter_0: inA: 4.0000, inB: -0.9000, outA = outB: 3.1000 +filter_1: inA: 3.1000, inB: 0.9000, outA: 3.1000, outB: 1.2100 +filter_2: inA: 3.1000, inB: 0.0000, outA: 3.1000, outB: -0.3100 +producer: Write sample[03]: +0.0000 +consumer: Read sample[01]: +3.1000 +filter_0: inA: -2.0000, inB: 1.2100, outA = outB: -0.7900 +filter_1: inA: -0.7900, inB: -0.3100, outA: -0.7900, outB: -0.3890 +filter_2: inA: -0.7900, inB: 0.0000, outA: -0.7900, outB: 0.0790 +producer: Write sample[04]: -3.0000 +consumer: Read sample[02]: -0.7900 +filter_0: inA: 0.0000, inB: -0.3890, outA = outB: -0.3890 +filter_1: inA: -0.3890, inB: 0.0790, outA: -0.3890, outB: 0.0401 +filter_2: inA: -0.3890, inB: 0.0000, outA: -0.3890, outB: 0.0389 +consumer: Read sample[03]: -0.3890 +filter_0: inA: -3.0000, inB: 0.0401, outA = outB: -2.9599 +filter_1: inA: -2.9599, inB: 0.0389, outA: -2.9599, outB: -0.2571 +filter_2: inA: -2.9599, inB: 0.0000, outA: -2.9599, outB: 0.2960 +consumer: Read sample[04]: -2.9599 diff --git a/dol/test/reference/examplesingleprocess_Linux.txt b/dol/test/reference/examplesingleprocess_Linux.txt new file mode 100644 index 0000000..1cbbe87 --- /dev/null +++ b/dol/test/reference/examplesingleprocess_Linux.txt @@ -0,0 +1,30 @@ +task_0: 0 +task_1: 0 +task_2: 0 +task_0: 1 +task_1: 1 +task_2: 1 +task_0: 2 +task_1: 2 +task_2: 2 +task_0: 3 +task_1: 3 +task_2: 3 +task_0: 4 +task_1: 4 +task_2: 4 +task_0: 5 +task_1: 5 +task_2: 5 +task_0: 6 +task_1: 6 +task_2: 6 +task_0: 7 +task_1: 7 +task_2: 7 +task_0: 8 +task_1: 8 +task_2: 8 +task_0: 9 +task_1: 9 +task_2: 9 diff --git a/dol/test/reference/examplesingleprocess_Windows XP.txt b/dol/test/reference/examplesingleprocess_Windows XP.txt new file mode 100644 index 0000000..1cbbe87 --- /dev/null +++ b/dol/test/reference/examplesingleprocess_Windows XP.txt @@ -0,0 +1,30 @@ +task_0: 0 +task_1: 0 +task_2: 0 +task_0: 1 +task_1: 1 +task_2: 1 +task_0: 2 +task_1: 2 +task_2: 2 +task_0: 3 +task_1: 3 +task_2: 3 +task_0: 4 +task_1: 4 +task_2: 4 +task_0: 5 +task_1: 5 +task_2: 5 +task_0: 6 +task_1: 6 +task_2: 6 +task_0: 7 +task_1: 7 +task_2: 7 +task_0: 8 +task_1: 8 +task_2: 8 +task_0: 9 +task_1: 9 +task_2: 9 diff --git a/dol/test/runtests.xml b/dol/test/runtests.xml new file mode 100644 index 0000000..f6578e9 --- /dev/null +++ b/dol/test/runtests.xml @@ -0,0 +1,96 @@ + + + + + + Ant build file to run tests. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dol/test/src/test/test/TreeValidator.java b/dol/test/src/test/test/TreeValidator.java new file mode 100644 index 0000000..4deede8 --- /dev/null +++ b/dol/test/src/test/test/TreeValidator.java @@ -0,0 +1,78 @@ +package test.test; + +import java.io.File; + +import test.util.XMLValidator; + +/** + * Class to check well-formedness and validity of XML documents. + */ +public class TreeValidator { + + /** + * Check the well-formedness and validity of XML files. + * + * @param args Specifies the XML file to be checked or the + * directory (including subdirectories) where XML + * and XSD files are checked. Multiple files or + * directories can be specified. + */ + public static void main(String args[]) throws Exception { + System.out.println("Run TreeValidator."); + if (args.length == 0) + browseDirectoryTree("./"); + else { + for (int k = 0; k < args.length; k++) + browseDirectoryTree(args[k]); + } + System.out.println("Finished."); + } + + /** + * Method which defines what is done for each file found in the + * directory tree: When the file is an XML or XSD file, it is + * validated using + * {@link test.util.XMLValidator#isValid(java.lang.String)}. + * + * @param filename file to process + */ + protected static void processFile(String filename) throws Exception { + if (filename.endsWith("xml") || filename.endsWith("xsd")) { + System.out.println("Checking " + filename + "..."); + if (!XMLValidator.isValid(filename)) + throw new Exception("File not valid."); + } + } + + /** + * Iterate through the given directory tree. For each file found in + * the file, the method {@link #processFile(java.lang.String)} is + * called. + * + * @param path the path of the directory to be browsed + */ + protected static void browseDirectoryTree(String path) throws Exception { + File file = new File(path); + + if (!file.exists()) return; + if (!file.isDirectory()) return; + + String filepath = file.getPath(); + String filename = file.getName(); + + //loop through files in directory + String[] files = file.list(); + + for (int k = 0; k < files.length; k++) { + File newfile = new File(file.getPath(), files[k]); + if (newfile.isFile()) + processFile(path + System.getProperty("file.separator") + + files[k]); + else if (newfile.isDirectory()) { + browseDirectoryTree(file.getPath() + + System.getProperty("file.separator") + + files[k]); + } + } + } +} diff --git a/dol/test/src/test/util/Diff.java b/dol/test/src/test/util/Diff.java new file mode 100644 index 0000000..dd0f73e --- /dev/null +++ b/dol/test/src/test/util/Diff.java @@ -0,0 +1,46 @@ +package test.util; + +import java.io.BufferedReader; +import java.io.FileReader; + +/** + * Class to diff two files + */ +public class Diff { + + /** + * Main. + * + * @param args names of the two files to compare + */ + public static void main(String[] args) throws Exception { + if (args.length != 2) { + //System.out.println("Usage: java Diff file1 file2"); + throw new Exception("Usage: java Diff file1 file2"); + } + + try { + BufferedReader fileOneReader = new BufferedReader(new FileReader(args[0])); + BufferedReader fileTwoReader = new BufferedReader(new FileReader(args[1])); + + String lineOne, lineTwo; + while ((lineOne = fileOneReader.readLine()) != null) { + lineTwo = fileTwoReader.readLine(); + if (lineTwo == null) + throw new Exception("Files are not equal: " + + args[1] + " is shorter."); + else if (!lineOne.equals(lineTwo)) + throw new Exception("Files do not match."); + } + + if ((lineTwo = fileTwoReader.readLine()) != null) + throw new Exception("Files are not equal: " + + args[0] + " is shorter."); + } + catch (Exception e) { + throw e; + } + + //System.out.println("Files are equal."); + } +} diff --git a/dol/test/src/test/util/XMLValidator.java b/dol/test/src/test/util/XMLValidator.java new file mode 100644 index 0000000..eba16cd --- /dev/null +++ b/dol/test/src/test/util/XMLValidator.java @@ -0,0 +1,56 @@ +package test.util; + +import java.util.ResourceBundle; +import java.io.IOException; +import org.jdom.JDOMException; +import org.jdom.input.SAXBuilder; + +/** + * Class to check well-formedness and validity of XML documents. + */ +public class XMLValidator { + + /** + * Check the well-formedness and validity of an XML document. + * The file is checked against the schema which is referenced from + * within the file. When the document is an XML schema, it is checked + * against http://www.w3.org/2001/XMLSchema.xsd. + * + * @param filename filename of the file to be checked + */ + public static boolean isValid(String filename) { + ResourceBundle resourceBundle = ResourceBundle.getBundle("test"); + + SAXBuilder builder = new SAXBuilder(true); + builder.setFeature("http://xml.org/sax/features/validation", + true); + builder.setFeature("http://apache.org/xml/features/validation/" + + "schema", true); + builder.setFeature("http://apache.org/xml/features/validation/" + + "schema-full-checking", true); + builder.setProperty("http://apache.org/xml/properties/schema/" + + "external-schemaLocation", + "http://www.w3.org/2001/XMLSchema " + + "http://www.w3.org/2001/XMLSchema.xsd " + + resourceBundle.getString("LOCAL_SCHEMAS")); + + try { + builder.build(filename); + } + catch (JDOMException e) { + System.out.println("Found an error in " + filename + "."); + System.out.println(e.getMessage()); + System.out.println(""); + return false; + } + catch (IOException e) { + System.out.println("Found an error in " + filename + "."); + System.out.println(e.getMessage()); + System.out.println(""); + return false; + } + + return true; + } +} diff --git a/dol/test/test.properties b/dol/test/test.properties new file mode 100644 index 0000000..0a6c222 --- /dev/null +++ b/dol/test/test.properties @@ -0,0 +1,9 @@ +#local schemas for validation of XML files +LOCAL_SCHEMAS = \ + http://www.tik.ee.ethz.ch/~shapes/schema/PROCESSNETWORK \ + file:///@schema_path@/processnetwork.xsd \ + http://www.tik.ee.ethz.ch/~shapes/schema/ARCHITECTURE \ + file:///@schema_path@/architecture.xsd \ + http://www.tik.ee.ethz.ch/~shapes/schema/MAPPING \ + file:///@schema_path@/mapping.xsd +