diff options
Diffstat (limited to 'lib/sail.h')
| -rw-r--r-- | lib/sail.h | 314 |
1 files changed, 253 insertions, 61 deletions
@@ -7,6 +7,7 @@ #include<stdbool.h> #include<string.h> #include<gmp.h> +#include<time.h> typedef int unit; @@ -16,6 +17,10 @@ unit undefined_unit(const unit u) { return UNIT; } +bool eq_unit(const unit u1, const unit u2) { + return true; +} + typedef struct { mp_bitcnt_t len; mpz_t *bits; @@ -23,32 +28,60 @@ typedef struct { typedef char *sail_string; -// This function should be called whenever a pattern match failure -// occurs. Pattern match failures are always fatal. +/* Temporary mpzs for use in functions below. To avoid conflicts, only + * use in functions that do not call other functions in this file. */ +static mpz_t sail_lib_tmp1, sail_lib_tmp2; + +/* Wrapper around >> operator to avoid UB when shift amount is greater + than or equal to 64. */ +uint64_t safe_rshift(const uint64_t x, const uint64_t n) { + if (n >= 64) { + return 0ul; + } else { + return x >> n; + } +} + +/* This function should be called whenever a pattern match failure + occurs. Pattern match failures are always fatal. */ void sail_match_failure(sail_string msg) { fprintf(stderr, "Pattern match failure in %s\n", msg); exit(EXIT_FAILURE); } +/* sail_assert implements the assert construct in Sail. If any + assertion fails we immediately exit the model. */ unit sail_assert(bool b, sail_string msg) { if (b) return UNIT; fprintf(stderr, "Assertion failed: %s\n", msg); exit(EXIT_FAILURE); } +/* If the sail model calls the exit() function we print a message and + exit successfully. */ unit sail_exit(const unit u) { - fprintf(stderr, "exit\n"); + fprintf(stderr, "Sail model exit\n"); exit(EXIT_SUCCESS); } +uint64_t g_elf_entry; + void elf_entry(mpz_t *rop, const unit u) { - mpz_set_ui(*rop, 0x400130ul); + mpz_set_ui(*rop, g_elf_entry); } void elf_tohost(mpz_t *rop, const unit u) { mpz_set_ui(*rop, 0x0ul); } +/* ASL->Sail model has an EnterLowPowerState() function that calls a + sleep request builtin. If it gets called we print a message and + exit the model. */ +unit sleep_request(const unit u) { + fprintf(stderr, "Sail model going to sleep\n"); + exit(EXIT_SUCCESS); +} + // Sail bits are mapped to uint64_t where bitzero = 0ul and bitone = 1ul bool eq_bit(const uint64_t a, const uint64_t b) { return a == b; @@ -56,6 +89,10 @@ bool eq_bit(const uint64_t a, const uint64_t b) { uint64_t undefined_bit(unit u) { return 0; } +unit skip(const unit u) { + return UNIT; +} + // ***** Sail booleans ***** bool not(const bool b) { @@ -98,6 +135,16 @@ void set_sail_string(sail_string *str1, const sail_string str2) { *str1 = strcpy(*str1, str2); } +void dec_str(sail_string *str, const mpz_t n) { + free(*str); + gmp_asprintf(str, "%Zd", n); +} + +void hex_str(sail_string *str, const mpz_t n) { + free(*str); + gmp_asprintf(str, "0x%Zx", n); +} + void clear_sail_string(sail_string *str) { free(*str); } @@ -106,6 +153,16 @@ bool eq_string(const sail_string str1, const sail_string str2) { return strcmp(str1, str2) == 0; } +void concat_str(sail_string *stro, const sail_string str1, const sail_string str2) { + *stro = realloc(*stro, strlen(str1) + strlen(str2) + 1); + (*stro)[0] = '\0'; + strcat(*stro, str1); + strcat(*stro, str2); +} + +void undefined_string(sail_string *str, const unit u) { +} + unit print_endline(const sail_string str) { printf("%s\n", str); return UNIT; @@ -136,6 +193,7 @@ unit print_int64(const sail_string str, const int64_t op) { unit sail_putchar(const mpz_t op) { char c = (char) mpz_get_ui(op); putchar(c); + return UNIT; } // ***** Arbitrary precision integers ***** @@ -209,6 +267,10 @@ void shl_int(mpz_t *rop, const mpz_t op1, const mpz_t op2) { mpz_mul_2exp(*rop, op1, mpz_get_ui(op2)); } +void shr_int(mpz_t *rop, const mpz_t op1, const mpz_t op2) { + mpz_fdiv_q_2exp(*rop, op1, mpz_get_ui(op2)); +} + void undefined_int(mpz_t *rop, const unit u) { mpz_set_ui(*rop, 0ul); } @@ -274,14 +336,34 @@ void pow2(mpz_t *rop, mpz_t exp) { mpz_clear(base); } +void get_time_ns(mpz_t *rop, const unit u) { + struct timespec t; + clock_gettime(CLOCK_REALTIME, &t); + mpz_set_si(*rop, t.tv_sec); + mpz_mul_ui(*rop, *rop, 1000000000); + mpz_add_ui(*rop, *rop, t.tv_nsec); +} + // ***** Sail bitvectors ***** -unit print_bits(const sail_string str, const bv_t op) +void string_of_int(sail_string *str, mpz_t i) { + gmp_asprintf(str, "%Zd", i); +} + +void string_of_bits(sail_string *str, const bv_t op) { + if ((op.len % 4) == 0) { + gmp_asprintf(str, "0x%*0Zx", op.len / 4, *op.bits); + } else { + gmp_asprintf(str, "0b%*0Zb", op.len, *op.bits); + } +} + +unit fprint_bits(const sail_string str, const bv_t op, FILE *stream) { - fputs(str, stdout); + fputs(str, stream); if (op.len % 4 == 0) { - fputs("0x", stdout); + fputs("0x", stream); mpz_t buf; mpz_init_set(buf, *op.bits); @@ -294,19 +376,30 @@ unit print_bits(const sail_string str, const bv_t op) } for (int i = op.len / 4; i > 0; --i) { - fputc(hex[i - 1], stdout); + fputc(hex[i - 1], stream); } free(hex); mpz_clear(buf); } else { - fputs("0b", stdout); + fputs("0b", stream); for (int i = op.len; i > 0; --i) { - fputc(mpz_tstbit(*op.bits, i - 1) + 0x30, stdout); + fputc(mpz_tstbit(*op.bits, i - 1) + 0x30, stream); } } - fputs("\n", stdout); + fputs("\n", stream); + return UNIT; +} + +unit print_bits(const sail_string str, const bv_t op) +{ + return fprint_bits(str, op, stdout); +} + +unit prerr_bits(const sail_string str, const bv_t op) +{ + return fprint_bits(str, op, stderr); } void length_bv_t(mpz_t *rop, const bv_t op) { @@ -324,6 +417,14 @@ void reinit_bv_t(bv_t *rop) { mpz_set_ui(*rop->bits, 0); } +void normalise_bv_t(bv_t *rop) { + /* TODO optimisation: keep a set of masks of various sizes handy */ + mpz_set_ui(sail_lib_tmp1, 1); + mpz_mul_2exp(sail_lib_tmp1, sail_lib_tmp1, rop->len); + mpz_sub_ui(sail_lib_tmp1, sail_lib_tmp1, 1); + mpz_and(*rop->bits, *rop->bits, sail_lib_tmp1); +} + void init_bv_t_of_uint64_t(bv_t *rop, const uint64_t op, const uint64_t len, const bool direction) { rop->bits = malloc(sizeof(mpz_t)); rop->len = len; @@ -349,7 +450,7 @@ void append_64(bv_t *rop, const bv_t op, const uint64_t chunk) { void append(bv_t *rop, const bv_t op1, const bv_t op2) { rop->len = op1.len + op2.len; mpz_mul_2exp(*rop->bits, *op1.bits, op2.len); - mpz_add(*rop->bits, *rop->bits, *op2.bits); + mpz_ior(*rop->bits, *rop->bits, *op2.bits); } void replicate_bits(bv_t *rop, const bv_t op1, const mpz_t op2) { @@ -363,9 +464,9 @@ void replicate_bits(bv_t *rop, const bv_t op1, const mpz_t op2) { } uint64_t fast_replicate_bits(const uint64_t shift, const uint64_t v, const int64_t times) { - uint64_t r = 0; - for (int i = 0; i < times; ++i) { - r |= v << shift; + uint64_t r = v; + for (int i = 1; i < times; ++i) { + r |= (r << shift); } return r; } @@ -397,10 +498,16 @@ void zero_extend(bv_t *rop, const bv_t op, const mpz_t len) { mpz_set(*rop->bits, *op.bits); } -/* FIXME */ void sign_extend(bv_t *rop, const bv_t op, const mpz_t len) { rop->len = mpz_get_ui(len); - mpz_set(*rop->bits, *op.bits); + if(mpz_tstbit(*op.bits, op.len - 1)) { + mpz_set(*rop->bits, *op.bits); + for(mp_bitcnt_t i = rop->len - 1; i >= op.len; i--) { + mpz_setbit(*rop->bits, i); + } + } else { + mpz_set(*rop->bits, *op.bits); + } } void clear_bv_t(bv_t *rop) { @@ -441,7 +548,10 @@ void or_bits(bv_t *rop, const bv_t op1, const bv_t op2) { void not_bits(bv_t *rop, const bv_t op) { rop->len = op.len; - mpz_com(*rop->bits, *op.bits); + mpz_set(*rop->bits, *op.bits); + for (mp_bitcnt_t i = 0; i < op.len; i++) { + mpz_combit(*rop->bits, i); + } } void xor_bits(bv_t *rop, const bv_t op1, const bv_t op2) { @@ -449,8 +559,6 @@ void xor_bits(bv_t *rop, const bv_t op1, const bv_t op2) { mpz_xor(*rop->bits, *op1.bits, *op2.bits); } -mpz_t eq_bits_test; - bool eq_bits(const bv_t op1, const bv_t op2) { for (mp_bitcnt_t i = 0; i < op1.len; i++) { @@ -459,39 +567,25 @@ bool eq_bits(const bv_t op1, const bv_t op2) return true; } -// These aren't very efficient, but they work. Question is how best to -// do these given GMP uses a sign bit representation? void sail_uint(mpz_t *rop, const bv_t op) { - mpz_set_ui(*rop, 0ul); - for (mp_bitcnt_t i = 0; i < op.len; ++i) { - if (mpz_tstbit(*op.bits, i)) { - mpz_setbit(*rop, i); - } else { - mpz_clrbit(*rop, i); - } - } + /* Normal form of bv_t is always positive so just return the bits. */ + mpz_set(*rop, *op.bits); } void sint(mpz_t *rop, const bv_t op) { - mpz_set_ui(*rop, 0ul); - if (mpz_tstbit(*op.bits, op.len - 1)) { - for (mp_bitcnt_t i = 0; i < op.len; ++i) { - if (mpz_tstbit(*op.bits, i)) { - mpz_clrbit(*rop, i); - } else { - mpz_setbit(*rop, i); - } - }; - mpz_add_ui(*rop, *rop, 1ul); - mpz_neg(*rop, *rop); + if (op.len == 0) { + mpz_set_ui(*rop, 0); } else { - for (mp_bitcnt_t i = 0; i < op.len; ++i) { - if (mpz_tstbit(*op.bits, i)) { - mpz_setbit(*rop, i); - } else { - mpz_clrbit(*rop, i); - } + mp_bitcnt_t sign_bit = op.len - 1; + mpz_set(*rop, *op.bits); + if (mpz_tstbit(*op.bits, sign_bit) != 0) { + /* If sign bit is unset then we are done, + otherwise clear sign_bit and subtract 2**sign_bit */ + mpz_set_ui(sail_lib_tmp1, 1); + mpz_mul_2exp(sail_lib_tmp1, sail_lib_tmp1, sign_bit); /* 2**sign_bit */ + mpz_combit(*rop, sign_bit); /* clear sign_bit */ + mpz_sub(*rop, *rop, sail_lib_tmp1); } } } @@ -499,19 +593,103 @@ void sint(mpz_t *rop, const bv_t op) void add_bits(bv_t *rop, const bv_t op1, const bv_t op2) { rop->len = op1.len; mpz_add(*rop->bits, *op1.bits, *op2.bits); + normalise_bv_t(rop); +} + +void sub_bits(bv_t *rop, const bv_t op1, const bv_t op2) { + rop->len = op1.len; + mpz_sub(*rop->bits, *op1.bits, *op2.bits); + normalise_bv_t(rop); } void add_bits_int(bv_t *rop, const bv_t op1, const mpz_t op2) { rop->len = op1.len; mpz_add(*rop->bits, *op1.bits, op2); + normalise_bv_t(rop); } void sub_bits_int(bv_t *rop, const bv_t op1, const mpz_t op2) { - printf("sub_bits_int\n"); rop->len = op1.len; mpz_sub(*rop->bits, *op1.bits, op2); } +void mults_vec(bv_t *rop, const bv_t op1, const bv_t op2) { + mpz_t op1_int, op2_int; + mpz_init(op1_int); + mpz_init(op2_int); + sint(&op1_int, op1); + sint(&op2_int, op2); + rop->len = op1.len * 2; + mpz_mul(*rop->bits, op1_int, op2_int); + normalise_bv_t(rop); + mpz_clear(op1_int); + mpz_clear(op2_int); +} + +void mult_vec(bv_t *rop, const bv_t op1, const bv_t op2) { + rop->len = op1.len * 2; + mpz_mul(*rop->bits, *op1.bits, *op2.bits); + normalise_bv_t(rop); /* necessary? */ +} + +void shift_bits_left(bv_t *rop, const bv_t op1, const bv_t op2) { + rop->len = op1.len; + mpz_mul_2exp(*rop->bits, *op1.bits, mpz_get_ui(*op2.bits)); + normalise_bv_t(rop); +} + +void shift_bits_right(bv_t *rop, const bv_t op1, const bv_t op2) { + rop->len = op1.len; + mpz_tdiv_q_2exp(*rop->bits, *op1.bits, mpz_get_ui(*op2.bits)); +} + +/* FIXME */ +void shift_bits_right_arith(bv_t *rop, const bv_t op1, const bv_t op2) { + rop->len = op1.len; + mp_bitcnt_t shift_amt = mpz_get_ui(*op2.bits); + mp_bitcnt_t sign_bit = op1.len - 1; + mpz_fdiv_q_2exp(*rop->bits, *op1.bits, shift_amt); + if(mpz_tstbit(*op1.bits, sign_bit) != 0) { + /* */ + for(; shift_amt > 0; shift_amt--) { + mpz_setbit(*rop->bits, sign_bit - shift_amt + 1); + } + } +} + +void reverse_endianness(bv_t *rop, const bv_t op) { + rop->len = op.len; + if (rop->len == 64ul) { + uint64_t x = mpz_get_ui(*op.bits); + x = (x & 0xFFFFFFFF00000000) >> 32 | (x & 0x00000000FFFFFFFF) << 32; + x = (x & 0xFFFF0000FFFF0000) >> 16 | (x & 0x0000FFFF0000FFFF) << 16; + x = (x & 0xFF00FF00FF00FF00) >> 8 | (x & 0x00FF00FF00FF00FF) << 8; + mpz_set_ui(*rop->bits, x); + } else if (rop->len == 32ul) { + uint64_t x = mpz_get_ui(*op.bits); + x = (x & 0xFFFF0000FFFF0000) >> 16 | (x & 0x0000FFFF0000FFFF) << 16; + x = (x & 0xFF00FF00FF00FF00) >> 8 | (x & 0x00FF00FF00FF00FF) << 8; + mpz_set_ui(*rop->bits, x); + } else if (rop->len == 16ul) { + uint64_t x = mpz_get_ui(*op.bits); + x = (x & 0xFF00FF00FF00FF00) >> 8 | (x & 0x00FF00FF00FF00FF) << 8; + mpz_set_ui(*rop->bits, x); + } else if (rop->len == 8ul) { + mpz_set(*rop->bits, *op.bits); + } else { + /* For other numbers of bytes we reverse the bytes. + * XXX could use mpz_import/export for this. */ + mpz_set_ui(sail_lib_tmp1, 0xff); // byte mask + mpz_set_ui(*rop->bits, 0); // reset accumulator for result + for(mp_bitcnt_t byte = 0; byte < op.len; byte+=8) { + mpz_tdiv_q_2exp(sail_lib_tmp2, *op.bits, byte); // shift byte to bottom + mpz_and(sail_lib_tmp2, sail_lib_tmp2, sail_lib_tmp1); // and with mask + mpz_mul_2exp(*rop->bits, *rop->bits, 8); // shift result left 8 + mpz_ior(*rop->bits, *rop->bits, sail_lib_tmp2); // or byte into result + } + } +} + // Takes a slice of the (two's complement) binary representation of // integer n, starting at bit start, and of length len. With the // argument in the following order: @@ -767,26 +945,18 @@ uint64_t MASK = 0xFFFFul; // are used in the second argument. void write_mem(uint64_t address, uint64_t byte) { + //printf("ADDR: %lu, BYTE: %lu\n", address, byte); + uint64_t mask = address & ~MASK; uint64_t offset = address & MASK; - struct block *prev = NULL; struct block *current = sail_memory; while (current != NULL) { if (current->block_id == mask) { current->mem[offset] = (uint8_t) byte; - - /* Move the accessed block to the front of the block list */ - if (prev != NULL) { - prev->next = current->next; - } - current->next = sail_memory->next; - sail_memory = current; - return; } else { - prev = current; current = current->next; } } @@ -886,6 +1056,18 @@ void read_ram(bv_t *data, mpz_clear(byte); } +unit load_raw(uint64_t addr, const sail_string file) { + FILE *fp = fopen(file, "r"); + + 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"); @@ -904,7 +1086,15 @@ void load_image(char *file) { ssize_t data_len = getline(&data, &len, fp); if (data_len == -1) break; - write_mem((uint64_t) atoll(addr), (uint64_t) atoll(data)); + if (!strcmp(addr, "elf_entry\n")) { + if (sscanf(data, "%" PRIu64 "\n", &g_elf_entry) != 1) { + fprintf(stderr, "Failed to parse elf_entry\n"); + exit(EXIT_FAILURE); + }; + printf("Elf entry point: %" PRIx64 "\n", g_elf_entry); + } else { + write_mem((uint64_t) atoll(addr), (uint64_t) atoll(data)); + } } free(addr); @@ -923,10 +1113,12 @@ void load_instr(uint64_t addr, uint32_t instr) { void setup_library(void) { mpf_set_default_prec(FLOAT_PRECISION); - mpz_init(eq_bits_test); + mpz_init(sail_lib_tmp1); + mpz_init(sail_lib_tmp2); } void cleanup_library(void) { - mpz_clear(eq_bits_test); + mpz_clear(sail_lib_tmp1); + mpz_clear(sail_lib_tmp2); kill_mem(); } |
