class AddressEncoder():
"""Address Encoder
-
- The purpose of this module is to take in a vector and
+
+ The purpose of this module is to take in a vector and
encode the bits that are one hot into an address. This module
combines both nmigen's Encoder and PriorityEncoder and will state
whether the input line has a single bit hot, multiple bits hot,
- or no bits hot. The output line will always have the lowest value
+ or no bits hot. The output line will always have the lowest value
address output.
-
+
Usage:
The output is valid when either single or multiple match is high.
Otherwise output is 0.
# Internal
self.encoder = Encoder(width)
self.p_encoder = PriorityEncoder(width)
-
+
# Input
self.i = Signal(width)
-
+
# Output
self.single_match = Signal(1)
self.multiple_match = Signal(1)
def elaborate(self, platform=None):
m = Module()
-
+
# Add internal submodules
m.submodules.encoder = self.encoder
m.submodules.p_encoder = self.p_encoder
-
+
m.d.comb += [
self.encoder.i.eq(self.i),
self.p_encoder.i.eq(self.i)
]
-
+
# If the priority encoder recieves an input of 0
- # If n is 1 then the output is not valid
+ # If n is 1 then the output is not valid
with m.If(self.p_encoder.n):
m.d.comb += [
self.single_match.eq(0),
m.d.comb += [
self.single_match.eq(0),
self.multiple_match.eq(1)
- ]
+ ]
# Single Match if encoder n is valid
with m.Else():
m.d.comb += [
self.single_match.eq(1),
self.multiple_match.eq(0)
- ]
- # Always set output based on priority encoder output
+ ]
+ # Always set output based on priority encoder output
m.d.comb += self.o.eq(self.p_encoder.o)
- return m
\ No newline at end of file
+ return m
class VectorAssembler():
""" Vector Assembler
-
+
The purpose of this module is to take a generic number of inputs
- and cleanly combine them into one vector. While this is very much
+ and cleanly combine them into one vector. While this is very much
possible through raw code it may result in a very unfortunate sight
- in a yosys graph. Thus this class was born! No more will ugly loops
- exist in my graphs! Get outta here ya goddam Lochness Monster.
+ in a yosys graph. Thus this class was born! No more will ugly loops
+ exist in my graphs! Get outta here ya goddam Lochness Monster.
"""
def __init__(self, width):
""" Arguments:
* width: (bit count) The desiered size of the output vector
-
+
"""
# Internal
self.width = width
-
+
# Input
self.input = Array(Signal(1) for index in range(width))
-
+
# Output
self.o = Signal(width)
-
+
def elaborate(self, platform=None):
m = Module()
for index in range(self.width):
m.d.comb += self.o[index].eq(self.input[index])
-
- return m
\ No newline at end of file
+
+ return m
def set_encoder(dut, i):
yield dut.i.eq(i)
yield
-
+
# Checks the single match of the AddressEncoder
# Arguments:
# dut: The AddressEncoder being tested
def check_single_match(dut, sm, op):
out_sm = yield dut.single_match
assert_op("Single Match", out_sm, sm, op)
-
+
# Checks the multiple match of the AddressEncoder
# Arguments:
# dut: The AddressEncoder being tested
# mm (Multiple Match): The expected match result
-# op (Operation): (0 => ==), (1 => !=)
+# op (Operation): (0 => ==), (1 => !=)
def check_multiple_match(dut, mm, op):
out_mm = yield dut.multiple_match
assert_op("Multiple Match", out_mm, mm, op)
-
+
# Checks the output of the AddressEncoder
# Arguments:
# dut: The AddressEncoder being tested
output = 0
yield from set_encoder(dut, input)
yield from check_all(dut, single_match, multiple_match, output, 0, 0, 0)
-
+
# Check single bit
input = 1
single_match = 1
multiple_match = 0
output = 0
yield from set_encoder(dut, input)
- yield from check_all(dut, single_match, multiple_match, output, 0, 0, 0)
-
+ yield from check_all(dut, single_match, multiple_match, output, 0, 0, 0)
+
# Check another single bit
input = 4
single_match = 1
multiple_match = 0
output = 2
yield from set_encoder(dut, input)
- yield from check_all(dut, single_match, multiple_match, output, 0, 0, 0)
-
+ yield from check_all(dut, single_match, multiple_match, output, 0, 0, 0)
+
# Check multiple match
# We expected the lowest bit to be returned which is address 0
input = 5
multiple_match = 1
output = 0
yield from set_encoder(dut, input)
- yield from check_all(dut, single_match, multiple_match, output, 0, 0, 0)
-
+ yield from check_all(dut, single_match, multiple_match, output, 0, 0, 0)
+
# Check another multiple match
# We expected the lowest bit to be returned which is address 1
input = 6
multiple_match = 1
output = 1
yield from set_encoder(dut, input)
- yield from check_all(dut, single_match, multiple_match, output, 0, 0, 0)
-
-
+ yield from check_all(dut, single_match, multiple_match, output, 0, 0, 0)
if __name__ == "__main__":
dut = AddressEncoder(4)
run_simulation(dut, testbench(dut), vcd_name="Waveforms/test_address_encoder.vcd")
- print("AddressEncoder Unit Test Success")
\ No newline at end of file
+ print("AddressEncoder Unit Test Success")
input_index = assembler_size - index - 1
yield dut.input[index].eq(input[input_index])
yield
-
+
# Checks the output of the VectorAssembler
# Arguments:
# dut: The VectorAssembler
def check_output(dut, o, op):
out_o = yield dut.o
assert_op("Output", out_o, o, op)
-
+
def testbench(dut):
# Input should but bit readable from left to right
# with Little Endian notation
output = 12
yield from set_assembler(dut, input)
yield from check_output(dut, output, 0)
-
+
input = [1, 1, 0, 1]
output = 13
yield from set_assembler(dut, input)
- yield from check_output(dut, output, 0)
+ yield from check_output(dut, output, 0)
if __name__ == "__main__":
dut = VectorAssembler(assembler_size)
run_simulation(dut, testbench(dut), vcd_name="Waveforms/test_vector_assembler.vcd")
- print("VectorAssembler Unit Test Success")
\ No newline at end of file
+ print("VectorAssembler Unit Test Success")