Example #1
0
def _sparse_adder(wire_array_2, adder):
    result = []
    for single_w_index in range(len(wire_array_2)):
        if len(wire_array_2[single_w_index]) == 2:  # Check if the two wire vectors overlap yet
            break
        result.append(wire_array_2[single_w_index][0])

    import six
    wires_to_zip = wire_array_2[single_w_index:]
    add_wires = tuple(six.moves.zip_longest(*wires_to_zip, fillvalue=pyrtl.Const(0)))
    adder_result = adder(pyrtl.concat_list(add_wires[0]), pyrtl.concat_list(add_wires[1]))
    return pyrtl.concat(adder_result, *reversed(result))
Example #2
0
def _sparse_adder(wire_array_2, adder):
    result = []
    for single_w_index in range(len(wire_array_2)):
        if len(wire_array_2[single_w_index]
               ) == 2:  # Check if the two wire vectors overlap yet
            break
        result.append(wire_array_2[single_w_index][0])

    import six
    wires_to_zip = wire_array_2[single_w_index:]
    add_wires = tuple(
        six.moves.zip_longest(*wires_to_zip, fillvalue=pyrtl.Const(0)))
    adder_result = adder(pyrtl.concat_list(add_wires[0]),
                         pyrtl.concat_list(add_wires[1]))
    return pyrtl.concat(adder_result, *reversed(result))
Example #3
0
def kogge_stone(a, b, cin=0):
    """
    Creates a Kogge-Stone adder given two inputs

    :param a, b: The two Wirevectors to add up (bitwidths don't need to match)
    :param cin: An optimal carry in Wirevector or value
    :return: a Wirevector representing the output of the adder

    The Kogge-Stone adder is a fast tree-based adder with O(log(n))
    propagation delay, useful for performance critical designs. However,
    it has O(n log(n)) area usage, and large fan out.
    """
    a, b = libutils.match_bitwidth(a, b)

    prop_orig = a ^ b
    prop_bits = [i for i in prop_orig]
    gen_bits = [i for i in a & b]
    prop_dist = 1

    # creation of the carry calculation
    while prop_dist < len(a):
        for i in reversed(range(prop_dist, len(a))):
            prop_old = prop_bits[i]
            gen_bits[i] = gen_bits[i] | (prop_old & gen_bits[i - prop_dist])
            if i >= prop_dist * 2:  # to prevent creating unnecessary nets and wires
                prop_bits[i] = prop_old & prop_bits[i - prop_dist]
        prop_dist *= 2

    # assembling the result of the addition
    # preparing the cin (and conveniently shifting the gen bits)
    gen_bits.insert(0, pyrtl.as_wires(cin))
    return pyrtl.concat_list(gen_bits) ^ prop_orig
Example #4
0
 def _sub_bytes(self, in_vector, inverse=False):
     self._build_memories_if_not_exists()
     subbed = [
         self.inv_sbox[byte] if inverse else self.sbox[byte]
         for byte in libutils.partition_wire(in_vector, 8)
     ]
     return pyrtl.concat_list(subbed)
Example #5
0
def kogge_stone(a, b, cin=0):
    """
    Creates a Kogge-Stone adder given two inputs

    :param a, b: The two Wirevectors to add up (bitwidths don't need to match)
    :param cin: An optimal carry in Wirevector or value
    :return: a Wirevector representing the output of the adder

    The Kogge-Stone adder is a fast tree-based adder with O(log(n))
    propagation delay, useful for performance critical designs. However,
    it has O(n log(n)) area usage, and large fan out.
    """
    a, b = libutils.match_bitwidth(a, b)

    prop_orig = a ^ b
    prop_bits = [i for i in prop_orig]
    gen_bits = [i for i in a & b]
    prop_dist = 1

    # creation of the carry calculation
    while prop_dist < len(a):
        for i in reversed(range(prop_dist, len(a))):
            prop_old = prop_bits[i]
            gen_bits[i] = gen_bits[i] | (prop_old & gen_bits[i - prop_dist])
            if i >= prop_dist * 2:  # to prevent creating unnecessary nets and wires
                prop_bits[i] = prop_old & prop_bits[i - prop_dist]
        prop_dist *= 2

    # assembling the result of the addition
    # preparing the cin (and conveniently shifting the gen bits)
    gen_bits.insert(0, pyrtl.as_wires(cin))
    return pyrtl.concat_list(gen_bits) ^ prop_orig
Example #6
0
    def _mix_col_subgroup(self, in_vector, gm_multipliers):
        def _mix_single(index):
            mult_items = [self._galois_mult(a[(index + loc) % 4], mult_table)
                          for loc, mult_table in enumerate(gm_multipliers)]
            return mult_items[0] ^ mult_items[1] ^ mult_items[2] ^ mult_items[3]

        a = libutils.partition_wire(in_vector, 8)
        return pyrtl.concat_list([_mix_single(index) for index in range(len(a))])
