Exemple #1
0
        cin: random.choice([0, 1])
        })
sim_trace.render_trace(symbol_len=5, segment_size=5)


# ---- Exporting to Verilog ----

# However, not only do we want to have a method to import from Verilog, we also
# want a way to export it back out to Verilog as well. To demonstrate PyRTL's
# ability to export in Verilog, we will create a sample 3-bit counter. However
# unlike the example in example2, we extend it to be synchronously resetting.

pyrtl.reset_working_block()

zero = pyrtl.Input(1, 'zero')
counter_output = pyrtl.Output(3, 'counter_output')
counter = pyrtl.Register(3, 'counter')
counter.next <<= pyrtl.mux(zero, counter + 1, 0)
counter_output <<= counter

# The counter gets 0 in the next cycle if the "zero" signal goes high, otherwise just
# counter + 1.  Note that both "0" and "1" are bit extended to the proper length and
# here we are making use of that native add operation.  Let's dump this bad boy out
# to a verilog file and see what is looks like (here we are using StringIO just to
# print it to a string for demo purposes, most likely you will want to pass a normal
# open file).

print("--- PyRTL Representation ---")
print(pyrtl.working_block())
print()
 def setUp(self):
     pyrtl.reset_working_block()
     self.bitwidth = 3
     self.r = pyrtl.Register(bitwidth=self.bitwidth)
     self.output = pyrtl.Output(bitwidth=self.bitwidth, name='r')
     self.output <<= self.r
 def setUp(self):
     pyrtl.reset_working_block()
     self.output = pyrtl.Output(name='r')
Exemple #4
0
# Our goal in this exercise is to implement a simplified 1-bit ALU
# that has 2 data inputs: {a, b}, 2 outputs: {r, cout},
# and compute one of the following 3 functions: r = a and b,
# r = a xnor b, and cout, r = a + b

import pyrtl

# Declare two 1-bit data inputs: a, b
a = pyrtl.Input(bitwidth=1, name='a')
b = pyrtl.Input(bitwidth=1, name='b')

# Declare two 1-bit outputs: r, cout
r = pyrtl.Output(bitwidth=1, name='r')
cout = pyrtl.Output(bitwidth=1, name='cout') 

# Declare control inputs
op = pyrtl.Input(bitwidth=2, name='op')

def half_adder(a, b):
    """
        ha_carry_out, ha_sum = a + b
    """
    ha_sum = a ^ b
    ha_carry_out = a & b# < add your code here >
    return ha_sum, ha_carry_out


