#include "read_crossbar.h" #include #include #include #include #include #include #include int run_ngspice(const char *crossbar_path) { if (!crossbar_path) { fprintf(stderr, "Crossbar path is required\n"); return -1; } char command[4096]; int written = snprintf(command, sizeof(command), "ngspice -b \"%s\" > /dev/null 2>&1", crossbar_path); if (written < 0 || (size_t)written >= sizeof(command)) { fprintf(stderr, "Could not construct ngspice command\n"); return -1; } int status = system(command); if (status != 0) { fprintf(stderr, "ngspice command failed\n"); return -1; } return 0; } int read_crossbar(const char *data_path, size_t num_outputs, Crossbar_Output_Matrix *result) { if (!data_path || num_outputs == 0 || !result) { return -1; } result->time = NULL; result->voltages = NULL; FILE *file = fopen(data_path, "r"); if (!file) { fprintf(stderr, "Failed to open crossbar data file\n"); return -1; } size_t capacity = 1024; if (num_outputs > SIZE_MAX / capacity || capacity * num_outputs > SIZE_MAX / sizeof(*result->voltages)) { fclose(file); return -1; } result->time = malloc(capacity * sizeof(*result->time)); result->voltages = malloc(capacity * num_outputs * sizeof(*result->voltages)); if (result->time == NULL || result->voltages == NULL) { fprintf(stderr, "Failed to allocate crossbar results\n"); fclose(file); free_crossbar_output_matrix(result); return -1; } char line[16384]; size_t sample = 0; while (fgets(line, sizeof(line), file) != NULL) { if (sample == capacity) { if (capacity > SIZE_MAX / 2 || capacity * 2 > SIZE_MAX / num_outputs || capacity * 2 * num_outputs > SIZE_MAX / sizeof(*result->voltages)) { goto fail; } capacity *= 2; double *new_times = realloc( result->time, capacity * sizeof(*result->time)); if (!new_times) { goto fail; } result->time = new_times; double *new_voltages = realloc( result->voltages, capacity * num_outputs * sizeof(*result->voltages)); if (!new_voltages) { goto fail; } result->voltages = new_voltages; } char *position = line; double sample_time = 0.0; for (size_t output = 0; output < num_outputs; output++) { double time; double voltage; int char_count; if (sscanf(position, "%lf %lf %n", &time, &voltage, &char_count) != 2) { fprintf(stderr, "Invalid crossbar data at sample %zu\n", sample); goto fail; } if (output == 0) { sample_time = time; } result->voltages[sample * num_outputs + output] = voltage; position += char_count; } result->time[sample] = sample_time; sample++; } if (ferror(file) || fclose(file) != 0) { free_crossbar_output_matrix(result); return -1; } return 0; fail: fclose(file); free_crossbar_output_matrix(result); return -1; } int convert_output_to_software(size_t num_neurons, size_t num_outputs, size_t num_timesteps, const double *voltages, const double *resistances, double load_resistance, const conductance_mapping *mapping, const double *row_voltages, double spike_amplitude, double *decoded_outputs) { (void)row_voltages; if (num_neurons == 0 || num_outputs == 0 || num_timesteps == 0 || !voltages || !resistances || !mapping || !decoded_outputs) { return -1; } if (load_resistance <= 0.0 || mapping->alpha == 0.0 || spike_amplitude == 0.0) { return -1; } size_t num_physical_columns = num_outputs * 2; for (size_t timestep = 0; timestep < num_timesteps; timestep++) { for (size_t output = 0; output < num_outputs; output++) { size_t positive_column; size_t negative_column; size_t positive_voltage_index; size_t negative_voltage_index; size_t output_index; double positive_conductance_sum = 0.0; double negative_conductance_sum = 0.0; double positive_voltage; double negative_voltage; double positive_load_current; double negative_load_current; double positive_source_current; double negative_source_current; positive_column = 2 * output; negative_column = positive_column + 1; for (size_t neuron = 0; neuron < num_neurons; neuron++) { size_t positive_resistance_index; size_t negative_resistance_index; positive_resistance_index = neuron * num_physical_columns + positive_column; negative_resistance_index = neuron * num_physical_columns + negative_column; positive_conductance_sum += 1.0 / resistances[positive_resistance_index]; negative_conductance_sum += 1.0 / resistances[negative_resistance_index]; } positive_voltage_index = timestep * num_physical_columns + positive_column; negative_voltage_index = timestep * num_physical_columns + negative_column; positive_voltage = voltages[positive_voltage_index]; negative_voltage = voltages[negative_voltage_index]; positive_load_current = positive_voltage / load_resistance; negative_load_current = negative_voltage / load_resistance; positive_source_current = positive_load_current + positive_voltage * positive_conductance_sum; negative_source_current = negative_load_current + negative_voltage * negative_conductance_sum; output_index = timestep * num_outputs + output; decoded_outputs[output_index] = (positive_source_current - negative_source_current) / (mapping->alpha * spike_amplitude); } } return 0; } void free_crossbar_output_matrix(Crossbar_Output_Matrix *result) { if (!result) { return; } free(result->time); free(result->voltages); result->time = NULL; result->voltages = NULL; }