diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index d74b361be..c6b899e6a 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -179,6 +179,9 @@ struct CPUArchState {
 
     target_ulong jvt;
 
+    /* Proj 5 */
+    uint32_t cpu_expect_lp;
+
 #ifdef CONFIG_USER_ONLY
     uint32_t elf_flags;
 #endif
@@ -396,6 +399,12 @@ struct CPUArchState {
     target_ulong cur_pmmask;
     target_ulong cur_pmbase;
 
+    /* Proj 5 */
+    target_ulong sfi_code_andmask;
+    target_ulong sfi_code_ormask;
+    target_ulong sfi_data_andmask;
+    target_ulong sfi_data_ormask;
+
     /* Fields from here on are preserved across CPU reset. */
     QEMUTimer *stimer; /* Internal timer for S-mode interrupt */
     QEMUTimer *vstimer; /* Internal timer for VS-mode interrupt */
@@ -554,6 +563,8 @@ FIELD(TB_FLAGS, ITRIGGER, 22, 1)
 FIELD(TB_FLAGS, VIRT_ENABLED, 23, 1)
 FIELD(TB_FLAGS, PRIV, 24, 2)
 FIELD(TB_FLAGS, AXL, 26, 2)
+/* Proj 5 */
+FIELD(TB_FLAGS, LP_EXPECTED, 28, 1)
 
 #ifdef TARGET_RISCV32
 #define riscv_cpu_mxl(env)  ((void)(env), MXL_RV32)
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index ebd7917d4..a5b7fe1b1 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -524,6 +524,14 @@
 #define CSR_VSPMBASE        0x2c2
 #define CSR_SCOUNTOVF       0xda0
 
+/*
+ * Proj 5
+ */
+#define CSR_SFI_CODE_ANDMASK   0x861
+#define CSR_SFI_CODE_ORMASK    0x862
+#define CSR_SFI_DATA_ANDMASK   0x863
+#define CSR_SFI_DATA_ORMASK    0x864
+
 /* Crypto Extension */
 #define CSR_SEED            0x015
 
@@ -549,6 +557,9 @@
 #define MSTATUS_TVM         0x00100000 /* since: priv-1.10 */
 #define MSTATUS_TW          0x00200000 /* since: priv-1.10 */
 #define MSTATUS_TSR         0x00400000 /* since: priv-1.10 */
+/* Proj 5 */
+#define MSTATUS_SPELP       0x02000000
+#define MSTATUS_MPELP       0x04000000
 #define MSTATUS_GVA         0x4000000000ULL
 #define MSTATUS_MPV         0x8000000000ULL
 
@@ -579,12 +590,18 @@ typedef enum {
 #define SSTATUS_XS          0x00018000
 #define SSTATUS_SUM         0x00040000 /* since: priv-1.10 */
 #define SSTATUS_MXR         0x00080000
+/* Proj 5 */
+#define SSTATUS_SPELP       MSTATUS_SPELP
 
 #define SSTATUS64_UXL       0x0000000300000000ULL
 
 #define SSTATUS32_SD        0x80000000
 #define SSTATUS64_SD        0x8000000000000000ULL
 
+/* Proj 5 */
+#define CPU_LP_NOT_EXPECTED 0
+#define CPU_LP_EXPECTED     1
+
 /* hstatus CSR bits */
 #define HSTATUS_VSBE         0x00000020
 #define HSTATUS_GVA          0x00000040
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index e7e23b34f..f3792aeb8 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -100,6 +100,10 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc,
         flags = FIELD_DP32(flags, TB_FLAGS, VILL, 1);
     }
 
+    /* Proj 5 */
+    flags = FIELD_DP32(flags, TB_FLAGS, LP_EXPECTED,
+                       env->cpu_expect_lp != CPU_LP_NOT_EXPECTED);
+
 #ifdef CONFIG_USER_ONLY
     fs = EXT_STATUS_DIRTY;
     vs = EXT_STATUS_DIRTY;
@@ -1739,6 +1743,9 @@ void riscv_cpu_do_interrupt(CPUState *cs)
     if (env->priv <= PRV_S && cause < 64 &&
         (((deleg >> cause) & 1) || s_injected || vs_injected)) {
         /* handle the trap in S-mode */
+        /* Proj 5 */
+        env->mstatus = set_field(env->mstatus, MSTATUS_SPELP,
+                                 env->cpu_expect_lp);
         if (riscv_has_ext(env, RVH)) {
             uint64_t hdeleg = async ? env->hideleg : env->hedeleg;
 
@@ -1787,6 +1794,9 @@ void riscv_cpu_do_interrupt(CPUState *cs)
         riscv_cpu_set_mode(env, PRV_S);
     } else {
         /* handle the trap in M-mode */
+        /* Proj 5 */
+        env->mstatus = set_field(env->mstatus, MSTATUS_MPELP,
+                                 env->cpu_expect_lp);
         if (riscv_has_ext(env, RVH)) {
             if (env->virt_enabled) {
                 riscv_cpu_swap_hypervisor_regs(env);
@@ -1818,6 +1828,9 @@ void riscv_cpu_do_interrupt(CPUState *cs)
         riscv_cpu_set_mode(env, PRV_M);
     }
 
+    /* Proj 5 */
+    env->cpu_expect_lp = CPU_LP_NOT_EXPECTED;
+
     /*
      * NOTE: it is not necessary to yield load reservations here. It is only
      * necessary for an SC from "another hart" to cause a load reservation
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index c50a33397..ede19660e 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -4198,6 +4198,68 @@ static RISCVException write_upmbase(CPURISCVState *env, int csrno,
 
 #endif
 
+/* Proj 5 */
+static RISCVException proj5(CPURISCVState *env, int csrno)
+{
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_sfi_code_andmask(CPURISCVState *env, int csrno,
+                                   target_ulong *val)
+{
+    *val = env->sfi_code_andmask;
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_sfi_code_andmask(CPURISCVState *env, int csrno,
+                                    target_ulong val)
+{
+    env->sfi_code_andmask = val;
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_sfi_code_ormask(CPURISCVState *env, int csrno,
+                                   target_ulong *val)
+{
+    *val = env->sfi_code_ormask;
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_sfi_code_ormask(CPURISCVState *env, int csrno,
+                                    target_ulong val)
+{
+    env->sfi_code_ormask = val;
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_sfi_data_andmask(CPURISCVState *env, int csrno,
+                                   target_ulong *val)
+{
+    *val = env->sfi_data_andmask;
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_sfi_data_andmask(CPURISCVState *env, int csrno,
+                                    target_ulong val)
+{
+    env->sfi_data_andmask = val;
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_sfi_data_ormask(CPURISCVState *env, int csrno,
+                                   target_ulong *val)
+{
+    *val = env->sfi_data_ormask;
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_sfi_data_ormask(CPURISCVState *env, int csrno,
+                                    target_ulong val)
+{
+    env->sfi_data_ormask = val;
+    return RISCV_EXCP_NONE;
+}
+
 /* Crypto Extension */
 static RISCVException rmw_seed(CPURISCVState *env, int csrno,
                                target_ulong *ret_value,
@@ -4507,6 +4569,16 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
     /* Zcmt Extension */
     [CSR_JVT] = {"jvt", zcmt, read_jvt, write_jvt},
 
+    /* Proj 5 */
+    [CSR_SFI_CODE_ANDMASK] = { "proj5", proj5, read_sfi_code_andmask,
+                               write_sfi_code_andmask                       },
+    [CSR_SFI_CODE_ORMASK] =  { "proj5", proj5, read_sfi_code_ormask,
+                               write_sfi_code_ormask                        },
+    [CSR_SFI_DATA_ANDMASK] = { "proj5", proj5, read_sfi_data_andmask,
+                               write_sfi_data_andmask                       },
+    [CSR_SFI_DATA_ORMASK] =  { "proj5", proj5, read_sfi_data_ormask,
+                               write_sfi_data_ormask                        },
+
 #if !defined(CONFIG_USER_ONLY)
     /* Machine Timers and Counters */
     [CSR_MCYCLE]    = { "mcycle",    any,   read_hpmcounter,
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 33597fe2b..d4673904d 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -134,7 +134,11 @@ sb       .......  .....   ..... 000 ..... 0100011 @s
 sh       .......  .....   ..... 001 ..... 0100011 @s
 sw       .......  .....   ..... 010 ..... 0100011 @s
 addi     ............     ..... 000 ..... 0010011 @i
-slti     ............     ..... 010 ..... 0010011 @i
+# *** Proj 5 ***
+{
+  lpad     000000000000     00000 010 00000 0010011
+  slti     ............     ..... 010 ..... 0010011 @i
+}
 sltiu    ............     ..... 011 ..... 0010011 @i
 xori     ............     ..... 100 ..... 0010011 @i
 # cbo.prefetch_{i,r,m} instructions are ori with rd=x0 and not decoded.
diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc
index faf6d6506..7497afdf8 100644
--- a/target/riscv/insn_trans/trans_rvi.c.inc
+++ b/target/riscv/insn_trans/trans_rvi.c.inc
@@ -50,39 +50,20 @@ static bool trans_jal(DisasContext *ctx, arg_jal *a)
     return true;
 }
 
+/* Proj 5 */
 static bool trans_jalr(DisasContext *ctx, arg_jalr *a)
 {
-    TCGLabel *misaligned = NULL;
-    TCGv target_pc = tcg_temp_new();
-    TCGv succ_pc = dest_gpr(ctx, a->rd);
-
-    tcg_gen_addi_tl(target_pc, get_gpr(ctx, a->rs1, EXT_NONE), a->imm);
-    tcg_gen_andi_tl(target_pc, target_pc, (target_ulong)-2);
-
-    if (get_xl(ctx) == MXL_RV32) {
-        tcg_gen_ext32s_tl(target_pc, target_pc);
-    }
-
-    if (!has_ext(ctx, RVC) && !ctx->cfg_ptr->ext_zca) {
-        TCGv t0 = tcg_temp_new();
-
-        misaligned = gen_new_label();
-        tcg_gen_andi_tl(t0, target_pc, 0x2);
-        tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0x0, misaligned);
-    }
-
-    gen_pc_plus_diff(succ_pc, ctx, ctx->cur_insn_len);
-    gen_set_gpr(ctx, a->rd, succ_pc);
-
-    tcg_gen_mov_tl(cpu_pc, target_pc);
-    lookup_and_goto_ptr(ctx);
+    gen_jalr(ctx, a->rs1, a->rd, a->imm);
+    return true;
+}
 
-    if (misaligned) {
-        gen_set_label(misaligned);
-        gen_exception_inst_addr_mis(ctx, target_pc);
+static bool trans_lpad(DisasContext *ctx, arg_lpad *a)
+{
+    if (ctx->base.pc_next == ctx->base.pc_first) {
+        ctx->disas_awaiting_lp = false;
     }
-    ctx->base.is_jmp = DISAS_NORETURN;
-
+    tcg_gen_st_i32(tcg_constant_i32(CPU_LP_NOT_EXPECTED), tcg_env,
+                   offsetof(CPURISCVState, cpu_expect_lp));
     return true;
 }
 
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 5355225d5..3bc6f591c 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -311,6 +311,10 @@ target_ulong helper_sret(CPURISCVState *env)
         riscv_cpu_set_virt_enabled(env, prev_virt);
     }
 
+    /* Proj 5 */
+    env->cpu_expect_lp = get_field(env->mstatus, MSTATUS_SPELP);
+    env->mstatus = set_field(env->mstatus, MSTATUS_SPELP, 0);
+
     riscv_cpu_set_mode(env, prev_priv);
 
     return retpc;
@@ -357,6 +361,10 @@ target_ulong helper_mret(CPURISCVState *env)
         riscv_cpu_set_virt_enabled(env, prev_virt);
     }
 
+    /* Proj 5 */
+    env->cpu_expect_lp = get_field(env->mstatus, MSTATUS_MPELP);
+    env->mstatus = set_field(env->mstatus, MSTATUS_MPELP, 0);
+
     return retpc;
 }
 
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index f0be79bb1..097586930 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -45,6 +45,8 @@ static TCGv load_val;
 /* globals for PM CSRs */
 static TCGv pm_mask;
 static TCGv pm_base;
+/* Proj 5 */
+static TCGOp *lp_check;
 
 /*
  * If an operation is being performed on less than TARGET_LONG_BITS,
@@ -115,6 +117,8 @@ typedef struct DisasContext {
     bool frm_valid;
     /* TCG of the current insn_start */
     TCGOp *insn_start;
+    /* Proj 5 */
+    bool disas_awaiting_lp;
 } DisasContext;
 
 static inline bool has_ext(DisasContext *ctx, uint32_t ext)
@@ -554,6 +558,41 @@ static void gen_set_fpr_d(DisasContext *ctx, int reg_num, TCGv_i64 t)
     }
 }
 
+/* Proj 5 */
+static void gen_jalr(DisasContext *ctx, int rs1, int rd, int imm)
+{
+    TCGLabel *misaligned = NULL;
+    TCGv target_pc = tcg_temp_new();
+    TCGv succ_pc = dest_gpr(ctx, rd);
+
+    tcg_gen_addi_tl(target_pc, get_gpr(ctx, rs1, EXT_NONE), imm);
+    tcg_gen_andi_tl(target_pc, target_pc, (target_ulong)-2);
+
+    if (get_xl(ctx) == MXL_RV32) {
+        tcg_gen_ext32s_tl(target_pc, target_pc);
+    }
+
+    if (!has_ext(ctx, RVC) && !ctx->cfg_ptr->ext_zca) {
+        TCGv t0 = tcg_temp_new();
+
+        misaligned = gen_new_label();
+        tcg_gen_andi_tl(t0, target_pc, 0x2);
+        tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0x0, misaligned);
+    }
+
+    gen_pc_plus_diff(succ_pc, ctx, ctx->cur_insn_len);
+    gen_set_gpr(ctx, rd, succ_pc);
+
+    tcg_gen_mov_tl(cpu_pc, target_pc);
+    lookup_and_goto_ptr(ctx);
+
+    if (misaligned) {
+        gen_set_label(misaligned);
+        gen_exception_inst_addr_mis(ctx, target_pc);
+    }
+    ctx->base.is_jmp = DISAS_NORETURN;
+}
+
 static void gen_jal(DisasContext *ctx, int rd, target_ulong imm)
 {
     TCGv succ_pc = dest_gpr(ctx, rd);
@@ -1197,10 +1236,28 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
     ctx->itrigger = FIELD_EX32(tb_flags, TB_FLAGS, ITRIGGER);
     ctx->zero = tcg_constant_tl(0);
     ctx->virt_inst_excp = false;
+    /* Proj 5 */
+    ctx->disas_awaiting_lp = FIELD_EX32(tb_flags, TB_FLAGS, LP_EXPECTED);
 }
 
 static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu)
 {
+    /* Proj 5 */
+    DisasContext *ctx = container_of(db, DisasContext, base);
+    if (ctx->disas_awaiting_lp) {
+        TCGv_i32 immediate;
+        TCGLabel *l;
+        l = gen_new_label();
+        immediate = tcg_temp_new_i32();
+        tcg_gen_movi_i32(immediate, 0);
+        lp_check = tcg_last_op();
+        tcg_gen_brcondi_i32(TCG_COND_EQ, immediate, 0, l);
+        tcg_gen_st_i32(tcg_constant_i32(CPU_LP_NOT_EXPECTED), tcg_env,
+                       offsetof(CPURISCVState, cpu_expect_lp));
+        gen_exception_illegal(ctx);
+        gen_set_label(l);
+        ctx->base.is_jmp = DISAS_NEXT;
+    }
 }
 
 static void riscv_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
@@ -1248,6 +1305,8 @@ static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
 static void riscv_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
 {
     DisasContext *ctx = container_of(dcbase, DisasContext, base);
+    /* Proj 5 */
+    CPURISCVState *env = cpu_env(cpu);
 
     switch (ctx->base.is_jmp) {
     case DISAS_TOO_MANY:
@@ -1258,6 +1317,19 @@ static void riscv_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
     default:
         g_assert_not_reached();
     }
+
+    /* Proj 5 */
+    if (ctx->disas_awaiting_lp) {
+        /* landing pad not found in disasm; make this block fault */
+        tcg_set_insn_param(lp_check, 1, tcgv_i32_arg(tcg_constant_i32(1)));
+    }
+    /*
+     * clear the landing pad expectation; note that, if this block
+     * itself ends with a checked jump, that jump will set
+     * cpu_expect_lp when executed, which will in turn affect the
+     * state of the _next_ block
+     */
+    env->cpu_expect_lp = CPU_LP_NOT_EXPECTED;
 }
 
 static void riscv_tr_disas_log(const DisasContextBase *dcbase,
