adding WIP memory_pipe_experiment
authorJacob Lifshay <programmerjake@gmail.com>
Sat, 18 Apr 2020 00:05:56 +0000 (17:05 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Sat, 18 Apr 2020 00:05:56 +0000 (17:05 -0700)
src/soc/memory_pipe_experiment/__init__.py
src/soc/memory_pipe_experiment/config.py
src/soc/memory_pipe_experiment/memory_op.py [new file with mode: 0644]
src/soc/memory_pipe_experiment/memory_pipe.py [new file with mode: 0644]
src/soc/memory_pipe_experiment/memory_queue.py [new file with mode: 0644]
src/soc/memory_pipe_experiment/memory_queue_entry.py [new file with mode: 0644]
src/soc/memory_pipe_experiment/test_config.py [new file with mode: 0644]
src/soc/memory_pipe_experiment/test_memory_op.py [new file with mode: 0644]
src/soc/memory_pipe_experiment/test_memory_pipe.py [new file with mode: 0644]
src/soc/memory_pipe_experiment/test_memory_queue.py [new file with mode: 0644]
src/soc/memory_pipe_experiment/test_memory_queue_entry.py [new file with mode: 0644]

index 14e0132106c727ee3b2f15a3bcee9306f242c76c..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,6 +0,0 @@
-from nmigen import Elaboratable, Module, Signal
-
-
-class L1Cache(Elaboratable):
-    def __init__(self, config):
-        self.config = config
index 4a975192a362667c271efae6964002916e9f456b..76c02947cbfb2130743cad76387abb87b5aa26cf 100644 (file)
@@ -2,10 +2,32 @@ class MemoryPipeConfig:
     def __init__(self, *,
                  bytes_per_cache_line=32,
                  l1_way_count=8,
-                 l1_set_count=64):
+                 l1_set_count=64,
+                 fu_op_id_shape=range(32),
+                 fu_op_id_nop_value=0,
+                 physical_address_bits=48,
+                 memory_queue_chunk_size=4,
+                 memory_queue_entry_count=8):
         self.bytes_per_cache_line = bytes_per_cache_line
         self.l1_way_count = l1_way_count
         self.l1_set_count = l1_set_count
+        self.fu_op_id_shape = fu_op_id_shape
+        self.fu_op_id_nop_value = fu_op_id_nop_value
+        self.physical_address_bits = physical_address_bits
+        self.memory_queue_chunk_size = memory_queue_chunk_size
+        self.memory_queue_entry_count = memory_queue_entry_count
+
+    def memory_queue_chunk_entries_start_index(self, chunk_index):
+        """ entry index of the first memory queue entry in the chunk `chunk_index`. """
+        return self.memory_queue_chunk_size * chunk_index
+
+    def memory_queue_entry_index(self, chunk_index, index_in_chunk):
+        return self.memory_queue_chunk_size * chunk_index + index_in_chunk
+
+    def memory_queue_chunk_entries_end_index(self, chunk_index):
+        """ one past the end entry index for in the chunk `chunk_index`. """
+        v = self.memory_queue_chunk_size * (chunk_index + 1)
+        return min(v, self.memory_queue_entry_count)
 
     @property
     def l1_line_count(self):
@@ -18,3 +40,7 @@ class MemoryPipeConfig:
     @property
     def bits_per_cache_line(self):
         return 8 * self.bytes_per_cache_line
