[rom_ctrl] Instantiate scrambling primitives for rom_ctrl

Also update SW build scripts so that we install the scrambled binaries
to build-bin as well and update all the documentation examples to show
how to use the new filename.

Note that we don't update top_englishbreakfast to match: that doesn't
have a rom_ctrl, so shouldn't take a scrambled ROM image.

Signed-off-by: Rupert Swarbrick <rswarbrick@lowrisc.org>
diff --git a/hw/ip/otbn/README.md b/hw/ip/otbn/README.md
index 948cc57..75c91af 100644
--- a/hw/ip/otbn/README.md
+++ b/hw/ip/otbn/README.md
@@ -105,7 +105,7 @@
 
 ```sh
 build/lowrisc_systems_chip_earlgrey_verilator_0.1/sim-verilator/Vchip_earlgrey_verilator \
-  --meminit=rom,build-bin/sw/device/boot_rom/boot_rom_sim_verilator.elf  \
+  --meminit=rom,build-bin/sw/device/boot_rom/boot_rom_sim_verilator.scr.40.vmem \
   --meminit=flash,build-bin/sw/device/tests/dif_otbn_smoketest_sim_verilator.elf \
   --meminit=otp,build-bin/sw/device/otp_img/otp_img_sim_verilator.vmem \
   +UARTDPI_LOG_uart0=- \
diff --git a/hw/ip/rom_ctrl/data/rom_ctrl.hjson b/hw/ip/rom_ctrl/data/rom_ctrl.hjson
index 6adcdb3..128ef77 100644
--- a/hw/ip/rom_ctrl/data/rom_ctrl.hjson
+++ b/hw/ip/rom_ctrl/data/rom_ctrl.hjson
@@ -18,6 +18,20 @@
       local:   "false",
       expose:  "true"
     }
+
+    { name:      "RndCnstScrNonce",
+      type:      "bit [63:0]",
+      desc:      "Fixed nonce used for address / data scrambling"
+      randcount: "64",
+      randtype:  "data"
+    }
+
+    { name:      "RndCnstScrKey",
+      type:      "bit [127:0]",
+      desc:      "Randomised constant used as a scrambling key for ROM data"
+      randcount: "128",
+      randtype:  "data"
+    }
   ]
   alert_list: [
     { name: "fatal"
diff --git a/hw/ip/rom_ctrl/rom_ctrl.core b/hw/ip/rom_ctrl/rom_ctrl.core
index 359e3df..cc8a49c 100644
--- a/hw/ip/rom_ctrl/rom_ctrl.core
+++ b/hw/ip/rom_ctrl/rom_ctrl.core
@@ -10,6 +10,7 @@
     depend:
       - lowrisc:prim:alert
       - lowrisc:prim:assert
+      - lowrisc:prim:cipher
       - lowrisc:prim:rom_adv
       - lowrisc:prim:subreg
       - lowrisc:prim:util
@@ -25,6 +26,7 @@
       - rtl/rom_ctrl_counter.sv
       - rtl/rom_ctrl_fsm.sv
       - rtl/rom_ctrl_mux.sv
+      - rtl/rom_ctrl_scrambled_rom.sv
     file_type: systemVerilogSource
 
   files_verilator_waiver:
diff --git a/hw/ip/rom_ctrl/rtl/rom_ctrl.sv b/hw/ip/rom_ctrl/rtl/rom_ctrl.sv
index 600d51c..d3ad41d 100644
--- a/hw/ip/rom_ctrl/rtl/rom_ctrl.sv
+++ b/hw/ip/rom_ctrl/rtl/rom_ctrl.sv
@@ -10,6 +10,8 @@
 #(
   parameter                       BootRomInitFile = "",
   parameter logic [NumAlerts-1:0] AlertAsyncOn = {NumAlerts{1'b1}},
+  parameter bit [63:0]            RndCnstScrNonce = '0,
+  parameter bit [127:0]           RndCnstScrKey = '0,
   parameter bit                   SkipCheck = 1'b1
 ) (
   input  clk_i,
@@ -49,7 +51,8 @@
 
   logic [RomIndexWidth-1:0] rom_index;
   logic                     rom_req;
-  logic [39:0]              rom_rdata;
+  logic [39:0]              rom_scr_rdata;
+  logic [39:0]              rom_clr_rdata;
   logic                     rom_rvalid;
 
   logic [RomIndexWidth-1:0] bus_rom_index;
@@ -142,37 +145,41 @@
   rom_ctrl_mux #(
     .AW (RomIndexWidth)
   ) u_mux (
-    .clk_i        (clk_i),
-    .rst_ni       (rst_ni),
-    .sel_i        (rom_select),
-    .bus_addr_i   (bus_rom_index),
-    .bus_req_i    (bus_rom_req),
-    .bus_gnt_o    (bus_rom_gnt),
-    .bus_rdata_o  (bus_rom_rdata),
-    .bus_rvalid_o (bus_rom_rvalid),
-    .chk_addr_i   (checker_rom_index),
-    .chk_rdata_o  (checker_rom_rdata),
-    .rom_addr_o   (rom_index),
-    .rom_req_o    (rom_req),
-    .rom_rdata_i  (rom_rdata),
-    .rom_rvalid_i (rom_rvalid),
-    .alert_o      (mux_alert)
+    .clk_i           (clk_i),
+    .rst_ni          (rst_ni),
+    .sel_i           (rom_select),
+    .bus_addr_i      (bus_rom_index),
+    .bus_req_i       (bus_rom_req),
+    .bus_gnt_o       (bus_rom_gnt),
+    .bus_rdata_o     (bus_rom_rdata),
+    .bus_rvalid_o    (bus_rom_rvalid),
+    .chk_addr_i      (checker_rom_index),
+    .chk_rdata_o     (checker_rom_rdata),
+    .rom_addr_o      (rom_index),
+    .rom_req_o       (rom_req),
+    .rom_scr_rdata_i (rom_scr_rdata),
+    .rom_clr_rdata_i (rom_clr_rdata),
+    .rom_rvalid_i    (rom_rvalid),
+    .alert_o         (mux_alert)
   );
 
   // The ROM itself ============================================================
 
-  prim_rom_adv #(
+  rom_ctrl_scrambled_rom #(
+    .MemInitFile (BootRomInitFile),
     .Width       (40),
     .Depth       (RomSizeWords),
-    .MemInitFile (BootRomInitFile)
+    .ScrNonce    (RndCnstScrNonce),
+    .ScrKey      (RndCnstScrKey)
   ) u_rom (
-    .clk_i    (clk_i),
-    .rst_ni   (rst_ni),
-    .req_i    (rom_req),
-    .addr_i   (rom_index),
-    .rdata_o  (rom_rdata),
-    .rvalid_o (rom_rvalid),
-    .cfg_i    (rom_cfg_i)
+    .clk_i       (clk_i),
+    .rst_ni      (rst_ni),
+    .req_i       (rom_req),
+    .addr_i      (rom_index),
+    .rvalid_o    (rom_rvalid),
+    .scr_rdata_o (rom_scr_rdata),
+    .clr_rdata_o (rom_clr_rdata),
+    .cfg_i       (rom_cfg_i)
   );
 
   // TODO: The ROM has been expanded to 40 bits wide to allow us to add 9 ECC check bits. At the
diff --git a/hw/ip/rom_ctrl/rtl/rom_ctrl_mux.sv b/hw/ip/rom_ctrl/rtl/rom_ctrl_mux.sv
index 9aec4bb..a45360d 100644
--- a/hw/ip/rom_ctrl/rtl/rom_ctrl_mux.sv
+++ b/hw/ip/rom_ctrl/rtl/rom_ctrl_mux.sv
@@ -29,7 +29,8 @@
   // Interface for ROM
   output logic [AW-1:0] rom_addr_o,
   output logic          rom_req_o,
-  input logic [39:0]    rom_rdata_i,
+  input logic [39:0]    rom_scr_rdata_i,
+  input logic [39:0]    rom_clr_rdata_i,
   input logic           rom_rvalid_i,
 
   // Alert output
@@ -52,11 +53,11 @@
 
   // The bus can have access every cycle, once the select signal has gone to zero
   assign bus_gnt_o    = ~sel_q;
-  assign bus_rdata_o  = rom_rdata_i;
+  assign bus_rdata_o  = rom_clr_rdata_i;
   // A high rom_rvalid_i is a response to a bus request if sel_i was zero on the previous cycle.
   assign bus_rvalid_o = ~sel_q & rom_rvalid_i;
 
-  assign chk_rdata_o = rom_rdata_i;
+  assign chk_rdata_o = rom_scr_rdata_i;
 
   assign rom_addr_o = sel_i ? chk_addr_i : bus_addr_i;
   assign rom_req_o  = sel_i ? 1'b1       : bus_req_i;
diff --git a/hw/ip/rom_ctrl/rtl/rom_ctrl_scrambled_rom.sv b/hw/ip/rom_ctrl/rtl/rom_ctrl_scrambled_rom.sv
new file mode 100644
index 0000000..af96881
--- /dev/null
+++ b/hw/ip/rom_ctrl/rtl/rom_ctrl_scrambled_rom.sv
@@ -0,0 +1,142 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+`include "prim_assert.sv"
+
+//
+// A scrambled ROM. This is scrambled with a fixed key, passed in as a parameter (this parameter
+// will be a compile-time random constant).
+//
+// This code follows the structure of prim_ram_1p_scr.sv (although it's much simplified because the
+// key is fixed and we don't support writes). For more information about what is going on, see that
+// file. Using the parameter names in prim_ram_1p_scr, we have NumPrinceRoundsHalf = 2 (so
+// approximately 5 effective rounds), NumDiffRounds = 2 and NumAddrScrRounds = 2 (enabling address
+// scrambling with 2 rounds).
+//
+
+module rom_ctrl_scrambled_rom
+  import prim_rom_pkg::rom_cfg_t;
+#(
+  // The initial contents of the ROM. This is used for synthesis. For simulation, this is not used;
+  // instead, the simulator loads the contents of ROM over DPI.
+  //
+  // In either case, the input file should be scrambled. That is, it should contain the bits that
+  // will appear in the physical ROM.
+  parameter MemInitFile = "",
+
+  // The width of ROM words in bits
+  parameter int Width = 40,
+
+  // The number of words in the ROM
+  parameter int Depth = 16,
+
+  // The nonce for data and address scrambling
+  parameter bit [63:0] ScrNonce = '0,
+
+  // The (fixed) key for the PRINCE cipher
+  parameter bit [127:0] ScrKey = '0,
+
+  localparam int Aw = $clog2(Depth)
+) (
+  input logic              clk_i,
+  input logic              rst_ni,
+
+  input  logic             req_i,
+  input  logic [Aw-1:0]    addr_i,
+  output logic             rvalid_o,
+  output logic [Width-1:0] scr_rdata_o,
+  output logic [Width-1:0] clr_rdata_o,
+
+  input rom_cfg_t          cfg_i
+);
+
+  localparam bit [63-Aw:0] DataScrNonce = ScrNonce[Aw +: (64 - Aw)];
+  localparam bit [Aw-1:0]  AddrScrNonce = ScrNonce[Aw-1:0];
+
+  // Parameter Checks ==========================================================
+
+  // The depth needs to be a power of 2 to use address scrambling
+  `ASSERT_INIT(DepthPow2Check_A, (Depth & (Depth - 1)) == 0)
+  // We only support a width up to 64
+  `ASSERT_INIT(MaxWidthCheck_A, Width <= 64)
+
+  // Address scrambling ========================================================
+
+  logic [Aw-1:0] addr_scr;
+  prim_subst_perm #(
+    .DataWidth (Aw),
+    .NumRounds (2),
+    .Decrypt   (0)
+  ) u_sp_addr (
+    .data_i (addr_i),
+    .key_i  (AddrScrNonce),
+    .data_o (addr_scr)
+  );
+
+  // Keystream generation ======================================================
+
+  logic [63:0] keystream;
+
+  prim_prince #(
+    .DataWidth      (64),
+    .KeyWidth       (128),
+    .NumRoundsHalf  (2),
+    .HalfwayDataReg (1'b1),
+    .HalfwayKeyReg  (1'b1)
+  ) u_prince (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+    .valid_i (req_i),
+    .data_i  ({DataScrNonce, addr_i}),
+    .key_i   (ScrKey),
+    .dec_i   (1'b0),
+    .data_o  (keystream),
+    .valid_o ()
+  );
+
+  if (Width < 64) begin : gen_unread_keystream
+    // Ignore top bits of keystream: we just use the bottom Width bits.
+    logic unused_top_keystream;
+    assign unused_top_keystream = &{1'b0, keystream[63:Width]};
+  end
+
+  // The physical ROM ==========================================================
+
+  logic [Width-1:0] rdata_scr;
+
+  prim_rom_adv #(
+    .Width       (Width),
+    .Depth       (Depth),
+    .MemInitFile (MemInitFile)
+  ) u_rom (
+    .clk_i    (clk_i),
+    .rst_ni   (rst_ni),
+    .req_i    (req_i),
+    .addr_i   (addr_scr),
+    .rvalid_o (rvalid_o),
+    .rdata_o  (rdata_scr),
+    .cfg_i    (cfg_i)
+  );
+
+  assign scr_rdata_o = rdata_scr;
+
+  // Data scrambling ===========================================================
+
+  logic [Width-1:0] rdata_xor;
+
+  prim_subst_perm #(
+    .DataWidth (Width),
+    .NumRounds (2),
+    .Decrypt   (1)
+  ) u_sp_data (
+    .data_i (rdata_scr),
+    .key_i  ('0),
+    .data_o (rdata_xor)
+  );
+
+  // XOR rdata with keystream ==================================================
+
+  assign clr_rdata_o = rdata_xor ^ keystream[Width-1:0];
+
+endmodule
diff --git a/hw/ip/rom_ctrl/util/mem.py b/hw/ip/rom_ctrl/util/mem.py
index 2f55169..8ee9be7 100644
--- a/hw/ip/rom_ctrl/util/mem.py
+++ b/hw/ip/rom_ctrl/util/mem.py
@@ -195,19 +195,23 @@
             if seg_type != 'PT_LOAD' or segment['p_memsz'] == 0:
                 continue
 
-            seg_lma = segment['p_paddr']
-            seg_end = seg_lma + segment['p_memsz']
+            # seg_lma is the (relative) address of the first byte to be loaded.
+            # seg_top is the address of the last byte to be loaded. A one-byte
+            # segment will have seg_lma == seg_top.
+            seg_lma = segment['p_paddr'] - base_addr
+            seg_top = seg_lma + segment['p_memsz'] - 1
+
+            assert seg_lma <= seg_top
 
             # We re-map the addresses relative to base_addr: check that no
             # segment starts before it.
-            if seg_lma < base_addr:
+            if seg_lma < 0:
                 raise ValueError('ELF file contains a segment starting at '
                                  '{:#x}, so cannot be loaded relative to base '
                                  'address {:#x}.'
-                                 .format(seg_lma, base_addr))
+                                 .format(base_addr + seg_lma, base_addr))
 
-            segments.append((seg_lma - base_addr,
-                             seg_end - base_addr, segment.data()))
+            segments.append((seg_lma, seg_top, segment.data()))
 
         # Sort the segments by base address
         segments.sort(key=lambda t: t[0])
@@ -215,21 +219,24 @@
         # Make sure that they don't overlap
         prev_lma = 0
         next_addr = 0
-        for lma, end, data in segments:
+        for lma, top, data in segments:
             if lma < next_addr:
                 raise ValueError('ELF file contains overlapping segments with '
                                  'address ranges {:#x}..{:#x} and '
                                  '{:#x}..{:#x}.'
-                                 .format(prev_lma, next_addr - 1, lma, end))
+                                 .format(base_addr + prev_lma,
+                                         base_addr + next_addr - 1,
+                                         base_addr + lma,
+                                         base_addr + top))
             prev_lma = lma
