//! Machine and user trap entry with a nested machine timer interrupt.
.text;
    li %s0 1073807360;
    slli %s0 %s0 1;
    sd %sp 0(%s0);
    li %t0 4096;
    sub %t0 %sp %t0;
    sd %t0 8(%s0);
    li %t0 0x12345678;
    sd %t0 16(%s0);
    la %t0 @handler;
    sd %t0 24(%s0);
    mv %a0 %s0;
    call @kernel::trap::install;
    li %ra 17;
    li %gp 51;
    li %tp 68;
    li %t0 85;
    li %t1 102;
    li %t2 119;
    li %s1 153;
    li %a0 170;
    li %a1 187;
    li %a2 204;
    li %a3 221;
    li %a4 238;
    li %a5 255;
    li %a6 272;
    li %a7 289;
    li %s2 306;
    li %s3 323;
    li %s4 340;
    li %s5 357;
    li %s6 374;
    li %s7 391;
    li %s8 408;
    li %s9 425;
    li %s10 442;
    li %s11 459;
    li %t3 476;
    li %t4 493;
    li %t5 510;
    li %t6 527;
    ecall;
    addi %t0 %t0 -85;
    bnez %t0 @fail;
    li %t0 17;
    bne %ra %t0 @fail;
    li %t0 51;
    bne %gp %t0 @fail;
    li %t0 68;
    bne %tp %t0 @fail;
    li %t0 102;
    bne %t1 %t0 @fail;
    li %t0 119;
    bne %t2 %t0 @fail;
    li %t0 153;
    bne %s1 %t0 @fail;
    li %t0 170;
    bne %a0 %t0 @fail;
    li %t0 187;
    bne %a1 %t0 @fail;
    li %t0 204;
    bne %a2 %t0 @fail;
    li %t0 221;
    bne %a3 %t0 @fail;
    li %t0 238;
    bne %a4 %t0 @fail;
    li %t0 255;
    bne %a5 %t0 @fail;
    li %t0 272;
    bne %a6 %t0 @fail;
    li %t0 289;
    bne %a7 %t0 @fail;
    li %t0 306;
    bne %s2 %t0 @fail;
    li %t0 323;
    bne %s3 %t0 @fail;
    li %t0 340;
    bne %s4 %t0 @fail;
    li %t0 357;
    bne %s5 %t0 @fail;
    li %t0 374;
    bne %s6 %t0 @fail;
    li %t0 391;
    bne %s7 %t0 @fail;
    li %t0 408;
    bne %s8 %t0 @fail;
    li %t0 425;
    bne %s9 %t0 @fail;
    li %t0 442;
    bne %s10 %t0 @fail;
    li %t0 459;
    bne %s11 %t0 @fail;
    li %t0 476;
    bne %t3 %t0 @fail;
    li %t0 493;
    bne %t4 %t0 @fail;
    li %t0 510;
    bne %t5 %t0 @fail;
    li %t0 527;
    bne %t6 %t0 @fail;
    li %t0 1073807360;
    slli %t0 %t0 1;
    bne %s0 %t0 @fail;
    ld %t0 0(%s0);
    bne %sp %t0 @fail;
    ld %t0 64(%s0);
    li %t1 2;
    bne %t0 %t1 @fail;
    la %t0 @user;
    csrw mepc %t0;
    csrw mstatus %zero;
    li %sp 1073809400;
    slli %sp %sp 1;
    mret;
@user
    li %ra 17;
    li %gp 51;
    li %tp 68;
    li %t0 85;
    li %t1 102;
    li %t2 119;
    li %s1 153;
    li %a0 170;
    li %a1 187;
    li %a2 204;
    li %a3 221;
    li %a4 238;
    li %a5 255;
    li %a6 272;
    li %a7 289;
    li %s2 306;
    li %s3 323;
    li %s4 340;
    li %s5 357;
    li %s6 374;
    li %s7 391;
    li %s8 408;
    li %s9 425;
    li %s10 442;
    li %s11 459;
    li %t3 476;
    li %t4 493;
    li %t5 510;
    li %t6 527;
    ecall;
    addi %t0 %t0 -85;
    bnez %t0 @fail;
    li %t0 17;
    bne %ra %t0 @fail;
    li %t0 51;
    bne %gp %t0 @fail;
    li %t0 68;
    bne %tp %t0 @fail;
    li %t0 102;
    bne %t1 %t0 @fail;
    li %t0 119;
    bne %t2 %t0 @fail;
    li %t0 153;
    bne %s1 %t0 @fail;
    li %t0 170;
    bne %a0 %t0 @fail;
    li %t0 187;
    bne %a1 %t0 @fail;
    li %t0 204;
    bne %a2 %t0 @fail;
    li %t0 221;
    bne %a3 %t0 @fail;
    li %t0 238;
    bne %a4 %t0 @fail;
    li %t0 255;
    bne %a5 %t0 @fail;
    li %t0 272;
    bne %a6 %t0 @fail;
    li %t0 289;
    bne %a7 %t0 @fail;
    li %t0 306;
    bne %s2 %t0 @fail;
    li %t0 323;
    bne %s3 %t0 @fail;
    li %t0 340;
    bne %s4 %t0 @fail;
    li %t0 357;
    bne %s5 %t0 @fail;
    li %t0 374;
    bne %s6 %t0 @fail;
    li %t0 391;
    bne %s7 %t0 @fail;
    li %t0 408;
    bne %s8 %t0 @fail;
    li %t0 425;
    bne %s9 %t0 @fail;
    li %t0 442;
    bne %s10 %t0 @fail;
    li %t0 459;
    bne %s11 %t0 @fail;
    li %t0 476;
    bne %t3 %t0 @fail;
    li %t0 493;
    bne %t4 %t0 @fail;
    li %t0 510;
    bne %t5 %t0 @fail;
    li %t0 527;
    bne %t6 %t0 @fail;
    li %t0 1073807360;
    slli %t0 %t0 1;
    bne %s0 %t0 @fail;
    li %t0 1073809400;
    slli %t0 %t0 1;
    bne %sp %t0 @fail;
    li %t0 85;
