/* * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2024 Emily Schmidt * Copyright (C) 2024 National Technology and Engineering Solutions of Sandia, LLC * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ #ifndef SIM_H #define SIM_H #include #include #include #include #include template 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< vals) { size_t k, i; k = 0; for (auto val : vals) { for(i = 0; i < 32; i++) if(i + k < n) _bits[i + k] = 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< 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; } int size() const { return n; } bool operator[](int i) const { assert(n >= 0 && i < n); return _bits[i]; } template Signal slice(size_t offset) const { Signal 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 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)< T as_numeric_clamped() const { for(size_t i = sizeof(T) * 8; i < n; i++) if(_bits[i]) return ~((T)0); return as_numeric(); } uint32_t as_int() const { return as_numeric(); } private: std::string as_string_p2(int b) const { std::string ret; for(int i = (n - 1) - (n - 1) % b; i >= 0; i -= b) ret += "0123456789abcdef"[(*this >> Signal<32>(i)).as_int() & ((1< t = *this; Signal b = 10; do{ ret += (char)('0' + (t % b).as_int()); t = t / b; }while(t.any()); std::reverse(ret.begin(), ret.end()); return ret; } public: std::string as_string(int base = 16, bool showbase = true) const { std::string ret; if(showbase) { ret += std::to_string(n); switch(base) { case 2: ret += "'b"; break; case 8: ret += "'o"; break; case 10: ret += "'d"; break; case 16: ret += "'h"; break; default: assert(0); } } switch(base) { case 2: return ret + as_string_p2(1); case 8: return ret + as_string_p2(3); case 10: return ret + as_string_b10(); case 16: return ret + as_string_p2(4); default: assert(0); } } friend std::ostream &operator << (std::ostream &os, Signal const &s) { return os << s.as_string(); } Signal operator ~() const { Signal ret; for(size_t i = 0; i < n; i++) ret._bits[i] = !_bits[i]; return ret; } Signal operator -() const { Signal ret; int x = 1; for(size_t i = 0; i < n; i++) { x += (int)!_bits[i]; ret._bits[i] = (x & 1) != 0; x >>= 1; } return ret; } Signal operator +(Signal const &b) const { Signal ret; int x = 0; 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; } 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; } Signal operator *(Signal const &b) const { Signal ret; int x = 0; for(size_t i = 0; i < n; i++){ for(size_t j = 0; j <= i; j++) x += (int)_bits[j] & (int)b._bits[i-j]; ret._bits[i] = x & 1; x >>= 1; } return ret; } private: Signal divmod(Signal const &b, bool modulo) const { if(!b.any()) return 0; Signal q = 0; Signal r = 0; for(size_t i = n; i-- != 0; ){ r = r << Signal<1>(1); r._bits[0] = _bits[i]; if(r >= b){ r = r - b; q._bits[i] = true; } } return modulo ? r : q; } public: Signal operator /(Signal const &b) const { return divmod(b, false); } Signal operator %(Signal const &b) const { return divmod(b, true); } bool operator ==(Signal const &b) const { for(size_t i = 0; i < n; i++) if(_bits[i] != b._bits[i]) return false; return true; } bool operator >=(Signal const &b) const { for(size_t i = n; i-- != 0; ) if(_bits[i] != b._bits[i]) return _bits[i]; return true; } bool operator >(Signal const &b) const { for(size_t i = n; i-- != 0; ) if(_bits[i] != b._bits[i]) return _bits[i]; return false; } 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; } bool signed_greater_than(Signal const &b) const { if(_bits[n-1] != b._bits[n-1]) return b._bits[n-1]; return *this > b; } bool signed_greater_equal(Signal const &b) const { if(_bits[n-1] != b._bits[n-1]) return b._bits[n-1]; return *this >= b; } 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 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 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 class Memory { std::array, 1< _contents; public: Memory() {} Memory(std::array, 1< const &contents) : _contents(contents) {} 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