/* * 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 using Signal = std::array; template Signal slice(Signal const& a, size_t offset) { Signal ret; std::copy(a.begin() + offset, a.begin() + offset + n, ret.begin()); return ret; } template Signal $const(uint32_t val) { size_t i; Signal ret; for(i = 0; i < n; i++) if(i < 32) ret[i] = 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< bool as_bool(Signal sig) { for(int i = 0; i < n; i++) if(sig[i]) return true; return false; } 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 $mux(Signal const& a, Signal const &b, Signal<1> const &s) { return s[0] ? b : a; } template Signal $not(Signal const& a) { Signal ret; for(size_t i = 0; i < n; i++) ret[i] = !a[i]; return ret; } 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; } template Signal<1> $reduce_or(Signal const& a) { return { as_bool(a) }; } template Signal<1> $reduce_and(Signal const& a) { for(size_t i = 0; i < n; i++) if(!a[i]) return { false }; return { true }; } template Signal<1> $reduce_bool(Signal const& a) { return { as_bool(a) }; } template Signal<1> $logic_and(Signal const& a, Signal const& b) { return { as_bool(a) && as_bool(b) }; } template Signal<1> $logic_or(Signal const& a, Signal const& b) { return { as_bool(a) || as_bool(b) }; } template Signal<1> $logic_not(Signal const& a) { return { !as_bool(a) }; } 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; } 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 }; } 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 }; } 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); } 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); } 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; } 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; } 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; } 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 }; } 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); } } 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 $memory_read(Memory memory, Signal addr) { return memory.contents[as_int(addr)]; } template Memory $memory_write(Memory memory, Signal addr, Signal data) { Memory ret = memory; ret.contents[as_int(addr)] = data; return ret; } #endif