def alu (a, b, op):
    """
        Implementation of the desired simplified ALU:
        if op == 0: return a and b
Exemple #5
0
                      romdata=gm11_data,
                      asynchronous=True)
GM13 = pyrtl.RomBlock(bitwidth=8,
                      addrwidth=8,
                      romdata=gm13_data,
                      asynchronous=True)
GM14 = pyrtl.RomBlock(bitwidth=8,
                      addrwidth=8,
                      romdata=gm14_data,
                      asynchronous=True)

_inv_gal_mult_dict = {9: GM9, 11: GM11, 13: GM13, 14: GM14}

# Hardware build.
aes_ciphertext = pyrtl.Input(bitwidth=128, name='aes_ciphertext')
aes_key = pyrtl.Input(bitwidth=128, name='aes_key')
aes_plaintext = pyrtl.Output(bitwidth=128, name='aes_plaintext')
aes_plaintext <<= aes_decryption(aes_ciphertext, aes_key)

sim_trace = pyrtl.SimulationTrace(
    wirevector_subset=[aes_ciphertext, aes_key, aes_plaintext])
sim = pyrtl.Simulation(tracer=sim_trace)

for cycle in range(1):
    sim.step({
        aes_ciphertext: 0x66e94bd4ef8a2c3b884cfa59ca342b2e,
        aes_key: 0x0
    })

sim_trace.render_trace(symbol_len=40, segment_size=1)

def coinc(a, b, d):
    assert isinstance(d, int)
    assert (d >= 0)
    tmp1 = min(a, b)
    tmp2 = max(a, b)
    tmp3 = delta(tmp1, d)
    out = inhibit(tmp2, tmp3)
    return out


# hardware

in1, in2 = (pyrtl.Input(1, "in" + str(x)) for x in range(1, 3))
out = pyrtl.Output(1, "out")

out <<= coinc(in1, in2, 3)

# simulation

in1_vals = [0, 0, 0, 0, 0, 0, 1, 1, 1, 1]
in2_vals = [0, 0, 1, 1, 1, 1, 1, 1, 1, 1]

sim_trace = pyrtl.SimulationTrace()
sim = pyrtl.Simulation(tracer=sim_trace)
for cycle in range(len(in1_vals)):
    sim.step({'in1': in1_vals[cycle], 'in2': in2_vals[cycle]})

sim_trace.render_trace()
Exemple #7
0
sample_instructions = [201326592, 286326786, 4202528, 2366177284]
mem = pyrtl.RomBlock(bitwidth=32,
                     addrwidth=2,
                     romdata=sample_instructions,
                     max_read_ports=1)

# variable counter will serve as an address in this example
counter = pyrtl.Register(bitwidth=2)
counter.next <<= counter + 1

# read data stored in rom
data = pyrtl.WireVector(bitwidth=32, name='data')
data <<= mem[counter]

# output data
op = pyrtl.Output(bitwidth=6, name='op')
rs = pyrtl.Output(bitwidth=5, name='rs')
rt = pyrtl.Output(bitwidth=5, name='rt')
rd = pyrtl.Output(bitwidth=5, name='rd')
sh = pyrtl.Output(bitwidth=5, name='sh')
func = pyrtl.Output(bitwidth=6, name='func')
imm = pyrtl.Output(bitwidth=16, name='imm')
addr = pyrtl.Output(bitwidth=26, name='addr')

### ADD YOUR INSTRUCTION DECODE LOGIC HERE ###
op <<= data[-6:]
rs <<= data[21:26]
rt <<= data[16:21]
rd <<= data[11:16]
sh <<= data[6:11]
func <<= data[0:6]
### Testing ###

# List of input values
test_din = [5, 2, 4]

# Create input wirevectors and assign the corresponding race values to them
sim_dict = {}
din_wv = []
for i, val in enumerate(test_din):
    locals()["din" + str(i)] = pyrtl.Input(bitwidth=1, name=str("din%d" % i))
    sim_dict[str("din%d" % i)] = race_testval(val).next
    din_wv.append(locals()["din" + str(i)])

# Create output wirevectors
inh_out_case0 = pyrtl.Output(bitwidth=1, name="inh(din1,din0)_out")
inh_out_case1 = pyrtl.Output(bitwidth=1, name="inh(din0,din1)_out")
max_out = pyrtl.Output(bitwidth=1, name="max_out")
min_out = pyrtl.Output(bitwidth=1, name="min_out")
add_const_out = pyrtl.Output(bitwidth=1, name="add_const_out")

# Call functions
inh_out_case0 <<= inhibit_rl(din1, din0)  # controlling input: din1
inh_out_case1 <<= inhibit_rl(din0, din1)  # controlling input: din0
max_out <<= max_rl(din_wv)
min_out <<= min_rl(din_wv)
add_const_out <<= add_const_rl(din0, 3)  # add k=3

# Simulate
sim_trace = pyrtl.SimulationTrace()
sim = pyrtl.Simulation(tracer=sim_trace)
Exemple #9
0
 def setUp(self):
     pyrtl.reset_working_block()
     self.in1, self.in2 = (pyrtl.Input(8, "in" + str(i))
                           for i in range(1, 3))
     self.out = pyrtl.Output(9, "out")
Exemple #10
0
import pyrtl

a = pyrtl.Input(1, "a")
b = pyrtl.Input(1, "b")

c = pyrtl.Output(1, "out")

wire = a & b
c <<= wire

d = pyrtl.Output(2, "concat")

d <<= pyrtl.concat(a, b)

sim = pyrtl.Simulation(tracer=pyrtl.SimulationTrace())

import random

sim_ins = {a: 0, b: 1}

sim.step(sim_ins)

for cycle in range(15):
    sim.step({
        a: random.choice([0, 1]),
        b: random.choice([0, 1]),
        # c: random.choice([0, 1])
    })

sim.tracer.render_trace(symbol_len=5, segment_size=5)
Exemple #11
0
# -*- coding: utf-8 -*-

import pyrtl

pyrtl.set_debug_mode(debug=True)

DATA_WIDTH = 8
ADDR_WIDTH = 8
RAM_DEPTH = 1 << 8

address = pyrtl.Input(ADDR_WIDTH, "address")
cs = pyrtl.Input(1, "cs")
we = pyrtl.Input(1, "we")
oe = pyrtl.Input(1, "oe")
data_in = pyrtl.Input(DATA_WIDTH, "data_in")
data_out = pyrtl.Output(DATA_WIDTH, "data_out")

mem = pyrtl.memory.MemBlock(RAM_DEPTH, ADDR_WIDTH,
                            name="mem", asynchronous=True)
mem[address] <<= pyrtl.MemBlock.EnabledWrite(data_in, we & cs)

data_out_wire = pyrtl.wire.WireVector(DATA_WIDTH, "DATA_WIDTH")

with pyrtl.conditional_assignment:
    with cs:
        with we:
            pass
        with pyrtl.otherwise:
            with oe:
                data_out_wire |= mem[address]
import pyrtl

# "pin" input/outputs
a = pyrtl.Input(8, 'a')
b = pyrtl.Input(8, 'b')
q = pyrtl.Output(8, 'q')
gt5 = pyrtl.Output(1, 'gt5')

sum = a + b  # makes an 8-bit adder
q <<= sum  # assigns output of adder to out pin
gt5 <<= sum > 5  # does a comparison, assigns that to different pin

# the simulation and waveform output
sim = pyrtl.Simulation()
sim.step_multiple({'a': [0, 1, 2, 3, 4], 'b': [2, 2, 3, 3, 4]})
sim.tracer.render_trace()
Exemple #13
0
 def setUp(self):
     pyrtl.reset_working_block()
     a, b = pyrtl.input_list('a/4 b/4')
     o = pyrtl.Output(5, 'o')
     o <<= a + b
Exemple #14
0
def routput(name=None):
    return pyrtl.Output(bitwidth=1, name=name)
        self.BBS[BBSind] = ~branch_outcome & 1
        #print("PHT", self.PHT[PHTind])


# Parameters
PHT_size = 1024
BBS_size = 4096
PHT_bitwidth = int(math.log(PHT_size, 2))
BBS_bitwidth = int(math.log(BBS_size, 2))
BHR_bitwidth = PHT_bitwidth
PHT_mask = pyrtl.Const(PHT_size - 1)
BBS_mask = pyrtl.Const(BBS_size - 1)

# Define Inputs and Outputs
pc_i, outcome_i = pyrtl.Input(32, 'pc'), pyrtl.Input(1, 'outcome')
prediction_o = pyrtl.Output(1, 'prediction')

# PyRTL description of the Agree Predictor
BHR_r = pyrtl.Register(bitwidth=BHR_bitwidth, name='BHR_r')
PHT_m = pyrtl.MemBlock(bitwidth=2,
                       addrwidth=PHT_bitwidth,
                       name='PHT_table',
                       asynchronous=True)
BBS_m = pyrtl.MemBlock(bitwidth=1,
                       addrwidth=BBS_bitwidth,
                       name='BBS_table',
                       asynchronous=True)

pc_shift_right_2bits = pc_i[-30:]
PHT_ind = pyrtl.WireVector(bitwidth=PHT_bitwidth, name='PHT_ind')
PHT_ind <<= (pc_shift_right_2bits ^ BHR_r) & PHT_mask
Exemple #16
0
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import pyrtl

chance = pyrtl.Input(4, "chance")
gene = pyrtl.Input(4, "gene")
out = pyrtl.Output(2, "out")

mutation_state = pyrtl.Register(2, "mutation_state")
NEUTRAL, GOOD, BAD = [pyrtl.Const(x, bitwidth=2) for x in range(3)]
with pyrtl.conditional_assignment:
    with chance == gene:
        mutation_state.next |= GOOD
    with chance == gene - 1:
        mutation_state.next |= BAD
    with pyrtl.otherwise:
        mutation_state.next |= NEUTRAL

out <<= mutation_state

# Setup the simulation
sim_trace = pyrtl.SimulationTrace([chance, gene, out])
sim = pyrtl.FastSimulation(tracer=sim_trace)
Exemple #17
0
#         'c': random.choice([0, 1])
#         })

reg_vec = [pyrtl.Register(32) for i in range(0, 8)]
inputs = [pyrtl.Input(32, 'input_{}'.format(i)) for i in range(0, 8)]
test_dict = {
    'input_0': 3,
    'input_1': -39 & 0xFFFFFFFF,
    'input_2': 17,
    'input_3': 7,
    'input_4': -42 & 0xFFFFFFFF,
    'input_5': -18 & 0xFFFFFFFF,
    'input_6': 37,
    'input_7': -6 & 0xFFFFFFFF
}
output_orig = [pyrtl.Output(32, 'out_orig_{}'.format(i)) for i in range(0, 8)]
output_relu = [pyrtl.Output(32, 'out_relu_{}'.format(i)) for i in range(0, 8)]

for index, reg in enumerate(reg_vec):
    # inputs[index] <<= test_dict[index]
    reg.next <<= inputs[index]
    output_orig[index] <<= reg
relu_func_out = relu(reg_vec)
for i, index in enumerate(output_relu):
    index <<= relu_func_out[i]

sim_trace = pyrtl.SimulationTrace()
sim = pyrtl.Simulation(tracer=sim_trace)

for cycle in range(35):
    sim.step(test_dict)
Exemple #18
0
from __future__ import division
import pyrtl
a, b = pyrtl.Input(1, 'a'), pyrtl.Input(1, 'b')
out_a, out_b = (pyrtl.Output(1, 'out_' + i) for i in ("a", "b"))

parity = a ^ b
out_a <<= parity ^ a
out_b <<= parity ^ b

trace = pyrtl.SimulationTrace()
sim = pyrtl.Simulation(tracer=trace)

for i in range(4):
    a_in = i % 2
    b_in = i // 2
    sim.step({a: a_in, b: b_in})
    # print("a = {}, b = {}".format(a_in, b_in))
    assert(a_in == sim.inspect(out_b))
    assert(b_in == sim.inspect(out_a))


trace.render_trace()

# b = a ^ b   # aka b_inter
# out_a = a ^b_inter
# out_b = out_a ^ b_inter


Exemple #19
0
import os, sys

sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'base'))
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)
Exemple #20
0
 def test_log_op_output(self):
     o = pyrtl.Output(1)
     w = pyrtl.WireVector(1)
     with self.assertRaises(pyrtl.PyrtlInternalError):
         x = w & o
    and will be demonstrated here.
"""

