/* ------------------------------ $Id: ssam.c,v 1.2 2006/02/02 16:35:11 marquet Exp $ ------------------------------------------------------------ First simulator of systems and architectures Philippe Marquet, Jan 2006 */ #include #include #include #include #include #include #include #include "ssam.h" #include "abar.h" #include "tools.h" #include "config.h" /*------------------------------ Connection management ------------------------------------------------------------*/ /* A connection is a pair of values, one for read and one for write. At each clock tick, the written value is shift to the read place. The place 0 of cnct_buf is used to write a value at time 0, to read a value at time 1, etc. as defined by cnct_read and cnct_write macros. */ union cnct_val_s { double cnct_double; unsigned cnct_int; unsigned cnct_bool:1; }; struct ssam_cnct_s { char cnct_name[CNCT_NAME_LG]; enum ssam_cnct_type_e cnct_type; union cnct_val_s cnct_buf[2]; # define cnct_write cnct_buf[current_tick & 0x01] # define cnct_read cnct_buf[1-(current_tick & 0x01)] char cnct_vcd_name[4]; /* "aaa\0" */ }; static struct ssam_cnct_s cncts[MAX_CNCT]; static int n_cnct = 0; /* number of active connections */ static struct abar_s *bar; struct ssam_cnct_s * ssam_create_connection(const char *name, enum ssam_cnct_type_e type) { int i, n; /* one more */ n_cnct++; fatal(n_cnct <= MAX_CNCT, "ssam_create_connection", "A maximum of %d connections is allowed", MAX_CNCT); /* register name */ strncpy(cncts[n_cnct-1].cnct_name, name, CNCT_NAME_LG-1); cncts[n_cnct-1].cnct_name[CNCT_NAME_LG] = '\0'; /* register type */ cncts[n_cnct-1].cnct_type = type; /* generate a vcd name: aaa, aab, aac..., 26 letters, so 26 digits */ cncts[n_cnct-1].cnct_vcd_name[3] = '\0'; for (n=n_cnct-1, i=2; i>=0; i--) { cncts[n_cnct-1].cnct_vcd_name[i] = (n % 26) + 'a'; n /= 26; } return &cncts[n_cnct-1]; } /*------------------------------ Components ------------------------------------------------------------*/ static int n_cpnt = 0; /* number of active components */ int ssam_create_component(void* (*component)(void*)) { pthread_t tid; /* register the component */ n_cpnt++; /* create the thread that will implement the component */ if ( pthread_create(&tid, NULL, component, NULL) ) return RETURN_FAILURE; return RETURN_SUCCESS; } /*------------------------------ Time and clock managment ------------------------------------------------------------*/ static int current_tick = 0; static int max_ticks = 0; int ssam_wait(void) { return abar_slave(bar); } int ssam_wait_duration(unsigned int duration) { int status = RETURN_SUCCESS; int i; for (i=0; i< duration; i++) if (ssam_wait() == RETURN_FAILURE) status = RETURN_FAILURE; return status; } /*------------------------------ Read and write routines ------------------------------------------------------------*/ int ssam_read(struct ssam_cnct_s *cnct, void *pval) { /*return nyi("ssam_read");*/ switch ( cnct->cnct_type ) { case SSAM_BOOL_T: *((unsigned*)pval) = cnct->cnct_read.cnct_bool; break; case SSAM_UINT_T: *((unsigned*)pval) = cnct->cnct_read.cnct_int; break; case SSAM_DOUBLE_T: *((double*)pval) = cnct->cnct_read.cnct_double; break; default: assert(! "Read : gni?!"); } return RETURN_SUCCESS; } int ssam_write(struct ssam_cnct_s *cnct, void *pval) { switch ( cnct->cnct_type ) { case SSAM_BOOL_T : cnct->cnct_write.cnct_bool = *((unsigned *) pval); break; case SSAM_UINT_T : cnct->cnct_write.cnct_int = *((unsigned *) pval); break; case SSAM_DOUBLE_T : cnct->cnct_write.cnct_double = *((double *) pval); break; default : assert(! "No pasaran!"); } return RETURN_SUCCESS; } /*------------------------------ Trace generation ------------------------------------------------------------*/ static FILE *trc_fd; /* trace file stream */ /* generate a vcd trace of the connection values */ static void trc_dump_cncts() { int i; int j; fprintf(trc_fd, "#%d\n", current_tick); for (i=0; i=0; j--) { fprintf(trc_fd, "%u", (cncts[i].cnct_write.cnct_int >> j) & 0x1); } fprintf(trc_fd, " %s\n", cncts[i].cnct_vcd_name); break; case SSAM_DOUBLE_T : fprintf(trc_fd, "r%.2f %s\n", cncts[i].cnct_write.cnct_double, cncts[i].cnct_vcd_name); break; default : assert(! "No pasaran!"); } } fprintf(trc_fd, "\n"); } /* call trc_dump_cncts at each tick */ static void* trc_thread() { printf("Starting trc thread\n"); do { abar_master(bar); trc_dump_cncts(); current_tick++; abar_release(bar); } while ( current_tick < max_ticks ); return NULL; } pthread_t trc_tid; static int trc_init(const char *trace_filename) { int i; /* open trace file */ trc_fd = fopen(trace_filename, "w"); assert(trc_fd); /* generate trace file header */ { time_t tloc; time(&tloc); fprintf(trc_fd, "$date\n" " %s\n" "$end\n\n", ctime(&tloc)); } fprintf(trc_fd, "$version\n" " %s\n" "$end\n\n", SSAM_VERSION); /* generate timescale */ fprintf(trc_fd, "$version\n" " %s\n" "$end\n\n", "1 ps"); /* generate scope, and vars */ fprintf(trc_fd, "$scope module SSAM $end\n"); for (i=0; i