Update kelvin linker script

* Use linker script to check code to be < 3MB
* Add model header at the fixed location in the linker script
* Fix HPS executable stack to 256kB (sim_kelvin failed on blown stack)

Fix: 269616844

Change-Id: I80f55032b317490cb8b9c6de8ef67cbf5d01e23d
(cherry picked from commit f34fbb1d2359e1d53a3727970c7f6b8d6726ad9d)
diff --git a/sw/device/lib/testing/test_framework/kelvin.ld b/sw/device/lib/testing/test_framework/kelvin.ld
index 048db0d..076aa68 100644
--- a/sw/device/lib/testing/test_framework/kelvin.ld
+++ b/sw/device/lib/testing/test_framework/kelvin.ld
@@ -15,10 +15,11 @@
  */
 
 MEMORY {
-  TCM(rwx): ORIGIN = 0x00000000, LENGTH = LENGTH(ram_ml_dmem)
+  TCM(rwx): ORIGIN = 0x00000000, LENGTH = 3M
+  MODEL_DATA(rw): ORIGIN = LENGTH(TCM), LENGTH = LENGTH(ram_ml_dmem) - LENGTH(TCM)
 }
 
-_stack_size = 0x4000;
+STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x4000;
 __heap_size__ = 0x1000;
 
 ENTRY(_start)
@@ -85,7 +86,26 @@
 
   .stack : ALIGN(4) {
     __stack_start__ = .;
-    . += _stack_size;
+    . += STACK_SIZE;
     __stack_end__ = .;
   } > TCM
 }
+
+SECTIONS {
+  . = ORIGIN(MODEL_DATA);
+  .model_data (NOLOAD) : ALIGN(4) {
+    __model_data_start__ = .;
+    *(.model_data)
+    __model_data_end__ = .;
+  } > MODEL_DATA
+
+  /*
+   * Model header information (model input/output addresses) is
+   * always at the end of DMEM.
+   */
+  .model_header LENGTH(ram_ml_dmem) - 4096 (NOLOAD) : ALIGN(4) {
+    __model_header_start__ = .;
+    *(.model_header*)
+    __model_header_end__ = .;
+  } > MODEL_DATA
+}
diff --git a/sw/device/tests/kelvin/hps-c-port/BUILD b/sw/device/tests/kelvin/hps-c-port/BUILD
index fb282e6..dcccb99 100644
--- a/sw/device/tests/kelvin/hps-c-port/BUILD
+++ b/sw/device/tests/kelvin/hps-c-port/BUILD
@@ -57,4 +57,7 @@
         "//sw/device/tests/kelvin/hps-c-port/model/inc:tfc_opt_util.h",
         "//sw/device/tests/kelvin/hps-c-port/model/inc:tfc_reshape.h",
     ],
+    linkopts = [
+        "-Wl,--defsym,__stack_size__=256k",
+    ],
 )
diff --git a/sw/device/tests/kelvin/hps-c-port/main_fpga.cc b/sw/device/tests/kelvin/hps-c-port/main_fpga.cc
index 4755b93..a42fe33 100644
--- a/sw/device/tests/kelvin/hps-c-port/main_fpga.cc
+++ b/sw/device/tests/kelvin/hps-c-port/main_fpga.cc
@@ -1,24 +1,24 @@
-#include "sw/device/tests/kelvin/hps-c-port/sw/init/kelvin.h"
-#include "sw/device/tests/kelvin/hps-c-port/model/inc/model.h"
 #include "sw/device/tests/kelvin/hps-c-port/ml_input.h"
+#include "sw/device/tests/kelvin/hps-c-port/model/inc/model.h"
+#include "sw/device/tests/kelvin/hps-c-port/sw/init/kelvin.h"
 
 constexpr int kImageLen = 240 * 320;
 
-constexpr uint32_t kCommand = 0x3FF000;  // +4.0MB - 4KB
-
 struct command_t {
   uint32_t input_addr;
   uint32_t output_addr;
   uint32_t padding[1024 - 2];
 };
-static_assert(sizeof(command_t) == 4096);
 
 static int8_t input_[kImageLen] __aligned__ __noinit__;
 
+// .model_header is at the DMEM - 4KB
+command_t command __attribute__((section(".model_header")));
+static_assert(sizeof(command) == 4096);
+
 int main(void) {
-  const command_t *command = reinterpret_cast<const command_t*>(kCommand);
-  const uint8_t *image = reinterpret_cast<const uint8_t*>(command->input_addr);
-  int8_t *output = reinterpret_cast<int8_t*>(command->output_addr);
+  const uint8_t *image = reinterpret_cast<const uint8_t *>(command.input_addr);
+  int8_t *output = reinterpret_cast<int8_t *>(command.output_addr);
 
   ml_input(kImageLen, image, input_);
   model(input_, output);