import pyrtl
from pyrtl.analysis import estimate

# --- Part 1: Timing Analysis ------------------------------------------------

# Timing and area usage are key considerations of any hardware block that one
# makes. PyRTL provides functions to do these operations.

# Creating a sample hardware block
pyrtl.reset_working_block()
const_wire = pyrtl.Const(6, bitwidth=4)
in_wire2 = pyrtl.Input(bitwidth=4, name="input2")
out_wire = pyrtl.Output(bitwidth=5, name="output")
out_wire <<= const_wire + in_wire2

# Now we will do the timing analysis as well as print out the critical path

# Generating timing analysis information
print("Pre Synthesis:")
timing = estimate.TimingAnalysis()
timing.print_max_length()

# We are also able to print out the critical paths as well as get them
# back as an array.
critical_path_info = timing.critical_path()

# --- Part 2: Area Analysis --------------------------------------------------
Exemple #22
0
 def test_slice_output(self):
     o = pyrtl.Output(2)
     with self.assertRaises(pyrtl.PyrtlInternalError):
         x = o[0]
Exemple #23
0
    def test_super_stress_test(self):
        allin = [pyrtl.Input(1, n) for n in 'abxyijkmzcd']
        a, b, x, y, i, j, k, m, z, c, d = allin
        allout = [pyrtl.Output(4, 'var' + str(index)) for index in range(5)]
        var0, var1, var2, var3, var4 = allout
        """ 
         1  with a:  # a
         2  with b:  # not(a) and b
         3      with x:  # not(a) and b and x
         4      with otherwise:  # not(a) and b and not(x)
         5      with y:  # not(a) and b and y;  check(3,4)
         6          with i:  # not(a) and b and y and i;  check(3,4)
         7          with j:  # not(a) and b and y and not(i) and j;  check(3,4)
         8          with otherwise:  # not(a) and b and y and not(i) and not(j):  check(3,4)
         9          with k:  # not(a) and b and y and k;  check(3,4,6,7,8)
         8          with otherwise:  # not(a) and b and y and not(k):  check(?)
        10          with m:  # not(a) and b and y and m;  check(?)
        11  with otherwise:  #not(a) and not(b)     
        12      with z: #not(a) and not(b) and z
        13  with c:  #c;  check(1,2,3,4,5,6,7,8,9,10,11,12)
        14  with d:  #not(c) and d;  check(1,2,3,4,5,6,7,8,9,10,11,12)
        """

        with pyrtl.conditional_assignment:
            with a:
                var0 |= 1
            with b:
                with x:
                    var0 |= 2
                with pyrtl.otherwise:
                    var0 |= 3

                with y:
                    with i:
                        var1 |= 1
                    with j:
                        var1 |= 2
                    with pyrtl.otherwise:
                        var1 |= 3

                    with k:
                        var2 |= 1
                    with pyrtl.otherwise:
                        var2 |= 2

                    with m:
                        var3 |= 3

            with pyrtl.otherwise:
                with z:
                    var0 |= 4

            with c:
                var4 |= 1
            with d:
                var4 |= 2

        sim_trace = pyrtl.SimulationTrace()
        sim = pyrtl.FastSimulation(tracer=sim_trace)
        for cycle in range(2**len(allin)):
            inputs = {v: 0x1 & (cycle >> i) for i, v in enumerate(allin[::-1])}
            sim.step(inputs)

        for cycle in range(len(sim_trace)):
            t0, t1, t2, t3, t4 = 0, 0, 0, 0, 0

            def v(var):
                return sim_trace.trace[var][cycle]

            if v(a):
                t0 = 1
            elif v(b):
                if v(x):
                    t0 = 2
                else:
                    t0 = 3
                if v(y):
                    if v(i):
                        t1 = 1
                    elif v(j):
                        t1 = 2
                    else:
                        t1 = 3
                    if v(k):
                        t2 = 1
                    else:
                        t2 = 2
                    if v(m):
                        t3 = 3
            else:
                if v(z):
                    t0 = 4
            if v(c):
                t4 = 1
            elif v(d):
                t4 = 2
            self.assertEqual(v(var0), t0)
            self.assertEqual(v(var1), t1)
            self.assertEqual(v(var2), t2)
            self.assertEqual(v(var3), t3)
            self.assertEqual(v(var4), t4)
 def setUp(self):
     pyrtl.reset_working_block()
     self.in1 = pyrtl.Input(8, "in1")
     self.in2 = pyrtl.Input(8, "in2")
     self.out = pyrtl.Output(16, "out")
