/* Authors: Aaron Graham (aaron.graham@unb.ca, aarongraham9@gmail.com), * Jean-Philippe Legault (jlegault@unb.ca, jeanphilippe.legault@gmail.com), * Alexandrea Demmings (alexandrea.demmings@unb.ca, lxdemmings@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 */ #include #include "internal_bits.hpp" #include "rtl_int.hpp" #include "rtl_utils.hpp" using namespace BitSpace; class compare_bit { private: uint8_t result = 0x0; public: compare_bit(uint8_t set_to){result = set_to;} bool is_unk(){ return (!result); } bool is_gt(){ return (result&(0x1)); } bool is_eq(){ return (result&(0x2)); } bool is_lt(){ return (result&(0x4)); } bool is_ne(){ return (!is_eq()); } bool is_ge(){ return (result&(0x3)); } bool is_le(){ return (result&(0x6)); } }; #define UNK_EVAL compare_bit(0x0) #define GT_EVAL compare_bit(0x1) #define EQ_EVAL compare_bit(0x2) #define LT_EVAL compare_bit(0x4) static compare_bit eval_op(VNumber& a_in, VNumber& b_in) { assert_Werr( a_in.size() , "empty 1st bit string" ); assert_Werr( b_in.size() , "empty 2nd bit string" ); bool neg_a = (a_in.is_negative()); bool neg_b = (b_in.is_negative()); if(neg_a && !neg_b) { return LT_EVAL; } else if(!neg_a && neg_b) { return GT_EVAL; } VNumber a; VNumber b; bool invert_result = (neg_a && neg_b); if(invert_result) { a = a_in.twos_complement(); b = b_in.twos_complement(); } else { a = a_in; b = b_in; } size_t std_length = std::max(a.size(), b.size()); bit_value_t pad_a = a.get_padding_bit(); bit_value_t pad_b = b.get_padding_bit(); for(size_t i=std_length-1; i < std_length ; i--) { bit_value_t bit_a = pad_a; if(i < a.size()) { bit_a = a.get_bit_from_lsb(i); } bit_value_t bit_b = pad_b; if(i < b.size()) { bit_b = b.get_bit_from_lsb(i); } if(BitSpace::l_lt[bit_a][bit_b] == BitSpace::_1) { return (!invert_result)? LT_EVAL: GT_EVAL; } else if(BitSpace::l_gt[bit_a][bit_b] == BitSpace::_1) { return (!invert_result)? GT_EVAL: LT_EVAL; } else if(BitSpace::l_eq[bit_a][bit_b] == BitSpace::_1) { continue; } else { return UNK_EVAL; } } return EQ_EVAL; } static compare_bit eval_op(VNumber a,int64_t b) { VNumber bits_value = VNumber(std::to_string(std::abs(b))); if(b < 0) bits_value = bits_value.twos_complement(); return eval_op(a, bits_value); } /** * Check if the Operation Should be Signed by Checking if Both Operands Are Signed: */ static bool is_signed_operation(VNumber& a, VNumber& b) { bool is_signed_operation = false; if((true == a.is_signed()) && (true == b.is_signed())) { is_signed_operation = true; } return is_signed_operation; } /** * Addition operations */ static VNumber sum_op(VNumber& a, VNumber& b, const bit_value_t& initial_carry, bool is_twos_complement_subtraction) { assert_Werr( a.size() , "empty 1st bit string" ); assert_Werr( b.size() , "empty 2nd bit string" ); size_t std_length = std::max(a.size(), b.size()); size_t new_length = ((true == is_twos_complement_subtraction) ? (std_length) : (std_length + 1)); const bit_value_t pad_a = a.get_padding_bit(); const bit_value_t pad_b = b.get_padding_bit(); bool is_addition_signed_operation = is_signed_operation(a, b); //("pad_b: '" << (unsigned(pad_b)) << "'"); bit_value_t previous_carry = initial_carry; VNumber result(new_length, _0, is_addition_signed_operation, a.is_defined_size() && b.is_defined_size()); for(size_t i = 0; i < new_length; i++) { bit_value_t bit_a = pad_a; if(i < a.size()) { bit_a = a.get_bit_from_lsb(i); } 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, l_sum[previous_carry][bit_a][bit_b]); previous_carry = l_carry[previous_carry][bit_a][bit_b]; } return result; } static VNumber shift_op(VNumber& a, int64_t b, bool sign_shift) { VNumber to_return; if(b==0) { to_return = a; } //if b is negative then shift right else if(b < 0) { size_t u_b = static_cast(-b); bit_value_t pad = ( sign_shift ) ? a.get_padding_bit(): BitSpace::_0; to_return = VNumber(a.size(), pad, sign_shift, a.is_defined_size()); for(size_t i=0; i < (a.size() - u_b); i++) { to_return.set_bit_from_lsb(i, a.get_bit_from_lsb(i+u_b)); } } else { size_t u_b = static_cast(b); bit_value_t pad = BitSpace::_0; to_return =VNumber((a.size() + u_b), pad, sign_shift, a.is_defined_size()); for(size_t i=0; i < a.size(); i++) { to_return.set_bit_from_lsb(i+u_b, a.get_bit_from_lsb(i)); } } return to_return; } bool V_TRUE(VNumber& a) { return a.is_true(); } bool V_FALSE(VNumber& a) { return a.is_false(); } bool V_UNK(VNumber& a) { return a.is_dont_care_string(); } bool V_IS_X(VNumber& a) { return a.is_x(); } bool V_IS_Z(VNumber& a) { return a.is_z(); } bool V_IS_SIGNED(VNumber& a) { return a.is_signed(); } bool V_IS_UNSIGNED(VNumber& a) { return !a.is_signed(); } std::string V_STRING(VNumber& a) { return a.to_printable(); } /*** * __ __ __ ___ __ ___ __ * | | |\ | /\ |__) \ / / \ |__) |__ |__) /\ | | / \ |\ | * \__/ | \| /~~\ | \ | \__/ | |___ | \ /~~\ | | \__/ | \| * */ VNumber V_BITWISE_NOT(VNumber& a) { return a.invert(); } VNumber V_LOGICAL_NOT(VNumber& a) { VNumber ored = a.bitwise_reduce(l_or); VNumber noted = ored.invert(); return noted; } VNumber V_ADD(VNumber& a) { VNumber result(a); return result; } VNumber V_MINUS(VNumber& a) { return a.twos_complement(); } VNumber V_UNSIGNED(VNumber& a) { return a.to_unsigned(); } VNumber V_SIGNED(VNumber& a) { return a.to_signed(); } VNumber V_BITWISE_AND(VNumber& a) { VNumber to_return = a.bitwise_reduce(l_and); return to_return; } VNumber V_BITWISE_OR(VNumber& a) { VNumber to_return = a.bitwise_reduce(l_or); return to_return; } VNumber V_BITWISE_XOR(VNumber& a) { VNumber to_return = a.bitwise_reduce(l_xor); return to_return; } VNumber V_BITWISE_NAND(VNumber& a) { VNumber to_return = a.bitwise_reduce(l_nand); return to_return; } VNumber V_BITWISE_NOR(VNumber& a) { VNumber to_return = a.bitwise_reduce(l_nor); return to_return; } VNumber V_BITWISE_XNOR(VNumber& a) { VNumber to_return = a.bitwise_reduce(l_xnor); return to_return; } /*** * __ __ __ __ ___ __ ___ __ * |__) | |\ | /\ |__) \ / / \ |__) |__ |__) /\ | | / \ |\ | * |__) | | \| /~~\ | \ | \__/ | |___ | \ /~~\ | | \__/ | \| * */ VNumber V_REPLICATE(VNumber& a, VNumber& n_times) { assert_Werr(! n_times.is_dont_care_string(), "Cannot use undefined number for the replication count"); return a.replicate(n_times.get_value()); } VNumber V_CONCAT(std::vector concat_list) { assert_Werr(!concat_list.empty(), "Concat List cannot be empty"); VNumber init = concat_list[0]; for(size_t i=1; i | | | | | | * | \/ \ | negative < –1 | –1 | zero | 1 | positive > 1 | * | op2 is \ | | | | | | * |-----------------------------------------------------------------------------| * | | | | | | | * | Positive | op1 ** op2 | op2 is odd -> –1 | 0 | 1 | op1 ** op2 | * | | | op2 is even -> 1 | | | | * | | | | | | | * |-----------------------------------------------------------------------------| * | | | | | | | * | Zero | 1 | 1 | 1 | 1 | 1 | * | | | | | | | * |-----------------------------------------------------------------------------| * | | | | | | | * | Negative | 0 | op2 is odd -> –1 | 'bx | 1 | 0 | * | | | op2 is even -> 1 | | | | * | | | | | | | * |-----------------------------------------------------------------------------| */ VNumber V_POWER(VNumber& a, VNumber& b) { if(a.is_dont_care_string() || b.is_dont_care_string()) { return VNumber("2'sbxx"); } compare_bit res_a = eval_op(a, 0); short val_a = (res_a.is_eq()) ? 0: (res_a.is_lt()) ? (eval_op(a,-1).is_lt()) ? -2: -1: /* GREATHER_THAN */ (eval_op(a,1).is_gt()) ? 2: 1; compare_bit res_b = eval_op(b, 0); short val_b = (res_b.is_eq()) ? 0: (res_b.is_lt()) ? -1: /* GREATHER_THAN */ 1; // Compute: Case Where 'val_a <= -2' or 'val_a >= 2'; As-Per the Spec: if(val_b > 0 && (val_a < -1 || val_a > 1 )) { VNumber result("2'sb01"); VNumber one = VNumber("2'sb01"); VNumber tmp_b = b; while(eval_op(tmp_b, 0).is_gt()) { VNumber tmp_b_comp = V_MINUS(tmp_b, one); if (tmp_b_comp.is_negative() && tmp_b.is_negative()) { /* special case: 2's comp is identical to original, must pad */ tmp_b_comp = VNumber(tmp_b, tmp_b.size()+1); tmp_b_comp = V_MINUS(tmp_b_comp); } tmp_b = tmp_b_comp; result = V_MULTIPLY(result, a); } return result; } else if (val_b == 0 || val_a == 1) { return VNumber("2'sb01"); } else if(val_b == -1 && val_a == 0) { return VNumber("2'sbxx"); } else if(val_a == -1) { // Even: if(BitSpace::_0 == b.get_bit_from_lsb(0)) { return VNumber("2'sb01"); } // Odd: else { return VNumber("2'sb11"); } } else { return VNumber("2'sb00"); } } ///////////////////////////// VNumber V_DIV(VNumber& a_in, VNumber& b_in) { if(a_in.is_dont_care_string() || b_in.is_dont_care_string() || eval_op(b_in,0).is_eq()) return VNumber("2'sbxx"); VNumber result("0"); bool is_division_signed_operation = is_signed_operation(a_in, b_in); bool neg_a = a_in.is_negative(); bool neg_b = b_in.is_negative(); VNumber a = neg_a ? V_MINUS(a_in) : a_in; VNumber b = neg_b ? V_MINUS(b_in) : b_in; if (neg_a && a.is_negative()) { /* special case: 2's comp is identical to original, must pad */ a = VNumber(a_in, a_in.size()+1); a = V_MINUS(a); } if (neg_b && b.is_negative()) { /* special case: 2's comp is identical to original, must pad */ b = VNumber(b_in, b_in.size()+1); b = V_MINUS(b); } while(eval_op(a, b).is_ge() ) { VNumber count("1"); VNumber tmp = b; // initialize our variables VNumber sub_with = tmp; VNumber count_sub_with = count; while(eval_op(tmp, a).is_le()) { sub_with = tmp; count_sub_with = count; count = shift_op(count, 1, is_division_signed_operation); tmp = shift_op(tmp, 1, is_division_signed_operation); } a = V_MINUS(a, sub_with); result = V_ADD(result, count_sub_with); } return (neg_a != neg_b) ? V_MINUS(result) : result; } VNumber V_MOD(VNumber& a_in, VNumber& b_in) { if(a_in.is_dont_care_string() || b_in.is_dont_care_string() || eval_op(b_in, 0).is_eq()) return VNumber("2'sbxx"); bool neg_a = a_in.is_negative(); bool neg_b = b_in.is_negative(); VNumber a = neg_a ? V_MINUS(a_in) : a_in; VNumber b = neg_b ? V_MINUS(b_in) : b_in; if (neg_a && a.is_negative()) { /* special case: 2's comp is identical to original, must pad */ a = VNumber(a_in, a_in.size()+1); a = V_MINUS(a); } if (neg_b && b.is_negative()) { /* special case: 2's comp is identical to original, must pad */ b = VNumber(b_in, b_in.size()+1); b = V_MINUS(b); } bool is_modulo_signed_operation = is_signed_operation(a, b); while(eval_op(a, b).is_ge()) { VNumber tmp = b; VNumber sub_with = tmp; while( eval_op(tmp, a).is_le() ) { sub_with = tmp; tmp = shift_op(tmp, 1, is_modulo_signed_operation); } a = V_MINUS(a, sub_with); } return (neg_a) ? V_MINUS(a) : a; } /*** * ___ ___ __ __ __ __ ___ __ ___ __ * | |__ |__) |\ | /\ |__) \ / / \ |__) |__ |__) /\ | | / \ |\ | * | |___ | \ | \| /~~\ | \ | \__/ | |___ | \ /~~\ | | \__/ | \| * */ VNumber V_TERNARY(VNumber& a_in, VNumber& b_in, VNumber& c_in) { /* if a evaluates properly */ compare_bit eval = eval_op(V_LOGICAL_NOT(a_in),0); return (eval.is_unk())? b_in.bitwise(c_in, l_ternary): (eval.is_eq())? VNumber(b_in): VNumber(c_in); }