diff options
Diffstat (limited to 'riscv/riscv_sys.sail')
| -rw-r--r-- | riscv/riscv_sys.sail | 1044 |
1 files changed, 0 insertions, 1044 deletions
diff --git a/riscv/riscv_sys.sail b/riscv/riscv_sys.sail deleted file mode 100644 index 58609949..00000000 --- a/riscv/riscv_sys.sail +++ /dev/null @@ -1,1044 +0,0 @@ -/* Machine-mode and supervisor-mode state definitions and operations. */ - -/* privilege level */ - -register cur_privilege : Privilege - -/* current instruction bits, used for illegal instruction exceptions */ - -register cur_inst : xlenbits - -/* State projections - * - * Some machine state is processed via projections from machine-mode views to - * views from lower privilege levels. So, for e.g. when mstatus is read from - * lower privilege levels, we use 'lowering_' projections: - * - * mstatus -> sstatus -> ustatus - * - * Similarly, when machine state is written from lower privileges, that state is - * lifted into the appropriate value for the machine-mode state. - * - * ustatus -> sstatus -> mstatus - * - * In addition, several fields in machine state registers are WARL or WLRL, - * requiring that values written to the registers be legalized. For each such - * register, there will be an associated 'legalize_' function. These functions - * will need to be supplied externally, and will depend on the legal values - * supported by a platform/implementation (or misa). The legalize_ functions - * generate a legal value from the current value and the written value. In more - * complex cases, they will also implicitly read the current values of misa, - * mstatus, etc. - * - * Each register definition below is followed by custom projections - * and choice of legalizations if needed. For now, we typically - * implement the simplest legalize_ alternatives. - */ - - -/* M-mode registers */ - -bitfield Misa : bits(64) = { - MXL : 63 .. 62, - - Z : 25, - Y : 24, - X : 23, - W : 22, - V : 21, - U : 20, - T : 19, - S : 18, - R : 17, - Q : 16, - P : 15, - O : 14, - N : 13, - M : 12, - L : 11, - K : 10, - J : 9, - I : 8, - H : 7, - G : 6, - F : 5, - E : 4, - D : 3, - C : 2, - B : 1, - A : 0 -} -register misa : Misa - -function legalize_misa(m : Misa, v : xlenbits) -> Misa = { - /* Allow modifications to C. */ - let v = Mk_Misa(v); - // Suppress changing C if nextPC would become misaligned. - if v.C() == false & nextPC[1] == true - then m - else update_C(m, v.C()) -} - -bitfield Mstatus : bits(64) = { - SD : 63, - - SXL : 35 .. 34, - UXL : 33 .. 32, - - TSR : 22, - TW : 21, - TVM : 20, - MXR : 19, - SUM : 18, - MPRV : 17, - - XS : 16 .. 15, - FS : 14 .. 13, - - MPP : 12 .. 11, - SPP : 8, - - MPIE : 7, - SPIE : 5, - UPIE : 4, - - MIE : 3, - SIE : 1, - UIE : 0 -} -register mstatus : Mstatus - -function legalize_mstatus(o : Mstatus, v : xlenbits) -> Mstatus = { - let m : Mstatus = Mk_Mstatus(v); - - /* We don't have any extension context yet. */ - let m = update_XS(m, extStatus_to_bits(Off)); - let m = update_FS(m, extStatus_to_bits(Off)); - - let m = update_SD(m, extStatus_of_bits(m.FS()) == Dirty - | extStatus_of_bits(m.XS()) == Dirty); - - /* For now, we don't allow SXL and UXL to be changed, for Spike compatibility. */ - let m = update_SXL(m, o.SXL()); - let m = update_UXL(m, o.UXL()); - - /* Hardwired to zero in the absence of 'N'. */ - let m = update_UPIE(m, false); - let m = update_UIE(m, false); - m -} - -/* architecture and extension checks */ - -function cur_Architecture() -> Architecture = { - let a : arch_xlen = - match (cur_privilege) { - Machine => misa.MXL(), - Supervisor => mstatus.SXL(), - User => mstatus.UXL() - }; - match architecture(a) { - Some(a) => a, - None() => internal_error("Invalid current architecture") - } -} - -function in32BitMode() -> bool = { - cur_Architecture() == RV32 -} - -function haveAtomics() -> bool = { misa.A() == true } -function haveRVC() -> bool = { misa.C() == true } -function haveMulDiv() -> bool = { misa.M() == true } -function haveFP() -> bool = { misa.F() == true | misa.D() == true } - -/* interrupt processing state */ - -bitfield Minterrupts : bits(64) = { - MEI : 11, /* external interrupts */ - SEI : 9, - UEI : 8, - - MTI : 7, /* timers interrupts */ - STI : 5, - UTI : 4, - - MSI : 3, /* software interrupts */ - SSI : 1, - USI : 0, -} -register mip : Minterrupts /* Pending */ -register mie : Minterrupts /* Enabled */ -register mideleg : Minterrupts /* Delegation to S-mode */ - -function legalize_mip(o : Minterrupts, v : xlenbits) -> Minterrupts = { - /* The only writable bits are the S-mode bits, and with the 'N' - * extension, the U-mode bits. */ - let v = Mk_Minterrupts(v); - let m = update_SEI(o, v.SEI()); - let m = update_STI(m, v.STI()); - let m = update_SSI(m, v.SSI()); - m -} - -function legalize_mie(o : Minterrupts, v : xlenbits) -> Minterrupts = { - let v = Mk_Minterrupts(v); - let m = update_MEI(o, v.MEI()); - let m = update_MTI(m, v.MTI()); - let m = update_MSI(m, v.MSI()); - let m = update_SEI(m, v.SEI()); - let m = update_STI(m, v.STI()); - let m = update_SSI(m, v.SSI()); - /* The U-mode bits will be modified if we have the 'N' extension. */ - m -} - -function legalize_mideleg(o : Minterrupts, v : xlenbits) -> Minterrupts = { - /* M-mode interrupt delegation bits "should" be hardwired to 0. */ - /* FIXME: needs verification against eventual spec language. */ - let m = Mk_Minterrupts(v); - let m = update_MEI(m, false); - let m = update_MTI(m, false); - let m = update_MSI(m, false); - m -} - -/* exception processing state */ - -bitfield Medeleg : bits(64) = { - SAMO_Page_Fault : 15, - Load_Page_Fault : 13, - Fetch_Page_Fault : 12, - MEnvCall : 10, - SEnvCall : 9, - UEnvCall : 8, - SAMO_Access_Fault : 7, - SAMO_Addr_Align : 6, - Load_Access_Fault : 5, - Load_Addr_Align : 4, - Breakpoint : 3, - Illegal_Instr : 2, - Fetch_Access_Fault: 1, - Fetch_Addr_Align : 0 -} -register medeleg : Medeleg /* Delegation to S-mode */ - -function legalize_medeleg(o : Medeleg, v : xlenbits) -> Medeleg = { - let m = Mk_Medeleg(v); - /* M-EnvCalls delegation is not supported */ - let m = update_MEnvCall(m, false); - m -} - -/* registers for trap handling */ - -bitfield Mtvec : bits(64) = { - Base : 63 .. 2, - Mode : 1 .. 0 -} -register mtvec : Mtvec /* Trap Vector */ - -function legalize_tvec(o : Mtvec, v : xlenbits) -> Mtvec = { - let v = Mk_Mtvec(v); - match (trapVectorMode_of_bits(v.Mode())) { - TV_Direct => v, - TV_Vector => v, - _ => update_Mode(v, o.Mode()) - } -} - -bitfield Mcause : bits(64) = { - IsInterrupt : 63, - Cause : 62 .. 0 -} -register mcause : Mcause - -/* Interpreting the trap-vector address */ -function tvec_addr(m : Mtvec, c : Mcause) -> option(xlenbits) = { - let base : xlenbits = m.Base() @ 0b00; - match (trapVectorMode_of_bits(m.Mode())) { - TV_Direct => Some(base), - TV_Vector => if c.IsInterrupt() == true - then Some(base + (EXTZ(c.Cause()) << 0b10)) - else Some(base), - TV_Reserved => None() - } -} - -/* Exception PC */ - -register mepc : xlenbits - -// legalizing writes to xepc -function legalize_xepc(v : xlenbits) -> xlenbits = { - v & EXTS(if haveRVC() then 0b110 else 0b100) -} - -// masking for reads to xepc -function pc_alignment_mask() -> xlenbits = - ~(EXTZ(if misa.C() == true then 0b00 else 0b10)) - -/* auxiliary exception registers */ - -register mtval : xlenbits -register mscratch : xlenbits - -/* counters */ - -bitfield Counteren : bits(32) = { - HPM : 31 .. 3, - IR : 2, - TM : 1, - CY : 0 -} - -register mcounteren : Counteren -register scounteren : Counteren - -function legalize_mcounteren(c : Counteren, v : xlenbits) -> Counteren = { - /* no HPM counters yet */ - let c = update_IR(c, v[2]); - let c = update_TM(c, v[1]); - let c = update_CY(c, v[0]); - c -} - -function legalize_scounteren(c : Counteren, v : xlenbits) -> Counteren = { - /* no HPM counters yet */ - let c = update_IR(c, v[2]); - let c = update_TM(c, v[1]); - let c = update_CY(c, v[0]); - c -} - -register mcycle : xlenbits -register mtime : xlenbits - -/* minstret - * - * minstret is an architectural register, and can be written to. The - * spec says that minstret increments on instruction retires need to - * occur before any explicit writes to instret. However, in our - * simulation loop, we need to execute an instruction to find out - * whether it retired, and hence can only increment instret after - * execution. To avoid doing this in the case minstret was explicitly - * written to, we track writes to it in a separate model-internal - * register. - */ -register minstret : xlenbits -register minstret_written : bool - -function retire_instruction() -> unit = { - if minstret_written == true - then minstret_written = false - else minstret = minstret + 1 -} - -/* informational registers */ -register mvendorid : xlenbits -register mimpid : xlenbits -register marchid : xlenbits -/* TODO: this should be readonly, and always 0 for now */ -register mhartid : xlenbits - -/* physical memory protection configuration */ -register pmpaddr0 : xlenbits -register pmpcfg0 : xlenbits - - -/* S-mode registers */ - -/* sstatus reveals a subset of mstatus */ -bitfield Sstatus : bits(64) = { - SD : 63, - UXL : 33 .. 32, - MXR : 19, - SUM : 18, - XS : 16 .. 15, - FS : 14 .. 13, - SPP : 8, - SPIE : 5, - UPIE : 4, - SIE : 1, - UIE : 0 -} -/* This is a view, so there is no register defined. */ -function lower_mstatus(m : Mstatus) -> Sstatus = { - let s = Mk_Sstatus(EXTZ(0b0)); - let s = update_SD(s, m.SD()); - let s = update_UXL(s, m.UXL()); - let s = update_MXR(s, m.MXR()); - let s = update_SUM(s, m.SUM()); - let s = update_XS(s, m.XS()); - let s = update_FS(s, m.FS()); - let s = update_SPP(s, m.SPP()); - let s = update_SPIE(s, m.SPIE()); - let s = update_UPIE(s, m.UPIE()); - let s = update_SIE(s, m.SIE()); - let s = update_UIE(s, m.UIE()); - s -} - -function lift_sstatus(m : Mstatus, s : Sstatus) -> Mstatus = { - // FIXME: This should be parameterized by a platform setting. For now, match spike. - // let m = update_UXL(m, s.UXL()); - let m = update_MXR(m, s.MXR()); - let m = update_SUM(m, s.SUM()); - - // FIXME: Should XS and FS check whether X and F|D are supported in misa? - let m = update_XS(m, s.XS()); - let m = update_FS(m, s.FS()); - let m = update_SD(m, extStatus_of_bits(m.FS()) == Dirty - | extStatus_of_bits(m.XS()) == Dirty); - - let m = update_SPP(m, s.SPP()); - let m = update_SPIE(m, s.SPIE()); - let m = update_UPIE(m, s.UPIE()); - let m = update_SIE(m, s.SIE()); - let m = update_UIE(m, s.UIE()); - m -} - -function legalize_sstatus(m : Mstatus, v : xlenbits) -> Mstatus = { - lift_sstatus(m, Mk_Sstatus(v)) -} - -bitfield Sedeleg : bits(64) = { - UEnvCall : 8, - SAMO_Access_Fault : 7, - SAMO_Addr_Align : 6, - Load_Access_Fault : 5, - Load_Addr_Align : 4, - Breakpoint : 3, - Illegal_Instr : 2, - Fetch_Access_Fault: 1, - Fetch_Addr_Align : 0 -} -register sedeleg : Sedeleg - -function legalize_sedeleg(s : Sedeleg, v : xlenbits) -> Sedeleg = { - Mk_Sedeleg(EXTZ(v[8..0])) -} - -bitfield Sinterrupts : bits(64) = { - SEI : 9, /* external interrupts */ - UEI : 8, - - STI : 5, /* timers interrupts */ - UTI : 4, - - SSI : 1, /* software interrupts */ - USI : 0 -} - -/* Provides the sip read view of mip as delegated by mideleg. */ -function lower_mip(m : Minterrupts, d : Minterrupts) -> Sinterrupts = { - let s : Sinterrupts = Mk_Sinterrupts(EXTZ(0b0)); - let s = update_SEI(s, m.SEI() & d.SEI()); - let s = update_STI(s, m.STI() & d.STI()); - let s = update_SSI(s, m.SSI() & d.SSI()); - - let s = update_UEI(s, m.UEI() & d.UEI()); - let s = update_UTI(s, m.UTI() & d.UTI()); - let s = update_USI(s, m.USI() & d.USI()); - s -} -/* Provides the sie read view of mie as delegated by mideleg. */ -function lower_mie(m : Minterrupts, d : Minterrupts) -> Sinterrupts = { - let s : Sinterrupts = Mk_Sinterrupts(EXTZ(0b0)); - let s = update_SEI(s, m.SEI() & d.SEI()); - let s = update_STI(s, m.STI() & d.STI()); - let s = update_SSI(s, m.SSI() & d.SSI()); - let s = update_UEI(s, m.UEI() & d.UEI()); - let s = update_UTI(s, m.UTI() & d.UTI()); - let s = update_USI(s, m.USI() & d.USI()); - s -} -/* Provides the sip write view of mip as delegated by mideleg. */ -function lift_sip(o : Minterrupts, d : Minterrupts, s : Sinterrupts) -> Minterrupts = { - let m : Minterrupts = o; - let m = update_SSI(m, s.SSI() & d.SSI()); - let m = update_UEI(m, m.UEI() & d.UEI()); - let m = update_USI(m, m.USI() & d.USI()); - m -} -function legalize_sip(m : Minterrupts, d : Minterrupts, v : xlenbits) -> Minterrupts = { - lift_sip(m, d, Mk_Sinterrupts(v)) -} -/* Provides the sie write view of mie as delegated by mideleg. */ -function lift_sie(o : Minterrupts, d : Minterrupts, s : Sinterrupts) -> Minterrupts = { - let m : Minterrupts = o; - let m = if d.SEI() == true then update_SEI(m, s.SEI()) else m; - let m = if d.STI() == true then update_STI(m, s.STI()) else m; - let m = if d.SSI() == true then update_SSI(m, s.SSI()) else m; - let m = if d.UEI() == true then update_UEI(m, s.UEI()) else m; - let m = if d.UTI() == true then update_UTI(m, s.UTI()) else m; - let m = if d.USI() == true then update_USI(m, s.USI()) else m; - m -} -function legalize_sie(m : Minterrupts, d : Minterrupts, v : xlenbits) -> Minterrupts = { - lift_sie(m, d, Mk_Sinterrupts(v)) -} - -register sideleg : Sinterrupts - -/* s-mode address translation and protection (satp) */ -bitfield Satp64 : bits(64) = { - Mode : 63 .. 60, - Asid : 59 .. 44, - PPN : 43 .. 0 -} -register satp : xlenbits - -function legalize_satp(a : Architecture, o : xlenbits, v : xlenbits) -> xlenbits = { - let s = Mk_Satp64(v); - match satpMode_of_bits(a, s.Mode()) { - None() => o, - Some(Sv32) => o, /* Sv32 is unsupported for now */ - Some(_) => s.bits() - } -} - -/* other supervisor state */ -register stvec : Mtvec -register sscratch : xlenbits -register sepc : xlenbits -register scause : Mcause -register stval : xlenbits - -/* disabled trigger/debug module */ -register tselect : xlenbits - -/* CSR names */ - -val cast csr_name : csreg -> string -function csr_name(csr) = { - match (csr) { - /* user trap setup */ - 0x000 => "ustatus", - 0x004 => "uie", - 0x005 => "utvec", - /* user floating-point context */ - 0x001 => "fflags", - 0x002 => "frm", - 0x003 => "fcsr", - /* counter/timers */ - 0xC00 => "cycle", - 0xC01 => "time", - 0xC02 => "instret", - 0xC80 => "cycleh", - 0xC81 => "timeh", - 0xC82 => "instreth", - /* TODO: other hpm counters */ - /* supervisor trap setup */ - 0x100 => "sstatus", - 0x102 => "sedeleg", - 0x103 => "sideleg", - 0x104 => "sie", - 0x105 => "stvec", - 0x106 => "scounteren", - /* supervisor trap handling */ - 0x140 => "sscratch", - 0x141 => "sepc", - 0x142 => "scause", - 0x143 => "stval", - 0x144 => "sip", - /* supervisor protection and translation */ - 0x180 => "satp", - /* machine information registers */ - 0xF11 => "mvendorid", - 0xF12 => "marchid", - 0xF13 => "mimpid", - 0xF14 => "mhartid", - /* machine trap setup */ - 0x300 => "mstatus", - 0x301 => "misa", - 0x302 => "medeleg", - 0x303 => "mideleg", - 0x304 => "mie", - 0x305 => "mtvec", - 0x306 => "mcounteren", - /* machine trap handling */ - 0x340 => "mscratch", - 0x341 => "mepc", - 0x342 => "mcause", - 0x343 => "mtval", - 0x344 => "mip", - - 0x3A0 => "pmpcfg0", - 0x3B0 => "pmpaddr0", - /* TODO: machine protection and translation */ - /* machine counters/timers */ - 0xB00 => "mcycle", - 0xB02 => "minstret", - 0xB80 => "mcycleh", - 0xB82 => "minstreth", - /* TODO: other hpm counters and events */ - /* trigger/debug */ - 0x7a0 => "tselect", - _ => "UNKNOWN" - } -} - -mapping csr_name_map : csreg <-> string = { - /* user trap setup */ - 0x000 <-> "ustatus", - 0x004 <-> "uie", - 0x005 <-> "utvec", - /* user trap handling */ - 0x040 <-> "uscratch", - 0x041 <-> "uepc", - 0x042 <-> "ucause", - 0x043 <-> "utval", - 0x044 <-> "uip", - /* user floating-point context */ - 0x001 <-> "fflags", - 0x002 <-> "frm", - 0x003 <-> "fcsr", - /* counter/timers */ - 0xC00 <-> "cycle", - 0xC01 <-> "time", - 0xC02 <-> "instret", - 0xC80 <-> "cycleh", - 0xC81 <-> "timeh", - 0xC82 <-> "instreth", - /* TODO: other hpm counters */ - /* supervisor trap setup */ - 0x100 <-> "sstatus", - 0x102 <-> "sedeleg", - 0x103 <-> "sideleg", - 0x104 <-> "sie", - 0x105 <-> "stvec", - 0x106 <-> "scounteren", - /* supervisor trap handling */ - 0x140 <-> "sscratch", - 0x141 <-> "sepc", - 0x142 <-> "scause", - 0x143 <-> "stval", - 0x144 <-> "sip", - /* supervisor protection and translation */ - 0x180 <-> "satp", - /* machine information registers */ - 0xF11 <-> "mvendorid", - 0xF12 <-> "marchid", - 0xF13 <-> "mimpid", - 0xF14 <-> "mhartid", - /* machine trap setup */ - 0x300 <-> "mstatus", - 0x301 <-> "misa", - 0x302 <-> "medeleg", - 0x303 <-> "mideleg", - 0x304 <-> "mie", - 0x305 <-> "mtvec", - 0x306 <-> "mcounteren", - /* machine trap handling */ - 0x340 <-> "mscratch", - 0x341 <-> "mepc", - 0x342 <-> "mcause", - 0x343 <-> "mtval", - 0x344 <-> "mip", - /* machine protection and translation */ - 0x3A0 <-> "pmpcfg0", - 0x3A1 <-> "pmpcfg1", - 0x3A2 <-> "pmpcfg2", - 0x3A3 <-> "pmpcfg3", - 0x3B0 <-> "pmpaddr0", - 0x3B1 <-> "pmpaddr1", - 0x3B2 <-> "pmpaddr2", - 0x3B3 <-> "pmpaddr3", - 0x3B4 <-> "pmpaddr4", - 0x3B5 <-> "pmpaddr5", - 0x3B6 <-> "pmpaddr6", - 0x3B7 <-> "pmpaddr7", - 0x3B8 <-> "pmpaddr8", - 0x3B9 <-> "pmpaddr9", - 0x3BA <-> "pmpaddr10", - 0x3BB <-> "pmpaddr11", - 0x3BC <-> "pmpaddr12", - 0x3BD <-> "pmpaddr13", - 0x3BE <-> "pmpaddr14", - 0x3BF <-> "pmpaddr15", - /* machine counters/timers */ - 0xB00 <-> "mcycle", - 0xB02 <-> "minstret", - 0xB80 <-> "mcycleh", - 0xB82 <-> "minstreth", - /* TODO: other hpm counters and events */ - /* trigger/debug */ - 0x7a0 <-> "tselect", - 0x7a1 <-> "tdata1", - 0x7a2 <-> "tdata2", - 0x7a3 <-> "tdata3" - - /* numeric fallback */ - /* reg <-> hex_bits_12(reg) */ - } - - -/* CSR access control */ - -function csrAccess(csr : csreg) -> csrRW = csr[11..10] -function csrPriv(csr : csreg) -> priv_level = csr[9..8] - -function is_CSR_defined (csr : bits(12), p : Privilege) -> bool = - match (csr) { - /* machine mode: informational */ - 0xf11 => p == Machine, // mvendorid - 0xf12 => p == Machine, // marchdid - 0xf13 => p == Machine, // mimpid - 0xf14 => p == Machine, // mhartid - /* machine mode: trap setup */ - 0x300 => p == Machine, // mstatus - 0x301 => p == Machine, // misa - 0x302 => p == Machine, // medeleg - 0x303 => p == Machine, // mideleg - 0x304 => p == Machine, // mie - 0x305 => p == Machine, // mtvec - 0x306 => p == Machine, // mcounteren - /* machine mode: trap handling */ - 0x340 => p == Machine, // mscratch - 0x341 => p == Machine, // mepc - 0x342 => p == Machine, // mcause - 0x343 => p == Machine, // mtval - 0x344 => p == Machine, // mip - - 0x3A0 => p == Machine, // pmpcfg0 - 0x3B0 => false, // (Disabled for Spike compatibility) -// 0x3B0 => p == Machine, // pmpaddr0 - - /* supervisor mode: trap setup */ - 0x100 => p == Machine | p == Supervisor, // sstatus - 0x102 => p == Machine | p == Supervisor, // sedeleg - 0x103 => p == Machine | p == Supervisor, // sideleg - 0x104 => p == Machine | p == Supervisor, // sie - 0x105 => p == Machine | p == Supervisor, // stvec - 0x106 => p == Machine | p == Supervisor, // scounteren - - /* supervisor mode: trap handling */ - 0x140 => p == Machine | p == Supervisor, // sscratch - 0x141 => p == Machine | p == Supervisor, // sepc - 0x142 => p == Machine | p == Supervisor, // scause - 0x143 => p == Machine | p == Supervisor, // stval - 0x144 => p == Machine | p == Supervisor, // sip - - /* supervisor mode: address translation */ - 0x180 => p == Machine | p == Supervisor, // satp - - /* disabled trigger/debug module */ - 0x7a0 => p == Machine, - - _ => false - } - -val check_CSR_access : (csrRW, priv_level, Privilege, bool) -> bool -function check_CSR_access(csrrw, csrpr, p, isWrite) = - (~ (isWrite == true & csrrw == 0b11)) /* read/write */ - & (privLevel_to_bits(p) >=_u csrpr) /* privilege */ - -function check_TVM_SATP(csr : csreg, p : Privilege) -> bool = - ~ (csr == 0x180 & p == Supervisor & mstatus.TVM() == true) - -function check_Counteren(csr : csreg, p : Privilege) -> bool = - match(csr, p) { - (0xC00, Supervisor) => mcounteren.CY() == true, - (0xC01, Supervisor) => mcounteren.TM() == true, - (0xC02, Supervisor) => mcounteren.IR() == true, - - (0xC00, User) => scounteren.CY() == true, - (0xC01, User) => scounteren.TM() == true, - (0xC02, User) => scounteren.IR() == true, - - (_, _) => /* no HPM counters for now */ - if 0xC03 <=_u csr & csr <=_u 0xC1F - then false - else true - } - -function check_CSR(csr : csreg, p : Privilege, isWrite : bool) -> bool = - is_CSR_defined(csr, p) - & check_CSR_access(csrAccess(csr), csrPriv(csr), p, isWrite) - & check_TVM_SATP(csr, p) - & check_Counteren(csr, p) - -/* Reservation handling for LR/SC. - * - * The reservation state is maintained external to the model since the - * reservation behavior is platform-specific anyway and maintaining - * this state outside the model simplifies the concurrency analysis. - * - * These are externs are defined here in the system module since - * we currently perform reservation cancellation on privilege level - * transition. Ideally, the platform should get more visibility into - * where cancellation can be performed. - */ - -val load_reservation = {ocaml: "Platform.load_reservation", c: "load_reservation", lem: "load_reservation"} : xlenbits -> unit - -val match_reservation = {ocaml: "Platform.match_reservation", lem: "speculate_conditional_success", c: "match_reservation"} : xlenbits -> bool effect {exmem} - -val cancel_reservation = {ocaml: "Platform.cancel_reservation", c: "cancel_reservation", lem: "cancel_reservation"} : unit -> unit - -/* Exception delegation: given an exception and the privilege at which - * it occured, returns the privilege at which it should be handled. - */ -function exception_delegatee(e : ExceptionType, p : Privilege) -> Privilege = { - let idx = num_of_ExceptionType(e); - let super = medeleg.bits()[idx]; - let user = sedeleg.bits()[idx]; - let deleg = /* if misa.N() == true & user then User - else */ - if misa.S() == true & super then Supervisor - else Machine; - /* Ensure there is no transition to a less-privileged mode. */ - if privLevel_to_bits(deleg) <_u privLevel_to_bits(p) - then p else deleg -} - -/* Interrupts are prioritized in privilege order, and for each - * privilege, in the order: external, software, timers. - */ -function findPendingInterrupt(ip : xlenbits) -> option(InterruptType) = { - let ip = Mk_Minterrupts(ip); - if ip.MEI() == true then Some(I_M_External) - else if ip.MSI() == true then Some(I_M_Software) - else if ip.MTI() == true then Some(I_M_Timer) - else if ip.SEI() == true then Some(I_S_External) - else if ip.SSI() == true then Some(I_S_Software) - else if ip.STI() == true then Some(I_S_Timer) - else if ip.UEI() == true then Some(I_U_External) - else if ip.USI() == true then Some(I_U_Software) - else if ip.UTI() == true then Some(I_U_Timer) - else None() -} - -/* Examines current M-mode interrupt state and returns an interrupt to be - * handled, and the privilege it should be handled at. Interrupts are - * dispatched in order of decreasing privilege, while ensuring that the - * resulting privilege level is not reduced; i.e. delegated interrupts to - * lower privileges are effectively masked until control returns to them. - * - * For now, it assumes 'S' and no 'N' extension, which is the common case. - */ -function curInterrupt(priv : Privilege, pend : Minterrupts, enbl : Minterrupts, delg : Minterrupts) - -> option((InterruptType, Privilege)) = { - let en_mip : xlenbits = pend.bits() & enbl.bits(); - if en_mip == EXTZ(0b0) then None() /* fast path */ - else { - /* check implicit enabling when in lower privileges */ - let eff_mie = priv != Machine | (priv == Machine & mstatus.MIE() == true); - let eff_sie = priv == User | (priv == Supervisor & mstatus.SIE() == true); - /* handle delegation */ - let eff_mip = en_mip & (~ (delg.bits())); /* retained at M-mode */ - let eff_sip = en_mip & delg.bits(); /* delegated to S-mode */ - - if eff_mie & eff_mip != EXTZ(0b0) - then match findPendingInterrupt(eff_mip) { - Some(i) => let r = (i, Machine) in Some(r), - None() => { internal_error("non-zero eff_mip=" ^ BitStr(eff_mip) ^ ", but nothing pending") } - } - else if eff_sie & eff_sip != EXTZ(0b0) - then match findPendingInterrupt(eff_sip) { - Some(i) => let r = (i, Supervisor) in Some(r), - None() => { internal_error("non-zero eff_sip=" ^ BitStr(eff_sip) ^ ", but nothing pending") } - } - else { - let p = if pend.MTI() == true then "1" else "0"; - let e = if enbl.MTI() == true then "1" else "0"; - let d = if delg.MTI() == true then "1" else "0"; - print_platform(" MTI: pend=" ^ p ^ " enbl=" ^ e ^ " delg=" ^ d); - let eff_mip = en_mip & (~ (delg.bits())); /* retained at M-mode */ - let eff_sip = en_mip & delg.bits(); /* delegated to S-mode */ - print_platform("mstatus=" ^ BitStr(mstatus.bits()) - ^ " mie,sie=" ^ BitStr(mstatus.MIE()) ^ "," ^ BitStr(mstatus.SIE()) - ^ " en_mip=" ^ BitStr(en_mip) - ^ " eff_mip=" ^ BitStr(eff_mip) - ^ " eff_sip=" ^ BitStr(eff_sip)); - None() - } - } -} - -/* privilege transitions due to exceptions and interrupts */ - -struct sync_exception = { - trap : ExceptionType, - excinfo : option(xlenbits) -} - -function tval(excinfo : option(xlenbits)) -> xlenbits = { - match (excinfo) { - Some(e) => e, - None() => EXTZ(0b0) - } -} - -union ctl_result = { - CTL_TRAP : sync_exception, - CTL_SRET : unit, - CTL_MRET : unit -/* TODO: CTL_URET */ -} - -$ifdef RVFI_DII -val rvfi_trap : unit -> unit effect {wreg} -function rvfi_trap () = - rvfi_exec->rvfi_trap() = 0x01 -$else -val rvfi_trap : unit -> unit -function rvfi_trap () = () -$endif - -/* handle exceptional ctl flow by updating nextPC and operating privilege */ - -function handle_trap(del_priv : Privilege, intr : bool, c : exc_code, pc : xlenbits, info : option(xlenbits)) - -> xlenbits = { - rvfi_trap(); - print_platform("handling " ^ (if intr then "int#" else "exc#") ^ BitStr(c) ^ " at priv " ^ del_priv ^ " with tval " ^ BitStr(tval(info))); - - match (del_priv) { - Machine => { - mcause->IsInterrupt() = intr; - mcause->Cause() = EXTZ(c); - - mstatus->MPIE() = mstatus.MIE(); - mstatus->MIE() = false; - mstatus->MPP() = privLevel_to_bits(cur_privilege); - mtval = tval(info); - mepc = pc; - - cur_privilege = del_priv; - - print_reg("CSR mstatus <- " ^ BitStr(mstatus.bits()) ^ " (input: " ^ BitStr(mstatus.bits()) ^ ")"); // Spike compatible log - - cancel_reservation(); - - match tvec_addr(mtvec, mcause) { - Some(epc) => epc, - None() => internal_error("Invalid mtvec mode") - } - }, - Supervisor => { - scause->IsInterrupt() = intr; - scause->Cause() = EXTZ(c); - - mstatus->SPIE() = mstatus.SIE(); - mstatus->SIE() = false; - mstatus->SPP() = match (cur_privilege) { - User => false, - Supervisor => true, - Machine => internal_error("invalid privilege for s-mode trap") - }; - stval = tval(info); - sepc = pc; - - cur_privilege = del_priv; - - print_reg("CSR mstatus <- " ^ BitStr(mstatus.bits()) ^ " (input: " ^ BitStr(mstatus.bits()) ^ ")"); // Spike compatible log - - cancel_reservation(); - - match tvec_addr(stvec, scause) { - Some(epc) => epc, - None() => internal_error("Invalid stvec mode") - } - - }, - User => internal_error("the N extension is currently unsupported") - }; -} - -function handle_exception(cur_priv : Privilege, ctl : ctl_result, - pc: xlenbits) -> xlenbits = { - match (cur_priv, ctl) { - (_, CTL_TRAP(e)) => { - let del_priv = exception_delegatee(e.trap, cur_priv); - print_platform("trapping from " ^ cur_priv ^ " to " ^ del_priv - ^ " to handle " ^ e.trap); - handle_trap(del_priv, false, e.trap, pc, e.excinfo) - }, - (_, CTL_MRET()) => { - let prev_priv = cur_privilege; - mstatus->MIE() = mstatus.MPIE(); - mstatus->MPIE() = true; - cur_privilege = privLevel_of_bits(mstatus.MPP()); - mstatus->MPP() = privLevel_to_bits(User); - - print_reg("CSR mstatus <- " ^ BitStr(mstatus.bits()) ^ " (input: " ^ BitStr(mstatus.bits()) ^ ")"); // Spike compatible log - print_platform("ret-ing from " ^ prev_priv ^ " to " ^ cur_privilege); - - cancel_reservation(); - mepc & pc_alignment_mask() - }, - (_, CTL_SRET()) => { - let prev_priv = cur_privilege; - mstatus->SIE() = mstatus.SPIE(); - mstatus->SPIE() = true; - cur_privilege = if mstatus.SPP() == true then Supervisor else User; - mstatus->SPP() = false; - - print_reg("CSR mstatus <- " ^ BitStr(mstatus.bits()) ^ " (input: " ^ BitStr(mstatus.bits()) ^ ")"); // Spike compatible log - print_platform("ret-ing from " ^ prev_priv ^ " to " ^ cur_privilege); - - cancel_reservation(); - sepc & pc_alignment_mask() - } - } -} - -function handle_mem_exception(addr : xlenbits, e : ExceptionType) -> unit = { - let t : sync_exception = struct { trap = e, - excinfo = Some(addr) } in - nextPC = handle_exception(cur_privilege, CTL_TRAP(t), PC) -} - -function handle_interrupt(i : InterruptType, del_priv : Privilege) -> unit = - nextPC = handle_trap(del_priv, true, i, PC, None()) - -/* state state initialization */ - -function init_sys() -> unit = { - cur_privilege = Machine; - - mhartid = EXTZ(0b0); - - misa->MXL() = arch_to_bits(RV64); - misa->A() = true; /* atomics */ - misa->C() = true; /* RVC */ - misa->I() = true; /* base integer ISA */ - misa->M() = true; /* integer multiply/divide */ - misa->U() = true; /* user-mode */ - misa->S() = true; /* supervisor-mode */ - - /* 64-bit only mode with no extensions */ - mstatus->SXL() = misa.MXL(); - mstatus->UXL() = misa.MXL(); - mstatus->SD() = false; - - mip->bits() = EXTZ(0b0); - mie->bits() = EXTZ(0b0); - mideleg->bits() = EXTZ(0b0); - medeleg->bits() = EXTZ(0b0); - mtvec->bits() = EXTZ(0b0); - mcause->bits() = EXTZ(0b0); - mepc = EXTZ(0b0); - mtval = EXTZ(0b0); - mscratch = EXTZ(0b0); - - mcycle = EXTZ(0b0); - mtime = EXTZ(0b0); - - mcounteren->bits() = EXTZ(0b0); - - minstret = EXTZ(0b0); - minstret_written = false; - - // log compatibility with spike - print_reg("CSR mstatus <- " ^ BitStr(mstatus.bits()) ^ " (input: " ^ BitStr(EXTZ(0b0) : xlenbits) ^ ")") -} - -/* memory access exceptions, defined here for use by the platform model. */ - -union MemoryOpResult ('a : Type) = { - MemValue : 'a, - MemException : ExceptionType -} |
