/* iword.c -- instruction-word decode. See iword.h for the layout. */ #include "v4/iword.h" /* The five opcodes that consume a target from the low bits of their slot * (section 1.2): jump, call, next, if, -if. A table rather than a switch so * that the set is visible in one place and can be counted in the tests. */ int v4_op_is_branch(unsigned op) { return op == V4_OP_JUMP || op == V4_OP_CALL || op == V4_OP_NEXT || op == V4_OP_IF || op == V4_OP_MINUS_IF; } int v4_iword_branch_legal(unsigned slot) { return slot < 4u; /* section 1.2: branches are legal in slots 0-3 only */ } uint32_t v4_iword_slot_mask(unsigned slot) { if (slot >= V4_SLOT_COUNT) return 0u; /* 27-5k address bits, e.g. 0x07FFFFFF for slot 0 down to 0x00000FFF for * slot 3. For slots 4 and 5 the formula still produces 7 and 2 bits; the * legality check is separate because those slots are simply not usable. */ return ((uint32_t)1u << V4_BRANCH_ADDR_BITS(slot)) - 1u; } unsigned v4_iword_op(v4_iword w, unsigned slot) { if (slot >= V4_SLOT_COUNT) return 0u; return (unsigned)((w >> V4_SLOT_LOW_BIT(slot)) & 0x1Fu); } unsigned v4_iword_spare(v4_iword w) { return (unsigned)(w & ((1u << V4_SPARE_BITS) - 1u)); } v4_iword v4_iword_target(v4_iword w, unsigned slot) { if (slot >= V4_SLOT_COUNT) return 0u; return w & v4_iword_slot_mask(slot); } v4_iword v4_iword_assemble(const unsigned op[V4_SLOT_COUNT], unsigned spare) { v4_iword w = 0u; for (unsigned k = 0; k < V4_SLOT_COUNT; k++) { /* An opcode that does not fit in 5 bits is a bug in whoever built the * word, not something to encode silently. Truncating here would let a * malformed capsule execute as something else. */ if (op[k] > 0x1Fu) return 0xFFFFFFFFu; w |= (v4_iword)(op[k] & 0x1Fu) << V4_SLOT_LOW_BIT(k); } if (spare > ((1u << V4_SPARE_BITS) - 1u)) return 0xFFFFFFFFu; w |= (v4_iword)(spare & ((1u << V4_SPARE_BITS) - 1u)); return w; } v4_cell v4_iword_branch(v4_cell p, v4_iword w, unsigned slot) { uint32_t mask = v4_iword_slot_mask(slot); v4_ucell up = (v4_ucell)p; /* Page-relative, as in the F18: the target supplies the low * V4_BRANCH_ADDR_BITS(slot) bits of P and the bits above them survive. The * mask is computed in 32 bits and widened, so a 64-bit P keeps its high * half -- which is the correct reading of "replaces the same low bits of P" * at any cell width. */ up = (up & ~(v4_ucell)mask) | (v4_ucell)(w & mask); return (v4_cell)up; }