From b1a2750e8735e9fe839214a239071e5810033f6a Mon Sep 17 00:00:00 2001
From: Enrico Zelioli <ezelioli@iis.ee.ethz.ch>
Date: Thu, 5 Dec 2024 11:51:15 +0100
Subject: [PATCH] Add SMP tests to Gitlab CI

- Add dual-core configuration in testbench
- Add number of cores parameter for consistent CLINT/PLIC generation
- Add PLIC configuration file generation according to number of cores
- Bump nonfree to version with baremetal SMP tests
---
 cheshire.mk                       |  8 +++-
 hw/rv_plic.cfg.hjson              |  2 +
 sw/link/rom.ld                    |  2 +
 sw/link/spm.ld                    |  2 +
 target/sim/src/tb_cheshire_pkg.sv | 16 ++++++--
 util/gen_pliccfg.py               | 61 +++++++++++++++++++++++++++++++
 6 files changed, 85 insertions(+), 6 deletions(-)
 create mode 100755 util/gen_pliccfg.py

diff --git a/cheshire.mk b/cheshire.mk
index 15355b05a..764f81abd 100644
--- a/cheshire.mk
+++ b/cheshire.mk
@@ -18,6 +18,7 @@ VLOGAN_ARGS ?= -kdb -nc -assert svaext +v2k -timescale=1ns/1ps
 
 # Common Bender flags for Cheshire RTL
 CHS_BENDER_RTL_FLAGS ?= -t rtl -t cva6 -t cv64a6_imafdcsclic_sv39
+NUM_CORES            ?= 1
 
 # Define used paths (prefixed to avoid name conflicts)
 CHS_ROOT      ?= $(shell $(BENDER) path cheshire)
@@ -64,7 +65,7 @@ chs-clean-deps:
 ######################
 
 CHS_NONFREE_REMOTE ?= git@iis-git.ee.ethz.ch:pulp-restricted/cheshire-nonfree.git
-CHS_NONFREE_COMMIT ?= 99aa8d9
+CHS_NONFREE_COMMIT ?= 1deb6804931b6ded1ec282b0766d0501ff8ce734
 
 CHS_PHONY += chs-nonfree-init
 chs-nonfree-init:
@@ -88,12 +89,15 @@ $(CHS_ROOT)/hw/regs/cheshire_reg_pkg.sv $(CHS_ROOT)/hw/regs/cheshire_reg_top.sv:
 	$(REGTOOL) -r $< --outdir $(dir $@)
 
 # CLINT
-CLINTCORES ?= 1
+CLINTCORES ?= $(NUM_CORES)
 include $(CLINTROOT)/clint.mk
 $(CLINTROOT)/.generated:
 	flock -x $@ $(MAKE) clint && touch $@
 
 # OpenTitan peripherals
+$(CHS_ROOT)/hw/rv_plic.cfg.hjson: $(CHS_ROOT)/util/gen_pliccfg.py
+	$(CHS_ROOT)/util/gen_pliccfg.py --num-cores $(NUM_CORES) > $@
+
 include $(OTPROOT)/otp.mk
 $(OTPROOT)/.generated: $(CHS_ROOT)/hw/rv_plic.cfg.hjson
 	flock -x $@ sh -c "cp $< $(dir $@)/src/rv_plic/; $(MAKE) -j1 otp" && touch $@
diff --git a/hw/rv_plic.cfg.hjson b/hw/rv_plic.cfg.hjson
index 865be3a9b..ad2f247d9 100644
--- a/hw/rv_plic.cfg.hjson
+++ b/hw/rv_plic.cfg.hjson
@@ -3,6 +3,8 @@
 // SPDX-License-Identifier: Apache-2.0
 //
 // Paul Scheffler <paulsc@iis.ee.ethz.ch>
