diff options
| -rw-r--r-- | lib/isabelle/Makefile | 6 | ||||
| -rw-r--r-- | lib/isabelle/Prompt_monad_extras.thy | 171 | ||||
| -rw-r--r-- | lib/isabelle/State_monad_extras.thy | 4 | ||||
| -rw-r--r-- | riscv/riscv_extras_embed_sequential.lem | 2 | ||||
| -rw-r--r-- | src/ast_util.ml | 44 | ||||
| -rw-r--r-- | src/ast_util.mli | 5 | ||||
| -rw-r--r-- | src/gen_lib/prompt.lem | 40 | ||||
| -rw-r--r-- | src/gen_lib/prompt_monad.lem | 204 | ||||
| -rw-r--r-- | src/gen_lib/sail_operators.lem | 1 | ||||
| -rw-r--r-- | src/gen_lib/sail_operators_bitlists.lem | 1 | ||||
| -rw-r--r-- | src/gen_lib/sail_operators_mwords.lem | 1 | ||||
| -rw-r--r-- | src/gen_lib/sail_values.lem | 126 | ||||
| -rw-r--r-- | src/gen_lib/state.lem | 1 | ||||
| -rw-r--r-- | src/gen_lib/state_monad.lem | 56 | ||||
| -rw-r--r-- | src/lem_interp/sail_impl_base.lem | 373 | ||||
| -rw-r--r-- | src/lem_interp/sail_instr_kinds.lem | 436 | ||||
| -rw-r--r-- | src/pretty_print_lem.ml | 184 | ||||
| -rw-r--r-- | src/process_file.ml | 2 | ||||
| -rw-r--r-- | src/sail.ml | 7 | ||||
| -rw-r--r-- | src/state.ml | 279 |
20 files changed, 1102 insertions, 841 deletions
diff --git a/lib/isabelle/Makefile b/lib/isabelle/Makefile index 84af5d75..50e6d471 100644 --- a/lib/isabelle/Makefile +++ b/lib/isabelle/Makefile @@ -1,4 +1,4 @@ -THYS = Sail_impl_base.thy Sail_values.thy Sail_operators.thy \ +THYS = Sail_instr_kinds.thy Sail_values.thy Sail_operators.thy \ Sail_operators_mwords.thy Sail_operators_bitlists.thy \ State_monad.thy State.thy Prompt_monad.thy Prompt.thy EXTRA_THYS = State_monad_extras.thy Prompt_monad_extras.thy @@ -14,10 +14,10 @@ heap-img: $(THYS) $(EXTRA_THYS) ROOT @echo '*** and add the isabelle binary to your PATH.' isabelle build -b Sail -Sail_impl_base.thy: ../../src/lem_interp/sail_impl_base.lem +Sail_instr_kinds.thy: ../../src/lem_interp/sail_instr_kinds.lem lem -isa -outdir . -lib ../../src/lem_interp -lib ../../src/gen_lib $< -Sail_values.thy: ../../src/gen_lib/sail_values.lem Sail_impl_base.thy +Sail_values.thy: ../../src/gen_lib/sail_values.lem Sail_instr_kinds.thy lem -isa -outdir . -lib ../../src/lem_interp -lib ../../src/gen_lib $< Sail_operators.thy: ../../src/gen_lib/sail_operators.lem Sail_values.thy diff --git a/lib/isabelle/Prompt_monad_extras.thy b/lib/isabelle/Prompt_monad_extras.thy index 0c319f97..e93c6052 100644 --- a/lib/isabelle/Prompt_monad_extras.thy +++ b/lib/isabelle/Prompt_monad_extras.thy @@ -2,60 +2,50 @@ theory Prompt_monad_extras imports Prompt_monad begin -lemma All_bind_dom: "bind_dom (oc, f)" - by (induction oc) (auto intro: bind.domintros; blast intro: bind.domintros)+ +lemma All_bind_dom: "bind_dom (m, f)" + by (induction m) (auto intro: bind.domintros) termination bind using All_bind_dom by auto +lemmas bind_induct[case_names Done Read_mem Write_memv Read_reg Excl_res Write_ea Barrier Write_reg Fail Error Exception] = bind.induct -lemma bind_induct[case_names Done Read_mem Read_reg Write_memv Excl_res Write_ea Barrier Footprint Write_reg Escape Fail Error Exception Internal]: - fixes m :: "('a, 'e) outcome" and f :: "'a \<Rightarrow> ('b, 'e) outcome" - assumes "\<And>a f. P (Done a) f" - and "\<And>rk addr sz k f. (\<And>v m' opt. (m', opt) = k v \<Longrightarrow> P m' f) \<Longrightarrow> P (Read_mem (rk, addr, sz) k) f" - and "\<And>reg k f. (\<And>v m' opt. (m', opt) = k v \<Longrightarrow> P m' f) \<Longrightarrow> P (Read_reg reg k) f" - and "\<And>val k f. (\<And>v m' opt. (m', opt) = k v \<Longrightarrow> P m' f) \<Longrightarrow> P (Write_memv val k) f" - and "\<And>k f. (\<And>v m' opt. (m', opt) = k v \<Longrightarrow> P m' f) \<Longrightarrow> P (Excl_res k) f" - and "\<And>wk addr sz m opt f. P m f \<Longrightarrow> P (Write_ea (wk, addr, sz) (m, opt)) f" - and "\<And>bk m opt f. P m f \<Longrightarrow> P (Barrier bk (m, opt)) f" - and "\<And>m opt f. P m f \<Longrightarrow> P (Footprint (m, opt)) f" - and "\<And>reg val m opt f. P m f \<Longrightarrow> P (Write_reg (reg, val) (m, opt)) f" - and "\<And>descr f. P (Escape descr) f" - and "\<And>descr f. P (Fail descr) f" and "\<And>descr f. P (Error descr) f" and "\<And>e f. P (Exception e) f" - and "\<And>i m opt f. P m f \<Longrightarrow> P (Internal i (m, opt)) f" - shows "P m f" - by (rule bind.induct[split_format (complete), OF assms]; blast) - -datatype event = +lemma bind_return[simp]: "bind (return a) f = f a" + by (auto simp: return_def) + +lemma bind_assoc[simp]: "bind (bind m f) g = bind m (\<lambda>x. bind (f x) g)" + by (induction m f arbitrary: g rule: bind.induct) auto + +lemma All_try_catch_dom: "try_catch_dom (m, h)" + by (induction m) (auto intro: try_catch.domintros) +termination try_catch using All_try_catch_dom by auto +lemmas try_catch_induct[case_names Done Read_mem Write_memv Read_reg Excl_res Write_ea Barrier Write_reg Fail Error Exception] = try_catch.induct + +datatype 'regval event = (* Request to read memory *) - Read_mem read_kind address_lifted nat memory_value + e_read_mem read_kind int int "memory_byte list" (* Write is imminent, at address lifted, of size nat *) - | Write_ea write_kind address_lifted nat + | e_write_ea write_kind int int (* Request the result of store-exclusive *) - | Excl_res bool + | e_excl_res bool (* Request to write memory at last signalled address. Memory value should be 8 times the size given in ea signal *) - | Write_memv memory_value bool + | e_write_memv "memory_byte list" bool (* Request a memory barrier *) - | Barrier " barrier_kind " - (* Tell the system to dynamically recalculate dependency footprint *) - | Footprint + | e_barrier " barrier_kind " (* Request to read register *) - | Read_reg reg_name register_value + | e_read_reg string 'regval (* Request to write register *) - | Write_reg reg_name register_value - | Internal " ( string option * (unit \<Rightarrow> string)option) " - -inductive_set T :: "(('a, 'e)outcome \<times> event \<times> ('a, 'e)outcome) set" where - Read_mem: "\<exists>opt. k v = (m, opt) \<Longrightarrow> ((outcome.Read_mem (rk, addr, sz) k), Read_mem rk addr sz v, m) \<in> T" -| Write_ea: "\<exists>opt. k = (m, opt) \<Longrightarrow> ((outcome.Write_ea (rk, addr, sz) k), Write_ea rk addr sz, m) \<in> T" -| Excl_res: "\<exists>opt. k r = (m, opt) \<Longrightarrow> ((outcome.Excl_res k), Excl_res r, m) \<in> T" -| Write_memv: "\<exists>opt. k r = (m, opt) \<Longrightarrow> ((outcome.Write_memv v k), Write_memv v r, m) \<in> T" -| Barrier: "\<exists>opt. k = (m, opt) \<Longrightarrow> ((outcome.Barrier bk k), Barrier bk, m) \<in> T" -| Footprint: "\<exists>opt. k = (m, opt) \<Longrightarrow> ((outcome.Footprint k), Footprint, m) \<in> T" -| Read_reg: "\<exists>opt. k v = (m, opt) \<Longrightarrow> ((outcome.Read_reg r k), Read_reg r v, m) \<in> T" -| Write_reg: "\<exists>opt. k = (m, opt) \<Longrightarrow> ((outcome.Write_reg (r, v) k), Write_reg r v, m) \<in> T" -| Internal: "\<exists>opt. k = (m, opt) \<Longrightarrow> ((outcome.Internal descr k), Internal descr, m) \<in> T" - -inductive_set Traces :: "(('a, 'r)outcome \<times> event list \<times> ('a, 'r)outcome) set" where + | e_write_reg string 'regval + +inductive_set T :: "(('rv, 'a, 'e) monad \<times> 'rv event \<times> ('rv, 'a, 'e) monad) set" where + Read_mem: "((Read_mem rk addr sz k), e_read_mem rk addr sz v, k v) \<in> T" +| Write_ea: "((Write_ea wk addr sz k), e_write_ea wk addr sz, k) \<in> T" +| Excl_res: "((Excl_res k), e_excl_res r, k r) \<in> T" +| Write_memv: "((Write_memv v k), e_write_memv v r, k r) \<in> T" +| Barrier: "((Barrier bk k), e_barrier bk, k) \<in> T" +| Read_reg: "((Read_reg r k), e_read_reg r v, k v) \<in> T" +| Write_reg: "((Write_reg r v k), e_write_reg r v, k) \<in> T" + +inductive_set Traces :: "(('rv, 'a, 'e) monad \<times> 'rv event list \<times> ('rv, 'a, 'e) monad) set" where Nil: "(s, [], s) \<in> Traces" | Step: "\<lbrakk>(s, e, s'') \<in> T; (s'', t, s') \<in> Traces\<rbrakk> \<Longrightarrow> (s, e # t, s') \<in> Traces" @@ -63,15 +53,13 @@ declare Traces.intros[intro] declare T.intros[intro] declare prod.splits[split] -(* lemma fst_case_bind[simp]: "fst (case k of (o1, x) \<Rightarrow> (bind o1 f, x)) = bind (fst k) f" - by (cases k) auto *) lemmas Traces_ConsI = T.intros[THEN Step, rotated] inductive_cases Traces_NilE[elim]: "(s, [], s') \<in> Traces" inductive_cases Traces_ConsE[elim]: "(s, e # t, s') \<in> Traces" -abbreviation Run :: "('a, 'r)outcome \<Rightarrow> event list \<Rightarrow> 'a \<Rightarrow> bool" +abbreviation Run :: "('rv, 'a, 'e) monad \<Rightarrow> 'rv event list \<Rightarrow> 'a \<Rightarrow> bool" where "Run s t a \<equiv> (s, t, Done a) \<in> Traces" lemma Run_appendI: @@ -84,60 +72,21 @@ proof (use assms in \<open>induction t1 arbitrary: s\<close>) qed auto lemma bind_DoneE: - assumes "bind m f = outcome.Done a" - obtains a' where "m = outcome.Done a'" and "f a' = outcome.Done a" + assumes "bind m f = Done a" + obtains a' where "m = Done a'" and "f a' = Done a" using assms by (auto elim: bind.elims) lemma bind_T_cases: assumes "(bind m f, e, s') \<in> T" obtains (Done) a where "m = Done a" | (Bind) m' where "s' = bind m' f" and "(m, e, m') \<in> T" -proof cases - assume D: "\<forall>a. m \<noteq> Done a" - show thesis using assms proof cases - case (Read_mem k v rk addr sz) - then obtain k' where "m = outcome.Read_mem (rk, addr, sz) k'" using D by (cases m) auto - then show ?thesis using Read_mem by (intro Bind[of "fst (k' v)"]) auto - next - case (Write_ea k rk addr sz) - then obtain k' where "m = outcome.Write_ea (rk, addr, sz) k'" using D by (cases m) auto - then show ?thesis using Write_ea by (intro Bind[of "fst k'"]) auto - next - case (Excl_res k r) - then obtain k' where "m = outcome.Excl_res k'" using D by (cases m) auto - then show ?thesis using Excl_res by (intro Bind[of "fst (k' r)"]) auto - next - case (Write_memv k r v) - then obtain k' where "m = outcome.Write_memv v k'" using D by (cases m) auto - then show ?thesis using Write_memv by (intro Bind[of "fst (k' r)"]) auto - next - case (Barrier k bk) - then obtain k' where "m = outcome.Barrier bk k'" using D by (cases m) auto - then show ?thesis using Barrier by (intro Bind[of "fst k'"]) auto - next - case (Footprint k) - then obtain k' where "m = outcome.Footprint k'" using D by (cases m) auto - then show ?thesis using Footprint by (intro Bind[of "fst k'"]) auto - next - case (Read_reg k v r) - then obtain k' where "m = outcome.Read_reg r k'" using D by (cases m) auto - then show ?thesis using Read_reg by (intro Bind[of "fst (k' v)"]) (auto split: prod.splits) - next - case (Write_reg k r v) - then obtain k' where "m = outcome.Write_reg (r, v) k'" using D by (cases m) auto - then show ?thesis using Write_reg by (intro Bind[of "fst k'"]) auto - next - case (Internal k descr) - then obtain k' where "m = outcome.Internal descr k'" using D by (cases m) auto - then show ?thesis using Internal by (intro Bind[of "fst k'"]) auto - qed -qed auto + using assms by (cases; blast elim: bind.elims) lemma Run_bindE: - fixes m :: "('b, 'r) outcome" and a :: 'a + fixes m :: "('rv, 'b, 'e) monad" and a :: 'a assumes "Run (bind m f) t a" obtains tm am tf where "t = tm @ tf" and "Run m tm am" and "Run (f am) tf a" -proof (use assms in \<open>induction "bind m f" t "Done a :: ('a,'r) outcome" arbitrary: m rule: Traces.induct\<close>) +proof (use assms in \<open>induction "bind m f" t "Done a :: ('rv, 'a, 'e) monad" arbitrary: m rule: Traces.induct\<close>) case Nil obtain am where "m = Done am" and "f am = Done a" using Nil(1) by (elim bind_DoneE) then show ?case by (intro Nil(2)) auto @@ -166,49 +115,15 @@ lemma Run_Done_iff_Nil[simp]: "Run (Done a) t a' \<longleftrightarrow> t = [] \< by (auto elim: Run_DoneE) lemma Run_BarrierE[elim!]: - assumes "Run (outcome.Barrier bk k) t a" - obtains t' where "t = Barrier bk # t'" and "Run (fst k) t' a" + assumes "Run (Barrier bk k) t a" + obtains t' where "t = e_barrier bk # t'" and "Run k t' a" using assms by cases (auto elim: T.cases) lemma bind_cong[fundef_cong]: assumes m: "m1 = m2" and f: "\<And>t a. Run m2 t a \<Longrightarrow> f1 a = f2 a" shows "bind m1 f1 = bind m2 f2" -proof (unfold m, use f in \<open>induction m2 f1 arbitrary: f2 rule: bind_induct\<close>) - case (Read_mem rk addr sz k f) - have "bind m' f = bind m' f2" if k: "k v = (m', opt)" for v m' opt - using k by (auto intro!: Read_mem.IH[of _ opt v] Read_mem.prems) - then show ?case by auto -next - case (Read_reg reg k f) - have "bind m' f = bind m' f2" if k: "k v = (m', opt)" for v m' opt - using k by (auto intro!: Read_reg.IH[of _ opt v] Read_reg.prems) - then show ?case by auto -next - case (Write_memv val k f) - have "bind m' f = bind m' f2" if k: "k v = (m', opt)" for v m' opt - using k by (auto intro!: Write_memv.IH[of _ opt v] Write_memv.prems) - then show ?case by auto -next - case (Excl_res k f) - have "bind m' f = bind m' f2" if k: "k v = (m', opt)" for v m' opt - using k by (auto intro!: Excl_res.IH[of _ opt v] Excl_res.prems) - then show ?case by auto -next - case (Write_ea wk addr sz m opt f) - show ?case by (auto intro!: Write_ea) -next - case (Barrier bk m opt f) - show ?case by (auto intro!: Barrier) -next - case (Footprint m opt f) - show ?case by (auto intro!: Footprint) -next - case (Write_reg reg val m opt f) - show ?case by (auto intro!: Write_reg) -next - case (Internal i m opt f) - show ?case by (auto intro!: Internal) -qed auto + unfolding m using f + by (induction m2 f1 arbitrary: f2 rule: bind.induct; unfold bind.simps; blast) end diff --git a/lib/isabelle/State_monad_extras.thy b/lib/isabelle/State_monad_extras.thy index c9522f58..cf042a02 100644 --- a/lib/isabelle/State_monad_extras.thy +++ b/lib/isabelle/State_monad_extras.thy @@ -7,8 +7,8 @@ lemma bind_ext_cong[fundef_cong]: and f: "\<And>a s'. (Value a, s') \<in> set (m2 s) \<Longrightarrow> f1 a s' = f2 a s'" shows "(bind m1 f1) s = (bind m2 f2) s" proof - - have "List.concat (map (\<lambda>x. case x of (Value a, s') \<Rightarrow> f1 a s' | (Exception0 e, s') \<Rightarrow> [(Exception0 e, s')]) (m2 s)) = - List.concat (map (\<lambda>x. case x of (Value a, s') \<Rightarrow> f2 a s' | (Exception0 e, s') \<Rightarrow> [(Exception0 e, s')]) (m2 s))" + have "List.concat (map (\<lambda>x. case x of (Value a, s') \<Rightarrow> f1 a s' | (Exception e, s') \<Rightarrow> [(Exception e, s')]) (m2 s)) = + List.concat (map (\<lambda>x. case x of (Value a, s') \<Rightarrow> f2 a s' | (Exception e, s') \<Rightarrow> [(Exception e, s')]) (m2 s))" using f by (intro arg_cong[where f = List.concat]) (auto intro: map_ext split: result.splits) then show ?thesis using m by (auto simp: bind_def) qed diff --git a/riscv/riscv_extras_embed_sequential.lem b/riscv/riscv_extras_embed_sequential.lem index cc2a5277..31eea6ab 100644 --- a/riscv/riscv_extras_embed_sequential.lem +++ b/riscv/riscv_extras_embed_sequential.lem @@ -1,6 +1,6 @@ open import Pervasives open import Pervasives_extra -open import Sail_impl_base +open import Sail_instr_kinds open import Sail_values open import Sail_operators_mwords open import State diff --git a/src/ast_util.ml b/src/ast_util.ml index 7f660745..27ae93e8 100644 --- a/src/ast_util.ml +++ b/src/ast_util.ml @@ -712,6 +712,21 @@ let rec string_of_index_range (BF_aux (ir, _)) = | BF_range (n, m) -> Big_int.to_string n ^ " .. " ^ Big_int.to_string m | BF_concat (ir1, ir2) -> "(" ^ string_of_index_range ir1 ^ ") : (" ^ string_of_index_range ir2 ^ ")" + +let rec pat_ids (P_aux (pat_aux, _)) = + match pat_aux with + | P_lit _ | P_wild -> IdSet.empty + | P_id id -> IdSet.singleton id + | P_as (pat, id) -> IdSet.add id (pat_ids pat) + | P_var (pat, _) | P_typ (_, pat) -> pat_ids pat + | P_app (_, pats) | P_tup pats | P_vector pats | P_vector_concat pats | P_list pats -> + List.fold_right IdSet.union (List.map pat_ids pats) IdSet.empty + | P_cons (pat1, pat2) -> + IdSet.union (pat_ids pat1) (pat_ids pat2) + | P_record (fpats, _) -> + List.fold_right IdSet.union (List.map fpat_ids fpats) IdSet.empty +and fpat_ids (FP_aux (FP_Fpat (_, pat), _)) = pat_ids pat + let id_of_fundef (FD_aux (FD_function (_, _, _, funcls), (l, _))) = match (List.fold_right (fun (FCL_aux (FCL_Funcl (id, _), _)) id' -> @@ -733,6 +748,20 @@ let id_of_type_def_aux = function | TD_bitfield (id, _, _) -> id let id_of_type_def (TD_aux (td_aux, _)) = id_of_type_def_aux td_aux +let id_of_val_spec (VS_aux (VS_val_spec (_, id, _, _), _)) = id + +let ids_of_def = function + | DEF_kind (KD_aux (KD_nabbrev (_, id, _, _), _)) -> IdSet.singleton id + | DEF_type td -> IdSet.singleton (id_of_type_def td) + | DEF_fundef fd -> IdSet.singleton (id_of_fundef fd) + | DEF_val (LB_aux (LB_val (pat, _), _)) -> pat_ids pat + | DEF_reg_dec (DEC_aux (DEC_reg (_, id), _)) -> IdSet.singleton id + | DEF_spec vs -> IdSet.singleton (id_of_val_spec vs) + | DEF_internal_mutrec fds -> IdSet.of_list (List.map id_of_fundef fds) + | _ -> IdSet.empty +let ids_of_defs (Defs defs) = + List.fold_left IdSet.union IdSet.empty (List.map ids_of_def defs) + module BE = struct type t = base_effect let compare be1 be2 = String.compare (string_of_base_effect be1) (string_of_base_effect be2) @@ -965,26 +994,13 @@ let split_defs f (Defs defs) = Some (Defs (List.rev pre_defs), def, Defs post_defs) let append_ast (Defs ast1) (Defs ast2) = Defs (ast1 @ ast2) +let concat_ast asts = List.fold_right append_ast asts (Defs []) let type_union_id (Tu_aux (aux, _)) = match aux with | Tu_id id -> id | Tu_ty_id (_, id) -> id -let rec pat_ids (P_aux (pat_aux, _)) = - match pat_aux with - | P_lit _ | P_wild -> IdSet.empty - | P_id id -> IdSet.singleton id - | P_as (pat, id) -> IdSet.add id (pat_ids pat) - | P_var (pat, _) | P_typ (_, pat) -> pat_ids pat - | P_app (_, pats) | P_tup pats | P_vector pats | P_vector_concat pats | P_list pats -> - List.fold_right IdSet.union (List.map pat_ids pats) IdSet.empty - | P_cons (pat1, pat2) -> - IdSet.union (pat_ids pat1) (pat_ids pat2) - | P_record (fpats, _) -> - List.fold_right IdSet.union (List.map fpat_ids fpats) IdSet.empty -and fpat_ids (FP_aux (FP_Fpat (_, pat), _)) = pat_ids pat - let rec subst id value (E_aux (e_aux, annot) as exp) = let wrap e_aux = E_aux (e_aux, annot) in let e_aux = match e_aux with diff --git a/src/ast_util.mli b/src/ast_util.mli index bc2181e8..bbbde27f 100644 --- a/src/ast_util.mli +++ b/src/ast_util.mli @@ -211,6 +211,7 @@ val string_of_index_range : index_range -> string val id_of_fundef : 'a fundef -> id val id_of_type_def : 'a type_def -> id +val id_of_val_spec : 'a val_spec -> id val id_of_kid : kid -> id val kid_of_id : id -> kid @@ -306,8 +307,12 @@ val rename_fundef : id -> 'a fundef -> 'a fundef val split_defs : ('a def -> bool) -> 'a defs -> ('a defs * 'a def * 'a defs) option val append_ast : 'a defs -> 'a defs -> 'a defs +val concat_ast : 'a defs list -> 'a defs val type_union_id : type_union -> id +val ids_of_def : 'a def -> IdSet.t +val ids_of_defs : 'a defs -> IdSet.t + val pat_ids : 'a pat -> IdSet.t val subst : id -> 'a exp -> 'a exp -> 'a exp diff --git a/src/gen_lib/prompt.lem b/src/gen_lib/prompt.lem index d398ab52..756bb699 100644 --- a/src/gen_lib/prompt.lem +++ b/src/gen_lib/prompt.lem @@ -1,24 +1,24 @@ open import Pervasives_extra -open import Sail_impl_base +(*open import Sail_impl_base*) open import Sail_values open import Prompt_monad open import {isabelle} `Prompt_monad_extras` -val iter_aux : forall 'a 'e. integer -> (integer -> 'a -> M unit 'e) -> list 'a -> M unit 'e +val iter_aux : forall 'rv 'a 'e. integer -> (integer -> 'a -> monad 'rv unit 'e) -> list 'a -> monad 'rv unit 'e let rec iter_aux i f xs = match xs with | x :: xs -> f i x >> iter_aux (i + 1) f xs | [] -> return () end -val iteri : forall 'a 'e. (integer -> 'a -> M unit 'e) -> list 'a -> M unit 'e +val iteri : forall 'rv 'a 'e. (integer -> 'a -> monad 'rv unit 'e) -> list 'a -> monad 'rv unit 'e let iteri f xs = iter_aux 0 f xs -val iter : forall 'a 'e. ('a -> M unit 'e) -> list 'a -> M unit 'e +val iter : forall 'rv 'a 'e. ('a -> monad 'rv unit 'e) -> list 'a -> monad 'rv unit 'e let iter f xs = iteri (fun _ x -> f x) xs -val foreachM_inc : forall 'vars 'e. (integer * integer * integer) -> 'vars -> - (integer -> 'vars -> M 'vars 'e) -> M 'vars 'e +val foreachM_inc : forall 'rv 'vars 'e. (integer * integer * integer) -> 'vars -> + (integer -> 'vars -> monad 'rv 'vars 'e) -> monad 'rv 'vars 'e let rec foreachM_inc (i,stop,by) vars body = if (by > 0 && i <= stop) || (by < 0 && stop <= i) then @@ -27,8 +27,8 @@ let rec foreachM_inc (i,stop,by) vars body = else return vars -val foreachM_dec : forall 'vars 'e. (integer * integer * integer) -> 'vars -> - (integer -> 'vars -> M 'vars 'e) -> M 'vars 'e +val foreachM_dec : forall 'rv 'vars 'e. (integer * integer * integer) -> 'vars -> + (integer -> 'vars -> monad 'rv 'vars 'e) -> monad 'rv 'vars 'e let rec foreachM_dec (i,stop,by) vars body = if (by > 0 && i >= stop) || (by < 0 && stop >= i) then @@ -40,21 +40,21 @@ val while_PP : forall 'vars. 'vars -> ('vars -> bool) -> ('vars -> 'vars) -> 'va let rec while_PP vars cond body = if cond vars then while_PP (body vars) cond body else vars -val while_PM : forall 'vars 'e. 'vars -> ('vars -> bool) -> - ('vars -> M 'vars 'e) -> M 'vars 'e +val while_PM : forall 'rv 'vars 'e. 'vars -> ('vars -> bool) -> + ('vars -> monad 'rv 'vars 'e) -> monad 'rv 'vars 'e let rec while_PM vars cond body = if cond vars then body vars >>= fun vars -> while_PM vars cond body else return vars -val while_MP : forall 'vars 'e. 'vars -> ('vars -> M bool 'e) -> - ('vars -> 'vars) -> M 'vars 'e +val while_MP : forall 'rv 'vars 'e. 'vars -> ('vars -> monad 'rv bool 'e) -> + ('vars -> 'vars) -> monad 'rv 'vars 'e let rec while_MP vars cond body = cond vars >>= fun cond_val -> if cond_val then while_MP (body vars) cond body else return vars -val while_MM : forall 'vars 'e. 'vars -> ('vars -> M bool 'e) -> - ('vars -> M 'vars 'e) -> M 'vars 'e +val while_MM : forall 'rv 'vars 'e. 'vars -> ('vars -> monad 'rv bool 'e) -> + ('vars -> monad 'rv 'vars 'e) -> monad 'rv 'vars 'e let rec while_MM vars cond body = cond vars >>= fun cond_val -> if cond_val then @@ -66,21 +66,21 @@ let rec until_PP vars cond body = let vars = body vars in if (cond vars) then vars else until_PP (body vars) cond body -val until_PM : forall 'vars 'e. 'vars -> ('vars -> bool) -> - ('vars -> M 'vars 'e) -> M 'vars 'e +val until_PM : forall 'rv 'vars 'e. 'vars -> ('vars -> bool) -> + ('vars -> monad 'rv 'vars 'e) -> monad 'rv 'vars 'e let rec until_PM vars cond body = body vars >>= fun vars -> if (cond vars) then return vars else until_PM vars cond body -val until_MP : forall 'vars 'e. 'vars -> ('vars -> M bool 'e) -> - ('vars -> 'vars) -> M 'vars 'e +val until_MP : forall 'rv 'vars 'e. 'vars -> ('vars -> monad 'rv bool 'e) -> + ('vars -> 'vars) -> monad 'rv 'vars 'e let rec until_MP vars cond body = let vars = body vars in cond vars >>= fun cond_val -> if cond_val then return vars else until_MP vars cond body -val until_MM : forall 'vars 'e. 'vars -> ('vars -> M bool 'e) -> - ('vars -> M 'vars 'e) -> M 'vars 'e +val until_MM : forall 'rv 'vars 'e. 'vars -> ('vars -> monad 'rv bool 'e) -> + ('vars -> monad 'rv 'vars 'e) -> monad 'rv 'vars 'e let rec until_MM vars cond body = body vars >>= fun vars -> cond vars >>= fun cond_val -> diff --git a/src/gen_lib/prompt_monad.lem b/src/gen_lib/prompt_monad.lem index 45733caa..ff5e3726 100644 --- a/src/gen_lib/prompt_monad.lem +++ b/src/gen_lib/prompt_monad.lem @@ -1,70 +1,88 @@ open import Pervasives_extra -open import Sail_impl_base +(*open import Sail_impl_base*) +open import Sail_instr_kinds open import Sail_values -type M 'a 'e = outcome 'a 'e - -val return : forall 'a 'e. 'a -> M 'a 'e +type register_name = string + +type monad 'regval 'a 'e = + | Done of 'a + | Read_mem of read_kind * integer * integer * (list memory_byte -> monad 'regval 'a 'e) + (* Tell the system a write is imminent, at address lifted, of size nat *) + | Write_ea of write_kind * integer * integer * monad 'regval 'a 'e + (* Request the result of store-exclusive *) + | Excl_res of (bool -> monad 'regval 'a 'e) + (* Request to write memory at last signalled address. Memory value should be 8 + times the size given in ea signal *) + | Write_memv of list memory_byte * (bool -> monad 'regval 'a 'e) + (* Request a memory barrier *) + | Barrier of barrier_kind * monad 'regval 'a 'e + (* Request to read register, will track dependency when mode.track_values *) + | Read_reg of register_name * ('regval -> monad 'regval 'a 'e) + (* Request to write register *) + | Write_reg of register_name * 'regval * monad 'regval 'a 'e + (*Result of a failed assert with possible error message to report*) + | Fail of string + | Error of string + (* Exception of type 'e *) + | Exception of 'e + (* TODO: Reading/writing tags *) + +val return : forall 'rv 'a 'e. 'a -> monad 'rv 'a 'e let return a = Done a -val bind : forall 'a 'b 'e. M 'a 'e -> ('a -> M 'b 'e) -> M 'b 'e +val bind : forall 'rv 'a 'b 'e. monad 'rv 'a 'e -> ('a -> monad 'rv 'b 'e) -> monad 'rv 'b 'e let rec bind m f = match m with - | Done a -> f a - | Read_mem descr k -> Read_mem descr (fun v -> let (o,opt) = k v in (bind o f,opt)) - | Read_reg descr k -> Read_reg descr (fun v -> let (o,opt) = k v in (bind o f,opt)) - | Write_memv descr k -> Write_memv descr (fun v -> let (o,opt) = k v in (bind o f,opt)) - | Excl_res k -> Excl_res (fun v -> let (o,opt) = k v in (bind o f,opt)) - | Write_ea descr o_s -> Write_ea descr (let (o,opt) = o_s in (bind o f,opt)) - | Barrier descr o_s -> Barrier descr (let (o,opt) = o_s in (bind o f,opt)) - | Footprint o_s -> Footprint (let (o,opt) = o_s in (bind o f,opt)) - | Write_reg descr o_s -> Write_reg descr (let (o,opt) = o_s in (bind o f,opt)) - | Escape descr -> Escape descr - | Fail descr -> Fail descr - | Error descr -> Error descr - | Exception e -> Exception e - | Internal descr o_s -> Internal descr (let (o,opt) = o_s in (bind o f ,opt)) + | Done a -> f a + | Read_mem rk a sz k -> Read_mem rk a sz (fun v -> bind (k v) f) + | Write_memv descr k -> Write_memv descr (fun v -> bind (k v) f) + | Read_reg descr k -> Read_reg descr (fun v -> bind (k v) f) + | Excl_res k -> Excl_res (fun v -> bind (k v) f) + | Write_ea wk a sz k -> Write_ea wk a sz (bind k f) + | Barrier bk k -> Barrier bk (bind k f) + | Write_reg r v k -> Write_reg r v (bind k f) + | Fail descr -> Fail descr + | Error descr -> Error descr + | Exception e -> Exception e end let inline (>>=) = bind -val (>>) : forall 'b 'e. M unit 'e -> M 'b 'e -> M 'b 'e +val (>>) : forall 'rv 'b 'e. monad 'rv unit 'e -> monad 'rv 'b 'e -> monad 'rv 'b 'e let inline (>>) m n = m >>= fun (_ : unit) -> n -val exit : forall 'a 'e. unit -> M 'a 'e -let exit () = Fail Nothing +val exit : forall 'rv 'a 'e. unit -> monad 'rv 'a 'e +let exit () = Fail "exit" -val assert_exp : forall 'e. bool -> string -> M unit 'e -let assert_exp exp msg = if exp then Done () else Fail (Just msg) +val assert_exp : forall 'rv 'e. bool -> string -> monad 'rv unit 'e +let assert_exp exp msg = if exp then Done () else Fail msg -val throw : forall 'a 'e. 'e -> M 'a 'e +val throw : forall 'rv 'a 'e. 'e -> monad 'rv 'a 'e let throw e = Exception e -val try_catch : forall 'a 'e1 'e2. M 'a 'e1 -> ('e1 -> M 'a 'e2) -> M 'a 'e2 +val try_catch : forall 'rv 'a 'e1 'e2. monad 'rv 'a 'e1 -> ('e1 -> monad 'rv 'a 'e2) -> monad 'rv 'a 'e2 let rec try_catch m h = match m with - | Done a -> Done a - | Read_mem descr k -> Read_mem descr (fun v -> let (o,opt) = k v in (try_catch o h,opt)) - | Read_reg descr k -> Read_reg descr (fun v -> let (o,opt) = k v in (try_catch o h,opt)) - | Write_memv descr k -> Write_memv descr (fun v -> let (o,opt) = k v in (try_catch o h,opt)) - | Excl_res k -> Excl_res (fun v -> let (o,opt) = k v in (try_catch o h,opt)) - | Write_ea descr o_s -> Write_ea descr (let (o,opt) = o_s in (try_catch o h,opt)) - | Barrier descr o_s -> Barrier descr (let (o,opt) = o_s in (try_catch o h,opt)) - | Footprint o_s -> Footprint (let (o,opt) = o_s in (try_catch o h,opt)) - | Write_reg descr o_s -> Write_reg descr (let (o,opt) = o_s in (try_catch o h,opt)) - | Escape descr -> Escape descr - | Fail descr -> Fail descr - | Error descr -> Error descr - | Exception e -> h e - | Internal descr o_s -> Internal descr (let (o,opt) = o_s in (try_catch o h ,opt)) + | Done a -> Done a + | Read_mem rk a sz k -> Read_mem rk a sz (fun v -> try_catch (k v) h) + | Write_memv descr k -> Write_memv descr (fun v -> try_catch (k v) h) + | Read_reg descr k -> Read_reg descr (fun v -> try_catch (k v) h) + | Excl_res k -> Excl_res (fun v -> try_catch (k v) h) + | Write_ea wk a sz k -> Write_ea wk a sz (try_catch k h) + | Barrier bk k -> Barrier bk (try_catch k h) + | Write_reg r v k -> Write_reg r v (try_catch k h) + | Fail descr -> Fail descr + | Error descr -> Error descr + | Exception e -> h e end (* For early return, we abuse exceptions by throwing and catching the return value. The exception type is "either 'r 'e", where "Right e" represents a proper exception and "Left r" an early return of value "r". *) -type MR 'a 'r 'e = M 'a (either 'r 'e) +type monadR 'rv 'a 'r 'e = monad 'rv 'a (either 'r 'e) -val early_return : forall 'a 'r 'e. 'r -> MR 'a 'r 'e +val early_return : forall 'rv 'a 'r 'e. 'r -> monadR 'rv 'a 'r 'e let early_return r = throw (Left r) -val catch_early_return : forall 'a 'e. MR 'a 'a 'e -> M 'a 'e +val catch_early_return : forall 'rv 'a 'e. monadR 'rv 'a 'a 'e -> monad 'rv 'a 'e let catch_early_return m = try_catch m (function @@ -73,11 +91,11 @@ let catch_early_return m = end) (* Lift to monad with early return by wrapping exceptions *) -val liftR : forall 'a 'r 'e. M 'a 'e -> MR 'a 'r 'e +val liftR : forall 'rv 'a 'r 'e. monad 'rv 'a 'e -> monadR 'rv 'a 'r 'e let liftR m = try_catch m (fun e -> throw (Right e)) (* Catch exceptions in the presence of early returns *) -val try_catchR : forall 'a 'r 'e1 'e2. MR 'a 'r 'e1 -> ('e1 -> MR 'a 'r 'e2) -> MR 'a 'r 'e2 +val try_catchR : forall 'rv 'a 'r 'e1 'e2. monadR 'rv 'a 'r 'e1 -> ('e1 -> monadR 'rv 'a 'r 'e2) -> monadR 'rv 'a 'r 'e2 let try_catchR m h = try_catch m (function @@ -86,59 +104,62 @@ let try_catchR m h = end) -val read_mem : forall 'a 'b 'e. Bitvector 'a, Bitvector 'b => read_kind -> 'a -> integer -> M 'b 'e +val read_mem : forall 'rv 'a 'b 'e. Bitvector 'a, Bitvector 'b => read_kind -> 'a -> integer -> monad 'rv 'b 'e let read_mem rk addr sz = - let addr = address_lifted_of_bitv (bits_of addr) in - let sz = natFromInteger sz in - let k memory_value = - let bitv = of_bits (internal_mem_value memory_value) in - (Done bitv,Nothing) in - Read_mem (rk,addr,sz) k - -val excl_result : forall 'e. unit -> M bool 'e + let addr = unsigned addr in + let k bytes = + let bitv = bits_of_bytes (List.reverse bytes) in + (Done bitv) in + Read_mem rk addr sz k + +val excl_result : forall 'rv 'e. unit -> monad 'rv bool 'e let excl_result () = - let k successful = (return successful,Nothing) in + let k successful = (return successful) in Excl_res k -val write_mem_ea : forall 'a 'e. Bitvector 'a => write_kind -> 'a -> integer -> M unit 'e -let write_mem_ea wk addr sz = - let addr = address_lifted_of_bitv (bits_of addr) in - let sz = natFromInteger sz in - Write_ea (wk,addr,sz) (Done (),Nothing) - -val write_mem_val : forall 'a 'e. Bitvector 'a => 'a -> M bool 'e -let write_mem_val v = - let v = external_mem_value (bits_of v) in - let k successful = (return successful,Nothing) in - Write_memv v k - -val read_reg_aux : forall 'a 'e. Bitvector 'a => reg_name -> M 'a 'e -let read_reg_aux reg = - let k reg_value = - let v = of_bits (internal_reg_value reg_value) in - (Done v,Nothing) in - Read_reg reg k +val write_mem_ea : forall 'rv 'a 'e. Bitvector 'a => write_kind -> 'a -> integer -> monad 'rv unit 'e +let write_mem_ea wk addr sz = Write_ea wk (unsigned addr) sz (Done ()) +val write_mem_val : forall 'rv 'a 'e. Bitvector 'a => 'a -> monad 'rv bool 'e +let write_mem_val v = match bytes_of_bits v with + | Just v -> + let k successful = (return successful) in + Write_memv (List.reverse v) k + | Nothing -> fail "write_mem_val" +end + +val read_reg : forall 's 'rv 'a 'e. register_ref 's 'rv 'a -> monad 'rv 'a 'e let read_reg reg = - read_reg_aux (external_reg_whole reg) + let k v = + match reg.of_regval v with + | Just v -> Done v + | Nothing -> Error "read_reg: unrecognised value" + end + in + Read_reg reg.name k + +(* TODO +val read_reg_range : forall 's 'r 'rv 'a 'e. Bitvector 'a => register_ref 's 'rv 'r -> integer -> integer -> monad 'rv 'a 'e let read_reg_range reg i j = - read_reg_aux (external_reg_slice reg (natFromInteger i,natFromInteger j)) + read_reg_aux of_bits (external_reg_slice reg (natFromInteger i,natFromInteger j)) + let read_reg_bit reg i = - read_reg_aux (external_reg_slice reg (natFromInteger i,natFromInteger i)) >>= fun v -> + read_reg_aux (fun v -> v) (external_reg_slice reg (natFromInteger i,natFromInteger i)) >>= fun v -> return (extract_only_element v) + let read_reg_field reg regfield = - read_reg_aux (external_reg_field_whole reg regfield.field_name) + read_reg_aux (external_reg_field_whole reg regfield) + let read_reg_bitfield reg regfield = - read_reg_aux (external_reg_field_whole reg regfield.field_name) >>= fun v -> - return (extract_only_element v) + read_reg_aux (external_reg_field_whole reg regfield) >>= fun v -> + return (extract_only_element v)*) let reg_deref = read_reg -val write_reg_aux : forall 'a 'e. Bitvector 'a => reg_name -> 'a -> M unit 'e -let write_reg_aux reg_name v = - let regval = external_reg_value reg_name (bits_of v) in - Write_reg (reg_name,regval) (Done (), Nothing) +val write_reg : forall 's 'rv 'a 'e. register_ref 's 'rv 'a -> 'a -> monad 'rv unit 'e +let write_reg reg v = Write_reg reg.name (reg.regval_of v) (Done ()) +(* TODO let write_reg reg v = write_reg_aux (external_reg_whole reg) v let write_reg_range reg i j v = @@ -149,20 +170,17 @@ let write_reg_pos reg i v = let write_reg_bit = write_reg_pos let write_reg_field reg regfield v = write_reg_aux (external_reg_field_whole reg regfield.field_name) v -(*let write_reg_field_bit reg regfield bit = +let write_reg_field_bit reg regfield bit = write_reg_aux (external_reg_field_whole reg regfield.field_name) - (Vector [bit] 0 (is_inc_of_reg reg))*) + (Vector [bit] 0 (is_inc_of_reg reg)) let write_reg_field_range reg regfield i j v = write_reg_aux (external_reg_field_slice reg regfield.field_name (natFromInteger i,natFromInteger j)) v let write_reg_field_pos reg regfield i v = write_reg_field_range reg regfield i i [v] -let write_reg_field_bit = write_reg_field_pos - -let write_reg_ref (reg, v) = write_reg reg v - -val barrier : forall 'e. barrier_kind -> M unit 'e -let barrier bk = Barrier bk (Done (), Nothing) +let write_reg_field_bit = write_reg_field_pos*) +val barrier : forall 'rv 'e. barrier_kind -> monad 'rv unit 'e +let barrier bk = Barrier bk (Done ()) -val footprint : forall 'e. M unit 'e -let footprint = Footprint (Done (),Nothing) +(*val footprint : forall 'rv 'e. monad 'rv unit 'e +let footprint = Footprint (Done ())*) diff --git a/src/gen_lib/sail_operators.lem b/src/gen_lib/sail_operators.lem index ada91bd0..7d6b156b 100644 --- a/src/gen_lib/sail_operators.lem +++ b/src/gen_lib/sail_operators.lem @@ -1,6 +1,5 @@ open import Pervasives_extra open import Machine_word -open import Sail_impl_base open import Sail_values (*** Bit vector operations *) diff --git a/src/gen_lib/sail_operators_bitlists.lem b/src/gen_lib/sail_operators_bitlists.lem index d2a2aea1..5658dc21 100644 --- a/src/gen_lib/sail_operators_bitlists.lem +++ b/src/gen_lib/sail_operators_bitlists.lem @@ -1,6 +1,5 @@ open import Pervasives_extra open import Machine_word -open import Sail_impl_base open import Sail_values open import Sail_operators diff --git a/src/gen_lib/sail_operators_mwords.lem b/src/gen_lib/sail_operators_mwords.lem index bd7ef2b4..fcc3153b 100644 --- a/src/gen_lib/sail_operators_mwords.lem +++ b/src/gen_lib/sail_operators_mwords.lem @@ -1,6 +1,5 @@ open import Pervasives_extra open import Machine_word -open import Sail_impl_base open import Sail_values open import Sail_operators diff --git a/src/gen_lib/sail_values.lem b/src/gen_lib/sail_values.lem index 4cbcc269..34e4bd98 100644 --- a/src/gen_lib/sail_values.lem +++ b/src/gen_lib/sail_values.lem @@ -2,7 +2,7 @@ open import Pervasives_extra open import Machine_word -open import Sail_impl_base +(*open import Sail_impl_base*) type ii = integer @@ -57,6 +57,7 @@ val repeat : forall 'a. list 'a -> integer -> list 'a let rec repeat xs n = if n <= 0 then [] else xs ++ repeat xs (n-1) +declare {isabelle} termination_argument repeat = automatic let duplicate_to_list bit length = repeat [bit] length @@ -66,6 +67,7 @@ let rec replace bs (n : integer) b' = match bs with if n = 0 then b' :: bs else b :: replace bs (n - 1) b' end +declare {isabelle} termination_argument replace = automatic let upper n = n @@ -135,7 +137,7 @@ end let cast_bit_bool = bool_of_bitU -let bit_lifted_of_bitU = function +(*let bit_lifted_of_bitU = function | B0 -> Bitl_zero | B1 -> Bitl_one | BU -> Bitl_undef @@ -157,7 +159,7 @@ let bitU_of_bit_lifted = function | Bitl_one -> B1 | Bitl_undef -> BU | Bitl_unknown -> failwith "bitU_of_bit_lifted Bitl_unknown" - end + end*) let not_bit = function | B1 -> B0 @@ -200,6 +202,7 @@ val bits_of_nat_aux : natural -> list bitU let rec bits_of_nat_aux x = if x = 0 then [] else (if x mod 2 = 1 then B1 else B0) :: bits_of_nat_aux (x / 2) +declare {isabelle} termination_argument bits_of_nat_aux = automatic let bits_of_nat n = List.reverse (bits_of_nat_aux n) val nat_of_bits : list bitU -> natural @@ -239,6 +242,7 @@ let signed_of_bits bits = val pad_bitlist : bitU -> list bitU -> integer -> list bitU let rec pad_bitlist b bits n = if n <= 0 then bits else pad_bitlist b (b :: bits) (n - 1) +declare {isabelle} termination_argument pad_bitlist = automatic let ext_bits pad len bits = let longer = len - (integerFromNat (List.length bits)) in @@ -259,6 +263,7 @@ let rec add_one_bit_ignore_overflow_aux bits = match bits with | B1 :: bits -> B0 :: add_one_bit_ignore_overflow_aux bits | BU :: _ -> failwith "add_one_bit_ignore_overflow: undefined bit" end +declare {isabelle} termination_argument add_one_bit_ignore_overflow_aux = automatic let add_one_bit_ignore_overflow bits = List.reverse (add_one_bit_ignore_overflow_aux (List.reverse bits)) @@ -300,6 +305,7 @@ let rec hexstring_of_bits bs = match bs with end | _ -> Nothing end +declare {isabelle} termination_argument hexstring_of_bits = automatic let show_bitlist bs = match hexstring_of_bits bs with @@ -370,6 +376,21 @@ let extract_only_element = function | _ -> failwith "extract_only_element called for list with more elements" end +(* just_list takes a list of maybes and returns Just xs if all elements have + a value, and Nothing if one of the elements is Nothing. *) +val just_list : forall 'a. list (maybe 'a) -> maybe (list 'a) +let rec just_list [] = Just [] +and just_list (x :: xs) = + match (x, just_list xs) with + | (Just x, Just xs) -> Just (x :: xs) + | (_, _) -> Nothing + end +declare {isabelle} termination_argument just_list = automatic + +lemma just_list_spec: + ((forall xs. (just_list xs = Nothing) <-> List.elem Nothing xs) && + (forall xs es. (just_list xs = Just es) <-> (xs = List.map Just es))) + (*** Machine words *) val length_mword : forall 'a. mword 'a -> integer @@ -503,14 +524,24 @@ let string_of_bv v = show_bitlist (bits_of v) (*** Bytes and addresses *) -val byte_chunks : forall 'a. nat -> list 'a -> list (list 'a) -let rec byte_chunks n list = match (n,list) with - | (0,_) -> [] - | (n+1, a::b::c::d::e::f::g::h::rest) -> [a;b;c;d;e;f;g;h] :: byte_chunks n rest - | _ -> failwith "byte_chunks not given enough bits" +type memory_byte = list bitU + +val byte_chunks : forall 'a. list 'a -> maybe (list (list 'a)) +let rec byte_chunks bs = match bs with + | [] -> Just [] + | a::b::c::d::e::f::g::h::rest -> + Maybe.bind (byte_chunks rest) (fun rest -> Just ([a;b;c;d;e;f;g;h] :: rest)) + | _ -> Nothing end +declare {isabelle} termination_argument byte_chunks = automatic + +val bytes_of_bits : forall 'a. Bitvector 'a => 'a -> maybe (list memory_byte) +let bytes_of_bits bs = byte_chunks (bits_of bs) -val bitv_of_byte_lifteds : list Sail_impl_base.byte_lifted -> list bitU +val bits_of_bytes : forall 'a. Bitvector 'a => list memory_byte -> 'a +let bits_of_bytes bs = of_bits (List.concat (List.map bits_of bs)) + +(*val bitv_of_byte_lifteds : list Sail_impl_base.byte_lifted -> list bitU let bitv_of_byte_lifteds v = foldl (fun x (Byte_lifted y) -> x ++ (List.map bitU_of_bit_lifted y)) [] v @@ -545,10 +576,13 @@ let address_lifted_of_bitv v = end in Address_lifted byte_lifteds maybe_address_integer +val bitv_of_address_lifted : address_lifted -> list bitU +let bitv_of_address_lifted (Address_lifted bs _) = bitv_of_byte_lifteds bs + val address_of_bitv : list bitU -> address let address_of_bitv v = let bytes = bytes_of_bitv v in - address_of_byte_list bytes + address_of_byte_list bytes*) let rec reverse_endianness_list bits = if List.length bits <= 8 then bits else @@ -560,7 +594,7 @@ let reverse_endianness v = of_bits (reverse_endianness_list (bits_of v)) (*** Registers *) -type register_field = string +(*type register_field = string type register_field_index = string * (integer * integer) (* name, start and end *) type register = @@ -570,14 +604,19 @@ type register = bool * (* is increasing *) list register_field_index | UndefinedRegister of integer (* length *) - | RegisterPair of register * register + | RegisterPair of register * register*) -type register_ref 'regstate 'a = - <| reg_name : string; - reg_start : integer; - reg_is_inc : bool; +type register_ref 'regstate 'regval 'a = + <| name : string; + is_inc : bool; read_from : 'regstate -> 'a; - write_to : 'regstate -> 'a -> 'regstate |> + write_to : 'regstate -> 'a -> 'regstate; + of_regval : 'regval -> maybe 'a; + regval_of : 'a -> 'regval |> + +type register_accessors 'regstate 'regval = + ((string -> 'regstate -> maybe 'regval) * + (string -> 'regval -> 'regstate -> maybe 'regstate)) type field_ref 'regtype 'a = <| field_name : string; @@ -586,7 +625,7 @@ type field_ref 'regtype 'a = get_field : 'regtype -> 'a; set_field : 'regtype -> 'a -> 'regtype |> -let name_of_reg = function +(*let name_of_reg = function | Register name _ _ _ _ -> name | UndefinedRegister _ -> failwith "name_of_reg UndefinedRegister" | RegisterPair _ _ -> failwith "name_of_reg RegisterPair" @@ -597,7 +636,7 @@ let size_of_reg = function | UndefinedRegister size -> size | RegisterPair _ _ -> failwith "size_of_reg RegisterPair" end - + let start_of_reg = function | Register _ _ start _ _ -> start | UndefinedRegister _ -> failwith "start_of_reg UndefinedRegister" @@ -638,11 +677,11 @@ let register_field_indices register rfield = let register_field_indices_nat reg regfield= let (i,j) = register_field_indices reg regfield in - (natFromInteger i,natFromInteger j) + (natFromInteger i,natFromInteger j)*) -let rec external_reg_value reg_name v = +(*let rec external_reg_value reg_name v = let (internal_start, external_start, direction) = - match reg_name with + match reg_name with | Reg _ start size dir -> (start, (if dir = D_increasing then start else (start - (size +1))), dir) | Reg_slice _ reg_start dir (slice_start, _) -> @@ -653,10 +692,10 @@ let rec external_reg_value reg_name v = slice_start, dir) | Reg_f_slice _ reg_start dir _ _ (slice_start, _) -> ((if dir = D_increasing then slice_start else (reg_start - slice_start)), - slice_start, dir) + slice_start, dir) end in let bits = bit_lifteds_of_bitv v in - <| rv_bits = bits; + <| rv_bits = bits; rv_dir = direction; rv_start = external_start; rv_start_internal = internal_start |> @@ -672,42 +711,45 @@ let external_slice (d:direction) (start:nat) ((i,j):(nat*nat)) = match d with (*This is the case the thread/concurrecny model expects, so no change needed*) | D_increasing -> (i,j) - | D_decreasing -> let slice_i = start - i in + | D_decreasing -> let slice_i = start - i in let slice_j = (i - j) + slice_i in (slice_i,slice_j) - end + end *) -let external_reg_whole reg = - Reg (name_of_reg reg) (start_of_reg_nat reg) (size_of_reg_nat reg) (dir_of_reg reg) - -let external_reg_slice reg (i,j) = - let start = start_of_reg_nat reg in - let dir = dir_of_reg reg in - Reg_slice (name_of_reg reg) start dir (external_slice dir start (i,j)) +(* TODO +let external_reg_whole r = + Reg (r.name) (natFromInteger r.start) (natFromInteger r.size) (dir_of_bool r.is_inc) + +let external_reg_slice r (i,j) = + let start = natFromInteger r.start in + let dir = dir_of_bool r.is_inc in + Reg_slice (r.name) start dir (external_slice dir start (i,j)) -let external_reg_field_whole reg rfield = +let external_reg_field_whole reg rfield = let (m,n) = register_field_indices_nat reg rfield in let start = start_of_reg_nat reg in let dir = dir_of_reg reg in Reg_field (name_of_reg reg) start dir rfield (external_slice dir start (m,n)) - -let external_reg_field_slice reg rfield (i,j) = + +let external_reg_field_slice reg rfield (i,j) = let (m,n) = register_field_indices_nat reg rfield in let start = start_of_reg_nat reg in let dir = dir_of_reg reg in Reg_f_slice (name_of_reg reg) start dir rfield (external_slice dir start (m,n)) - (external_slice dir start (i,j)) + (external_slice dir start (i,j))*) +(*val external_mem_value : list bitU -> memory_value let external_mem_value v = byte_lifteds_of_bitv v $> List.reverse +val internal_mem_value : memory_value -> list bitU let internal_mem_value bytes = - List.reverse bytes $> bitv_of_byte_lifteds + List.reverse bytes $> bitv_of_byte_lifteds*) + - val foreach_inc : forall 'vars. (integer * integer * integer) -> 'vars -> (integer -> 'vars -> 'vars) -> 'vars @@ -756,7 +798,7 @@ let toNaturalFiveTup (n1,n2,n3,n4,n5) = | RSliceBit of (string * integer) | RField of (string * string) -type niafp = +type niafp = | NIAFP_successor | NIAFP_concrete_address of vector bitU | NIAFP_LR @@ -764,13 +806,13 @@ type niafp = | NIAFP_register of regfp (* only for MIPS *) -type diafp = +type diafp = | DIAFP_none | DIAFP_concrete of vector bitU | DIAFP_reg of regfp let regfp_to_reg (reg_info : string -> maybe string -> (nat * nat * direction * (nat * nat))) = function - | RFull name -> + | RFull name -> let (start,length,direction,_) = reg_info name Nothing in Reg name start length direction | RSlice (name,i,j) -> diff --git a/src/gen_lib/state.lem b/src/gen_lib/state.lem index ac6d55b5..d4e2b128 100644 --- a/src/gen_lib/state.lem +++ b/src/gen_lib/state.lem @@ -1,5 +1,4 @@ open import Pervasives_extra -open import Sail_impl_base open import Sail_values open import State_monad open import {isabelle} `State_monad_extras` diff --git a/src/gen_lib/state_monad.lem b/src/gen_lib/state_monad.lem index 2d8e412e..a3bf4b5f 100644 --- a/src/gen_lib/state_monad.lem +++ b/src/gen_lib/state_monad.lem @@ -1,5 +1,5 @@ open import Pervasives_extra -open import Sail_impl_base +open import Sail_instr_kinds open import Sail_values (* 'a is result type *) @@ -103,37 +103,21 @@ let rec range i j = else if i = j then [i] else i :: range (i+1) j -val get_reg : forall 'regs 'a. sequential_state 'regs -> register_ref 'regs 'a -> 'a +val get_reg : forall 'regs 'rv 'a. sequential_state 'regs -> register_ref 'regs 'rv 'a -> 'a let get_reg state reg = reg.read_from state.regstate -val set_reg : forall 'regs 'a. sequential_state 'regs -> register_ref 'regs 'a -> 'a -> sequential_state 'regs +val set_reg : forall 'regs 'rv 'a. sequential_state 'regs -> register_ref 'regs 'rv 'a -> 'a -> sequential_state 'regs let set_reg state reg v = <| state with regstate = reg.write_to state.regstate v |> -let is_exclusive = function - | Sail_impl_base.Read_plain -> false - | Sail_impl_base.Read_reserve -> true - | Sail_impl_base.Read_acquire -> false - | Sail_impl_base.Read_exclusive -> true - | Sail_impl_base.Read_exclusive_acquire -> true - | Sail_impl_base.Read_stream -> false - | Sail_impl_base.Read_RISCV_acquire -> false - | Sail_impl_base.Read_RISCV_strong_acquire -> false - | Sail_impl_base.Read_RISCV_reserved -> true - | Sail_impl_base.Read_RISCV_reserved_acquire -> true - | Sail_impl_base.Read_RISCV_reserved_strong_acquire -> true - | Sail_impl_base.Read_X86_locked -> true -end - - val read_mem : forall 'regs 'a 'b 'e. Bitvector 'a, Bitvector 'b => read_kind -> 'a -> integer -> M 'regs 'b 'e let read_mem read_kind addr sz state = let addr = unsigned addr in let addrs = range addr (addr+sz-1) in let memory_value = List.map (fun addr -> Map_extra.find addr state.memstate) addrs in - let value = of_bits (Sail_values.internal_mem_value memory_value) in - if is_exclusive read_kind + let value = bits_of_bytes (List.reverse memory_value) in + if read_is_exclusive read_kind then [(Value value, <| state with last_exclusive_operation_was_load = true |>)] else [(Value value, state)] @@ -147,7 +131,7 @@ let read_tag read_kind addr state = | Just t -> t | Nothing -> B0 end in - if is_exclusive read_kind + if read_is_exclusive read_kind then [(Value tag, <| state with last_exclusive_operation_was_load = true |>)] else [(Value tag, state)] @@ -167,11 +151,15 @@ let write_mem_val v state = | Nothing -> failwith "write ea has not been announced yet" | Just write_ea -> write_ea end in let addrs = range addr (addr+sz-1) in - let v = external_mem_value (bits_of v) in - let addresses_with_value = List.zip addrs v in - let memstate = List.foldl (fun mem (addr,v) -> Map.insert addr v mem) - state.memstate addresses_with_value in - [(Value true, <| state with memstate = memstate |>)] + match bytes_of_bits v with + | Just v -> + let addresses_with_value = List.zip addrs (List.reverse v) in + let memstate = List.foldl (fun mem (addr,v) -> Map.insert addr v mem) + state.memstate addresses_with_value in + [(Value true, <| state with memstate = memstate |>)] + | Nothing -> + [(Exception (Assert "write_mem_val"), state)] + end val write_tag : forall 'regs 'e. bitU -> M 'regs bool 'e let write_tag t state = @@ -182,7 +170,7 @@ let write_tag t state = let tagstate = Map.insert taddr t state.tagstate in [(Value true, <| state with tagstate = tagstate |>)] -val read_reg : forall 'regs 'a 'e. register_ref 'regs 'a -> M 'regs 'a 'e +val read_reg : forall 'regs 'rv 'a 'e. register_ref 'regs 'rv 'a -> M 'regs 'a 'e let read_reg reg state = let v = reg.read_from state.regstate in [(Value v,state)] @@ -201,13 +189,13 @@ let read_reg_bitfield reg regfield = let reg_deref = read_reg -val write_reg : forall 'regs 'a 'e. register_ref 'regs 'a -> 'a -> M 'regs unit 'e +val write_reg : forall 'regs 'rv 'a 'e. register_ref 'regs 'rv 'a -> 'a -> M 'regs unit 'e let write_reg reg v state = [(Value (), <| state with regstate = reg.write_to state.regstate v |>)] let write_reg_ref (reg, v) = write_reg reg v -val update_reg : forall 'regs 'a 'b 'e. register_ref 'regs 'a -> ('a -> 'b -> 'a) -> 'b -> M 'regs unit 'e +val update_reg : forall 'regs 'rv 'a 'b 'e. register_ref 'regs 'rv 'a -> ('a -> 'b -> 'a) -> 'b -> M 'regs unit 'e let update_reg reg f v state = let current_value = get_reg state reg in let new_value = f current_value v in @@ -215,14 +203,14 @@ let update_reg reg f v state = let write_reg_field reg regfield = update_reg reg regfield.set_field -val update_reg_range : forall 'regs 'a 'b. Bitvector 'a, Bitvector 'b => register_ref 'regs 'a -> integer -> integer -> 'a -> 'b -> 'a -let update_reg_range reg i j reg_val new_val = set_bits (reg.reg_is_inc) reg_val i j (bits_of new_val) +val update_reg_range : forall 'regs 'rv 'a 'b. Bitvector 'a, Bitvector 'b => register_ref 'regs 'rv 'a -> integer -> integer -> 'a -> 'b -> 'a +let update_reg_range reg i j reg_val new_val = set_bits (reg.is_inc) reg_val i j (bits_of new_val) let write_reg_range reg i j = update_reg reg (update_reg_range reg i j) -let update_reg_pos reg i reg_val x = update_list reg.reg_is_inc reg_val i x +let update_reg_pos reg i reg_val x = update_list reg.is_inc reg_val i x let write_reg_pos reg i = update_reg reg (update_reg_pos reg i) -let update_reg_bit reg i reg_val bit = set_bit (reg.reg_is_inc) reg_val i (to_bitU bit) +let update_reg_bit reg i reg_val bit = set_bit (reg.is_inc) reg_val i (to_bitU bit) let write_reg_bit reg i = update_reg reg (update_reg_bit reg i) let update_reg_field_range regfield i j reg_val new_val = diff --git a/src/lem_interp/sail_impl_base.lem b/src/lem_interp/sail_impl_base.lem index 219677ac..f029b952 100644 --- a/src/lem_interp/sail_impl_base.lem +++ b/src/lem_interp/sail_impl_base.lem @@ -49,7 +49,7 @@ (*========================================================================*) open import Pervasives_extra - +open import Sail_instr_kinds class ( EnumerationType 'a ) @@ -478,373 +478,10 @@ end (* Data structures for building up instructions *) -(* careful: changes in the read/write/barrier kinds have to be - reflected in deep_shallow_convert *) -type read_kind = - (* common reads *) - | Read_plain - (* Power reads *) - | Read_reserve - (* AArch64 reads *) - | Read_acquire | Read_exclusive | Read_exclusive_acquire | Read_stream - (* RISC-V reads *) - | Read_RISCV_acquire | Read_RISCV_strong_acquire - | Read_RISCV_reserved | Read_RISCV_reserved_acquire - | Read_RISCV_reserved_strong_acquire - (* x86 reads *) - | Read_X86_locked (* the read part of a lock'd instruction (rmw) *) - -instance (Show read_kind) - let show = function - | Read_plain -> "Read_plain" - | Read_reserve -> "Read_reserve" - | Read_acquire -> "Read_acquire" - | Read_exclusive -> "Read_exclusive" - | Read_exclusive_acquire -> "Read_exclusive_acquire" - | Read_stream -> "Read_stream" - | Read_RISCV_acquire -> "Read_RISCV_acquire" - | Read_RISCV_strong_acquire -> "Read_RISCV_strong_acquire" - | Read_RISCV_reserved -> "Read_RISCV_reserved" - | Read_RISCV_reserved_acquire -> "Read_RISCV_reserved_acquire" - | Read_RISCV_reserved_strong_acquire -> "Read_RISCV_reserved_strong_acquire" - | Read_X86_locked -> "Read_X86_locked" - end -end - -type write_kind = - (* common writes *) - | Write_plain - (* Power writes *) - | Write_conditional - (* AArch64 writes *) - | Write_release | Write_exclusive | Write_exclusive_release - (* RISC-V *) - | Write_RISCV_release | Write_RISCV_strong_release - | Write_RISCV_conditional | Write_RISCV_conditional_release - | Write_RISCV_conditional_strong_release - (* x86 writes *) - | Write_X86_locked (* the write part of a lock'd instruction (rmw) *) - -instance (Show write_kind) - let show = function - | Write_plain -> "Write_plain" - | Write_conditional -> "Write_conditional" - | Write_release -> "Write_release" - | Write_exclusive -> "Write_exclusive" - | Write_exclusive_release -> "Write_exclusive_release" - | Write_RISCV_release -> "Write_RISCV_release" - | Write_RISCV_strong_release -> "Write_RISCV_strong_release" - | Write_RISCV_conditional -> "Write_RISCV_conditional" - | Write_RISCV_conditional_release -> "Write_RISCV_conditional_release" - | Write_RISCV_conditional_strong_release -> "Write_RISCV_conditional_strong_release" - | Write_X86_locked -> "Write_X86_locked" - end -end - -type barrier_kind = - (* Power barriers *) - Barrier_Sync | Barrier_LwSync | Barrier_Eieio | Barrier_Isync - (* AArch64 barriers *) - | Barrier_DMB | Barrier_DMB_ST | Barrier_DMB_LD | Barrier_DSB - | Barrier_DSB_ST | Barrier_DSB_LD | Barrier_ISB - | Barrier_TM_COMMIT - (* MIPS barriers *) - | Barrier_MIPS_SYNC - (* RISC-V barriers *) - | Barrier_RISCV_rw_rw - | Barrier_RISCV_r_rw - | Barrier_RISCV_r_r - | Barrier_RISCV_rw_w - | Barrier_RISCV_w_w - | Barrier_RISCV_i - (* X86 *) - | Barrier_x86_MFENCE - - -instance (Show barrier_kind) - let show = function - | Barrier_Sync -> "Barrier_Sync" - | Barrier_LwSync -> "Barrier_LwSync" - | Barrier_Eieio -> "Barrier_Eieio" - | Barrier_Isync -> "Barrier_Isync" - | Barrier_DMB -> "Barrier_DMB" - | Barrier_DMB_ST -> "Barrier_DMB_ST" - | Barrier_DMB_LD -> "Barrier_DMB_LD" - | Barrier_DSB -> "Barrier_DSB" - | Barrier_DSB_ST -> "Barrier_DSB_ST" - | Barrier_DSB_LD -> "Barrier_DSB_LD" - | Barrier_ISB -> "Barrier_ISB" - | Barrier_TM_COMMIT -> "Barrier_TM_COMMIT" - | Barrier_MIPS_SYNC -> "Barrier_MIPS_SYNC" - | Barrier_RISCV_rw_rw -> "Barrier_RISCV_rw_rw" - | Barrier_RISCV_r_rw -> "Barrier_RISCV_r_rw" - | Barrier_RISCV_r_r -> "Barrier_RISCV_r_r" - | Barrier_RISCV_rw_w -> "Barrier_RISCV_rw_w" - | Barrier_RISCV_w_w -> "Barrier_RISCV_w_w" - | Barrier_RISCV_i -> "Barrier_RISCV_i" - | Barrier_x86_MFENCE -> "Barrier_x86_MFENCE" - end -end - -type trans_kind = - (* AArch64 *) - | Transaction_start | Transaction_commit | Transaction_abort - -instance (Show trans_kind) - let show = function - | Transaction_start -> "Transaction_start" - | Transaction_commit -> "Transaction_commit" - | Transaction_abort -> "Transaction_abort" - end -end - -type instruction_kind = - | IK_barrier of barrier_kind - | IK_mem_read of read_kind - | IK_mem_write of write_kind - | IK_mem_rmw of (read_kind * write_kind) - | IK_cond_branch - (* unconditional branches are not distinguished in the instruction_kind; - they just have particular nias (and will be IK_simple *) - (* | IK_uncond_branch *) - | IK_trans of trans_kind - | IK_simple - - -instance (Show instruction_kind) - let show = function - | IK_barrier barrier_kind -> "IK_barrier " ^ (show barrier_kind) - | IK_mem_read read_kind -> "IK_mem_read " ^ (show read_kind) - | IK_mem_write write_kind -> "IK_mem_write " ^ (show write_kind) - | IK_cond_branch -> "IK_cond_branch" - | IK_trans trans_kind -> "IK_trans " ^ (show trans_kind) - | IK_simple -> "IK_simple" - end -end - - - -let ~{ocaml} read_kindCompare rk1 rk2 = - match (rk1, rk2) with - | (Read_plain, Read_plain) -> EQ - | (Read_plain, Read_reserve) -> LT - | (Read_plain, Read_acquire) -> LT - | (Read_plain, Read_exclusive) -> LT - | (Read_plain, Read_exclusive_acquire) -> LT - | (Read_plain, Read_stream) -> LT - - | (Read_reserve, Read_plain) -> GT - | (Read_reserve, Read_reserve) -> EQ - | (Read_reserve, Read_acquire) -> LT - | (Read_reserve, Read_exclusive) -> LT - | (Read_reserve, Read_exclusive_acquire) -> LT - | (Read_reserve, Read_stream) -> LT - - | (Read_acquire, Read_plain) -> GT - | (Read_acquire, Read_reserve) -> GT - | (Read_acquire, Read_acquire) -> EQ - | (Read_acquire, Read_exclusive) -> LT - | (Read_acquire, Read_exclusive_acquire) -> LT - | (Read_acquire, Read_stream) -> LT - - | (Read_exclusive, Read_plain) -> GT - | (Read_exclusive, Read_reserve) -> GT - | (Read_exclusive, Read_acquire) -> GT - | (Read_exclusive, Read_exclusive) -> EQ - | (Read_exclusive, Read_exclusive_acquire) -> LT - | (Read_exclusive, Read_stream) -> LT - - | (Read_exclusive_acquire, Read_plain) -> GT - | (Read_exclusive_acquire, Read_reserve) -> GT - | (Read_exclusive_acquire, Read_acquire) -> GT - | (Read_exclusive_acquire, Read_exclusive) -> GT - | (Read_exclusive_acquire, Read_exclusive_acquire) -> EQ - | (Read_exclusive_acquire, Read_stream) -> GT - - | (Read_stream, Read_plain) -> GT - | (Read_stream, Read_reserve) -> GT - | (Read_stream, Read_acquire) -> GT - | (Read_stream, Read_exclusive) -> GT - | (Read_stream, Read_exclusive_acquire) -> GT - | (Read_stream, Read_stream) -> EQ -end -let inline {ocaml} read_kindCompare = defaultCompare - -let ~{ocaml} read_kindLess b1 b2 = read_kindCompare b1 b2 = LT -let ~{ocaml} read_kindLessEq b1 b2 = read_kindCompare b1 b2 <> GT -let ~{ocaml} read_kindGreater b1 b2 = read_kindCompare b1 b2 = GT -let ~{ocaml} read_kindGreaterEq b1 b2 = read_kindCompare b1 b2 <> LT - -let inline {ocaml} read_kindLess = defaultLess -let inline {ocaml} read_kindLessEq = defaultLessEq -let inline {ocaml} read_kindGreater = defaultGreater -let inline {ocaml} read_kindGreaterEq = defaultGreaterEq - -instance (Ord read_kind) - let compare = read_kindCompare - let (<) = read_kindLess - let (<=) = read_kindLessEq - let (>) = read_kindGreater - let (>=) = read_kindGreaterEq -end - -let ~{ocaml} write_kindCompare wk1 wk2 = - match (wk1, wk2) with - | (Write_plain, Write_plain) -> EQ - | (Write_plain, Write_conditional) -> LT - | (Write_plain, Write_release) -> LT - | (Write_plain, Write_exclusive) -> LT - | (Write_plain, Write_exclusive_release) -> LT - - | (Write_conditional, Write_plain) -> GT - | (Write_conditional, Write_conditional) -> EQ - | (Write_conditional, Write_release) -> LT - | (Write_conditional, Write_exclusive) -> LT - | (Write_conditional, Write_exclusive_release) -> LT - - | (Write_release, Write_plain) -> GT - | (Write_release, Write_conditional) -> GT - | (Write_release, Write_release) -> EQ - | (Write_release, Write_exclusive) -> LT - | (Write_release, Write_exclusive_release) -> LT - - | (Write_exclusive, Write_plain) -> GT - | (Write_exclusive, Write_conditional) -> GT - | (Write_exclusive, Write_release) -> GT - | (Write_exclusive, Write_exclusive) -> EQ - | (Write_exclusive, Write_exclusive_release) -> LT - - | (Write_exclusive_release, Write_plain) -> GT - | (Write_exclusive_release, Write_conditional) -> GT - | (Write_exclusive_release, Write_release) -> GT - | (Write_exclusive_release, Write_exclusive) -> GT - | (Write_exclusive_release, Write_exclusive_release) -> EQ -end -let inline {ocaml} write_kindCompare = defaultCompare - -let ~{ocaml} write_kindLess b1 b2 = write_kindCompare b1 b2 = LT -let ~{ocaml} write_kindLessEq b1 b2 = write_kindCompare b1 b2 <> GT -let ~{ocaml} write_kindGreater b1 b2 = write_kindCompare b1 b2 = GT -let ~{ocaml} write_kindGreaterEq b1 b2 = write_kindCompare b1 b2 <> LT - -let inline {ocaml} write_kindLess = defaultLess -let inline {ocaml} write_kindLessEq = defaultLessEq -let inline {ocaml} write_kindGreater = defaultGreater -let inline {ocaml} write_kindGreaterEq = defaultGreaterEq - -instance (Ord write_kind) - let compare = write_kindCompare - let (<) = write_kindLess - let (<=) = write_kindLessEq - let (>) = write_kindGreater - let (>=) = write_kindGreaterEq -end - -(* Barrier comparison that uses less memory in Isabelle/HOL *) -let ~{ocaml} barrier_number = function - | Barrier_Sync -> (0 : natural) - | Barrier_LwSync -> 1 - | Barrier_Eieio -> 2 - | Barrier_Isync -> 3 - | Barrier_DMB -> 4 - | Barrier_DMB_ST -> 5 - | Barrier_DMB_LD -> 6 - | Barrier_DSB -> 7 - | Barrier_DSB_ST -> 8 - | Barrier_DSB_LD -> 9 - | Barrier_ISB -> 10 - | Barrier_TM_COMMIT -> 11 - | Barrier_MIPS_SYNC -> 12 - | Barrier_RISCV_rw_rw -> 13 - | Barrier_RISCV_r_rw -> 14 - | Barrier_RISCV_r_r -> 15 - | Barrier_RISCV_rw_w -> 16 - | Barrier_RISCV_w_w -> 17 - | Barrier_RISCV_i -> 18 - | Barrier_x86_MFENCE -> 19 - end - -let ~{ocaml} barrier_kindCompare bk1 bk2 = - let n1 = barrier_number bk1 in - let n2 = barrier_number bk2 in - if n1 < n2 then LT - else if n1 = n2 then EQ - else GT -let inline {ocaml} barrier_kindCompare = defaultCompare - -(*let ~{ocaml} barrier_kindCompare bk1 bk2 = - match (bk1, bk2) with - | (Barrier_Sync, Barrier_Sync) -> EQ - | (Barrier_Sync, _) -> LT - | (_, Barrier_Sync) -> GT - - | (Barrier_LwSync, Barrier_LwSync) -> EQ - | (Barrier_LwSync, _) -> LT - | (_, Barrier_LwSync) -> GT - - | (Barrier_Eieio, Barrier_Eieio) -> EQ - | (Barrier_Eieio, _) -> LT - | (_, Barrier_Eieio) -> GT - - | (Barrier_Isync, Barrier_Isync) -> EQ - | (Barrier_Isync, _) -> LT - | (_, Barrier_Isync) -> GT - - | (Barrier_DMB, Barrier_DMB) -> EQ - | (Barrier_DMB, _) -> LT - | (_, Barrier_DMB) -> GT - - | (Barrier_DMB_ST, Barrier_DMB_ST) -> EQ - | (Barrier_DMB_ST, _) -> LT - | (_, Barrier_DMB_ST) -> GT - - | (Barrier_DMB_LD, Barrier_DMB_LD) -> EQ - | (Barrier_DMB_LD, _) -> LT - | (_, Barrier_DMB_LD) -> GT - - | (Barrier_DSB, Barrier_DSB) -> EQ - | (Barrier_DSB, _) -> LT - | (_, Barrier_DSB) -> GT - - | (Barrier_DSB_ST, Barrier_DSB_ST) -> EQ - | (Barrier_DSB_ST, _) -> LT - | (_, Barrier_DSB_ST) -> GT - - | (Barrier_DSB_LD, Barrier_DSB_LD) -> EQ - | (Barrier_DSB_LD, _) -> LT - | (_, Barrier_DSB_LD) -> GT - - | (Barrier_ISB, Barrier_ISB) -> EQ - | (Barrier_ISB, _) -> LT - | (_, Barrier_ISB) -> GT - - | (Barrier_TM_COMMIT, Barrier_TM_COMMIT) -> EQ - | (Barrier_TM_COMMIT, _) -> LT - | (_, Barrier_TM_COMMIT) -> GT - - | (Barrier_MIPS_SYNC, Barrier_MIPS_SYNC) -> EQ - (* | (Barrier_MIPS_SYNC, _) -> LT - | (_, Barrier_MIPS_SYNC) -> GT *) - - end*) - -let ~{ocaml} barrier_kindLess b1 b2 = barrier_kindCompare b1 b2 = LT -let ~{ocaml} barrier_kindLessEq b1 b2 = barrier_kindCompare b1 b2 <> GT -let ~{ocaml} barrier_kindGreater b1 b2 = barrier_kindCompare b1 b2 = GT -let ~{ocaml} barrier_kindGreaterEq b1 b2 = barrier_kindCompare b1 b2 <> LT - -let inline {ocaml} barrier_kindLess = defaultLess -let inline {ocaml} barrier_kindLessEq = defaultLessEq -let inline {ocaml} barrier_kindGreater = defaultGreater -let inline {ocaml} barrier_kindGreaterEq = defaultGreaterEq - -instance (Ord barrier_kind) - let compare = barrier_kindCompare - let (<) = barrier_kindLess - let (<=) = barrier_kindLessEq - let (>) = barrier_kindGreater - let (>=) = barrier_kindGreaterEq -end +(* read_kind, write_kind, barrier_kind, trans_kind and instruction_kind have + been moved to sail_instr_kinds.lem. This removes the dependency of the + shallow embedding on the rest of sail_impl_base.lem, and helps avoid name + clashes between the different monad types. *) type event = | E_read_mem of read_kind * address_lifted * nat * maybe (list reg_name) diff --git a/src/lem_interp/sail_instr_kinds.lem b/src/lem_interp/sail_instr_kinds.lem new file mode 100644 index 00000000..89ff67b2 --- /dev/null +++ b/src/lem_interp/sail_instr_kinds.lem @@ -0,0 +1,436 @@ +(*========================================================================*) +(* Sail *) +(* *) +(* Copyright (c) 2013-2017 *) +(* Kathyrn Gray *) +(* Shaked Flur *) +(* Stephen Kell *) +(* Gabriel Kerneis *) +(* Robert Norton-Wright *) +(* Christopher Pulte *) +(* Peter Sewell *) +(* Alasdair Armstrong *) +(* Brian Campbell *) +(* Thomas Bauereiss *) +(* Anthony Fox *) +(* Jon French *) +(* Dominic Mulligan *) +(* Stephen Kell *) +(* Mark Wassell *) +(* *) +(* 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. *) +(*========================================================================*) + +open import Pervasives_extra + +(* Data structures for building up instructions *) + +(* careful: changes in the read/write/barrier kinds have to be + reflected in deep_shallow_convert *) +type read_kind = + (* common reads *) + | Read_plain + (* Power reads *) + | Read_reserve + (* AArch64 reads *) + | Read_acquire | Read_exclusive | Read_exclusive_acquire | Read_stream + (* RISC-V reads *) + | Read_RISCV_acquire | Read_RISCV_strong_acquire + | Read_RISCV_reserved | Read_RISCV_reserved_acquire + | Read_RISCV_reserved_strong_acquire + (* x86 reads *) + | Read_X86_locked (* the read part of a lock'd instruction (rmw) *) + +instance (Show read_kind) + let show = function + | Read_plain -> "Read_plain" + | Read_reserve -> "Read_reserve" + | Read_acquire -> "Read_acquire" + | Read_exclusive -> "Read_exclusive" + | Read_exclusive_acquire -> "Read_exclusive_acquire" + | Read_stream -> "Read_stream" + | Read_RISCV_acquire -> "Read_RISCV_acquire" + | Read_RISCV_strong_acquire -> "Read_RISCV_strong_acquire" + | Read_RISCV_reserved -> "Read_RISCV_reserved" + | Read_RISCV_reserved_acquire -> "Read_RISCV_reserved_acquire" + | Read_RISCV_reserved_strong_acquire -> "Read_RISCV_reserved_strong_acquire" + | Read_X86_locked -> "Read_X86_locked" + end +end + +type write_kind = + (* common writes *) + | Write_plain + (* Power writes *) + | Write_conditional + (* AArch64 writes *) + | Write_release | Write_exclusive | Write_exclusive_release + (* RISC-V *) + | Write_RISCV_release | Write_RISCV_strong_release + | Write_RISCV_conditional | Write_RISCV_conditional_release + | Write_RISCV_conditional_strong_release + (* x86 writes *) + | Write_X86_locked (* the write part of a lock'd instruction (rmw) *) + +instance (Show write_kind) + let show = function + | Write_plain -> "Write_plain" + | Write_conditional -> "Write_conditional" + | Write_release -> "Write_release" + | Write_exclusive -> "Write_exclusive" + | Write_exclusive_release -> "Write_exclusive_release" + | Write_RISCV_release -> "Write_RISCV_release" + | Write_RISCV_strong_release -> "Write_RISCV_strong_release" + | Write_RISCV_conditional -> "Write_RISCV_conditional" + | Write_RISCV_conditional_release -> "Write_RISCV_conditional_release" + | Write_RISCV_conditional_strong_release -> "Write_RISCV_conditional_strong_release" + | Write_X86_locked -> "Write_X86_locked" + end +end + +type barrier_kind = + (* Power barriers *) + Barrier_Sync | Barrier_LwSync | Barrier_Eieio | Barrier_Isync + (* AArch64 barriers *) + | Barrier_DMB | Barrier_DMB_ST | Barrier_DMB_LD | Barrier_DSB + | Barrier_DSB_ST | Barrier_DSB_LD | Barrier_ISB + | Barrier_TM_COMMIT + (* MIPS barriers *) + | Barrier_MIPS_SYNC + (* RISC-V barriers *) + | Barrier_RISCV_rw_rw + | Barrier_RISCV_r_rw + | Barrier_RISCV_r_r + | Barrier_RISCV_rw_w + | Barrier_RISCV_w_w + | Barrier_RISCV_i + (* X86 *) + | Barrier_x86_MFENCE + + +instance (Show barrier_kind) + let show = function + | Barrier_Sync -> "Barrier_Sync" + | Barrier_LwSync -> "Barrier_LwSync" + | Barrier_Eieio -> "Barrier_Eieio" + | Barrier_Isync -> "Barrier_Isync" + | Barrier_DMB -> "Barrier_DMB" + | Barrier_DMB_ST -> "Barrier_DMB_ST" + | Barrier_DMB_LD -> "Barrier_DMB_LD" + | Barrier_DSB -> "Barrier_DSB" + | Barrier_DSB_ST -> "Barrier_DSB_ST" + | Barrier_DSB_LD -> "Barrier_DSB_LD" + | Barrier_ISB -> "Barrier_ISB" + | Barrier_TM_COMMIT -> "Barrier_TM_COMMIT" + | Barrier_MIPS_SYNC -> "Barrier_MIPS_SYNC" + | Barrier_RISCV_rw_rw -> "Barrier_RISCV_rw_rw" + | Barrier_RISCV_r_rw -> "Barrier_RISCV_r_rw" + | Barrier_RISCV_r_r -> "Barrier_RISCV_r_r" + | Barrier_RISCV_rw_w -> "Barrier_RISCV_rw_w" + | Barrier_RISCV_w_w -> "Barrier_RISCV_w_w" + | Barrier_RISCV_i -> "Barrier_RISCV_i" + | Barrier_x86_MFENCE -> "Barrier_x86_MFENCE" + end +end + +type trans_kind = + (* AArch64 *) + | Transaction_start | Transaction_commit | Transaction_abort + +instance (Show trans_kind) + let show = function + | Transaction_start -> "Transaction_start" + | Transaction_commit -> "Transaction_commit" + | Transaction_abort -> "Transaction_abort" + end +end + +type instruction_kind = + | IK_barrier of barrier_kind + | IK_mem_read of read_kind + | IK_mem_write of write_kind + | IK_mem_rmw of (read_kind * write_kind) + | IK_cond_branch + (* unconditional branches are not distinguished in the instruction_kind; + they just have particular nias (and will be IK_simple *) + (* | IK_uncond_branch *) + | IK_trans of trans_kind + | IK_simple + + +instance (Show instruction_kind) + let show = function + | IK_barrier barrier_kind -> "IK_barrier " ^ (show barrier_kind) + | IK_mem_read read_kind -> "IK_mem_read " ^ (show read_kind) + | IK_mem_write write_kind -> "IK_mem_write " ^ (show write_kind) + | IK_cond_branch -> "IK_cond_branch" + | IK_trans trans_kind -> "IK_trans " ^ (show trans_kind) + | IK_simple -> "IK_simple" + end +end + + + +let ~{ocaml} read_kindCompare rk1 rk2 = + match (rk1, rk2) with + | (Read_plain, Read_plain) -> EQ + | (Read_plain, Read_reserve) -> LT + | (Read_plain, Read_acquire) -> LT + | (Read_plain, Read_exclusive) -> LT + | (Read_plain, Read_exclusive_acquire) -> LT + | (Read_plain, Read_stream) -> LT + + | (Read_reserve, Read_plain) -> GT + | (Read_reserve, Read_reserve) -> EQ + | (Read_reserve, Read_acquire) -> LT + | (Read_reserve, Read_exclusive) -> LT + | (Read_reserve, Read_exclusive_acquire) -> LT + | (Read_reserve, Read_stream) -> LT + + | (Read_acquire, Read_plain) -> GT + | (Read_acquire, Read_reserve) -> GT + | (Read_acquire, Read_acquire) -> EQ + | (Read_acquire, Read_exclusive) -> LT + | (Read_acquire, Read_exclusive_acquire) -> LT + | (Read_acquire, Read_stream) -> LT + + | (Read_exclusive, Read_plain) -> GT + | (Read_exclusive, Read_reserve) -> GT + | (Read_exclusive, Read_acquire) -> GT + | (Read_exclusive, Read_exclusive) -> EQ + | (Read_exclusive, Read_exclusive_acquire) -> LT + | (Read_exclusive, Read_stream) -> LT + + | (Read_exclusive_acquire, Read_plain) -> GT + | (Read_exclusive_acquire, Read_reserve) -> GT + | (Read_exclusive_acquire, Read_acquire) -> GT + | (Read_exclusive_acquire, Read_exclusive) -> GT + | (Read_exclusive_acquire, Read_exclusive_acquire) -> EQ + | (Read_exclusive_acquire, Read_stream) -> GT + + | (Read_stream, Read_plain) -> GT + | (Read_stream, Read_reserve) -> GT + | (Read_stream, Read_acquire) -> GT + | (Read_stream, Read_exclusive) -> GT + | (Read_stream, Read_exclusive_acquire) -> GT + | (Read_stream, Read_stream) -> EQ +end +let inline {ocaml} read_kindCompare = defaultCompare + +let ~{ocaml} read_kindLess b1 b2 = read_kindCompare b1 b2 = LT +let ~{ocaml} read_kindLessEq b1 b2 = read_kindCompare b1 b2 <> GT +let ~{ocaml} read_kindGreater b1 b2 = read_kindCompare b1 b2 = GT +let ~{ocaml} read_kindGreaterEq b1 b2 = read_kindCompare b1 b2 <> LT + +let inline {ocaml} read_kindLess = defaultLess +let inline {ocaml} read_kindLessEq = defaultLessEq +let inline {ocaml} read_kindGreater = defaultGreater +let inline {ocaml} read_kindGreaterEq = defaultGreaterEq + +instance (Ord read_kind) + let compare = read_kindCompare + let (<) = read_kindLess + let (<=) = read_kindLessEq + let (>) = read_kindGreater + let (>=) = read_kindGreaterEq +end + +let read_is_exclusive = function + | Read_plain -> false + | Read_reserve -> true + | Read_acquire -> false + | Read_exclusive -> true + | Read_exclusive_acquire -> true + | Read_stream -> false + | Read_RISCV_acquire -> false + | Read_RISCV_strong_acquire -> false + | Read_RISCV_reserved -> true + | Read_RISCV_reserved_acquire -> true + | Read_RISCV_reserved_strong_acquire -> true + | Read_X86_locked -> true +end + +let ~{ocaml} write_kindCompare wk1 wk2 = + match (wk1, wk2) with + | (Write_plain, Write_plain) -> EQ + | (Write_plain, Write_conditional) -> LT + | (Write_plain, Write_release) -> LT + | (Write_plain, Write_exclusive) -> LT + | (Write_plain, Write_exclusive_release) -> LT + + | (Write_conditional, Write_plain) -> GT + | (Write_conditional, Write_conditional) -> EQ + | (Write_conditional, Write_release) -> LT + | (Write_conditional, Write_exclusive) -> LT + | (Write_conditional, Write_exclusive_release) -> LT + + | (Write_release, Write_plain) -> GT + | (Write_release, Write_conditional) -> GT + | (Write_release, Write_release) -> EQ + | (Write_release, Write_exclusive) -> LT + | (Write_release, Write_exclusive_release) -> LT + + | (Write_exclusive, Write_plain) -> GT + | (Write_exclusive, Write_conditional) -> GT + | (Write_exclusive, Write_release) -> GT + | (Write_exclusive, Write_exclusive) -> EQ + | (Write_exclusive, Write_exclusive_release) -> LT + + | (Write_exclusive_release, Write_plain) -> GT + | (Write_exclusive_release, Write_conditional) -> GT + | (Write_exclusive_release, Write_release) -> GT + | (Write_exclusive_release, Write_exclusive) -> GT + | (Write_exclusive_release, Write_exclusive_release) -> EQ +end +let inline {ocaml} write_kindCompare = defaultCompare + +let ~{ocaml} write_kindLess b1 b2 = write_kindCompare b1 b2 = LT +let ~{ocaml} write_kindLessEq b1 b2 = write_kindCompare b1 b2 <> GT +let ~{ocaml} write_kindGreater b1 b2 = write_kindCompare b1 b2 = GT +let ~{ocaml} write_kindGreaterEq b1 b2 = write_kindCompare b1 b2 <> LT + +let inline {ocaml} write_kindLess = defaultLess +let inline {ocaml} write_kindLessEq = defaultLessEq +let inline {ocaml} write_kindGreater = defaultGreater +let inline {ocaml} write_kindGreaterEq = defaultGreaterEq + +instance (Ord write_kind) + let compare = write_kindCompare + let (<) = write_kindLess + let (<=) = write_kindLessEq + let (>) = write_kindGreater + let (>=) = write_kindGreaterEq +end + +(* Barrier comparison that uses less memory in Isabelle/HOL *) +let ~{ocaml} barrier_number = function + | Barrier_Sync -> (0 : natural) + | Barrier_LwSync -> 1 + | Barrier_Eieio -> 2 + | Barrier_Isync -> 3 + | Barrier_DMB -> 4 + | Barrier_DMB_ST -> 5 + | Barrier_DMB_LD -> 6 + | Barrier_DSB -> 7 + | Barrier_DSB_ST -> 8 + | Barrier_DSB_LD -> 9 + | Barrier_ISB -> 10 + | Barrier_TM_COMMIT -> 11 + | Barrier_MIPS_SYNC -> 12 + | Barrier_RISCV_rw_rw -> 13 + | Barrier_RISCV_r_rw -> 14 + | Barrier_RISCV_r_r -> 15 + | Barrier_RISCV_rw_w -> 16 + | Barrier_RISCV_w_w -> 17 + | Barrier_RISCV_i -> 18 + | Barrier_x86_MFENCE -> 19 + end + +let ~{ocaml} barrier_kindCompare bk1 bk2 = + let n1 = barrier_number bk1 in + let n2 = barrier_number bk2 in + if n1 < n2 then LT + else if n1 = n2 then EQ + else GT +let inline {ocaml} barrier_kindCompare = defaultCompare + +(*let ~{ocaml} barrier_kindCompare bk1 bk2 = + match (bk1, bk2) with + | (Barrier_Sync, Barrier_Sync) -> EQ + | (Barrier_Sync, _) -> LT + | (_, Barrier_Sync) -> GT + + | (Barrier_LwSync, Barrier_LwSync) -> EQ + | (Barrier_LwSync, _) -> LT + | (_, Barrier_LwSync) -> GT + + | (Barrier_Eieio, Barrier_Eieio) -> EQ + | (Barrier_Eieio, _) -> LT + | (_, Barrier_Eieio) -> GT + + | (Barrier_Isync, Barrier_Isync) -> EQ + | (Barrier_Isync, _) -> LT + | (_, Barrier_Isync) -> GT + + | (Barrier_DMB, Barrier_DMB) -> EQ + | (Barrier_DMB, _) -> LT + | (_, Barrier_DMB) -> GT + + | (Barrier_DMB_ST, Barrier_DMB_ST) -> EQ + | (Barrier_DMB_ST, _) -> LT + | (_, Barrier_DMB_ST) -> GT + + | (Barrier_DMB_LD, Barrier_DMB_LD) -> EQ + | (Barrier_DMB_LD, _) -> LT + | (_, Barrier_DMB_LD) -> GT + + | (Barrier_DSB, Barrier_DSB) -> EQ + | (Barrier_DSB, _) -> LT + | (_, Barrier_DSB) -> GT + + | (Barrier_DSB_ST, Barrier_DSB_ST) -> EQ + | (Barrier_DSB_ST, _) -> LT + | (_, Barrier_DSB_ST) -> GT + + | (Barrier_DSB_LD, Barrier_DSB_LD) -> EQ + | (Barrier_DSB_LD, _) -> LT + | (_, Barrier_DSB_LD) -> GT + + | (Barrier_ISB, Barrier_ISB) -> EQ + | (Barrier_ISB, _) -> LT + | (_, Barrier_ISB) -> GT + + | (Barrier_TM_COMMIT, Barrier_TM_COMMIT) -> EQ + | (Barrier_TM_COMMIT, _) -> LT + | (_, Barrier_TM_COMMIT) -> GT + + | (Barrier_MIPS_SYNC, Barrier_MIPS_SYNC) -> EQ + (* | (Barrier_MIPS_SYNC, _) -> LT + | (_, Barrier_MIPS_SYNC) -> GT *) + + end*) + +let ~{ocaml} barrier_kindLess b1 b2 = barrier_kindCompare b1 b2 = LT +let ~{ocaml} barrier_kindLessEq b1 b2 = barrier_kindCompare b1 b2 <> GT +let ~{ocaml} barrier_kindGreater b1 b2 = barrier_kindCompare b1 b2 = GT +let ~{ocaml} barrier_kindGreaterEq b1 b2 = barrier_kindCompare b1 b2 <> LT + +let inline {ocaml} barrier_kindLess = defaultLess +let inline {ocaml} barrier_kindLessEq = defaultLessEq +let inline {ocaml} barrier_kindGreater = defaultGreater +let inline {ocaml} barrier_kindGreaterEq = defaultGreaterEq + +instance (Ord barrier_kind) + let compare = barrier_kindCompare + let (<) = barrier_kindLess + let (<=) = barrier_kindLessEq + let (>) = barrier_kindGreater + let (>=) = barrier_kindGreaterEq +end diff --git a/src/pretty_print_lem.ml b/src/pretty_print_lem.ml index 350b5388..88ad8065 100644 --- a/src/pretty_print_lem.ml +++ b/src/pretty_print_lem.ml @@ -217,7 +217,7 @@ let rec lem_nexps_of_typ (Typ_aux (t,_)) = NexpSet.singleton (orig_nexp m) else trec elem_typ | Typ_app(Id_aux (Id "register", _), [Typ_arg_aux (Typ_arg_typ etyp, _)]) -> - if !opt_sequential then trec etyp else NexpSet.empty + trec etyp | Typ_app(Id_aux (Id "range", _),_) | Typ_app(Id_aux (Id "implicit", _),_) | Typ_app(Id_aux (Id "atom", _), _) -> NexpSet.empty @@ -274,12 +274,7 @@ let doc_typ_lem, doc_atomic_typ_lem = | _ -> string "list" ^^ space ^^ typ elem_typ in if atyp_needed then parens tpp else tpp | Typ_app(Id_aux (Id "register", _), [Typ_arg_aux (Typ_arg_typ etyp, _)]) -> - (* TODO: Better distinguish register names and contents? *) - (* fn_typ regtypes atyp_needed etyp *) - let tpp = - if !opt_sequential - then string "register_ref regstate " ^^ typ etyp - else string "register" in + let tpp = string "register_ref regstate register_value " ^^ typ etyp in if atyp_needed then parens tpp else tpp | Typ_app(Id_aux (Id "range", _),_) -> (string "integer") @@ -912,7 +907,7 @@ let doc_typdef_lem (TD_aux(td, (l, annot))) = match td with mk_typ (Typ_app (id, targs)) | TypQ_aux (TypQ_no_forall, _) -> mk_id_typ id in let fs_doc = group (separate_map (break 1) f_pp fs) in - let doc_field (ftyp, fid) = + (* let doc_field (ftyp, fid) = let reftyp = mk_typ (Typ_app (Id_aux (Id "field_ref", Parse_ast.Unknown), [mk_typ_arg (Typ_arg_typ rectyp); @@ -942,12 +937,12 @@ let doc_typdef_lem (TD_aux(td, (l, annot))) = match td with doc_op equals (string "field_start") (string (Big_int.to_string start)); semi_sp; doc_op equals (string "field_is_inc") (string (if is_inc then "true" else "false")); semi_sp; doc_op equals (string "get_field") (parens (doc_op arrow (string "fun rec_val") get)); semi_sp; - doc_op equals (string "set_field") (parens (doc_op arrow (string "fun rec_val v") set)); space])) in + doc_op equals (string "set_field") (parens (doc_op arrow (string "fun rec_val v") set)); space])) in *) doc_op equals (separate space [string "type"; doc_id_lem_type id; doc_typquant_items_lem None typq]) - ((*doc_typquant_lem typq*) (anglebars (space ^^ align fs_doc ^^ space))) ^^ hardline ^^ - if !opt_sequential && string_of_id id = "regstate" then empty - else separate_map hardline doc_field fs + ((*doc_typquant_lem typq*) (anglebars (space ^^ align fs_doc ^^ space))) ^^ hardline + (* if !opt_sequential && string_of_id id = "regstate" then empty + else separate_map hardline doc_field fs *) | TD_variant(id,nm,typq,ar,_) -> (match id with | Id_aux ((Id "read_kind"),_) -> empty @@ -1284,8 +1279,8 @@ let rec doc_fundef_lem (FD_aux(FD_function(r, typa, efa, fcls),fannot) as fd) = let doc_dec_lem (DEC_aux (reg, ((l, _) as annot))) = match reg with - | DEC_reg(typ,id) -> - if !opt_sequential then empty + | DEC_reg(typ,id) -> empty + (* if !opt_sequential then empty else let env = env_of_annot annot in let rt = Env.base_typ_of env typ in @@ -1303,7 +1298,7 @@ let doc_dec_lem (DEC_aux (reg, ((l, _) as annot))) = string "[]"])) ^/^ hardline else raise (Reporting_basic.err_unreachable l ("can't deal with register type " ^ string_of_typ typ)) - else raise (Reporting_basic.err_unreachable l ("can't deal with register type " ^ string_of_typ typ)) + else raise (Reporting_basic.err_unreachable l ("can't deal with register type " ^ string_of_typ typ)) *) | DEC_alias(id,alspec) -> empty | DEC_typ_alias(typ,id,alspec) -> empty @@ -1359,121 +1354,53 @@ let doc_regtype_fields (tname, (n1, n2, fields)) = in separate_map hardline doc_field fields -let rec doc_def_lem regtypes def = +let rec doc_def_lem def = (* let _ = Pretty_print_sail.pp_defs stderr (Defs [def]) in *) match def with - | DEF_spec v_spec -> (empty,doc_spec_lem v_spec) - | DEF_fixity _ -> (empty,empty) - | DEF_overload _ -> (empty,empty) - | DEF_type t_def -> (group (doc_typdef_lem t_def) ^/^ hardline,empty) - | DEF_reg_dec dec -> (group (doc_dec_lem dec),empty) - - | DEF_default df -> (empty,empty) - | DEF_fundef fdef -> - let doc_fdef = group (doc_fundef_lem fdef) ^/^ hardline in - if is_field_accessor regtypes fdef then (doc_fdef, empty) else (empty, doc_fdef) - | DEF_internal_mutrec fundefs -> - (empty, doc_mutrec_lem fundefs ^/^ hardline) - | DEF_val lbind -> (empty,group (doc_let_lem empty_ctxt lbind) ^/^ hardline) + | DEF_spec v_spec -> doc_spec_lem v_spec + | DEF_fixity _ -> empty + | DEF_overload _ -> empty + | DEF_type t_def -> group (doc_typdef_lem t_def) ^/^ hardline + | DEF_reg_dec dec -> group (doc_dec_lem dec) + + | DEF_default df -> empty + | DEF_fundef fdef -> group (doc_fundef_lem fdef) ^/^ hardline + | DEF_internal_mutrec fundefs -> doc_mutrec_lem fundefs ^/^ hardline + | DEF_val (LB_aux (LB_val (pat, _), _) as lbind) -> + group (doc_let_lem empty_ctxt lbind) ^/^ hardline | DEF_scattered sdef -> failwith "doc_def_lem: shoulnd't have DEF_scattered at this point" - | DEF_kind _ -> (empty,empty) - - | DEF_comm (DC_comm s) -> (empty,comment (string s)) - | DEF_comm (DC_comm_struct d) -> - let (typdefs,vdefs) = doc_def_lem regtypes d in - (empty,comment (typdefs ^^ hardline ^^ vdefs)) - - -let doc_defs_lem (Defs defs) = - let regtypes = [] in - let field_refs = separate_map hardline doc_regtype_fields regtypes in - let (typdefs,valdefs) = List.split (List.map (doc_def_lem regtypes) defs) in - (separate empty typdefs ^^ field_refs, separate empty valdefs) - -let find_registers (Defs defs) = - List.fold_left - (fun acc def -> - match def with - | DEF_reg_dec (DEC_aux(DEC_reg (typ, id), annot)) -> - let env = match annot with - | (_, Some (env, _, _)) -> env - | _ -> Env.empty in - (typ, id, env) :: acc - | _ -> acc - ) [] defs - -let find_exc_typ (Defs defs) = + | DEF_kind _ -> empty + + | DEF_comm (DC_comm s) -> comment (string s) + | DEF_comm (DC_comm_struct d) -> comment (doc_def_lem d) + + +let find_exc_typ defs = let is_exc_typ_def = function | DEF_type td -> string_of_id (id_of_type_def td) = "exception" | _ -> false in if List.exists is_exc_typ_def defs then "exception" else "unit" -let doc_regstate_lem registers = - let l = Parse_ast.Unknown in - let annot = (l, None) in - let regstate = match registers with - | [] -> - TD_abbrev ( - Id_aux (Id "regstate", l), - Name_sect_aux (Name_sect_none, l), - TypSchm_aux (TypSchm_ts (TypQ_aux (TypQ_tq [], l), unit_typ), l)) - | _ -> - TD_record ( - Id_aux (Id "regstate", l), - Name_sect_aux (Name_sect_none, l), - TypQ_aux (TypQ_tq [], l), - List.map (fun (typ, id, env) -> (typ, id)) registers, - false) +let pp_defs_lem (types_file,types_modules) (defs_file,defs_modules) (Defs defs) top_line = + (* let regtypes = find_regtypes d in *) + let state_ids = + State.generate_regstate_defs !opt_mwords defs + |> Initial_check.val_spec_ids in - let initregstate = - if !Initial_check.opt_undefined_gen then - let exp = match registers with - | [] -> E_aux (E_lit (mk_lit L_unit), (l, Some (Env.empty, unit_typ, no_effect))) - | _ -> - let initreg (typ, id, env) = - let annot typ = Some (env, typ, no_effect) in - let initval = undefined_of_typ !opt_mwords l annot typ in - FE_aux (FE_Fexp (id, initval), (l, annot typ)) in - E_aux ( - E_record (FES_aux (FES_Fexps (List.map initreg registers, false), annot)), - (l, Some (Env.empty, mk_id_typ (mk_id "regstate"), no_effect))) - in - doc_op equals (string "let initial_regstate") (doc_exp_lem empty_ctxt false exp) - else empty + let is_state_def = function + | DEF_spec vs -> IdSet.mem (id_of_val_spec vs) state_ids + | DEF_fundef fd -> IdSet.mem (id_of_fundef fd) state_ids + | _ -> false in - doc_typdef_lem (TD_aux (regstate, annot)), - initregstate - -let doc_register_refs_lem registers = - let doc_register_ref (typ, id, env) = - let idd = doc_id_lem id in - let field = if prefix_recordtype then string "regstate_" ^^ idd else idd in - let base_typ = Env.base_typ_of env typ in - let (start, is_inc) = - try - let (start, _, ord, _) = vector_typ_args_of base_typ in - match nexp_simp start with - | Nexp_aux (Nexp_constant i, _) -> (i, is_order_inc ord) - | _ -> - raise (Reporting_basic.err_unreachable Parse_ast.Unknown - ("register " ^ string_of_id id ^ " has non-constant start index " ^ string_of_nexp start)) - with - | _ -> (Big_int.zero, true) in - concat [string "let "; idd; string " = <|"; hardline; - string " reg_name = \""; idd; string "\";"; hardline; - string " reg_start = "; string (Big_int.to_string start); string ";"; hardline; - string " reg_is_inc = "; string (if is_inc then "true" else "false"); string ";"; hardline; - string " read_from = (fun s -> s."; field; string ");"; hardline; - string " write_to = (fun s v -> (<| s with "; field; string " = v |>)) |>"] in - separate_map hardline doc_register_ref registers - -let pp_defs_lem (types_file,types_modules) (defs_file,defs_modules) d top_line = - (* let regtypes = find_regtypes d in *) - let (typdefs,valdefs) = doc_defs_lem d in - let regstate_def, initregstate_def = doc_regstate_lem (find_registers d) in - let register_refs = doc_register_refs_lem (find_registers d) in - let exc_typ = find_exc_typ d in + let is_typ_def = function + | DEF_type _ -> true + | _ -> false + in + let exc_typ = find_exc_typ defs in + let typdefs, defs = List.partition is_typ_def defs in + let statedefs, defs = List.partition is_state_def defs in + let register_refs = State.register_refs_lem prefix_recordtype !opt_mwords (State.find_registers defs) in (print types_file) (concat [string "(*" ^^ (string top_line) ^^ string "*)";hardline; @@ -1491,20 +1418,20 @@ let pp_defs_lem (types_file,types_modules) (defs_file,defs_modules) d top_line = string "module SIA = Interp_ast"; hardline; hardline] else empty; - typdefs; hardline; + separate empty (List.map doc_def_lem typdefs); hardline; hardline; + separate empty (List.map doc_def_lem statedefs); hardline; + hardline; + register_refs; hardline; if !opt_sequential then - concat [regstate_def; hardline; - hardline; + concat [ string ("type MR 'a 'r = State_monad.MR regstate 'a 'r " ^ exc_typ); hardline; string ("type M 'a = State_monad.M regstate 'a " ^ exc_typ); hardline; - hardline; - register_refs ] else concat [ - string ("type MR 'a 'r = Prompt_monad.MR 'a 'r " ^ exc_typ); hardline; - string ("type M 'a = Prompt_monad.M 'a " ^ exc_typ); hardline + string ("type MR 'a 'r = monadR register_value 'a 'r " ^ exc_typ); hardline; + string ("type M 'a = monad register_value 'a " ^ exc_typ); hardline ] ]); (print defs_file) @@ -1513,6 +1440,5 @@ let pp_defs_lem (types_file,types_modules) (defs_file,defs_modules) d top_line = (separate_map hardline) (fun lib -> separate space [string "open import";string lib]) defs_modules;hardline; hardline; - valdefs; - hardline; - initregstate_def]); + separate empty (List.map doc_def_lem defs); + hardline]); diff --git a/src/process_file.ml b/src/process_file.ml index 1da893c3..8e309901 100644 --- a/src/process_file.ml +++ b/src/process_file.ml @@ -239,7 +239,7 @@ let output_lem filename libs defs = let libs = List.map (fun lib -> lib ^ seq_suffix) libs in let base_imports = [ "Pervasives_extra"; - "Sail_impl_base"; + "Sail_instr_kinds"; "Sail_values"; operators_module ] @ monad_modules diff --git a/src/sail.ml b/src/sail.ml index 2aae2472..35a7279b 100644 --- a/src/sail.ml +++ b/src/sail.ml @@ -267,8 +267,11 @@ let main() = C_backend.compile_ast (C_backend.initial_ctx type_envs) ast_c else ()); (if !(opt_print_lem) - then let ast_lem = rewrite_ast_lem ast in - output "" (Lem_out (!opt_libs_lem)) [out_name,ast_lem] + then + let mwords = !Pretty_print_lem.opt_mwords in + let type_envs, ast_lem = State.add_regstate_defs mwords type_envs ast in + let ast_lem = rewrite_ast_lem ast_lem in + output "" (Lem_out (!opt_libs_lem)) [out_name,ast_lem] else ()); end diff --git a/src/state.ml b/src/state.ml new file mode 100644 index 00000000..83af7d2f --- /dev/null +++ b/src/state.ml @@ -0,0 +1,279 @@ +(**************************************************************************) +(* Sail *) +(* *) +(* Copyright (c) 2013-2017 *) +(* Kathyrn Gray *) +(* Shaked Flur *) +(* Stephen Kell *) +(* Gabriel Kerneis *) +(* Robert Norton-Wright *) +(* Christopher Pulte *) +(* Peter Sewell *) +(* Alasdair Armstrong *) +(* Brian Campbell *) +(* Thomas Bauereiss *) +(* Anthony Fox *) +(* Jon French *) +(* Dominic Mulligan *) +(* Stephen Kell *) +(* Mark Wassell *) +(* *) +(* 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. *) +(**************************************************************************) + +module Big_int = Nat_big_num + +open Initial_check +open Type_check +open Ast +open Ast_util +open PPrint +open Pretty_print_common +open Pretty_print_sail + +let defs_of_string = ast_of_def_string Ast_util.inc_ord + +let find_registers defs = + List.fold_left + (fun acc def -> + match def with + | DEF_reg_dec (DEC_aux(DEC_reg (typ, id), annot)) -> + let env = match annot with + | (_, Some (env, _, _)) -> env + | _ -> Env.empty + in + (Env.expand_synonyms env typ, id) :: acc + | _ -> acc + ) [] defs + +let generate_regstate = function + | [] -> ["type regstate = unit"] + | registers -> + let reg (typ, id) = Printf.sprintf "%s : %s" (string_of_id id) (to_string (doc_typ typ)) in + let initreg (_, id) = Printf.sprintf "%s = undefined" (string_of_id id) in + let regstate = + "struct regstate = { " ^ + (String.concat ", " (List.map reg registers)) ^ + " }" + in + let initstate = + "let initial_regstate : regstate = struct { " ^ + (String.concat ", " (List.map initreg registers)) ^ + " }" + in + regstate :: (if !Initial_check.opt_undefined_gen then [initstate] else []) + +let rec regval_constr_id mwords (Typ_aux (t, l) as typ) = match t with + | Typ_id id -> id + | Typ_app (id, args) -> + let name_arg (Typ_arg_aux (targ, _)) = match targ with + | Typ_arg_typ targ -> string_of_id (regval_constr_id mwords targ) + | Typ_arg_nexp nexp when is_nexp_constant (nexp_simp nexp) -> + string_of_nexp (nexp_simp nexp) + | Typ_arg_order (Ord_aux (Ord_inc, _)) -> "inc" + | Typ_arg_order (Ord_aux (Ord_dec, _)) -> "dec" + | _ -> + raise (Reporting_basic.err_typ l "Unsupported register type") + in + let builtins = IdSet.of_list (List.map mk_id ["vector"; "list"; "option"]) in + if IdSet.mem id builtins && not (mwords && is_bitvector_typ typ) then id else + append_id id (String.concat "_" ("" :: List.map name_arg args)) + | _ -> raise (Reporting_basic.err_typ l "Unsupported register type") + +let register_base_types mwords typs = + let rec add_base_typs typs (Typ_aux (t, _) as typ) = + let builtins = IdSet.of_list (List.map mk_id ["vector"; "list"; "option"]) in + match t with + | Typ_app (id, args) + when IdSet.mem id builtins && not (mwords && is_bitvector_typ typ) -> + let add_typ_arg base_typs (Typ_arg_aux (targ, _)) = + match targ with + | Typ_arg_typ typ -> add_base_typs typs typ + | _ -> typs + in + List.fold_left add_typ_arg typs args + | _ -> Bindings.add (regval_constr_id mwords typ) typ typs + in + List.fold_left add_base_typs Bindings.empty typs + +let generate_regval_typ typs = + let constr (constr_id, typ) = + Printf.sprintf "Regval_%s : %s" (string_of_id constr_id) (to_string (doc_typ typ)) in + let builtins = + "Regval_vector : (int, bool, list(register_value)), " ^ + "Regval_list : list(register_value), " ^ + "Regval_option : option(register_value)" + in + ["union register_value = { " ^ + (String.concat ", " (builtins :: List.map constr (Bindings.bindings typs))) ^ + " }"] + +let add_regval_conv id typ defs = + let id = string_of_id id in + let is_defined name = IdSet.mem (mk_id name) (ids_of_defs defs) in + let typ_str = to_string (doc_typ typ) in + (* Create a function that converts from regval to the target type. *) + let from_name = id ^ "_of_regval" in + let from_val = Printf.sprintf "val %s : register_value -> option(%s)" from_name typ_str in + let from_function = String.concat "\n" [ + Printf.sprintf "function %s Regval_%s(v) = Some(v)" from_name id; + Printf.sprintf "and %s _ = None" from_name + ] in + let from_defs = if is_defined from_name then [] else [from_val; from_function] in + (* Create a function that converts from target type to regval. *) + let to_name = "regval_of_" ^ id in + let to_val = Printf.sprintf "val %s : %s -> register_value" to_name typ_str in + let to_function = Printf.sprintf "function %s v = Regval_%s(v)" to_name id in + let to_defs = if is_defined to_name then [] else [to_val; to_function] in + let cdefs = concat_ast (List.map defs_of_string (from_defs @ to_defs)) in + append_ast defs cdefs + +let rec regval_convs_lem mwords (Typ_aux (t, _) as typ) = match t with + | Typ_app _ when is_vector_typ typ && not (mwords && is_bitvector_typ typ) -> + let _, size, ord, etyp = vector_typ_args_of typ in + let size = string_of_nexp (nexp_simp size) in + let is_inc = if is_order_inc ord then "true" else "false" in + let etyp_of, of_etyp = regval_convs_lem mwords etyp in + "(fun v -> vector_of_regval " ^ etyp_of ^ " v)", + "(fun v -> regval_of_vector " ^ of_etyp ^ " " ^ size ^ " " ^ is_inc ^ " v)" + | Typ_app (id, [Typ_arg_aux (Typ_arg_typ etyp, _)]) + when string_of_id id = "list" -> + let etyp_of, of_etyp = regval_convs_lem mwords etyp in + "(fun v -> list_of_regval " ^ etyp_of ^ " v)", + "(fun v -> regval_of_list " ^ of_etyp ^ " v)" + | Typ_app (id, [Typ_arg_aux (Typ_arg_typ etyp, _)]) + when string_of_id id = "option" -> + let etyp_of, of_etyp = regval_convs_lem mwords etyp in + "(fun v -> option_of_regval " ^ etyp_of ^ " v)", + "(fun v -> regval_of_option " ^ of_etyp ^ " v)" + | _ -> + let id = string_of_id (regval_constr_id mwords typ) in + "(fun v -> " ^ id ^ "_of_regval v)", "(fun v -> regval_of_" ^ id ^ " v)" + +let register_refs_lem prefix_recordtype mwords registers = + let generic_convs = + separate_map hardline string [ + "val vector_of_regval : forall 'a. (register_value -> maybe 'a) -> register_value -> maybe (list 'a)"; + "let vector_of_regval of_regval = function"; + " | Regval_vector (_, _, v) -> just_list (List.map of_regval v)"; + " | _ -> Nothing"; + "end"; + ""; + "val regval_of_vector : forall 'a. ('a -> register_value) -> integer -> bool -> list 'a -> register_value"; + "let regval_of_vector regval_of size is_inc xs = Regval_vector (size, is_inc, List.map regval_of xs)"; + ""; + "val list_of_regval : forall 'a. (register_value -> maybe 'a) -> register_value -> maybe (list 'a)"; + "let list_of_regval of_regval = function"; + " | Regval_list v -> just_list (List.map of_regval v)"; + " | _ -> Nothing"; + "end"; + ""; + "val regval_of_list : forall 'a. ('a -> register_value) -> list 'a -> register_value"; + "let regval_of_list regval_of xs = Regval_list (List.map regval_of xs)"; + ""; + "val option_of_regval : forall 'a. (register_value -> maybe 'a) -> register_value -> maybe (maybe 'a)"; + "let option_of_regval of_regval = function"; + " | Regval_option v -> Maybe.map of_regval v"; + " | _ -> Nothing"; + "end"; + ""; + "val regval_of_option : forall 'a. ('a -> register_value) -> maybe 'a -> register_value"; + "let regval_of_option regval_of v = Regval_option (Maybe.map regval_of v)"; + ""; + "" + ] + in + let register_ref (typ, id) = + let idd = string (string_of_id id) in + let field = if prefix_recordtype then string "regstate_" ^^ idd else idd in + let is_inc = + if is_bitvector_typ typ then + let _, _, ord, _ = vector_typ_args_of typ in + if is_order_inc ord then "true" else "false" + else "true" + in + let of_regval, regval_of = regval_convs_lem mwords typ in + concat [string "let "; idd; string " = <|"; hardline; + string " name = \""; idd; string "\";"; hardline; + string " is_inc = "; string is_inc; string ";"; hardline; + string " read_from = (fun s -> s."; field; string ");"; hardline; + string " write_to = (fun s v -> (<| s with "; field; string " = v |>));"; hardline; + string " of_regval = "; string of_regval; string ";"; hardline; + string " regval_of = "; string regval_of; string " |>"; hardline] + in + let refs = separate_map hardline register_ref registers in + let get_set_reg (_, id) = + let idd = string_of_id id in + string (" if reg_name = \"" ^ idd ^ "\" then Just (" ^ idd ^ ".regval_of (" ^ idd ^ ".read_from s)) else"), + string (" if reg_name = \"" ^ idd ^ "\" then Maybe.map (" ^ idd ^ ".write_to s) (" ^ idd ^ ".of_regval v) else") + in + let getters_setters = + let getters, setters = List.split (List.map get_set_reg registers) in + string "val get_regval : string -> regstate -> maybe register_value" ^^ hardline ^^ + string "let get_regval reg_name s =" ^^ hardline ^^ + separate hardline getters ^^ hardline ^^ + string " Nothing" ^^ hardline ^^ hardline ^^ + string "val set_regval : string -> register_value -> regstate -> maybe regstate" ^^ hardline ^^ + string "let set_regval reg_name v s =" ^^ hardline ^^ + separate hardline setters ^^ hardline ^^ + string " Nothing" ^^ hardline ^^ hardline ^^ + string "let register_accessors = (get_regval, set_regval)" ^^ hardline ^^ hardline + in + separate hardline [generic_convs; refs; getters_setters] + +let generate_regstate_defs mwords defs = + let registers = find_registers defs in + let def_ids = ids_of_defs (Defs defs) in + let has_def name = IdSet.mem (mk_id name) def_ids in + let regtyps = register_base_types mwords (List.map fst registers) in + let option_typ = + if has_def "option" then [] else + ["union option ('a : Type) = {None, Some : 'a}"] + in + let regval_typ = if has_def "register_value" then [] else generate_regval_typ regtyps in + let regstate_typ = if has_def "regstate" then [] else generate_regstate registers in + (* FIXME We currently don't want to generate undefined_type functions + for register state and values. For the Lem backend, this would require + taking the dependencies of those functions into account when partitioning + definitions into the different lem files, which we currently don't do. *) + let gen_undef = !Initial_check.opt_undefined_gen in + Initial_check.opt_undefined_gen := false; + let defs = + option_typ @ regval_typ @ regstate_typ + |> List.map defs_of_string + |> concat_ast + |> Bindings.fold add_regval_conv regtyps + in + Initial_check.opt_undefined_gen := gen_undef; + defs + +let add_regstate_defs mwords env (Defs defs) = + let reg_defs, env = check env (generate_regstate_defs mwords defs) in + env, append_ast (Defs defs) reg_defs |
