// memory_logic.h
#ifndef MEMORY_LOGIC_H
#define MEMORY_LOGIC_H

#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>

// Core structure for memory region management
typedef struct {
    void* base_addr;
    size_t size;
    int fd;
    uint8_t* state_map;
} MemoryRegion;

// Structure for a single logic gate in memory
typedef struct {
    uint32_t input_offset_a;
    uint32_t input_offset_b;
    uint32_t output_offset;
    uint8_t current_state;
    uint64_t operation_count;
    uint64_t last_operation_time;
} MemGate;

// Structure for performance monitoring
typedef struct {
    uint64_t start_time;
    uint64_t operation_count;
    uint64_t total_transitions;
    uint64_t errors;
    double avg_transition_time;
} PerformanceMetrics;

// Core functions for memory management
MemoryRegion* init_memory_region(const char* device_path, size_t offset, size_t size);
void cleanup_memory_region(MemoryRegion* region);

// Basic gate operations
uint8_t mem_nand(MemoryRegion* region, MemGate* gate);
uint8_t mem_read_state(MemoryRegion* region, uint32_t offset);
void mem_write_state(MemoryRegion* region, uint32_t offset, uint8_t state);

// Performance monitoring
void start_performance_monitoring(PerformanceMetrics* metrics);
void update_metrics(PerformanceMetrics* metrics, uint64_t operation_time);
void log_performance(PerformanceMetrics* metrics, const char* operation);

#endif

// memory_logic.c
#include "memory_logic.h"
#include <time.h>
#include <stdio.h>

MemoryRegion* init_memory_region(const char* device_path, size_t offset, size_t size) {
    MemoryRegion* region = malloc(sizeof(MemoryRegion));
    if (!region) return NULL;

    // Open device with direct I/O flag for bypassing cache
    region->fd = open(device_path, O_RDWR | O_DIRECT);
    if (region->fd < 0) {
        free(region);
        return NULL;
    }

    // Map memory region
    region->base_addr = mmap(NULL, size, PROT_READ | PROT_WRITE,
                           MAP_SHARED, region->fd, offset);
    if (region->base_addr == MAP_FAILED) {
        close(region->fd);
        free(region);
        return NULL;
    }

    region->size = size;
    region->state_map = calloc(size / 8, sizeof(uint8_t)); // bit map for states

    return region;
}

uint8_t mem_nand(MemoryRegion* region, MemGate* gate) {
    struct timespec start, end;
    clock_gettime(CLOCK_MONOTONIC, &start);

    // Read input states
    uint8_t input_a = mem_read_state(region, gate->input_offset_a);
    uint8_t input_b = mem_read_state(region, gate->input_offset_b);

    // Perform NAND operation
    uint8_t result = !(input_a & input_b);

    // Write result
    mem_write_state(region, gate->output_offset, result);

    // Update gate metrics
    clock_gettime(CLOCK_MONOTONIC, &end);
    gate->last_operation_time = (end.tv_sec - start.tv_sec) * 1000000000 +
                               (end.tv_nsec - start.tv_nsec);
    gate->operation_count++;
    gate->current_state = result;

    return result;
}

void mem_write_state(MemoryRegion* region, uint32_t offset, uint8_t state) {
    // Ensure aligned writes
    uint32_t aligned_offset = offset & ~(sizeof(uint64_t) - 1);
    uint64_t* target = (uint64_t*)((uint8_t*)region->base_addr + aligned_offset);
    
    // Use atomic operation for state update
    __atomic_store_n(target, state ? ~0ULL : 0ULL, __ATOMIC_RELEASE);
    
    // Update state map
    uint32_t byte_offset = offset / 8;
    uint8_t bit_offset = offset % 8;
    if (state) {
        region->state_map[byte_offset] |= (1 << bit_offset);
    } else {
        region->state_map[byte_offset] &= ~(1 << bit_offset);
    }
}