Add AddressEncoder to consolidate encoder modules and hide ugliness
authorDaniel Benusovich <flyingmonkeys1996@gmail.com>
Sat, 9 Mar 2019 02:59:27 +0000 (18:59 -0800)
committerDaniel Benusovich <flyingmonkeys1996@gmail.com>
Sat, 9 Mar 2019 02:59:27 +0000 (18:59 -0800)
TLB/src/AddressEncoder.py [new file with mode: 0644]
TLB/test/test_address_encoder.py [new file with mode: 0644]

diff --git a/TLB/src/AddressEncoder.py b/TLB/src/AddressEncoder.py
new file mode 100644 (file)
index 0000000..c6437fc
--- /dev/null
@@ -0,0 +1,54 @@
+from nmigen import Module, Signal
+from nmigen.lib.coding import Encoder, PriorityEncoder
+
+class AddressEncoder():
+    def __init__(self, width):
+        # 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)
+        self.o = Signal(width)
+        
+    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        
+        with m.If(self.p_encoder.n):
+            m.d.comb += [
+                self.single_match.eq(0),
+                self.multiple_match.eq(0),
+                self.o.eq(0)
+            ]
+        # If the priority encoder recieves an input > 0
+        with m.Else():
+            # Multiple Match if encoder n is invalid
+            with m.If(self.encoder.n):
+                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    
+            m.d.comb += self.o.eq(self.p_encoder.o)
+        return m
\ No newline at end of file
diff --git a/TLB/test/test_address_encoder.py b/TLB/test/test_address_encoder.py
new file mode 100644 (file)
index 0000000..db555e1
--- /dev/null
@@ -0,0 +1,80 @@
+import sys
+sys.path.append("../src")
+sys.path.append("../../TestUtil")
+
+from nmigen.compat.sim import run_simulation
+
+from AddressEncoder import AddressEncoder
+
+from test_helper import assert_eq, assert_ne, assert_op
+
+def set_encoder(dut, i):
+    yield dut.i.eq(i)
+    yield
+    
+def check_single_match(dut, sm, op):
+    out_sm = yield dut.single_match
+    assert_op("Single Match", out_sm, sm, op)
+    
+def check_multiple_match(dut, mm, op):
+    out_mm = yield dut.multiple_match
+    assert_op("Multiple Match", out_mm, mm, op)
+    
+def check_output(dut, o, op):
+    out_o = yield dut.o
+    assert_op("Output", out_o, o, op)
+    
+def check_all(dut, sm, mm, o, sm_op, mm_op, o_op):
+    yield from check_single_match(dut, sm, sm_op)
+    yield from check_multiple_match(dut, mm, mm_op)
+    yield from check_output(dut, o, o_op)
+
+def testbench(dut):
+    # Check invalid input
+    input = 0
+    single_match = 0
+    multiple_match = 0
+    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)   
+    
+    # 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)  
+    
+    # Check multiple match
+    # We expected the lowest bit to be returned which is address 0
+    input = 5
+    single_match = 0
+    multiple_match = 1
+    output = 0
+    yield from set_encoder(dut, input)
+    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
+    single_match = 0
+    multiple_match = 1
+    output = 1
+    yield from set_encoder(dut, input)
+    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