Last active
September 17, 2019 00:41
-
-
Save multiplemonomials/f3f8821c465dcd88a7d894f49d45b747 to your computer and use it in GitHub Desktop.
Test suite for ALU logic equations for EE 457 Lab 3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np | |
NUM_BITS = 4 | |
def bitwise_not(num:int, width=None): | |
"""Python doesn't have bitwise not so we have to improvise using XOR""" | |
if width is None: | |
width = num.bit_length() + 1 | |
# bitmask for all bits with a value | |
bitmask = (1 << width) - 1 | |
return num ^ bitmask | |
def get_bit(num:int, bit:int): | |
""" Get the Nth bit of a number, as a 1 or 0 integer value.""" | |
return (num & (1 << bit)) >> bit | |
def convert_to_signed(num:int, num_bits=NUM_BITS): | |
""" Converts a binary number into its integer value as if it was a two's complement number with NUM_BITS bits. | |
Python's integers have variable width so logic like this is needed for proper evaluation.""" | |
if get_bit(num, num_bits - 1): | |
return -(bitwise_not(num, num_bits) + 1) | |
else: | |
# signed representation is not negative | |
return num | |
def binary_add(A:int, B:int, negate_B = False): | |
""" Mimics the function of a 4-bit ALU. Adds the numbers and attempts to detect overflow.""" | |
# TODO: handle negate_B | |
if negate_B: | |
B_after_inv = ??? | |
carry_in_0 = ??? | |
else: | |
B_after_inv = B | |
carry_in_0 = 0 | |
# carry out for each bit | |
carry_out = 0 | |
# result | |
result = 0 | |
for bit in range(0, NUM_BITS): | |
A_bit = get_bit(A, bit) | |
B_bit = get_bit(B_after_inv, bit) | |
if bit == 0: | |
carry_in = carry_in_0 | |
else: | |
carry_in = get_bit(carry_out, bit - 1) | |
# TODO: Add the bits here. | |
# Hint: these equations are given in Redekopp's EE 109 slides in Unit 11 | |
result_bit = ??? | |
carry_out_bit = ??? | |
result |= result_bit << bit | |
carry_out |= carry_out_bit << bit | |
# These values will be useful in the overflow calculations | |
carry_out_msb = get_bit(carry_out, NUM_BITS - 1) | |
A_msb = get_bit(A, NUM_BITS - 1) | |
B_msb = get_bit(B, NUM_BITS - 1) | |
B_after_inv_msb = get_bit(B_after_inv, NUM_BITS - 1) | |
result_msb = get_bit(result, NUM_BITS - 1) | |
# TODO: detect signed overflow | |
signed_overflow = ??? | |
return result, carry_out_msb == 1, signed_overflow | |
for num1 in range(0, 16): | |
for num2 in range(0, 16): | |
# test unsigned addition | |
alu_result, carry_out, signed_overflow = binary_add(num1, num2) | |
uint_result = num1 + num2 | |
expected_carry_out = uint_result > 0b1111 | |
if (not carry_out and alu_result != uint_result) or (carry_out and alu_result + (1 << NUM_BITS) != uint_result): | |
print(f"UNSIGNED ADDITION WRONG! Num1: {num1:04b} ({num1}), Num2: {num2:04b} ({num2}), ALU result: {alu_result} [Cout = {carry_out}], correct result: {uint_result} [Cout = {expected_carry_out}]") | |
# test signed addition | |
# get the numbers interpreted as signed numbers | |
signed_num1 = convert_to_signed(num1) | |
signed_num2 = convert_to_signed(num2) | |
int_result = signed_num1 + signed_num2 | |
signed_alu_result = convert_to_signed(alu_result) | |
# per the textbook section 3.2, overflow occurs during addition when two positive numbers yield a negative number, or | |
# when two negative numbers yield a positive number | |
should_have_signed_overflow = ((signed_num1 >= 0 and signed_num2 >= 0 and signed_alu_result < 0) or | |
(signed_num1 < 0 and signed_num2 < 0 and signed_alu_result >= 0)) | |
if should_have_signed_overflow and not signed_overflow: | |
print(f"SIGNED ADDITION FAILED TO DETECT OVERFLOW! Num1: {np.binary_repr(signed_num1, width=NUM_BITS)} ({signed_num1}), Num2: {np.binary_repr(signed_num2, width=NUM_BITS)} ({signed_num2}), ALU result: {signed_alu_result}, correct result: {int_result}") | |
elif signed_alu_result != int_result and not signed_overflow: | |
print(f"SIGNED ADDITION WRONG! Num1: {np.binary_repr(signed_num1, width=NUM_BITS)} ({signed_num1}), Num2: {np.binary_repr(signed_num2, width=NUM_BITS)} ({signed_num2}), ALU result: {signed_alu_result}, correct result: {int_result}") | |
elif signed_overflow and not should_have_signed_overflow: | |
print(f"SIGNED ADDITION INCORRECTLY DETECTED OVERFLOW! Num1: {np.binary_repr(signed_num1, width=NUM_BITS)} ({signed_num1}), Num2: {np.binary_repr(signed_num2, width=NUM_BITS)} ({signed_num2}), ALU result: {signed_alu_result}, correct result: {int_result}") | |
for num1 in range(0, 16): | |
for num2 in range(0, 16): | |
# test unsigned subtraction | |
alu_result, carry_out, signed_overflow = binary_add(num1, num2, negate_B=True) | |
signed_alu_result = convert_to_signed(alu_result) | |
uint_result = num1 - num2 | |
should_have_unsigned_overflow = uint_result < 0 | |
expected_carry_out = uint_result >= 0 | |
if (uint_result & ((1 << NUM_BITS)- 1)) == alu_result and (expected_carry_out == (get_bit(uint_result, NUM_BITS) == 1)): | |
print(f"UNSIGNED SUBTRACTION WRONG! Num1: {num1:04b} ({num1}), Num2: {num2:04b} ({num2}), ALU result: {alu_result} [Cout = {carry_out}], correct result: {uint_result} [Cout = {expected_carry_out}]") | |
# get the numbers interpreted as signed numbers | |
signed_num1 = convert_to_signed(num1) | |
signed_num2 = convert_to_signed(num2) | |
int_result = signed_num1 - signed_num2 | |
# from textbook section 3.2 | |
should_have_signed_overflow = ((signed_num1 >= 0 and signed_num2 < 0 and signed_alu_result < 0) or | |
(signed_num1 < 0 and signed_num2 >= 0 and signed_alu_result >= 0)) | |
if should_have_signed_overflow and not signed_overflow: | |
print(f"SIGNED SUBTRACTION FAILED TO DETECT OVERFLOW! Num1: {np.binary_repr(signed_num1, width=NUM_BITS)} ({signed_num1}), Num2: {np.binary_repr(signed_num2, width=NUM_BITS)} ({signed_num2}), ALU result: {signed_alu_result}, correct result: {int_result}") | |
elif signed_alu_result != int_result and not signed_overflow: | |
print(f"SIGNED SUBTRACTION WRONG! Num1: {np.binary_repr(signed_num1, width=NUM_BITS)} ({signed_num1}), Num2: {np.binary_repr(signed_num2, width=NUM_BITS)} ({signed_num2}), ALU result: {signed_alu_result}, correct result: {int_result}.") | |
elif signed_overflow and not should_have_signed_overflow: | |
print(f"SIGNED SUBTRACTION INCORRECTLY DETECTED OVERFLOW! Num1: {np.binary_repr(signed_num1, width=NUM_BITS)} ({signed_num1}), Num2: {np.binary_repr(signed_num2, width=NUM_BITS)} ({signed_num2}), ALU result: {signed_alu_result}, correct result: {int_result}") | |
print("All tests finished.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment