summaryrefslogtreecommitdiff
path: root/mips
diff options
context:
space:
mode:
Diffstat (limited to 'mips')
-rw-r--r--mips/Makefile31
-rw-r--r--mips/main.sail57
-rw-r--r--mips/mips_ast_decl.sail44
-rw-r--r--mips/mips_epilogue.sail42
-rw-r--r--mips/mips_extras.lem94
-rw-r--r--mips/mips_insts.sail1708
-rw-r--r--mips/mips_prelude.sail620
-rw-r--r--mips/mips_regfp.sail455
-rw-r--r--mips/mips_ri.sail42
-rw-r--r--mips/mips_tlb.sail148
-rw-r--r--mips/mips_tlb_stub.sail48
-rw-r--r--mips/mips_wrappers.sail86
-rw-r--r--mips/prelude.sail391
13 files changed, 3766 insertions, 0 deletions
diff --git a/mips/Makefile b/mips/Makefile
new file mode 100644
index 00000000..55d8e986
--- /dev/null
+++ b/mips/Makefile
@@ -0,0 +1,31 @@
+THIS_MAKEFILE := $(realpath $(lastword $(MAKEFILE_LIST)))
+SAIL_DIR:=$(realpath $(dir $(THIS_MAKEFILE))..)
+export SAIL_DIR
+SAIL_LIB_DIR:=$(SAIL_DIR)/lib
+MIPS_SAIL_DIR:=$(SAIL_DIR)/mips
+
+SAIL:=$(SAIL_DIR)/sail
+
+MIPS_PRE:=$(SAIL_LIB_DIR)/flow.sail $(MIPS_SAIL_DIR)/prelude.sail $(MIPS_SAIL_DIR)/mips_prelude.sail
+MIPS_TLB:=$(MIPS_SAIL_DIR)/mips_tlb.sail
+MIPS_TLB_STUB:=$(MIPS_SAIL_DIR)/mips_tlb_stub.sail
+MIPS_SAILS:=$(MIPS_SAIL_DIR)/mips_wrappers.sail $(MIPS_SAIL_DIR)/mips_ast_decl.sail $(MIPS_SAIL_DIR)/mips_insts.sail $(MIPS_SAIL_DIR)/mips_ri.sail $(MIPS_SAIL_DIR)/mips_epilogue.sail
+MIPS_MAIN:=$(MIPS_SAIL_DIR)/main.sail
+
+mips: $(MIPS_PRE) $(MIPS_TLB) $(MIPS_SAILS) $(MIPS_MAIN)
+ $(SAIL) -ocaml -o mips $^
+
+mips_no_tlb.lem: $(MIPS_PRE) $(MIPS_TLB_STUB) $(MIPS_SAILS)
+ $(SAIL) -lem -o mips_no_tlb -lem_mwords -lem_lib Mips_extras -undefined_gen $^
+mips_no_tlb_types.lem: mips_no_tlb.lem
+
+# TODO: Use monomorphisation so that we can switch to machine words
+mips.lem: $(MIPS_PRE) $(MIPS_TLB) $(MIPS_SAILS)
+ $(SAIL) -lem -o mips -lem_lib Mips_extras -undefined_gen $^
+mips_types.lem: mips.lem
+
+M%.thy: m%.lem m%_types.lem mips_extras.lem
+ lem -isa -outdir . -lib $(SAIL_DIR)/src/gen_lib -lib $(SAIL_DIR)/src/lem_interp $^
+
+clean:
+ rm -rf mips Mips.thy mips.lem _sbuild
diff --git a/mips/main.sail b/mips/main.sail
new file mode 100644
index 00000000..2df5c0f8
--- /dev/null
+++ b/mips/main.sail
@@ -0,0 +1,57 @@
+
+
+
+val fetch_and_execute : unit -> unit effect {barr, eamem, escape, rmem, rreg, wmv, wreg, undef, wmvt, rmemt}
+function fetch_and_execute () = {
+ while true do {
+ PC = nextPC;
+ inBranchDelay = branchPending;
+ branchPending = 0b0;
+ nextPC = if inBranchDelay then delayedPC else PC + 4;
+ cp2_next_pc();
+
+ print_bits("PC: ", PC);
+ try {
+ let pc_pa = TranslatePC(PC);
+ /*print_bits("pa: ", pc_pa);*/
+ let instr = MEMr_wrapper(pc_pa, 4);
+ /*print_bits("hex: ", instr);*/
+ let instr_ast = decode(instr);
+ match instr_ast {
+ Some(HCF()) => {
+ print("simulation stopped due to halt instruction.");
+ return ();
+ },
+ Some(ast) => execute(ast),
+ None() => {print("Decode failed"); exit (())} /* Never expect this -- unknown instruction should actually result in reserved instruction ISA-level exception (see mips_ri.sail). */
+ }
+ } catch {
+ ISAException() => print("EXCEPTION")
+ /* ISA-level exception occurrred either during TranslatePC or execute --
+ just continue from nextPC, which should have been set to the appropriate
+ exception vector (along with clearing branchPending etc.) . */
+ };
+ };
+ skip_rmemt();
+ skip_wmvt();
+}
+
+val elf_entry = "Elf_loader.elf_entry" : unit -> int
+
+val main : unit -> unit effect {barr, eamem, escape, rmem, rreg, undef, wmv, wreg, rmemt, wmvt}
+
+function dump_mips_state () : unit -> unit = {
+ print_bits("DEBUG MIPS PC ", PC);
+ foreach (idx from 0 to 31) {
+ print(concat_str("DEBUG MIPS REG ", concat_str(string_of_int(idx), concat_str(" ", BitStr(rGPR(to_bits(5,idx)))))));
+ }
+}
+
+function main () = {
+ init_cp0_state();
+ init_cp2_state();
+ nextPC = to_bits(64, elf_entry());
+ fetch_and_execute();
+ dump_mips_state ();
+ dump_cp2_state ()
+}
diff --git a/mips/mips_ast_decl.sail b/mips/mips_ast_decl.sail
new file mode 100644
index 00000000..e39bc270
--- /dev/null
+++ b/mips/mips_ast_decl.sail
@@ -0,0 +1,44 @@
+/*========================================================================*/
+/* */
+/* Copyright (c) 2015-2017 Robert M. Norton */
+/* Copyright (c) 2015-2017 Kathyrn Gray */
+/* All rights reserved. */
+/* */
+/* This software was developed by the University of Cambridge Computer */
+/* Laboratory as part of the Rigorous Engineering of Mainstream Systems */
+/* (REMS) project, funded by EPSRC grant EP/K008528/1. */
+/* */
+/* Redistribution and use in source and binary forms, with or without */
+/* modification, are permitted provided that the following conditions */
+/* are met: */
+/* 1. Redistributions of source code must retain the above copyright */
+/* notice, this list of conditions and the following disclaimer. */
+/* 2. Redistributions in binary form must reproduce the above copyright */
+/* notice, this list of conditions and the following disclaimer in */
+/* the documentation and/or other materials provided with the */
+/* distribution. */
+/* */
+/* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' */
+/* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED */
+/* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A */
+/* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR */
+/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
+/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
+/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF */
+/* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND */
+/* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, */
+/* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */
+/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF */
+/* SUCH DAMAGE. */
+/*========================================================================*/
+
+/* misp_insts.sail: mips instruction decode and execute clauses and AST node
+ declarations */
+
+scattered union ast
+
+val execute : ast -> unit effect {barr, eamem, escape, rmem, rreg, undef, wmv, wreg}
+scattered function execute
+
+val decode : bits(32) -> option(ast) effect pure
+scattered function decode
diff --git a/mips/mips_epilogue.sail b/mips/mips_epilogue.sail
new file mode 100644
index 00000000..c7477a50
--- /dev/null
+++ b/mips/mips_epilogue.sail
@@ -0,0 +1,42 @@
+/*========================================================================*/
+/* */
+/* Copyright (c) 2015-2017 Robert M. Norton */
+/* Copyright (c) 2015-2017 Kathyrn Gray */
+/* All rights reserved. */
+/* */
+/* This software was developed by the University of Cambridge Computer */
+/* Laboratory as part of the Rigorous Engineering of Mainstream Systems */
+/* (REMS) project, funded by EPSRC grant EP/K008528/1. */
+/* */
+/* Redistribution and use in source and binary forms, with or without */
+/* modification, are permitted provided that the following conditions */
+/* are met: */
+/* 1. Redistributions of source code must retain the above copyright */
+/* notice, this list of conditions and the following disclaimer. */
+/* 2. Redistributions in binary form must reproduce the above copyright */
+/* notice, this list of conditions and the following disclaimer in */
+/* the documentation and/or other materials provided with the */
+/* distribution. */
+/* */
+/* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' */
+/* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED */
+/* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A */
+/* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR */
+/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
+/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
+/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF */
+/* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND */
+/* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, */
+/* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */
+/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF */
+/* SUCH DAMAGE. */
+/*========================================================================*/
+
+/* mips_epilogue.sail: end of decode, execute and AST definitions. */
+
+end decode
+end execute
+end ast
+
+val supported_instructions : ast -> option(ast)
+function supported_instructions instr = Some(instr)
diff --git a/mips/mips_extras.lem b/mips/mips_extras.lem
new file mode 100644
index 00000000..920277f6
--- /dev/null
+++ b/mips/mips_extras.lem
@@ -0,0 +1,94 @@
+open import Pervasives
+open import Pervasives_extra
+open import Sail_instr_kinds
+open import Sail_values
+open import Sail_operators
+open import Prompt_monad
+open import Prompt
+
+val MEMr : forall 'regval 'a 'b 'e. Bitvector 'a, Bitvector 'b => 'a -> integer -> monad 'regval 'b 'e
+val MEMr_reserve : forall 'regval 'a 'b 'e. Bitvector 'a, Bitvector 'b => 'a -> integer -> monad 'regval 'b 'e
+val MEMr_tag : forall 'regval 'a 'b 'e. Bitvector 'a, Bitvector 'b => 'a -> integer -> monad 'regval (bool * 'b) 'e
+val MEMr_tag_reserve : forall 'regval 'a 'b 'e. Bitvector 'a, Bitvector 'b => 'a -> integer -> monad 'regval (bool * 'b) 'e
+
+let MEMr addr size = read_mem Read_plain addr size
+let MEMr_reserve addr size = read_mem Read_reserve addr size
+
+let MEMr_tag addr size =
+ read_mem Read_plain addr size >>= fun v ->
+ read_tag addr >>= fun t ->
+ return (bool_of_bitU t, v)
+
+let MEMr_tag_reserve addr size =
+ read_mem Read_plain addr size >>= fun v ->
+ read_tag addr >>= fun t ->
+ return (bool_of_bitU t, v)
+
+
+val MEMea : forall 'regval 'a 'e. Bitvector 'a => 'a -> integer -> monad 'regval unit 'e
+val MEMea_conditional : forall 'regval 'a 'e. Bitvector 'a => 'a -> integer -> monad 'regval unit 'e
+val MEMea_tag : forall 'regval 'a 'e. Bitvector 'a => 'a -> integer -> monad 'regval unit 'e
+val MEMea_tag_conditional : forall 'regval 'a 'e. Bitvector 'a => 'a -> integer -> monad 'regval unit 'e
+
+let MEMea addr size = write_mem_ea Write_plain addr size
+let MEMea_conditional addr size = write_mem_ea Write_conditional addr size
+
+let MEMea_tag addr size = write_mem_ea Write_plain addr size
+let MEMea_tag_conditional addr size = write_mem_ea Write_conditional addr size
+
+
+val MEMval : forall 'regval 'a 'b 'e. Bitvector 'a, Bitvector 'b => 'a -> integer -> 'b -> monad 'regval unit 'e
+val MEMval_conditional : forall 'regval 'a 'b 'e. Bitvector 'a, Bitvector 'b => 'a -> integer -> 'b -> monad 'regval bool 'e
+val MEMval_tag : forall 'regval 'a 'b 'e. Bitvector 'a, Bitvector 'b => 'a -> integer -> bool -> 'b -> monad 'regval unit 'e
+val MEMval_tag_conditional : forall 'regval 'a 'b 'e. Bitvector 'a, Bitvector 'b => 'a -> integer -> bool -> 'b -> monad 'regval bool 'e
+
+let MEMval _ size v = write_mem_val v >>= fun _ -> return ()
+let MEMval_conditional _ size v = write_mem_val v >>= fun b -> return (if b then true else false)
+let MEMval_tag _ size t v = write_mem_val v >>= fun _ -> write_tag_val (bitU_of_bool t) >>= fun _ -> return ()
+let MEMval_tag_conditional _ size t v = write_mem_val v >>= fun b -> write_tag_val (bitU_of_bool t) >>= fun _ -> return (if b then true else false)
+
+val MEM_sync : forall 'regval 'e. unit -> monad 'regval unit 'e
+
+let MEM_sync () = barrier Barrier_MIPS_SYNC
+
+(* Some wrappers copied from aarch64_extras *)
+(* TODO: Harmonise into a common library *)
+
+let get_slice_int_bl len n lo =
+ (* TODO: Is this the intended behaviour? *)
+ let hi = lo + len - 1 in
+ let bits = bits_of_int (hi + 1) n in
+ get_bits false bits hi lo
+
+val get_slice_int : forall 'a. Bitvector 'a => integer -> integer -> integer -> 'a
+let get_slice_int len n lo = of_bits (get_slice_int_bl len n lo)
+
+let write_ram _ size _ addr data =
+ MEMea addr size >>
+ MEMval addr size data
+
+let read_ram _ size _ addr = MEMr addr size
+
+let sign_extend bits len = exts_bv len bits
+let zero_extend bits len = extz_bv len bits
+
+let shift_bits_left v n = shiftl_bv v (unsigned n)
+let shift_bits_right v n = shiftr_bv v (unsigned n)
+let shift_bits_right_arith v n = arith_shiftr_bv v (unsigned n)
+
+(* TODO: These could be monadic instead of hardcoded *)
+let internal_pick vs = head vs
+let undefined_string () = ""
+let undefined_unit () = ()
+let undefined_int () = (0:ii)
+let undefined_bool () = false
+val undefined_vector : forall 'a. integer -> 'a -> list 'a
+let undefined_vector len u = repeat [u] len
+val undefined_bitvector : forall 'a. Bitvector 'a => integer -> 'a
+let undefined_bitvector len = of_bits (repeat [B0] len)
+let undefined_bits len = undefined_bitvector len
+let undefined_bit () = B0
+let undefined_real () = realFromFrac 0 1
+let undefined_range i j = i
+let undefined_atom i = i
+let undefined_nat () = (0:ii)
diff --git a/mips/mips_insts.sail b/mips/mips_insts.sail
new file mode 100644
index 00000000..e8f9a0f7
--- /dev/null
+++ b/mips/mips_insts.sail
@@ -0,0 +1,1708 @@
+/*========================================================================*/
+/* */
+/* Copyright (c) 2015-2017 Robert M. Norton */
+/* Copyright (c) 2015-2017 Kathyrn Gray */
+/* All rights reserved. */
+/* */
+/* This software was developed by the University of Cambridge Computer */
+/* Laboratory as part of the Rigorous Engineering of Mainstream Systems */
+/* (REMS) project, funded by EPSRC grant EP/K008528/1. */
+/* */
+/* Redistribution and use in source and binary forms, with or without */
+/* modification, are permitted provided that the following conditions */
+/* are met: */
+/* 1. Redistributions of source code must retain the above copyright */
+/* notice, this list of conditions and the following disclaimer. */
+/* 2. Redistributions in binary form must reproduce the above copyright */
+/* notice, this list of conditions and the following disclaimer in */
+/* the documentation and/or other materials provided with the */
+/* distribution. */
+/* */
+/* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' */
+/* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED */
+/* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A */
+/* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR */
+/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
+/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
+/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF */
+/* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND */
+/* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, */
+/* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */
+/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF */
+/* SUCH DAMAGE. */
+/*========================================================================*/
+
+/* misp_insts.sail: mips instruction decode and execute clauses and AST node
+ declarations */
+
+/**************************************************************************************/
+/* [D]ADD[I][U] various forms of ADD */
+/**************************************************************************************/
+
+/* DADDIU Doubleword Add Immediate Unsigned --
+ the simplest possible instruction, no undefined behaviour or exceptions
+ reg, reg, immediate */
+
+union clause ast = DADDIU : (regno, regno, imm16)
+
+function clause decode (0b011001 @ rs : regno @ rt : regno @ imm : imm16) =
+ Some(DADDIU(rs, rt, imm))
+
+function clause execute (DADDIU (rs, rt, imm)) =
+ {
+ wGPR(rt) = rGPR(rs) + EXTS(imm)
+ }
+
+/* DADDU Doubleword Add Unsigned -- another very simple instruction,
+ reg, reg, reg */
+
+union clause ast = DADDU : (regno, regno, regno)
+
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b101101) =
+ Some(DADDU(rs, rt, rd))
+
+function clause execute (DADDU (rs, rt, rd)) =
+ {
+ wGPR(rd) = rGPR(rs) + rGPR(rt)
+ }
+
+/* DADDI Doubleword Add Immediate
+ reg, reg, imm with possible exception */
+
+union clause ast = DADDI : (regno, regno, bits(16))
+
+function clause decode (0b011000 @ rs : regno @ rt : regno @ imm : imm16) =
+ Some(DADDI(rs, rt, imm))
+
+function clause execute (DADDI (rs, rt, imm)) =
+ {
+ let sum65 : bits(65) = EXTS(rGPR(rs)) + EXTS(imm) in
+ {
+ if (sum65[64] != sum65[63]) then
+ (SignalException(Ov))
+ else
+ wGPR(rt) = sum65[63..0]
+ }
+ }
+
+/* DADD Doubleword Add
+ reg, reg, reg with possible exception */
+
+union clause ast = DADD : (regno, regno, regno)
+
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b101100) =
+ Some(DADD(rs, rt, rd))
+
+function clause execute (DADD (rs, rt, rd)) =
+ {
+ let sum65 : bits(65) = EXTS(rGPR(rs)) + EXTS(rGPR(rt)) in
+ {
+ if sum65[64] != sum65[63] then
+ (SignalException(Ov))
+ else
+ wGPR(rd) = sum65[63..0]
+ }
+ }
+
+/* ADD 32-bit add -- reg, reg, reg with possible undefined behaviour or exception */
+
+union clause ast = ADD : (regno, regno, regno)
+
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b100000) =
+ Some(ADD(rs, rt, rd))
+
+function clause execute (ADD(rs, rt, rd)) =
+ {
+ opA : bits(64) = rGPR(rs);
+ opB : bits(64) = rGPR(rt);
+ if NotWordVal(opA) | NotWordVal(opB) then
+ wGPR(rd) = undefined /* XXX could exit instead */
+ else
+ let sum33 : bits(33) = EXTS(opA[31 .. 0]) + EXTS(opB[31 .. 0])in
+ if sum33[32] != sum33[31] then
+ (SignalException(Ov))
+ else
+ wGPR(rd) = EXTS(sum33[31..0])
+ }
+
+/* ADDI 32-bit add immediate -- reg, reg, imm with possible undefined behaviour or exception */
+
+union clause ast = ADDI : (regno, regno, bits(16))
+
+function clause decode (0b001000 @ rs : regno @ rt : regno @ imm : imm16) =
+ Some(ADDI(rs, rt, imm))
+
+function clause execute (ADDI(rs, rt, imm)) =
+ {
+ opA = rGPR(rs);
+ if NotWordVal(opA) then
+ wGPR(rt) = undefined /* XXX could exit instead */
+ else
+ let sum33 : bits(33) = EXTS(opA[31 .. 0]) + EXTS(imm) in
+ if sum33[32] != sum33[31] then
+ (SignalException(Ov))
+ else
+ wGPR(rt) = EXTS(sum33[31..0])
+ }
+
+/* ADDU 32-bit add immediate -- reg, reg, reg with possible undefined behaviour */
+
+union clause ast = ADDU : (regno, regno, regno)
+
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b100001) =
+ Some(ADDU(rs, rt, rd))
+
+function clause execute (ADDU(rs, rt, rd)) =
+ {
+ opA = rGPR(rs);
+ opB = rGPR(rt);
+ if NotWordVal(opA) | NotWordVal(opB) then
+ wGPR(rd) = undefined
+ else
+ wGPR(rd) = EXTS(opA[31..0] + opB[31..0])
+ }
+
+
+/* ADDIU 32-bit add immediate -- reg, reg, imm with possible undefined behaviour */
+
+union clause ast = ADDIU : (regno, regno, bits(16))
+
+function clause decode (0b001001 @ rs : regno @ rt : regno @ imm : imm16) =
+ Some(ADDIU(rs, rt, imm))
+
+function clause execute (ADDIU(rs, rt, imm)) =
+ {
+ opA = rGPR(rs);
+ if NotWordVal(opA) then
+ wGPR(rt) = undefined /* XXX could exit instead */
+ else
+ wGPR(rt) = EXTS((opA[31 .. 0]) + EXTS(imm))
+ }
+
+/**************************************************************************************/
+/* [D]SUB[U] various forms of SUB */
+/**************************************************************************************/
+
+/* DSUBU doubleword subtract 'unsigned' reg, reg, reg */
+
+union clause ast = DSUBU : (regno, regno, regno)
+
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b101111) =
+ Some(DSUBU(rs, rt, rd))
+
+function clause execute (DSUBU (rs, rt, rd)) =
+ {
+ wGPR(rd) = rGPR(rs) - rGPR(rt)
+ }
+
+/* DSUB reg, reg, reg with possible exception */
+
+union clause ast = DSUB : (regno, regno, regno)
+
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b101110) =
+ Some(DSUB(rs, rt, rd))
+
+function clause execute (DSUB (rs, rt, rd)) =
+ {
+ let temp65 : bits(65) = EXTS(rGPR(rs)) - EXTS(rGPR(rt)) in
+ {
+ if temp65[64] != temp65[63] then
+ (SignalException(Ov))
+ else
+ wGPR(rd) = temp65[63..0]
+ }
+ }
+
+/* SUB 32-bit sub -- reg, reg, reg with possible undefined behaviour or exception */
+
+union clause ast = SUB : (regno, regno, regno)
+
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b100010) =
+ Some(SUB(rs, rt, rd))
+
+function clause execute (SUB(rs, rt, rd)) =
+ {
+ opA = rGPR(rs);
+ opB = rGPR(rt);
+ if NotWordVal(opA) | NotWordVal(opB) then
+ wGPR(rd) = undefined /* XXX could instead */
+ else
+ let temp33 : bits(33) = EXTS(opA[31..0]) - EXTS(opB[31..0]) in
+ if temp33[32] != temp33[31] then
+ (SignalException(Ov))
+ else
+ wGPR(rd) = EXTS(temp33[31..0])
+ }
+
+/* SUBU 32-bit 'unsigned' sub -- reg, reg, reg with possible undefined behaviour */
+
+union clause ast = SUBU : (regno, regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b100011) =
+ Some(SUBU(rs, rt, rd))
+
+function clause execute (SUBU(rs, rt, rd)) =
+ {
+ opA = rGPR(rs);
+ opB = rGPR(rt);
+ if NotWordVal(opA) | NotWordVal(opB) then
+ wGPR(rd) = undefined
+ else
+ wGPR(rd) = EXTS(opA[31..0] - opB[31..0])
+ }
+
+/**************************************************************************************/
+/* Logical bitwise operations */
+/**************************************************************************************/
+
+/* AND reg, reg, reg */
+
+union clause ast = AND : (regno, regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b100100) =
+ Some(AND(rs, rt, rd))
+
+function clause execute (AND (rs, rt, rd)) =
+ {
+ wGPR(rd) = (rGPR(rs) & rGPR(rt))
+ }
+
+/* ANDI reg, reg, imm */
+
+union clause ast = ANDI : (regno, regno, bits(16))
+function clause decode (0b001100 @ rs : regno @ rt : regno @ imm : imm16) =
+ Some(ANDI(rs, rt, imm))
+function clause execute (ANDI (rs, rt, imm)) =
+ {
+ wGPR(rt) = (rGPR(rs) & EXTZ(imm))
+ }
+
+/* OR reg, reg, reg */
+
+union clause ast = OR : (regno, regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b100101) =
+ Some(OR(rs, rt, rd))
+function clause execute (OR (rs, rt, rd)) =
+ {
+ wGPR(rd) = (rGPR(rs) | rGPR(rt))
+ }
+
+/* ORI reg, reg, imm */
+
+union clause ast = ORI : (regno, regno, bits(16))
+function clause decode (0b001101 @ rs : regno @ rt : regno @ imm : imm16) =
+ Some(ORI(rs, rt, imm))
+function clause execute (ORI (rs, rt, imm)) =
+ {
+ wGPR(rt) = (rGPR(rs) | EXTZ(imm))
+ }
+
+/* NOR reg, reg, reg */
+
+union clause ast = NOR : (regno, regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b100111) =
+ Some(NOR(rs, rt, rd))
+function clause execute (NOR (rs, rt, rd)) =
+ {
+ wGPR(rd) = ~(rGPR(rs) | rGPR(rt))
+ }
+
+/* XOR reg, reg, reg */
+
+union clause ast = XOR : (regno, regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b100110) =
+ Some(XOR(rs, rt, rd))
+function clause execute (XOR (rs, rt, rd)) =
+ {
+ wGPR(rd) = (rGPR(rs) ^ rGPR(rt))
+ }
+
+/* XORI reg, reg, imm */
+union clause ast = XORI : (regno, regno, bits(16))
+function clause decode (0b001110 @ rs : regno @ rt : regno @ imm : imm16) =
+ Some(XORI(rs, rt, imm))
+function clause execute (XORI (rs, rt, imm)) =
+ {
+ wGPR(rt) = (rGPR(rs) ^ EXTZ(imm))
+ }
+
+/* LUI reg, imm 32-bit load immediate into upper 16 bits */
+union clause ast = LUI : (regno, imm16)
+function clause decode (0b001111 @ 0b00000 @ rt : regno @ imm : imm16) =
+ Some(LUI(rt, imm))
+function clause execute (LUI (rt, imm)) =
+ {
+ wGPR(rt) = EXTS(imm @ 0x0000)
+ }
+
+/**************************************************************************************/
+/* 64-bit shift operations */
+/**************************************************************************************/
+
+/* DSLL reg, reg, imm5 */
+
+union clause ast = DSLL : (regno, regno, regno)
+function clause decode (0b000000 @ 0b00000 @ rt : regno @ rd : regno @ sa : bits(5) @ 0b111000) =
+ Some(DSLL(rt, rd, sa))
+function clause execute (DSLL (rt, rd, sa)) =
+ {
+
+ wGPR(rd) = (rGPR(rt) << sa)
+ }
+
+/* DSLL32 reg, reg, imm5 */
+
+union clause ast = DSLL32 : (regno, regno, regno)
+function clause decode (0b000000 @ 0b00000 @ rt : regno @ rd : regno @ sa : bits(5) @ 0b111100) =
+ Some(DSLL32(rt, rd, sa))
+function clause execute (DSLL32 (rt, rd, sa)) =
+ {
+ wGPR(rd) = (rGPR(rt) << (0b1 @ sa))
+ }
+
+/* DSLLV reg, reg, reg */
+
+union clause ast = DSLLV : (regno, regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b010100) =
+ Some(DSLLV(rs, rt, rd))
+function clause execute (DSLLV (rs, rt, rd)) =
+ {
+ wGPR(rd) = (rGPR(rt) << ((rGPR(rs))[5 .. 0]))
+ }
+
+/* DSRA arithmetic shift duplicating sign bit - reg, reg, imm5 */
+
+union clause ast = DSRA : (regno, regno, regno)
+function clause decode (0b000000 @ 0b00000 @ rt : regno @ rd : regno @ sa : bits(5) @ 0b111011) =
+ Some(DSRA(rt, rd, sa))
+function clause execute (DSRA (rt, rd, sa)) =
+ {
+ temp = rGPR(rt);
+ wGPR(rd) = temp >>_s sa
+ }
+
+/* DSRA32 reg, reg, imm5 */
+
+union clause ast = DSRA32 : (regno, regno, regno)
+function clause decode (0b000000 @ 0b00000 @ rt : regno @ rd : regno @ sa : bits(5) @ 0b111111) =
+ Some(DSRA32(rt, rd, sa))
+function clause execute (DSRA32 (rt, rd, sa)) =
+ {
+ temp = rGPR(rt);
+ sa32 = 0b1 @ sa; /* sa+32 */
+ wGPR(rd) = temp >>_s sa32
+ }
+
+/* DSRAV reg, reg, reg */
+union clause ast = DSRAV : (regno, regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b010111) =
+ Some(DSRAV(rs, rt, rd))
+function clause execute (DSRAV (rs, rt, rd)) =
+ {
+ temp = rGPR(rt);
+ sa = rGPR(rs)[5..0];
+ wGPR(rd) = temp >>_s sa
+ }
+
+/* DSRL shift right logical - reg, reg, imm5 */
+
+union clause ast = DSRL : (regno, regno, regno)
+function clause decode (0b000000 @ 0b00000 @ rt : regno @ rd : regno @ sa : bits(5) @ 0b111010) =
+ Some(DSRL(rt, rd, sa))
+function clause execute (DSRL (rt, rd, sa)) =
+ {
+ temp = rGPR(rt);
+ wGPR(rd) = temp >> sa;
+ }
+
+/* DSRL32 reg, reg, imm5 */
+
+union clause ast = DSRL32 : (regno, regno, regno)
+function clause decode (0b000000 @ 0b00000 @ rt : regno @ rd : regno @ sa : bits(5) @ 0b111110) =
+ Some(DSRL32(rt, rd, sa))
+function clause execute (DSRL32 (rt, rd, sa)) =
+ {
+ temp = rGPR(rt);
+ sa32 = 0b1 @ sa; /* sa+32 */
+ wGPR(rd) = temp >> sa32;
+ }
+
+/* DSRLV reg, reg, reg */
+
+union clause ast = DSRLV : (regno, regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b010110) =
+ Some(DSRLV(rs, rt, rd))
+function clause execute (DSRLV (rs, rt, rd)) =
+ {
+ temp = rGPR(rt);
+ sa = rGPR(rs)[5..0];
+ wGPR(rd) = temp >> sa;
+ }
+
+/**************************************************************************************/
+/* 32-bit shift operations */
+/**************************************************************************************/
+
+/* SLL 32-bit shift left */
+
+union clause ast = SLL : (regno, regno, regno)
+function clause decode (0b000000 @ 0b00000 @ rt : regno @ rd : regno @ sa : regno @ 0b000000) =
+ Some(SLL(rt, rd, sa))
+function clause execute (SLL(rt, rd, sa)) =
+ {
+ rt32 = rGPR(rt)[31..0];
+ wGPR(rd) = EXTS(rt32 << sa);
+ }
+
+/* SLLV 32-bit shift left variable */
+
+union clause ast = SLLV : (regno, regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b000100) =
+ Some(SLLV(rs, rt, rd))
+function clause execute (SLLV(rs, rt, rd)) =
+ {
+ sa = rGPR(rs)[4..0];
+ rt32 = rGPR(rt)[31..0];
+ wGPR(rd) = EXTS(rt32 << sa)
+ }
+
+/* SRA 32-bit arithmetic shift right */
+
+union clause ast = SRA : (regno, regno, regno)
+function clause decode (0b000000 @ 0b00000 @ rt : regno @ rd : regno @ sa : regno @ 0b000011) =
+ Some(SRA(rt, rd, sa))
+function clause execute (SRA(rt, rd, sa)) =
+ {
+ temp = rGPR(rt);
+ if (NotWordVal(temp)) then
+ wGPR(rd) = undefined
+ else {
+ rt32 = temp[31..0];
+ wGPR(rd) = EXTS(rt32 >>_s sa);
+ }
+ }
+
+/* SRAV 32-bit arithmetic shift right variable */
+
+union clause ast = SRAV : (regno, regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b000111) =
+ Some(SRAV(rs, rt, rd))
+function clause execute (SRAV(rs, rt, rd)) =
+ {
+ temp = rGPR(rt);
+ sa = rGPR(rs)[4..0];
+ if (NotWordVal(temp)) then
+ wGPR(rd) = undefined
+ else {
+ rt32 = temp[31..0];
+ wGPR(rd) = EXTS(rt32 >>_s sa)
+ }
+ }
+
+/* SRL 32-bit shift right */
+
+union clause ast = SRL : (regno, regno, regno)
+function clause decode (0b000000 @ 0b00000 @ rt : regno @ rd : regno @ sa : regno @ 0b000010) =
+ Some(SRL(rt, rd, sa))
+function clause execute (SRL(rt, rd, sa)) =
+ {
+ temp = rGPR(rt);
+ if (NotWordVal(temp)) then
+ wGPR(rd) = undefined
+ else {
+ rt32 = temp[31..0];
+ wGPR(rd) = EXTS(rt32 >> sa);
+ }
+ }
+
+/* SRLV 32-bit shift right variable */
+
+union clause ast = SRLV : (regno, regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b000110) =
+ Some(SRLV(rs, rt, rd))
+function clause execute (SRLV(rs, rt, rd)) =
+ {
+ temp = rGPR(rt);
+ sa = (rGPR(rs))[4..0];
+ if (NotWordVal(temp)) then
+ wGPR(rd) = undefined
+ else {
+ rt32 = temp[31..0];
+ wGPR(rd) = EXTS(rt32 >> sa);
+ }
+ }
+
+/**************************************************************************************/
+/* set less than / conditional move */
+/**************************************************************************************/
+
+/* SLT set if less than (signed) */
+
+union clause ast = SLT : (regno, regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b101010) =
+ Some(SLT(rs, rt, rd))
+function clause execute (SLT(rs, rt, rd)) =
+ {
+ wGPR(rd) = EXTZ(if (rGPR(rs) <_s rGPR(rt)) then 0b1 else 0b0)
+ }
+
+/* SLT set if less than immediate (signed) */
+
+union clause ast = SLTI : (regno, regno, bits(16))
+function clause decode (0b001010 @ rs : regno @ rt : regno @ imm : imm16) =
+ Some(SLTI(rs, rt, imm))
+function clause execute (SLTI(rs, rt, imm)) =
+ {
+ let imm_val = signed(imm) in
+ let rs_val = signed(rGPR(rs)) in
+ wGPR(rt) = EXTZ(if (rs_val < imm_val) then 0b1 else 0b0)
+ }
+
+/* SLTU set if less than unsigned */
+
+union clause ast = SLTU : (regno, regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b101011) =
+ Some(SLTU(rs, rt, rd))
+function clause execute (SLTU(rs, rt, rd)) =
+ {
+ let rs_val = rGPR(rs) in
+ let rt_val = rGPR(rt) in
+ wGPR(rd) = EXTZ(if (rs_val <_u rt_val) then 0b1 else 0b0)
+ }
+
+/* SLTIU set if less than immediate unsigned */
+
+union clause ast = SLTIU : (regno, regno, bits(16))
+function clause decode (0b001011 @ rs : regno @ rt : regno @ imm : imm16) =
+ Some(SLTIU(rs, rt, imm))
+function clause execute (SLTIU(rs, rt, imm)) =
+ {
+ let rs_val = rGPR(rs) in
+ let immext : bits(64) = EXTS(imm) in /* NB defined to sign extend here even though comparison is unsigned! */
+ wGPR(rt) = EXTZ(if (rs_val <_u immext) then 0b1 else 0b0)
+ }
+
+/* MOVN move if non-zero */
+
+union clause ast = MOVN : (regno, regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b001011) =
+ Some(MOVN(rs, rt, rd))
+function clause execute (MOVN(rs, rt, rd)) =
+ {
+ if (rGPR(rt) != 0x0000000000000000) then
+ wGPR(rd) = rGPR(rs)
+ }
+
+/* MOVZ move if zero */
+
+union clause ast = MOVZ : (regno, regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b001010) =
+ Some(MOVZ(rs, rt, rd))
+function clause execute (MOVZ(rs, rt, rd)) =
+ {
+ if (rGPR(rt) == 0x0000000000000000) then
+ wGPR(rd) = rGPR(rs)
+ }
+
+/******************************************************************************/
+/* MUL/DIV instructions */
+/******************************************************************************/
+
+/* MFHI move from HI register */
+union clause ast = MFHI : regno
+function clause decode (0b000000 @ 0b0000000000 @ rd : regno @ 0b00000 @ 0b010000) =
+ Some(MFHI(rd))
+function clause execute (MFHI(rd)) =
+ {
+ wGPR(rd) = HI
+ }
+
+/* MFLO move from LO register */
+union clause ast = MFLO : regno
+function clause decode (0b000000 @ 0b0000000000 @ rd : regno @ 0b00000 @ 0b010010) =
+ Some(MFLO(rd))
+function clause execute (MFLO(rd)) =
+ {
+ wGPR(rd) = LO
+ }
+
+/* MTHI move to HI register */
+union clause ast = MTHI : regno
+function clause decode (0b000000 @ rs : regno @ 0b000000000000000 @ 0b010001) =
+ Some(MTHI(rs))
+function clause execute (MTHI(rs)) =
+ {
+ HI = rGPR(rs)
+ }
+
+/* MTLO move to LO register */
+union clause ast = MTLO : regno
+function clause decode (0b000000 @ rs : regno @ 0b000000000000000 @ 0b010011) =
+ Some(MTLO(rs))
+function clause execute (MTLO(rs)) =
+ {
+ LO = rGPR(rs)
+ }
+
+/* MUL 32-bit multiply into GPR */
+union clause ast = MUL : (regno, regno, regno)
+function clause decode (0b011100 @ rs : regno @ rt : regno @ rd : regno @ 0b00000 @ 0b000010) =
+ Some(MUL(rs, rt, rd))
+function clause execute (MUL(rs, rt, rd)) =
+ {
+ rsVal = rGPR(rs);
+ rtVal = rGPR(rt);
+ result : bits(64) = EXTS((rsVal[31..0]) *_s (rtVal[31..0]));
+ wGPR(rd) = if (NotWordVal(rsVal) | NotWordVal(rtVal)) then
+ undefined
+ else
+ EXTS(result[31..0]);
+ /* HI and LO are technically undefined after MUL, but this causes problems with tests and
+ (potentially) context switch so just leave them alone
+ HI = undefined;
+ LO = undefined;
+ */
+ }
+
+/* MULT 32-bit multiply into HI/LO */
+union clause ast = MULT : (regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ 0b00000 @ 0b00000 @ 0b011000) =
+ Some(MULT(rs, rt))
+function clause execute (MULT(rs, rt)) =
+ {
+ rsVal = rGPR(rs);
+ rtVal = rGPR(rt);
+ result : bits(64) = if (NotWordVal(rsVal) | NotWordVal(rtVal)) then
+ undefined
+ else
+ (rsVal[31..0]) *_s (rtVal[31..0]);
+ HI = EXTS(result[63..32]);
+ LO = EXTS(result[31..0]);
+ }
+
+/* MULTU 32-bit unsignedm rultiply into HI/LO */
+union clause ast = MULTU : (regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ 0b00000 @ 0b00000 @ 0b011001) =
+ Some(MULTU(rs, rt))
+function clause execute (MULTU(rs, rt)) =
+ {
+ rsVal = rGPR(rs);
+ rtVal = rGPR(rt);
+ result : bits(64) = if (NotWordVal(rsVal) | NotWordVal(rtVal)) then
+ undefined
+ else
+ (rsVal[31..0]) *_u (rtVal[31..0]);
+ HI = EXTS(result[63..32]);
+ LO = EXTS(result[31..0]);
+ }
+
+/* DMULT 64-bit multiply into HI/LO */
+union clause ast = DMULT : (regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ 0b00000 @ 0b00000 @ 0b011100) =
+ Some(DMULT(rs, rt))
+function clause execute (DMULT(rs, rt)) =
+ {
+ result = rGPR(rs) *_s rGPR(rt);
+ HI = (result[127..64]);
+ LO = (result[63..0]);
+ }
+
+/* DMULTU 64-bit unsigned multiply into HI/LO */
+union clause ast = DMULTU : (regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ 0b00000 @ 0b00000 @ 0b011101) =
+ Some(DMULTU(rs, rt))
+function clause execute (DMULTU(rs, rt)) =
+ {
+ result = rGPR(rs) *_u rGPR(rt);
+ HI = (result[127..64]);
+ LO = (result[63..0]);
+ }
+
+/* MADD 32-bit signed multiply and add into HI/LO */
+union clause ast = MADD : (regno, regno)
+function clause decode (0b011100 @ rs : regno @ rt : regno @ 0b00000 @ 0b00000 @ 0b000000) =
+ Some(MADD(rs, rt))
+function clause execute (MADD(rs, rt)) =
+ {
+ rsVal = rGPR(rs);
+ rtVal = rGPR(rt);
+ mul_result : bits(64) = if (NotWordVal(rsVal) | NotWordVal(rtVal)) then
+ undefined
+ else
+ rsVal[31..0] *_s rtVal[31..0];
+ result = mul_result + (HI[31..0] @ LO[31..0]);
+ HI = EXTS(result[63..32]);
+ LO = EXTS(result[31..0]);
+ }
+
+/* MADDU 32-bit unsigned multiply and add into HI/LO */
+union clause ast = MADDU : (regno, regno)
+function clause decode (0b011100 @ rs : regno @ rt : regno @ 0b00000 @ 0b00000 @ 0b000001) =
+ Some(MADDU(rs, rt))
+function clause execute (MADDU(rs, rt)) =
+ {
+ rsVal = rGPR(rs);
+ rtVal = rGPR(rt);
+ mul_result : bits(64) = if (NotWordVal(rsVal) | NotWordVal(rtVal)) then
+ undefined
+ else
+ rsVal[31..0] *_u rtVal[31..0];
+ result = mul_result + (HI[31..0] @ LO[31..0]);
+ HI = EXTS(result[63..32]);
+ LO = EXTS(result[31..0]);
+ }
+
+/* MSUB 32-bit signed multiply and sub from HI/LO */
+union clause ast = MSUB : (regno, regno)
+function clause decode (0b011100 @ rs : regno @ rt : regno @ 0b00000 @ 0b00000 @ 0b000100) =
+ Some(MSUB(rs, rt))
+function clause execute (MSUB(rs, rt)) =
+ {
+ rsVal = rGPR(rs);
+ rtVal = rGPR(rt);
+ mul_result : bits(64) = if (NotWordVal(rsVal) | NotWordVal(rtVal)) then
+ undefined
+ else
+ rsVal[31..0] *_s rtVal[31..0];
+ result = (HI[31..0] @ LO[31..0]) - mul_result;
+ HI = EXTS(result[63..32]);
+ LO = EXTS(result[31..0]);
+ }
+
+/* MSUBU 32-bit unsigned multiply and sub from HI/LO */
+union clause ast = MSUBU : (regno, regno)
+function clause decode (0b011100 @ rs : regno @ rt : regno @ 0b00000 @ 0b00000 @ 0b000101) =
+ Some(MSUBU(rs, rt))
+function clause execute (MSUBU(rs, rt)) =
+ {
+ rsVal = rGPR(rs);
+ rtVal = rGPR(rt);
+ mul_result : bits(64) = if (NotWordVal(rsVal) | NotWordVal(rtVal)) then
+ undefined
+ else
+ rsVal[31..0] *_u rtVal[31..0];
+ result = (HI[31..0] @ LO[31..0]) - mul_result;
+ HI = EXTS(result[63..32]);
+ LO = EXTS(result[31..0]);
+ }
+
+/* DIV 32-bit divide into HI/LO */
+union clause ast = DIV : (regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ 0b00000 @ 0b00000 @ 0b011010) =
+ Some(DIV(rs, rt))
+function clause execute (DIV(rs, rt)) =
+ {
+ rsVal = rGPR(rs);
+ rtVal = rGPR(rt);
+ let (q, r) =
+ if (NotWordVal(rsVal) | NotWordVal(rtVal) | (rtVal == 0x0000000000000000)) then
+ (undefined : bits(32), undefined : bits(32))
+ else
+ let si = signed((rsVal[31..0])) in
+ let ti = signed((rtVal[31..0])) in
+ let qi = quot_round_zero(si, ti) in
+ let ri = si - (ti*qi) in
+ (to_bits(32, qi), to_bits(32, ri))
+ in
+ {
+ HI = EXTS(r);
+ LO = EXTS(q);
+ }
+ }
+
+/* DIVU 32-bit unsigned divide into HI/LO */
+union clause ast = DIVU : (regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ 0b00000 @ 0b00000 @ 0b011011) =
+ Some(DIVU(rs, rt))
+function clause execute (DIVU(rs, rt)) =
+ {
+ rsVal = rGPR(rs);
+ rtVal = rGPR(rt);
+ let (q, r) =
+ if (NotWordVal(rsVal) | NotWordVal(rtVal) | rtVal == 0x0000000000000000) then
+ (undefined : bits(32), undefined : bits(32))
+ else
+ let si = unsigned(rsVal[31..0]) in
+ let ti = unsigned(rtVal[31..0]) in
+ let qi = quot_round_zero(si, ti) in
+ let ri = rem_round_zero(si, ti) in
+ (to_bits(32, qi), to_bits(32, ri))
+ in
+ {
+ HI = EXTS(r);
+ LO = EXTS(q);
+ }
+ }
+
+/* DDIV 64-bit divide into HI/LO */
+union clause ast = DDIV : (regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ 0b00000 @ 0b00000 @ 0b011110) =
+ Some(DDIV(rs, rt))
+function clause execute (DDIV(rs, rt)) =
+ {
+ rsVal = signed(rGPR(rs));
+ rtVal = signed(rGPR(rt));
+ let (q , r) =
+ if (rtVal == 0)
+ then (undefined : bits(64), undefined : bits(64))
+ else
+ let qi = quot_round_zero(rsVal, rtVal) in
+ let ri = (rsVal - (qi * rtVal)) in
+ (to_bits(64, qi), to_bits(64, ri)) in
+ {
+ LO = q;
+ HI = r;
+ }
+ }
+
+/* DDIV 64-bit divide into HI/LO */
+union clause ast = DDIVU : (regno, regno)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ 0b00000 @ 0b00000 @ 0b011111) =
+ Some(DDIVU(rs, rt))
+function clause execute (DDIVU(rs, rt)) =
+ {
+ rsVal = unsigned(rGPR(rs));
+ rtVal = unsigned(rGPR(rt));
+ let (q, r) =
+ if (rtVal == 0)
+ then (undefined : bits(64), undefined : bits(64))
+ else
+ let qi = quot_round_zero(rsVal, rtVal) in
+ let ri = rem_round_zero(rsVal, rtVal) in
+ (to_bits(64, qi), to_bits(64, ri)) in
+ {
+ LO = q;
+ HI = r;
+ }
+ }
+
+/**************************************************************************************/
+/* Jump instructions -- unconditional branches */
+/**************************************************************************************/
+
+/* J - jump, the simplest control flow instruction, with branch delay slot */
+union clause ast = J : bits(26)
+function clause decode (0b000010 @ offset : bits(26)) =
+ Some(J(offset))
+function clause execute (J(offset)) =
+ {
+ delayedPC = (PC + 4)[63..28] @ offset @ 0b00;
+ branchPending = 0b1
+ }
+
+/* JAL - jump and link */
+union clause ast = JAL : bits(26)
+function clause decode (0b000011 @ offset : bits(26)) =
+ Some(JAL(offset))
+function clause execute (JAL(offset)) =
+ {
+ delayedPC = (PC + 4)[63..28] @ offset @ 0b00;
+ branchPending = 0b1;
+ wGPR(0b11111) = PC + 8;
+ }
+
+/* JR -- jump via register */
+union clause ast = JR : regno
+function clause decode (0b000000 @ rs : regno @ 0b00000 @ 0b00000 @ hint : regno @ 0b001000) =
+ Some(JR(rs)) /* hint is ignored */
+function clause execute (JR(rs)) =
+ {
+ delayedPC = rGPR(rs);
+ branchPending = 0b1;
+ }
+
+/* JALR -- jump via register with link */
+union clause ast = JALR : (regno, regno)
+function clause decode (0b000000 @ rs : regno @ 0b00000 @ rd : regno @ hint : regno @ 0b001001) =
+ Some(JALR(rs, rd)) /* hint is ignored */
+function clause execute (JALR(rs, rd)) =
+ {
+ delayedPC = rGPR(rs);
+ branchPending = 0b1;
+ wGPR(rd) = PC + 8;
+ }
+
+/**************************************************************************************/
+/* B[N]EQ[L] - branch on (not) equal (likely) */
+/* Conditional branch instructions with two register operands */
+/**************************************************************************************/
+
+union clause ast = BEQ : (regno, regno, imm16, bool, bool)
+function clause decode (0b000100 @ rs : regno @ rt : regno @ imm : imm16) =
+ Some(BEQ(rs, rt, imm, false, false)) /* BEQ */
+function clause decode (0b010100 @ rs : regno @ rt : regno @ imm : imm16) =
+ Some(BEQ(rs, rt, imm, false, true)) /* BEQL */
+function clause decode (0b000101 @ rs : regno @ rt : regno @ imm : imm16) =
+ Some(BEQ(rs, rt, imm, true , false)) /* BNE */
+function clause decode (0b010101 @ rs : regno @ rt : regno @ imm : imm16) =
+ Some(BEQ(rs, rt, imm, true , true)) /* BNEL */
+function clause execute (BEQ(rs, rd, imm, ne, likely)) =
+ {
+ if ((rGPR(rs) == rGPR(rd)) ^ ne) then
+ {
+ let offset : bits(64) = (EXTS(imm @ 0b00) + 4) in
+ delayedPC = PC + offset;
+ branchPending = 0b1;
+ }
+ else
+ {
+ if (likely) then
+ nextPC = PC + 8; /* skip branch delay */
+ }
+ }
+
+/*
+
+ Branches comparing with zero (single register operand, possible link in r31)
+*/
+
+/**************************************************************************************/
+/* BGEZ[AL][L] - branch on comparison with zero (possibly link, likely) */
+/* Conditional branch instructions with single register operand */
+/**************************************************************************************/
+
+union clause ast = BCMPZ : (regno, imm16, Comparison, bool, bool)
+function clause decode (0b000001 @ rs : regno @ 0b00000 @ imm : imm16) =
+ Some(BCMPZ(rs, imm, LT, false, false)) /* BLTZ */
+function clause decode (0b000001 @ rs : regno @ 0b10000 @ imm : imm16) =
+ Some(BCMPZ(rs, imm, LT, true, false)) /* BLTZAL */
+function clause decode (0b000001 @ rs : regno @ 0b00010 @ imm : imm16) =
+ Some(BCMPZ(rs, imm, LT, false, true)) /* BLTZL */
+function clause decode (0b000001 @ rs : regno @ 0b10010 @ imm : imm16) =
+ Some(BCMPZ(rs, imm, LT, true, true)) /* BLTZALL */
+
+function clause decode (0b000001 @ rs : regno @ 0b00001 @ imm : imm16) =
+ Some(BCMPZ(rs, imm, GE, false, false)) /* BGEZ */
+function clause decode (0b000001 @ rs : regno @ 0b10001 @ imm : imm16) =
+ Some(BCMPZ(rs, imm, GE, true, false)) /* BGEZAL */
+function clause decode (0b000001 @ rs : regno @ 0b00011 @ imm : imm16) =
+ Some(BCMPZ(rs, imm, GE, false, true)) /* BGEZL */
+function clause decode (0b000001 @ rs : regno @ 0b10011 @ imm : imm16) =
+ Some(BCMPZ(rs, imm, GE, true, true)) /* BGEZALL */
+
+function clause decode (0b000111 @ rs : regno @ 0b00000 @ imm : imm16) =
+ Some(BCMPZ(rs, imm, GT, false, false)) /* BGTZ */
+function clause decode (0b010111 @ rs : regno @ 0b00000 @ imm : imm16) =
+ Some(BCMPZ(rs, imm, GT, false, true)) /* BGTZL */
+
+function clause decode (0b000110 @ rs : regno @ 0b00000 @ imm : imm16) =
+ Some(BCMPZ(rs, imm, LE, false, false)) /* BLEZ */
+function clause decode (0b010110 @ rs : regno @ 0b00000 @ imm : imm16) =
+ Some(BCMPZ(rs, imm, LE, false, true)) /* BLEZL */
+
+function clause execute (BCMPZ(rs, imm, cmp, link, likely)) =
+ {
+ linkVal = PC + 8;
+ regVal = rGPR(rs);
+ condition = compare(cmp, regVal, EXTZ(0b0));
+ if (condition) then
+ {
+ let offset : bits(64) = (EXTS(imm @ 0b00) + 4) in
+ delayedPC = PC + offset;
+ branchPending = 0b1;
+ }
+ else if (likely) then
+ {
+ nextPC = PC + 8 /* skip branch delay */
+ };
+ if (link) then
+ wGPR(0b11111) = linkVal
+ }
+
+/**************************************************************************************/
+/* SYSCALL/BREAK/WAIT/Trap */
+/**************************************************************************************/
+
+/* Co-opt syscall 0xfffff for use as thread start in pccmem */
+union clause ast = SYSCALL_THREAD_START : unit
+function clause decode (0b000000 @ 0xfffff @ 0b001100) =
+ Some(SYSCALL_THREAD_START())
+function clause execute (SYSCALL_THREAD_START()) = ()
+
+
+/* fake stop fetching instruction for ppcmem, execute doesn't do anything,
+ decode never produces it */
+
+union clause ast = ImplementationDefinedStopFetching : unit
+function clause execute (ImplementationDefinedStopFetching()) = ()
+
+
+union clause ast = SYSCALL : unit
+function clause decode (0b000000 @ code : bits(20) @ 0b001100) =
+ Some(SYSCALL()) /* code is ignored */
+function clause execute (SYSCALL()) =
+ {
+ (SignalException(Sys))
+ }
+
+/* BREAK is identical to SYSCALL exception for the exception raised */
+union clause ast = BREAK : unit
+function clause decode (0b000000 @ code : bits(20) @ 0b001101) =
+ Some(BREAK()) /* code is ignored */
+function clause execute (BREAK()) =
+ {
+ (SignalException(Bp))
+ }
+
+/* Accept WAIT as a NOP */
+union clause ast = WAIT : unit
+function clause decode (0b010000 @ 0x80000 @ 0b100000) =
+ Some(WAIT()) /* we only accept code == 0 */
+function clause execute (WAIT()) = {
+ nextPC = PC;
+}
+
+/* Trap instructions with two register operands */
+union clause ast = TRAPREG : (regno, regno, Comparison)
+function clause decode (0b000000 @ rs : regno @ rt : regno @ code : bits(10) @ 0b110000) =
+ Some(TRAPREG(rs, rt, GE)) /* TGE */
+function clause decode (0b000000 @ rs : regno @ rt : regno @ code : bits(10) @ 0b110001) =
+ Some(TRAPREG(rs, rt, GEU)) /* TGEU */
+function clause decode (0b000000 @ rs : regno @ rt : regno @ code : bits(10) @ 0b110010) =
+ Some(TRAPREG(rs, rt, LT)) /* TLT */
+function clause decode (0b000000 @ rs : regno @ rt : regno @ code : bits(10) @ 0b110011) =
+ Some(TRAPREG(rs, rt, LTU)) /* TLTU */
+function clause decode (0b000000 @ rs : regno @ rt : regno @ code : bits(10) @ 0b110100) =
+ Some(TRAPREG(rs, rt, EQ)) /* TEQ */
+function clause decode (0b000000 @ rs : regno @ rt : regno @ code : bits(10) @ 0b110110) =
+ Some(TRAPREG(rs, rt, NE)) /* TNE */
+function clause execute (TRAPREG(rs, rt, cmp)) =
+ {
+ rs_val = rGPR(rs);
+ rt_val = rGPR(rt);
+ condition = compare(cmp, rs_val, rt_val);
+ if (condition) then
+ (SignalException(Tr))
+ }
+
+
+/* Trap instructions with one register and one immediate operand */
+union clause ast = TRAPIMM : (regno, imm16, Comparison)
+function clause decode (0b000001 @ rs : regno @ 0b01100 @ imm : imm16) =
+ Some(TRAPIMM(rs, imm, EQ)) /* TEQI */
+function clause decode (0b000001 @ rs : regno @ 0b01110 @ imm : imm16) =
+ Some(TRAPIMM(rs, imm, NE)) /* TNEI */
+function clause decode (0b000001 @ rs : regno @ 0b01000 @ imm : imm16) =
+ Some(TRAPIMM(rs, imm, GE)) /* TGEI */
+function clause decode (0b000001 @ rs : regno @ 0b01001 @ imm : imm16) =
+ Some(TRAPIMM(rs, imm, GEU)) /* TGEIU */
+function clause decode (0b000001 @ rs : regno @ 0b01010 @ imm : imm16) =
+ Some(TRAPIMM(rs, imm, LT)) /* TLTI */
+function clause decode (0b000001 @ rs : regno @ 0b01011 @ imm : imm16) =
+ Some(TRAPIMM(rs, imm, LTU)) /* TLTIU */
+function clause execute (TRAPIMM(rs, imm, cmp)) =
+ {
+ rs_val = rGPR(rs);
+ imm_val : bits(64) = EXTS(imm);
+ condition = compare(cmp, rs_val, imm_val);
+ if (condition) then
+ (SignalException(Tr))
+ }
+
+/**************************************************************************************/
+/* Load instructions -- various width/signs */
+/**************************************************************************************/
+
+union clause ast = Load : (WordType, bool, bool, regno, regno, imm16)
+function clause decode (0b100000 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(Load(B, true, false, base, rt, offset)) /* LB */
+function clause decode (0b100100 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(Load(B, false, false, base, rt, offset)) /* LBU */
+function clause decode (0b100001 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(Load(H, true, false, base, rt, offset)) /* LH */
+function clause decode (0b100101 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(Load(H, false, false, base, rt, offset)) /* LHU */
+function clause decode (0b100011 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(Load(W, true, false, base, rt, offset)) /* LW */
+function clause decode (0b100111 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(Load(W, false, false, base, rt, offset)) /* LWU */
+function clause decode (0b110111 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(Load(D, false, false, base, rt, offset)) /* LD */
+function clause decode (0b110000 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(Load(W, true, true, base, rt, offset)) /* LL */
+function clause decode (0b110100 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(Load(D, false, true, base, rt, offset)) /* LLD */
+
+val extendLoad : forall 'sz, 'sz <= 64 . (bits('sz), bool) -> bits(64) effect pure
+function extendLoad(memResult, sign) = {
+ if (sign) then
+ EXTS(memResult)
+ else
+ EXTZ(memResult)
+}
+
+function clause execute (Load(width, sign, linked, base, rt, offset)) =
+ {
+ vAddr : bits(64) = addrWrapper(EXTS(offset) + rGPR(base), LoadData, width);
+ if ~ (isAddressAligned(vAddr, width)) then
+ (SignalExceptionBadAddr(AdEL, vAddr)) /* unaligned access */
+ else
+ let pAddr = (TLBTranslate(vAddr, LoadData)) in
+ {
+ memResult : bits(64) = if (linked) then
+ {
+ CP0LLBit = 0b1;
+ CP0LLAddr = pAddr;
+ match width {
+ B => extendLoad(MEMr_reserve_wrapper(pAddr, 1), sign),
+ H => extendLoad(MEMr_reserve_wrapper(pAddr, 2), sign),
+ W => extendLoad(MEMr_reserve_wrapper(pAddr, 4), sign),
+ D => extendLoad(MEMr_reserve_wrapper(pAddr, 8), sign)
+ }
+ }
+ else
+ {
+ match width {
+ B => extendLoad(MEMr_wrapper(pAddr, 1), sign),
+ H => extendLoad(MEMr_wrapper(pAddr, 2), sign),
+ W => extendLoad(MEMr_wrapper(pAddr, 4), sign),
+ D => extendLoad(MEMr_wrapper(pAddr, 8), sign)
+ }
+ };
+ wGPR(rt) = memResult
+ }
+ }
+
+/**************************************************************************************/
+/* Store instructions -- various widths */
+/**************************************************************************************/
+
+union clause ast = Store : (WordType, bool, regno, regno, imm16)
+function clause decode (0b101000 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(Store(B, false, base, rt, offset)) /* SB */
+function clause decode (0b101001 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(Store(H, false, base, rt, offset)) /* SH */
+function clause decode (0b101011 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(Store(W, false, base, rt, offset)) /* SW */
+function clause decode (0b111111 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(Store(D, false, base, rt, offset)) /* SD */
+function clause decode (0b111000 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(Store(W, true, base, rt, offset)) /* SC */
+function clause decode (0b111100 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(Store(D, true, base, rt, offset)) /* SCD */
+function clause execute (Store(width, conditional, base, rt, offset)) =
+ {
+ vAddr : bits(64) = addrWrapper(EXTS(offset) + rGPR(base), StoreData, width);
+ rt_val = rGPR(rt);
+ if ~ (isAddressAligned(vAddr, width)) then
+ (SignalExceptionBadAddr(AdES, vAddr)) /* unaligned access */
+ else
+ let pAddr = (TLBTranslate(vAddr, StoreData)) in
+ {
+ if (conditional) then
+ {
+ success : bool = if (CP0LLBit[0]) then match width
+ {
+ B => MEMw_conditional_wrapper(pAddr, 1, rt_val[7..0]),
+ H => MEMw_conditional_wrapper(pAddr, 2, rt_val[15..0]),
+ W => MEMw_conditional_wrapper(pAddr, 4, rt_val[31..0]),
+ D => MEMw_conditional_wrapper(pAddr, 8, rt_val)
+ } else false;
+ wGPR(rt) = EXTZ(success)
+ }
+ else
+ match width
+ {
+ B => MEMw_wrapper(pAddr, 1) = rt_val[7..0],
+ H => MEMw_wrapper(pAddr, 2) = rt_val[15..0],
+ W => MEMw_wrapper(pAddr, 4) = rt_val[31..0],
+ D => MEMw_wrapper(pAddr, 8) = rt_val
+ }
+ }
+ }
+
+/* LWL - Load word left (big-endian only) */
+
+union clause ast = LWL : (regno, regno, bits(16))
+function clause decode(0b100010 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(LWL(base, rt, offset))
+function clause execute(LWL(base, rt, offset)) =
+ {
+ /* XXX length check not quite right, but conservative */
+ vAddr = addrWrapper(EXTS(offset) + rGPR(base), LoadData, W);
+ let pAddr = (TLBTranslate(vAddr, LoadData)) in
+ {
+ mem_val = MEMr_wrapper (pAddr[63..2] @ 0b00, 4); /* read word of interest */
+ reg_val = rGPR(rt);
+ result : bits(32) = match vAddr[1..0]
+ {
+ 0b00 => mem_val,
+ 0b01 => mem_val[23..0] @ reg_val[07..0],
+ 0b10 => mem_val[15..0] @ reg_val[15..0],
+ 0b11 => mem_val[07..0] @ reg_val[23..0]
+ };
+ wGPR(rt) = EXTS(result);
+ }
+ }
+union clause ast = LWR : (regno, regno, bits(16))
+function clause decode(0b100110 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(LWR(base, rt, offset))
+function clause execute(LWR(base, rt, offset)) =
+ {
+ /* XXX length check not quite right, but conservative */
+ vAddr = addrWrapper(EXTS(offset) + rGPR(base), LoadData, W);
+ let pAddr = (TLBTranslate(vAddr, LoadData)) in
+ {
+ mem_val = MEMr_wrapper(pAddr[63..2] @ 0b00, 4); /* read word of interest */
+ reg_val = rGPR(rt);
+ result : bits(32) = match vAddr[1..0]
+ {
+ 0b00 => reg_val[31..8] @ mem_val[31..24],
+ 0b01 => reg_val[31..16] @ mem_val[31..16],
+ 0b10 => reg_val[31..24] @ mem_val[31..8],
+ 0b11 => mem_val
+ };
+ wGPR(rt) = EXTS(result)
+ }
+ }
+
+/* SWL - Store word left */
+union clause ast = SWL : (regno, regno, bits(16))
+function clause decode(0b101010 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(SWL(base, rt, offset))
+function clause execute(SWL(base, rt, offset)) =
+ {
+ /* XXX length check not quite right, but conservative */
+ vAddr = addrWrapper(EXTS(offset) + rGPR(base), StoreData, W);
+ let pAddr = TLBTranslate(vAddr, StoreData) in
+ {
+ reg_val = rGPR(rt);
+ match vAddr[1..0]
+ {
+ 0b00 => (MEMw_wrapper(pAddr, 4) = reg_val[31..0]),
+ 0b01 => (MEMw_wrapper(pAddr, 3) = reg_val[31..8]),
+ 0b10 => (MEMw_wrapper(pAddr, 2) = reg_val[31..16]),
+ 0b11 => (MEMw_wrapper(pAddr, 1) = reg_val[31..24])
+ }
+ }
+ }
+
+union clause ast = SWR : (regno, regno, bits(16))
+function clause decode(0b101110 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(SWR(base, rt, offset))
+function clause execute(SWR(base, rt, offset)) =
+ {
+ /* XXX length check not quite right, but conservative */
+ vAddr = addrWrapper(EXTS(offset) + rGPR(base), StoreData, W);
+ let pAddr = TLBTranslate(vAddr, StoreData) in
+ {
+ wordAddr = pAddr[63..2] @ 0b00;
+ reg_val = rGPR(rt);
+ match vAddr[1..0]
+ {
+ 0b00 => (MEMw_wrapper(wordAddr, 1) = reg_val[7..0]),
+ 0b01 => (MEMw_wrapper(wordAddr, 2) = reg_val[15..0]),
+ 0b10 => (MEMw_wrapper(wordAddr, 3) = reg_val[23..0]),
+ 0b11 => (MEMw_wrapper(wordAddr, 4) = reg_val[31..0])
+ }
+ }
+ }
+
+/* Load double-word left */
+union clause ast = LDL : (regno, regno, bits(16))
+function clause decode(0b011010 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(LDL(base, rt, offset))
+function clause execute(LDL(base, rt, offset)) =
+ {
+ /* XXX length check not quite right, but conservative */
+ vAddr = addrWrapper(EXTS(offset) + rGPR(base), LoadData, D);
+ let pAddr = TLBTranslate(vAddr, StoreData) in
+ {
+ mem_val = MEMr_wrapper(pAddr[63..3] @ 0b000, 8); /* read double of interest */
+ reg_val = rGPR(rt);
+ wGPR(rt) = match vAddr[2..0]
+ {
+ 0b000 => mem_val,
+ 0b001 => mem_val[55..0] @ reg_val[7..0],
+ 0b010 => mem_val[47..0] @ reg_val[15..0],
+ 0b011 => mem_val[39..0] @ reg_val[23..0],
+ 0b100 => mem_val[31..0] @ reg_val[31..0],
+ 0b101 => mem_val[23..0] @ reg_val[39..0],
+ 0b110 => mem_val[15..0] @ reg_val[47..0],
+ 0b111 => mem_val[07..0] @ reg_val[55..0]
+ };
+ }
+ }
+
+/* Load double-word right */
+union clause ast = LDR : (regno, regno, bits(16))
+function clause decode(0b011011 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(LDR(base, rt, offset))
+function clause execute(LDR(base, rt, offset)) =
+ {
+ /* XXX length check not quite right, but conservative */
+ vAddr = addrWrapper(EXTS(offset) + rGPR(base), LoadData, D);
+ let pAddr = TLBTranslate(vAddr, StoreData) in
+ {
+ mem_val = MEMr_wrapper(pAddr[63..3] @ 0b000, 8); /* read double of interest */
+ reg_val = rGPR(rt);
+ wGPR(rt) = match vAddr[2..0]
+ {
+ 0b000 => reg_val[63..08] @ mem_val[63..56],
+ 0b001 => reg_val[63..16] @ mem_val[63..48],
+ 0b010 => reg_val[63..24] @ mem_val[63..40],
+ 0b011 => reg_val[63..32] @ mem_val[63..32],
+ 0b100 => reg_val[63..40] @ mem_val[63..24],
+ 0b101 => reg_val[63..48] @ mem_val[63..16],
+ 0b110 => reg_val[63..56] @ mem_val[63..08],
+ 0b111 => mem_val
+ };
+ }
+ }
+
+/* SDL - Store double-word left */
+union clause ast = SDL : (regno, regno, bits(16))
+function clause decode(0b101100 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(SDL(base, rt, offset))
+function clause execute(SDL(base, rt, offset)) =
+ {
+ /* XXX length check not quite right, but conservative */
+ vAddr = addrWrapper(EXTS(offset) + rGPR(base), StoreData, D);
+ let pAddr = TLBTranslate(vAddr, StoreData) in
+ {
+ reg_val = rGPR(rt);
+ match vAddr[2..0]
+ {
+ 0b000 => (MEMw_wrapper(pAddr, 8) = reg_val[63..00]),
+ 0b001 => (MEMw_wrapper(pAddr, 7) = reg_val[63..08]),
+ 0b010 => (MEMw_wrapper(pAddr, 6) = reg_val[63..16]),
+ 0b011 => (MEMw_wrapper(pAddr, 5) = reg_val[63..24]),
+ 0b100 => (MEMw_wrapper(pAddr, 4) = reg_val[63..32]),
+ 0b101 => (MEMw_wrapper(pAddr, 3) = reg_val[63..40]),
+ 0b110 => (MEMw_wrapper(pAddr, 2) = reg_val[63..48]),
+ 0b111 => (MEMw_wrapper(pAddr, 1) = reg_val[63..56])
+ }
+ }
+ }
+
+
+/* SDR - Store double-word right */
+union clause ast = SDR : (regno, regno, bits(16))
+function clause decode(0b101101 @ base : regno @ rt : regno @ offset : imm16) =
+ Some(SDR(base, rt, offset))
+function clause execute(SDR(base, rt, offset)) =
+ {
+ /* XXX length check not quite right, but conservative */
+ vAddr = addrWrapper(EXTS(offset) + rGPR(base), StoreData, D);
+ let pAddr = TLBTranslate(vAddr, StoreData) in
+ {
+ reg_val = rGPR(rt);
+ wordAddr = pAddr[63..3] @ 0b000;
+ match vAddr[2..0]
+ {
+ 0b000 => (MEMw_wrapper(wordAddr, 1) = reg_val[07..0]),
+ 0b001 => (MEMw_wrapper(wordAddr, 2) = reg_val[15..0]),
+ 0b010 => (MEMw_wrapper(wordAddr, 3) = reg_val[23..0]),
+ 0b011 => (MEMw_wrapper(wordAddr, 4) = reg_val[31..0]),
+ 0b100 => (MEMw_wrapper(wordAddr, 5) = reg_val[39..0]),
+ 0b101 => (MEMw_wrapper(wordAddr, 6) = reg_val[47..0]),
+ 0b110 => (MEMw_wrapper(wordAddr, 7) = reg_val[55..0]),
+ 0b111 => (MEMw_wrapper(wordAddr, 8) = reg_val[63..0])
+ }
+ }
+ }
+
+/* CACHE - manipulate (non-existent) caches */
+
+union clause ast = CACHE : (regno, regno, bits(16))
+function clause decode (0b101111 @ base : regno @ op : regno @ imm : imm16) =
+ Some(CACHE(base, op, imm))
+function clause execute (CACHE(base, op, imm)) =
+ checkCP0Access () /* pretty much a NOP because no caches */
+
+/* PREF - prefetching into (non-existent) caches */
+
+union clause ast = PREF : (regno, regno, bits(16))
+function clause decode (0b110011 @ base : regno @ op : regno @ imm : imm16) =
+ Some(PREF(base, op, imm))
+function clause execute (PREF(base, op, imm)) =
+ () /* XXX NOP */
+
+
+/* SYNC - Memory barrier */
+union clause ast = SYNC : unit
+function clause decode (0b000000 @ 0b00000 @ 0b00000 @ 0b00000 @ stype : regno @ 0b001111) =
+ Some(SYNC()) /* stype is currently ignored */
+function clause execute(SYNC()) =
+ MEM_sync()
+
+union clause ast = MFC0 : (regno, regno, bits(3), bool)
+function clause decode (0b010000 @ 0b00000 @ rt : regno @ rd : regno @ 0b00000000 @ sel : bits(3)) =
+ Some(MFC0(rt, rd, sel, false)) /* MFC0 */
+function clause decode (0b010000 @ 0b00001 @ rt : regno @ rd : regno @ 0b00000000 @ sel : bits(3)) =
+ Some(MFC0(rt, rd, sel, true)) /* DMFC0 */
+function clause execute (MFC0(rt, rd, sel, double)) = {
+ checkCP0Access();
+ let result : bits(64) = match (rd, sel)
+ {
+ (0b00000,0b000) => let idx : bits(31) = EXTZ(TLBIndex) in
+ (0x00000000 @ TLBProbe @ idx), /* 0, TLB Index */
+ (0b00001,0b000) => EXTZ(TLBRandom), /* 1, TLB Random */
+ (0b00010,0b000) => TLBEntryLo0.bits(), /* 2, TLB EntryLo0 */
+ (0b00011,0b000) => TLBEntryLo1.bits(), /* 3, TLB EntryLo1 */
+ (0b00100,0b000) => TLBContext.bits(), /* 4, TLB Context */
+ (0b00101,0b000) => EXTZ(TLBPageMask @ 0x000), /* 5, TLB PageMask */
+ (0b00110,0b000) => EXTZ(TLBWired), /* 6, TLB Wired */
+ (0b00111,0b000) => EXTZ(CP0HWREna), /* 7, HWREna */
+ (0b01000,0b000) => CP0BadVAddr, /* 8, BadVAddr reg */
+ (0b01000,0b001) => EXTZ(0b0), /* 8, BadInstr reg XXX TODO */
+ (0b01001,0b000) => EXTZ(CP0Count), /* 9, Count reg */
+ (0b01010,0b000) => TLBEntryHi.bits(),/* 10, TLB EntryHi */
+ (0b01011,0b000) => EXTZ(CP0Compare), /* 11, Compare reg */
+ (0b01100,0b000) => EXTZ(CP0Status.bits()), /* 12, Status reg */
+ (0b01101,0b000) => EXTZ(CP0Cause.bits()), /* 13, Cause reg */
+ (0b01110,0b000) => CP0EPC, /* 14, EPC */
+ (0b01111,0b000) => EXTZ(0x00000400), /* 15, sel 0: PrID processor ID */
+ (0b01111,0b110) => EXTZ(0b0), /* 15, sel 6: CHERI core ID */
+ (0b01111,0b111) => EXTZ(0b0), /* 15, sel 7: CHERI thread ID */
+ (0b10000,0b000) => EXTZ(0b1 /* M */ /* 16, sel 0: Config0 */
+ @ 0b000000000000000 /* Impl */
+ @ 0b1 /* BE */
+ @ 0b10 /* AT */
+ @ 0b000 /* AR */
+ @ 0b001 /* MT standard TLB */
+ @ 0b0000 /* zero */
+ @ 0b000),
+ (0b10000,0b001) => EXTZ( /* 16, sel 1: Config1 */
+ 0b1 /* M */
+ @ TLBIndexMax /* MMU size-1 */
+ @ 0b000 /* IS icache sets */
+ @ 0b000 /* IL icache lines */
+ @ 0b000 /* IA icache assoc. */
+ @ 0b000 /* DS dcache sets */
+ @ 0b000 /* DL dcache lines */
+ @ 0b000 /* DA dcache assoc. */
+ @ bool_to_bits(have_cp2) /* C2 CP2 presence */
+ @ 0b0 /* MD MDMX implemented */
+ @ 0b0 /* PC performance counters */
+ @ 0b0 /* WR watch registers */
+ @ 0b0 /* CA 16e code compression */
+ @ 0b0 /* EP EJTAG */
+ @ 0b0), /* FP FPU present */
+ (0b10000,0b010) => EXTZ( /* 16, sel 2: Config2 */
+ 0b1 /* M */
+ @ 0b000 /* TU L3 control */
+ @ 0b0000 /* TS L3 sets */
+ @ 0b0000 /* TL L3 lines */
+ @ 0b0000 /* TA L3 assoc. */
+ @ 0b0000 /* SU L2 control */
+ @ 0b0000 /* SS L2 sets */
+ @ 0b0000 /* SL L2 lines */
+ @ 0b0000), /* SA L2 assoc. */
+ (0b10000,0b011) => 0x0000000000002000, /* 16, sel 3: Config3 zero except for bit 13 == ulri */
+ (0b10000,0b101) => 0x0000000000000000, /* 16, sel 5: Config5 beri specific -- no extended TLB */
+ (0b10001,0b000) => CP0LLAddr, /* 17, sel 0: LLAddr */
+ (0b10010,0b000) => EXTZ(0b0), /* 18, WatchLo */
+ (0b10011,0b000) => EXTZ(0b0), /* 19, WatchHi */
+ (0b10100,0b000) => TLBXContext.bits(), /* 20, XContext */
+ (0b11110,0b000) => CP0ErrorEPC, /* 30, ErrorEPC */
+ _ => (SignalException(ResI))
+ } in
+ wGPR(rt) = if (double) then result else EXTS(result[31..0])
+}
+
+/* simulator halt instruction "MTC0 rt, r23" (cheri specific behaviour) */
+union clause ast = HCF : unit
+function clause decode (0b010000 @ 0b00100 @ rt : regno @ 0b10111 @ 0b00000000000) =
+ Some(HCF())
+
+function clause decode (0b010000 @ 0b00100 @ rt : regno @ 0b11010 @ 0b00000000000) =
+ Some(HCF())
+
+function clause execute (HCF()) =
+ () /* halt instruction actually executed by interpreter framework */
+
+union clause ast = MTC0 : (regno, regno, bits(3), bool)
+function clause decode (0b010000 @ 0b00100 @ rt : regno @ rd : regno @ 0b00000000 @ sel : bits(3)) =
+ Some(MTC0(rt, rd, sel, false)) /* MTC0 */
+function clause decode (0b010000 @ 0b00101 @ rt : regno @ rd : regno @ 0b00000000 @ sel : bits(3)) =
+ Some(MTC0(rt, rd, sel, true)) /* DMTC0 */
+function clause execute (MTC0(rt, rd, sel, double)) = {
+ checkCP0Access();
+ let reg_val = rGPR(rt) in
+ match (rd, sel)
+ {
+ (0b00000,0b000) => TLBIndex = mask(reg_val), /* NB no write to TLBProbe */
+ (0b00001,0b000) => (), /* TLBRandom is read only */
+ (0b00010,0b000) => TLBEntryLo0->bits() = reg_val,
+ (0b00011,0b000) => TLBEntryLo1->bits() = reg_val,
+ (0b00100,0b000) => TLBContext->PTEBase() = reg_val[63..23],
+ (0b00100,0b010) => CP0UserLocal = reg_val,
+ (0b00101,0b000) => TLBPageMask = reg_val[28..13],
+ (0b00110,0b000) => {
+ TLBWired = mask(reg_val);
+ TLBRandom = TLBIndexMax;
+ },
+ (0b00111,0b000) => CP0HWREna = (reg_val[31..29] @ 0b0000000000000000000000000 @ reg_val[3..0]),
+ (0b01000,0b000) => (), /* BadVAddr read only */
+ (0b01001,0b000) => CP0Count = reg_val[31..0],
+ (0b01010,0b000) => {
+ TLBEntryHi->R() = reg_val[63..62];
+ TLBEntryHi->VPN2() = reg_val[39..13];
+ TLBEntryHi->ASID() = reg_val[7..0];
+ },
+ (0b01011,0b000) => { /* 11, sel 0: Compare reg */
+ CP0Compare = reg_val[31..0];
+ CP0Cause->IP() = CP0Cause.IP() & 0x7f; /* clear IP7 */
+ },
+ (0b01100,0b000) => { /* 12 Status */
+ CP0Status->CU() = reg_val[31..28];
+ CP0Status->BEV() = reg_val[22];
+ CP0Status->IM() = reg_val[15..8];
+ CP0Status->KX() = reg_val[7];
+ CP0Status->SX() = reg_val[6];
+ CP0Status->UX() = reg_val[5];
+ CP0Status->KSU() = reg_val[4..3];
+ CP0Status->ERL() = reg_val[2];
+ CP0Status->EXL() = reg_val[1];
+ CP0Status->IE() = reg_val[0];
+ },
+ (0b01101,0b000) => { /* 13 Cause */
+ CP0Cause->IV() = reg_val[23]; /* TODO special interrupt vector not implemeneted */
+ let ip = CP0Cause.IP() in
+ CP0Cause->IP() = ((ip[7..2]) @ (reg_val[9..8]));
+ },
+ (0b01110,0b000) => CP0EPC = reg_val, /* 14, EPC */
+ (0b10000,0b000) => (), /* XXX ignore K0 cache config 16: Config0 */
+ (0b10100,0b000) => TLBXContext->XPTEBase() = reg_val[63..33],
+ (0b11110,0b000) => CP0ErrorEPC = reg_val, /* 30, ErrorEPC */
+ _ => (SignalException(ResI))
+ }
+}
+
+val TLBWriteEntry : TLBIndexT -> unit effect {rreg, wreg, escape}
+function TLBWriteEntry(idx) = {
+ pagemask = TLBPageMask;
+ match pagemask {
+ 0x0000 => (),
+ 0x0003 => (),
+ 0x000f => (),
+ 0x003f => (),
+ 0x00ff => (),
+ 0x03ff => (),
+ 0x0fff => (),
+ 0x3fff => (),
+ 0xffff => (),
+ _ => (SignalException(MCheck))
+ };
+ let i as atom(_) = unsigned(idx) in
+ let entry = TLBEntries[i] in {
+ entry.pagemask() = pagemask;
+ entry.r() = TLBEntryHi.R();
+ entry.vpn2() = TLBEntryHi.VPN2();
+ entry.asid() = TLBEntryHi.ASID();
+ entry.g() = ((TLBEntryLo0.G()) & (TLBEntryLo1.G()));
+ entry.valid() = bitone;
+ entry.caps0() = TLBEntryLo0.CapS();
+ entry.capl0() = TLBEntryLo0.CapL();
+ entry.pfn0() = TLBEntryLo0.PFN();
+ entry.c0() = TLBEntryLo0.C();
+ entry.d0() = TLBEntryLo0.D();
+ entry.v0() = TLBEntryLo0.V();
+ entry.caps1() = TLBEntryLo1.CapS();
+ entry.capl1() = TLBEntryLo1.CapL();
+ entry.pfn1() = TLBEntryLo1.PFN();
+ entry.c1() = TLBEntryLo1.C();
+ entry.d1() = TLBEntryLo1.D();
+ entry.v1() = TLBEntryLo1.V();
+ }
+}
+
+union clause ast = TLBWI : unit
+function clause decode (0b010000 @ 0b10000000000000000000 @ 0b000010) = Some(TLBWI() : ast)
+function clause execute (TLBWI()) = {
+ checkCP0Access();
+ TLBWriteEntry(TLBIndex);
+}
+
+union clause ast = TLBWR : unit
+function clause decode (0b010000 @ 0b10000000000000000000 @ 0b000110) = Some(TLBWR() : ast)
+function clause execute (TLBWR()) = {
+ checkCP0Access();
+ TLBWriteEntry(TLBRandom);
+}
+
+union clause ast = TLBR : unit
+function clause decode (0b010000 @ 0b10000000000000000000 @ 0b000001) = Some(TLBR() : ast)
+function clause execute (TLBR()) = {
+ checkCP0Access();
+ let i as atom(_) = unsigned(TLBIndex) in
+ let entry = reg_deref(TLBEntries[i]) in {
+ TLBPageMask = entry.pagemask();
+ TLBEntryHi->R() = entry.r();
+ TLBEntryHi->VPN2() = entry.vpn2();
+ TLBEntryHi->ASID() = entry.asid();
+ TLBEntryLo0->CapS()= entry.caps0();
+ TLBEntryLo0->CapL()= entry.capl0();
+ TLBEntryLo0->PFN() = entry.pfn0();
+ TLBEntryLo0->C() = entry.c0();
+ TLBEntryLo0->D() = entry.d0();
+ TLBEntryLo0->V() = entry.v0();
+ TLBEntryLo0->G() = entry.g();
+ TLBEntryLo1->CapS()= entry.caps1();
+ TLBEntryLo1->CapL()= entry.capl1();
+ TLBEntryLo1->PFN() = entry.pfn1();
+ TLBEntryLo1->C() = entry.c1();
+ TLBEntryLo1->D() = entry.d1();
+ TLBEntryLo1->V() = entry.v1();
+ TLBEntryLo1->G() = entry.g();
+ }
+}
+
+union clause ast = TLBP : unit
+function clause decode (0b010000 @ 0b10000000000000000000 @ 0b001000) = Some(TLBP() : ast)
+function clause execute (TLBP()) = {
+ checkCP0Access();
+ let result = tlbSearch(TLBEntryHi.bits()) in
+ match result {
+ (Some(idx)) => {
+ TLBProbe = [bitzero];
+ TLBIndex = idx;
+ },
+ None() => {
+ TLBProbe = [bitone];
+ TLBIndex = 0b000000;
+ }
+ }
+}
+
+union clause ast = RDHWR : (regno, regno)
+function clause decode (0b011111 @ 0b00000 @ rt : regno @ rd : regno @ 0b00000 @ 0b111011) =
+ Some(RDHWR(rt, rd))
+function clause execute (RDHWR(rt, rd)) = {
+ let accessLevel = getAccessLevel() in
+ let haveAccessLevel : bool = accessLevel == Kernel in
+ let haveCU0 : bool = bitone == (CP0Status.CU()[0]) in
+ let rdi as atom(_) = unsigned(rd) in
+ let haveHWREna : bool = bitone == (CP0HWREna[rdi]) in
+ if ~(haveAccessLevel | haveCU0 | haveHWREna) then
+ (SignalException(ResI));
+ let temp : bits(64) = match rd {
+ 0b00000 => EXTZ([bitzero]), /* CPUNum */
+ 0b00001 => EXTZ([bitzero]), /* SYNCI_step */
+ 0b00010 => EXTZ(CP0Count), /* Count */
+ 0b00011 => EXTZ([bitone]), /* Count resolution */
+ 0b11101 => CP0UserLocal, /* User local register */
+ _ => (SignalException(ResI))
+ } in
+ wGPR(rt) = temp;
+}
+
+union clause ast = ERET : unit
+
+function clause decode (0b010000 @ 0b1 @ 0b0000000000000000000 @ 0b011000) =
+ Some(ERET())
+function clause execute (ERET()) =
+ {
+ checkCP0Access();
+ ERETHook();
+ CP0LLBit = 0b0;
+ if (CP0Status.ERL() == bitone) then
+ {
+ nextPC = CP0ErrorEPC;
+ CP0Status->ERL() = 0b0;
+ }
+ else
+ {
+ nextPC = CP0EPC;
+ CP0Status->EXL() = 0b0;
+ }
+ }
diff --git a/mips/mips_prelude.sail b/mips/mips_prelude.sail
new file mode 100644
index 00000000..b4f09548
--- /dev/null
+++ b/mips/mips_prelude.sail
@@ -0,0 +1,620 @@
+/*========================================================================*/
+/* */
+/* Copyright (c) 2015-2017 Robert M. Norton */
+/* Copyright (c) 2015-2017 Kathyrn Gray */
+/* All rights reserved. */
+/* */
+/* This software was developed by the University of Cambridge Computer */
+/* Laboratory as part of the Rigorous Engineering of Mainstream Systems */
+/* (REMS) project, funded by EPSRC grant EP/K008528/1. */
+/* */
+/* Redistribution and use in source and binary forms, with or without */
+/* modification, are permitted provided that the following conditions */
+/* are met: */
+/* 1. Redistributions of source code must retain the above copyright */
+/* notice, this list of conditions and the following disclaimer. */
+/* 2. Redistributions in binary form must reproduce the above copyright */
+/* notice, this list of conditions and the following disclaimer in */
+/* the documentation and/or other materials provided with the */
+/* distribution. */
+/* */
+/* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' */
+/* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED */
+/* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A */
+/* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR */
+/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
+/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
+/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF */
+/* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND */
+/* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, */
+/* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */
+/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF */
+/* SUCH DAMAGE. */
+/*========================================================================*/
+
+/* mips_prelude.sail: declarations of mips registers, and functions common
+ to mips instructions (e.g. address translation) */
+
+register PC : bits(64)
+register nextPC : bits(64)
+
+/* CP0 Registers */
+
+bitfield CauseReg : bits(32) = {
+ BD : 31, /* branch delay */
+ /*Z0 : 30,*/
+ CE : 29.. 28, /* for coprocessor enable exception */
+ /*Z1 : 27.. 24,*/
+ IV : 23, /* special interrupt vector not supported */
+ WP : 22, /* watchpoint exception occurred */
+ /*Z2 : 21.. 16, */
+ IP : 15.. 8, /* interrupt pending bits */
+ /*Z3 : 7,*/
+ ExcCode : 6.. 2, /* code of last exception */
+ /*Z4 : 1.. 0,*/
+}
+
+bitfield TLBEntryLoReg : bits(64) = {
+ CapS : 63,
+ CapL : 62,
+ PFN : 29.. 6,
+ C : 5.. 3,
+ D : 2,
+ V : 1,
+ G : 0,
+}
+
+bitfield TLBEntryHiReg : bits(64) = {
+ R : 63.. 62,
+ VPN2 : 39.. 13,
+ ASID : 7.. 0,
+}
+
+bitfield ContextReg : bits(64) = {
+ PTEBase : 63.. 23,
+ BadVPN2 : 22.. 4,
+ /*ZR : 3.. 0,*/
+}
+
+bitfield XContextReg : bits(64) = {
+ XPTEBase : 63.. 33,
+ XR : 32.. 31,
+ XBadVPN2 : 30.. 4,
+}
+
+let TLBNumEntries = 64
+type TLBIndexT = (bits(6))
+let TLBIndexMax : TLBIndexT = 0b111111
+
+val MAX : forall 'n. atom('n) -> atom(2 ^ 'n - 1) effect pure
+function MAX(n) = pow2(n) - 1
+
+let MAX_U64 = MAX(64) /*unsigned(0xffffffffffffffff)*/
+let MAX_VA = MAX(40) /*unsigned(0xffffffffff)*/
+let MAX_PA = MAX(36) /*unsigned(0xfffffffff)*/
+
+bitfield TLBEntry : bits(117) = {
+ pagemask : 116.. 101,
+ r : 100.. 99,
+ vpn2 : 98.. 72,
+ asid : 71.. 64,
+ g : 63,
+ valid : 62,
+ caps1 : 61,
+ capl1 : 60,
+ pfn1 : 59.. 36,
+ c1 : 35.. 33,
+ d1 : 32,
+ v1 : 31,
+ caps0 : 30,
+ capl0 : 29,
+ pfn0 : 28.. 5,
+ c0 : 4.. 2,
+ d0 : 1,
+ v0 : 0,
+}
+
+register TLBProbe : bits(1)
+register TLBIndex : TLBIndexT
+register TLBRandom : TLBIndexT
+register TLBEntryLo0 : TLBEntryLoReg
+register TLBEntryLo1 : TLBEntryLoReg
+register TLBContext : ContextReg
+register TLBPageMask : bits(16)
+register TLBWired : TLBIndexT
+register TLBEntryHi : TLBEntryHiReg
+register TLBXContext : XContextReg
+
+register TLBEntry00 : TLBEntry
+register TLBEntry01 : TLBEntry
+register TLBEntry02 : TLBEntry
+register TLBEntry03 : TLBEntry
+register TLBEntry04 : TLBEntry
+register TLBEntry05 : TLBEntry
+register TLBEntry06 : TLBEntry
+register TLBEntry07 : TLBEntry
+register TLBEntry08 : TLBEntry
+register TLBEntry09 : TLBEntry
+register TLBEntry10 : TLBEntry
+register TLBEntry11 : TLBEntry
+register TLBEntry12 : TLBEntry
+register TLBEntry13 : TLBEntry
+register TLBEntry14 : TLBEntry
+register TLBEntry15 : TLBEntry
+register TLBEntry16 : TLBEntry
+register TLBEntry17 : TLBEntry
+register TLBEntry18 : TLBEntry
+register TLBEntry19 : TLBEntry
+register TLBEntry20 : TLBEntry
+register TLBEntry21 : TLBEntry
+register TLBEntry22 : TLBEntry
+register TLBEntry23 : TLBEntry
+register TLBEntry24 : TLBEntry
+register TLBEntry25 : TLBEntry
+register TLBEntry26 : TLBEntry
+register TLBEntry27 : TLBEntry
+register TLBEntry28 : TLBEntry
+register TLBEntry29 : TLBEntry
+register TLBEntry30 : TLBEntry
+register TLBEntry31 : TLBEntry
+register TLBEntry32 : TLBEntry
+register TLBEntry33 : TLBEntry
+register TLBEntry34 : TLBEntry
+register TLBEntry35 : TLBEntry
+register TLBEntry36 : TLBEntry
+register TLBEntry37 : TLBEntry
+register TLBEntry38 : TLBEntry
+register TLBEntry39 : TLBEntry
+register TLBEntry40 : TLBEntry
+register TLBEntry41 : TLBEntry
+register TLBEntry42 : TLBEntry
+register TLBEntry43 : TLBEntry
+register TLBEntry44 : TLBEntry
+register TLBEntry45 : TLBEntry
+register TLBEntry46 : TLBEntry
+register TLBEntry47 : TLBEntry
+register TLBEntry48 : TLBEntry
+register TLBEntry49 : TLBEntry
+register TLBEntry50 : TLBEntry
+register TLBEntry51 : TLBEntry
+register TLBEntry52 : TLBEntry
+register TLBEntry53 : TLBEntry
+register TLBEntry54 : TLBEntry
+register TLBEntry55 : TLBEntry
+register TLBEntry56 : TLBEntry
+register TLBEntry57 : TLBEntry
+register TLBEntry58 : TLBEntry
+register TLBEntry59 : TLBEntry
+register TLBEntry60 : TLBEntry
+register TLBEntry61 : TLBEntry
+register TLBEntry62 : TLBEntry
+register TLBEntry63 : TLBEntry
+
+let TLBEntries : vector(64, dec, register(TLBEntry)) = [
+ ref TLBEntry63,
+ ref TLBEntry62,
+ ref TLBEntry61,
+ ref TLBEntry60,
+ ref TLBEntry59,
+ ref TLBEntry58,
+ ref TLBEntry57,
+ ref TLBEntry56,
+ ref TLBEntry55,
+ ref TLBEntry54,
+ ref TLBEntry53,
+ ref TLBEntry52,
+ ref TLBEntry51,
+ ref TLBEntry50,
+ ref TLBEntry49,
+ ref TLBEntry48,
+ ref TLBEntry47,
+ ref TLBEntry46,
+ ref TLBEntry45,
+ ref TLBEntry44,
+ ref TLBEntry43,
+ ref TLBEntry42,
+ ref TLBEntry41,
+ ref TLBEntry40,
+ ref TLBEntry39,
+ ref TLBEntry38,
+ ref TLBEntry37,
+ ref TLBEntry36,
+ ref TLBEntry35,
+ ref TLBEntry34,
+ ref TLBEntry33,
+ ref TLBEntry32,
+ ref TLBEntry31,
+ ref TLBEntry30,
+ ref TLBEntry29,
+ ref TLBEntry28,
+ ref TLBEntry27,
+ ref TLBEntry26,
+ ref TLBEntry25,
+ ref TLBEntry24,
+ ref TLBEntry23,
+ ref TLBEntry22,
+ ref TLBEntry21,
+ ref TLBEntry20,
+ ref TLBEntry19,
+ ref TLBEntry18,
+ ref TLBEntry17,
+ ref TLBEntry16,
+ ref TLBEntry15,
+ ref TLBEntry14,
+ ref TLBEntry13,
+ ref TLBEntry12,
+ ref TLBEntry11,
+ ref TLBEntry10,
+ ref TLBEntry09,
+ ref TLBEntry08,
+ ref TLBEntry07,
+ ref TLBEntry06,
+ ref TLBEntry05,
+ ref TLBEntry04,
+ ref TLBEntry03,
+ ref TLBEntry02,
+ ref TLBEntry01,
+ ref TLBEntry00
+]
+
+register CP0Compare : bits(32)
+register CP0Cause : CauseReg
+register CP0EPC : bits(64)
+register CP0ErrorEPC : bits(64)
+register CP0LLBit : bits(1)
+register CP0LLAddr : bits(64)
+register CP0BadVAddr : bits(64)
+register CP0Count : bits(32)
+register CP0HWREna : bits(32)
+register CP0UserLocal : bits(64)
+
+bitfield StatusReg : bits(32) = {
+ CU : 31.. 28, /* co-processor enable bits */
+ /* RP/FR/RE/MX/PX not implemented */
+ BEV : 22, /* use boot exception vectors (initialised to one) */
+ /* TS/SR/NMI not implemented */
+ IM : 15.. 8, /* Interrupt mask */
+ KX : 7, /* kernel 64-bit enable */
+ SX : 6, /* supervisor 64-bit enable */
+ UX : 5, /* user 64-bit enable */
+ KSU : 4.. 3, /* Processor mode */
+ ERL : 2, /* error level (should be initialised to one, but BERI is different) */
+ EXL : 1, /* exception level */
+ IE : 0, /* interrupt enable */
+}
+register CP0Status : StatusReg
+
+/* Implementation registers -- not ISA defined */
+register branchPending : bits(1) /* Set by branch instructions to implement branch delay */
+register inBranchDelay : bits(1) /* Needs to be set by outside world when in branch delay slot */
+register delayedPC : bits(64) /* Set by branch instructions to implement branch delay */
+
+/* General purpose registers */
+
+
+/* Special registers For MUL/DIV */
+register HI : bits(64)
+register LO : bits(64)
+
+register GPR : vector(32, dec, bits(64))
+
+/* JTAG Uart registers */
+
+register UART_WDATA : bits(8)
+register UART_WRITTEN : bits(1)
+register UART_RDATA : bits(8)
+register UART_RVALID : bits(1)
+
+/* Check whether a given 64-bit vector is a properly sign extended 32-bit word */
+val NotWordVal : bits(64) -> bool effect pure
+function NotWordVal (word) =
+ (word[31] ^^ 32) != word[63..32]
+
+/* Read numbered GP reg. (r0 is always zero) */
+val rGPR : bits(5) -> bits(64) effect {rreg}
+function rGPR idx = {
+ let i as atom(_) = unsigned(idx) in
+ if i == 0 then 0x0000000000000000 else GPR[i]
+}
+
+/* Write numbered GP reg. (writes to r0 ignored) */
+val wGPR : (bits(5), bits(64)) -> unit effect {wreg}
+function wGPR (idx, v) = {
+ let i as atom(_) = unsigned(idx) in
+ if i == 0 then () else GPR[i] = v
+}
+
+val MEMr = {lem: "MEMr"} : forall 'n.
+ ( bits(64) , atom('n) ) -> (bits(8 * 'n)) effect { rmem }
+val MEMr_reserve = {lem: "MEMr_reserve"} : forall 'n.
+ ( bits(64) , atom('n) ) -> (bits(8 * 'n)) effect { rmem }
+val MEM_sync = {lem: "MEM_sync"} :
+ unit -> unit effect { barr }
+
+val MEMea = {lem: "MEMea"} : forall 'n.
+ ( bits(64) , atom('n)) -> unit effect { eamem }
+val MEMea_conditional = {lem: "MEMea_conditional"} : forall 'n.
+ ( bits(64) , atom('n)) -> unit effect { eamem }
+val MEMval = {lem: "MEMval"} : forall 'n.
+ ( bits(64) , atom('n), bits(8*'n)) -> unit effect { wmv }
+val MEMval_conditional = {lem: "MEMval_conditional"} : forall 'n.
+ ( bits(64) , atom('n), bits(8*'n)) -> bool effect { wmv }
+
+/* Extern nops with effects, sometimes useful for faking effect */
+val skip_eamem = "skip" : unit -> unit effect {eamem}
+val skip_barr = "skip" : unit -> unit effect {barr}
+val skip_wreg = "skip" : unit -> unit effect {wreg}
+val skip_rreg = "skip" : unit -> unit effect {rreg}
+val skip_wmvt = "skip" : unit -> unit effect {wmvt}
+val skip_rmemt = "skip" : unit -> unit effect {rmemt}
+val skip_escape = "skip" : unit -> unit effect {escape}
+
+function MEMr (addr, size) = __MIPS_read(addr, size)
+function MEMr_reserve (addr, size) = __MIPS_read(addr, size)
+function MEM_sync () = skip_barr()
+
+function MEMea (addr, size) = skip_eamem()
+function MEMea_conditional (addr, size) = skip_eamem()
+function MEMval (addr, size, data) = __MIPS_write(addr, size, data)
+function MEMval_conditional (addr, size, data) = { __MIPS_write(addr, size, data); true }
+
+enum Exception =
+{
+ Interrupt, TLBMod, TLBL, TLBS, AdEL, AdES, Sys, Bp, ResI, CpU, Ov, Tr, C2E, C2Trap,
+ XTLBRefillL, XTLBRefillS, XTLBInvL, XTLBInvS, MCheck
+}
+
+/* Return the ISA defined code for an exception condition */
+function ExceptionCode (ex) : Exception -> bits(5)=
+ let x : bits(8) = match ex
+ {
+ Interrupt => 0x00, /* Interrupt */
+ TLBMod => 0x01, /* TLB modification exception */
+ TLBL => 0x02, /* TLB exception (load or fetch) */
+ TLBS => 0x03, /* TLB exception (store) */
+ AdEL => 0x04, /* Address error (load or fetch) */
+ AdES => 0x05, /* Address error (store) */
+ Sys => 0x08, /* Syscall */
+ Bp => 0x09, /* Breakpoint */
+ ResI => 0x0a, /* Reserved instruction */
+ CpU => 0x0b, /* Coprocessor Unusable */
+ Ov => 0x0c, /* Arithmetic overflow */
+ Tr => 0x0d, /* Trap */
+ C2E => 0x12, /* C2E coprocessor 2 exception */
+ C2Trap => 0x12, /* C2Trap maps to same exception code, different vector */
+ XTLBRefillL => 0x02,
+ XTLBRefillS => 0x03,
+ XTLBInvL => 0x02,
+ XTLBInvS => 0x03,
+ MCheck => 0x18
+ } in x[4..0]
+
+
+val SignalExceptionMIPS : forall ('o : Type) . (Exception, bits(64)) -> 'o effect {escape, rreg, wreg}
+function SignalExceptionMIPS (ex, kccBase) =
+ {
+ /* Only update EPC and BD if not already in EXL mode */
+ if (~ (CP0Status.EXL())) then
+ {
+ if (inBranchDelay[0]) then
+ {
+ CP0EPC = PC - 4;
+ CP0Cause->BD() = 0b1;
+ }
+ else
+ {
+ CP0EPC = PC;
+ CP0Cause->BD() = 0b0;
+ }
+ };
+
+ /* choose an exception vector to branch to. Some are not supported
+ e.g. Reset */
+ vectorOffset =
+ if (CP0Status.EXL()) then
+ 0x180 /* Always use common vector if in exception mode already */
+ else if ((ex == XTLBRefillL) | (ex == XTLBRefillS)) then
+ 0x080
+ else if (ex == C2Trap) then
+ 0x280 /* Special vector for CHERI traps */
+ else
+ 0x180; /* Common vector */
+ vectorBase : bits(64) = if CP0Status.BEV() then
+ 0xFFFFFFFFBFC00200
+ else
+ 0xFFFFFFFF80000000;
+ /* On CHERI we have to subtract KCC.base so that we end up at the
+ right absolute vector address after indirecting via new PCC */
+ nextPC = vectorBase + EXTS(vectorOffset) - kccBase;
+ CP0Cause->ExcCode() = ExceptionCode(ex);
+ CP0Status->EXL() = 0b1;
+ throw (ISAException());
+ }
+
+/* Defined either in mips_wrappers (directly calling SignalExceptionMIPS) or in cheri_prelude_common (cheri things plus above) */
+val SignalException : forall ('o : Type) . Exception -> 'o effect {escape, rreg, wreg}
+
+val SignalExceptionBadAddr : forall ('o : Type) . (Exception, bits(64)) -> 'o effect {escape, rreg, wreg}
+function SignalExceptionBadAddr(ex, badAddr) =
+ {
+ CP0BadVAddr = badAddr;
+ SignalException(ex);
+ }
+
+val SignalExceptionTLB : forall ('o : Type) . (Exception, bits(64)) -> 'o effect {escape, rreg, wreg}
+function SignalExceptionTLB(ex, badAddr) = {
+ CP0BadVAddr = badAddr;
+ TLBContext->BadVPN2() = (badAddr[31..13]);
+ TLBXContext->XBadVPN2()= (badAddr[39..13]);
+ TLBXContext->XR() = (badAddr[63..62]);
+ TLBEntryHi->R() = (badAddr[63..62]);
+ TLBEntryHi->VPN2() = (badAddr[39..13]);
+ SignalException(ex);
+}
+
+enum MemAccessType = {Instruction, LoadData, StoreData}
+enum AccessLevel = {User, Supervisor, Kernel}
+
+function getAccessLevel() : unit -> AccessLevel=
+ if ((CP0Status.EXL()) | (CP0Status.ERL())) then
+ Kernel
+ else match CP0Status.KSU()
+ {
+ 0b00 => Kernel,
+ 0b01 => Supervisor,
+ 0b10 => User,
+ _ => User /* behaviour undefined, assume user */
+ }
+
+val checkCP0Access : unit->unit effect{escape, rreg, wreg}
+function checkCP0Access () =
+ {
+ let accessLevel = getAccessLevel() in
+ if ((accessLevel != Kernel) & (~(CP0Status.CU()[0]))) then
+ {
+ CP0Cause->CE() = 0b00;
+ SignalException(CpU);
+ }
+ }
+
+val incrementCP0Count : unit -> unit effect {rreg,wreg,escape}
+function incrementCP0Count() = {
+ TLBRandom = (if (TLBRandom == TLBWired)
+ then (TLBIndexMax) else (TLBRandom - 1));
+
+ CP0Count = (CP0Count + 1);
+ if (CP0Count == CP0Compare) then {
+ CP0Cause->IP() = CP0Cause.IP() | 0x80; /* IP7 is timer interrupt */
+ };
+
+ let ims = CP0Status.IM() in
+ let ips = CP0Cause.IP() in
+ let ie = CP0Status.IE() in
+ let exl = CP0Status.EXL() in
+ let erl = CP0Status.ERL() in
+ if ((~(exl)) & (~(erl)) & ie & ((ips & ims) != 0x00)) then
+ SignalException(Interrupt);
+}
+
+type regno = bits(5) /* a register number */
+type imm16 = bits(16) /* 16-bit immediate */
+/* a commonly used instruction format with three register operands */
+type regregreg = (regno, regno, regno)
+/* a commonly used instruction format with two register operands and 16-bit immediate */
+type regregimm16 = (regno, regno, imm16)
+
+enum decode_failure = {
+ no_matching_pattern,
+ unsupported_instruction,
+ illegal_instruction,
+ internal_error
+}
+
+/* Used by branch and trap instructions */
+enum Comparison = {
+ EQ, /* equal */
+ NE, /* not equal */
+ GE, /* signed greater than or equal */
+ GEU,/* unsigned greater than or equal */
+ GT, /* signed strictly greater than */
+ LE, /* signed less than or equal */
+ LT, /* signed strictly less than */
+ LTU /* unsigned less than or qual */
+}
+
+val compare : (Comparison, bits(64), bits(64)) -> bool
+function compare (cmp, valA, valB) =
+ match cmp {
+ EQ => valA == valB,
+ NE => valA != valB,
+ GE => valA >=_s valB,
+ GEU => valA >=_u valB,
+ GT => valB <_s valA,
+ LE => valB >=_s valA,
+ LT => valA <_s valB,
+ LTU => valA <_u valB
+ }
+enum WordType = { B, H, W, D}
+
+val wordWidthBytes : WordType -> range(1, 8)
+function wordWidthBytes(w) =
+ match w {
+ B => 1,
+ H => 2,
+ W => 4,
+ D => 8
+ }
+
+/* This function checks that memory accesses are naturally aligned
+ -- it is disabled in favour of BERI specific behaviour below.
+function bool isAddressAligned(addr, (WordType) wordType) =
+ match wordType {
+ B => true
+ H => (addr[0] == 0)
+ W => (addr[1..0] == 0b00)
+ D => (addr[2..0] == 0b000)
+ }
+*/
+
+/* BERI relaxes the natural alignment requirement for loads and stores
+ but still throws an exception if an access spans a cache line
+ boundary. Here we assume this is 32 bytes so that we don't have to
+ worry about clearing multiple tags when an access spans more than
+ one capability. Capability load/stores are still naturally
+ aligned. Provided this is a factor of smallest supported page size
+ (4k) we don't need to worry about accesses spanning page boundaries
+ either.
+*/
+let alignment_width = 16
+val isAddressAligned : (bits(64), WordType) -> bool
+function isAddressAligned (addr, wordType) =
+ let a = unsigned(addr) in
+ a / alignment_width == (a + wordWidthBytes(wordType) - 1) / alignment_width
+
+val reverse_endianness = "reverse_endianness" : forall 'W, 'W >= 1. bits(8 * 'W) -> bits(8 * 'W) effect pure
+
+/*
+function rec forall Nat 'W, 'W >= 1. bits(8 * 'W) reverse_endianness' (w, value) =
+{
+ ([:8 * 'W:]) width = length(value);
+ if width <= 8
+ then value
+ else value[7..0] : reverse_endianness'(w - 1, value[(width - 1) .. 8])
+}
+
+
+
+function rec forall Nat 'W, 'W >= 1. bits(8 * 'W) reverse_endianness ((bits(8 * 'W)) value) =
+{
+ reverse_endianness'(sizeof 'W, value)
+}*/
+
+val MEMr_wrapper : forall 'n, 1 <= 'n <=8 . (bits(64), atom('n)) -> bits(8*'n) effect {rmem}
+function MEMr_wrapper (addr, size) = reverse_endianness(MEMr (addr, size))
+/* TODO
+ if (addr == 0x000000007f000000) then
+ {
+ let rvalid = UART_RVALID in
+ let rdata = (bits(8 * 'n)) (mask(0x00000000 : UART_RDATA : rvalid : 0b0000000 : 0x0000)) in
+ {
+ UART_RVALID = [bitzero];
+ rdata
+ }
+ }
+ else if (addr == 0x000000007f000004) then
+ mask(0x000000000004ffff) /* Always plenty of write space available and jtag activity */
+ else
+ reverse_endianness(MEMr(addr, size)) /* MEMr assumes little endian */ */
+
+val MEMr_reserve_wrapper : forall 'n, 1 <= 'n <= 8 . ( bits(64) , atom('n) ) -> (bits(8 * 'n)) effect { rmem }
+function MEMr_reserve_wrapper (addr , size) =
+ reverse_endianness(MEMr_reserve(addr, size))
+
+
+function init_cp0_state () : unit -> unit = {
+ CP0Status->BEV() = bitone;
+}
+
+val init_cp2_state : unit -> unit effect {wreg}
+val cp2_next_pc: unit -> unit effect {rreg, wreg}
+val dump_cp2_state : unit -> unit effect {rreg, escape}
diff --git a/mips/mips_regfp.sail b/mips/mips_regfp.sail
new file mode 100644
index 00000000..4bf96022
--- /dev/null
+++ b/mips/mips_regfp.sail
@@ -0,0 +1,455 @@
+/*========================================================================*/
+/* */
+/* Copyright (c) 2015-2017 Robert M. Norton */
+/* Copyright (c) 2015-2017 Kathyrn Gray */
+/* All rights reserved. */
+/* */
+/* This software was developed by the University of Cambridge Computer */
+/* Laboratory as part of the Rigorous Engineering of Mainstream Systems */
+/* (REMS) project, funded by EPSRC grant EP/K008528/1. */
+/* */
+/* Redistribution and use in source and binary forms, with or without */
+/* modification, are permitted provided that the following conditions */
+/* are met: */
+/* 1. Redistributions of source code must retain the above copyright */
+/* notice, this list of conditions and the following disclaimer. */
+/* 2. Redistributions in binary form must reproduce the above copyright */
+/* notice, this list of conditions and the following disclaimer in */
+/* the documentation and/or other materials provided with the */
+/* distribution. */
+/* */
+/* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' */
+/* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED */
+/* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A */
+/* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR */
+/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
+/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
+/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF */
+/* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND */
+/* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, */
+/* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */
+/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF */
+/* SUCH DAMAGE. */
+/*========================================================================*/
+
+let GPRs : vector <0, 32, inc, string > =
+ [ "GPR00", "GPR01", "GPR02", "GPR03", "GPR04", "GPR05", "GPR06", "GPR07", "GPR08", "GPR09", "GPR10",
+ "GPR11", "GPR12", "GPR13", "GPR14", "GPR15", "GPR16", "GPR17", "GPR18", "GPR19", "GPR20",
+ "GPR21", "GPR22", "GPR23", "GPR24", "GPR25", "GPR26", "GPR27", "GPR28", "GPR29", "GPR30", "GPR31"
+ ]
+
+let CIA_fp = RFull("CIA")
+let NIA_fp = RFull("NIA")
+
+function (regfps,regfps,regfps,niafps,diafp,instruction_kind) initial_analysis ((ast) instr) = {
+ (regfps) iR = [|| ||];
+ (regfps) oR = [|| ||];
+ (regfps) aR = [|| ||];
+ (instruction_kind) ik = IK_simple;
+ (niafps) Nias = [|| ||];
+ (diafp) Dia = DIAFP_none;
+
+ switch instr {
+ (DADDIU (rs, rt, imm)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else oR = RFull(GPRs[rt]) :: oR;
+ }
+ (DADDU (rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (DADDI (rs, rt, imm)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else oR = RFull(GPRs[rt]) :: oR;
+ }
+ (DADD (rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (ADD(rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (ADDI(rs, rt, imm)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else oR = RFull(GPRs[rt]) :: oR;
+ }
+ (ADDU(rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (ADDIU(rs, rt, imm)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else oR = RFull(GPRs[rt]) :: oR;
+ }
+ (DSUBU (rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (DSUB (rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (SUB(rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (SUBU(rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (AND (rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (ANDI (rs, rt, imm)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else oR = RFull(GPRs[rt]) :: oR;
+ }
+ (OR (rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (ORI (rs, rt, imm)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else oR = RFull(GPRs[rt]) :: oR;
+ }
+ (NOR (rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (XOR (rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (XORI (rs, rt, imm)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else oR = RFull(GPRs[rt]) :: oR;
+ }
+ (LUI (rt, imm)) => {
+ if rt == 0 then () else oR = RFull(GPRs[rt]) :: oR;
+ }
+ (DSLL (rt, rd, sa)) => {
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (DSLL32 (rt, rd, sa)) => {
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (DSLLV (rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (DSRA (rt, rd, sa)) => {
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (DSRA32 (rt, rd, sa)) => {
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (DSRAV (rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (DSRL (rt, rd, sa)) => {
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (DSRL32 (rt, rd, sa)) => {
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (DSRLV (rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (SLL(rt, rd, sa)) => {
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (SLLV(rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (SRA(rt, rd, sa)) => {
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (SRAV(rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (SRL(rt, rd, sa)) => {
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (SRLV(rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (SLT(rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (SLTI(rs, rt, imm)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else oR = RFull(GPRs[rt]) :: oR;
+ }
+ (SLTU(rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (SLTIU(rs, rt, imm)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else oR = RFull(GPRs[rt]) :: oR;
+ }
+ (MOVN(rs, rt, rd)) => {
+ /* XXX don't always write rd */
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (MOVZ(rs, rt, rd)) => {
+ /* XXX don't always write rd */
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (MFHI(rd)) => {
+ iR = RFull("HI") :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (MFLO(rd)) => {
+ iR = RFull("LO") :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (MTHI(rs)) => {
+ oR = RFull("HI") :: oR;
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ }
+ (MTLO(rs)) => {
+ oR = RFull("LO") :: oR;
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ }
+ (MUL(rs, rt, rd)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ if rd == 0 then () else oR = RFull(GPRs[rd]) :: oR;
+ }
+ (MULT(rs, rt)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ oR = RFull("HI") :: RFull ("LO") :: oR;
+ }
+ (MULTU(rs, rt)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ oR = RFull("HI") :: RFull ("LO") :: oR;
+ }
+ (DMULT(rs, rt)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ oR = RFull("HI") :: RFull ("LO") :: oR;
+ }
+ (DMULTU(rs, rt)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ oR = RFull("HI") :: RFull ("LO") :: oR;
+ }
+ (MADD(rs, rt)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ iR = RFull("HI") :: RFull ("LO") :: iR;
+ oR = RFull("HI") :: RFull ("LO") :: oR;
+ }
+ (MADDU(rs, rt)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ iR = RFull("HI") :: RFull ("LO") :: iR;
+ oR = RFull("HI") :: RFull ("LO") :: oR;
+ }
+ (MSUB(rs, rt)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ iR = RFull("HI") :: RFull ("LO") :: iR;
+ oR = RFull("HI") :: RFull ("LO") :: oR;
+ }
+ (MSUBU(rs, rt)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ iR = RFull("HI") :: RFull ("LO") :: iR;
+ oR = RFull("HI") :: RFull ("LO") :: oR;
+ }
+ (DIV(rs, rt)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ oR = RFull("HI") :: RFull ("LO") :: oR;
+ }
+ (DIVU(rs, rt)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ oR = RFull("HI") :: RFull ("LO") :: oR;
+ }
+ (DDIV(rs, rt)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ oR = RFull("HI") :: RFull ("LO") :: oR;
+ }
+ (DDIVU(rs, rt)) => {
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ oR = RFull("HI") :: RFull ("LO") :: oR;
+ }
+ (J(offset)) => {
+ /* XXX actually unconditional jump */
+ /*ik = IK_cond_branch;*/
+ Dia = DIAFP_concrete((PC + 4)[63..28] : offset : 0b00);
+ }
+ (JAL(offset)) => {
+ /* XXX actually unconditional jump */
+ /*ik = IK_cond_branch;*/
+ oR = RFull("GPR31") :: oR;
+ Dia = DIAFP_concrete((PC + 4)[63..28] : offset : 0b00);
+ }
+ (JR(rs)) => {
+ /* XXX actually unconditional jump */
+ /*ik = IK_cond_branch;*/
+ iR = RFull(GPRs[rs]) :: iR;
+ Dia = DIAFP_reg(RFull(GPRs[rs]));
+ }
+ (JALR(rs, rd)) => {
+ /* XXX actually unconditional jump */
+ /*ik = IK_cond_branch;*/
+ iR = RFull(GPRs[rs]) :: iR;
+ oR = RFull("GPR31") :: oR;
+ Dia = DIAFP_reg(RFull(GPRs[rs]));
+ }
+ (BEQ(rs, rd, imm, ne, likely)) => {
+ ik = IK_cond_branch;
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if rd == 0 then () else iR = RFull(GPRs[rd]) :: iR;
+ let offset : bits(64) = (EXTS(imm : 0b00) + 4) in
+ Dia = DIAFP_concrete (PC + offset);
+ }
+ (BCMPZ(rs, imm, cmp, link, likely)) => {
+ ik = IK_cond_branch;
+ if rs == 0 then () else iR = RFull(GPRs[rs]) :: iR;
+ if link then
+ oR = RFull("GPR31") :: oR;
+ let offset : bits(64) = (EXTS(imm : 0b00) + 4) in
+ Dia = DIAFP_concrete (PC + offset);
+ }
+ (SYSCALL_THREAD_START) => ()
+/*
+
+ case (SYSCALL) =
+ case (BREAK) =
+ case (WAIT) = {
+ case (TRAPREG(rs, rt, cmp)) =
+ case (TRAPIMM(rs, imm, cmp)) =
+*/
+ (Load(width, signed, linked, base, rt, offset)) => {
+ ik = IK_mem_read (if linked then Read_reserve else Read_plain);
+ if linked then oR = RFull("CP0LLBit")::RFull("CP0LLAddr")::oR else ();
+ if base == 0 then () else aR = RFull(GPRs[base]) :: aR;
+ iR = aR;
+ if rt == 0 then () else oR = RFull(GPRs[rt]) :: oR;
+ }
+ (Store(width, conditional, base, rt, offset)) => {
+ ik = IK_mem_write(if conditional then Write_conditional else Write_plain);
+ if base == 0 then () else aR = RFull(GPRs[base]) :: aR;
+ iR = aR;
+ if conditional then iR = RFull("CP0LLBit")::iR else ();
+ if (conditional & (rt != 0)) then oR = RFull(GPRs[rt])::oR else ();
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ }
+ (LWL(base, rt, offset)) => {
+ ik = IK_mem_read(Read_plain);
+ if base == 0 then () else aR = RFull(GPRs[base]) :: aR;
+ iR = aR;
+ if rt == 0 then () else oR = RFull(GPRs[rt]) :: oR;
+ }
+ (LWR(base, rt, offset)) => {
+ ik = IK_mem_read(Read_plain);
+ if base == 0 then () else aR = RFull(GPRs[base]) :: aR;
+ iR = aR;
+ if rt == 0 then () else oR = RFull(GPRs[rt]) :: oR;
+ }
+ (SWL(base, rt, offset)) => {
+ ik = IK_mem_write(Write_plain);
+ if base == 0 then () else aR = RFull(GPRs[base]) :: aR;
+ iR = aR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ }
+ (SWR(base, rt, offset)) => {
+ ik = IK_mem_write(Write_plain);
+ if base == 0 then () else aR = RFull(GPRs[base]) :: aR;
+ iR = aR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ }
+ (LDL(base, rt, offset)) => {
+ ik = IK_mem_read(Read_plain);
+ if base == 0 then () else aR = RFull(GPRs[base]) :: aR;
+ iR = aR;
+ if rt == 0 then () else oR = RFull(GPRs[rt]) :: oR;
+ }
+ (LDR(base, rt, offset)) => {
+ ik = IK_mem_read(Read_plain);
+ if base == 0 then () else aR = RFull(GPRs[base]) :: aR;
+ iR = aR;
+ if rt == 0 then () else oR = RFull(GPRs[rt]) :: oR;
+ }
+ (SDL(base, rt, offset)) => {
+ ik = IK_mem_write(Write_plain);
+ if base == 0 then () else aR = RFull(GPRs[base]) :: aR;
+ iR = aR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ }
+ (SDR(base, rt, offset)) => {
+ ik = IK_mem_write(Write_plain);
+ if base == 0 then () else aR = RFull(GPRs[base]) :: aR;
+ iR = aR;
+ if rt == 0 then () else iR = RFull(GPRs[rt]) :: iR;
+ }
+/*
+ case (CACHE(base, op, imm)) =
+ case (PREF(base, op, imm)) =
+*/
+ (SYNC) => {
+ iK = IK_barrier(Barrier_MIPS_SYNC);
+ }
+/*
+ case (MFC0(rt, rd, sel, double))
+ case (HCF)
+ case (MTC0(rt, rd, sel, double))
+ case (TLBWI)
+ case (TLBWR)
+ case (TLBR)
+ case ((TLBP))
+ case (RDHWR(rt, rd))
+ case (ERET)
+*/
+ };
+ (iR,oR,aR,Nias,Dia,ik)
+}
diff --git a/mips/mips_ri.sail b/mips/mips_ri.sail
new file mode 100644
index 00000000..edce0657
--- /dev/null
+++ b/mips/mips_ri.sail
@@ -0,0 +1,42 @@
+/*========================================================================*/
+/* */
+/* Copyright (c) 2015-2017 Robert M. Norton */
+/* Copyright (c) 2015-2017 Kathyrn Gray */
+/* All rights reserved. */
+/* */
+/* This software was developed by the University of Cambridge Computer */
+/* Laboratory as part of the Rigorous Engineering of Mainstream Systems */
+/* (REMS) project, funded by EPSRC grant EP/K008528/1. */
+/* */
+/* Redistribution and use in source and binary forms, with or without */
+/* modification, are permitted provided that the following conditions */
+/* are met: */
+/* 1. Redistributions of source code must retain the above copyright */
+/* notice, this list of conditions and the following disclaimer. */
+/* 2. Redistributions in binary form must reproduce the above copyright */
+/* notice, this list of conditions and the following disclaimer in */
+/* the documentation and/or other materials provided with the */
+/* distribution. */
+/* */
+/* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' */
+/* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED */
+/* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A */
+/* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR */
+/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
+/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
+/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF */
+/* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND */
+/* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, */
+/* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */
+/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF */
+/* SUCH DAMAGE. */
+/*========================================================================*/
+
+/* mips_ri.sail: only use if want unknown instructions to throw
+ exception (like real hardware) instead of die (convenient for ppcmem) */
+
+union clause ast = RI : unit
+function clause decode _ = Some(RI())
+function clause execute (RI()) =
+ SignalException (ResI)
+
diff --git a/mips/mips_tlb.sail b/mips/mips_tlb.sail
new file mode 100644
index 00000000..741eb84c
--- /dev/null
+++ b/mips/mips_tlb.sail
@@ -0,0 +1,148 @@
+/*========================================================================*/
+/* */
+/* Copyright (c) 2015-2017 Robert M. Norton */
+/* Copyright (c) 2015-2017 Kathyrn Gray */
+/* All rights reserved. */
+/* */
+/* This software was developed by the University of Cambridge Computer */
+/* Laboratory as part of the Rigorous Engineering of Mainstream Systems */
+/* (REMS) project, funded by EPSRC grant EP/K008528/1. */
+/* */
+/* Redistribution and use in source and binary forms, with or without */
+/* modification, are permitted provided that the following conditions */
+/* are met: */
+/* 1. Redistributions of source code must retain the above copyright */
+/* notice, this list of conditions and the following disclaimer. */
+/* 2. Redistributions in binary form must reproduce the above copyright */
+/* notice, this list of conditions and the following disclaimer in */
+/* the documentation and/or other materials provided with the */
+/* distribution. */
+/* */
+/* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' */
+/* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED */
+/* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A */
+/* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR */
+/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
+/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
+/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF */
+/* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND */
+/* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, */
+/* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */
+/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF */
+/* SUCH DAMAGE. */
+/*========================================================================*/
+
+val tlbEntryMatch : (bits(2), bits(27), bits(8), TLBEntry) -> bool effect pure
+function tlbEntryMatch(r, vpn2, asid, entry) =
+ let entryValid = entry.valid() in
+ let entryR = entry.r() in
+ let entryMask = entry.pagemask() in
+ let entryVPN = entry.vpn2() in
+ let entryASID = entry.asid() in
+ let entryG = entry.g() in
+ let vpnMask : bits(27) = ~(EXTZ(entryMask)) in
+ (entryValid &
+ (r == entryR) &
+ ((vpn2 & vpnMask) == ((entryVPN) & vpnMask)) &
+ ((asid == (entryASID)) | (entryG)))
+
+val tlbSearch : bits(64) -> option(TLBIndexT) effect {rreg}
+function tlbSearch(VAddr) =
+ let r = (VAddr[63..62]) in
+ let vpn2 = (VAddr[39..13]) in
+ let asid = TLBEntryHi.ASID() in {
+ foreach (idx from 0 to 63) {
+ if(tlbEntryMatch(r, vpn2, asid, reg_deref(TLBEntries[idx]))) then
+ return Some(to_bits(6, idx))
+ };
+ None()
+ }
+
+/** For given virtual address and accessType returns physical address and
+bool flag indicating whether capability stores / loads are permitted for
+page (depending on access type). */
+
+val TLBTranslate2 : (bits(64), MemAccessType) -> (bits(64), bool) effect {rreg, wreg, undef, escape}
+function TLBTranslate2 (vAddr, accessType) = {
+ let idx = tlbSearch(vAddr) in
+ match idx {
+ Some(idx) =>
+ let i as atom(_) = unsigned(idx) in
+ let entry = reg_deref(TLBEntries[i]) in
+ let entryMask = entry.pagemask() in
+ let 'evenOddBit : range(12,28) = match (entryMask) {
+ 0x0000 => 12,
+ 0x0003 => 14,
+ 0x000f => 16,
+ 0x003f => 18,
+ 0x00ff => 20,
+ 0x03ff => 22,
+ 0x0fff => 24,
+ 0x3fff => 26,
+ 0xffff => 28,
+ _ => undefined
+ } in
+ let isOdd = (vAddr[evenOddBit]) in
+ let (caps : bits(1), capl : bits(1), pfn : bits(24), d : bits(1), v : bits(1)) =
+ if (isOdd) then
+ (entry.caps1(), entry.capl1(), entry.pfn1(), entry.d1(), entry.v1())
+ else
+ (entry.caps0(), entry.capl0(), entry.pfn0(), entry.d0(), entry.v0()) in
+ if (~(v)) then
+ SignalExceptionTLB(if (accessType == StoreData) then XTLBInvS else XTLBInvL, vAddr)
+ else if ((accessType == StoreData) & ~(d)) then
+ SignalExceptionTLB(TLBMod, vAddr)
+ else
+ let res : bits(64) = EXTZ(pfn[23..(evenOddBit - 12)] @ vAddr[(evenOddBit - 1) .. 0]) in
+ (res, bits_to_bool(if (accessType == StoreData) then caps else capl)),
+ None() => SignalExceptionTLB(
+ if (accessType == StoreData) then XTLBRefillS else XTLBRefillL, vAddr)
+ }
+}
+
+val cast_AccessLevel : AccessLevel -> int effect pure
+function cast_AccessLevel level =
+ match level {
+ User => 0,
+ Supervisor => 1,
+ Kernel => 2
+ }
+
+/* perform TLB translation. bool is CHERI specific TLB bits noStoreCap/suppressTag */
+val TLBTranslateC : (bits(64), MemAccessType) -> (bits(64), bool) effect {escape, rreg, undef, wreg}
+function TLBTranslateC (vAddr, accessType) =
+ {
+ let currentAccessLevel = getAccessLevel() in
+ let compat32 = (vAddr[61..31] == 0b1111111111111111111111111111111) in
+ let (requiredLevel, addr) : (AccessLevel, option(bits(64))) = match (vAddr[63..62]) {
+ 0b11 => match (compat32, vAddr[30..29]) { /* xkseg */
+ (true, 0b11) => (Kernel, None() : option(bits(64))), /* kseg3 mapped 32-bit compat */
+ (true, 0b10) => (Supervisor, None() : option(bits(64))), /* sseg mapped 32-bit compat */
+ (true, 0b01) => (Kernel, Some(0x00000000 @ 0b000 @ vAddr[28..0])), /* kseg1 unmapped uncached 32-bit compat */
+ (true, 0b00) => (Kernel, Some(0x00000000 @ 0b000 @ vAddr[28..0])), /* kseg0 unmapped cached 32-bit compat */
+ (_, _) => (Kernel, None() : option(bits(64))) /* xkseg mapped */
+ },
+ 0b10 => (Kernel, Some(0b00000 @ vAddr[58..0])), /* xkphys bits 61-59 are cache mode (ignored) */
+ 0b01 => (Supervisor, None() : option(bits(64))), /* xsseg - supervisor mapped */
+ 0b00 => (User, None() : option(bits(64))) /* xuseg - user mapped */
+ } in
+ if (cast_AccessLevel(currentAccessLevel) < cast_AccessLevel(requiredLevel)) then
+ SignalExceptionBadAddr(if (accessType == StoreData) then AdES else AdEL, vAddr)
+ else
+ let (pa, c) : (bits(64), bool) = match addr {
+ Some(a) => (a, false),
+ None() => if ((~(compat32)) & (unsigned(vAddr[61..0]) > MAX_VA)) then
+ SignalExceptionBadAddr(if (accessType == StoreData) then AdES else AdEL, vAddr)
+ else
+ TLBTranslate2(vAddr, accessType)
+ }
+ in if (unsigned(pa) > MAX_PA) then
+ SignalExceptionBadAddr(if (accessType == StoreData) then AdES else AdEL, vAddr)
+ else
+ (pa, c)
+ }
+
+/* TLB translate function for MIPS (throws away capability flag) */
+val TLBTranslate : (bits(64), MemAccessType) -> bits(64) effect {rreg, wreg, escape, undef}
+function TLBTranslate (vAddr, accessType) =
+ let (addr, c) = TLBTranslateC(vAddr, accessType) in addr
diff --git a/mips/mips_tlb_stub.sail b/mips/mips_tlb_stub.sail
new file mode 100644
index 00000000..f0ffb9dd
--- /dev/null
+++ b/mips/mips_tlb_stub.sail
@@ -0,0 +1,48 @@
+/*========================================================================*/
+/* */
+/* Copyright (c) 2015-2017 Robert M. Norton */
+/* Copyright (c) 2015-2017 Kathyrn Gray */
+/* All rights reserved. */
+/* */
+/* This software was developed by the University of Cambridge Computer */
+/* Laboratory as part of the Rigorous Engineering of Mainstream Systems */
+/* (REMS) project, funded by EPSRC grant EP/K008528/1. */
+/* */
+/* Redistribution and use in source and binary forms, with or without */
+/* modification, are permitted provided that the following conditions */
+/* are met: */
+/* 1. Redistributions of source code must retain the above copyright */
+/* notice, this list of conditions and the following disclaimer. */
+/* 2. Redistributions in binary form must reproduce the above copyright */
+/* notice, this list of conditions and the following disclaimer in */
+/* the documentation and/or other materials provided with the */
+/* distribution. */
+/* */
+/* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' */
+/* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED */
+/* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A */
+/* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR */
+/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
+/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
+/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF */
+/* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND */
+/* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, */
+/* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */
+/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF */
+/* SUCH DAMAGE. */
+/*========================================================================*/
+
+$ifndef _MIPS_TLB_STUB
+$define _MIPS_TLB_STUB
+
+val tlbEntryMatch : (bits(2), bits(27), bits(8), TLBEntry) -> bool effect pure
+function tlbSearch(VAddr) : bits(64) -> option(TLBIndexT) = None
+
+val TLBTranslate2 : (bits(64), MemAccessType) -> (bits(64), bool) effect pure
+function TLBTranslate (vAddr, accessType) : (bits(64), MemAccessType) -> bits(64) =
+ vAddr
+
+val TLBTranslateC : (bits(64), MemAccessType) -> (bits(64), bool) effect pure
+function TLBTranslateC (vAddr, accessType) : (bits(64), MemAccessType) -> (bits(64), bool) = (vAddr, false)
+
+$endif
diff --git a/mips/mips_wrappers.sail b/mips/mips_wrappers.sail
new file mode 100644
index 00000000..70e6fa83
--- /dev/null
+++ b/mips/mips_wrappers.sail
@@ -0,0 +1,86 @@
+/*========================================================================*/
+/* */
+/* Copyright (c) 2015-2017 Robert M. Norton */
+/* Copyright (c) 2015-2017 Kathyrn Gray */
+/* All rights reserved. */
+/* */
+/* This software was developed by the University of Cambridge Computer */
+/* Laboratory as part of the Rigorous Engineering of Mainstream Systems */
+/* (REMS) project, funded by EPSRC grant EP/K008528/1. */
+/* */
+/* Redistribution and use in source and binary forms, with or without */
+/* modification, are permitted provided that the following conditions */
+/* are met: */
+/* 1. Redistributions of source code must retain the above copyright */
+/* notice, this list of conditions and the following disclaimer. */
+/* 2. Redistributions in binary form must reproduce the above copyright */
+/* notice, this list of conditions and the following disclaimer in */
+/* the documentation and/or other materials provided with the */
+/* distribution. */
+/* */
+/* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' */
+/* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED */
+/* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A */
+/* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR */
+/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
+/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
+/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF */
+/* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND */
+/* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, */
+/* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */
+/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF */
+/* SUCH DAMAGE. */
+/*========================================================================*/
+
+/* mips_wrappers.sail: wrappers functions and hooks for CHERI extensibility
+ (mostly identity functions here) */
+
+val MEMw_wrapper : forall 'n, 1 <= 'n <= 8. (bits(64), atom('n), bits(8 * 'n)) -> unit effect {eamem, wmv, wreg}
+
+function MEMw_wrapper(addr, size, data) =
+ let ledata = reverse_endianness(data) in
+ if (addr == 0x000000007f000000) then
+ {
+ UART_WDATA = ledata[7..0];
+ UART_WRITTEN = bitone;
+ } else {
+ MEMea(addr, size);
+ MEMval(addr, size, ledata);
+ }
+
+val MEMw_conditional_wrapper : forall 'n, 1 <= 'n <= 8. (bits(64), atom('n), bits(8 * 'n)) -> bool effect {eamem, wmv}
+
+function MEMw_conditional_wrapper(addr, size, data) =
+ {
+ MEMea_conditional(addr, size);
+ MEMval_conditional(addr, size, reverse_endianness(data))
+ }
+
+val addrWrapper : (bits(64), MemAccessType, WordType) -> bits(64)
+function addrWrapper(addr, accessType, width) =
+ addr
+
+$ifdef _MIPS_TLB_STUB
+val TranslatePC : bits(64) -> bits(64) effect {rreg, wreg, escape}
+$else
+val TranslatePC : bits(64) -> bits(64) effect {rreg, wreg, escape, undef}
+$endif
+
+function TranslatePC (vAddr) = {
+ incrementCP0Count();
+ if (vAddr[1..0] != 0b00) then /* bad PC alignment */
+ (SignalExceptionBadAddr(AdEL, vAddr))
+ else
+ TLBTranslate(vAddr, Instruction)
+}
+
+let have_cp2 = false
+
+function SignalException (ex) = SignalExceptionMIPS(ex, 0x0000000000000000)
+
+val ERETHook : unit -> unit
+function ERETHook() = ()
+
+function init_cp2_state () = skip_wreg()
+function cp2_next_pc() = {skip_wreg(); skip_rreg()}
+function dump_cp2_state () = {skip_rreg(); skip_escape();}
diff --git a/mips/prelude.sail b/mips/prelude.sail
new file mode 100644
index 00000000..5b89521f
--- /dev/null
+++ b/mips/prelude.sail
@@ -0,0 +1,391 @@
+default Order dec
+
+type bits ('n : Int) = vector('n, dec, bit)
+union option ('a : Type) = {None : unit, Some : 'a}
+
+val eq_vec = {ocaml: "eq_list", lem: "eq_vec"} : forall 'n. (bits('n), bits('n)) -> bool
+
+val eq_string = {ocaml: "eq_string", lem: "eq"} : (string, string) -> bool
+
+val eq_real = {ocaml: "eq_real", lem: "eq"} : (real, real) -> bool
+
+val eq_anything = {ocaml: "(fun (x, y) -> x = y)", lem: "eq"} : forall ('a : Type). ('a, 'a) -> bool
+
+val bitvector_length = {ocaml: "length", lem: "length"} : forall 'n. bits('n) -> atom('n)
+val vector_length = {ocaml: "length", lem: "length_list"} : forall 'n ('a : Type). vector('n, dec, 'a) -> atom('n)
+val list_length = {ocaml: "length", lem: "length_list"} : forall ('a : Type). list('a) -> int
+
+overload length = {bitvector_length, vector_length, list_length}
+
+val "reg_deref" : forall ('a : Type). register('a) -> 'a effect {rreg}
+/* sneaky deref with no effect necessary for bitfield writes */
+val _reg_deref = "reg_deref" : forall ('a : Type). register('a) -> 'a
+
+overload operator == = {eq_atom, eq_int, eq_vec, eq_string, eq_real, eq_anything}
+
+val vector_subrange = {ocaml: "subrange", lem: "subrange_vec_dec"} : forall ('n : Int) ('m : Int) ('o : Int), 'o <= 'm <= 'n.
+ (bits('n), atom('m), atom('o)) -> bits('m - ('o - 1))
+
+val bitvector_access = {ocaml: "access", lem: "access_vec_dec"} : forall ('n : Int) ('m : Int), 0 <= 'm < 'n.
+ (bits('n), atom('m)) -> bit
+
+val any_vector_access = {ocaml: "access", lem: "access_list_dec"} : forall ('n : Int) ('m : Int) ('a : Type), 0 <= 'm < 'n.
+ (vector('n, dec, 'a), atom('m)) -> 'a
+
+overload vector_access = {bitvector_access, any_vector_access}
+
+val bitvector_update = {ocaml: "update", lem: "update_vec_dec"} : forall 'n.
+ (bits('n), int, bit) -> bits('n)
+
+val any_vector_update = {ocaml: "update", lem: "update_list_dec"} : forall 'n ('a : Type).
+ (vector('n, dec, 'a), int, 'a) -> vector('n, dec, 'a)
+
+overload vector_update = {bitvector_update, any_vector_update}
+
+val update_subrange = {ocaml: "update_subrange", lem: "update_subrange_vec_dec"} : forall 'n 'm 'o.
+ (bits('n), atom('m), atom('o), bits('m - ('o - 1))) -> bits('n)
+
+val vcons = {lem: "cons_vec"} : forall ('n : Int) ('a : Type).
+ ('a, vector('n, dec, 'a)) -> vector('n + 1, dec, 'a)
+
+val bitvector_concat = {ocaml: "append", lem: "concat_vec"} : forall ('n : Int) ('m : Int).
+ (bits('n), bits('m)) -> bits('n + 'm)
+
+val vector_concat = {ocaml: "append", lem: "append_list"} : forall ('n : Int) ('m : Int) ('a : Type).
+ (vector('n, dec, 'a), vector('m, dec, 'a)) -> vector('n + 'm, dec, 'a)
+
+overload append = {bitvector_concat, vector_concat}
+
+val not_vec = "not_vec" : forall 'n. bits('n) -> bits('n)
+
+overload ~ = {not_bool, not_vec}
+
+val not = "not" : bool -> bool
+
+val neq_vec = {lem: "neq"} : forall 'n. (bits('n), bits('n)) -> bool
+function neq_vec (x, y) = not_bool(eq_vec(x, y))
+
+val neq_anything = {lem: "neq"} : forall ('a : Type). ('a, 'a) -> bool
+function neq_anything (x, y) = not_bool(x == y)
+
+overload operator != = {neq_atom, neq_int, neq_vec, neq_anything}
+
+val builtin_and_vec = {ocaml: "and_vec"} : forall 'n. (bits('n), bits('n)) -> bits('n)
+
+val and_vec = {lem: "and_vec"} : forall 'n. (bits('n), bits('n)) -> bits('n)
+
+function and_vec (xs, ys) = builtin_and_vec(xs, ys)
+
+overload operator & = {and_bool, and_vec}
+
+val builtin_or_vec = {ocaml: "or_vec"} : forall 'n. (bits('n), bits('n)) -> bits('n)
+
+val or_vec = {lem: "or_vec"} : forall 'n. (bits('n), bits('n)) -> bits('n)
+
+function or_vec (xs, ys) = builtin_or_vec(xs, ys)
+
+overload operator | = {or_bool, or_vec}
+
+val unsigned = {ocaml: "uint", lem: "unsigned"} : forall 'n. bits('n) -> range(0, 2 ^ 'n - 1)
+
+val signed = {ocaml: "sint", lem: "signed"} : forall 'n. bits('n) -> range(- (2 ^ ('n - 1)), 2 ^ ('n - 1) - 1)
+
+val hex_slice = "hex_slice" : forall 'n 'm. (string, atom('n), atom('m)) -> bits('n - 'm)
+
+val __SetSlice_bits = "set_slice" : forall 'n 'm.
+ (atom('n), atom('m), bits('n), int, bits('m)) -> bits('n)
+
+val __SetSlice_int = "set_slice_int" : forall 'w. (atom('w), int, int, bits('w)) -> int
+
+val __raw_SetSlice_int : forall 'w. (atom('w), int, int, bits('w)) -> int
+
+val __raw_GetSlice_int = "get_slice_int" : forall 'w. (atom('w), int, int) -> bits('w)
+
+val __GetSlice_int : forall 'n. (atom('n), int, int) -> bits('n)
+
+function __GetSlice_int (n, m, o) = __raw_GetSlice_int(n, m, o)
+
+val __raw_SetSlice_bits : forall 'n 'w.
+ (atom('n), atom('w), bits('n), int, bits('w)) -> bits('n)
+
+val __raw_GetSlice_bits : forall 'n 'w.
+ (atom('n), atom('w), bits('n), int) -> bits('w)
+
+val __SignExtendSlice = {lem: "exts_slice"} : forall 'm. (bits('m), int, int) -> bits('m)
+
+val __ZeroExtendSlice = {lem: "extz_slice"} : forall 'm. (bits('m), int, int) -> bits('m)
+
+val cast cast_unit_vec : bit -> bits(1)
+
+function cast_unit_vec bitzero = 0b0
+and cast_unit_vec bitone = 0b1
+
+val print = "prerr_endline" : string -> unit
+
+val putchar = "putchar" : forall ('a : Type). 'a -> unit
+
+val concat_str = {ocaml: "concat_str", lem: "stringAppend"} : (string, string) -> string
+
+val string_of_int = "string_of_int" : int -> string
+
+val DecStr : int -> string
+
+val HexStr : int -> string
+
+val BitStr = "string_of_bits" : forall 'n. bits('n) -> string
+
+val xor_vec = "xor_vec" : forall 'n. (bits('n), bits('n)) -> bits('n)
+
+val int_power = {ocaml: "int_power", lem: "pow"} : (int, int) -> int
+
+val real_power = {ocaml: "real_power", lem: "realPowInteger"} : (real, int) -> real
+
+overload operator ^ = {xor_vec, int_power, real_power}
+
+val add_range = {ocaml: "add_int", lem: "integerAdd"} : forall 'n 'm 'o 'p.
+ (range('n, 'm), range('o, 'p)) -> range('n + 'o, 'm + 'p)
+
+val add_int = {ocaml: "add_int", lem: "integerAdd"} : (int, int) -> int
+
+val add_vec = "add_vec" : forall 'n. (bits('n), bits('n)) -> bits('n)
+
+val add_vec_int = "add_vec_int" : forall 'n. (bits('n), int) -> bits('n)
+
+val add_real = {ocaml: "add_real", lem: "realAdd"} : (real, real) -> real
+
+overload operator + = {add_range, add_int, add_vec, add_vec_int, add_real}
+
+val sub_range = {ocaml: "sub_int", lem: "integerMinus"} : forall 'n 'm 'o 'p.
+ (range('n, 'm), range('o, 'p)) -> range('n - 'p, 'm - 'o)
+
+val sub_int = {ocaml: "sub_int", lem: "integerMinus"} : (int, int) -> int
+
+val "sub_vec" : forall 'n. (bits('n), bits('n)) -> bits('n)
+
+val "sub_vec_int" : forall 'n. (bits('n), int) -> bits('n)
+
+val sub_real = {ocaml: "sub_real", lem: "realMinus"} : (real, real) -> real
+
+val negate_range = {ocaml: "minus_big_int", lem: "integerNegate"} : forall 'n 'm. range('n, 'm) -> range(- 'm, - 'n)
+
+val negate_int = {ocaml: "minus_big_int", lem: "integerNegate"} : int -> int
+
+val negate_real = {ocaml: "Num.minus_num", lem: "realNegate"} : real -> real
+
+overload operator - = {sub_range, sub_int, sub_vec, sub_vec_int, sub_real}
+
+overload negate = {negate_range, negate_int, negate_real}
+
+val mult_range = {ocaml: "mult", lem: "integerMult"} : forall 'n 'm 'o 'p.
+ (range('n, 'm), range('o, 'p)) -> range('n * 'o, 'm * 'p)
+
+val mult_int = {ocaml: "mult", lem: "integerMult"} : (int, int) -> int
+
+val mult_real = {ocaml: "mult_real", lem: "realMult"} : (real, real) -> real
+
+overload operator * = {mult_range, mult_int, mult_real}
+
+val Sqrt = {ocaml: "sqrt_real", lem: "realSqrt"} : real -> real
+
+val gteq_real = {ocaml: "gteq_real", lem: "gteq"} : (real, real) -> bool
+
+overload operator >= = {gteq_atom, gteq_int, gteq_real}
+
+val lteq_real = {ocaml: "lteq_real", lem: "lteq"} : (real, real) -> bool
+
+overload operator <= = {lteq_atom, lteq_int, lteq_real}
+
+val gt_real = {ocaml: "gt_real", lem: "gt"} : (real, real) -> bool
+
+overload operator > = {gt_atom, gt_int, gt_real}
+
+val lt_real = {ocaml: "lt_real", lem: "lt"} : (real, real) -> bool
+
+overload operator < = {lt_atom, lt_int, lt_real}
+
+val RoundDown = {ocaml: "round_down", lem: "realFloor"} : real -> int
+
+val RoundUp = {ocaml: "round_up", lem: "realCeiling"} : real -> int
+
+val abs_int = {ocaml: "abs_int", lem: "abs"} : int -> int
+
+val abs_real = {ocaml: "abs_real", lem: "abs"} : real -> real
+
+overload abs = {abs_int, abs_real}
+
+val quotient_nat = {ocaml: "quotient", lem: "integerDiv"} : (nat, nat) -> nat
+
+val quotient_real = {ocaml: "quotient_real", lem: "realDiv"} : (real, real) -> real
+
+val quotient = {ocaml: "quotient", lem: "integerDiv"} : (int, int) -> int
+
+overload operator / = {quotient_nat, quotient, quotient_real}
+
+val quot_round_zero = {ocaml: "quot_round_zero", lem: "hardware_quot"} : (int, int) -> int
+val rem_round_zero = {ocaml: "rem_round_zero", lem: "hardware_mod"} : (int, int) -> int
+
+val modulus = {ocaml: "modulus", lem: "hardware_mod"} : forall 'n, 'n > 0 . (int, atom('n)) -> range(0, 'n - 1)
+
+overload operator % = {modulus}
+
+val Real = {ocaml: "Num.num_of_big_int", lem: "realFromInteger"} : int -> real
+
+val shl_int = "shl_int" : (int, int) -> int
+
+val shr_int = "shr_int" : (int, int) -> int
+
+val min_nat = {ocaml: "min_int", lem: "min"} : (nat, nat) -> nat
+
+val min_int = {ocaml: "min_int", lem: "min"} : (int, int) -> int
+
+val max_nat = {ocaml: "max_int", lem: "max"} : (nat, nat) -> nat
+
+val max_int = {ocaml: "max_int", lem: "max"} : (int, int) -> int
+
+val min_atom = {ocaml: "min_int", lem: "min"} : forall 'a 'b . (atom('a), atom('b)) -> {'c, ('c = 'a | 'c = 'b) & 'c <= 'a & 'c <= 'b . atom('c)}
+
+val max_atom = {ocaml: "max_int", lem: "max"} : forall 'a 'b . (atom('a), atom('b)) -> {'c, ('c = 'a | 'c = 'b) & 'c >= 'a & 'c >= 'b . atom('c)}
+
+overload min = {min_atom, min_nat, min_int}
+
+overload max = {max_atom, max_nat, max_int}
+
+val __WriteRAM = "write_ram" : forall 'n 'm.
+ (atom('m), atom('n), bits('m), bits('m), bits(8 * 'n)) -> unit effect {wmv}
+
+val __MIPS_write : forall 'n. (bits(64), atom('n), bits(8 * 'n)) -> unit effect {wmv}
+function __MIPS_write (addr, width, data) = __WriteRAM(64, width, 0x0000_0000_0000_0000, addr, data)
+
+val __TraceMemoryWrite : forall 'n 'm.
+ (atom('n), bits('m), bits(8 * 'n)) -> unit
+
+val __ReadRAM = "read_ram" : forall 'n 'm.
+ (atom('m), atom('n), bits('m), bits('m)) -> bits(8 * 'n) effect {rmem}
+
+val __MIPS_read : forall 'n. (bits(64), atom('n)) -> bits(8 * 'n) effect {rmem}
+function __MIPS_read (addr, width) = __ReadRAM(64, width, 0x0000_0000_0000_0000, addr)
+
+val __TraceMemoryRead : forall 'n 'm. (atom('n), bits('m), bits(8 * 'n)) -> unit
+
+val replicate_bits = "replicate_bits" : forall 'n 'm. (bits('n), atom('m)) -> bits('n * 'm)
+
+infix 8 ^^
+val operator ^^ = {lem: "replicate_bits"} : forall 'n 'm . (bits('n), atom('m)) -> bits('n * 'm)
+function operator ^^ (bs, n) = replicate_bits (bs, n)
+
+val cast ex_nat : nat -> {'n, 'n >= 0. atom('n)}
+
+function ex_nat 'n = n
+
+val cast ex_int : int -> {'n, true. atom('n)}
+
+function ex_int 'n = n
+
+/*
+val cast ex_range : forall 'n 'm. range('n, 'm) -> {'o, 'n <= 'o <= 'm. atom('o)}
+
+function ex_range (n as 'N) = n
+*/
+
+val coerce_int_nat : int -> nat effect {escape}
+
+function coerce_int_nat 'x = {
+ assert(constraint('x >= 0));
+ x
+}
+
+val slice = "slice" : forall ('n : Int) ('m : Int), 'm >= 0 & 'n >= 0.
+ (bits('m), int, atom('n)) -> bits('n)
+
+val pow2 = "pow2" : forall 'n. atom('n) -> atom(2 ^ 'n)
+
+val print_int = "print_int" : (string, int) -> unit
+val print_bits = "print_bits" : forall 'n. (string, bits('n)) -> unit
+val print_string = "print_string" : (string, string) -> unit
+
+union exception = {
+ ISAException : unit,
+ Error_not_implemented : string,
+ Error_misaligned_access : unit,
+ Error_EBREAK : unit,
+ Error_internal_error : unit
+}
+
+val "sign_extend" : forall 'n 'm, 'm >= 'n. (bits('n), atom('m)) -> bits('m)
+val "zero_extend" : forall 'n 'm, 'm >= 'n. (bits('n), atom('m)) -> bits('m)
+
+val EXTS : forall 'n 'm , 'm >= 'n . bits('n) -> bits('m)
+val EXTZ : forall 'n 'm , 'm >= 'n . bits('n) -> bits('m)
+
+function EXTS v = sign_extend(v, sizeof('m))
+function EXTZ v = zero_extend(v, sizeof('m))
+
+val zeros : forall 'n, 'n >= 0 . unit -> bits('n)
+function zeros() = replicate_bits (0b0,'n)
+
+val ones : forall 'n, 'n >= 0 . unit -> bits('n)
+function ones() = replicate_bits (0b1,'n)
+
+infix 4 <_s
+infix 4 >=_s
+infix 4 <_u
+infix 4 >=_u
+
+val operator <_s = {lem: "slt_vec"} : forall 'n. (bits('n), bits('n)) -> bool
+val operator >=_s = {lem: "sgteq_vec"} : forall 'n. (bits('n), bits('n)) -> bool
+val operator <_u = {lem: "ult_vec"} : forall 'n. (bits('n), bits('n)) -> bool
+val operator >=_u = {lem: "ugteq_vec"} : forall 'n. (bits('n), bits('n)) -> bool
+
+function operator <_s (x, y) = signed(x) < signed(y)
+function operator >=_s (x, y) = signed(x) >= signed(y)
+function operator <_u (x, y) = unsigned(x) < unsigned(y)
+function operator >=_u (x, y) = unsigned(x) >= unsigned(y)
+
+val cast bool_to_bits : bool -> bits(1)
+function bool_to_bits x = if x then 0b1 else 0b0
+
+val cast bit_to_bool : bit -> bool
+function bit_to_bool bitone = true
+and bit_to_bool bitzero = false
+
+val cast bits_to_bool : bits(1) -> bool
+function bits_to_bool x = bit_to_bool(x[0])
+
+infix 1 >>
+infix 1 <<
+infix 1 >>_s
+
+val "shift_bits_right" : forall 'n 'm. (bits('n), bits('m)) -> bits('n)
+val "shift_bits_left" : forall 'n 'm. (bits('n), bits('m)) -> bits('n)
+
+val "shiftl" : forall 'm 'n, 'n >= 0. (bits('m), atom('n)) -> bits('m)
+val "shiftr" : forall 'm 'n, 'n >= 0. (bits('m), atom('n)) -> bits('m)
+
+overload operator >> = {shift_bits_right, shiftr}
+overload operator << = {shift_bits_left, shiftl}
+val operator >>_s = "shift_bits_right_arith" : forall 'n 'm. (bits('n), bits('m)) -> bits('n)
+
+infix 7 *_s
+val operator *_s = "smult_vec" : forall 'n . (bits('n), bits('n)) -> bits(2 * 'n)
+infix 7 *_u
+val operator *_u = "mult_vec" : forall 'n . (bits('n), bits('n)) -> bits(2 * 'n)
+
+val vector64 : int -> bits(64)
+
+function vector64 n = __raw_GetSlice_int(64, n, 0)
+
+val to_bits : forall 'l.(atom('l), int) -> bits('l)
+function to_bits (l, n) = __raw_GetSlice_int(l, n, 0)
+
+function break () : unit -> unit = ()
+
+val vector_update_subrange_dec = {ocaml: "update_subrange", lem: "update_subrange_vec_dec"} : forall 'n 'm 'o.
+ (bits('n), atom('m), atom('o), bits('m - ('o - 1))) -> bits('n)
+
+val vector_update_subrange_inc = {ocaml: "update_subrange", lem: "update_subrange_vec_inc"} : forall 'n 'm 'o.
+ (vector('n, inc, bit), atom('m), atom('o), vector('o - ('m - 1), inc, bit)) -> vector('n, inc, bit)
+
+overload vector_update_subrange = {vector_update_subrange_dec, vector_update_subrange_inc}
+
+val mask : forall 'm 'n , 'm >= 'n > 0 . bits('m) -> bits('n)
+function mask bs = bs['n - 1 .. 0]