/* * Copyright (c) 2010 Tony Bybell. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ /* * to compile: gcc -o transaction transaction.c -DHAVE_INTTYPES_H * then in this directory run: gtkwave transaction.fst transaction.sav */ #include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef HAVE_INTTYPES_H #include <inttypes.h> #endif #define OPTIONAL_DEBUG if(1) /* * some structs we'll be using for event harvesting from the VCD that * gtkwave sends via stdin into this executable */ struct tim_t { struct tim_t *next; uint64_t tim; int val; int delta; }; struct event_t { struct event_t *next; uint64_t tim; char *name; }; int main(void) { uint64_t min_time = 0, max_time = 0; uint64_t tim = 0; int prevtim = 0; int prevval = 255; struct tim_t *t_head = NULL, *t_curr = NULL; struct tim_t *t_tmp; int hcnt; uint64_t control_start = 0, control_end = 0; int blks; struct event_t *hdr_head = NULL, *hdr_curr = NULL; struct event_t *data_head = NULL, *data_curr = NULL; OPTIONAL_DEBUG { fprintf(stderr, "*** t_filter executable init ***\n"); } top: /* main control loop */ hcnt = 0; control_start = 0; control_end = 0; blks = 0; while(1) /* reading input from stdin until data_end comment received */ { char buf[1025]; char *pnt = NULL; buf[0] = 0; pnt = fgets(buf, 1024, stdin); /* CACHE (VIA puts()) THIS INPUT TO A FILE TO DEVELOP YOUR CLIENT OFFLINE FROM GTKWAVE! */ if(buf[0]) { pnt = buf; while(*pnt) /* strip off end of line character */ { if(*pnt != '\n') { pnt++; } else { *pnt = 0; break; } } if(buf[0] == '#') /* look for and extract time value */ { char *str = buf+1; unsigned char ch; tim=0; while((ch=*(str++))) { if((ch>='0')&&(ch<='9')) { tim=(tim*10+(ch&15)); } } } else if(buf[0] == 'b') /* extract the binary value of the "val" symbol */ { int collect = 0; pnt = buf+1; while(*pnt && (*pnt != ' ')) { collect <<= 1; collect |= ((*pnt) & 1); pnt++; } if((prevval ^ collect) & 128) { t_tmp = calloc(1, sizeof(struct tim_t)); t_tmp->tim = tim; t_tmp->val = collect; t_tmp->delta = tim - prevtim; prevtim = tim; if(!t_curr) { t_head = t_curr = t_tmp; } else { t_curr = t_curr->next = t_tmp; } } prevval = collect; } else if(buf[0] == '$') /* directive processing */ { if(strstr(buf, "$comment")) { if((pnt = strstr(buf, "min_time"))) { sscanf(pnt + 9, "%"SCNu64, &min_time); OPTIONAL_DEBUG { fprintf(stderr, "min: %d\n", (int)min_time); } } else if((pnt = strstr(buf, "max_time"))) { sscanf(pnt + 9, "%"SCNu64, &max_time); OPTIONAL_DEBUG { fprintf(stderr, "max: %d\n", (int)max_time); } } else if(strstr(buf, "data_end")) { break; } } } } if(feof(stdin)) /* broken pipe coming up */ { OPTIONAL_DEBUG { fprintf(stderr, "*** Terminated t_filter executable\n"); } exit(0); } } printf("$name Decoded FSK\n"); /* 1st trace name */ printf("#0\n"); { uint64_t p_tim = 0; int state = 0; int byte_remain = 0; int bcnt = 0; t_tmp = t_head; while(t_tmp) { if(t_tmp->delta == 16) { int sync_cnt = 0; uint64_t t_start = p_tim; int i; for(i=0;i<16;i++) { if(t_tmp->delta == 16) { sync_cnt++; p_tim = t_tmp->tim; t_tmp = t_tmp->next; } else { break; } } if(sync_cnt==16) { printf("#%"PRIu64" ?darkblue?Sync\n", t_start); /* write out sync xact */ printf("#%"PRIu64"\n", p_tim - 4); /* 'z' midline is no value after time */ printf("MA%"PRIu64" Start\n", t_start); /* set position/name for marker A */ control_start = t_start; goto found_sync; } continue; } p_tim = t_tmp->tim; t_tmp = t_tmp->next; } found_sync: state = 0; byte_remain = 11; /* printf("MB%"PRIu64" Num Blocks\n", p_tim); */ while(t_tmp) { int i; int collect = 0; uint64_t t_start = p_tim; if((state == 0) && (byte_remain == 10)) { struct event_t *evt = calloc(1, sizeof(struct event_t)); char buf[32]; evt->tim = p_tim; sprintf(buf, "H%d", hcnt/2); evt->name = strdup(buf); if(!control_end) { control_end = p_tim; } if(!hdr_head) { hdr_head = hdr_curr = evt; } else { hdr_curr = hdr_curr->next = evt; } /**/ if(data_curr) { evt = calloc(1, sizeof(struct event_t)); evt->tim = p_tim; evt->name = NULL; data_curr = data_curr->next = evt; } } if((state == 1) && (byte_remain == 64)) { struct event_t *evt = calloc(1, sizeof(struct event_t)); char buf[32]; evt->tim = p_tim; sprintf(buf, "D%d:", hcnt/2); evt->name = calloc(1, 74); strcpy(evt->name, buf); if(!data_head) { data_head = data_curr = evt; } else { data_curr = data_curr->next = evt; } /**/ if(hdr_curr) { evt = calloc(1, sizeof(struct event_t)); evt->tim = p_tim; evt->name = NULL; hdr_curr = hdr_curr->next = evt; } hcnt++; } for(i=0;(t_tmp) && (i<8);i++) { collect <<= 1; if(t_tmp->delta == 16) { collect |= 1; t_tmp = t_tmp->next; } else { } p_tim = t_tmp->tim; t_tmp = t_tmp->next; } if(!bcnt) { printf("#%"PRIu64" ?gray24?%02X\n", t_start, collect); blks = collect; bcnt++; } else { if(state == 1) { char conv = ((collect < ' ') || (collect >= 127)) ? '.' : collect; int slen = strlen(data_curr->name); data_curr->name[slen] = conv; if((collect >= ' ') && (collect < 127)) { printf("#%"PRIu64" ?darkgreen?%c\n", t_start, (unsigned char)collect); } else { printf("#%"PRIu64" ?darkred?%02X\n", t_start, collect); } } else { printf("#%"PRIu64" ?purple3?%02X\n", t_start, collect); } } printf("#%"PRIu64"\n", p_tim - 4); byte_remain--; if(!byte_remain) { if(state == 0) { state = 1; byte_remain = 64; } else { state = 0; byte_remain = 10; } } } } t_tmp = t_head; /* free up memory allocated */ while(t_tmp) { t_curr = t_tmp->next; free(t_tmp); t_tmp = t_curr; } t_head = t_curr = NULL; printf("$next\n"); /* indicate there is a next trace */ printf("$name Control\n"); /* next trace name */ printf("#0\n"); printf("#%"PRIu64" ?darkblue?%02X blks\n", control_start, blks); printf("#%"PRIu64"\n", control_end); printf("$next\n"); /* indicate there is a next trace */ printf("$name Headers\n"); /* next trace name */ printf("#0\n"); while(hdr_head) { if(hdr_head->name) { printf("#%"PRIu64" ?purple3?%s\n", hdr_head->tim, hdr_head->name); free(hdr_head->name); } else { printf("#%"PRIu64"\n", hdr_head->tim); } hdr_curr = hdr_head->next; free(hdr_head); hdr_head = hdr_curr; } printf("$next\n"); /* indicate there is a next trace */ printf("$name Data Payload\n"); /* next trace name */ printf("#0\n"); while(data_head) { if(data_head->name) { printf("#%"PRIu64" ?darkgreen?%s\n", data_head->tim, data_head->name); free(data_head->name); } else { printf("#%"PRIu64"\n", data_head->tim); } data_curr = data_head->next; free(data_head); data_head = data_curr; } printf("$finish\n"); /* directive to return control to gtkwave */ fflush(stdout); /* ensure nothing is stuck in output buffers which could hang gtkwave */ OPTIONAL_DEBUG { fprintf(stderr, "back to gtkwave...\n"); } goto top; /* loop forever in order to process next xact query */ return(0); }