Exemple #25
0
def fib(first, second):
    a = pyrtl.Register(bitwidth=32, name='a')
    b = pyrtl.Register(bitwidth=32, name='b')
    return_val = pyrtl.WireVector(bitwidth=32, name='return_val')
    with pyrtl.conditional_assignment:
        with a == 0:
            with b == 0:
                a.next |= first
                b.next |= second
                return_val |= first
        with pyrtl.otherwise:
            a.next |= b
            b.next |= a + b
            return_val |= b

    return return_val


A = pyrtl.Input(bitwidth=32, name='A')
B = pyrtl.Input(bitwidth=32, name='B')
result = pyrtl.Output(bitwidth=32, name='result')
result <<= fib(A, B)

sim_trace = pyrtl.SimulationTrace()
sim = pyrtl.Simulation(tracer=sim_trace)
for cycle in range(16):
    sim.step({'A': 1, 'B': 2})

sim_trace.render_trace()
Exemple #26
0
    a, b = pyrtl.match_bitwidth(a, b)
    # this function is a function that allows us to match the bitwidth of multiple
    # different wires. By default, it zero extends the shorter bits
    if len(a) == 1:
        sumbits, carry_out = one_bit_add(a, b, carry_in)
    else:
        lsbit, ripplecarry = one_bit_add(a[0], b[0], carry_in)
        msbits, carry_out = ripple_add(a[1:], b[1:], ripplecarry)
        sumbits = pyrtl.concat(msbits, lsbit)
    return sumbits, carry_out


