2
* $Id: vcd.c,v 1.3 2003/12/01 05:48:35 troth Exp $
4
****************************************************************************
6
* simulavr-vcd - A vcd file writer as display process for simulavr.
7
* Copyright (C) 2002 Carsten Beth
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2 of the License, or
12
* (at your option) any later version.
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software
21
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
****************************************************************************
26
/* WARNING: This code is a hack and needs major improvements. */
37
int vcd_read_config (char *config_file_name);
39
/* from config_parser.c */
41
extern int parse_config (FILE * infile);
43
/* Definitions for debugging (Add -DENABLE_DEBUG=1 to compile command to
44
enable debugging output). */
47
# define ENABLE_DEBUG 0
51
# define DEBUG_FKT_CALL( x ) x;
53
# define DEBUG_FKT_CALL( x )
58
char *vcd_file_name = NULL;
59
FILE *vcd_file = NULL;
61
/* Number of clocks (time = 1/f * clk) */
65
/* Dump tables are used to store the information which signals has to be
66
written to the vcd file. We define one char for each signal. Each Signal
67
with a dump table value != 0 will be written. */
69
char *io_reg_dump_table;
71
char *sram_dump_table;
75
/* A signal is an entry in the vcd file which has to be traced. */
77
typedef struct t_signal
79
char *name; /* Visible name */
80
char *shortcut; /* Short name which is written in vcd file */
81
int addr; /* Address of signal */
82
unsigned int width; /* Width of the traced signal */
83
t_signal_type type; /* vcd type of the traced signal */
84
struct t_signal *next; /* Pointer to the next signal */
87
/* There are several kinds of signals. */
89
t_signal *io_reg_signals = NULL;
90
t_signal *reg_signals = NULL;
91
t_signal *sram_signals = NULL;
92
t_signal *other_signals = NULL;
101
vcd_new_signal (t_signal **signals, char *name, char *shortcut, int addr,
102
unsigned int width, t_signal_type type)
106
/* Allocate memory for new signal */
107
new = (t_signal *)malloc (sizeof (t_signal));
109
/* If there is a name, make a copy */
112
new->name = (char *)malloc (strlen (name));
113
strcpy (new->name, name);
118
/* If there is a shortcut, make a copy */
121
new->shortcut = (char *)malloc (strlen (shortcut));
122
strcpy (new->shortcut, shortcut);
127
/* Copy the other values */
132
/* Link to signal list */
133
new->next = *signals;
140
vcd_free_signals (t_signal **signals)
146
/* Remove from list */
148
*signals = (*signals)->next;
159
/* Close a vcd_file */
164
if (vcd_file && vcd_file != stdout)
171
/* Open a vcd_file by name. If name is "-" stdout will be used to write to. */
174
vcd_open (char *vcd_file_name)
178
fprintf (stderr, "unvalid VCD file name: (NULL)\n");
182
/* Possibly close an opened vcd file */
186
/* Open a VCD file */
187
if (strcmp (vcd_file_name, "-") == 0)
191
vcd_file = fopen (vcd_file_name, "w");
194
fprintf (stderr, "open VCD file failed: %s\n", strerror (errno));
202
/* Close files and free memory. */
209
if (io_reg_dump_table)
210
free (io_reg_dump_table);
213
free (reg_dump_table);
216
free (sram_dump_table);
218
vcd_free_signals (&io_reg_signals);
219
vcd_free_signals (®_signals);
220
vcd_free_signals (&sram_signals);
221
vcd_free_signals (&other_signals);
224
free (vcd_file_name);
227
/* Initialize dump tables, parse config file and open vcd file. */
230
vcd_init (int sram_size, int eeprom_size)
232
DEBUG_FKT_CALL (fprintf
233
(stderr, "vcd_init( %i, %i )\n", sram_size, eeprom_size));
237
sizes.sram_size = sram_size;
238
sizes.eeprom_size = eeprom_size;
240
/* Initialize dump tables */
241
io_reg_dump_table = (char *)calloc (64, sizeof (char));
242
reg_dump_table = (char *)calloc (32, sizeof (char));
243
sram_dump_table = (char *)calloc (sram_size, sizeof (char));
247
if (!io_reg_dump_table || !reg_dump_table || !sram_dump_table)
249
fprintf (stderr, "virtual memory exhausted\n");
253
/* Parse configuration file */
254
if (!vcd_read_config ("vcd.cfg"))
258
if (!vcd_open (vcd_file_name))
264
/***************************************************************/
266
/* Write the current date and time to the vcd file */
269
vcd_write_time (void)
271
time_t current_time = time (NULL);
276
fprintf (vcd_file, "$date\n");
277
fprintf (vcd_file, " %s", ctime (¤t_time));
278
fprintf (vcd_file, "$end\n");
279
fprintf (vcd_file, "\n");
284
/* Write the version to the vcd file */
287
vcd_write_version (void)
292
fprintf (vcd_file, "$version\n");
293
fprintf (vcd_file, " simulavr vcd dumper version %s\n", VCD_VERSION);
294
fprintf (vcd_file, "$end\n");
295
fprintf (vcd_file, "\n");
300
/* Write the timescale to the vcd file. The timescale is always 1 ns. */
303
vcd_write_timescale (void)
308
fprintf (vcd_file, "$timescale\n");
309
fprintf (vcd_file, " 1ns\n");
310
fprintf (vcd_file, "$end\n");
311
fprintf (vcd_file, "\n");
317
vcd_bind_io_reg_shortcut (char *io_reg_name, int io_reg_addr)
323
DEBUG_FKT_CALL (fprintf
324
(stderr, "vcd_bind_io_register_shortcut( %s, %i )\n",
325
io_reg_name, io_reg_addr));
330
/* Generate a name and shortcut */
331
snprintf (name, 100 - 1, "%x_%s", io_reg_addr, io_reg_name);
332
snprintf (shortcut, 100 - 1, "ioreg%x", io_reg_addr);
334
/* Count io_reg_signals to search for matching names or addresses */
335
for (p = io_reg_signals; p; p = p->next)
337
/* Does the addresses or names match? */
338
if ((p->addr == io_reg_addr)
339
|| (p->name && (strcmp (p->name, io_reg_name) == 0)))
341
/* Mark register as used */
342
io_reg_dump_table[io_reg_addr] = 1;
344
/* Change the signals name */
347
p->name = (char *)malloc (strlen (name));
348
strcpy (p->name, name);
350
/* Copy the address */
351
p->addr = io_reg_addr;
353
/* Copy the shortcut */
356
p->shortcut = (char *)malloc (strlen (shortcut));
357
strcpy (p->shortcut, shortcut);
365
/* Set the controlers clock frequency. */
368
vcd_set_frequency (int f)
370
DEBUG_FKT_CALL (fprintf (stderr, "vcd_set_frequency( %i )\n", f));
375
/* Set the file name which sould be used for the vcd file. */
378
vcd_set_file_name (char *name)
380
DEBUG_FKT_CALL (fprintf (stderr, "vcd_set_file_name( %s )\n", name));
383
free (vcd_file_name);
385
vcd_file_name = name;
388
/* Mark a io-register for tracing. This function can be called either with an
389
io_reg_name or an io_reg_addr. */
392
vcd_trace_io_reg (char *io_reg_name, int io_reg_addr)
394
vcd_new_signal (&io_reg_signals, io_reg_name, NULL, io_reg_addr, 8,
397
return 0; /* FIXME: why wasn't this returning
401
/* Mark register reg_num for tracing. */
404
vcd_trace_reg (int reg_num)
409
/* Generate a name and shortcut */
410
snprintf (name, 100 - 1, "REG_%02x", reg_num);
411
snprintf (shortcut, 100 - 1, "reg%x", reg_num);
413
vcd_new_signal (®_signals, name, shortcut, -1, 8, ST_REGISTER);
415
/* mark register as used */
416
reg_dump_table[reg_num] = 1;
418
return 0; /* FIXME: why wasn't this returning
422
/* Mark sram[sram_addr] for tracing. */
425
vcd_trace_sram (int sram_addr)
430
if ((sram_addr < 0) || (sram_addr > sizes.sram_size - 1))
433
/* Generate name and shortcut */
434
sprintf (name, "SRAM_%02x", sram_addr);
435
sprintf (shortcut, "sram%x", sram_addr);
437
vcd_new_signal (&sram_signals, name, shortcut, -1, 8, ST_REGISTER);
439
/* mark sram cell as used */
440
sram_dump_table[sram_addr] = 1;
442
return 0; /* FIXME: why wasn't this returning
446
/* Mark stack pointer for tracing. */
451
vcd_new_signal (&other_signals, "SP", "sp", -1, 16, ST_REGISTER);
453
/* mark sp cell as used */
456
return 0; /* FIXME: why wasn't this returning
460
/* Mark program counter for tracing. */
465
vcd_new_signal (&other_signals, "PC", "pc", -1, 16, ST_REGISTER);
467
/* mark pc cell as used */
470
return 0; /* FIXME: why wasn't this returning
474
/* Read an parse the config file. */
477
vcd_read_config (char *config_file_name)
481
DEBUG_FKT_CALL (fprintf
482
(stderr, "vcd_read_config( %s )\n", config_file_name));
484
config_file = fopen (config_file_name, "r");
487
fprintf (stderr, "open config file failed: %s\n", strerror (errno));
491
if (!parse_config (config_file))
493
fprintf (stderr, "error while reading config file\n");
494
fclose (config_file);
498
fclose (config_file);
502
/* Write signal declarations to the vcd file. */
505
vcd_write_signals (t_signal *signals, char *module_name)
509
fprintf (vcd_file, "$scope module %s $end\n", module_name);
511
for (; signals; signals = signals->next)
512
if (signals->shortcut)
513
fprintf (vcd_file, "$var reg %i %s %s $end\n",
514
signals->width, signals->shortcut, signals->name);
516
fprintf (vcd_file, "$upscope $end\n");
517
fprintf (vcd_file, "\n");
521
/* Write the header to the vcd file. */
524
vcd_write_header (void)
526
DEBUG_FKT_CALL (fprintf (stderr, "vcd_write_header()\n"));
532
fseek (vcd_file, 0, SEEK_SET);
535
vcd_write_version ();
536
vcd_write_timescale ();
538
vcd_write_signals (io_reg_signals, "io_register");
539
vcd_write_signals (reg_signals, "register");
540
vcd_write_signals (sram_signals, "sram");
541
vcd_write_signals (other_signals, "other");
543
fprintf (vcd_file, "$enddefinitions $end\n");
544
fprintf (vcd_file, "\n");
546
/* Go back to the end of the vcd-file */
547
fseek (vcd_file, 0, SEEK_END);
552
/* Write a 8 bit binary value to the vcd file. */
555
vcd_write_bit8 (unsigned char val)
559
fputc ('b', vcd_file); /* write binary signature */
560
for (i = 0x80; i > 0; i /= 2) /* shift bit in i for masking */
561
fputc (((val & i) != 0) + '0', vcd_file); /* write masked bit */
564
/* Write a 16 bit binary value to the vcd file. */
567
vcd_write_bit16 (unsigned short val)
571
fputc ('b', vcd_file); /* write binary signature */
572
for (i = 0x8000; i > 0; i /= 2) /* shift bit in i for masking */
573
fputc (((val & i) != 0) + '0', vcd_file); /* write masked bit */
576
/* Write io-register to the vcd file. */
579
vcd_write_io_reg (int io_reg_addr, unsigned char val)
581
DEBUG_FKT_CALL (fprintf
582
(stderr, "io_vcd_write_reg( %i, %i )\n", io_reg_addr,
588
if (!io_reg_dump_table[io_reg_addr])
592
vcd_write_bit8 (val);
593
fprintf (vcd_file, " ioreg%x\n", io_reg_addr); /* write identifier */
595
fflush (vcd_file); /* for debug only */
600
/* Write register to the vcd file. */
603
vcd_write_reg (int reg_num, unsigned char val)
605
DEBUG_FKT_CALL (fprintf
606
(stderr, "vcd_write_reg( %i, %i )\n", reg_num, val));
611
if (!reg_dump_table[reg_num])
615
vcd_write_bit8 (val);
616
fprintf (vcd_file, " reg%x\n", reg_num); /* write identifier */
618
fflush (vcd_file); /* for debug only */
623
/* Write sram to the vcd file. */
626
vcd_write_sram (int sram_addr, unsigned char val)
628
DEBUG_FKT_CALL (fprintf
629
(stderr, "vcd_write_sram( %i, %i )\n", sram_addr, val));
634
if ((sram_addr < 0) || (sram_addr > sizes.sram_size - 1))
637
if (!sram_dump_table[sram_addr])
641
vcd_write_bit8 (val);
642
fprintf (vcd_file, " sram%x\n", sram_addr); /* write identifier */
644
fflush (vcd_file); /* for debug only */
649
/* Write stack pointer to the vcd file. */
652
vcd_write_sp (int sp)
654
static unsigned int written_sp = -1;
656
DEBUG_FKT_CALL (fprintf (stderr, "vcd_write_sp( %i )\n", sp));
661
if (!sp_dump_table || (sp == written_sp))
667
vcd_write_bit16 (sp);
668
fprintf (vcd_file, " sp\n"); /* write identifier */
670
fflush (vcd_file); /* for debug only */
675
/* Write program counter to the vcd file. */
678
vcd_write_pc (int pc)
680
DEBUG_FKT_CALL (fprintf (stderr, "vcd_write_pc( %i )\n", pc));
689
vcd_write_bit16 (pc);
690
fprintf (vcd_file, " pc\n"); /* write identifier */
692
fflush (vcd_file); /* for debug only */
697
/* Set the current time. */
700
vcd_set_clock (unsigned int c)
704
return 0; /* FIXME: why wasn't this returning
708
/* Write current time to the vcd file. */
711
vcd_write_clock (void)
713
static unsigned int written_clk = -1;
714
static unsigned int factor = 1e9;
719
/* Have we already written the current time? */
720
if (clk == written_clk)
724
/* Write the current time */
725
fprintf (vcd_file, "#%i\n", clk * (factor / frequency));
727
fflush (vcd_file); /* for debug only */