-            next_addr = end + 1
+            next_addr = top + 1
 
         # Merge any adjacent segments, bridging any sub-word gaps. This doesn't
         # do any other right padding: we'll do that on the final pass that
         # converts to 32-bit words.
         merged_segments = []  # type: List[Tuple[int, int, bytes]]
         next_word = 0
-        for lma, end, data in segments:
+        for lma, top, data in segments:
             # Round the LMA down to the previous word boundary. The non-overlap
             # check above should ensure that this is never actually less than
             # next_word.
@@ -239,22 +246,25 @@
             # If there isn't an aligned whole word between the two segments,
             # bridge the gap
             if merged_segments and next_word == lma_word:
-                last_lma_word, last_end, last_data = merged_segments[-1]
-                if last_end < lma:
-                    # The largest gap here is be something like last_end = 1;
-                    # lma = 7, which has size 2*4 - 1 - 1 = 6.
-                    assert lma - last_end <= 6
-                    last_data += bytes(lma - last_end)
-                merged_segments[-1] = (last_lma_word, end, last_data + data)
+                last_lma_word, last_top, last_data = merged_segments[-1]
+                if last_top < lma:
+                    # The largest gap possible here happens with addresses like
+                    # last_top = 0x100; lma = 0x107, which just bridges two
+                    # 4-byte words (0x100..0x103 and 0x104..0x107) with one
+                    # byte used from each, leaving 6 bytes to fill.
+                    assert lma - (last_top + 1) <= 6
+                    last_data += bytes(lma - (last_top + 1))
+                merged_segments[-1] = (last_lma_word, top, last_data + data)
             else:
                 # Pad on the left if necessary to ensure that lma is 32-bit
                 # aligned.
                 if lma % 4:
