\section{Using Sail} \label{sec:usage} In its most basic use-case Sail is a command-line tool, analogous to a compiler: one gives it a list of input Sail files; it type-checks them and provides translated output. To simply typecheck Sail files, one can pass them on the command line with no other options, so for our \riscv\ spec: \begin{verbatim} sail prelude.sail riscv_types.sail riscv_mem.sail riscv_sys.sail riscv_vmem.sail riscv.sail \end{verbatim} The sail files passed on the command line are simply treated as if they are one large file concatenated together, although the parser will keep track of locations on a per-file basis for error-reporting. As can be seen, this specification is split into several logical components. \verb+prelude.sail+ defines the initial type environment and builtins, \verb+riscv_types.sail+ gives type definitions used in the rest of the specification, \verb+riscv_mem.sail+ and \verb+riscv_vmem.sail+ describe the physical and virtual memory interaction, and then \verb+riscv_sys.sail+ and \verb+riscv.sail+ implement most of the specification. For more complex projects, one can use \ll{$include} statements in Sail source, for example: \begin{lstlisting} $include $include "file.sail" \end{lstlisting} Here, Sail will look for \verb+library.sail+ in the \verb+$SAIL_DIR/lib+, where \verb+$SAIL_DIR+ is usually the root of the sail repository. It will search for \verb+file.sail+ relative to the location of the file containing the \ll{$include}. The space after the \ll{$include} is mandatory. Sail also supports \ll{$define}, \ll{$ifdef}, and \ll{$ifndef}. These are things that are understood by Sail itself, not a separate preprocessor, and are handled after the AST is parsed~\footnote{This can affect precedence declarations for custom user defined operators---the precedence must be redeclared in the file you are including the operator into.}. \subsection{OCaml compilation} To compile a Sail specification into OCaml, one calls Sail as \begin{verbatim} sail -ocaml FILES \end{verbatim} This will produce a version of the specification translated into OCaml, which is placed into a directory called \verb+_sbuild+, similar to ocamlbuild's \verb+_build+ directory. The generated OCaml is intended to be fairly close to the original Sail source, and currently we do not attempt to do much optimisation on this output. The contents of the \verb+_sbuild+ directory are set up as an ocamlbuild project, so one can simply switch into that directory and run \begin{verbatim} ocamlbuild -use-ocamlfind out.cmx \end{verbatim} to compile the generated model. Currently the OCaml compilation requires that lem, linksem, and zarith are available as ocamlfind findable libraries, and also that the environment variable \verb+$SAIL_DIR+ is set to the root of the Sail repository. If the Sail specification contains a \ll{main} function with type \ll{unit -> unit} that implements a fetch/decode/execute loop then the OCaml backend can produce a working executable, by running \begin{verbatim} sail -o out -ocaml FILES \end{verbatim} Then one can run \begin{verbatim} ./out ELF_FILE \end{verbatim} to simulate an ELF file on the specification. One can do \ll{$include } to gain access to some useful functions for accessing information about the loaded ELF file from within the Sail specification. In particular \verb+elf.sail+ defines a function \ll{elf_entry : unit -> int} which can be used to set the PC to the correct location. ELF loading is done by the linksem library\footnote{\url{https://github.com/rems-project/linksem}}. There is also an \verb+-ocaml_trace+ option which is the same as \verb+-ocaml+ except it instruments the generated OCaml code with tracing information. \subsection{C compilation} To compile Sail into C, the \verb+-c+ option is used, like so: \begin{verbatim} sail -c FILES 1> out.c \end{verbatim} The translated C is by default printed to stdout, but one can also use the \verb+-o+ option to output to a file, so \begin{verbatim} sail -c FILES -o out \end{verbatim} will generate a file called \verb+out.c+. To produce an executable this needs to be compiled and linked with the C files in the \verb+sail/lib+ directory: \begin{verbatim} gcc out.c $SAIL_DIR/lib/*.c -lgmp -lz -I $SAIL_DIR/lib/ -o out \end{verbatim} The C output requires the GMP library for arbitrary precision arithmetic, as well as zlib for working with compressed ELF binaries. There are several Sail options that affect the C output: \begin{itemize} \item \verb+-O+ turns on optimisations. The generated C code will be quite slow unless this flag is set. \item \verb+-Oconstant_fold+ apply constant folding optimisations. \item \verb+-c_include+ Supply additional header files to be included in the generated C. \item \verb+-c_no_main+ Do not generate a \verb+main()+ function. \item \verb+-static+ Mark generated C functions as static where possible. This is useful for measuring code coverage. \end{itemize} The generated executable for the Sail specification (provided a main function is generated) supports several options for loading ELF files and binary data into the specification memory. \begin{itemize} \item \verb+-e/--elf+ Loads an ELF file into memory. Currently only AArch64 and RISC-V ELF files are supported. \item \verb+-b/--binary+ Loads raw binary data into the specification's memory. It is used like so: \begin{verbatim} ./out --binary=0xADDRESS,FILE ./out -b 0xADDRESS,FILE \end{verbatim} The contents of the supplied file will be placed in memory starting at the given address, which must be given as a hexadecimal number. \item \verb+-i/--image+ For ELF files that are not loadable via the \verb+--elf+ flag, they can be pre-processed by Sail using linksem into a special image file that can be loaded via this flag. This is done like so: \begin{verbatim} sail -elf ELF_FILE -o image.bin ./out --image=image.bin \end{verbatim} The advantage of this flag is that it uses Linksem to process the ELF file, so it can handle any ELF file that linksem is able to understand. This also guarantees that the contents of the ELF binary loaded into memory is exactly the same as for the OCaml backend and the interpreter as they both also use Linksem internally to load ELF files. \item \verb+-n/--entry+ sets a custom entry point returned by the \ll{elf_entry} function. Must be a hexadecimal address prefixed by \verb+0x+. \item \verb+-l/--cyclelimit+ run the simulation until a set number of cycles have been reached. The main loop of the specification must call the \ll{cycle_count} function for this to work. \end{itemize} \subsection{Lem, Isabelle \& HOL4} We have a separate document detailing how to generate Isabelle theories from Sail models, and how to work with those models in Isabelle, see: \begin{center} \anonymise{\url{https://github.com/rems-project/sail/raw/sail2/snapshots/isabelle/Manual.pdf}} \end{center} Currently there are generated Isabelle snapshots for some of our models in \verb+snapshots/isabelle+ in the Sail repository. These snapshots are provided for convenience, and are not guaranteed to be up-to-date. In order to open a theory of one of the specifications in Isabelle, use the \verb+-l Sail+ command-line flag to load the session containing the Sail library. Snapshots of the Sail and Lem libraries are in the \verb+lib/sail+ and \verb+lib/lem+ directories, respectively. You can tell Isabelle where to find them using the \verb+-d+ flag, as in \begin{verbatim} isabelle jedit -l Sail -d lib/lem -d lib/sail riscv/Riscv.thy \end{verbatim} When run from the \verb+snapshots/isabelle+ directory this will open the RISC-V specification. \subsection{Interactive mode} Compiling Sail with \begin{verbatim} make isail \end{verbatim} builds it with a GHCi-style interactive interpreter. This can be used by starting Sail with \verb+sail -i+. If Sail is not compiled with interactive support the \verb+-i+ flag does nothing. Sail will still handle any other command line arguments as per usual, including compiling to OCaml or Lem. One can also pass a list of commands to the interpreter by using the \verb+-is+ flag, as \begin{verbatim} sail -is FILE \end{verbatim} where \verb+FILE+ contains a list of commands. Once inside the interactive mode, a list of commands can be accessed by typing \verb+:commands+, while \verb+:help+ can be used to provide some documentation for each command. \subsection{\LaTeX\ Generation} Sail can be used to generate latex for inclusion in documentation as: \begin{verbatim} sail -o DIRECTORY -latex FILES \end{verbatim} The list of \verb+FILES+ is a list of Sail files to produce latex for, and \verb+DIRECTORY+ is the directory where the generated latex will be placed. The list of files must be a valid type-checkable series of Sail files. The intention behind this latex generation is for it to be included within existing ISA manuals written in Latex, as such the latex output generates a list of commands for each top-level Sail declaration in \verb+DIRECTORY/commands.tex+. The rest of this section discusses the stable features of the latex generation process---there are additional features for including markdown doc-comments in Sail code and formatting them into latex for inclusion id documentation, among other things, but these features are not completely stable yet. This manual itself makes use of the Sail latex generation, so \verb+doc/manual.tex+, and \verb+doc/Makefile+ can be used to see how the process is set up. \paragraph{Requirements} The generated latex uses the \emph{listings} package for formatting source code, uses the macros in the \emph{etoolbox} package for the generated commands, and relies on the \emph{hyperref} package for cross-referencing. These packages are available in most TeX distributions, and are available as part of thetexlive packages for Ubuntu. \paragraph{Usage} Due to the oddities of latex verbatim environments each Sail declaration must be placed in it's own file then the command in \verb+commands.tex+ includes in with \verb+\lstinputlisting+. To include the generated Sail in a document one would do something like: \begin{lstlisting}[language=TeX] \input{commands.tex} \sailval{my_function} \sailfn{my_function} \end{lstlisting} which would enclude the type declaration (\verb+\sailval+) for \verb+my_function+ as well as type body of that function (\verb+\sailfn+). It is sometimes useful to include multiple versions of the same Sail definitions in a latex document. In this case the \verb+-latex_prefix+ option can be used. For example if we used \verb+-latex_prefix prefix+ then the above example would become: \begin{lstlisting}[language=TeX] \input{commands.tex} \prefixval{my_function} \prefixfn{my_function} \end{lstlisting} The generated definitions are created wrapped in customisable macros that can be overridden to change the formatting of the Sail code. For \verb+\sailfn+ there is a macro \verb+\saildocfn+ that must be defined, and similarly for the other Sail toplevel types. \paragraph{Cross-referencing} For each macro \verb+\sail+\emph{X}\verb+{id}+ there is a macro \verb+\sailref+\emph{X}\verb+{id}{text}+ which creates a hyper-reference to the original definition. This requires the hyper-ref package. \subsection{Other options} Here we summarize most of the other options available for Sail. Debugging options (usually for debugging Sail itself) are indicated by starting with the letter \verb+d+. \begin{itemize} \item {\verb+-v+} Print the Sail version. \item {\verb+-help+} Print a list of options. \item {\verb+-no_warn+} Turn off warnings. \item {\verb+-enum_casts+} Allow elements of enumerations to be automatically cast to numbers. \item \verb+-memo_z3+ Memoize calls to the Z3 solver. This can greatly improve typechecking times if you are repeatedly typechecking the same specification while developing it. \item \verb+-no_lexp_bounds_check+ Turn off bounds checking in the left hand side of assignments. \item \verb+-no_effects+ Turn off effect checking. May break some backends that assume effects are properly checked. \item \verb+-undefined_gen+ Generate functions that create undefined values of user-defined types. Every type \ll{T} will get a \ll{undefined_T} function created for it. This flag is set automatically by some backends that want to re-write \ll{undefined}. \item \verb+-just_check+ Force Sail to terminate immediately after typechecking. \item \verb+-dno_cast+ Force Sail to never perform type coercions under any circumstances. \item \verb+-dtc_verbose + Make the typechecker print a trace of typing judgements. If the verbosity level is 1, then this should only include fairly readable judgements about checking and inference rules. If verbosity is 2 then it will include a large amount of debugging information. This option can be useful to diagnose tricky type-errors, especially if the error message isn't very good. \item \verb+-ddump_tc_ast+ Write the typechecked AST to stdout after typechecking \item \verb+-ddump_rewrite_ast + Write the AST out after each re-writing pass. The output from each pass is placed in a file starting with \verb+prefix+. \item \verb+-dsanity+ Perform extra sanity checks on the AST. \item \verb+-dmagic_hash+ Allow the \# symbol in identifiers. It's currently used as a magic symbol to separate generated identifiers from those the user can write, so this option allows for the output of the various other debugging options to be fed back into Sail. \end{itemize}