From 2e6d559dce59cf0d39c6dfdeb5dc274e2eb3549e Mon Sep 17 00:00:00 2001
From: Kia <kia@special-circumstanc.es>
Date: Tue, 9 Mar 2021 21:03:00 -0700
Subject: [PATCH] unoptimized_lr/skidbuffer.py

---
 unoptimized_lr/skidbuffer.py | 164 +++++++++++++++++++++++++++++++++++
 1 file changed, 164 insertions(+)
 create mode 100755 unoptimized_lr/skidbuffer.py

diff --git a/unoptimized_lr/skidbuffer.py b/unoptimized_lr/skidbuffer.py
new file mode 100755
index 0000000..33cde80
--- /dev/null
+++ b/unoptimized_lr/skidbuffer.py
@@ -0,0 +1,164 @@
+from nmigen import *
+from nmigen.cli import main
+
+
+class NonRegisteredSkidBuffer(Elaboratable): # non-registered
+        def __init__(self, width):
+            self.width = width
+
+            self.upstream_valid_in =    Signal(1)
+            self.upstream_ready_out =   Signal(1)
+            self.upstream_data_in =     Signal(self.width)
+
+            self.downstream_valid_out = Signal(1)
+            self.downstream_ready_in =  Signal(1)
+            self.downstream_data_out =  Signal(self.width)
+
+        def elaborate(self, platform):
+            m = Module()
+
+            skid_buffer = Signal(self.width)
+            skid_buffer_frozen = Signal(1)
+
+            # we signal ready to upstream if and only if the skid buffer is empty
+            m.d.comb += self.upstream_ready_out.eq(~skid_buffer_frozen)
+
+
+            # should we capture a value in the skid buffer?
+            # we should if upstream has data for us *and* downstream cannot accept
+
+            # If we want to fill our skid buffer, we need:
+            # 1. valid input data       (upstream_valid_in   == 1)
+            # 2. a buffer that is empty (skid_buffer_frozen  == 0)
+            # 3. stalled downstream     (downstream_ready_in == 0)
+
+            with m.If(self.upstream_valid_in & (~skid_buffer_frozen)  & (~self.downstream_ready_in)):
+                m.d.sync += skid_buffer_frozen.eq(1)
+
+            # if downstream is accepting data again, we will flush our skid buffer
+            with m.If(self.downstream_ready_in == 1):
+                m.d.sync += skid_buffer_frozen.eq(0)
+
+
+            m.d.comb += self.downstream_valid_out.eq(self.upstream_valid_in | skid_buffer_frozen)
+
+
+            # data path
+
+            # always clock data into the skid buffer as long as the buffer isn't frozen
+
+            with m.If(skid_buffer_frozen == 0):
+                m.d.sync += skid_buffer.eq(self.upstream_data_in)
+
+            with m.If(skid_buffer_frozen == 1):
+                m.d.comb += self.downstream_data_out.eq(skid_buffer)
+
+            # NON registered
+            with m.Elif(self.upstream_valid_in == 1):
+                m.d.comb += self.downstream_data_out.eq(self.upstream_data_in)
+
+            return m
+
+
+
+class RegisteredSkidBuffer(Elaboratable): # registered
+        def __init__(self, width):
+            self.width = width
+
+            self.upstream_valid_in =    Signal(1)
+            self.upstream_ready_out =   Signal(1)
+            self.upstream_data_in =     Signal(self.width)
+
+            self.downstream_valid_out = Signal(1)
+            self.downstream_ready_in =  Signal(1)
+            self.downstream_data_out =  Signal(self.width)
+
+        def elaborate(self, platform):
+            m = Module()
+
+            skid_buffer = Signal(self.width)
+            skid_buffer_frozen = Signal(1)
+
+            # we signal ready to upstream if and only if the skid buffer is empty
+            m.d.comb += self.upstream_ready_out.eq(~skid_buffer_frozen)
+
+
+            # should we capture a value in the skid buffer?
+            # we should if upstream has data for us *and* downstream cannot accept
+
+            # If we want to fill our skid buffer, we need:
+            # 1. valid input data       (upstream_valid_in   == 1)
+            # 2. a buffer that is empty (skid_buffer_frozen  == 0)
+            # 3. stalled downstream     (downstream_ready_in == 0) & (downstream_valid_out == 1)
+
+            with m.If(self.upstream_valid_in & (~skid_buffer_frozen)  & (~self.downstream_ready_in) & (self.downstream_valid_out)):
+                m.d.sync += skid_buffer_frozen.eq(1)
+
+            # if downstream is accepting data again, we will flush our skid buffer
+            with m.If(self.downstream_ready_in == 1):
+                m.d.sync += skid_buffer_frozen.eq(0)
+
+
+            # Stalled == (downstream_ready_in == 0 & downstream_valid_out == 1)
+            # so not stalled = !(downstream_ready_in == 0 & downstream_valid_out == 1)
+            #    = downstream_ready_in == 1 | downstream_valid_out == 0
+            # by de Morgan
+
+            with m.If((self.downstream_ready_in) | (~self.downstream_valid_out)):
+                m.d.sync += self.downstream_valid_out.eq(self.upstream_valid_in | skid_buffer_frozen)
+
+            # data path
+
+            # always clock data into the skid buffer as long as the buffer isn't filled
+
+            with m.If(skid_buffer_frozen == 0):
+                m.d.sync += skid_buffer.eq(self.upstream_data_in)
+
+            # not stalled condition
+            with m.If((self.downstream_ready_in) | (~self.downstream_valid_out)):
+                with m.If(skid_buffer_frozen == 1):
+                    m.d.sync += self.downstream_data_out.eq(skid_buffer)
+                with m.Elif(self.upstream_valid_in == 1):
+                    m.d.sync += self.downstream_data_out.eq(self.upstream_data_in)
+
+            return m
+
+
+
+
+class DummyPlug(Elaboratable):
+    def elaborate(self, platform):
+        m = Module()
+        egg = RegisteredSkidBuffer(8)
+        m.submodules += egg
+
+        cntr = Signal(8)
+        intctr = Signal(8)
+        data_in = Signal(8)
+        m.d.sync += intctr.eq(intctr +1)
+        m.d.comb += egg.upstream_data_in.eq(data_in)
+
+        upstream_valid = Signal(1)
+        m.d.comb += egg.upstream_valid_in.eq(upstream_valid)
+        m.d.comb += upstream_valid.eq(1)
+
+        downstream_ready = Signal(1)
+        m.d.comb += egg.downstream_ready_in.eq(downstream_ready)
+        m.d.comb += downstream_ready.eq(1)
+        m.d.comb += data_in.eq(cntr)
+        with m.If((intctr == 4) | (intctr == 5) | (intctr == 6)):
+            m.d.comb += downstream_ready.eq(0)
+#        with m.If((intctr == 4) | (intctr == 5)):
+#            m.d.comb += upstream_valid.eq(0)
+#            m.d.comb += data_in.eq(0)
+
+        with m.If(egg.upstream_ready_out == 1):
+            m.d.sync += cntr.eq(cntr+1)
+
+
+        return m
+
+
+if __name__ == '__main__':
+    baka =DummyPlug()
+    main(baka)
\ No newline at end of file
-- 
GitLab