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

#ifndef PMP_OK_SHARE_1_GEN_CLASS_H
#define PMP_OK_SHARE_1_GEN_CLASS_H

#include <string>
#include <iostream>

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

class pmp_ok_share_1_gen_class
{
 protected:
  int enable_umode_test;
  int expected_r_fail;
  int expected_w_fail;
  int expected_x_fail;
  int m_mode_rwx;
  int pmp_l;
  int pmp_r;
  int pmp_x;
  string tag;
  int typex;

 public:
  pmp_ok_share_1_gen_class() :
    enable_umode_test (0), expected_r_fail (0), expected_w_fail (0), expected_x_fail (0), m_mode_rwx (0), pmp_l (0), pmp_r (0), pmp_x (0), typex (0)
  {
  }
  
  pmp_ok_share_1_gen_class(int _enable_umode_test, int _expected_r_fail, int _expected_w_fail, int _expected_x_fail, int _m_mode_rwx, int _pmp_l, int _pmp_r, int _pmp_x, const string &_tag, int _typex) :
    enable_umode_test (_enable_umode_test), expected_r_fail (_expected_r_fail), expected_w_fail (_expected_w_fail), expected_x_fail (_expected_x_fail), m_mode_rwx (_m_mode_rwx), pmp_l (_pmp_l), pmp_r (_pmp_r), pmp_x (_pmp_x), tag (_tag), typex (_typex)
  {
  }

  void set_enable_umode_test(int _enable_umode_test)
  {
    enable_umode_test = _enable_umode_test;
  }

  void set_expected_r_fail(int _expected_r_fail)
  {
    expected_r_fail = _expected_r_fail;
  }

  void set_expected_w_fail(int _expected_w_fail)
  {
    expected_w_fail = _expected_w_fail;
  }

  void set_expected_x_fail(int _expected_x_fail)
  {
    expected_x_fail = _expected_x_fail;
  }

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

  void set_pmp_l(int _pmp_l)
  {
    pmp_l = _pmp_l;
  }

  void set_pmp_r(int _pmp_r)
  {
    pmp_r = _pmp_r;
  }

  void set_pmp_x(int _pmp_x)
  {
    pmp_x = _pmp_x;
  }

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

  void set_typex(int _typex)
  {
    typex = _typex;
  }

  void generate_pmp_ok_share_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_ok_share_1.cc_skel.";
    stream << "\n";
    stream << indent_str;
    stream << " * ";
    stream << "\n";
    stream << indent_str;
    stream << " * This test program is to test pmp_ok() when share mode (RW=01).";
    stream << "\n";
    stream << indent_str;
    stream << " * Based on other test cases for mseccfg stiky bits, this test expects following:";
    stream << "\n";
    stream << indent_str;
    stream << " * - RW = 01. For RW != 01, less combinations to show it fail.";
    stream << "\n";
    stream << indent_str;
    stream << " * - MML set";
    stream << "\n";
    stream << indent_str;
    stream << " * - Regine matched.";
    stream << "\n";
    stream << indent_str;
    stream << " * ";
    stream << "\n";
    stream << indent_str;
    stream << " * Remarks:";
    stream << "\n";
    stream << indent_str;
    stream << " * - ";
    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 << "#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 << typex;
    stream << ")";
    stream << "\n";
    stream << indent_str;
    stream << "#define TEST_FETCH (";
    stream << typex;
    stream << ")";
    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_r_fail = ";
    stream << expected_r_fail;
    stream << ";";
    stream << "\n";
    stream << indent_str;
    stream << "static unsigned actual_r_fail = 0;";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "static const unsigned long expected_w_fail = ";
    stream << expected_w_fail;
    stream << ";";
    stream << "\n";
    stream << indent_str;
    stream << "static unsigned actual_w_fail = 0;";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "static const unsigned long expected_x_fail = ";
    stream << expected_x_fail;
    stream << ";";
    stream << "\n";
    stream << indent_str;
    stream << "static unsigned actual_x_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 << "    if (epc >= TEST_MEM_START && epc < TEST_MEM_END) {";
    stream << "\n";
    stream << indent_str;
    stream << "        asm volatile (\"nop\");";
    stream << "\n";
    stream << indent_str;
    stream << "        actual_x_fail = 1;";
    stream << "\n";
    stream << indent_str;
    stream << "        checkTestResult();";
    stream << "\n";
    stream << indent_str;
    stream << "    } else if (cause == CAUSE_LOAD_ACCESS || cause == CAUSE_STORE_ACCESS) {";
    stream << "\n";
    stream << indent_str;
    stream << "        reg_t addr;";
    stream << "\n";
    stream << indent_str;
    stream << "        asm volatile (\"csrr %0, mtval\\n\" : \"=r\"(addr));";
    stream << "\n";
    stream << indent_str;
    stream << "        if (addr >= TEST_MEM_START && addr < TEST_MEM_END) {";
    stream << "\n";
    stream << indent_str;
    stream << "            if (cause == CAUSE_LOAD_ACCESS)";
    stream << "\n";
    stream << indent_str;
    stream << "                actual_r_fail = 1;";
    stream << "\n";
    stream << indent_str;
    stream << "            else ";
    stream << "\n";
    stream << indent_str;
    stream << "                actual_w_fail = 1;";
    stream << "\n";
    stream << indent_str;
    stream << "            return epc + 4;";
    stream << "\n";
    stream << indent_str;
    stream << "        }";
    stream << "\n";
    stream << indent_str;
    indent = 8;
    stream << "        ";
    indent = 0;
    stream << "\n";
    stream << indent_str;
    stream << "        if (addr == FAKE_ADDRESS) {";
    stream << "\n";
    stream << indent_str;
    stream << "            asm volatile (\"nop\");";
    stream << "\n";
    stream << indent_str;
    stream << "            asm volatile (\"nop\");";
    stream << "\n";
    stream << indent_str;
    stream << "            checkTestResult();";
    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 << "    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 << "static void switch_mode_access() {";
    stream << "\n";
    stream << indent_str;
    stream << "    reg_t tmp;";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (";
    stream << "\n";
    stream << indent_str;
    stream << "            \"li %0, %1\\n\"";
    stream << "\n";
    stream << indent_str;
    stream << "            \"\\tcsrc mstatus, t0\\n\"";
    stream << "\n";
    stream << indent_str;
    stream << "            \"\\tla %0, try_access_umode \\n\"";
    stream << "\n";
    stream << indent_str;
    stream << "            \"\\tcsrw mepc, %0\\n\"";
    stream << "\n";
    stream << indent_str;
    stream << "            \"\\tli sp, %2\\n\"";
    stream << "\n";
    stream << indent_str;
    stream << "            \"\\tmret\\n\"";
    stream << "\n";
    stream << indent_str;
    stream << "            : \"=r\"(tmp) : \"n\"(MSTATUS_MPP), \"n\"(U_MEM_END) : \"memory\");";
    stream << "\n";
    stream << indent_str;
    stream << "}";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "__attribute ((section(\".text_test_foo\"), noinline))";
    stream << "\n";
    stream << indent_str;
    stream << "static void target_foo() {";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"nop\");";
    stream << "\n";
    stream << indent_str;
    stream << "    actual_x_fail = 0;";
    stream << "\n";
    stream << indent_str;
    stream << "}";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "/*";
    stream << "\n";
    stream << indent_str;
    stream << " * avoid to access actual_x_fail lies in M mode";
    stream << "\n";
    stream << indent_str;
    stream << " */";
    stream << "\n";
    stream << indent_str;
    stream << "__attribute ((section(\".text_test_foo\"), noinline))";
    stream << "\n";
    stream << indent_str;
    stream << "static void target_foo_umode() {";
    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 << "static 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 << "/*";
    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 << "\n";
    stream << indent_str;
    stream << "    /*";
    stream << "\n";
    stream << indent_str;
    stream << "     * set MSECCFG_RLB to avoid locked";
    stream << "\n";
    stream << indent_str;
    stream << "     */";
    stream << "\n";
    stream << indent_str;
    stream << "    unsigned rlb_value = MSECCFG_RLB;";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"csrs 0x747, %0 \\n\"::\"r\"(rlb_value));";
    stream << "\n";
    stream << indent_str;
    stream << "#endif";
    stream << "\n";
    stream << indent_str;
    indent = 4;
    stream << "    ";
    indent = 0;
    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 << "    // need to set L bit for M mode before set MML";
    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;
    indent = 8;
    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 << "    // set proc->state.mseccfg, for MML/MMWP";
    stream << "\n";
    stream << indent_str;
    stream << "    const unsigned seccfg_bits = MSECCFG_MML | MSECCFG_MMWP;";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"csrs 0x747, %0 \\n\"::\"r\"(seccfg_bits));";
    stream << "\n";
    stream << indent_str;
    indent = 4;
    stream << "    ";
    indent = 0;
    stream << "\n";
    stream << indent_str;
    stream << "    // after set MML, RW=01 is possible";
    stream << "\n";
    stream << indent_str;
    stream << "    cfg0 |= (PMP_R | PMP_W | PMP_X | PMP_TOR) << 24;    // for U_MEM";
    stream << "\n";
    stream << indent_str;
    stream << "    cfg0 |= ((";
    stream << pmp_r;
    stream << " ? PMP_R : 0)                  // for TEST_MEM";
    stream << "\n";
    stream << indent_str;
    stream << "            | PMP_W";
    stream << "\n";
    stream << indent_str;
    stream << "            | (";
    stream << pmp_x;
    stream << " ? PMP_X : 0)    ";
    stream << "\n";
    stream << indent_str;
    stream << "            | (";
    stream << pmp_l;
    stream << " ? PMP_L : 0) ";
    stream << "\n";
    stream << indent_str;
    stream << "            | PMP_TOR) << 16;";
    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;
    indent = 4;
    stream << "    ";
    indent = 0;
    stream << "\n";
    stream << indent_str;
    stream << "    // currently dummy since tlb flushed when set_csr on mseccfg";
    stream << "\n";
    stream << indent_str;
    stream << "    asm volatile (\"fence.i \\n\");";
    stream << "\n";
    stream << indent_str;
    stream << "}";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "// from pmp_ok() side,W/R/X is similar";
    stream << "\n";
    stream << indent_str;
    stream << "__attribute ((noinline))";
    stream << "\n";
    stream << indent_str;
    stream << "static void try_access() {";
    stream << "\n";
    stream << indent_str;
    stream << "#if TEST_RW";
    stream << "\n";
    stream << indent_str;
    stream << "    target_arr[0] += 1;";
    stream << "\n";
    stream << indent_str;
    stream << "    const unsigned long delta = (unsigned long)0x1020304005060708ULL;";
    stream << "\n";
    stream << indent_str;
    stream << "    *(long *)target_arr += delta;";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "    if (actual_r_fail == 0 && actual_w_fail == 0) {";
    stream << "\n";
    stream << indent_str;
    stream << "        if (*(long *)target_arr != (unsigned long)0x0807060504030201ULL + delta + 1) {";
    stream << "\n";
    stream << indent_str;
    stream << "            actual_r_fail = 1;";
    stream << "\n";
    stream << indent_str;
    stream << "            actual_w_fail = 1;";
    stream << "\n";
    stream << indent_str;
    stream << "        }";
    stream << "\n";
    stream << indent_str;
    stream << "    }";
    stream << "\n";
    stream << indent_str;
    stream << "#endif";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "#if TEST_FETCH";
    stream << "\n";
    stream << indent_str;
    stream << "    actual_x_fail = 1;  // reset inside target_foo()";
    stream << "\n";
    stream << indent_str;
    stream << "    target_foo();";
    stream << "\n";
    stream << indent_str;
    stream << "#endif";
    stream << "\n";
    stream << indent_str;
    stream << "}";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "// in case mml set, printf cannot be used in U mode";
    stream << "\n";
    stream << indent_str;
    stream << "__attribute ((section(\".text_umode\")))";
    stream << "\n";
    stream << indent_str;
    stream << "void try_access_umode() {";
    stream << "\n";
    stream << indent_str;
    stream << "#if TEST_RW";
    stream << "\n";
    stream << indent_str;
    stream << "    target_arr[0] += 1;";
    stream << "\n";
    stream << indent_str;
    stream << "//    const unsigned long delta = 0x1020304005060708UL;";
    stream << "\n";
    stream << indent_str;
    stream << "//    *(long *)target_arr += delta;";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "//    if (*(long *)target_arr != 0x0807060504030201UL + delta + 1) {";
    stream << "\n";
    stream << indent_str;
    stream << "//        actual_rw_fail = 1;";
    stream << "\n";
    stream << indent_str;
    stream << "//    }";
    stream << "\n";
    stream << indent_str;
    stream << "#endif";
    stream << "\n";
    stream << indent_str;
    stream << "\n";
    stream << indent_str;
    stream << "#if TEST_FETCH";
    stream << "\n";
    stream << indent_str;
    stream << "    target_foo_umode();";
    stream << "\n";
    stream << indent_str;
    stream << "#endif";
    stream << "\n";
    stream << indent_str;
    indent = 4;
    stream << "    ";
    indent = 0;
    stream << "\n";
    stream << indent_str;
    stream << "    /*";
    stream << "\n";
    stream << indent_str;
    stream << "     * switch to M mode by invoking a write access fault for special address.";
    stream << "\n";
    stream << indent_str;
    stream << "     */ ";
    stream << "\n";
    stream << indent_str;
    stream << "    volatile unsigned char * p = (unsigned char *)(FAKE_ADDRESS);";
    stream << "\n";
    stream << indent_str;
    stream << "    *p = 1;";
    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_r_fail != actual_r_fail) {";
    stream << "\n";
    stream << indent_str;
    stream << "        ret += 1;";
    stream << "\n";
    stream << indent_str;
    stream << "    }";
    stream << "\n";
    stream << indent_str;
    stream << "    if (expected_w_fail != actual_w_fail) {";
    stream << "\n";
    stream << indent_str;
    stream << "        ret += 2;";
    stream << "\n";
    stream << indent_str;
    stream << "    }";
    stream << "\n";
    stream << indent_str;
    stream << "    if (expected_x_fail != actual_x_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 << "    try_access();";
    stream << "\n";
    stream << indent_str;
    stream << "#if ";
    stream << enable_umode_test;
    stream << "\n";
    stream << indent_str;
    stream << "    switch_mode_access();   // access in umode and report final result";
    stream << "\n";
    stream << indent_str;
    stream << "#else";
    stream << "\n";
    stream << indent_str;
    stream << "    checkTestResult();";
    stream << "\n";
    stream << indent_str;
    stream << "#endif";
    stream << "\n";
    stream << indent_str;
    stream << "    return 0; // assert 0";
    stream << "\n";
    stream << indent_str;
    stream << "}";
    stream << "\n";
    stream << indent_str;
  }
};

#endif // PMP_OK_SHARE_1_GEN_CLASS_H
