diff options
author | Prashanth Mundkur <prashanth.mundkur@gmail.com> | 2019-01-16 10:24:17 -0800 |
---|---|---|
committer | Prashanth Mundkur <prashanth.mundkur@gmail.com> | 2019-01-16 10:24:17 -0800 |
commit | 254ed382c60fae295985fe7b83775adf116e49ba (patch) | |
tree | cd0e174f34b6332dab2aeca622e1f05b181d80cd /c_emulator | |
parent | 9d0282a0a52f0fa37e1d07827a4c0189dd01301c (diff) | |
download | sail-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 'c_emulator')
-rw-r--r-- | c_emulator/riscv_config.h | 7 | ||||
-rw-r--r-- | c_emulator/riscv_platform.c | 74 | ||||
-rw-r--r-- | c_emulator/riscv_platform.h | 29 | ||||
-rw-r--r-- | c_emulator/riscv_platform_impl.c | 29 | ||||
-rw-r--r-- | c_emulator/riscv_platform_impl.h | 28 | ||||
-rw-r--r-- | c_emulator/riscv_prelude.c | 32 | ||||
-rw-r--r-- | c_emulator/riscv_prelude.h | 10 | ||||
-rw-r--r-- | c_emulator/riscv_sail.h | 54 | ||||
-rw-r--r-- | c_emulator/riscv_sim.c | 723 |
9 files changed, 986 insertions, 0 deletions
diff --git a/c_emulator/riscv_config.h b/c_emulator/riscv_config.h new file mode 100644 index 0000000..f8f3eb3 --- /dev/null +++ b/c_emulator/riscv_config.h @@ -0,0 +1,7 @@ +#pragma once +#include <stdbool.h> + +extern bool config_print_instr; +extern bool config_print_reg; +extern bool config_print_mem_access; +extern bool config_print_platform; diff --git a/c_emulator/riscv_platform.c b/c_emulator/riscv_platform.c new file mode 100644 index 0000000..3587206 --- /dev/null +++ b/c_emulator/riscv_platform.c @@ -0,0 +1,74 @@ +#include "sail.h" +#include "rts.h" +#include "riscv_prelude.h" +#include "riscv_platform_impl.h" + +/* This file contains the definitions of the C externs of Sail model. */ + +static mach_bits reservation = 0; +static bool reservation_valid = false; + +bool plat_enable_dirty_update(unit u) +{ return rv_enable_dirty_update; } + +bool plat_enable_misaligned_access(unit u) +{ return rv_enable_misaligned; } + +bool plat_mtval_has_illegal_inst_bits(unit u) +{ return rv_mtval_has_illegal_inst_bits; } + +mach_bits plat_ram_base(unit u) +{ return rv_ram_base; } + +mach_bits plat_ram_size(unit u) +{ return rv_ram_size; } + +mach_bits plat_rom_base(unit u) +{ return rv_rom_base; } + +mach_bits plat_rom_size(unit u) +{ return rv_rom_size; } + +mach_bits plat_clint_base(unit u) +{ return rv_clint_base; } + +mach_bits plat_clint_size(unit u) +{ return rv_clint_size; } + +unit load_reservation(mach_bits addr) +{ + reservation = addr; + reservation_valid = true; + return UNIT; +} + +bool speculate_conditional(unit u) +{ return true; } + +bool match_reservation(mach_bits addr) +{ return reservation_valid && reservation == addr; } + +unit cancel_reservation(unit u) +{ + reservation_valid = false; + return UNIT; +} + +unit plat_term_write(mach_bits s) +{ char c = s & 0xff; + plat_term_write_impl(c); + return UNIT; +} + +void plat_insns_per_tick(sail_int *rop, unit u) +{ } + +mach_bits plat_htif_tohost(unit u) +{ + return rv_htif_tohost; +} + +unit memea(mach_bits len, sail_int n) +{ + return UNIT; +} diff --git a/c_emulator/riscv_platform.h b/c_emulator/riscv_platform.h new file mode 100644 index 0000000..728555e --- /dev/null +++ b/c_emulator/riscv_platform.h @@ -0,0 +1,29 @@ +#pragma once +#include "sail.h" + +bool plat_enable_dirty_update(unit); +bool plat_enable_misaligned_access(unit); +bool plat_mtval_has_illegal_inst_bits(unit); + +mach_bits plat_ram_base(unit); +mach_bits plat_ram_size(unit); +bool within_phys_mem(mach_bits, sail_int); + +mach_bits plat_rom_base(unit); +mach_bits plat_rom_size(unit); + +mach_bits plat_clint_base(unit); +mach_bits plat_clint_size(unit); + +bool speculate_conditional(unit); +unit load_reservation(mach_bits); +bool match_reservation(mach_bits); +unit cancel_reservation(unit); + +void plat_insns_per_tick(sail_int *rop, unit); + +unit plat_term_write(mach_bits); +mach_bits plat_htif_tohost(unit); + +unit memea(mach_bits, sail_int); + diff --git a/c_emulator/riscv_platform_impl.c b/c_emulator/riscv_platform_impl.c new file mode 100644 index 0000000..04a661c --- /dev/null +++ b/c_emulator/riscv_platform_impl.c @@ -0,0 +1,29 @@ +#include "riscv_platform_impl.h" +#include <unistd.h> +#include <stdio.h> + +/* Settings of the platform implementation, with common defaults. */ + +bool rv_enable_dirty_update = false; +bool rv_enable_misaligned = false; +bool rv_mtval_has_illegal_inst_bits = false; + +uint64_t rv_ram_base = UINT64_C(0x80000000); +uint64_t rv_ram_size = UINT64_C(0x80000000); + +uint64_t rv_rom_base = UINT64_C(0x1000); +uint64_t rv_rom_size = UINT64_C(0x100); + +uint64_t rv_clint_base = UINT64_C(0x2000000); +uint64_t rv_clint_size = UINT64_C(0xc0000); + +uint64_t rv_htif_tohost = UINT64_C(0x80001000); +uint64_t rv_insns_per_tick = UINT64_C(100); + +int term_fd = 1; // set during startup +void plat_term_write_impl(char c) +{ + if (write(term_fd, &c, sizeof(c)) < 0) { + fprintf(stderr, "Unable to write to terminal!\n"); + } +} diff --git a/c_emulator/riscv_platform_impl.h b/c_emulator/riscv_platform_impl.h new file mode 100644 index 0000000..85e25c9 --- /dev/null +++ b/c_emulator/riscv_platform_impl.h @@ -0,0 +1,28 @@ +#pragma once + +#include <stdbool.h> +#include <stdint.h> + +/* Settings of the platform implementation. */ + +#define DEFAULT_RSTVEC 0x00001000 +#define SAIL_XLEN 64 + +extern bool rv_enable_dirty_update; +extern bool rv_enable_misaligned; +extern bool rv_mtval_has_illegal_inst_bits; + +extern uint64_t rv_ram_base; +extern uint64_t rv_ram_size; + +extern uint64_t rv_rom_base; +extern uint64_t rv_rom_size; + +extern uint64_t rv_clint_base; +extern uint64_t rv_clint_size; + +extern uint64_t rv_htif_tohost; +extern uint64_t rv_insns_per_tick; + +extern int term_fd; +void plat_term_write_impl(char c); diff --git a/c_emulator/riscv_prelude.c b/c_emulator/riscv_prelude.c new file mode 100644 index 0000000..1621913 --- /dev/null +++ b/c_emulator/riscv_prelude.c @@ -0,0 +1,32 @@ +#include "riscv_prelude.h" +#include "riscv_config.h" + +unit print_string(sail_string prefix, sail_string msg) +{ + printf("%s%s\n", prefix, msg); + return UNIT; +} + +unit print_instr(sail_string s) +{ + if (config_print_instr) printf("%s\n", s); + return UNIT; +} + +unit print_reg(sail_string s) +{ + if (config_print_reg) printf("%s\n", s); + return UNIT; +} + +unit print_mem_access(sail_string s) +{ + if (config_print_mem_access) printf("%s\n", s); + return UNIT; +} + +unit print_platform(sail_string s) +{ + if (config_print_platform) printf("%s\n", s); + return UNIT; +} diff --git a/c_emulator/riscv_prelude.h b/c_emulator/riscv_prelude.h new file mode 100644 index 0000000..a296c7e --- /dev/null +++ b/c_emulator/riscv_prelude.h @@ -0,0 +1,10 @@ +#pragma once +#include "sail.h" +#include "rts.h" + +unit print_string(sail_string prefix, sail_string msg); + +unit print_instr(sail_string s); +unit print_reg(sail_string s); +unit print_mem_access(sail_string s); +unit print_platform(sail_string s); diff --git a/c_emulator/riscv_sail.h b/c_emulator/riscv_sail.h new file mode 100644 index 0000000..424b64b --- /dev/null +++ b/c_emulator/riscv_sail.h @@ -0,0 +1,54 @@ +/* Top-level interfaces to the Sail model. + Ideally, this would be autogenerated. + */ + +typedef int unit; +#define UNIT 0 +typedef uint64_t mach_bits; + +struct zMisa {mach_bits zMisa_chunk_0;}; +struct zMisa zmisa; + +void model_init(void); +void model_fini(void); + +unit zinit_platform(unit); +unit zinit_sys(unit); +bool zstep(sail_int); +unit ztick_clock(unit); +unit ztick_platform(unit); +unit z_set_Misa_C(struct zMisa*, mach_bits); + +#ifdef RVFI_DII +unit zrvfi_set_instr_packet(mach_bits); +mach_bits zrvfi_get_cmd(unit); +bool zrvfi_step(sail_int); +unit zrvfi_zzero_exec_packet(unit); +unit zrvfi_halt_exec_packet(unit); +void zrvfi_get_exec_packet(sail_bits *rop, unit); +#endif + +extern bool zhtif_done; +extern mach_bits zhtif_exit_code; +extern bool have_exception; + +/* machine state */ + +extern uint32_t zcur_privilege; + +extern mach_bits zPC; + +extern mach_bits + zx1, zx2, zx3, zx4, zx5, zx6, zx7, + zx8, zx9, zx10, zx11, zx12, zx13, zx14, zx15, + zx16, zx17, zx18, zx19, zx20, zx21, zx22, zx23, + zx24, zx25, zx26, zx27, zx28, zx29, zx30, zx31; + +extern mach_bits zmstatus; +extern mach_bits zmepc, zmtval; +extern mach_bits zsepc, zstval; + +struct zMcause {mach_bits zMcause_chunk_0;}; +struct zMcause zmcause, zscause; + +extern mach_bits zminstret; diff --git a/c_emulator/riscv_sim.c b/c_emulator/riscv_sim.c new file mode 100644 index 0000000..2a70167 --- /dev/null +++ b/c_emulator/riscv_sim.c @@ -0,0 +1,723 @@ +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <netinet/ip.h> +#include <fcntl.h> + +#include "elf.h" +#include "sail.h" +#include "rts.h" +#include "riscv_platform.h" +#include "riscv_platform_impl.h" +#include "riscv_sail.h" + +#ifdef ENABLE_SPIKE +#include "tv_spike_intf.h" +#else +struct tv_spike_t; +#endif + +/* Selected CSRs from riscv-isa-sim/riscv/encoding.h */ +#define CSR_STVEC 0x105 +#define CSR_SEPC 0x141 +#define CSR_SCAUSE 0x142 +#define CSR_STVAL 0x143 + +#define CSR_MSTATUS 0x300 +#define CSR_MISA 0x301 +#define CSR_MEDELEG 0x302 +#define CSR_MIDELEG 0x303 +#define CSR_MIE 0x304 +#define CSR_MTVEC 0x305 +#define CSR_MEPC 0x341 +#define CSR_MCAUSE 0x342 +#define CSR_MTVAL 0x343 +#define CSR_MIP 0x344 + +static bool do_dump_dts = false; +static bool disable_compressed = false; +static bool do_show_times = false; +struct tv_spike_t *s = NULL; +char *term_log = NULL; +char *dtb_file = NULL; +unsigned char *dtb = NULL; +size_t dtb_len = 0; +#ifdef RVFI_DII +static bool rvfi_dii = false; +static int rvfi_dii_port; +static int rvfi_dii_sock; +#endif + +unsigned char *spike_dtb = NULL; +size_t spike_dtb_len = 0; + +bool config_print_instr = true; +bool config_print_reg = true; +bool config_print_mem_access = true; +bool config_print_platform = true; + +struct timeval init_start, init_end, run_end; +int total_insns = 0; + +static struct option options[] = { + {"enable-dirty", no_argument, 0, 'd'}, + {"enable-misaligned", no_argument, 0, 'm'}, + {"ram-size", required_argument, 0, 'z'}, + {"disable-compressed", no_argument, 0, 'C'}, + {"mtval-has-illegal-inst-bits", no_argument, 0, 'i'}, + {"dump-dts", no_argument, 0, 's'}, + {"device-tree-blob", required_argument, 0, 'b'}, + {"terminal-log", required_argument, 0, 't'}, + {"show-times", required_argument, 0, 'p'}, +#ifdef RVFI_DII + {"rvfi-dii", required_argument, 0, 'r'}, +#endif + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} +}; + +static void print_usage(const char *argv0, int ec) +{ +#ifdef RVFI_DII + fprintf(stdout, "Usage: %s [options] <elf_file>\n %s [options] -r <port>\n", argv0, argv0); +#else + fprintf(stdout, "Usage: %s [options] <elf_file>\n", argv0); +#endif + struct option *opt = options; + while (opt->name) { + fprintf(stdout, "\t -%c\t %s\n", (char)opt->val, opt->name); + opt++; + } + exit(ec); +} + +static void dump_dts(void) +{ +#ifdef ENABLE_SPIKE + size_t dts_len = 0; + struct tv_spike_t *s = tv_init("RV64IMAC", rv_ram_size, 0); + tv_get_dts(s, NULL, &dts_len); + if (dts_len > 0) { + unsigned char *dts = (unsigned char *)malloc(dts_len + 1); + dts[dts_len] = '\0'; + tv_get_dts(s, dts, &dts_len); + fprintf(stdout, "%s\n", dts); + } +#else + fprintf(stdout, "Spike linkage is currently needed to generate DTS.\n"); +#endif + exit(0); +} + +static void read_dtb(const char *path) +{ + int fd = open(path, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Unable to read DTB file %s: %s\n", path, strerror(errno)); + exit(1); + } + struct stat st; + if (fstat(fd, &st) < 0) { + fprintf(stderr, "Unable to stat DTB file %s: %s\n", path, strerror(errno)); + exit(1); + } + char *m = (char *)mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (m == MAP_FAILED) { + fprintf(stderr, "Unable to map DTB file %s: %s\n", path, strerror(errno)); + exit(1); + } + dtb = (unsigned char *)malloc(st.st_size); + if (dtb == NULL) { + fprintf(stderr, "Cannot allocate DTB from file %s!\n", path); + exit(1); + } + memcpy(dtb, m, st.st_size); + dtb_len = st.st_size; + munmap(m, st.st_size); + close(fd); + + fprintf(stdout, "Read %ld bytes of DTB from %s.\n", dtb_len, path); +} + +char *process_args(int argc, char **argv) +{ + int c, idx = 1; + uint64_t ram_size = 0; + while(true) { + c = getopt_long(argc, argv, "dmCspz:b:t:v:hr:", options, &idx); + if (c == -1) break; + switch (c) { + case 'd': + fprintf(stderr, "enabling dirty update.\n"); + rv_enable_dirty_update = true; + break; + case 'm': + fprintf(stderr, "enabling misaligned access.\n"); + rv_enable_misaligned = true; + break; + case 'C': + disable_compressed = true; + break; + case 'i': + rv_mtval_has_illegal_inst_bits = true; + case 's': + do_dump_dts = true; + break; + case 'p': + do_show_times = true; + break; + case 'z': + ram_size = atol(optarg); + if (ram_size) { + fprintf(stderr, "setting ram-size to %lu MB\n", ram_size); + rv_ram_size = ram_size << 20; + } + break; + case 'b': + dtb_file = strdup(optarg); + break; + case 't': + term_log = strdup(optarg); + break; + case 'h': + print_usage(argv[0], 0); + break; +#ifdef RVFI_DII + case 'r': + rvfi_dii = true; + rvfi_dii_port = atoi(optarg); + break; +#endif + default: + fprintf(stderr, "Unrecognized optchar %c\n", c); + print_usage(argv[0], 1); + } + } + if (do_dump_dts) dump_dts(); +#ifdef RVFI_DII + if (idx > argc || (idx == argc && !rvfi_dii)) print_usage(argv[0], 0); +#else + if (idx >= argc) print_usage(argv[0], 0); +#endif + if (term_log == NULL) term_log = strdup("term.log"); + if (dtb_file) read_dtb(dtb_file); + +#ifdef RVFI_DII + if (!rvfi_dii) +#endif + fprintf(stdout, "Running file %s.\n", argv[optind]); + return argv[optind]; +} + +uint64_t load_sail(char *f) +{ + bool is32bit; + uint64_t entry; + load_elf(f, &is32bit, &entry); + if (is32bit) { + fprintf(stderr, "32-bit RISC-V not yet supported.\n"); + exit(1); + } + fprintf(stdout, "ELF Entry @ %lx\n", entry); + /* locate htif ports */ + if (lookup_sym(f, "tohost", &rv_htif_tohost) < 0) { + fprintf(stderr, "Unable to locate htif tohost port.\n"); + exit(1); + } + fprintf(stderr, "tohost located at %0" PRIx64 "\n", rv_htif_tohost); + return entry; +} + +void init_spike(const char *f, uint64_t entry, uint64_t ram_size) +{ +#ifdef ENABLE_SPIKE + bool mismatch = false; + s = tv_init("RV64IMAC", ram_size, 1); + if (tv_is_dirty_enabled(s) != rv_enable_dirty_update) { + mismatch = true; + fprintf(stderr, "inconsistent enable-dirty-update setting: spike %s, sail %s\n", + tv_is_dirty_enabled(s) ? "on" : "off", + rv_enable_dirty_update ? "on" : "off"); + } + if (tv_is_misaligned_enabled(s) != rv_enable_misaligned) { + mismatch = true; + fprintf(stderr, "inconsistent enable-misaligned-access setting: spike %s, sail %s\n", + tv_is_misaligned_enabled(s) ? "on" : "off", + rv_enable_misaligned ? "on" : "off"); + } + if (tv_ram_size(s) != rv_ram_size) { + mismatch = true; + fprintf(stderr, "inconsistent ram-size setting: spike %lx, sail %lx\n", + tv_ram_size(s), rv_ram_size); + } + if (mismatch) exit(1); + + /* The initialization order below matters. */ + tv_set_verbose(s, 1); + tv_set_dtb_in_rom(s, 1); + tv_load_elf(s, f); + tv_reset(s); + + /* sync the insns per tick */ + rv_insns_per_tick = tv_get_insns_per_tick(s); + + /* get DTB from spike */ + tv_get_dtb(s, NULL, &spike_dtb_len); + if (spike_dtb_len > 0) { + spike_dtb = (unsigned char *)malloc(spike_dtb_len + 1); + spike_dtb[spike_dtb_len] = '\0'; + if (!tv_get_dtb(s, spike_dtb, &spike_dtb_len)) { + fprintf(stderr, "Got %ld bytes of dtb at %p\n", spike_dtb_len, spike_dtb); + } else { + fprintf(stderr, "Error getting DTB from Spike.\n"); + exit(1); + } + } else { + fprintf(stderr, "No DTB available from Spike.\n"); + } +#else + s = NULL; +#endif +} + +void tick_spike() +{ +#ifdef ENABLE_SPIKE + tv_tick_clock(s); + tv_step_io(s); +#endif +} + +void init_sail_reset_vector(uint64_t entry) +{ +#define RST_VEC_SIZE 8 + uint32_t reset_vec[RST_VEC_SIZE] = { + 0x297, // auipc t0,0x0 + 0x28593 + (RST_VEC_SIZE * 4 << 20), // addi a1, t0, &dtb + 0xf1402573, // csrr a0, mhartid + SAIL_XLEN == 32 ? + 0x0182a283u : // lw t0,24(t0) + 0x0182b283u, // ld t0,24(t0) + 0x28067, // jr t0 + 0, + (uint32_t) (entry & 0xffffffff), + (uint32_t) (entry >> 32) + }; + + rv_rom_base = DEFAULT_RSTVEC; + uint64_t addr = rv_rom_base; + for (int i = 0; i < sizeof(reset_vec); i++) + write_mem(addr++, (uint64_t)((char *)reset_vec)[i]); + + if (dtb && dtb_len) { + for (size_t i = 0; i < dtb_len; i++) + write_mem(addr++, dtb[i]); + } + +#ifdef ENABLE_SPIKE + if (dtb && dtb_len) { + // Ensure that Spike's DTB matches the one provided. + bool matched = dtb_len == spike_dtb_len; + if (matched) { + for (size_t i = 0; i < dtb_len; i++) + matched = matched && (dtb[i] == spike_dtb[i]); + } + if (!matched) { + fprintf(stderr, "Provided DTB does not match Spike's!\n"); + exit(1); + } + } else { + if (spike_dtb_len > 0) { + // Use the DTB from Spike. + for (size_t i = 0; i < spike_dtb_len; i++) + write_mem(addr++, spike_dtb[i]); + } else { + fprintf(stderr, "Running without rom device tree.\n"); + } + } +#endif + + /* zero-fill to page boundary */ + const int align = 0x1000; + uint64_t rom_end = (addr + align -1)/align * align; + for (int i = addr; i < rom_end; i++) + write_mem(addr++, 0); + + /* set rom size */ + rv_rom_size = rom_end - rv_rom_base; + /* boot at reset vector */ + zPC = rv_rom_base; +} + +void init_sail(uint64_t elf_entry) +{ + model_init(); + zinit_platform(UNIT); + zinit_sys(UNIT); +#ifdef RVFI_DII + if (rvfi_dii) { + rv_ram_base = UINT64_C(0x80000000); + rv_ram_size = UINT64_C(0x10000); + rv_rom_base = UINT64_C(0); + rv_rom_size = UINT64_C(0); + zPC = elf_entry; + } else +#endif + init_sail_reset_vector(elf_entry); + if (disable_compressed) + z_set_Misa_C(&zmisa, 0); +} + +int init_check(struct tv_spike_t *s) +{ + int passed = 1; +#ifdef ENABLE_SPIKE + passed &= tv_check_csr(s, CSR_MISA, zmisa.zMisa_chunk_0); +#endif + return passed; +} + +void finish(int ec) +{ + model_fini(); +#ifdef ENABLE_SPIKE + tv_free(s); +#endif + if (gettimeofday(&run_end, NULL) < 0) { + fprintf(stderr, "Cannot gettimeofday: %s\n", strerror(errno)); + exit(1); + } + if (do_show_times) { + int init_msecs = (init_end.tv_sec - init_start.tv_sec)*1000 + (init_end.tv_usec - init_start.tv_usec)/1000; + int exec_msecs = (run_end.tv_sec - init_end.tv_sec)*1000 + (run_end.tv_usec - init_end.tv_usec)/1000; + double Kips = ((double)total_insns)/((double)exec_msecs); + fprintf(stderr, "Initialization: %d msecs\n", init_msecs); + fprintf(stderr, "Execution: %d msecs\n", exec_msecs); + fprintf(stderr, "Instructions: %d\n", total_insns); + fprintf(stderr, "Perf: %.3f Kips\n", Kips); + } + exit(ec); +} + +int compare_states(struct tv_spike_t *s) +{ + int passed = 1; + +#ifdef ENABLE_SPIKE +#define TV_CHECK(reg, spike_reg, sail_reg) \ + passed &= tv_check_ ## reg(s, spike_reg, sail_reg); + + // fix default C enum map for cur_privilege + uint8_t priv = (zcur_privilege == 2) ? 3 : zcur_privilege; + passed &= tv_check_priv(s, priv); + + passed &= tv_check_pc(s, zPC); + + TV_CHECK(gpr, 1, zx1); + TV_CHECK(gpr, 2, zx2); + TV_CHECK(gpr, 3, zx3); + TV_CHECK(gpr, 4, zx4); + TV_CHECK(gpr, 5, zx5); + TV_CHECK(gpr, 6, zx6); + TV_CHECK(gpr, 7, zx7); + TV_CHECK(gpr, 8, zx8); + TV_CHECK(gpr, 9, zx9); + TV_CHECK(gpr, 10, zx10); + TV_CHECK(gpr, 11, zx11); + TV_CHECK(gpr, 12, zx12); + TV_CHECK(gpr, 13, zx13); + TV_CHECK(gpr, 14, zx14); + TV_CHECK(gpr, 15, zx15); + TV_CHECK(gpr, 15, zx15); + TV_CHECK(gpr, 16, zx16); + TV_CHECK(gpr, 17, zx17); + TV_CHECK(gpr, 18, zx18); + TV_CHECK(gpr, 19, zx19); + TV_CHECK(gpr, 20, zx20); + TV_CHECK(gpr, 21, zx21); + TV_CHECK(gpr, 22, zx22); + TV_CHECK(gpr, 23, zx23); + TV_CHECK(gpr, 24, zx24); + TV_CHECK(gpr, 25, zx25); + TV_CHECK(gpr, 25, zx25); + TV_CHECK(gpr, 26, zx26); + TV_CHECK(gpr, 27, zx27); + TV_CHECK(gpr, 28, zx28); + TV_CHECK(gpr, 29, zx29); + TV_CHECK(gpr, 30, zx30); + TV_CHECK(gpr, 31, zx31); + + /* some selected CSRs for now */ + + TV_CHECK(csr, CSR_MCAUSE, zmcause.zMcause_chunk_0); + TV_CHECK(csr, CSR_MEPC, zmepc); + TV_CHECK(csr, CSR_MTVAL, zmtval); + TV_CHECK(csr, CSR_MSTATUS, zmstatus); + + TV_CHECK(csr, CSR_SCAUSE, zscause.zMcause_chunk_0); + TV_CHECK(csr, CSR_SEPC, zsepc); + TV_CHECK(csr, CSR_STVAL, zstval); + +#undef TV_CHECK +#endif + + return passed; +} + +void flush_logs(void) +{ + fprintf(stderr, "\n"); + fflush(stderr); + fprintf(stdout, "\n"); + fflush(stdout); +} + +#ifdef RVFI_DII +void rvfi_send_trace(void) { + sail_bits packet; + CREATE(lbits)(&packet); + zrvfi_get_exec_packet(&packet, UNIT); + if (packet.len % 8 != 0) { + fprintf(stderr, "RVFI-DII trace packet not byte aligned: %d\n", (int)packet.len); + exit(1); + } + unsigned char bytes[packet.len / 8]; + /* mpz_export might not write all of the null bytes */ + memset(bytes, 0, sizeof(bytes)); + mpz_export(bytes, NULL, -1, 1, 0, 0, *(packet.bits)); + if (write(rvfi_dii_sock, bytes, packet.len / 8) == -1) { + fprintf(stderr, "Writing RVFI DII trace failed: %s", strerror(errno)); + exit(1); + } + KILL(lbits)(&packet); +} +#endif + +void run_sail(void) +{ + bool spike_done; + bool stepped; + bool diverged = false; + + /* initialize the step number */ + mach_int step_no = 0; + int insn_cnt = 0; +#ifdef RVFI_DII + bool need_instr = true; +#endif + + while (!zhtif_done) { +#ifdef RVFI_DII + if (rvfi_dii) { + if (need_instr) { + mach_bits instr_bits; + int res = read(rvfi_dii_sock, &instr_bits, sizeof(instr_bits)); + if (res == 0) { + rvfi_dii = false; + return; + } + if (res < sizeof(instr_bits)) { + fprintf(stderr, "Reading RVFI DII command failed: insufficient input"); + exit(1); + } + if (res == -1) { + fprintf(stderr, "Reading RVFI DII command failed: %s", strerror(errno)); + exit(1); + } + zrvfi_set_instr_packet(instr_bits); + zrvfi_zzero_exec_packet(UNIT); + mach_bits cmd = zrvfi_get_cmd(UNIT); + switch (cmd) { + case 0: /* EndOfTrace */ + zrvfi_halt_exec_packet(UNIT); + rvfi_send_trace(); + return; + case 1: /* Instruction */ + break; + default: + fprintf(stderr, "Unknown RVFI-DII command: %d\n", (int)cmd); + exit(1); + } + } + sail_int sail_step; + CREATE(sail_int)(&sail_step); + CONVERT_OF(sail_int, mach_int)(&sail_step, step_no); + stepped = zrvfi_step(sail_step); + if (have_exception) goto step_exception; + flush_logs(); + KILL(sail_int)(&sail_step); + if (stepped) { + need_instr = true; + rvfi_send_trace(); + } else + need_instr = false; + } else +#endif + { /* run a Sail step */ + sail_int sail_step; + CREATE(sail_int)(&sail_step); + CONVERT_OF(sail_int, mach_int)(&sail_step, step_no); + stepped = zstep(sail_step); + if (have_exception) goto step_exception; + flush_logs(); + KILL(sail_int)(&sail_step); + } + if (stepped) { + step_no++; + insn_cnt++; + total_insns++; + } + +#ifdef ENABLE_SPIKE + { /* run a Spike step */ + tv_step(s); + spike_done = tv_is_done(s); + flush_logs(); + } + + if (zhtif_done) { + if (!spike_done) { + fprintf(stdout, "Sail done (exit-code %ld), but not Spike!\n", zhtif_exit_code); + exit(1); + } + } else { + if (spike_done) { + fprintf(stdout, "Spike done, but not Sail!\n"); + exit(1); + } + } + if (!compare_states(s)) { + diverged = true; + break; + } +#endif + if (zhtif_done) { + /* check exit code */ + if (zhtif_exit_code == 0) + fprintf(stdout, "SUCCESS\n"); + else + fprintf(stdout, "FAILURE: %lu\n", zhtif_exit_code); + } + + if (insn_cnt == rv_insns_per_tick) { + insn_cnt = 0; + ztick_clock(UNIT); + ztick_platform(UNIT); + + tick_spike(); + } + } + + dump_state: + if (diverged) { + /* TODO */ + } + finish(diverged); + + step_exception: + fprintf(stderr, "Sail exception!"); + goto dump_state; +} + +void init_logs() +{ +#ifdef ENABLE_SPIKE + // The Spike interface uses stdout for terminal output, and stderr for logs. + // Do the same here. + if (dup2(1, 2) < 0) { + fprintf(stderr, "Unable to dup 1 -> 2: %s\n", strerror(errno)); + exit(1); + } +#endif + + if ((term_fd = open(term_log, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR)) < 0) { + fprintf(stderr, "Cannot create terminal log '%s': %s\n", term_log, strerror(errno)); + exit(1); + } +} + +int main(int argc, char **argv) +{ + char *file = process_args(argc, argv); + init_logs(); + + if (gettimeofday(&init_start, NULL) < 0) { + fprintf(stderr, "Cannot gettimeofday: %s\n", strerror(errno)); + exit(1); + } + +#ifdef RVFI_DII + uint64_t entry; + if (rvfi_dii) { + entry = 0x80000000; + int listen_sock = socket(AF_INET, SOCK_STREAM, 0); + if (listen_sock == -1) { + fprintf(stderr, "Unable to create socket: %s", strerror(errno)); + return 1; + } + int opt = 1; + if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) { + fprintf(stderr, "Unable to set reuseaddr on socket: %s", strerror(errno)); + return 1; + } + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = INADDR_ANY, + .sin_port = htons(rvfi_dii_port) + }; + if (bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + fprintf(stderr, "Unable to set bind socket: %s", strerror(errno)); + return 1; + } + if (listen(listen_sock, 1) == -1) { + fprintf(stderr, "Unable to listen on socket: %s", strerror(errno)); + return 1; + } + printf("Waiting for connection\n"); + rvfi_dii_sock = accept(listen_sock, NULL, NULL); + if (rvfi_dii_sock == -1) { + fprintf(stderr, "Unable to accept connection on socket: %s", strerror(errno)); + return 1; + } + close(listen_sock); + printf("Connected\n"); + } else + entry = load_sail(file); +#else + uint64_t entry = load_sail(file); +#endif + + /* initialize spike before sail so that we can access the device-tree blob, + * until we roll our own. + */ + init_spike(file, entry, rv_ram_size); + init_sail(entry); + + if (!init_check(s)) finish(1); + + if (gettimeofday(&init_end, NULL) < 0) { + fprintf(stderr, "Cannot gettimeofday: %s\n", strerror(errno)); + exit(1); + } + + do { + run_sail(); +#ifndef RVFI_DII + } while (0); +#else + model_fini(); + if (rvfi_dii) { + /* Reset for next test */ + init_sail(entry); + } + } while (rvfi_dii); +#endif + flush_logs(); +} |