-                    merged_segments.append((lma_word, end, bytes(lma % 4) + data))
+                    merged_segments.append((lma_word, top, bytes(lma % 4) + data))
                 else:
-                    merged_segments.append((lma_word, end, data))
+                    merged_segments.append((lma_word, top, data))
 
-            next_word = 1 + (end // 4)
+            # The index of the first word that starts strictly above top.
+            next_word = 1 + (top // 4)
 
         # Assemble the bytes in each segment into little-endian 32-bit words.
         # Zero-extend any partial word at the end of a segment. Because of the
diff --git a/hw/top_earlgrey/chip_earlgrey_nexysvideo.core b/hw/top_earlgrey/chip_earlgrey_nexysvideo.core
index 2836fab..e46352b 100644
--- a/hw/top_earlgrey/chip_earlgrey_nexysvideo.core
+++ b/hw/top_earlgrey/chip_earlgrey_nexysvideo.core
@@ -35,14 +35,14 @@
 parameters:
   # XXX: This parameter needs to be absolute, or relative to the *.runs/synth_1
   # directory. It's best to pass it as absolute path when invoking fusesoc, e.g.
-  # --BootRomInitFile=$PWD/build-bin/sw/device/boot_rom/boot_rom_fpga_nexysvideo.32.vmem
+  # --BootRomInitFile=$PWD/build-bin/sw/device/boot_rom/boot_rom_fpga_nexysvideo.scr.40.vmem
   # XXX: The VMEM file should be added to the sources of the Vivado project to
   # make the Vivado dependency tracking work. However this requires changes to
   # fusesoc first.
   BootRomInitFile:
     datatype: str
-    description: Boot ROM initialization file in 32 bit vmem hex format
-    default: "../../../../../build-bin/sw/device/boot_rom/boot_rom_fpga_nexysvideo.32.vmem"
+    description: Scrambled boot ROM initialization file in 40 bit vmem hex format
+    default: "../../../../../build-bin/sw/device/boot_rom/boot_rom_fpga_nexysvideo.scr.40.vmem"
     paramtype: vlogparam
   OtpCtrlMemInitFile:
     datatype: str
diff --git a/hw/top_earlgrey/chip_earlgrey_verilator.cc b/hw/top_earlgrey/chip_earlgrey_verilator.cc
index 7b5856a..348817e 100644
--- a/hw/top_earlgrey/chip_earlgrey_verilator.cc
+++ b/hw/top_earlgrey/chip_earlgrey_verilator.cc
@@ -21,9 +21,9 @@
       "u_prim_ram_1p_adv.u_mem."
       "gen_generic.u_impl_generic");
 
-  MemArea rom(
-      top_scope + ".u_rom_ctrl.u_rom.u_prim_rom.gen_generic.u_impl_generic",
-      0x4000 / 4, 4);
+  MemArea rom(top_scope + (".u_rom_ctrl.u_rom.u_rom."
+                           "u_prim_rom.gen_generic.u_impl_generic"),
+              0x4000 / 4, 4);
   MemArea ram(top_scope + ".u_ram1p_ram_main." + ram1p_adv_scope, 0x20000 / 4,
               4);
   MemArea flash(top_scope +
diff --git a/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson b/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson
index af28623..0336d02 100644
--- a/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson
+++ b/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson
@@ -5040,6 +5040,26 @@
           expose: "true"
           name_top: RomCtrlBootRomInitFile
         }
+        {
+          name: RndCnstScrNonce
+          desc: Fixed nonce used for address / data scrambling
+          type: bit [63:0]
+          randcount: 64
+          randtype: data
+          name_top: RndCnstRomCtrlScrNonce
+          default: 0xfc00de9d9734c3fe
+          randwidth: 64
+        }
+        {
+          name: RndCnstScrKey
+          desc: Randomised constant used as a scrambling key for ROM data
+          type: bit [127:0]
+          randcount: 128
+          randtype: data
+          name_top: RndCnstRomCtrlScrKey
+          default: 0x23c074e020fd502869582e71443c8be0
+          randwidth: 128
+        }
       ]
       inter_signal_list:
       [
diff --git a/hw/top_earlgrey/dv/env/seq_lib/chip_sw_base_vseq.sv b/hw/top_earlgrey/dv/env/seq_lib/chip_sw_base_vseq.sv
index 25ba066..3c9630d 100644
--- a/hw/top_earlgrey/dv/env/seq_lib/chip_sw_base_vseq.sv
+++ b/hw/top_earlgrey/dv/env/seq_lib/chip_sw_base_vseq.sv
@@ -37,7 +37,7 @@
     cfg.flash_bank1_bkdr_vif.set_mem();
 
     // Backdoor load memories with sw images.
-    cfg.rom_bkdr_vif.load_mem_from_file({cfg.sw_images[SwTypeRom], ".32.vmem"});
+    cfg.rom_bkdr_vif.load_mem_from_file({cfg.sw_images[SwTypeRom], ".scr.40.vmem"});
 
     // TODO: the location of the main execution image should be randomized for either bank in future
     if (cfg.use_spi_load_bootstrap) begin
diff --git a/hw/top_earlgrey/dv/tb/chip_hier_macros.svh b/hw/top_earlgrey/dv/tb/chip_hier_macros.svh
index d71592f..cefaa1f 100644
--- a/hw/top_earlgrey/dv/tb/chip_hier_macros.svh
+++ b/hw/top_earlgrey/dv/tb/chip_hier_macros.svh
@@ -11,7 +11,7 @@
 `define CPU_HIER           `CHIP_HIER.u_rv_core_ibex
 `define RAM_MAIN_HIER      `CHIP_HIER.u_ram1p_ram_main.u_prim_ram_1p_adv.u_mem
 `define RAM_RET_HIER       `CHIP_HIER.u_ram1p_ram_ret_aon.u_prim_ram_1p_adv.u_mem
-`define ROM_HIER           `CHIP_HIER.u_rom_ctrl.u_rom.u_prim_rom
+`define ROM_HIER           `CHIP_HIER.u_rom_ctrl.u_rom.u_rom.u_prim_rom
 `define FLASH_HIER         `CHIP_HIER.u_flash_eflash.u_flash
 `define RSTMGR_HIER        `CHIP_HIER.u_rstmgr_aon
 `define CLKMGR_HIER        `CHIP_HIER.u_clkmgr_aon
diff --git a/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv b/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv
index 7e7698f..7aac243 100644
--- a/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv
+++ b/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv
@@ -2274,7 +2274,9 @@
 
   rom_ctrl #(
     .AlertAsyncOn(alert_handler_reg_pkg::AsyncOn[30:30]),
-    .BootRomInitFile(RomCtrlBootRomInitFile)
+    .BootRomInitFile(RomCtrlBootRomInitFile),
+    .RndCnstScrNonce(RndCnstRomCtrlScrNonce),
+    .RndCnstScrKey(RndCnstRomCtrlScrKey)
   ) u_rom_ctrl (
       // [30]: fatal
       .alert_tx_o  ( alert_tx[30:30] ),
diff --git a/hw/top_earlgrey/rtl/autogen/top_earlgrey_rnd_cnst_pkg.sv b/hw/top_earlgrey/rtl/autogen/top_earlgrey_rnd_cnst_pkg.sv
index 12dbfc5..01fb60b 100644
--- a/hw/top_earlgrey/rtl/autogen/top_earlgrey_rnd_cnst_pkg.sv
+++ b/hw/top_earlgrey/rtl/autogen/top_earlgrey_rnd_cnst_pkg.sv
@@ -228,4 +228,17 @@
     256'hA46ED80E5942BC02513FBDFD5A98A66805BC17DDED6CCD3271A3E37A08C92847
   };
 
