mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	rewrite functional c++ simulation library
This commit is contained in:
		
							parent
							
								
									eb2bb8c45b
								
							
						
					
					
						commit
						21bb1cf1bc
					
				
					 3 changed files with 384 additions and 417 deletions
				
			
		| 
						 | 
				
			
			@ -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 <typename T> void visit(T &fn) {\n");
 | 
			
		||||
    f.printf("\n\t\ttemplate <typename T> 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<class NodeNames> 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 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,363 +24,333 @@
 | 
			
		|||
#include <cassert>
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
using Signal = std::array<bool, n>;
 | 
			
		||||
 | 
			
		||||
template<size_t n, size_t m>
 | 
			
		||||
Signal<n> slice(Signal<m> const& a, size_t offset)
 | 
			
		||||
{
 | 
			
		||||
    Signal<n> ret;
 | 
			
		||||
 | 
			
		||||
    std::copy(a.begin() + offset, a.begin() + offset + n, ret.begin());
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<n> $const(uint32_t val)
 | 
			
		||||
{
 | 
			
		||||
    size_t i;
 | 
			
		||||
    Signal<n> ret;
 | 
			
		||||
 | 
			
		||||
    for(i = 0; i < n; i++)
 | 
			
		||||
        if(i < 32)
 | 
			
		||||
            ret[i] = val & (1<<i);
 | 
			
		||||
        else
 | 
			
		||||
            ret[i] = false;
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<n> $const(std::initializer_list<uint32_t> vals)
 | 
			
		||||
{
 | 
			
		||||
    size_t k, i;
 | 
			
		||||
    Signal<n> ret;
 | 
			
		||||
 | 
			
		||||
    k = 0;
 | 
			
		||||
    for (auto val : vals) {
 | 
			
		||||
        for(i = 0; i < 32; i++)
 | 
			
		||||
            if(i + k < n)
 | 
			
		||||
                ret[i + k] = val & (1<<i);
 | 
			
		||||
        k += 32;
 | 
			
		||||
class Signal {
 | 
			
		||||
    template<size_t m> friend class Signal;
 | 
			
		||||
    std::array<bool, n> _bits;
 | 
			
		||||
public:
 | 
			
		||||
    Signal() { }
 | 
			
		||||
    Signal(uint32_t val)
 | 
			
		||||
    {
 | 
			
		||||
        for(size_t i = 0; i < n; i++)
 | 
			
		||||
            if(i < 32)
 | 
			
		||||
                _bits[i] = val & (1<<i);
 | 
			
		||||
            else
 | 
			
		||||
                _bits[i] = false;
 | 
			
		||||
    }
 | 
			
		||||
    for(; k < n; k++)
 | 
			
		||||
        ret[k] = false;
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
bool as_bool(Signal<n> sig)
 | 
			
		||||
{
 | 
			
		||||
    for(int i = 0; i < n; i++)
 | 
			
		||||
        if(sig[i])
 | 
			
		||||
            return true;
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
    Signal(std::initializer_list<uint32_t> vals)
 | 
			
		||||
    {
 | 
			
		||||
        size_t k, i;
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
uint32_t as_int(Signal<n> sig)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t ret = 0;
 | 
			
		||||
    for(int i = 0; i < n; i++)
 | 
			
		||||
        if(sig[i] && i < 32)
 | 
			
		||||
            ret |= 1<<i;
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<n> $mux(Signal<n> const& a, Signal<n> const &b, Signal<1> const &s)
 | 
			
		||||
{
 | 
			
		||||
    return s[0] ? b : a;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<n> $not(Signal<n> const& a)
 | 
			
		||||
{
 | 
			
		||||
    Signal<n> ret;
 | 
			
		||||
    for(size_t i = 0; i < n; i++)
 | 
			
		||||
        ret[i] = !a[i];
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<n> $neg(Signal<n> const& a)
 | 
			
		||||
{
 | 
			
		||||
    Signal<n> 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<1> $reduce_or(Signal<n> const& a)
 | 
			
		||||
{
 | 
			
		||||
    return { as_bool(a) };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<1> $reduce_and(Signal<n> const& a)
 | 
			
		||||
{
 | 
			
		||||
    for(size_t i = 0; i < n; i++)
 | 
			
		||||
        if(!a[i])
 | 
			
		||||
            return { false };
 | 
			
		||||
    return { true };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<1> $reduce_bool(Signal<n> const& a)
 | 
			
		||||
{
 | 
			
		||||
    return { as_bool(a) };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<1> $logic_and(Signal<n> const& a, Signal<n> const& b)
 | 
			
		||||
{
 | 
			
		||||
    return { as_bool(a) && as_bool(b) };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<1> $logic_or(Signal<n> const& a, Signal<n> const& b)
 | 
			
		||||
{
 | 
			
		||||
    return { as_bool(a) || as_bool(b) };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<1> $logic_not(Signal<n> const& a)
 | 
			
		||||
{
 | 
			
		||||
    return { !as_bool(a) };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<n> $add(Signal<n> const& a, Signal<n> const &b)
 | 
			
		||||
{
 | 
			
		||||
    Signal<n> 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<size_t n>
 | 
			
		||||
Signal<n> $sub(Signal<n> const& a, Signal<n> const &b)
 | 
			
		||||
{
 | 
			
		||||
    Signal<n> 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<1> $uge(Signal<n> const& a, Signal<n> const &b)
 | 
			
		||||
{
 | 
			
		||||
    for(size_t i = n; i-- != 0; )
 | 
			
		||||
        if(a[i] != b[i])
 | 
			
		||||
            return { a[i] };
 | 
			
		||||
    return { true };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<1> $ugt(Signal<n> const& a, Signal<n> const &b)
 | 
			
		||||
{
 | 
			
		||||
    for(size_t i = n; i-- != 0; )
 | 
			
		||||
        if(a[i] != b[i])
 | 
			
		||||
            return { a[i] };
 | 
			
		||||
    return { false };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<1> $ge(Signal<n> const& a, Signal<n> const &b)
 | 
			
		||||
{
 | 
			
		||||
    if(a[n-1] != b[n-1])
 | 
			
		||||
        return { b[n-1] };
 | 
			
		||||
    return $uge(a, b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<1> $gt(Signal<n> const& a, Signal<n> const &b)
 | 
			
		||||
{
 | 
			
		||||
    if(a[n-1] != b[n-1])
 | 
			
		||||
        return { b[n-1] };
 | 
			
		||||
    return $ugt(a, b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n> Signal<1> $ule(Signal<n> const& a, Signal<n> const &b) { return $uge(b, a); }
 | 
			
		||||
template<size_t n> Signal<1> $ult(Signal<n> const& a, Signal<n> const &b) { return $ugt(b, a); }
 | 
			
		||||
template<size_t n> Signal<1> $le(Signal<n> const& a, Signal<n> const &b) { return $ge(b, a); }
 | 
			
		||||
template<size_t n> Signal<1> $lt(Signal<n> const& a, Signal<n> const &b) { return $gt(b, a); }
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<n> $and(Signal<n> const& a, Signal<n> const &b)
 | 
			
		||||
{
 | 
			
		||||
    Signal<n> ret;
 | 
			
		||||
    for(size_t i = 0; i < n; i++)
 | 
			
		||||
        ret[i] = a[i] && b[i];
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<n> $or(Signal<n> const& a, Signal<n> const &b)
 | 
			
		||||
{
 | 
			
		||||
    Signal<n> ret;
 | 
			
		||||
    for(size_t i = 0; i < n; i++)
 | 
			
		||||
        ret[i] = a[i] || b[i];
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<n> $xor(Signal<n> const& a, Signal<n> const &b)
 | 
			
		||||
{
 | 
			
		||||
    Signal<n> ret;
 | 
			
		||||
    for(size_t i = 0; i < n; i++)
 | 
			
		||||
        ret[i] = a[i] != b[i];
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n, size_t na, size_t nb>
 | 
			
		||||
Signal<n> $shl(Signal<na> const& a, Signal<nb> 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<n> ret = $const<n>(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<size_t n, size_t nb>
 | 
			
		||||
Signal<n> $shr(Signal<n> const& a, Signal<nb> 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<n> 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<size_t n, size_t nb>
 | 
			
		||||
Signal<n> $asr(Signal<n> const& a, Signal<nb> 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<n> 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<1> $eq(Signal<n> const& a, Signal<n> const &b)
 | 
			
		||||
{
 | 
			
		||||
    for(size_t i = 0; i < n; i++)
 | 
			
		||||
        if(a[i] != b[i])
 | 
			
		||||
            return { false };
 | 
			
		||||
    return { true };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n>
 | 
			
		||||
Signal<1> $ne(Signal<n> const& a, Signal<n> const &b)
 | 
			
		||||
{
 | 
			
		||||
    for(size_t i = 0; i < n; i++)
 | 
			
		||||
        if(a[i] != b[i])
 | 
			
		||||
            return { true };
 | 
			
		||||
    return { false };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n, size_t ns>
 | 
			
		||||
Signal<n> $pmux(Signal<n> const& a, Signal<n*ns> const &b, Signal<ns> const &s)
 | 
			
		||||
{
 | 
			
		||||
    bool found;
 | 
			
		||||
    Signal<n> ret;
 | 
			
		||||
 | 
			
		||||
    found = false;
 | 
			
		||||
    ret = a;
 | 
			
		||||
    for(size_t i = 0; i < ns; i++){
 | 
			
		||||
        if(s[i]){
 | 
			
		||||
            if(found)
 | 
			
		||||
                return $const<n>(0);
 | 
			
		||||
            found = true;
 | 
			
		||||
            ret = slice<n>(b, n * i);
 | 
			
		||||
        k = 0;
 | 
			
		||||
        for (auto val : vals) {
 | 
			
		||||
            for(i = 0; i < 32; i++)
 | 
			
		||||
                if(i + k < n)
 | 
			
		||||
                    _bits[i + k] = val & (1<<i);
 | 
			
		||||
            k += 32;
 | 
			
		||||
        }
 | 
			
		||||
        for(; k < n; k++)
 | 
			
		||||
            _bits[k] = false;
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t n, size_t m>
 | 
			
		||||
Signal<n+m> concat(Signal<n> const& a, Signal<m> const& b)
 | 
			
		||||
{
 | 
			
		||||
    Signal<n + m> ret;
 | 
			
		||||
    std::copy(a.begin(), a.end(), ret.begin());
 | 
			
		||||
    std::copy(b.begin(), b.end(), ret.begin() + n);
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    static Signal from_array(T vals)
 | 
			
		||||
    {
 | 
			
		||||
        size_t k, i;
 | 
			
		||||
        Signal ret;
 | 
			
		||||
 | 
			
		||||
template<size_t n, size_t m>
 | 
			
		||||
Signal<n> $zero_extend(Signal<m> const& a)
 | 
			
		||||
{
 | 
			
		||||
    assert(n >= m);
 | 
			
		||||
    Signal<n> ret;
 | 
			
		||||
    std::copy(a.begin(), a.end(), ret.begin());
 | 
			
		||||
    for(size_t i = m; i < n; i++)
 | 
			
		||||
        ret[i] = false;
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
        k = 0;
 | 
			
		||||
        for (auto val : vals) {
 | 
			
		||||
            for(i = 0; i < 32; i++)
 | 
			
		||||
                if(i + k < n)
 | 
			
		||||
                    ret._bits[i + k] = val & (1<<i);
 | 
			
		||||
            k += 32;
 | 
			
		||||
        }
 | 
			
		||||
        for(; k < n; k++)
 | 
			
		||||
            ret._bits[k] = false;
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
template<size_t n, size_t m>
 | 
			
		||||
Signal<n> $sign_extend(Signal<m> const& a)
 | 
			
		||||
{
 | 
			
		||||
    assert(n >= m);
 | 
			
		||||
    Signal<n> ret;
 | 
			
		||||
    std::copy(a.begin(), a.end(), ret.begin());
 | 
			
		||||
    for(size_t i = m; i < n; i++)
 | 
			
		||||
        ret[i] = a[m-1];
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
    static Signal from_signed(int32_t val)
 | 
			
		||||
    {
 | 
			
		||||
        Signal<n> ret;
 | 
			
		||||
        for(size_t i = 0; i < n; i++)
 | 
			
		||||
            if(i < 32)
 | 
			
		||||
                ret._bits[i] = val & (1<<i);
 | 
			
		||||
            else
 | 
			
		||||
                ret._bits[i] = val < 0;
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    static Signal repeat(bool b)
 | 
			
		||||
    {
 | 
			
		||||
        Signal<n> ret;
 | 
			
		||||
        for(size_t i = 0; i < n; i++)
 | 
			
		||||
            ret._bits[i] = b;
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
template<size_t a, size_t d>
 | 
			
		||||
struct Memory {
 | 
			
		||||
    std::array<Signal<d>, 1<<a> contents;
 | 
			
		||||
    int size() const { return n; }
 | 
			
		||||
    bool operator[](int i) const { assert(n >= 0 && i < n); return _bits[i]; }
 | 
			
		||||
 | 
			
		||||
    template<size_t m>
 | 
			
		||||
    Signal<m> slice(size_t offset) const
 | 
			
		||||
    {
 | 
			
		||||
        Signal<m> ret;
 | 
			
		||||
 | 
			
		||||
        assert(offset + m <= n);
 | 
			
		||||
        std::copy(_bits.begin() + offset, _bits.begin() + offset + m, ret._bits.begin());
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool any() const
 | 
			
		||||
    {
 | 
			
		||||
        for(int i = 0; i < n; i++)
 | 
			
		||||
            if(_bits[i])
 | 
			
		||||
                return true;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool all() const
 | 
			
		||||
    {
 | 
			
		||||
        for(int i = 0; i < n; i++)
 | 
			
		||||
            if(!_bits[i])
 | 
			
		||||
                return false;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool parity() const
 | 
			
		||||
    {
 | 
			
		||||
        bool result = false;
 | 
			
		||||
        for(int i = 0; i < n; i++)
 | 
			
		||||
            result ^= _bits[i];
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool sign() const { return _bits[n-1]; }
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    T as_numeric() const
 | 
			
		||||
    {
 | 
			
		||||
        T ret = 0;
 | 
			
		||||
        for(size_t i = 0; i < std::min<size_t>(sizeof(T) * 8, n); i++)
 | 
			
		||||
            if(_bits[i])
 | 
			
		||||
                ret |= ((T)1)<<i;
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    T as_numeric_clamped() const
 | 
			
		||||
    {
 | 
			
		||||
        for(size_t i = sizeof(T) * 8; i < n; i++)
 | 
			
		||||
            if(_bits[i])
 | 
			
		||||
                return ~0;
 | 
			
		||||
        return as_numeric<T>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint32_t as_int() { return as_numeric<uint32_t>(); }
 | 
			
		||||
 | 
			
		||||
    Signal<n> operator ~() const
 | 
			
		||||
    {
 | 
			
		||||
        Signal<n> ret;
 | 
			
		||||
        for(size_t i = 0; i < n; i++)
 | 
			
		||||
            ret._bits[i] = !_bits[i];
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Signal<n> operator -() const
 | 
			
		||||
    {
 | 
			
		||||
        Signal<n> 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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Signal<n> operator +(Signal<n> const &b) const
 | 
			
		||||
    {
 | 
			
		||||
        Signal<n> 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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Signal<n> operator -(Signal<n> const &b) const
 | 
			
		||||
    {
 | 
			
		||||
        Signal<n> 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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool operator ==(Signal<n> const &b) const
 | 
			
		||||
    {
 | 
			
		||||
        for(size_t i = 0; i < n; i++)
 | 
			
		||||
            if(_bits[i] != b._bits[i])
 | 
			
		||||
                return false;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool operator >=(Signal<n> const &b) const
 | 
			
		||||
    {
 | 
			
		||||
        for(size_t i = n; i-- != 0; )
 | 
			
		||||
            if(_bits[i] != b._bits[i])
 | 
			
		||||
                return _bits[i];
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool operator >(Signal<n> const &b) const
 | 
			
		||||
    {
 | 
			
		||||
        for(size_t i = n; i-- != 0; )
 | 
			
		||||
            if(_bits[i] != b._bits[i])
 | 
			
		||||
                return _bits[i];
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool operator !=(Signal<n> const &b) const { return !(*this == b); }
 | 
			
		||||
    bool operator <=(Signal<n> const &b) const { return b <= *this; }
 | 
			
		||||
    bool operator <(Signal<n> const &b) const { return b < *this; }
 | 
			
		||||
 | 
			
		||||
    bool signed_greater_than(Signal<n> const &b) const
 | 
			
		||||
    {
 | 
			
		||||
        if(_bits[n-1] != b._bits[n-1])
 | 
			
		||||
            return b._bits[n-1];
 | 
			
		||||
        return *this > b;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool signed_greater_equal(Signal<n> const &b) const
 | 
			
		||||
    {
 | 
			
		||||
        if(_bits[n-1] != b._bits[n-1])
 | 
			
		||||
            return b._bits[n-1];
 | 
			
		||||
        return *this >= b;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Signal<n> operator &(Signal<n> const &b) const
 | 
			
		||||
    {
 | 
			
		||||
        Signal<n> ret;
 | 
			
		||||
        for(size_t i = 0; i < n; i++)
 | 
			
		||||
            ret._bits[i] = _bits[i] && b._bits[i];
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Signal<n> operator |(Signal<n> const &b) const
 | 
			
		||||
    {
 | 
			
		||||
        Signal<n> ret;
 | 
			
		||||
        for(size_t i = 0; i < n; i++)
 | 
			
		||||
            ret._bits[i] = _bits[i] || b._bits[i];
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Signal<n> operator ^(Signal<n> const &b) const
 | 
			
		||||
    {
 | 
			
		||||
        Signal<n> ret;
 | 
			
		||||
        for(size_t i = 0; i < n; i++)
 | 
			
		||||
            ret._bits[i] = _bits[i] != b._bits[i];
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<size_t nb>
 | 
			
		||||
    Signal<n> operator <<(Signal<nb> const &b) const
 | 
			
		||||
    {
 | 
			
		||||
        Signal<n> ret = 0;
 | 
			
		||||
        size_t amount = b.template as_numeric_clamped<size_t>();
 | 
			
		||||
        if(amount < n)
 | 
			
		||||
            std::copy(_bits.begin(), _bits.begin() + (n - amount), ret._bits.begin() + amount);
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<size_t nb>
 | 
			
		||||
    Signal<n> operator >>(Signal<nb> const &b) const
 | 
			
		||||
    {
 | 
			
		||||
        Signal<n> ret = 0;
 | 
			
		||||
        size_t amount = b.template as_numeric_clamped<size_t>();
 | 
			
		||||
        if(amount < n)
 | 
			
		||||
            std::copy(_bits.begin() + amount, _bits.end(), ret._bits.begin());
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<size_t nb>
 | 
			
		||||
    Signal<n> arithmetic_shift_right(Signal<nb> const &b) const
 | 
			
		||||
    {
 | 
			
		||||
        Signal<n> ret = Signal::repeat(sign());
 | 
			
		||||
        size_t amount = b.template as_numeric_clamped<size_t>();
 | 
			
		||||
        if(amount < n)
 | 
			
		||||
            std::copy(_bits.begin() + amount, _bits.end(), ret._bits.begin());
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<size_t ns>
 | 
			
		||||
    Signal<n> pmux(Signal<n*ns> const &b, Signal<ns> const &s) const
 | 
			
		||||
    {
 | 
			
		||||
        bool found;
 | 
			
		||||
        Signal<n> 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>(n * i);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<size_t m>
 | 
			
		||||
    Signal<n+m> concat(Signal<m> const& b) const
 | 
			
		||||
    {
 | 
			
		||||
        Signal<n + m> 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<size_t m>
 | 
			
		||||
    Signal<m> zero_extend() const
 | 
			
		||||
    {
 | 
			
		||||
        assert(m >= n);
 | 
			
		||||
        Signal<m> ret = 0;
 | 
			
		||||
        std::copy(_bits.begin(), _bits.end(), ret._bits.begin());
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<size_t m>
 | 
			
		||||
    Signal<m> sign_extend() const
 | 
			
		||||
    {
 | 
			
		||||
        assert(m >= n);
 | 
			
		||||
        Signal<m> ret = Signal<m>::repeat(sign());
 | 
			
		||||
        std::copy(_bits.begin(), _bits.end(), ret._bits.begin());
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<size_t a, size_t d>
 | 
			
		||||
Signal<d> $memory_read(Memory<a, d> memory, Signal<a> addr)
 | 
			
		||||
{
 | 
			
		||||
    return memory.contents[as_int(addr)];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<size_t a, size_t d>
 | 
			
		||||
Memory<a, d> $memory_write(Memory<a, d> memory, Signal<a> addr, Signal<d> data)
 | 
			
		||||
{
 | 
			
		||||
    Memory<a, d> ret = memory;
 | 
			
		||||
    ret.contents[as_int(addr)] = data;
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
class Memory {
 | 
			
		||||
    std::array<Signal<d>, 1<<a> _contents;
 | 
			
		||||
public:
 | 
			
		||||
    Signal<d> read(Signal<a> addr) const
 | 
			
		||||
    {
 | 
			
		||||
        return _contents[addr.template as_numeric<size_t>()];
 | 
			
		||||
    }
 | 
			
		||||
    Memory write(Signal<a> addr, Signal<d> data) const
 | 
			
		||||
    {
 | 
			
		||||
        Memory ret = *this;
 | 
			
		||||
        ret._contents[addr.template as_numeric<size_t>()] = data;
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue