/*
 * File automatically generated by
 * gengen 1.4.2 by Lorenzo Bettini 
 * http://www.gnu.org/software/gengen
 */

#ifndef PMP_CSR_1_GEN_CLASS_H
#define PMP_CSR_1_GEN_CLASS_H

#include <string>
#include <iostream>

using std::string;
using std::ostream;

class pmp_csr_1_gen_class
{
 protected:
  int addr_idx;
  int addr_offset;
  int cfg_idx;
  int cfg_sub_idx;
  int expected_pmpaddr_fail;
  int expected_pmpcfg_fail;
  int expected_seccfg_fail;
  int group_pmp;
  int lock_bypass;
  int lock_once;
  int m_mode_rwx;
  int pmp_lock;
  int pre_sec_mml;
  int pre_sec_mmwp;
  int revert_rwx;
  int sec_mml;
  int sec_mmwp;
  int sec_rlb;
  string tag;

 public:
  pmp_csr_1_gen_class() :
    addr_idx (0), addr_offset (0), cfg_idx (0), cfg_sub_idx (0), expected_pmpaddr_fail (0), expected_pmpcfg_fail (0), expected_seccfg_fail (0), group_pmp (0), lock_bypass (0), lock_once (0), m_mode_rwx (0), pmp_lock (0), pre_sec_mml (0), pre_sec_mmwp (0), revert_rwx (0), sec_mml (0), sec_mmwp (0), sec_rlb (0)
  {
  }
  
  pmp_csr_1_gen_class(int _addr_idx, int _addr_offset, int _cfg_idx, int _cfg_sub_idx, int _expected_pmpaddr_fail, int _expected_pmpcfg_fail, int _expected_seccfg_fail, int _group_pmp, int _lock_bypass, int _lock_once, int _m_mode_rwx, int _pmp_lock, int _pre_sec_mml, int _pre_sec_mmwp, int _revert_rwx, int _sec_mml, int _sec_mmwp, int _sec_rlb, const string &_tag) :
    addr_idx (_addr_idx), addr_offset (_addr_offset), cfg_idx (_cfg_idx), cfg_sub_idx (_cfg_sub_idx), expected_pmpaddr_fail (_expected_pmpaddr_fail), expected_pmpcfg_fail (_expected_pmpcfg_fail), expected_seccfg_fail (_expected_seccfg_fail), group_pmp (_group_pmp), lock_bypass (_lock_bypass), lock_once (_lock_once), m_mode_rwx (_m_mode_rwx), pmp_lock (_pmp_lock), pre_sec_mml (_pre_sec_mml), pre_sec_mmwp (_pre_sec_mmwp), revert_rwx (_revert_rwx), sec_mml (_sec_mml), sec_mmwp (_sec_mmwp), sec_rlb (_sec_rlb), tag (_tag)
  {
  }

  void set_addr_idx(int _addr_idx)
  {
    addr_idx = _addr_idx;
  }

  void set_addr_offset(int _addr_offset)
  {
    addr_offset = _addr_offset;
  }

  void set_cfg_idx(int _cfg_idx)
  {
    cfg_idx = _cfg_idx;
  }

  void set_cfg_sub_idx(int _cfg_sub_idx)
  {
    cfg_sub_idx = _cfg_sub_idx;
  }

  void set_expected_pmpaddr_fail(int _expected_pmpaddr_fail)
  {
    expected_pmpaddr_fail = _expected_pmpaddr_fail;
  }

  void set_expected_pmpcfg_fail(int _expected_pmpcfg_fail)
  {
    expected_pmpcfg_fail = _expected_pmpcfg_fail;
  }

  void set_expected_seccfg_fail(int _expected_seccfg_fail)
  {
    expected_seccfg_fail = _expected_seccfg_fail;
  }

  void set_group_pmp(int _group_pmp)
  {
    group_pmp = _group_pmp;
  }

  void set_lock_bypass(int _lock_bypass)
  {
    lock_bypass = _lock_bypass;
  }

  void set_lock_once(int _lock_once)
  {
    lock_once = _lock_once;
  }

  void set_m_mode_rwx(int _m_mode_rwx)
  {
    m_mode_rwx = _m_mode_rwx;
  }

  void set_pmp_lock(int _pmp_lock)
  {
    pmp_lock = _pmp_lock;
  }