Example #7
0
 def _key_expansion(self, old_key, key_expand_round):
     self._build_memories_if_not_exists()
     w = libutils.partition_wire(old_key, 32)
     x = [w[3] ^ self._g(w[0], key_expand_round)]
     x.insert(0, x[0] ^ w[2])
     x.insert(0, x[0] ^ w[1])
     x.insert(0, x[0] ^ w[0])
     return pyrtl.concat_list(x)
Example #8
0
 def _key_expansion(self, old_key, key_expand_round):
     self._build_memories_if_not_exists()
     w = libutils.partition_wire(old_key, 32)
     x = [w[3] ^ self._g(w[0], key_expand_round)]
     x.insert(0, x[0] ^ w[2])
     x.insert(0, x[0] ^ w[1])
     x.insert(0, x[0] ^ w[0])
     return pyrtl.concat_list(x)
Example #9
0
    def test_key_expansion(self):
        # This is not at all correct. Needs to be completely rewritten
        self.out_vector <<= pyrtl.concat_list(self.aes_encrypt._key_gen(self.in_vector))

        in_vals = [0x4c9c1e66f771f0762c3f868e534df256, 0xc57e1c159a9bd286f05f4be098c63439]
        true_result = [0x3bd92268fc74fb735767cbe0c0590e2d, 0xb458124c68b68a014b99f82e5f15554c]
        calculated_result = testingutils.sim_and_ret_out(self.out_vector, (self.in_vector,),
                                                         (in_vals,))
        self.assertEqual(calculated_result, true_result)
Example #10
0
def _sparse_adder(wire_array_2, adder):
    bitwidth = len(wire_array_2)
    add_wires = [], []
    result = []
    for single_w_index in range(bitwidth):
        if len(wire_array_2[single_w_index]) == 2:  # Check if the two wire vectors overlap yet
            break
        result.append(wire_array_2[single_w_index][0])

    for w_loc in range(single_w_index, bitwidth):
        for i in range(2):
            if len(wire_array_2[w_loc]) >= i + 1:
                add_wires[i].append(wire_array_2[w_loc][i])
            else:
                add_wires[i].append(pyrtl.Const(0))

    adder_result = adder(pyrtl.concat_list(add_wires[0]), pyrtl.concat_list(add_wires[1]))
    return pyrtl.concat(adder_result, *reversed(result))
Example #11
0
def _sparse_adder(wire_array_2, adder):
    bitwidth = len(wire_array_2)
    add_wires = [], []
    result = []
    for single_w_index in range(bitwidth):
        if len(wire_array_2[single_w_index]
               ) == 2:  # Check if the two wire vectors overlap yet
            break
        result.append(wire_array_2[single_w_index][0])

    for w_loc in range(single_w_index, bitwidth):
        for i in range(2):
            if len(wire_array_2[w_loc]) >= i + 1:
                add_wires[i].append(wire_array_2[w_loc][i])
            else:
                add_wires[i].append(pyrtl.Const(0))

    adder_result = adder(pyrtl.concat_list(add_wires[0]),
                         pyrtl.concat_list(add_wires[1]))
    return pyrtl.concat(adder_result, *reversed(result))
Example #12
0
    def _mix_col_subgroup(self, in_vector, gm_multipliers):
        def _mix_single(index):
            mult_items = [
                self._galois_mult(a[(index + loc) % 4], mult_table)
                for loc, mult_table in enumerate(gm_multipliers)
            ]
            return mult_items[0] ^ mult_items[1] ^ mult_items[2] ^ mult_items[3]

        a = libutils.partition_wire(in_vector, 8)
        return pyrtl.concat_list(
            [_mix_single(index) for index in range(len(a))])
Example #13
0
 def _g(self, word, key_expand_round):
     """
     One-byte left circular rotation, substitution of each byte
     """
     import numbers
     self._build_memories_if_not_exists()
     a = libutils.partition_wire(word, 8)
     sub = [self.sbox[a[index]] for index in (3, 0, 1, 2)]
     if isinstance(key_expand_round, numbers.Number):
         rcon_data = self._rcon_data[key_expand_round + 1]  # int value
     else:
         rcon_data = self.rcon[key_expand_round + 1]
     sub[3] = sub[3] ^ rcon_data
     return pyrtl.concat_list(sub)
Example #14
0
 def _g(self, word, key_expand_round):
     """
     One-byte left circular rotation, substitution of each byte
     """
     import numbers
     self._build_memories_if_not_exists()
     a = libutils.partition_wire(word, 8)
     sub = [self.sbox[a[index]] for index in (3, 0, 1, 2)]
     if isinstance(key_expand_round, numbers.Number):
         rcon_data = self._rcon_data[key_expand_round + 1]  # int value
     else:
         rcon_data = self.rcon[key_expand_round + 1]
     sub[3] = sub[3] ^ rcon_data
     return pyrtl.concat_list(sub)
