blob: 5692e1d9980c22b3c2b3870ea1ffebe027930258 [file] [log] [blame]
#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 4 //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
class AtomicBuffer
{
private:
struct BitFields
{
uint8_t i0:2;
uint8_t i1:2;
uint8_t i2:2;
uint8_t i3:2;
} bits[BUFFER_SIZE/4];
std::atomic<bool> lock;
int32_t cycle;
uint8_t to_val(data_t val_in)
{
return (val_in == 0)? 0: (val_in == 1)? 1 : 2;
}
template<typename T>
data_t val(T val_in)
{
switch(val_in)
{
case 0: //fallthrough
case '0': return 0;
case 1: //fallthrough
case '1': return 1;
default: return -1;
}
}
template<typename T>
char val_c(T val_in)
{
switch(val_in)
{
case 0: //fallthrough
case '0': return '0';
case 1: //fallthrough
case '1': return '1';
default: return 'x';
}
}
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);
}
uint8_t get_bits(int64_t index)
{
uint8_t modindex = (uint8_t)(index%(BUFFER_SIZE));
uint8_t address = modindex/4;
uint8_t bit_index = modindex%4;
switch(bit_index)
{
case 0: return (uint8_t)(this->bits[address].i0);
case 1: return (uint8_t)(this->bits[address].i1);
case 2: return (uint8_t)(this->bits[address].i2);
case 3: return (uint8_t)(this->bits[address].i3);
default: return (uint8_t)0x3;
}
}
void set_bits(int64_t index, uint8_t value)
{
uint8_t modindex = (uint8_t)(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 = (uint8_t)(value&0x3); break;
case 1: this->bits[address].i1 = (uint8_t)(value&0x3); break;
case 2: this->bits[address].i2 = (uint8_t)(value&0x3); break;
case 3: this->bits[address].i3 = (uint8_t)(value&0x3); 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++)
printf("%c",val_c(get_bits(i)));
printf("\n");
}
void init_all_values( data_t value)
{
this->lock = false;
for(int i=0; i<BUFFER_SIZE; i++)
set_bits( i, to_val(value));
}
int64_t lock_free_get_cycle()
{
return (int64_t)this->cycle;
}
void lock_free_update_cycle( int64_t cycle_in)
{
//if (cycle_in > this->cycle)
this->cycle = (int32_t)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, to_val(value_in) );
lock_free_update_cycle( cycle_in);
}
}
void lock_free_copy_foward_one_cycle( int64_t cycle_in)
{
if (cycle_in > this->cycle)
{
set_bits( cycle_in+1, get_bits(cycle_in) );
lock_free_update_cycle( cycle_in );
}
}
int64_t get_cycle()
{
lock_it();
int64_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