+// Enrico Zelioli <ezelioli@iis.ee.ethz.ch>
+// AUTOMATICALLY GENERATED by gen_pliccfg.py; edit the script instead.
 
 {
     instance_name: "rv_plic",
diff --git a/sw/link/rom.ld b/sw/link/rom.ld
index 29550ae2c..f386645c5 100644
--- a/sw/link/rom.ld
+++ b/sw/link/rom.ld
@@ -9,6 +9,8 @@
 INCLUDE common.ldh
 
 SECTIONS {
+  __stack_pointer$  = ORIGIN(spm) + LENGTH(spm) - 8;
+
   /* Put all LOAD sections in one contiguous output section */
   .misc : {
     *(.text._start)
diff --git a/sw/link/spm.ld b/sw/link/spm.ld
index bedd94734..ff96285cc 100644
--- a/sw/link/spm.ld
+++ b/sw/link/spm.ld
@@ -9,6 +9,8 @@
 INCLUDE common.ldh
 
 SECTIONS {
+  __stack_pointer$  = ORIGIN(spm) + LENGTH(spm) - 8;
+
   .text : {
     *(.text._start)
     *(.text)
diff --git a/target/sim/src/tb_cheshire_pkg.sv b/target/sim/src/tb_cheshire_pkg.sv
index 8197b2dfa..7b5f882db 100644
--- a/target/sim/src/tb_cheshire_pkg.sv
+++ b/target/sim/src/tb_cheshire_pkg.sv
@@ -23,14 +23,22 @@ package tb_cheshire_pkg;
       return ret;
     endfunction
 
+    // A dedicated dual-core config
+    function automatic cheshire_cfg_t gen_cheshire_dualcore_cfg();
+      cheshire_cfg_t ret = DefaultCfg;
+      ret.NumCores = 2;
+      return ret;
+    endfunction
+
     // Number of Cheshire configurations
-    localparam int unsigned NumCheshireConfigs = 32'd3;
+    localparam int unsigned NumCheshireConfigs = 32'd4;
 
     // Assemble a configuration array indexed by a numeric parameter
     localparam cheshire_cfg_t [NumCheshireConfigs-1:0] TbCheshireConfigs = {
-        gen_cheshire_clic_cfg(), // 2: CLIC-enabled configuration
-        gen_cheshire_rt_cfg(),   // 1: RT-enabled configuration
-        DefaultCfg               // 0: Default configuration
+        gen_cheshire_dualcore_cfg(), // 3: Dual-core configuration
+        gen_cheshire_clic_cfg(),     // 2: CLIC-enabled configuration
+        gen_cheshire_rt_cfg(),       // 1: RT-enabled configuration
+        DefaultCfg                   // 0: Default configuration
     };
 
 endpackage
diff --git a/util/gen_pliccfg.py b/util/gen_pliccfg.py
new file mode 100755
index 000000000..07d7e5705
--- /dev/null
+++ b/util/gen_pliccfg.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+#
+# Copyright 2022 ETH Zurich and University of Bologna.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+#
+# Nicole Narr <narrn@student.ethz.ch>
+# Christopher Reinwardt <creinwar@student.ethz.ch>
+#
+# Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
+# Florian Zaruba <zarubaf@iis.ee.ethz.ch>
+# Stefan Mach <smach@iis.ee.ethz.ch>
+# Thomas Benz <tbenz@iis.ee.ethz.ch>
+# Paul Scheffler <paulsc@iis.ee.ethz.ch>
+# Wolfgang Roenninger <wroennin@iis.ee.ethz.ch>
+# Gianna Paulin <pauling@iis.ee.ethz.ch>
+# Tim Fischer <fischeti@iis.ee.ethz.ch>
+# Enrico Zelioli <ezelioli@iis.ee.ethz.ch>
+
+import os
+import argparse
+
+# Parse arguments.
+parser = argparse.ArgumentParser(description="Generate rv_plic.cfg.hjson")
+parser.add_argument(
+    "--num-cores",
+    "-n",
+    dest="num_cores",
+    default=1,
+    type=int,
+    help=
+    "Number of cores attached to the PLIC. The number of PLIC targets is set accordingly (2 * num-cores)"
+)
+args = parser.parse_args()
+
+num_targets = args.num_cores * 2
+
+# Emit the code.
+print("""
+// Copyright 2022 ETH Zurich and University of Bologna.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Paul Scheffler <paulsc@iis.ee.ethz.ch>
+// Enrico Zelioli <ezelioli@iis.ee.ethz.ch>
+// AUTOMATICALLY GENERATED by {script}; edit the script instead.
+
+{{
+    instance_name: \"rv_plic\",
+    param_values: {{
+        src: 58,
+        target: {targets},  // We need *two targets* per hart: M and S modes
+        prio: 7,
+        nonstd_regs: 0  // Do *not* include these: MSIPs are not used and we use a 64 MiB address space
+    }},
+}}
+
+""".strip().format(
+    script=os.path.basename(__file__),
+    targets=num_targets
+))