+
+    @property
+    def memory_queue_chunk_count(self):
+        return self.memory_queue_entry_count // self.memory_queue_chunk_size
diff --git a/src/soc/memory_pipe_experiment/memory_op.py b/src/soc/memory_pipe_experiment/memory_op.py
new file mode 100644 (file)
index 0000000..43bcaeb
--- /dev/null
@@ -0,0 +1,38 @@
+import enum
+from nmutil.iocontrol import Object
+from nmigen import Signal
+from .config import MemoryPipeConfig
+
+
+class MemoryOpKind(enum.IntEnum):
+    Fence = enum.auto()
+    Read = enum.auto()
+    Write = enum.auto()
+    AMO = enum.auto()
+    LoadLinked = enum.auto()
+    StoreConditional = enum.auto()
+
+
+class MemoryOpData(Object):
+    def __init__(self, config: MemoryPipeConfig):
+        self.config = config
+        Object.__init__(self)
+        self.kind = Signal(MemoryOpKind)
+        self.is_cachable = Signal()
+        self.blocks_combining_with_earlier_reads = Signal()
+        self.blocks_combining_with_earlier_writes = Signal()
+        self.blocks_combining_with_later_reads = Signal()
+        self.blocks_combining_with_later_writes = Signal()
+        self.is_speculative = Signal()
+        self.physical_address = Signal(config.physical_address_bits)
+        self.byte_mask = Signal(config.bytes_per_cache_line)
+        self.fu_op_id = Signal(config.fu_op_id_shape,
+                               reset=self.config.fu_op_id_nop_value)
+
+    @property
+    def is_empty(self):
+        self.fu_op_id == self.config.fu_op_id_nop_value
+
+    def eq_empty(self):
+        """ assign self to the canonical empty value. """
+        return self.eq(MemoryOpData(self.config))
diff --git a/src/soc/memory_pipe_experiment/memory_pipe.py b/src/soc/memory_pipe_experiment/memory_pipe.py
new file mode 100644 (file)
index 0000000..9b8f5ee
--- /dev/null
@@ -0,0 +1,15 @@
+from nmigen import Elaboratable, Signal, Module, Mux, Repl, Array
+from .config import MemoryPipeConfig
+from .l1_cache_memory import L1CacheMemory
+
+
+class MemoryPipe(Elaboratable):
+    def __init__(self, config: MemoryPipeConfig):
+        self.config = config
+        self.l1_cache_memory = L1CacheMemory(config)
+        # FIXME(programmerjake): add MemoryQueue as submodule and wire everything up
+
+    def elaborate(self, platform):
+        m = Module()
+        m.submodules.l1_cache_memory = self.l1_cache_memory
+        return m
diff --git a/src/soc/memory_pipe_experiment/memory_queue.py b/src/soc/memory_pipe_experiment/memory_queue.py
new file mode 100644 (file)
index 0000000..32f0698
--- /dev/null
@@ -0,0 +1,49 @@
+from nmigen import Elaboratable, Module
+from .config import MemoryPipeConfig
+from .memory_queue_entry import MemoryQueueEntry
+from typing import Optional
+
+
+class MemoryQueueChunk(Elaboratable):
+    next_back_chunk: Optional["MemoryQueueChunk"]
+
+    def __init__(self, config: MemoryPipeConfig, chunk_index: int):
+        self.config = config
+        self.chunk_index = chunk_index
+        start = config.memory_queue_chunk_entries_start_index(chunk_index)
+        end = config.memory_queue_chunk_entries_end_index(chunk_index)
+        self.entries = [MemoryQueueEntry(config)
+                        for i in range(start, end)]
+
+    def elaborate(self, platform):
+        m = Module()
+        for i in range(len(self.entries)):
+            entry = self.entries[i]
+            entry_index = self.config.memory_queue_entry_index(
+                self.chunk_index, i)
+            setattr(m.submodules, f"entry_{entry_index}", entry)
+            if self.next_back_chunk is not None and i < len(self.next_back_chunk.entries):
+                m.d.comb += entry.next_back_chunks_next_op.eq(
+                    self.next_back_chunk.entries[i])
+            else:
+                m.d.comb += entry.next_back_chunks_next_op.eq_empty()
+        return m
+
+
+class MemoryQueue(Elaboratable):
+    def __init__(self, config: MemoryPipeConfig):
+        self.config = config
+        self.chunks = [MemoryQueueChunk(config, i)
+                       for i in range(config.memory_queue_chunk_count)]
+        self.entries = []
+        for chunk in self.chunks:
+            self.entries.extend(chunk.entries)
+
+    def elaborate(self, platform):
+        m = Module()
+        for i in range(self.config.memory_queue_chunk_count):
+            chunk = self.chunks[i]
+            setattr(m.submodules, f"chunk_{i}", chunk)
+            if i > 0:
+                self.chunks[i - 1].next_back_chunk = chunk
+        return m
diff --git a/src/soc/memory_pipe_experiment/memory_queue_entry.py b/src/soc/memory_pipe_experiment/memory_queue_entry.py
new file mode 100644 (file)
index 0000000..d7f04f8
--- /dev/null
@@ -0,0 +1,59 @@
+from nmigen import Elaboratable, Module, Signal
+from .config import MemoryPipeConfig
+from .memory_op import MemoryOpData
+
+
+class MemoryQueueEntryComb(Elaboratable):
+    """ Combinatorial state calculation for a memory queue entry, without shifting. """
+
+    def __init__(self, config: MemoryPipeConfig):
+        self.config = config
+        self.op = MemoryOpData(config)
+        self.op_out = MemoryOpData(config)
+
+    def elaborate(self, platform):
+        m = Module()
+
+        kind = self.op.kind
+        is_cachable = self.op.is_cachable
+        is_acquire_operation = self.op.is_acquire_operation
+        is_release_operation = self.op.is_release_operation
+        is_speculative = self.op.is_speculative
+        physical_address = self.op.physical_address
+        byte_mask = self.op.byte_mask
+        fu_op_id = self.op.fu_op_id
+
+        # FIXME(programmerjake): wire up actual operations
+
+        m.d.comb += self.op_out.kind.eq(kind)
+        m.d.comb += self.op_out.is_cachable.eq(is_cachable)
+        m.d.comb += self.op_out.is_acquire_operation.eq(is_acquire_operation)
+        m.d.comb += self.op_out.is_release_operation.eq(is_release_operation)
+        m.d.comb += self.op_out.is_speculative.eq(is_speculative)
+        m.d.comb += self.op_out.physical_address.eq(physical_address)
+        m.d.comb += self.op_out.byte_mask.eq(byte_mask)
+        m.d.comb += self.op_out.fu_op_id.eq(fu_op_id)
+        return m
+
+
+class MemoryQueueEntry(Elaboratable):
+    def __init__(self, config: MemoryPipeConfig):
+        self.config = config
+        self.op = MemoryOpData(config)
+        self.next_op = MemoryOpData(config)
+
+        """ `next_op` of corresponding memory queue entry in the next chunk towards the back of the queue. """
+        self.next_back_chunks_next_op = MemoryOpData(config)
+        self.do_shift = Signal()
+        self.entry_comb = MemoryQueueEntryComb(config)
+
+    def elaborate(self, platform):
+        m = Module()
+        m.submodules.entry_comb = self.entry_comb
+        m.d.comb += self.entry_comb.op.eq(self.op)
+        m.d.comb += self.next_op.eq(self.entry_comb.op_out)
+        with m.If(self.do_shift):
+            m.d.sync += self.op.eq(self.next_back_chunks_next_op)
+        with m.Else():
+            m.d.sync += self.op.eq(self.next_op)
+        return m
diff --git a/src/soc/memory_pipe_experiment/test_config.py b/src/soc/memory_pipe_experiment/test_config.py
new file mode 100644 (file)
index 0000000..fd25a71
--- /dev/null
@@ -0,0 +1 @@
+# FIXME(programmerjake): add tests for config.py
diff --git a/src/soc/memory_pipe_experiment/test_memory_op.py b/src/soc/memory_pipe_experiment/test_memory_op.py
new file mode 100644 (file)
index 0000000..7464481
--- /dev/null
@@ -0,0 +1 @@
+# FIXME(programmerjake): add tests for memory_op.py
diff --git a/src/soc/memory_pipe_experiment/test_memory_pipe.py b/src/soc/memory_pipe_experiment/test_memory_pipe.py
new file mode 100644 (file)
index 0000000..10bfa87
--- /dev/null
@@ -0,0 +1 @@
+# FIXME(programmerjake): add tests for memory_pipe.py
diff --git a/src/soc/memory_pipe_experiment/test_memory_queue.py b/src/soc/memory_pipe_experiment/test_memory_queue.py
new file mode 100644 (file)
index 0000000..1a7aa76
--- /dev/null
@@ -0,0 +1 @@
+# FIXME(programmerjake): add tests for memory_queue.py
diff --git a/src/soc/memory_pipe_experiment/test_memory_queue_entry.py b/src/soc/memory_pipe_experiment/test_memory_queue_entry.py
new file mode 100644 (file)
index 0000000..9ea6521
--- /dev/null
@@ -0,0 +1 @@
+# FIXME(programmerjake): add tests for memory_queue_entry.py