diff options
Diffstat (limited to 'src/gallium/drivers')
-rw-r--r-- | src/gallium/drivers/nv50/nv50_pc.h | 27 | ||||
-rw-r--r-- | src/gallium/drivers/nv50/nv50_pc_emit.c | 98 | ||||
-rw-r--r-- | src/gallium/drivers/nv50/nv50_program.c | 3 | ||||
-rw-r--r-- | src/gallium/drivers/nv50/nv50_program.h | 5 |
4 files changed, 79 insertions, 54 deletions
diff --git a/src/gallium/drivers/nv50/nv50_pc.h b/src/gallium/drivers/nv50/nv50_pc.h index fd2799eba1e..2ead80430b0 100644 --- a/src/gallium/drivers/nv50/nv50_pc.h +++ b/src/gallium/drivers/nv50/nv50_pc.h @@ -295,28 +295,6 @@ struct nv_basic_block { uint32_t live_set[NV_PC_MAX_VALUES / 32]; }; -#define NV_FIXUP_CFLOW_RELOC 0 -#define NV_FIXUP_PARAM_RELOC 1 - -struct nv_fixup { - ubyte type; - ubyte shift; - uint32_t mask; - uint32_t data; - uint32_t offset; -}; - -static INLINE void -nv_fixup_apply(uint32_t *bin, struct nv_fixup *fixup, uint32_t data) -{ - uint32_t val; - - val = bin[fixup->offset / 4] & ~fixup->mask; - data = (fixup->shift < 0) ? (data >> fixup->shift) : (data << fixup->shift); - val |= (fixup->data + data) & fixup->mask; - bin[fixup->offset / 4] = val; -} - struct nv50_translation_info; struct nv_pc { @@ -346,8 +324,8 @@ struct nv_pc { unsigned bin_size; unsigned bin_pos; - struct nv_fixup *fixups; - int num_fixups; + void *fixups; + unsigned num_fixups; /* optimization enables */ boolean opt_reload_elim; @@ -471,6 +449,7 @@ nv_reference(struct nv_pc *pc, struct nv_ref **d, struct nv_value *s) /* nv50_emit.c */ void nv50_emit_instruction(struct nv_pc *, struct nv_instruction *); +unsigned nv50_inst_min_size(struct nv_instruction *); /* nv50_print.c */ const char *nv_opcode_name(uint opcode); diff --git a/src/gallium/drivers/nv50/nv50_pc_emit.c b/src/gallium/drivers/nv50/nv50_pc_emit.c index 137a531dd62..f37dc51e6aa 100644 --- a/src/gallium/drivers/nv50/nv50_pc_emit.c +++ b/src/gallium/drivers/nv50/nv50_pc_emit.c @@ -23,8 +23,6 @@ #include "nv50_context.h" #include "nv50_pc.h" -// Definitions - #define FLAGS_CC_SHIFT 7 #define FLAGS_ID_SHIFT 12 #define FLAGS_WR_ID_SHIFT 4 @@ -33,6 +31,64 @@ #define FLAGS_WR_EN (1 << 6) #define FLAGS_WR_ID_MASK (0x3 << FLAGS_WR_ID_SHIFT) +#define NV50_FIXUP_CODE_RELOC 0 +#define NV50_FIXUP_DATA_RELOC 1 + +struct nv50_fixup { + uint8_t type; + int8_t shift; + uint32_t mask; + uint32_t data; + uint32_t offset; +}; + +void +nv50_relocate_program(struct nv50_program *p, + uint32_t code_base, + uint32_t data_base) +{ + struct nv50_fixup *f = (struct nv50_fixup *)p->fixups; + unsigned i; + + for (i = 0; i < p->num_fixups; ++i) { + uint32_t data; + + switch (f[i].type) { + case NV50_FIXUP_CODE_RELOC: data = code_base + f[i].data; break; + case NV50_FIXUP_DATA_RELOC: data = data_base + f[i].data; break; + default: + data = f[i].data; + break; + } + data = (f[i].shift < 0) ? (data >> -f[i].shift) : (data << f[i].shift); + + p->code[f[i].offset / 4] &= ~f[i].mask; + p->code[f[i].offset / 4] |= data & f[i].mask; + } +} + +static void +new_fixup(struct nv_pc *pc, uint8_t ty, int w, uint32_t data, uint32_t m, int s) +{ + struct nv50_fixup *f; + + const unsigned size = sizeof(struct nv50_fixup); + const unsigned n = pc->num_fixups; + + if (!(n % 8)) + pc->fixups = REALLOC(pc->fixups, n * size, (n + 8) * size); + + f = (struct nv50_fixup *)pc->fixups; + + f[n].offset = (pc->bin_pos + w) * 4; + f[n].type = ty; + f[n].data = data; + f[n].mask = m; + f[n].shift = s; + + ++pc->num_fixups; +} + const ubyte nv50_inst_min_size_tab[NV_OP_COUNT] = { 0, 0, 0, 8, 8, 4, 4, 4, 8, 4, 4, 8, 8, 8, 8, 8, /* 15 */ @@ -41,10 +97,6 @@ const ubyte nv50_inst_min_size_tab[NV_OP_COUNT] = 4, 8, 8, 8, 8, 8, 0, 0, 8 }; -/* XXX: silence, you ! */ -unsigned -nv50_inst_min_size(struct nv_instruction *i); - unsigned nv50_inst_min_size(struct nv_instruction *i) { @@ -159,27 +211,9 @@ set_immd(struct nv_pc *pc, struct nv_ref *ref) set_immd_u32(pc, get_immd_u32(ref)); } -static void -new_fixup(struct nv_pc *pc, unsigned type, uint32_t data, uint32_t m, int s) -{ - const unsigned size = sizeof(struct nv_fixup); - const unsigned n = pc->num_fixups; - return; - - if (!(n % 8)) - pc->fixups = REALLOC(pc->fixups, n * size, (n + 8) * size); - - pc->fixups[n].offset = pc->bin_pos + (s / 32); - pc->fixups[n].type = type; - pc->fixups[n].data = data; - pc->fixups[n].mask = m << (s % 32); - pc->fixups[n].shift = s % 32; - - ++pc->num_fixups; - - assert(((data << (s % 32)) & pc->fixups[n].mask) == (data << (s % 32))); -} - +/* Allocate data in immediate buffer, if we want to load the immediate + * for a constant buffer instead of inlining it into the code. + */ static void nv_pc_alloc_immd(struct nv_pc *pc, struct nv_ref *ref) { @@ -446,7 +480,7 @@ emit_ld(struct nv_pc *pc, struct nv_instruction *i) sf = NV_FILE_MEM_C(0); nv_pc_alloc_immd(pc, i->src[0]); - new_fixup(pc, NV_FIXUP_PARAM_RELOC, SREG(i->src[0])->id, 0xffff, 9); + new_fixup(pc, NV50_FIXUP_DATA_RELOC, 0, SREG(i->src[0])->id, 0xffff, 9); } if (sf == NV_FILE_MEM_S || @@ -723,8 +757,12 @@ emit_flow(struct nv_pc *pc, struct nv_instruction *i, ubyte flow_op) set_pred(pc, i); if (i->target && (i->opcode != NV_OP_BREAK)) { - new_fixup(pc, NV_FIXUP_CFLOW_RELOC, i->target->bin_pos, 0x7ff800, 11); - pc->emit[0] |= (i->target->bin_pos / 4) << 11; + uint32_t pos = i->target->bin_pos; + + new_fixup(pc, NV50_FIXUP_CODE_RELOC, 0, pos, 0xffff << 11, 9); + new_fixup(pc, NV50_FIXUP_CODE_RELOC, 1, pos, 0x3f << 14, -4); + + pc->emit[0] |= (pos / 4) << 11; } } diff --git a/src/gallium/drivers/nv50/nv50_program.c b/src/gallium/drivers/nv50/nv50_program.c index b3600f7ba73..db681764910 100644 --- a/src/gallium/drivers/nv50/nv50_program.c +++ b/src/gallium/drivers/nv50/nv50_program.c @@ -653,5 +653,8 @@ nv50_program_destroy(struct nv50_context *nv50, struct nv50_program *p) if (p->code) FREE(p->code); + if (p->fixups) + FREE(p->fixups); + p->translated = FALSE; } diff --git a/src/gallium/drivers/nv50/nv50_program.h b/src/gallium/drivers/nv50/nv50_program.h index c92af317f43..37b02bbec7c 100644 --- a/src/gallium/drivers/nv50/nv50_program.h +++ b/src/gallium/drivers/nv50/nv50_program.h @@ -85,6 +85,7 @@ struct nv50_program { uint8_t prim_type; /* point, line strip or tri strip */ } gp; + /* relocation records */ void *fixups; unsigned num_fixups; }; @@ -126,6 +127,10 @@ struct nv50_translation_info { }; int nv50_generate_code(struct nv50_translation_info *ti); + +void nv50_relocate_program(struct nv50_program *p, + uint32_t code_base, uint32_t data_base); + boolean nv50_program_tx(struct nv50_program *p); #endif /* __NV50_PROG_H__ */ |