blob: 5356fdce922e68c654e05baa7652a4b4c8f5a49e [file] [log] [blame]
#include "lut.h"
#include <sstream>
#include "vtr_assert.h"
#include "vpr_error.h"
#include "vtr_util.h"
namespace fasm {
Lut::Lut(size_t num_inputs) : num_inputs_(num_inputs), table_(1 << num_inputs, vtr::LogicValue::DONT_CARE) {}
void Lut::SetOutput(const std::vector<vtr::LogicValue> &inputs, vtr::LogicValue value) {
VTR_ASSERT(inputs.size() == num_inputs_);
std::vector<size_t> dont_care_inputs;
dont_care_inputs.reserve(num_inputs_);
for(size_t address = 0; address < table_.size(); ++address) {
bool match = true;
for(size_t input = 0; input < inputs.size(); ++input) {
if(inputs[input] == vtr::LogicValue::TRUE && (address & (1 << input)) == 0) {
match = false;
break;
} else if(inputs[input] == vtr::LogicValue::FALSE && (address & (1 << input)) != 0) {
match = false;
break;
}
}
if(match) {
VTR_ASSERT(table_[address] == vtr::LogicValue::DONT_CARE || table_[address] == value);
table_[address] = value;
}
}
}
void Lut::CreateWire(size_t input_pin) {
std::vector<vtr::LogicValue> inputs(num_inputs_, vtr::LogicValue::DONT_CARE);
inputs[input_pin] = vtr::LogicValue::FALSE;
SetOutput(inputs, vtr::LogicValue::FALSE);
inputs[input_pin] = vtr::LogicValue::TRUE;
SetOutput(inputs, vtr::LogicValue::TRUE);
}
void Lut::SetConstant(vtr::LogicValue value) {
std::vector<vtr::LogicValue> inputs(num_inputs_, vtr::LogicValue::DONT_CARE);
SetOutput(inputs, value);
}
const LogicVec & Lut::table() {
// Make sure the entire table is defined.
for(size_t address = 0; address < table_.size(); ++address) {
if(table_[address] == vtr::LogicValue::DONT_CARE) {
table_[address] = vtr::LogicValue::FALSE;
}
}
return table_;
}
LutOutputDefinition::LutOutputDefinition(std::string definition) {
// Parse LUT.INIT[63:0] into
// fasm_feature = LUT.INIT
// start_bit = 0
// end_bit = 63
// num_inputs = log2(end_bit-start_bit+1)
size_t slice_start = definition.find_first_of('[');
size_t slice = std::string::npos;
size_t slice_end = std::string::npos;
if(slice_start != std::string::npos) {
slice = definition.find_first_of(':', slice_start);
}
if(slice != std::string::npos) {
slice_end = definition.find_first_of(']');
}
if(slice_start == std::string::npos ||
slice == std::string::npos ||
slice_end == std::string::npos ||
slice_start+1 > slice-1 ||
slice+1 > slice_end-1) {
vpr_throw(
VPR_ERROR_OTHER, __FILE__, __LINE__,
"Could not parse LUT definition %s",
definition.c_str());
}
fasm_feature = definition.substr(0, slice_start);
std::string end_bit_str = definition.substr(slice_start+1, (slice-1)-(slice_start+1)+1);
std::string start_bit_str = definition.substr(slice+1, (slice_end-1)-(slice+1)+1);
end_bit = vtr::atoi(end_bit_str);
start_bit = vtr::atoi(start_bit_str);
int width = end_bit - start_bit + 1;
// If an exact power of two, only 1 bit will be set in width.
if(width < 0 || __builtin_popcount(width) != 1) {
vpr_throw(
VPR_ERROR_OTHER, __FILE__, __LINE__,
"Invalid LUT start_bit %d and end_bit %d, not a power of 2 width.",
start_bit, end_bit);
}
// For exact power's of 2, ctz (count trailing zeros) is log2(width).
num_inputs = __builtin_ctz(width);
}
std::string LutOutputDefinition::CreateWire(int input) const {
Lut lut(num_inputs);
lut.CreateWire(input);
return CreateInit(lut.table());
}
std::string LutOutputDefinition::CreateConstant(vtr::LogicValue value) const {
Lut lut(num_inputs);
lut.SetConstant(value);
return CreateInit(lut.table());
}
std::string LutOutputDefinition::CreateInit(const LogicVec & table) const {
if(table.size() != (1u << num_inputs)) {
vpr_throw(
VPR_ERROR_OTHER, __FILE__, __LINE__,
"LUT with %d inputs requires a INIT LogicVec of size %d, got %d",
num_inputs, (1 << num_inputs), table.size());
}
std::stringstream ss;
ss << fasm_feature << "[" << end_bit << ":" << start_bit << "]=" << table;
return ss.str();
}
} // namespace fasm