+  ////////////////////////////////////////////
+  // rom_ctrl
+  ////////////////////////////////////////////
+  // Fixed nonce used for address / data scrambling
+  parameter bit [63:0] RndCnstRomCtrlScrNonce = {
+    64'hFC00DE9D9734C3FE
+  };
+
+  // Randomised constant used as a scrambling key for ROM data
+  parameter bit [127:0] RndCnstRomCtrlScrKey = {
+    128'h23C074E020FD502869582E71443C8BE0
+  };
+
 endpackage : top_earlgrey_rnd_cnst_pkg
diff --git a/hw/top_earlgrey/util/opentitan_earlgrey_usbdev_pin_config_sim.sh b/hw/top_earlgrey/util/opentitan_earlgrey_usbdev_pin_config_sim.sh
index b5a3232..da2c9c4 100755
--- a/hw/top_earlgrey/util/opentitan_earlgrey_usbdev_pin_config_sim.sh
+++ b/hw/top_earlgrey/util/opentitan_earlgrey_usbdev_pin_config_sim.sh
@@ -7,7 +7,7 @@
 VERILATOR=build/lowrisc_systems_chip_earlgrey_verilator_0.1/sim-verilator/Vchip_earlgrey_verilator
 
 # Code to load
-ROMCODE=build-bin/sw/device/boot_rom/boot_rom_sim_verilator.elf
+ROMCODE=build-bin/sw/device/boot_rom/boot_rom_sim_verilator.scr.40.vmem
 FLASH=build-bin/sw/device/examples/hello_usbdev/hello_usbdev_sim_verilator.elf
 OTP=build-bin/sw/device/otp_img/otp_img_sim_verilator.vmem