예제 #1
0
void Log_printf(char *fmt, ...)
//********************
// Wrapper around vfprintf that checks for any file I/O errors. Since the
// printf() style functions will occasionally flush the stdio buffers, they
// can return a system level error (such as disk full). Using a wrapper
// function that checks for errors immediately after each printf() guarantees
// that errno will still be valid and that strerror() wlll produce a useful
// message to the user.
{
   char strBuffer[MAXBUF];
   va_list args;

   // Do nothing if the log file could not be opened or was already closed
   // due to a previous error.
   if(!File) {
      return;
   }

   // Call the real fvprintf function to do the actual printing
   va_start(args, fmt);
   vfprintf(File, fmt, args);

   // If any I/O error occurred, break with error message and close log file
   if(ferror(File)) {
      snprintf(strBuffer, MAXBUF, "Could not write \"%s\" file: %s",
         FILE_NAME, strerror(errno));
      BREAK(strBuffer);
      Close_file();
   }

   va_end(args);
}
예제 #2
0
void On_simulation_begin()
//************************
// VMLAB informs you that the simulation is starting. Initialize pin values
// here Open files; allocate memory, etc.
// The first instance to enter this function is responsible for opening the
// single log file and initializing any global data. Although the log filename
// doesn't change with each simulation, it's better to open it here and close it
// in On_simulation_end(). This allows the user to delete or move the log file
// without having to close or rebuild the project.
{
   char strBuffer[MAXBUF];

   // Force the initial value of data input to be logged at time step 0
   VAR(Log_data) = -1;

   // Keep track of how many instances have already been created
   VAR(Instance_number) = Instance_count;
   Instance_count++;
   
   // Because the VCD file format uses a single ASCII character to identify each
   // signal, it limits the number of vcdlog instances that can be used in a
   // project
   if(VAR(Instance_number) + MIN_ID > MAX_ID) {
      snprintf(strBuffer, MAXBUF, "Too many instances (max %d)",
         MAX_ID - MIN_ID + 1);
      BREAK(strBuffer);
      Close_file();
   }

   // The first instance to have its On_simulation_begin() called is responsible
   // for opening the log file and initializing global variables.
   if(Instance_count == 1) {
      Total_time = 0;

      // Setting Log_time to -1 forces the first instance entering
      // On_time_step(), to finish writing the VCD header section.
      Log_time = -1;

      // Create or overwrite log file in current directory
      File = fopen(FILE_NAME, "w");

      // We can still run if the file won't open; we just can't log anything.
      if(!File) {
         snprintf(strBuffer, MAXBUF, "Could not create \"%s\" file: %s",
            FILE_NAME, strerror(errno));
         BREAK(strBuffer);
      }
      
      // Write out the global VCD file header
      Log_printf("$version VMLAB vcdlog component $end\n");
      Log_printf("$timescale 1 %s $end\n", TIME_UNITS);
      Log_printf("$scope module vmlab $end\n");
   }

   // Write out per instance part of the VCD header that contains the variable
   // name and the ASCII identifier.
   Log_printf("$var wire 1 %c %s $end\n",
      VAR(Instance_number) + MIN_ID, GET_INSTANCE());
}
예제 #3
0
void On_simulation_end()
//**********************
// Undo here the operations done at On_simulation_begin: free memory, close
// files, etc.
{
   free(VAR(Sample_buffer));
   Close_file();
}
예제 #4
0
void On_simulation_end()
//**********************
// Undo here the operations done at On_simulation_begin: free memory, close
// files, etc.
{
   // Do nothing if the log file could not be opened
   if(!VAR(File)) {
      return;
   }

   // Write the last pending entry to the log
   Write_log(0);

   // Close the log file so it can be moved or deleted
   Close_file();
}
예제 #5
0
int create_index_file(char* filename) {
	FILE *fd;

	if ((fd = fopen(filename,"wx")) != NULL)
		fprintf(fd, "<html><body><h1>ur file has been removed. so get out of here!</h1></body></html>\n");
	else if (errno == EEXIST) {
		msg(MSG_ERROR, "index.html already exists\n");
		return -1;
	}
	else {
		msg(MSG_ERROR, "could not create the index.html: %s", strerror(errno));
		return -1;
	}
	
	fflush(fd);
	Close_file(fd);
	return 0;
}
예제 #6
0
void On_simulation_end()
//**********************
// Undo here the operations done at On_simulation_begin: free memory, close
// files, etc.
{
   // Write the total elapsed simulation time at the end of the VCD file,
   // making sure to convert it to nanoseconds. Without this final "delay"
   // in the VCD file, any bit value changes in the last time step might
   // not be visible in some waveform viewers like GTKWave.
   Log_printf("#%.0lf\n", Total_time * TIME_MULT);

   // Since there is nothing else left to do here, except for closing the
   // log file, we just let the first instance to enter On_simulation_end()
   // close the file and reset the global Instance_count in preparation for
   // another simulation.
   Close_file();
   Instance_count = 0;
}
예제 #7
0
void On_simulation_begin()
//************************
// VMLAB informs you that the simulation is starting. Initialize pin values
// here Open files; allocate memory, etc.
// Although the wav filename doesn't change with each simulation, it's better to
// open it here and close it in On_simulation_end(). This allows the user to
// delete or move the log file without having to close or rebuild the project.
{
   char strBuffer[MAXBUF];

   // Open existing wav file in current directory. The libsndfile API requires
   // the SF_INFO.format field set to 0 before opening a file for read access.
   VAR(File_info).format = 0;
   snprintf(strBuffer, MAXBUF, "%s.wav", GET_INSTANCE());
   VAR(File) = sf_open(strBuffer, SFM_READ, &VAR(File_info));

   // We can still run if the file won't open; output stays at POWER()/2.
   if(!VAR(File)) {
      snprintf(strBuffer, MAXBUF, "Could not open \"%s.wav\" file: %s",
         GET_INSTANCE(), sf_strerror(VAR(File)));
      BREAK(strBuffer);
      return;
   }
   
   // If the WAV file contains more than one channel, print an error mssage
   // that the additional channels will be ignored.
   if(VAR(File_info).channels != 1) {
      snprintf(strBuffer, MAXBUF, "File \"%s.wav\" has multiple channels; "
         "only first (left) channel used", GET_INSTANCE());
      PRINT(strBuffer);
   }
   
   // Allocate buffer large enough to hold a single sample across all the
   // channels. The libsndfile library requires that all the channels are read
   // at once, and it provides no way to ignore unwanted channels.
   VAR(Sample_buffer) = (double *)
      malloc(sizeof(double) * VAR(File_info).channels);
   if(!VAR(Sample_buffer)) {
      BREAK("Error allocating memory buffer");
      Close_file();
      return;
   }
}
예제 #8
0
void On_remind_me(double pTime, int pData)
//***************************************
// VMLAB notifies about a previouly sent REMIND_ME() function.
// Read the next voltage sample from the WAV file, set the analog voltage on the
// output pin, and schedule another output update based on the sampling rate of
// the input wav file.
{
   char strBuffer[MAXBUF];

   // Do nothing if the wav file is closed due to an error
   if(!VAR(File)) {
      return;
   }
   
   // Read the next voltage sample from the wav file. If an error occurs or
   // EOF is reached, then the wav file is closed, the output voltage remains
   // set to the previous value and no more output updates are scheduled.
   if(sf_readf_double(VAR(File), VAR(Sample_buffer), 1) != 1) {
      // Break with an error message if an actual I/O or decode error occurred
      if(sf_error(VAR(File))) {
         snprintf(strBuffer, MAXBUF, "Error reading \"%s.wav\" file: %s",
            GET_INSTANCE(), sf_strerror(VAR(File)));
         BREAK(strBuffer);         
      }
      
      // Close the file on either an error or a normal end-of-file
      Close_file();
      return;
   }

   // The voltage in VMLAB ranges from 0 to POWER(), while the sample that
   // libsndfile returns ranges from -1 to +1. Only the sample from the
   // first (left) channel is used here. Samples from additional channels
   // are simply discarded.
   SET_VOLTAGE(DATA, (*VAR(Sample_buffer) + 1) * 0.5 * POWER());

   // Schedule the next On_remind_me() based on the sampling rate
   REMIND_ME(1.0 / VAR(File_info).samplerate);
}
예제 #9
0
void Write_log(double pTime)
//********************
// If the elapsed time "pTime" of the current time step is different from the
// previous time step at "VAR(Log_time)" then write a log entry for the previous
// time step. Because On_digital_in_edge() may be called multiple times for the
// same time step, we want to delay writing any log entry until we know the time
// step has been fully simulated.
{
   char strBuffer[MAXBUF];
   double logCycle;

   // Do nothing if log file could not be opened or if the next time step has
   // not been reached yet.
   if(!VAR(File) || pTime == VAR(Log_time)) {
      return;
   }

   // The elapsed time (in seconds) is converted to a cycle count based on the
   // MCU's clock rate (specified as a parameter). The "- VAR(offset)" subtracts
   // out the initial power on delay from the cycle count. Also, to avoid any
   // floating point round off errors, the fprintf() is used to round up the
   // result to the closest integer instead of using an integer cast.
   logCycle = (VAR(Log_time) - VAR(Clock_delay)) / VAR(Clock_period);      
   fprintf(VAR(File), "%09.0lf:%02X\n", logCycle, VAR(Log_data));

   // If any errors occur with writing the file, then break with an error
   // message and close the file to prevent any further logging.
   if(ferror(VAR(File))) {
      snprintf(strBuffer, MAXBUF, "Could not write \"%s.log\" file: %s",
         GET_INSTANCE(), strerror(errno));
      BREAK(strBuffer);
      
      Close_file();
   }

   // Record current time so next log entry isn't written until next time step
   VAR(Log_time) = pTime;
}