aboutsummaryrefslogtreecommitdiff
path: root/dyngen.h
diff options
context:
space:
mode:
Diffstat (limited to 'dyngen.h')
-rw-r--r--dyngen.h60
1 files changed, 45 insertions, 15 deletions
diff --git a/dyngen.h b/dyngen.h
index fe0a9364e7..2a87c448fd 100644
--- a/dyngen.h
+++ b/dyngen.h
@@ -19,7 +19,7 @@
*/
int __op_param1, __op_param2, __op_param3;
-#ifdef __sparc__
+#if defined(__sparc__) || defined(__arm__)
void __op_gen_label1(){}
void __op_gen_label2(){}
void __op_gen_label3(){}
@@ -145,18 +145,16 @@ void fix_bsr(void *p, int offset) {
#ifdef __arm__
-#define MAX_OP_SIZE (128 * 4) /* in bytes */
-/* max size of the code that can be generated without calling arm_flush_ldr */
-#define MAX_FRAG_SIZE (1024 * 4)
-//#define MAX_FRAG_SIZE (135 * 4) /* for testing */
+#define ARM_LDR_TABLE_SIZE 1024
typedef struct LDREntry {
uint8_t *ptr;
uint32_t *data_ptr;
+ unsigned type:2;
} LDREntry;
static LDREntry arm_ldr_table[1024];
-static uint32_t arm_data_table[1024];
+static uint32_t arm_data_table[ARM_LDR_TABLE_SIZE];
extern char exec_loop;
@@ -175,8 +173,9 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
int offset, data_size, target;
uint8_t *data_ptr;
uint32_t insn;
+ uint32_t mask;
- data_size = (uint8_t *)data_end - (uint8_t *)data_start;
+ data_size = (data_end - data_start) << 2;
if (gen_jmp) {
/* generate branch to skip the data */
@@ -198,17 +197,48 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) +
(unsigned long)data_ptr -
(unsigned long)ptr - 8;
- insn = *ptr & ~(0xfff | 0x00800000);
if (offset < 0) {
- offset = - offset;
- } else {
- insn |= 0x00800000;
- }
- if (offset > 0xfff) {
- fprintf(stderr, "Error ldr offset\n");
+ fprintf(stderr, "Negative constant pool offset\n");
abort();
}
- insn |= offset;
+ switch (le->type) {
+ case 0: /* ldr */
+ mask = ~0x00800fff;
+ if (offset >= 4096) {
+ fprintf(stderr, "Bad ldr offset\n");
+ abort();
+ }
+ break;
+ case 1: /* ldc */
+ mask = ~0x008000ff;
+ if (offset >= 1024 ) {
+ fprintf(stderr, "Bad ldc offset\n");
+ abort();
+ }
+ break;
+ case 2: /* add */
+ mask = ~0xfff;
+ if (offset >= 1024 ) {
+ fprintf(stderr, "Bad add offset\n");
+ abort();
+ }
+ break;
+ default:
+ fprintf(stderr, "Bad pc relative fixup\n");
+ abort();
+ }
+ insn = *ptr & mask;
+ switch (le->type) {
+ case 0: /* ldr */
+ insn |= offset | 0x00800000;
+ break;
+ case 1: /* ldc */
+ insn |= (offset >> 2) | 0x00800000;
+ break;
+ case 2: /* add */
+ insn |= (offset >> 2) | 0xf00;
+ break;
+ }
*ptr = insn;
}
return gen_code_ptr;