diff --git a/backends/functional/cxx.cc b/backends/functional/cxx.cc index 5f63a06153b..d866dfea210 100644 --- a/backends/functional/cxx.cc +++ b/backends/functional/cxx.cc @@ -86,7 +86,7 @@ struct CxxStruct { for (auto p : types) { f.printf("\t\t%s %s;\n", p.second.to_string().c_str(), scope(p.first).c_str()); } - f.printf("\n\t\ttemplate void visit(T &fn) {\n"); + f.printf("\n\t\ttemplate void visit(T &&fn) {\n"); for (auto p : types) { f.printf("\t\t\tfn(\"%s\", %s);\n", RTLIL::unescape_id(p.first).c_str(), scope(p.first).c_str()); } @@ -148,37 +148,37 @@ template struct CxxPrintVisitor { return CxxTemplate::format(fmt, arg_to_string(args)...); } std::string buf(Node, Node n) { return np(n); } - std::string slice(Node, Node a, int, int offset, int out_width) { return format("slice<%2>(%0, %1)", a, offset, out_width); } - std::string zero_extend(Node, Node a, int, int out_width) { return format("$zero_extend<%1>(%0)", a, out_width); } - std::string sign_extend(Node, Node a, int, int out_width) { return format("$sign_extend<%1>(%0)", a, out_width); } - std::string concat(Node, Node a, int, Node b, int) { return format("concat(%0, %1)", a, b); } - std::string add(Node, Node a, Node b, int) { return format("$add(%0, %1)", a, b); } - std::string sub(Node, Node a, Node b, int) { return format("$sub(%0, %1)", a, b); } - std::string bitwise_and(Node, Node a, Node b, int) { return format("$and(%0, %1)", a, b); } - std::string bitwise_or(Node, Node a, Node b, int) { return format("$or(%0, %1)", a, b); } - std::string bitwise_xor(Node, Node a, Node b, int) { return format("$xor(%0, %1)", a, b); } - std::string bitwise_not(Node, Node a, int) { return format("$not(%0)", a); } - std::string unary_minus(Node, Node a, int) { return format("$neg(%0)", a); } - std::string reduce_and(Node, Node a, int) { return format("$reduce_and(%0)", a); } - std::string reduce_or(Node, Node a, int) { return format("$reduce_or(%0)", a); } - std::string reduce_xor(Node, Node a, int) { return format("$reduce_xor(%0)", a); } - std::string equal(Node, Node a, Node b, int) { return format("$eq(%0, %1)", a, b); } - std::string not_equal(Node, Node a, Node b, int) { return format("$ne(%0, %1)", a, b); } - std::string signed_greater_than(Node, Node a, Node b, int) { return format("$gt(%0, %1)", a, b); } - std::string signed_greater_equal(Node, Node a, Node b, int) { return format("$ge(%0, %1)", a, b); } - std::string unsigned_greater_than(Node, Node a, Node b, int) { return format("$ugt(%0, %1)", a, b); } - std::string unsigned_greater_equal(Node, Node a, Node b, int) { return format("$uge(%0, %1)", a, b); } - std::string logical_shift_left(Node, Node a, Node b, int, int) { return format("$shl<%2>(%0, %1)", a, b, a.width()); } - std::string logical_shift_right(Node, Node a, Node b, int, int) { return format("$shr<%2>(%0, %1)", a, b, a.width()); } - std::string arithmetic_shift_right(Node, Node a, Node b, int, int) { return format("$asr<%2>(%0, %1)", a, b, a.width()); } - std::string mux(Node, Node a, Node b, Node s, int) { return format("$mux(%0, %1, %2)", a, b, s); } - std::string pmux(Node, Node a, Node b, Node s, int, int) { return format("$pmux(%0, %1, %2)", a, b, s); } - std::string constant(Node, RTLIL::Const value) { return format("$const<%0>(%1)", value.size(), value.as_int()); } + std::string slice(Node, Node a, int, int offset, int out_width) { return format("%0.slice<%2>(%1)", a, offset, out_width); } + std::string zero_extend(Node, Node a, int, int out_width) { return format("%0.zero_extend<%1>()", a, out_width); } + std::string sign_extend(Node, Node a, int, int out_width) { return format("%0.sign_extend<%1>()", a, out_width); } + std::string concat(Node, Node a, int, Node b, int) { return format("%0.concat(%1)", a, b); } + std::string add(Node, Node a, Node b, int) { return format("%0 + %1", a, b); } + std::string sub(Node, Node a, Node b, int) { return format("%0 - %1", a, b); } + std::string bitwise_and(Node, Node a, Node b, int) { return format("%0 & %1", a, b); } + std::string bitwise_or(Node, Node a, Node b, int) { return format("%0 | %1", a, b); } + std::string bitwise_xor(Node, Node a, Node b, int) { return format("%0 ^ %1", a, b); } + std::string bitwise_not(Node, Node a, int) { return format("~%0", a); } + std::string unary_minus(Node, Node a, int) { return format("-%0", a); } + std::string reduce_and(Node, Node a, int) { return format("%0.all()", a); } + std::string reduce_or(Node, Node a, int) { return format("%0.any()", a); } + std::string reduce_xor(Node, Node a, int) { return format("%0.parity()", a); } + std::string equal(Node, Node a, Node b, int) { return format("%0 == %1", a, b); } + std::string not_equal(Node, Node a, Node b, int) { return format("%0 != %1", a, b); } + std::string signed_greater_than(Node, Node a, Node b, int) { return format("%0.signed_greater_than(%1)", a, b); } + std::string signed_greater_equal(Node, Node a, Node b, int) { return format("%0.signed_greater_equal(%1)", a, b); } + std::string unsigned_greater_than(Node, Node a, Node b, int) { return format("%0 > %1", a, b); } + std::string unsigned_greater_equal(Node, Node a, Node b, int) { return format("%0 >= %1", a, b); } + std::string logical_shift_left(Node, Node a, Node b, int, int) { return format("%0 << %1", a, b); } + std::string logical_shift_right(Node, Node a, Node b, int, int) { return format("%0 >> %1", a, b); } + std::string arithmetic_shift_right(Node, Node a, Node b, int, int) { return format("%0.arithmetic_shift_right(%1)", a, b); } + std::string mux(Node, Node a, Node b, Node s, int) { return format("%2.any() ? %1 : %0", a, b, s); } + std::string pmux(Node, Node a, Node b, Node s, int, int) { return format("%0.pmux(%1, %2)", a, b, s); } + std::string constant(Node, RTLIL::Const value) { return format("Signal<%0>(%1)", value.size(), value.as_int()); } std::string input(Node, IdString name) { return format("input.%0", input_struct[name]); } std::string state(Node, IdString name) { return format("current_state.%0", state_struct[name]); } - std::string memory_read(Node, Node mem, Node addr, int, int) { return format("$memory_read(%0, %1)", mem, addr); } - std::string memory_write(Node, Node mem, Node addr, Node data, int, int) { return format("$memory_write(%0, %1, %2)", mem, addr, data); } - std::string undriven(Node, int width) { return format("$const<%0>(0)", width); } + std::string memory_read(Node, Node mem, Node addr, int, int) { return format("%0.read(%1)", mem, addr); } + std::string memory_write(Node, Node mem, Node addr, Node data, int, int) { return format("%0.write(%1, %2)", mem, addr, data); } + std::string undriven(Node, int width) { return format("Signal<%0>(0)", width); } }; struct CxxModule { diff --git a/backends/functional/cxx_runtime/sim.h b/backends/functional/cxx_runtime/sim.h index 3a398a13a5a..0614fb34cf7 100644 --- a/backends/functional/cxx_runtime/sim.h +++ b/backends/functional/cxx_runtime/sim.h @@ -24,363 +24,333 @@ #include template -using Signal = std::array; +class Signal { + template friend class Signal; + std::array _bits; +public: + Signal() { } + Signal(uint32_t val) + { + for(size_t i = 0; i < n; i++) + if(i < 32) + _bits[i] = val & (1< -Signal slice(Signal const& a, size_t offset) -{ - Signal ret; + Signal(std::initializer_list vals) + { + size_t k, i; - std::copy(a.begin() + offset, a.begin() + offset + n, ret.begin()); - return ret; -} + k = 0; + for (auto val : vals) { + for(i = 0; i < 32; i++) + if(i + k < n) + _bits[i + k] = val & (1< -Signal $const(uint32_t val) -{ - size_t i; - Signal ret; - - for(i = 0; i < n; i++) - if(i < 32) - ret[i] = val & (1< + static Signal from_array(T vals) + { + size_t k, i; + Signal ret; + + k = 0; + for (auto val : vals) { + for(i = 0; i < 32; i++) + if(i + k < n) + ret._bits[i + k] = val & (1< -Signal $const(std::initializer_list vals) -{ - size_t k, i; - Signal ret; - - k = 0; - for (auto val : vals) { - for(i = 0; i < 32; i++) - if(i + k < n) - ret[i + k] = val & (1< ret; + for(size_t i = 0; i < n; i++) + if(i < 32) + ret._bits[i] = val & (1< ret; + for(size_t i = 0; i < n; i++) + ret._bits[i] = b; + return ret; + } -template -bool as_bool(Signal sig) -{ - for(int i = 0; i < n; i++) - if(sig[i]) - return true; - return false; -} + int size() const { return n; } + bool operator[](int i) const { assert(n >= 0 && i < n); return _bits[i]; } -template -uint32_t as_int(Signal sig) -{ - uint32_t ret = 0; - for(int i = 0; i < n; i++) - if(sig[i] && i < 32) - ret |= 1< + Signal slice(size_t offset) const + { + Signal ret; -template -Signal $mux(Signal const& a, Signal const &b, Signal<1> const &s) -{ - return s[0] ? b : a; -} + assert(offset + m <= n); + std::copy(_bits.begin() + offset, _bits.begin() + offset + m, ret._bits.begin()); + return ret; + } -template -Signal $not(Signal const& a) -{ - Signal ret; - for(size_t i = 0; i < n; i++) - ret[i] = !a[i]; - return ret; -} + bool any() const + { + for(int i = 0; i < n; i++) + if(_bits[i]) + return true; + return false; + } -template -Signal $neg(Signal const& a) -{ - Signal ret; - bool carry = true; - for(size_t i = 0; i < n; i++) { - int r = !a[i] + carry; - ret[i] = (r & 1) != 0; - carry = (r >> 1) != 0; - } - return ret; -} + bool all() const + { + for(int i = 0; i < n; i++) + if(!_bits[i]) + return false; + return true; + } -template -Signal<1> $reduce_or(Signal const& a) -{ - return { as_bool(a) }; -} + bool parity() const + { + bool result = false; + for(int i = 0; i < n; i++) + result ^= _bits[i]; + return result; + } -template -Signal<1> $reduce_and(Signal const& a) -{ - for(size_t i = 0; i < n; i++) - if(!a[i]) - return { false }; - return { true }; -} + bool sign() const { return _bits[n-1]; } -template -Signal<1> $reduce_bool(Signal const& a) -{ - return { as_bool(a) }; -} + template + T as_numeric() const + { + T ret = 0; + for(size_t i = 0; i < std::min(sizeof(T) * 8, n); i++) + if(_bits[i]) + ret |= ((T)1)< -Signal<1> $logic_and(Signal const& a, Signal const& b) -{ - return { as_bool(a) && as_bool(b) }; -} + template + T as_numeric_clamped() const + { + for(size_t i = sizeof(T) * 8; i < n; i++) + if(_bits[i]) + return ~0; + return as_numeric(); + } -template -Signal<1> $logic_or(Signal const& a, Signal const& b) -{ - return { as_bool(a) || as_bool(b) }; -} + uint32_t as_int() { return as_numeric(); } -template -Signal<1> $logic_not(Signal const& a) -{ - return { !as_bool(a) }; -} + Signal operator ~() const + { + Signal ret; + for(size_t i = 0; i < n; i++) + ret._bits[i] = !_bits[i]; + return ret; + } -template -Signal $add(Signal const& a, Signal const &b) -{ - Signal ret; - size_t i; - int x = 0; - for(i = 0; i < n; i++){ - x += (int)a[i] + (int)b[i]; - ret[i] = x & 1; - x >>= 1; - } - return ret; -} -template -Signal $sub(Signal const& a, Signal const &b) -{ - Signal ret; - int x = 1; - for(size_t i = 0; i < n; i++){ - x += (int)a[i] + (int)!b[i]; - ret[i] = x & 1; - x >>= 1; - } - return ret; -} + Signal operator -() const + { + Signal ret; + bool carry = true; + for(size_t i = 0; i < n; i++) { + int r = !_bits[i] + carry; + ret._bits[i] = (r & 1) != 0; + carry = (r >> 1) != 0; + } + return ret; + } -template -Signal<1> $uge(Signal const& a, Signal const &b) -{ - for(size_t i = n; i-- != 0; ) - if(a[i] != b[i]) - return { a[i] }; - return { true }; -} + Signal operator +(Signal const &b) const + { + Signal ret; + size_t i; + int x = 0; + for(i = 0; i < n; i++){ + x += (int)_bits[i] + (int)b._bits[i]; + ret._bits[i] = x & 1; + x >>= 1; + } + return ret; + } -template -Signal<1> $ugt(Signal const& a, Signal const &b) -{ - for(size_t i = n; i-- != 0; ) - if(a[i] != b[i]) - return { a[i] }; - return { false }; -} + Signal operator -(Signal const &b) const + { + Signal ret; + int x = 1; + for(size_t i = 0; i < n; i++){ + x += (int)_bits[i] + (int)!b._bits[i]; + ret._bits[i] = x & 1; + x >>= 1; + } + return ret; + } -template -Signal<1> $ge(Signal const& a, Signal const &b) -{ - if(a[n-1] != b[n-1]) - return { b[n-1] }; - return $uge(a, b); -} + bool operator ==(Signal const &b) const + { + for(size_t i = 0; i < n; i++) + if(_bits[i] != b._bits[i]) + return false; + return true; + } -template -Signal<1> $gt(Signal const& a, Signal const &b) -{ - if(a[n-1] != b[n-1]) - return { b[n-1] }; - return $ugt(a, b); -} - -template Signal<1> $ule(Signal const& a, Signal const &b) { return $uge(b, a); } -template Signal<1> $ult(Signal const& a, Signal const &b) { return $ugt(b, a); } -template Signal<1> $le(Signal const& a, Signal const &b) { return $ge(b, a); } -template Signal<1> $lt(Signal const& a, Signal const &b) { return $gt(b, a); } + bool operator >=(Signal const &b) const + { + for(size_t i = n; i-- != 0; ) + if(_bits[i] != b._bits[i]) + return _bits[i]; + return true; + } -template -Signal $and(Signal const& a, Signal const &b) -{ - Signal ret; - for(size_t i = 0; i < n; i++) - ret[i] = a[i] && b[i]; - return ret; -} + bool operator >(Signal const &b) const + { + for(size_t i = n; i-- != 0; ) + if(_bits[i] != b._bits[i]) + return _bits[i]; + return false; + } -template -Signal $or(Signal const& a, Signal const &b) -{ - Signal ret; - for(size_t i = 0; i < n; i++) - ret[i] = a[i] || b[i]; - return ret; -} + bool operator !=(Signal const &b) const { return !(*this == b); } + bool operator <=(Signal const &b) const { return b <= *this; } + bool operator <(Signal const &b) const { return b < *this; } -template -Signal $xor(Signal const& a, Signal const &b) -{ - Signal ret; - for(size_t i = 0; i < n; i++) - ret[i] = a[i] != b[i]; - return ret; -} - -template -Signal $shl(Signal const& a, Signal const &b) -{ - if(nb >= sizeof(int) * 8 - 1) - for(size_t i = sizeof(int) * 8 - 1; i < nb; i++) - assert(!b[i]); - size_t amount = as_int(b); - Signal ret = $const(0); - if(amount < n){ - if(amount + na > n) - std::copy(a.begin(), a.begin() + (n - amount), ret.begin() + amount); - else - std::copy(a.begin(), a.end(), ret.begin() + amount); - } - return ret; -} - -template -Signal $shr(Signal const& a, Signal const &b) -{ - if(nb >= sizeof(int) * 8 - 1) - for(size_t i = sizeof(int) * 8 - 1; i < nb; i++) - assert(!b[i]); - size_t amount = as_int(b); - Signal ret; - for (size_t i = 0; i < n; i++) { - if(i + amount < n) - ret[i] = a[i + amount]; - else - ret[i] = false; - } - return ret; -} - -template -Signal $asr(Signal const& a, Signal const &b) -{ - if(nb >= sizeof(int) * 8 - 1) - for(size_t i = sizeof(int) * 8 - 1; i < nb; i++) - assert(!b[i]); - size_t amount = as_int(b); - Signal ret; - for (size_t i = 0; i < n; i++) { - if(i + amount < n) - ret[i] = a[i + amount]; - else - ret[i] = a[n - 1]; - } - return ret; -} + bool signed_greater_than(Signal const &b) const + { + if(_bits[n-1] != b._bits[n-1]) + return b._bits[n-1]; + return *this > b; + } -template -Signal<1> $eq(Signal const& a, Signal const &b) -{ - for(size_t i = 0; i < n; i++) - if(a[i] != b[i]) - return { false }; - return { true }; -} + bool signed_greater_equal(Signal const &b) const + { + if(_bits[n-1] != b._bits[n-1]) + return b._bits[n-1]; + return *this >= b; + } -template -Signal<1> $ne(Signal const& a, Signal const &b) -{ - for(size_t i = 0; i < n; i++) - if(a[i] != b[i]) - return { true }; - return { false }; -} - -template -Signal $pmux(Signal const& a, Signal const &b, Signal const &s) -{ - bool found; - Signal ret; - - found = false; - ret = a; - for(size_t i = 0; i < ns; i++){ - if(s[i]){ - if(found) - return $const(0); - found = true; - ret = slice(b, n * i); + Signal operator &(Signal const &b) const + { + Signal ret; + for(size_t i = 0; i < n; i++) + ret._bits[i] = _bits[i] && b._bits[i]; + return ret; + } + + Signal operator |(Signal const &b) const + { + Signal ret; + for(size_t i = 0; i < n; i++) + ret._bits[i] = _bits[i] || b._bits[i]; + return ret; + } + + Signal operator ^(Signal const &b) const + { + Signal ret; + for(size_t i = 0; i < n; i++) + ret._bits[i] = _bits[i] != b._bits[i]; + return ret; + } + + template + Signal operator <<(Signal const &b) const + { + Signal ret = 0; + size_t amount = b.template as_numeric_clamped(); + if(amount < n) + std::copy(_bits.begin(), _bits.begin() + (n - amount), ret._bits.begin() + amount); + return ret; + } + + template + Signal operator >>(Signal const &b) const + { + Signal ret = 0; + size_t amount = b.template as_numeric_clamped(); + if(amount < n) + std::copy(_bits.begin() + amount, _bits.end(), ret._bits.begin()); + return ret; + } + + template + Signal arithmetic_shift_right(Signal const &b) const + { + Signal ret = Signal::repeat(sign()); + size_t amount = b.template as_numeric_clamped(); + if(amount < n) + std::copy(_bits.begin() + amount, _bits.end(), ret._bits.begin()); + return ret; + } + + template + Signal pmux(Signal const &b, Signal const &s) const + { + bool found; + Signal ret; + + found = false; + ret = *this; + for(size_t i = 0; i < ns; i++){ + if(s._bits[i]){ + if(found) + return 0; + found = true; + ret = b.template slice(n * i); + } } + return ret; } - return ret; -} - -template -Signal concat(Signal const& a, Signal const& b) -{ - Signal ret; - std::copy(a.begin(), a.end(), ret.begin()); - std::copy(b.begin(), b.end(), ret.begin() + n); - return ret; -} - -template -Signal $zero_extend(Signal const& a) -{ - assert(n >= m); - Signal ret; - std::copy(a.begin(), a.end(), ret.begin()); - for(size_t i = m; i < n; i++) - ret[i] = false; - return ret; -} - -template -Signal $sign_extend(Signal const& a) -{ - assert(n >= m); - Signal ret; - std::copy(a.begin(), a.end(), ret.begin()); - for(size_t i = m; i < n; i++) - ret[i] = a[m-1]; - return ret; -} -template -struct Memory { - std::array, 1< contents; -}; + template + Signal concat(Signal const& b) const + { + Signal ret; + std::copy(_bits.begin(), _bits.end(), ret._bits.begin()); + std::copy(b._bits.begin(), b._bits.end(), ret._bits.begin() + n); + return ret; + } -template -Signal $memory_read(Memory memory, Signal addr) -{ - return memory.contents[as_int(addr)]; -} + template + Signal zero_extend() const + { + assert(m >= n); + Signal ret = 0; + std::copy(_bits.begin(), _bits.end(), ret._bits.begin()); + return ret; + } + + template + Signal sign_extend() const + { + assert(m >= n); + Signal ret = Signal::repeat(sign()); + std::copy(_bits.begin(), _bits.end(), ret._bits.begin()); + return ret; + } +}; template -Memory $memory_write(Memory memory, Signal addr, Signal data) -{ - Memory ret = memory; - ret.contents[as_int(addr)] = data; - return ret; -} +class Memory { + std::array, 1< _contents; +public: + Signal read(Signal addr) const + { + return _contents[addr.template as_numeric()]; + } + Memory write(Signal addr, Signal data) const + { + Memory ret = *this; + ret._contents[addr.template as_numeric()] = data; + return ret; + } +}; #endif diff --git a/tests/functional/single_cells/vcd_harness.cc b/tests/functional/single_cells/vcd_harness.cc index 10ab10e428e..18c9ed5dfaa 100644 --- a/tests/functional/single_cells/vcd_harness.cc +++ b/tests/functional/single_cells/vcd_harness.cc @@ -33,22 +33,30 @@ struct Dump { } }; -// Function to set all values in a signal to false -template -void set_all_false(Signal& signal) { - std::fill(signal.begin(), signal.end(), false); -} - -template -void set_all_random(Signal& signal) { +template +Signal random_signal() { std::random_device rd; // Random device for seeding std::mt19937 gen(rd()); // Mersenne Twister engine - std::bernoulli_distribution dist(0.5); // 50-50 distribution + std::uniform_int_distribution dist; + std::array words; + for(auto &w : words) + w = dist(gen); + return Signal::from_array(words); +} - for (auto& value : signal) { - value = dist(gen); // Set each value to a random boolean +struct Reset { + template + void operator()(const char *, Signal &signal) { + signal = 0; } -} +}; + +struct Randomize { + template + void operator()(const char *, Signal &signal) { + signal = random_signal(); + } +}; int main(int argc, char **argv) { @@ -62,10 +70,10 @@ int main(int argc, char **argv) constexpr int steps = 10; constexpr int number_timescale = 1; const std::string units_timescale = "us"; - gold_Inputs inputs; - gold_Outputs outputs; - gold_State state; - gold_State next_state; + gold::Inputs inputs; + gold::Outputs outputs; + gold::State state; + gold::State next_state; std::ofstream vcd_file(functional_vcd_filename); @@ -73,45 +81,34 @@ int main(int argc, char **argv) vcd_file << "$scope module gold $end\n"; { DumpHeader d(vcd_file); - inputs.dump(d); - outputs.dump(d); - state.dump(d); + inputs.visit(d); + outputs.visit(d); + state.visit(d); } vcd_file << "$enddefinitions $end\n$dumpvars\n"; vcd_file << "#0\n"; // Set all signals to false - for (int i = 0; i < inputs.size(); ++i) { - auto input_variant = inputs.get_input(i); - std::visit([](auto& signal_ref) { - set_all_false(signal_ref.get()); - }, input_variant); - } + inputs.visit(Reset()); - gold(inputs, outputs, state, next_state); + gold::eval(inputs, outputs, state, next_state); { Dump d(vcd_file); - inputs.dump(d); - outputs.dump(d); - state.dump(d); + inputs.visit(d); + outputs.visit(d); + state.visit(d); } for (int step = 0; step < steps; ++step) { // Functional backend cxx vcd_file << "#" << (step + 1) << "\n"; - // Set all signals to random - for (int i = 0; i < inputs.size(); ++i) { - auto input_variant = inputs.get_input(i); - std::visit([](auto& signal_ref) { - set_all_random(signal_ref.get()); - }, input_variant); - } + inputs.visit(Randomize()); - gold(inputs, outputs, state, next_state); + gold::eval(inputs, outputs, state, next_state); { Dump d(vcd_file); - inputs.dump(d); - outputs.dump(d); - state.dump(d); + inputs.visit(d); + outputs.visit(d); + state.visit(d); } state = next_state;