blob: 4556c645eced4266d8351782c5d459110a4f63fe [file] [log] [blame]
#ifndef SIMULATION_BUFFER_H
#define SIMULATION_BUFFER_H
#include <atomic>
#include <thread>
#include <assert.h>
/**
* 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
#define BUFFER_ARRAY_SIZE(input_size) (((input_size/4) + ((input_size%4)?1:0)))
class AtomicBuffer
{
private:
uint8_t bits[BUFFER_ARRAY_SIZE(BUFFER_SIZE)];
std::atomic_flag lock = ATOMIC_FLAG_INIT;
int64_t cycle;
template<typename T>
uint8_t to_val(T val_in)
{
switch(val_in)
{
case 0: //fallthrough
case '0': return 0;
case 1: //fallthrough
case '1': return 1;
default: return 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()
{
uint8_t count = 0;
while(lock.test_and_set(std::memory_order_acquire))
{
count = (count + 1) % ((uint8_t)128);
if(!count)
std::this_thread::yield();
}
}
void unlock_it()
{
lock.clear(std::memory_order_release);
}
template<typename CYCLE_T>
uint8_t get_addr(CYCLE_T in)
{
int64_t cycle_in = static_cast<int64_t>(in) % static_cast<int64_t>(size());
uint8_t casted_addr = static_cast<uint8_t>(cycle_in);
return (casted_addr/4);
}
template<typename CYCLE_T>
uint8_t get_index(CYCLE_T in)
{
int64_t cycle_in = static_cast<int64_t>(in) % static_cast<int64_t>(size());
uint8_t casted_addr = static_cast<uint8_t>(cycle_in);
return (uint8_t)((casted_addr%4) * 2);
}
template<typename CYCLE_T>
data_t get_bits(CYCLE_T index)
{
uint8_t addr = get_addr(index);
uint8_t id = get_index(index);
uint8_t bitset = bits[addr];
bitset = (uint8_t)(bitset >> id);
bitset = (uint8_t)(bitset & 0x3);
return val(bitset);
}
template<typename CYCLE_T, typename VAL_T>
void set_bits(CYCLE_T index, VAL_T value)
{
uint8_t addr = get_addr(index);
uint8_t id = get_index(index);
uint8_t value_in = to_val(value);
uint8_t reset_mask = (uint8_t)(0x3);
reset_mask = (uint8_t)(reset_mask << id);
reset_mask = (uint8_t)(~reset_mask);
value_in = (uint8_t)(value_in << id);
bits[addr] = (uint8_t)(bits[addr] & reset_mask);
bits[addr] = (uint8_t)(bits[addr] | value_in);
}
void lock_free_update_cycle( int64_t cycle_in)
{
assert(is_greater_cycle(cycle_in));
this->cycle = cycle_in;
}
bool is_greater_cycle(int64_t cycle_in)
{
return (cycle_in >= this->cycle);
}
public:
AtomicBuffer(data_t value_in)
{
this->cycle = -1;
for(size_t i=0; i<size(); i++)
set_bits( i, value_in);
}
uint8_t size()
{
return (BUFFER_ARRAY_SIZE(BUFFER_SIZE)*4);
}
void print()
{
for(size_t i=0; i<size(); i++)
printf("%c",val_c(get_bits(i)));
printf("\n");
}
void init_all_values( data_t value_in)
{
lock_it();
for(size_t i=0; i<size(); i++)
set_bits( i, value_in);
unlock_it();
}
int64_t get_cycle()
{
lock_it();
int64_t value = this->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 = get_bits( cycle_in);
unlock_it();
return value;
}
void update_value( data_t value_in, int64_t cycle_in)
{
lock_it();
lock_free_update_cycle( cycle_in );
set_bits( cycle_in, value_in );
unlock_it();
}
};
#endif