/* * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2024 Emily Schmidt * * 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 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(); } 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; 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 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; } 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; } 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 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; } 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: 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