# Inputs and outputs of the module
load = pyrtl.Input(1, 'load')
data = pyrtl.Input(8, 'data')
out = pyrtl.Output(8, 'out')

# Simple logic to allow loading of the counter
counter = pyrtl.Register(8, 'counter')
sum, carry_out = ripple_add(counter, pyrtl.Const("1'b1"))
counter.next <<= pyrtl.mux(load, sum, data)
out <<= counter

# Setup the simulation
sim_trace = pyrtl.SimulationTrace([load, data, out])
sim = pyrtl.Simulation(tracer=sim_trace)
# Run until receive a 'q' from the named pipe
while True:
    cmd = os.read(inFifo, 3)
    if cmd != '':
        if cmd == 'q':
Exemple #27
0
    def test_adder(self):
        inwire1, inwire2 = pyrtl.Input(bitwidth=3), pyrtl.Input(bitwidth=3)
        outwire = pyrtl.Output(bitwidth=4)

        outwire <<= inwire1 + inwire2
        self.everything_t_procedure()
Exemple #28
0
b = pyrtl.Input(bitwidth=1, name='b')
c = pyrtl.Input(bitwidth=1, name='c')
d = pyrtl.Input(bitwidth=1, name='d')
e = pyrtl.Input(bitwidth=1, name='e')

