aboutsummaryrefslogtreecommitdiff
path: root/ocaml_emulator/platform_impl.ml
diff options
context:
space:
mode:
authorPrashanth Mundkur <prashanth.mundkur@gmail.com>2019-01-16 10:24:17 -0800
committerPrashanth Mundkur <prashanth.mundkur@gmail.com>2019-01-16 10:24:17 -0800
commit254ed382c60fae295985fe7b83775adf116e49ba (patch)
treecd0e174f34b6332dab2aeca622e1f05b181d80cd /ocaml_emulator/platform_impl.ml
parent9d0282a0a52f0fa37e1d07827a4c0189dd01301c (diff)
downloadsail-riscv-254ed382c60fae295985fe7b83775adf116e49ba.zip
sail-riscv-254ed382c60fae295985fe7b83775adf116e49ba.tar.gz
sail-riscv-254ed382c60fae295985fe7b83775adf116e49ba.tar.bz2
Make it clearer that the outer c,ocaml sub-dirs contain supporting files for the emulators.
Diffstat (limited to 'ocaml_emulator/platform_impl.ml')
-rw-r--r--ocaml_emulator/platform_impl.ml189
1 files changed, 189 insertions, 0 deletions
diff --git a/ocaml_emulator/platform_impl.ml b/ocaml_emulator/platform_impl.ml
new file mode 100644
index 0000000..3eb8217
--- /dev/null
+++ b/ocaml_emulator/platform_impl.ml
@@ -0,0 +1,189 @@
+(* FIXME: copyright header *)
+
+(* int->byte converters in little-endian order *)
+
+let uint32_to_bytes u = let open Int32 in
+ List.map to_int
+ [ logand u 0xffl;
+ logand (shift_right u 8) 0xffl;
+ logand (shift_right u 16) 0xffl;
+ logand (shift_right u 24) 0xffl;
+ ]
+
+let uint64_to_bytes u = let open Int64 in
+ List.map to_int
+ [ logand u 0xffL;
+ logand (shift_right u 8) 0xffL;
+ logand (shift_right u 16) 0xffL;
+ logand (shift_right u 24) 0xffL;
+ logand (shift_right u 32) 0xffL;
+ logand (shift_right u 40) 0xffL;
+ logand (shift_right u 48) 0xffL;
+ logand (shift_right u 56) 0xffL;
+ ]
+
+(* reset vector for the rom *)
+
+let reset_vec_size = 8l;;
+
+let reset_vec_int start_pc = [
+ 0x297l; (* auipc t0, 0x0 *)
+ (let open Int32 in
+ add 0x28593l (shift_left (mul reset_vec_size 4l) 20)); (* addi a1, t0, ofs(dtb) *)
+ 0xf1402573l; (* csrr a0, mhartid *)
+ 0x0182b283l; (* ld t0, 24(t0) *)
+ 0x28067l; (* jr t0 *)
+ 0x0l;
+ (let open Int64 in to_int32 (logand start_pc 0xffffffffL));
+ (let open Int64 in to_int32 (shift_right_logical start_pc 32));
+]
+
+(* address map *)
+
+let dram_base = 0x80000000L;; (* Spike::DRAM_BASE *)
+let clint_base = 0x02000000L;; (* Spike::CLINT_BASE *)
+let clint_size = 0x000c0000L;; (* Spike::CLINT_SIZE *)
+let rom_base = 0x00001000L;; (* Spike::DEFAULT_RSTVEC *)
+
+let dram_size_ref = ref (Int64.(shift_left 2048L 20))
+
+type mem_region = {
+ addr : Int64.t;
+ size : Int64.t
+}
+
+(* dts from spike *)
+let spike_dts isa_spec cpu_hz insns_per_rtc_tick mems =
+ "/dts-v1/;\n"
+ ^ "\n"
+ ^ "/ {\n"
+ ^ " #address-cells = <2>;\n"
+ ^ " #size-cells = <2>;\n"
+ ^ " compatible = \"ucbbar,spike-bare-dev\";\n"
+ ^ " model = \"ucbbar,spike-bare\";\n"
+ ^ " cpus {\n"
+ ^ " #address-cells = <1>;\n"
+ ^ " #size-cells = <0>;\n"
+ ^ " timebase-frequency = <" ^ string_of_int (cpu_hz/insns_per_rtc_tick) ^ ">;\n"
+ ^ " CPU0: cpu@0 {\n"
+ ^ " device_type = \"cpu\";\n"
+ ^ " reg = <0>;\n"
+ ^ " status = \"okay\";\n"
+ ^ " compatible = \"riscv\";\n"
+ ^ " riscv,isa = \"" ^ isa_spec ^ "\";\n"
+ ^ " mmu-type = \"riscv,sv39\";\n"
+ ^ " clock-frequency = <" ^ string_of_int cpu_hz ^ ">;\n"
+ ^ " CPU0_intc: interrupt-controller {\n"
+ ^ " #interrupt-cells = <1>;\n"
+ ^ " interrupt-controller;\n"
+ ^ " compatible = \"riscv,cpu-intc\";\n"
+ ^ " };\n"
+ ^ " };\n"
+ ^ " };\n"
+ ^ (List.fold_left (^) ""
+ (List.map (fun m ->
+ " memory@" ^ Printf.sprintf "%Lx" m.addr ^ " {\n"
+ ^ " device_type = \"memory\";\n"
+ ^ " reg = <0x" ^ Printf.sprintf "%Lx" Int64.(shift_right_logical m.addr 32) ^ " 0x" ^ Printf.sprintf "%Lx" Int64.(logand m.addr 0xffffffffL)
+ ^ " 0x" ^ Printf.sprintf "%Lx" Int64.(shift_right_logical m.size 32) ^ " 0x" ^ Printf.sprintf "%Lx" Int64.(logand m.size 0xffffffffL) ^ ">;\n"
+ ^ " };\n") mems))
+ ^ " soc {\n"
+ ^ " #address-cells = <2>;\n"
+ ^ " #size-cells = <2>;\n"
+ ^ " compatible = \"ucbbar,spike-bare-soc\", \"simple-bus\";\n"
+ ^ " ranges;\n"
+ ^ " clint@" ^ Printf.sprintf "%Lx" clint_base ^ " {\n"
+ ^ " compatible = \"riscv,clint0\";\n"
+ ^ " interrupts-extended = <&CPU0_intc 3 &CPU0_intc 7 >;\n"
+ ^ " reg = <0x" ^ Printf.sprintf "%Lx" Int64.(shift_right_logical clint_base 32) ^ " 0x" ^ Printf.sprintf "%Lx" Int64.(logand clint_base 0xffffffffL)
+ ^ " 0x" ^ Printf.sprintf "%Lx" Int64.(shift_right_logical clint_size 32) ^ " 0x" ^ Printf.sprintf "%Lx" Int64.(logand clint_size 0xffffffffL) ^ ">;\n"
+ ^ " };\n"
+ ^ " };\n"
+ ^ " htif {\n"
+ ^ " compatible = \"ucb,htif0\";\n"
+ ^ " };\n"
+ ^ "};\n"
+
+let cpu_hz = 1000000000;;
+let insns_per_tick = 100;;
+
+let make_mems () = [{ addr = dram_base;
+ size = !dram_size_ref }];;
+
+let make_dts () = spike_dts "rv64imac" cpu_hz insns_per_tick (make_mems ());;
+
+let bytes_to_string bytes =
+ String.init (List.length bytes) (fun i -> Char.chr (List.nth bytes i))
+
+let dtc_path = ref "/usr/bin/dtc"
+
+let set_dtc path =
+ try let st = Unix.stat path in
+ if st.Unix.st_kind = Unix.S_REG && st.Unix.st_perm != 0
+ then dtc_path := path
+ else ( Printf.eprintf "%s doesn't seem like a valid executable.\n%!" path;
+ exit 1)
+ with Unix.Unix_error (e, _, _) ->
+ ( Printf.eprintf "Error accessing %s: %s\n%!" path (Unix.error_message e);
+ exit 1)
+
+let set_dram_size mb =
+ dram_size_ref := Int64.(shift_left (Int64.of_int mb) 20)
+
+let make_dtb dts = (* Call the dtc compiler, assumed to be at /usr/bin/dtc *)
+ try
+ let cmd = Printf.sprintf "%s -I dts" !dtc_path in
+ let (cfrom, cto, cerr) =
+ Unix.open_process_full cmd [||]
+ in (
+ output_string cto dts;
+ (* print_endline " sent dts to dtc ..."; *)
+ close_out cto;
+ (* simple and stupid for now *)
+ let rec accum_bytes cin acc =
+ match (
+ try Some (input_byte cin)
+ with End_of_file -> None
+ ) with
+ | Some b -> accum_bytes cin (b :: acc)
+ | None -> List.rev acc
+ in
+ (* let _ = print_endline " accumulating dtb ..." in *)
+ let dtb = accum_bytes cfrom [] in
+ (* let _ = print_endline " accumulating emsg ..." in *)
+ let emsg = bytes_to_string (accum_bytes cerr []) in
+ match Unix.close_process_full (cfrom, cto, cerr) with
+ | Unix.WEXITED 0 -> dtb
+ | _ -> (Printf.printf "%s\n%!" ("Error executing dtc: " ^ emsg);
+ exit 1)
+ )
+ with Unix.Unix_error (e, fn, _) ->
+ (Printf.printf "%s\n" ("Error executing dtc: " ^ fn ^ ": " ^ Unix.error_message e);
+ exit 1)
+
+(* Terminal I/O *)
+
+let term_write char =
+ ignore (Unix.write_substring Unix.stderr (String.make 1 char) 0 1)
+
+let rec term_read () =
+ let buf = Bytes.make 1 '\000' in
+ let nbytes = Unix.read Unix.stdin buf 0 1 in
+ (* todo: handle nbytes == 0 *)
+ Bytes.get buf 0
+
+(* Platform diagnostics *)
+
+let show_bytes s =
+ output_string stdout s
+
+let dump_dts () = show_bytes (make_dts ())
+let dump_dtb () = show_bytes (bytes_to_string (make_dtb (make_dts ())))
+
+(*
+let save_string_to_file s fname =
+ let out = open_out fname in
+ output_string out s;
+ close_out out;;
+
+ *)