diff options
Diffstat (limited to 'src/state.ml')
| -rw-r--r-- | src/state.ml | 279 |
1 files changed, 279 insertions, 0 deletions
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 |
