| #ifndef SIMULATION_BUFFER_H |
| #define SIMULATION_BUFFER_H |
| |
| #include <atomic> |
| #include <thread> |
| /** |
| * Odin use -1 internally, so we need to go back on forth |
| * TODO: change the default odin value to match both the Blif value and this buffer |
| */ |
| typedef signed char data_t; |
| |
| #define BUFFER_SIZE 12 //use something divisible by 4 since the compact buffer can contain 4 value |
| #define CONCURENCY_LIMIT (BUFFER_SIZE-1) // access to cycle -1 with an extra pdding cell |
| |
| |
| struct BitFields |
| { |
| uint8_t i0:2; |
| uint8_t i1:2; |
| uint8_t i2:2; |
| uint8_t i3:2; |
| }; |
| |
| class AtomicBuffer |
| { |
| private: |
| BitFields bits[BUFFER_SIZE/4]; |
| std::atomic<bool> lock; |
| int32_t cycle; |
| |
| |
| void lock_it() |
| { |
| std::atomic_thread_fence(std::memory_order_acquire); |
| while(lock.exchange(true, std::memory_order_relaxed)) |
| { |
| std::this_thread::yield(); |
| } |
| } |
| |
| void unlock_it() |
| { |
| lock.exchange(false, std::memory_order_relaxed); |
| std::atomic_thread_fence(std::memory_order_relaxed); |
| } |
| |
| /////////////////////////// |
| // 2 bits are used per value |
| data_t val(uint8_t val_in) |
| { |
| return ((val_in != 0 && val_in != 1)? -1 : val_in); |
| } |
| |
| uint8_t get_bits(uint8_t index) |
| { |
| uint8_t modindex = index%(BUFFER_SIZE); |
| uint8_t address = modindex/4; |
| uint8_t bit_index = modindex%4; |
| switch(bit_index) |
| { |
| case 0: return (this->bits[address].i0); |
| case 1: return (this->bits[address].i1); |
| case 2: return (this->bits[address].i2); |
| case 3: return (this->bits[address].i3); |
| default: return 0x3; |
| } |
| } |
| |
| void set_bits(uint8_t index, uint8_t value) |
| { |
| uint8_t modindex = index%(BUFFER_SIZE); |
| uint8_t address = modindex/4; |
| uint8_t bit_index = modindex%4; |
| |
| value = value&0x3; |
| |
| switch(bit_index) |
| { |
| case 0: this->bits[address].i0 = value; break; |
| case 1: this->bits[address].i1 = value; break; |
| case 2: this->bits[address].i2 = value; break; |
| case 3: this->bits[address].i3 = value; break; |
| default: break; |
| } |
| } |
| public: |
| |
| AtomicBuffer(data_t value_in) |
| { |
| this->lock = false; |
| this->cycle = -1; |
| this->init_all_values(value_in); |
| } |
| |
| void print() |
| { |
| for(int i=0; i<BUFFER_SIZE; i++) |
| { |
| uint8_t value = get_bits( i); |
| printf("%s",(value == 0)? "0": (value == 1)? "1": "x"); |
| } |
| printf("\n"); |
| } |
| |
| void init_all_values( data_t value) |
| { |
| this->lock = false; |
| for(int i=0; i<BUFFER_SIZE; i++) |
| set_bits( i, value); |
| } |
| |
| int32_t lock_free_get_cycle() |
| { |
| return this->cycle; |
| } |
| |
| void lock_free_update_cycle( int64_t cycle_in) |
| { |
| //if (cycle_in > this->cycle) |
| this->cycle = cycle_in; |
| } |
| |
| data_t lock_free_get_value( int64_t cycle_in) |
| { |
| return val(get_bits( cycle_in)); |
| } |
| |
| void lock_free_update_value( data_t value_in, int64_t cycle_in) |
| { |
| if (cycle_in > this->cycle) |
| { |
| set_bits( cycle_in,value_in); |
| lock_free_update_cycle( cycle_in); |
| } |
| } |
| |
| void lock_free_copy_foward_one_cycle( int64_t cycle_in) |
| { |
| set_bits( cycle_in+1,get_bits(cycle_in)); |
| lock_free_update_cycle( cycle_in); |
| } |
| |
| int32_t get_cycle() |
| { |
| lock_it(); |
| int32_t value = lock_free_get_cycle(); |
| unlock_it(); |
| return value; |
| } |
| |
| void update_cycle( int64_t cycle_in) |
| { |
| lock_it(); |
| lock_free_update_cycle(cycle_in); |
| unlock_it(); |
| } |
| |
| data_t get_value( int64_t cycle_in) |
| { |
| lock_it(); |
| data_t value = lock_free_get_value( cycle_in); |
| unlock_it(); |
| return value; |
| } |
| |
| void update_value( data_t value_in, int64_t cycle_in) |
| { |
| lock_it(); |
| lock_free_update_value( value_in, cycle_in); |
| unlock_it(); |
| |
| } |
| |
| void copy_foward_one_cycle( int64_t cycle_in) |
| { |
| lock_it(); |
| lock_free_copy_foward_one_cycle( cycle_in); |
| unlock_it(); |
| } |
| |
| }; |
| |
| #endif |