@illegalInstruction
    csrr %t0 mhartid;
    addi %t0 %t0 -85;
    bnez %t0 @fail;
    li %a7 1234;
    ecall;
    j @fail;
@success
    li %t0 0x10001000;
    li %t1 0x5555;
    sw %t1 0(%t0);
@fail
    li %t0 0x10001000;
    li %t1 0x13333;
    sw %t1 0(%t0);
@park
    wfi;
    j @park;

// Validate stack/base switching before enabling a nested timer interrupt.
@handler
    li %t0 0x12345678;
    bne %gp %t0 @fail;
    li %t0 1073807360;
    slli %t0 %t0 1;
    bne %tp %t0 @fail;
    bne %a1 %tp @fail;
    bne %a0 %sp @fail;
    ld %t0 272(%a0);
    li %t1 1;
    slli %t1 %t1 63;
    ori %t1 %t1 7;
    beq %t0 %t1 @timer;
    li %t1 8;
    beq %t0 %t1 @userCall;
    li %t1 2;
    beq %t0 %t1 @illegal;
    li %t1 11;
    bne %t0 %t1 @fail;
    ld %t0 64(%tp);
    bnez %t0 @fail;
    li %t0 1;
    sd %t0 64(%tp);
    addi %sp %sp -16;
    sd %ra 0(%sp);
    sd %a0 8(%sp);
    li %t0 0x02004000;
    sd %zero 0(%t0);
    li %t0 128;
    csrw mie %t0;
    li %s10 0;
    csrr %t0 mstatus;
    ori %t0 %t0 8;
    csrw mstatus %t0;
@awaitTimer
    addi %s10 %s10 1;
    ld %t0 64(%tp);
    li %t1 2;
    bne %t0 %t1 @awaitTimer;
    li %t0 1;
    bne %s10 %t0 @fail;
    csrr %t0 mstatus;
    andi %t0 %t0 8;
    beqz %t0 @fail;
    csrr %t0 mstatus;
    andi %t0 %t0 -9;
    csrw mstatus %t0;
    csrw mie %zero;
    ld %ra 0(%sp);
    ld %a0 8(%sp);
    addi %sp %sp 16;
    j @advance;
@timer
    ld %t0 256(%a0);
    la %t1 @awaitTimer;
    bne %t0 %t1 @fail;
    ld %t0 264(%a0);
    li %t1 0x1800;
    and %t0 %t0 %t1;
    bne %t0 %t1 @fail;
    ld %t0 16(%a0);
    addi %t1 %a0 288;
    bne %t0 %t1 @fail;
    li %t0 0x02004000;
    li %t1 -1;
    sd %t1 0(%t0);
    li %t0 2;
    sd %t0 64(%tp);
    ret;
@illegal
    ld %t0 256(%a0);
    la %t1 @illegalInstruction;
    bne %t0 %t1 @fail;
    ld %t0 280(%a0);
    li %t1 2023756153;
    slli %t1 %t1 1;
    addi %t1 %t1 1;
    bne %t0 %t1 @fail;
    li %t0 1;
    sd %t0 72(%tp);
    j @advance;
@userCall
    ld %t0 136(%a0);
    li %t1 1234;
    bne %t0 %t1 @checkUserFrame;
    ld %t0 72(%tp);
    li %t1 1;
    bne %t0 %t1 @fail;
    j @success;
@checkUserFrame
    ld %t0 264(%a0);
    li %t1 0x1800;
    and %t0 %t0 %t1;
    bnez %t0 @fail;
    ld %t0 0(%tp);
    addi %t0 %t0 -288;
    bne %a0 %t0 @fail;
@advance
    ld %t0 256(%a0);
    addi %t0 %t0 4;
    sd %t0 256(%a0);
    ret;
