blob: ce353ff6e01f6dcbfecf9cf792979b21fa1629b2 [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 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