# Declare control inputs
# < add your code here >

s = pyrtl.Input(bitwidth=3, name='s')
#s1 = pyrtl.Input(bitwidth=1, name='s1')
#s2 = pyrtl.Input(bitwidth=1, name='s2')

# Declare outputs
# < add your code here >

o = pyrtl.Output(bitwidth=1, name='o')

# Describe your 5:1 MUX implementation
# < add your code here >

sel0 = s[2]
sel1 = s[1]
sel2 = s[0]

temp1 = ((~sel0) & (~sel1) & (~sel2)) & a
temp2 = ((~sel0) & (~sel1) & (sel2)) & b
temp3 = ((~sel0) & (sel1) & (~sel2)) & c
temp4 = ((~sel0) & (sel1) & (sel2)) & d
temp5 = ((sel0) & (~sel1) & (~sel2)) & e

o <<= temp1 | temp2 | temp3 | temp4 | temp5
Exemple #29
0
 def test_assign_output(self):
     o = pyrtl.Output(1)
     w = pyrtl.WireVector(1)
     with self.assertRaises(pyrtl.PyrtlInternalError):
         w <<= o
Exemple #30
0
""" Example 3:  A State Machine built with ConditionalUpdate

    In this example we describe how ConditionalUpdate works in the context of
    a vending machine that will dispense an item when it has received 4 tokens.
    If a refund is requested, it returns the tokens.
"""

import pyrtl

token_in = pyrtl.Input(1, 'token_in')
req_refund = pyrtl.Input(1, 'req_refund')
dispense = pyrtl.Output(1, 'dispense')
refund = pyrtl.Output(1, 'refund')
state = pyrtl.Register(3, 'state')

# First new step, let's enumerate a set of constant to serve as our states
WAIT, TOK1, TOK2, TOK3, DISPENSE, REFUND = [
    pyrtl.Const(x, bitwidth=3) for x in range(6)
]

# Now we could build a state machine using just the registers and logic discussed
# in the earlier examples, but doing operations *conditional* on some input is a pretty
# fundamental operation in hardware design.  PyRTL provides a class "ConditionalUpdate"
# to provide a predicated update to a registers, wires, and memories.
#
# Conditional assignments are specified with a "|=" instead of a "<<=" operator.  The
# conditional assignment is only value in the context of a condition, and update to those
# values only happens when that condition is true.  In hardware this is implemented
# with a simple mux -- for people coming from software it is important to remember that this
# is describing a big logic function NOT an "if-then-else" clause.  All of these things will
# execute straight through when "build_everything" is called.  More comments after the code.