| /* Authors: Aaron Graham (aaron.graham@unb.ca, aarongraham9@gmail.com), |
| * Jean-Philippe Legault (jlegault@unb.ca, jeanphilippe.legault@gmail.com) and |
| * Dr. Kenneth B. Kent (ken@unb.ca) |
| * for the Reconfigurable Computing Research Lab at the |
| * Univerity of New Brunswick in Fredericton, New Brunswick, Canada |
| */ |
| |
| #ifndef INTERNAL_BITS_HPP |
| #define INTERNAL_BITS_HPP |
| |
| #include <cstdint> |
| #include <string> |
| #include <algorithm> |
| #include <vector> |
| #include <bitset> |
| #include "rtl_utils.hpp" |
| |
| typedef uint64_t veri_internal_bits_t; |
| // typedef VNumber<64> veri_64_t; |
| // typedef VNumber<32> veri_32_t; |
| |
| template <typename T> |
| uint8_t get_veri_integer_limit() |
| { |
| return (sizeof(T)*8); |
| } |
| |
| namespace BitSpace { |
| typedef uint8_t bit_value_t; |
| |
| static const veri_internal_bits_t _All_0 = static_cast<veri_internal_bits_t>(0x0000000000000000UL); |
| static const veri_internal_bits_t _All_1 = static_cast<veri_internal_bits_t>(0x5555555555555555UL); |
| static const veri_internal_bits_t _All_x = static_cast<veri_internal_bits_t>(0xAAAAAAAAAAAAAAAAUL); |
| static const veri_internal_bits_t _All_z = static_cast<veri_internal_bits_t>(0xFFFFFFFFFFFFFFFFUL); |
| |
| static const bit_value_t _0 = 0x0; |
| static const bit_value_t _1 = 0x1; |
| static const bit_value_t _x = 0x2; |
| static const bit_value_t _z = 0x3; |
| |
| /*** |
| * these are taken from the raw verilog truth tables so that the evaluation are correct. |
| * only use this to evaluate any expression for the number_t binary digits. |
| * reference: http://staff.ustc.edu.cn/~songch/download/IEEE.1364-2005.pdf |
| * |
| *******************************************************/ |
| |
| static const bit_value_t l_buf[4] = { |
| /* 0 1 x z <- a*/ |
| _0,_1,_x,_x |
| }; |
| |
| static const bit_value_t l_not[4] = { |
| /* 0 1 x z <- a */ |
| _1,_0,_x,_x |
| }; |
| |
| static const bit_value_t is_unk[4] = { |
| /* 0 1 x z <- a*/ |
| _0,_0,_1,_1 |
| }; |
| |
| #define unroll_1d(lut) { lut[_0], lut[_1], lut[_x], lut[_z] } |
| #define unroll_2d(lut) { unroll_1d(lut[_0]), unroll_1d(lut[_1]), unroll_1d(lut[_x]), unroll_1d(lut[_z]) } |
| |
| #define unroll_1d_invert(lut) { l_not[lut[_0]], l_not[lut[_1]], l_not[lut[_x]], l_not[lut[_z]] } |
| #define unroll_2d_invert(lut) { unroll_1d_invert(lut[_0]), unroll_1d_invert(lut[_1]), unroll_1d_invert(lut[_x]), unroll_1d_invert(lut[_z]) } |
| |
| static const bit_value_t l_and[4][4] = { |
| /* a / 0 1 x z <-b */ |
| /* 0 */ {_0,_0,_0,_0}, |
| /* 1 */ {_0,_1,_x,_x}, |
| /* x */ {_0,_x,_x,_x}, |
| /* z */ {_0,_x,_x,_x} |
| }; |
| static const bit_value_t l_nand[4][4] = |
| unroll_2d_invert(l_and); |
| |
| static const bit_value_t l_or[4][4] = { |
| /* a / 0 1 x z <-b */ |
| /* 0 */ {_0,_1,_x,_x}, |
| /* 1 */ {_1,_1,_1,_1}, |
| /* x */ {_x,_1,_x,_x}, |
| /* z */ {_x,_1,_x,_x} |
| }; |
| static const bit_value_t l_nor[4][4] = |
| unroll_2d_invert(l_or); |
| |
| static const bit_value_t l_xor[4][4] = { |
| /* a / 0 1 x z <-b */ |
| /* 0 */ {_0,_1,_x,_x}, |
| /* 1 */ {_1,_0,_x,_x}, |
| /* x */ {_x,_x,_x,_x}, |
| /* z */ {_x,_x,_x,_x} |
| }; |
| static const bit_value_t l_xnor[4][4] = |
| unroll_2d_invert(l_xor); |
| |
| |
| /***************************************************** |
| * Tran NO SUPPORT FOR THESE YET |
| */ |
| static const bit_value_t l_notif1[4][4] = { |
| /* in / 0 1 x z <-control */ |
| /* 0 */ {_z,_1,_x,_x}, |
| /* 1 */ {_z,_0,_x,_x}, |
| /* x */ {_z,_x,_x,_x}, |
| /* z */ {_z,_x,_x,_x} |
| }; |
| |
| static const bit_value_t l_notif0[4][4] = { |
| /* in / 0 1 x z <-control */ |
| /* 0 */ {_1,_z,_x,_x}, |
| /* 1 */ {_0,_z,_x,_x}, |
| /* x */ {_x,_z,_x,_x}, |
| /* z */ {_x,_z,_x,_x} |
| }; |
| |
| static const bit_value_t l_bufif1[4][4] = { |
| /* in / 0 1 x z <-control */ |
| /* 0 */ {_z,_0,_x,_x}, |
| /* 1 */ {_z,_1,_x,_x}, |
| /* x */ {_z,_x,_x,_x}, |
| /* z */ {_z,_x,_x,_x} |
| }; |
| |
| static const bit_value_t l_bufif0[4][4] = { |
| /* in / 0 1 x z <-control */ |
| /* 0 */ {_0,_z,_x,_x}, |
| /* 1 */ {_1,_z,_x,_x}, |
| /* x */ {_x,_z,_x,_x}, |
| /* z */ {_x,_z,_x,_x} |
| }; |
| |
| /* cmos gates */ |
| static const bit_value_t l_rpmos[4][4] = { |
| /* in / 0 1 x z <-control */ |
| /* 0 */ {_0,_z,_x,_x}, |
| /* 1 */ {_1,_z,_x,_x}, |
| /* x */ {_x,_z,_x,_x}, |
| /* z */ {_z,_z,_z,_z} |
| }; |
| |
| static const bit_value_t l_rnmos[4][4] = { |
| /* in / 0 1 x z <-control */ |
| /* 0 */ {_z,_0,_x,_x}, |
| /* 1 */ {_z,_1,_x,_x}, |
| /* x */ {_z,_x,_x,_x}, |
| /* z */ {_z,_z,_z,_z} |
| }; |
| |
| static const bit_value_t l_nmos[4][4] = { |
| /* in / 0 1 x z <-control */ |
| /* 0 */ {_z,_0,_x,_x}, |
| /* 1 */ {_z,_1,_x,_x}, |
| /* x */ {_z,_x,_x,_x}, |
| /* z */ {_z,_z,_z,_z} |
| }; |
| |
| |
| // see table 5-21 p:54 IEEE 1364-2005 |
| static const bit_value_t l_ternary[4][4] = { |
| /* in / 0 1 x z <-control */ |
| /* 0 */ {_0,_x,_x,_x}, |
| /* 1 */ {_x,_1,_x,_x}, |
| /* x */ {_x,_x,_x,_x}, |
| /* z */ {_x,_x,_x,_x} |
| }; |
| |
| /***** |
| * these extend the library and simplify the process |
| */ |
| /* helper */ |
| static const bit_value_t l_unk[4][4] = { |
| /* in / 0 1 x z <-control */ |
| /* 0 */ {_x,_x,_x,_x}, |
| /* 1 */ {_x,_x,_x,_x}, |
| /* x */ {_x,_x,_x,_x}, |
| /* z */ {_x,_x,_x,_x} |
| }; |
| |
| |
| static const bit_value_t l_case_eq[4][4] = { |
| /* a / 0 1 x z <-b */ |
| /* 0 */ {_1,_0,_0,_0}, |
| /* 1 */ {_0,_1,_0,_0}, |
| /* x */ {_0,_0,_1,_0}, |
| /* z */ {_0,_0,_0,_1} |
| }; |
| |
| static const bit_value_t l_case_neq[4][4] = |
| unroll_2d_invert(l_case_eq); |
| |
| |
| static const bit_value_t l_lt[4][4] = { |
| /* a / 0 1 x z <-b */ |
| /* 0 */ {_0,_0,_x,_x}, |
| /* 1 */ {_1,_0,_x,_x}, |
| /* x */ {_x,_x,_x,_x}, |
| /* z */ {_x,_x,_x,_x} |
| }; |
| static const bit_value_t l_ge[4][4] = unroll_2d(l_lt); |
| |
| static const bit_value_t l_gt[4][4] = { |
| /* a / 0 1 x z <-b */ |
| /* 0 */ {_0,_1,_x,_x}, |
| /* 1 */ {_0,_0,_x,_x}, |
| /* x */ {_x,_x,_x,_x}, |
| /* z */ {_x,_x,_x,_x} |
| }; |
| static const bit_value_t l_le[4][4] = unroll_2d(l_gt); |
| |
| static const bit_value_t l_eq[4][4] = |
| unroll_2d(l_xnor); |
| |
| static const bit_value_t l_sum[4][4][4] = { |
| /* c_in */ |
| /* 0 */ unroll_2d(l_xor), |
| /* 1 */ unroll_2d(l_xnor), |
| /* x */ unroll_2d(l_unk), |
| /* z */ unroll_2d(l_unk) |
| }; |
| |
| static const bit_value_t l_carry[4][4][4] = { |
| /* c_in */ |
| /* 0 */ unroll_2d(l_and), |
| /* 1 */ unroll_2d(l_or), |
| /* x */ unroll_2d(l_ternary), |
| /* z */ unroll_2d(l_ternary) |
| }; |
| |
| static const bit_value_t l_half_carry[4][4] = unroll_2d(l_carry[_0]); |
| static const bit_value_t l_half_sum[4][4] = unroll_2d(l_sum[_0]); |
| |
| static char bit_to_c(bit_value_t bit) |
| { |
| switch(bit) |
| { |
| case _0: return '0'; |
| case _1: return '1'; |
| case _z: return 'z'; |
| default: return 'x'; |
| } |
| } |
| |
| static bit_value_t c_to_bit(char c) |
| { |
| switch(c) |
| { |
| case '0': return _0; |
| case '1': return _1; |
| case 'z': return _z; |
| default: return _x; |
| } |
| } |
| template<typename T> |
| class BitFields |
| { |
| private : |
| |
| T bits = _All_x; |
| |
| size_t get_bit_location(size_t address) |
| { |
| return ((address%this->size())<<1); |
| } |
| |
| T make_insert(size_t loc, bit_value_t value) |
| { |
| return (static_cast<T>(value) << (loc)); |
| } |
| |
| T make_mask(size_t loc) |
| { |
| return (~make_insert(loc,_0)); |
| } |
| |
| public : |
| |
| BitFields(bit_value_t init_v) |
| { |
| |
| this->bits = |
| (_0 == init_v)? _All_0: |
| (_1 == init_v)? _All_1: |
| (_z == init_v)? _All_z: |
| _All_x; |
| } |
| |
| bit_value_t get_bit(size_t address) |
| { |
| return ((this->bits >> (this->get_bit_location(address))) & 0x3UL); |
| } |
| |
| void set_bit(size_t address, bit_value_t value) |
| { |
| size_t real_address = this->get_bit_location(address); |
| |
| T long_value = static_cast<T>(value); |
| |
| T set_value = long_value << real_address; |
| T zero_out_location = ~(0x3UL << real_address); |
| |
| this->bits &= zero_out_location; |
| this->bits |= set_value; |
| } |
| |
| static size_t size() |
| { |
| return (sizeof(T)<<2); // 8 bit in a byte, 2 bits for a verilog bits = 4 bits in a byte, << 2 = sizeof x 4 |
| } |
| }; |
| |
| #define DEBUG_V_BITS |
| |
| /***** |
| * we use large array since we process the bits in chunks |
| */ |
| class VerilogBits |
| { |
| private: |
| |
| std::vector<BitFields<veri_internal_bits_t>> bits; |
| size_t bit_size; |
| |
| size_t to_index(size_t address) |
| { |
| return (address / BitFields<veri_internal_bits_t>::size() ); |
| } |
| |
| size_t list_size() |
| { |
| return this->bits.size(); |
| } |
| |
| |
| |
| public: |
| |
| VerilogBits() |
| { |
| } |
| |
| VerilogBits(size_t data_size, bit_value_t value_in) |
| { |
| this->bit_size = data_size; |
| this->bits = std::vector<BitSpace::BitFields<veri_internal_bits_t>>(); |
| |
| size_t bitfield_count = (this->bit_size / BitFields<veri_internal_bits_t>::size()) +1; |
| |
| for(size_t i=0; i<bitfield_count; i++) |
| { |
| this->bits.push_back(BitSpace::BitFields<veri_internal_bits_t>(value_in)); |
| } |
| } |
| |
| VerilogBits(VerilogBits *other) |
| { |
| this->bit_size = other->size(); |
| this->bits = other->get_internal_bitvector(); |
| } |
| |
| size_t size() |
| { |
| return this->bit_size; |
| } |
| |
| std::vector<BitFields<veri_internal_bits_t>> get_internal_bitvector() |
| { |
| return this->bits; |
| } |
| |
| BitFields<veri_internal_bits_t> *get_bitfield(size_t index) |
| { |
| |
| #ifdef DEBUG_V_BITS |
| if (index >= this->bits.size() ) |
| { |
| std::cerr << "Bit array indexing out of bounds " << index << " but size is " << this->bit_size << std::endl; |
| std::abort(); |
| } |
| #endif |
| |
| return (&this->bits[index]); |
| } |
| |
| bit_value_t get_bit(size_t address) |
| { |
| #ifdef DEBUG_V_BITS |
| if (address >= this->bit_size ) |
| { |
| std::cerr << "Bit index array out of bounds " << address << " but size is " << this->bit_size << std::endl; |
| std::abort(); |
| } |
| #endif |
| |
| return (this->get_bitfield(to_index(address))->get_bit(address)); |
| } |
| |
| void set_bit(size_t address, bit_value_t value) |
| { |
| #ifdef DEBUG_V_BITS |
| if (address >= this->bit_size ) |
| { |
| std::cerr << "Bit index array out of bounds " << address << " but size is " << this->bit_size << std::endl; |
| std::abort(); |
| } |
| #endif |
| (this->get_bitfield(to_index(address))->set_bit(address, value)); |
| } |
| |
| std::string to_string(bool big_endian) |
| { |
| // make a big endian string |
| std::string to_return = ""; |
| for(size_t address=0x0; address < this->size(); address++) |
| { |
| to_return.push_back(BitSpace::bit_to_c(this->get_bit(address))); |
| } |
| |
| if(!big_endian) |
| return std::string(to_return.crbegin(), to_return.crend()); |
| else |
| return to_return; |
| } |
| |
| bool has_unknowns() |
| { |
| for(size_t address=0x0; address < this->size(); address++) |
| { |
| if(is_unk[this->get_bit(address)]) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Unary Reduction operations |
| * This is Msb to Lsb on purpose, as per specs |
| */ |
| VerilogBits bitwise_reduce(const bit_value_t lut[4][4]) |
| { |
| |
| bit_value_t result = this->get_bit(this->size()-1); |
| for(size_t i=this->size()-2; i < this->size(); i--) |
| { |
| result = lut[result][this->get_bit(i)]; |
| } |
| |
| return VerilogBits(1, result); |
| } |
| |
| VerilogBits invert() |
| { |
| VerilogBits other(this->bit_size, _0); |
| |
| for(size_t i=0; i<this->size(); i++) |
| other.set_bit(i, BitSpace::l_not[this->get_bit(i)]); |
| |
| return other; |
| } |
| |
| VerilogBits twos_complement() |
| { |
| BitSpace::bit_value_t previous_carry = BitSpace::_1; |
| VerilogBits other(this->bit_size, _0); |
| |
| for(size_t i=0; i<this->size(); i++) |
| { |
| BitSpace::bit_value_t not_bit_i = BitSpace::l_not[this->get_bit(i)]; |
| |
| other.set_bit(i,BitSpace::l_half_sum[previous_carry][not_bit_i]); |
| previous_carry = BitSpace::l_half_carry[previous_carry][not_bit_i]; |
| } |
| |
| return other; |
| } |
| |
| /** |
| * size of zero compact to the least amount of bits |
| */ |
| VerilogBits resize(BitSpace::bit_value_t pad, size_t size) |
| { |
| |
| /** |
| * find the new size |
| */ |
| if(size == 0) |
| { |
| |
| size_t last_bit_id = this->size() - 1; |
| size_t next_bit_id = last_bit_id -1; |
| |
| |
| while(next_bit_id < this->size()-1) |
| { |
| BitSpace::bit_value_t current = this->get_bit(last_bit_id); |
| BitSpace::bit_value_t next = this->get_bit(next_bit_id); |
| |
| if(current == next && current == pad) |
| { |
| last_bit_id--; |
| next_bit_id--; |
| } |
| else |
| { |
| break; /* it down. oh. oh! */ |
| } |
| |
| |
| } |
| |
| size = last_bit_id+1; |
| } |
| |
| VerilogBits other(size, BitSpace::_0); |
| |
| size_t i = 0; |
| |
| while(i < this->size() && i < size) |
| { |
| other.set_bit(i, this->get_bit(i)); |
| i++; |
| } |
| |
| while(i < size) |
| { |
| other.set_bit(i, pad);/* <- ask Eve about it */ |
| i++; |
| } |
| |
| return other; |
| } |
| }; |
| } |
| |
| //template<size_t bit_size> |
| class VNumber |
| { |
| private: |
| bool sign; |
| bool defined_size; |
| BitSpace::VerilogBits bitstring; |
| |
| VNumber(BitSpace::VerilogBits other_bitstring, bool other_sign) |
| { |
| bitstring = BitSpace::VerilogBits(other_bitstring); |
| sign = other_sign; |
| } |
| |
| public: |
| |
| VNumber(){} |
| |
| VNumber(VNumber&&) = default; |
| VNumber& operator=(VNumber&&) = default; |
| VNumber& operator=(const VNumber& other) = default; |
| |
| VNumber(const VNumber& other) |
| { |
| this->sign = other.sign; |
| this->bitstring = other.bitstring; |
| this->defined_size = other.defined_size; |
| } |
| |
| VNumber(VNumber other, size_t length) |
| { |
| this->sign = other.sign; |
| this->bitstring = other.bitstring.resize(other.get_padding_bit(),length); |
| } |
| |
| VNumber(const std::string& verilog_string) |
| { |
| set_value(verilog_string); |
| } |
| |
| VNumber(int64_t numeric_value) |
| { |
| set_value(numeric_value); |
| } |
| |
| VNumber(size_t len, BitSpace::bit_value_t initial_bits, bool input_sign) |
| { |
| this->bitstring = new BitSpace::VerilogBits(len, initial_bits); |
| this->sign = input_sign; |
| } |
| |
| /*** |
| * getters |
| */ |
| int64_t get_value() |
| { |
| assert_Werr( (! this->bitstring.has_unknowns() ) , |
| "Invalid Number contains dont care values. number: " + this->bitstring.to_string(false) |
| ); |
| |
| int64_t result = 0; |
| int8_t pad = this->get_padding_bit(); // = this->is_negative(); |
| for(size_t bit_index = 0; bit_index < this->size(); bit_index++) |
| { |
| int64_t current_bit = pad; |
| if(bit_index < this->size()) |
| current_bit = this->bitstring.get_bit(bit_index); |
| |
| result |= (current_bit << bit_index); |
| } |
| |
| return result; |
| } |
| |
| // convert lsb_msb bitstring to verilog |
| std::string to_full_string() |
| { |
| std::string out = this->to_bit_string(); |
| size_t len = this->bitstring.size(); |
| |
| return std::to_string(len) + ((this->is_signed())? "\'sb": "\'b") + out; |
| } |
| |
| std::string to_bit_string() |
| { |
| std::string out = this->bitstring.to_string(false); |
| return out; |
| } |
| |
| /*** |
| * setters |
| */ |
| void set_value(const std::string& input) |
| { |
| std::string verilog_string(input); |
| |
| if(!verilog_string.size()) |
| { |
| return; |
| } |
| |
| size_t loc = verilog_string.find("\'"); |
| |
| |
| if(loc == std::string::npos) |
| { |
| verilog_string.insert(0, "\'sd"); |
| loc = 0; |
| } |
| |
| size_t bitsize = 0; |
| if(loc != 0) |
| { |
| std::string bit_length_char = verilog_string.substr(0, loc); |
| bitsize = strtoul(bit_length_char.c_str(), nullptr, 10); |
| this->defined_size = true; |
| } |
| else |
| { |
| bitsize = 32; |
| this->defined_size = false; |
| } |
| |
| |
| this->sign = false; |
| if(std::tolower(verilog_string[loc+1]) == 's') |
| { |
| this->sign = true; |
| } |
| |
| |
| char base = static_cast<char>(std::tolower(verilog_string[loc+1+sign])); |
| |
| |
| uint8_t radix = 0; |
| switch(base){ |
| case 'b': radix = 2; break; |
| case 'o': radix = 8; break; |
| case 'd': radix = 10; break; |
| case 'h': radix = 16; break; |
| default: |
| assert_Werr( false, |
| "Invalid radix base for number: " + std::string(1,base) |
| ); |
| break; |
| } |
| |
| |
| //remove underscores |
| std::string v_value_str = verilog_string.substr(loc+2+sign); |
| v_value_str.erase(std::remove(v_value_str.begin(), v_value_str.end(), '_'), v_value_str.end()); |
| |
| |
| //little endian bitstring string |
| std::string temp_bitstring = string_of_radix_to_bitstring(v_value_str, radix); |
| |
| |
| char pad = temp_bitstring[0]; |
| |
| |
| if(!this->sign && pad == '1') |
| { |
| pad = '0'; |
| } |
| |
| |
| |
| // convert the bits to the internal data struct (bit at index 0 in string is msb since string go from msb to lsb) |
| BitSpace::VerilogBits new_bitstring(temp_bitstring.size(), BitSpace::_0); |
| size_t counter = temp_bitstring.size()-1; |
| for(char in: temp_bitstring) |
| { |
| new_bitstring.set_bit(counter--,BitSpace::c_to_bit(in)); |
| } |
| |
| |
| this->bitstring = new_bitstring.resize(BitSpace::c_to_bit(pad), bitsize); |
| } |
| |
| void set_value(int64_t in) |
| { |
| this->set_value(std::to_string(in)); |
| } |
| |
| size_t msb_index() |
| { |
| return this->bitstring.size()-1; |
| } |
| |
| /**** |
| * bit twiddling functions |
| */ |
| BitSpace::bit_value_t get_bit_from_msb(size_t index) |
| { |
| return this->bitstring.get_bit(msb_index()-index); |
| } |
| |
| BitSpace::bit_value_t get_bit_from_lsb(size_t index) |
| { |
| if (index < this->size()) |
| return this->bitstring.get_bit(index); |
| else |
| return this->get_padding_bit(); |
| } |
| |
| void set_bit_from_msb(size_t index, BitSpace::bit_value_t val) |
| { |
| this->bitstring.set_bit(msb_index()-index, val); |
| } |
| |
| void set_bit_from_lsb(size_t index, BitSpace::bit_value_t val) |
| { |
| this->bitstring.set_bit(index, val); |
| } |
| |
| /*** |
| * other |
| */ |
| size_t size() |
| { |
| |
| return this->bitstring.size(); |
| } |
| |
| bool is_signed() const |
| { |
| return this->sign; |
| } |
| |
| bool is_defined_size() |
| { |
| return this->defined_size; |
| } |
| |
| bool is_negative() |
| { |
| return ( this->get_bit_from_msb(0) == BitSpace::_1 && this->sign ); |
| } |
| |
| BitSpace::bit_value_t get_padding_bit() |
| { |
| return this->is_negative()? BitSpace::_1:BitSpace::_0; |
| } |
| |
| bool is_dont_care_string() |
| { |
| return this->bitstring.has_unknowns(); |
| } |
| |
| VNumber twos_complement() |
| { |
| return VNumber(this->bitstring.twos_complement(),this->sign); |
| } |
| |
| VNumber invert() |
| { |
| return VNumber(this->bitstring.invert(),this->sign); |
| } |
| |
| VNumber bitwise_reduce(const BitSpace::bit_value_t lut[4][4]) |
| { |
| return VNumber(this->bitstring.bitwise_reduce(lut),false); |
| } |
| |
| /** |
| * Binary Reduction operations |
| */ |
| VNumber bitwise(VNumber& b, const BitSpace::bit_value_t lut[4][4]) |
| { |
| size_t std_length = std::max(this->size(), b.size()); |
| const BitSpace::bit_value_t pad_a = this->get_padding_bit(); |
| const BitSpace::bit_value_t pad_b = b.get_padding_bit(); |
| |
| VNumber result(std_length, BitSpace::_x, false); |
| |
| for(size_t i=0; i < result.size(); i++) |
| { |
| BitSpace::bit_value_t bit_a = pad_a; |
| if(i < this->size()) |
| bit_a = this->get_bit_from_lsb(i); |
| |
| BitSpace::bit_value_t bit_b = pad_b; |
| if(i < b.size()) |
| bit_b = b.get_bit_from_lsb(i); |
| |
| result.set_bit_from_lsb(i, lut[bit_a][bit_b]); |
| } |
| |
| return result; |
| } |
| |
| }; |
| |
| #endif |