summaryrefslogtreecommitdiff
path: root/lib/int128/rts.c
diff options
context:
space:
mode:
authorAlasdair2019-05-05 16:24:02 +0100
committerAlasdair2019-05-05 19:02:05 +0100
commit39168f905eb9e671813cfc43309ddae44828123a (patch)
tree21d9e5fb2b7758aeed2aea1f6873a22750397477 /lib/int128/rts.c
parentaeb4e23aeb12a99568dcc49f0d39ae86c7bd5065 (diff)
C: Add option to compile using __int128 rather than GMP
Only requires a very small change to c_backend.ml. Most of this commit is duplication of the builtins and runtime in lib/int128. But the actual differences in those files is also fairly minor could be handled by some simple ifdefs for the integer builtins.
Diffstat (limited to 'lib/int128/rts.c')
-rw-r--r--lib/int128/rts.c529
1 files changed, 529 insertions, 0 deletions
diff --git a/lib/int128/rts.c b/lib/int128/rts.c
new file mode 100644
index 00000000..86c305c9
--- /dev/null
+++ b/lib/int128/rts.c
@@ -0,0 +1,529 @@
+#include<string.h>
+#include<getopt.h>
+#include<inttypes.h>
+
+#include"sail.h"
+#include"rts.h"
+#include"elf.h"
+
+static uint64_t g_elf_entry;
+uint64_t g_cycle_count = 0;
+static uint64_t g_cycle_limit;
+
+void sail_match_failure(sail_string msg)
+{
+ fprintf(stderr, "Pattern match failure in %s\n", msg);
+ exit(EXIT_FAILURE);
+}
+
+unit sail_assert(bool b, sail_string msg)
+{
+ if (b) return UNIT;
+ fprintf(stderr, "Assertion failed: %s\n", msg);
+ exit(EXIT_FAILURE);
+}
+
+unit sail_exit(unit u)
+{
+ fprintf(stderr, "[Sail] Exiting after %" PRIu64 " cycles\n", g_cycle_count);
+ exit(EXIT_SUCCESS);
+ return UNIT;
+}
+
+static uint64_t g_verbosity = 0;
+
+fbits sail_get_verbosity(const unit u)
+{
+ return g_verbosity;
+}
+
+bool g_sleeping = false;
+
+unit sleep_request(const unit u)
+{
+ fprintf(stderr, "Sail CPU model going to sleep\n");
+ g_sleeping = true;
+ return UNIT;
+}
+
+unit wakeup_request(const unit u)
+{
+ fprintf(stderr, "Sail CPU model waking up\n");
+ g_sleeping = false;
+ return UNIT;
+}
+
+bool sleeping(const unit u)
+{
+ return g_sleeping;
+}
+
+/* ***** Sail memory builtins ***** */
+
+/*
+ * We organise memory available to the sail model into a linked list
+ * of dynamically allocated MASK + 1 size blocks.
+ */
+struct block {
+ uint64_t block_id;
+ uint8_t *mem;
+ struct block *next;
+};
+
+struct block *sail_memory = NULL;
+
+struct tag_block {
+ uint64_t block_id;
+ bool *mem;
+ struct tag_block *next;
+};
+
+struct tag_block *sail_tags = NULL;
+
+/*
+ * Must be one less than a power of two.
+ */
+uint64_t MASK = 0xFFFFFFul;
+
+/*
+ * All sail vectors are at least 64-bits, but only the bottom 8 bits
+ * are used in the second argument.
+ */
+void write_mem(uint64_t address, uint64_t byte)
+{
+ uint64_t mask = address & ~MASK;
+ uint64_t offset = address & MASK;
+
+ //if ((byte >= 97 && byte <= 122) || (byte >= 64 && byte <= 90) || (byte >= 48 && byte <= 57) || byte == 10 || byte == 32) {
+ // fprintf(stderr, "%c", (char) byte);
+ //}
+
+ struct block *current = sail_memory;
+
+ while (current != NULL) {
+ if (current->block_id == mask) {
+ current->mem[offset] = (uint8_t) byte;
+ return;
+ } else {
+ current = current->next;
+ }
+ }
+
+ /*
+ * If we couldn't find a block matching the mask, allocate a new
+ * one, write the byte, and put it at the front of the block list.
+ */
+ fprintf(stderr, "[Sail] Allocating new block 0x%" PRIx64 "\n", mask);
+ struct block *new_block = malloc(sizeof(struct block));
+ new_block->block_id = mask;
+ new_block->mem = calloc(MASK + 1, sizeof(uint8_t));
+ new_block->mem[offset] = (uint8_t) byte;
+ new_block->next = sail_memory;
+ sail_memory = new_block;
+}
+
+uint64_t read_mem(uint64_t address)
+{
+ uint64_t mask = address & ~MASK;
+ uint64_t offset = address & MASK;
+
+ struct block *current = sail_memory;
+
+ while (current != NULL) {
+ if (current->block_id == mask) {
+ return (uint64_t) current->mem[offset];
+ } else {
+ current = current->next;
+ }
+ }
+
+ return 0x00;
+}
+
+unit write_tag_bool(const uint64_t address, const bool tag)
+{
+ uint64_t mask = address & ~MASK;
+ uint64_t offset = address & MASK;
+
+ struct tag_block *current = sail_tags;
+
+ while (current != NULL) {
+ if (current->block_id == mask) {
+ current->mem[offset] = tag;
+ return UNIT;
+ } else {
+ current = current->next;
+ }
+ }
+
+ /*
+ * If we couldn't find a block matching the mask, allocate a new
+ * one, write the byte, and put it at the front of the block list.
+ */
+ fprintf(stderr, "[Sail] Allocating new tag block 0x%" PRIx64 "\n", mask);
+ struct tag_block *new_block = malloc(sizeof(struct tag_block));
+ new_block->block_id = mask;
+ new_block->mem = calloc(MASK + 1, sizeof(bool));
+ new_block->mem[offset] = tag;
+ new_block->next = sail_tags;
+ sail_tags = new_block;
+
+ return UNIT;
+}
+
+bool read_tag_bool(const uint64_t address)
+{
+ uint64_t mask = address & ~MASK;
+ uint64_t offset = address & MASK;
+
+ struct tag_block *current = sail_tags;
+
+ while (current != NULL) {
+ if (current->block_id == mask) {
+ return current->mem[offset];
+ } else {
+ current = current->next;
+ }
+ }
+
+ return false;
+}
+
+void kill_mem()
+{
+ while (sail_memory != NULL) {
+ struct block *next = sail_memory->next;
+
+ free(sail_memory->mem);
+ free(sail_memory);
+
+ sail_memory = next;
+ }
+
+ while (sail_tags != NULL) {
+ struct tag_block *next = sail_tags->next;
+
+ free(sail_tags->mem);
+ free(sail_tags);
+
+ sail_tags = next;
+ }
+}
+
+// ***** Memory builtins *****
+
+mpz_t write_buf;
+
+bool write_ram(const sail_int addr_size, // Either 32 or 64
+ const sail_int data_size_mpz, // Number of bytes
+ const lbits hex_ram, // Currently unused
+ const lbits addr_bv,
+ const lbits data)
+{
+ uint64_t addr = mpz_get_ui(*addr_bv.bits);
+ uint64_t data_size = (uint64_t) data_size_mpz;
+
+ if (data_size <= 8) {
+ uint64_t bytes = mpz_get_ui(*data.bits);
+
+ for(uint64_t i = 0; i < data_size; ++i) {
+ write_mem(addr + i, bytes & 0xFF);
+ bytes >>= 8;
+ }
+
+ return true;
+ } else {
+ mpz_set(write_buf, *data.bits);
+
+ uint64_t byte;
+ for(uint64_t i = 0; i < data_size; ++i) {
+ // Take the 8 low bits of write_buf and write to addr.
+ byte = mpz_get_ui(write_buf) & 0xFF;
+ write_mem(addr + i, byte);
+
+ // Then shift buf 8 bits right.
+ mpz_fdiv_q_2exp(write_buf, write_buf, 8);
+ }
+
+ return true;
+ }
+}
+
+sbits fast_read_ram(const int64_t data_size,
+ const uint64_t addr)
+{
+ uint64_t r = 0;
+
+ uint64_t byte;
+ for(uint64_t i = (uint64_t) data_size; i > 0; --i) {
+ byte = read_mem(addr + (i - 1));
+ r = r << 8;
+ r = r + byte;
+ }
+ sbits res = {.len = data_size * 8, .bits = r };
+ return res;
+}
+
+mpz_t read_buf;
+
+void read_ram(lbits *data,
+ const sail_int addr_size,
+ const sail_int data_size_mpz,
+ const lbits hex_ram,
+ const lbits addr_bv)
+{
+ uint64_t addr = mpz_get_ui(*addr_bv.bits);
+ uint64_t data_size = (uint64_t) data_size_mpz;
+
+ if (data_size <= 8) {
+ uint64_t byte = 0;
+
+ for(uint64_t i = data_size; i > 0; --i) {
+ byte = byte << 8;
+ byte += read_mem(addr + (i - 1));
+ }
+
+ mpz_set_ui(*data->bits, byte);
+ data->len = data_size * 8;
+ } else {
+ mpz_set_ui(*data->bits, 0);
+ data->len = data_size * 8;
+
+ for(uint64_t i = data_size; i > 0; --i) {
+ mpz_set_ui(read_buf, read_mem(addr + (i - 1)));
+ mpz_mul_2exp(*data->bits, *data->bits, 8);
+ mpz_add(*data->bits, *data->bits, read_buf);
+ }
+ }
+}
+
+unit load_raw(fbits addr, const sail_string file)
+{
+ FILE *fp = fopen(file, "r");
+
+ if (!fp) {
+ fprintf(stderr, "[Sail] Raw file %s could not be loaded\n", file);
+ exit(EXIT_FAILURE);
+ }
+
+ uint64_t byte;
+ while ((byte = (uint64_t)fgetc(fp)) != EOF) {
+ write_mem(addr, byte);
+ addr++;
+ }
+
+ return UNIT;
+}
+
+void load_image(char *file)
+{
+ FILE *fp = fopen(file, "r");
+
+ if (!fp) {
+ fprintf(stderr, "[Sail] Image file %s could not be loaded\n", file);
+ exit(EXIT_FAILURE);
+ }
+
+ char *addr = NULL;
+ char *data = NULL;
+ size_t len = 0;
+
+ while (true) {
+ ssize_t addr_len = getline(&addr, &len, fp);
+ if (addr_len == -1) break;
+ ssize_t data_len = getline(&data, &len, fp);
+ if (data_len == -1) break;
+
+ if (!strcmp(addr, "elf_entry\n")) {
+ if (sscanf(data, "%" PRIu64 "\n", &g_elf_entry) != 1) {
+ fprintf(stderr, "[Sail] Failed to parse elf_entry\n");
+ exit(EXIT_FAILURE);
+ };
+ fprintf(stderr, "[Sail] Elf entry point: %" PRIx64 "\n", g_elf_entry);
+ } else {
+ write_mem((uint64_t) atoll(addr), (uint64_t) atoll(data));
+ }
+ }
+
+ free(addr);
+ free(data);
+ fclose(fp);
+}
+
+/* ***** ELF functions ***** */
+
+sail_int elf_entry(const unit u)
+{
+ return (__int128) g_elf_entry;
+}
+
+sail_int elf_tohost(const unit u)
+{
+ return (__int128) 0;
+}
+
+/* ***** Cycle limit ***** */
+
+/* NB Also increments cycle_count */
+bool cycle_limit_reached(const unit u)
+{
+ return ++g_cycle_count >= g_cycle_limit && g_cycle_limit != 0;
+}
+
+unit cycle_count(const unit u)
+{
+ if (cycle_limit_reached(UNIT)) {
+ printf("\n[Sail] TIMEOUT: exceeded %" PRId64 " cycles\n", g_cycle_limit);
+ exit(EXIT_SUCCESS);
+ }
+ return UNIT;
+}
+
+sail_int get_cycle_count(const unit u)
+{
+ return (__int128) g_cycle_count;
+}
+
+/* ***** Argument Parsing ***** */
+
+static struct option options[] = {
+ {"binary", required_argument, 0, 'b'},
+ {"cyclelimit", required_argument, 0, 'l'},
+ {"config", required_argument, 0, 'C'},
+ {"elf", required_argument, 0, 'e'},
+ {"entry", required_argument, 0, 'n'},
+ {"image", required_argument, 0, 'i'},
+ {"verbosity", required_argument, 0, 'v'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+};
+
+static void print_usage()
+{
+ struct option *opt = options;
+ while (opt->name) {
+ printf("\t -%c\t %s\n", (char)opt->val, opt->name);
+ opt++;
+ }
+ exit(EXIT_SUCCESS);
+}
+
+int process_arguments(int argc, char *argv[])
+{
+ int c;
+ bool elf_entry_set = false;
+ uint64_t elf_entry;
+
+ while (true) {
+ int option_index = 0;
+ c = getopt_long(argc, argv, "e:n:i:b:l:C:h", options, &option_index);
+
+ if (c == -1) break;
+
+ switch (c) {
+ case 'C': {
+ char arg[100];
+ uint64_t value;
+ if (sscanf(optarg, "%99[a-zA-Z0-9_-.]=0x%" PRIx64, arg, &value) == 2) {
+ // fprintf(stderr, "Got hex flag %s %" PRIx64 "\n", arg, value);
+ // do nothing
+ } else if (sscanf(optarg, "%99[a-zA-Z0-9_-.]=%" PRId64, arg, &value) == 2) {
+ // fprintf(stderr, "Got decimal flag %s %" PRIx64 "\n", arg, value);
+ // do nothing
+ } else {
+ fprintf(stderr, "Could not parse argument %s\n", optarg);
+#ifdef HAVE_SETCONFIG
+ z__ListConfig(UNIT);
+#endif
+ return -1;
+ };
+#ifdef HAVE_SETCONFIG
+ mpz_t s_value;
+ mpz_init_set_ui(s_value, value);
+ z__SetConfig(arg, s_value);
+ mpz_clear(s_value);
+#else
+ fprintf(stderr, "Ignoring flag -C %s", optarg);
+#endif
+ }
+ break;
+
+ case 'b': ;
+ uint64_t addr;
+ char *file;
+
+ if (!sscanf(optarg, "0x%" PRIx64 ",%ms", &addr, &file)) {
+ fprintf(stderr, "Could not parse argument %s\n", optarg);
+ return -1;
+ };
+
+ load_raw(addr, file);
+ free(file);
+ break;
+
+ case 'i':
+ load_image(optarg);
+ break;
+
+ case 'e':
+ load_elf(optarg, NULL, NULL);
+ break;
+
+ case 'n':
+ if (!sscanf(optarg, "0x%" PRIx64, &elf_entry)) {
+ fprintf(stderr, "Could not parse address %s\n", optarg);
+ return -1;
+ }
+ elf_entry_set = true;
+ break;
+
+ case 'l':
+ if (!sscanf(optarg, "%" PRId64, &g_cycle_limit)) {
+ fprintf(stderr, "Could not parse cycle limit %s\n", optarg);
+ return -1;
+ }
+ break;
+
+ case 'v':
+ if (!sscanf(optarg, "0x%" PRIx64, &g_verbosity)) {
+ fprintf(stderr, "Could not parse verbosity flags %s\n", optarg);
+ return -1;
+ }
+ break;
+
+ case 'h':
+ print_usage();
+ break;
+
+ default:
+ fprintf(stderr, "Unrecognized option %s\n", optarg);
+ print_usage();
+ return -1;
+ }
+ }
+
+ // assignment to g_elf_entry is deferred until the end of file so that an
+ // explicit command line flag will override the address read from the ELF
+ // file.
+ if (elf_entry_set) {
+ g_elf_entry = elf_entry;
+ }
+
+ return 0;
+}
+
+/* ***** Setup and cleanup functions for RTS ***** */
+
+void setup_rts(void)
+{
+ mpz_init(write_buf);
+ mpz_init(read_buf);
+ return;
+}
+
+void cleanup_rts(void)
+{
+ mpz_clear(write_buf);
+ mpz_clear(read_buf);
+ kill_mem();
+}