summaryrefslogtreecommitdiff
path: root/lib/sail.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sail.h')
-rw-r--r--lib/sail.h314
1 files changed, 253 insertions, 61 deletions
diff --git a/lib/sail.h b/lib/sail.h
index b5328377..99b57d8a 100644
--- a/lib/sail.h
+++ b/lib/sail.h
@@ -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();
}