From c06bd2c77d023aab739f056d31fecef0a53de283 Mon Sep 17 00:00:00 2001
From: Romain Dolbeau <romain@dolbeau.org>
Date: Sat, 8 May 2021 07:39:13 -0400
Subject: [PATCH] Make the [ID]TLB size configurable from Litex ; expand the
 DTS to include cache/TLB/topology in CPUs & generate the required information
 for VexRiscv

---
 litex/soc/cores/cpu/vexriscv_smp/core.py | 28 ++++++++++++
 litex/tools/litex_json2dts.py            | 57 +++++++++++++++++++++---
 2 files changed, 80 insertions(+), 5 deletions(-)

diff --git a/litex/soc/cores/cpu/vexriscv_smp/core.py b/litex/soc/cores/cpu/vexriscv_smp/core.py
index 3b95b73aa..bdc7476cd 100644
--- a/litex/soc/cores/cpu/vexriscv_smp/core.py
+++ b/litex/soc/cores/cpu/vexriscv_smp/core.py
@@ -56,6 +56,8 @@ class VexRiscvSMP(CPU):
     with_fpu             = False
     cpu_per_fpu          = 4
     with_rvc             = False
+    dtlb_size            = 4
+    itlb_size            = 4
 
     # Command line configuration arguments.
     @staticmethod
@@ -75,6 +77,8 @@ class VexRiscvSMP(CPU):
         parser.add_argument("--with-fpu"                    , action="store_true", help="Enable the F32/F64 FPU")
         parser.add_argument("--cpu-per-fpu"                 , default="4",         help="Maximal ratio between CPU count and FPU count. Will instanciate as many FPU as necessary.")
         parser.add_argument("--with-rvc"                    , action="store_true", help="Enable RISC-V compressed instruction support")
+        parser.add_argument("--dtlb-size",                    default=4,           help="Data TLB size.")
+        parser.add_argument("--itlb-size",                    default=4,           help="Instruction TLB size.")
 
     @staticmethod
     def args_read(args):
@@ -106,6 +110,8 @@ class VexRiscvSMP(CPU):
             VexRiscvSMP.cpu_per_fpu = args.cpu_per_fpu
         if(args.with_rvc):
             VexRiscvSMP.with_rvc     = True
+        if(args.dtlb_size):                    VexRiscvSMP.dtlb_size             = int(args.dtlb_size)
+        if(args.itlb_size):                    VexRiscvSMP.itlb_size             = int(args.itlb_size)
 
     # ABI.
     @staticmethod
@@ -159,6 +165,9 @@ class VexRiscvSMP(CPU):
         f"Dw{VexRiscvSMP.dcache_width}" \
         f"Ds{VexRiscvSMP.dcache_size}"  \
         f"Dy{VexRiscvSMP.dcache_ways}"  \
+        "_" \
+        f"ITs{VexRiscvSMP.itlb_size}" \
+        f"DTs{VexRiscvSMP.dtlb_size}" \
         f"{'_'+ldw if not VexRiscvSMP.wishbone_memory  else ''}" \
         f"{'_Cdma' if VexRiscvSMP.coherent_dma         else ''}" \
         f"{'_Aes'  if VexRiscvSMP.aes_instruction      else ''}" \
@@ -250,6 +259,8 @@ class VexRiscvSMP(CPU):
         gen_args.append(f"--rvc={VexRiscvSMP.with_rvc}")
         gen_args.append(f"--netlist-name={VexRiscvSMP.cluster_name}")
         gen_args.append(f"--netlist-directory={vdir}")
+        gen_args.append(f"--dtlb-size={VexRiscvSMP.dtlb_size}")
+        gen_args.append(f"--itlb-size={VexRiscvSMP.itlb_size}")
 
         cmd = 'cd {path} && sbt "runMain vexriscv.demo.smp.VexRiscvLitexSmpClusterCmdGen {args}"'.format(path=os.path.join(vdir, "ext", "VexRiscv"), args=" ".join(gen_args))
         if os.system(cmd) != 0:
@@ -361,6 +372,23 @@ class VexRiscvSMP(CPU):
         # Define number of CPUs
         soc.add_config("CPU_COUNT", VexRiscvSMP.cpu_count)
         soc.add_constant("CPU_ISA", VexRiscvSMP.get_arch())
+        # constants for cache so we can add them in the DTS
+        if (VexRiscvSMP.dcache_size > 0):
+            soc.add_constant("cpu_dcache_size", VexRiscvSMP.dcache_size)
+            soc.add_constant("cpu_dcache_ways", VexRiscvSMP.dcache_ways)
+            soc.add_constant("cpu_dcache_block_size", 64) # hardwired?
+        if (VexRiscvSMP.icache_size > 0):
+            soc.add_constant("cpu_icache_size", VexRiscvSMP.icache_size)
+            soc.add_constant("cpu_icache_ways", VexRiscvSMP.icache_ways)
+            soc.add_constant("cpu_icache_block_size", 64) # hardwired?
+        # constants for TLB so we can add them in the DTS
+        # full associative so only the size is described
+        if (VexRiscvSMP.dtlb_size > 0):
+            soc.add_constant("cpu_dtlb_size", VexRiscvSMP.dtlb_size)
+            soc.add_constant("cpu_dtlb_ways", VexRiscvSMP.dtlb_size)
+        if (VexRiscvSMP.itlb_size > 0):
+            soc.add_constant("cpu_itlb_size", VexRiscvSMP.itlb_size)
+            soc.add_constant("cpu_itlb_ways", VexRiscvSMP.itlb_size)
 
         # Add PLIC as Bus Slave
         self.plicbus = plicbus  = wishbone.Interface()