  void set_pre_sec_mml(int _pre_sec_mml)
  {
    pre_sec_mml = _pre_sec_mml;
  }

  void set_pre_sec_mmwp(int _pre_sec_mmwp)
  {
    pre_sec_mmwp = _pre_sec_mmwp;
  }

  void set_revert_rwx(int _revert_rwx)
  {
    revert_rwx = _revert_rwx;
  }

  void set_sec_mml(int _sec_mml)
  {
    sec_mml = _sec_mml;
  }

  void set_sec_mmwp(int _sec_mmwp)
  {
    sec_mmwp = _sec_mmwp;
  }

  void set_sec_rlb(int _sec_rlb)
  {
    sec_rlb = _sec_rlb;
  }

  void set_tag(const string &_tag)
  {
    tag = _tag;
  }

  void generate_pmp_csr_1(ostream &stream, unsigned int indent = 0)
  {
    string indent_str (indent, ' ');
    indent = 0;
  
    stream << "\n";
    stream << indent_str;
    stream << "/*";
    stream << "\n";
    stream << indent_str;
    stream << " * ";
    stream << tag;
    stream << "\n";
    stream << indent_str;
    stream << " * Generated from gen_pmp_test.cc and test_pmp_csr_1.cc_skel.";
    stream << "\n";
    stream << indent_str;
    stream << " * ";
    stream << "\n";
    stream << indent_str;
    stream << " * This test program is verify the pmp CSR access when seccfg introduced.";
    stream << "\n";
    stream << indent_str;
    stream << " * It's expected to executed from M mode.";
    stream << "\n";
    stream << indent_str;
    stream << " * ";
    stream << "\n";
    stream << indent_str;
    stream << " * Remarks:";
    stream << "\n";
    stream << indent_str;
    stream << " * - CSR protection for non-M mode access is assumed and not coverred.";
    stream << "\n";
    stream << indent_str;
    stream << " * - The access on invalid CSR index like pmpcfg1 for rv64 is not coverred.";
    stream << "\n";
    stream << indent_str;
    stream << " * - Executed on RV64 only.";
    stream << "\n";
    stream << indent_str;
    stream << " */";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "/*";
    stream << "\n";
    stream << indent_str;
    stream << " * Macros from encoding.h";
    stream << "\n";
    stream << indent_str;
    stream << " */";
    stream << "\n";
    stream << indent_str;
    stream << "#define MSTATUS_MPP         0x00001800";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "#define PMP_R     0x01";
    stream << "\n";
    stream << indent_str;
    stream << "#define PMP_W     0x02";
    stream << "\n";
    stream << indent_str;
    stream << "#define PMP_X     0x04";
    stream << "\n";
    stream << indent_str;
    stream << "#define PMP_A     0x18";
    stream << "\n";
    stream << indent_str;
    stream << "#define PMP_L     0x80";
    stream << "\n";
    stream << indent_str;
    stream << "#define PMP_SHIFT 2";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "#if ((PMP_R | PMP_W | PMP_X) != 0x7)";
    stream << "\n";
    stream << indent_str;
    stream << "#error unexpected";
    stream << "\n";
    stream << indent_str;
    stream << "#endif";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "#define PMP_OFF   0x0";
    stream << "\n";
    stream << indent_str;
    stream << "#define PMP_TOR   0x08";
    stream << "\n";
    stream << indent_str;
    stream << "#define PMP_NA4   0x10";
    stream << "\n";
    stream << indent_str;
    stream << "#define PMP_NAPOT 0x18";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "#define MSECCFG_MML  0x1";
    stream << "\n";
    stream << indent_str;
    stream << "#define MSECCFG_MMWP 0x2";
    stream << "\n";
    stream << indent_str;
    stream << "#define MSECCFG_RLB  0x4";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "#define TEST_RW 1";
    stream << "\n";
    stream << indent_str;
    stream << "#define TEST_FETCH 1";
    stream << "\n";
    stream << indent_str;
    stream << "/*";
    stream << "\n";
    stream << indent_str;
    stream << " * Whether rwx share single cfg for M mode";
    stream << "\n";
    stream << indent_str;
    stream << " * When ";
    stream << "@";
    stream << "set_sec_mml";
    stream << "@";
    stream << " set, it must be 0, otherwise unexpected exception";
    stream << "\n";
    stream << indent_str;
    stream << " */";
    stream << "\n";
    stream << indent_str;
    stream << "#define M_MODE_RWX ";
    stream << m_mode_rwx;
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "#define CAUSE_LOAD_ACCESS 0x5";
    stream << "\n";
    stream << indent_str;
    stream << "#define CAUSE_STORE_ACCESS 0x7";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "typedef unsigned long reg_t;";
    stream << "\n";
    stream << indent_str;
    stream << "typedef unsigned long uintptr_t;";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "/*";
    stream << "\n";
    stream << indent_str;
    stream << " * functions from syscalls.c";
    stream << "\n";
    stream << indent_str;
    stream << " */";
    stream << "\n";
    stream << indent_str;
    stream << "#if PRINTF_SUPPORTED";
    stream << "\n";
    stream << indent_str;
    stream << "int printf(const char* fmt, ...);";
    stream << "\n";
    stream << indent_str;
    stream << "#else";
    stream << "\n";
    stream << indent_str;
    stream << "#define printf(...)";
    stream << "\n";
    stream << indent_str;
    stream << "#endif";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "void __attribute__((noreturn)) tohost_exit(uintptr_t code);";
    stream << "\n";
    stream << indent_str;
    stream << "void exit(int code);";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "/*";
    stream << "\n";
    stream << indent_str;
    stream << " * local status";
    stream << "\n";
    stream << indent_str;
    stream << " */";
    stream << "\n";
    stream << indent_str;
    stream << "#define TEST_MEM_START 0x80200000";
    stream << "\n";
    stream << indent_str;
    stream << "#define TEST_MEM_END 0x80240000";
    stream << "\n";
    stream << indent_str;
    stream << "#define U_MEM_END (TEST_MEM_END + 0x10000)";
    stream << "\n";
    stream << indent_str;
    stream << "#define FAKE_ADDRESS 0x10000000";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "static const unsigned long expected_seccfg_fail = ";
    stream << expected_seccfg_fail;
    stream << ";";
    stream << "\n";
    stream << indent_str;
    stream << "static unsigned actual_seccfg_fail = 0;";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "static const unsigned long expected_pmpaddr_fail = ";
    stream << expected_pmpaddr_fail;
    stream << ";";
    stream << "\n";
    stream << indent_str;
    stream << "static unsigned actual_pmpaddr_fail = 0;";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "static const unsigned long expected_pmpcfg_fail = ";
    stream << expected_pmpcfg_fail;
    stream << ";";
    stream << "\n";
    stream << indent_str;
    stream << "static unsigned actual_pmpcfg_fail = 0;";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "static void checkTestResult(void);";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "/*";
    stream << "\n";
    stream << indent_str;
    stream << " * override syscalls.c.";
    stream << "\n";
    stream << indent_str;
    stream << " *  currently simply skip to nexp instruction";
    stream << "\n";
    stream << indent_str;
    stream << " */";
    stream << "\n";
    stream << indent_str;
    stream << "uintptr_t handle_trap(uintptr_t cause, uintptr_t epc, uintptr_t regs[32])";
    stream << "\n";
    stream << indent_str;
    stream << "{ ";
    stream << "\n";
    stream << indent_str;
    stream << "    tohost_exit(1337);";
    stream << "\n";
    stream << indent_str;
    stream << "}";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "__attribute ((section(\".text_test_foo\"), noinline))";
    stream << "\n";
    stream << indent_str;
    stream << "void target_foo() {";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"nop\");";
    stream << "\n";
    stream << indent_str;
    stream << "}";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "__attribute ((section(\".data_test_arr\"), aligned(8)))";
    stream << "\n";
    stream << indent_str;
    stream << "volatile unsigned char target_arr[100] = {";
    stream << "\n";
    stream << indent_str;
    stream << "        1,2,3,4,5,6,7,8,";
    stream << "\n";
    stream << indent_str;
    stream << "};";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "__attribute ((section(\".text_umode\"), noinline))";
    stream << "\n";
    stream << indent_str;
    stream << "void target_foo_U() {";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"nop\");";
    stream << "\n";
    stream << indent_str;
    stream << "}";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "__attribute ((section(\".data_umode\"), aligned(8)))";
    stream << "\n";
    stream << indent_str;
    stream << "volatile unsigned char target_arr_U[100] = {";
    stream << "\n";
    stream << indent_str;
    stream << "        1,2,3,4,5,6,7,8,";
    stream << "\n";
    stream << indent_str;
    stream << "};";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "/*";
    stream << "\n";
    stream << indent_str;
    stream << " * On processor_t::reset():";
    stream << "\n";
    stream << indent_str;
    stream << " *  - set_csr(CSR_PMPADDR0, ~reg_t(0));";
    stream << "\n";
    stream << indent_str;
    stream << " *    set_csr(CSR_PMPCFG0, PMP_R | PMP_W | PMP_X | PMP_NAPOT);";
    stream << "\n";
    stream << indent_str;
    stream << " */";
    stream << "\n";
    stream << indent_str;
    stream << "static void set_cfg() {";
    stream << "\n";
    stream << indent_str;
    stream << "#if 1 // ";
    stream << "@";
    stream << "set_rlb_at_start:int";
    stream << "@";
    stream << "\n";
    stream << indent_str;
    stream << "    /*";
    stream << "\n";
    stream << indent_str;
    stream << "     * set MSECCFG_RLB to avoid locked at start";
    stream << "\n";
    stream << indent_str;
    stream << "     */";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"csrs 0x747, %0 \\n\"::\"r\"(MSECCFG_RLB));";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"nop\");";
    stream << "\n";
    stream << indent_str;
    stream << "#endif";
    stream << "\n";
    stream << indent_str;
    indent = 4;
    stream << "    ";
    indent = 0;
    stream << "\n";
    stream << indent_str;
    stream << "//------------------------Set current status before the test target (CSR access)";
    stream << "\n";
    stream << indent_str;
    stream << "    /*";
    stream << "\n";
    stream << indent_str;
    stream << "     * Set pmp0cfg for M mode (M_MEM), and pmp1cfg for base of TOR.";
    stream << "\n";
    stream << indent_str;
    stream << "     * Then use pmp2cfg for TEST_MEM. Both test code and data share PMP entrance.";
    stream << "\n";
    stream << indent_str;
    stream << "     * Also use pmp3cfg for fixed U mode (U_MEM).";
    stream << "\n";
    stream << indent_str;
    stream << "     */";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"csrw pmpaddr7, %0 \\n\" :: \"r\"(0x8ffffff8 >> 2) : \"memory\");       // for ibex signature addr";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"csrw pmpaddr3, %0 \\n\" :: \"r\"(U_MEM_END >> 2) : \"memory\");";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"csrw pmpaddr2, %0 \\n\" :: \"r\"(TEST_MEM_END >> 2) : \"memory\");";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"csrw pmpaddr1, %0 \\n\" :: \"r\"(TEST_MEM_START >> 2) : \"memory\");";
    stream << "\n";
    stream << indent_str;
    indent = 4;
    stream << "    ";
    indent = 0;
    stream << "\n";
    stream << indent_str;
    stream << "#if M_MODE_RWX";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"csrw pmpaddr0, %0 \\n\" :: \"r\"((0x80000000 >> 2) | 0xfffff) : \"memory\");";
    stream << "\n";
    stream << indent_str;
    stream << "    reg_t cfg0 = (PMP_R | PMP_W | PMP_X | PMP_NAPOT);";
    stream << "\n";
    stream << indent_str;
    stream << "    reg_t cfg1 = (PMP_R | PMP_W | PMP_NAPOT) << 24;";
    stream << "\n";
    stream << indent_str;
    stream << "#else";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"csrw pmpaddr6, %0 \\n\" :: \"r\"(TEST_MEM_START >> 2) : \"memory\");   // for data";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"csrw pmpaddr5, %0 \\n\" :: \"r\"(0x80010000 >> 2) : \"memory\");       // for code";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"csrw pmpaddr4, %0 \\n\" :: \"r\"(0x80000000 >> 2) : \"memory\");       // addr start";
    stream << "\n";
    stream << indent_str;
    stream << "    reg_t cfg0 = PMP_OFF;";
    stream << "\n";
    stream << indent_str;
    stream << "    reg_t cfg1 = PMP_OFF | ((PMP_R | PMP_W | PMP_NAPOT) << 24)";
    stream << "\n";
    stream << indent_str;
    stream << "                         | ((PMP_R | PMP_W | PMP_TOR) << 16) ";
    stream << "\n";
    stream << indent_str;
    stream << "                         | ((PMP_X | PMP_TOR) << 8);";
    stream << "\n";
    stream << indent_str;
    stream << "#endif";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "    if (";
    stream << pre_sec_mml;
    stream << ") {    // need to set L bit for M mode code access";
    stream << "\n";
    stream << indent_str;
    stream << "#if M_MODE_RWX";
    stream << "\n";
    stream << indent_str;
    stream << "        cfg0 |= PMP_L;";
    stream << "\n";
    stream << indent_str;
    stream << "        cfg1 |= (PMP_L << 24);";
    stream << "\n";
    stream << indent_str;
    stream << "#else";
    stream << "\n";
    stream << indent_str;
    stream << "        cfg1 |= ((PMP_L << 8) | (PMP_L << 16) | (PMP_L << 24));";
    stream << "\n";
    stream << indent_str;
    stream << "#endif";
    stream << "\n";
    stream << indent_str;
    stream << "    }";
    stream << "\n";
    stream << indent_str;
    indent = 4;
    stream << "    ";
    indent = 0;
    stream << "\n";
    stream << indent_str;
    stream << "    reg_t sub_cfg = PMP_R | PMP_W | PMP_X | PMP_TOR | ((";
    stream << lock_once;
    stream << " || ";
    stream << pmp_lock;
    stream << ") ? PMP_L : 0);";
    stream << "\n";
    stream << indent_str;
    stream << "    cfg0 |= sub_cfg << 24;    // for U_MEM";
    stream << "\n";
    stream << indent_str;
    stream << "    cfg0 |= sub_cfg << 16;    // for TEST_MEM";
    stream << "\n";
    stream << indent_str;
    indent = 4;
    stream << "    ";
    indent = 0;
    stream << "\n";
    stream << indent_str;
    stream << "#if __riscv_xlen == 64";
    stream << "\n";
    stream << indent_str;
    stream << "    cfg0 |= (cfg1 << 32);";
    stream << "\n";
    stream << indent_str;
    stream << "#else";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"csrw pmpcfg1, %0 \\n\"";
    stream << "\n";
    stream << indent_str;
    stream << "                :";
    stream << "\n";
    stream << indent_str;
    stream << "                : \"r\"(cfg1)";
    stream << "\n";
    stream << indent_str;
    stream << "                : \"memory\");";
    stream << "\n";
    stream << indent_str;
    stream << "#endif // __riscv_xlen == 64";
    stream << "\n";
    stream << indent_str;
    indent = 4;
    stream << "    ";
    indent = 0;
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"csrw pmpcfg0, %0 \\n\"";
    stream << "\n";
    stream << indent_str;
    stream << "                :";
    stream << "\n";
    stream << indent_str;
    stream << "                : \"r\"(cfg0)";
    stream << "\n";
    stream << indent_str;
    stream << "                : \"memory\");";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "    if (";
    stream << lock_once;
    stream << " != ";
    stream << pmp_lock;
    stream << ") {";
    stream << "\n";
    stream << indent_str;
    stream << "        reg_t lock_bits = (PMP_L << 16) | ((reg_t)PMP_L << 24); // avoid use (default) int type";
    stream << "\n";
    stream << indent_str;
    stream << "        if (";
    stream << pmp_lock;
    stream << ") {";
    stream << "\n";
    stream << indent_str;
    stream << "            asm volatile (\"csrs pmpcfg0, %0 \\n\"";
    stream << "\n";
    stream << indent_str;
    stream << "                            :";
    stream << "\n";
    stream << indent_str;
    stream << "                            : \"r\"(lock_bits)";
    stream << "\n";
    stream << indent_str;
    stream << "                            : \"memory\");";
    stream << "\n";
    stream << indent_str;
    stream << "        } else {";
    stream << "\n";
    stream << indent_str;
    stream << "            asm volatile (\"csrc pmpcfg0, %0 \\n\"";
    stream << "\n";
    stream << indent_str;
    stream << "                            :";
    stream << "\n";
    stream << indent_str;
    stream << "                            : \"r\"(lock_bits)";
    stream << "\n";
    stream << indent_str;
    stream << "                            : \"memory\");";
    stream << "\n";
    stream << indent_str;
    stream << "        }";
    stream << "\n";
    stream << indent_str;
    stream << "    }";
    stream << "\n";
    stream << indent_str;
    indent = 4;
    stream << "    ";
    indent = 0;
    stream << "\n";
    stream << indent_str;
    stream << "    // set proc->state.mseccfg";
    stream << "\n";
    stream << indent_str;
    stream << "    const unsigned seccfg_bits = (";
    stream << lock_bypass;
    stream << " ? MSECCFG_RLB : 0) ";
    stream << "\n";
    stream << indent_str;
    stream << "            | (";
    stream << pre_sec_mml;
    stream << " ? MSECCFG_MML : 0) ";
    stream << "\n";
    stream << indent_str;
    stream << "            | (";
    stream << pre_sec_mmwp;
    stream << " ? MSECCFG_MMWP : 0);";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"csrw 0x747, %0 \\n\"::\"r\"(seccfg_bits));";
    stream << "\n";
    stream << indent_str;
    indent = 4;
    stream << "    ";
    indent = 0;
    stream << "\n";
    stream << indent_str;
    stream << "//------------------------Test target";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"nop\");";
    stream << "\n";
    stream << indent_str;
    stream << "    /*";
    stream << "\n";
    stream << indent_str;
    stream << "     * Need to separate pmp and seccfg access since pmplock_recorded status may be ";
    stream << "\n";
    stream << indent_str;
    stream << "     * updated again when accessing pmpcfg.";
    stream << "\n";
    stream << indent_str;
    stream << "     */";
    stream << "\n";
    stream << indent_str;
    stream << "    reg_t wval = 0, rval;";
    stream << "\n";
    stream << indent_str;
    stream << "    reg_t prev_val = 0;";
    stream << "\n";
    stream << indent_str;
    stream << "#if ";
    stream << group_pmp;
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"csrr %0, pmpaddr";
    stream << addr_idx;
    stream << " \\n\"";
    stream << "\n";
    stream << indent_str;
    stream << "            : \"=r\"(rval));";
    stream << "\n";
    stream << indent_str;
    stream << "    // give a valid value for both NAPOT and TOR";
    stream << "\n";
    stream << indent_str;
    stream << "    if (";
    stream << addr_idx;
    stream << " == 0) {";
    stream << "\n";
    stream << indent_str;
    stream << "        wval = ((rval + 1) << 1) - 1;   // NAPOT mask";
    stream << "\n";
    stream << indent_str;
    stream << "    } else {";
    stream << "\n";
    stream << indent_str;
    stream << "        wval = (rval << 1) + ";
    stream << addr_offset;
    stream << ";   ";
    stream << "\n";
    stream << indent_str;
    stream << "    }";
    stream << "\n";
    stream << indent_str;
    stream << "    prev_val = rval;";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"csrw pmpaddr";
    stream << addr_idx;
    stream << ", %1 \\n\"";
    stream << "\n";
    stream << indent_str;
    stream << "                \"\\tcsrr %0, pmpaddr";
    stream << addr_idx;
    stream << " \\n\"";
    stream << "\n";
    stream << indent_str;
    stream << "            : \"=r\"(rval)";
    stream << "\n";
    stream << indent_str;
    stream << "            : \"r\"(wval)";
    stream << "\n";
    stream << indent_str;
    stream << "              : \"memory\");";
    stream << "\n";
    stream << indent_str;
    stream << "    if (wval != rval) {";
    stream << "\n";
    stream << indent_str;
    stream << "        actual_pmpaddr_fail = 1;";
    stream << "\n";
    stream << indent_str;
    stream << "    }";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"csrw pmpaddr";
    stream << addr_idx;
    stream << ", %0 \\n\"";
    stream << "\n";
    stream << indent_str;
    stream << "            :: \"r\"(prev_val));";
    stream << "\n";
    stream << indent_str;
    stream << "    // Update cfg0 to avoid changing idx other than ";
    stream << cfg_sub_idx;
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"csrr %0, pmpcfg";
    stream << cfg_idx;
    stream << " \\n\"";
    stream << "\n";
    stream << indent_str;
    stream << "                    : \"=r\"(cfg0)";
    stream << "\n";
    stream << indent_str;
    stream << "                    :";
    stream << "\n";
    stream << indent_str;
    stream << "                    : \"memory\");";
    stream << "\n";
    stream << indent_str;
    indent = 4;
    stream << "    ";
    indent = 0;
    stream << "\n";
    stream << indent_str;
    stream << "    // reuse lock_once here since it's for RLB and independent with pmp_lock";
    stream << "\n";
    stream << indent_str;
    stream << "    wval = cfg0 ^ ((reg_t)(";
    stream << revert_rwx;
    stream << " | (";
    stream << lock_once;
    stream << " ? PMP_L : 0)) << (";
    stream << cfg_sub_idx;
    stream << " * 8));";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"csrw pmpcfg";
    stream << cfg_idx;
    stream << ", %1 \\n\"";
    stream << "\n";
    stream << indent_str;
    stream << "                \"\\tcsrr %0, pmpcfg";
    stream << cfg_idx;
    stream << " \\n\"";
    stream << "\n";
    stream << indent_str;
    stream << "            : \"=r\"(rval)";
    stream << "\n";
    stream << indent_str;
    stream << "            : \"r\"(wval)";
    stream << "\n";
    stream << indent_str;
    stream << "              : \"memory\");";
    stream << "\n";
    stream << indent_str;
    stream << "    if (wval != rval) {";
    stream << "\n";
    stream << indent_str;
    stream << "        actual_pmpcfg_fail = 1;";
    stream << "\n";
    stream << indent_str;
    stream << "    }";
    stream << "\n";
    stream << indent_str;
    stream << "#else";
    stream << "\n";
    stream << indent_str;
    stream << "    /*";
    stream << "\n";
    stream << indent_str;
    stream << "     * need to set PMP_L for cfg0 otherwise next PC will illegal";
    stream << "\n";
    stream << indent_str;
    stream << "     * This is a little coverage hole for non-PMP_L + mml, which should be";
    stream << "\n";
    stream << indent_str;
    stream << "     * a restricted use case and can be accepted anyway.";
    stream << "\n";
    stream << indent_str;
    stream << "     */ ";
    stream << "\n";
    stream << indent_str;
    stream << "    if (";
    stream << sec_mml;
    stream << ") {    ";
    stream << "\n";
    stream << indent_str;
    stream << "#if M_MODE_RWX";
    stream << "\n";
    stream << indent_str;
    stream << "        asm volatile (\"csrs pmpcfg0, %0 \\n\"::\"r\"(PMP_L));";
    stream << "\n";
    stream << indent_str;
    stream << "#else";
    stream << "\n";
    stream << indent_str;
    stream << "#if __riscv_xlen == 64";
    stream << "\n";
    stream << indent_str;
    stream << "        asm volatile (\"csrs pmpcfg0, %0 \\n\"::\"r\"(((reg_t)PMP_L << 40) | ((reg_t)PMP_L << 48)));";
    stream << "\n";
    stream << indent_str;
    stream << "#else";
    stream << "\n";
    stream << indent_str;
    stream << "        asm volatile (\"csrs pmpcfg1, %0 \\n\"::\"r\"((PMP_L << 8) | (PMP_L << 16) | (PMP_L << 24)));";
    stream << "\n";
    stream << indent_str;
    stream << "#endif // __riscv_xlen == 64";
    stream << "\n";
    stream << indent_str;
    stream << "#endif // M_MODE_RWX";
    stream << "\n";
    stream << indent_str;
    stream << "    }";
    stream << "\n";
    stream << indent_str;
    indent = 4;
    stream << "    ";
    indent = 0;
    stream << "\n";
    stream << indent_str;
    stream << "    wval = (";
    stream << sec_rlb;
    stream << " ? MSECCFG_RLB : 0) ";
    stream << "\n";
    stream << indent_str;
    stream << "            | (";
    stream << sec_mml;
    stream << " ? MSECCFG_MML : 0) ";
    stream << "\n";
    stream << indent_str;
    stream << "            | (";
    stream << sec_mmwp;
    stream << " ? MSECCFG_MMWP : 0);";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"csrw 0x747, %1 \\n\"";
    stream << "\n";
    stream << indent_str;
    stream << "                \"\\tcsrr %0, 0x747 \\n\"";
    stream << "\n";
    stream << indent_str;
    stream << "            : \"=r\"(rval)";
    stream << "\n";
    stream << indent_str;
    stream << "            : \"r\"(wval)";
    stream << "\n";
    stream << indent_str;
    stream << "              : \"memory\");";
    stream << "\n";
    stream << indent_str;
    stream << "    reg_t expected_val = wval & (MSECCFG_RLB | MSECCFG_MML | MSECCFG_MMWP);";
    stream << "\n";
    stream << indent_str;
    stream << "    /*";
    stream << "\n";
    stream << indent_str;
    stream << "     * pre_sec_mml means cfg0 locked";
    stream << "\n";
    stream << indent_str;
    stream << "     * pmp_lock means cfg2/3 locked";
    stream << "\n";
    stream << indent_str;
    stream << "     * sec_mml is the test coverage hole just mentioned";
    stream << "\n";
    stream << indent_str;
    stream << "     */";
    stream << "\n";
    stream << indent_str;
    stream << "    if ((";
    stream << pre_sec_mml;
    stream << " || ";
    stream << pmp_lock;
    stream << " || ";
    stream << sec_mml;
    stream << ") ";
    stream << "\n";
    stream << indent_str;
    stream << "            && ";
    stream << lock_bypass;
    stream << " == 0) {";
    stream << "\n";
    stream << indent_str;
    stream << "        expected_val &= ~MSECCFG_RLB;";
    stream << "\n";
    stream << indent_str;
    stream << "    } ";
    stream << "\n";
    stream << indent_str;
    stream << "    if (";
    stream << pre_sec_mml;
    stream << ") {";
    stream << "\n";
    stream << indent_str;
    stream << "        expected_val |= MSECCFG_MML;";
    stream << "\n";
    stream << indent_str;
    stream << "    }";
    stream << "\n";
    stream << indent_str;
    stream << "    if (";
    stream << pre_sec_mmwp;
    stream << ") {";
    stream << "\n";
    stream << indent_str;
    stream << "        expected_val |= MSECCFG_MMWP;";
    stream << "\n";
    stream << indent_str;
    stream << "    }";
    stream << "\n";
    stream << indent_str;
    indent = 4;
    stream << "    ";
    indent = 0;
    stream << "\n";
    stream << indent_str;
    stream << "    if (expected_val != rval) actual_seccfg_fail = 1;";
    stream << "\n";
    stream << indent_str;
    stream << "#endif";
    stream << "\n";
    stream << indent_str;
    stream << "}";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "static void checkTestResult() {";
    stream << "\n";
    stream << indent_str;
    stream << "    int ret = 0;";
    stream << "\n";
    stream << indent_str;
    stream << "    if (expected_seccfg_fail != actual_seccfg_fail) {";
    stream << "\n";
    stream << indent_str;
    stream << "        ret += 1;";
    stream << "\n";
    stream << indent_str;
    stream << "    }";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "    if (expected_pmpaddr_fail != actual_pmpaddr_fail) {";
    stream << "\n";
    stream << indent_str;
    stream << "        ret += 2;";
    stream << "\n";
    stream << indent_str;
    stream << "    }";
    stream << "\n";
    stream << indent_str;
    indent = 4;
    stream << "    ";
    indent = 0;
    stream << "\n";
    stream << indent_str;
    stream << "    if (expected_pmpcfg_fail != actual_pmpcfg_fail) {";
    stream << "\n";
    stream << indent_str;
    stream << "        ret += 4;";
    stream << "\n";
    stream << indent_str;
    stream << "    }";
    stream << "\n";
    stream << indent_str;
    indent = 4;
    stream << "    ";
    indent = 0;
    stream << "\n";
    stream << indent_str;
    indent = 4;
    stream << "    ";
    indent = 0;
    stream << "\n";
    stream << indent_str;
    stream << "    exit(ret); ";
    stream << "\n";
    stream << indent_str;
    stream << "}";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "int main() {";
    stream << "\n";
    stream << indent_str;
    stream << "    // assert in M mode";
    stream << "\n";
    stream << indent_str;
    stream << "    set_cfg();";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "    checkTestResult();";
    stream << "\n";
    stream << indent_str;
    stream << "    return 0; // assert 0";
    stream << "\n";
    stream << indent_str;
    stream << "}";
    stream << "\n";
    stream << indent_str;
  }
};

#endif // PMP_CSR_1_GEN_CLASS_H
