diff options
| author | Alasdair | 2019-05-05 16:24:02 +0100 |
|---|---|---|
| committer | Alasdair | 2019-05-05 19:02:05 +0100 |
| commit | 39168f905eb9e671813cfc43309ddae44828123a (patch) | |
| tree | 21d9e5fb2b7758aeed2aea1f6873a22750397477 /lib/int128/rts.c | |
| parent | aeb4e23aeb12a99568dcc49f0d39ae86c7bd5065 (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.c | 529 |
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(); +} |