diff --git a/litex/tools/litex_json2dts.py b/litex/tools/litex_json2dts.py
index e5e9d0b40..41d371df4 100755
--- a/litex/tools/litex_json2dts.py
+++ b/litex/tools/litex_json2dts.py
@@ -61,16 +61,60 @@ def generate_dts(d, initrd_start=None, initrd_size=None, polling=False):
 
     # VexRiscv-SMP
     if cpu_name == "vexriscv smp-linux":
+        # cache description
+        cache_desc = ""
+        if "cpu_dcache_size" in d["constants"]:
+            cache_desc += """
+                d-cache-size = <{d_cache_size}>;
+                d-cache-sets = <{d_cache_ways}>;
+                d-cache-block-size = <{d_cache_block_size}>;
+""".format(d_cache_size=d["constants"]["cpu_dcache_size"], d_cache_ways=d["constants"]["cpu_dcache_ways"], d_cache_block_size=d["constants"]["cpu_dcache_block_size"])
+        if "cpu_icache_size" in d["constants"]:
+            cache_desc += """
+                i-cache-size = <{i_cache_size}>;
+                i-cache-sets = <{i_cache_ways}>;
+                i-cache-block-size = <{i_cache_block_size}>;
+""".format(i_cache_size=d["constants"]["cpu_icache_size"], i_cache_ways=d["constants"]["cpu_icache_ways"], i_cache_block_size=d["constants"]["cpu_icache_block_size"])
+
+        # tlb description
+        tlb_desc = ""
+        if "cpu_dtlb_size" in d["constants"]:
+            tlb_desc += """
+                d-tlb-size = <{d_tlb_size}>;
+                d-tlb-sets = <{d_tlb_ways}>;
+""".format(d_tlb_size=d["constants"]["cpu_dtlb_size"], d_tlb_ways=d["constants"]["cpu_dtlb_ways"])
+        if "cpu_itlb_size" in d["constants"]:
+            tlb_desc += """
+                i-tlb-size = <{i_tlb_size}>;
+                i-tlb-sets = <{i_tlb_ways}>;
+""".format(i_tlb_size=d["constants"]["cpu_itlb_size"], i_tlb_ways=d["constants"]["cpu_itlb_ways"])
+
+        cpus = range(int(d["constants"]["config_cpu_count"]))
+
+        # topology
+        cpu_map = ""
+        if int(d["constants"]["config_cpu_count"]) > 1:
+            cpu_map += """
+            cpu-map {
+                cluster0 {"""
+            for cpu in cpus:
+                cpu_map += """
+                    core{cpu} {{
+                        cpu = <&CPU{cpu}>;
+                    }};""".format(cpu=cpu)
+            cpu_map += """
+                };
+            };"""
+
         dts += """
         cpus {{
             #address-cells = <1>;
             #size-cells    = <0>;
             timebase-frequency = <{sys_clk_freq}>;
 """.format(sys_clk_freq=d["constants"]["config_clock_frequency"])
-        cpus = range(int(d["constants"]["config_cpu_count"]))
         for cpu in cpus:
             dts += """
-            cpu@{cpu} {{
+            CPU{cpu}: cpu@{cpu} {{
                 device_type = "cpu";
                 compatible = "riscv";
                 riscv,isa = "{cpu_isa}";
@@ -78,16 +122,19 @@ def generate_dts(d, initrd_start=None, initrd_size=None, polling=False):
                 reg = <{cpu}>;
                 clock-frequency = <{sys_clk_freq}>;
                 status = "okay";
+                {cache_desc}
+                {tlb_desc}
                 L{irq}: interrupt-controller {{
                     #interrupt-cells = <0x00000001>;
                     interrupt-controller;
                     compatible = "riscv,cpu-intc";
                 }};
             }};
-""".format(cpu=cpu, irq=cpu, sys_clk_freq=d["constants"]["config_clock_frequency"], cpu_isa=d["constants"]["cpu_isa"])
+""".format(cpu=cpu, irq=cpu, sys_clk_freq=d["constants"]["config_clock_frequency"], cpu_isa=d["constants"]["cpu_isa"], cache_desc=cache_desc, tlb_desc=tlb_desc)
         dts += """
-        };
-"""
+            {cpu_map}
+        }};
+""".format(cpu_map=cpu_map)
 
     # mor1kx
     elif cpu_name == "mor1kx":