831 lines
18 KiB
C++
831 lines
18 KiB
C++
/* 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 <string>
|
||
|
||
#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<size_t>(-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<size_t>(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<VNumber> concat_list)
|
||
{
|
||
assert_Werr(!concat_list.empty(),
|
||
"Concat List cannot be empty");
|
||
|
||
VNumber init = concat_list[0];
|
||
for(size_t i=1; i<concat_list.size(); i++)
|
||
{
|
||
init = init.insert_at_lsb(concat_list[i]);
|
||
}
|
||
return init;
|
||
}
|
||
|
||
VNumber V_BITWISE_AND(VNumber& a, VNumber& b)
|
||
{
|
||
return a.bitwise(b,l_and);
|
||
}
|
||
|
||
VNumber V_BITWISE_OR(VNumber& a, VNumber& b)
|
||
{
|
||
return a.bitwise(b,l_or);
|
||
}
|
||
|
||
VNumber V_BITWISE_XOR(VNumber& a, VNumber& b)
|
||
{
|
||
return a.bitwise(b,l_xor);
|
||
}
|
||
|
||
VNumber V_BITWISE_NAND(VNumber& a, VNumber& b)
|
||
{
|
||
return a.bitwise(b,l_nand);
|
||
}
|
||
|
||
VNumber V_BITWISE_NOR(VNumber& a, VNumber& b)
|
||
{
|
||
return a.bitwise(b,l_nor);
|
||
}
|
||
|
||
VNumber V_BITWISE_XNOR(VNumber& a, VNumber& b)
|
||
{
|
||
return a.bitwise(b,l_xnor);
|
||
}
|
||
|
||
/**
|
||
* Logical Operations
|
||
*/
|
||
|
||
VNumber V_CASE_EQUAL(VNumber& a, VNumber& b)
|
||
{
|
||
VNumber longEval = a.bitwise(b, l_case_eq);
|
||
VNumber eq = V_BITWISE_AND(longEval);
|
||
return eq;
|
||
}
|
||
|
||
VNumber V_CASE_NOT_EQUAL(VNumber& a, VNumber& b)
|
||
{
|
||
VNumber eq = V_CASE_EQUAL(a,b);
|
||
VNumber neq = V_LOGICAL_NOT(eq);
|
||
return neq;
|
||
}
|
||
|
||
VNumber V_LOGICAL_AND(VNumber& a, VNumber& b)
|
||
{
|
||
VNumber reduxA = a.bitwise_reduce(l_or);
|
||
VNumber reduxB = b.bitwise_reduce(l_or);
|
||
|
||
VNumber to_return = reduxA.bitwise(reduxB, l_and);
|
||
|
||
return to_return;
|
||
}
|
||
|
||
VNumber V_LOGICAL_OR(VNumber& a, VNumber& b)
|
||
{
|
||
VNumber reduxA = a.bitwise_reduce(l_or);
|
||
VNumber reduxB = b.bitwise_reduce(l_or);
|
||
|
||
VNumber to_return = reduxA.bitwise(reduxB, l_or);
|
||
|
||
return to_return;
|
||
}
|
||
|
||
VNumber V_LT(VNumber& a, VNumber& b)
|
||
{
|
||
compare_bit cmp = eval_op(a,b);
|
||
BitSpace::bit_value_t result = cmp.is_unk()? BitSpace::_x: cmp.is_lt()? BitSpace::_1: BitSpace::_0;
|
||
VNumber to_return(1, result, false, true);
|
||
return to_return;
|
||
}
|
||
|
||
VNumber V_GT(VNumber& a, VNumber& b)
|
||
{
|
||
compare_bit cmp = eval_op(a,b);
|
||
BitSpace::bit_value_t result = cmp.is_unk()? BitSpace::_x: cmp.is_gt()? BitSpace::_1: BitSpace::_0;
|
||
VNumber to_return(1, result, false, true);
|
||
return to_return;
|
||
}
|
||
|
||
VNumber V_EQUAL(VNumber& a, VNumber& b)
|
||
{
|
||
compare_bit cmp = eval_op(a,b);
|
||
BitSpace::bit_value_t result = cmp.is_unk()? BitSpace::_x: cmp.is_eq()? BitSpace::_1: BitSpace::_0;
|
||
VNumber to_return(1, result, false, true);
|
||
return to_return;
|
||
}
|
||
|
||
VNumber V_GE(VNumber& a, VNumber& b)
|
||
{
|
||
compare_bit cmp = eval_op(a,b);
|
||
BitSpace::bit_value_t result = cmp.is_unk()? BitSpace::_x: cmp.is_ge()? BitSpace::_1: BitSpace::_0;
|
||
VNumber to_return(1, result, false, true);
|
||
return to_return;
|
||
}
|
||
|
||
VNumber V_LE(VNumber& a, VNumber& b)
|
||
{
|
||
compare_bit cmp = eval_op(a,b);
|
||
BitSpace::bit_value_t result = cmp.is_unk()? BitSpace::_x: cmp.is_le()? BitSpace::_1: BitSpace::_0;
|
||
VNumber to_return(1, result, false, true);
|
||
return to_return;
|
||
}
|
||
|
||
VNumber V_NOT_EQUAL(VNumber& a, VNumber& b)
|
||
{
|
||
compare_bit cmp = eval_op(a,b);
|
||
BitSpace::bit_value_t result = cmp.is_unk()? BitSpace::_x: cmp.is_ne()? BitSpace::_1: BitSpace::_0;
|
||
VNumber to_return(1, result, false, true);
|
||
return to_return;
|
||
}
|
||
|
||
VNumber V_SIGNED_SHIFT_LEFT(VNumber& a, VNumber& b)
|
||
{
|
||
if(b.is_dont_care_string())
|
||
return VNumber("2'sbxx");
|
||
|
||
return shift_op(a, b.get_value(), a.is_signed());
|
||
}
|
||
|
||
VNumber V_SHIFT_LEFT(VNumber& a, VNumber& b)
|
||
{
|
||
if(b.is_dont_care_string())
|
||
return VNumber("2'sbxx");
|
||
|
||
return shift_op(a, b.get_value(), false);
|
||
}
|
||
|
||
VNumber V_SIGNED_SHIFT_RIGHT(VNumber& a, VNumber& b)
|
||
{
|
||
if(b.is_dont_care_string())
|
||
return VNumber("2'sbxx");
|
||
|
||
return shift_op(a, -1* b.get_value(), a.is_signed());
|
||
}
|
||
|
||
VNumber V_SHIFT_RIGHT(VNumber& a, VNumber& b)
|
||
{
|
||
if(b.is_dont_care_string())
|
||
return VNumber("2'sbxx");
|
||
|
||
return shift_op(a, -1* b.get_value(), false);
|
||
}
|
||
|
||
VNumber V_ADD(VNumber& a, VNumber& b)
|
||
{
|
||
return sum_op(a, b, _0, /* is_twos_complement_subtraction */ false);
|
||
}
|
||
|
||
VNumber V_MINUS(VNumber& a, VNumber& b)
|
||
{
|
||
size_t std_length = std::max(a.size(), b.size());
|
||
VNumber padded_a(a, std_length);
|
||
VNumber padded_b(b, std_length);
|
||
|
||
VNumber complement = V_MINUS(padded_b);
|
||
if (padded_b.is_negative() && complement.is_negative())
|
||
{
|
||
/* special case: 2's comp is identical to original, must pad */
|
||
complement = VNumber(padded_b, padded_b.size()+1);
|
||
complement = V_MINUS(complement);
|
||
}
|
||
|
||
return sum_op(padded_a, complement, _0, /* is_twos_complement_subtraction */ true);
|
||
}
|
||
|
||
VNumber V_MULTIPLY(VNumber& a_in, VNumber& b_in)
|
||
{
|
||
|
||
if(a_in.is_dont_care_string() || b_in.is_dont_care_string())
|
||
{
|
||
return VNumber("2'sbxx");
|
||
}
|
||
|
||
VNumber a;
|
||
VNumber b;
|
||
|
||
bool is_multiply_signed_operation = is_signed_operation(a_in, b_in);
|
||
bool neg_a = a_in.is_negative();
|
||
bool neg_b = b_in.is_negative();
|
||
|
||
|
||
if(neg_a)
|
||
{
|
||
a = V_MINUS(a_in);
|
||
|
||
if (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);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
a = a_in;
|
||
}
|
||
|
||
if(neg_b)
|
||
{
|
||
b = V_MINUS(b_in);
|
||
|
||
if (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);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
b = b_in;
|
||
}
|
||
|
||
|
||
bool invert_result = ((!neg_a && neg_b) || (neg_a && !neg_b));
|
||
|
||
|
||
VNumber result("0");
|
||
VNumber b_copy = b;
|
||
|
||
for(size_t i = 0; i < a.size(); i++)
|
||
{
|
||
bit_value_t bit_a = a.get_bit_from_lsb(i);
|
||
|
||
|
||
if(bit_a == _1)
|
||
{
|
||
result = V_ADD(result, b_copy);
|
||
}
|
||
|
||
|
||
b_copy = shift_op(b_copy, 1, is_multiply_signed_operation);
|
||
|
||
}
|
||
|
||
|
||
if(invert_result)
|
||
{
|
||
result = V_MINUS(result);
|
||
}
|
||
|
||
|
||
return result;
|
||
}
|
||
|
||
/*
|
||
* From Table 5-6 "Power operator rules" of IEEE Standard 1364-2005:
|
||
* "Verilog Hardware Description Language"; on Page 46 (PDF Page 76):
|
||
*
|
||
* Table 5-6 — Power operator rules:
|
||
*
|
||
* |-----------------------------------------------------------------------------|
|
||
* | | \ op1 is -> | | | | | |
|
||
* | \/ \ | 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);
|
||
}
|