Example #15
0
def _trivial_mult(A, B):
    """
    turns a multiplication into an And gate if one of the
    wires is a bitwidth of 1

    :param A:
    :param B:
    :return:
    """
    if len(B) == 1:
        A, B = B, A  # so that we can reuse the code below :)
    if len(A) == 1:
        a_vals = A.sign_extended(len(B))

        # keep the wirevector len consistent
        return pyrtl.concat_list([a_vals & B, pyrtl.Const(0)])
Example #16
0
def _trivial_mult(A, B):
    """
    turns a multiplication into an And gate if one of the
    wires is a bitwidth of 1

    :param A:
    :param B:
    :return:
    """
    if len(B) == 1:
        A, B = B, A  # so that we can reuse the code below :)
    if len(A) == 1:
        a_vals = A.sign_extended(len(B))

        # keep the wirevector len consistent
        return pyrtl.concat_list([a_vals & B, pyrtl.Const(0)])
Example #17
0
    def test_key_expansion(self):
        # This is not at all correct. Needs to be completely rewritten
        self.out_vector <<= pyrtl.concat_list(
            self.aes_encrypt._key_gen(self.in_vector))

        in_vals = [
            0x4c9c1e66f771f0762c3f868e534df256,
            0xc57e1c159a9bd286f05f4be098c63439
        ]
        true_result = [
            0x3bd92268fc74fb735767cbe0c0590e2d,
            0xb458124c68b68a014b99f82e5f15554c
        ]
        calculated_result = testingutils.sim_and_ret_out(
            self.out_vector, (self.in_vector, ), (in_vals, ))
        self.assertEqual(calculated_result, true_result)
Example #18
0
 def _shift_rows(in_vector):
     a = libutils.partition_wire(in_vector, 8)
     return pyrtl.concat_list(
         (a[4], a[9], a[14], a[3], a[8], a[13], a[2], a[7], a[12], a[1],
          a[6], a[11], a[0], a[5], a[10], a[15]))
Example #19
0
 def _mix_columns(self, in_vector, inverse=False):
     self._build_memories_if_not_exists()
     igm_mults = [14, 9, 13, 11] if inverse else [2, 1, 1, 3]
     subgroups = libutils.partition_wire(in_vector, 32)
     return pyrtl.concat_list(
         [self._mix_col_subgroup(sg, igm_mults) for sg in subgroups])
Example #20
0
 def _mix_columns(self, in_vector, inverse=False):
     self._build_memories_if_not_exists()
     igm_mults = [14, 9, 13, 11] if inverse else [2, 1, 1, 3]
     subgroups = libutils.partition_wire(in_vector, 32)
     return pyrtl.concat_list([self._mix_col_subgroup(sg, igm_mults) for sg in subgroups])
Example #21
0
 def _shift_rows(in_vector):
     a = libutils.partition_wire(in_vector, 8)
     return pyrtl.concat_list((a[4], a[9], a[14], a[3],
                               a[8], a[13], a[2], a[7],
                               a[12], a[1], a[6], a[11],
                               a[0], a[5], a[10], a[15]))
Example #22
0
 def _sub_bytes(self, in_vector, inverse=False):
     self._build_memories_if_not_exists()
     subbed = [self.inv_sbox[byte] if inverse else self.sbox[byte]
               for byte in libutils.partition_wire(in_vector, 8)]
     return pyrtl.concat_list(subbed)
Example #23
0
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'racetrees'))
from flat_racetree import FlatRaceTree
from racelogic_sim_input_stimuli import race_testval

### Testing ###

inp_res = 4  # input resolution -- in this case we are using 4-bit inputs
tree_depth = 2  # depth of the tree

# Build
x = pyrtl.Input(bitwidth=1, name='x')
y = pyrtl.Input(bitwidth=1, name='y')
out_bin = pyrtl.Output(bitwidth=tree_depth, name='out_bin')
valid_out = pyrtl.Output(bitwidth=1, name='valid_out')

attributes = pyrtl.concat_list([x, y])  # list of the tree's attributes
tree_nodes = [[2, 0], [1, 0], [1, 1]]  # [threshold, attribute_index]

RT = FlatRaceTree(inp_res, tree_depth, attributes, tree_nodes)

tree_out = RT.tree()
out_bin <<= tree_out[0]
valid_out <<= tree_out[1]

# Simulate
xin, yin = race_testval(2), race_testval(3)
sim_trace = pyrtl.SimulationTrace()
sim = pyrtl.Simulation(tracer=sim_trace)
for cycle in range(2**inp_res + 1):
    sim.step({'x': xin.next(), 'y': yin.next()})
sim_trace.render_trace(symbol_len=5, segment_size=1)